From d378208f77a516c4890c04a37cdfad4cde66f4c4 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Thu, 4 Jul 2024 18:02:20 +0200 Subject: [PATCH] creds: cleaning up after refactor --- examples/lakers-no_std/src/main.rs | 24 ++++++--- lib/src/edhoc.rs | 5 -- lib/src/lib.rs | 12 ++--- shared/src/cred_new.rs | 78 ++++++++++++++++++------------ 4 files changed, 70 insertions(+), 49 deletions(-) diff --git a/examples/lakers-no_std/src/main.rs b/examples/lakers-no_std/src/main.rs index 18e8dbe7..61cf22db 100644 --- a/examples/lakers-no_std/src/main.rs +++ b/examples/lakers-no_std/src/main.rs @@ -101,15 +101,20 @@ fn main() -> ! { println!("Test test_prepare_message_1 passed."); fn test_handshake() { - let cred_i = CredentialRPK::new(CRED_I.try_into().unwrap()).unwrap(); - let cred_r = CredentialRPK::new(CRED_R.try_into().unwrap()).unwrap(); + let cred_i = Credential::parse_ccs(CRED_I.try_into().unwrap()).unwrap(); + let cred_r = Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap(); - let mut initiator = EdhocInitiator::new( + let initiator = EdhocInitiator::new( lakers_crypto::default_crypto(), EDHOCMethod::StatStat, EDHOCSuite::CipherSuite2, ); - let responder = EdhocResponder::new(lakers_crypto::default_crypto(), R, cred_r.clone()); + let responder = EdhocResponder::new( + lakers_crypto::default_crypto(), + EDHOCMethod::StatStat, + R.try_into().expect("Wrong length of responder private key"), + cred_r.clone(), + ); let (initiator, message_1) = initiator.prepare_message_1(None, &None).unwrap(); @@ -118,9 +123,16 @@ fn main() -> ! { .prepare_message_2(CredentialTransfer::ByReference, None, &None) .unwrap(); - let (initiator, c_r, id_cred_r, ead_2) = initiator.parse_message_2(&message_2).unwrap(); + let (mut initiator, _c_r, id_cred_r, _ead_2) = + initiator.parse_message_2(&message_2).unwrap(); let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap(); - let initiator = initiator.verify_message_2(I, cred_i, valid_cred_r).unwrap(); + initiator + .set_identity( + I.try_into().expect("Wrong length of initiator private key"), + cred_i.clone(), + ) + .unwrap(); // exposing own identity only after validating cred_r + let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); let (mut initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 1437f5c8..446f264d 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -24,10 +24,6 @@ pub fn edhoc_key_update( context: &BytesMaxContextBuffer, context_len: usize, ) -> BytesHashLen { - // FIXME: Normally we would decompose `state` here, but hax disallows aliasing a `mut` item. - // The best fix for this is to change state from a tuple-struct to a regular struct. - // In the code below, `state.6` means `mut prk_out` and `state.7` means `mut prk_exporter` - // new PRK_out let prk_new_buf = edhoc_kdf( crypto, @@ -151,7 +147,6 @@ pub fn r_prepare_message_2( )) } -// FIXME fetch ID_CRED_I and CRED_I based on kid pub fn r_parse_message_3( state: &mut WaitM3, crypto: &mut impl CryptoTrait, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index caed15c9..08b56e76 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -15,7 +15,6 @@ //! [EDHOC]: https://datatracker.ietf.org/doc/html/rfc9528 #![cfg_attr(not(test), no_std)] -// use defmt_or_log::*; // FIXME: still not working use log::trace; pub use {lakers_shared::Crypto as CryptoTrait, lakers_shared::*}; @@ -26,7 +25,6 @@ pub use lakers_ead_authz::*; mod edhoc; pub use edhoc::*; -// TODO: clean these structs and remove the cred_x whre they are not needed anymore /// Starting point for performing EDHOC in the role of the Initiator. #[derive(Debug)] pub struct EdhocInitiator { @@ -498,16 +496,16 @@ pub fn credential_check_or_fetch( // 4. Is the trust model Pre-knowledge + TOFU? YES (hardcoded to YES for now) // 6. Validate CRED_X. Generally a CCS has to be validated only syntactically and semantically, unlike a certificate or a CWT. // Is the validation successful? - // IMPL,NOTE: the credential has already been parsed with CredentialRPK::new in the *_parse_message_* function // 5. Is the authentication credential authorized for use in the context of this EDHOC session? // IMPL,TODO: we just skip this step for now // 7. Store CRED_X as valid and trusted. // Pair it with consistent credential identifiers, for each supported type of credential identifier. - assert!(!id_cred_received.reference_only()); - // FIXME: this is not elegant, should be solved at IdCred level - Credential::parse_ccs(id_cred_received.as_full_value()[2..].try_into().unwrap()) - .map_err(|_| EDHOCError::ParsingError) + if let Some(cred) = id_cred_received.get_ccs() { + Ok(cred) + } else { + Err(EDHOCError::ParsingError) + } } // 8. Is this authentication credential good to use in the context of this EDHOC session? diff --git a/shared/src/cred_new.rs b/shared/src/cred_new.rs index 452cedc6..b4f82956 100644 --- a/shared/src/cred_new.rs +++ b/shared/src/cred_new.rs @@ -43,7 +43,6 @@ impl From for IdCredType { /// A value of ID_CRED_x: a credential identifier /// /// Possible values include key IDs, credentials by value and others. -// TODO: rename to just IdCred #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct IdCred { /// The value is always stored in the ID_CRED_x form as a serialized one-element dictionary; @@ -72,7 +71,7 @@ impl IdCred { // kid that has been encoded as CBOR integer &[x] if Self::bstr_representable_as_int(x) => { BufferIdCred::new_from_slice(&[0xa1, KID_LABEL, 0x41, x]) - .map_err(|_| EDHOCError::CredentialTooLongError)? // TODO: make this error handling less verbose? + .map_err(|_| EDHOCError::CredentialTooLongError)? // TODO: how to avoid map_err overuse? } // kid that has been encoded as CBOR byte string &[0x41, x, ..] if !Self::bstr_representable_as_int(x) => { @@ -129,22 +128,6 @@ impl IdCred { fn bstr_representable_as_int(value: u8) -> bool { (0x0..=0x17).contains(&value) || (0x20..=0x37).contains(&value) } - - // FIXME: function only used while CredentialRPK is still around - pub fn tmp_from_ccs_or_kid(value: &[u8], label: u8) -> Result { - let mut bytes = BufferIdCred::new_from_slice(&[0xa1, label]) - .map_err(|_| EDHOCError::CredentialTooLongError)?; - if label == IdCredType::KID as u8 { - // the actual value of the kid is always a byte string - bytes - .extend_from_slice(&[0x40 | value.len() as u8]) - .map_err(|_| EDHOCError::CredentialTooLongError)?; - } - bytes - .extend_from_slice(value) - .map_err(|_| EDHOCError::CredentialTooLongError)?; - Ok(Self { bytes }) - } } #[derive(Clone, Copy, Debug, PartialEq)] @@ -159,7 +142,6 @@ pub struct Credential { pub cred_type: CredentialType, } -// FIXME: should handle errors instead of panicking impl Credential { /// Creates a new CCS credential with the given bytes and public key pub fn new_ccs(bytes: BufferCred, public_key: BytesKeyEC2) -> Self { @@ -192,18 +174,53 @@ impl Credential { /// Parse a CCS style credential /// - /// If the given value matches the shape Lakers expects of a CCS, its public key and key ID are - /// extracted into a full credential. + /// If the given value matches the shape lakers expects of a CCS, i.e. credentials from RFC9529, + /// its public key and key ID are extracted into a full credential. pub fn parse_ccs(value: &[u8]) -> Result { - // Implementing in terms of the old structure, to be moved in here in later versions of - // this change set - let (public_key, kid) = CredentialRPK::parse(value)?; - Ok(Self { - bytes: BufferCred::new_from_slice(value).map_err(|_| EDHOCError::ParsingError)?, - key: CredentialKey::EC2Compact(public_key), - kid: Some(BufferKid::new_from_slice(&[kid]).unwrap()), - cred_type: CredentialType::CCS, - }) + const CCS_PREFIX_LEN: usize = 3; + const CNF_AND_COSE_KEY_PREFIX_LEN: usize = 8; + const COSE_KEY_FIRST_ITEMS_LEN: usize = 6; + + if value.len() + < 3 + CCS_PREFIX_LEN + + 1 + + CNF_AND_COSE_KEY_PREFIX_LEN + + COSE_KEY_FIRST_ITEMS_LEN + + P256_ELEM_LEN + { + Err(EDHOCError::ParsingError) + } else { + let subject_len = CBORDecoder::info_of(value[2]) as usize; + + let id_cred_offset: usize = CCS_PREFIX_LEN + .checked_add(subject_len) + .and_then(|x| x.checked_add(CNF_AND_COSE_KEY_PREFIX_LEN)) + .ok_or(EDHOCError::ParsingError)?; + + let g_a_x_offset: usize = id_cred_offset + .checked_add(COSE_KEY_FIRST_ITEMS_LEN) + .ok_or(EDHOCError::ParsingError)?; + + if g_a_x_offset + .checked_add(P256_ELEM_LEN) + .map_or(false, |end| end <= value.len()) + { + let public_key: BytesKeyEC2 = value[g_a_x_offset..g_a_x_offset + P256_ELEM_LEN] + .try_into() + .expect("Wrong key length"); + let kid = value[id_cred_offset]; + + Ok(Self { + bytes: BufferCred::new_from_slice(value) + .map_err(|_| EDHOCError::ParsingError)?, + key: CredentialKey::EC2Compact(public_key), + kid: Some(BufferKid::new_from_slice(&[kid]).unwrap()), + cred_type: CredentialType::CCS, + }) + } else { + Err(EDHOCError::ParsingError) + } + } } /// Parse a CCS style credential, but the key is a symmetric key @@ -211,7 +228,6 @@ impl Credential { /// If the given value matches the shape Lakers expects of a CCS, its public key and key ID are /// extracted into a full credential. pub fn parse_ccs_psk(value: &[u8]) -> Result { - // TODO: actually implement this const CCS_PREFIX_LEN: usize = 3; const CNF_AND_COSE_KEY_PREFIX_LEN: usize = 8; const COSE_KEY_FIRST_ITEMS_LEN: usize = 3; //COSE for symmetric key