use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
use serde_bytes::ByteBuf;
use serde_cbor::Error as CborError;
use serde_cbor::Value as CborValue;
use crate::crypto::{Hash, SigningPrivateKey, SigningPublicKey};
use crate::error::CoseError;
use crate::header_map::{map_to_empty_or_serialized, HeaderMap};
#[derive(Debug, Clone, Serialize)]
pub struct SigStructure(
String,
ByteBuf,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
Option<ByteBuf>,
#[serde(default)]
ByteBuf,
#[serde(default)]
ByteBuf,
);
impl SigStructure {
pub fn new_sign1(body_protected: &[u8], payload: &[u8]) -> Result<Self, CborError> {
Ok(SigStructure(
String::from("Signature1"),
ByteBuf::from(body_protected.to_vec()),
None,
ByteBuf::new(),
ByteBuf::from(payload.to_vec()),
))
}
pub fn new_sign1_cbor_value(
body_protected: &[u8],
payload: &CborValue,
) -> Result<Self, CborError> {
Self::new_sign1(body_protected, &serde_cbor::to_vec(payload)?)
}
pub fn as_bytes(&self) -> Result<Vec<u8>, CborError> {
serde_cbor::to_vec(self)
}
}
#[derive(Debug, Clone)]
pub struct CoseSign1 {
protected: ByteBuf,
unprotected: HeaderMap,
payload: ByteBuf,
signature: ByteBuf,
}
impl Serialize for CoseSign1 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(4))?;
seq.serialize_element(&self.protected)?;
seq.serialize_element(&self.unprotected)?;
seq.serialize_element(&self.payload)?;
seq.serialize_element(&self.signature)?;
seq.end()
}
}
impl<'de> Deserialize<'de> for CoseSign1 {
fn deserialize<D>(deserializer: D) -> Result<CoseSign1, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::{Error, SeqAccess, Visitor};
use std::fmt;
struct CoseSign1Visitor;
impl<'de> Visitor<'de> for CoseSign1Visitor {
type Value = CoseSign1;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a possibly tagged CoseSign1 structure")
}
fn visit_seq<A>(self, mut seq: A) -> Result<CoseSign1, A::Error>
where
A: SeqAccess<'de>,
{
let protected = match seq.next_element()? {
Some(v) => v,
None => return Err(A::Error::missing_field("protected")),
};
let unprotected = match seq.next_element()? {
Some(v) => v,
None => return Err(A::Error::missing_field("unprotected")),
};
let payload = match seq.next_element()? {
Some(v) => v,
None => return Err(A::Error::missing_field("payload")),
};
let signature = match seq.next_element()? {
Some(v) => v,
None => return Err(A::Error::missing_field("signature")),
};
Ok(CoseSign1 {
protected,
unprotected,
payload,
signature,
})
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<CoseSign1, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(CoseSign1Visitor)
}
}
deserializer.deserialize_any(CoseSign1Visitor)
}
}
impl CoseSign1 {
pub fn new<H: Hash>(
payload: &[u8],
unprotected: &HeaderMap,
key: &dyn SigningPrivateKey,
) -> Result<Self, CoseError> {
let (sig_alg, _) = key.get_parameters()?;
let mut protected = HeaderMap::new();
protected.insert(1.into(), (sig_alg as i8).into());
Self::new_with_protected::<H>(payload, &protected, unprotected, key)
}
pub fn new_with_protected<H: Hash>(
payload: &[u8],
protected: &HeaderMap,
unprotected: &HeaderMap,
key: &dyn SigningPrivateKey,
) -> Result<Self, CoseError> {
let (_, digest) = key.get_parameters()?;
let protected_bytes =
map_to_empty_or_serialized(protected).map_err(CoseError::SerializationError)?;
let sig_structure = SigStructure::new_sign1(&protected_bytes, payload)
.map_err(CoseError::SerializationError)?;
let struct_digest = H::hash(
digest,
&sig_structure
.as_bytes()
.map_err(CoseError::SerializationError)?,
)
.map_err(|e| CoseError::SignatureError(Box::new(e)))?;
let signature = key.sign(struct_digest.as_ref())?;
Ok(CoseSign1 {
protected: ByteBuf::from(protected_bytes),
unprotected: unprotected.clone(),
payload: ByteBuf::from(payload.to_vec()),
signature: ByteBuf::from(signature),
})
}
pub fn as_bytes(&self, tagged: bool) -> Result<Vec<u8>, CoseError> {
let bytes = if tagged {
serde_cbor::to_vec(&serde_cbor::tags::Tagged::new(Some(18), &self))
} else {
serde_cbor::to_vec(&self)
};
bytes.map_err(CoseError::SerializationError)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoseError> {
let cosesign1: serde_cbor::tags::Tagged<Self> =
serde_cbor::from_slice(bytes).map_err(CoseError::SerializationError)?;
match cosesign1.tag {
None | Some(18) => (),
Some(tag) => return Err(CoseError::TagError(Some(tag))),
}
let protected = cosesign1.value.protected.as_slice();
let _: HeaderMap =
serde_cbor::from_slice(protected).map_err(CoseError::SerializationError)?;
Ok(cosesign1.value)
}
pub fn from_bytes_tagged(bytes: &[u8]) -> Result<Self, CoseError> {
let cosesign1: serde_cbor::tags::Tagged<Self> =
serde_cbor::from_slice(bytes).map_err(CoseError::SerializationError)?;
match cosesign1.tag {
Some(18) => (),
other => return Err(CoseError::TagError(other)),
}
let protected = cosesign1.value.protected.as_slice();
let _: HeaderMap =
serde_cbor::from_slice(protected).map_err(CoseError::SerializationError)?;
Ok(cosesign1.value)
}
pub fn verify_signature<H: Hash>(&self, key: &dyn SigningPublicKey) -> Result<bool, CoseError> {
let (signature_alg, digest) = key.get_parameters()?;
let protected: HeaderMap =
HeaderMap::from_bytes(&self.protected).map_err(CoseError::SerializationError)?;
if let Some(protected_signature_alg_val) = protected.get(&CborValue::Integer(1)) {
let protected_signature_alg = match protected_signature_alg_val {
CborValue::Integer(val) => val,
_ => {
return Err(CoseError::SpecificationError(
"Protected Header contains invalid Signature Algorithm specification"
.to_string(),
))
}
};
if protected_signature_alg != &(signature_alg as i8 as i128) {
return Ok(false);
}
} else {
return Err(CoseError::SpecificationError(
"Protected Header does not contain a valid Signature Algorithm specification"
.to_string(),
));
}
let sig_structure = SigStructure::new_sign1(&self.protected, &self.payload)
.map_err(CoseError::SerializationError)?;
let struct_digest = H::hash(
digest,
&sig_structure
.as_bytes()
.map_err(CoseError::SerializationError)?,
)
.map_err(|e| CoseError::SignatureError(Box::new(e)))?;
key.verify(struct_digest.as_ref(), &self.signature)
}
pub fn get_protected_and_payload<H: Hash>(
&self,
key: Option<&dyn SigningPublicKey>,
) -> Result<(HeaderMap, Vec<u8>), CoseError> {
if key.is_some() && !self.verify_signature::<H>(key.unwrap())? {
return Err(CoseError::UnverifiedSignature);
}
let protected: HeaderMap =
HeaderMap::from_bytes(&self.protected).map_err(CoseError::SerializationError)?;
Ok((protected, self.payload.to_vec()))
}
pub fn get_payload<H: Hash>(
&self,
key: Option<&dyn SigningPublicKey>,
) -> Result<Vec<u8>, CoseError> {
if key.is_some() && !self.verify_signature::<H>(key.unwrap())? {
return Err(CoseError::UnverifiedSignature);
}
Ok(self.payload.to_vec())
}
pub fn get_unprotected(&self) -> &HeaderMap {
&self.unprotected
}
}
#[cfg(test)]
mod tests {
const TEXT: &[u8] = b"It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.";
mod generic {
use crate::crypto::SignatureAlgorithm;
use crate::sign::*;
use super::TEXT;
#[test]
fn map_serialization() {
let map: HeaderMap = HeaderMap::new();
assert_eq!(map_to_empty_or_serialized(&map).unwrap(), [] as [u8; 0]);
let map: HeaderMap = SignatureAlgorithm::ES256.into();
assert_eq!(
map_to_empty_or_serialized(&map).unwrap(),
[0xa1, 0x01, 0x26]
);
let map: HeaderMap = SignatureAlgorithm::ES384.into();
assert_eq!(
map_to_empty_or_serialized(&map).unwrap(),
[0xa1, 0x01, 0x38, 0x22]
);
let map: HeaderMap = SignatureAlgorithm::ES512.into();
assert_eq!(
map_to_empty_or_serialized(&map).unwrap(),
[0xa1, 0x01, 0x38, 0x23]
);
}
#[test]
fn map_with_duplicates() {
let test = [0xa2, 0x01, 0x18, 0x2A, 0x02, 0x18, 0x2A];
let map: HeaderMap = serde_cbor::from_slice(&test).unwrap();
assert_eq!(
map.get(&CborValue::Integer(1)),
Some(&CborValue::Integer(42))
);
assert_eq!(
map.get(&CborValue::Integer(2)),
Some(&CborValue::Integer(42))
);
let test = [0xa3, 0x01, 0x18, 0x2A, 0x02, 0x18, 0x2A, 0x01, 0x18, 0x2B];
let map: Result<HeaderMap, _> = serde_cbor::from_slice(&test);
assert!(map.is_err());
let test = [0xa3, 0x01, 0x18, 0x2A, 0x02, 0x18, 0x2A, 0x02, 0x18, 0x2A];
let map: Result<HeaderMap, _> = serde_cbor::from_slice(&test);
assert!(map.is_err());
}
#[test]
fn sig_structure_text() {
let map = HeaderMap::new();
let map_serialized = map_to_empty_or_serialized(&map).unwrap();
let sig_structure = SigStructure::new_sign1(&map_serialized, TEXT).unwrap();
assert_eq!(
vec![
0x84, 0x6A, 0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x31,
0x40, 0x40, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75,
0x74, 0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C,
0x79, 0x20, 0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65,
0x64, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E,
0x67, 0x6C, 0x65, 0x20, 0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F,
0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61,
0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65,
0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6E, 0x20,
0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x77, 0x69, 0x66,
0x65, 0x2E,
],
sig_structure.as_bytes().unwrap()
);
let map: HeaderMap = SignatureAlgorithm::ES256.into();
let map_serialized = map_to_empty_or_serialized(&map).unwrap();
let sig_structure = SigStructure::new_sign1(&map_serialized, TEXT).unwrap();
assert_eq!(
vec![
0x84, 0x6A, 0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x31,
0x43, 0xA1, 0x01, 0x26, 0x40, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75,
0x74, 0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C,
0x79, 0x20, 0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65,
0x64, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E,
0x67, 0x6C, 0x65, 0x20, 0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F,
0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61,
0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65,
0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6E, 0x20,
0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x77, 0x69, 0x66,
0x65, 0x2E,
],
sig_structure.as_bytes().unwrap()
);
}
}
#[cfg(feature = "key_openssl_pkey")]
mod openssl {
use crate::crypto::Openssl;
use crate::crypto::SignatureAlgorithm;
use crate::sign::*;
use openssl::pkey::{PKey, Private, Public};
use super::TEXT;
fn get_ec256_test_key() -> (PKey<Private>, PKey<Public>) {
let alg =
openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1).unwrap();
let x = openssl::bn::BigNum::from_hex_str(
"9ff7423a1aace5f3e33dfaeda2c7744e3d15c2a4f6382386c93fa60c1bdb260c",
)
.unwrap();
let y = openssl::bn::BigNum::from_hex_str(
"3489e6b132f36e5ece948e73bd44231a1c3d0dacf566712a44fe8a9835d5b6fe",
)
.unwrap();
let d = openssl::bn::BigNum::from_hex_str(
"8e21d79fb6955dbe7bb592d92de4690f8bf75dc1495b2433ba78d5828e1f933f",
)
.unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key_affine_coordinates(&alg, &x, &y).unwrap();
let ec_private =
openssl::ec::EcKey::from_private_components(&alg, &d, &ec_public.public_key())
.unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
fn get_ec384_test_key() -> (PKey<Private>, PKey<Public>) {
let alg = openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::SECP384R1).unwrap();
let x = openssl::bn::BigNum::from_hex_str(
"5a829f62f2f4f095c0e922719285b4b981c677912870a413137a5d7319916fa8\
584a6036951d06ffeae99ca73ab1a2dc",
)
.unwrap();
let y = openssl::bn::BigNum::from_hex_str(
"e1b76e08cb20d6afcea7423f8b49ec841dde6f210a6174750bf8136a31549422\
4df153184557a6c29a1d7994804f604c",
)
.unwrap();
let d = openssl::bn::BigNum::from_hex_str(
"55c6aa815a31741bc37f0ffddea73af2397bad640816ef22bfb689efc1b6cc68\
2a73f7e5a657248e3abad500e46d5afc",
)
.unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key_affine_coordinates(&alg, &x, &y).unwrap();
let ec_private =
openssl::ec::EcKey::from_private_components(&alg, &d, &ec_public.public_key())
.unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
fn get_ec512_test_key() -> (PKey<Private>, PKey<Public>) {
let alg = openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::SECP521R1).unwrap();
let x = openssl::bn::BigNum::from_hex_str(
"004365ee31a93b6e69b2c895890aaae14194cd84601bbb59587ad08ab5960522\
7dc7b34288e6471b0f06050763b88b4fb017f279c86030b0069100401e4016a3\
be8a",
)
.unwrap();
let y = openssl::bn::BigNum::from_hex_str(
"00792d772bf93cd965027df2df02d3f99ea1c4ecd18c20738ebae66854fd3afc\
d2ea4e902bcd37a4d2a5c639caee71513acaf7d8f7ffa11042257c5d8c697409\
5713",
)
.unwrap();
let d = openssl::bn::BigNum::from_hex_str(
"007c6fd88271bcd6c5d6bada258691a27700abeff0ad86891a27f93a73f00947\
7c53b4e069db544429ad8220d18813f5f3ab90946ebdf4f41ca929999709f7c4\
89e8",
)
.unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key_affine_coordinates(&alg, &x, &y).unwrap();
let ec_private =
openssl::ec::EcKey::from_private_components(&alg, &d, &ec_public.public_key())
.unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
fn generate_ec256_test_key() -> (PKey<Private>, PKey<Public>) {
let alg =
openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1).unwrap();
let ec_private = openssl::ec::EcKey::generate(&alg).unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key(&alg, ec_private.public_key()).unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
fn generate_ec384_test_key() -> (PKey<Private>, PKey<Public>) {
let alg = openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::SECP384R1).unwrap();
let ec_private = openssl::ec::EcKey::generate(&alg).unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key(&alg, ec_private.public_key()).unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
fn generate_ec512_test_key() -> (PKey<Private>, PKey<Public>) {
let alg = openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::SECP521R1).unwrap();
let ec_private = openssl::ec::EcKey::generate(&alg).unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key(&alg, ec_private.public_key()).unwrap();
(
PKey::from_ec_key(ec_private).unwrap(),
PKey::from_ec_key(ec_public).unwrap(),
)
}
#[test]
fn cose_sign1_ec256_validate() {
let (_, ec_public) = get_ec256_test_key();
let cose_doc = CoseSign1::from_bytes(&[
0xd9, 0x00, 0x12, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x40, 0x6E, 0x6D, 0xF6, 0x54, 0x89, 0xEA, 0x3B, 0x01, 0x88, 0x33, 0xF5, 0xFC, 0x4F, 0x84,
0xF8, 0x1B, 0x4D, 0x5E, 0xFD, 0x5A, 0x09, 0xD5, 0xC6, 0x2F, 0x2E, 0x92, 0x38, 0x5D,
0xCE, 0x31, 0xE2, 0xD1, 0x5A, 0x53, 0xA9, 0xF0, 0x75, 0xE8, 0xFB, 0x39, 0x66, 0x9F, 0xCD, 0x4E, 0xB5, 0x22,
0xC8, 0x5C, 0x92, 0x77, 0x45, 0x2F, 0xA8, 0x57, 0xF5, 0xFE, 0x37, 0x9E, 0xDD, 0xEF,
0x0F, 0xAB, 0x3C, 0xDD,
])
.unwrap();
assert_eq!(
cose_doc.get_payload::<Openssl>(Some(&ec_public)).unwrap(),
TEXT
);
}
#[test]
fn cose_sign1_ec384_validate() {
let (_, ec_public) = get_ec384_test_key();
let cose_doc = CoseSign1::from_bytes(&[
0x84, 0x44, 0xA1, 0x01, 0x38, 0x22, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x60, 0xCD, 0x42, 0xD2, 0x76, 0x32, 0xD5, 0x41, 0x4E, 0x4B, 0x54, 0x5C, 0x95, 0xFD, 0xE6,
0xE3, 0x50, 0x5B, 0x93, 0x58, 0x0F, 0x4B, 0x77, 0x31, 0xD1, 0x4A, 0x86, 0x52, 0x31,
0x75, 0x26, 0x6C, 0xDE, 0xB2, 0x4A, 0xFF, 0x2D, 0xE3, 0x36, 0x4E, 0x9C, 0xEE, 0xE9,
0xF9, 0xF7, 0x95, 0xA0, 0x15, 0x15, 0x5B, 0xC7, 0x12, 0xAA, 0x28, 0x63, 0xE2, 0xAA, 0xF6, 0x07, 0x8A, 0x81, 0x90, 0x93,
0xFD, 0xFC, 0x70, 0x59, 0xA3, 0xF1, 0x46, 0x7F, 0x64, 0xEC, 0x7E, 0x22, 0x1F, 0xD1,
0x63, 0xD8, 0x0B, 0x3B, 0x55, 0x26, 0x25, 0xCF, 0x37, 0x9D, 0x1C, 0xBB, 0x9E, 0x51,
0x38, 0xCC, 0xD0, 0x7A, 0x19, 0x31,
])
.unwrap();
assert_eq!(
cose_doc.get_payload::<Openssl>(Some(&ec_public)).unwrap(),
TEXT
);
}
#[test]
fn cose_sign1_ec512_validate() {
let (_, ec_public) = get_ec512_test_key();
let cose_doc = CoseSign1::from_bytes(&[
0x84, 0x44, 0xA1, 0x01, 0x38, 0x23, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x84, 0x01, 0xE5, 0xAE, 0x6A, 0xE6, 0xE2, 0xE3, 0xC0, 0xB5, 0x1D, 0xD1, 0x62, 0x74, 0x1C,
0xF9, 0x9D, 0xA6, 0x88, 0x19, 0x5C, 0xD9, 0x0E, 0x65, 0xFB, 0xBE, 0xE2, 0x38, 0x83,
0x81, 0x32, 0x3C, 0xAE, 0xC9, 0x1B, 0x3D, 0x0E, 0x3A, 0xC1, 0x4D, 0x0B, 0x8B, 0x29,
0xA8, 0x56, 0x2E, 0xB2, 0x17, 0x65, 0x9F, 0x27, 0xBE, 0xB4, 0x30, 0xA1, 0xD7, 0x4F,
0x42, 0x35, 0x3A, 0x2C, 0x0A, 0xC5, 0x1F, 0xC2, 0x36, 0x48, 0x00, 0x00, 0x89, 0xEA, 0xF7, 0x09, 0x50, 0xF8, 0x45, 0x83, 0xA7, 0xC4, 0x79, 0x2F,
0xAD, 0xC6, 0x96, 0xC3, 0x03, 0x33, 0xF2, 0xDF, 0x19, 0x48, 0x83, 0x93, 0xAB, 0xAE,
0x31, 0x6A, 0x2E, 0x17, 0x1D, 0x58, 0x87, 0x65, 0xC4, 0x36, 0xA2, 0xA2, 0x05, 0xAD,
0x81, 0x51, 0xF3, 0x97, 0x3E, 0xC0, 0xB4, 0xA7, 0xB8, 0x97, 0xE4, 0x90, 0x8C, 0x79,
0x6F, 0x85, 0x24, 0x84, 0xAE, 0x39, 0x26, 0xB3, 0xB8, 0x1B,
])
.unwrap();
assert_eq!(
cose_doc.get_payload::<Openssl>(Some(&ec_public)).unwrap(),
TEXT
);
}
#[test]
fn cose_sign1_ec256_text() {
let (ec_private, ec_public) = generate_ec256_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&cose_doc1.as_bytes(false).unwrap()).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&ec_public)).unwrap()
);
assert!(!cose_doc2.get_unprotected().is_empty(),);
assert_eq!(
cose_doc2.get_unprotected().get(&CborValue::Integer(4)),
Some(&CborValue::Bytes(b"11".to_vec())),
);
}
#[test]
fn cose_sign1_ec256_text_tagged() {
let (ec_private, ec_public) = generate_ec256_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
assert_eq!(tagged_bytes[0], 6 << 5 | 18);
assert_eq!(tagged_bytes[1], 4 << 5 | 4);
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&ec_public)).unwrap()
);
}
#[test]
fn cose_sign1_ec256_text_tagged_serde() {
let (ec_private, ec_public) = generate_ec256_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
assert_eq!(tagged_bytes[0], 6 << 5 | 18);
let cose_doc2: CoseSign1 = serde_cbor::from_slice(&tagged_bytes).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&ec_public)).unwrap()
);
}
#[test]
fn cose_sign1_ec256_text_with_extra_protected() {
let (ec_private, ec_public) = generate_ec256_test_key();
let mut protected = HeaderMap::new();
protected.insert(
CborValue::Integer(1),
(SignatureAlgorithm::ES256 as i8).into(),
);
protected.insert(CborValue::Integer(15), CborValue::Bytes(b"12".to_vec()));
let mut unprotected = HeaderMap::new();
unprotected.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new_with_protected::<Openssl>(
TEXT,
&protected,
&unprotected,
&ec_private,
)
.unwrap();
let cose_doc2 = CoseSign1::from_bytes(&cose_doc1.as_bytes(false).unwrap()).unwrap();
let (protected, payload) = cose_doc2
.get_protected_and_payload::<Openssl>(Some(&ec_public))
.unwrap();
assert_eq!(
protected.get(&CborValue::Integer(1)),
Some(&CborValue::Integer(-7)),
);
assert_eq!(
protected.get(&CborValue::Integer(15)),
Some(&CborValue::Bytes(b"12".to_vec())),
);
assert_eq!(payload, TEXT,);
}
#[test]
fn cose_sign1_ec384_text() {
let (ec_private, ec_public) = generate_ec384_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&cose_doc1.as_bytes(false).unwrap()).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&ec_public)).unwrap()
);
}
#[test]
fn cose_sign1_ec512_text() {
let (ec_private, ec_public) = generate_ec512_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&cose_doc1.as_bytes(false).unwrap()).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(Some(&ec_public)).unwrap(),
TEXT.to_vec()
);
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&ec_public)).unwrap()
);
}
#[test]
fn unknown_curve() {
let alg = openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::SECP256K1).unwrap();
let ec_private = openssl::ec::EcKey::generate(&alg).unwrap();
let ec_private = PKey::from_ec_key(ec_private).unwrap();
let map = HeaderMap::new();
let result = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private);
assert!(result.is_err());
}
#[test]
fn validate_with_wrong_key() {
let (ec_private, ec_public) = generate_ec512_test_key();
let (_, ec_public_other) = generate_ec512_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
assert!(cose_doc1.verify_signature::<Openssl>(&ec_public).unwrap());
assert!(!cose_doc1
.verify_signature::<Openssl>(&ec_public_other)
.unwrap());
}
#[test]
fn validate_with_wrong_key_type() {
let (ec_private, ec_public) = generate_ec512_test_key();
let (_, ec_public_other) = generate_ec384_test_key();
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &ec_private).unwrap();
assert!(cose_doc1.verify_signature::<Openssl>(&ec_public).unwrap());
assert!(!cose_doc1
.verify_signature::<Openssl>(&ec_public_other)
.unwrap());
}
#[test]
fn cose_sign1_ec256_tampered_content() {
let (_, ec_public) = get_ec256_test_key();
let cose_doc = CoseSign1::from_bytes(&[
0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6F, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x40, 0x6E, 0x6D, 0xF6, 0x54, 0x89, 0xEA, 0x3B, 0x01, 0x88, 0x33, 0xF5, 0xFC, 0x4F, 0x84,
0xF8, 0x1B, 0x4D, 0x5E, 0xFD, 0x5A, 0x09, 0xD5, 0xC6, 0x2F, 0x2E, 0x92, 0x38, 0x5D,
0xCE, 0x31, 0xE2, 0xD1, 0x5A, 0x53, 0xA9, 0xF0, 0x75, 0xE8, 0xFB, 0x39, 0x66, 0x9F, 0xCD, 0x4E, 0xB5, 0x22,
0xC8, 0x5C, 0x92, 0x77, 0x45, 0x2F, 0xA8, 0x57, 0xF5, 0xFE, 0x37, 0x9E, 0xDD, 0xEF,
0x0F, 0xAB, 0x3C, 0xDD,
])
.unwrap();
assert!(cose_doc.get_payload::<Openssl>(Some(&ec_public)).is_err());
}
#[test]
fn cose_sign1_ec256_tampered_signature() {
let (_, ec_public) = get_ec256_test_key();
let cose_doc = CoseSign1::from_bytes(&[
0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x40, 0x6E, 0x6D, 0xF6, 0x54, 0x89, 0xEA, 0x3B, 0x01, 0x88, 0x33, 0xF5, 0xFC, 0x4F, 0x84,
0xF8, 0x1B, 0x4D, 0x5E, 0xFD, 0x5B, 0x09, 0xD5, 0xC6, 0x2F, 0x2E, 0x92, 0x38, 0x5D,
0xCE, 0x31, 0xE2, 0xD1, 0x5A, 0x53, 0xA9, 0xF0, 0x75, 0xE8, 0xFB, 0x39, 0x66, 0x9F, 0xCD, 0x4E, 0xB5, 0x22,
0xC8, 0x5C, 0x92, 0x77, 0x45, 0x2F, 0xA8, 0x57, 0xF5, 0xFE, 0x37, 0x9E, 0xDD, 0xEF,
0x0F, 0xAB, 0x3C, 0xDD,
])
.unwrap();
assert!(cose_doc.get_payload::<Openssl>(Some(&ec_public)).is_err());
}
#[test]
fn cose_sign1_ec256_invalid_tag() {
let cose_doc = CoseSign1::from_bytes(&[
0xd3, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x40, 0x6E, 0x6D, 0xF6, 0x54, 0x89, 0xEA, 0x3B, 0x01, 0x88, 0x33, 0xF5, 0xFC, 0x4F, 0x84,
0xF8, 0x1B, 0x4D, 0x5E, 0xFD, 0x5A, 0x09, 0xD5, 0xC6, 0x2F, 0x2E, 0x92, 0x38, 0x5D,
0xCE, 0x31, 0xE2, 0xD1, 0x5A, 0x53, 0xA9, 0xF0, 0x75, 0xE8, 0xFB, 0x39, 0x66, 0x9F, 0xCD, 0x4E, 0xB5, 0x22,
0xC8, 0x5C, 0x92, 0x77, 0x45, 0x2F, 0xA8, 0x57, 0xF5, 0xFE, 0x37, 0x9E, 0xDD, 0xEF,
0x0F, 0xAB, 0x3C, 0xDD,
]);
match cose_doc.unwrap_err() {
CoseError::TagError(Some(19)) => (),
_ => panic!(),
}
}
#[test]
fn cose_sign1_ec256_missing_tag() {
let cose_doc = CoseSign1::from_bytes_tagged(&[
0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, 0x31, 0x58, 0x75, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74,
0x68, 0x20, 0x75, 0x6E, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6C, 0x6C, 0x79, 0x20,
0x61, 0x63, 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x64, 0x2C, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
0x6D, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73,
0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20,
0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20,
0x61, 0x20, 0x77, 0x69, 0x66, 0x65, 0x2E, 0x58, 0x40, 0x6E, 0x6D, 0xF6, 0x54, 0x89, 0xEA, 0x3B, 0x01, 0x88, 0x33, 0xF5, 0xFC, 0x4F, 0x84,
0xF8, 0x1B, 0x4D, 0x5E, 0xFD, 0x5A, 0x09, 0xD5, 0xC6, 0x2F, 0x2E, 0x92, 0x38, 0x5D,
0xCE, 0x31, 0xE2, 0xD1, 0x5A, 0x53, 0xA9, 0xF0, 0x75, 0xE8, 0xFB, 0x39, 0x66, 0x9F, 0xCD, 0x4E, 0xB5, 0x22,
0xC8, 0x5C, 0x92, 0x77, 0x45, 0x2F, 0xA8, 0x57, 0xF5, 0xFE, 0x37, 0x9E, 0xDD, 0xEF,
0x0F, 0xAB, 0x3C, 0xDD,
]);
match cose_doc.unwrap_err() {
CoseError::TagError(None) => (),
_ => panic!(),
}
}
fn rfc_8152_key_kid_11() -> PKey<Public> {
let alg =
openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1).unwrap();
let x = openssl::bn::BigNum::from_hex_str(
"bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff",
)
.unwrap();
let y = openssl::bn::BigNum::from_hex_str(
"20138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e",
)
.unwrap();
let ec_public =
openssl::ec::EcKey::from_public_key_affine_coordinates(&alg, &x, &y).unwrap();
PKey::from_ec_key(ec_public).unwrap()
}
#[test]
fn rfc_8152_c_2_1_sign1_validate() {
let payload = "This is the content.".as_bytes().to_vec();
let signature = "8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4d25a91aef0b0117e2af9a291aa32e14ab834dc56e\
d2a223444547e01f11d3b0916e5a4c345cacb36";
let mut unprotected = HeaderMap::new();
unprotected.insert(4.into(), "11".as_bytes().to_vec().into());
let cose_doc = CoseSign1 {
payload: ByteBuf::from(payload.clone()),
protected: ByteBuf::from(hex::decode("a10126").unwrap()),
unprotected,
signature: ByteBuf::from(hex::decode(signature).unwrap()),
};
let ec_public = rfc_8152_key_kid_11();
assert_eq!(
cose_doc.get_payload::<Openssl>(Some(&ec_public)).unwrap(),
payload
);
}
}
#[cfg(feature = "key_tpm")]
mod tpm {
use super::TEXT;
use crate::crypto::tpm::TpmKey;
use crate::crypto::Openssl;
use crate::sign::*;
use tss_esapi::{
attributes::SessionAttributesBuilder,
constants::SessionType,
interface_types::{
algorithm::EccSchemeAlgorithm, algorithm::HashingAlgorithm, ecc::EccCurve,
resource_handles::Hierarchy,
},
structures::{EccScheme, SymmetricDefinition},
utils::create_unrestricted_signing_ecc_public,
Context, Tcti,
};
#[test]
fn cose_sign_tpm() {
let mut tpm_context =
Context::new(Tcti::from_environment_variable().expect("Failed to get TCTI"))
.expect("Failed to create context");
let tpm_session = tpm_context
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Error creating TPM session")
.expect("Expected AuthSession");
let (session_attrs, session_attrs_mask) = SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
tpm_context
.tr_sess_set_attributes(tpm_session, session_attrs, session_attrs_mask)
.expect("Error setting session attributes");
tpm_context.set_sessions((Some(tpm_session), None, None));
let prim_key = tpm_context
.create_primary(
Hierarchy::Owner,
create_unrestricted_signing_ecc_public(
EccScheme::create(
EccSchemeAlgorithm::EcDsa,
Some(HashingAlgorithm::Sha256),
None,
)
.expect("Error creating ECC scheme"),
EccCurve::NistP256,
)
.expect("Error creating TPM2B_PUBLIC"),
None,
None,
None,
None,
)
.expect("Unable to create primary key")
.key_handle;
let mut tpm_key = TpmKey::new(tpm_context, prim_key).expect("Error creating TpmKey");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &mut tpm_key).unwrap();
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
assert_eq!(tagged_bytes[0], 6 << 5 | 18);
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2
.get_payload::<Openssl>(Some(&mut tpm_key))
.unwrap()
);
}
#[test]
fn cose_sign_tpm_invalid_signature() {
let mut tpm_context =
Context::new(Tcti::from_environment_variable().expect("Failed to get TCTI"))
.expect("Failed to create context");
let tpm_session = tpm_context
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Error creating TPM session")
.expect("Expected AuthSession");
let (session_attrs, session_attrs_mask) = SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
tpm_context
.tr_sess_set_attributes(tpm_session, session_attrs, session_attrs_mask)
.expect("Error setting session attributes");
tpm_context.set_sessions((Some(tpm_session), None, None));
let prim_key = tpm_context
.create_primary(
Hierarchy::Owner,
create_unrestricted_signing_ecc_public(
EccScheme::create(
EccSchemeAlgorithm::EcDsa,
Some(HashingAlgorithm::Sha256),
None,
)
.expect("Error creating ECC scheme"),
EccCurve::NistP256,
)
.expect("Error creating TPM2B_PUBLIC"),
None,
None,
None,
None,
)
.expect("Unable to create primary key")
.key_handle;
let mut tpm_key = TpmKey::new(tpm_context, prim_key).expect("Error creating TpmKey");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let mut cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &mut tpm_key).unwrap();
cose_doc1.signature[0] = 0;
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
match cose_doc2.get_payload::<Openssl>(Some(&mut tpm_key)) {
Ok(_) => panic!("Did not fail"),
Err(CoseError::UnverifiedSignature) => {}
Err(e) => {
panic!("Unexpected error: {:?}", e)
}
}
}
}
#[cfg(feature = "key_kms")]
mod kms {
use std::str::FromStr;
use super::TEXT;
use crate::{
crypto::{kms::KmsKey, Openssl, SignatureAlgorithm},
sign::*,
};
use aws_config::BehaviorVersion;
use std::env;
#[tokio::test]
async fn cose_sign_kms() {
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let kms_client = aws_sdk_kms::Client::new(&config);
tokio::task::spawn_blocking(|| {
let key_id =
env::var("AWS_KMS_TEST_KEY_ARN").expect("Please set AWS_KMS_TEST_KEY_ARN");
let sig_alg = env::var("TEST_KEY_SIG_ALG").expect("Please set TEST_KEY_SIG_ALG");
let sig_alg =
SignatureAlgorithm::from_str(&sig_alg).expect("Invalid TEST_KEY_SIG_ALG");
let kms_key =
KmsKey::new(kms_client, key_id, sig_alg).expect("Error building kms_key");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &kms_key).unwrap();
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
assert_eq!(tagged_bytes[0], 6 << 5 | 18);
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&kms_key)).unwrap()
);
})
.await
.unwrap();
}
#[tokio::test]
async fn cose_sign_kms_invalid_signature() {
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let kms_client = aws_sdk_kms::Client::new(&config);
tokio::task::spawn_blocking(|| {
let key_id =
env::var("AWS_KMS_TEST_KEY_ARN").expect("Please set AWS_KMS_TEST_KEY_ARN");
let sig_alg = env::var("TEST_KEY_SIG_ALG").expect("Please set TEST_KEY_SIG_ALG");
let sig_alg =
SignatureAlgorithm::from_str(&sig_alg).expect("Invalid TEST_KEY_SIG_ALG");
let kms_key =
KmsKey::new(kms_client, key_id, sig_alg).expect("Error building kms_key");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let mut cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &kms_key).unwrap();
cose_doc1.signature[0] ^= 0xff;
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
match cose_doc2.get_payload::<Openssl>(Some(&kms_key)) {
Ok(_) => panic!("Did not fail"),
Err(CoseError::UnverifiedSignature) => {}
Err(e) => {
panic!("Unexpected error: {:?}", e)
}
}
})
.await
.unwrap();
}
#[cfg(feature = "key_openssl_pkey")]
#[tokio::test]
async fn cose_sign_kms_public_key() {
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let kms_client = aws_sdk_kms::Client::new(&config);
let key_id = env::var("AWS_KMS_TEST_KEY_ARN").expect("Please set AWS_KMS_TEST_KEY_ARN");
tokio::task::spawn_blocking(|| {
let kms_key = KmsKey::new_with_public_key(kms_client, key_id, None)
.expect("Error building kms_key");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &kms_key).unwrap();
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
assert_eq!(tagged_bytes[0], 6 << 5 | 18);
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
assert_eq!(
cose_doc1.get_payload::<Openssl>(None).unwrap(),
cose_doc2.get_payload::<Openssl>(Some(&kms_key)).unwrap()
);
})
.await
.unwrap();
}
#[cfg(feature = "key_openssl_pkey")]
#[tokio::test]
async fn cose_sign_kms_public_key_invalid_signature() {
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let kms_client = aws_sdk_kms::Client::new(&config);
let key_id = env::var("AWS_KMS_TEST_KEY_ARN").expect("Please set AWS_KMS_TEST_KEY_ARN");
tokio::task::spawn_blocking(|| {
let kms_key = KmsKey::new_with_public_key(kms_client, key_id, None)
.expect("Error building kms_key");
let mut map = HeaderMap::new();
map.insert(CborValue::Integer(4), CborValue::Bytes(b"11".to_vec()));
let mut cose_doc1 = CoseSign1::new::<Openssl>(TEXT, &map, &kms_key).unwrap();
cose_doc1.signature[0] ^= 0xff;
let tagged_bytes = cose_doc1.as_bytes(true).unwrap();
let cose_doc2 = CoseSign1::from_bytes(&tagged_bytes).unwrap();
match cose_doc2.get_payload::<Openssl>(Some(&kms_key)) {
Ok(_) => panic!("Did not fail"),
Err(CoseError::UnverifiedSignature) => {}
Err(e) => {
panic!("Unexpected error: {:?}", e)
}
}
})
.await
.unwrap();
}
}
}