From 8d80f0e4a85ff9f14e3ecba24064c6d6637ecfa5 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Thu, 4 Jul 2024 09:02:13 +0200 Subject: [PATCH] creds: obtain idcred item type --- lib/src/edhoc.rs | 48 +++++++++++++++++++++++++----------------- lib/src/lib.rs | 20 ++++++++++-------- shared/src/cred_new.rs | 43 +++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 37 deletions(-) diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index b20c1db8..3e23a942 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -156,7 +156,7 @@ pub fn r_parse_message_3( state: &mut WaitM3, crypto: &mut impl CryptoTrait, message_3: &BufferMessage3, -) -> Result<(ProcessingM3, CredentialRPK, Option), EDHOCError> { +) -> Result<(ProcessingM3, BufferIdCred, Option), EDHOCError> { let plaintext_3 = decrypt_message_3(crypto, &state.prk_3e2m, &state.th_3, message_3); if let Ok(plaintext_3) = plaintext_3 { @@ -211,20 +211,26 @@ pub fn r_parse_message_3( pub fn r_verify_message_3( state: &mut ProcessingM3, crypto: &mut impl CryptoTrait, - valid_cred_i: CredentialRPK, + id_cred_i: IdCredNew, + valid_cred_i: Credential, ) -> Result<(Completed, BytesHashLen), EDHOCError> { // compute salt_4e3m let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3); // TODO compute prk_4e3m - let prk_4e3m = compute_prk_4e3m(crypto, &salt_4e3m, &state.y, &valid_cred_i.public_key); + let prk_4e3m = match valid_cred_i.key { + CredentialKey::EC2Compact(public_key) => { + compute_prk_4e3m(crypto, &salt_4e3m, &state.y, &public_key) + } + CredentialKey::Symmetric(_) => todo!("Symmetric keys are not supported yet"), + }; // compute mac_3 let expected_mac_3 = compute_mac_3( crypto, &prk_4e3m, &state.th_3, - &valid_cred_i.get_id_cred(), - valid_cred_i.value.as_slice(), + id_cred_i.as_full_value(), + valid_cred_i.bytes.as_slice(), &state.ead_3, ); @@ -234,7 +240,7 @@ pub fn r_verify_message_3( crypto, &state.th_3, &state.plaintext_3, - valid_cred_i.value.as_slice(), + valid_cred_i.bytes.as_slice(), ); let mut th_4_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; @@ -405,27 +411,28 @@ pub fn i_verify_message_2( pub fn i_prepare_message_3( state: &ProcessedM2, crypto: &mut impl CryptoTrait, - cred_i: CredentialRPK, + cred_i: Credential, cred_transfer: CredentialTransfer, ead_3: &Option, // FIXME: make it a list of EADItem ) -> Result<(Completed, BufferMessage3, BytesHashLen), EDHOCError> { + let id_cred_i = match cred_transfer { + CredentialTransfer::ByValue => cred_i.by_value()?, + CredentialTransfer::ByReference => cred_i.by_reference()?, + }; + let mac_3 = compute_mac_3( crypto, &state.prk_4e3m, &state.th_3, - &cred_i.get_id_cred(), - cred_i.value.as_slice(), + &id_cred_i, + cred_i.bytes.as_slice(), ead_3, ); - let id_cred_i = match cred_transfer { - CredentialTransfer::ByValue => IdCred::FullCredential(cred_i.value.as_slice()), - CredentialTransfer::ByReference => IdCred::CompactKid(cred_i.kid), - }; let plaintext_3 = encode_plaintext_3(&id_cred_i, &mac_3, &ead_3)?; let message_3 = encrypt_message_3(crypto, &state.prk_3e2m, &state.th_3, &plaintext_3); - let th_4 = compute_th_4(crypto, &state.th_3, &plaintext_3, cred_i.value.as_slice()); + let th_4 = compute_th_4(crypto, &state.th_3, &plaintext_3, cred_i.bytes.as_slice()); let mut th_4_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; th_4_buf[..th_4.len()].copy_from_slice(&th_4[..]); @@ -643,14 +650,17 @@ fn edhoc_kdf( } fn encode_plaintext_3( - id_cred_i: &IdCred, + id_cred_i: &BufferIdCred, mac_3: &BytesMac3, ead_3: &Option, ) -> Result { let mut plaintext_3: BufferPlaintext3 = BufferPlaintext3::new(); // plaintext: P = ( ? PAD, ID_CRED_I / bstr / int, Signature_or_MAC_3, ? EAD_3 ) - id_cred_i.write_to_message(&mut plaintext_3)?; + // id_cred_i.write_to_message(&mut plaintext_3)?; + plaintext_3 + .extend_from_slice(id_cred_i.as_slice()) + .map_err(|_| EDHOCError::CredentialTooLongError)?; let offset_cred = plaintext_3.len; plaintext_3.content[offset_cred] = CBOR_MAJOR_BYTE_STRING | MAC_LENGTH_3 as u8; plaintext_3.content[offset_cred + 1..][..mac_3.len()].copy_from_slice(&mac_3[..]); @@ -793,7 +803,7 @@ fn decrypt_message_3( // output must hold id_cred.len() + cred.len() fn encode_kdf_context( c_r: Option, // only present for MAC_2 - id_cred: &BytesIdCred, + id_cred: &[u8], th: &BytesHashLen, cred: &[u8], ead: &Option, @@ -809,7 +819,7 @@ fn encode_kdf_context( } else { 0 // no u8 encoded }; - output[output_len..output_len + id_cred.len()].copy_from_slice(&id_cred[..]); + output[output_len..output_len + id_cred.len()].copy_from_slice(id_cred); output[output_len + id_cred.len()] = CBOR_BYTE_STRING; output[output_len + id_cred.len() + 1] = SHA256_DIGEST_LEN as u8; output[output_len + id_cred.len() + 2..output_len + id_cred.len() + 2 + th.len()] @@ -835,7 +845,7 @@ fn compute_mac_3( crypto: &mut impl CryptoTrait, prk_4e3m: &BytesHashLen, th_3: &BytesHashLen, - id_cred_i: &BytesIdCred, + id_cred_i: &[u8], cred_i: &[u8], ead_3: &Option, ) -> BytesMac3 { diff --git a/lib/src/lib.rs b/lib/src/lib.rs index b4824bf3..54d515dd 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -32,7 +32,7 @@ pub use edhoc::*; pub struct EdhocInitiator { state: InitiatorStart, // opaque state i: Option, // static public key of myself - cred_i: Option, + cred_i: Option, crypto: Crypto, } @@ -40,7 +40,7 @@ pub struct EdhocInitiator { pub struct EdhocInitiatorWaitM2 { state: WaitM2, // opaque state i: Option, - cred_i: Option, + cred_i: Option, crypto: Crypto, } @@ -48,14 +48,14 @@ pub struct EdhocInitiatorWaitM2 { pub struct EdhocInitiatorProcessingM2 { state: ProcessingM2, // opaque state i: Option, - cred_i: Option, + cred_i: Option, crypto: Crypto, } #[derive(Debug)] pub struct EdhocInitiatorProcessedM2 { state: ProcessedM2, // opaque state - cred_i: Option, + cred_i: Option, crypto: Crypto, } @@ -183,7 +183,7 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderWaitM3 { ) -> Result< ( EdhocResponderProcessingM3, - CredentialRPK, + BufferIdCred, Option, ), EDHOCError, @@ -206,10 +206,11 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderWaitM3 { impl<'a, Crypto: CryptoTrait> EdhocResponderProcessingM3 { pub fn verify_message_3( mut self, - cred_i: CredentialRPK, + id_cred_i: IdCredNew, + cred_i: Credential, ) -> Result<(EdhocResponderDone, [u8; SHA256_DIGEST_LEN]), EDHOCError> { trace!("Enter verify_message_3"); - match r_verify_message_3(&mut self.state, &mut self.crypto, cred_i) { + match r_verify_message_3(&mut self.state, &mut self.crypto, id_cred_i, cred_i) { Ok((state, prk_out)) => Ok(( EdhocResponderDone { state, @@ -348,7 +349,7 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessingM2 { pub fn set_identity( &mut self, i: BytesP256ElemLen, - cred_i: CredentialRPK, + cred_i: Credential, ) -> Result<(), EDHOCError> { if self.i.is_some() || self.cred_i.is_some() { return Err(EDHOCError::IdentityAlreadySet); @@ -665,7 +666,8 @@ mod test { let (responder, id_cred_i, _ead_3) = responder.parse_message_3(&message_3).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); // if ead_3: process ead_3 - let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + let (mut responder, r_prk_out) = + responder.verify_message_3(id_cred_i, valid_cred_i).unwrap(); // ---- end responder handling // check that prk_out is equal at initiator and responder side diff --git a/shared/src/cred_new.rs b/shared/src/cred_new.rs index 0170ab63..797590bd 100644 --- a/shared/src/cred_new.rs +++ b/shared/src/cred_new.rs @@ -24,18 +24,34 @@ pub enum CredentialType { // C509, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IdCredType { + KID = 4, + KCCS = 14, +} + +impl From for IdCredType { + fn from(value: u8) -> Self { + match value { + 4 => IdCredType::KID, + 14 => IdCredType::KCCS, + _ => panic!("Invalid 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 -pub struct StructIdCredNew { +pub struct IdCredNew { /// The value is always stored in the ID_CRED_x form as a serialized one-element dictionary; /// while this technically wastes two bytes, it has the convenient property of having the full /// value available as a slice. pub bytes: BufferIdCred, // variable size, can contain either the contents of a BufferCred or a BufferKid } -impl StructIdCredNew { +impl IdCredNew { pub fn new() -> Self { Self { bytes: BufferIdCred::new(), @@ -49,13 +65,20 @@ impl StructIdCredNew { /// View the value as encoded in the ID_CRED_x position of plaintext_2 and plaintext_3, /// applying the Compact Encoding of ID_CRED Fields described in RFC9528 Section 3.5.3.2 - pub fn as_compact_encoding(&self) -> &[u8] { + /// Note that this does NOT encode the value as CBOR, it rather just applies the EDHOC Compact Encoding when applicable. + pub fn encode_for_plaintext(&self) -> &[u8] { match self.bytes.as_slice() { - [0xa1, 0x04, 0x41, x] if (x >> 5) < 2 && (x & 0x1f) < 24 => &self.bytes.as_slice()[3..], - [0xa1, 0x04, ..] => &self.bytes.as_slice()[2..], + [0xa1, KID_LABEL, 0x41, x] if (x >> 5) < 2 && (x & 0x1f) < 24 => { + &self.bytes.as_slice()[3..] + } + [0xa1, KID_LABEL, ..] => &self.bytes.as_slice()[2..], _ => self.bytes.as_slice(), } } + + pub fn item_type(&self) -> IdCredType { + self.bytes.as_slice()[1].into() + } } #[derive(Clone, Copy, Debug, PartialEq)] @@ -175,10 +198,10 @@ impl Credential { /// /// For example, if the credential is a CCS: /// { /kccs/ 14: bytes } - pub fn by_value(&self) -> Result { + pub fn by_value(&self) -> Result { match self.cred_type { CredentialType::CCS => { - let mut id_cred = StructIdCredNew::new(); + let mut id_cred = IdCredNew::new(); id_cred .bytes .extend_from_slice(&[CBOR_MAJOR_MAP + 1, KCSS_LABEL]) @@ -201,11 +224,11 @@ impl Credential { /// { /kid/ 4: kid } /// /// TODO: accept a parameter to specify the type of reference, e.g. kid, x5t, etc. - pub fn by_kid(&self) -> Result { + pub fn by_kid(&self) -> Result { let Some(kid) = self.kid.as_ref() else { return Err(EDHOCError::MissingIdentity); }; - let mut id_cred = StructIdCredNew::new(); + let mut id_cred = IdCredNew::new(); id_cred .bytes .extend_from_slice(&[ @@ -252,8 +275,10 @@ mod test { .with_kid(KID_VALUE_TV.try_into().unwrap()); let id_cred = cred.by_value().unwrap(); assert_eq!(id_cred.bytes.as_slice(), ID_CRED_BY_VALUE_TV); + assert_eq!(id_cred.item_type(), IdCredType::KCCS); let id_cred = cred.by_kid().unwrap(); assert_eq!(id_cred.bytes.as_slice(), ID_CRED_BY_REF_TV); + assert_eq!(id_cred.item_type(), IdCredType::KID); } #[test]