use crate::common::cbor_map::ToCborMap;
use crate::error::CoseCipherError;
use crate::token::CoseCipherCommon;
use crate::{CoseEncrypt0Cipher, CoseMac0Cipher, CoseSign1Cipher};
use ciborium::value::Value;
use core::convert::identity;
use core::fmt::Debug;
use coset::iana::Algorithm;
use coset::{Header, Label};
pub(crate) fn expect_ser_de<T>(
value: T,
transform_value: Option<fn(T) -> T>,
expected_hex: &str,
) -> Result<(), String>
where
T: ToCborMap + Clone + Debug + PartialEq,
{
let copy = value.clone();
let mut result = Vec::new();
value
.serialize_into(&mut result)
.map_err(|x| x.to_string())?;
#[cfg(feature = "std")]
println!("Result: {:?}, Original: {:?}", hex::encode(&result), ©);
assert_eq!(
&result,
&hex::decode(expected_hex).map_err(|x| x.to_string())?
);
let decoded = T::deserialize_from(result.as_slice()).map_err(|x| x.to_string());
if let Ok(decoded_value) = decoded {
let decoded_value = transform_value.unwrap_or(identity)(decoded_value);
assert_eq!(copy, decoded_value);
Ok(())
} else if let Err(e) = decoded {
Err(e)
} else {
Err("Invalid value: Not a CBOR map!".to_string())
}
}
#[derive(Copy, Clone)]
pub(crate) struct FakeCrypto {}
impl CoseCipherCommon for FakeCrypto {
type Error = String;
fn header(
&self,
unprotected_header: &mut Header,
protected_header: &mut Header,
) -> Result<(), CoseCipherError<Self::Error>> {
if let Some(label) = unprotected_header
.rest
.iter()
.find(|x| x.0 == Label::Int(47))
{
return Err(CoseCipherError::existing_header_label(&label.0));
}
if protected_header.alg != None {
return Err(CoseCipherError::existing_header("alg"));
}
unprotected_header.rest.push((Label::Int(47), Value::Null));
protected_header.alg = Some(coset::Algorithm::Assigned(Algorithm::Direct));
Ok(())
}
}
impl CoseEncrypt0Cipher for FakeCrypto {
fn encrypt(&mut self, data: &[u8], aad: &[u8]) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
result.append(&mut data.to_vec());
result.append(&mut aad.to_vec());
result
}
fn decrypt(
&mut self,
data: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
if data.len() < aad.len() {
return Err(CoseCipherError::Other(
"Encrypted data must be at least as long as AAD!".to_string(),
));
}
let mut result: Vec<u8> = data.to_vec();
let aad_result = result.split_off(data.len() - aad.len());
if aad == aad_result {
Ok(result)
} else {
Err(CoseCipherError::Other("AADs don't match!".to_string()))
}
}
}
impl CoseSign1Cipher for FakeCrypto {
fn generate_signature(&mut self, data: &[u8]) -> Vec<u8> {
data.to_vec()
}
fn verify_signature(
&mut self,
sig: &[u8],
data: &[u8],
) -> Result<(), CoseCipherError<Self::Error>> {
if sig == self.generate_signature(data) {
Ok(())
} else {
Err(CoseCipherError::VerificationFailure)
}
}
}
impl CoseMac0Cipher for FakeCrypto {
fn generate_tag(&mut self, target: &[u8]) -> Vec<u8> {
target.to_vec()
}
fn verify_tag(
&mut self,
tag: &[u8],
maced_data: &[u8],
) -> Result<(), CoseCipherError<Self::Error>> {
if tag == self.generate_tag(maced_data) {
Ok(())
} else {
Err(CoseCipherError::VerificationFailure)
}
}
}