• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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