From 153a97efecd2cebfec5e305b5ef021dd93a2fa70 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Thu, 24 Oct 2024 10:09:11 +0200 Subject: [PATCH 01/19] edhoc: Adding functions for message_4 Adding trait to call the edhoc_exporter and edhoc_prk_update either when in state in message 3 or 4. Adding functions to prepare, parse, and process message 4 --- .gitignore | 5 + examples/coap/src/bin/coapclient.rs | 12 +- .../coap/src/bin/coapserver-coaphandler.rs | 8 +- examples/coap/src/bin/coapserver.rs | 8 +- examples/lakers-nrf52840/src/bin/initiator.rs | 41 ++- examples/lakers-nrf52840/src/bin/responder.rs | 26 +- lib/src/edhoc.rs | 290 +++++++++++++++++- lib/src/lib.rs | 148 ++++++++- shared/src/lib.rs | 40 +++ 9 files changed, 524 insertions(+), 54 deletions(-) diff --git a/.gitignore b/.gitignore index bf6e3d0a..a0da5cdb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,8 @@ cscope* .vscode *.log + +color-map-gpi +memory/ +old_results/ +plots/ \ No newline at end of file diff --git a/examples/coap/src/bin/coapclient.rs b/examples/coap/src/bin/coapclient.rs index ae80c7e8..0ee1c656 100644 --- a/examples/coap/src/bin/coapclient.rs +++ b/examples/coap/src/bin/coapclient.rs @@ -60,16 +60,22 @@ fn client_handshake() -> Result<(), EDHOCError> { let initiator = initiator.verify_message_2(valid_cred_r)?; let mut msg_3 = Vec::from(c_r.as_cbor()); - let (mut initiator, message_3, prk_out) = + let (mut initiator, message_3, i_prk_out, i_prk_out_exporter) = initiator.prepare_message_3(CredentialTransfer::ByReference, &None)?; msg_3.extend_from_slice(message_3.as_slice()); println!("message_3 len = {}", msg_3.len()); let _response = CoAPClient::post_with_timeout(url, msg_3, timeout).unwrap(); - // we don't care about the response to message_3 for now + // if response.get_status() != &ResponseType::Changed { + // panic!("Message 3 response error: {:?}", response.get_status()); + // } + // println!("response_vec = {:02x?}", response.message.payload); + // println!("message_3 len = {}", response.message.payload.len()); + // let message_4 = EdhocMessageBuffer::new_from_slice(&response.message.payload[..]).unwrap(); + // let (mut initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); println!("EDHOC exchange successfully completed"); - println!("PRK_out: {:02x?}", prk_out); + println!("PRK_out: {:02x?}", i_prk_out); let mut oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0 let mut oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1 diff --git a/examples/coap/src/bin/coapserver-coaphandler.rs b/examples/coap/src/bin/coapserver-coaphandler.rs index 895982ec..8f335e08 100644 --- a/examples/coap/src/bin/coapserver-coaphandler.rs +++ b/examples/coap/src/bin/coapserver-coaphandler.rs @@ -180,14 +180,16 @@ impl coap_handler::Handler for EdhocHandler { let cred_i = Credential::parse_ccs(CRED_I.try_into().expect("Static credential is too large")) .expect("Static credential is not processable"); - let valid_cred_i = + let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).map_err(render_error)?; - let (mut responder, prk_out) = + let (responder, prk_out, prk_exporter) = responder.verify_message_3(valid_cred_i).map_err(|e| { println!("EDHOC processing error: {:?}", e); render_error(e) })?; - + + let ead_4 = None; + let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); println!("EDHOC exchange successfully completed"); println!("PRK_out: {:02x?}", prk_out); diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index a114dc67..b82c3786 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -108,16 +108,20 @@ fn main() { }; let cred_i = Credential::parse_ccs(CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - let Ok((mut responder, prk_out)) = responder.verify_message_3(valid_cred_i) else { + let Ok((mut responder, r_prk_out, r_prk_exporter)) = responder.verify_message_3(valid_cred_i) else { println!("EDHOC error at verify_message_3: {:?}", valid_cred_i); continue; }; + // let ead_4 = None; + // let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); + // send empty ack back + response.message.payload = b"".to_vec(); // send empty ack back response.message.payload = b"".to_vec(); println!("EDHOC exchange successfully completed"); - println!("PRK_out: {:02x?}", prk_out); + println!("PRK_out: {:02x?}", r_prk_out); let mut _oscore_secret = responder.edhoc_exporter(0u8, &[], 16); // label is 0 println!("OSCORE secret: {:02x?}", _oscore_secret); diff --git a/examples/lakers-nrf52840/src/bin/initiator.rs b/examples/lakers-nrf52840/src/bin/initiator.rs index 1171b6c0..2452cd4b 100644 --- a/examples/lakers-nrf52840/src/bin/initiator.rs +++ b/examples/lakers-nrf52840/src/bin/initiator.rs @@ -86,25 +86,42 @@ async fn main(spawner: Spawner) { match rcvd { Ok(pckt_2) => { + info!("Received message_2"); let message_2: EdhocMessageBuffer = pckt_2.pdu[1..pckt_2.len].try_into().expect("wrong length"); let (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(valid_cred_r).unwrap(); + let initiator = initiator + .verify_message_2(valid_cred_r) + .unwrap(); - let (mut initiator, message_3, i_prk_out) = initiator + let (mut initiator, message_3, i_prk_out, i_prk_out_exporter) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); - - common::transmit_without_response( - &mut radio, - common::Packet::new_from_slice(message_3.as_slice(), Some(c_r.as_slice()[0])) - .unwrap(), - ) - .await; - - info!("Handshake completed. prk_out = {:X}", i_prk_out); + let pckt_3 = common::Packet::new_from_slice(message_3.as_slice(), Some(c_r.as_slice()[0])) + .expect("Buffer not long enough"); + info!("Send message_3 and wait message_4"); + let rcvd = common::transmit_and_wait_response( + &mut radio, + pckt_3, + Some(c_r.as_slice()[0]), + ).await; + + info!("Sent message_3"); + match rcvd { + Ok(pckt_4) => { + info!("Received message_4"); + let message_4: EdhocMessageBuffer = + pckt_4.pdu[1..pckt_4.len].try_into().expect("wrong length"); + + let (initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); + + info!("Handshake completed. prk_out = {:X}", i_prk_out); + } + Err(_) => panic!("parsing error"), + } } Err(_) => panic!("parsing error"), } -} + +} \ No newline at end of file diff --git a/examples/lakers-nrf52840/src/bin/responder.rs b/examples/lakers-nrf52840/src/bin/responder.rs index 2c086bae..820b265a 100644 --- a/examples/lakers-nrf52840/src/bin/responder.rs +++ b/examples/lakers-nrf52840/src/bin/responder.rs @@ -117,24 +117,30 @@ async fn main(spawner: Spawner) { // anyway legally continue; }; - - let cred_i = - Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); + let cred_i: Credential = + Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - - let Ok((responder, prk_out)) = responder.verify_message_3(valid_cred_i) + let Ok((responder, r_prk_out, r_prk_exporter)) = responder.verify_message_3(valid_cred_i) else { - info!("EDHOC error at verify_message_3"); + info!("EDHOC error at parse_message_3"); continue; }; - info!("Handshake completed. prk_out: {:X}", prk_out); + info!("Prepare message_4"); + let ead_4 = None; + let (responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); - unwrap!(spawner.spawn(example_application_task(prk_out))); + info!("Send message_4"); + common::transmit_without_response( + &mut radio, + common::Packet::new_from_slice(message_4.as_slice(),Some(c_r.unwrap().as_slice()[0])) + .unwrap(), + ).await; + + info!("Handshake completed. prk_out = {:X}", r_prk_out); } else { info!("Another packet interrupted the handshake."); - continue; } } Err(PacketError::TimeoutError) => info!("Timeout while waiting for message_3!"), @@ -144,6 +150,8 @@ async fn main(spawner: Spawner) { } } + + #[embassy_executor::task] async fn example_application_task(secret: BytesHashLen) { info!( diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 446f264d..58d47fe6 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,7 +1,51 @@ use lakers_shared::{Crypto as CryptoTrait, *}; +// Implementation of edhoc_exporter for 3 or 4 messages +pub trait StateDone { + fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN]; + fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN]; + fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN]; +} +// Implement for different states +impl StateDone for WaitM4 { + fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_exporter + } + fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { + &mut self.prk_out + } + fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_out + } +} + +// Implement for both state types +impl StateDone for Completed { + fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_exporter + } + fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { + &mut self.prk_out + } + fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_out + } +} + +impl StateDone for ProcessedM3 { + fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_exporter + } + fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { + &mut self.prk_out + } + fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { + &self.prk_out + } +} + pub fn edhoc_exporter( - state: &Completed, + state: &impl StateDone, crypto: &mut impl CryptoTrait, label: u8, context: &BytesMaxContextBuffer, @@ -10,7 +54,7 @@ pub fn edhoc_exporter( ) -> BytesMaxBuffer { edhoc_kdf( crypto, - &state.prk_exporter, + state.get_prk_exporter(), label, context, context_len, @@ -19,34 +63,42 @@ pub fn edhoc_exporter( } pub fn edhoc_key_update( - state: &mut Completed, + state: &mut impl StateDone, crypto: &mut impl CryptoTrait, context: &BytesMaxContextBuffer, context_len: usize, ) -> BytesHashLen { // new PRK_out + let mut prk_out = *state.get_prk_out(); + let mut prk_exporter = *state.get_prk_exporter(); let prk_new_buf = edhoc_kdf( crypto, - &state.prk_out, + &prk_out, 11u8, context, context_len, SHA256_DIGEST_LEN, ); - state.prk_out[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + // state.get_prk_out_mut()[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + prk_out.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); // new PRK_exporter let prk_new_buf = edhoc_kdf( crypto, - &state.prk_out, + &prk_out, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], 0, SHA256_DIGEST_LEN, ); - state.prk_exporter[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + // state.get_prk_exporter()[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + prk_exporter.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); - state.prk_out + // Update state + state.get_prk_out_mut().copy_from_slice(&prk_out); + state.get_prk_out_mut().copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + + prk_out } pub fn r_process_message_1( @@ -184,7 +236,7 @@ pub fn r_verify_message_3( state: &mut ProcessingM3, crypto: &mut impl CryptoTrait, valid_cred_i: Credential, -) -> Result<(Completed, BytesHashLen), EDHOCError> { +) -> Result<(ProcessedM3, BytesHashLen, BytesHashLen), EDHOCError> { // compute salt_4e3m let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3); @@ -243,17 +295,38 @@ pub fn r_verify_message_3( prk_exporter[..SHA256_DIGEST_LEN].copy_from_slice(&prk_exporter_buf[..SHA256_DIGEST_LEN]); Ok(( - Completed { - prk_out, - prk_exporter, + ProcessedM3 { + prk_4e3m: prk_4e3m, + th_4: th_4, + prk_out: prk_out, + prk_exporter: prk_exporter }, prk_out, + prk_exporter, )) } else { Err(EDHOCError::MacVerificationFailed) } } +pub fn r_prepare_message_4( + state: &ProcessedM3, + crypto: &mut impl CryptoTrait, + ead_4: &Option, // FIXME: make it a list of EADItem +) -> Result<(Completed, BufferMessage4), EDHOCError> { + // compute ciphertext_4 + let plaintext_4 = encode_plaintext_4(&ead_4)?; + let message_4 = encrypt_message_4(crypto, &state.prk_4e3m, &state.th_4, &plaintext_4); + + Ok(( + Completed { + prk_out: state.prk_out, + prk_exporter: state.prk_exporter, + }, + message_4, + )) +} + pub fn i_prepare_message_1( state: &InitiatorStart, crypto: &mut impl CryptoTrait, @@ -377,7 +450,7 @@ pub fn i_prepare_message_3( cred_i: Credential, cred_transfer: CredentialTransfer, ead_3: &Option, // FIXME: make it a list of EADItem -) -> Result<(Completed, BufferMessage3, BytesHashLen), EDHOCError> { +) -> Result<(WaitM4, BufferMessage3, BytesHashLen, BytesHashLen), EDHOCError> { let id_cred_i = match cred_transfer { CredentialTransfer::ByValue => cred_i.by_value()?, CredentialTransfer::ByReference => cred_i.by_kid()?, @@ -427,15 +500,40 @@ pub fn i_prepare_message_3( prk_exporter[..SHA256_DIGEST_LEN].copy_from_slice(&prk_exporter_buf[..SHA256_DIGEST_LEN]); Ok(( - Completed { - prk_out, - prk_exporter, + WaitM4 { + prk_4e3m: state.prk_4e3m, + th_4: th_4, + prk_out: prk_out, + prk_exporter: prk_exporter, }, message_3, prk_out, + prk_exporter, )) } +pub fn i_process_message_4( + state: &mut WaitM4, + crypto: &mut impl CryptoTrait, + message_4: &BufferMessage4, +) -> Result<(Completed, Option), EDHOCError> { + + let plaintext_4 = decrypt_message_4(crypto, &state.prk_4e3m, &state.th_4, &message_4)?; + let decoded_p4_res = decode_plaintext_4(&plaintext_4); + + if let Ok(ead_4) = decoded_p4_res { + Ok(( + Completed { + prk_out: state.prk_out, + prk_exporter: state.prk_exporter, + }, + ead_4, + )) + } else { + Err(decoded_p4_res.unwrap_err()) + } +} + fn encode_ead_item(ead_1: &EADItem) -> Result { let mut output = EdhocMessageBuffer::new(); @@ -642,6 +740,24 @@ fn encode_plaintext_3( } } +fn encode_plaintext_4( + ead_4: &Option, +) -> Result { + let mut plaintext_4: BufferPlaintext4 = BufferPlaintext4::new(); + + if let Some(ead_4) = ead_4 { + match encode_ead_item(ead_4) { + Ok(ead_4) => plaintext_4 + .extend_from_slice(ead_4.as_slice()) + .and(Ok(plaintext_4)) + .or(Err(EDHOCError::EadTooLongError)), + Err(e) => Err(e), + } + } else { + Ok(plaintext_4) + } +} + fn encode_enc_structure(th_3: &BytesHashLen) -> BytesEncStructureLen { let mut encrypt0: Bytes8 = [0x00; 8]; encrypt0[0] = 0x45u8; // 'E' @@ -694,6 +810,33 @@ fn compute_k_3_iv_3( (k_3, iv_3) } +fn compute_k_4_iv_4( + crypto: &mut impl CryptoTrait, + prk_4e3m: &BytesHashLen, + th_4: &BytesHashLen, +) -> (BytesCcmKeyLen, BytesCcmIvLen) { + // K_4 = EDHOC-KDF( PRK_4e3m, ?? , TH_4, key_length ) + let mut k_4: BytesCcmKeyLen = [0x00; AES_CCM_KEY_LEN]; + let mut th_4_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; + th_4_buf[..th_4.len()].copy_from_slice(&th_4[..]); + let k_4_buf = edhoc_kdf( + crypto, + prk_4e3m, + 8u8, // FIXME + &th_4_buf, + th_4.len(), + AES_CCM_KEY_LEN, + ); + k_4[..].copy_from_slice(&k_4_buf[..AES_CCM_KEY_LEN]); + + // IV_3 = EDHOC-KDF( PRK_4e3m, ?? , TH_4, iv_length ) + let mut iv_4: BytesCcmIvLen = [0x00; AES_CCM_IV_LEN]; + let iv_4_buf = edhoc_kdf(crypto, prk_4e3m, 9u8, &th_4_buf, th_4.len(), AES_CCM_IV_LEN); + iv_4[..].copy_from_slice(&iv_4_buf[..AES_CCM_IV_LEN]); + + (k_4, iv_4) +} + // calculates ciphertext_3 wrapped in a cbor byte string fn encrypt_message_3( crypto: &mut impl CryptoTrait, @@ -763,6 +906,74 @@ fn decrypt_message_3( crypto.aes_ccm_decrypt_tag_8(&k_3, &iv_3, &enc_structure, &ciphertext_3) } +fn encrypt_message_4( + crypto: &mut impl CryptoTrait, + prk_4e3m: &BytesHashLen, + th_4: &BytesHashLen, + plaintext_4: &BufferPlaintext4, +) -> BufferMessage4 { + let mut output: BufferMessage4 = BufferMessage4::new(); + let bytestring_length = plaintext_4.len + AES_CCM_TAG_LEN; + let prefix_length; + // FIXME: Reuse CBOR encoder + if bytestring_length < 24 { + output.content[0] = CBOR_MAJOR_BYTE_STRING | (bytestring_length) as u8; + prefix_length = 1; + } else { + // FIXME: Assumes we don't exceed 256 bytes which is the current buffer size + output.content[0] = CBOR_MAJOR_BYTE_STRING | 24; + output.content[1] = bytestring_length as _; + prefix_length = 2; + }; + output.len = prefix_length + bytestring_length; + // FIXME: Make the function fallible, especially with the prospect of algorithm agility + assert!( + output.len <= MAX_MESSAGE_SIZE_LEN, + "Tried to encode a message that is too large." + ); + + let enc_structure = encode_enc_structure(th_4); + + let (k_4, iv_4) = compute_k_4_iv_4(crypto, prk_4e3m, th_4); + + let ciphertext_4 = crypto.aes_ccm_encrypt_tag_8(&k_4, &iv_4, &enc_structure[..], plaintext_4); + + output.content[prefix_length..][..ciphertext_4.len].copy_from_slice(ciphertext_4.as_slice()); + + output +} + +fn decrypt_message_4( + crypto: &mut impl CryptoTrait, + prk_4e3m: &BytesHashLen, + th_4: &BytesHashLen, + message_4: &BufferMessage4, +) -> Result { + // decode message_3 + let bytestring_length: usize; + let prefix_length; + // FIXME: Reuse CBOR decoder + if (0..=23).contains(&(message_4.content[0] ^ CBOR_MAJOR_BYTE_STRING)) { + bytestring_length = (message_4.content[0] ^ CBOR_MAJOR_BYTE_STRING).into(); + prefix_length = 1; + } else { + // FIXME: Assumes we don't exceed 256 bytes which is the current buffer size + bytestring_length = message_4.content[1].into(); + prefix_length = 2; + } + + let mut ciphertext_4: BufferCiphertext4 = BufferCiphertext4::new(); + ciphertext_4.len = bytestring_length; + ciphertext_4.content[..bytestring_length] + .copy_from_slice(&message_4.content[prefix_length..][..bytestring_length]); + + let (k_4, iv_4) = compute_k_4_iv_4(crypto, prk_4e3m, th_4); + + let enc_structure = encode_enc_structure(th_4); + + crypto.aes_ccm_decrypt_tag_8(&k_4, &iv_4, &enc_structure, &ciphertext_4) +} + // output must hold id_cred.len() + cred.len() fn encode_kdf_context( c_r: Option, // only present for MAC_2 @@ -1069,6 +1280,11 @@ mod tests { const MESSAGE_3_TV: &str = "52e562097bc417dd5919485ac7891ffd90a9fc"; const PRK_4E3M_TV: BytesP256ElemLen = hex!("81cc8a298e357044e3c466bb5c0a1e507e01d49238aeba138df94635407c0ff7"); + const MESSAGE_4_TV: &str = "4828c966b7ca304f83"; + const CIPHERTEXT_4_TV: &str = "28c966b7ca304f83"; + const PLAINTEXT_4_TV: &str = ""; + const K_4_TV: BytesCcmKeyLen = hex!("d3c77872b6eeb508911bdbd308b2e6a0"); + const IV_4_TV: BytesCcmIvLen = hex!("04ff0f44456e96e217853c3601"); const CRED_I_TV : [u8; 107] = hex!("a2027734322d35302d33312d46462d45462d33372d33322d333908a101a5010202412b2001215820ac75e9ece3e50bfc8ed60399889522405c47bf16df96660a41298cb4307f7eb62258206e5de611388a4b8a8211334ac7d37ecb52a387d257e6db3c2a93df21ff3affc8"); const ID_CRED_R_TV: BytesIdCred = hex!("a1044132"); const CRED_R_TV : [u8; 95] = hex!("a2026b6578616d706c652e65647508a101a501020241322001215820bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f02258204519e257236b2a0ce2023f0931f1f386ca7afda64fcde0108c224c51eabf6072"); @@ -1433,6 +1649,48 @@ mod tests { } } + #[test] + fn test_decode_plaintext_4() { + let plaintext_4_tv = BufferPlaintext2::from_hex(PLAINTEXT_4_TV); + + let plaintext_4 = decode_plaintext_4(&plaintext_4_tv); + assert!(plaintext_4.is_ok()); + let (ead_4) = plaintext_4.unwrap(); + assert!(ead_4.is_none()); + } + + #[test] + fn test_encrypt_message_4() { + let plaintext_4_tv = BufferPlaintext4::from_hex(PLAINTEXT_4_TV); + let message_4_tv = BufferMessage4::from_hex(MESSAGE_4_TV); + + let message_4 = encrypt_message_4( + &mut default_crypto(), + &PRK_4E3M_TV, + &TH_4_TV, + &plaintext_4_tv, + ); + assert_eq!(message_4, message_4_tv); + } + + #[test] + fn test_decrypt_message_4() { + let plaintext_4_tv = BufferPlaintext4::from_hex(PLAINTEXT_4_TV); + let message_4_tv = BufferMessage3::from_hex(MESSAGE_4_TV); + + let plaintext_4 = + decrypt_message_4(&mut default_crypto(), &PRK_4E3M_TV, &TH_4_TV, &message_4_tv); + assert!(plaintext_4.is_ok()); + assert_eq!(plaintext_4.unwrap(), plaintext_4_tv); + } + + #[test] + fn test_compute_k_4_iv_4() { + let (k_4, iv_4) = compute_k_4_iv_4(&mut default_crypto(), &PRK_4E3M_TV, &TH_4_TV); + assert_eq!(k_4, K_4_TV); + assert_eq!(iv_4, IV_4_TV); + } + #[test] fn test_compute_prk_4e3m() { let prk_4e3m = compute_prk_4e3m(&mut default_crypto(), &SALT_4E3M_TV, &SK_I_TV, &G_Y_TV); diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 4e0a8139..017e900d 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -56,6 +56,12 @@ pub struct EdhocInitiatorProcessedM2 { crypto: Crypto, } +#[derive(Debug)] +pub struct EdhocInitiatorWaitM4 { + state: WaitM4, // opaque state + crypto: Crypto, +} + #[derive(Debug)] pub struct EdhocInitiatorDone { state: Completed, @@ -91,6 +97,12 @@ pub struct EdhocResponderProcessingM3 { crypto: Crypto, } +#[derive(Debug)] +pub struct EdhocResponderProcessedM3 { + state: ProcessedM3, // opaque state + crypto: Crypto, +} + #[derive(Debug)] pub struct EdhocResponderDone { state: Completed, @@ -197,21 +209,77 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderProcessingM3 { pub fn verify_message_3( mut self, cred_i: Credential, - ) -> Result<(EdhocResponderDone, [u8; SHA256_DIGEST_LEN]), EDHOCError> { + ) -> Result<(EdhocResponderProcessedM3, [u8; SHA256_DIGEST_LEN], [u8; SHA256_DIGEST_LEN]), EDHOCError> { trace!("Enter verify_message_3"); match r_verify_message_3(&mut self.state, &mut self.crypto, cred_i) { - Ok((state, prk_out)) => Ok(( - EdhocResponderDone { + Ok((state, prk_out, prk_exporter)) => Ok(( + EdhocResponderProcessedM3 { state, crypto: self.crypto, }, prk_out, + prk_exporter, )), Err(error) => Err(error), } } } +impl EdhocResponderProcessedM3 { + pub fn prepare_message_4( + mut self, + ead_4: &Option, + ) -> Result<( + EdhocResponderDone, + BufferMessage4 + ), EDHOCError> { + trace!("Enter prepare_message_4"); + match r_prepare_message_4( + &self.state, + &mut self.crypto, + ead_4, + ) { + Ok((state, message_4)) => Ok(( + EdhocResponderDone { + state, + crypto: self.crypto, + }, + message_4, + )), + Err(error) => Err(error), + } + } + pub fn edhoc_exporter( + &mut self, + label: u8, + context: &[u8], + length: usize, + ) -> [u8; MAX_BUFFER_LEN] { + let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + edhoc_exporter( + &self.state, + &mut self.crypto, + label, + &context_buf, + context.len(), + length, + ) + } + pub fn edhoc_key_update(&mut self, context: &[u8]) -> [u8; SHA256_DIGEST_LEN] { + let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + edhoc_key_update( + &mut self.state, + &mut self.crypto, + &context_buf, + context.len(), + ) + } +} + impl EdhocResponderDone { pub fn edhoc_exporter( &mut self, @@ -374,9 +442,10 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessedM2 { ead_3: &Option, ) -> Result< ( - EdhocInitiatorDone, + EdhocInitiatorWaitM4, BufferMessage3, [u8; SHA256_DIGEST_LEN], + [u8; SHA256_DIGEST_LEN], ), EDHOCError, > { @@ -391,17 +460,73 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessedM2 { cred_transfer, ead_3, ) { - Ok((state, message_3, prk_out)) => Ok(( - EdhocInitiatorDone { + Ok((state, message_3, prk_out, prk_exporter)) => Ok(( + EdhocInitiatorWaitM4 { state, crypto: self.crypto, }, message_3, prk_out, + prk_exporter, + )), + Err(error) => Err(error), + } + } +} + +impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM4 { + pub fn process_message_4( + mut self, + message_4: &'a BufferMessage4, + ) -> Result< + ( + EdhocInitiatorDone, + Option, + ), + EDHOCError, + > { + trace!("Enter parse_message_4"); + match i_process_message_4(&mut self.state, &mut self.crypto, message_4) { + Ok((state, ead_4)) => Ok (( + EdhocInitiatorDone { + state: state, + crypto: self.crypto, + }, + ead_4, )), Err(error) => Err(error), } } + pub fn edhoc_exporter( + &mut self, + label: u8, + context: &[u8], + length: usize, + ) -> [u8; MAX_BUFFER_LEN] { + let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + edhoc_exporter( + &self.state, + &mut self.crypto, + label, + &context_buf, + context.len(), + length, + ) + } + + pub fn edhoc_key_update(&mut self, context: &[u8]) -> [u8; SHA256_DIGEST_LEN] { + let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + edhoc_key_update( + &mut self.state, + &mut self.crypto, + &context_buf, + context.len(), + ) + } } impl EdhocInitiatorDone { @@ -648,7 +773,7 @@ mod test { let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); // if needed: prepare ead_3 - let (mut initiator, message_3, i_prk_out) = initiator + let (mut initiator, message_3, i_prk_out, i_prk_exporter) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); // ---- end initiator handling @@ -656,10 +781,15 @@ mod test { // ---- begin responder handling 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, r_prk_exporter) = responder.verify_message_3(valid_cred_i).unwrap(); + + // Send message_4 + let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); // ---- end responder handling + let (mut initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); + // ---- end initiator handling + // check that prk_out is equal at initiator and responder side assert_eq!(i_prk_out, r_prk_out); diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 17473a71..a0b41147 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -101,12 +101,15 @@ pub type BytesCcmKeyLen = [u8; AES_CCM_KEY_LEN]; pub type BytesCcmIvLen = [u8; AES_CCM_IV_LEN]; pub type BufferPlaintext2 = EdhocMessageBuffer; pub type BufferPlaintext3 = EdhocMessageBuffer; +pub type BufferPlaintext4 = EdhocMessageBuffer; pub type BytesMac2 = [u8; MAC_LENGTH_2]; pub type BytesMac3 = [u8; MAC_LENGTH_3]; pub type BufferMessage1 = EdhocMessageBuffer; pub type BufferMessage3 = EdhocMessageBuffer; +pub type BufferMessage4 = EdhocMessageBuffer; pub type BufferCiphertext2 = EdhocMessageBuffer; pub type BufferCiphertext3 = EdhocMessageBuffer; +pub type BufferCiphertext4 = EdhocMessageBuffer; pub type BytesHashLen = [u8; SHA256_DIGEST_LEN]; pub type BytesP256ElemLen = [u8; P256_ELEM_LEN]; pub type BufferMessage2 = EdhocMessageBuffer; @@ -395,6 +398,22 @@ pub struct PreparingM3 { pub mac_3: BytesMac3, } +#[derive(Debug)] +pub struct ProcessedM3 { + pub prk_4e3m: BytesHashLen, + pub th_4: BytesHashLen, + pub prk_out: BytesHashLen, + pub prk_exporter: BytesHashLen, +} + +#[derive(Debug)] +pub struct WaitM4 { + pub prk_4e3m: BytesHashLen, + pub th_4: BytesHashLen, + pub prk_out: BytesHashLen, + pub prk_exporter: BytesHashLen, +} + #[derive(Default, Debug)] #[repr(C)] pub struct Completed { @@ -791,6 +810,27 @@ mod edhoc_parser { Err(EDHOCError::ParsingError) } } + + pub fn decode_plaintext_4( + plaintext_4: &BufferPlaintext4, + ) -> Result, EDHOCError> { + trace!("Enter decode_plaintext_4"); + let decoder = CBORDecoder::new(plaintext_4.as_slice()); + + if plaintext_4.len > decoder.position() { + // assume only one EAD item + let ead_res = parse_ead(decoder.remaining_buffer()?); + if let Ok(ead_4) = ead_res { + Ok(ead_4) + } else { + Err(ead_res.unwrap_err()) + } + } else if decoder.finished() { + Ok(None) + } else { + Err(EDHOCError::ParsingError) + } + } } mod cbor_decoder { From 16407d47516f5938dfb27b16aa49a1d61b367966 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Thu, 24 Oct 2024 11:41:15 +0200 Subject: [PATCH 02/19] examples: fix errors, add cryptocell, add explanantions --- .gitignore | 5 +-- examples/coap/src/bin/coapclient.rs | 20 ++++----- .../coap/src/bin/coapserver-coaphandler.rs | 4 +- examples/coap/src/bin/coapserver.rs | 13 +++--- examples/lakers-nrf52840/.cargo/config.toml | 2 +- examples/lakers-nrf52840/Cargo.toml | 2 +- examples/lakers-nrf52840/src/bin/initiator.rs | 43 +++++++++---------- examples/lakers-nrf52840/src/bin/responder.rs | 31 +++++++------ lib/src/edhoc.rs | 29 ++++++------- lib/src/lib.rs | 33 ++++++-------- shared/src/lib.rs | 2 +- 11 files changed, 86 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index a0da5cdb..8648d64b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,4 @@ cscope* *.log -color-map-gpi -memory/ -old_results/ -plots/ \ No newline at end of file +results/ \ No newline at end of file diff --git a/examples/coap/src/bin/coapclient.rs b/examples/coap/src/bin/coapclient.rs index 0ee1c656..06463947 100644 --- a/examples/coap/src/bin/coapclient.rs +++ b/examples/coap/src/bin/coapclient.rs @@ -60,22 +60,22 @@ fn client_handshake() -> Result<(), EDHOCError> { let initiator = initiator.verify_message_2(valid_cred_r)?; let mut msg_3 = Vec::from(c_r.as_cbor()); - let (mut initiator, message_3, i_prk_out, i_prk_out_exporter) = + let (mut initiator, message_3, prk_out, prk_out_exporter) = initiator.prepare_message_3(CredentialTransfer::ByReference, &None)?; msg_3.extend_from_slice(message_3.as_slice()); println!("message_3 len = {}", msg_3.len()); - let _response = CoAPClient::post_with_timeout(url, msg_3, timeout).unwrap(); - // if response.get_status() != &ResponseType::Changed { - // panic!("Message 3 response error: {:?}", response.get_status()); - // } - // println!("response_vec = {:02x?}", response.message.payload); - // println!("message_3 len = {}", response.message.payload.len()); - // let message_4 = EdhocMessageBuffer::new_from_slice(&response.message.payload[..]).unwrap(); - // let (mut initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); + let response = CoAPClient::post_with_timeout(url, msg_3, timeout).unwrap(); + if response.get_status() != &ResponseType::Changed { + panic!("Message 3 response error: {:?}", response.get_status()); + } + println!("response_vec = {:02x?}", response.message.payload); + println!("message_3 len = {}", response.message.payload.len()); + let message_4 = EdhocMessageBuffer::new_from_slice(&response.message.payload[..]).unwrap(); + let (mut initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); println!("EDHOC exchange successfully completed"); - println!("PRK_out: {:02x?}", i_prk_out); + println!("PRK_out: {:02x?}", prk_out); let mut oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0 let mut oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1 diff --git a/examples/coap/src/bin/coapserver-coaphandler.rs b/examples/coap/src/bin/coapserver-coaphandler.rs index 8f335e08..2ec821ac 100644 --- a/examples/coap/src/bin/coapserver-coaphandler.rs +++ b/examples/coap/src/bin/coapserver-coaphandler.rs @@ -180,14 +180,14 @@ impl coap_handler::Handler for EdhocHandler { let cred_i = Credential::parse_ccs(CRED_I.try_into().expect("Static credential is too large")) .expect("Static credential is not processable"); - let valid_cred_i = + let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).map_err(render_error)?; let (responder, prk_out, prk_exporter) = responder.verify_message_3(valid_cred_i).map_err(|e| { println!("EDHOC processing error: {:?}", e); render_error(e) })?; - + let ead_4 = None; let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); println!("EDHOC exchange successfully completed"); diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index b82c3786..f97dbd25 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -108,20 +108,19 @@ fn main() { }; let cred_i = Credential::parse_ccs(CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - let Ok((mut responder, r_prk_out, r_prk_exporter)) = responder.verify_message_3(valid_cred_i) else { + let Ok((mut responder, prk_out, prk_exporter)) = + responder.verify_message_3(valid_cred_i) + else { println!("EDHOC error at verify_message_3: {:?}", valid_cred_i); continue; }; - // let ead_4 = None; - // let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); - // send empty ack back - response.message.payload = b"".to_vec(); - + let ead_4 = None; + let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); // send empty ack back response.message.payload = b"".to_vec(); println!("EDHOC exchange successfully completed"); - println!("PRK_out: {:02x?}", r_prk_out); + println!("PRK_out: {:02x?}", prk_out); let mut _oscore_secret = responder.edhoc_exporter(0u8, &[], 16); // label is 0 println!("OSCORE secret: {:02x?}", _oscore_secret); diff --git a/examples/lakers-nrf52840/.cargo/config.toml b/examples/lakers-nrf52840/.cargo/config.toml index 17616a05..066c5164 100644 --- a/examples/lakers-nrf52840/.cargo/config.toml +++ b/examples/lakers-nrf52840/.cargo/config.toml @@ -3,7 +3,7 @@ runner = "probe-rs run --chip nRF52840_xxAA" [build] -target = "thumbv7em-none-eabi" +target = "thumbv7em-none-eabihf" [env] DEFMT_LOG = "trace" diff --git a/examples/lakers-nrf52840/Cargo.toml b/examples/lakers-nrf52840/Cargo.toml index 1e882943..6a7e5dce 100644 --- a/examples/lakers-nrf52840/Cargo.toml +++ b/examples/lakers-nrf52840/Cargo.toml @@ -34,7 +34,7 @@ cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } [features] -default = [ "crypto-psa", "ead-none" ] +default = [ "crypto-cryptocell310", "ead-none" ] crypto-cryptocell310 = [ "lakers-crypto/cryptocell310" ] crypto-psa = [ "lakers-crypto/psa-baremetal" ] ead-none = [ ] diff --git a/examples/lakers-nrf52840/src/bin/initiator.rs b/examples/lakers-nrf52840/src/bin/initiator.rs index 2452cd4b..2a5f321f 100644 --- a/examples/lakers-nrf52840/src/bin/initiator.rs +++ b/examples/lakers-nrf52840/src/bin/initiator.rs @@ -59,12 +59,12 @@ async fn main(spawner: Spawner) { info!("init_handshake"); // Memory buffer for mbedtls - #[cfg(feature = "crypto-psa")] - let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - #[cfg(feature = "crypto-psa")] - unsafe { - mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); - } + // #[cfg(feature = "crypto-psa")] + // let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; + // #[cfg(feature = "crypto-psa")] + // unsafe { + // mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); + // } let cred_i = Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); let cred_r = Credential::parse_ccs(common::CRED_R.try_into().unwrap()).unwrap(); @@ -81,47 +81,44 @@ async fn main(spawner: Spawner) { let (initiator, message_1) = initiator.prepare_message_1(Some(c_i), &None).unwrap(); let pckt_1 = common::Packet::new_from_slice(message_1.as_slice(), Some(0xf5)) .expect("Buffer not long enough"); - let rcvd = common::transmit_and_wait_response(&mut radio, pckt_1, Some(0xf5)).await; match rcvd { Ok(pckt_2) => { info!("Received message_2"); let message_2: EdhocMessageBuffer = + // starts in 1 to consider only the content and not the metadata pckt_2.pdu[1..pckt_2.len].try_into().expect("wrong length"); + info!("message_2 :{:?}", message_2.content); let (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(valid_cred_r) - .unwrap(); + let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); let (mut initiator, message_3, i_prk_out, i_prk_out_exporter) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); - let pckt_3 = common::Packet::new_from_slice(message_3.as_slice(), Some(c_r.as_slice()[0])) - .expect("Buffer not long enough"); + let pckt_3 = + common::Packet::new_from_slice(message_3.as_slice(), Some(c_r.as_slice()[0])) + .expect("Buffer not long enough"); info!("Send message_3 and wait message_4"); - let rcvd = common::transmit_and_wait_response( - &mut radio, - pckt_3, - Some(c_r.as_slice()[0]), - ).await; - + let rcvd = + common::transmit_and_wait_response(&mut radio, pckt_3, Some(c_r.as_slice()[0])) + .await; + info!("Sent message_3"); match rcvd { Ok(pckt_4) => { info!("Received message_4"); let message_4: EdhocMessageBuffer = pckt_4.pdu[1..pckt_4.len].try_into().expect("wrong length"); - + let (initiator, ead_4) = initiator.process_message_4(&message_4).unwrap(); - + info!("Handshake completed. prk_out = {:X}", i_prk_out); - } + } Err(_) => panic!("parsing error"), } } Err(_) => panic!("parsing error"), } - -} \ No newline at end of file +} diff --git a/examples/lakers-nrf52840/src/bin/responder.rs b/examples/lakers-nrf52840/src/bin/responder.rs index 820b265a..ef617c2a 100644 --- a/examples/lakers-nrf52840/src/bin/responder.rs +++ b/examples/lakers-nrf52840/src/bin/responder.rs @@ -53,12 +53,12 @@ async fn main(spawner: Spawner) { radio.set_crc_poly(CRC_POLY); // Memory buffer for mbedtls - #[cfg(feature = "crypto-psa")] - let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - #[cfg(feature = "crypto-psa")] - unsafe { - mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); - } + // #[cfg(feature = "crypto-psa")] + // let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; + // #[cfg(feature = "crypto-psa")] + // unsafe { + // mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); + // } loop { let mut buffer: [u8; MAX_PDU] = [0x00u8; MAX_PDU]; @@ -117,11 +117,12 @@ async fn main(spawner: Spawner) { // anyway legally continue; }; - let cred_i: Credential = - Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); + let cred_i: Credential = + Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - let Ok((responder, r_prk_out, r_prk_exporter)) = responder.verify_message_3(valid_cred_i) + let Ok((responder, r_prk_out, r_prk_exporter)) = + responder.verify_message_3(valid_cred_i) else { info!("EDHOC error at parse_message_3"); continue; @@ -134,9 +135,13 @@ async fn main(spawner: Spawner) { info!("Send message_4"); common::transmit_without_response( &mut radio, - common::Packet::new_from_slice(message_4.as_slice(),Some(c_r.unwrap().as_slice()[0])) - .unwrap(), - ).await; + common::Packet::new_from_slice( + message_4.as_slice(), + Some(c_r.unwrap().as_slice()[0]), + ) + .unwrap(), + ) + .await; info!("Handshake completed. prk_out = {:X}", r_prk_out); } else { @@ -150,8 +155,6 @@ async fn main(spawner: Spawner) { } } - - #[embassy_executor::task] async fn example_application_task(secret: BytesHashLen) { info!( diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 58d47fe6..1a19bb91 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,13 +1,13 @@ use lakers_shared::{Crypto as CryptoTrait, *}; // Implementation of edhoc_exporter for 3 or 4 messages -pub trait StateDone { +pub trait Done { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN]; fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN]; fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN]; } // Implement for different states -impl StateDone for WaitM4 { +impl Done for WaitM4 { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } @@ -20,7 +20,7 @@ impl StateDone for WaitM4 { } // Implement for both state types -impl StateDone for Completed { +impl Done for Completed { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } @@ -32,7 +32,7 @@ impl StateDone for Completed { } } -impl StateDone for ProcessedM3 { +impl Done for ProcessedM3 { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } @@ -45,7 +45,7 @@ impl StateDone for ProcessedM3 { } pub fn edhoc_exporter( - state: &impl StateDone, + state: &impl Done, crypto: &mut impl CryptoTrait, label: u8, context: &BytesMaxContextBuffer, @@ -63,7 +63,7 @@ pub fn edhoc_exporter( } pub fn edhoc_key_update( - state: &mut impl StateDone, + state: &mut impl Done, crypto: &mut impl CryptoTrait, context: &BytesMaxContextBuffer, context_len: usize, @@ -79,7 +79,6 @@ pub fn edhoc_key_update( context_len, SHA256_DIGEST_LEN, ); - // state.get_prk_out_mut()[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); prk_out.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); // new PRK_exporter @@ -91,12 +90,13 @@ pub fn edhoc_key_update( 0, SHA256_DIGEST_LEN, ); - // state.get_prk_exporter()[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); prk_exporter.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); // Update state state.get_prk_out_mut().copy_from_slice(&prk_out); - state.get_prk_out_mut().copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + state + .get_prk_out_mut() + .copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); prk_out } @@ -299,7 +299,7 @@ pub fn r_verify_message_3( prk_4e3m: prk_4e3m, th_4: th_4, prk_out: prk_out, - prk_exporter: prk_exporter + prk_exporter: prk_exporter, }, prk_out, prk_exporter, @@ -517,7 +517,6 @@ pub fn i_process_message_4( crypto: &mut impl CryptoTrait, message_4: &BufferMessage4, ) -> Result<(Completed, Option), EDHOCError> { - let plaintext_4 = decrypt_message_4(crypto, &state.prk_4e3m, &state.th_4, &message_4)?; let decoded_p4_res = decode_plaintext_4(&plaintext_4); @@ -740,9 +739,7 @@ fn encode_plaintext_3( } } -fn encode_plaintext_4( - ead_4: &Option, -) -> Result { +fn encode_plaintext_4(ead_4: &Option) -> Result { let mut plaintext_4: BufferPlaintext4 = BufferPlaintext4::new(); if let Some(ead_4) = ead_4 { @@ -1280,7 +1277,7 @@ mod tests { const MESSAGE_3_TV: &str = "52e562097bc417dd5919485ac7891ffd90a9fc"; const PRK_4E3M_TV: BytesP256ElemLen = hex!("81cc8a298e357044e3c466bb5c0a1e507e01d49238aeba138df94635407c0ff7"); - const MESSAGE_4_TV: &str = "4828c966b7ca304f83"; + const MESSAGE_4_TV: &str = "4828c966b7ca304f83"; const CIPHERTEXT_4_TV: &str = "28c966b7ca304f83"; const PLAINTEXT_4_TV: &str = ""; const K_4_TV: BytesCcmKeyLen = hex!("d3c77872b6eeb508911bdbd308b2e6a0"); @@ -1690,7 +1687,7 @@ mod tests { assert_eq!(k_4, K_4_TV); assert_eq!(iv_4, IV_4_TV); } - + #[test] fn test_compute_prk_4e3m() { let prk_4e3m = compute_prk_4e3m(&mut default_crypto(), &SALT_4E3M_TV, &SK_I_TV, &G_Y_TV); diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 017e900d..b148eada 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -209,7 +209,14 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderProcessingM3 { pub fn verify_message_3( mut self, cred_i: Credential, - ) -> Result<(EdhocResponderProcessedM3, [u8; SHA256_DIGEST_LEN], [u8; SHA256_DIGEST_LEN]), EDHOCError> { + ) -> Result< + ( + EdhocResponderProcessedM3, + [u8; SHA256_DIGEST_LEN], + [u8; SHA256_DIGEST_LEN], + ), + EDHOCError, + > { trace!("Enter verify_message_3"); match r_verify_message_3(&mut self.state, &mut self.crypto, cred_i) { Ok((state, prk_out, prk_exporter)) => Ok(( @@ -229,16 +236,9 @@ impl EdhocResponderProcessedM3 { pub fn prepare_message_4( mut self, ead_4: &Option, - ) -> Result<( - EdhocResponderDone, - BufferMessage4 - ), EDHOCError> { + ) -> Result<(EdhocResponderDone, BufferMessage4), EDHOCError> { trace!("Enter prepare_message_4"); - match r_prepare_message_4( - &self.state, - &mut self.crypto, - ead_4, - ) { + match r_prepare_message_4(&self.state, &mut self.crypto, ead_4) { Ok((state, message_4)) => Ok(( EdhocResponderDone { state, @@ -478,16 +478,10 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM4 { pub fn process_message_4( mut self, message_4: &'a BufferMessage4, - ) -> Result< - ( - EdhocInitiatorDone, - Option, - ), - EDHOCError, - > { + ) -> Result<(EdhocInitiatorDone, Option), EDHOCError> { trace!("Enter parse_message_4"); match i_process_message_4(&mut self.state, &mut self.crypto, message_4) { - Ok((state, ead_4)) => Ok (( + Ok((state, ead_4)) => Ok(( EdhocInitiatorDone { state: state, crypto: self.crypto, @@ -781,7 +775,8 @@ mod test { // ---- begin responder handling 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(); - let (mut responder, r_prk_out, r_prk_exporter) = responder.verify_message_3(valid_cred_i).unwrap(); + let (mut responder, r_prk_out, r_prk_exporter) = + responder.verify_message_3(valid_cred_i).unwrap(); // Send message_4 let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); diff --git a/shared/src/lib.rs b/shared/src/lib.rs index a0b41147..3ac970f4 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -816,7 +816,7 @@ mod edhoc_parser { ) -> Result, EDHOCError> { trace!("Enter decode_plaintext_4"); let decoder = CBORDecoder::new(plaintext_4.as_slice()); - + if plaintext_4.len > decoder.position() { // assume only one EAD item let ead_res = parse_ead(decoder.remaining_buffer()?); From 319045478bdff94035864d3c954462ef0f5904a4 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sat, 2 Nov 2024 12:56:13 +0100 Subject: [PATCH 03/19] lib: fix test_authz --- lib/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index b148eada..2f518557 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -918,7 +918,7 @@ mod test_authz { .unwrap(); let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); - let (mut _initiator, message_3, i_prk_out) = initiator + let (mut _initiator, message_3, i_prk_out, i_prk_exporter) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); @@ -928,7 +928,8 @@ mod test_authz { } else { id_cred_i.get_ccs().unwrap() }; - let (mut _responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + let (mut _responder, r_prk_out, r_prk_exporter) = + responder.verify_message_3(valid_cred_i).unwrap(); // check that prk_out is equal at initiator and responder side assert_eq!(i_prk_out, r_prk_out); From 978bcd41b44a674542313cbd1f247d6522613af0 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sat, 2 Nov 2024 13:27:26 +0100 Subject: [PATCH 04/19] edhoc: correcting mutable references. gstar. --- lib/src/edhoc.rs | 70 +++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 1a19bb91..64e4d2a7 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,47 +1,64 @@ use lakers_shared::{Crypto as CryptoTrait, *}; -// Implementation of edhoc_exporter for 3 or 4 messages pub trait Done { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN]; - fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN]; fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN]; + fn update_keys( + &mut self, + new_prk_out: &[u8; SHA256_DIGEST_LEN], + new_prk_exporter: &[u8; SHA256_DIGEST_LEN], + ); } -// Implement for different states + impl Done for WaitM4 { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } - fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { - &mut self.prk_out - } fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_out } + fn update_keys( + &mut self, + new_prk_out: &[u8; SHA256_DIGEST_LEN], + new_prk_exporter: &[u8; SHA256_DIGEST_LEN], + ) { + self.prk_out.copy_from_slice(new_prk_out); + self.prk_exporter.copy_from_slice(new_prk_exporter); + } } -// Implement for both state types impl Done for Completed { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } - fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { - &mut self.prk_out - } fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_out } + fn update_keys( + &mut self, + new_prk_out: &[u8; SHA256_DIGEST_LEN], + new_prk_exporter: &[u8; SHA256_DIGEST_LEN], + ) { + self.prk_out.copy_from_slice(new_prk_out); + self.prk_exporter.copy_from_slice(new_prk_exporter); + } } impl Done for ProcessedM3 { fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_exporter } - fn get_prk_out_mut(&mut self) -> &mut [u8; SHA256_DIGEST_LEN] { - &mut self.prk_out - } fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { &self.prk_out } + fn update_keys( + &mut self, + new_prk_out: &[u8; SHA256_DIGEST_LEN], + new_prk_exporter: &[u8; SHA256_DIGEST_LEN], + ) { + self.prk_out.copy_from_slice(new_prk_out); + self.prk_exporter.copy_from_slice(new_prk_exporter); + } } pub fn edhoc_exporter( @@ -68,37 +85,34 @@ pub fn edhoc_key_update( context: &BytesMaxContextBuffer, context_len: usize, ) -> BytesHashLen { - // new PRK_out - let mut prk_out = *state.get_prk_out(); - let mut prk_exporter = *state.get_prk_exporter(); + // Calculate new PRK_out let prk_new_buf = edhoc_kdf( crypto, - &prk_out, + state.get_prk_out(), 11u8, context, context_len, SHA256_DIGEST_LEN, ); - prk_out.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + let mut new_prk_out = [0u8; SHA256_DIGEST_LEN]; + new_prk_out.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); - // new PRK_exporter - let prk_new_buf = edhoc_kdf( + // Calculate new PRK_exporter + let prk_exporter_buf = edhoc_kdf( crypto, - &prk_out, + &new_prk_out, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], 0, SHA256_DIGEST_LEN, ); - prk_exporter.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + let mut new_prk_exporter = [0u8; SHA256_DIGEST_LEN]; + new_prk_exporter.copy_from_slice(&prk_exporter_buf[..SHA256_DIGEST_LEN]); - // Update state - state.get_prk_out_mut().copy_from_slice(&prk_out); - state - .get_prk_out_mut() - .copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + // Update state with new keys + state.update_keys(&new_prk_out, &new_prk_exporter); - prk_out + new_prk_out } pub fn r_process_message_1( From 0fac1f0fa532206cfa890c63f856b5f25e522db2 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sat, 2 Nov 2024 19:02:00 +0100 Subject: [PATCH 05/19] example: uncomment psa memory buffer --- examples/lakers-nrf52840/src/bin/initiator.rs | 12 ++++++------ examples/lakers-nrf52840/src/bin/responder.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/lakers-nrf52840/src/bin/initiator.rs b/examples/lakers-nrf52840/src/bin/initiator.rs index 2a5f321f..5ff8ad3b 100644 --- a/examples/lakers-nrf52840/src/bin/initiator.rs +++ b/examples/lakers-nrf52840/src/bin/initiator.rs @@ -59,12 +59,12 @@ async fn main(spawner: Spawner) { info!("init_handshake"); // Memory buffer for mbedtls - // #[cfg(feature = "crypto-psa")] - // let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - // #[cfg(feature = "crypto-psa")] - // unsafe { - // mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); - // } + #[cfg(feature = "crypto-psa")] + let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; + #[cfg(feature = "crypto-psa")] + unsafe { + mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); + } let cred_i = Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); let cred_r = Credential::parse_ccs(common::CRED_R.try_into().unwrap()).unwrap(); diff --git a/examples/lakers-nrf52840/src/bin/responder.rs b/examples/lakers-nrf52840/src/bin/responder.rs index ef617c2a..7e059754 100644 --- a/examples/lakers-nrf52840/src/bin/responder.rs +++ b/examples/lakers-nrf52840/src/bin/responder.rs @@ -53,12 +53,12 @@ async fn main(spawner: Spawner) { radio.set_crc_poly(CRC_POLY); // Memory buffer for mbedtls - // #[cfg(feature = "crypto-psa")] - // let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - // #[cfg(feature = "crypto-psa")] - // unsafe { - // mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); - // } + #[cfg(feature = "crypto-psa")] + let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; + #[cfg(feature = "crypto-psa")] + unsafe { + mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); + } loop { let mut buffer: [u8; MAX_PDU] = [0x00u8; MAX_PDU]; From 9b23deacbf062fb67842d884e1ea2089af7e317a Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sat, 2 Nov 2024 20:21:20 +0100 Subject: [PATCH 06/19] edhoc: new structure for message 4 Added test_handshake for 3 and 4 messages to derive prk_exporter in both cases Added a function completed_without_message4 for handshake with 3 messages Removed the trait for Done Fix minor mistakes --- examples/coap/src/bin/coapclient.rs | 2 +- .../coap/src/bin/coapserver-coaphandler.rs | 9 +- examples/coap/src/bin/coapserver.rs | 7 +- examples/lakers-nrf52840/src/bin/initiator.rs | 2 +- examples/lakers-nrf52840/src/bin/responder.rs | 3 +- lib/src/edhoc.rs | 110 +++-------- lib/src/lib.rs | 186 +++++++++++------- 7 files changed, 148 insertions(+), 171 deletions(-) diff --git a/examples/coap/src/bin/coapclient.rs b/examples/coap/src/bin/coapclient.rs index 06463947..c52403ca 100644 --- a/examples/coap/src/bin/coapclient.rs +++ b/examples/coap/src/bin/coapclient.rs @@ -60,7 +60,7 @@ fn client_handshake() -> Result<(), EDHOCError> { let initiator = initiator.verify_message_2(valid_cred_r)?; let mut msg_3 = Vec::from(c_r.as_cbor()); - let (mut initiator, message_3, prk_out, prk_out_exporter) = + let (mut initiator, message_3, prk_out) = initiator.prepare_message_3(CredentialTransfer::ByReference, &None)?; msg_3.extend_from_slice(message_3.as_slice()); println!("message_3 len = {}", msg_3.len()); diff --git a/examples/coap/src/bin/coapserver-coaphandler.rs b/examples/coap/src/bin/coapserver-coaphandler.rs index 2ec821ac..55b8b4f2 100644 --- a/examples/coap/src/bin/coapserver-coaphandler.rs +++ b/examples/coap/src/bin/coapserver-coaphandler.rs @@ -182,11 +182,10 @@ impl coap_handler::Handler for EdhocHandler { .expect("Static credential is not processable"); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).map_err(render_error)?; - let (responder, prk_out, prk_exporter) = - responder.verify_message_3(valid_cred_i).map_err(|e| { - println!("EDHOC processing error: {:?}", e); - render_error(e) - })?; + let (responder, prk_out) = responder.verify_message_3(valid_cred_i).map_err(|e| { + println!("EDHOC processing error: {:?}", e); + render_error(e) + })?; let ead_4 = None; let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index f97dbd25..1534d03b 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -108,14 +108,11 @@ fn main() { }; let cred_i = Credential::parse_ccs(CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - let Ok((mut responder, prk_out, prk_exporter)) = - responder.verify_message_3(valid_cred_i) - else { + let Ok((mut responder, prk_out)) = responder.verify_message_3(valid_cred_i) else { println!("EDHOC error at verify_message_3: {:?}", valid_cred_i); continue; }; - let ead_4 = None; - let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); + let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); // send empty ack back response.message.payload = b"".to_vec(); diff --git a/examples/lakers-nrf52840/src/bin/initiator.rs b/examples/lakers-nrf52840/src/bin/initiator.rs index 5ff8ad3b..f5465a90 100644 --- a/examples/lakers-nrf52840/src/bin/initiator.rs +++ b/examples/lakers-nrf52840/src/bin/initiator.rs @@ -94,7 +94,7 @@ async fn main(spawner: Spawner) { let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap(); let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); - let (mut initiator, message_3, i_prk_out, i_prk_out_exporter) = initiator + let (mut initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); let pckt_3 = diff --git a/examples/lakers-nrf52840/src/bin/responder.rs b/examples/lakers-nrf52840/src/bin/responder.rs index 7e059754..3a586ab5 100644 --- a/examples/lakers-nrf52840/src/bin/responder.rs +++ b/examples/lakers-nrf52840/src/bin/responder.rs @@ -121,8 +121,7 @@ async fn main(spawner: Spawner) { Credential::parse_ccs(common::CRED_I.try_into().unwrap()).unwrap(); let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); - let Ok((responder, r_prk_out, r_prk_exporter)) = - responder.verify_message_3(valid_cred_i) + let Ok((responder, r_prk_out)) = responder.verify_message_3(valid_cred_i) else { info!("EDHOC error at parse_message_3"); continue; diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 64e4d2a7..2a7b28ba 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,68 +1,7 @@ use lakers_shared::{Crypto as CryptoTrait, *}; -pub trait Done { - fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN]; - fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN]; - fn update_keys( - &mut self, - new_prk_out: &[u8; SHA256_DIGEST_LEN], - new_prk_exporter: &[u8; SHA256_DIGEST_LEN], - ); -} - -impl Done for WaitM4 { - fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_exporter - } - fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_out - } - fn update_keys( - &mut self, - new_prk_out: &[u8; SHA256_DIGEST_LEN], - new_prk_exporter: &[u8; SHA256_DIGEST_LEN], - ) { - self.prk_out.copy_from_slice(new_prk_out); - self.prk_exporter.copy_from_slice(new_prk_exporter); - } -} - -impl Done for Completed { - fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_exporter - } - fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_out - } - fn update_keys( - &mut self, - new_prk_out: &[u8; SHA256_DIGEST_LEN], - new_prk_exporter: &[u8; SHA256_DIGEST_LEN], - ) { - self.prk_out.copy_from_slice(new_prk_out); - self.prk_exporter.copy_from_slice(new_prk_exporter); - } -} - -impl Done for ProcessedM3 { - fn get_prk_exporter(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_exporter - } - fn get_prk_out(&self) -> &[u8; SHA256_DIGEST_LEN] { - &self.prk_out - } - fn update_keys( - &mut self, - new_prk_out: &[u8; SHA256_DIGEST_LEN], - new_prk_exporter: &[u8; SHA256_DIGEST_LEN], - ) { - self.prk_out.copy_from_slice(new_prk_out); - self.prk_exporter.copy_from_slice(new_prk_exporter); - } -} - pub fn edhoc_exporter( - state: &impl Done, + state: &Completed, crypto: &mut impl CryptoTrait, label: u8, context: &BytesMaxContextBuffer, @@ -71,7 +10,7 @@ pub fn edhoc_exporter( ) -> BytesMaxBuffer { edhoc_kdf( crypto, - state.get_prk_exporter(), + &state.prk_exporter, label, context, context_len, @@ -80,39 +19,34 @@ pub fn edhoc_exporter( } pub fn edhoc_key_update( - state: &mut impl Done, + state: &mut Completed, crypto: &mut impl CryptoTrait, context: &BytesMaxContextBuffer, context_len: usize, ) -> BytesHashLen { - // Calculate new PRK_out + // new PRK_out let prk_new_buf = edhoc_kdf( crypto, - state.get_prk_out(), + &state.prk_out, 11u8, context, context_len, SHA256_DIGEST_LEN, ); - let mut new_prk_out = [0u8; SHA256_DIGEST_LEN]; - new_prk_out.copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); + state.prk_out[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); - // Calculate new PRK_exporter - let prk_exporter_buf = edhoc_kdf( + // new PRK_exporter + let prk_new_buf = edhoc_kdf( crypto, - &new_prk_out, + &state.prk_out, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], 0, SHA256_DIGEST_LEN, ); - let mut new_prk_exporter = [0u8; SHA256_DIGEST_LEN]; - new_prk_exporter.copy_from_slice(&prk_exporter_buf[..SHA256_DIGEST_LEN]); + state.prk_exporter[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); - // Update state with new keys - state.update_keys(&new_prk_out, &new_prk_exporter); - - new_prk_out + state.prk_out } pub fn r_process_message_1( @@ -250,7 +184,7 @@ pub fn r_verify_message_3( state: &mut ProcessingM3, crypto: &mut impl CryptoTrait, valid_cred_i: Credential, -) -> Result<(ProcessedM3, BytesHashLen, BytesHashLen), EDHOCError> { +) -> Result<(ProcessedM3, BytesHashLen), EDHOCError> { // compute salt_4e3m let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3); @@ -316,7 +250,6 @@ pub fn r_verify_message_3( prk_exporter: prk_exporter, }, prk_out, - prk_exporter, )) } else { Err(EDHOCError::MacVerificationFailed) @@ -341,6 +274,13 @@ pub fn r_prepare_message_4( )) } +pub fn r_complete_without_message_4(state: &ProcessedM3) -> Result { + Ok(Completed { + prk_out: state.prk_out, + prk_exporter: state.prk_exporter, + }) +} + pub fn i_prepare_message_1( state: &InitiatorStart, crypto: &mut impl CryptoTrait, @@ -464,7 +404,7 @@ pub fn i_prepare_message_3( cred_i: Credential, cred_transfer: CredentialTransfer, ead_3: &Option, // FIXME: make it a list of EADItem -) -> Result<(WaitM4, BufferMessage3, BytesHashLen, BytesHashLen), EDHOCError> { +) -> Result<(WaitM4, BufferMessage3, BytesHashLen), EDHOCError> { let id_cred_i = match cred_transfer { CredentialTransfer::ByValue => cred_i.by_value()?, CredentialTransfer::ByReference => cred_i.by_kid()?, @@ -522,7 +462,6 @@ pub fn i_prepare_message_3( }, message_3, prk_out, - prk_exporter, )) } @@ -547,6 +486,13 @@ pub fn i_process_message_4( } } +pub fn i_complete_without_message_4(state: &WaitM4) -> Result { + Ok(Completed { + prk_out: state.prk_out, + prk_exporter: state.prk_exporter, + }) +} + fn encode_ead_item(ead_1: &EADItem) -> Result { let mut output = EdhocMessageBuffer::new(); @@ -960,7 +906,7 @@ fn decrypt_message_4( th_4: &BytesHashLen, message_4: &BufferMessage4, ) -> Result { - // decode message_3 + // decode message_4 let bytestring_length: usize; let prefix_length; // FIXME: Reuse CBOR decoder diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 2f518557..08cc7f4f 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -209,23 +209,15 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderProcessingM3 { pub fn verify_message_3( mut self, cred_i: Credential, - ) -> Result< - ( - EdhocResponderProcessedM3, - [u8; SHA256_DIGEST_LEN], - [u8; SHA256_DIGEST_LEN], - ), - EDHOCError, - > { + ) -> Result<(EdhocResponderProcessedM3, [u8; SHA256_DIGEST_LEN]), EDHOCError> { trace!("Enter verify_message_3"); match r_verify_message_3(&mut self.state, &mut self.crypto, cred_i) { - Ok((state, prk_out, prk_exporter)) => Ok(( + Ok((state, prk_out)) => Ok(( EdhocResponderProcessedM3 { state, crypto: self.crypto, }, prk_out, - prk_exporter, )), Err(error) => Err(error), } @@ -249,34 +241,16 @@ impl EdhocResponderProcessedM3 { Err(error) => Err(error), } } - pub fn edhoc_exporter( - &mut self, - label: u8, - context: &[u8], - length: usize, - ) -> [u8; MAX_BUFFER_LEN] { - let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - edhoc_exporter( - &self.state, - &mut self.crypto, - label, - &context_buf, - context.len(), - length, - ) - } - pub fn edhoc_key_update(&mut self, context: &[u8]) -> [u8; SHA256_DIGEST_LEN] { - let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - edhoc_key_update( - &mut self.state, - &mut self.crypto, - &context_buf, - context.len(), - ) + pub fn completed_without_message_4(self) -> Result, EDHOCError> { + trace!("Enter completed"); + match r_complete_without_message_4(&self.state) { + Ok(state) => Ok(EdhocResponderDone { + state, + crypto: self.crypto, + }), + Err(error) => Err(error), + } } } @@ -445,7 +419,6 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessedM2 { EdhocInitiatorWaitM4, BufferMessage3, [u8; SHA256_DIGEST_LEN], - [u8; SHA256_DIGEST_LEN], ), EDHOCError, > { @@ -460,14 +433,13 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorProcessedM2 { cred_transfer, ead_3, ) { - Ok((state, message_3, prk_out, prk_exporter)) => Ok(( + Ok((state, message_3, prk_out)) => Ok(( EdhocInitiatorWaitM4 { state, crypto: self.crypto, }, message_3, prk_out, - prk_exporter, )), Err(error) => Err(error), } @@ -491,35 +463,16 @@ impl<'a, Crypto: CryptoTrait> EdhocInitiatorWaitM4 { Err(error) => Err(error), } } - pub fn edhoc_exporter( - &mut self, - label: u8, - context: &[u8], - length: usize, - ) -> [u8; MAX_BUFFER_LEN] { - let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - edhoc_exporter( - &self.state, - &mut self.crypto, - label, - &context_buf, - context.len(), - length, - ) - } - pub fn edhoc_key_update(&mut self, context: &[u8]) -> [u8; SHA256_DIGEST_LEN] { - let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - edhoc_key_update( - &mut self.state, - &mut self.crypto, - &context_buf, - context.len(), - ) + pub fn completed_without_message_4(self) -> Result, EDHOCError> { + trace!("Enter completed"); + match i_complete_without_message_4(&self.state) { + Ok(state) => Ok(EdhocResponderDone { + state, + crypto: self.crypto, + }), + Err(error) => Err(error), + } } } @@ -767,16 +720,99 @@ mod test { let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); // if needed: prepare ead_3 - let (mut initiator, message_3, i_prk_out, i_prk_exporter) = initiator + let (mut initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); + let mut initiator = initiator.completed_without_message_4().unwrap(); // ---- end initiator handling // ---- begin responder handling 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(); - let (mut responder, r_prk_out, r_prk_exporter) = - responder.verify_message_3(valid_cred_i).unwrap(); + let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + + let mut responder = responder.completed_without_message_4().unwrap(); + // ---- end responder handling + + // check that prk_out is equal at initiator and responder side + assert_eq!(i_prk_out, r_prk_out); + + // derive OSCORE secret and salt at both sides and compare + let i_oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0 + let i_oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1 + + let r_oscore_secret = responder.edhoc_exporter(0u8, &[], 16); // label is 0 + let r_oscore_salt = responder.edhoc_exporter(1u8, &[], 8); // label is 1 + + assert_eq!(i_oscore_secret, r_oscore_secret); + assert_eq!(i_oscore_salt, r_oscore_salt); + + // test key update with context from draft-ietf-lake-traces + let context = &[ + 0xa0, 0x11, 0x58, 0xfd, 0xb8, 0x20, 0x89, 0x0c, 0xd6, 0xbe, 0x16, 0x96, 0x02, 0xb8, + 0xbc, 0xea, + ]; + let i_prk_out_new = initiator.edhoc_key_update(context); + let r_prk_out_new = responder.edhoc_key_update(context); + + assert_eq!(i_prk_out_new, r_prk_out_new); + } + + #[cfg(feature = "test-ead-none")] + #[test] + fn test_handshake_message4() { + 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 initiator = EdhocInitiator::new( + default_crypto(), + EDHOCMethod::StatStat, + EDHOCSuite::CipherSuite2, + ); + + let responder = EdhocResponder::new( + default_crypto(), + EDHOCMethod::StatStat, + R.try_into().expect("Wrong length of responder private key"), + cred_r.clone(), + ); // has to select an identity before learning who is I + + // ---- begin initiator handling + // if needed: prepare ead_1 + let (initiator, message_1) = initiator.prepare_message_1(None, &None).unwrap(); + // ---- end initiator handling + + // ---- begin responder handling + let (responder, _c_i, _ead_1) = responder.process_message_1(&message_1).unwrap(); + // if ead_1: process ead_1 + // if needed: prepare ead_2 + let (responder, message_2) = responder + .prepare_message_2(CredentialTransfer::ByReference, None, &None) + .unwrap(); + // ---- end responder handling + + // ---- being initiator handling + 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(); + 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(); + + // if needed: prepare ead_3 + let (mut initiator, message_3, i_prk_out) = initiator + .prepare_message_3(CredentialTransfer::ByReference, &None) + .unwrap(); + // ---- end initiator handling + + // ---- begin responder handling + 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(); + let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); // Send message_4 let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); @@ -918,19 +954,19 @@ mod test_authz { .unwrap(); let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); - let (mut _initiator, message_3, i_prk_out, i_prk_exporter) = initiator + let (mut initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); - + let _initiator = initiator.completed_without_message_4(); let (responder, id_cred_i, _ead_3) = responder.parse_message_3(&message_3).unwrap(); let valid_cred_i = if id_cred_i.reference_only() { mock_fetch_cred_i(id_cred_i).unwrap() } else { id_cred_i.get_ccs().unwrap() }; - let (mut _responder, r_prk_out, r_prk_exporter) = - responder.verify_message_3(valid_cred_i).unwrap(); + let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + let mut _responder = responder.completed_without_message_4(); // check that prk_out is equal at initiator and responder side assert_eq!(i_prk_out, r_prk_out); } From c7b9cfe9938874d0233e316452b1635b1ea67b49 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sun, 3 Nov 2024 12:21:35 +0100 Subject: [PATCH 07/19] python: fix python examples remove test_handshake_message_4 in lib.rs --- lakers-python/src/initiator.rs | 30 +++++++++++- lakers-python/src/responder.rs | 29 +++++++++++- lib/src/lib.rs | 84 ---------------------------------- shared/src/lib.rs | 6 +-- 4 files changed, 60 insertions(+), 89 deletions(-) diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index c9e080b0..78550581 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -10,6 +10,7 @@ pub struct PyEdhocInitiator { wait_m2: WaitM2, processing_m2: ProcessingM2, processed_m2: ProcessedM2, + wait_m4: WaitM4, completed: Completed, } @@ -34,6 +35,7 @@ impl PyEdhocInitiator { wait_m2: WaitM2::default(), processing_m2: ProcessingM2::default(), processed_m2: ProcessedM2::default(), + wait_m4: WaitM4::default(), completed: Completed::default(), } } @@ -122,7 +124,7 @@ impl PyEdhocInitiator { &ead_3, ) { Ok((state, message_3, prk_out)) => { - self.completed = state; + self.wait_m4 = state; Ok(( PyBytes::new_bound(py, message_3.as_slice()), PyBytes::new_bound(py, prk_out.as_slice()), @@ -132,6 +134,32 @@ impl PyEdhocInitiator { } } + pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { + match i_complete_without_message_4(&self.wait_m4) { + Ok(state) => { + self.completed = state; + Ok(()) + } + Err(error) => Err(error.into()), + } + } + + pub fn propcess_message_4<'a>( + &mut self, + py: Python<'a>, + message_4: Vec, + ) -> PyResult> { + let message_4 = EdhocMessageBuffer::new_from_slice(message_4.as_slice())?; + + match i_process_message_4(&mut self.wait_m4, &mut default_crypto(), &message_4) { + Ok((state, ead_4)) => { + self.completed = state; + Ok(ead_4) + } + Err(error) => Err(error.into()), + } + } + pub fn edhoc_exporter<'a>( &mut self, py: Python<'a>, diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index 16d6aaad..78e6cfec 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -11,6 +11,7 @@ pub struct PyEdhocResponder { processing_m1: ProcessingM1, wait_m3: WaitM3, processing_m3: ProcessingM3, + processed_m3: ProcessedM3, completed: Completed, } @@ -34,6 +35,7 @@ impl PyEdhocResponder { processing_m1: ProcessingM1::default(), wait_m3: WaitM3::default(), processing_m3: ProcessingM3::default(), + processed_m3: ProcessedM3::default(), completed: Completed::default(), }) } @@ -112,13 +114,38 @@ impl PyEdhocResponder { let valid_cred_i = valid_cred_i.to_credential()?; match r_verify_message_3(&mut self.processing_m3, &mut default_crypto(), valid_cred_i) { Ok((state, prk_out)) => { - self.completed = state; + self.processed_m3 = state; Ok(PyBytes::new_bound(py, prk_out.as_slice())) } Err(error) => Err(error.into()), } } + #[pyo3(signature = (ead_4=None))] + fn prepare_message_4<'a>( + &mut self, + py: Python<'a>, + ead_4: Option, + ) -> PyResult> { + match r_prepare_message_4(&self.processed_m3, &mut default_crypto(), &ead_4) { + Ok((state, message_4)) => { + self.completed = state; + Ok(PyBytes::new_bound(py, message_4.as_slice())) + } + Err(error) => Err(error.into()), + } + } + + pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { + match r_complete_without_message_4(&self.processed_m3) { + Ok(state) => { + self.completed = state; + Ok(()) + } + Err(error) => Err(error.into()), + } + } + pub fn edhoc_exporter<'a>( &mut self, py: Python<'a>, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 08cc7f4f..2162fe94 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -719,90 +719,6 @@ mod test { .unwrap(); // exposing own identity only after validating cred_r let initiator = initiator.verify_message_2(valid_cred_r).unwrap(); - // if needed: prepare ead_3 - let (mut initiator, message_3, i_prk_out) = initiator - .prepare_message_3(CredentialTransfer::ByReference, &None) - .unwrap(); - let mut initiator = initiator.completed_without_message_4().unwrap(); - // ---- end initiator handling - - // ---- begin responder handling - 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(); - let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); - - let mut responder = responder.completed_without_message_4().unwrap(); - // ---- end responder handling - - // check that prk_out is equal at initiator and responder side - assert_eq!(i_prk_out, r_prk_out); - - // derive OSCORE secret and salt at both sides and compare - let i_oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0 - let i_oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1 - - let r_oscore_secret = responder.edhoc_exporter(0u8, &[], 16); // label is 0 - let r_oscore_salt = responder.edhoc_exporter(1u8, &[], 8); // label is 1 - - assert_eq!(i_oscore_secret, r_oscore_secret); - assert_eq!(i_oscore_salt, r_oscore_salt); - - // test key update with context from draft-ietf-lake-traces - let context = &[ - 0xa0, 0x11, 0x58, 0xfd, 0xb8, 0x20, 0x89, 0x0c, 0xd6, 0xbe, 0x16, 0x96, 0x02, 0xb8, - 0xbc, 0xea, - ]; - let i_prk_out_new = initiator.edhoc_key_update(context); - let r_prk_out_new = responder.edhoc_key_update(context); - - assert_eq!(i_prk_out_new, r_prk_out_new); - } - - #[cfg(feature = "test-ead-none")] - #[test] - fn test_handshake_message4() { - 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 initiator = EdhocInitiator::new( - default_crypto(), - EDHOCMethod::StatStat, - EDHOCSuite::CipherSuite2, - ); - - let responder = EdhocResponder::new( - default_crypto(), - EDHOCMethod::StatStat, - R.try_into().expect("Wrong length of responder private key"), - cred_r.clone(), - ); // has to select an identity before learning who is I - - // ---- begin initiator handling - // if needed: prepare ead_1 - let (initiator, message_1) = initiator.prepare_message_1(None, &None).unwrap(); - // ---- end initiator handling - - // ---- begin responder handling - let (responder, _c_i, _ead_1) = responder.process_message_1(&message_1).unwrap(); - // if ead_1: process ead_1 - // if needed: prepare ead_2 - let (responder, message_2) = responder - .prepare_message_2(CredentialTransfer::ByReference, None, &None) - .unwrap(); - // ---- end responder handling - - // ---- being initiator handling - 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(); - 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(); - // if needed: prepare ead_3 let (mut initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 3ac970f4..62b9c2db 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -390,7 +390,7 @@ pub struct ProcessingM3 { pub ead_3: Option, } -#[derive(Debug)] +#[derive(Default, Debug)] pub struct PreparingM3 { pub prk_3e2m: BytesHashLen, pub prk_4e3m: BytesHashLen, @@ -398,7 +398,7 @@ pub struct PreparingM3 { pub mac_3: BytesMac3, } -#[derive(Debug)] +#[derive(Default, Debug)] pub struct ProcessedM3 { pub prk_4e3m: BytesHashLen, pub th_4: BytesHashLen, @@ -406,7 +406,7 @@ pub struct ProcessedM3 { pub prk_exporter: BytesHashLen, } -#[derive(Debug)] +#[derive(Default, Debug)] pub struct WaitM4 { pub prk_4e3m: BytesHashLen, pub th_4: BytesHashLen, From 21e044b74383dd40314e5b262baf5aadf2fee4c9 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sun, 3 Nov 2024 13:14:53 +0100 Subject: [PATCH 08/19] lakers-c: fixing c wrapper for message_4 --- lakers-c/src/initiator.rs | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/lakers-c/src/initiator.rs b/lakers-c/src/initiator.rs index 3d3802b3..6a2719d6 100644 --- a/lakers-c/src/initiator.rs +++ b/lakers-c/src/initiator.rs @@ -15,6 +15,7 @@ pub struct EdhocInitiator { pub wait_m2: WaitM2, pub processing_m2: ProcessingM2C, pub processed_m2: ProcessedM2, + pub wait_m4: WaitM4, pub cred_i: *mut CredentialC, pub completed: Completed, } @@ -181,7 +182,7 @@ pub unsafe extern "C" fn initiator_prepare_message_3( &ead_3, ) { Ok((state, msg_3, prk_out)) => { - (*initiator_c).completed = state; + (*initiator_c).wait_m4 = state; *message_3 = msg_3; *prk_out_c = prk_out; 0 @@ -190,6 +191,56 @@ pub unsafe extern "C" fn initiator_prepare_message_3( } } +#[no_mangle] +pub unsafe extern "C" fn initiator_process_message_4( + // input params + initiator_c: *mut EdhocInitiator, + message_4: *const EdhocMessageBuffer, + // output params + ead_4_c_out: *mut EADItemC, +) -> i8 { + // this is a parsing function, so all output parameters are mandatory + if initiator_c.is_null() || message_4.is_null() || ead_4_c_out.is_null() { + return -1; + } + let crypto = &mut default_crypto(); + + let mut state = core::ptr::read(&(*initiator_c).wait_m4); + + let result = match i_process_message_4(&mut state, crypto, &(*message_4)) { + Ok((state, ead_4)) => { + (*initiator_c).completed = state; + if let Some(ead_4) = ead_4 { + EADItemC::copy_into_c(ead_4, ead_4_c_out); + } + + 0 + } + Err(err) => err as i8, + }; + + result +} + +#[no_mangle] +pub unsafe extern "C" fn completed_without_message_4( + // input params + initiator_c: *mut EdhocInitiator, +) -> i8 { + if initiator_c.is_null() { + return -1; + } + let state = core::ptr::read(&(*initiator_c).wait_m4); + + match i_complete_without_message_4(&state) { + Ok(state) => { + (*initiator_c).completed = state; + 0 + } + Err(err) => err as i8, + } +} + #[no_mangle] pub unsafe extern "C" fn initiator_compute_ephemeral_secret( initiator_c: *const EdhocInitiator, From 9dc60116aa942706793d8d169c03bb084aa0697d Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Sun, 3 Nov 2024 13:23:35 +0100 Subject: [PATCH 09/19] examples: fix lakers-no_std --- examples/lakers-no_std/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/lakers-no_std/src/main.rs b/examples/lakers-no_std/src/main.rs index 9df603a4..a05a31cc 100644 --- a/examples/lakers-no_std/src/main.rs +++ b/examples/lakers-no_std/src/main.rs @@ -140,6 +140,9 @@ fn main() -> ! { let valid_cred_i = credential_check_or_fetch(Some(cred_i), id_cred_i).unwrap(); let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + let initiator = initiator.completed_without_message_4().unwrap(); + let responder = responder.completed_without_message_4().unwrap(); + // check that prk_out is equal at initiator and responder side assert_eq!(i_prk_out, r_prk_out); From 993d4d23c43915cf9d2a856e179484b4e5ecaf76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mali=C5=A1a=20Vu=C4=8Dini=C4=87?= Date: Mon, 28 Oct 2024 16:43:53 +0100 Subject: [PATCH 10/19] example: remove git dependencies on embassy --- examples/lakers-nrf52840/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/lakers-nrf52840/Cargo.toml b/examples/lakers-nrf52840/Cargo.toml index 6a7e5dce..445d3ad5 100644 --- a/examples/lakers-nrf52840/Cargo.toml +++ b/examples/lakers-nrf52840/Cargo.toml @@ -10,9 +10,9 @@ categories.workspace = true [dependencies] # embassy deps -embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { git = "https://github.com/embassy-rs/embassy", branch = "main", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-executor = { version = "0.6.1", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.2.0", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } # lakers lakers = { package = "lakers", path = "../../lib", features = [ "defmt" ] } From 0923a74d338d3461cc5bfd32acb13042462a898c Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Mon, 28 Oct 2024 16:07:42 +0100 Subject: [PATCH 11/19] example: improve nrf readme on multiple probes --- examples/lakers-nrf52840/README.md | 8 ++++---- examples/lakers-nrf52840/src/bin/responder.rs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/lakers-nrf52840/README.md b/examples/lakers-nrf52840/README.md index bb5cc547..4b19b675 100644 --- a/examples/lakers-nrf52840/README.md +++ b/examples/lakers-nrf52840/README.md @@ -14,12 +14,12 @@ The example is configured to be ran on nRF52840-DK board. This folder's `.cargo/config.toml` configures the target (`thumbv7m-none-eabi`) and the probe-rs runner so the things should just work: - cargo run --bin initiator - cargo run --bin responder + cargo run --bin initiator -- --probe 1366:1015:000683965284 + cargo run --bin responder -- --probe 1366:1051:001050286964 -You may want to prefix the commands above with e.g. PROBE_RS_PROBE=1366:1051:001050288491 in order to specify which board you want to connect to. +Note that if there are two boards connected to your computer, we need to specify which one we want to use. You can get the name of your probes by running: probe-rs list -You can enhance debugging by passing environment variables such as `DEFMT_LOG=trace`." \ No newline at end of file +You can enhance debugging by passing environment variables such as `DEFMT_LOG=trace`." diff --git a/examples/lakers-nrf52840/src/bin/responder.rs b/examples/lakers-nrf52840/src/bin/responder.rs index 3a586ab5..dda1ebdd 100644 --- a/examples/lakers-nrf52840/src/bin/responder.rs +++ b/examples/lakers-nrf52840/src/bin/responder.rs @@ -60,6 +60,8 @@ async fn main(spawner: Spawner) { mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); } + info!("Responder started, will wait for messages"); + loop { let mut buffer: [u8; MAX_PDU] = [0x00u8; MAX_PDU]; let mut c_r: Option = None; From d46cd5129bda9a00dddbf5293afeabef1fd1ef4e Mon Sep 17 00:00:00 2001 From: chrysn Date: Mon, 4 Nov 2024 15:18:42 +0000 Subject: [PATCH 12/19] python: Make safer to use Previously, a call to `.edhoc_exporter()` would happily have produced exports from the all-zero key material. --- lakers-python/src/initiator.rs | 50 ++++++++++++++++------------ lakers-python/src/lib.rs | 22 +++++++++++++ lakers-python/src/responder.rs | 59 ++++++++++++++++++++-------------- 3 files changed, 87 insertions(+), 44 deletions(-) diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index 78550581..9013ebba 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -3,15 +3,19 @@ use lakers_crypto::{default_crypto, CryptoTrait}; use log::trace; use pyo3::{prelude::*, types::PyBytes}; +use super::StateMismatch; + #[pyclass(name = "EdhocInitiator")] pub struct PyEdhocInitiator { cred_i: Option, + // FIXME: This does *not* get taken out, so some data stays available for longer than it needs + // to be -- but that is apparently needed in selected_cipher_suite and + // compute_ephemeral_secret. start: InitiatorStart, - wait_m2: WaitM2, - processing_m2: ProcessingM2, - processed_m2: ProcessedM2, - wait_m4: WaitM4, - completed: Completed, + wait_m2: Option, + processing_m2: Option, + processed_m2: Option, + completed: Option, } #[pymethods] @@ -32,11 +36,10 @@ impl PyEdhocInitiator { method: EDHOCMethod::StatStat.into(), suites_i, }, - wait_m2: WaitM2::default(), - processing_m2: ProcessingM2::default(), - processed_m2: ProcessedM2::default(), - wait_m4: WaitM4::default(), - completed: Completed::default(), + wait_m2: None, + processing_m2: None, + processed_m2: None, + completed: None, } } @@ -56,7 +59,7 @@ impl PyEdhocInitiator { match i_prepare_message_1(&self.start, &mut default_crypto(), c_i, &ead_1) { Ok((state, message_1)) => { - self.wait_m2 = state; + self.wait_m2 = Some(state); Ok(PyBytes::new_bound(py, message_1.as_slice())) } Err(error) => Err(error.into()), @@ -70,9 +73,13 @@ impl PyEdhocInitiator { ) -> PyResult<(Bound<'a, PyBytes>, Bound<'a, PyBytes>, Option)> { let message_2 = EdhocMessageBuffer::new_from_slice(message_2.as_slice())?; - match i_parse_message_2(&self.wait_m2, &mut default_crypto(), &message_2) { + match i_parse_message_2( + &self.wait_m2.take().ok_or(StateMismatch)?, + &mut default_crypto(), + &message_2, + ) { Ok((state, c_r, id_cred_r, ead_2)) => { - self.processing_m2 = state; + self.processing_m2 = Some(state); Ok(( PyBytes::new_bound(py, c_r.as_slice()), PyBytes::new_bound(py, id_cred_r.bytes.as_slice()), @@ -93,7 +100,7 @@ impl PyEdhocInitiator { let valid_cred_r = valid_cred_r.to_credential()?; match i_verify_message_2( - &self.processing_m2, + &self.processing_m2.take().ok_or(StateMismatch)?, &mut default_crypto(), valid_cred_r, i.as_slice() @@ -101,7 +108,7 @@ impl PyEdhocInitiator { .expect("Wrong length of initiator private key"), ) { Ok(state) => { - self.processed_m2 = state; + self.processed_m2 = Some(state); self.cred_i = Some(cred_i); Ok(()) } @@ -117,14 +124,14 @@ impl PyEdhocInitiator { ead_3: Option, ) -> PyResult<(Bound<'a, PyBytes>, Bound<'a, PyBytes>)> { match i_prepare_message_3( - &mut self.processed_m2, + &mut self.processed_m2.take().ok_or(StateMismatch)?, &mut default_crypto(), self.cred_i.unwrap(), cred_transfer, &ead_3, ) { Ok((state, message_3, prk_out)) => { - self.wait_m4 = state; + self.completed = Some(state); Ok(( PyBytes::new_bound(py, message_3.as_slice()), PyBytes::new_bound(py, prk_out.as_slice()), @@ -171,7 +178,7 @@ impl PyEdhocInitiator { context_buf[..context.len()].copy_from_slice(context.as_slice()); let res = edhoc_exporter( - &self.completed, + self.completed.as_ref().ok_or(StateMismatch)?, &mut default_crypto(), label, &context_buf, @@ -190,7 +197,7 @@ impl PyEdhocInitiator { context_buf[..context.len()].copy_from_slice(context.as_slice()); let res = edhoc_key_update( - &mut self.completed, + self.completed.as_mut().ok_or(StateMismatch)?, &mut default_crypto(), &context_buf, context.len(), @@ -199,7 +206,10 @@ impl PyEdhocInitiator { } pub fn get_h_message_1<'a>(&self, py: Python<'a>) -> PyResult> { - Ok(PyBytes::new_bound(py, &self.wait_m2.h_message_1[..])) + Ok(PyBytes::new_bound( + py, + &self.wait_m2.as_ref().ok_or(StateMismatch)?.h_message_1[..], + )) } pub fn compute_ephemeral_secret<'a>( diff --git a/lakers-python/src/lib.rs b/lakers-python/src/lib.rs index 89309ef2..d89a22c1 100644 --- a/lakers-python/src/lib.rs +++ b/lakers-python/src/lib.rs @@ -12,6 +12,28 @@ mod ead_authz; mod initiator; mod responder; +/// Error raised when operations on a Python object did not happen in the sequence in which they +/// were intended. +/// +/// This currently has no more detailed response because for every situation this can occur in, +/// there are different possible explainations that we can't get across easily in a single message. +/// For example, if `responder.processing_m1` is absent, that can be either because no message 1 +/// was processed into it yet, or because message 2 was already generated. +#[derive(Debug)] +pub(crate) struct StateMismatch; + +impl std::error::Error for StateMismatch {} +impl std::fmt::Display for StateMismatch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Type state mismatch") + } +} +impl From for PyErr { + fn from(err: StateMismatch) -> PyErr { + pyo3::exceptions::PyRuntimeError::new_err(err.to_string()) + } +} + // NOTE: throughout this implementation, we use Vec for incoming byte lists and PyBytes for outgoing byte lists. // This is because the incoming lists of bytes are automatically converted to `Vec` by pyo3, // but the outgoing ones must be explicitly converted to `PyBytes`. diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index 78e6cfec..9d74340c 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -3,16 +3,17 @@ use lakers_crypto::{default_crypto, CryptoTrait}; use log::trace; use pyo3::{prelude::*, types::PyBytes}; +use super::StateMismatch; + #[pyclass(name = "EdhocResponder")] pub struct PyEdhocResponder { r: Vec, cred_r: Credential, - start: ResponderStart, - processing_m1: ProcessingM1, - wait_m3: WaitM3, - processing_m3: ProcessingM3, - processed_m3: ProcessedM3, - completed: Completed, + start: Option, + processing_m1: Option, + wait_m3: Option, + processing_m3: Option, + completed: Option, } #[pymethods] @@ -27,16 +28,15 @@ impl PyEdhocResponder { Ok(Self { r, cred_r, - start: ResponderStart { + start: Some(ResponderStart { method: EDHOCMethod::StatStat.into(), y, g_y, - }, - processing_m1: ProcessingM1::default(), - wait_m3: WaitM3::default(), - processing_m3: ProcessingM3::default(), - processed_m3: ProcessedM3::default(), - completed: Completed::default(), + }), + processing_m1: None, + wait_m3: None, + processing_m3: None, + completed: None, }) } @@ -46,9 +46,12 @@ impl PyEdhocResponder { message_1: Vec, ) -> PyResult<(Bound<'a, PyBytes>, Option)> { let message_1 = EdhocMessageBuffer::new_from_slice(message_1.as_slice())?; - let (state, c_i, ead_1) = - r_process_message_1(&self.start, &mut default_crypto(), &message_1)?; - self.processing_m1 = state; + let (state, c_i, ead_1) = r_process_message_1( + &self.start.take().ok_or(StateMismatch)?, + &mut default_crypto(), + &message_1, + )?; + self.processing_m1 = Some(state); let c_i = PyBytes::new_bound(py, c_i.as_slice()); Ok((c_i, ead_1)) @@ -75,7 +78,7 @@ impl PyEdhocResponder { r.copy_from_slice(self.r.as_slice()); match r_prepare_message_2( - &self.processing_m1, + self.processing_m1.as_ref().ok_or(StateMismatch)?, &mut default_crypto(), self.cred_r, &r, @@ -84,7 +87,7 @@ impl PyEdhocResponder { &ead_2, ) { Ok((state, message_2)) => { - self.wait_m3 = state; + self.wait_m3 = Some(state); Ok(PyBytes::new_bound(py, message_2.as_slice())) } Err(error) => Err(error.into()), @@ -97,9 +100,13 @@ impl PyEdhocResponder { message_3: Vec, ) -> PyResult<(Bound<'a, PyBytes>, Option)> { let message_3 = EdhocMessageBuffer::new_from_slice(message_3.as_slice())?; - match r_parse_message_3(&mut self.wait_m3, &mut default_crypto(), &message_3) { + match r_parse_message_3( + &mut self.wait_m3.take().ok_or(StateMismatch)?, + &mut default_crypto(), + &message_3, + ) { Ok((state, id_cred_i, ead_3)) => { - self.processing_m3 = state; + self.processing_m3 = Some(state); Ok((PyBytes::new_bound(py, id_cred_i.bytes.as_slice()), ead_3)) } Err(error) => Err(error.into()), @@ -112,9 +119,13 @@ impl PyEdhocResponder { valid_cred_i: super::AutoCredential, ) -> PyResult> { let valid_cred_i = valid_cred_i.to_credential()?; - match r_verify_message_3(&mut self.processing_m3, &mut default_crypto(), valid_cred_i) { + match r_verify_message_3( + &mut self.processing_m3.take().ok_or(StateMismatch)?, + &mut default_crypto(), + valid_cred_i, + ) { Ok((state, prk_out)) => { - self.processed_m3 = state; + self.completed = Some(state); Ok(PyBytes::new_bound(py, prk_out.as_slice())) } Err(error) => Err(error.into()), @@ -157,7 +168,7 @@ impl PyEdhocResponder { context_buf[..context.len()].copy_from_slice(context.as_slice()); let res = edhoc_exporter( - &self.completed, + self.completed.as_ref().ok_or(StateMismatch)?, &mut default_crypto(), label, &context_buf, @@ -176,7 +187,7 @@ impl PyEdhocResponder { context_buf[..context.len()].copy_from_slice(context.as_slice()); let res = edhoc_key_update( - &mut self.completed, + self.completed.as_mut().ok_or(StateMismatch)?, &mut default_crypto(), &context_buf, context.len(), From 160e3b26bc9d8cbe5958836d480a55ed7bdb94ff Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Tue, 5 Nov 2024 12:25:52 +0100 Subject: [PATCH 13/19] python: rebase to add chris commit. python-no-zero-keys --- lakers-python/src/initiator.rs | 8 +++++--- lakers-python/src/responder.rs | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index 9013ebba..aaa46468 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -15,6 +15,7 @@ pub struct PyEdhocInitiator { wait_m2: Option, processing_m2: Option, processed_m2: Option, + wait_m4: Option, completed: Option, } @@ -39,6 +40,7 @@ impl PyEdhocInitiator { wait_m2: None, processing_m2: None, processed_m2: None, + wait_m4: None, completed: None, } } @@ -131,7 +133,7 @@ impl PyEdhocInitiator { &ead_3, ) { Ok((state, message_3, prk_out)) => { - self.completed = Some(state); + self.wait_m4 = Some(state); Ok(( PyBytes::new_bound(py, message_3.as_slice()), PyBytes::new_bound(py, prk_out.as_slice()), @@ -144,7 +146,7 @@ impl PyEdhocInitiator { pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { match i_complete_without_message_4(&self.wait_m4) { Ok(state) => { - self.completed = state; + self.completed = Some(state); Ok(()) } Err(error) => Err(error.into()), @@ -160,7 +162,7 @@ impl PyEdhocInitiator { match i_process_message_4(&mut self.wait_m4, &mut default_crypto(), &message_4) { Ok((state, ead_4)) => { - self.completed = state; + self.completed = Some(state); Ok(ead_4) } Err(error) => Err(error.into()), diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index 9d74340c..0c545b33 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -13,6 +13,7 @@ pub struct PyEdhocResponder { processing_m1: Option, wait_m3: Option, processing_m3: Option, + processed_m3: Option, completed: Option, } @@ -36,6 +37,7 @@ impl PyEdhocResponder { processing_m1: None, wait_m3: None, processing_m3: None, + processed_m3: None, completed: None, }) } @@ -125,7 +127,7 @@ impl PyEdhocResponder { valid_cred_i, ) { Ok((state, prk_out)) => { - self.completed = Some(state); + self.processed_m3 = Some(state); Ok(PyBytes::new_bound(py, prk_out.as_slice())) } Err(error) => Err(error.into()), @@ -140,7 +142,7 @@ impl PyEdhocResponder { ) -> PyResult> { match r_prepare_message_4(&self.processed_m3, &mut default_crypto(), &ead_4) { Ok((state, message_4)) => { - self.completed = state; + self.completed = Some(state); Ok(PyBytes::new_bound(py, message_4.as_slice())) } Err(error) => Err(error.into()), @@ -150,7 +152,7 @@ impl PyEdhocResponder { pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { match r_complete_without_message_4(&self.processed_m3) { Ok(state) => { - self.completed = state; + self.completed = Some(state); Ok(()) } Err(error) => Err(error.into()), From 25e1206ab4651f32b01eff58c2643f61929244c4 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Tue, 5 Nov 2024 13:20:04 +0100 Subject: [PATCH 14/19] python: fix examples in python. Advanced state. Fix optional values --- lakers-python/README.md | 2 +- lakers-python/src/initiator.rs | 4 ++-- lakers-python/src/responder.rs | 4 ++-- lakers-python/test/test_lakers.py | 4 ++++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lakers-python/README.md b/lakers-python/README.md index abc0eabd..227dcfb6 100644 --- a/lakers-python/README.md +++ b/lakers-python/README.md @@ -42,7 +42,7 @@ To deploy: ln -s ../examples ./examples MATURIN_PYPI_TOKEN= maturin publish ``` - +.take().ok_or(StateMismatch)?, ## Requirements The maturin executable must be available. The recommended way is to install and use it in a virtual environment: diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index aaa46468..c158aaca 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -144,7 +144,7 @@ impl PyEdhocInitiator { } pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { - match i_complete_without_message_4(&self.wait_m4) { + match i_complete_without_message_4(&self.wait_m4.take().ok_or(StateMismatch)?) { Ok(state) => { self.completed = Some(state); Ok(()) @@ -160,7 +160,7 @@ impl PyEdhocInitiator { ) -> PyResult> { let message_4 = EdhocMessageBuffer::new_from_slice(message_4.as_slice())?; - match i_process_message_4(&mut self.wait_m4, &mut default_crypto(), &message_4) { + match i_process_message_4(&mut self.wait_m4.take().ok_or(StateMismatch)?, &mut default_crypto(), &message_4) { Ok((state, ead_4)) => { self.completed = Some(state); Ok(ead_4) diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index 0c545b33..c861138c 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -140,7 +140,7 @@ impl PyEdhocResponder { py: Python<'a>, ead_4: Option, ) -> PyResult> { - match r_prepare_message_4(&self.processed_m3, &mut default_crypto(), &ead_4) { + match r_prepare_message_4(&self.processed_m3.take().ok_or(StateMismatch)?, &mut default_crypto(), &ead_4) { Ok((state, message_4)) => { self.completed = Some(state); Ok(PyBytes::new_bound(py, message_4.as_slice())) @@ -150,7 +150,7 @@ impl PyEdhocResponder { } pub fn completed_without_message_4<'a>(&mut self, py: Python<'a>) -> PyResult<()> { - match r_complete_without_message_4(&self.processed_m3) { + match r_complete_without_message_4(&self.processed_m3.take().ok_or(StateMismatch)?) { Ok(state) => { self.completed = Some(state); Ok(()) diff --git a/lakers-python/test/test_lakers.py b/lakers-python/test/test_lakers.py index 9dc93715..710445ff 100644 --- a/lakers-python/test/test_lakers.py +++ b/lakers-python/test/test_lakers.py @@ -69,6 +69,10 @@ def _test_handshake(cred_r_transfer, cred_i_transfer): assert i_prk_out == r_prk_out + # advanced state + responder.completed_without_message_4() + initiator.completed_without_message_4() + i_oscore_secret = initiator.edhoc_exporter(0, [], 16) i_oscore_salt = initiator.edhoc_exporter(1, [], 8) r_oscore_secret = responder.edhoc_exporter(0, [], 16) From 96448156067ea5730e8cf376a7c71f3117b6fa22 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Tue, 5 Nov 2024 13:24:35 +0100 Subject: [PATCH 15/19] python: correct style --- lakers-python/src/initiator.rs | 6 +++++- lakers-python/src/responder.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index c158aaca..9a2899a2 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -160,7 +160,11 @@ impl PyEdhocInitiator { ) -> PyResult> { let message_4 = EdhocMessageBuffer::new_from_slice(message_4.as_slice())?; - match i_process_message_4(&mut self.wait_m4.take().ok_or(StateMismatch)?, &mut default_crypto(), &message_4) { + match i_process_message_4( + &mut self.wait_m4.take().ok_or(StateMismatch)?, + &mut default_crypto(), + &message_4, + ) { Ok((state, ead_4)) => { self.completed = Some(state); Ok(ead_4) diff --git a/lakers-python/src/responder.rs b/lakers-python/src/responder.rs index c861138c..bb218bd1 100644 --- a/lakers-python/src/responder.rs +++ b/lakers-python/src/responder.rs @@ -140,7 +140,11 @@ impl PyEdhocResponder { py: Python<'a>, ead_4: Option, ) -> PyResult> { - match r_prepare_message_4(&self.processed_m3.take().ok_or(StateMismatch)?, &mut default_crypto(), &ead_4) { + match r_prepare_message_4( + &self.processed_m3.take().ok_or(StateMismatch)?, + &mut default_crypto(), + &ead_4, + ) { Ok((state, message_4)) => { self.completed = Some(state); Ok(PyBytes::new_bound(py, message_4.as_slice())) From 815c2a4bdbcad39bd366965ac4e59d382f5717df Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Tue, 19 Nov 2024 09:58:42 +0100 Subject: [PATCH 16/19] lakers-no_std: update mutable references --- examples/lakers-no_std/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/lakers-no_std/src/main.rs b/examples/lakers-no_std/src/main.rs index a05a31cc..8d32440f 100644 --- a/examples/lakers-no_std/src/main.rs +++ b/examples/lakers-no_std/src/main.rs @@ -132,16 +132,16 @@ fn main() -> ! { .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 + let (initiator, message_3, i_prk_out) = initiator .prepare_message_3(CredentialTransfer::ByReference, &None) .unwrap(); 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(); - let (mut responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); + let (responder, r_prk_out) = responder.verify_message_3(valid_cred_i).unwrap(); - let initiator = initiator.completed_without_message_4().unwrap(); - let responder = responder.completed_without_message_4().unwrap(); + let mut initiator = initiator.completed_without_message_4().unwrap(); + let mut responder = responder.completed_without_message_4().unwrap(); // check that prk_out is equal at initiator and responder side assert_eq!(i_prk_out, r_prk_out); From 628266e7c11cfb0b404ccc75a7a5fb786a1d659a Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Tue, 19 Nov 2024 10:20:08 +0100 Subject: [PATCH 17/19] shared: adding WaitM4 to cbindgen --- examples/coap/src/bin/coapserver-coaphandler.rs | 3 +-- shared/cbindgen.toml | 2 +- shared/src/lib.rs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/coap/src/bin/coapserver-coaphandler.rs b/examples/coap/src/bin/coapserver-coaphandler.rs index 55b8b4f2..6982e4c9 100644 --- a/examples/coap/src/bin/coapserver-coaphandler.rs +++ b/examples/coap/src/bin/coapserver-coaphandler.rs @@ -187,8 +187,7 @@ impl coap_handler::Handler for EdhocHandler { render_error(e) })?; - let ead_4 = None; - let (mut responder, message_4) = responder.prepare_message_4(&ead_4).unwrap(); + let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); println!("EDHOC exchange successfully completed"); println!("PRK_out: {:02x?}", prk_out); diff --git a/shared/cbindgen.toml b/shared/cbindgen.toml index ff11b562..04a17b74 100644 --- a/shared/cbindgen.toml +++ b/shared/cbindgen.toml @@ -21,6 +21,6 @@ include = [ "EdhocBuffer", "BufferKid", "BufferCred", "BufferIdCred", "CredentialKey", "CredentialType", "IdCred", "CredentialTransfer", - "InitiatorStart", "WaitM2", "Completed", "ProcessedM2", + "InitiatorStart", "WaitM2", "Completed", "ProcessedM2", "WaitM4", "EdhocInitiatorC", "EdhocInitiatorWaitM2C", "EdhocInitiatorProcessingM2C", "EdhocInitiatorProcessedM2C", "EdhocInitiatorDoneC", ] diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 62b9c2db..13000451 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -407,6 +407,7 @@ pub struct ProcessedM3 { } #[derive(Default, Debug)] +#[repr(C)] pub struct WaitM4 { pub prk_4e3m: BytesHashLen, pub th_4: BytesHashLen, From 47c72165becd86334c3e93032b352048ff322aa8 Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Fri, 22 Nov 2024 22:52:04 +0100 Subject: [PATCH 18/19] python: correct typo in function process_message_4 --- lakers-python/src/initiator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lakers-python/src/initiator.rs b/lakers-python/src/initiator.rs index 9a2899a2..61238df1 100644 --- a/lakers-python/src/initiator.rs +++ b/lakers-python/src/initiator.rs @@ -153,7 +153,7 @@ impl PyEdhocInitiator { } } - pub fn propcess_message_4<'a>( + pub fn process_message_4<'a>( &mut self, py: Python<'a>, message_4: Vec, From 5b46303cda54409a73f680fbfa9d95410dca945a Mon Sep 17 00:00:00 2001 From: Elsa Lopez Perez Date: Fri, 22 Nov 2024 23:08:07 +0100 Subject: [PATCH 19/19] python: adding message_4 in test_lakers.py --- examples/coap/src/bin/coapserver.rs | 2 +- lakers-python/README.md | 1 - lakers-python/test/test_lakers.py | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index 1534d03b..1fa8fd23 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -114,7 +114,7 @@ fn main() { }; let (mut responder, message_4) = responder.prepare_message_4(&None).unwrap(); // send empty ack back - response.message.payload = b"".to_vec(); + response.message.payload = Vec::from(message_4.as_slice()); println!("EDHOC exchange successfully completed"); println!("PRK_out: {:02x?}", prk_out); diff --git a/lakers-python/README.md b/lakers-python/README.md index 227dcfb6..c0fac05e 100644 --- a/lakers-python/README.md +++ b/lakers-python/README.md @@ -44,7 +44,6 @@ MATURIN_PYPI_TOKEN= maturin publish ``` .take().ok_or(StateMismatch)?, ## Requirements - The maturin executable must be available. The recommended way is to install and use it in a virtual environment: ``` diff --git a/lakers-python/test/test_lakers.py b/lakers-python/test/test_lakers.py index 710445ff..281987ac 100644 --- a/lakers-python/test/test_lakers.py +++ b/lakers-python/test/test_lakers.py @@ -66,12 +66,12 @@ def _test_handshake(cred_r_transfer, cred_i_transfer): assert ead_3 == None valid_cred_i = lakers.credential_check_or_fetch(id_cred_i, CRED_I) r_prk_out = responder.verify_message_3(valid_cred_i) + message_4 = responder.prepare_message_4(None) assert i_prk_out == r_prk_out - # advanced state - responder.completed_without_message_4() - initiator.completed_without_message_4() + # initiator + ead_4 = initiator.process_message_4(message_4) i_oscore_secret = initiator.edhoc_exporter(0, [], 16) i_oscore_salt = initiator.edhoc_exporter(1, [], 8)