use crate::{
Algorithm, ByteBuf, CborDeserialize, CborDeserializer, CborSerialize, CborValue, Error, Result,
};
use alloc::{string::String, vec::Vec};
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum HeaderLabel {
Algorithm,
Critical,
ContentType,
Kid,
Iv,
PartialIv,
EphemeralKey,
Int(i64),
Text(String),
}
impl HeaderLabel {
pub fn from_i64(label: i64) -> Self {
match label {
1 => Self::Algorithm,
2 => Self::Critical,
3 => Self::ContentType,
4 => Self::Kid,
5 => Self::Iv,
6 => Self::PartialIv,
-1 => Self::EphemeralKey,
other => Self::Int(other),
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Self::Algorithm => Some(1),
Self::Critical => Some(2),
Self::ContentType => Some(3),
Self::Kid => Some(4),
Self::Iv => Some(5),
Self::PartialIv => Some(6),
Self::EphemeralKey => Some(-1),
Self::Int(value) => Some(*value),
Self::Text(_) => None,
}
}
}
impl CborSerialize for HeaderLabel {
fn serialize(&self, serializer: &mut crate::CborSerializer<'_>) -> Result<()> {
match self {
Self::Text(value) => value.serialize(serializer),
_ => self
.as_i64()
.ok_or(Error::InvalidArgument)?
.serialize(serializer),
}
}
}
impl<'de> CborDeserialize<'de> for HeaderLabel {
fn deserialize(deserializer: &mut CborDeserializer<'de>) -> Result<Self> {
match deserializer.decoder_mut().peek_type() {
Some(crate::CborMajorType::TEXT) => Ok(Self::Text(String::deserialize(deserializer)?)),
Some(crate::CborMajorType::UINT) | Some(crate::CborMajorType::NEGATIVE_INT) => {
Ok(Self::from_i64(i64::deserialize(deserializer)?))
}
_ => Err(Error::CborType),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum HeaderValue {
Algorithm(Algorithm),
Int(i64),
Text(String),
Bytes(Vec<u8>),
Array(Vec<CborValue>),
Raw(CborValue),
}
impl CborSerialize for HeaderValue {
fn serialize(&self, serializer: &mut crate::CborSerializer<'_>) -> Result<()> {
match self {
Self::Algorithm(value) => value.id().serialize(serializer),
Self::Int(value) => value.serialize(serializer),
Self::Text(value) => value.serialize(serializer),
Self::Bytes(value) => ByteBuf(value.clone()).serialize(serializer),
Self::Array(value) => value.serialize(serializer),
Self::Raw(value) => value.serialize(serializer),
}
}
}
impl<'de> CborDeserialize<'de> for HeaderValue {
fn deserialize(deserializer: &mut CborDeserializer<'de>) -> Result<Self> {
let value = CborValue::deserialize(deserializer)?;
Ok(match value {
CborValue::Integer(value) => Self::Int(value),
CborValue::Unsigned(value) => {
let value = i64::try_from(value).map_err(|_| Error::CborOverflow)?;
Self::Int(value)
}
CborValue::Text(value) => Self::Text(value),
CborValue::Bytes(value) => Self::Bytes(value),
CborValue::Array(value) => Self::Array(value),
value => Self::Raw(value),
})
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct HeaderMap {
entries: Vec<(HeaderLabel, HeaderValue)>,
}
impl HeaderMap {
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn insert(&mut self, label: HeaderLabel, value: HeaderValue) {
if let Some((_, existing)) = self.entries.iter_mut().find(|(entry, _)| *entry == label) {
*existing = value;
} else {
self.entries.push((label, value));
}
}
pub fn get(&self, label: &HeaderLabel) -> Option<&HeaderValue> {
self.entries
.iter()
.find_map(|(entry, value)| (entry == label).then_some(value))
}
pub fn iter(&self) -> impl Iterator<Item = &(HeaderLabel, HeaderValue)> {
self.entries.iter()
}
pub fn algorithm(&self) -> Option<Algorithm> {
match self.get(&HeaderLabel::Algorithm) {
Some(HeaderValue::Algorithm(value)) => Some(*value),
Some(HeaderValue::Int(value)) => i32::try_from(*value).ok().map(Algorithm::from_id),
_ => None,
}
}
pub fn kid(&self) -> Option<&[u8]> {
match self.get(&HeaderLabel::Kid) {
Some(HeaderValue::Bytes(value)) => Some(value),
_ => None,
}
}
}
impl CborSerialize for HeaderMap {
fn serialize(&self, serializer: &mut crate::CborSerializer<'_>) -> Result<()> {
serializer.map(self.entries.len())?;
for (label, value) in &self.entries {
label.serialize(serializer)?;
value.serialize(serializer)?;
}
Ok(())
}
}
impl<'de> CborDeserialize<'de> for HeaderMap {
fn deserialize(deserializer: &mut CborDeserializer<'de>) -> Result<Self> {
let len = deserializer.map()?;
let mut map = Self::new();
for _ in 0..len {
let label = HeaderLabel::deserialize(deserializer)?;
let mut value = HeaderValue::deserialize(deserializer)?;
if label == HeaderLabel::Algorithm {
if let HeaderValue::Int(id) = value {
value = HeaderValue::Algorithm(Algorithm::from_id(
i32::try_from(id).map_err(|_| Error::CborOverflow)?,
));
}
}
map.insert(label, value);
}
Ok(map)
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ProtectedHeader(pub HeaderMap);
#[derive(Clone, Debug, Default, PartialEq)]
pub struct UnprotectedHeader(pub HeaderMap);
impl ProtectedHeader {
pub fn from_bstr(input: &[u8]) -> Result<Self> {
if input.is_empty() {
return Ok(Self(HeaderMap::new()));
}
crate::from_slice(input).map(Self)
}
}