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