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