use crate::common::{BstrHeaderMap, HeaderMap, MAX_SUPPORTED_ACCESSTOKEN_LEN};
use crate::cose_recipient::IterCoseRecipient;
use crate::errors::{CoseError, ErrorImpl};
use crate::hmac::verify_mac;
use minicbor::{Decode, Encode};
#[allow(dead_code)]
const MAX_CEK_KEY_LEN: usize = 64;
#[derive(Debug, Encode, Decode)]
#[cbor(array)]
pub struct CoseMac0<'a> {
#[b(0)]
protected: BstrHeaderMap<'a>,
#[b(1)]
unprotected: HeaderMap<'a>,
#[cbor(b(2), with = "minicbor::bytes")]
payload: Option<&'a [u8]>,
#[cbor(b(3), with = "minicbor::bytes")]
tag: &'a [u8],
}
#[allow(dead_code)]
#[derive(minicbor::Encode)]
pub(crate) struct MacStructure<'a> {
#[n(0)]
context: &'static str, #[cbor(b(1), with = "minicbor::bytes")]
body_protected: &'a [u8],
#[cbor(b(2), with = "minicbor::bytes")]
external_aad: &'a [u8],
#[cbor(b(3), with = "minicbor::bytes")]
payload: &'a [u8],
}
impl CoseMac0<'_> {
#[cfg(feature = "hmac")]
pub fn suit_verify_mac0(
&self,
payload_buf: Option<&[u8]>,
keys: &[u8],
) -> Result<(), CoseError> {
let headers = self.unprotected.updated_with(&self.protected.get()?);
let payload = match self.payload {
Some(p) => p,
None => payload_buf.ok_or(ErrorImpl::MissingPayload)?,
};
let aad = MacStructure {
context: "MAC0",
body_protected: self.protected.inner_bytes()?,
external_aad: &[],
payload,
};
let mut to_be_maced = heapless::Vec::<u8, MAX_SUPPORTED_ACCESSTOKEN_LEN>::new();
minicbor::encode(aad, minicbor_adapters::WriteToHeapless(&mut to_be_maced))?;
verify_mac::verify_cose_mac(keys, headers, &to_be_maced, self.tag)
}
}
#[derive(Debug, Encode, Decode)]
#[cbor(array)]
#[allow(dead_code)]
pub struct CoseMac<'a> {
#[b(0)]
protected: BstrHeaderMap<'a>,
#[b(1)]
unprotected: HeaderMap<'a>,
#[cbor(b(2), with = "minicbor::bytes")]
payload: Option<&'a [u8]>,
#[cbor(b(3), with = "minicbor::bytes")]
tag: &'a [u8],
#[n(4)]
pub recipients: IterCoseRecipient<'a>, }
#[cfg(feature = "hmac")]
impl CoseMac<'_> {
pub fn suit_verify_mac(
&self,
payload_buf: Option<&[u8]>,
keys: &[u8],
) -> Result<(), CoseError> {
let payload = match self.payload {
Some(p) => p,
None => payload_buf.ok_or(ErrorImpl::MissingPayload)?,
};
let aad = MacStructure {
context: "MAC",
body_protected: self.protected.inner_bytes()?,
external_aad: &[],
payload,
};
let mut to_be_maced = heapless::Vec::<u8, MAX_SUPPORTED_ACCESSTOKEN_LEN>::new();
minicbor::encode(aad, minicbor_adapters::WriteToHeapless(&mut to_be_maced))?;
let mut cek: heapless::Vec<u8, MAX_CEK_KEY_LEN> = heapless::Vec::new();
let mut saw_unsupported = false;
for cr in self.recipients.get()?.filter_map(Result::ok) {
match cr.decrypt_process(keys, &mut cek) {
Ok(()) => {
return verify_mac::verify_mac(&cek, &to_be_maced, self.tag);
}
Err(e) => {
if matches!(e.source, ErrorImpl::UnexpectedMacAlg) {
saw_unsupported = true;
continue;
}
}
}
}
if saw_unsupported {
Err(ErrorImpl::UnexpectedMacAlg.into())
} else {
Err(ErrorImpl::InconsistentDetails.into())
}
}
}