use core::fmt::{Debug, Display, Formatter};
use core::ops::Deref;
use coset::{CoseEncrypt0, CoseKey};
use strum_macros::IntoStaticStr;
#[cfg(not(feature = "std"))]
use {alloc::boxed::Box, alloc::format, alloc::vec, alloc::vec::Vec};
#[cfg(test)]
mod tests;
pub type ByteString = Vec<u8>;
pub(crate) type KeyId = ByteString;
pub(crate) struct CborMapValue<T>(pub(crate) T)
where
i32: Into<T>,
T: Into<i32> + Copy;
#[derive(Debug, PartialEq, Clone, IntoStaticStr)]
#[allow(clippy::large_enum_variant)] pub enum ProofOfPossessionKey {
PlainCoseKey(CoseKey),
EncryptedCoseKey(CoseEncrypt0),
KeyId(KeyId),
}
impl ProofOfPossessionKey {
#[must_use]
pub fn key_id(&self) -> &KeyId {
match self {
ProofOfPossessionKey::PlainCoseKey(k) => &k.key_id,
ProofOfPossessionKey::KeyId(k) => k,
ProofOfPossessionKey::EncryptedCoseKey(k) => {
if k.protected.header.key_id.is_empty() {
&k.unprotected.key_id
} else {
&k.protected.header.key_id
}
}
}
}
}
impl<T> Deref for CborMapValue<T>
where
T: From<i32> + Into<i32> + Copy,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> Display for CborMapValue<T>
where
i32: Into<T>,
T: Into<i32> + Copy + Display,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
mod conversion {
use ciborium::value::Value;
use coset::{AsCborValue, CoseEncrypt0, CoseKey};
use erased_serde::Serialize as ErasedSerialize;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::common::cbor_map::ToCborMap;
use crate::error::{TryFromCborMapError, WrongSourceTypeError};
use super::*;
impl<T> Serialize for CborMapValue<T>
where
T: From<i32> + Into<i32> + Copy,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let cbor_value: i32 = self.0.into();
Value::from(cbor_value).serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for CborMapValue<T>
where
T: From<i32> + Into<i32> + Copy,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if let Ok(Value::Integer(i)) = Value::deserialize(deserializer) {
Ok(CborMapValue(
i32::try_from(i)
.map_err(|_| D::Error::custom("CBOR map key too high for i32"))?
.into(),
))
} else {
Err(D::Error::custom("CBOR map value must be an Integer"))
}
}
}
impl ToCborMap for ProofOfPossessionKey {
fn to_cbor_map(&self) -> Vec<(i128, Option<Box<dyn ErasedSerialize + '_>>)> {
match self {
Self::PlainCoseKey(key) => {
let x: i128 = 1;
vec![(
x,
Some(Box::new(key.clone().to_cbor_value().expect("Invalid key"))),
)]
}
Self::EncryptedCoseKey(enc) => {
let x: i128 = 2;
vec![(
x,
Some(Box::new(
(*enc).clone().to_cbor_value().expect("Invalid key"),
)),
)]
}
Self::KeyId(kid) => {
let x: i128 = 3;
vec![(x, Some(Box::new(Value::Bytes(kid.clone()))))]
}
}
}
fn try_from_cbor_map(map: Vec<(i128, Value)>) -> Result<Self, TryFromCborMapError>
where
Self: Sized + ToCborMap,
{
if map.len() != 1 {
Err(TryFromCborMapError::from_message(
"given CBOR map must contain exactly one element",
))
} else if let Some(entry) = map.into_iter().next() {
match entry {
(1, x) => CoseKey::from_cbor_value(x)
.map(ProofOfPossessionKey::PlainCoseKey)
.map_err(|x| {
TryFromCborMapError::from_message(format!(
"couldn't create CoseKey from CBOR value: {x}"
))
}),
(2, x) => CoseEncrypt0::from_cbor_value(x)
.map(ProofOfPossessionKey::EncryptedCoseKey)
.map_err(|x| {
TryFromCborMapError::from_message(format!(
"couldn't create CoseEncrypt0 from CBOR value: {x}"
))
}),
(3, Value::Bytes(x)) => Ok(ProofOfPossessionKey::KeyId(x)),
(x, _) => Err(TryFromCborMapError::unknown_field(u8::try_from(x)?)),
}
} else {
unreachable!(
"we have previously verified that map.len() == 1, \
so map.into_iter().next() must return a next element"
)
}
}
}
impl From<CoseKey> for ProofOfPossessionKey {
fn from(key: CoseKey) -> Self {
ProofOfPossessionKey::PlainCoseKey(key)
}
}
impl From<ByteString> for ProofOfPossessionKey {
fn from(kid: ByteString) -> Self {
ProofOfPossessionKey::KeyId(kid)
}
}
impl From<CoseEncrypt0> for ProofOfPossessionKey {
fn from(enc: CoseEncrypt0) -> Self {
ProofOfPossessionKey::EncryptedCoseKey(enc)
}
}
impl TryFrom<ProofOfPossessionKey> for CoseKey {
type Error = WrongSourceTypeError<ProofOfPossessionKey>;
fn try_from(
value: ProofOfPossessionKey,
) -> Result<Self, WrongSourceTypeError<ProofOfPossessionKey>> {
if let ProofOfPossessionKey::PlainCoseKey(key) = value {
Ok(key)
} else {
Err(WrongSourceTypeError::new("PlainCoseKey", value.into()))
}
}
}
impl TryFrom<ProofOfPossessionKey> for CoseEncrypt0 {
type Error = WrongSourceTypeError<ProofOfPossessionKey>;
fn try_from(
value: ProofOfPossessionKey,
) -> Result<Self, WrongSourceTypeError<ProofOfPossessionKey>> {
if let ProofOfPossessionKey::EncryptedCoseKey(key) = value {
Ok(key)
} else {
Err(WrongSourceTypeError::new("EncryptedCoseKey", value.into()))
}
}
}
impl TryFrom<ProofOfPossessionKey> for KeyId {
type Error = WrongSourceTypeError<ProofOfPossessionKey>;
fn try_from(
value: ProofOfPossessionKey,
) -> Result<Self, WrongSourceTypeError<ProofOfPossessionKey>> {
if let ProofOfPossessionKey::KeyId(kid) = value {
Ok(kid)
} else {
Err(WrongSourceTypeError::new("KeyId", value.into()))
}
}
}
}