1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 //! COSE_KDF_Context functionality. 18 19 use crate::{ 20 cbor::value::Value, 21 common::AsCborValue, 22 iana, 23 util::{cbor_type_error, ValueTryAs}, 24 Algorithm, CoseError, ProtectedHeader, Result, 25 }; 26 use alloc::{vec, vec::Vec}; 27 use core::convert::TryInto; 28 29 #[cfg(test)] 30 mod tests; 31 32 /// A nonce value. 33 #[derive(Clone, Debug, Eq, PartialEq)] 34 pub enum Nonce { 35 Bytes(Vec<u8>), 36 Integer(i64), 37 } 38 39 /// Structure representing a party involved in key derivation. 40 /// 41 /// ```cddl 42 /// PartyInfo = ( 43 /// identity : bstr / nil, 44 /// nonce : bstr / int / nil, 45 /// other : bstr / nil 46 /// ) 47 /// ``` 48 #[derive(Clone, Debug, Default, Eq, PartialEq)] 49 pub struct PartyInfo { 50 pub identity: Option<Vec<u8>>, 51 pub nonce: Option<Nonce>, 52 pub other: Option<Vec<u8>>, 53 } 54 55 impl crate::CborSerializable for PartyInfo {} 56 57 impl AsCborValue for PartyInfo { from_cbor_value(value: Value) -> Result<Self>58 fn from_cbor_value(value: Value) -> Result<Self> { 59 let mut a = value.try_as_array()?; 60 if a.len() != 3 { 61 return Err(CoseError::UnexpectedItem("array", "array with 3 items")); 62 } 63 64 // Remove array elements in reverse order to avoid shifts. 65 Ok(Self { 66 other: match a.remove(2) { 67 Value::Null => None, 68 Value::Bytes(b) => Some(b), 69 v => return cbor_type_error(&v, "bstr / nil"), 70 }, 71 nonce: match a.remove(1) { 72 Value::Null => None, 73 Value::Bytes(b) => Some(Nonce::Bytes(b)), 74 Value::Integer(u) => Some(Nonce::Integer(u.try_into()?)), 75 v => return cbor_type_error(&v, "bstr / int / nil"), 76 }, 77 identity: match a.remove(0) { 78 Value::Null => None, 79 Value::Bytes(b) => Some(b), 80 v => return cbor_type_error(&v, "bstr / nil"), 81 }, 82 }) 83 } 84 to_cbor_value(self) -> Result<Value>85 fn to_cbor_value(self) -> Result<Value> { 86 Ok(Value::Array(vec![ 87 match self.identity { 88 None => Value::Null, 89 Some(b) => Value::Bytes(b), 90 }, 91 match self.nonce { 92 None => Value::Null, 93 Some(Nonce::Bytes(b)) => Value::Bytes(b), 94 Some(Nonce::Integer(i)) => Value::from(i), 95 }, 96 match self.other { 97 None => Value::Null, 98 Some(b) => Value::Bytes(b), 99 }, 100 ])) 101 } 102 } 103 104 /// Builder for [`PartyInfo`] objects. 105 #[derive(Debug, Default)] 106 pub struct PartyInfoBuilder(PartyInfo); 107 108 impl PartyInfoBuilder { 109 builder! {PartyInfo} 110 builder_set_optional! {identity: Vec<u8>} 111 builder_set_optional! {nonce: Nonce} 112 builder_set_optional! {other: Vec<u8>} 113 } 114 115 /// Structure representing supplemental public information. 116 /// 117 /// ```cddl 118 /// SuppPubInfo : [ 119 /// keyDataLength : uint, 120 /// protected : empty_or_serialized_map, 121 /// ? other : bstr 122 /// ], 123 /// ``` 124 #[derive(Clone, Debug, Default, PartialEq)] 125 pub struct SuppPubInfo { 126 pub key_data_length: u64, 127 pub protected: ProtectedHeader, 128 pub other: Option<Vec<u8>>, 129 } 130 131 impl crate::CborSerializable for SuppPubInfo {} 132 133 impl AsCborValue for SuppPubInfo { from_cbor_value(value: Value) -> Result<Self>134 fn from_cbor_value(value: Value) -> Result<Self> { 135 let mut a = value.try_as_array()?; 136 if a.len() != 2 && a.len() != 3 { 137 return Err(CoseError::UnexpectedItem( 138 "array", 139 "array with 2 or 3 items", 140 )); 141 } 142 143 // Remove array elements in reverse order to avoid shifts. 144 Ok(Self { 145 other: { 146 if a.len() == 3 { 147 Some(a.remove(2).try_as_bytes()?) 148 } else { 149 None 150 } 151 }, 152 protected: ProtectedHeader::from_cbor_bstr(a.remove(1))?, 153 key_data_length: a.remove(0).try_as_integer()?.try_into()?, 154 }) 155 } 156 to_cbor_value(self) -> Result<Value>157 fn to_cbor_value(self) -> Result<Value> { 158 let mut v = vec![ 159 Value::from(self.key_data_length), 160 self.protected.cbor_bstr()?, 161 ]; 162 if let Some(other) = self.other { 163 v.push(Value::Bytes(other)); 164 } 165 Ok(Value::Array(v)) 166 } 167 } 168 169 /// Builder for [`SuppPubInfo`] objects. 170 #[derive(Debug, Default)] 171 pub struct SuppPubInfoBuilder(SuppPubInfo); 172 173 impl SuppPubInfoBuilder { 174 builder! {SuppPubInfo} 175 builder_set! {key_data_length: u64} 176 builder_set_protected! {protected} 177 builder_set_optional! {other: Vec<u8>} 178 } 179 180 /// Structure representing a a key derivation context. 181 /// ```cdl 182 /// COSE_KDF_Context = [ 183 /// AlgorithmID : int / tstr, 184 /// PartyUInfo : [ PartyInfo ], 185 /// PartyVInfo : [ PartyInfo ], 186 /// SuppPubInfo : [ 187 /// keyDataLength : uint, 188 /// protected : empty_or_serialized_map, 189 /// ? other : bstr 190 /// ], 191 /// ? SuppPrivInfo : bstr 192 /// ] 193 /// ``` 194 #[derive(Clone, Debug, Default, PartialEq)] 195 pub struct CoseKdfContext { 196 algorithm_id: Algorithm, 197 party_u_info: PartyInfo, 198 party_v_info: PartyInfo, 199 supp_pub_info: SuppPubInfo, 200 supp_priv_info: Vec<Vec<u8>>, 201 } 202 203 impl crate::CborSerializable for CoseKdfContext {} 204 205 impl AsCborValue for CoseKdfContext { from_cbor_value(value: Value) -> Result<Self>206 fn from_cbor_value(value: Value) -> Result<Self> { 207 let mut a = value.try_as_array()?; 208 if a.len() < 4 { 209 return Err(CoseError::UnexpectedItem( 210 "array", 211 "array with at least 4 items", 212 )); 213 } 214 215 // Remove array elements in reverse order to avoid shifts. 216 let mut supp_priv_info = Vec::with_capacity(a.len() - 4); 217 for i in (4..a.len()).rev() { 218 supp_priv_info.push(a.remove(i).try_as_bytes()?); 219 } 220 supp_priv_info.reverse(); 221 222 Ok(Self { 223 supp_priv_info, 224 supp_pub_info: SuppPubInfo::from_cbor_value(a.remove(3))?, 225 party_v_info: PartyInfo::from_cbor_value(a.remove(2))?, 226 party_u_info: PartyInfo::from_cbor_value(a.remove(1))?, 227 algorithm_id: Algorithm::from_cbor_value(a.remove(0))?, 228 }) 229 } 230 to_cbor_value(self) -> Result<Value>231 fn to_cbor_value(self) -> Result<Value> { 232 let mut v = vec![ 233 self.algorithm_id.to_cbor_value()?, 234 self.party_u_info.to_cbor_value()?, 235 self.party_v_info.to_cbor_value()?, 236 self.supp_pub_info.to_cbor_value()?, 237 ]; 238 for supp_priv_info in self.supp_priv_info { 239 v.push(Value::Bytes(supp_priv_info)); 240 } 241 Ok(Value::Array(v)) 242 } 243 } 244 245 /// Builder for [`CoseKdfContext`] objects. 246 #[derive(Debug, Default)] 247 pub struct CoseKdfContextBuilder(CoseKdfContext); 248 249 impl CoseKdfContextBuilder { 250 builder! {CoseKdfContext} 251 builder_set! {party_u_info: PartyInfo} 252 builder_set! {party_v_info: PartyInfo} 253 builder_set! {supp_pub_info: SuppPubInfo} 254 255 /// Set the algorithm. 256 #[must_use] algorithm(mut self, alg: iana::Algorithm) -> Self257 pub fn algorithm(mut self, alg: iana::Algorithm) -> Self { 258 self.0.algorithm_id = Algorithm::Assigned(alg); 259 self 260 } 261 262 /// Add supplemental private info. 263 #[must_use] add_supp_priv_info(mut self, supp_priv_info: Vec<u8>) -> Self264 pub fn add_supp_priv_info(mut self, supp_priv_info: Vec<u8>) -> Self { 265 self.0.supp_priv_info.push(supp_priv_info); 266 self 267 } 268 } 269