• 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_Sign* functionality.
18 
19 use crate::{
20     cbor,
21     cbor::value::Value,
22     common::AsCborValue,
23     iana,
24     util::{cbor_type_error, to_cbor_array, ValueTryAs},
25     CoseError, Header, ProtectedHeader, Result,
26 };
27 use alloc::{borrow::ToOwned, vec, vec::Vec};
28 
29 #[cfg(test)]
30 mod tests;
31 
32 /// Structure representing a cryptographic signature.
33 ///
34 /// ```cddl
35 ///  COSE_Signature =  [
36 ///       Headers,
37 ///       signature : bstr
38 ///  ]
39 ///  ```
40 #[derive(Clone, Debug, Default, PartialEq)]
41 pub struct CoseSignature {
42     pub protected: ProtectedHeader,
43     pub unprotected: Header,
44     pub signature: Vec<u8>,
45 }
46 
47 impl crate::CborSerializable for CoseSignature {}
48 
49 impl AsCborValue for CoseSignature {
from_cbor_value(value: Value) -> Result<Self>50     fn from_cbor_value(value: Value) -> Result<Self> {
51         let mut a = value.try_as_array()?;
52         if a.len() != 3 {
53             return Err(CoseError::UnexpectedItem("array", "array with 3 items"));
54         }
55 
56         // Remove array elements in reverse order to avoid shifts.
57         Ok(Self {
58             signature: a.remove(2).try_as_bytes()?,
59             unprotected: Header::from_cbor_value(a.remove(1))?,
60             protected: ProtectedHeader::from_cbor_bstr(a.remove(0))?,
61         })
62     }
63 
to_cbor_value(self) -> Result<Value>64     fn to_cbor_value(self) -> Result<Value> {
65         Ok(Value::Array(vec![
66             self.protected.cbor_bstr()?,
67             self.unprotected.to_cbor_value()?,
68             Value::Bytes(self.signature),
69         ]))
70     }
71 }
72 
73 /// Builder for [`CoseSignature`] objects.
74 #[derive(Debug, Default)]
75 pub struct CoseSignatureBuilder(CoseSignature);
76 
77 impl CoseSignatureBuilder {
78     builder! {CoseSignature}
79     builder_set_protected! {protected}
80     builder_set! {unprotected: Header}
81     builder_set! {signature: Vec<u8>}
82 }
83 
84 /// Signed payload with signatures.
85 ///
86 /// ```cdl
87 ///   COSE_Sign = [
88 ///       Headers,
89 ///       payload : bstr / nil,
90 ///       signatures : [+ COSE_Signature]
91 ///   ]
92 /// ```
93 #[derive(Clone, Debug, Default, PartialEq)]
94 pub struct CoseSign {
95     pub protected: ProtectedHeader,
96     pub unprotected: Header,
97     pub payload: Option<Vec<u8>>,
98     pub signatures: Vec<CoseSignature>,
99 }
100 
101 impl crate::CborSerializable for CoseSign {}
102 impl crate::TaggedCborSerializable for CoseSign {
103     const TAG: u64 = iana::CborTag::CoseSign as u64;
104 }
105 
106 impl AsCborValue for CoseSign {
from_cbor_value(value: Value) -> Result<Self>107     fn from_cbor_value(value: Value) -> Result<Self> {
108         let mut a = value.try_as_array()?;
109         if a.len() != 4 {
110             return Err(CoseError::UnexpectedItem("array", "array with 4 items"));
111         }
112 
113         // Remove array elements in reverse order to avoid shifts.
114         let signatures = a.remove(3).try_as_array_then_convert(|v| {
115             CoseSignature::from_cbor_value(v)
116                 .map_err(|_e| CoseError::UnexpectedItem("non-signature", "map for COSE_Signature"))
117         })?;
118 
119         Ok(Self {
120             signatures,
121             payload: match a.remove(2) {
122                 Value::Bytes(b) => Some(b),
123                 Value::Null => None,
124                 v => return cbor_type_error(&v, "bstr or nil"),
125             },
126             unprotected: Header::from_cbor_value(a.remove(1))?,
127             protected: ProtectedHeader::from_cbor_bstr(a.remove(0))?,
128         })
129     }
130 
to_cbor_value(self) -> Result<Value>131     fn to_cbor_value(self) -> Result<Value> {
132         Ok(Value::Array(vec![
133             self.protected.cbor_bstr()?,
134             self.unprotected.to_cbor_value()?,
135             match self.payload {
136                 Some(b) => Value::Bytes(b),
137                 None => Value::Null,
138             },
139             to_cbor_array(self.signatures)?,
140         ]))
141     }
142 }
143 
144 impl CoseSign {
145     /// Verify the indidated signature value, using `verifier` on the signature value and serialized
146     /// data (in that order).
147     ///
148     /// # Panics
149     ///
150     /// This method will panic if `which` is >= `self.signatures.len()`.
verify_signature<F, E>(&self, which: usize, aad: &[u8], verifier: F) -> Result<(), E> where F: FnOnce(&[u8], &[u8]) -> Result<(), E>,151     pub fn verify_signature<F, E>(&self, which: usize, aad: &[u8], verifier: F) -> Result<(), E>
152     where
153         F: FnOnce(&[u8], &[u8]) -> Result<(), E>,
154     {
155         let sig = &self.signatures[which];
156         let tbs_data = self.tbs_data(aad, sig);
157         verifier(&sig.signature, &tbs_data)
158     }
159 
160     /// Construct the to-be-signed data for this object.
tbs_data(&self, aad: &[u8], sig: &CoseSignature) -> Vec<u8>161     fn tbs_data(&self, aad: &[u8], sig: &CoseSignature) -> Vec<u8> {
162         sig_structure_data(
163             SignatureContext::CoseSignature,
164             self.protected.clone(),
165             Some(sig.protected.clone()),
166             aad,
167             self.payload.as_ref().unwrap_or(&vec![]),
168         )
169     }
170 }
171 
172 /// Builder for [`CoseSign`] objects.
173 #[derive(Debug, Default)]
174 pub struct CoseSignBuilder(CoseSign);
175 
176 impl CoseSignBuilder {
177     builder! {CoseSign}
178     builder_set_protected! {protected}
179     builder_set! {unprotected: Header}
180     builder_set_optional! {payload: Vec<u8>}
181 
182     /// Add a signature value.
183     #[must_use]
add_signature(mut self, sig: CoseSignature) -> Self184     pub fn add_signature(mut self, sig: CoseSignature) -> Self {
185         self.0.signatures.push(sig);
186         self
187     }
188 
189     /// Calculate the signature value, using `signer` to generate the signature bytes that will be
190     /// used to complete `sig`.  Any protected header values should be set before using this
191     /// method.
192     #[must_use]
add_created_signature<F>(self, mut sig: CoseSignature, aad: &[u8], signer: F) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,193     pub fn add_created_signature<F>(self, mut sig: CoseSignature, aad: &[u8], signer: F) -> Self
194     where
195         F: FnOnce(&[u8]) -> Vec<u8>,
196     {
197         let tbs_data = self.0.tbs_data(aad, &sig);
198         sig.signature = signer(&tbs_data);
199         self.add_signature(sig)
200     }
201 
202     /// Calculate the signature value, using `signer` to generate the signature bytes that will be
203     /// used to complete `sig`.  Any protected header values should be set before using this
204     /// method.
try_add_created_signature<F, E>( self, mut sig: CoseSignature, aad: &[u8], signer: F, ) -> Result<Self, E> where F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,205     pub fn try_add_created_signature<F, E>(
206         self,
207         mut sig: CoseSignature,
208         aad: &[u8],
209         signer: F,
210     ) -> Result<Self, E>
211     where
212         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
213     {
214         let tbs_data = self.0.tbs_data(aad, &sig);
215         sig.signature = signer(&tbs_data)?;
216         Ok(self.add_signature(sig))
217     }
218 }
219 
220 /// Signed payload with a single signature.
221 ///
222 /// ```cddl
223 ///   COSE_Sign1 = [
224 ///       Headers,
225 ///       payload : bstr / nil,
226 ///       signature : bstr
227 ///   ]
228 /// ```
229 #[derive(Clone, Debug, Default, PartialEq)]
230 pub struct CoseSign1 {
231     pub protected: ProtectedHeader,
232     pub unprotected: Header,
233     pub payload: Option<Vec<u8>>,
234     pub signature: Vec<u8>,
235 }
236 
237 impl crate::CborSerializable for CoseSign1 {}
238 impl crate::TaggedCborSerializable for CoseSign1 {
239     const TAG: u64 = iana::CborTag::CoseSign1 as u64;
240 }
241 
242 impl AsCborValue for CoseSign1 {
from_cbor_value(value: Value) -> Result<Self>243     fn from_cbor_value(value: Value) -> Result<Self> {
244         let mut a = value.try_as_array()?;
245         if a.len() != 4 {
246             return Err(CoseError::UnexpectedItem("array", "array with 4 items"));
247         }
248 
249         // Remove array elements in reverse order to avoid shifts.
250         Ok(Self {
251             signature: a.remove(3).try_as_bytes()?,
252             payload: match a.remove(2) {
253                 Value::Bytes(b) => Some(b),
254                 Value::Null => None,
255                 v => return cbor_type_error(&v, "bstr or nil"),
256             },
257             unprotected: Header::from_cbor_value(a.remove(1))?,
258             protected: ProtectedHeader::from_cbor_bstr(a.remove(0))?,
259         })
260     }
261 
to_cbor_value(self) -> Result<Value>262     fn to_cbor_value(self) -> Result<Value> {
263         Ok(Value::Array(vec![
264             self.protected.cbor_bstr()?,
265             self.unprotected.to_cbor_value()?,
266             match self.payload {
267                 Some(b) => Value::Bytes(b),
268                 None => Value::Null,
269             },
270             Value::Bytes(self.signature),
271         ]))
272     }
273 }
274 
275 impl CoseSign1 {
276     /// Verify the signature value, using `verifier` on the signature value and serialized data (in
277     /// that order).
verify_signature<F, E>(&self, aad: &[u8], verifier: F) -> Result<(), E> where F: FnOnce(&[u8], &[u8]) -> Result<(), E>,278     pub fn verify_signature<F, E>(&self, aad: &[u8], verifier: F) -> Result<(), E>
279     where
280         F: FnOnce(&[u8], &[u8]) -> Result<(), E>,
281     {
282         let tbs_data = self.tbs_data(aad);
283         verifier(&self.signature, &tbs_data)
284     }
285 
286     /// Construct the to-be-signed data for this object.
tbs_data(&self, aad: &[u8]) -> Vec<u8>287     fn tbs_data(&self, aad: &[u8]) -> Vec<u8> {
288         sig_structure_data(
289             SignatureContext::CoseSign1,
290             self.protected.clone(),
291             None,
292             aad,
293             self.payload.as_ref().unwrap_or(&vec![]),
294         )
295     }
296 }
297 
298 /// Builder for [`CoseSign1`] objects.
299 #[derive(Debug, Default)]
300 pub struct CoseSign1Builder(CoseSign1);
301 
302 impl CoseSign1Builder {
303     builder! {CoseSign1}
304     builder_set_protected! {protected}
305     builder_set! {unprotected: Header}
306     builder_set! {signature: Vec<u8>}
307     builder_set_optional! {payload: Vec<u8>}
308 
309     /// Calculate the signature value, using `signer` to generate the signature bytes.  Any
310     /// protected header values should be set before using this method.
311     #[must_use]
create_signature<F>(self, aad: &[u8], signer: F) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,312     pub fn create_signature<F>(self, aad: &[u8], signer: F) -> Self
313     where
314         F: FnOnce(&[u8]) -> Vec<u8>,
315     {
316         let sig_data = signer(&self.0.tbs_data(aad));
317         self.signature(sig_data)
318     }
319 
320     /// Calculate the signature value, using `signer` to generate the signature bytes.  Any
321     /// protected header values should be set before using this method.
try_create_signature<F, E>(self, aad: &[u8], signer: F) -> Result<Self, E> where F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,322     pub fn try_create_signature<F, E>(self, aad: &[u8], signer: F) -> Result<Self, E>
323     where
324         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
325     {
326         let sig_data = signer(&self.0.tbs_data(aad))?;
327         Ok(self.signature(sig_data))
328     }
329 }
330 
331 /// Possible signature contexts.
332 #[derive(Clone, Copy)]
333 pub enum SignatureContext {
334     CoseSignature,
335     CoseSign1,
336     CounterSignature,
337 }
338 
339 impl SignatureContext {
340     /// Return the context string as per RFC 8152 section 4.4.
text(&self) -> &'static str341     fn text(&self) -> &'static str {
342         match self {
343             SignatureContext::CoseSignature => "Signature",
344             SignatureContext::CoseSign1 => "Signature1",
345             SignatureContext::CounterSignature => "CounterSignature",
346         }
347     }
348 }
349 
350 /// Create a binary blob that will be signed.
351 ///
352 /// ```cddl
353 ///   Sig_structure = [
354 ///       context : "Signature" / "Signature1" / "CounterSignature",
355 ///       body_protected : empty_or_serialized_map,
356 ///       ? sign_protected : empty_or_serialized_map,
357 ///       external_aad : bstr,
358 ///       payload : bstr
359 ///   ]
360 /// ```
sig_structure_data( context: SignatureContext, body: ProtectedHeader, sign: Option<ProtectedHeader>, aad: &[u8], payload: &[u8], ) -> Vec<u8>361 pub fn sig_structure_data(
362     context: SignatureContext,
363     body: ProtectedHeader,
364     sign: Option<ProtectedHeader>,
365     aad: &[u8],
366     payload: &[u8],
367 ) -> Vec<u8> {
368     let mut arr = vec![
369         Value::Text(context.text().to_owned()),
370         body.cbor_bstr().expect("failed to serialize header"), // safe: always serializable
371     ];
372     if let Some(sign) = sign {
373         arr.push(sign.cbor_bstr().expect("failed to serialize header")); // safe: always
374                                                                          // serializable
375     }
376     arr.push(Value::Bytes(aad.to_vec()));
377     arr.push(Value::Bytes(payload.to_vec()));
378     let mut data = Vec::new();
379     cbor::ser::into_writer(&Value::Array(arr), &mut data).unwrap(); // safe: always serializable
380     data
381 }
382