#![allow(missing_docs)]
use wolfcose::{
from_slice, to_vec, Algorithm, ByteStr, CborSerialize, CborSerializer, CborValue,
CoseEncrypt0Message, CoseEncryptMessage, CoseMac0Message, CoseMacMessage, CoseMessageKind,
CoseSign1Message, CoseSignMessage, Error, HeaderLabel, HeaderMap, HeaderValue, ProtectedHeader,
};
#[test]
fn parses_all_cose_message_envelope_shapes() {
let sign1 = envelope(CoseMessageKind::Sign1, false, 0, true);
let sign1 = CoseSign1Message::parse(&sign1).unwrap();
assert!(sign1.payload_attached());
assert_eq!(sign1.raw().len(), sign1.raw().len());
let sign = envelope(CoseMessageKind::Sign, true, 2, true);
let sign = CoseSignMessage::parse(&sign).unwrap();
assert!(!sign.payload_attached());
assert_eq!(sign.signer_count(), 2);
assert_eq!(sign.protected().algorithm(), Some(Algorithm::HMAC256));
let encrypt0 = envelope(CoseMessageKind::Encrypt0, true, 0, true);
assert_eq!(
CoseEncrypt0Message::parse(&encrypt0),
Err(Error::CborMalformed)
);
let encrypt = envelope(CoseMessageKind::Encrypt, false, 2, true);
let encrypt = CoseEncryptMessage::parse(&encrypt).unwrap();
assert!(encrypt.ciphertext_attached());
assert_eq!(encrypt.recipient_count(), 2);
let mac0 = envelope(CoseMessageKind::Mac0, false, 0, false);
let mac0 = CoseMac0Message::parse(&mac0).unwrap();
assert!(mac0.payload_attached());
let mac = envelope(CoseMessageKind::Mac, true, 2, false);
let mac = CoseMacMessage::parse(&mac).unwrap();
assert!(!mac.payload_attached());
assert_eq!(mac.recipient_count(), 2);
let bad_tag = envelope(CoseMessageKind::Sign1, false, 0, true);
assert_eq!(CoseMac0Message::parse(&bad_tag), Err(Error::CoseBadTag));
let mut trailing = envelope(CoseMessageKind::Sign1, false, 0, true);
trailing.push(0);
assert_eq!(
CoseSign1Message::parse(&trailing),
Err(Error::CborMalformed)
);
}
#[test]
fn typed_headers_preserve_known_and_unknown_values() {
assert_eq!(HeaderLabel::from_i64(1), HeaderLabel::Algorithm);
assert_eq!(HeaderLabel::from_i64(2), HeaderLabel::Critical);
assert_eq!(HeaderLabel::from_i64(3), HeaderLabel::ContentType);
assert_eq!(HeaderLabel::from_i64(4), HeaderLabel::Kid);
assert_eq!(HeaderLabel::from_i64(5), HeaderLabel::Iv);
assert_eq!(HeaderLabel::from_i64(6), HeaderLabel::PartialIv);
assert_eq!(HeaderLabel::from_i64(-1), HeaderLabel::EphemeralKey);
assert_eq!(HeaderLabel::Text("x".to_owned()).as_i64(), None);
let mut headers = HeaderMap::new();
assert!(headers.is_empty());
headers.insert(
HeaderLabel::Algorithm,
HeaderValue::Int(Algorithm::HMAC256.id() as i64),
);
headers.insert(HeaderLabel::Kid, HeaderValue::Bytes(b"kid".to_vec()));
headers.insert(
HeaderLabel::Critical,
HeaderValue::Array(vec![CborValue::Unsigned(1)]),
);
headers.insert(
HeaderLabel::Text("raw".to_owned()),
HeaderValue::Raw(CborValue::Null),
);
headers.insert(
HeaderLabel::ContentType,
HeaderValue::Text("text/plain".to_owned()),
);
headers.insert(HeaderLabel::Iv, HeaderValue::Bytes(vec![1, 2, 3]));
headers.insert(HeaderLabel::PartialIv, HeaderValue::Bytes(vec![4, 5]));
headers.insert(
HeaderLabel::EphemeralKey,
HeaderValue::Raw(CborValue::Map(vec![])),
);
headers.insert(HeaderLabel::Int(99), HeaderValue::Int(7));
headers.insert(HeaderLabel::Kid, HeaderValue::Bytes(b"replaced".to_vec()));
assert_eq!(headers.len(), 9);
assert_eq!(headers.kid(), Some(&b"replaced"[..]));
assert_eq!(headers.algorithm(), Some(Algorithm::HMAC256));
assert_eq!(headers.iter().count(), 9);
let decoded: HeaderMap = from_slice(&to_vec(&headers).unwrap()).unwrap();
assert_eq!(decoded.algorithm(), Some(Algorithm::HMAC256));
assert_eq!(decoded.kid(), Some(&b"replaced"[..]));
assert_eq!(ProtectedHeader::from_bstr(&[]).unwrap().0.len(), 0);
let err = from_slice::<HeaderLabel>(&to_vec(&()).unwrap()).unwrap_err();
assert_eq!(err, Error::CborType);
}
fn envelope(
kind: CoseMessageKind,
detached_body: bool,
trailing_count: usize,
include_tag: bool,
) -> Vec<u8> {
let mut protected = HeaderMap::new();
protected.insert(
HeaderLabel::Algorithm,
HeaderValue::Algorithm(Algorithm::HMAC256),
);
let protected = to_vec(&protected).unwrap();
let mut unprotected = HeaderMap::new();
unprotected.insert(HeaderLabel::Kid, HeaderValue::Bytes(b"kid".to_vec()));
let mut out = [0; 512];
let mut serializer = CborSerializer::new(&mut out);
if include_tag {
serializer.tag(tag_for(kind)).unwrap();
}
serializer.array(array_len_for(kind)).unwrap();
ByteStr(&protected).serialize(&mut serializer).unwrap();
unprotected.serialize(&mut serializer).unwrap();
if detached_body {
Option::<u8>::None.serialize(&mut serializer).unwrap();
} else {
ByteStr(b"body").serialize(&mut serializer).unwrap();
}
match kind {
CoseMessageKind::Sign1 => ByteStr(b"signature").serialize(&mut serializer).unwrap(),
CoseMessageKind::Encrypt0 => {}
CoseMessageKind::Mac0 => ByteStr(b"tag").serialize(&mut serializer).unwrap(),
CoseMessageKind::Sign | CoseMessageKind::Encrypt => {
serializer.array(trailing_count).unwrap();
for _ in 0..trailing_count {
serializer.array(0).unwrap();
}
}
CoseMessageKind::Mac => {
ByteStr(b"tag").serialize(&mut serializer).unwrap();
serializer.array(trailing_count).unwrap();
for _ in 0..trailing_count {
serializer.array(0).unwrap();
}
}
}
serializer.as_written().to_vec()
}
fn tag_for(kind: CoseMessageKind) -> u64 {
match kind {
CoseMessageKind::Sign1 => wolfcose::raw::WOLFCOSE_TAG_SIGN1 as u64,
CoseMessageKind::Sign => wolfcose::raw::WOLFCOSE_TAG_SIGN as u64,
CoseMessageKind::Encrypt0 => wolfcose::raw::WOLFCOSE_TAG_ENCRYPT0 as u64,
CoseMessageKind::Encrypt => wolfcose::raw::WOLFCOSE_TAG_ENCRYPT as u64,
CoseMessageKind::Mac0 => wolfcose::raw::WOLFCOSE_TAG_MAC0 as u64,
CoseMessageKind::Mac => wolfcose::raw::WOLFCOSE_TAG_MAC as u64,
}
}
fn array_len_for(kind: CoseMessageKind) -> usize {
match kind {
CoseMessageKind::Encrypt0 => 3,
CoseMessageKind::Mac => 5,
_ => 4,
}
}