diff --git a/src/iana/mod.rs b/src/iana/mod.rs index 3702014..7933168 100644 --- a/src/iana/mod.rs +++ b/src/iana/mod.rs @@ -787,6 +787,28 @@ iana_registry! { } } +iana_registry! { + /// OSCORE Security Context Parameters + /// From IANA registry https://www.iana.org/assignments/ace/ace.xhtml + /// as of 2022-11-29 + OscoreSecurityContextParameter { + /// OSCORE Input Material Identifier ("id": byte string). + Id: 0, + /// OSCORE Version ("version": unsigned integer). + Version: 1, + /// OSCORE Master Secret value ("ms": byte string). + Ms: 2, + /// OSCORE HKDF value ("hkd": text string / integer). + Hkdf: 3, + /// OSCORE AEAD Algorithm value ("al": text string / integer). + Alg: 4, + /// an input to OSCORE Master Salt value ("salt": byte string). + Salt: 5, + /// OSCORE ID Context value ("contextId": byte string). + ContextId: 6, + } +} + /// Integer values for CWT claims below this value are reserved for private use. pub const CWT_CLAIM_PRIVATE_USE_MAX: i64 = -65536; diff --git a/src/lib.rs b/src/lib.rs index 4ce9c93..3738d6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,3 +124,5 @@ mod mac; pub use mac::*; mod sign; pub use sign::*; +mod oscore; +pub use oscore::*; diff --git a/src/oscore/mod.rs b/src/oscore/mod.rs new file mode 100644 index 0000000..6143685 --- /dev/null +++ b/src/oscore/mod.rs @@ -0,0 +1,78 @@ +//! Types for the ACE OSCORE profile (RFC 9203) + +use crate::{ + cbor::value::Value, + common::AsCborValue, + iana, + util::ValueTryAs, + Algorithm, CoseError, Label, Result, +}; +use alloc::{collections::BTreeSet, vec::Vec}; + +/// OSCORE_Input_Material, suitable to produce OSCORE keys when applying the ACE OSCORE profile +/// (RFC 9203) +/// +/// This is typically transported in a token response as a variant of the cnf. +#[derive(Clone, Debug, PartialEq, Default)] +pub struct OscoreInputMaterial { + /// OSCORE Input Material Identifier + pub id: Option>, + /// OSCORE Version + pub version: Option, + /// OSCORE Master Secret value + pub ms: Option>, + /// OSCORE HKDF value + pub hkdf: Option, + /// OSCORE AEAD Algorithm value + pub alg: Option, + /// an input to OSCORE Master Salt value + pub salt: Option>, + /// OSCORE ID Context value + pub context_id: Option>, +} + +const ID: Label = Label::Int(iana::OscoreSecurityContextParameter::Id as i64); +const VERSION: Label = Label::Int(iana::OscoreSecurityContextParameter::Version as i64); +const MS: Label = Label::Int(iana::OscoreSecurityContextParameter::Ms as i64); +const HKDF: Label = Label::Int(iana::OscoreSecurityContextParameter::Hkdf as i64); +const ALG: Label = Label::Int(iana::OscoreSecurityContextParameter::Alg as i64); +const SALT: Label = Label::Int(iana::OscoreSecurityContextParameter::Salt as i64); +const CONTEXTID: Label = Label::Int(iana::OscoreSecurityContextParameter::ContextId as i64); + +impl AsCborValue for OscoreInputMaterial { + fn from_cbor_value(value: Value) -> Result { + + let m = value.try_as_map()?; + let mut material = Self::default(); + let mut seen = BTreeSet::new(); + for (l, value) in m.into_iter() { + // The `ciborium` CBOR library does not police duplicate map keys. + // RFC 8152 section 14 requires that COSE does police duplicates, so do it here. + let label = Label::from_cbor_value(l)?; + if seen.contains(&label) { + return Err(CoseError::DuplicateMapKey); + } + seen.insert(label.clone()); + match label { + ID => material.id = Some(value.try_as_bytes()?), + VERSION => material.version = Some(value.try_as_integer()?), + MS => material.ms = Some(value.try_as_bytes()?), + HKDF => material.hkdf = Some(Algorithm::from_cbor_value(value)?), + ALG => material.alg = Some(Algorithm::from_cbor_value(value)?), + SALT => material.salt = Some(value.try_as_bytes()?), + CONTEXTID => material.context_id = Some(value.try_as_bytes()?), + _label => { + return Err(CoseError::UnregisteredIanaValue); + }, + } + } + // No checks for required properties: All parameters are (at least formally, not + // practically) optional + + Ok(material) + } + + fn to_cbor_value(self) -> Result { + todo!() + } +}