use crate::{
ByteBuf, CborDeserialize, CborDeserializer, CborMajorType, CborValue, Error, HeaderMap,
ProtectedHeader, Result, UnprotectedHeader,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CoseMessageKind {
Sign1,
Sign,
Encrypt0,
Encrypt,
Mac0,
Mac,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseSign1Message<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
payload_attached: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseSignMessage<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
payload_attached: bool,
signer_count: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseEncrypt0Message<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
ciphertext_attached: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseEncryptMessage<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
ciphertext_attached: bool,
recipient_count: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseMac0Message<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
payload_attached: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CoseMacMessage<'a> {
raw: &'a [u8],
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
payload_attached: bool,
recipient_count: usize,
}
macro_rules! common_methods {
($ty:ty, $attached:ident, $attached_name:ident) => {
impl<'a> $ty {
pub fn raw(&self) -> &'a [u8] {
self.raw
}
pub fn protected(&self) -> &HeaderMap {
&self.protected.0
}
pub fn unprotected(&self) -> &HeaderMap {
&self.unprotected.0
}
pub fn $attached_name(&self) -> bool {
self.$attached
}
}
};
}
common_methods!(CoseSign1Message<'a>, payload_attached, payload_attached);
common_methods!(CoseSignMessage<'a>, payload_attached, payload_attached);
common_methods!(
CoseEncrypt0Message<'a>,
ciphertext_attached,
ciphertext_attached
);
common_methods!(
CoseEncryptMessage<'a>,
ciphertext_attached,
ciphertext_attached
);
common_methods!(CoseMac0Message<'a>, payload_attached, payload_attached);
common_methods!(CoseMacMessage<'a>, payload_attached, payload_attached);
impl<'a> CoseSign1Message<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Sign1, 4)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
payload_attached: parsed.body_attached,
})
}
}
impl<'a> CoseSignMessage<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Sign, 4)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
payload_attached: parsed.body_attached,
signer_count: parsed.trailing_count,
})
}
pub fn signer_count(&self) -> usize {
self.signer_count
}
}
impl<'a> CoseEncrypt0Message<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Encrypt0, 3)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
ciphertext_attached: parsed.body_attached,
})
}
}
impl<'a> CoseEncryptMessage<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Encrypt, 4)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
ciphertext_attached: parsed.body_attached,
recipient_count: parsed.trailing_count,
})
}
pub fn recipient_count(&self) -> usize {
self.recipient_count
}
}
impl<'a> CoseMac0Message<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Mac0, 4)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
payload_attached: parsed.body_attached,
})
}
}
impl<'a> CoseMacMessage<'a> {
pub fn parse(input: &'a [u8]) -> Result<Self> {
let parsed = parse_envelope(input, CoseMessageKind::Mac, 5)?;
Ok(Self {
raw: input,
protected: parsed.protected,
unprotected: parsed.unprotected,
payload_attached: parsed.body_attached,
recipient_count: parsed.trailing_count,
})
}
pub fn recipient_count(&self) -> usize {
self.recipient_count
}
}
struct ParsedEnvelope {
protected: ProtectedHeader,
unprotected: UnprotectedHeader,
body_attached: bool,
trailing_count: usize,
}
fn parse_envelope(input: &[u8], kind: CoseMessageKind, array_len: usize) -> Result<ParsedEnvelope> {
let mut deserializer = CborDeserializer::new(input);
consume_optional_expected_tag(&mut deserializer, kind)?;
let len = deserializer.array()?;
if len != array_len {
return Err(Error::CborMalformed);
}
let protected =
ProtectedHeader::from_bstr(ByteBuf::deserialize(&mut deserializer)?.0.as_slice())?;
let unprotected = UnprotectedHeader(HeaderMap::deserialize(&mut deserializer)?);
let body_attached = !consume_null_or_item(&mut deserializer)?;
let trailing_count = match kind {
CoseMessageKind::Sign1 | CoseMessageKind::Encrypt0 | CoseMessageKind::Mac0 => {
deserializer.decoder_mut().skip()?;
0
}
CoseMessageKind::Sign | CoseMessageKind::Encrypt => {
let count = deserializer.array()?;
for _ in 0..count {
deserializer.decoder_mut().skip()?;
}
count
}
CoseMessageKind::Mac => {
deserializer.decoder_mut().skip()?;
let count = deserializer.array()?;
for _ in 0..count {
deserializer.decoder_mut().skip()?;
}
count
}
};
if !deserializer.is_finished() {
return Err(Error::CborMalformed);
}
Ok(ParsedEnvelope {
protected,
unprotected,
body_attached,
trailing_count,
})
}
fn consume_optional_expected_tag(
deserializer: &mut CborDeserializer<'_>,
kind: CoseMessageKind,
) -> Result<()> {
if deserializer.decoder_mut().peek_type() != Some(CborMajorType::TAG) {
return Ok(());
}
let tag = deserializer.tag()?;
let expected = match kind {
CoseMessageKind::Sign1 => crate::raw::WOLFCOSE_TAG_SIGN1 as u64,
CoseMessageKind::Sign => crate::raw::WOLFCOSE_TAG_SIGN as u64,
CoseMessageKind::Encrypt0 => crate::raw::WOLFCOSE_TAG_ENCRYPT0 as u64,
CoseMessageKind::Encrypt => crate::raw::WOLFCOSE_TAG_ENCRYPT as u64,
CoseMessageKind::Mac0 => crate::raw::WOLFCOSE_TAG_MAC0 as u64,
CoseMessageKind::Mac => crate::raw::WOLFCOSE_TAG_MAC as u64,
};
if tag == expected {
Ok(())
} else {
Err(Error::CoseBadTag)
}
}
fn consume_null_or_item(deserializer: &mut CborDeserializer<'_>) -> Result<bool> {
if deserializer.decoder_mut().peek_initial_byte() == Some(crate::raw::WOLFCOSE_CBOR_NULL as u8)
{
deserializer.null()?;
Ok(true)
} else {
CborValue::deserialize(deserializer)?;
Ok(false)
}
}