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_Key functionality. 18 19 use crate::{ 20 cbor::value::Value, 21 common::AsCborValue, 22 iana, 23 iana::EnumI64, 24 util::{to_cbor_array, ValueTryAs}, 25 Algorithm, CoseError, Label, Result, 26 }; 27 use alloc::{collections::BTreeSet, vec, vec::Vec}; 28 29 #[cfg(test)] 30 mod tests; 31 32 /// Key type. 33 pub type KeyType = crate::RegisteredLabel<iana::KeyType>; 34 35 impl Default for KeyType { default() -> Self36 fn default() -> Self { 37 KeyType::Assigned(iana::KeyType::Reserved) 38 } 39 } 40 41 /// Key operation. 42 pub type KeyOperation = crate::RegisteredLabel<iana::KeyOperation>; 43 44 /// A collection of [`CoseKey`] objects. 45 #[derive(Clone, Debug, Default, PartialEq)] 46 pub struct CoseKeySet(pub Vec<CoseKey>); 47 48 impl crate::CborSerializable for CoseKeySet {} 49 50 impl AsCborValue for CoseKeySet { from_cbor_value(value: Value) -> Result<Self>51 fn from_cbor_value(value: Value) -> Result<Self> { 52 Ok(Self( 53 value.try_as_array_then_convert(CoseKey::from_cbor_value)?, 54 )) 55 } 56 to_cbor_value(self) -> Result<Value>57 fn to_cbor_value(self) -> Result<Value> { 58 to_cbor_array(self.0) 59 } 60 } 61 62 /// Structure representing a cryptographic key. 63 /// 64 /// ```cddl 65 /// COSE_Key = { 66 /// 1 => tstr / int, ; kty 67 /// ? 2 => bstr, ; kid 68 /// ? 3 => tstr / int, ; alg 69 /// ? 4 => [+ (tstr / int) ], ; key_ops 70 /// ? 5 => bstr, ; Base IV 71 /// * label => values 72 /// } 73 /// ``` 74 #[derive(Clone, Debug, Default, PartialEq)] 75 pub struct CoseKey { 76 /// Key type identification. 77 pub kty: KeyType, 78 /// Key identification. 79 pub key_id: Vec<u8>, 80 /// Key use restriction to this algorithm. 81 pub alg: Option<Algorithm>, 82 /// Restrict set of possible operations. 83 pub key_ops: BTreeSet<KeyOperation>, 84 /// Base IV to be xor-ed with partial IVs. 85 pub base_iv: Vec<u8>, 86 /// Any additional parameter (label,value) pairs. If duplicate labels are present, 87 /// CBOR-encoding will fail. 88 pub params: Vec<(Label, Value)>, 89 } 90 91 impl crate::CborSerializable for CoseKey {} 92 93 const KTY: Label = Label::Int(iana::KeyParameter::Kty as i64); 94 const KID: Label = Label::Int(iana::KeyParameter::Kid as i64); 95 const ALG: Label = Label::Int(iana::KeyParameter::Alg as i64); 96 const KEY_OPS: Label = Label::Int(iana::KeyParameter::KeyOps as i64); 97 const BASE_IV: Label = Label::Int(iana::KeyParameter::BaseIv as i64); 98 99 impl AsCborValue for CoseKey { from_cbor_value(value: Value) -> Result<Self>100 fn from_cbor_value(value: Value) -> Result<Self> { 101 let m = value.try_as_map()?; 102 let mut key = Self::default(); 103 let mut seen = BTreeSet::new(); 104 for (l, value) in m.into_iter() { 105 // The `ciborium` CBOR library does not police duplicate map keys. 106 // RFC 8152 section 14 requires that COSE does police duplicates, so do it here. 107 let label = Label::from_cbor_value(l)?; 108 if seen.contains(&label) { 109 return Err(CoseError::DuplicateMapKey); 110 } 111 seen.insert(label.clone()); 112 match label { 113 KTY => key.kty = KeyType::from_cbor_value(value)?, 114 115 KID => { 116 key.key_id = value.try_as_nonempty_bytes()?; 117 } 118 119 ALG => key.alg = Some(Algorithm::from_cbor_value(value)?), 120 121 KEY_OPS => { 122 let key_ops = value.try_as_array()?; 123 for key_op in key_ops.into_iter() { 124 if !key.key_ops.insert(KeyOperation::from_cbor_value(key_op)?) { 125 return Err(CoseError::UnexpectedItem( 126 "repeated array entry", 127 "unique array label", 128 )); 129 } 130 } 131 if key.key_ops.is_empty() { 132 return Err(CoseError::UnexpectedItem("empty array", "non-empty array")); 133 } 134 } 135 136 BASE_IV => { 137 key.base_iv = value.try_as_nonempty_bytes()?; 138 } 139 140 label => key.params.push((label, value)), 141 } 142 } 143 // Check that key type has been set. 144 if key.kty == KeyType::Assigned(iana::KeyType::Reserved) { 145 return Err(CoseError::UnexpectedItem( 146 "no kty label", 147 "mandatory kty label", 148 )); 149 } 150 151 Ok(key) 152 } 153 to_cbor_value(self) -> Result<Value>154 fn to_cbor_value(self) -> Result<Value> { 155 let mut map: Vec<(Value, Value)> = vec![(KTY.to_cbor_value()?, self.kty.to_cbor_value()?)]; 156 if !self.key_id.is_empty() { 157 map.push((KID.to_cbor_value()?, Value::Bytes(self.key_id))); 158 } 159 if let Some(alg) = self.alg { 160 map.push((ALG.to_cbor_value()?, alg.to_cbor_value()?)); 161 } 162 if !self.key_ops.is_empty() { 163 map.push((KEY_OPS.to_cbor_value()?, to_cbor_array(self.key_ops)?)); 164 } 165 if !self.base_iv.is_empty() { 166 map.push((BASE_IV.to_cbor_value()?, Value::Bytes(self.base_iv))); 167 } 168 let mut seen = BTreeSet::new(); 169 for (label, value) in self.params { 170 if seen.contains(&label) { 171 return Err(CoseError::DuplicateMapKey); 172 } 173 seen.insert(label.clone()); 174 map.push((label.to_cbor_value()?, value)); 175 } 176 Ok(Value::Map(map)) 177 } 178 } 179 180 /// Builder for [`CoseKey`] objects. 181 #[derive(Debug, Default)] 182 pub struct CoseKeyBuilder(CoseKey); 183 184 impl CoseKeyBuilder { 185 builder! {CoseKey} 186 builder_set! {key_id: Vec<u8>} 187 builder_set! {base_iv: Vec<u8>} 188 189 /// Constructor for an elliptic curve public key specified by `x` and `y` coordinates. new_ec2_pub_key(curve: iana::EllipticCurve, x: Vec<u8>, y: Vec<u8>) -> Self190 pub fn new_ec2_pub_key(curve: iana::EllipticCurve, x: Vec<u8>, y: Vec<u8>) -> Self { 191 Self(CoseKey { 192 kty: KeyType::Assigned(iana::KeyType::EC2), 193 params: vec![ 194 ( 195 Label::Int(iana::Ec2KeyParameter::Crv as i64), 196 Value::from(curve as u64), 197 ), 198 (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(x)), 199 (Label::Int(iana::Ec2KeyParameter::Y as i64), Value::Bytes(y)), 200 ], 201 ..Default::default() 202 }) 203 } 204 205 /// Constructor for an elliptic curve public key specified by `x` coordinate plus sign of `y` 206 /// coordinate. new_ec2_pub_key_y_sign(curve: iana::EllipticCurve, x: Vec<u8>, y_sign: bool) -> Self207 pub fn new_ec2_pub_key_y_sign(curve: iana::EllipticCurve, x: Vec<u8>, y_sign: bool) -> Self { 208 Self(CoseKey { 209 kty: KeyType::Assigned(iana::KeyType::EC2), 210 params: vec![ 211 ( 212 Label::Int(iana::Ec2KeyParameter::Crv as i64), 213 Value::from(curve as u64), 214 ), 215 (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(x)), 216 ( 217 Label::Int(iana::Ec2KeyParameter::Y as i64), 218 Value::Bool(y_sign), 219 ), 220 ], 221 ..Default::default() 222 }) 223 } 224 225 /// Constructor for an elliptic curve private key specified by `d`, together with public `x` and 226 /// `y` coordinates. new_ec2_priv_key( curve: iana::EllipticCurve, x: Vec<u8>, y: Vec<u8>, d: Vec<u8>, ) -> Self227 pub fn new_ec2_priv_key( 228 curve: iana::EllipticCurve, 229 x: Vec<u8>, 230 y: Vec<u8>, 231 d: Vec<u8>, 232 ) -> Self { 233 let mut builder = Self::new_ec2_pub_key(curve, x, y); 234 builder 235 .0 236 .params 237 .push((Label::Int(iana::Ec2KeyParameter::D as i64), Value::Bytes(d))); 238 builder 239 } 240 241 /// Constructor for a symmetric key specified by `k`. new_symmetric_key(k: Vec<u8>) -> Self242 pub fn new_symmetric_key(k: Vec<u8>) -> Self { 243 Self(CoseKey { 244 kty: KeyType::Assigned(iana::KeyType::Symmetric), 245 params: vec![( 246 Label::Int(iana::SymmetricKeyParameter::K as i64), 247 Value::Bytes(k), 248 )], 249 ..Default::default() 250 }) 251 } 252 253 /// Set the algorithm. 254 #[must_use] algorithm(mut self, alg: iana::Algorithm) -> Self255 pub fn algorithm(mut self, alg: iana::Algorithm) -> Self { 256 self.0.alg = Some(Algorithm::Assigned(alg)); 257 self 258 } 259 260 /// Add a key operation. 261 #[must_use] add_key_op(mut self, op: iana::KeyOperation) -> Self262 pub fn add_key_op(mut self, op: iana::KeyOperation) -> Self { 263 self.0.key_ops.insert(KeyOperation::Assigned(op)); 264 self 265 } 266 267 /// Set a parameter value. 268 /// 269 /// # Panics 270 /// 271 /// This function will panic if it used to set a parameter label from the [`iana::KeyParameter`] 272 /// range. 273 #[must_use] param(mut self, label: i64, value: Value) -> Self274 pub fn param(mut self, label: i64, value: Value) -> Self { 275 if iana::KeyParameter::from_i64(label).is_some() { 276 panic!("param() method used to set KeyParameter"); // safe: invalid input 277 } 278 self.0.params.push((Label::Int(label), value)); 279 self 280 } 281 } 282