From 63af7aa42d3a583c578c1f2e1125842045d6daa2 Mon Sep 17 00:00:00 2001 From: Radu Marias Date: Mon, 5 Aug 2024 16:46:50 +0300 Subject: [PATCH] Revert migration to `coset::CoseKey`. Small refactoring. --- src/cose.rs | 1 + src/cose/mac0.rs | 89 ++++++-------------------- src/cose/serialize.rs | 15 +++++ src/cose/sign1.rs | 83 ++++-------------------- src/definitions/device.rs | 1 + src/definitions/device_key/cose_key.rs | 67 ++++++++++++++++++- src/definitions/mod.rs | 1 + 7 files changed, 111 insertions(+), 146 deletions(-) create mode 100644 src/cose/serialize.rs create mode 100644 src/definitions/device.rs diff --git a/src/cose.rs b/src/cose.rs index 5aca68c1..e70cc68a 100644 --- a/src/cose.rs +++ b/src/cose.rs @@ -1,4 +1,5 @@ pub mod mac0; +mod serialize; pub mod sign1; use coset::iana; diff --git a/src/cose/mac0.rs b/src/cose/mac0.rs index 8b517e97..80f0ce9c 100644 --- a/src/cose/mac0.rs +++ b/src/cose/mac0.rs @@ -12,6 +12,8 @@ use serde::{ser, Deserialize, Deserializer, Serialize}; use serde_cbor::tags::Tagged; use sha2::Sha256; +use crate::cose::serialize; + /// Prepared `COSE_Mac0` for remote signing. /// /// To produce a `COSE_Mac0` do the following: @@ -28,7 +30,6 @@ use sha2::Sha256; /// use digest::Mac; /// use hex::FromHex;use hmac::Hmac; /// use sha2::Sha256; -/// use isomdl::cose::mac0::PreparedCoseMac0; /// /// let key = Vec::::from_hex("a361316953796d6d6574726963613305622d318f187418681869187318201869187318201874186818651820186b18651879").unwrap(); /// let signer = Hmac::::new_from_slice(&key).expect("failed to create HMAC signer"); @@ -143,6 +144,10 @@ impl PreparedCoseMac0 { (Some(payload), None) => payload, (None, Some(payload)) => payload, }; + let payload = payload + // Payload is mandatory + .as_ref() + .ok_or(Error::NoPayload)?; // Create the signature payload ot be used later on signing. let tag_payload = mac_structure_data( MacContext::CoseMac0, @@ -249,75 +254,16 @@ impl ser::Serialize for CoseMac0 { .inner .clone() .to_cbor_value() - .map_err(ser::Error::custom)?; // Convert the inner CoseMac0 object to a tagged CBOR vector - if self.tagged { - return Tagged::new(Some(iana::CborTag::CoseMac0 as u64), value).serialize(serializer); - } - match value { - Value::Bytes(x) => serializer.serialize_bytes(&x), - Value::Bool(x) => serializer.serialize_bool(x), - Value::Text(x) => serializer.serialize_str(x.as_str()), - Value::Null => serializer.serialize_unit(), - - Value::Tag(tag, ref v) => Tagged::new(Some(tag), v).serialize(serializer), - - Value::Float(x) => { - let y = x as f32; - if (y as f64).to_bits() == x.to_bits() { - serializer.serialize_f32(y) - } else { - serializer.serialize_f64(x) - } - } - - #[allow(clippy::unnecessary_fallible_conversions)] - Value::Integer(x) => { - if let Ok(x) = u8::try_from(x) { - serializer.serialize_u8(x) - } else if let Ok(x) = i8::try_from(x) { - serializer.serialize_i8(x) - } else if let Ok(x) = u16::try_from(x) { - serializer.serialize_u16(x) - } else if let Ok(x) = i16::try_from(x) { - serializer.serialize_i16(x) - } else if let Ok(x) = u32::try_from(x) { - serializer.serialize_u32(x) - } else if let Ok(x) = i32::try_from(x) { - serializer.serialize_i32(x) - } else if let Ok(x) = u64::try_from(x) { - serializer.serialize_u64(x) - } else if let Ok(x) = i64::try_from(x) { - serializer.serialize_i64(x) - } else if let Ok(x) = u128::try_from(x) { - serializer.serialize_u128(x) - } else if let Ok(x) = i128::try_from(x) { - serializer.serialize_i128(x) - } else { - unreachable!() - } - } - - Value::Array(x) => { - let mut map = serializer.serialize_seq(Some(x.len()))?; - - for v in x { - map.serialize_element(&v)?; - } - - map.end() - } - - Value::Map(x) => { - let mut map = serializer.serialize_map(Some(x.len()))?; - - for (k, v) in x { - map.serialize_entry(&k, &v)?; - } - - map.end() - } - _ => unimplemented!(), - } + .map_err(ser::Error::custom)?; + serialize::serialize( + &value, + if self.tagged { + Some(iana::CborTag::CoseMac0 as u64) + } else { + None + }, + serializer, + ) } } @@ -355,7 +301,6 @@ mod hmac { #[cfg(test)] mod tests { - use crate::cose::mac0::{CoseMac0, PreparedCoseMac0}; use coset::cwt::{ClaimsSet, Timestamp}; use coset::{iana, CborSerializable, Header}; use digest::Mac; @@ -363,6 +308,8 @@ mod tests { use hmac::Hmac; use sha2::Sha256; + use crate::cose::mac0::{CoseMac0, PreparedCoseMac0}; + static COSE_MAC0: &str = include_str!("../../test/definitions/cose/mac0/serialized.cbor"); static COSE_KEY: &str = include_str!("../../test/definitions/cose/mac0/secret_key"); diff --git a/src/cose/serialize.rs b/src/cose/serialize.rs new file mode 100644 index 00000000..ce85a217 --- /dev/null +++ b/src/cose/serialize.rs @@ -0,0 +1,15 @@ +use ciborium::Value; +use serde::{ser, Serialize}; +use serde_cbor::tags::Tagged; + +pub(crate) fn serialize( + value: &Value, + tag: Option, + serializer: S, +) -> Result { + if tag.is_some() { + Tagged::new(tag, value).serialize(serializer) + } else { + value.serialize(serializer) + } +} diff --git a/src/cose/sign1.rs b/src/cose/sign1.rs index 82648b6a..cf586e39 100644 --- a/src/cose/sign1.rs +++ b/src/cose/sign1.rs @@ -4,12 +4,10 @@ use coset::{ iana, sig_structure_data, AsCborValue, CborSerializable, CoseError, RegisteredLabelWithPrivate, SignatureContext, }; -use serde::ser::{SerializeMap, SerializeSeq}; use serde::{ser, Deserialize, Deserializer, Serialize}; -use serde_cbor::tags::Tagged; use signature::Verifier; -use crate::cose::SignatureAlgorithm; +use crate::cose::{serialize, SignatureAlgorithm}; /// Prepared `COSE_Sign1` for remote signing. /// @@ -264,75 +262,16 @@ impl ser::Serialize for CoseSign1 { .inner .clone() .to_cbor_value() - .map_err(ser::Error::custom)?; // Convert the inner CoseSign1 object to a tagged CBOR vector - if self.tagged { - return Tagged::new(Some(iana::CborTag::CoseSign1 as u64), value).serialize(serializer); - } - match value { - Value::Bytes(x) => serializer.serialize_bytes(&x), - Value::Bool(x) => serializer.serialize_bool(x), - Value::Text(x) => serializer.serialize_str(x.as_str()), - Value::Null => serializer.serialize_unit(), - - Value::Tag(tag, ref v) => Tagged::new(Some(tag), v).serialize(serializer), - - Value::Float(x) => { - let y = x as f32; - if (y as f64).to_bits() == x.to_bits() { - serializer.serialize_f32(y) - } else { - serializer.serialize_f64(x) - } - } - - #[allow(clippy::unnecessary_fallible_conversions)] - Value::Integer(x) => { - if let Ok(x) = u8::try_from(x) { - serializer.serialize_u8(x) - } else if let Ok(x) = i8::try_from(x) { - serializer.serialize_i8(x) - } else if let Ok(x) = u16::try_from(x) { - serializer.serialize_u16(x) - } else if let Ok(x) = i16::try_from(x) { - serializer.serialize_i16(x) - } else if let Ok(x) = u32::try_from(x) { - serializer.serialize_u32(x) - } else if let Ok(x) = i32::try_from(x) { - serializer.serialize_i32(x) - } else if let Ok(x) = u64::try_from(x) { - serializer.serialize_u64(x) - } else if let Ok(x) = i64::try_from(x) { - serializer.serialize_i64(x) - } else if let Ok(x) = u128::try_from(x) { - serializer.serialize_u128(x) - } else if let Ok(x) = i128::try_from(x) { - serializer.serialize_i128(x) - } else { - unreachable!() - } - } - - Value::Array(x) => { - let mut map = serializer.serialize_seq(Some(x.len()))?; - - for v in x { - map.serialize_element(&v)?; - } - - map.end() - } - - Value::Map(x) => { - let mut map = serializer.serialize_map(Some(x.len()))?; - - for (k, v) in x { - map.serialize_entry(&k, &v)?; - } - - map.end() - } - _ => unimplemented!(), - } + .map_err(ser::Error::custom)?; + serialize::serialize( + &value, + if self.tagged { + Some(iana::CborTag::CoseSign1 as u64) + } else { + None + }, + serializer, + ) } } diff --git a/src/definitions/device.rs b/src/definitions/device.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/definitions/device.rs @@ -0,0 +1 @@ + diff --git a/src/definitions/device_key/cose_key.rs b/src/definitions/device_key/cose_key.rs index d2cf0576..e9a3610c 100644 --- a/src/definitions/device_key/cose_key.rs +++ b/src/definitions/device_key/cose_key.rs @@ -1,10 +1,14 @@ +use std::collections::BTreeMap; + use aes::cipher::generic_array::{typenum::U8, GenericArray}; -use coset::iana; +use coset::iana::EllipticCurve; +use coset::{iana, CborSerializable}; use p256::EncodedPoint; use serde::{Deserialize, Serialize}; use serde_cbor::Value as CborValue; use ssi_jwk::JWK; -use std::collections::BTreeMap; + +use crate::definitions::traits::ToCbor; /// An implementation of RFC-8152 [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-13) /// restricted to the requirements of ISO/IEC 18013-5:2021. @@ -31,6 +35,23 @@ pub enum EC2Curve { P256K, } +impl From for EC2Curve { + fn from(value: EllipticCurve) -> Self { + match value { + EllipticCurve::Reserved => unimplemented!("{value:?} is not implemented"), + EllipticCurve::P_256 => EC2Curve::P256, + EllipticCurve::P_384 => EC2Curve::P384, + EllipticCurve::P_521 => EC2Curve::P521, + EllipticCurve::X25519 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::X448 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::Ed25519 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::Ed448 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::Secp256k1 => unimplemented!("{value:?} is not implemented"), + _ => unimplemented!("{value:?} is not implemented"), + } + } +} + /// The RFC-8152 identifier of the curve, for OKP key type. #[derive(Debug, Clone, PartialEq, Eq)] pub enum OKPCurve { @@ -40,6 +61,23 @@ pub enum OKPCurve { Ed448, } +impl From for OKPCurve { + fn from(value: EllipticCurve) -> Self { + match value { + EllipticCurve::Reserved => unimplemented!("{value:?} is not implemented"), + EllipticCurve::P_256 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::P_384 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::P_521 => unimplemented!("{value:?} is not implemented"), + EllipticCurve::X25519 => OKPCurve::X25519, + EllipticCurve::X448 => OKPCurve::X448, + EllipticCurve::Ed25519 => OKPCurve::Ed25519, + EllipticCurve::Ed448 => OKPCurve::Ed448, + EllipticCurve::Secp256k1 => unimplemented!("{value:?} is not implemented"), + _ => unimplemented!("{value:?} is not implemented"), + } + } +} + /// Errors that can occur when deserialising a COSE_Key. #[derive(Debug, Clone, thiserror::Error)] pub enum Error { @@ -393,11 +431,34 @@ impl TryFrom<&ssi_jwk::OctetParams> for OKPCurve { } } +impl TryFrom for coset::CoseKey { + type Error = coset::CoseError; + + fn try_from(value: CoseKey) -> Result { + coset::CoseKey::from_slice( + &value + .to_cbor_bytes() + .map_err(|_| coset::CoseError::EncodeFailed)? + .to_vec(), + ) + } +} + +impl TryFrom for CoseKey { + type Error = Error; + + fn try_from(value: coset::CoseKey) -> Result { + serde_cbor::from_slice(&value.to_vec().map_err(|_| Error::InvalidCoseKey)?) + .map_err(|_| Error::InvalidCoseKey) + } +} + #[cfg(test)] mod test { - use super::*; use hex::FromHex; + use super::*; + static EC_P256: &str = include_str!("../../../test/definitions/cose_key/ec_p256.cbor"); #[test] diff --git a/src/definitions/mod.rs b/src/definitions/mod.rs index f146dccf..e5a01783 100644 --- a/src/definitions/mod.rs +++ b/src/definitions/mod.rs @@ -1,3 +1,4 @@ +mod device; pub mod device_engagement; pub mod device_key; pub mod device_request;