diff --git a/examples/coap/src/bin/coapclient.rs b/examples/coap/src/bin/coapclient.rs index 13c6f6a3..61eaed2d 100644 --- a/examples/coap/src/bin/coapclient.rs +++ b/examples/coap/src/bin/coapclient.rs @@ -54,10 +54,16 @@ fn client_handshake() -> Result<(), EDHOCError> { println!("message_2 len = {}", response.message.payload.len()); let message_2 = EdhocBuffer::new_from_slice(&response.message.payload[..]).unwrap(); - let (mut initiator, c_r, id_cred_r, ead_2) = initiator.parse_message_2(&message_2)?; + let (mut initiator, c_r, details, ead_2) = initiator.parse_message_2(&message_2)?; + let ParsedMessage2Details::StatStat { id_cred_r } = details; ead_2.processed_critical_items().unwrap(); let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap(); - initiator.set_identity(I.try_into().unwrap(), cred_i)?; + initiator.set_identity( + InitiatorIdentity::StatStat { + i: I.try_into().unwrap(), + }, + cred_i, + )?; let initiator = initiator.verify_message_2(valid_cred_r)?; let mut msg_3 = Vec::from(c_r.as_cbor()); diff --git a/examples/coap/src/bin/coapserver-coaphandler.rs b/examples/coap/src/bin/coapserver-coaphandler.rs index d574e430..464ba9ff 100644 --- a/examples/coap/src/bin/coapserver-coaphandler.rs +++ b/examples/coap/src/bin/coapserver-coaphandler.rs @@ -116,7 +116,9 @@ impl coap_handler::Handler for EdhocHandler { let (responder, _c_i, mut ead_1) = EdhocResponder::new( lakers_crypto::default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, cred_r, ) .process_message_1(message_1) diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index ade28591..d3fa1718 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -47,7 +47,9 @@ fn main() { let cred_r: Credential = Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap(); let responder = EdhocResponder::new( lakers_crypto::default_crypto(), - R.try_into().unwrap(), + ResponderIdentity::StatStat { + r: R.try_into().unwrap(), + }, cred_r, ); diff --git a/examples/lakers-no_std/src/main.rs b/examples/lakers-no_std/src/main.rs index 15732e6b..cdc354ab 100644 --- a/examples/lakers-no_std/src/main.rs +++ b/examples/lakers-no_std/src/main.rs @@ -108,7 +108,9 @@ fn main() -> ! { ); let responder = EdhocResponder::new( lakers_crypto::default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, cred_r.clone(), ); @@ -119,12 +121,14 @@ fn main() -> ! { .prepare_message_2(CredentialTransfer::ByReference, None, &EadItems::new()) .unwrap(); - let (mut initiator, _c_r, id_cred_r, _ead_2) = - initiator.parse_message_2(&message_2).unwrap(); + let (mut initiator, _c_r, details, _ead_2) = initiator.parse_message_2(&message_2).unwrap(); + let ParsedMessage2Details::StatStat { id_cred_r } = details; let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap(); initiator .set_identity( - I.try_into().expect("Wrong length of initiator private key"), + InitiatorIdentity::StatStat { + i: I.try_into().expect("Wrong length of initiator private key"), + }, cred_i.clone(), ) .unwrap(); // exposing own identity only after validating cred_r diff --git a/lakers-c/src/initiator.rs b/lakers-c/src/initiator.rs index c805dabe..a74f5a24 100644 --- a/lakers-c/src/initiator.rs +++ b/lakers-c/src/initiator.rs @@ -8,13 +8,12 @@ use crate::*; /// structs compatible with the C FFI -#[derive(Debug)] #[repr(C)] pub struct EdhocInitiator { pub start: InitiatorStart, pub wait_m2: WaitM2, pub processing_m2: ProcessingM2C, - pub processed_m2: ProcessedM2, + pub processed_m2: ProcessedM2C, pub wait_m4: WaitM4, pub cred_i: *mut CredentialC, pub completed: Completed, @@ -106,11 +105,14 @@ pub unsafe extern "C" fn initiator_parse_message_2( let state = core::ptr::read(&(*initiator_c).wait_m2); let result = match i_parse_message_2(&state, crypto, &(*message_2)) { - Ok((state, c_r, id_cred_r, ead_2)) => { + Ok((state, c_r, details, ead_2)) => { ProcessingM2C::copy_into_c(state, &mut (*initiator_c).processing_m2); let c_r = c_r.as_slice(); assert_eq!(c_r.len(), 1, "C API only supports short C_R"); *c_r_out = c_r[0]; + let id_cred_r = match details { + ParsedMessage2Details::StatStat { id_cred_r } => id_cred_r, + }; *id_cred_r_out = id_cred_r; EadItemsC::copy_into_c(ead_2, ead_2_c_out); @@ -140,9 +142,14 @@ pub unsafe extern "C" fn initiator_verify_message_2( let state = core::ptr::read(&(*initiator_c).processing_m2).to_rust(); - match i_verify_message_2(&state, crypto, (*valid_cred_r).to_rust(), &(*i)) { + match i_verify_message_2( + &state, + crypto, + (*valid_cred_r).to_rust(), + InitiatorIdentity::StatStat { i: *i }, + ) { Ok(state) => { - (*initiator_c).processed_m2 = state; + ProcessedM2C::copy_into_c(state, &mut (*initiator_c).processed_m2); (*initiator_c).cred_i = cred_i; 0 } @@ -165,7 +172,7 @@ pub unsafe extern "C" fn initiator_prepare_message_3( } let crypto = &mut default_crypto(); - let state = core::ptr::read(&(*initiator_c).processed_m2); + let state = core::ptr::read(&(*initiator_c).processed_m2).to_rust(); let ead_3 = if ead_3_c.is_null() { EadItems::new() diff --git a/lakers-c/src/lib.rs b/lakers-c/src/lib.rs index e75fd3ef..38eec749 100644 --- a/lakers-c/src/lib.rs +++ b/lakers-c/src/lib.rs @@ -93,31 +93,59 @@ impl EadItemsC { } } -#[derive(Debug)] #[repr(C)] -pub struct ProcessingM2C { +pub enum ProcessingM2MethodSpecificsKindC { + Pm2StatStat, + // Pm2Psk +} + +#[repr(C)] +pub struct ProcessingM2StatStatC { pub mac_2: BytesMac2, + pub id_cred_r: IdCred, +} + +#[repr(C)] +pub union ProcessingM2MethodSpecificsDataC { + pub statstat: core::mem::ManuallyDrop, +} + +#[repr(C)] +pub struct ProcessingM2MethodSpecificsC { + pub kind: ProcessingM2MethodSpecificsKindC, + pub data: ProcessingM2MethodSpecificsDataC, +} + +#[repr(C)] +pub struct ProcessingM2C { + pub method_specifics: ProcessingM2MethodSpecificsC, pub prk_2e: BytesHashLen, pub th_2: BytesHashLen, pub x: BytesP256ElemLen, pub g_y: BytesP256ElemLen, pub plaintext_2: EdhocMessageBuffer, pub c_r: u8, - pub id_cred_r: IdCred, pub ead_2: *mut EadItemsC, } impl Default for ProcessingM2C { fn default() -> Self { ProcessingM2C { - mac_2: Default::default(), + method_specifics: ProcessingM2MethodSpecificsC { + kind: ProcessingM2MethodSpecificsKindC::Pm2StatStat, + data: ProcessingM2MethodSpecificsDataC { + statstat: core::mem::ManuallyDrop::new(ProcessingM2StatStatC { + mac_2: Default::default(), + id_cred_r: Default::default(), + }), + }, + }, prk_2e: Default::default(), th_2: Default::default(), x: Default::default(), g_y: Default::default(), plaintext_2: Default::default(), c_r: Default::default(), - id_cred_r: Default::default(), ead_2: core::ptr::null_mut(), } } @@ -125,8 +153,21 @@ impl Default for ProcessingM2C { impl ProcessingM2C { pub fn to_rust(&self) -> ProcessingM2 { + let method_specifics = match self.method_specifics.kind { + ProcessingM2MethodSpecificsKindC::Pm2StatStat => { + // SAFETY: Accessing a union field is unsafe. We just matched on + // `self.method_specifics.kind == ProcessingM2MethodSpecificsKindC::Pm2StatStat`, + // so `data.statstat` is the active variant. + let stat = unsafe { &self.method_specifics.data.statstat }; + ProcessingM2MethodSpecifics::StatStat { + mac_2: stat.mac_2, + id_cred_r: stat.id_cred_r.clone(), + } + } + }; + ProcessingM2 { - mac_2: self.mac_2, + method_specifics, prk_2e: self.prk_2e, th_2: self.th_2, x: self.x, @@ -134,7 +175,6 @@ impl ProcessingM2C { plaintext_2: self.plaintext_2.clone(), #[allow(deprecated)] c_r: ConnId::from_int_raw(self.c_r), - id_cred_r: self.id_cred_r.clone(), ead_2: unsafe { (*self.ead_2).to_rust() }, } } @@ -145,7 +185,6 @@ impl ProcessingM2C { panic!("processing_m2_c is null"); } - (*processing_m2_c).mac_2 = processing_m2.mac_2; (*processing_m2_c).prk_2e = processing_m2.prk_2e; (*processing_m2_c).th_2 = processing_m2.th_2; (*processing_m2_c).x = processing_m2.x; @@ -154,7 +193,20 @@ impl ProcessingM2C { let c_r = processing_m2.c_r.as_slice(); assert_eq!(c_r.len(), 1, "C API only supports short C_R"); (*processing_m2_c).c_r = c_r[0]; - (*processing_m2_c).id_cred_r = processing_m2.id_cred_r; + + match processing_m2.method_specifics { + ProcessingM2MethodSpecifics::StatStat { mac_2, id_cred_r } => { + (*processing_m2_c).method_specifics = ProcessingM2MethodSpecificsC { + kind: ProcessingM2MethodSpecificsKindC::Pm2StatStat, + data: ProcessingM2MethodSpecificsDataC { + statstat: core::mem::ManuallyDrop::new(ProcessingM2StatStatC { + mac_2: mac_2, + id_cred_r: id_cred_r, + }), + }, + }; + } + } } } @@ -188,6 +240,90 @@ impl CredentialC { } } +#[repr(C)] +pub enum ProcessedM2MethodSpecificsKindC { + Prm2StatStat, + // Pm2Psk, +} +#[repr(C)] +pub struct ProcessedM2StatStatC {} + +#[repr(C)] +pub union ProcessedM2MethodSpecificsDataC { + pub statstat: core::mem::ManuallyDrop, +} + +#[repr(C)] +pub struct ProcessedM2MethodSpecificsC { + pub kind: ProcessedM2MethodSpecificsKindC, + pub data: ProcessedM2MethodSpecificsDataC, +} + +#[repr(C)] +pub struct ProcessedM2C { + pub method_specifics: ProcessedM2MethodSpecificsC, + pub prk_3e2m: BytesHashLen, + pub prk_4e3m: BytesHashLen, + pub th_3: BytesHashLen, +} + +impl Default for ProcessedM2C { + fn default() -> Self { + Self { + method_specifics: ProcessedM2MethodSpecificsC { + kind: ProcessedM2MethodSpecificsKindC::Prm2StatStat, + data: ProcessedM2MethodSpecificsDataC { + statstat: core::mem::ManuallyDrop::new(ProcessedM2StatStatC {}), + }, + }, + prk_3e2m: Default::default(), + prk_4e3m: Default::default(), + th_3: Default::default(), + } + } +} + +impl ProcessedM2C { + pub fn to_rust(&self) -> ProcessedM2 { + let method_specifics = match self.method_specifics.kind { + ProcessedM2MethodSpecificsKindC::Prm2StatStat => { + ProcessedM2MethodSpecifics::StatStat {} + } // ProcessedM2MethodSpecificsKindC::Prm2Psk => { + // let psk = unsafe { &self.method_specifics.data.psk }; + // ProcessedM2MethodSpecifics::Psk { ...from psk... } + // } + }; + + ProcessedM2 { + method_specifics, + prk_3e2m: self.prk_3e2m, + prk_4e3m: self.prk_4e3m, + th_3: self.th_3, + } + } + + pub unsafe fn copy_into_c(processed_m2: ProcessedM2, processed_m2_c: *mut ProcessedM2C) { + if processed_m2_c.is_null() { + panic!("processed_m2_c is null"); + } + + (*processed_m2_c).prk_3e2m = processed_m2.prk_3e2m; + (*processed_m2_c).prk_4e3m = processed_m2.prk_4e3m; + (*processed_m2_c).th_3 = processed_m2.th_3; + + match processed_m2.method_specifics { + ProcessedM2MethodSpecifics::StatStat {} => { + (*processed_m2_c).method_specifics = ProcessedM2MethodSpecificsC { + kind: ProcessedM2MethodSpecificsKindC::Prm2StatStat, + data: ProcessedM2MethodSpecificsDataC { + statstat: core::mem::ManuallyDrop::new(ProcessedM2StatStatC {}), + }, + }; + } + } + } +} + #[no_mangle] pub unsafe extern "C" fn credential_new( cred: *mut CredentialC, diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index 29fcfcad..97d30c1b 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -110,8 +110,12 @@ impl PyEdhocInitiator { let message_2 = EdhocMessageBuffer::new_from_slice(message_2.as_slice()) .with_cause(py, "Message 2 too long")?; - let (state, c_r, id_cred_r, ead_2) = + let (state, c_r, details, ead_2) = i_parse_message_2(&self.take_wait_m2()?, &mut default_crypto(), &message_2)?; + let id_cred_r = match details { + ParsedMessage2Details::StatStat { id_cred_r } => id_cred_r, + // ParsedMessage2Details::Psk { ead_2 } => (IdCred::new(), ead_2), + }; self.processing_m2 = Some(state); Ok(( PyBytes::new(py, c_r.as_slice()), @@ -143,9 +147,11 @@ impl PyEdhocInitiator { &self.take_processing_m2()?, &mut default_crypto(), valid_cred_r, - i.as_slice() - .try_into() - .expect("Wrong length of initiator private key"), + InitiatorIdentity::StatStat { + i: i.as_slice() + .try_into() + .expect("Wrong length of initiator private key"), + }, )?; self.processed_m2 = Some(state); self.cred_i = Some(cred_i); diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index 3ef6ddd8..c3a6ff7f 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -105,15 +105,23 @@ impl PyEdhocResponder { let ead_2 = ead_2.try_into()?; let mut r = BytesP256ElemLen::default(); r.copy_from_slice(self.r.as_slice()); + let processing_m1 = self.as_ref_processing_m1()?; + let method_details = match processing_m1.method { + EDHOCMethod::StatStat => PrepareMessage2Details::StatStat { + r: &r, + cred_transfer, + }, + // EDHOCMethod::PSK => PrepareMessage2Details::Psk, + _ => return Err(EDHOCError::UnsupportedMethod.into()), + }; let (state, message_2) = r_prepare_message_2( - self.as_ref_processing_m1()?, + processing_m1, &mut default_crypto(), // FIXME: take as reference rather than cloning self.cred_r.clone(), - &r, + method_details, c_r, - cred_transfer, &ead_2, )?; self.wait_m3 = Some(state); diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index e01df29e..4db0300c 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,5 +1,11 @@ +use crate::InitiatorIdentity; use digest::Digest; use lakers_shared::{Crypto as CryptoTrait, *}; +mod statstat; +use statstat::{ + i_parse_message_2_statstat, i_prepare_message_3_statstat, i_verify_message_2_statstat, + r_parse_message_3_statstat, r_prepare_message_2_statstat, r_verify_message_3_statstat, +}; pub fn edhoc_exporter( state: &Completed, @@ -44,6 +50,7 @@ pub fn r_process_message_1( let h_message_1 = crypto.sha256_digest(message_1.as_slice()); Ok(( ProcessingM1 { + method: method, y: state.y, g_y: state.g_y, c_i, @@ -69,59 +76,18 @@ pub fn r_prepare_message_2( state: &ProcessingM1, crypto: &mut impl CryptoTrait, cred_r: Credential, - r: &BytesP256ElemLen, // R's static private DH key + method_details: PrepareMessage2Details<'_>, c_r: ConnId, - cred_transfer: CredentialTransfer, ead_2: &EadItems, ) -> Result<(WaitM3, BufferMessage2), EDHOCError> { - // compute TH_2 - let th_2 = compute_th_2(crypto, &state.g_y, &state.h_message_1); - - // compute prk_3e2m - let prk_2e = compute_prk_2e(crypto, &state.y, &state.g_x, &th_2); - let salt_3e2m = compute_salt_3e2m(crypto, &prk_2e, &th_2); - let prk_3e2m = compute_prk_3e2m(crypto, &salt_3e2m, r, &state.g_x); - - let id_cred_r = match cred_transfer { - CredentialTransfer::ByValue => cred_r.by_value()?, - CredentialTransfer::ByReference => cred_r.by_kid()?, - }; - - // compute MAC_2 - let mac_2 = compute_mac_2( - crypto, - &prk_3e2m, - c_r, - id_cred_r.as_full_value(), - cred_r.bytes.as_slice(), - &th_2, - ead_2, - ); - - // compute ciphertext_2 - let plaintext_2 = encode_plaintext_2(c_r, id_cred_r.as_encoded_value(), &mac_2, &ead_2)?; - - // step is actually from processing of message_3 - // but we do it here to avoid storing plaintext_2 in State - let th_3 = compute_th_3(crypto, &th_2, &plaintext_2, cred_r.bytes.as_slice()); - - let mut ct: BufferCiphertext2 = BufferCiphertext2::new(); - ct.fill_with_slice(plaintext_2.as_slice()).unwrap(); // TODO(hax): can we prove with hax that this won't panic since they use the same underlying buffer length? - - let ciphertext_2 = encrypt_decrypt_ciphertext_2(crypto, &prk_2e, &th_2, &ct); - - ct.fill_with_slice(ciphertext_2.as_slice()).unwrap(); // TODO(hax): same as just above. - - let message_2 = encode_message_2(&state.g_y, &ct); - - Ok(( - WaitM3 { - y: state.y, - prk_3e2m: prk_3e2m, - th_3: th_3, - }, - message_2, - )) + match (state.method, method_details) { + (EDHOCMethod::StatStat, PrepareMessage2Details::StatStat { r, cred_transfer }) => { + r_prepare_message_2_statstat(state, crypto, cred_r, r, c_r, cred_transfer, ead_2) + } + // (EDHOCMethod::PSK, PrepareMessage2Details::Psk) => + // FIXME: it is not an error, but more a lack of agreement between peers. + _ => Err(EDHOCError::UnsupportedMethod), + } } pub fn r_parse_message_3( @@ -129,89 +95,24 @@ pub fn r_parse_message_3( crypto: &mut impl CryptoTrait, message_3: &BufferMessage3, ) -> Result<(ProcessingM3, IdCred, EadItems), EDHOCError> { - let plaintext_3 = decrypt_message_3(crypto, &state.prk_3e2m, &state.th_3, message_3); - - if let Ok(plaintext_3) = plaintext_3 { - let decoded_p3_res = decode_plaintext_3(&plaintext_3); - - if let Ok((id_cred_i, mac_3, ead_3)) = decoded_p3_res { - Ok(( - ProcessingM3 { - mac_3, - y: state.y, - prk_3e2m: state.prk_3e2m, - th_3: state.th_3, - id_cred_i: id_cred_i.clone(), // needed for compute_mac_3 - plaintext_3, // NOTE: this is needed for th_4, which needs valid_cred_i, which is only available at the 'verify' step - ead_3: ead_3.clone(), // NOTE: this clone could be avoided by using a reference or an index to the ead_3 item in plaintext_3 - }, - id_cred_i, - ead_3, - )) - } else { - Err(decoded_p3_res.unwrap_err()) - } - } else { - // error handling for err = decrypt_message_3(&prk_3e2m, &th_3, message_3); - Err(plaintext_3.unwrap_err()) + match state.method_specifics { + WaitM3MethodSpecifics::StatStat { .. } => { + r_parse_message_3_statstat(state, crypto, message_3) + } // WaitM3MethodSpecifics::Psk { .. } => } } pub fn r_verify_message_3( - state: &mut ProcessingM3, + state: &ProcessingM3, crypto: &mut impl CryptoTrait, valid_cred_i: Credential, ) -> Result<(ProcessedM3, BytesHashLen), EDHOCError> { - // compute salt_4e3m - let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3); - - let prk_4e3m = match valid_cred_i.key { - CredentialKey::EC2Compact(public_key) => { - compute_prk_4e3m(crypto, &salt_4e3m, &state.y, &public_key) - } - CredentialKey::Symmetric(_psk) => todo!("PSK not implemented"), - }; - - // compute mac_3 - let expected_mac_3 = compute_mac_3( - crypto, - &prk_4e3m, - &state.th_3, - state.id_cred_i.as_full_value(), - valid_cred_i.bytes.as_slice(), - &state.ead_3, - ); - - // verify mac_3 - if state.mac_3 == expected_mac_3 { - let th_4 = compute_th_4( - crypto, - &state.th_3, - &state.plaintext_3, - valid_cred_i.bytes.as_slice(), - ); - - // compute prk_out - // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let mut prk_out: BytesHashLen = Default::default(); - edhoc_kdf(crypto, &prk_4e3m, 7u8, &th_4, &mut prk_out); - - // compute prk_exporter from prk_out - // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let mut prk_exporter = BytesHashLen::default(); - edhoc_kdf(crypto, &prk_out, 10u8, &[], &mut prk_exporter); - - Ok(( - ProcessedM3 { - prk_4e3m: prk_4e3m, - th_4: th_4, - prk_out: prk_out, - prk_exporter: prk_exporter, - }, - prk_out, - )) - } else { - Err(EDHOCError::MacVerificationFailed) + match &state.method_specifics { + ProcessingM3MethodSpecifics::StatStat { mac_3, id_cred_i } => { + r_verify_message_3_statstat(state, crypto, valid_cred_i, *mac_3, id_cred_i) + } // ProcessingM3MethodSpecifics::Psk { ... } => { + // r_verify_message_3_psk(state, crypto, valid_cred_i, ...) + // } } } @@ -254,6 +155,7 @@ pub fn i_prepare_message_1( Ok(( WaitM2 { + method: state.method, x: state.x, h_message_1, }, @@ -261,43 +163,15 @@ pub fn i_prepare_message_1( )) } -// returns c_r pub fn i_parse_message_2<'a>( state: &WaitM2, crypto: &mut impl CryptoTrait, message_2: &BufferMessage2, -) -> Result<(ProcessingM2, ConnId, IdCred, EadItems), EDHOCError> { - let res = parse_message_2(message_2); - if let Ok((g_y, ciphertext_2)) = res { - let th_2 = compute_th_2(crypto, &g_y, &state.h_message_1); - - // compute prk_2e - let prk_2e = compute_prk_2e(crypto, &state.x, &g_y, &th_2); - - let plaintext_2 = encrypt_decrypt_ciphertext_2(crypto, &prk_2e, &th_2, &ciphertext_2); - - // decode plaintext_2 - let plaintext_2_decoded = decode_plaintext_2(&plaintext_2); - - if let Ok((c_r_2, id_cred_r, mac_2, ead_2)) = plaintext_2_decoded { - let state = ProcessingM2 { - mac_2, - prk_2e, - th_2, - x: state.x, - g_y, - plaintext_2: plaintext_2, - c_r: c_r_2, - id_cred_r: id_cred_r.clone(), // needed for compute_mac_2 - ead_2: ead_2.clone(), // needed for compute_mac_2 - }; - - Ok((state, c_r_2, id_cred_r, ead_2)) - } else { - Err(EDHOCError::ParsingError) - } - } else { - Err(res.unwrap_err()) +) -> Result<(ProcessingM2, ConnId, ParsedMessage2Details, EadItems), EDHOCError> { + match state.method { + EDHOCMethod::StatStat => i_parse_message_2_statstat(state, crypto, message_2), + // EDHOCMethod::PSK => i_parse_message_2_psk() + _ => Err(EDHOCError::UnsupportedMethod), } } @@ -305,52 +179,14 @@ pub fn i_verify_message_2( state: &ProcessingM2, crypto: &mut impl CryptoTrait, valid_cred_r: Credential, - i: &BytesP256ElemLen, // I's static private DH key + i: InitiatorIdentity, // I's static private DH key when required by method ) -> Result { - // verify mac_2 - let salt_3e2m = compute_salt_3e2m(crypto, &state.prk_2e, &state.th_2); - - let prk_3e2m = match valid_cred_r.key { - CredentialKey::EC2Compact(public_key) => { - compute_prk_3e2m(crypto, &salt_3e2m, &state.x, &public_key) - } - CredentialKey::Symmetric(_psk) => todo!("PSK not implemented"), - }; - - let expected_mac_2 = compute_mac_2( - crypto, - &prk_3e2m, - state.c_r, - state.id_cred_r.as_full_value(), - valid_cred_r.bytes.as_slice(), - &state.th_2, - &state.ead_2, - ); - - if state.mac_2 == expected_mac_2 { - // step is actually from processing of message_3 - // but we do it here to avoid storing plaintext_2 in State - let th_3 = compute_th_3( - crypto, - &state.th_2, - &state.plaintext_2, - valid_cred_r.bytes.as_slice(), - ); - // message 3 processing - - let salt_4e3m = compute_salt_4e3m(crypto, &prk_3e2m, &th_3); - - let prk_4e3m = compute_prk_4e3m(crypto, &salt_4e3m, i, &state.g_y); - - let state = ProcessedM2 { - prk_3e2m: prk_3e2m, - prk_4e3m: prk_4e3m, - th_3: th_3, - }; - - Ok(state) - } else { - Err(EDHOCError::MacVerificationFailed) + match (&state.method_specifics, &i) { + (ProcessingM2MethodSpecifics::StatStat { .. }, InitiatorIdentity::StatStat { i }) => { + i_verify_message_2_statstat(state, crypto, valid_cred_r, i) + } // ProcessingM2MethodSpecifics::Psk { .. } => + // FIXME: it is not an error, but more a lack of agreement between peers. + _ => Err(EDHOCError::MissingIdentity), // or UnsupportedMethod } } @@ -361,45 +197,11 @@ pub fn i_prepare_message_3( cred_transfer: CredentialTransfer, ead_3: &EadItems, ) -> Result<(WaitM4, BufferMessage3, BytesHashLen), EDHOCError> { - let id_cred_i = match cred_transfer { - CredentialTransfer::ByValue => cred_i.by_value()?, - CredentialTransfer::ByReference => cred_i.by_kid()?, - }; - - let mac_3 = compute_mac_3( - crypto, - &state.prk_4e3m, - &state.th_3, - id_cred_i.as_full_value(), - cred_i.bytes.as_slice(), - ead_3, - ); - - let plaintext_3 = encode_plaintext_3(id_cred_i.as_encoded_value(), &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.bytes.as_slice()); - - // compute prk_out - // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let mut prk_out: BytesHashLen = Default::default(); - edhoc_kdf(crypto, &state.prk_4e3m, 7u8, &th_4, &mut prk_out); - - // compute prk_exporter from prk_out - // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let mut prk_exporter: BytesHashLen = Default::default(); - edhoc_kdf(crypto, &prk_out, 10u8, &[], &mut prk_exporter); - - Ok(( - WaitM4 { - prk_4e3m: state.prk_4e3m, - th_4: th_4, - prk_out: prk_out, - prk_exporter: prk_exporter, - }, - message_3, - prk_out, - )) + match state.method_specifics { + ProcessedM2MethodSpecifics::StatStat { .. } => { + i_prepare_message_3_statstat(state, crypto, cred_i, cred_transfer, ead_3) + } // ProcessedM2MethodSpecifics::Psk { .. } => i_prepare_message_3_psk() + } } pub fn i_process_message_4( diff --git a/lib/src/edhoc/statstat.rs b/lib/src/edhoc/statstat.rs new file mode 100644 index 00000000..4513c57c --- /dev/null +++ b/lib/src/edhoc/statstat.rs @@ -0,0 +1,322 @@ +use super::{ + compute_mac_2, compute_mac_3, compute_prk_2e, compute_prk_3e2m, compute_prk_4e3m, + compute_salt_3e2m, compute_salt_4e3m, compute_th_2, compute_th_3, compute_th_4, + decode_plaintext_2, decode_plaintext_3, decrypt_message_3, edhoc_kdf, encode_message_2, + encode_plaintext_2, encode_plaintext_3, encrypt_decrypt_ciphertext_2, encrypt_message_3, + parse_message_2, BufferCiphertext2, BufferMessage2, BufferMessage3, BytesHashLen, BytesMac3, + BytesP256ElemLen, ConnId, Credential, CredentialKey, CredentialTransfer, EDHOCError, EadItems, + IdCred, ParsedMessage2Details, ProcessedM2, ProcessedM2MethodSpecifics, ProcessedM3, + ProcessingM1, ProcessingM2, ProcessingM2MethodSpecifics, ProcessingM3, + ProcessingM3MethodSpecifics, WaitM2, WaitM3, WaitM3MethodSpecifics, WaitM4, +}; +use lakers_shared::Crypto as CryptoTrait; +pub(crate) fn r_prepare_message_2_statstat( + state: &ProcessingM1, + crypto: &mut impl CryptoTrait, + cred_r: Credential, + r: &BytesP256ElemLen, // R's static private DH key + c_r: ConnId, + cred_transfer: CredentialTransfer, + ead_2: &EadItems, +) -> Result<(WaitM3, BufferMessage2), EDHOCError> { + // compute TH_2 + let th_2 = compute_th_2(crypto, &state.g_y, &state.h_message_1); + + // compute prk_3e2m + let prk_2e = compute_prk_2e(crypto, &state.y, &state.g_x, &th_2); + let salt_3e2m = compute_salt_3e2m(crypto, &prk_2e, &th_2); + let prk_3e2m = compute_prk_3e2m(crypto, &salt_3e2m, r, &state.g_x); + + let id_cred_r = match cred_transfer { + CredentialTransfer::ByValue => cred_r.by_value()?, + CredentialTransfer::ByReference => cred_r.by_kid()?, + }; + + // compute MAC_2 + let mac_2 = compute_mac_2( + crypto, + &prk_3e2m, + c_r, + id_cred_r.as_full_value(), + cred_r.bytes.as_slice(), + &th_2, + ead_2, + ); + + // compute ciphertext_2 + let plaintext_2 = encode_plaintext_2(c_r, id_cred_r.as_encoded_value(), &mac_2, &ead_2)?; + + // step is actually from processing of message_3 + // but we do it here to avoid storing plaintext_2 in State + let th_3 = compute_th_3(crypto, &th_2, &plaintext_2, cred_r.bytes.as_slice()); + + let mut ct: BufferCiphertext2 = BufferCiphertext2::new(); + ct.fill_with_slice(plaintext_2.as_slice()).unwrap(); // TODO(hax): can we prove with hax that this won't panic since they use the same underlying buffer length? + + let ciphertext_2 = encrypt_decrypt_ciphertext_2(crypto, &prk_2e, &th_2, &ct); + + ct.fill_with_slice(ciphertext_2.as_slice()).unwrap(); // TODO(hax): same as just above. + + let message_2 = encode_message_2(&state.g_y, &ct); + + Ok(( + WaitM3 { + method_specifics: WaitM3MethodSpecifics::StatStat {}, + y: state.y, + prk_3e2m: prk_3e2m, + th_3: th_3, + }, + message_2, + )) +} + +pub(crate) fn r_parse_message_3_statstat( + state: &mut WaitM3, + crypto: &mut impl CryptoTrait, + message_3: &BufferMessage3, +) -> Result<(ProcessingM3, IdCred, EadItems), EDHOCError> { + let plaintext_3 = decrypt_message_3(crypto, &state.prk_3e2m, &state.th_3, message_3); + + if let Ok(plaintext_3) = plaintext_3 { + let decoded_p3_res = decode_plaintext_3(&plaintext_3); + + if let Ok((id_cred_i, mac_3, ead_3)) = decoded_p3_res { + Ok(( + ProcessingM3 { + method_specifics: ProcessingM3MethodSpecifics::StatStat { + mac_3, + id_cred_i: id_cred_i.clone(), // needed for compute_mac_3 + }, + y: state.y, + prk_3e2m: state.prk_3e2m, + th_3: state.th_3, + plaintext_3, // NOTE: this is needed for th_4, which needs valid_cred_i, which is only available at the 'verify' step + ead_3: ead_3.clone(), // NOTE: this clone could be avoided by using a reference or an index to the ead_3 item in plaintext_3 + }, + id_cred_i, + ead_3, + )) + } else { + Err(decoded_p3_res.unwrap_err()) + } + } else { + // error handling for err = decrypt_message_3(&prk_3e2m, &th_3, message_3); + Err(plaintext_3.unwrap_err()) + } +} + +pub(crate) fn r_verify_message_3_statstat( + state: &ProcessingM3, + crypto: &mut impl CryptoTrait, + valid_cred_i: Credential, + mac_3: BytesMac3, + id_cred_i: &IdCred, +) -> Result<(ProcessedM3, BytesHashLen), EDHOCError> { + // compute salt_4e3m + let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3); + + let prk_4e3m = match valid_cred_i.key { + CredentialKey::EC2Compact(public_key) => { + compute_prk_4e3m(crypto, &salt_4e3m, &state.y, &public_key) + } + // FIXME: the error is not accurate. It is a lack of agreement between peers. + _ => return Err(EDHOCError::UnsupportedMethod), + }; + + // compute mac_3 + let expected_mac_3 = compute_mac_3( + crypto, + &prk_4e3m, + &state.th_3, + id_cred_i.as_full_value(), + valid_cred_i.bytes.as_slice(), + &state.ead_3, + ); + + // verify mac_3 + if mac_3 == expected_mac_3 { + let th_4 = compute_th_4( + crypto, + &state.th_3, + &state.plaintext_3, + valid_cred_i.bytes.as_slice(), + ); + + // compute prk_out + // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) + let mut prk_out: BytesHashLen = Default::default(); + edhoc_kdf(crypto, &prk_4e3m, 7u8, &th_4, &mut prk_out); + + // compute prk_exporter from prk_out + // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) + let mut prk_exporter = BytesHashLen::default(); + edhoc_kdf(crypto, &prk_out, 10u8, &[], &mut prk_exporter); + + Ok(( + ProcessedM3 { + prk_4e3m: prk_4e3m, + th_4: th_4, + prk_out: prk_out, + prk_exporter: prk_exporter, + }, + prk_out, + )) + } else { + Err(EDHOCError::MacVerificationFailed) + } +} + +pub(crate) fn i_parse_message_2_statstat<'a>( + state: &WaitM2, + crypto: &mut impl CryptoTrait, + message_2: &BufferMessage2, +) -> Result<(ProcessingM2, ConnId, ParsedMessage2Details, EadItems), EDHOCError> { + let res = parse_message_2(message_2); + if let Ok((g_y, ciphertext_2)) = res { + let th_2 = compute_th_2(crypto, &g_y, &state.h_message_1); + + // compute prk_2e + let prk_2e = compute_prk_2e(crypto, &state.x, &g_y, &th_2); + + let plaintext_2 = encrypt_decrypt_ciphertext_2(crypto, &prk_2e, &th_2, &ciphertext_2); + + // decode plaintext_2 + let plaintext_2_decoded = decode_plaintext_2(&plaintext_2); + + if let Ok((c_r_2, id_cred_r, mac_2, ead_2)) = plaintext_2_decoded { + let state = ProcessingM2 { + method_specifics: ProcessingM2MethodSpecifics::StatStat { + mac_2, + id_cred_r: id_cred_r.clone(), // needed for compute_mac_2 + }, + prk_2e, + th_2, + x: state.x, + g_y, + plaintext_2: plaintext_2, + c_r: c_r_2, + ead_2: ead_2.clone(), // needed for compute_mac_2 + }; + + Ok(( + state, + c_r_2, + ParsedMessage2Details::StatStat { id_cred_r }, + ead_2, + )) + } else { + Err(EDHOCError::ParsingError) + } + } else { + Err(res.unwrap_err()) + } +} + +pub(crate) fn i_verify_message_2_statstat( + state: &ProcessingM2, + crypto: &mut impl CryptoTrait, + valid_cred_r: Credential, + i: &BytesP256ElemLen, // I's static private DH key +) -> Result { + // verify mac_2 + let salt_3e2m = compute_salt_3e2m(crypto, &state.prk_2e, &state.th_2); + + let prk_3e2m = match valid_cred_r.key { + CredentialKey::EC2Compact(public_key) => { + compute_prk_3e2m(crypto, &salt_3e2m, &state.x, &public_key) + } + // FIXME: the error is not accurate. It is a lack of agreement between peers. + _ => return Err(EDHOCError::UnsupportedMethod), + }; + + let (id_cred_r, mac_2) = match &state.method_specifics { + ProcessingM2MethodSpecifics::StatStat { id_cred_r, mac_2 } => (id_cred_r, *mac_2), + }; + + let expected_mac_2 = compute_mac_2( + crypto, + &prk_3e2m, + state.c_r, + id_cred_r.as_full_value(), + valid_cred_r.bytes.as_slice(), + &state.th_2, + &state.ead_2, + ); + + if mac_2 == expected_mac_2 { + // step is actually from processing of message_3 + // but we do it here to avoid storing plaintext_2 in State + let th_3 = compute_th_3( + crypto, + &state.th_2, + &state.plaintext_2, + valid_cred_r.bytes.as_slice(), + ); + // message 3 processing + + let salt_4e3m = compute_salt_4e3m(crypto, &prk_3e2m, &th_3); + + let prk_4e3m = compute_prk_4e3m(crypto, &salt_4e3m, i, &state.g_y); + + let state = ProcessedM2 { + // We need the method for next step. Since we are in the branch of StatStat, + // we can add EDHOCMethod::StatStat + method_specifics: ProcessedM2MethodSpecifics::StatStat {}, + prk_3e2m: prk_3e2m, + prk_4e3m: prk_4e3m, + th_3: th_3, + }; + + Ok(state) + } else { + Err(EDHOCError::MacVerificationFailed) + } +} + +pub(crate) fn i_prepare_message_3_statstat( + state: &ProcessedM2, + crypto: &mut impl CryptoTrait, + cred_i: Credential, + cred_transfer: CredentialTransfer, + ead_3: &EadItems, +) -> Result<(WaitM4, BufferMessage3, BytesHashLen), EDHOCError> { + let id_cred_i = match cred_transfer { + CredentialTransfer::ByValue => cred_i.by_value()?, + CredentialTransfer::ByReference => cred_i.by_kid()?, + }; + + let mac_3 = compute_mac_3( + crypto, + &state.prk_4e3m, + &state.th_3, + id_cred_i.as_full_value(), + cred_i.bytes.as_slice(), + ead_3, + ); + + let plaintext_3 = encode_plaintext_3(id_cred_i.as_encoded_value(), &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.bytes.as_slice()); + + // compute prk_out + // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) + let mut prk_out: BytesHashLen = Default::default(); + edhoc_kdf(crypto, &state.prk_4e3m, 7u8, &th_4, &mut prk_out); + + // compute prk_exporter from prk_out + // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) + let mut prk_exporter: BytesHashLen = Default::default(); + edhoc_kdf(crypto, &prk_out, 10u8, &[], &mut prk_exporter); + + Ok(( + WaitM4 { + prk_4e3m: state.prk_4e3m, + th_4: th_4, + prk_out: prk_out, + prk_exporter: prk_exporter, + }, + message_3, + prk_out, + )) +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 3117947e..7d4fbcab 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -24,8 +24,8 @@ pub use edhoc::*; /// Starting point for performing EDHOC in the role of the Initiator. #[derive(Debug)] pub struct EdhocInitiator { - state: InitiatorStart, // opaque state - i: Option, // static public key of myself + state: InitiatorStart, // opaque state + i: Option, // static authentication identity of I when required by method cred_i: Option, crypto: Crypto, } @@ -33,7 +33,7 @@ pub struct EdhocInitiator { #[derive(Debug)] pub struct EdhocInitiatorWaitM2 { state: WaitM2, // opaque state - i: Option, + i: Option, cred_i: Option, crypto: Crypto, } @@ -41,7 +41,7 @@ pub struct EdhocInitiatorWaitM2 { #[derive(Debug)] pub struct EdhocInitiatorProcessingM2 { state: ProcessingM2, // opaque state - i: Option, + i: Option, cred_i: Option, crypto: Crypto, } @@ -69,16 +69,16 @@ pub struct EdhocInitiatorDone { #[derive(Debug)] pub struct EdhocResponder { state: ResponderStart, // opaque state - r: BytesP256ElemLen, // private authentication key of R + r: ResponderIdentity, // private authentication key of R when required by method cred_r: Credential, // R's full credential crypto: Crypto, } #[derive(Debug)] pub struct EdhocResponderProcessedM1 { - state: ProcessingM1, // opaque state - r: BytesP256ElemLen, // private authentication key of R - cred_r: Credential, // R's full credential + state: ProcessingM1, // opaque state + r: ResponderIdentity, // private authentication key of R when required by method + cred_r: Credential, // R's full credential crypto: Crypto, } @@ -106,14 +106,26 @@ pub struct EdhocResponderDone { crypto: Crypto, } +#[derive(Debug)] +pub enum ResponderIdentity { + StatStat { r: BytesP256ElemLen }, + Psk, +} + +#[derive(Debug)] +pub enum InitiatorIdentity { + StatStat { i: BytesP256ElemLen }, + Psk, +} + impl EdhocResponder { - pub fn new(mut crypto: Crypto, r: BytesP256ElemLen, cred_r: Credential) -> Self { + pub fn new(mut crypto: Crypto, identity: ResponderIdentity, cred_r: Credential) -> Self { trace!("Initializing EdhocResponder"); let (y, g_y) = crypto.p256_generate_key_pair(); EdhocResponder { state: ResponderStart { y, g_y }, - r, + r: identity, cred_r, crypto, } @@ -152,13 +164,23 @@ impl EdhocResponderProcessedM1 { None => generate_connection_identifier_cbor(&mut self.crypto), }; + let method_details = match (self.state.method, &self.r) { + (EDHOCMethod::StatStat, ResponderIdentity::StatStat { r }) => { + PrepareMessage2Details::StatStat { r, cred_transfer } + } + // (EDHOCMethod::Psk, ResponderIdentity::Psk) => { + // PrepareMessage2Details::Psk + // } + // FIXME: Distinguish `MissingIdentity` from `MethodIdentityMismatch` here; + _ => return Err(EDHOCError::MissingIdentity), // or UnsupportedMethod + }; + match r_prepare_message_2( &self.state, &mut self.crypto, self.cred_r, - &self.r, + method_details, c_r, - cred_transfer, ead_2, ) { Ok((state, message_2)) => Ok(( @@ -272,7 +294,7 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiator { } pub fn set_identity(&mut self, i: BytesP256ElemLen, cred_i: Credential) { - self.i = Some(i); + self.i = Some(InitiatorIdentity::StatStat { i }); self.cred_i = Some(cred_i); } @@ -314,10 +336,18 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM2 { pub fn parse_message_2( mut self, message_2: &'a BufferMessage2, - ) -> Result<(EdhocInitiatorProcessingM2, ConnId, IdCred, EadItems), EDHOCError> { + ) -> Result< + ( + EdhocInitiatorProcessingM2, + ConnId, + ParsedMessage2Details, + EadItems, + ), + EDHOCError, + > { trace!("Enter parse_message_2"); match i_parse_message_2(&self.state, &mut self.crypto, message_2) { - Ok((state, c_r, id_cred_r, ead_2)) => Ok(( + Ok((state, c_r, details, ead_2)) => Ok(( EdhocInitiatorProcessingM2 { state, i: self.i, @@ -325,7 +355,7 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM2 { crypto: self.crypto, }, c_r, - id_cred_r, + details, ead_2, )), Err(error) => Err(error), @@ -336,13 +366,13 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM2 { impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessingM2 { pub fn set_identity( &mut self, - i: BytesP256ElemLen, + identity: InitiatorIdentity, cred_i: Credential, ) -> Result<(), EDHOCError> { if self.i.is_some() || self.cred_i.is_some() { return Err(EDHOCError::IdentityAlreadySet); } - self.i = Some(i); + self.i = Some(identity); self.cred_i = Some(cred_i); Ok(()) } @@ -352,10 +382,8 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessingM2 { valid_cred_r: Credential, ) -> Result, EDHOCError> { trace!("Enter verify_message_2"); - let Some(i) = self.i else { - return Err(EDHOCError::MissingIdentity); - }; - match i_verify_message_2(&self.state, &mut self.crypto, valid_cred_r, &i) { + let i = self.i.ok_or(EDHOCError::MissingIdentity)?; + match i_verify_message_2(&self.state, &mut self.crypto, valid_cred_r, i) { Ok(state) => Ok(EdhocInitiatorProcessedM2 { state, cred_i: self.cred_i, @@ -557,7 +585,9 @@ mod test { fn test_new_responder() { let _responder = EdhocResponder::new( default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap(), ); } @@ -579,7 +609,9 @@ mod test { fn test_process_message_1() { let responder = EdhocResponder::new( default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap(), ); @@ -592,7 +624,9 @@ mod test { // responder or initiator let responder = EdhocResponder::new( default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap(), ); @@ -621,7 +655,9 @@ mod test { let responder = EdhocResponder::new( default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, cred_r.clone(), ); // has to select an identity before learning who is I @@ -640,12 +676,14 @@ mod test { // ---- end responder handling // ---- being initiator handling - let (mut initiator, _c_r, id_cred_r, _ead_2) = - initiator.parse_message_2(&message_2).unwrap(); + let (mut initiator, _c_r, details, _ead_2) = initiator.parse_message_2(&message_2).unwrap(); + let ParsedMessage2Details::StatStat { id_cred_r } = details; let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap(); initiator .set_identity( - I.try_into().expect("Wrong length of initiator private key"), + InitiatorIdentity::StatStat { + i: I.try_into().expect("Wrong length of initiator private key"), + }, cred_i.clone(), ) .unwrap(); // exposing own identity only after validating cred_r @@ -740,7 +778,9 @@ mod test_authz { ); let responder = EdhocResponder::new( default_crypto(), - R.try_into().expect("Wrong length of responder private key"), + ResponderIdentity::StatStat { + r: R.try_into().expect("Wrong length of responder private key"), + }, cred_r.clone(), ); @@ -797,15 +837,17 @@ mod test_authz { .prepare_message_2(CredentialTransfer::ByValue, None, &ead_2) .unwrap(); - let (mut initiator, _c_r, id_cred_r, ead_2) = - initiator.parse_message_2(&message_2).unwrap(); + let (mut initiator, _c_r, details, ead_2) = initiator.parse_message_2(&message_2).unwrap(); + let ParsedMessage2Details::StatStat { id_cred_r } = details; let valid_cred_r = credential_check_or_fetch(None, id_cred_r).unwrap(); let result = device.process_ead_2(&mut default_crypto(), ead_2.iter().next().unwrap(), CRED_R); assert!(result.is_ok()); initiator .set_identity( - I.try_into().expect("Wrong length of initiator private key"), + InitiatorIdentity::StatStat { + i: I.try_into().expect("Wrong length of initiator private key"), + }, cred_i.clone(), ) .unwrap(); diff --git a/shared/cbindgen.toml b/shared/cbindgen.toml index 868459a3..21f67fd6 100644 --- a/shared/cbindgen.toml +++ b/shared/cbindgen.toml @@ -137,6 +137,6 @@ include = [ "EdhocBuffer", "BufferKid", "BufferCred", "BufferIdCred", "CredentialKey", "CredentialType", "IdCred", "CredentialTransfer", - "InitiatorStart", "WaitM2", "Completed", "ProcessedM2", "WaitM4", + "InitiatorStart", "WaitM2", "Completed", "WaitM4", "EdhocInitiatorC", "EdhocInitiatorWaitM2C", "EdhocInitiatorProcessingM2C", "EdhocInitiatorProcessedM2C", "EdhocInitiatorDoneC", ] diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 3048df11..bd17e4d0 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -492,6 +492,7 @@ pub struct ResponderStart { #[derive(Debug)] pub struct ProcessingM1 { + pub method: EDHOCMethod, pub y: BytesP256ElemLen, pub g_y: BytesP256ElemLen, pub c_i: ConnId, @@ -502,58 +503,87 @@ pub struct ProcessingM1 { #[derive(Clone, Debug)] #[repr(C)] pub struct WaitM2 { + pub method: EDHOCMethod, pub x: BytesP256ElemLen, // ephemeral private key of the initiator pub h_message_1: BytesHashLen, } - +#[derive(Debug)] +pub enum WaitM3MethodSpecifics { + StatStat {}, + // Psk { cred_r: Credential }, +} #[derive(Debug)] pub struct WaitM3 { + pub method_specifics: WaitM3MethodSpecifics, pub y: BytesP256ElemLen, // ephemeral private key of the responder pub prk_3e2m: BytesHashLen, pub th_3: BytesHashLen, } +/// Method-specific details required to prepare EDHOC message_2. +#[derive(Copy, Clone, Debug)] +pub enum PrepareMessage2Details<'a> { + StatStat { + r: &'a BytesP256ElemLen, + cred_transfer: CredentialTransfer, + }, + // Psk, +} + +#[derive(Debug)] +#[repr(C)] +pub enum ProcessingM2MethodSpecifics { + StatStat { mac_2: BytesMac2, id_cred_r: IdCred }, + // PSK, -- is empty, but in other stages it might have fields that StatStat has not. +} #[derive(Debug)] #[repr(C)] pub struct ProcessingM2 { - pub mac_2: BytesMac2, + pub method_specifics: ProcessingM2MethodSpecifics, pub prk_2e: BytesHashLen, pub th_2: BytesHashLen, pub x: BytesP256ElemLen, pub g_y: BytesP256ElemLen, pub plaintext_2: BufferPlaintext2, pub c_r: ConnId, - pub id_cred_r: IdCred, pub ead_2: EadItems, } +#[derive(Debug)] +pub enum ParsedMessage2Details { + StatStat { id_cred_r: IdCred }, + // Psk { }, +} + +#[derive(Debug)] +#[repr(C)] +pub enum ProcessedM2MethodSpecifics { + StatStat {}, + // Psk { cred_r: Credential }, +} + #[derive(Debug)] #[repr(C)] pub struct ProcessedM2 { + pub method_specifics: ProcessedM2MethodSpecifics, pub prk_3e2m: BytesHashLen, pub prk_4e3m: BytesHashLen, pub th_3: BytesHashLen, } - +#[derive(Debug)] +pub enum ProcessingM3MethodSpecifics { + StatStat { mac_3: BytesMac3, id_cred_i: IdCred }, +} #[derive(Debug)] pub struct ProcessingM3 { - pub mac_3: BytesMac3, + pub method_specifics: ProcessingM3MethodSpecifics, pub y: BytesP256ElemLen, // ephemeral private key of the responder pub prk_3e2m: BytesHashLen, pub th_3: BytesHashLen, - pub id_cred_i: IdCred, pub plaintext_3: BufferPlaintext3, pub ead_3: EadItems, } -#[derive(Debug)] -pub struct PreparingM3 { - pub prk_3e2m: BytesHashLen, - pub prk_4e3m: BytesHashLen, - pub th_3: BytesHashLen, - pub mac_3: BytesMac3, -} - #[derive(Debug)] pub struct ProcessedM3 { pub prk_4e3m: BytesHashLen,