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, CborOrdering},
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 CoseKey {
92     /// Re-order the contents of the key so that the contents will be emitted in one of the standard
93     /// CBOR sorted orders.
canonicalize(&mut self, ordering: CborOrdering)94     pub fn canonicalize(&mut self, ordering: CborOrdering) {
95         // The keys that are represented as named fields CBOR-encode as single bytes 0x01 - 0x05,
96         // which sort before any other CBOR values (other than 0x00) in either sorting scheme:
97         // - In length-first sorting, a single byte sorts before anything multi-byte and 1-5 sorts
98         //   before any other value.
99         // - In encoded-lexicographic sorting, there are no valid CBOR-encoded single values that
100         //   start with a byte in the range 0x01 - 0x05 other than the values 1-5.
101         // So we only need to sort the `params`.
102         match ordering {
103             CborOrdering::Lexicographic => self.params.sort_by(|l, r| l.0.cmp(&r.0)),
104             CborOrdering::LengthFirstLexicographic => {
105                 self.params.sort_by(|l, r| l.0.cmp_canonical(&r.0))
106             }
107         }
108     }
109 }
110 
111 impl crate::CborSerializable for CoseKey {}
112 
113 const KTY: Label = Label::Int(iana::KeyParameter::Kty as i64);
114 const KID: Label = Label::Int(iana::KeyParameter::Kid as i64);
115 const ALG: Label = Label::Int(iana::KeyParameter::Alg as i64);
116 const KEY_OPS: Label = Label::Int(iana::KeyParameter::KeyOps as i64);
117 const BASE_IV: Label = Label::Int(iana::KeyParameter::BaseIv as i64);
118 
119 impl AsCborValue for CoseKey {
from_cbor_value(value: Value) -> Result<Self>120     fn from_cbor_value(value: Value) -> Result<Self> {
121         let m = value.try_as_map()?;
122         let mut key = Self::default();
123         let mut seen = BTreeSet::new();
124         for (l, value) in m.into_iter() {
125             // The `ciborium` CBOR library does not police duplicate map keys.
126             // RFC 8152 section 14 requires that COSE does police duplicates, so do it here.
127             let label = Label::from_cbor_value(l)?;
128             if seen.contains(&label) {
129                 return Err(CoseError::DuplicateMapKey);
130             }
131             seen.insert(label.clone());
132             match label {
133                 KTY => key.kty = KeyType::from_cbor_value(value)?,
134 
135                 KID => {
136                     key.key_id = value.try_as_nonempty_bytes()?;
137                 }
138 
139                 ALG => key.alg = Some(Algorithm::from_cbor_value(value)?),
140 
141                 KEY_OPS => {
142                     let key_ops = value.try_as_array()?;
143                     for key_op in key_ops.into_iter() {
144                         if !key.key_ops.insert(KeyOperation::from_cbor_value(key_op)?) {
145                             return Err(CoseError::UnexpectedItem(
146                                 "repeated array entry",
147                                 "unique array label",
148                             ));
149                         }
150                     }
151                     if key.key_ops.is_empty() {
152                         return Err(CoseError::UnexpectedItem("empty array", "non-empty array"));
153                     }
154                 }
155 
156                 BASE_IV => {
157                     key.base_iv = value.try_as_nonempty_bytes()?;
158                 }
159 
160                 label => key.params.push((label, value)),
161             }
162         }
163         // Check that key type has been set.
164         if key.kty == KeyType::Assigned(iana::KeyType::Reserved) {
165             return Err(CoseError::UnexpectedItem(
166                 "no kty label",
167                 "mandatory kty label",
168             ));
169         }
170 
171         Ok(key)
172     }
173 
to_cbor_value(self) -> Result<Value>174     fn to_cbor_value(self) -> Result<Value> {
175         let mut map: Vec<(Value, Value)> = vec![(KTY.to_cbor_value()?, self.kty.to_cbor_value()?)];
176         if !self.key_id.is_empty() {
177             map.push((KID.to_cbor_value()?, Value::Bytes(self.key_id)));
178         }
179         if let Some(alg) = self.alg {
180             map.push((ALG.to_cbor_value()?, alg.to_cbor_value()?));
181         }
182         if !self.key_ops.is_empty() {
183             map.push((KEY_OPS.to_cbor_value()?, to_cbor_array(self.key_ops)?));
184         }
185         if !self.base_iv.is_empty() {
186             map.push((BASE_IV.to_cbor_value()?, Value::Bytes(self.base_iv)));
187         }
188         let mut seen = BTreeSet::new();
189         for (label, value) in self.params {
190             if seen.contains(&label) {
191                 return Err(CoseError::DuplicateMapKey);
192             }
193             seen.insert(label.clone());
194             map.push((label.to_cbor_value()?, value));
195         }
196         Ok(Value::Map(map))
197     }
198 }
199 
200 /// Builder for [`CoseKey`] objects.
201 #[derive(Debug, Default)]
202 pub struct CoseKeyBuilder(CoseKey);
203 
204 impl CoseKeyBuilder {
205     builder! {CoseKey}
206     builder_set! {kty: KeyType}
207     builder_set! {key_id: Vec<u8>}
208     builder_set! {base_iv: Vec<u8>}
209 
210     /// 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>) -> Self211     pub fn new_ec2_pub_key(curve: iana::EllipticCurve, x: Vec<u8>, y: Vec<u8>) -> Self {
212         Self(CoseKey {
213             kty: KeyType::Assigned(iana::KeyType::EC2),
214             params: vec![
215                 (
216                     Label::Int(iana::Ec2KeyParameter::Crv as i64),
217                     Value::from(curve as u64),
218                 ),
219                 (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(x)),
220                 (Label::Int(iana::Ec2KeyParameter::Y as i64), Value::Bytes(y)),
221             ],
222             ..Default::default()
223         })
224     }
225 
226     /// Constructor for an elliptic curve public key specified by `x` coordinate plus sign of `y`
227     /// coordinate.
new_ec2_pub_key_y_sign(curve: iana::EllipticCurve, x: Vec<u8>, y_sign: bool) -> Self228     pub fn new_ec2_pub_key_y_sign(curve: iana::EllipticCurve, x: Vec<u8>, y_sign: bool) -> Self {
229         Self(CoseKey {
230             kty: KeyType::Assigned(iana::KeyType::EC2),
231             params: vec![
232                 (
233                     Label::Int(iana::Ec2KeyParameter::Crv as i64),
234                     Value::from(curve as u64),
235                 ),
236                 (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(x)),
237                 (
238                     Label::Int(iana::Ec2KeyParameter::Y as i64),
239                     Value::Bool(y_sign),
240                 ),
241             ],
242             ..Default::default()
243         })
244     }
245 
246     /// Constructor for an elliptic curve private key specified by `d`, together with public `x` and
247     /// `y` coordinates.
new_ec2_priv_key( curve: iana::EllipticCurve, x: Vec<u8>, y: Vec<u8>, d: Vec<u8>, ) -> Self248     pub fn new_ec2_priv_key(
249         curve: iana::EllipticCurve,
250         x: Vec<u8>,
251         y: Vec<u8>,
252         d: Vec<u8>,
253     ) -> Self {
254         let mut builder = Self::new_ec2_pub_key(curve, x, y);
255         builder
256             .0
257             .params
258             .push((Label::Int(iana::Ec2KeyParameter::D as i64), Value::Bytes(d)));
259         builder
260     }
261 
262     /// Constructor for a symmetric key specified by `k`.
new_symmetric_key(k: Vec<u8>) -> Self263     pub fn new_symmetric_key(k: Vec<u8>) -> Self {
264         Self(CoseKey {
265             kty: KeyType::Assigned(iana::KeyType::Symmetric),
266             params: vec![(
267                 Label::Int(iana::SymmetricKeyParameter::K as i64),
268                 Value::Bytes(k),
269             )],
270             ..Default::default()
271         })
272     }
273 
274     /// Constructor for a octet keypair key.
new_okp_key() -> Self275     pub fn new_okp_key() -> Self {
276         Self(CoseKey {
277             kty: KeyType::Assigned(iana::KeyType::OKP),
278             ..Default::default()
279         })
280     }
281 
282     /// Set the key type.
283     #[must_use]
key_type(mut self, key_type: iana::KeyType) -> Self284     pub fn key_type(mut self, key_type: iana::KeyType) -> Self {
285         self.0.kty = KeyType::Assigned(key_type);
286         self
287     }
288 
289     /// Set the algorithm.
290     #[must_use]
algorithm(mut self, alg: iana::Algorithm) -> Self291     pub fn algorithm(mut self, alg: iana::Algorithm) -> Self {
292         self.0.alg = Some(Algorithm::Assigned(alg));
293         self
294     }
295 
296     /// Add a key operation.
297     #[must_use]
add_key_op(mut self, op: iana::KeyOperation) -> Self298     pub fn add_key_op(mut self, op: iana::KeyOperation) -> Self {
299         self.0.key_ops.insert(KeyOperation::Assigned(op));
300         self
301     }
302 
303     /// Set a parameter value.
304     ///
305     /// # Panics
306     ///
307     /// This function will panic if it used to set a parameter label from the [`iana::KeyParameter`]
308     /// range.
309     #[must_use]
param(mut self, label: i64, value: Value) -> Self310     pub fn param(mut self, label: i64, value: Value) -> Self {
311         if iana::KeyParameter::from_i64(label).is_some() {
312             panic!("param() method used to set KeyParameter"); // safe: invalid input
313         }
314         self.0.params.push((Label::Int(label), value));
315         self
316     }
317 }
318