summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cose/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
commit9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/cose/src
parentInitial commit. (diff)
downloadthunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz
thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/cose/src')
-rw-r--r--third_party/rust/cose/src/cose.rs72
-rw-r--r--third_party/rust/cose/src/decoder.rs235
-rw-r--r--third_party/rust/cose/src/test_cose.rs496
-rw-r--r--third_party/rust/cose/src/test_setup.rs169
-rw-r--r--third_party/rust/cose/src/util.rs27
5 files changed, 999 insertions, 0 deletions
diff --git a/third_party/rust/cose/src/cose.rs b/third_party/rust/cose/src/cose.rs
new file mode 100644
index 0000000000..d55dda8d16
--- /dev/null
+++ b/third_party/rust/cose/src/cose.rs
@@ -0,0 +1,72 @@
+//! This crate implements [COSE](https://tools.ietf.org/html/rfc8152) signature
+//! parsing. Verification has to be performed by the caller.
+//!
+//! Example usage: Let `payload` and `cose_signature` be variables holding the
+//! signed payload and the COSE signature bytes respectively.
+//! Let further `verify_callback` be a function callback that implements
+//! signature verification.
+//!
+//!```rust,ignore
+//! use cose::decoder::decode_signature;
+//!
+//! // Parse the incoming signature.
+//! let cose_signatures = decode_signature(cose_signature, &payload);
+//! let cose_signatures = match cose_signatures {
+//! Ok(signature) => signature,
+//! Err(_) => Vec::new(),
+//! };
+//! if cose_signatures.len() < 1 {
+//! return false;
+//! }
+//!
+//! let mut result = true;
+//! for cose_signature in cose_signatures {
+//! // Call callback to verify the parsed signatures.
+//! result &= verify_callback(cose_signature);
+//!
+//! // We can stop early. The cose_signature is not valid.
+//! if !result {
+//! return result;
+//! }
+//! }
+//!```
+extern crate moz_cbor as cbor;
+
+pub mod decoder;
+pub mod util;
+
+/// Errors that can be returned from COSE functions.
+#[derive(Debug, PartialEq)]
+pub enum CoseError {
+ DecodingFailure,
+ LibraryFailure,
+ MalformedInput,
+ MissingHeader,
+ UnexpectedHeaderValue,
+ UnexpectedTag,
+ UnexpectedType,
+ Unimplemented,
+ VerificationFailed,
+ UnknownSignatureScheme,
+ SigningFailed,
+ InvalidArgument,
+}
+
+/// An enum identifying supported signature algorithms.
+/// Currently ES256 (ECDSA with P256 and SHA256), ES384 (ECDSA with P384 and SHA384)
+/// ES512 (ECDSA with P521 and SHA512), and PS256 (RSASSA-PSS with SHA256)
+/// are supported. Note that with PS256, the salt length is defined
+/// to be 32 bytes.
+#[derive(Debug)]
+#[derive(PartialEq)]
+pub enum SignatureAlgorithm {
+ ES256,
+ ES384,
+ ES512,
+ PS256,
+}
+
+#[cfg(test)]
+mod test_setup;
+#[cfg(test)]
+mod test_cose;
diff --git a/third_party/rust/cose/src/decoder.rs b/third_party/rust/cose/src/decoder.rs
new file mode 100644
index 0000000000..90463d5dd2
--- /dev/null
+++ b/third_party/rust/cose/src/decoder.rs
@@ -0,0 +1,235 @@
+//! Parse and decode COSE signatures.
+
+use cbor::CborType;
+use cbor::decoder::decode;
+use {CoseError, SignatureAlgorithm};
+use util::get_sig_struct_bytes;
+use std::collections::BTreeMap;
+
+pub const COSE_SIGN_TAG: u64 = 98;
+
+/// The result of `decode_signature` holding a decoded COSE signature.
+#[derive(Debug)]
+pub struct CoseSignature {
+ pub signature_type: SignatureAlgorithm,
+ pub signature: Vec<u8>,
+ pub signer_cert: Vec<u8>,
+ pub certs: Vec<Vec<u8>>,
+ pub to_verify: Vec<u8>,
+}
+
+pub const COSE_TYPE_ES256: i64 = -7;
+pub const COSE_TYPE_ES384: i64 = -35;
+pub const COSE_TYPE_ES512: i64 = -36;
+pub const COSE_TYPE_PS256: i64 = -37;
+
+pub const COSE_HEADER_ALG: u64 = 1;
+pub const COSE_HEADER_KID: u64 = 4;
+
+macro_rules! unpack {
+ ($to:tt, $var:ident) => (
+ match *$var {
+ CborType::$to(ref cbor_object) => {
+ cbor_object
+ }
+ _ => return Err(CoseError::UnexpectedType),
+ };
+ )
+}
+
+fn get_map_value(
+ map: &BTreeMap<CborType, CborType>,
+ key: &CborType,
+) -> Result<CborType, CoseError> {
+ match map.get(key) {
+ Some(x) => Ok(x.clone()),
+ _ => Err(CoseError::MissingHeader),
+ }
+}
+
+/// Ensure that the referenced `CborType` is an empty map.
+fn ensure_empty_map(map: &CborType) -> Result<(), CoseError> {
+ let unpacked = unpack!(Map, map);
+ if !unpacked.is_empty() {
+ return Err(CoseError::MalformedInput);
+ }
+ Ok(())
+}
+
+// This syntax is a little unintuitive. Taken together, the two previous definitions essentially
+// mean:
+//
+// COSE_Sign = [
+// protected : empty_or_serialized_map,
+// unprotected : header_map
+// payload : bstr / nil,
+// signatures : [+ COSE_Signature]
+// ]
+//
+// (COSE_Sign is an array. The first element is an empty or serialized map (in our case, it is
+// never expected to be empty). The second element is a map (it is expected to be empty. The third
+// element is a bstr or nil (it is expected to be nil). The fourth element is an array of
+// COSE_Signature.)
+//
+// COSE_Signature = [
+// Headers,
+// signature : bstr
+// ]
+//
+// but again, unpacking this:
+//
+// COSE_Signature = [
+// protected : empty_or_serialized_map,
+// unprotected : header_map
+// signature : bstr
+// ]
+fn decode_signature_struct(
+ cose_signature: &CborType,
+ payload: &[u8],
+ protected_body_head: &CborType,
+) -> Result<CoseSignature, CoseError> {
+ let cose_signature = unpack!(Array, cose_signature);
+ if cose_signature.len() != 3 {
+ return Err(CoseError::MalformedInput);
+ }
+ let protected_signature_header_serialized = &cose_signature[0];
+ let protected_signature_header_bytes = unpack!(Bytes, protected_signature_header_serialized);
+
+ // Parse the protected signature header.
+ let protected_signature_header = &match decode(protected_signature_header_bytes) {
+ Err(_) => return Err(CoseError::DecodingFailure),
+ Ok(value) => value,
+ };
+ let protected_signature_header = unpack!(Map, protected_signature_header);
+ if protected_signature_header.len() != 2 {
+ return Err(CoseError::MalformedInput);
+ }
+ let signature_algorithm = get_map_value(
+ protected_signature_header,
+ &CborType::Integer(COSE_HEADER_ALG),
+ )?;
+ let signature_algorithm = match signature_algorithm {
+ CborType::SignedInteger(val) => {
+ match val {
+ COSE_TYPE_ES256 => SignatureAlgorithm::ES256,
+ COSE_TYPE_ES384 => SignatureAlgorithm::ES384,
+ COSE_TYPE_ES512 => SignatureAlgorithm::ES512,
+ COSE_TYPE_PS256 => SignatureAlgorithm::PS256,
+ _ => return Err(CoseError::UnexpectedHeaderValue),
+ }
+ }
+ _ => return Err(CoseError::UnexpectedType),
+ };
+
+ let ee_cert = &get_map_value(
+ protected_signature_header,
+ &CborType::Integer(COSE_HEADER_KID),
+ )?;
+ let ee_cert = unpack!(Bytes, ee_cert).clone();
+
+ // The unprotected header section is expected to be an empty map.
+ ensure_empty_map(&cose_signature[1])?;
+
+ // Build signature structure to verify.
+ let signature_bytes = &cose_signature[2];
+ let signature_bytes = unpack!(Bytes, signature_bytes).clone();
+ let sig_structure_bytes = get_sig_struct_bytes(
+ protected_body_head.clone(),
+ protected_signature_header_serialized.clone(),
+ payload,
+ );
+
+ // Read intermediate certificates from protected_body_head.
+ // Any tampering of the protected header during transport will be detected
+ // because it is input to the signature verification.
+ // Note that a protected header has to be present and hold a kid with an
+ // empty list of intermediate certificates.
+ let protected_body_head_bytes = unpack!(Bytes, protected_body_head);
+ let protected_body_head_map = &match decode(protected_body_head_bytes) {
+ Ok(value) => value,
+ Err(_) => return Err(CoseError::DecodingFailure),
+ };
+ let protected_body_head_map = unpack!(Map, protected_body_head_map);
+ if protected_body_head_map.len() != 1 {
+ return Err(CoseError::MalformedInput);
+ }
+ let intermediate_certs_array =
+ &get_map_value(protected_body_head_map, &CborType::Integer(COSE_HEADER_KID))?;
+ let intermediate_certs = unpack!(Array, intermediate_certs_array);
+ let mut certs: Vec<Vec<u8>> = Vec::new();
+ for cert in intermediate_certs {
+ let cert = unpack!(Bytes, cert);
+ certs.push(cert.clone());
+ }
+
+ Ok(CoseSignature {
+ signature_type: signature_algorithm,
+ signature: signature_bytes,
+ signer_cert: ee_cert,
+ certs: certs,
+ to_verify: sig_structure_bytes,
+ })
+}
+
+/// Decode COSE signature bytes and return a vector of `CoseSignature`.
+///
+///```rust,ignore
+/// COSE_Sign = [
+/// Headers,
+/// payload : bstr / nil,
+/// signatures : [+ COSE_Signature]
+/// ]
+///
+/// Headers = (
+/// protected : empty_or_serialized_map,
+/// unprotected : header_map
+/// )
+///```
+pub fn decode_signature(bytes: &[u8], payload: &[u8]) -> Result<Vec<CoseSignature>, CoseError> {
+ // This has to be a COSE_Sign object, which is a tagged array.
+ let tagged_cose_sign = match decode(bytes) {
+ Err(_) => return Err(CoseError::DecodingFailure),
+ Ok(value) => value,
+ };
+ let cose_sign_array = match tagged_cose_sign {
+ CborType::Tag(tag, cose_sign) => {
+ if tag != COSE_SIGN_TAG {
+ return Err(CoseError::UnexpectedTag);
+ }
+ match *cose_sign {
+ CborType::Array(values) => values,
+ _ => return Err(CoseError::UnexpectedType),
+ }
+ }
+ _ => return Err(CoseError::UnexpectedType),
+ };
+ if cose_sign_array.len() != 4 {
+ return Err(CoseError::MalformedInput);
+ }
+
+ // The unprotected header section is expected to be an empty map.
+ ensure_empty_map(&cose_sign_array[1])?;
+
+ // The payload is expected to be Null (i.e. this is a detached signature).
+ match cose_sign_array[2] {
+ CborType::Null => {}
+ _ => return Err(CoseError::UnexpectedType),
+ };
+
+ let signatures = &cose_sign_array[3];
+ let signatures = unpack!(Array, signatures);
+
+ // Decode COSE_Signatures.
+ // There has to be at least one signature to make this a valid COSE signature.
+ if signatures.len() < 1 {
+ return Err(CoseError::MalformedInput);
+ }
+ let mut result = Vec::new();
+ for cose_signature in signatures {
+ // cose_sign_array[0] holds the protected body header.
+ let signature = decode_signature_struct(cose_signature, payload, &cose_sign_array[0])?;
+ result.push(signature);
+ }
+
+ Ok(result)
+}
diff --git a/third_party/rust/cose/src/test_cose.rs b/third_party/rust/cose/src/test_cose.rs
new file mode 100644
index 0000000000..7c680a879c
--- /dev/null
+++ b/third_party/rust/cose/src/test_cose.rs
@@ -0,0 +1,496 @@
+use test_setup as test;
+use {CoseError, SignatureAlgorithm};
+use decoder::{COSE_HEADER_ALG, COSE_HEADER_KID, COSE_SIGN_TAG, COSE_TYPE_ES256, decode_signature};
+use cbor::CborType;
+use std::collections::BTreeMap;
+
+#[test]
+fn test_cose_decode() {
+ let payload = b"This is the content.";
+ let cose_signatures = decode_signature(&test::COSE_SIGNATURE_BYTES, payload).unwrap();
+ assert_eq!(cose_signatures.len(), 1);
+ assert_eq!(cose_signatures[0].signature_type, SignatureAlgorithm::ES256);
+ assert_eq!(cose_signatures[0].signature, test::SIGNATURE_BYTES.to_vec());
+ assert_eq!(cose_signatures[0].certs[0], test::P256_ROOT.to_vec());
+ assert_eq!(cose_signatures[0].certs[1], test::P256_INT.to_vec());
+}
+
+fn test_cose_format_error(bytes: &[u8], expected_error: CoseError) {
+ let payload = vec![0];
+ let result = decode_signature(bytes, &payload);
+ assert!(result.is_err());
+ assert_eq!(result.err(), Some(expected_error));
+}
+
+// Helper function to take a `Vec<CborType>`, wrap it in a `CborType::Array`, tag it with the
+// COSE_Sign tag (COSE_SIGN_TAG = 98), and serialize it to a `Vec<u8>`.
+fn wrap_tag_and_encode_array(array: Vec<CborType>) -> Vec<u8> {
+ CborType::Tag(COSE_SIGN_TAG, Box::new(CborType::Array(array))).serialize()
+}
+
+// Helper function to create an encoded protected header for a COSE_Sign or COSE_Signature
+// structure.
+fn encode_test_protected_header(keys: Vec<CborType>, values: Vec<CborType>) -> Vec<u8> {
+ assert_eq!(keys.len(), values.len());
+ let mut map: BTreeMap<CborType, CborType> = BTreeMap::new();
+ for (key, value) in keys.iter().zip(values) {
+ map.insert(key.clone(), value.clone());
+ }
+ CborType::Map(map).serialize()
+}
+
+// Helper function to create a test COSE_Signature structure with the given protected header.
+fn build_test_cose_signature(protected_header: Vec<u8>) -> CborType {
+ CborType::Array(vec![CborType::Bytes(protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Bytes(Vec::new())])
+}
+
+// Helper function to create the minimally-valid COSE_Sign (i.e. "body") protected header.
+fn make_minimally_valid_cose_sign_protected_header() -> Vec<u8> {
+ encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::Array(Vec::new())],
+ )
+}
+
+// Helper function to create a minimally-valid COSE_Signature (i.e. "body").
+fn make_minimally_valid_cose_signature_protected_header() -> Vec<u8> {
+ encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Bytes(Vec::new())],
+ )
+}
+
+// This tests the minimally-valid COSE_Sign structure according to this implementation.
+// The structure must be a CBOR array of length 4 tagged with the integer 98.
+// The COSE_Sign protected header must have the `kid` integer key and no others. The value for `kid`
+// must be an array (although it may be empty). Each element of the array must be of type bytes.
+// The COSE_Sign unprotected header must be an empty map.
+// The COSE_Sign payload must be nil.
+// The COSE_Sign signatures must be an array with at least one COSE_Signature.
+// Each COSE_Signature must be an array of length 3.
+// Each COSE_Signature protected header must have the `alg` and `kid` integer keys and no others.
+// The value for `alg` must be a valid algorithm identifier. The value for `kid` must be bytes,
+// although it may be empty.
+// Each COSE_Signature unprotected header must be an empty map.
+// Each COSE_Signature signature must be of type bytes (although it may be empty).
+#[test]
+fn test_cose_sign_minimally_valid() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ let payload = vec![0];
+ let result = decode_signature(&bytes, &payload);
+ assert!(result.is_ok());
+ let decoded = result.unwrap();
+ assert_eq!(decoded.len(), 1);
+ assert_eq!(decoded[0].signer_cert.len(), 0);
+ assert_eq!(decoded[0].certs.len(), 0);
+}
+
+#[test]
+fn test_cose_sign_not_tagged() {
+ let bytes = CborType::Array(vec![CborType::Integer(0)]).serialize();
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_wrong_tag() {
+ // The expected COSE_Sign tag is 98.
+ let bytes = CborType::Tag(99, Box::new(CborType::Integer(0))).serialize();
+ test_cose_format_error(&bytes, CoseError::UnexpectedTag);
+}
+
+#[test]
+fn test_cose_sign_right_tag_wrong_contents() {
+ // The COSE_Sign tag is 98, but the contents should be an array.
+ let bytes = CborType::Tag(98, Box::new(CborType::Integer(0))).serialize();
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_too_small() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_too_large() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(Vec::new()),
+ CborType::Array(Vec::new())];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_protected_header_empty() {
+ let body_protected_header = encode_test_protected_header(Vec::new(), Vec::new());
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_protected_header_missing_kid() {
+ let body_protected_header =
+ encode_test_protected_header(vec![CborType::Integer(2)], vec![CborType::Integer(2)]);
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_sign_protected_header_kid_wrong_type() {
+ let body_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::Integer(2)],
+ );
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_protected_header_extra_header_key() {
+ let body_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_KID),
+ CborType::Integer(2)],
+ vec![CborType::Bytes(Vec::new()),
+ CborType::Integer(2)],
+ );
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_unprotected_header_wrong_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Integer(1),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_unprotected_header_not_empty() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let mut unprotected_header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+ unprotected_header_map.insert(CborType::Integer(0), CborType::SignedInteger(-1));
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(unprotected_header_map),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_payload_not_null() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Integer(0),
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signatures_not_array() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Integer(0)];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signatures_empty() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(Vec::new())];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_protected_header_wrong_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature = CborType::Array(vec![CborType::Null,
+ CborType::Map(BTreeMap::new()),
+ CborType::SignedInteger(-1)]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signature_protected_header_empty() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(Vec::new(), Vec::new());
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_protected_header_too_large() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Bytes(Vec::new()),
+ CborType::Null]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_protected_header_bad_encoding() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ // The bytes here are a truncated integer encoding.
+ let signature = CborType::Array(vec![CborType::Bytes(vec![0x1a, 0x00, 0x00]),
+ CborType::Map(BTreeMap::new()),
+ CborType::Bytes(Vec::new())]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::DecodingFailure);
+}
+
+#[test]
+fn test_cose_signature_protected_header_missing_alg() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(2),
+ CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Bytes(Vec::new())],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_signature_protected_header_missing_kid() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(3)],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Bytes(Vec::new())],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_signature_protected_header_wrong_key_types() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::SignedInteger(-1),
+ CborType::Bytes(vec![0])],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Bytes(Vec::new())],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_signature_protected_header_unexpected_alg_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::Integer(10),
+ CborType::Integer(4)],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signature_protected_header_unsupported_alg() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::SignedInteger(-10),
+ CborType::Bytes(Vec::new())],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedHeaderValue);
+}
+
+#[test]
+fn test_cose_signature_protected_header_unexpected_kid_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(COSE_HEADER_KID)],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Integer(0)],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signature_protected_header_extra_key() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = encode_test_protected_header(
+ vec![CborType::Integer(COSE_HEADER_ALG),
+ CborType::Integer(COSE_HEADER_KID),
+ CborType::Integer(5)],
+ vec![CborType::SignedInteger(COSE_TYPE_ES256),
+ CborType::Bytes(Vec::new()),
+ CborType::Integer(5)],
+ );
+ let signature = build_test_cose_signature(signature_protected_header);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_unprotected_header_wrong_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+ CborType::Integer(1),
+ CborType::Bytes(Vec::new())]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signature_unprotected_header_not_empty() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let mut unprotected_header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+ unprotected_header_map.insert(CborType::Integer(0), CborType::SignedInteger(-1));
+ let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+ CborType::Map(unprotected_header_map),
+ CborType::Bytes(Vec::new())]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_signature_wrong_type() {
+ let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+ let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+ let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::SignedInteger(-1)]);
+ let values = vec![CborType::Bytes(body_protected_header),
+ CborType::Map(BTreeMap::new()),
+ CborType::Null,
+ CborType::Array(vec![signature])];
+ let bytes = wrap_tag_and_encode_array(values);
+ test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
diff --git a/third_party/rust/cose/src/test_setup.rs b/third_party/rust/cose/src/test_setup.rs
new file mode 100644
index 0000000000..fce0676a66
--- /dev/null
+++ b/third_party/rust/cose/src/test_setup.rs
@@ -0,0 +1,169 @@
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P256_INT: [u8; 332] = [
+ 0x30, 0x82, 0x01, 0x48, 0x30, 0x81, 0xf0, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x43, 0x63, 0x59, 0xad, 0x04, 0x34, 0x56, 0x80,
+ 0x43, 0xec, 0x90, 0x6a, 0xd4, 0x10, 0x64, 0x7c, 0x7f, 0x38, 0x32,
+ 0xe2, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+ 0x03, 0x02, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32,
+ 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30,
+ 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18,
+ 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69, 0x6e, 0x74, 0x2d,
+ 0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf,
+ 0xbb, 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac,
+ 0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e,
+ 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2,
+ 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e,
+ 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07,
+ 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0xa3, 0x1d, 0x30, 0x1b,
+ 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
+ 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04,
+ 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44,
+ 0x02, 0x20, 0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff,
+ 0xd1, 0x16, 0x4e, 0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf,
+ 0x77, 0x5c, 0x93, 0x60, 0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d,
+ 0x24, 0x02, 0x20, 0x3d, 0x87, 0x0f, 0xac, 0x22, 0x4d, 0x16, 0xd9,
+ 0xa1, 0x95, 0xbb, 0x56, 0xe0, 0x21, 0x05, 0x93, 0xd1, 0x07, 0xb5,
+ 0x25, 0x3b, 0xf4, 0x57, 0x20, 0x87, 0x13, 0xa2, 0xf7, 0x78, 0x15,
+ 0x30, 0xa7
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P256_ROOT: [u8; 334] = [
+ 0x30, 0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02,
+ 0x02, 0x14, 0x5f, 0x3f, 0xae, 0x90, 0x49, 0x30, 0x2f, 0x33, 0x6e, 0x95,
+ 0x23, 0xa7, 0xcb, 0x23, 0xd7, 0x65, 0x4f, 0xea, 0x3c, 0xf7, 0x30, 0x0a,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x14,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72,
+ 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
+ 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
+ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f,
+ 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
+ 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04,
+ 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c,
+ 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36,
+ 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90,
+ 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6,
+ 0xc0, 0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30,
+ 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d,
+ 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75,
+ 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02,
+ 0x21, 0x00, 0xc2, 0xe4, 0xc1, 0xa8, 0xe2, 0x89, 0xdc, 0xa1, 0xbb, 0xe7,
+ 0xd5, 0x4f, 0x5c, 0x88, 0xad, 0xeb, 0xa4, 0x78, 0xa1, 0x19, 0xbe, 0x22,
+ 0x54, 0xc8, 0x9f, 0xef, 0xb8, 0x5d, 0xa2, 0x40, 0xd9, 0x8b
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const COSE_SIGNATURE_BYTES: [u8; 1062] = [
+ 0xd8, 0x62, 0x84, 0x59, 0x02, 0xa3, 0xa1, 0x04, 0x82, 0x59, 0x01, 0x4e,
+ 0x30, 0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02,
+ 0x02, 0x14, 0x5f, 0x3f, 0xae, 0x90, 0x49, 0x30, 0x2f, 0x33, 0x6e, 0x95,
+ 0x23, 0xa7, 0xcb, 0x23, 0xd7, 0x65, 0x4f, 0xea, 0x3c, 0xf7, 0x30, 0x0a,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x14,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72,
+ 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
+ 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
+ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f,
+ 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
+ 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04,
+ 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c,
+ 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36,
+ 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90,
+ 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6,
+ 0xc0, 0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30,
+ 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d,
+ 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75,
+ 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02,
+ 0x21, 0x00, 0xc2, 0xe4, 0xc1, 0xa8, 0xe2, 0x89, 0xdc, 0xa1, 0xbb, 0xe7,
+ 0xd5, 0x4f, 0x5c, 0x88, 0xad, 0xeb, 0xa4, 0x78, 0xa1, 0x19, 0xbe, 0x22,
+ 0x54, 0xc8, 0x9f, 0xef, 0xb8, 0x5d, 0xa2, 0x40, 0xd9, 0x8b, 0x59, 0x01,
+ 0x4c, 0x30, 0x82, 0x01, 0x48, 0x30, 0x81, 0xf0, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x43, 0x63, 0x59, 0xad, 0x04, 0x34, 0x56, 0x80, 0x43,
+ 0xec, 0x90, 0x6a, 0xd4, 0x10, 0x64, 0x7c, 0x7f, 0x38, 0x32, 0xe2, 0x30,
+ 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
+ 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09,
+ 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18,
+ 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32,
+ 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x13, 0x31,
+ 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69, 0x6e,
+ 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
+ 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04,
+ 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c,
+ 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36,
+ 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90,
+ 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6,
+ 0xc0, 0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30,
+ 0x44, 0x02, 0x20, 0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff,
+ 0xd1, 0x16, 0x4e, 0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf, 0x77,
+ 0x5c, 0x93, 0x60, 0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d, 0x24, 0x02,
+ 0x20, 0x3d, 0x87, 0x0f, 0xac, 0x22, 0x4d, 0x16, 0xd9, 0xa1, 0x95, 0xbb,
+ 0x56, 0xe0, 0x21, 0x05, 0x93, 0xd1, 0x07, 0xb5, 0x25, 0x3b, 0xf4, 0x57,
+ 0x20, 0x87, 0x13, 0xa2, 0xf7, 0x78, 0x15, 0x30, 0xa7, 0xa0, 0xf6, 0x81,
+ 0x83, 0x59, 0x01, 0x33, 0xa2, 0x01, 0x26, 0x04, 0x59, 0x01, 0x2c, 0x30,
+ 0x82, 0x01, 0x28, 0x30, 0x81, 0xcf, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+ 0x14, 0x2f, 0xc3, 0x5f, 0x05, 0x80, 0xb4, 0x49, 0x45, 0x13, 0x92, 0xd6,
+ 0x93, 0xb7, 0x2d, 0x71, 0x19, 0xc5, 0x8c, 0x40, 0x39, 0x30, 0x0a, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x13, 0x31,
+ 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69, 0x6e,
+ 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30,
+ 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30, 0x0e,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d, 0x70, 0x32,
+ 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01,
+ 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0, 0xf8,
+ 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b,
+ 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45,
+ 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07,
+ 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b,
+ 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30, 0x0a, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00,
+ 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd,
+ 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73,
+ 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6,
+ 0x02, 0x21, 0x00, 0xff, 0x81, 0xbe, 0xa8, 0x0d, 0x03, 0x36, 0x6b, 0x75,
+ 0xe2, 0x70, 0x6a, 0xac, 0x07, 0x2e, 0x4c, 0xdc, 0xf9, 0xc5, 0x89, 0xc1,
+ 0xcf, 0x88, 0xc2, 0xc8, 0x2a, 0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b, 0xa0,
+ 0x58, 0x40, 0x11, 0xe5, 0x73, 0x2c, 0x23, 0x31, 0x6f, 0xb4, 0x17, 0xcf,
+ 0xa9, 0xee, 0xc5, 0xe3, 0x57, 0xcc, 0x77, 0x82, 0x29, 0x1f, 0xba, 0x97,
+ 0xbf, 0x32, 0xaf, 0x8d, 0x88, 0x27, 0xde, 0x69, 0xd2, 0xdf, 0xd6, 0xec,
+ 0x9e, 0x5b, 0xd3, 0x9d, 0xf8, 0x9d, 0x68, 0xc6, 0xce, 0x91, 0x32, 0x41,
+ 0x50, 0x5f, 0xd8, 0x72, 0xb0, 0x41, 0xb9, 0x39, 0x3d, 0xdf, 0x44, 0xee,
+ 0x89, 0x74, 0x4d, 0x9e, 0xb4, 0xd7
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const SIGNATURE_BYTES: [u8; 64] = [
+ 0x11, 0xe5, 0x73, 0x2c, 0x23, 0x31, 0x6f, 0xb4, 0x17, 0xcf,
+ 0xa9, 0xee, 0xc5, 0xe3, 0x57, 0xcc, 0x77, 0x82, 0x29, 0x1f, 0xba, 0x97,
+ 0xbf, 0x32, 0xaf, 0x8d, 0x88, 0x27, 0xde, 0x69, 0xd2, 0xdf, 0xd6, 0xec,
+ 0x9e, 0x5b, 0xd3, 0x9d, 0xf8, 0x9d, 0x68, 0xc6, 0xce, 0x91, 0x32, 0x41,
+ 0x50, 0x5f, 0xd8, 0x72, 0xb0, 0x41, 0xb9, 0x39, 0x3d, 0xdf, 0x44, 0xee,
+ 0x89, 0x74, 0x4d, 0x9e, 0xb4, 0xd7
+];
diff --git a/third_party/rust/cose/src/util.rs b/third_party/rust/cose/src/util.rs
new file mode 100644
index 0000000000..8f1cf7e954
--- /dev/null
+++ b/third_party/rust/cose/src/util.rs
@@ -0,0 +1,27 @@
+use cbor::CborType;
+
+/// Sig_structure is a CBOR array:
+///
+/// Sig_structure = [
+/// context : "Signature" / "Signature1" / "CounterSignature",
+/// body_protected : empty_or_serialized_map,
+/// ? sign_protected : empty_or_serialized_map,
+/// external_aad : bstr,
+/// payload : bstr
+/// ]
+///
+/// In this case, the context is "Signature". There is no external_aad, so this defaults to a
+/// zero-length bstr.
+pub fn get_sig_struct_bytes(
+ protected_body_header_serialized: CborType,
+ protected_signature_header_serialized: CborType,
+ payload: &[u8],
+) -> Vec<u8> {
+ let sig_structure_array: Vec<CborType> = vec![CborType::String(String::from("Signature")),
+ protected_body_header_serialized,
+ protected_signature_header_serialized,
+ CborType::Null,
+ CborType::Bytes(payload.to_vec())];
+
+ CborType::Array(sig_structure_array).serialize()
+}