blob: 708e67cb17b2856271b0a7ed5e7c1ca974d75a8b [file] [log] [blame]
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
//! COSE_KDF_Context functionality.
use crate::{
cbor::value::Value,
common::AsCborValue,
iana,
util::{cbor_type_error, ValueTryAs},
Algorithm, CoseError, ProtectedHeader, Result,
};
use alloc::{vec, vec::Vec};
use core::convert::TryInto;
#[cfg(test)]
mod tests;
/// A nonce value.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Nonce {
Bytes(Vec<u8>),
Integer(i64),
}
/// Structure representing a party involved in key derivation.
///
/// ```cddl
/// PartyInfo = (
/// identity : bstr / nil,
/// nonce : bstr / int / nil,
/// other : bstr / nil
/// )
/// ```
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PartyInfo {
pub identity: Option<Vec<u8>>,
pub nonce: Option<Nonce>,
pub other: Option<Vec<u8>>,
}
impl crate::CborSerializable for PartyInfo {}
impl AsCborValue for PartyInfo {
fn from_cbor_value(value: Value) -> Result<Self> {
let mut a = value.try_as_array()?;
if a.len() != 3 {
return Err(CoseError::UnexpectedItem("array", "array with 3 items"));
}
// Remove array elements in reverse order to avoid shifts.
Ok(Self {
other: match a.remove(2) {
Value::Null => None,
Value::Bytes(b) => Some(b),
v => return cbor_type_error(&v, "bstr / nil"),
},
nonce: match a.remove(1) {
Value::Null => None,
Value::Bytes(b) => Some(Nonce::Bytes(b)),
Value::Integer(u) => Some(Nonce::Integer(u.try_into()?)),
v => return cbor_type_error(&v, "bstr / int / nil"),
},
identity: match a.remove(0) {
Value::Null => None,
Value::Bytes(b) => Some(b),
v => return cbor_type_error(&v, "bstr / nil"),
},
})
}
fn to_cbor_value(self) -> Result<Value> {
Ok(Value::Array(vec![
match self.identity {
None => Value::Null,
Some(b) => Value::Bytes(b),
},
match self.nonce {
None => Value::Null,
Some(Nonce::Bytes(b)) => Value::Bytes(b),
Some(Nonce::Integer(i)) => Value::from(i),
},
match self.other {
None => Value::Null,
Some(b) => Value::Bytes(b),
},
]))
}
}
/// Builder for [`PartyInfo`] objects.
#[derive(Debug, Default)]
pub struct PartyInfoBuilder(PartyInfo);
impl PartyInfoBuilder {
builder! {PartyInfo}
builder_set_optional! {identity: Vec<u8>}
builder_set_optional! {nonce: Nonce}
builder_set_optional! {other: Vec<u8>}
}
/// Structure representing supplemental public information.
///
/// ```cddl
/// SuppPubInfo : [
/// keyDataLength : uint,
/// protected : empty_or_serialized_map,
/// ? other : bstr
/// ],
/// ```
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SuppPubInfo {
pub key_data_length: u64,
pub protected: ProtectedHeader,
pub other: Option<Vec<u8>>,
}
impl crate::CborSerializable for SuppPubInfo {}
impl AsCborValue for SuppPubInfo {
fn from_cbor_value(value: Value) -> Result<Self> {
let mut a = value.try_as_array()?;
if a.len() != 2 && a.len() != 3 {
return Err(CoseError::UnexpectedItem(
"array",
"array with 2 or 3 items",
));
}
// Remove array elements in reverse order to avoid shifts.
Ok(Self {
other: {
if a.len() == 3 {
Some(a.remove(2).try_as_bytes()?)
} else {
None
}
},
protected: ProtectedHeader::from_cbor_bstr(a.remove(1))?,
key_data_length: a.remove(0).try_as_integer()?.try_into()?,
})
}
fn to_cbor_value(self) -> Result<Value> {
let mut v = vec![
Value::from(self.key_data_length),
self.protected.cbor_bstr()?,
];
if let Some(other) = self.other {
v.push(Value::Bytes(other));
}
Ok(Value::Array(v))
}
}
/// Builder for [`SuppPubInfo`] objects.
#[derive(Debug, Default)]
pub struct SuppPubInfoBuilder(SuppPubInfo);
impl SuppPubInfoBuilder {
builder! {SuppPubInfo}
builder_set! {key_data_length: u64}
builder_set_protected! {protected}
builder_set_optional! {other: Vec<u8>}
}
/// Structure representing a a key derivation context.
/// ```cdl
/// COSE_KDF_Context = [
/// AlgorithmID : int / tstr,
/// PartyUInfo : [ PartyInfo ],
/// PartyVInfo : [ PartyInfo ],
/// SuppPubInfo : [
/// keyDataLength : uint,
/// protected : empty_or_serialized_map,
/// ? other : bstr
/// ],
/// ? SuppPrivInfo : bstr
/// ]
/// ```
#[derive(Clone, Debug, Default, PartialEq)]
pub struct CoseKdfContext {
algorithm_id: Algorithm,
party_u_info: PartyInfo,
party_v_info: PartyInfo,
supp_pub_info: SuppPubInfo,
supp_priv_info: Vec<Vec<u8>>,
}
impl crate::CborSerializable for CoseKdfContext {}
impl AsCborValue for CoseKdfContext {
fn from_cbor_value(value: Value) -> Result<Self> {
let mut a = value.try_as_array()?;
if a.len() < 4 {
return Err(CoseError::UnexpectedItem(
"array",
"array with at least 4 items",
));
}
// Remove array elements in reverse order to avoid shifts.
let mut supp_priv_info = Vec::with_capacity(a.len() - 4);
for i in (4..a.len()).rev() {
supp_priv_info.push(a.remove(i).try_as_bytes()?);
}
supp_priv_info.reverse();
Ok(Self {
supp_priv_info,
supp_pub_info: SuppPubInfo::from_cbor_value(a.remove(3))?,
party_v_info: PartyInfo::from_cbor_value(a.remove(2))?,
party_u_info: PartyInfo::from_cbor_value(a.remove(1))?,
algorithm_id: Algorithm::from_cbor_value(a.remove(0))?,
})
}
fn to_cbor_value(self) -> Result<Value> {
let mut v = vec![
self.algorithm_id.to_cbor_value()?,
self.party_u_info.to_cbor_value()?,
self.party_v_info.to_cbor_value()?,
self.supp_pub_info.to_cbor_value()?,
];
for supp_priv_info in self.supp_priv_info {
v.push(Value::Bytes(supp_priv_info));
}
Ok(Value::Array(v))
}
}
/// Builder for [`CoseKdfContext`] objects.
#[derive(Debug, Default)]
pub struct CoseKdfContextBuilder(CoseKdfContext);
impl CoseKdfContextBuilder {
builder! {CoseKdfContext}
builder_set! {party_u_info: PartyInfo}
builder_set! {party_v_info: PartyInfo}
builder_set! {supp_pub_info: SuppPubInfo}
/// Set the algorithm.
#[must_use]
pub fn algorithm(mut self, alg: iana::Algorithm) -> Self {
self.0.algorithm_id = Algorithm::Assigned(alg);
self
}
/// Add supplemental private info.
#[must_use]
pub fn add_supp_priv_info(mut self, supp_priv_info: Vec<u8>) -> Self {
self.0.supp_priv_info.push(supp_priv_info);
self
}
}