Skip to content

Commit

Permalink
Revert migration to coset::CoseKey. Small refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
radumarias committed Aug 5, 2024
1 parent ffe7d22 commit 63af7aa
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 146 deletions.
1 change: 1 addition & 0 deletions src/cose.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod mac0;
mod serialize;
pub mod sign1;

use coset::iana;
Expand Down
89 changes: 18 additions & 71 deletions src/cose/mac0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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::<u8>::from_hex("a361316953796d6d6574726963613305622d318f187418681869187318201869187318201874186818651820186b18651879").unwrap();
/// let signer = Hmac::<Sha256>::new_from_slice(&key).expect("failed to create HMAC signer");
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
)
}
}

Expand Down Expand Up @@ -355,14 +301,15 @@ 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;
use hex::FromHex;
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");

Expand Down
15 changes: 15 additions & 0 deletions src/cose/serialize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use ciborium::Value;
use serde::{ser, Serialize};
use serde_cbor::tags::Tagged;

pub(crate) fn serialize<S: ser::Serializer>(
value: &Value,
tag: Option<u64>,
serializer: S,
) -> Result<S::Ok, S::Error> {
if tag.is_some() {
Tagged::new(tag, value).serialize(serializer)
} else {
value.serialize(serializer)
}
}
83 changes: 11 additions & 72 deletions src/cose/sign1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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,
)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/definitions/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

67 changes: 64 additions & 3 deletions src/definitions/device_key/cose_key.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -31,6 +35,23 @@ pub enum EC2Curve {
P256K,
}

impl From<EllipticCurve> 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 {
Expand All @@ -40,6 +61,23 @@ pub enum OKPCurve {
Ed448,
}

impl From<EllipticCurve> 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 {
Expand Down Expand Up @@ -393,11 +431,34 @@ impl TryFrom<&ssi_jwk::OctetParams> for OKPCurve {
}
}

impl TryFrom<CoseKey> for coset::CoseKey {
type Error = coset::CoseError;

fn try_from(value: CoseKey) -> Result<Self, Self::Error> {
coset::CoseKey::from_slice(
&value
.to_cbor_bytes()
.map_err(|_| coset::CoseError::EncodeFailed)?
.to_vec(),
)
}
}

impl TryFrom<coset::CoseKey> for CoseKey {
type Error = Error;

fn try_from(value: coset::CoseKey) -> Result<Self, Self::Error> {
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]
Expand Down
1 change: 1 addition & 0 deletions src/definitions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod device;
pub mod device_engagement;
pub mod device_key;
pub mod device_request;
Expand Down

0 comments on commit 63af7aa

Please sign in to comment.