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 indicated 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     /// Verify the indicated signature value for a detached payload, using `verifier` on the
161     /// signature value and serialized data (in that order).
162     ///
163     /// # Panics
164     ///
165     /// This method will panic if `which` is >= `self.signatures.len()`.
166     ///
167     /// This method will panic if `self.payload.is_some()`.
verify_detached_signature<F, E>( &self, which: usize, payload: &[u8], aad: &[u8], verifier: F, ) -> Result<(), E> where F: FnOnce(&[u8], &[u8]) -> Result<(), E>,168     pub fn verify_detached_signature<F, E>(
169         &self,
170         which: usize,
171         payload: &[u8],
172         aad: &[u8],
173         verifier: F,
174     ) -> Result<(), E>
175     where
176         F: FnOnce(&[u8], &[u8]) -> Result<(), E>,
177     {
178         let sig = &self.signatures[which];
179         let tbs_data = self.tbs_detached_data(payload, aad, sig);
180         verifier(&sig.signature, &tbs_data)
181     }
182 
183     /// Construct the to-be-signed data for this object.
tbs_data(&self, aad: &[u8], sig: &CoseSignature) -> Vec<u8>184     pub fn tbs_data(&self, aad: &[u8], sig: &CoseSignature) -> Vec<u8> {
185         sig_structure_data(
186             SignatureContext::CoseSignature,
187             self.protected.clone(),
188             Some(sig.protected.clone()),
189             aad,
190             self.payload.as_ref().unwrap_or(&vec![]),
191         )
192     }
193 
194     /// Construct the to-be-signed data for this object, using a detached payload.
195     ///
196     /// # Panics
197     ///
198     /// This method will panic if `self.payload.is_some()`.
tbs_detached_data(&self, payload: &[u8], aad: &[u8], sig: &CoseSignature) -> Vec<u8>199     pub fn tbs_detached_data(&self, payload: &[u8], aad: &[u8], sig: &CoseSignature) -> Vec<u8> {
200         assert!(self.payload.is_none());
201         sig_structure_data(
202             SignatureContext::CoseSignature,
203             self.protected.clone(),
204             Some(sig.protected.clone()),
205             aad,
206             payload,
207         )
208     }
209 }
210 
211 /// Builder for [`CoseSign`] objects.
212 #[derive(Debug, Default)]
213 pub struct CoseSignBuilder(CoseSign);
214 
215 impl CoseSignBuilder {
216     builder! {CoseSign}
217     builder_set_protected! {protected}
218     builder_set! {unprotected: Header}
219     builder_set_optional! {payload: Vec<u8>}
220 
221     /// Add a signature value.
222     #[must_use]
add_signature(mut self, sig: CoseSignature) -> Self223     pub fn add_signature(mut self, sig: CoseSignature) -> Self {
224         self.0.signatures.push(sig);
225         self
226     }
227 
228     /// Calculate the signature value, using `signer` to generate the signature bytes that will be
229     /// used to complete `sig`.  Any protected header values should be set before using this
230     /// method.
231     #[must_use]
add_created_signature<F>(self, mut sig: CoseSignature, aad: &[u8], signer: F) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,232     pub fn add_created_signature<F>(self, mut sig: CoseSignature, aad: &[u8], signer: F) -> Self
233     where
234         F: FnOnce(&[u8]) -> Vec<u8>,
235     {
236         let tbs_data = self.0.tbs_data(aad, &sig);
237         sig.signature = signer(&tbs_data);
238         self.add_signature(sig)
239     }
240 
241     /// Calculate the signature value for a detached payload, using `signer` to generate the
242     /// signature bytes that will be used to complete `sig`.  Any protected header values should
243     /// be set before using this method.
244     ///
245     /// # Panics
246     ///
247     /// This method will panic if `self.payload.is_some()`.
248     #[must_use]
add_detached_signature<F>( self, mut sig: CoseSignature, payload: &[u8], aad: &[u8], signer: F, ) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,249     pub fn add_detached_signature<F>(
250         self,
251         mut sig: CoseSignature,
252         payload: &[u8],
253         aad: &[u8],
254         signer: F,
255     ) -> Self
256     where
257         F: FnOnce(&[u8]) -> Vec<u8>,
258     {
259         let tbs_data = self.0.tbs_detached_data(payload, aad, &sig);
260         sig.signature = signer(&tbs_data);
261         self.add_signature(sig)
262     }
263 
264     /// Calculate the signature value, using `signer` to generate the signature bytes that will be
265     /// used to complete `sig`.  Any protected header values should be set before using this
266     /// 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>,267     pub fn try_add_created_signature<F, E>(
268         self,
269         mut sig: CoseSignature,
270         aad: &[u8],
271         signer: F,
272     ) -> Result<Self, E>
273     where
274         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
275     {
276         let tbs_data = self.0.tbs_data(aad, &sig);
277         sig.signature = signer(&tbs_data)?;
278         Ok(self.add_signature(sig))
279     }
280 
281     /// Calculate the signature value for a detached payload, using `signer` to generate the
282     /// signature bytes that will be used to complete `sig`.  Any protected header values should
283     /// be set before using this method.
284     ///
285     /// # Panics
286     ///
287     /// This method will panic if `self.payload.is_some()`.
try_add_detached_signature<F, E>( self, mut sig: CoseSignature, payload: &[u8], aad: &[u8], signer: F, ) -> Result<Self, E> where F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,288     pub fn try_add_detached_signature<F, E>(
289         self,
290         mut sig: CoseSignature,
291         payload: &[u8],
292         aad: &[u8],
293         signer: F,
294     ) -> Result<Self, E>
295     where
296         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
297     {
298         let tbs_data = self.0.tbs_detached_data(payload, aad, &sig);
299         sig.signature = signer(&tbs_data)?;
300         Ok(self.add_signature(sig))
301     }
302 }
303 
304 /// Signed payload with a single signature.
305 ///
306 /// ```cddl
307 ///   COSE_Sign1 = [
308 ///       Headers,
309 ///       payload : bstr / nil,
310 ///       signature : bstr
311 ///   ]
312 /// ```
313 #[derive(Clone, Debug, Default, PartialEq)]
314 pub struct CoseSign1 {
315     pub protected: ProtectedHeader,
316     pub unprotected: Header,
317     pub payload: Option<Vec<u8>>,
318     pub signature: Vec<u8>,
319 }
320 
321 impl crate::CborSerializable for CoseSign1 {}
322 impl crate::TaggedCborSerializable for CoseSign1 {
323     const TAG: u64 = iana::CborTag::CoseSign1 as u64;
324 }
325 
326 impl AsCborValue for CoseSign1 {
from_cbor_value(value: Value) -> Result<Self>327     fn from_cbor_value(value: Value) -> Result<Self> {
328         let mut a = value.try_as_array()?;
329         if a.len() != 4 {
330             return Err(CoseError::UnexpectedItem("array", "array with 4 items"));
331         }
332 
333         // Remove array elements in reverse order to avoid shifts.
334         Ok(Self {
335             signature: a.remove(3).try_as_bytes()?,
336             payload: match a.remove(2) {
337                 Value::Bytes(b) => Some(b),
338                 Value::Null => None,
339                 v => return cbor_type_error(&v, "bstr or nil"),
340             },
341             unprotected: Header::from_cbor_value(a.remove(1))?,
342             protected: ProtectedHeader::from_cbor_bstr(a.remove(0))?,
343         })
344     }
345 
to_cbor_value(self) -> Result<Value>346     fn to_cbor_value(self) -> Result<Value> {
347         Ok(Value::Array(vec![
348             self.protected.cbor_bstr()?,
349             self.unprotected.to_cbor_value()?,
350             match self.payload {
351                 Some(b) => Value::Bytes(b),
352                 None => Value::Null,
353             },
354             Value::Bytes(self.signature),
355         ]))
356     }
357 }
358 
359 impl CoseSign1 {
360     /// Verify the signature value, using `verifier` on the signature value and serialized data (in
361     /// that order).
verify_signature<F, E>(&self, aad: &[u8], verifier: F) -> Result<(), E> where F: FnOnce(&[u8], &[u8]) -> Result<(), E>,362     pub fn verify_signature<F, E>(&self, aad: &[u8], verifier: F) -> Result<(), E>
363     where
364         F: FnOnce(&[u8], &[u8]) -> Result<(), E>,
365     {
366         let tbs_data = self.tbs_data(aad);
367         verifier(&self.signature, &tbs_data)
368     }
369 
370     /// Verify the indicated signature value for a detached payload, using `verifier` on the
371     /// signature value and serialized data (in that order).
372     ///
373     /// # Panics
374     ///
375     /// This method will panic if `self.payload.is_some()`.
verify_detached_signature<F, E>( &self, payload: &[u8], aad: &[u8], verifier: F, ) -> Result<(), E> where F: FnOnce(&[u8], &[u8]) -> Result<(), E>,376     pub fn verify_detached_signature<F, E>(
377         &self,
378         payload: &[u8],
379         aad: &[u8],
380         verifier: F,
381     ) -> Result<(), E>
382     where
383         F: FnOnce(&[u8], &[u8]) -> Result<(), E>,
384     {
385         let tbs_data = self.tbs_detached_data(payload, aad);
386         verifier(&self.signature, &tbs_data)
387     }
388 
389     /// Construct the to-be-signed data for this object.
tbs_data(&self, aad: &[u8]) -> Vec<u8>390     pub fn tbs_data(&self, aad: &[u8]) -> Vec<u8> {
391         sig_structure_data(
392             SignatureContext::CoseSign1,
393             self.protected.clone(),
394             None,
395             aad,
396             self.payload.as_ref().unwrap_or(&vec![]),
397         )
398     }
399 
400     /// Construct the to-be-signed data for this object, using a detached payload.
401     ///
402     /// # Panics
403     ///
404     /// This method will panic if `self.payload.is_some()`.
tbs_detached_data(&self, payload: &[u8], aad: &[u8]) -> Vec<u8>405     pub fn tbs_detached_data(&self, payload: &[u8], aad: &[u8]) -> Vec<u8> {
406         assert!(self.payload.is_none());
407         sig_structure_data(
408             SignatureContext::CoseSign1,
409             self.protected.clone(),
410             None,
411             aad,
412             payload,
413         )
414     }
415 }
416 
417 /// Builder for [`CoseSign1`] objects.
418 #[derive(Debug, Default)]
419 pub struct CoseSign1Builder(CoseSign1);
420 
421 impl CoseSign1Builder {
422     builder! {CoseSign1}
423     builder_set_protected! {protected}
424     builder_set! {unprotected: Header}
425     builder_set! {signature: Vec<u8>}
426     builder_set_optional! {payload: Vec<u8>}
427 
428     /// Calculate the signature value, using `signer` to generate the signature bytes.  Any
429     /// protected header values should be set before using this method.
430     #[must_use]
create_signature<F>(self, aad: &[u8], signer: F) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,431     pub fn create_signature<F>(self, aad: &[u8], signer: F) -> Self
432     where
433         F: FnOnce(&[u8]) -> Vec<u8>,
434     {
435         let sig_data = signer(&self.0.tbs_data(aad));
436         self.signature(sig_data)
437     }
438 
439     /// Calculate the signature value for a detached payload, using `signer` to generate the
440     /// signature bytes.  Any protected header values should be set before using this method.
441     ///
442     /// # Panics
443     ///
444     /// This method will panic if `self.payload.is_some()`.
445     #[must_use]
create_detached_signature<F>(self, payload: &[u8], aad: &[u8], signer: F) -> Self where F: FnOnce(&[u8]) -> Vec<u8>,446     pub fn create_detached_signature<F>(self, payload: &[u8], aad: &[u8], signer: F) -> Self
447     where
448         F: FnOnce(&[u8]) -> Vec<u8>,
449     {
450         let sig_data = signer(&self.0.tbs_detached_data(payload, aad));
451         self.signature(sig_data)
452     }
453 
454     /// Calculate the signature value, using `signer` to generate the signature bytes.  Any
455     /// 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>,456     pub fn try_create_signature<F, E>(self, aad: &[u8], signer: F) -> Result<Self, E>
457     where
458         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
459     {
460         let sig_data = signer(&self.0.tbs_data(aad))?;
461         Ok(self.signature(sig_data))
462     }
463 
464     /// Calculate the signature value for a detached payload, using `signer` to generate the
465     /// signature bytes.  Any protected header values should be set before using this method.
466     ///
467     /// # Panics
468     ///
469     /// This method will panic if `self.payload.is_some()`.
try_create_detached_signature<F, E>( self, payload: &[u8], aad: &[u8], signer: F, ) -> Result<Self, E> where F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,470     pub fn try_create_detached_signature<F, E>(
471         self,
472         payload: &[u8],
473         aad: &[u8],
474         signer: F,
475     ) -> Result<Self, E>
476     where
477         F: FnOnce(&[u8]) -> Result<Vec<u8>, E>,
478     {
479         let sig_data = signer(&self.0.tbs_detached_data(payload, aad))?;
480         Ok(self.signature(sig_data))
481     }
482 }
483 
484 /// Possible signature contexts.
485 #[derive(Clone, Copy)]
486 pub enum SignatureContext {
487     CoseSignature,
488     CoseSign1,
489     CounterSignature,
490 }
491 
492 impl SignatureContext {
493     /// Return the context string as per RFC 8152 section 4.4.
text(&self) -> &'static str494     fn text(&self) -> &'static str {
495         match self {
496             SignatureContext::CoseSignature => "Signature",
497             SignatureContext::CoseSign1 => "Signature1",
498             SignatureContext::CounterSignature => "CounterSignature",
499         }
500     }
501 }
502 
503 /// Create a binary blob that will be signed.
504 ///
505 /// ```cddl
506 ///   Sig_structure = [
507 ///       context : "Signature" / "Signature1" / "CounterSignature",
508 ///       body_protected : empty_or_serialized_map,
509 ///       ? sign_protected : empty_or_serialized_map,
510 ///       external_aad : bstr,
511 ///       payload : bstr
512 ///   ]
513 /// ```
sig_structure_data( context: SignatureContext, body: ProtectedHeader, sign: Option<ProtectedHeader>, aad: &[u8], payload: &[u8], ) -> Vec<u8>514 pub fn sig_structure_data(
515     context: SignatureContext,
516     body: ProtectedHeader,
517     sign: Option<ProtectedHeader>,
518     aad: &[u8],
519     payload: &[u8],
520 ) -> Vec<u8> {
521     let mut arr = vec![
522         Value::Text(context.text().to_owned()),
523         body.cbor_bstr().expect("failed to serialize header"), // safe: always serializable
524     ];
525     if let Some(sign) = sign {
526         arr.push(sign.cbor_bstr().expect("failed to serialize header")); // safe: always
527                                                                          // serializable
528     }
529     arr.push(Value::Bytes(aad.to_vec()));
530     arr.push(Value::Bytes(payload.to_vec()));
531     let mut data = Vec::new();
532     cbor::ser::into_writer(&Value::Array(arr), &mut data).unwrap(); // safe: always serializable
533     data
534 }
535