From 8a284575e5925b075bcbd06155442efa6d164f6f Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Mon, 2 Oct 2023 15:29:28 +0200 Subject: [PATCH 01/16] refactor: remove hacspec sub-crate --- Cargo.toml | 2 - examples/coap/Cargo.toml | 2 +- examples/edhoc-rs-cc2538/Cargo.toml | 5 +- examples/edhoc-rs-no_std/Cargo.toml | 3 - hacspec/Cargo.toml | 18 - hacspec/adjust_features_for_hax.patch | 49 - hacspec/src/lib.rs | 2293 ------------------------- lib/Cargo.toml | 6 - lib/src/lib.rs | 345 ---- 9 files changed, 3 insertions(+), 2720 deletions(-) delete mode 100644 hacspec/Cargo.toml delete mode 100644 hacspec/adjust_features_for_hax.patch delete mode 100644 hacspec/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c548161b..37212ef4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ members = [ "lib", - "hacspec", "ead", "ead/edhoc-ead-none", "ead/edhoc-ead-zeroconf", @@ -20,7 +19,6 @@ members = [ # tested on the host architecture default-members = [ "lib", - "hacspec", "ead", "crypto", "crypto/edhoc-crypto-hacspec", diff --git a/examples/coap/Cargo.toml b/examples/coap/Cargo.toml index f94fd75a..9a47f5a6 100644 --- a/examples/coap/Cargo.toml +++ b/examples/coap/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -edhoc-rs = { path = "../../lib", features = [ "hacspec-hacspec" ] } +edhoc-rs = { path = "../../lib", features = [ "rust-psa" ] } coap = { version = "0.13" } coap-lite = { version = "0.11.3" } diff --git a/examples/edhoc-rs-cc2538/Cargo.toml b/examples/edhoc-rs-cc2538/Cargo.toml index 2fb5d035..dd095641 100644 --- a/examples/edhoc-rs-cc2538/Cargo.toml +++ b/examples/edhoc-rs-cc2538/Cargo.toml @@ -19,7 +19,6 @@ panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] } rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] -default = [ "cc2538" ] -cc2538 = [ "edhoc-rs/hacspec-cc2538" ] -psa = [ "edhoc-rs/hacspec-psa-baremetal" ] +default = [ "psa" ] +psa = [ "edhoc-rs/rust-psa-baremetal" ] diff --git a/examples/edhoc-rs-no_std/Cargo.toml b/examples/edhoc-rs-no_std/Cargo.toml index 05772a7f..b9ce318c 100644 --- a/examples/edhoc-rs-no_std/Cargo.toml +++ b/examples/edhoc-rs-no_std/Cargo.toml @@ -21,11 +21,8 @@ rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] default = [ ] -hacspec-cc2538 = [ "edhoc-rs/hacspec-cc2538" ] -hacspec-psa = [ "edhoc-rs/hacspec-psa-baremetal" ] rust-psa = [ "edhoc-rs/rust-psa-baremetal" ] rtt = [ ] -hacspec-cryptocell310 = [ "edhoc-rs/hacspec-cryptocell310" ] rust-cryptocell310 = [ "edhoc-rs/rust-cryptocell310" ] ead-none = [ "edhoc-rs/ead-none" ] ead-zeroconf = [ "edhoc-rs/ead-zeroconf" ] diff --git a/hacspec/Cargo.toml b/hacspec/Cargo.toml deleted file mode 100644 index 94b80aeb..00000000 --- a/hacspec/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "edhoc-hacspec" -version = "0.1.0" -edition = "2021" -authors = ["Mališa Vučinić "] -license = "BSD" -description = "EDHOC implementation" - -[dependencies] -hacspec-lib = { version = "0.1.0-beta.1", default-features = false, features = [ "alloc" ] } -edhoc-crypto = { path = "../crypto", default-features = false } -edhoc-ead = { path = "../ead", default-features = false } -edhoc-consts = { path = "../consts" } - -[features] -default = [ "edhoc-ead/edhoc-ead-none" ] -ead-none = [ "edhoc-ead/edhoc-ead-none" ] -ead-zeroconf = [ "edhoc-ead/edhoc-ead-zeroconf" ] diff --git a/hacspec/adjust_features_for_hax.patch b/hacspec/adjust_features_for_hax.patch deleted file mode 100644 index 3f4c9456..00000000 --- a/hacspec/adjust_features_for_hax.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml -index 5c625a6..9dc22c3 100644 ---- a/crypto/Cargo.toml -+++ b/crypto/Cargo.toml -@@ -10,7 +10,7 @@ description = "EDHOC crypto library dispatch crate" - edhoc-consts = { path = "../consts", default-features = false } - - # hacspec --edhoc-crypto-hacspec = { path = "./edhoc-crypto-hacspec", optional = true } -+edhoc-crypto-hacspec = { path = "./edhoc-crypto-hacspec", optional = true, features = ["hacspec-pure"] } - - # cc2538 hardware accelerated - edhoc-crypto-cc2538 = { path = "./edhoc-crypto-cc2538", optional = true } -@@ -22,7 +22,7 @@ edhoc-crypto-psa = { path = "./edhoc-crypto-psa", default-features = false, opti - edhoc-crypto-cryptocell310 = { path = "./edhoc-crypto-cryptocell310-sys", optional = true } - - [features] --default = [ ] -+default = [ "hacspec" ] - hacspec = [ "edhoc-crypto-hacspec" ] - cc2538 = [ "edhoc-crypto-cc2538" ] - psa = [ "edhoc-crypto-psa/hacspec" ] -diff --git a/crypto/edhoc-crypto-hacspec/Cargo.toml b/crypto/edhoc-crypto-hacspec/Cargo.toml -index e59a361..14f606e 100644 ---- a/crypto/edhoc-crypto-hacspec/Cargo.toml -+++ b/crypto/edhoc-crypto-hacspec/Cargo.toml -@@ -15,3 +15,6 @@ hacspec-sha256 = { version = "0.1.0" } - hacspec-aes = { version = "0.1.0" } - hacspec-aes-ccm = { version = "0.1.0" } - rand = "0.8.5" -+ -+[features] -+hacspec-pure = [] -\ No newline at end of file -diff --git a/hacspec/Cargo.toml b/hacspec/Cargo.toml -index 94b80ae..51dbeb2 100644 ---- a/hacspec/Cargo.toml -+++ b/hacspec/Cargo.toml -@@ -8,8 +8,8 @@ description = "EDHOC implementation" - - [dependencies] - hacspec-lib = { version = "0.1.0-beta.1", default-features = false, features = [ "alloc" ] } --edhoc-crypto = { path = "../crypto", default-features = false } --edhoc-ead = { path = "../ead", default-features = false } -+edhoc-crypto = { path = "../crypto" } -+edhoc-ead = { path = "../ead" } - edhoc-consts = { path = "../consts" } - - [features] diff --git a/hacspec/src/lib.rs b/hacspec/src/lib.rs deleted file mode 100644 index 7e8f49e3..00000000 --- a/hacspec/src/lib.rs +++ /dev/null @@ -1,2293 +0,0 @@ -#![no_std] - -use edhoc_consts::*; -use edhoc_crypto::*; -use edhoc_ead::*; -use hacspec_lib::*; - -pub fn edhoc_exporter( - state: State, - label: U8, - context: &BytesMaxContextBuffer, - context_len: usize, - length: usize, -) -> Result<(State, BytesMaxBuffer), EDHOCError> { - let State( - current_state, - _x_or_y, - _c_i, - _gy_or_gx, - _prk_3e2m, - _prk_4e3m, - _prk_out, - prk_exporter, - _h_message_1, - _th_3, - ) = state; - - let mut output = BytesMaxBuffer::new(); - let mut error = EDHOCError::UnknownError; - - if current_state == EDHOCState::Completed { - output = edhoc_kdf(&prk_exporter, label, context, context_len, length); - Ok((state, output)) - } else { - Err(EDHOCError::WrongState) - } -} - -pub fn edhoc_key_update( - mut state: State, - context: &BytesMaxContextBuffer, - context_len: usize, -) -> Result<(State, BytesHashLen), EDHOCError> { - let State( - current_state, - _x_or_y, - _c_i, - _gy_or_gx, - _prk_3e2m, - _prk_4e3m, - mut prk_out, - mut prk_exporter, - _h_message_1, - _th_3, - ) = state; - - let mut prk_new_buf = BytesMaxBuffer::new(); - let mut error = EDHOCError::UnknownError; - - if current_state == EDHOCState::Completed { - // new PRK_out - prk_new_buf = edhoc_kdf( - &prk_out, - U8(11 as u8), - context, - context_len, - SHA256_DIGEST_LEN, - ); - prk_out = prk_out.update_slice(0, &prk_new_buf, 0, SHA256_DIGEST_LEN); - - // new PRK_exporter - prk_new_buf = edhoc_kdf( - &prk_out, - U8(10 as u8), - &BytesMaxContextBuffer::new(), - 0, - SHA256_DIGEST_LEN, - ); - prk_exporter = prk_exporter.update_slice(0, &prk_new_buf, 0, SHA256_DIGEST_LEN); - - state = construct_state( - current_state, - _x_or_y, - _c_i, - _gy_or_gx, - _prk_3e2m, - _prk_4e3m, - prk_out, - prk_exporter, - _h_message_1, - _th_3, - ); - - Ok((state, prk_out)) - } else { - Err(EDHOCError::WrongState) - } -} - -/// process message_1: parse, check method, check cipher suite -pub fn r_process_message_1( - mut state: State, - message_1: &BufferMessage1, -) -> Result { - let State( - mut current_state, - _y, - mut c_i, - g_x, - _prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - mut h_message_1, - _th_3, - ) = state; - - let mut error = EDHOCError::UnknownError; - - if current_state == EDHOCState::Start { - // Step 1: decode message_1 - // g_x will be saved to the state - let res = parse_message_1(message_1); - - if res.is_ok() { - let (method, suites_i, suites_i_len, g_x, c_i, ead_1) = res.unwrap(); - // verify that the method is supported - if method.declassify() == EDHOC_METHOD { - // Step 2: verify that the selected cipher suite is supported - if suites_i[suites_i_len - 1].declassify() - == EDHOC_SUPPORTED_SUITES[0u8].declassify() - { - // Step 3: If EAD is present make it available to the application - let ead_success = if let Some(ead_1) = ead_1 { - r_process_ead_1(ead_1.to_public_item()).is_ok() - } else { - true - }; - if ead_success { - // hash message_1 and save the hash to the state to avoid saving the whole message - h_message_1 = sha256_digest( - &BytesMaxBuffer::from_slice(&message_1.content, 0, message_1.len), - message_1.len, - ); - - error = EDHOCError::Success; - current_state = EDHOCState::ProcessedMessage1; - - state = construct_state( - current_state, - _y, - c_i, - g_x, - _prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - _th_3, - ); - } else { - error = EDHOCError::EADError; - } - } else { - error = EDHOCError::UnsupportedCipherSuite; - } - } else { - error = EDHOCError::UnsupportedMethod; - } - } else { - error = res.unwrap_err(); - } - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok(state), - _ => Err(error), - } -} - -/// Constructs message_2, which has the following format: -/// message_2 = ( -/// G_Y_CIPHERTEXT_2 : bstr, -/// ) -/// Note that the plaintext is: -/// PLAINTEXT_2 = ( C_R, ID_CRED_R / bstr / -24..23, Signature_or_MAC_2, ? EAD_2 ) -/// returns: (state, message_2, c_r) -pub fn r_prepare_message_2( - mut state: State, - id_cred_r: &BytesIdCred, - cred_r: &BytesMaxBuffer, - cred_r_len: usize, - r: &BytesP256ElemLen, // R's static private DH key - y: BytesP256ElemLen, // R's ephemeral private DH key - g_y: BytesP256ElemLen, // R's ephemeral public DH key - c_r: U8, -) -> Result<(State, BufferMessage2, U8), EDHOCError> { - let State( - mut current_state, - mut _y, - _c_i, - g_x, - mut prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - mut th_3, - ) = state; - - let mut error = EDHOCError::UnknownError; - let mut message_2 = BufferMessage2::new(); - - if current_state == EDHOCState::ProcessedMessage1 { - // compute TH_2 - let th_2 = compute_th_2(&g_y, &h_message_1); - - // compute prk_3e2m - let prk_2e = compute_prk_2e(&y, &g_x, &th_2); - let salt_3e2m = compute_salt_3e2m(&prk_2e, &th_2); - prk_3e2m = compute_prk_3e2m(&salt_3e2m, r, &g_x); - - // compute MAC_2 - let mac_2 = compute_mac_2(&prk_3e2m, id_cred_r, cred_r, cred_r_len, &th_2); - - let ead_2 = match r_prepare_ead_2() { - Some(ead_item) => Some(EADItemHacspec::from_public_item(&ead_item)), - None => None, - }; - - // compute ciphertext_2 - let plaintext_2 = encode_plaintext_2(c_r, id_cred_r, &mac_2, &ead_2); - - // step is actually from processing of message_3 - // but we do it here to avoid storing plaintext_2 in State - th_3 = compute_th_3(&th_2, &plaintext_2, cred_r, cred_r_len); - - let (ciphertext_2, ciphertext_2_len) = - encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &plaintext_2); - - message_2 = encode_message_2( - &g_y, - &BufferCiphertext2::from_slice(&ciphertext_2, 0, ciphertext_2_len), - ); - - error = EDHOCError::Success; - current_state = EDHOCState::WaitMessage3; - - state = construct_state( - current_state, - y, - _c_i, - g_x, - prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - th_3, - ); - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok((state, message_2, c_r)), - _ => Err(error), - } -} - -/// process message_3: decrypt, parse, check kid, check mac -/// returns (state, prk_out) -// FIXME fetch ID_CRED_I and CRED_I based on kid -pub fn r_process_message_3( - mut state: State, - message_3: &BufferMessage3, - id_cred_i_expected: &BytesIdCred, - cred_i_expected: &BytesMaxBuffer, - cred_i_len: usize, - g_i: &BytesP256ElemLen, // I's public DH key -) -> Result<(State, BytesHashLen), EDHOCError> { - let State( - mut current_state, - y, - _c_i, - _g_x, - prk_3e2m, - mut prk_4e3m, - mut prk_out, - mut prk_exporter, - _h_message_1, - th_3, - ) = state; - - let mut error = EDHOCError::UnknownError; - - if current_state == EDHOCState::WaitMessage3 { - let plaintext_3 = decrypt_message_3(&prk_3e2m, &th_3, message_3); - - if plaintext_3.is_ok() { - let plaintext_3 = plaintext_3.unwrap(); - let decoded_p3_res = decode_plaintext_3(&plaintext_3); - - if decoded_p3_res.is_ok() { - let (kid, mac_3, ead_3) = decoded_p3_res.unwrap(); - - // Step 3: If EAD is present make it available to the application - let ead_success = if let Some(ead_3) = ead_3 { - r_process_ead_3(ead_3.to_public_item()).is_ok() - } else { - true - }; - if ead_success { - // compare the kid received with the kid expected in id_cred_i - if kid.declassify() - == id_cred_i_expected[id_cred_i_expected.len() - 1].declassify() - { - // compute salt_4e3m - let salt_4e3m = compute_salt_4e3m(&prk_3e2m, &th_3); - // compute prk_4e3m - prk_4e3m = compute_prk_4e3m(&salt_4e3m, &y, g_i); - - // compute mac_3 - let expected_mac_3 = compute_mac_3( - &prk_4e3m, - &th_3, - id_cred_i_expected, - cred_i_expected, - cred_i_len, - ); - - // verify mac_3 - if mac_3.declassify_eq(&expected_mac_3) { - error = EDHOCError::Success; - let th_4 = - compute_th_4(&th_3, &plaintext_3, cred_i_expected, cred_i_len); - - // compute prk_out - // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let prk_out_buf = edhoc_kdf( - &prk_4e3m, - U8(7 as u8), - &BytesMaxContextBuffer::from_slice(&th_4, 0, th_4.len()), - th_4.len(), - SHA256_DIGEST_LEN, - ); - prk_out = prk_out.update_slice(0, &prk_out_buf, 0, SHA256_DIGEST_LEN); - - // compute prk_exporter from prk_out - // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let prk_exporter_buf = edhoc_kdf( - &prk_out, - U8(10 as u8), - &BytesMaxContextBuffer::new(), - 0, - SHA256_DIGEST_LEN, - ); - prk_exporter = prk_exporter.update_slice( - 0, - &prk_exporter_buf, - 0, - SHA256_DIGEST_LEN, - ); - - error = EDHOCError::Success; - current_state = EDHOCState::Completed; - - state = construct_state( - current_state, - y, - _c_i, - _g_x, - prk_3e2m, - prk_4e3m, - prk_out, - prk_exporter, - _h_message_1, - th_3, - ); - } else { - error = EDHOCError::MacVerificationFailed; - } - } else { - error = EDHOCError::UnknownPeer; - } - } else { - error = EDHOCError::EADError; - } - } else { - error = decoded_p3_res.unwrap_err(); - } - } else { - // error handling for err = decrypt_message_3(&prk_3e2m, &th_3, message_3); - error = plaintext_3.unwrap_err(); - } - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok((state, prk_out)), - _ => Err(error), - } -} - -/// Constructs message_2, which has the following format: -/// message_1 = ( -/// METHOD : int, -/// SUITES_I : suites, -/// G_X : bstr, -/// C_I : bstr / -24..23, -/// ? EAD_1, -/// ) -/// -/// suites = [ 2* int ] / int -/// EAD_1 = 1* ead -/// returns: (state, message_1) -pub fn i_prepare_message_1( - mut state: State, - x: BytesP256ElemLen, - g_x: BytesP256ElemLen, - c_i: U8, -) -> Result<(State, BufferMessage1), EDHOCError> { - let State( - mut current_state, - mut _x, - mut _c_i, - _g_y, - _prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - mut h_message_1, - _th_3, - ) = state; - - let mut error = EDHOCError::UnknownError; - - let mut message_1 = BufferMessage1::new(); - - if current_state == EDHOCState::Start { - // we only support a single cipher suite which is already CBOR-encoded - let suites_i = - BytesSuites::from_slice(&EDHOC_SUPPORTED_SUITES, 0, EDHOC_SUPPORTED_SUITES.len()); - - let ead_1 = match i_prepare_ead_1() { - Some(ead_item) => Some(EADItemHacspec::from_public_item(&ead_item)), - None => None, - }; - - // Encode message_1 as a sequence of CBOR encoded data items as specified in Section 5.2.1 - message_1 = encode_message_1( - U8(EDHOC_METHOD), - &suites_i, - EDHOC_SUPPORTED_SUITES.len(), - &g_x, - c_i, - &ead_1, - ); - - // hash message_1 here to avoid saving the whole message in the state - h_message_1 = sha256_digest( - &BytesMaxBuffer::from_slice(&message_1.content, 0, message_1.len), - message_1.len, - ); - error = EDHOCError::Success; - current_state = EDHOCState::WaitMessage2; - - state = construct_state( - current_state, - x, - c_i, - _g_y, - _prk_3e2m, - _prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - _th_3, - ); - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok((state, message_1)), - _ => Err(error), - } -} - -/// process message_2: parse, decrypt, check mac, check kid -/// returns c_r -pub fn i_process_message_2( - mut state: State, - message_2: &BufferMessage2, - id_cred_r_expected: &BytesIdCred, - cred_r_expected: &BytesMaxBuffer, - cred_r_len: usize, - g_r: &BytesP256ElemLen, // R's static public DH key - i: &BytesP256ElemLen, // I's static private DH key -) -> Result<(State, U8, U8), EDHOCError> { - let State( - mut current_state, - x, - _c_i, - g_y, - mut prk_3e2m, - mut prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - mut th_3, - ) = state; - - // init error - let mut error = EDHOCError::UnknownError; - let mut c_r = U8(0xffu8); // invalidate c_r - let mut kid = U8(0xffu8); // invalidate kid - - if current_state == EDHOCState::WaitMessage2 { - let res = parse_message_2(message_2); - if res.is_ok() { - let (g_y, ciphertext_2) = res.unwrap(); - - let th_2 = compute_th_2(&g_y, &h_message_1); - - // compute prk_2e - let prk_2e = compute_prk_2e(&x, &g_y, &th_2); - - let (plaintext_2, plaintext_2_len) = - encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &ciphertext_2); - - // decode plaintext_2 - let plaintext_2_decoded = decode_plaintext_2(&plaintext_2, plaintext_2_len); - - if plaintext_2_decoded.is_ok() { - let (c_r_2, kid, mac_2, ead_2) = plaintext_2_decoded.unwrap(); - c_r = c_r_2; - - // Step 3: If EAD is present make it available to the application - let ead_success = if let Some(ead_2) = ead_2 { - i_process_ead_2(ead_2.to_public_item()).is_ok() - } else { - true - }; - if ead_success { - // verify mac_2 - let salt_3e2m = compute_salt_3e2m(&prk_2e, &th_2); - - prk_3e2m = compute_prk_3e2m(&salt_3e2m, &x, g_r); - - let expected_mac_2 = compute_mac_2( - &prk_3e2m, - id_cred_r_expected, - cred_r_expected, - cred_r_len, - &th_2, - ); - - // Check MAC before checking KID - if mac_2.declassify_eq(&expected_mac_2) { - if kid.declassify() - == id_cred_r_expected[id_cred_r_expected.len() - 1].declassify() - { - // step is actually from processing of message_3 - // but we do it here to avoid storing plaintext_2 in State - th_3 = compute_th_3( - &th_2, - &BufferPlaintext2::from_slice(&plaintext_2, 0, plaintext_2_len), - cred_r_expected, - cred_r_len, - ); - // message 3 processing - - let salt_4e3m = compute_salt_4e3m(&prk_3e2m, &th_3); - - prk_4e3m = compute_prk_4e3m(&salt_4e3m, i, &g_y); - - error = EDHOCError::Success; - current_state = EDHOCState::ProcessedMessage2; - - state = construct_state( - current_state, - x, - _c_i, - g_y, - prk_3e2m, - prk_4e3m, - _prk_out, - _prk_exporter, - h_message_1, - th_3, - ); - } else { - // Unknown peer - error = EDHOCError::UnknownPeer; - } - } else { - error = EDHOCError::MacVerificationFailed; - } - } else { - error = EDHOCError::EADError; - } - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok((state, c_r, kid)), - _ => Err(error), - } -} - -/// Build message_3 as follows: -/// message_3 = ( -/// CIPHERTEXT_3 : bstr, -/// ) -/// Note that the plaintext is: -/// PLAINTEXT_3 = ( ID_CRED_I / bstr / -24..23, Signature_or_MAC_3, ? EAD_3 ) -/// returns: (state, message_3, prk_out) -pub fn i_prepare_message_3( - mut state: State, - id_cred_i: &BytesIdCred, - cred_i: &BytesMaxBuffer, - cred_i_len: usize, -) -> Result<(State, BufferMessage3, BytesHashLen), EDHOCError> { - let State( - mut current_state, - _x, - _c_i, - _g_y, - prk_3e2m, - prk_4e3m, - mut prk_out, - mut prk_exporter, - _h_message_1, - th_3, - ) = state; - - let mut error = EDHOCError::UnknownError; - let mut message_3 = BufferMessage3::new(); - - if current_state == EDHOCState::ProcessedMessage2 { - let mac_3 = compute_mac_3(&prk_4e3m, &th_3, id_cred_i, cred_i, cred_i_len); - - let ead_3 = match i_prepare_ead_3() { - Some(ead_item) => Some(EADItemHacspec::from_public_item(&ead_item)), - None => None, - }; - - let plaintext_3 = encode_plaintext_3(id_cred_i, &mac_3, &ead_3); - message_3 = encrypt_message_3(&prk_3e2m, &th_3, &plaintext_3); - - let th_4 = compute_th_4(&th_3, &plaintext_3, cred_i, cred_i_len); - - // compute prk_out - // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let prk_out_buf = edhoc_kdf( - &prk_4e3m, - U8(7 as u8), - &BytesMaxContextBuffer::from_slice(&th_4, 0, th_4.len()), - th_4.len(), - SHA256_DIGEST_LEN, - ); - prk_out = prk_out.update_slice(0, &prk_out_buf, 0, SHA256_DIGEST_LEN); - - // compute prk_exporter from prk_out - // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let prk_exporter_buf = edhoc_kdf( - &prk_out, - U8(10 as u8), - &BytesMaxContextBuffer::new(), - 0, - SHA256_DIGEST_LEN, - ); - prk_exporter = prk_exporter.update_slice(0, &prk_exporter_buf, 0, SHA256_DIGEST_LEN); - error = EDHOCError::Success; - current_state = EDHOCState::Completed; - - state = construct_state( - current_state, - _x, - _c_i, - _g_y, - prk_3e2m, - prk_4e3m, - prk_out, - prk_exporter, - _h_message_1, - th_3, - ); - } else { - error = EDHOCError::WrongState; - } - - match error { - EDHOCError::Success => Ok((state, message_3, prk_out)), - _ => Err(error), - } -} - -pub fn construct_state( - state: EDHOCState, - x_or_y: BytesP256ElemLen, - c_i: U8, - gx_or_gy: BytesP256ElemLen, - prk_3e2m: BytesHashLen, - prk_4e3m: BytesHashLen, - prk_out: BytesHashLen, - prk_exporter: BytesHashLen, - h_message_1: BytesHashLen, - th_3: BytesHashLen, -) -> State { - State( - state, - x_or_y, - c_i, - gx_or_gy, - prk_3e2m, - prk_4e3m, - prk_out, - prk_exporter, - h_message_1, - th_3, - ) -} - -/// Check for: an unsigned integer encoded as a single byte -#[inline(always)] -fn is_cbor_uint_1byte(byte: U8) -> bool { - let byte = byte.declassify(); - return byte >= CBOR_UINT_1BYTE_START && byte <= CBOR_UINT_1BYTE_END; -} - -/// Check for: an unsigned integer encoded as two bytes -#[inline(always)] -fn is_cbor_uint_2bytes(byte: U8) -> bool { - return byte.declassify() == CBOR_UINT_1BYTE; -} - -/// Check for: a negative integer encoded as a single byte -#[inline(always)] -fn is_cbor_neg_int_1byte(byte: U8) -> bool { - let byte = byte.declassify(); - return byte >= CBOR_NEG_INT_1BYTE_START && byte <= CBOR_NEG_INT_1BYTE_END; -} - -/// Check for: a bstr denoted by a single byte which encodes both type and content length -#[inline(always)] -fn is_cbor_bstr_1byte_prefix(byte: U8) -> bool { - let byte = byte.declassify(); - return byte >= CBOR_MAJOR_BYTE_STRING && byte <= CBOR_MAJOR_BYTE_STRING_MAX; -} - -/// Check for: a bstr denoted by two bytes, onr for type the other for content length -#[inline(always)] -fn is_cbor_bstr_2bytes_prefix(byte: U8) -> bool { - return byte.declassify() == CBOR_BYTE_STRING; -} - -/// Check for: an array denoted by a single byte which encodes both type and content length -#[inline(always)] -fn is_cbor_array_1byte_prefix(byte: U8) -> bool { - let byte = byte.declassify(); - return byte >= CBOR_MAJOR_ARRAY && byte <= CBOR_MAJOR_ARRAY_MAX; -} - -fn parse_suites_i( - rcvd_message_1: &BufferMessage1, -) -> Result<(BytesSuites, usize, usize), EDHOCError> { - let mut error: EDHOCError = EDHOCError::UnknownError; - let mut raw_suites_len = 0; - let mut suites_i = BytesSuites::new(); - let mut suites_i_len: usize = 0; - - // match based on first byte of SUITES_I, which can be either an int or an array - if is_cbor_uint_1byte(rcvd_message_1.content[1]) { - // CBOR unsigned integer (0..=23) - suites_i[0] = rcvd_message_1.content[1]; - suites_i_len = 1; - raw_suites_len = 1; - error = EDHOCError::Success; - } else if is_cbor_uint_2bytes(rcvd_message_1.content[1]) { - // CBOR unsigned integer (one-byte uint8_t follows) - suites_i[0] = rcvd_message_1.content[2]; - suites_i_len = 1; - raw_suites_len = 2; - error = EDHOCError::Success; - } else if is_cbor_array_1byte_prefix(rcvd_message_1.content[1]) { - // CBOR array (0..=23 data items follow) - // the CBOR array length is encoded in the first byte, so we extract it - let suites_len: U8 = rcvd_message_1.content[1] - U8(CBOR_MAJOR_ARRAY); - let suites_len: usize = suites_len.declassify().into(); - raw_suites_len = 1; // account for the CBOR_MAJOR_ARRAY byte - if suites_len > 1 && suites_len <= EDHOC_SUITES.len() { - // cipher suite array must be at least 2 elements long, but not longer than the defined cipher suites - let mut error_occurred = false; - for j in 0..suites_len { - raw_suites_len += 1; - if !error_occurred { - // parse based on cipher suite identifier - if is_cbor_uint_1byte(rcvd_message_1.content[raw_suites_len]) { - // CBOR unsigned integer (0..23) - suites_i[j] = rcvd_message_1.content[raw_suites_len]; - suites_i_len += 1; - } else if is_cbor_uint_2bytes(rcvd_message_1.content[raw_suites_len]) { - // CBOR unsigned integer (one-byte uint8_t follows) - raw_suites_len += 1; // account for the 0x18 tag byte - suites_i[j] = rcvd_message_1.content[raw_suites_len]; - suites_i_len += 1; - } else { - error = EDHOCError::ParsingError; - error_occurred = true; - } - } - } - if !error_occurred { - error = EDHOCError::Success; - } - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - - match error { - EDHOCError::Success => Ok((suites_i, suites_i_len, raw_suites_len)), - _ => Err(error), - } -} - -fn parse_ead( - message: &EdhocMessageBufferHacspec, - offset: usize, -) -> Result, EDHOCError> { - let mut error: EDHOCError = EDHOCError::UnknownError; - let mut ead_item = None::; - let mut ead_value = None::; - - // assume label is a single byte integer (negative or positive) - let label = message.content[offset]; - let res_label = if is_cbor_uint_1byte(label) { - // CBOR unsigned integer (0..=23) - Ok((label.declassify() as u8, false)) - } else if is_cbor_neg_int_1byte(label) { - // CBOR negative integer (-1..=-24) - Ok((label.declassify() - (CBOR_NEG_INT_1BYTE_START - 1), true)) - } else { - Err(EDHOCError::ParsingError) - }; - - if res_label.is_ok() { - let (label, is_critical) = res_label.unwrap(); - if message.len > (offset + 1) { - // EAD value is present - let buffer = EdhocMessageBufferHacspec::from_slice( - &message.content, - offset + 1, - message.len - (offset + 1), - ); - ead_value = Some(buffer); - } - ead_item = Some(EADItemHacspec { - label: U8(label), - is_critical, - value: ead_value, - }); - error = EDHOCError::Success; - } else { - error = res_label.unwrap_err(); - } - - match error { - EDHOCError::Success => Ok(ead_item), - _ => Err(error), - } -} - -fn parse_message_1( - rcvd_message_1: &BufferMessage1, -) -> Result< - ( - U8, - BytesSuites, - usize, - BytesP256ElemLen, - U8, - Option, - ), - EDHOCError, -> { - let mut error: EDHOCError = EDHOCError::UnknownError; - let mut method: U8 = U8(0xff); - let mut g_x: BytesP256ElemLen = BytesP256ElemLen::new(); - let mut suites_i = BytesSuites::new(); - let mut suites_i_len: usize = 0; - let mut raw_suites_len: usize = 0; - let mut c_i = U8(0); - let mut ead_1 = None::; - - // first element of CBOR sequence must be an integer - if is_cbor_uint_1byte(rcvd_message_1.content[0]) { - method = rcvd_message_1.content[0]; - - let res_suites = parse_suites_i(rcvd_message_1); - - if res_suites.is_ok() { - (suites_i, suites_i_len, raw_suites_len) = res_suites.unwrap(); - - if is_cbor_bstr_2bytes_prefix(rcvd_message_1.content[1 + raw_suites_len]) { - g_x = BytesP256ElemLen::from_slice( - &rcvd_message_1.content, - 3 + raw_suites_len, - P256_ELEM_LEN, - ); - - c_i = rcvd_message_1.content[3 + raw_suites_len + P256_ELEM_LEN]; - // check that c_i is encoded as single-byte int (we still do not support bstr encoding) - if is_cbor_neg_int_1byte(c_i) || is_cbor_uint_1byte(c_i) { - // if there is still more to parse, the rest will be the EAD_1 - if rcvd_message_1.len > (4 + raw_suites_len + P256_ELEM_LEN) { - // NOTE: since the current implementation only supports one EAD handler, - // we assume only one EAD item - let ead_res = parse_ead(rcvd_message_1, 4 + raw_suites_len + P256_ELEM_LEN); - if ead_res.is_ok() { - ead_1 = ead_res.unwrap(); - error = EDHOCError::Success; - } else { - error = ead_res.unwrap_err(); - } - } else if rcvd_message_1.len == (4 + raw_suites_len + P256_ELEM_LEN) { - error = EDHOCError::Success; - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - } else { - error = res_suites.unwrap_err(); - } - } else { - error = EDHOCError::ParsingError; - } - - match error { - EDHOCError::Success => Ok((method, suites_i, suites_i_len, g_x, c_i, ead_1)), - _ => Err(error), - } -} - -fn encode_ead_item(ead_1: &EADItemHacspec) -> EdhocMessageBufferHacspec { - let mut output = EdhocMessageBufferHacspec::new(); - - // encode label - if ead_1.is_critical { - output.content[0] = ead_1.label + U8(CBOR_NEG_INT_1BYTE_START - 1); - } else { - output.content[0] = ead_1.label; - } - output.len = 1; - - // encode value - if let Some(ead_1_value) = &ead_1.value { - output.content = output - .content - .update_slice(1, &ead_1_value.content, 0, ead_1_value.len); - output.len += ead_1_value.len; - } - - output -} - -fn encode_message_1( - method: U8, - suites: &BytesSuites, - suites_len: usize, - g_x: &BytesP256ElemLen, - c_i: U8, - ead_1: &Option, -) -> BufferMessage1 { - let mut output = BufferMessage1::new(); - let mut raw_suites_len: usize = 0; - - output.content[0] = method; // CBOR unsigned int less than 24 is encoded verbatim - - if suites_len == 1 { - // only one suite, will be encoded as a single integer - if (suites[0] as U8).declassify() <= CBOR_UINT_1BYTE { - output.content[1] = suites[0]; - raw_suites_len = 1; - } else { - output.content[1] = U8(CBOR_UINT_1BYTE); - output.content[2] = suites[0]; // assume it is smaller than 255, which all suites are - raw_suites_len = 2; - } - } else { - // several suites, will be encoded as an array - output.content[1] = U8(CBOR_MAJOR_ARRAY + suites_len as u8); - raw_suites_len += 1; - for i in 0..suites_len { - if (suites[i] as U8).declassify() <= CBOR_UINT_1BYTE { - output.content[1 + raw_suites_len] = suites[i]; - raw_suites_len += 1; - } else { - output.content[1 + raw_suites_len] = U8(CBOR_UINT_1BYTE); - output.content[2 + raw_suites_len] = suites[i]; - raw_suites_len += 2; - } - } - }; - - output.content[1 + raw_suites_len] = U8(CBOR_BYTE_STRING); // CBOR byte string magic number - output.content[2 + raw_suites_len] = U8(P256_ELEM_LEN as u8); // length of the byte string - output.content = output.content.update(3 + raw_suites_len, g_x); - output.content[3 + raw_suites_len + P256_ELEM_LEN] = c_i; - output.len = 3 + raw_suites_len + P256_ELEM_LEN + 1; - - if let Some(ead_1) = ead_1 { - let ead_1 = encode_ead_item(ead_1); - output.content = output - .content - .update_slice(output.len, &ead_1.content, 0, ead_1.len); - output.len += ead_1.len; - } - - output -} - -fn parse_message_2( - rcvd_message_2: &BufferMessage2, -) -> Result<(BytesP256ElemLen, BufferCiphertext2), EDHOCError> { - let mut error: EDHOCError = EDHOCError::UnknownError; - // FIXME decode negative integers as well - let mut g_y: BytesP256ElemLen = BytesP256ElemLen::new(); - let mut ciphertext_2: BufferCiphertext2 = BufferCiphertext2::new(); - - // ensure the whole message is a single CBOR sequence - if is_cbor_bstr_2bytes_prefix(rcvd_message_2.content[0]) - && (rcvd_message_2.content[1] as U8).declassify() == (rcvd_message_2.len as u8 - 2) - { - g_y = BytesP256ElemLen::from_slice(&rcvd_message_2.content, 2, P256_ELEM_LEN); - let ciphertext_2_len = rcvd_message_2.len - P256_ELEM_LEN - 2; // len - gy_len - 2 - ciphertext_2 = BufferCiphertext2::from_slice( - &rcvd_message_2.content, - 2 + P256_ELEM_LEN, - ciphertext_2_len, - ); - error = EDHOCError::Success; - } else { - error = EDHOCError::ParsingError; - } - - match error { - EDHOCError::Success => Ok((g_y, ciphertext_2)), - _ => Err(error), - } -} - -fn encode_message_2(g_y: &BytesP256ElemLen, ciphertext_2: &BufferCiphertext2) -> BufferMessage2 { - let mut output = BufferMessage2::new(); - - output.content[0] = U8(CBOR_BYTE_STRING); - output.content[1] = U8(P256_ELEM_LEN as u8 + ciphertext_2.len as u8); - output.content = output.content.update(2, g_y); - output.content = output.content.update_slice( - 2 + P256_ELEM_LEN, - &ciphertext_2.content, - 0, - ciphertext_2.len, - ); - - output.len = 2 + P256_ELEM_LEN + ciphertext_2.len; - output -} - -fn compute_th_2(g_y: &BytesP256ElemLen, h_message_1: &BytesHashLen) -> BytesHashLen { - let mut message = BytesMaxBuffer::new(); - message[0] = U8(CBOR_BYTE_STRING); - message[1] = U8(P256_ELEM_LEN as u8); - message = message.update(2, g_y); - message[2 + P256_ELEM_LEN] = U8(CBOR_BYTE_STRING); - message[3 + P256_ELEM_LEN] = U8(SHA256_DIGEST_LEN as u8); - message = message.update(4 + P256_ELEM_LEN, h_message_1); - - let len = 4 + P256_ELEM_LEN + SHA256_DIGEST_LEN; - - let th_2 = sha256_digest(&message, len); - - th_2 -} - -fn compute_th_3( - th_2: &BytesHashLen, - plaintext_2: &BufferPlaintext2, - cred_r: &BytesMaxBuffer, - cred_r_len: usize, -) -> BytesHashLen { - let mut message = BytesMaxBuffer::new(); - - message[0] = U8(CBOR_BYTE_STRING); - message[1] = U8(th_2.len() as u8); - message = message.update(2, th_2); - message = message.update_slice(2 + th_2.len(), &plaintext_2.content, 0, plaintext_2.len); - message = message.update_slice(2 + th_2.len() + plaintext_2.len, cred_r, 0, cred_r_len); - - let output = sha256_digest(&message, th_2.len() + 2 + plaintext_2.len + cred_r_len); - - output -} - -fn compute_th_4( - th_3: &BytesHashLen, - plaintext_3: &BufferPlaintext3, - cred_i: &BytesMaxBuffer, - cred_i_len: usize, -) -> BytesHashLen { - let mut message = BytesMaxBuffer::new(); - - message[0] = U8(CBOR_BYTE_STRING); - message[1] = U8(th_3.len() as u8); - message = message.update(2, th_3); - message = message.update_slice(2 + th_3.len(), &plaintext_3.content, 0, plaintext_3.len); - message = message.update_slice(2 + th_3.len() + plaintext_3.len, cred_i, 0, cred_i_len); - - let output = sha256_digest(&message, th_3.len() + 2 + plaintext_3.len + cred_i_len); - - output -} - -fn edhoc_kdf( - prk: &BytesHashLen, - label: U8, - context: &BytesMaxContextBuffer, - context_len: usize, - length: usize, -) -> BytesMaxBuffer { - let mut info = BytesMaxInfoBuffer::new(); - let mut info_len = 0; - - // construct info with inline cbor encoding - info[0] = label; - if context_len < 24 { - info[1] = U8(context_len as u8 | CBOR_MAJOR_BYTE_STRING); - info = info.update_slice(2, context, 0, context_len); - info_len = 2 + context_len; - } else { - info[1] = U8(CBOR_BYTE_STRING); - info[2] = U8(context_len as u8); - info = info.update_slice(3, context, 0, context_len); - info_len = 3 + context_len; - } - if length < 24 { - info[info_len] = U8(length as u8); - info_len = info_len + 1; - } else { - info[info_len] = U8(CBOR_UINT_1BYTE); - info[info_len + 1] = U8(length as u8); - info_len = info_len + 2; - } - - let output = hkdf_expand(prk, &info, info_len, length); - - output -} - -fn decode_plaintext_3( - plaintext_3: &BufferPlaintext3, -) -> Result<(U8, BytesMac3, Option), EDHOCError> { - let mut ead_3 = None::; - let mut error = EDHOCError::UnknownError; - let mut kid = U8(0xff); - let mut mac_3 = BytesMac3::new(); - - // check ID_CRED_I and MAC_3 - if (is_cbor_neg_int_1byte(plaintext_3.content[0]) || is_cbor_uint_1byte(plaintext_3.content[0])) - && (is_cbor_bstr_1byte_prefix(plaintext_3.content[1])) - { - kid = plaintext_3.content[0]; - // skip the CBOR magic byte as we know how long the MAC is - mac_3 = BytesMac3::from_slice(&plaintext_3.content, 2, MAC_LENGTH_3); - - // if there is still more to parse, the rest will be the EAD_3 - if plaintext_3.len > (2 + MAC_LENGTH_3) { - // NOTE: since the current implementation only supports one EAD handler, - // we assume only one EAD item - let ead_res = parse_ead(plaintext_3, 2 + MAC_LENGTH_3); - if ead_res.is_ok() { - ead_3 = ead_res.unwrap(); - error = EDHOCError::Success; - } else { - error = ead_res.unwrap_err(); - } - } else if plaintext_3.len == (2 + MAC_LENGTH_3) { - error = EDHOCError::Success; - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - - match error { - EDHOCError::Success => Ok((kid, mac_3, ead_3)), - _ => Err(error), - } -} - -fn encode_plaintext_3( - id_cred_i: &BytesIdCred, - mac_3: &BytesMac3, - ead_3: &Option, -) -> BufferPlaintext3 { - let mut plaintext_3 = BufferPlaintext3::new(); - - // plaintext: P = ( ? PAD, ID_CRED_I / bstr / int, Signature_or_MAC_3, ? EAD_3 ) - plaintext_3.content[0] = id_cred_i[id_cred_i.len() - 1]; // hack: take the last byte of ID_CRED_I as KID - plaintext_3.content[1] = U8(CBOR_MAJOR_BYTE_STRING | MAC_LENGTH_3 as u8); - plaintext_3.content = plaintext_3.content.update(2, mac_3); - plaintext_3.len = 2 + MAC_LENGTH_3; - - if let Some(ead_3) = ead_3 { - let ead_3 = encode_ead_item(ead_3); - plaintext_3.content = - plaintext_3 - .content - .update_slice(plaintext_3.len, &ead_3.content, 0, ead_3.len); - plaintext_3.len += ead_3.len; - } - - plaintext_3 -} - -fn encode_enc_structure(th_3: &BytesHashLen) -> BytesEncStructureLen { - let mut encrypt0 = Bytes8::new(); - encrypt0[0] = U8(0x45u8); // 'E' - encrypt0[1] = U8(0x6eu8); // 'n' - encrypt0[2] = U8(0x63u8); // 'c' - encrypt0[3] = U8(0x72u8); // 'r' - encrypt0[4] = U8(0x79u8); // 'y' - encrypt0[5] = U8(0x70u8); // 'p' - encrypt0[6] = U8(0x74u8); // 't' - encrypt0[7] = U8(0x30u8); // '0' - - let mut enc_structure = BytesEncStructureLen::new(); - - // encode Enc_structure from draft-ietf-cose-rfc8152bis Section 5.3 - enc_structure[0] = U8(CBOR_MAJOR_ARRAY | 3 as u8); // 3 is the fixed number of elements in the array - enc_structure[1] = U8(CBOR_MAJOR_TEXT_STRING | encrypt0.len() as u8); - enc_structure = enc_structure.update(2, &encrypt0); - enc_structure[encrypt0.len() + 2] = U8(CBOR_MAJOR_BYTE_STRING | 0x00 as u8); // 0 for zero-length byte string - enc_structure[encrypt0.len() + 3] = U8(CBOR_BYTE_STRING); // byte string greater than 24 - enc_structure[encrypt0.len() + 4] = U8(SHA256_DIGEST_LEN as u8); - enc_structure = enc_structure.update(encrypt0.len() + 5, th_3); - - enc_structure -} - -fn compute_k_3_iv_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, -) -> (BytesCcmKeyLen, BytesCcmIvLen) { - // K_3 = EDHOC-KDF( PRK_3e2m, 3, TH_3, key_length ) - let k_3 = BytesCcmKeyLen::from_slice( - &edhoc_kdf( - prk_3e2m, - U8(3 as u8), - &BytesMaxContextBuffer::from_slice(th_3, 0, th_3.len()), - th_3.len(), - AES_CCM_KEY_LEN, - ), - 0, - AES_CCM_KEY_LEN, - ); - // IV_3 = EDHOC-KDF( PRK_3e2m, 4, TH_3, iv_length ) - let iv_3 = BytesCcmIvLen::from_slice( - &edhoc_kdf( - prk_3e2m, - U8(4 as u8), - &BytesMaxContextBuffer::from_slice(th_3, 0, th_3.len()), - th_3.len(), - AES_CCM_IV_LEN, - ), - 0, - AES_CCM_IV_LEN, - ); - - (k_3, iv_3) -} - -// calculates ciphertext_3 wrapped in a cbor byte string -fn encrypt_message_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, - plaintext_3: &BufferPlaintext3, -) -> BufferMessage3 { - let mut output = BufferMessage3::new(); - output.len = 1 + plaintext_3.len + AES_CCM_TAG_LEN; - output.content[0] = U8(CBOR_MAJOR_BYTE_STRING | (plaintext_3.len + AES_CCM_TAG_LEN) as u8); - - let enc_structure = encode_enc_structure(th_3); - - let (k_3, iv_3) = compute_k_3_iv_3(prk_3e2m, th_3); - - let ciphertext_3 = aes_ccm_encrypt_tag_8(&k_3, &iv_3, &enc_structure, plaintext_3); - - output.content = output - .content - .update_slice(1, &ciphertext_3.content, 0, ciphertext_3.len); - - output -} - -fn decrypt_message_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, - message_3: &BufferMessage3, -) -> Result { - let mut error = EDHOCError::UnknownError; - let mut plaintext_3 = BufferPlaintext3::new(); - - // decode message_3 - let len = (message_3.content[0usize] ^ U8(CBOR_MAJOR_BYTE_STRING)).declassify() as usize; - - let ciphertext_3 = BufferCiphertext3::from_slice(&message_3.content, 1, len); - - let (k_3, iv_3) = compute_k_3_iv_3(prk_3e2m, th_3); - - let enc_structure = encode_enc_structure(th_3); - - let p3 = aes_ccm_decrypt_tag_8(&k_3, &iv_3, &enc_structure, &ciphertext_3); - - if p3.is_ok() { - error = EDHOCError::Success; - let p3 = p3.unwrap(); - plaintext_3.content = plaintext_3.content.update_slice(0, &p3.content, 0, p3.len); - plaintext_3.len = p3.len; - } else { - error = p3.unwrap_err(); - } - - match error { - EDHOCError::Success => Ok(plaintext_3), - _ => Err(error), - } -} - -// output must hold id_cred.len() + cred.len() -fn encode_kdf_context( - id_cred: &BytesIdCred, - th: &BytesHashLen, - cred: &BytesMaxBuffer, - cred_len: usize, -) -> (BytesMaxContextBuffer, usize) { - // encode context in line - // assumes ID_CRED_R and CRED_R are already CBOR-encoded - let mut output = BytesMaxContextBuffer::new(); - output = output.update(0, id_cred); - output[id_cred.len()] = U8(CBOR_BYTE_STRING); - output[id_cred.len() + 1] = U8(SHA256_DIGEST_LEN as u8); - output = output.update(id_cred.len() + 2, th); - output = output.update_slice(id_cred.len() + 2 + SHA256_DIGEST_LEN, cred, 0, cred_len); - - let output_len = (id_cred.len() + 2 + SHA256_DIGEST_LEN + cred_len) as usize; - - (output, output_len) -} - -fn compute_mac_3( - prk_4e3m: &BytesHashLen, - th_3: &BytesHashLen, - id_cred_i: &BytesIdCred, - cred_i: &BytesMaxBuffer, - cred_i_len: usize, -) -> BytesMac3 { - // MAC_3 = EDHOC-KDF( PRK_4e3m, 6, context_3, mac_length_3 ) - let (context, context_len) = encode_kdf_context(id_cred_i, th_3, cred_i, cred_i_len); - - // compute mac_3 - let output_buf = edhoc_kdf( - prk_4e3m, - U8(6 as u8), // registered label for "MAC_3" - &context, - context_len, - MAC_LENGTH_3, - ); - - let output = BytesMac3::from_slice(&output_buf, 0, MAC_LENGTH_3); - output -} - -fn compute_mac_2( - prk_3e2m: &BytesHashLen, - id_cred_r: &BytesIdCred, - cred_r: &BytesMaxBuffer, - cred_r_len: usize, - th_2: &BytesHashLen, -) -> BytesMac2 { - // compute MAC_2 - let (context, context_len) = encode_kdf_context(id_cred_r, th_2, cred_r, cred_r_len); - - // MAC_2 = EDHOC-KDF( PRK_3e2m, 2, context_2, mac_length_2 ) - let mac_2 = BytesMac2::from_slice( - &edhoc_kdf(prk_3e2m, U8(2 as u8), &context, context_len, MAC_LENGTH_2), - 0, - MAC_LENGTH_2, - ); - - mac_2 -} - -fn decode_plaintext_2( - plaintext_2: &BytesMaxBuffer, - plaintext_2_len: usize, -) -> Result<(U8, U8, BytesMac2, Option), EDHOCError> { - let mut error = EDHOCError::UnknownError; - let mut ead_2 = None::; - let mut c_r: U8 = U8(0xff); - let mut id_cred_r: U8 = U8(0xff); - let mut mac_2 = BytesMac2::new(); - - // check CBOR sequence types for c_r, id_cred_r, and mac_2 - if (is_cbor_neg_int_1byte(plaintext_2[0]) || is_cbor_uint_1byte(plaintext_2[0])) - && (is_cbor_neg_int_1byte(plaintext_2[1]) || is_cbor_uint_1byte(plaintext_2[1])) - && (is_cbor_bstr_1byte_prefix(plaintext_2[2])) - // TODO: check mac length as well - { - c_r = plaintext_2[0]; - id_cred_r = plaintext_2[1]; - // NOTE: skipping cbor byte string byte as we know how long the string is - mac_2 = BytesMac2::from_slice(plaintext_2, 3, MAC_LENGTH_2); - - // if there is still more to parse, the rest will be the EAD_2 - if plaintext_2_len > (3 + MAC_LENGTH_2) { - // NOTE: since the current implementation only supports one EAD handler, - // we assume only one EAD item - let ead_res = parse_ead( - &EdhocMessageBufferHacspec::from_slice(plaintext_2, 0, plaintext_2_len), - 3 + MAC_LENGTH_2, - ); - if ead_res.is_ok() { - ead_2 = ead_res.unwrap(); - error = EDHOCError::Success; - } else { - error = ead_res.unwrap_err(); - } - } else if plaintext_2_len == (3 + MAC_LENGTH_2) { - error = EDHOCError::Success; - } else { - error = EDHOCError::ParsingError; - } - } else { - error = EDHOCError::ParsingError; - } - - match error { - EDHOCError::Success => Ok((c_r, id_cred_r, mac_2, ead_2)), - _ => Err(error), - } -} - -fn encode_plaintext_2( - c_r: U8, - id_cred_r: &BytesIdCred, - mac_2: &BytesMac2, - ead_2: &Option, -) -> BufferPlaintext2 { - let mut plaintext_2 = BufferPlaintext2::new(); - plaintext_2.content[0] = c_r; - plaintext_2.content[1] = id_cred_r[id_cred_r.len() - 1]; - plaintext_2.content[2] = U8(CBOR_MAJOR_BYTE_STRING | MAC_LENGTH_2 as u8); - plaintext_2.content = plaintext_2.content.update(3, mac_2); - plaintext_2.len = 3 + mac_2.len(); - - if let Some(ead_2) = ead_2 { - let ead_2 = encode_ead_item(ead_2); - plaintext_2.content = - plaintext_2 - .content - .update_slice(plaintext_2.len, &ead_2.content, 0, ead_2.len); - plaintext_2.len += ead_2.len; - } - - plaintext_2 -} - -fn encrypt_decrypt_ciphertext_2( - prk_2e: &BytesHashLen, - th_2: &BytesHashLen, - ciphertext_2: &BufferCiphertext2, -) -> (BytesMaxBuffer, usize) { - // convert the transcript hash th_2 to BytesMaxContextBuffer type - let th_2_context = BytesMaxContextBuffer::from_slice(th_2, 0, th_2.len()); - - // KEYSTREAM_2 = EDHOC-KDF( PRK_2e, 0, TH_2, plaintext_length ) - let keystream_2 = edhoc_kdf( - prk_2e, - U8(0 as u8), - &th_2_context, - SHA256_DIGEST_LEN, - ciphertext_2.len, - ); - - let mut plaintext_2 = BytesMaxBuffer::new(); - // decrypt/encrypt ciphertext_2 - for i in 0..ciphertext_2.len { - plaintext_2[i] = ciphertext_2.content[i] ^ keystream_2[i]; - } - - (plaintext_2, ciphertext_2.len) -} - -fn compute_salt_4e3m(prk_3e2m: &BytesHashLen, th_3: &BytesHashLen) -> BytesHashLen { - let th_3_context = BytesMaxContextBuffer::from_slice(th_3, 0, th_3.len()); - let salt_4e3m_buf = edhoc_kdf( - prk_3e2m, - U8(5 as u8), - &th_3_context, - th_3.len(), - SHA256_DIGEST_LEN, - ); - let mut salt_4e3m = BytesHashLen::new(); - salt_4e3m = salt_4e3m.update_slice(0, &salt_4e3m_buf, 0, SHA256_DIGEST_LEN); - - salt_4e3m -} - -fn compute_prk_4e3m( - salt_4e3m: &BytesHashLen, - i: &BytesP256ElemLen, - g_y: &BytesP256ElemLen, -) -> BytesHashLen { - // compute g_rx from static R's public key and private ephemeral key - let g_iy = p256_ecdh(i, g_y); - let prk_4e3m = hkdf_extract(salt_4e3m, &g_iy); - - prk_4e3m -} - -fn compute_salt_3e2m(prk_2e: &BytesHashLen, th_2: &BytesHashLen) -> BytesHashLen { - let th_2_context = BytesMaxContextBuffer::from_slice(th_2, 0, th_2.len()); - - let salt_3e2m_buf = edhoc_kdf( - prk_2e, - U8(1 as u8), - &th_2_context, - SHA256_DIGEST_LEN, - SHA256_DIGEST_LEN, - ); - - let mut salt_3e2m = BytesHashLen::new(); - salt_3e2m = salt_3e2m.update_slice(0, &salt_3e2m_buf, 0, SHA256_DIGEST_LEN); - - salt_3e2m -} - -fn compute_prk_3e2m( - salt_3e2m: &BytesHashLen, - x_or_r: &BytesP256ElemLen, - gx_or_gr: &BytesP256ElemLen, -) -> BytesHashLen { - // compute g_rx from static private key and public ephemeral key - let g_rx = p256_ecdh(x_or_r, gx_or_gr); - let prk_3e2m = hkdf_extract(salt_3e2m, &g_rx); - - prk_3e2m -} - -fn compute_prk_2e( - x: &BytesP256ElemLen, - g_y: &BytesP256ElemLen, - th_2: &BytesHashLen, -) -> BytesHashLen { - // compute the shared secret - let g_xy = p256_ecdh(x, g_y); - // compute prk_2e as PRK_2e = HMAC-SHA-256( salt, G_XY ) - let prk_2e = hkdf_extract(th_2, &g_xy); - - prk_2e -} - -#[cfg(test)] -mod tests { - use super::*; - // test vectors (TV) - - // message_1 (first_time) - const METHOD_TV_FIRST_TIME: u8 = 0x03; - const SUITES_I_TV_FIRST_TIME: &str = "060000000000000000"; - const G_X_TV_FIRST_TIME: &str = - "741a13d7ba048fbb615e94386aa3b61bea5b3d8f65f32620b749bee8d278efa9"; - const C_I_TV_FIRST_TIME: u8 = 0x0e; - const MESSAGE_1_TV_FIRST_TIME: &str = - "03065820741a13d7ba048fbb615e94386aa3b61bea5b3d8f65f32620b749bee8d278efa90e"; - - // message_1 (second time) - const METHOD_TV: u8 = 0x03; - const SUITES_I_TV: &str = "060200000000000000"; - const G_X_TV: &str = "8af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b6"; - const C_I_TV: u8 = 0x37; - const MESSAGE_1_TV: &str = - "0382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b637"; - // below are a few truncated messages for the purpose of testing cipher suites - // message with one cipher suite (23..=255) - const MESSAGE_1_TV_SUITE_ONLY_A: &str = "031818"; - // message with an array having two cipher suites with small values (0..=23) - const MESSAGE_1_TV_SUITE_ONLY_B: &str = "03820201"; - // message with an array having two cipher suites, where one is a large value (23..=255) - const MESSAGE_1_TV_SUITE_ONLY_C: &str = "0382021819"; - // message with an array having too many cipher suites (more than 9) - const MESSAGE_1_TV_SUITE_ONLY_ERR: &str = "038A02020202020202020202"; - const EAD_DUMMY_LABEL_TV: u8 = 0x01; - const EAD_DUMMY_VALUE_TV: &str = "cccccc"; - const EAD_DUMMY_CRITICAL_TV: &str = "20cccccc"; - const MESSAGE_1_WITH_DUMMY_EAD_NO_VALUE_TV: &str = - "0382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b63701"; - const MESSAGE_1_WITH_DUMMY_EAD_TV: &str = - "0382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b63701cccccc"; - const MESSAGE_1_WITH_DUMMY_CRITICAL_EAD_TV: &str = - "0382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b63720cccccc"; - const PLAINTEXT_2_WITH_DUMMY_CRITICAL_EAD_TV: &str = "3248d0d1a594797d0aaf20cccccc"; - const PLAINTEXT_3_WITH_DUMMY_CRITICAL_EAD_TV: &str = "2b48ddf106b86fd22fe420cccccc"; - const G_Y_TV: &str = "419701d7f00a26c2dc587a36dd752549f33763c893422c8ea0f955a13a4ff5d5"; - const C_R_TV: u8 = 0x27; - pub const MESSAGE_2_LEN_TV: usize = 45; - pub const CIPHERTEXT_2_LEN_TV: usize = MESSAGE_2_LEN_TV - P256_ELEM_LEN - 2; - pub const PLAINTEXT_2_LEN_TV: usize = CIPHERTEXT_2_LEN_TV; - const MESSAGE_2_TV: &str = - "582b419701d7f00a26c2dc587a36dd752549f33763c893422c8ea0f955a13a4ff5d59862a11de42a95d785386a"; - const CIPHERTEXT_2_TV: &str = "9862a11de42a95d785386a"; - const H_MESSAGE_1_TV: &str = "ca02cabda5a8902749b42f711050bb4dbd52153e87527594b39f50cdf019888c"; - const TH_2_TV: &str = "356efd53771425e008f3fe3a86c83ff4c6b16e57028ff39d5236c182b202084b"; - const TH_3_TV: &str = "dfe5b065e64c72d226d500c12d49bee6dc4881ded0965e9bdf89d24a54f2e59a"; - const CIPHERTEXT_3_TV: &str = "473dd16077dd71d65b56e6bd71e7a49d6012"; - const TH_4_TV: &str = "baf60adbc500fce789af25b108ada2275575056c52c1c2036a2da4a643891cb4"; - const PRK_2E_TV: &str = "5aa0d69f3e3d1e0c479f0b8a486690c9802630c3466b1dc92371c982563170b5"; - const KEYSTREAM_2_TV: &str = "bf50e9e7bad0bb68173399"; - const PRK_3E2M_TV: &str = "0ca3d3398296b3c03900987620c11f6fce70781c1d1219720f9ec08c122d8434"; - const CONTEXT_INFO_MAC_2_TV: &str = "a10441325820356efd53771425e008f3fe3a86c83ff4c6b16e57028ff39d5236c182b202084ba2026b6578616d706c652e65647508a101a501020241322001215820bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f02258204519e257236b2a0ce2023f0931f1f386ca7afda64fcde0108c224c51eabf6072"; - const MAC_2_TV: &str = "fa5efa2ebf920bf3"; - const ID_CRED_I_TV: &str = "a104412b"; - const MAC_3_TV: &str = "a5eeb9effdabfc39"; - const MESSAGE_3_TV: &str = "52473dd16077dd71d65b56e6bd71e7a49d6012"; - const PRK_4E3M_TV: &str = "e9cb832a240095d3d0643dbe12e9e2e7b18f0360a3172cea7ac0013ee240e072"; - const CRED_I_TV: &str = "a2027734322d35302d33312d46462d45462d33372d33322d333908a101a5010202412b2001215820ac75e9ece3e50bfc8ed60399889522405c47bf16df96660a41298cb4307f7eb62258206e5de611388a4b8a8211334ac7d37ecb52a387d257e6db3c2a93df21ff3affc8"; - const ID_CRED_R_TV: &str = "a1044132"; - const CRED_R_TV: &str = "a2026b6578616d706c652e65647508a101a501020241322001215820bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f02258204519e257236b2a0ce2023f0931f1f386ca7afda64fcde0108c224c51eabf6072"; - const PLAINTEXT_2_TV: &str = "273248fa5efa2ebf920bf3"; - const SK_I_TV: &str = "fb13adeb6518cee5f88417660841142e830a81fe334380a953406a1305e8706b"; - const X_TV: &str = "368ec1f69aeb659ba37d5a8d45b21bdc0299dceaa8ef235f3ca42ce3530f9525"; - const G_R_TV: &str = "bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f0"; - const PLAINTEXT_3_TV: &str = "2b48a5eeb9effdabfc39"; - const SALT_3E2M_TV: &str = "af4e103a47cb3cf32570d5c25ad27732bd8d8178e9a69d061c31a27f8e3ca926"; - const SALT_4E3M_TV: &str = "84f8a2a9534ddd78dcc7e76e0d4df60bfad7cd3ad6e1d531c7f373a7eda52d1c"; - const G_XY_TV: &str = "2f0cb7e860ba538fbf5c8bded009f6259b4b628fe1eb7dbe9378e5ecf7a824ba"; - const PRK_OUT_TV: &str = "6b2dae4032306571cfbc2e4f94a255fb9f1f3fb29ca6f379fec989d4fa90dcf0"; - const PRK_EXPORTER_TV: &str = - "4f0a5a823d06d0005e1becda8a6e61f3c8c67a8b15da7d44d3585ec5854e91e2"; - const OSCORE_MASTER_SECRET_TV: &str = "8c409a332223ad900e44f3434d2d2ce3"; - const OSCORE_MASTER_SALT_TV: &str = "6163f44be862adfa"; - - // invalid test vectors, should result in a parsing error - const MESSAGE_1_INVALID_ARRAY_TV: &str = - "8403025820741a13d7ba048fbb615e94386aa3b61bea5b3d8f65f32620b749bee8d278efa90e"; - const MESSAGE_1_INVALID_C_I_TV: &str = - "03025820741a13d7ba048fbb615e94386aa3b61bea5b3d8f65f32620b749bee8d278efa9410e"; - const MESSAGE_1_INVALID_CIPHERSUITE_TV: &str = - "0381025820741a13d7ba048fbb615e94386aa3b61bea5b3d8f65f32620b749bee8d278efa90e"; - const MESSAGE_1_INVALID_TEXT_EPHEMERAL_KEY_TV: &str = - "0302782020616972207370656564206F66206120756E6C6164656E207377616C6C6F77200e"; - const MESSAGE_2_INVALID_NUMBER_OF_CBOR_SEQUENCE_TV: &str = - "5820419701d7f00a26c2dc587a36dd752549f33763c893422c8ea0f955a13a4ff5d54B9862a11de42a95d785386a"; - const PLAINTEXT_2_SURPLUS_MAP_ID_CRED_TV: &str = "27a10442321048fa5efa2ebf920bf3"; - const PLAINTEXT_2_SURPLUS_BSTR_ID_CRED_TV: &str = "27413248fa5efa2ebf920bf3"; - - #[test] - fn test_ecdh() { - let x_tv = BytesP256ElemLen::from_hex(X_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let g_xy_tv = BytesP256ElemLen::from_hex(G_XY_TV); - - let g_xy = p256_ecdh(&x_tv, &g_y_tv); - - assert_bytes_eq!(g_xy, g_xy_tv); - } - - #[test] - fn test_encode_message_1() { - let method_tv = U8(METHOD_TV); - let suites_i_tv = BytesSuites::from_hex(SUITES_I_TV); - let suites_i_tv_len: usize = 2; - let g_x_tv = BytesP256ElemLen::from_hex(G_X_TV); - let c_i_tv = U8(C_I_TV); - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_TV); - - let message_1 = encode_message_1( - method_tv, - &suites_i_tv, - suites_i_tv_len, - &g_x_tv, - c_i_tv, - &None::, - ); - - assert_bytes_eq!(message_1.content, message_1_tv.content); - } - - #[test] - fn test_parse_suites_i() { - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_TV); - let suites_i_tv = BytesSuites::from_hex(SUITES_I_TV); - - let res = parse_suites_i(&message_1_tv); - assert!(res.is_ok()); - let (suites_i, suites_i_len, raw_suites_len) = res.unwrap(); - assert_bytes_eq!(suites_i, suites_i_tv); - - let res = parse_suites_i(&BufferMessage1::from_hex(MESSAGE_1_TV_SUITE_ONLY_A)); - assert!(res.is_ok()); - let (suites_i, suites_i_len, raw_suites_len) = res.unwrap(); - assert_eq!((suites_i[0] as U8).declassify(), 0x18); - - let (suites_i, suites_i_len, raw_suites_len) = - parse_suites_i(&BufferMessage1::from_hex(MESSAGE_1_TV_SUITE_ONLY_B)).unwrap(); - assert_eq!(suites_i_len, 2); - assert_eq!(raw_suites_len, 3); - assert_eq!((suites_i[0] as U8).declassify(), 0x02); - assert_eq!((suites_i[1] as U8).declassify(), 0x01); - - let (suites_i, suites_i_len, raw_suites_len) = - parse_suites_i(&BufferMessage1::from_hex(MESSAGE_1_TV_SUITE_ONLY_C)).unwrap(); - assert_eq!(suites_i_len, 2); - assert_eq!(raw_suites_len, 4); - assert_eq!((suites_i[0] as U8).declassify(), 0x02); - assert_eq!((suites_i[1] as U8).declassify(), 0x19); - - let res = parse_suites_i(&BufferMessage1::from_hex(MESSAGE_1_TV_SUITE_ONLY_ERR)); - assert_eq!(res.unwrap_err(), EDHOCError::ParsingError); - } - - #[test] - fn test_parse_message_1() { - let message_1_tv_first_time = BufferMessage1::from_hex(MESSAGE_1_TV_FIRST_TIME); - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_TV); - let suites_i_tv_first_time = BytesSuites::from_hex(SUITES_I_TV_FIRST_TIME); - let suites_i_tv = BytesSuites::from_hex(SUITES_I_TV); - let g_x_tv_first_time = BytesP256ElemLen::from_hex(G_X_TV_FIRST_TIME); - let g_x_tv = BytesP256ElemLen::from_hex(G_X_TV); - let c_i_tv_first_time = U8(C_I_TV_FIRST_TIME); - let c_i_tv = U8(C_I_TV); - - // first time message_1 parsing - let res = parse_message_1(&message_1_tv_first_time); - assert!(res.is_ok()); - let (method, suites_i, suites_i_len, g_x, c_i, _ead_1) = res.unwrap(); - assert_eq!(method.declassify(), METHOD_TV_FIRST_TIME); - assert_bytes_eq!(suites_i, suites_i_tv_first_time); - assert_bytes_eq!(g_x, g_x_tv_first_time); - assert_eq!(c_i.declassify(), c_i_tv_first_time.declassify()); - - // second time message_1 - let res = parse_message_1(&message_1_tv); - assert!(res.is_ok()); - let (method, suites_i, suites_i_len, g_x, c_i, _ead_1) = res.unwrap(); - - assert_eq!(method.declassify(), METHOD_TV); - assert_bytes_eq!(suites_i, suites_i_tv); - assert_bytes_eq!(g_x, g_x_tv); - assert_eq!(c_i.declassify(), c_i_tv.declassify()); - } - - #[test] - fn test_parse_message_1_invalid_traces() { - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_INVALID_ARRAY_TV); - assert_eq!( - parse_message_1(&message_1_tv).unwrap_err(), - EDHOCError::ParsingError - ); - - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_INVALID_C_I_TV); - assert_eq!( - parse_message_1(&message_1_tv).unwrap_err(), - EDHOCError::ParsingError - ); - - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_INVALID_CIPHERSUITE_TV); - assert_eq!( - parse_message_1(&message_1_tv).unwrap_err(), - EDHOCError::ParsingError - ); - - let message_1_tv = BufferMessage1::from_hex(MESSAGE_1_INVALID_TEXT_EPHEMERAL_KEY_TV); - assert_eq!( - parse_message_1(&message_1_tv).unwrap_err(), - EDHOCError::ParsingError - ); - } - - #[test] - fn test_parse_message_2_invalid_traces() { - let message_2_tv = BufferMessage1::from_hex(MESSAGE_2_INVALID_NUMBER_OF_CBOR_SEQUENCE_TV); - assert_eq!( - parse_message_2(&message_2_tv).unwrap_err(), - EDHOCError::ParsingError - ); - } - - #[test] - fn test_encode_message_2() { - let message_2_tv = BufferMessage2::from_hex(MESSAGE_2_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let ciphertext_2_tv = BufferCiphertext2::from_hex(CIPHERTEXT_2_TV); - - let message_2 = encode_message_2(&g_y_tv, &ciphertext_2_tv); - - assert_bytes_eq!(message_2.content, message_2_tv.content); - } - - #[test] - fn test_parse_message_2() { - let message_2_tv = BufferMessage2::from_hex(MESSAGE_2_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let ciphertext_2_tv = BufferCiphertext2::from_hex(CIPHERTEXT_2_TV); - - let ret = parse_message_2(&message_2_tv); - assert!(ret.is_ok()); - let (g_y, ciphertext_2) = ret.unwrap(); - - assert_bytes_eq!(g_y, g_y_tv); - assert_bytes_eq!(ciphertext_2.content, ciphertext_2_tv.content); - } - - #[test] - fn test_compute_th_2() { - let h_message_1_tv = BytesHashLen::from_hex(H_MESSAGE_1_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let th_2_tv = BytesHashLen::from_hex(TH_2_TV); - - let th_2 = compute_th_2(&g_y_tv, &h_message_1_tv); - assert_bytes_eq!(th_2, th_2_tv); - } - - #[test] - fn test_compute_th_3() { - let th_2_tv = BytesHashLen::from_hex(TH_2_TV); - let th_3_tv = BytesHashLen::from_hex(TH_3_TV); - let plaintext_2_tv = BufferPlaintext2::from_hex(PLAINTEXT_2_TV); - let cred_r_tv = - BytesMaxBuffer::from_slice(&ByteSeq::from_hex(CRED_R_TV), 0, CRED_R_TV.len() / 2); - - let th_3 = compute_th_3(&th_2_tv, &plaintext_2_tv, &cred_r_tv, CRED_R_TV.len() / 2); - assert_bytes_eq!(th_3, th_3_tv); - } - - #[test] - fn test_compute_th_4() { - let th_3_tv = BytesHashLen::from_hex(TH_3_TV); - let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - let th_4_tv = BytesHashLen::from_hex(TH_4_TV); - let cred_i_tv = - BytesMaxBuffer::from_slice(&ByteSeq::from_hex(CRED_I_TV), 0, CRED_I_TV.len() / 2); - - let th_4 = compute_th_4(&th_3_tv, &plaintext_3_tv, &cred_i_tv, CRED_I_TV.len() / 2); - assert_bytes_eq!(th_4, th_4_tv); - } - - #[test] - fn test_edhoc_kdf() { - let th_2_context_tv = - BytesMaxContextBuffer::from_slice(&ByteSeq::from_hex(TH_2_TV), 0, TH_2_TV.len() / 2); - let prk_2e_tv = BytesHashLen::from_hex(PRK_2E_TV); - let keystream_2_tv = BufferPlaintext2::from_hex(KEYSTREAM_2_TV); - const LEN_TV: usize = PLAINTEXT_2_LEN_TV; - - let output = edhoc_kdf( - &prk_2e_tv, - U8(0), - &th_2_context_tv, - SHA256_DIGEST_LEN, - LEN_TV, - ); - for i in 0..keystream_2_tv.len { - assert_eq!( - keystream_2_tv.content[i].declassify(), - output[i].declassify() - ); - } - - let prk_3e2m_tv = BytesHashLen::from_hex(PRK_3E2M_TV); - let context_info_mac_2 = BytesMaxContextBuffer::from_slice( - &ByteSeq::from_hex(CONTEXT_INFO_MAC_2_TV), - 0, - CONTEXT_INFO_MAC_2_TV.len() / 2, - ); - let mac_2_tv = BytesMac2::from_hex(MAC_2_TV); - - let output_2 = edhoc_kdf( - &prk_3e2m_tv, - U8(2), // length of "MAC_2" - &context_info_mac_2, - CONTEXT_INFO_MAC_2_TV.len() / 2, // divide by two to get num of bytes from hex string - MAC_LENGTH_2, - ); - - for i in 0..MAC_2_TV.len() / 2 { - assert_eq!(mac_2_tv[i].declassify(), output_2[i].declassify()); - } - } - - #[test] - fn test_encrypt_message_3() { - let prk_3e2m_tv = BytesHashLen::from_hex(PRK_3E2M_TV); - let th_3_tv = BytesHashLen::from_hex(TH_3_TV); - let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - let message_3_tv = BufferMessage3::from_hex(MESSAGE_3_TV); - - let message_3 = encrypt_message_3(&prk_3e2m_tv, &th_3_tv, &plaintext_3_tv); - assert_bytes_eq!(message_3.content, message_3_tv.content); - } - - #[test] - fn test_decrypt_message_3() { - let message_3_tv = BufferMessage3::from_hex(MESSAGE_3_TV); - let prk_3e2m_tv = BytesHashLen::from_hex(PRK_3E2M_TV); - let th_3_tv = BytesHashLen::from_hex(TH_3_TV); - let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - - let plaintext_3 = decrypt_message_3(&prk_3e2m_tv, &th_3_tv, &message_3_tv); - - assert!(plaintext_3.is_ok()); - assert_bytes_eq!(plaintext_3.unwrap().content, plaintext_3_tv.content); - } - - #[test] - fn test_compute_mac_3() { - let prk_4e3m_tv = BytesHashLen::from_hex(PRK_4E3M_TV); - let th_3_tv = BytesHashLen::from_hex(TH_3_TV); - let id_cred_i_tv = BytesIdCred::from_hex(ID_CRED_I_TV); - let cred_i_tv = - BytesMaxBuffer::from_slice(&ByteSeq::from_hex(CRED_I_TV), 0, CRED_I_TV.len() / 2); - let mac_3_tv = BytesMac3::from_hex(MAC_3_TV); - - let mac_3 = compute_mac_3( - &prk_4e3m_tv, - &th_3_tv, - &id_cred_i_tv, - &cred_i_tv, - CRED_I_TV.len() / 2, // divide by two to get num of bytes from hex string - ); - assert_bytes_eq!(mac_3, mac_3_tv); - } - - #[test] - fn test_compute_and_verify_mac_2() { - let prk_3e2m_tv = BytesHashLen::from_hex(PRK_3E2M_TV); - let id_cred_r_tv = BytesIdCred::from_hex(ID_CRED_R_TV); - let cred_r_tv = - BytesMaxBuffer::from_slice(&ByteSeq::from_hex(CRED_R_TV), 0, CRED_R_TV.len() / 2); - let th_2_tv = BytesHashLen::from_hex(TH_2_TV); - let mac_2_tv = BytesMac2::from_hex(MAC_2_TV); - - let rcvd_mac_2 = compute_mac_2( - &prk_3e2m_tv, - &id_cred_r_tv, - &cred_r_tv, - CRED_R_TV.len() / 2, - &th_2_tv, - ); - - assert_bytes_eq!(rcvd_mac_2, mac_2_tv); - } - - #[test] - fn test_encode_plaintext_2() { - let plaintext_2_tv = BufferPlaintext2::from_hex(PLAINTEXT_2_TV); - let c_r_tv = U8(C_R_TV); - let id_cred_r_tv = BytesIdCred::from_hex(ID_CRED_R_TV); - let mac_2_tv = BytesMac2::from_hex(MAC_2_TV); - - let plaintext_2 = - encode_plaintext_2(c_r_tv, &id_cred_r_tv, &mac_2_tv, &None::); - - assert_bytes_eq!(plaintext_2.content, plaintext_2_tv.content); - } - - #[test] - fn test_parse_plaintext_2_invalid_traces() { - let plaintext_2_tv_len = PLAINTEXT_2_SURPLUS_MAP_ID_CRED_TV.len() / 2; - let plaintext_2_tv = BytesMaxBuffer::from_slice( - &ByteSeq::from_hex(PLAINTEXT_2_SURPLUS_MAP_ID_CRED_TV), - 0, - plaintext_2_tv_len, - ); - let plaintext_2 = decode_plaintext_2(&plaintext_2_tv, plaintext_2_tv_len); - assert_eq!(plaintext_2.unwrap_err(), EDHOCError::ParsingError); - - let plaintext_2_tv_len = PLAINTEXT_2_SURPLUS_BSTR_ID_CRED_TV.len() / 2; - let plaintext_2_tv = BytesMaxBuffer::from_slice( - &ByteSeq::from_hex(PLAINTEXT_2_SURPLUS_BSTR_ID_CRED_TV), - 0, - plaintext_2_tv_len, - ); - let plaintext_2 = decode_plaintext_2(&plaintext_2_tv, plaintext_2_tv_len); - assert_eq!(plaintext_2.unwrap_err(), EDHOCError::ParsingError); - } - - #[test] - fn test_decode_plaintext_2() { - let plaintext_2_tv = BytesMaxBuffer::from_slice( - &ByteSeq::from_hex(PLAINTEXT_2_TV), - 0, - PLAINTEXT_2_TV.len() / 2, - ); - let c_r_tv = U8(C_R_TV); - let id_cred_r_tv = BytesIdCred::from_hex(ID_CRED_R_TV); - let mac_2_tv = BytesMac2::from_hex(MAC_2_TV); - - let plaintext_2 = decode_plaintext_2(&plaintext_2_tv, PLAINTEXT_2_LEN_TV); - assert!(plaintext_2.is_ok()); - let (c_r, id_cred_r, mac_2, ead_2) = plaintext_2.unwrap(); - assert_eq!(U8::declassify(c_r), U8::declassify(c_r_tv)); - assert_eq!(U8::declassify(id_cred_r), U8::declassify(id_cred_r_tv[3])); - assert_bytes_eq!(mac_2, mac_2_tv); - assert!(ead_2.is_none()); - } - - #[test] - fn test_encrypt_decrypt_ciphertext_2() { - let prk_2e_tv = BytesHashLen::from_hex(PRK_2E_TV); - let th_2_tv = BytesHashLen::from_hex(TH_2_TV); - let ciphertext_2_tv = BufferCiphertext2::from_hex(CIPHERTEXT_2_TV); - let plaintext_2_tv = BufferPlaintext2::from_hex(PLAINTEXT_2_TV); - - // test decryption - let (plaintext_2, plaintext_2_len) = - encrypt_decrypt_ciphertext_2(&prk_2e_tv, &th_2_tv, &ciphertext_2_tv); - - assert_eq!(plaintext_2_len, PLAINTEXT_2_LEN_TV); - for i in 0..PLAINTEXT_2_LEN_TV { - assert_eq!( - plaintext_2[i].declassify(), - plaintext_2_tv.content[i].declassify() - ); - } - - let plaintext_2_tmp = BufferCiphertext2::from_slice(&plaintext_2, 0, plaintext_2_len); - - // test encryption - let (ciphertext_2, ciphertext_2_len) = - encrypt_decrypt_ciphertext_2(&prk_2e_tv, &th_2_tv, &plaintext_2_tmp); - - assert_eq!(ciphertext_2_len, CIPHERTEXT_2_LEN_TV); - for i in 0..CIPHERTEXT_2_LEN_TV { - assert_eq!( - ciphertext_2[i].declassify(), - ciphertext_2_tv.content[i].declassify() - ); - } - } - - #[test] - fn test_compute_prk_4e3m() { - let salt_4e3m_tv = BytesHashLen::from_hex(SALT_4E3M_TV); - let i_tv = BytesP256ElemLen::from_hex(SK_I_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let prk_4e3m_tv = BytesHashLen::from_hex(PRK_4E3M_TV); - - let prk_4e3m = compute_prk_4e3m(&salt_4e3m_tv, &i_tv, &g_y_tv); - assert_bytes_eq!(prk_4e3m, prk_4e3m_tv); - } - - #[test] - fn test_compute_prk_3e2m() { - let salt_3e2m_tv = BytesHashLen::from_hex(SALT_3E2M_TV); - let x_tv = BytesP256ElemLen::from_hex(X_TV); - let g_r_tv = BytesP256ElemLen::from_hex(G_R_TV); - let prk_3e2m_tv = BytesHashLen::from_hex(PRK_3E2M_TV); - - let prk_3e2m = compute_prk_3e2m(&salt_3e2m_tv, &x_tv, &g_r_tv); - assert_bytes_eq!(prk_3e2m, prk_3e2m_tv); - } - - #[test] - fn test_compute_prk_2e() { - let x_tv = BytesP256ElemLen::from_hex(X_TV); - let g_y_tv = BytesP256ElemLen::from_hex(G_Y_TV); - let th_2_tv = BytesHashLen::from_hex(TH_2_TV); - let prk_2e_tv = BytesHashLen::from_hex(PRK_2E_TV); - - let prk_2e = compute_prk_2e(&x_tv, &g_y_tv, &th_2_tv); - assert_bytes_eq!(prk_2e, prk_2e_tv); - } - - #[test] - fn test_encode_plaintext_3() { - let id_cred_i_tv = BytesIdCred::from_hex(ID_CRED_I_TV); - let mac_3_tv = BytesMac3::from_hex(MAC_3_TV); - let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - - let plaintext_3 = encode_plaintext_3(&id_cred_i_tv, &mac_3_tv, &None::); - assert_bytes_eq!(plaintext_3.content, plaintext_3_tv.content); - } - - #[test] - fn test_decode_plaintext_3() { - let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - let mac_3_tv = BytesMac3::from_hex(MAC_3_TV); - let kid_tv = BytesIdCred::from_hex(ID_CRED_I_TV); - let kid_tv = kid_tv[kid_tv.len() - 1]; - - let (kid, mac_3, _ead_3) = decode_plaintext_3(&plaintext_3_tv).unwrap(); - - assert_bytes_eq!(mac_3, mac_3_tv); - assert_eq!(kid.declassify(), kid_tv.declassify()); - } - - #[test] - fn test_encode_ead_item() { - let ead_tv = EdhocMessageBufferHacspec::from_hex(EAD_DUMMY_CRITICAL_TV); - - let ead_item = EADItemHacspec { - label: U8(EAD_DUMMY_LABEL_TV), - is_critical: true, - value: Some(EdhocMessageBufferHacspec::from_hex(EAD_DUMMY_VALUE_TV)), - }; - - let ead_buffer = encode_ead_item(&ead_item); - assert_bytes_eq!(ead_buffer.content, ead_tv.content); - } - - #[test] - fn test_encode_message_with_ead_item() { - let method_tv = U8(METHOD_TV); - let suites_i_tv = BytesSuites::from_hex(SUITES_I_TV); - let suites_i_tv_len: usize = 2; - let g_x_tv = BytesP256ElemLen::from_hex(G_X_TV); - let c_i_tv = U8(C_I_TV); - let message_1_ead_tv = BufferMessage1::from_hex(MESSAGE_1_WITH_DUMMY_CRITICAL_EAD_TV); - let ead_item = EADItemHacspec { - label: U8(EAD_DUMMY_LABEL_TV), - is_critical: true, - value: Some(EdhocMessageBufferHacspec::from_hex(EAD_DUMMY_VALUE_TV)), - }; - - let message_1 = encode_message_1( - method_tv, - &suites_i_tv, - suites_i_tv_len, - &g_x_tv, - c_i_tv, - &Some(ead_item), - ); - - assert_bytes_eq!(message_1.content, message_1_ead_tv.content); - } - - #[test] - fn test_parse_ead_item() { - let message_tv_offset = MESSAGE_1_TV.len() / 2; - let message_ead_tv = BufferMessage1::from_hex(MESSAGE_1_WITH_DUMMY_EAD_TV); - let ead_value_tv = EdhocMessageBufferHacspec::from_hex(EAD_DUMMY_VALUE_TV); - - let res = parse_ead(&message_ead_tv, message_tv_offset); - assert!(res.is_ok()); - let ead_item = res.unwrap(); - assert!(ead_item.is_some()); - let ead_item = ead_item.unwrap(); - assert!(!ead_item.is_critical); - assert_eq!(ead_item.label.declassify(), EAD_DUMMY_LABEL_TV); - assert_bytes_eq!(ead_item.value.unwrap().content, ead_value_tv.content); - - let message_ead_tv = BufferMessage1::from_hex(MESSAGE_1_WITH_DUMMY_CRITICAL_EAD_TV); - - let res = parse_ead(&message_ead_tv, message_tv_offset).unwrap(); - let ead_item = res.unwrap(); - assert!(ead_item.is_critical); - assert_eq!(ead_item.label.declassify(), EAD_DUMMY_LABEL_TV); - assert_bytes_eq!(ead_item.value.unwrap().content, ead_value_tv.content); - - let message_ead_tv = BufferMessage1::from_hex(MESSAGE_1_WITH_DUMMY_EAD_NO_VALUE_TV); - - let res = parse_ead(&message_ead_tv, message_tv_offset).unwrap(); - let ead_item = res.unwrap(); - assert!(!ead_item.is_critical); - assert_eq!(ead_item.label.declassify(), EAD_DUMMY_LABEL_TV); - assert!(ead_item.value.is_none()); - } - - #[test] - fn test_parse_message_with_ead_item() { - let message_1_ead_tv = BufferMessage1::from_hex(MESSAGE_1_WITH_DUMMY_CRITICAL_EAD_TV); - let ead_value_tv = EdhocMessageBufferHacspec::from_hex(EAD_DUMMY_VALUE_TV); - - let res = parse_message_1(&message_1_ead_tv); - assert!(res.is_ok()); - let (_method, _suites_i, _suites_i_len, _g_x, _c_i, ead_1) = res.unwrap(); - let ead_1 = ead_1.unwrap(); - assert!(ead_1.is_critical); - assert_eq!(ead_1.label.declassify(), EAD_DUMMY_LABEL_TV); - assert_bytes_eq!(ead_1.value.unwrap().content, ead_value_tv.content); - } - - #[test] - fn test_compute_prk_out() { - let prk_4e3m_tv = BytesHashLen::from_hex(PRK_4E3M_TV); - let th_4_tv = BytesHashLen::from_hex(TH_4_TV); - let prk_out_tv = BytesHashLen::from_hex(PRK_OUT_TV); - - let mut prk_out = BytesHashLen::new(); - - let prk_out_buf = edhoc_kdf( - &prk_4e3m_tv, - U8(7 as u8), - &BytesMaxContextBuffer::from_slice(&th_4_tv, 0, th_4_tv.len()), - th_4_tv.len(), - SHA256_DIGEST_LEN, - ); - prk_out = prk_out.update_slice(0, &prk_out_buf, 0, SHA256_DIGEST_LEN); - - assert_bytes_eq!(prk_out, prk_out_tv); - } - - #[test] - fn test_compute_prk_exporter() { - let prk_out_tv = BytesHashLen::from_hex(PRK_OUT_TV); - let prk_exporter_tv = BytesHashLen::from_hex(PRK_EXPORTER_TV); - - let mut prk_exporter = BytesHashLen::new(); - let prk_exporter_buf = edhoc_kdf( - &prk_out_tv, - U8(10 as u8), - &BytesMaxContextBuffer::new(), - 0, - SHA256_DIGEST_LEN, - ); - prk_exporter = prk_exporter.update_slice(0, &prk_exporter_buf, 0, SHA256_DIGEST_LEN); - - assert_bytes_eq!(prk_exporter, prk_exporter_tv); - } - - #[test] - fn test_compute_oscore_master_secret_salt() { - let prk_exporter_tv = BytesHashLen::from_hex(PRK_EXPORTER_TV); - let mut oscore_master_secret_tv_buf = BytesMaxBuffer::new(); - let oscore_master_secret_tv = BytesCcmKeyLen::from_hex(OSCORE_MASTER_SECRET_TV); - oscore_master_secret_tv_buf = oscore_master_secret_tv_buf.update_slice( - 0, - &oscore_master_secret_tv, - 0, - oscore_master_secret_tv.len(), - ); - - let mut oscore_master_salt_tv_buf = BytesMaxBuffer::new(); - let oscore_master_salt_tv = Bytes8::from_hex(OSCORE_MASTER_SALT_TV); - let oscore_master_salt_tv_buf = oscore_master_salt_tv_buf.update_slice( - 0, - &oscore_master_salt_tv, - 0, - oscore_master_salt_tv.len(), - ); - - let oscore_master_secret_buf = edhoc_kdf( - &prk_exporter_tv, - U8(0 as u8), - &BytesMaxContextBuffer::new(), - 0, - oscore_master_secret_tv.len(), - ); - assert_bytes_eq!(oscore_master_secret_buf, oscore_master_secret_tv_buf); - - let oscore_master_salt_buf = edhoc_kdf( - &prk_exporter_tv, - U8(1 as u8), - &BytesMaxContextBuffer::new(), - 0, - oscore_master_salt_tv.len(), - ); - - assert_bytes_eq!(oscore_master_salt_buf, oscore_master_salt_tv_buf); - } -} diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 9de74e59..15503fa1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -10,7 +10,6 @@ description = "EDHOC implementation in Rust" hexlit = "0.5.3" hex = { version = "0.4.3", default-features = false } -edhoc-hacspec = { path = "../hacspec", optional = true } hacspec-lib = { version = "0.1.0-beta.1", default-features = false, optional = true } edhoc-crypto = { path = "../crypto", default-features = false } edhoc-consts = { path = "../consts", default-features = false } @@ -22,11 +21,6 @@ cbindgen = "0.24.5" [features] default = [ "edhoc-ead/ead-none" ] -hacspec-hacspec = ["hacspec-lib/std", "edhoc-hacspec", "edhoc-crypto/hacspec", "edhoc-consts/hacspec" ] -hacspec-cc2538 = ["hacspec-lib/alloc", "edhoc-hacspec", "edhoc-crypto/cc2538", "edhoc-consts/hacspec" ] # FIXME: stubs -hacspec-psa = ["hacspec-lib/alloc", "edhoc-hacspec", "edhoc-crypto/psa", "edhoc-consts/hacspec" ] -hacspec-psa-baremetal = ["hacspec-psa", "edhoc-crypto/psa-baremetal", "edhoc-consts/hacspec" ] -hacspec-cryptocell310 = ["hacspec-lib/alloc", "edhoc-hacspec", "edhoc-crypto/cryptocell310", "edhoc-consts/hacspec" ] rust-psa = [ "edhoc-consts/rust", "edhoc-crypto/psa-rust" ] rust-psa-baremetal = [ "edhoc-crypto/psa-rust-baremetal", "edhoc-consts/rust", "panic-semihosting" ] rust-cryptocell310 = [ "edhoc-consts/rust", "edhoc-crypto/cryptocell310-rust", "panic-semihosting" ] diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 95f1b5f8..6284ccfc 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,17 +1,5 @@ #![cfg_attr(not(test), no_std)] -#[cfg(any( - feature = "hacspec-hacspec", - feature = "hacspec-cc2538", - feature = "hacspec-psa", - feature = "hacspec-cryptocell310" -))] -pub use { - edhoc_consts::State as EdhocState, edhoc_consts::*, edhoc_crypto::*, - hacspec::generate_connection_identifier, hacspec::HacspecEdhocInitiator as EdhocInitiator, - hacspec::HacspecEdhocResponder as EdhocResponder, -}; - #[cfg(any( feature = "rust-psa", feature = "rust-psa-baremetal", @@ -54,339 +42,6 @@ mod c_wrapper; ))] use c_wrapper::*; -#[cfg(any( - feature = "hacspec-hacspec", - feature = "hacspec-cc2538", - feature = "hacspec-psa", - feature = "hacspec-cryptocell310" -))] -mod hacspec { - use edhoc_consts::*; - use edhoc_hacspec::*; - use hacspec_lib::*; - - #[repr(C)] - #[derive(Default, Copy, Clone, Debug)] - pub struct HacspecEdhocInitiator<'a> { - state: State, // opaque state - i: &'a str, // private authentication key of I - g_r: &'a str, // public authentication key of R - id_cred_i: &'a str, // identifier of I's credential - cred_i: &'a str, // I's full credential - id_cred_r: &'a str, // identifier of R's credential - cred_r: &'a str, // R's full credential - } - - #[repr(C)] - #[derive(Default, Copy, Clone, Debug)] - pub struct HacspecEdhocResponder<'a> { - state: State, // opaque state - r: &'a str, // private authentication key of R - g_i: &'a str, // public authentication key of I - id_cred_i: &'a str, // identifier of I's credential - cred_i: &'a str, // I's full credential - id_cred_r: &'a str, // identifier of R's credential - cred_r: &'a str, // R's full credential - } - - impl<'a> HacspecEdhocResponder<'a> { - pub fn new( - state: State, - r: &'a str, - g_i: &'a str, - id_cred_i: &'a str, - cred_i: &'a str, - id_cred_r: &'a str, - cred_r: &'a str, - ) -> HacspecEdhocResponder<'a> { - assert!(r.len() == P256_ELEM_LEN * 2); - assert!(g_i.len() == P256_ELEM_LEN * 2); - assert!(id_cred_i.len() == ID_CRED_LEN * 2); - assert!(id_cred_r.len() == ID_CRED_LEN * 2); - - HacspecEdhocResponder { - state: state, - r: r, - g_i: g_i, - id_cred_i: id_cred_i, - cred_i: cred_i, - id_cred_r: id_cred_r, - cred_r: cred_r, - } - } - - pub fn process_message_1( - self: &mut HacspecEdhocResponder<'a>, - message_1: &EdhocMessageBuffer, - ) -> Result<(), EDHOCError> { - match r_process_message_1(self.state, &BufferMessage1::from_public_buffer(message_1)) { - Ok(state) => { - self.state = state; - Ok(()) - } - Err(error) => Err(error), - } - } - - pub fn prepare_message_2( - self: &mut HacspecEdhocResponder<'a>, - ) -> Result<(EdhocMessageBuffer, u8), EDHOCError> { - // init hacspec structs for id_cred_r and cred_r - let id_cred_r = BytesIdCred::from_hex(self.id_cred_r); - let mut cred_r = BytesMaxBuffer::new(); - cred_r = cred_r.update(0, &ByteSeq::from_hex(self.cred_r)); - let cred_r_len = self.cred_r.len() / 2; - - // init hacspec structs for R's public static DH key - let r = BytesP256ElemLen::from_hex(self.r); - - // Generate ephemeral key pair - let (y, g_y) = edhoc_crypto::p256_generate_key_pair(); - let c_r = generate_connection_identifier_cbor(); - - match r_prepare_message_2(self.state, &id_cred_r, &cred_r, cred_r_len, &r, y, g_y, c_r) - { - Ok((state, message_2, c_r)) => { - self.state = state; - Ok((message_2.to_public_buffer(), c_r.declassify())) - } - Err(error) => Err(error), - } - } - - pub fn process_message_3( - self: &mut HacspecEdhocResponder<'a>, - message_3: &EdhocMessageBuffer, - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - // init hacspec structs for id_cred_r and cred_r - let id_cred_i = BytesIdCred::from_hex(self.id_cred_i); - let mut cred_i = BytesMaxBuffer::new(); - cred_i = cred_i.update(0, &ByteSeq::from_hex(self.cred_i)); - let cred_i_len = self.cred_i.len() / 2; - - // init hacspec structs for R's public static DH key - let g_i = BytesP256ElemLen::from_hex(self.g_i); - - match r_process_message_3( - self.state, - &BufferMessage3::from_public_buffer(&message_3), - &id_cred_i, - &cred_i, - cred_i_len, - &g_i, - ) { - Ok((state, prk_out)) => { - self.state = state; - Ok(prk_out.to_public_array()) - } - Err(error) => Err(error), - } - } - - pub fn edhoc_exporter( - self: &mut HacspecEdhocResponder<'a>, - label: u8, - context: &[u8], - length: usize, - ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { - // init hacspec struct for context - let mut context_hacspec = BytesMaxContextBuffer::new(); - context_hacspec = context_hacspec.update(0, &ByteSeq::from_public_slice(context)); - - match edhoc_exporter( - self.state, - U8(label), - &context_hacspec, - context.len(), - length, - ) { - Ok((state, output)) => { - self.state = state; - Ok(output.to_public_array()) - } - Err(error) => Err(error), - } - } - - pub fn edhoc_key_update( - self: &mut HacspecEdhocResponder<'a>, - context: &[u8], - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - // init hacspec struct for context - let mut context_hacspec = BytesMaxContextBuffer::new(); - context_hacspec = context_hacspec.update(0, &ByteSeq::from_public_slice(context)); - - match edhoc_key_update(self.state, &context_hacspec, context.len()) { - Ok((state, prk_out_new)) => { - self.state = state; - Ok(prk_out_new.to_public_array()) - } - Err(error) => Err(error), - } - } - } - - impl<'a> HacspecEdhocInitiator<'a> { - pub fn new( - state: State, - i: &'a str, - g_r: &'a str, - id_cred_i: &'a str, - cred_i: &'a str, - id_cred_r: &'a str, - cred_r: &'a str, - ) -> HacspecEdhocInitiator<'a> { - assert!(i.len() == P256_ELEM_LEN * 2); - assert!(g_r.len() == P256_ELEM_LEN * 2); - assert!(id_cred_i.len() == ID_CRED_LEN * 2); - assert!(id_cred_r.len() == ID_CRED_LEN * 2); - - HacspecEdhocInitiator { - state: state, - i: i, - g_r: g_r, - id_cred_i: id_cred_i, - cred_i: cred_i, - id_cred_r: id_cred_r, - cred_r: cred_r, - } - } - - pub fn prepare_message_1( - self: &mut HacspecEdhocInitiator<'a>, - ) -> Result { - // Generate ephemeral key pair - let (x, g_x) = edhoc_crypto::p256_generate_key_pair(); - let c_i = generate_connection_identifier_cbor(); - - match edhoc_hacspec::i_prepare_message_1(self.state, x, g_x, c_i) { - Ok((state, message_1)) => { - self.state = state; - Ok(message_1.to_public_buffer()) - } - Err(error) => Err(error), - } - } - - pub fn process_message_2( - self: &mut HacspecEdhocInitiator<'a>, - message_2: &EdhocMessageBuffer, - ) -> Result { - // init hacspec struct for I, I's private static DH key - let i = BytesP256ElemLen::from_hex(self.i); - - // init hacspec structs for id_cred_r and cred_r - let id_cred_r = BytesIdCred::from_hex(self.id_cred_r); - let mut cred_r = BytesMaxBuffer::new(); - cred_r = cred_r.update(0, &ByteSeq::from_hex(self.cred_r)); - let cred_r_len = self.cred_r.len() / 2; - - // init hacspec structs for R's public static DH key - let g_r = BytesP256ElemLen::from_hex(self.g_r); - - // init hacspec struct for message_2 - let message_2_hacspec = BufferMessage2::from_public_buffer(&message_2); - - match edhoc_hacspec::i_process_message_2( - self.state, - &message_2_hacspec, - &id_cred_r, - &cred_r, - cred_r_len, - &g_r, - &i, - ) { - Ok((state, c_r, _id_cred_r)) => { - self.state = state; - Ok(c_r.declassify()) - } - Err(error) => Err(error), - } - } - - pub fn prepare_message_3( - self: &mut HacspecEdhocInitiator<'a>, - ) -> Result<(EdhocMessageBuffer, [u8; SHA256_DIGEST_LEN]), EDHOCError> { - // init hacspec structs for id_cred_i and cred_i - let id_cred_i = BytesIdCred::from_hex(self.id_cred_i); - let mut cred_i = BytesMaxBuffer::new(); - cred_i = cred_i.update(0, &ByteSeq::from_hex(self.cred_i)); - let cred_i_len = self.cred_i.len() / 2; - - match i_prepare_message_3(self.state, &id_cred_i, &cred_i, cred_i_len) { - Ok((state, message_3, prk_out)) => { - self.state = state; - Ok((message_3.to_public_buffer(), prk_out.to_public_array())) - } - Err(error) => Err(error), - } - } - - pub fn edhoc_exporter( - self: &mut HacspecEdhocInitiator<'a>, - label: u8, - context: &[u8], - length: usize, - ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { - // init hacspec struct for context - let mut context_hacspec = BytesMaxContextBuffer::new(); - context_hacspec = context_hacspec.update(0, &ByteSeq::from_public_slice(context)); - - match edhoc_exporter( - self.state, - U8(label), - &context_hacspec, - context.len(), - length, - ) { - Ok((state, output)) => { - self.state = state; - Ok(output.to_public_array()) - } - Err(error) => Err(error), - } - } - - pub fn edhoc_key_update( - self: &mut HacspecEdhocInitiator<'a>, - context: &[u8], - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - // init hacspec struct for context - let mut context_hacspec = BytesMaxContextBuffer::new(); - context_hacspec = context_hacspec.update(0, &ByteSeq::from_public_slice(context)); - - match edhoc_key_update(self.state, &context_hacspec, context.len()) { - Ok((state, prk_out_new)) => { - self.state = state; - Ok(prk_out_new.to_public_array()) - } - Err(error) => Err(error), - } - } - } - - pub fn generate_connection_identifier_cbor() -> U8 { - let c_i = generate_connection_identifier(); - if c_i >= 0 && c_i <= 23 { - return U8(c_i as u8); // verbatim encoding of single byte integer - } else if c_i < 0 && c_i >= -24 { - // negative single byte integer encoding - return U8(CBOR_NEG_INT_1BYTE_START - 1 + (c_i.abs() as u8)); - } else { - return U8(0); - } - } - - /// generates an identifier that can be serialized as a single CBOR integer, i.e. -24 <= x <= 23 - pub fn generate_connection_identifier() -> i8 { - let mut conn_id = edhoc_crypto::get_random_byte().declassify() as i8; - while conn_id < -24 || conn_id > 23 { - conn_id = edhoc_crypto::get_random_byte().declassify() as i8; - } - conn_id - } -} - #[cfg(any( feature = "rust-psa", feature = "rust-psa-baremetal", From dcb71b9ea2792afc35b11431397cd104853ea257 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Mon, 2 Oct 2023 15:42:48 +0200 Subject: [PATCH 02/16] refactor: remove hacspec consts and CI libs --- .github/workflows/build-and-test.yml | 8 +- consts/src/lib.rs | 166 --------------------------- 2 files changed, 4 insertions(+), 170 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 47f8f9ec..6e3e811d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [hacspec, rust] + edhoc_lib: [rust] crypto: [hacspec, psa] ead: [ead-none, ead-zeroconf] exclude: @@ -49,7 +49,7 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [hacspec, rust] + edhoc_lib: [rust] crypto: [hacspec, psa, psa-baremetal, cryptocell310] ead: [ead-none, ead-zeroconf] exclude: @@ -137,7 +137,7 @@ jobs: strategy: fail-fast: false matrix: - config: [hacspec-psa, rust-psa] + config: [rust-psa] ead: [ead-none, ead-zeroconf] steps: @@ -162,7 +162,7 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [hacspec, rust] + edhoc_lib: [rust] crypto: [psa, cryptocell310] ead: [ead-none, ead-zeroconf] diff --git a/consts/src/lib.rs b/consts/src/lib.rs index fb48fc74..844c8e7b 100644 --- a/consts/src/lib.rs +++ b/consts/src/lib.rs @@ -195,169 +195,3 @@ mod rust { pub BytesHashLen, // th_3 ); } - -#[cfg(feature = "hacspec")] -mod hacspec { - use super::common::*; - use hacspec_lib::*; - - array!(BytesMessageBuffer, MAX_MESSAGE_SIZE_LEN, U8); - - #[derive(Debug)] - pub struct EdhocMessageBufferHacspec { - pub content: BytesMessageBuffer, - pub len: usize, - } - - pub trait MessageBufferHacspecTrait { - fn new() -> Self; - fn from_hex(hex: &str) -> Self; - fn from_public_buffer(buffer: &EdhocMessageBuffer) -> Self; - fn from_slice(slice: &A, start: usize, len: usize) -> Self - where - A: SeqTrait; - fn from_seq(buffer: &Seq) -> Self; - fn to_public_buffer(&self) -> EdhocMessageBuffer; - } - - impl MessageBufferHacspecTrait for EdhocMessageBufferHacspec { - fn new() -> Self { - EdhocMessageBufferHacspec { - content: BytesMessageBuffer::new(), - len: 0, - } - } - fn from_hex(hex: &str) -> Self { - let mut buffer = EdhocMessageBufferHacspec::new(); - buffer.len = hex.len() / 2; - for (i, chunk) in hex.as_bytes().chunks(2).enumerate() { - let chunk_str = core::str::from_utf8(chunk).unwrap(); - buffer.content[i] = U8(u8::from_str_radix(chunk_str, 16).unwrap()); - } - buffer - } - fn from_public_buffer(buffer: &EdhocMessageBuffer) -> Self { - let mut hacspec_buffer = EdhocMessageBufferHacspec::new(); - hacspec_buffer.len = buffer.len; - hacspec_buffer.content = BytesMessageBuffer::from_public_slice(&buffer.content[..]); - hacspec_buffer - } - fn from_slice(slice: &A, start: usize, len: usize) -> Self - where - A: SeqTrait, - { - let mut hacspec_buffer = EdhocMessageBufferHacspec::new(); - hacspec_buffer.len = len; - hacspec_buffer.content = BytesMessageBuffer::from_slice(slice, start, len); - hacspec_buffer - } - fn from_seq(buffer: &Seq) -> Self { - EdhocMessageBufferHacspec { - content: BytesMessageBuffer::from_slice(buffer, 0, buffer.len()), - len: buffer.len(), - } - } - fn to_public_buffer(&self) -> EdhocMessageBuffer { - let mut buffer = EdhocMessageBuffer::new(); - buffer.content = self.content.to_public_array(); - buffer.len = self.len; - buffer - } - } - - #[derive(Debug)] - pub struct EADItemHacspec { - pub label: U8, - pub is_critical: bool, - // TODO[ead]: have adjustable (smaller) length for this buffer - pub value: Option, - } - - pub trait EADItemHacspecTrait { - fn new() -> Self; - fn from_public_item(item: &EADItem) -> Self; - fn to_public_item(&self) -> EADItem; - } - - impl EADItemHacspecTrait for EADItemHacspec { - fn new() -> Self { - EADItemHacspec { - label: U8(0), - is_critical: false, - value: None, - } - } - fn from_public_item(item: &EADItem) -> Self { - EADItemHacspec { - label: U8(item.label), - is_critical: item.is_critical, - value: match &item.value { - Some(value) => Some(EdhocMessageBufferHacspec::from_public_buffer(value)), - None => None, - }, - } - } - fn to_public_item(&self) -> EADItem { - EADItem { - label: self.label.declassify(), - is_critical: self.is_critical, - value: match &self.value { - Some(value) => Some(value.to_public_buffer()), - None => None, - }, - } - } - } - - array!(BytesIdCred, ID_CRED_LEN, U8); - array!(BytesSuites, SUITES_LEN, U8); - array!(BytesSupportedSuites, SUPPORTED_SUITES_LEN, U8); - array!(Bytes8, 8, U8); - array!(BytesCcmKeyLen, AES_CCM_KEY_LEN, U8); - array!(BytesCcmIvLen, AES_CCM_IV_LEN, U8); - pub type BufferPlaintext2 = EdhocMessageBufferHacspec; - pub type BufferPlaintext3 = EdhocMessageBufferHacspec; - array!(BytesMac2, MAC_LENGTH_2, U8); - array!(BytesMac3, MAC_LENGTH_3, U8); - pub type BufferMessage1 = EdhocMessageBufferHacspec; - pub type BufferMessage3 = EdhocMessageBufferHacspec; - pub type BufferCiphertext2 = EdhocMessageBufferHacspec; - pub type BufferCiphertext3 = EdhocMessageBufferHacspec; - array!(BytesHashLen, SHA256_DIGEST_LEN, U8); - array!(BytesP256ElemLen, P256_ELEM_LEN, U8); - pub type BufferMessage2 = EdhocMessageBufferHacspec; - array!(BytesMaxBuffer, MAX_BUFFER_LEN, U8); - array!(BytesMaxContextBuffer, MAX_KDF_CONTEXT_LEN, U8); - array!(BytesMaxInfoBuffer, MAX_INFO_LEN, U8); - array!(BytesMaxLabelBuffer, MAX_KDF_LABEL_LEN, U8); - array!(BytesEncStructureLen, ENC_STRUCTURE_LEN, U8); - - // Currently only suite number 2 is supported, - // which corresponds to the array 10, -16, 8, 1, -7, 10, -16, - // which in turn corresponds to the following: - // - AES-CCM-16-64-128 | EDHOC AEAD algorithm - // - SHA-256 | EDHOC hash algorithm - // - 8 | MAC length in bytes - // - P-256 | key exchange algorithm - // - ES256 | signature algorithm - // - AES-CCM-16-64-128 | Application AEAD algorithm - // - SHA-256 | Application hash algorithm - pub const EDHOC_SUPPORTED_SUITES: BytesSupportedSuites = - BytesSupportedSuites(secret_bytes!([0x2u8])); - pub const EDHOC_SUITES: BytesSuites = BytesSuites(secret_bytes!([0, 1, 2, 3, 4, 5, 6, 24, 25])); // all but private cipher suites - - #[repr(C)] - #[derive(Default, Copy, Clone, Debug)] - pub struct State( - pub EDHOCState, - pub BytesP256ElemLen, // x or y, ephemeral private key of myself - pub U8, // c_i, connection identifier chosen by the initiator - pub BytesP256ElemLen, // g_y or g_x, ephemeral public key of the peer - pub BytesHashLen, // prk_3e2m - pub BytesHashLen, // prk_4e3m - pub BytesHashLen, // prk_out - pub BytesHashLen, // prk_exporter - pub BytesHashLen, // h_message_1 - pub BytesHashLen, // th_3 - ); -} From 780c01a89045a0a26e3cf89be42f21a07ab6e2d1 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Mon, 2 Oct 2023 16:54:07 +0200 Subject: [PATCH 03/16] refactor: adjust namespaces after removing hacspec --- .github/workflows/build-and-test.yml | 1 + consts/src/lib.rs | 181 ++++---- lib/src/c_wrapper.rs | 14 +- lib/src/lib.rs | 598 +++++++++++++-------------- 4 files changed, 377 insertions(+), 417 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6e3e811d..88c60d0c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -70,6 +70,7 @@ jobs: hacspec-to-fstar: + # TODO: rename to `generate-fstar` and adjust to use the main library needs: unit-tests runs-on: ubuntu-latest steps: diff --git a/consts/src/lib.rs b/consts/src/lib.rs index 844c8e7b..3d13112d 100644 --- a/consts/src/lib.rs +++ b/consts/src/lib.rs @@ -1,14 +1,81 @@ #![no_std] -pub use common::*; +pub use consts::*; +pub use structs::*; -#[cfg(feature = "hacspec")] -pub use hacspec::*; +mod consts { + use super::structs::*; -#[cfg(feature = "rust")] -pub use rust::*; + pub const MAX_MESSAGE_SIZE_LEN: usize = 64; + pub const MAX_EAD_SIZE_LEN: usize = 64; + pub type EADMessageBuffer = EdhocMessageBuffer; // TODO: make it of size MAX_EAD_SIZE_LEN + pub const EAD_ZEROCONF_LABEL: u8 = 0x1; // NOTE: in lake-authz-draft-02 it is still TBD1 + + pub const ID_CRED_LEN: usize = 4; + pub const SUITES_LEN: usize = 9; + pub const SUPPORTED_SUITES_LEN: usize = 1; + pub const EDHOC_METHOD: u8 = 3u8; // stat-stat is the only supported method + pub const P256_ELEM_LEN: usize = 32; + pub const SHA256_DIGEST_LEN: usize = 32; + pub const AES_CCM_KEY_LEN: usize = 16; + pub const AES_CCM_IV_LEN: usize = 13; + pub const AES_CCM_TAG_LEN: usize = 8; + pub const MAC_LENGTH_2: usize = 8; + pub const MAC_LENGTH_3: usize = MAC_LENGTH_2; + + // maximum supported length of connection identifier for R + pub const MAX_KDF_CONTEXT_LEN: usize = 150; + pub const MAX_KDF_LABEL_LEN: usize = 15; // for "KEYSTREAM_2" + pub const MAX_BUFFER_LEN: usize = 220; + pub const CBOR_BYTE_STRING: u8 = 0x58u8; + pub const CBOR_UINT_1BYTE: u8 = 0x18u8; + pub const CBOR_NEG_INT_1BYTE_START: u8 = 0x20u8; + pub const CBOR_NEG_INT_1BYTE_END: u8 = 0x37u8; + pub const CBOR_UINT_1BYTE_START: u8 = 0x0u8; + pub const CBOR_UINT_1BYTE_END: u8 = 0x17u8; + pub const CBOR_MAJOR_TEXT_STRING: u8 = 0x60u8; + pub const CBOR_MAJOR_BYTE_STRING: u8 = 0x40u8; + pub const CBOR_MAJOR_BYTE_STRING_MAX: u8 = 0x57u8; + pub const CBOR_MAJOR_ARRAY: u8 = 0x80u8; + pub const CBOR_MAJOR_ARRAY_MAX: u8 = 0x97u8; + pub const MAX_INFO_LEN: usize = 2 + SHA256_DIGEST_LEN + // 32-byte digest as bstr + 1 + MAX_KDF_LABEL_LEN + // label <24 bytes as tstr + 1 + MAX_KDF_CONTEXT_LEN + // context <24 bytes as bstr + 1; // length as u8 + + pub const ENC_STRUCTURE_LEN: usize = 8 + 5 + SHA256_DIGEST_LEN; // 8 for ENCRYPT0 + + pub const EDHOC_SUITES: BytesSuites = [0, 1, 2, 3, 4, 5, 6, 24, 25]; // all but private cipher suites + pub const EDHOC_SUPPORTED_SUITES: BytesSupportedSuites = [0x2u8]; +} -mod common { +mod structs { + use super::consts::*; + + pub type U8 = u8; // TODO: remove + pub type BytesEad2 = [u8; 0]; + pub type BytesIdCred = [u8; ID_CRED_LEN]; + pub type BytesSuites = [u8; SUITES_LEN]; + pub type BytesSupportedSuites = [u8; SUPPORTED_SUITES_LEN]; + pub type Bytes8 = [u8; 8]; + 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 BytesMac2 = [u8; MAC_LENGTH_2]; + pub type BytesMac3 = [u8; MAC_LENGTH_3]; + pub type BufferMessage1 = EdhocMessageBuffer; + pub type BufferMessage3 = EdhocMessageBuffer; + pub type BufferCiphertext2 = EdhocMessageBuffer; + pub type BufferCiphertext3 = EdhocMessageBuffer; + pub type BytesHashLen = [u8; SHA256_DIGEST_LEN]; + pub type BytesP256ElemLen = [u8; P256_ELEM_LEN]; + pub type BufferMessage2 = EdhocMessageBuffer; + pub type BytesMaxBuffer = [u8; MAX_BUFFER_LEN]; + pub type BytesMaxContextBuffer = [u8; MAX_KDF_CONTEXT_LEN]; + pub type BytesMaxInfoBuffer = [u8; MAX_INFO_LEN]; + pub type BytesMaxLabelBuffeer = [u8; MAX_KDF_LABEL_LEN]; + pub type BytesEncStructureLen = [u8; ENC_STRUCTURE_LEN]; #[repr(C)] #[derive(Default, PartialEq, Copy, Clone, Debug)] @@ -36,6 +103,21 @@ mod common { UnknownError = 8, } + #[repr(C)] + #[derive(Default, Copy, Clone, Debug)] + pub struct State( + pub EDHOCState, + pub BytesP256ElemLen, // x or y, ephemeral private key of myself + pub u8, // c_i, connection identifier chosen by the initiator + pub BytesP256ElemLen, // g_y or g_x, ephemeral public key of the peer + pub BytesHashLen, // prk_3e2m + pub BytesHashLen, // prk_4e3m + pub BytesHashLen, // prk_out + pub BytesHashLen, // prk_exporter + pub BytesHashLen, // h_message_1 + pub BytesHashLen, // th_3 + ); + #[repr(C)] #[derive(PartialEq, Debug)] pub struct EdhocMessageBuffer { @@ -107,91 +189,4 @@ mod common { } } } - - pub const MAX_MESSAGE_SIZE_LEN: usize = 64; - pub const MAX_EAD_SIZE_LEN: usize = 64; - pub type EADMessageBuffer = EdhocMessageBuffer; // TODO: make it of size MAX_EAD_SIZE_LEN - pub const EAD_ZEROCONF_LABEL: u8 = 0x1; // NOTE: in lake-authz-draft-02 it is still TBD1 - - pub const ID_CRED_LEN: usize = 4; - pub const SUITES_LEN: usize = 9; - pub const SUPPORTED_SUITES_LEN: usize = 1; - pub const EDHOC_METHOD: u8 = 3u8; // stat-stat is the only supported method - pub const P256_ELEM_LEN: usize = 32; - pub const SHA256_DIGEST_LEN: usize = 32; - pub const AES_CCM_KEY_LEN: usize = 16; - pub const AES_CCM_IV_LEN: usize = 13; - pub const AES_CCM_TAG_LEN: usize = 8; - pub const MAC_LENGTH_2: usize = 8; - pub const MAC_LENGTH_3: usize = MAC_LENGTH_2; - - // maximum supported length of connection identifier for R - pub const MAX_KDF_CONTEXT_LEN: usize = 150; - pub const MAX_KDF_LABEL_LEN: usize = 15; // for "KEYSTREAM_2" - pub const MAX_BUFFER_LEN: usize = 220; - pub const CBOR_BYTE_STRING: u8 = 0x58u8; - pub const CBOR_UINT_1BYTE: u8 = 0x18u8; - pub const CBOR_NEG_INT_1BYTE_START: u8 = 0x20u8; - pub const CBOR_NEG_INT_1BYTE_END: u8 = 0x37u8; - pub const CBOR_UINT_1BYTE_START: u8 = 0x0u8; - pub const CBOR_UINT_1BYTE_END: u8 = 0x17u8; - pub const CBOR_MAJOR_TEXT_STRING: u8 = 0x60u8; - pub const CBOR_MAJOR_BYTE_STRING: u8 = 0x40u8; - pub const CBOR_MAJOR_BYTE_STRING_MAX: u8 = 0x57u8; - pub const CBOR_MAJOR_ARRAY: u8 = 0x80u8; - pub const CBOR_MAJOR_ARRAY_MAX: u8 = 0x97u8; - pub const MAX_INFO_LEN: usize = 2 + SHA256_DIGEST_LEN + // 32-byte digest as bstr - 1 + MAX_KDF_LABEL_LEN + // label <24 bytes as tstr - 1 + MAX_KDF_CONTEXT_LEN + // context <24 bytes as bstr - 1; // length as u8 - - pub const ENC_STRUCTURE_LEN: usize = 8 + 5 + SHA256_DIGEST_LEN; // 8 for ENCRYPT0 -} - -#[cfg(feature = "rust")] -mod rust { - use super::common::*; - - pub type U8 = u8; - pub type BytesEad2 = [u8; 0]; - pub type BytesIdCred = [u8; ID_CRED_LEN]; - pub type BytesSuites = [u8; SUITES_LEN]; - pub type BytesSupportedSuites = [u8; SUPPORTED_SUITES_LEN]; - pub type Bytes8 = [u8; 8]; - 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 BytesMac2 = [u8; MAC_LENGTH_2]; - pub type BytesMac3 = [u8; MAC_LENGTH_3]; - pub type BufferMessage1 = EdhocMessageBuffer; - pub type BufferMessage3 = EdhocMessageBuffer; - pub type BufferCiphertext2 = EdhocMessageBuffer; - pub type BufferCiphertext3 = EdhocMessageBuffer; - pub type BytesHashLen = [u8; SHA256_DIGEST_LEN]; - pub type BytesP256ElemLen = [u8; P256_ELEM_LEN]; - pub type BufferMessage2 = EdhocMessageBuffer; - pub type BytesMaxBuffer = [u8; MAX_BUFFER_LEN]; - pub type BytesMaxContextBuffer = [u8; MAX_KDF_CONTEXT_LEN]; - pub type BytesMaxInfoBuffer = [u8; MAX_INFO_LEN]; - pub type BytesMaxLabelBuffeer = [u8; MAX_KDF_LABEL_LEN]; - pub type BytesEncStructureLen = [u8; ENC_STRUCTURE_LEN]; - - pub const EDHOC_SUITES: BytesSuites = [0, 1, 2, 3, 4, 5, 6, 24, 25]; // all but private cipher suites - pub const EDHOC_SUPPORTED_SUITES: BytesSupportedSuites = [0x2u8]; - - #[repr(C)] - #[derive(Default, Copy, Clone, Debug)] - pub struct State( - pub EDHOCState, - pub BytesP256ElemLen, // x or y, ephemeral private key of myself - pub u8, // c_i, connection identifier chosen by the initiator - pub BytesP256ElemLen, // g_y or g_x, ephemeral public key of the peer - pub BytesHashLen, // prk_3e2m - pub BytesHashLen, // prk_4e3m - pub BytesHashLen, // prk_out - pub BytesHashLen, // prk_exporter - pub BytesHashLen, // h_message_1 - pub BytesHashLen, // th_3 - ); } diff --git a/lib/src/c_wrapper.rs b/lib/src/c_wrapper.rs index 45ca9117..cce7d04f 100644 --- a/lib/src/c_wrapper.rs +++ b/lib/src/c_wrapper.rs @@ -1,4 +1,4 @@ -use crate::rust::*; +use crate::*; use core::{slice, str}; use edhoc_consts::*; @@ -37,8 +37,8 @@ pub struct EdhocInitiatorC { } impl EdhocInitiatorC { - pub fn to_rust(&self) -> RustEdhocInitiator { - RustEdhocInitiator::new( + pub fn to_rust(&self) -> EdhocInitiator { + EdhocInitiator::new( self.state, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(self.i, self.i_len)) }, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(self.g_r, self.g_r_len)) }, @@ -76,8 +76,8 @@ pub struct EdhocResponderC { } impl EdhocResponderC { - pub fn to_rust(&self) -> RustEdhocResponder { - RustEdhocResponder::new( + pub fn to_rust(&self) -> EdhocResponder { + EdhocResponder::new( self.state, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(self.r, self.r_len)) }, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(self.g_i, self.g_i_len)) }, @@ -112,7 +112,7 @@ pub unsafe extern "C" fn responder_new( cred_r: *const u8, cred_r_len: usize, ) -> EdhocResponderC { - RustEdhocResponder::new( + EdhocResponder::new( State::default(), str::from_utf8_unchecked(slice::from_raw_parts(r, r_len)), str::from_utf8_unchecked(slice::from_raw_parts(g_i, g_i_len)), @@ -139,7 +139,7 @@ pub unsafe extern "C" fn initiator_new( cred_r: *const u8, cred_r_len: usize, ) -> EdhocInitiatorC { - RustEdhocInitiator::new( + EdhocInitiator::new( State::default(), str::from_utf8_unchecked(slice::from_raw_parts(i, i_len)), str::from_utf8_unchecked(slice::from_raw_parts(g_r, g_r_len)), diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 6284ccfc..ca03faf0 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,379 +1,343 @@ #![cfg_attr(not(test), no_std)] -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] pub use { edhoc_consts::State as EdhocState, edhoc_consts::*, edhoc_crypto::*, - rust::generate_connection_identifier, rust::RustEdhocInitiator as EdhocInitiator, - rust::RustEdhocResponder as EdhocResponder, + EdhocInitiatorState as EdhocInitiator, EdhocResponderState as EdhocResponder, }; #[cfg(any(feature = "ead-none", feature = "ead-zeroconf"))] pub use edhoc_ead::*; -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] mod edhoc; - -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] use edhoc::*; -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] mod c_wrapper; - -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] use c_wrapper::*; -#[cfg(any( - feature = "rust-psa", - feature = "rust-psa-baremetal", - feature = "rust-cryptocell310" -))] -mod rust { - use super::*; - use edhoc_consts::*; - use hex::FromHex; - - #[derive(Default, Copy, Clone, Debug)] - pub struct RustEdhocInitiator<'a> { - state: State, // opaque state - i: &'a str, // private authentication key of I - g_r: &'a str, // public authentication key of R - id_cred_i: &'a str, // identifier of I's credential - cred_i: &'a str, // I's full credential - id_cred_r: &'a str, // identifier of R's credential - cred_r: &'a str, // R's full credential - } +use edhoc_consts::*; +use hex::FromHex; + +#[derive(Default, Copy, Clone, Debug)] +pub struct EdhocInitiatorState<'a> { + state: State, // opaque state + i: &'a str, // private authentication key of I + g_r: &'a str, // public authentication key of R + id_cred_i: &'a str, // identifier of I's credential + cred_i: &'a str, // I's full credential + id_cred_r: &'a str, // identifier of R's credential + cred_r: &'a str, // R's full credential +} - #[derive(Default, Copy, Clone, Debug)] - pub struct RustEdhocResponder<'a> { - state: State, // opaque state - r: &'a str, // private authentication key of R - g_i: &'a str, // public authentication key of I - id_cred_i: &'a str, // identifier of I's credential - cred_i: &'a str, // I's full credential - id_cred_r: &'a str, // identifier of R's credential - cred_r: &'a str, // R's full credential - } +#[derive(Default, Copy, Clone, Debug)] +pub struct EdhocResponderState<'a> { + state: State, // opaque state + r: &'a str, // private authentication key of R + g_i: &'a str, // public authentication key of I + id_cred_i: &'a str, // identifier of I's credential + cred_i: &'a str, // I's full credential + id_cred_r: &'a str, // identifier of R's credential + cred_r: &'a str, // R's full credential +} - impl<'a> RustEdhocResponder<'a> { - pub fn to_c(&self) -> EdhocResponderC { - EdhocResponderC { - state: self.state, - r: self.r.as_ptr(), - r_len: self.r.len(), - g_i: self.g_i.as_ptr(), - g_i_len: self.g_i.len(), - id_cred_i: self.id_cred_i.as_ptr(), - id_cred_i_len: self.id_cred_i.len(), - cred_i: self.cred_i.as_ptr(), - cred_i_len: self.cred_i.len(), - id_cred_r: self.id_cred_r.as_ptr(), - id_cred_r_len: self.id_cred_r.len(), - cred_r: self.cred_r.as_ptr(), - cred_r_len: self.cred_r.len(), - } +impl<'a> EdhocResponderState<'a> { + pub fn to_c(&self) -> EdhocResponderC { + EdhocResponderC { + state: self.state, + r: self.r.as_ptr(), + r_len: self.r.len(), + g_i: self.g_i.as_ptr(), + g_i_len: self.g_i.len(), + id_cred_i: self.id_cred_i.as_ptr(), + id_cred_i_len: self.id_cred_i.len(), + cred_i: self.cred_i.as_ptr(), + cred_i_len: self.cred_i.len(), + id_cred_r: self.id_cred_r.as_ptr(), + id_cred_r_len: self.id_cred_r.len(), + cred_r: self.cred_r.as_ptr(), + cred_r_len: self.cred_r.len(), } + } - pub fn new( - state: State, - r: &'a str, - g_i: &'a str, - id_cred_i: &'a str, - cred_i: &'a str, - id_cred_r: &'a str, - cred_r: &'a str, - ) -> RustEdhocResponder<'a> { - assert!(r.len() == P256_ELEM_LEN * 2); - assert!(g_i.len() == P256_ELEM_LEN * 2); - assert!(id_cred_i.len() == ID_CRED_LEN * 2); - assert!(id_cred_r.len() == ID_CRED_LEN * 2); - - RustEdhocResponder { - state: state, - r: r, - g_i: g_i, - id_cred_i: id_cred_i, - cred_i: cred_i, - id_cred_r: id_cred_r, - cred_r: cred_r, - } + pub fn new( + state: State, + r: &'a str, + g_i: &'a str, + id_cred_i: &'a str, + cred_i: &'a str, + id_cred_r: &'a str, + cred_r: &'a str, + ) -> EdhocResponderState<'a> { + assert!(r.len() == P256_ELEM_LEN * 2); + assert!(g_i.len() == P256_ELEM_LEN * 2); + assert!(id_cred_i.len() == ID_CRED_LEN * 2); + assert!(id_cred_r.len() == ID_CRED_LEN * 2); + + EdhocResponderState { + state: state, + r: r, + g_i: g_i, + id_cred_i: id_cred_i, + cred_i: cred_i, + id_cred_r: id_cred_r, + cred_r: cred_r, } + } - pub fn process_message_1( - self: &mut RustEdhocResponder<'a>, - message_1: &BufferMessage1, - ) -> Result<(), EDHOCError> { - let state = r_process_message_1(self.state, message_1)?; - self.state = state; + pub fn process_message_1( + self: &mut EdhocResponderState<'a>, + message_1: &BufferMessage1, + ) -> Result<(), EDHOCError> { + let state = r_process_message_1(self.state, message_1)?; + self.state = state; - Ok(()) - } + Ok(()) + } - pub fn prepare_message_2( - self: &mut RustEdhocResponder<'a>, - ) -> Result<(BufferMessage2, u8), EDHOCError> { - let mut cred_r: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; - hex::decode_to_slice(self.cred_r, &mut cred_r[..self.cred_r.len() / 2]) - .expect("Decoding failed"); - let (y, g_y) = edhoc_crypto::p256_generate_key_pair(); - let c_r = generate_connection_identifier_cbor(); - - match r_prepare_message_2( - self.state, - &::from_hex(self.id_cred_r).expect("Decoding failed"), - &cred_r, - self.cred_r.len() / 2, - &::from_hex(self.r).expect("Decoding failed"), - y, - g_y, - c_r, - ) { - Ok((state, message_2, c_r)) => { - self.state = state; - Ok((message_2, c_r)) - } - Err(error) => Err(error), + pub fn prepare_message_2( + self: &mut EdhocResponderState<'a>, + ) -> Result<(BufferMessage2, u8), EDHOCError> { + let mut cred_r: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + hex::decode_to_slice(self.cred_r, &mut cred_r[..self.cred_r.len() / 2]) + .expect("Decoding failed"); + let (y, g_y) = edhoc_crypto::p256_generate_key_pair(); + let c_r = generate_connection_identifier_cbor(); + + match r_prepare_message_2( + self.state, + &::from_hex(self.id_cred_r).expect("Decoding failed"), + &cred_r, + self.cred_r.len() / 2, + &::from_hex(self.r).expect("Decoding failed"), + y, + g_y, + c_r, + ) { + Ok((state, message_2, c_r)) => { + self.state = state; + Ok((message_2, c_r)) } + Err(error) => Err(error), } + } - pub fn process_message_3( - self: &mut RustEdhocResponder<'a>, - message_3: &BufferMessage3, - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - let mut cred_i: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; - hex::decode_to_slice(self.cred_i, &mut cred_i[..self.cred_i.len() / 2]) - .expect("Decoding failed"); - - match r_process_message_3( - self.state, - message_3, - &::from_hex(self.id_cred_i).expect("Decoding failed"), - &cred_i, - self.cred_i.len() / 2, - &::from_hex(self.g_i).expect("Decoding failed"), - ) { - Ok((state, prk_out)) => { - self.state = state; - Ok(prk_out) - } - Err(error) => Err(error), + pub fn process_message_3( + self: &mut EdhocResponderState<'a>, + message_3: &BufferMessage3, + ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { + let mut cred_i: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + hex::decode_to_slice(self.cred_i, &mut cred_i[..self.cred_i.len() / 2]) + .expect("Decoding failed"); + + match r_process_message_3( + self.state, + message_3, + &::from_hex(self.id_cred_i).expect("Decoding failed"), + &cred_i, + self.cred_i.len() / 2, + &::from_hex(self.g_i).expect("Decoding failed"), + ) { + Ok((state, prk_out)) => { + self.state = state; + Ok(prk_out) } + Err(error) => Err(error), } + } - pub fn edhoc_exporter( - self: &mut RustEdhocResponder<'a>, - label: u8, - context: &[u8], - length: usize, - ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { - let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { - Ok((state, output)) => { - self.state = state; - Ok(output) - } - Err(error) => Err(error), + pub fn edhoc_exporter( + self: &mut EdhocResponderState<'a>, + label: u8, + context: &[u8], + length: usize, + ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { + let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { + Ok((state, output)) => { + self.state = state; + Ok(output) } + Err(error) => Err(error), } + } - pub fn edhoc_key_update( - self: &mut RustEdhocResponder<'a>, - context: &[u8], - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - match edhoc_key_update(self.state, &context_buf, context.len()) { - Ok((state, prk_out_new)) => { - self.state = state; - Ok(prk_out_new) - } - Err(error) => Err(error), + pub fn edhoc_key_update( + self: &mut EdhocResponderState<'a>, + context: &[u8], + ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { + let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + match edhoc_key_update(self.state, &context_buf, context.len()) { + Ok((state, prk_out_new)) => { + self.state = state; + Ok(prk_out_new) } + Err(error) => Err(error), } } +} - impl<'a> RustEdhocInitiator<'a> { - pub fn to_c(&self) -> EdhocInitiatorC { - EdhocInitiatorC { - state: self.state, - i: self.i.as_ptr(), - i_len: self.i.len(), - g_r: self.g_r.as_ptr(), - g_r_len: self.g_r.len(), - id_cred_i: self.id_cred_i.as_ptr(), - id_cred_i_len: self.id_cred_i.len(), - cred_i: self.cred_i.as_ptr(), - cred_i_len: self.cred_i.len(), - id_cred_r: self.id_cred_r.as_ptr(), - id_cred_r_len: self.id_cred_r.len(), - cred_r: self.cred_r.as_ptr(), - cred_r_len: self.cred_r.len(), - } +impl<'a> EdhocInitiatorState<'a> { + pub fn to_c(&self) -> EdhocInitiatorC { + EdhocInitiatorC { + state: self.state, + i: self.i.as_ptr(), + i_len: self.i.len(), + g_r: self.g_r.as_ptr(), + g_r_len: self.g_r.len(), + id_cred_i: self.id_cred_i.as_ptr(), + id_cred_i_len: self.id_cred_i.len(), + cred_i: self.cred_i.as_ptr(), + cred_i_len: self.cred_i.len(), + id_cred_r: self.id_cred_r.as_ptr(), + id_cred_r_len: self.id_cred_r.len(), + cred_r: self.cred_r.as_ptr(), + cred_r_len: self.cred_r.len(), } + } - pub fn new( - state: State, - i: &'a str, - g_r: &'a str, - id_cred_i: &'a str, - cred_i: &'a str, - id_cred_r: &'a str, - cred_r: &'a str, - ) -> RustEdhocInitiator<'a> { - assert!(i.len() == P256_ELEM_LEN * 2); - assert!(g_r.len() == P256_ELEM_LEN * 2); - assert!(id_cred_i.len() == ID_CRED_LEN * 2); - assert!(id_cred_r.len() == ID_CRED_LEN * 2); - - RustEdhocInitiator { - state: state, - i: i, - g_r: g_r, - id_cred_i: id_cred_i, - cred_i: cred_i, - id_cred_r: id_cred_r, - cred_r: cred_r, - } + pub fn new( + state: State, + i: &'a str, + g_r: &'a str, + id_cred_i: &'a str, + cred_i: &'a str, + id_cred_r: &'a str, + cred_r: &'a str, + ) -> EdhocInitiatorState<'a> { + assert!(i.len() == P256_ELEM_LEN * 2); + assert!(g_r.len() == P256_ELEM_LEN * 2); + assert!(id_cred_i.len() == ID_CRED_LEN * 2); + assert!(id_cred_r.len() == ID_CRED_LEN * 2); + + EdhocInitiatorState { + state: state, + i: i, + g_r: g_r, + id_cred_i: id_cred_i, + cred_i: cred_i, + id_cred_r: id_cred_r, + cred_r: cred_r, } + } - pub fn prepare_message_1( - self: &mut RustEdhocInitiator<'a>, - ) -> Result { - let (x, g_x) = edhoc_crypto::p256_generate_key_pair(); - let c_i = generate_connection_identifier_cbor(); - - match i_prepare_message_1(self.state, x, g_x, c_i) { - Ok((state, message_1)) => { - self.state = state; - Ok(message_1) - } - Err(error) => Err(error), + pub fn prepare_message_1( + self: &mut EdhocInitiatorState<'a>, + ) -> Result { + let (x, g_x) = edhoc_crypto::p256_generate_key_pair(); + let c_i = generate_connection_identifier_cbor(); + + match i_prepare_message_1(self.state, x, g_x, c_i) { + Ok((state, message_1)) => { + self.state = state; + Ok(message_1) } + Err(error) => Err(error), } + } - pub fn process_message_2( - self: &mut RustEdhocInitiator<'a>, - message_2: &BufferMessage2, - ) -> Result { - let mut cred_r: BytesMaxBuffer = [0x00u8; MAX_BUFFER_LEN]; - hex::decode_to_slice(self.cred_r, &mut cred_r[..self.cred_r.len() / 2]) - .expect("Decoding failed"); - - match i_process_message_2( - self.state, - message_2, - &::from_hex(self.id_cred_r).expect("Decoding failed"), - &cred_r, - self.cred_r.len() / 2, - &::from_hex(self.g_r).expect("Decoding failed"), - &::from_hex(self.i).expect("Decoding failed"), - ) { - Ok((state, c_r, _kid)) => { - self.state = state; - Ok(c_r) - } - Err(error) => Err(error), + pub fn process_message_2( + self: &mut EdhocInitiatorState<'a>, + message_2: &BufferMessage2, + ) -> Result { + let mut cred_r: BytesMaxBuffer = [0x00u8; MAX_BUFFER_LEN]; + hex::decode_to_slice(self.cred_r, &mut cred_r[..self.cred_r.len() / 2]) + .expect("Decoding failed"); + + match i_process_message_2( + self.state, + message_2, + &::from_hex(self.id_cred_r).expect("Decoding failed"), + &cred_r, + self.cred_r.len() / 2, + &::from_hex(self.g_r).expect("Decoding failed"), + &::from_hex(self.i).expect("Decoding failed"), + ) { + Ok((state, c_r, _kid)) => { + self.state = state; + Ok(c_r) } + Err(error) => Err(error), } + } - pub fn prepare_message_3( - self: &mut RustEdhocInitiator<'a>, - ) -> Result<(BufferMessage3, [u8; SHA256_DIGEST_LEN]), EDHOCError> { - let mut cred_i: BytesMaxBuffer = [0x00u8; MAX_BUFFER_LEN]; - hex::decode_to_slice(self.cred_i, &mut cred_i[..self.cred_i.len() / 2]) - .expect("Decoding failed"); - - match i_prepare_message_3( - self.state, - &::from_hex(self.id_cred_i).expect("Decoding failed"), - &cred_i, - self.cred_i.len() / 2, - ) { - Ok((state, message_3, prk_out)) => { - self.state = state; - Ok((message_3, prk_out)) - } - Err(error) => Err(error), + pub fn prepare_message_3( + self: &mut EdhocInitiatorState<'a>, + ) -> Result<(BufferMessage3, [u8; SHA256_DIGEST_LEN]), EDHOCError> { + let mut cred_i: BytesMaxBuffer = [0x00u8; MAX_BUFFER_LEN]; + hex::decode_to_slice(self.cred_i, &mut cred_i[..self.cred_i.len() / 2]) + .expect("Decoding failed"); + + match i_prepare_message_3( + self.state, + &::from_hex(self.id_cred_i).expect("Decoding failed"), + &cred_i, + self.cred_i.len() / 2, + ) { + Ok((state, message_3, prk_out)) => { + self.state = state; + Ok((message_3, prk_out)) } + Err(error) => Err(error), } + } - pub fn edhoc_exporter( - self: &mut RustEdhocInitiator<'a>, - label: u8, - context: &[u8], - length: usize, - ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { - let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { - Ok((state, output)) => { - self.state = state; - Ok(output) - } - Err(error) => Err(error), + pub fn edhoc_exporter( + self: &mut EdhocInitiatorState<'a>, + label: u8, + context: &[u8], + length: usize, + ) -> Result<[u8; MAX_BUFFER_LEN], EDHOCError> { + let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { + Ok((state, output)) => { + self.state = state; + Ok(output) } + Err(error) => Err(error), } + } - pub fn edhoc_key_update( - self: &mut RustEdhocInitiator<'a>, - context: &[u8], - ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { - let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; - context_buf[..context.len()].copy_from_slice(context); - - match edhoc_key_update(self.state, &context_buf, context.len()) { - Ok((state, prk_out_new)) => { - self.state = state; - Ok(prk_out_new) - } - Err(error) => Err(error), + pub fn edhoc_key_update( + self: &mut EdhocInitiatorState<'a>, + context: &[u8], + ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { + let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; + context_buf[..context.len()].copy_from_slice(context); + + match edhoc_key_update(self.state, &context_buf, context.len()) { + Ok((state, prk_out_new)) => { + self.state = state; + Ok(prk_out_new) } + Err(error) => Err(error), } } +} - pub fn generate_connection_identifier_cbor() -> u8 { - let c_i = generate_connection_identifier(); - if c_i >= 0 && c_i <= 23 { - return c_i as u8; // verbatim encoding of single byte integer - } else if c_i < 0 && c_i >= -24 { - // negative single byte integer encoding - return CBOR_NEG_INT_1BYTE_START - 1 + (c_i.abs() as u8); - } else { - return 0; - } +pub fn generate_connection_identifier_cbor() -> u8 { + let c_i = generate_connection_identifier(); + if c_i >= 0 && c_i <= 23 { + return c_i as u8; // verbatim encoding of single byte integer + } else if c_i < 0 && c_i >= -24 { + // negative single byte integer encoding + return CBOR_NEG_INT_1BYTE_START - 1 + (c_i.abs() as u8); + } else { + return 0; } +} - /// generates an identifier that can be serialized as a single CBOR integer, i.e. -24 <= x <= 23 - pub fn generate_connection_identifier() -> i8 { - let mut conn_id = edhoc_crypto::get_random_byte() as i8; - while conn_id < -24 || conn_id > 23 { - conn_id = edhoc_crypto::get_random_byte() as i8; - } - conn_id +/// generates an identifier that can be serialized as a single CBOR integer, i.e. -24 <= x <= 23 +pub fn generate_connection_identifier() -> i8 { + let mut conn_id = edhoc_crypto::get_random_byte() as i8; + while conn_id < -24 || conn_id > 23 { + conn_id = edhoc_crypto::get_random_byte() as i8; } + conn_id } #[cfg(test)] From 0d84bec86957e9bf075b4092c30541fbee9660b0 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 10:19:00 +0200 Subject: [PATCH 04/16] refactor: adjust ci fstar to run on main crates --- .github/workflows/build-and-test.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 88c60d0c..cf5128b1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -69,16 +69,15 @@ jobs: run: cargo build --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="${{ matrix.edhoc_lib }}-${{ matrix.crypto }}, ${{ matrix.ead }}" --release - hacspec-to-fstar: - # TODO: rename to `generate-fstar` and adjust to use the main library + generate-fstar: needs: unit-tests runs-on: ubuntu-latest steps: - name: Checkout edhoc-rs uses: actions/checkout@v3 - - name: Patch edhoc-rs features - run: git apply ./hacspec/adjust_features_for_hax.patch + # - name: Patch edhoc-rs features + # run: git apply ./hacspec/adjust_features_for_hax.patch - name: Checkout hacspec-v2 uses: actions/checkout@v3 @@ -92,7 +91,7 @@ jobs: - name: Generate fstar run: | - docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs/hacspec && cargo-hax -C -p edhoc-hacspec -p edhoc-crypto -p edhoc-consts -p edhoc-crypto-hacspec \; into fstar" + docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs/hacspec && cargo-hax -C --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-psa, ead-none" --release \; into fstar" zip -j -r edhoc-rs-fstar.zip $(find . -name *fst) - name: Upload artifact @@ -197,7 +196,7 @@ jobs: release: runs-on: ubuntu-latest - needs: [build-edhoc-package, run-example-on-qemu, build-example-for-cortex-m4, build-coap-example, hacspec-to-fstar, build-static-lib-and-headers] + needs: [build-edhoc-package, run-example-on-qemu, build-example-for-cortex-m4, build-coap-example, generate-fstar, build-static-lib-and-headers] if: >- github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') From 804b4405ac3f4c8aa9947e026ab8274c9aba3e10 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 10:33:50 +0200 Subject: [PATCH 05/16] refactor: remove hacspec code from psa and cc310 crypto backends --- .../edhoc-crypto-cryptocell310-sys/src/lib.rs | 786 ++++++------------ crypto/edhoc-crypto-psa/src/lib.rs | 732 +++++----------- 2 files changed, 457 insertions(+), 1061 deletions(-) diff --git a/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs b/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs index 794b9b24..be73d460 100644 --- a/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs +++ b/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs @@ -18,594 +18,278 @@ fn convert_array(input: &[u32]) -> [u8; SHA256_DIGEST_LEN] { output } -#[cfg(feature = "hacspec")] -pub use hacspec::*; - -#[cfg(feature = "rust")] -pub use rust::*; - -#[cfg(feature = "hacspec")] -mod hacspec { - use super::*; - use hacspec_lib::*; - - pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; - - unsafe { - CRYS_HASH( - CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, - message.to_public_array().as_mut_ptr(), - message_len, - buffer.as_mut_ptr(), - ); - } - - BytesHashLen::from_public_slice(&convert_array(&buffer[0..SHA256_DIGEST_LEN / 4])) +pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { + let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; + + unsafe { + CRYS_HASH( + CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, + message.clone().as_mut_ptr(), + message_len, + buffer.as_mut_ptr(), + ); } - pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, - ) -> BytesMaxBuffer { - let mut buffer = [0x00u8; MAX_BUFFER_LEN]; - unsafe { - CRYS_HKDF_KeyDerivFunc( - CRYS_HKDF_HASH_OpMode_t_CRYS_HKDF_HASH_SHA256_mode, - core::ptr::null_mut(), - 0 as usize, - prk.to_public_array().as_mut_ptr(), - prk.len() as u32, - info.to_public_array().as_mut_ptr(), - info_len as u32, - buffer.as_mut_ptr(), - length as u32, - SaSiBool_SASI_TRUE, - ); - } - - BytesMaxBuffer::from_public_slice(&buffer) - } - - pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 - - // TODO generalize if salt is not provided - let output = hmac_sha256(&mut ikm.to_public_array(), salt.to_public_array()); + convert_array(&buffer[0..SHA256_DIGEST_LEN / 4]) +} - output +pub fn hkdf_expand( + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, +) -> BytesMaxBuffer { + let mut buffer = [0x00u8; MAX_BUFFER_LEN]; + unsafe { + CRYS_HKDF_KeyDerivFunc( + CRYS_HKDF_HASH_OpMode_t_CRYS_HKDF_HASH_SHA256_mode, + core::ptr::null_mut(), + 0 as usize, + prk.clone().as_mut_ptr(), + prk.len() as u32, + info.clone().as_mut_ptr(), + info_len as u32, + buffer.as_mut_ptr(), + length as u32, + SaSiBool_SASI_TRUE, + ); } - pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, - ) -> BufferCiphertext3 { - let mut output = EdhocMessageBuffer::new(); - let mut tag: CRYS_AESCCM_Mac_Res_t = Default::default(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); - - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key.to_public_array()); - - let err = unsafe { - CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_ENCRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.to_public_array().as_mut_ptr(), - iv.len() as u8, - ad.to_public_array().as_mut_ptr(), - ad.len() as u32, - plaintext.content.to_public_array()[..plaintext.len].as_mut_ptr(), - plaintext.len as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - tag.as_mut_ptr(), - 0 as u32, // CCM - ) - }; - - output.content[plaintext.len..plaintext.len + AES_CCM_TAG_LEN] - .copy_from_slice(&tag[..AES_CCM_TAG_LEN]); - output.len = plaintext.len + AES_CCM_TAG_LEN; - - BufferCiphertext3::from_public_buffer(&output) - } + buffer +} - pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, - ) -> Result { - let mut output = EdhocMessageBuffer::new(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); - - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key.to_public_array()); - - let mut err = EDHOCError::MacVerificationFailed; - let mut plaintext = BufferPlaintext3::new(); - - unsafe { - match CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_DECRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.to_public_array().as_mut_ptr(), - iv.len() as u8, - ad.to_public_array().as_mut_ptr(), - ad.len() as u32, - ciphertext.content.to_public_array().as_mut_ptr(), - (ciphertext.len - AES_CCM_TAG_LEN) as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - ciphertext.content.to_public_array()[ciphertext.len - AES_CCM_TAG_LEN..] - .as_mut_ptr(), - 0 as u32, // CCM - ) { - CRYS_OK => { - output.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(BufferPlaintext3::from_public_buffer(&output)) - } - _ => Err(EDHOCError::MacVerificationFailed), - } - } - } - pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, - ) -> BytesP256ElemLen { - let mut output = [0x0u8; P256_ELEM_LEN]; - let mut output_len: u32 = output.len() as u32; - - let mut tmp: CRYS_ECDH_TempData_t = Default::default(); - - let mut public_key_compressed = [0x0u8; P256_ELEM_LEN + 1]; - public_key_compressed[0] = 0x02; - public_key_compressed[1..].copy_from_slice(&public_key.to_public_array()); - - let mut public_key_cc310: CRYS_ECPKI_UserPublKey_t = Default::default(); - - let mut domain = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; - - unsafe { - _DX_ECPKI_BuildPublKey( - domain, - public_key_compressed.as_mut_ptr(), - (P256_ELEM_LEN + 1) as u32, - EC_PublKeyCheckMode_t_CheckPointersAndSizesOnly, - &mut public_key_cc310, - core::ptr::null_mut(), - ); - } +pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { + // Implementation of HKDF-Extract as per RFC 5869 - let mut private_key_cc310: CRYS_ECPKI_UserPrivKey_t = Default::default(); + // TODO generalize if salt is not provided + let output = hmac_sha256(&mut ikm.clone()[..], *salt); - unsafe { - CRYS_ECPKI_BuildPrivKey( - domain, - private_key.to_public_array().as_mut_ptr(), - P256_ELEM_LEN as u32, - &mut private_key_cc310, - ); - } + output +} - unsafe { - CRYS_ECDH_SVDP_DH( - &mut public_key_cc310, - &mut private_key_cc310, - output.as_mut_ptr(), - &mut output_len, - &mut tmp, - ); - } +pub fn aes_ccm_encrypt_tag_8( + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, +) -> BufferCiphertext3 { + let mut output: BufferCiphertext3 = BufferCiphertext3::new(); + let mut tag: CRYS_AESCCM_Mac_Res_t = Default::default(); + let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); + + aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); + + let err = unsafe { + CC_AESCCM( + SaSiAesEncryptMode_t_SASI_AES_ENCRYPT, + aesccm_key.as_mut_ptr(), + CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, + iv.clone().as_mut_ptr(), + iv.len() as u8, + ad.clone().as_mut_ptr(), + ad.len() as u32, + plaintext.content.clone().as_mut_ptr(), + plaintext.len as u32, + output.content.as_mut_ptr(), + AES_CCM_TAG_LEN as u8, // authentication tag length + tag.as_mut_ptr(), + 0 as u32, // CCM + ) + }; + + output.content[plaintext.len..plaintext.len + AES_CCM_TAG_LEN] + .copy_from_slice(&tag[..AES_CCM_TAG_LEN]); + output.len = plaintext.len + AES_CCM_TAG_LEN; - BytesP256ElemLen::from_public_slice(&output) - } + output +} - fn hmac_sha256(message: &mut [u8], mut key: [u8; SHA256_DIGEST_LEN]) -> BytesHashLen { - let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; - - unsafe { - CRYS_HMAC( - CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, - key.as_mut_ptr(), - key.len() as u16, - message.as_mut_ptr(), - message.len(), - buffer.as_mut_ptr(), - ); +pub fn aes_ccm_decrypt_tag_8( + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, +) -> Result { + let mut output: BufferPlaintext3 = BufferPlaintext3::new(); + let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); + + aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); + + let mut err = EDHOCError::MacVerificationFailed; + + unsafe { + match CC_AESCCM( + SaSiAesEncryptMode_t_SASI_AES_DECRYPT, + aesccm_key.as_mut_ptr(), + CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, + iv.clone().as_mut_ptr(), + iv.len() as u8, + ad.clone().as_mut_ptr(), + ad.len() as u32, + ciphertext.content.clone().as_mut_ptr(), + (ciphertext.len - AES_CCM_TAG_LEN) as u32, + output.content.as_mut_ptr(), + AES_CCM_TAG_LEN as u8, // authentication tag length + ciphertext.content.clone()[ciphertext.len - AES_CCM_TAG_LEN..].as_mut_ptr(), + 0 as u32, // CCM + ) { + CRYS_OK => { + output.len = ciphertext.len - AES_CCM_TAG_LEN; + Ok(output) + } + _ => Err(EDHOCError::MacVerificationFailed), } - - BytesHashLen::from_public_slice(&convert_array(&buffer[..SHA256_DIGEST_LEN / 4])) } +} - pub fn get_random_byte() -> U8 { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let mut buffer = [0u8; 1]; - unsafe { - CRYS_RND_GenerateVector( - &mut rnd_context as *mut _ as *mut c_void, - 1, - buffer.as_mut_ptr(), - ); - } - U8(buffer[0]) +pub fn p256_ecdh( + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, +) -> BytesP256ElemLen { + let mut output = [0x0u8; P256_ELEM_LEN]; + let mut output_len: u32 = output.len() as u32; + + let mut tmp: CRYS_ECDH_TempData_t = Default::default(); + + let mut public_key_compressed = [0x0u8; P256_ELEM_LEN + 1]; + public_key_compressed[0] = 0x02; + public_key_compressed[1..].copy_from_slice(&public_key[..]); + + let mut public_key_cc310: CRYS_ECPKI_UserPublKey_t = Default::default(); + + let mut domain = + unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; + + unsafe { + _DX_ECPKI_BuildPublKey( + domain, + public_key_compressed.as_mut_ptr(), + (P256_ELEM_LEN + 1) as u32, + EC_PublKeyCheckMode_t_CheckPointersAndSizesOnly, + &mut public_key_cc310, + core::ptr::null_mut(), + ); } - pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let rnd_generate_vect_func: SaSiRndGenerateVectWorkFunc_t = Some(CRYS_RND_GenerateVector); - let mut curve_256 = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; - let mut crys_private_key: *mut CRYS_ECPKI_UserPrivKey_t = - &mut CRYS_ECPKI_UserPrivKey_t::default(); - let mut crys_public_key: *mut CRYS_ECPKI_UserPublKey_t = - &mut CRYS_ECPKI_UserPublKey_t::default(); - let mut temp_data: *mut CRYS_ECPKI_KG_TempData_t = &mut CRYS_ECPKI_KG_TempData_t::default(); - let mut temp_fips_buffer: *mut CRYS_ECPKI_KG_FipsContext_t = - &mut CRYS_ECPKI_KG_FipsContext_t::default(); - - unsafe { - CRYS_ECPKI_GenKeyPair( - &mut rnd_context as *mut _ as *mut c_void, - rnd_generate_vect_func, - curve_256, - crys_private_key, - crys_public_key, - temp_data, - temp_fips_buffer, - ); - } - - let mut private_key: [u8; P256_ELEM_LEN] = [0x0; P256_ELEM_LEN]; - let mut key_size: u32 = P256_ELEM_LEN.try_into().unwrap(); - - unsafe { - CRYS_ECPKI_ExportPrivKey(crys_private_key, private_key.as_mut_ptr(), &mut key_size); - } - - let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - - let mut public_key: [u8; P256_ELEM_LEN + 1] = [0x0; P256_ELEM_LEN + 1]; - let mut key_size: u32 = (P256_ELEM_LEN as u32) + 1; - let compressed_flag: CRYS_ECPKI_PointCompression_t = - CRYS_ECPKI_PointCompression_t_CRYS_EC_PointCompressed; - - unsafe { - CRYS_ECPKI_ExportPublKey( - crys_public_key, - compressed_flag, - public_key.as_mut_ptr(), - &mut key_size, - ); - } - - let public_key = BytesP256ElemLen::from_public_slice(&public_key[1..]); // discard sign byte + let mut private_key_cc310: CRYS_ECPKI_UserPrivKey_t = Default::default(); - (private_key, public_key) + unsafe { + CRYS_ECPKI_BuildPrivKey( + domain, + private_key.clone().as_mut_ptr(), + P256_ELEM_LEN as u32, + &mut private_key_cc310, + ); } - pub fn test_hmac_sha256() { - let mut KEY: [u8; 32] = [0x0b; 32]; - let mut MESSAGE_1: [u8; 0] = []; - const RESULT_1_TV: [u8; 32] = [ - 0x51, 0x77, 0xe6, 0x37, 0xaa, 0xac, 0x0b, 0x50, 0xe5, 0xdc, 0xa8, 0xbb, 0x05, 0xb0, - 0xb5, 0x71, 0x44, 0x4b, 0xd5, 0x9b, 0x9b, 0x0d, 0x83, 0x4d, 0x50, 0x68, 0x1a, 0xf2, - 0x1f, 0xc1, 0x4b, 0x1e, - ]; - let mut MESSAGE_2: [u8; 1] = [0x0a]; - const RESULT_2_TV: [u8; 32] = [ - 0x30, 0x50, 0x86, 0x79, 0x39, 0x85, 0x02, 0xd9, 0xdd, 0x70, 0x7e, 0xff, 0x6c, 0x84, - 0x08, 0x9d, 0x83, 0x12, 0xcc, 0xea, 0x25, 0x36, 0x4d, 0x9c, 0xb8, 0xb0, 0xbd, 0x94, - 0xd0, 0xe6, 0x55, 0xa3, - ]; - - let result_1 = hmac_sha256(&mut MESSAGE_1, KEY).to_public_array(); - assert_eq!(result_1, RESULT_1_TV); - - let result_2 = hmac_sha256(&mut MESSAGE_2, KEY).to_public_array(); - assert_eq!(result_2, RESULT_2_TV); + unsafe { + CRYS_ECDH_SVDP_DH( + &mut public_key_cc310, + &mut private_key_cc310, + output.as_mut_ptr(), + &mut output_len, + &mut tmp, + ); } -} - -#[cfg(feature = "rust")] -mod rust { - use super::*; - - pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; - unsafe { - CRYS_HASH( - CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, - message.clone().as_mut_ptr(), - message_len, - buffer.as_mut_ptr(), - ); - } + output +} - convert_array(&buffer[0..SHA256_DIGEST_LEN / 4]) +fn hmac_sha256(message: &mut [u8], mut key: [u8; SHA256_DIGEST_LEN]) -> BytesHashLen { + let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; + + unsafe { + CRYS_HMAC( + CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, + key.as_mut_ptr(), + key.len() as u16, + message.as_mut_ptr(), + message.len(), + buffer.as_mut_ptr(), + ); } - pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, - ) -> BytesMaxBuffer { - let mut buffer = [0x00u8; MAX_BUFFER_LEN]; - unsafe { - CRYS_HKDF_KeyDerivFunc( - CRYS_HKDF_HASH_OpMode_t_CRYS_HKDF_HASH_SHA256_mode, - core::ptr::null_mut(), - 0 as usize, - prk.clone().as_mut_ptr(), - prk.len() as u32, - info.clone().as_mut_ptr(), - info_len as u32, - buffer.as_mut_ptr(), - length as u32, - SaSiBool_SASI_TRUE, - ); - } + convert_array(&buffer[..SHA256_DIGEST_LEN / 4]) +} - buffer +pub fn get_random_byte() -> u8 { + let mut rnd_context = CRYS_RND_State_t::default(); + let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); + unsafe { + SaSi_LibInit(); + CRYS_RndInit( + &mut rnd_context as *mut _ as *mut c_void, + &mut rnd_work_buffer as *mut _, + ); } - - pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 - - // TODO generalize if salt is not provided - let output = hmac_sha256(&mut ikm.clone()[..], *salt); - - output + let mut buffer = [0u8; 1]; + unsafe { + CRYS_RND_GenerateVector( + &mut rnd_context as *mut _ as *mut c_void, + 1, + buffer.as_mut_ptr(), + ); } + buffer[0] +} - pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, - ) -> BufferCiphertext3 { - let mut output: BufferCiphertext3 = BufferCiphertext3::new(); - let mut tag: CRYS_AESCCM_Mac_Res_t = Default::default(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); - - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); - - let err = unsafe { - CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_ENCRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.clone().as_mut_ptr(), - iv.len() as u8, - ad.clone().as_mut_ptr(), - ad.len() as u32, - plaintext.content.clone().as_mut_ptr(), - plaintext.len as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - tag.as_mut_ptr(), - 0 as u32, // CCM - ) - }; - - output.content[plaintext.len..plaintext.len + AES_CCM_TAG_LEN] - .copy_from_slice(&tag[..AES_CCM_TAG_LEN]); - output.len = plaintext.len + AES_CCM_TAG_LEN; - - output +pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { + let mut rnd_context = CRYS_RND_State_t::default(); + let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); + unsafe { + SaSi_LibInit(); + CRYS_RndInit( + &mut rnd_context as *mut _ as *mut c_void, + &mut rnd_work_buffer as *mut _, + ); } - - pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, - ) -> Result { - let mut output: BufferPlaintext3 = BufferPlaintext3::new(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); - - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); - - let mut err = EDHOCError::MacVerificationFailed; - - unsafe { - match CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_DECRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.clone().as_mut_ptr(), - iv.len() as u8, - ad.clone().as_mut_ptr(), - ad.len() as u32, - ciphertext.content.clone().as_mut_ptr(), - (ciphertext.len - AES_CCM_TAG_LEN) as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - ciphertext.content.clone()[ciphertext.len - AES_CCM_TAG_LEN..].as_mut_ptr(), - 0 as u32, // CCM - ) { - CRYS_OK => { - output.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(output) - } - _ => Err(EDHOCError::MacVerificationFailed), - } - } + let rnd_generate_vect_func: SaSiRndGenerateVectWorkFunc_t = Some(CRYS_RND_GenerateVector); + let mut curve_256 = + unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; + let mut crys_private_key: *mut CRYS_ECPKI_UserPrivKey_t = + &mut CRYS_ECPKI_UserPrivKey_t::default(); + let mut crys_public_key: *mut CRYS_ECPKI_UserPublKey_t = + &mut CRYS_ECPKI_UserPublKey_t::default(); + let mut temp_data: *mut CRYS_ECPKI_KG_TempData_t = &mut CRYS_ECPKI_KG_TempData_t::default(); + let mut temp_fips_buffer: *mut CRYS_ECPKI_KG_FipsContext_t = + &mut CRYS_ECPKI_KG_FipsContext_t::default(); + + unsafe { + CRYS_ECPKI_GenKeyPair( + &mut rnd_context as *mut _ as *mut c_void, + rnd_generate_vect_func, + curve_256, + crys_private_key, + crys_public_key, + temp_data, + temp_fips_buffer, + ); } - pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, - ) -> BytesP256ElemLen { - let mut output = [0x0u8; P256_ELEM_LEN]; - let mut output_len: u32 = output.len() as u32; - - let mut tmp: CRYS_ECDH_TempData_t = Default::default(); - - let mut public_key_compressed = [0x0u8; P256_ELEM_LEN + 1]; - public_key_compressed[0] = 0x02; - public_key_compressed[1..].copy_from_slice(&public_key[..]); - - let mut public_key_cc310: CRYS_ECPKI_UserPublKey_t = Default::default(); - - let mut domain = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; - - unsafe { - _DX_ECPKI_BuildPublKey( - domain, - public_key_compressed.as_mut_ptr(), - (P256_ELEM_LEN + 1) as u32, - EC_PublKeyCheckMode_t_CheckPointersAndSizesOnly, - &mut public_key_cc310, - core::ptr::null_mut(), - ); - } - - let mut private_key_cc310: CRYS_ECPKI_UserPrivKey_t = Default::default(); - - unsafe { - CRYS_ECPKI_BuildPrivKey( - domain, - private_key.clone().as_mut_ptr(), - P256_ELEM_LEN as u32, - &mut private_key_cc310, - ); - } - - unsafe { - CRYS_ECDH_SVDP_DH( - &mut public_key_cc310, - &mut private_key_cc310, - output.as_mut_ptr(), - &mut output_len, - &mut tmp, - ); - } + let mut private_key: [u8; P256_ELEM_LEN] = [0x0; P256_ELEM_LEN]; + let mut key_size: u32 = P256_ELEM_LEN.try_into().unwrap(); - output + unsafe { + CRYS_ECPKI_ExportPrivKey(crys_private_key, private_key.as_mut_ptr(), &mut key_size); } - fn hmac_sha256(message: &mut [u8], mut key: [u8; SHA256_DIGEST_LEN]) -> BytesHashLen { - let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; - - unsafe { - CRYS_HMAC( - CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, - key.as_mut_ptr(), - key.len() as u16, - message.as_mut_ptr(), - message.len(), - buffer.as_mut_ptr(), - ); - } + // let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - convert_array(&buffer[..SHA256_DIGEST_LEN / 4]) - } + let mut public_key: [u8; P256_ELEM_LEN + 1] = [0x0; P256_ELEM_LEN + 1]; + let mut key_size: u32 = (P256_ELEM_LEN as u32) + 1; + let compressed_flag: CRYS_ECPKI_PointCompression_t = + CRYS_ECPKI_PointCompression_t_CRYS_EC_PointCompressed; - pub fn get_random_byte() -> u8 { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let mut buffer = [0u8; 1]; - unsafe { - CRYS_RND_GenerateVector( - &mut rnd_context as *mut _ as *mut c_void, - 1, - buffer.as_mut_ptr(), - ); - } - buffer[0] + unsafe { + CRYS_ECPKI_ExportPublKey( + crys_public_key, + compressed_flag, + public_key.as_mut_ptr(), + &mut key_size, + ); } - pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let rnd_generate_vect_func: SaSiRndGenerateVectWorkFunc_t = Some(CRYS_RND_GenerateVector); - let mut curve_256 = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; - let mut crys_private_key: *mut CRYS_ECPKI_UserPrivKey_t = - &mut CRYS_ECPKI_UserPrivKey_t::default(); - let mut crys_public_key: *mut CRYS_ECPKI_UserPublKey_t = - &mut CRYS_ECPKI_UserPublKey_t::default(); - let mut temp_data: *mut CRYS_ECPKI_KG_TempData_t = &mut CRYS_ECPKI_KG_TempData_t::default(); - let mut temp_fips_buffer: *mut CRYS_ECPKI_KG_FipsContext_t = - &mut CRYS_ECPKI_KG_FipsContext_t::default(); - - unsafe { - CRYS_ECPKI_GenKeyPair( - &mut rnd_context as *mut _ as *mut c_void, - rnd_generate_vect_func, - curve_256, - crys_private_key, - crys_public_key, - temp_data, - temp_fips_buffer, - ); - } - - let mut private_key: [u8; P256_ELEM_LEN] = [0x0; P256_ELEM_LEN]; - let mut key_size: u32 = P256_ELEM_LEN.try_into().unwrap(); - - unsafe { - CRYS_ECPKI_ExportPrivKey(crys_private_key, private_key.as_mut_ptr(), &mut key_size); - } - - // let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - - let mut public_key: [u8; P256_ELEM_LEN + 1] = [0x0; P256_ELEM_LEN + 1]; - let mut key_size: u32 = (P256_ELEM_LEN as u32) + 1; - let compressed_flag: CRYS_ECPKI_PointCompression_t = - CRYS_ECPKI_PointCompression_t_CRYS_EC_PointCompressed; + let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // discard sign byte - unsafe { - CRYS_ECPKI_ExportPublKey( - crys_public_key, - compressed_flag, - public_key.as_mut_ptr(), - &mut key_size, - ); - } - - let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // discard sign byte - - (private_key, public_key) - } + (private_key, public_key) } diff --git a/crypto/edhoc-crypto-psa/src/lib.rs b/crypto/edhoc-crypto-psa/src/lib.rs index 94b92d30..25762fdd 100644 --- a/crypto/edhoc-crypto-psa/src/lib.rs +++ b/crypto/edhoc-crypto-psa/src/lib.rs @@ -20,547 +20,259 @@ pub extern "C" fn mbedtls_hardware_poll( 0i32 } -#[cfg(feature = "hacspec")] -pub use hacspec::*; +pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { + let hash_alg = Hash::Sha256; + let mut hash: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN]; + psa_crypto::init().unwrap(); + hash_compute(hash_alg, &message[..message_len], &mut hash).unwrap(); -#[cfg(feature = "rust")] -pub use rust::*; - -#[cfg(feature = "hacspec")] -mod hacspec { - use super::*; - use hacspec_lib::*; - - pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let hash_alg = Hash::Sha256; - let mut hash: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN]; - let message = message.to_public_array(); - psa_crypto::init().unwrap(); - hash_compute(hash_alg, &message[..message_len], &mut hash).unwrap(); - let output = BytesHashLen::from_public_slice(&hash); - - output - } - - pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, - ) -> BytesMaxBuffer { - // Implementation of HKDF-Expand as per RFC5869 - - let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - - let mut n = 0; - - // N = ceil(L/HashLen) - if length % SHA256_DIGEST_LEN == 0 { - n = length / SHA256_DIGEST_LEN; - } else { - n = length / SHA256_DIGEST_LEN + 1; - } - - let info_buf = info.to_public_array(); - - let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] = - [0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1]; - message[..info_len].copy_from_slice(&info_buf[..info_len]); - message[info_len] = 0x01; - let mut t_i = - hmac_sha256(&message[..info_len + 1], prk.to_public_array()).to_public_array(); - output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - - for i in 2..n { - message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len] - .copy_from_slice(&info_buf[..info_len]); - message[SHA256_DIGEST_LEN + info_len] = i as u8; - t_i = hmac_sha256( - &message[..SHA256_DIGEST_LEN + info_len + 1], - prk.to_public_array(), - ) - .to_public_array(); - output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); - } - - output[length..].fill(0x00); - - BytesMaxBuffer::from_public_slice(&output) - } - - pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 + hash +} - // TODO generalize if salt is not provided - let output = hmac_sha256(&ikm.to_public_array(), salt.to_public_array()); +pub fn hkdf_expand( + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, +) -> BytesMaxBuffer { + // Implementation of HKDF-Expand as per RFC5869 - output - } + let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, - ) -> BufferCiphertext3 { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_encrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key.to_public_array()).unwrap(); - let mut output_buffer = EdhocMessageBuffer::new(); - - aead::encrypt( - my_key, - alg, - &iv.to_public_array(), - &ad.to_public_array(), - &plaintext.content.to_public_array()[..plaintext.len], - &mut output_buffer.content, - ) - .unwrap(); + let mut n = 0; - output_buffer.len = plaintext.len + AES_CCM_TAG_LEN; - let output = BufferCiphertext3::from_public_buffer(&output_buffer); - output + // N = ceil(L/HashLen) + if length % SHA256_DIGEST_LEN == 0 { + n = length / SHA256_DIGEST_LEN; + } else { + n = length / SHA256_DIGEST_LEN + 1; } - pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, - ) -> Result { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_decrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key.to_public_array()).unwrap(); - let mut output_buffer = EdhocMessageBuffer::new(); - - match aead::decrypt( - my_key, - alg, - &iv.to_public_array(), - &ad.to_public_array(), - &ciphertext.content.to_public_array()[..ciphertext.len], - &mut output_buffer.content, - ) { - Ok(_) => { - output_buffer.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(BufferPlaintext3::from_public_buffer(&output_buffer)) - } - Err(_) => Err(EDHOCError::MacVerificationFailed), - } - } - pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, - ) -> BytesP256ElemLen { - let mut peer_public_key: [u8; 33] = [0; 33]; - peer_public_key[0] = 0x02; // sign does not matter for ECDH operation - peer_public_key[1..33].copy_from_slice(&public_key.to_public_array()); - - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - let my_key = - key_management::import(attributes, None, &private_key.to_public_array()).unwrap(); - let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - - key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer) - .unwrap(); - - let output = BytesP256ElemLen::from_public_slice(&output_buffer[..]); - - output + let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] = + [0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1]; + message[..info_len].copy_from_slice(&info[..info_len]); + message[info_len] = 0x01; + let mut t_i = hmac_sha256(&message[..info_len + 1], prk); + output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); + + for i in 2..n { + message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); + message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len] + .copy_from_slice(&info[..info_len]); + message[SHA256_DIGEST_LEN + info_len] = i as u8; + t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk); + output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); } - pub fn hmac_sha256(message: &[u8], key: [u8; SHA256_DIGEST_LEN]) -> BytesHashLen { - // implementation of HMAC as per RFC2104 + output[length..].fill(0x00); - const IPAD: [u8; 64] = [0x36; 64]; - const OPAD: [u8; 64] = [0x5C; 64]; + output +} - // (1) append zeros to the end of K to create a B byte string - // (e.g., if K is of length 20 bytes and B=64, then K will be - // appended with 44 zero bytes 0x00) - let mut b: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - b[0..SHA256_DIGEST_LEN].copy_from_slice(&key); +pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { + // Implementation of HKDF-Extract as per RFC 5869 - // (2) XOR (bitwise exclusive-OR) the B byte string computed in step - // (1) with ipad - let mut s2: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - for i in 0..64 { - s2[i] = b[i] ^ IPAD[i]; - } + // TODO generalize if salt is not provided + let output = hmac_sha256(ikm, salt); - // (3) append the stream of data 'text' to the B byte string resulting - // from step (2) - s2[64..64 + message.len()].copy_from_slice(message); + output +} - // (4) apply H to the stream generated in step (3) - let ih = sha256_digest(&BytesMaxBuffer::from_public_slice(&s2), 64 + message.len()); +pub fn aes_ccm_encrypt_tag_8( + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, +) -> BufferCiphertext3 { + psa_crypto::init().unwrap(); + + let alg = Aead::AeadWithShortenedTag { + aead_alg: AeadWithDefaultLengthTag::Ccm, + tag_length: 8, + }; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_encrypt(); + + let attributes = Attributes { + key_type: Type::Aes, + bits: 128, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: alg.into(), + }, + }; + let my_key = key_management::import(attributes, None, &key[..]).unwrap(); + let mut output_buffer: BufferCiphertext3 = BufferCiphertext3::new(); + + aead::encrypt( + my_key, + alg, + iv, + ad, + &plaintext.content[..plaintext.len], + &mut output_buffer.content, + ) + .unwrap(); + + output_buffer.len = plaintext.len + AES_CCM_TAG_LEN; + output_buffer +} - // (5) XOR (bitwise exclusive-OR) the B byte string computed in - // step (1) with opad - let mut s5: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - for i in 0..64 { - s5[i] = b[i] ^ OPAD[i]; +pub fn aes_ccm_decrypt_tag_8( + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, +) -> Result { + psa_crypto::init().unwrap(); + + let alg = Aead::AeadWithShortenedTag { + aead_alg: AeadWithDefaultLengthTag::Ccm, + tag_length: 8, + }; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_decrypt(); + + let attributes = Attributes { + key_type: Type::Aes, + bits: 128, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: alg.into(), + }, + }; + let my_key = key_management::import(attributes, None, &key[..]).unwrap(); + let mut output_buffer: BufferPlaintext3 = BufferPlaintext3::new(); + + match aead::decrypt( + my_key, + alg, + iv, + ad, + &ciphertext.content[..ciphertext.len], + &mut output_buffer.content, + ) { + Ok(_) => { + output_buffer.len = ciphertext.len - AES_CCM_TAG_LEN; + Ok(output_buffer) } - // (6) append the H result from step (4) to the B byte string - // resulting from step (5) - s5[64..64 + SHA256_DIGEST_LEN].copy_from_slice(&ih.to_public_array()); - - // (7) apply H to the stream generated in step (6) and output - // the result - let oh = sha256_digest( - &BytesMaxBuffer::from_public_slice(&s5), - 3 * SHA256_DIGEST_LEN, - ); - - oh - } - - pub fn get_random_byte() -> U8 { - psa_crypto::init().unwrap(); - let mut buffer = [0u8; 1]; - generate_random(&mut buffer); // TODO: check return value - U8(buffer[0]) - } - - pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = UsageFlags::default(); - usage_flags.set_export(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - - let key_id = key_management::generate(attributes, None).unwrap(); - let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - key_management::export(key_id, &mut private_key).unwrap(); - let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - - let mut public_key: [u8; P256_ELEM_LEN * 2 + 1] = [0; P256_ELEM_LEN * 2 + 1]; // allocate buffer for: sign, x, and y coordinates - key_management::export_public(key_id, &mut public_key).unwrap(); - let public_key = BytesP256ElemLen::from_public_slice(&public_key[1..33]); // return only the x coordinate - - (private_key, public_key) + Err(_) => Err(EDHOCError::MacVerificationFailed), } } -#[cfg(feature = "rust")] -mod rust { - use super::*; - - pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let hash_alg = Hash::Sha256; - let mut hash: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN]; - psa_crypto::init().unwrap(); - hash_compute(hash_alg, &message[..message_len], &mut hash).unwrap(); - - hash - } - - pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, - ) -> BytesMaxBuffer { - // Implementation of HKDF-Expand as per RFC5869 - - let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - - let mut n = 0; - - // N = ceil(L/HashLen) - if length % SHA256_DIGEST_LEN == 0 { - n = length / SHA256_DIGEST_LEN; - } else { - n = length / SHA256_DIGEST_LEN + 1; - } - - let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] = - [0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1]; - message[..info_len].copy_from_slice(&info[..info_len]); - message[info_len] = 0x01; - let mut t_i = hmac_sha256(&message[..info_len + 1], prk); - output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - - for i in 2..n { - message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len] - .copy_from_slice(&info[..info_len]); - message[SHA256_DIGEST_LEN + info_len] = i as u8; - t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk); - output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); - } +pub fn p256_ecdh( + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, +) -> BytesP256ElemLen { + let mut peer_public_key: [u8; 33] = [0; 33]; + peer_public_key[0] = 0x02; // sign does not matter for ECDH operation + peer_public_key[1..33].copy_from_slice(&public_key[..]); + + let alg = RawKeyAgreement::Ecdh; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_derive(); + let attributes = Attributes { + key_type: Type::EccKeyPair { + curve_family: EccFamily::SecpR1, + }, + bits: 256, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: KeyAgreement::Raw(alg).into(), + }, + }; + + psa_crypto::init().unwrap(); + let my_key = key_management::import(attributes, None, private_key).unwrap(); + let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; + + key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer) + .unwrap(); - output[length..].fill(0x00); + output_buffer +} - output - } +pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLen { + // implementation of HMAC as per RFC2104 - pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 + const IPAD: [u8; 64] = [0x36; 64]; + const OPAD: [u8; 64] = [0x5C; 64]; - // TODO generalize if salt is not provided - let output = hmac_sha256(ikm, salt); + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B=64, then K will be + // appended with 44 zero bytes 0x00) + let mut b: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; + b[0..SHA256_DIGEST_LEN].copy_from_slice(&key[..]); - output + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step + // (1) with ipad + let mut s2: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; + for i in 0..64 { + s2[i] = b[i] ^ IPAD[i]; } - pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, - ) -> BufferCiphertext3 { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_encrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key[..]).unwrap(); - let mut output_buffer: BufferCiphertext3 = BufferCiphertext3::new(); - - aead::encrypt( - my_key, - alg, - iv, - ad, - &plaintext.content[..plaintext.len], - &mut output_buffer.content, - ) - .unwrap(); + // (3) append the stream of data 'text' to the B byte string resulting + // from step (2) + s2[64..64 + message.len()].copy_from_slice(message); - output_buffer.len = plaintext.len + AES_CCM_TAG_LEN; - output_buffer - } + // (4) apply H to the stream generated in step (3) + let ih = sha256_digest(&s2, 64 + message.len()); - pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, - ) -> Result { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_decrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key[..]).unwrap(); - let mut output_buffer: BufferPlaintext3 = BufferPlaintext3::new(); - - match aead::decrypt( - my_key, - alg, - iv, - ad, - &ciphertext.content[..ciphertext.len], - &mut output_buffer.content, - ) { - Ok(_) => { - output_buffer.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(output_buffer) - } - Err(_) => Err(EDHOCError::MacVerificationFailed), - } + // (5) XOR (bitwise exclusive-OR) the B byte string computed in + // step (1) with opad + let mut s5: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; + for i in 0..64 { + s5[i] = b[i] ^ OPAD[i]; } + // (6) append the H result from step (4) to the B byte string + // resulting from step (5) + s5[64..64 + SHA256_DIGEST_LEN].copy_from_slice(&ih); - pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, - ) -> BytesP256ElemLen { - let mut peer_public_key: [u8; 33] = [0; 33]; - peer_public_key[0] = 0x02; // sign does not matter for ECDH operation - peer_public_key[1..33].copy_from_slice(&public_key[..]); - - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - let my_key = key_management::import(attributes, None, private_key).unwrap(); - let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - - key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer) - .unwrap(); - - output_buffer - } + // (7) apply H to the stream generated in step (6) and output + // the result + let oh = sha256_digest(&s5, 3 * SHA256_DIGEST_LEN); - pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLen { - // implementation of HMAC as per RFC2104 - - const IPAD: [u8; 64] = [0x36; 64]; - const OPAD: [u8; 64] = [0x5C; 64]; - - // (1) append zeros to the end of K to create a B byte string - // (e.g., if K is of length 20 bytes and B=64, then K will be - // appended with 44 zero bytes 0x00) - let mut b: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - b[0..SHA256_DIGEST_LEN].copy_from_slice(&key[..]); - - // (2) XOR (bitwise exclusive-OR) the B byte string computed in step - // (1) with ipad - let mut s2: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - for i in 0..64 { - s2[i] = b[i] ^ IPAD[i]; - } - - // (3) append the stream of data 'text' to the B byte string resulting - // from step (2) - s2[64..64 + message.len()].copy_from_slice(message); - - // (4) apply H to the stream generated in step (3) - let ih = sha256_digest(&s2, 64 + message.len()); - - // (5) XOR (bitwise exclusive-OR) the B byte string computed in - // step (1) with opad - let mut s5: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; - for i in 0..64 { - s5[i] = b[i] ^ OPAD[i]; - } - // (6) append the H result from step (4) to the B byte string - // resulting from step (5) - s5[64..64 + SHA256_DIGEST_LEN].copy_from_slice(&ih); - - // (7) apply H to the stream generated in step (6) and output - // the result - let oh = sha256_digest(&s5, 3 * SHA256_DIGEST_LEN); - - oh - } + oh +} - pub fn get_random_byte() -> u8 { - psa_crypto::init().unwrap(); - let mut buffer = [0u8; 1]; - generate_random(&mut buffer); // TODO: check return value - buffer[0] - } +pub fn get_random_byte() -> u8 { + psa_crypto::init().unwrap(); + let mut buffer = [0u8; 1]; + generate_random(&mut buffer); // TODO: check return value + buffer[0] +} - pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = UsageFlags::default(); - usage_flags.set_export(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - - let key_id = key_management::generate(attributes, None).unwrap(); - let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - key_management::export(key_id, &mut private_key).unwrap(); - - let mut public_key: [u8; P256_ELEM_LEN * 2 + 1] = [0; P256_ELEM_LEN * 2 + 1]; // allocate buffer for: sign, x, and y coordinates - key_management::export_public(key_id, &mut public_key).unwrap(); - let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // return only the x coordinate - - (private_key, public_key) - } +pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { + let alg = RawKeyAgreement::Ecdh; + let mut usage_flags: UsageFlags = UsageFlags::default(); + usage_flags.set_export(); + usage_flags.set_derive(); + let attributes = Attributes { + key_type: Type::EccKeyPair { + curve_family: EccFamily::SecpR1, + }, + bits: 256, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: KeyAgreement::Raw(alg).into(), + }, + }; + + psa_crypto::init().unwrap(); + + let key_id = key_management::generate(attributes, None).unwrap(); + let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; + key_management::export(key_id, &mut private_key).unwrap(); + + let mut public_key: [u8; P256_ELEM_LEN * 2 + 1] = [0; P256_ELEM_LEN * 2 + 1]; // allocate buffer for: sign, x, and y coordinates + key_management::export_public(key_id, &mut public_key).unwrap(); + let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // return only the x coordinate + + (private_key, public_key) } #[cfg(test)] @@ -583,10 +295,10 @@ mod tests { 0xd0, 0xe6, 0x55, 0xa3, ]; - let result_1 = hmac_sha256(&MESSAGE_1, KEY).to_public_array(); + let result_1 = hmac_sha256(&MESSAGE_1, &KEY); assert_eq!(result_1, RESULT_1_TV); - let result_2 = hmac_sha256(&MESSAGE_2, KEY).to_public_array(); + let result_2 = hmac_sha256(&MESSAGE_2, &KEY); assert_eq!(result_2, RESULT_2_TV); } } From 7ee0f1e7ac7ac43fd1b5ddeaf8adf9b5cbe9ab47 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 10:34:59 +0200 Subject: [PATCH 06/16] refactor: remove U8 aliases in non-hacspec code --- consts/src/lib.rs | 1 - lib/src/edhoc.rs | 46 +++++++++++++++++++++++----------------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/consts/src/lib.rs b/consts/src/lib.rs index 3d13112d..3eb85b28 100644 --- a/consts/src/lib.rs +++ b/consts/src/lib.rs @@ -52,7 +52,6 @@ mod consts { mod structs { use super::consts::*; - pub type U8 = u8; // TODO: remove pub type BytesEad2 = [u8; 0]; pub type BytesIdCred = [u8; ID_CRED_LEN]; pub type BytesSuites = [u8; SUITES_LEN]; diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 8c12a296..0de1eb79 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -6,7 +6,7 @@ use edhoc_ead::*; pub fn edhoc_exporter( state: State, - label: U8, + label: u8, context: &BytesMaxContextBuffer, context_len: usize, length: usize, @@ -178,8 +178,8 @@ pub fn r_prepare_message_2( r: &BytesP256ElemLen, // R's static private DH key y: BytesP256ElemLen, g_y: BytesP256ElemLen, - c_r: U8, -) -> Result<(State, BufferMessage2, U8), EDHOCError> { + c_r: u8, +) -> Result<(State, BufferMessage2, u8), EDHOCError> { let State( mut current_state, mut _y, @@ -381,7 +381,7 @@ pub fn i_prepare_message_1( mut state: State, x: BytesP256ElemLen, g_x: BytesP256ElemLen, - c_i: U8, + c_i: u8, ) -> Result<(State, BufferMessage1), EDHOCError> { let State( mut current_state, @@ -456,7 +456,7 @@ pub fn i_process_message_2( cred_r_len: usize, g_r: &BytesP256ElemLen, // R's static public DH key i: &BytesP256ElemLen, // I's static private DH key -) -> Result<(State, U8, U8), EDHOCError> { +) -> Result<(State, u8, u8), EDHOCError> { let State( mut current_state, x, @@ -649,7 +649,7 @@ pub fn i_prepare_message_3( pub fn construct_state( state: EDHOCState, x_or_y: BytesP256ElemLen, - c_i: U8, + c_i: u8, gx_or_gy: BytesP256ElemLen, prk_3e2m: BytesHashLen, prk_4e3m: BytesHashLen, @@ -674,37 +674,37 @@ pub fn construct_state( /// Check for: an unsigned integer encoded as a single byte #[inline(always)] -fn is_cbor_uint_1byte(byte: U8) -> bool { +fn is_cbor_uint_1byte(byte: u8) -> bool { return byte >= CBOR_UINT_1BYTE_START && byte <= CBOR_UINT_1BYTE_END; } /// Check for: an unsigned integer encoded as two bytes #[inline(always)] -fn is_cbor_uint_2bytes(byte: U8) -> bool { +fn is_cbor_uint_2bytes(byte: u8) -> bool { return byte == CBOR_UINT_1BYTE; } /// Check for: a negative integer encoded as a single byte #[inline(always)] -fn is_cbor_neg_int_1byte(byte: U8) -> bool { +fn is_cbor_neg_int_1byte(byte: u8) -> bool { return byte >= CBOR_NEG_INT_1BYTE_START && byte <= CBOR_NEG_INT_1BYTE_END; } /// Check for: a bstr denoted by a single byte which encodes both type and content length #[inline(always)] -fn is_cbor_bstr_1byte_prefix(byte: U8) -> bool { +fn is_cbor_bstr_1byte_prefix(byte: u8) -> bool { return byte >= CBOR_MAJOR_BYTE_STRING && byte <= CBOR_MAJOR_BYTE_STRING_MAX; } /// Check for: a bstr denoted by two bytes, onr for type the other for content length #[inline(always)] -fn is_cbor_bstr_2bytes_prefix(byte: U8) -> bool { +fn is_cbor_bstr_2bytes_prefix(byte: u8) -> bool { return byte == CBOR_BYTE_STRING; } /// Check for: an array denoted by a single byte which encodes both type and content length #[inline(always)] -fn is_cbor_array_1byte_prefix(byte: U8) -> bool { +fn is_cbor_array_1byte_prefix(byte: u8) -> bool { return byte >= CBOR_MAJOR_ARRAY && byte <= CBOR_MAJOR_ARRAY_MAX; } @@ -819,17 +819,17 @@ fn parse_message_1( rcvd_message_1: &BufferMessage1, ) -> Result< ( - U8, + u8, BytesSuites, usize, BytesP256ElemLen, - U8, + u8, Option, ), EDHOCError, > { let mut error: EDHOCError = EDHOCError::UnknownError; - let mut method: U8 = 0xff; + let mut method: u8 = 0xff; let mut g_x: BytesP256ElemLen = [0x00; P256_ELEM_LEN]; let mut suites_i: BytesSuites = [0u8; SUITES_LEN]; let mut suites_i_len: usize = 0; @@ -910,11 +910,11 @@ fn encode_ead_item(ead_1: &EADItem) -> EdhocMessageBuffer { } fn encode_message_1( - method: U8, + method: u8, suites: &BytesSuites, suites_len: usize, g_x: &BytesP256ElemLen, - c_i: U8, + c_i: u8, ead_1: &Option, ) -> BufferMessage1 { let mut output = BufferMessage1::new(); @@ -1070,7 +1070,7 @@ fn compute_th_4( fn edhoc_kdf( prk: &BytesHashLen, - label: U8, + label: u8, context: &BytesMaxContextBuffer, context_len: usize, length: usize, @@ -1106,7 +1106,7 @@ fn edhoc_kdf( fn decode_plaintext_3( plaintext_3: &BufferPlaintext3, -) -> Result<(U8, BytesMac3, Option), EDHOCError> { +) -> Result<(u8, BytesMac3, Option), EDHOCError> { let mut ead_3 = None::; let mut error = EDHOCError::UnknownError; let mut kid: u8 = 0xff; @@ -1338,11 +1338,11 @@ fn compute_mac_2( fn decode_plaintext_2( plaintext_2: &BytesMaxBuffer, plaintext_2_len: usize, -) -> Result<(U8, U8, BytesMac2, Option), EDHOCError> { +) -> Result<(u8, u8, BytesMac2, Option), EDHOCError> { let mut error = EDHOCError::UnknownError; let mut ead_2 = None::; - let mut c_r: U8 = 0xff; - let mut id_cred_r: U8 = 0xff; + let mut c_r: u8 = 0xff; + let mut id_cred_r: u8 = 0xff; let mut mac_2: BytesMac2 = [0x00; MAC_LENGTH_2]; // check CBOR sequence types for c_r, id_cred_r, and mac_2 @@ -1386,7 +1386,7 @@ fn decode_plaintext_2( } fn encode_plaintext_2( - c_r: U8, + c_r: u8, id_cred_r: &BytesIdCred, mac_2: &BytesMac2, ead_2: &Option, From de4bee337fe0c7df75cbd69cb588c561d1652037 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 10:43:01 +0200 Subject: [PATCH 07/16] fix: adjust ci for fstar --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index cf5128b1..2ff21ff2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -91,7 +91,7 @@ jobs: - name: Generate fstar run: | - docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs/hacspec && cargo-hax -C --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-psa, ead-none" --release \; into fstar" + docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs/ && cargo-hax -C --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-psa, ead-none" --release \; into fstar" zip -j -r edhoc-rs-fstar.zip $(find . -name *fst) - name: Upload artifact From 19fd669611f8f550ffb46a3c321616e6532b0bad Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 12:12:06 +0200 Subject: [PATCH 08/16] feat: enable rust-hacscpec configuration --- .github/workflows/build-and-test.yml | 3 - crypto/edhoc-crypto-hacspec/src/lib.rs | 149 ++++++++++++++++++++----- crypto/edhoc-crypto-psa/src/lib.rs | 6 +- lib/Cargo.toml | 1 + 4 files changed, 122 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2ff21ff2..ff1835dc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -76,9 +76,6 @@ jobs: - name: Checkout edhoc-rs uses: actions/checkout@v3 - # - name: Patch edhoc-rs features - # run: git apply ./hacspec/adjust_features_for_hax.patch - - name: Checkout hacspec-v2 uses: actions/checkout@v3 with: diff --git a/crypto/edhoc-crypto-hacspec/src/lib.rs b/crypto/edhoc-crypto-hacspec/src/lib.rs index 13c312b5..350fe741 100644 --- a/crypto/edhoc-crypto-hacspec/src/lib.rs +++ b/crypto/edhoc-crypto-hacspec/src/lib.rs @@ -9,9 +9,74 @@ use hacspec_p256::*; use hacspec_sha256::*; use rand::Rng; +// Types and functions to aid in translation between the hacspec and non-hacspec world + +// TODO: the `array!` construct is not needed anymore. +// Ideally this should be: `type BytesCcmKeyLen = [u8; AES_CCM_KEY_LEN];` +// However, it is not clear how to implement the equivalents to `from_public_slice` and friends +// when using the normal array construct. +array!(BytesCcmKeyLenHacspec, AES_CCM_KEY_LEN, U8); +array!(BytesCcmIvLenHacspec, AES_CCM_IV_LEN, U8); +array!(BytesHashLenHacspec, SHA256_DIGEST_LEN, U8); +array!(BytesP256ElemLenHacspec, P256_ELEM_LEN, U8); +array!(BytesMaxBufferHacspec, MAX_BUFFER_LEN, U8); +array!(BytesMaxInfoBufferHacspec, MAX_INFO_LEN, U8); +array!(BytesEncStructureLenHacspec, ENC_STRUCTURE_LEN, U8); + +array!(BytesMessageBuffer, MAX_MESSAGE_SIZE_LEN, U8); + +#[derive(Debug)] +pub struct EdhocMessageBufferHacspec { + pub content: BytesMessageBuffer, + pub len: usize, +} + +pub trait MessageBufferHacspecTrait { + fn new() -> Self; + fn from_public_buffer(buffer: &EdhocMessageBuffer) -> Self; + fn from_seq(buffer: &Seq) -> Self; + fn to_public_buffer(&self) -> EdhocMessageBuffer; +} + +impl MessageBufferHacspecTrait for EdhocMessageBufferHacspec { + fn new() -> Self { + EdhocMessageBufferHacspec { + content: BytesMessageBuffer::new(), + len: 0, + } + } + fn from_public_buffer(buffer: &EdhocMessageBuffer) -> Self { + let mut hacspec_buffer = EdhocMessageBufferHacspec::new(); + hacspec_buffer.len = buffer.len; + hacspec_buffer.content = BytesMessageBuffer::from_public_slice(&buffer.content[..]); + hacspec_buffer + } + fn from_seq(buffer: &Seq) -> Self { + EdhocMessageBufferHacspec { + content: BytesMessageBuffer::from_slice(buffer, 0, buffer.len()), + len: buffer.len(), + } + } + fn to_public_buffer(&self) -> EdhocMessageBuffer { + let mut buffer = EdhocMessageBuffer::new(); + buffer.content = self.content.to_public_array(); + buffer.len = self.len; + buffer + } +} + +type BufferCiphertext3Hacspec = EdhocMessageBufferHacspec; +type BufferPlaintext3Hacspec = EdhocMessageBufferHacspec; + +// Public functions + pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let output = BytesHashLen::from_seq(&hash(&ByteSeq::from_slice(message, 0, message_len))); - output + let message: BytesMaxBufferHacspec = BytesMaxBufferHacspec::from_public_slice(message); + + let output = + BytesHashLenHacspec::from_seq(&hash(&ByteSeq::from_slice(&message, 0, message_len))); + + output.to_public_array() } pub fn hkdf_expand( @@ -20,25 +85,33 @@ pub fn hkdf_expand( info_len: usize, length: usize, ) -> BytesMaxBuffer { - let mut output = BytesMaxBuffer::new(); + let mut output = BytesMaxBufferHacspec::new(); output = output.update( 0, &expand( - &ByteSeq::from_slice(prk, 0, prk.len()), - &ByteSeq::from_slice(info, 0, info_len), + &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(prk), 0, prk.len()), + &ByteSeq::from_slice( + &BytesMaxInfoBufferHacspec::from_public_slice(info), + 0, + info_len, + ), length, ) .unwrap(), ); - output + output.to_public_array() } pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - let output = BytesHashLen::from_seq(&extract( - &ByteSeq::from_slice(salt, 0, salt.len()), - &ByteSeq::from_slice(ikm, 0, ikm.len()), + let output = BytesHashLenHacspec::from_seq(&extract( + &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(salt), 0, salt.len()), + &ByteSeq::from_slice( + &BytesP256ElemLenHacspec::from_public_slice(ikm), + 0, + ikm.len(), + ), )); - output + output.to_public_array() } pub fn aes_ccm_encrypt_tag_8( @@ -47,15 +120,21 @@ pub fn aes_ccm_encrypt_tag_8( ad: &BytesEncStructureLen, plaintext: &BufferPlaintext3, ) -> BufferCiphertext3 { - let output = BufferCiphertext3::from_seq(&encrypt_ccm( - ByteSeq::from_slice(ad, 0, ad.len()), - ByteSeq::from_slice(iv, 0, iv.len()), + let plaintext = BufferPlaintext3Hacspec::from_public_buffer(plaintext); + + let output = BufferCiphertext3Hacspec::from_seq(&encrypt_ccm( + ByteSeq::from_slice( + &BytesEncStructureLenHacspec::from_public_slice(ad), + 0, + ad.len(), + ), + ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), ByteSeq::from_slice(&plaintext.content, 0, plaintext.len), - Key128::from_slice(key, 0, key.len()), + Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), AES_CCM_TAG_LEN, )); - output + output.to_public_buffer() } pub fn aes_ccm_decrypt_tag_8( @@ -64,15 +143,21 @@ pub fn aes_ccm_decrypt_tag_8( ad: &BytesEncStructureLen, ciphertext: &BufferCiphertext3, ) -> Result { + let ciphertext = BufferCiphertext3Hacspec::from_public_buffer(ciphertext); + match decrypt_ccm( - ByteSeq::from_slice(ad, 0, ad.len()), - ByteSeq::from_slice(iv, 0, iv.len()), - Key128::from_slice(key, 0, key.len()), + ByteSeq::from_slice( + &BytesEncStructureLenHacspec::from_public_slice(ad), + 0, + ad.len(), + ), + ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), + Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), ByteSeq::from_slice(&ciphertext.content, 0, ciphertext.len), ciphertext.len, AES_CCM_TAG_LEN, ) { - Ok(p) => Ok(BufferPlaintext3::from_seq(&p)), + Ok(p) => Ok(BufferPlaintext3Hacspec::from_seq(&p).to_public_buffer()), Err(_) => Err(EDHOCError::MacVerificationFailed), } } @@ -81,28 +166,32 @@ pub fn p256_ecdh( private_key: &BytesP256ElemLen, public_key: &BytesP256ElemLen, ) -> BytesP256ElemLen { - let scalar = P256Scalar::from_byte_seq_be(private_key); + let private_key = BytesP256ElemLenHacspec::from_public_slice(private_key); + let public_key = BytesP256ElemLenHacspec::from_public_slice(public_key); + + let scalar = P256Scalar::from_byte_seq_be(&private_key); let point = ( - P256FieldElement::from_byte_seq_be(public_key), - p256_calculate_w(P256FieldElement::from_byte_seq_be(public_key)), + P256FieldElement::from_byte_seq_be(&public_key), + p256_calculate_w(P256FieldElement::from_byte_seq_be(&public_key)), ); // we only care about the x coordinate let (x, _y) = p256_point_mul(scalar, point).unwrap(); - let secret = BytesP256ElemLen::from_seq(&x.to_byte_seq_be()); - secret + let secret = BytesP256ElemLenHacspec::from_seq(&x.to_byte_seq_be()); + + secret.to_public_array() } #[cfg(not(feature = "hacspec-pure"))] -pub fn get_random_byte() -> U8 { - U8(rand::thread_rng().gen::()) +pub fn get_random_byte() -> u8 { + rand::thread_rng().gen::() } #[cfg(not(feature = "hacspec-pure"))] pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { // generate a private key - let mut private_key = BytesP256ElemLen::new(); + let mut private_key = BytesP256ElemLenHacspec::new(); loop { for i in 0..private_key.len() { private_key[i] = U8(rand::thread_rng().gen::()); @@ -115,9 +204,9 @@ pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { // obtain the corresponding public key let scalar = P256Scalar::from_byte_seq_be(&private_key); let public_key_point = p256_point_mul_base(scalar).unwrap(); - let public_key = BytesP256ElemLen::from_seq(&public_key_point.0.to_byte_seq_be()); + let public_key = BytesP256ElemLenHacspec::from_seq(&public_key_point.0.to_byte_seq_be()); - (private_key, public_key) + (private_key.to_public_array(), public_key.to_public_array()) } #[cfg(test)] @@ -135,6 +224,6 @@ mod tests { let g_xy = p256_ecdh(&x, &g_y); let g_yx = p256_ecdh(&y, &g_x); - assert_bytes_eq!(g_xy, g_yx); + assert_eq!(g_xy, g_yx); } } diff --git a/crypto/edhoc-crypto-psa/src/lib.rs b/crypto/edhoc-crypto-psa/src/lib.rs index 25762fdd..938ba1dc 100644 --- a/crypto/edhoc-crypto-psa/src/lib.rs +++ b/crypto/edhoc-crypto-psa/src/lib.rs @@ -57,8 +57,7 @@ pub fn hkdf_expand( for i in 2..n { message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len] - .copy_from_slice(&info[..info_len]); + message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len].copy_from_slice(&info[..info_len]); message[SHA256_DIGEST_LEN + info_len] = i as u8; t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk); output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); @@ -189,8 +188,7 @@ pub fn p256_ecdh( let my_key = key_management::import(attributes, None, private_key).unwrap(); let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer) - .unwrap(); + key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer).unwrap(); output_buffer } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 15503fa1..c7cfbf94 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -21,6 +21,7 @@ cbindgen = "0.24.5" [features] default = [ "edhoc-ead/ead-none" ] +rust-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ] rust-psa = [ "edhoc-consts/rust", "edhoc-crypto/psa-rust" ] rust-psa-baremetal = [ "edhoc-crypto/psa-rust-baremetal", "edhoc-consts/rust", "panic-semihosting" ] rust-cryptocell310 = [ "edhoc-consts/rust", "edhoc-crypto/cryptocell310-rust", "panic-semihosting" ] From 96995748797f7d5cce0da9f74e6dda928112e625 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sat, 30 Sep 2023 12:31:02 +0200 Subject: [PATCH 09/16] feat!: Allow applications to pick their C_x The change allows applications to pick usable C_x (i.e., C_I and C_R) values, which they are in a position to decide, because unlike the EDHOC library, they keep track of all the ongoing exchanges. The c_wrapper API is *not* changed at this point, because the API change would be way too subtle (the "out" parameter would be changed to an "in" parameter). BREAKING CHANGE: This alters the message 1 and 2 API. --- examples/coap/src/bin/coapclient.rs | 3 ++- examples/coap/src/bin/coapserver.rs | 3 ++- examples/edhoc-rs-no_std/src/main.rs | 11 +++++++---- lib/src/c_wrapper.rs | 10 ++++++---- lib/src/edhoc.rs | 4 ++-- lib/src/lib.rs | 27 ++++++++++++++++----------- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/examples/coap/src/bin/coapclient.rs b/examples/coap/src/bin/coapclient.rs index 275074d8..353a01e4 100644 --- a/examples/coap/src/bin/coapclient.rs +++ b/examples/coap/src/bin/coapclient.rs @@ -23,7 +23,8 @@ fn main() { // Send Message 1 over CoAP and convert the response to byte let mut msg_1_buf = Vec::from([0xf5u8]); // EDHOC message_1 when transported over CoAP is prepended with CBOR true - let message_1 = initiator.prepare_message_1().unwrap(); + let c_i = generate_connection_identifier_cbor(); + let message_1 = initiator.prepare_message_1(c_i).unwrap(); msg_1_buf.extend_from_slice(&message_1.content[..message_1.len]); println!("message_1 len = {}", msg_1_buf.len()); diff --git a/examples/coap/src/bin/coapserver.rs b/examples/coap/src/bin/coapserver.rs index 08344ef8..28337b18 100644 --- a/examples/coap/src/bin/coapserver.rs +++ b/examples/coap/src/bin/coapserver.rs @@ -40,7 +40,8 @@ fn main() { ); if error.is_ok() { - let (message_2, c_r) = responder.prepare_message_2().unwrap(); + let c_r = generate_connection_identifier_cbor(); + let message_2 = responder.prepare_message_2(c_r).unwrap(); response.message.payload = Vec::from(&message_2.content[..message_2.len]); // save edhoc connection edhoc_connections.push((c_r, responder)); diff --git a/examples/edhoc-rs-no_std/src/main.rs b/examples/edhoc-rs-no_std/src/main.rs index 23d913fb..a1026e28 100644 --- a/examples/edhoc-rs-no_std/src/main.rs +++ b/examples/edhoc-rs-no_std/src/main.rs @@ -99,7 +99,8 @@ fn main() -> ! { let mut initiator = EdhocInitiator::new(state, I, G_R, ID_CRED_I, CRED_I, ID_CRED_R, CRED_R); - let message_1 = initiator.prepare_message_1(); + let c_i: u8 = generate_connection_identifier_cbor().into(); + let message_1 = initiator.prepare_message_1(c_i); assert!(message_1.is_ok()); } @@ -128,16 +129,18 @@ fn main() -> ! { CRED_R, ); - let ret = initiator.prepare_message_1(); // to update the state + let c_i: u8 = generate_connection_identifier_cbor().into(); + let ret = initiator.prepare_message_1(c_i); // to update the state assert!(ret.is_ok()); let message_1 = ret.unwrap(); let ret = responder.process_message_1(&message_1); assert!(ret.is_ok()); - let ret = responder.prepare_message_2(); + let c_r: u8 = generate_connection_identifier_cbor().into(); + let ret = responder.prepare_message_2(c_r); assert!(ret.is_ok()); - let (message_2, c_r) = ret.unwrap(); + let message_2 = ret.unwrap(); assert!(c_r != 0xff); let _c_r = initiator.process_message_2(&message_2); diff --git a/lib/src/c_wrapper.rs b/lib/src/c_wrapper.rs index cce7d04f..1ea2e54f 100644 --- a/lib/src/c_wrapper.rs +++ b/lib/src/c_wrapper.rs @@ -158,7 +158,8 @@ pub unsafe extern "C" fn initiator_prepare_message_1( ) -> i8 { let mut initiator = (*initiator_c).to_rust(); - let result = match initiator.prepare_message_1() { + let c_i: u8 = generate_connection_identifier_cbor().into(); + let result = match initiator.prepare_message_1(c_i) { Ok(msg_1) => { *message_1 = msg_1; 0 @@ -196,10 +197,11 @@ pub unsafe extern "C" fn responder_prepare_message_2( ) -> i8 { let mut responder = (*responder_c).to_rust(); - let result = match responder.prepare_message_2() { - Ok((msg_2, c_r_res)) => { + let c_r_chosen: u8 = generate_connection_identifier_cbor().into(); + let result = match responder.prepare_message_2(c_r_chosen) { + Ok(msg_2) => { *message_2 = msg_2; - *c_r = c_r_res; + *c_r = c_r_chosen; 0 } Err(err) => err as i8, diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 0de1eb79..3f79f3d7 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -179,7 +179,7 @@ pub fn r_prepare_message_2( y: BytesP256ElemLen, g_y: BytesP256ElemLen, c_r: u8, -) -> Result<(State, BufferMessage2, u8), EDHOCError> { +) -> Result<(State, BufferMessage2), EDHOCError> { let State( mut current_state, mut _y, @@ -247,7 +247,7 @@ pub fn r_prepare_message_2( } match error { - EDHOCError::Success => Ok((state, message_2, c_r)), + EDHOCError::Success => Ok((state, message_2)), _ => Err(error), } } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index ca03faf0..2d98c958 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -95,12 +95,12 @@ impl<'a> EdhocResponderState<'a> { pub fn prepare_message_2( self: &mut EdhocResponderState<'a>, - ) -> Result<(BufferMessage2, u8), EDHOCError> { + c_r: u8, + ) -> Result { let mut cred_r: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; hex::decode_to_slice(self.cred_r, &mut cred_r[..self.cred_r.len() / 2]) .expect("Decoding failed"); let (y, g_y) = edhoc_crypto::p256_generate_key_pair(); - let c_r = generate_connection_identifier_cbor(); match r_prepare_message_2( self.state, @@ -112,9 +112,9 @@ impl<'a> EdhocResponderState<'a> { g_y, c_r, ) { - Ok((state, message_2, c_r)) => { + Ok((state, message_2)) => { self.state = state; - Ok((message_2, c_r)) + Ok(message_2) } Err(error) => Err(error), } @@ -225,9 +225,9 @@ impl<'a> EdhocInitiatorState<'a> { pub fn prepare_message_1( self: &mut EdhocInitiatorState<'a>, + c_i: u8, ) -> Result { let (x, g_x) = edhoc_crypto::p256_generate_key_pair(); - let c_i = generate_connection_identifier_cbor(); match i_prepare_message_1(self.state, x, g_x, c_i) { Ok((state, message_1)) => { @@ -380,7 +380,8 @@ mod test { let mut initiator = EdhocInitiator::new(state, I, G_R, ID_CRED_I, CRED_I, ID_CRED_R, CRED_R); - let message_1 = initiator.prepare_message_1(); + let c_i = generate_connection_identifier_cbor(); + let message_1 = initiator.prepare_message_1(c_i); assert!(message_1.is_ok()); } @@ -431,16 +432,18 @@ mod test { CRED_R, ); - let result = initiator.prepare_message_1(); // to update the state + let c_i: u8 = generate_connection_identifier_cbor(); + let result = initiator.prepare_message_1(c_i); // to update the state assert!(result.is_ok()); let error = responder.process_message_1(&result.unwrap()); assert!(error.is_ok()); - let ret = responder.prepare_message_2(); + let c_r = generate_connection_identifier_cbor(); + let ret = responder.prepare_message_2(c_r); assert!(ret.is_ok()); - let (message_2, c_r) = ret.unwrap(); + let message_2 = ret.unwrap(); assert!(c_r != 0xff); let _c_r = initiator.process_message_2(&message_2); @@ -524,7 +527,8 @@ mod test { EADResponderProtocolState::Start ); - let message_1 = initiator.prepare_message_1().unwrap(); + let c_i = generate_connection_identifier_cbor(); + let message_1 = initiator.prepare_message_1(c_i).unwrap(); assert_eq!( ead_initiator_state.protocol_state, EADInitiatorProtocolState::WaitEAD2 @@ -536,7 +540,8 @@ mod test { EADResponderProtocolState::ProcessedEAD1 ); - let (message_2, _c_r) = responder.prepare_message_2().unwrap(); + let c_r = generate_connection_identifier_cbor(); + let message_2 = responder.prepare_message_2(c_r).unwrap(); assert_eq!( ead_responder_state.protocol_state, EADResponderProtocolState::Completed From a0f44fe8e350b9aa0ad906b87eba4b62ccc946fe Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 14:05:22 +0200 Subject: [PATCH 10/16] feat: update ci --- .github/workflows/build-and-test.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ff1835dc..7f9a81e7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -27,19 +27,15 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [rust] crypto: [hacspec, psa] ead: [ead-none, ead-zeroconf] - exclude: - - edhoc_lib: rust - crypto: hacspec steps: - name: Checkout repo uses: actions/checkout@v3 - name: Run unit tests # note that we only add `--package edhoc-hacspec` when testing the hacspec version of the lib - run: cargo test --package edhoc-rs --package edhoc-crypto --package edhoc-ead ${{ matrix.edhoc_lib == 'hacspec' && '--package edhoc-hacspec' || '' }} --no-default-features --features="${{ matrix.edhoc_lib }}-${{ matrix.crypto }}, ${{ matrix.ead }}" --no-fail-fast + run: cargo test --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}" --no-fail-fast build-edhoc-package: @@ -49,12 +45,8 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [rust] crypto: [hacspec, psa, psa-baremetal, cryptocell310] ead: [ead-none, ead-zeroconf] - exclude: - - edhoc_lib: rust - crypto: hacspec steps: - name: Checkout repo @@ -66,7 +58,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build - run: cargo build --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="${{ matrix.edhoc_lib }}-${{ matrix.crypto }}, ${{ matrix.ead }}" --release + run: cargo build --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}" --release generate-fstar: @@ -105,7 +97,6 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [rust] crypto: [psa-baremetal, cryptocell310] steps: @@ -118,7 +109,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build static library, generate headers, and zip to file - run: ./build_for_c.sh "${{ matrix.edhoc_lib }}-${{ matrix.crypto }}" + run: ./build_for_c.sh "rust-${{ matrix.crypto }}" - name: Upload artifact uses: actions/upload-artifact@v3 @@ -159,7 +150,6 @@ jobs: strategy: fail-fast: false matrix: - edhoc_lib: [rust] crypto: [psa, cryptocell310] ead: [ead-none, ead-zeroconf] @@ -173,7 +163,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build example - run: cd examples/edhoc-rs-no_std && cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="${{ matrix.edhoc_lib }}-${{ matrix.crypto }}, ${{ matrix.ead }}, rtt" --release + run: cd examples/edhoc-rs-no_std && cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}, rtt" --release build-coap-example: From 2238f9fbc13118b1894e35bfb98fd6ea52ca5665 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Tue, 3 Oct 2023 14:49:43 +0200 Subject: [PATCH 11/16] refactor: rename features Since hacspec was removed, any feature with 'rust' in the name became obsolete. Before this, a feature like rust-psa would select library version and crypto backend. Now, we have features like cb-psa, which select only the crypto backend. --- .github/workflows/build-and-test.yml | 24 +++++++++---------- README.md | 2 +- build_for_c.sh | 6 ++--- consts/Cargo.toml | 8 ------- crypto/Cargo.toml | 7 ++---- .../edhoc-crypto-cryptocell310-sys/Cargo.toml | 5 ---- crypto/edhoc-crypto-hacspec/Cargo.toml | 2 +- crypto/edhoc-crypto-psa/Cargo.toml | 3 --- examples/c-wrapper-riot/Makefile | 6 ++--- examples/c-wrapper-riot/README.md | 8 +++---- examples/c-wrapper-riot/main.c | 4 ++-- examples/coap/Cargo.toml | 2 +- examples/edhoc-rs-cc2538/Cargo.toml | 2 +- examples/edhoc-rs-no_std/Cargo.toml | 4 ++-- examples/edhoc-rs-no_std/src/main.rs | 14 ++++------- lib/Cargo.toml | 10 ++++---- lib/src/c_wrapper.rs | 2 +- 17 files changed, 43 insertions(+), 66 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7f9a81e7..30cafee7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - crypto: [hacspec, psa] + crypto_backend: [cb-hacspec, cb-psa] ead: [ead-none, ead-zeroconf] steps: @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@v3 - name: Run unit tests # note that we only add `--package edhoc-hacspec` when testing the hacspec version of the lib - run: cargo test --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}" --no-fail-fast + run: cargo test --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}" --no-fail-fast build-edhoc-package: @@ -45,7 +45,7 @@ jobs: strategy: fail-fast: false matrix: - crypto: [hacspec, psa, psa-baremetal, cryptocell310] + crypto_backend: [cb-hacspec, cb-psa, cb-psa-baremetal, cb-cryptocell310] ead: [ead-none, ead-zeroconf] steps: @@ -58,7 +58,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build - run: cargo build --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}" --release + run: cargo build --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}" --release generate-fstar: @@ -78,9 +78,9 @@ jobs: run: docker build -f .docker/Dockerfile . -t hacspec-v2 working-directory: hacspec-v2-repo - - name: Generate fstar + - name: Generate fstar code using the main library and the hacspec crypto backend run: | - docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs/ && cargo-hax -C --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="rust-psa, ead-none" --release \; into fstar" + docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs && cargo-hax -C -p edhoc-rs -p edhoc-crypto -p edhoc-ead --no-default-features --features='cb-hacspec, ead-none' --release \; into fstar" zip -j -r edhoc-rs-fstar.zip $(find . -name *fst) - name: Upload artifact @@ -97,7 +97,7 @@ jobs: strategy: fail-fast: false matrix: - crypto: [psa-baremetal, cryptocell310] + crypto_backend: [cb-psa-baremetal, cb-cryptocell310] steps: - name: Checkout repo @@ -109,7 +109,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build static library, generate headers, and zip to file - run: ./build_for_c.sh "rust-${{ matrix.crypto }}" + run: ./build_for_c.sh "${{ matrix.crypto_backend }}" - name: Upload artifact uses: actions/upload-artifact@v3 @@ -125,7 +125,7 @@ jobs: strategy: fail-fast: false matrix: - config: [rust-psa] + crypto_backend: [cb-psa] ead: [ead-none, ead-zeroconf] steps: @@ -140,7 +140,7 @@ jobs: run: sudo apt-get -y install qemu-system-arm - name: Run tests in QEMU - run: cd examples/edhoc-rs-no_std && cargo run --target="thumbv7m-none-eabi" --no-default-features --features="${{ matrix.config }}, ${{ matrix.ead }}" --release + run: cd examples/edhoc-rs-no_std && cargo run --target="thumbv7m-none-eabi" --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}" --release build-example-for-cortex-m4: @@ -150,7 +150,7 @@ jobs: strategy: fail-fast: false matrix: - crypto: [psa, cryptocell310] + crypto_backend: [cb-psa, cb-cryptocell310] ead: [ead-none, ead-zeroconf] steps: @@ -163,7 +163,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get -y install gcc-arm-none-eabi - name: Build example - run: cd examples/edhoc-rs-no_std && cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="rust-${{ matrix.crypto }}, ${{ matrix.ead }}, rtt" --release + run: cd examples/edhoc-rs-no_std && cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}, rtt" --release build-coap-example: diff --git a/README.md b/README.md index bb5f6f02..ced5ea00 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ cd ./examples/edhoc-rs-no_std cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="hacspec-psa, rtt" --release # build using the rust version of the lib, and hardware-accelerated crypto -cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="rust-cryptocell310, rtt" +cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="cb-cryptocell310, rtt" ``` To build **and** flash to the board, replace the word `build` with `embed` in the commands above (you may need to `cargo install cargo-embed`). diff --git a/build_for_c.sh b/build_for_c.sh index 006dacb9..0c007709 100755 --- a/build_for_c.sh +++ b/build_for_c.sh @@ -11,9 +11,9 @@ cargo_features=$1 -if [[ $cargo_features != "rust-cryptocell310" && $cargo_features != "rust-psa-baremetal" ]]; then - echo "Select one of: rust-cryptocell310, rust-psa-baremetal" - echo "Example: ./build_static_lib.sh rust-cryptocell310" +if [[ $cargo_features != "cb-cryptocell310" && $cargo_features != "cb-psa-baremetal" ]]; then + echo "Select one of: cb-cryptocell310, cb-psa-baremetal" + echo "Example: ./build_static_lib.sh cb-cryptocell310" exit 1 fi diff --git a/consts/Cargo.toml b/consts/Cargo.toml index d5a82d2e..9d1b8538 100644 --- a/consts/Cargo.toml +++ b/consts/Cargo.toml @@ -6,13 +6,5 @@ authors = ["Mališa Vučinić "] license = "BSD" description = "EDHOC crypto library constants crate" -[dependencies] -hacspec-lib = { version = "0.1.0-beta.1", default-features = false, optional = true } - [build-dependencies] cbindgen = "0.24.5" - -[features] -default = [ ] -hacspec = [ "hacspec-lib/alloc" ] -rust = [ ] diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 5c625a66..7a27aa8c 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -25,9 +25,6 @@ edhoc-crypto-cryptocell310 = { path = "./edhoc-crypto-cryptocell310-sys", option default = [ ] hacspec = [ "edhoc-crypto-hacspec" ] cc2538 = [ "edhoc-crypto-cc2538" ] -psa = [ "edhoc-crypto-psa/hacspec" ] +psa = [ "edhoc-crypto-psa" ] psa-baremetal = [ "psa", "edhoc-crypto-psa/baremetal" ] -psa-rust = [ "edhoc-crypto-psa/rust" ] -psa-rust-baremetal = [ "psa-rust", "edhoc-crypto-psa/baremetal" ] -cryptocell310 = [ "edhoc-crypto-cryptocell310/hacspec" ] -cryptocell310-rust = [ "edhoc-crypto-cryptocell310/rust" ] +cryptocell310 = [ "edhoc-crypto-cryptocell310" ] diff --git a/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml b/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml index 4b5e9480..03739a11 100644 --- a/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml +++ b/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml @@ -9,11 +9,6 @@ links = "nrf_cc310_0.9.13" [dependencies] edhoc-consts = { path = "../../consts" } -hacspec-lib = { version = "0.1.0-beta.1", default-features = false, features = [ "alloc" ], optional = true } [build-dependencies] bindgen = "0.63.0" - -[features] -rust = [ ] -hacspec = [ "hacspec-lib" ] diff --git a/crypto/edhoc-crypto-hacspec/Cargo.toml b/crypto/edhoc-crypto-hacspec/Cargo.toml index e59a361c..df741064 100644 --- a/crypto/edhoc-crypto-hacspec/Cargo.toml +++ b/crypto/edhoc-crypto-hacspec/Cargo.toml @@ -7,7 +7,7 @@ license = "BSD" description = "EDHOC crypto library hacspec backend" [dependencies] -edhoc-consts = { path = "../../consts", default-features = false, features = ["hacspec"] } +edhoc-consts = { path = "../../consts", default-features = false } hacspec-lib = { version = "0.1.0-beta.1", default-features = false } hacspec-p256 = { version = "0.1.0" } hacspec-hkdf = { version = "0.1.0" } diff --git a/crypto/edhoc-crypto-psa/Cargo.toml b/crypto/edhoc-crypto-psa/Cargo.toml index 1716cdc2..d3df8a5e 100644 --- a/crypto/edhoc-crypto-psa/Cargo.toml +++ b/crypto/edhoc-crypto-psa/Cargo.toml @@ -8,10 +8,7 @@ description = "EDHOC crypto library PSA backend" [dependencies] edhoc-consts = { path = "../../consts" } -hacspec-lib = { version = "0.1.0-beta.1", default-features = false, features = [ "alloc" ], optional = true } psa-crypto = { version = "0.9.2" } [features] baremetal = [ "psa-crypto/baremetal" ] -hacspec = [ "hacspec-lib" ] -rust = [ ] diff --git a/examples/c-wrapper-riot/Makefile b/examples/c-wrapper-riot/Makefile index 44e00f6e..a692efea 100644 --- a/examples/c-wrapper-riot/Makefile +++ b/examples/c-wrapper-riot/Makefile @@ -7,13 +7,13 @@ BOARD ?= nrf52840dk INCLUDES += -I$(CURDIR)/../../target/include ARCHIVES += $(CURDIR)/../../target/thumbv7em-none-eabihf/release/libedhoc_rs.a -ifeq ($(EDHOC_CRYPTO), RUST_PSA) +ifeq ($(EDHOC_CRYPTO), CB_PSA) CFLAGS += -D$(EDHOC_CRYPTO) else - CFLAGS += -DRUST_CRYPTOCELL310 + CFLAGS += -DCB_CRYPTOCELL310 endif -# This is actually only needed in the RUST_CRYPTOCELL310 configuration +# This is actually only needed in the CB_CRYPTOCELL310 configuration CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=16384 -DISR_STACKSIZE=16384 USEMODULE += od diff --git a/examples/c-wrapper-riot/README.md b/examples/c-wrapper-riot/README.md index f61e5276..758d16a8 100644 --- a/examples/c-wrapper-riot/README.md +++ b/examples/c-wrapper-riot/README.md @@ -8,21 +8,21 @@ See [Requirements](#requirements) below. First, go to the top level directory and generate the headers and static library: ```bash -./build_for_c.sh rust-cryptocell310 # or rust-psa-baremetal +./build_for_c.sh cb-cryptocell310 # or cb-psa-baremetal ``` Then, compile and flash to the board (default is nRF52840), as shown below. -With `rust-cryptocell310`: +With `cb-cryptocell310`: ```bash make flash term ``` -With `rust-psa-baremetal`: +With `cb-psa-baremetal`: ```bash -make flash term EDHOC_CRYPTO=RUST_PSA +make flash term EDHOC_CRYPTO=CB_PSA ``` # Requirements diff --git a/examples/c-wrapper-riot/main.c b/examples/c-wrapper-riot/main.c index 3c030232..2ee187d0 100644 --- a/examples/c-wrapper-riot/main.c +++ b/examples/c-wrapper-riot/main.c @@ -3,7 +3,7 @@ #include "od.h" #include "edhoc_rs.h" -#ifdef RUST_PSA +#ifdef CB_PSA extern void mbedtls_memory_buffer_alloc_init(uint8_t *buf, size_t len); #endif @@ -20,7 +20,7 @@ int main(void) { puts("Calling edhoc-rs from C!"); -#ifdef RUST_PSA +#ifdef CB_PSA // Memory buffer for mbedtls uint8_t buffer[4096 * 2] = {0}; mbedtls_memory_buffer_alloc_init(buffer, 4096 * 2); diff --git a/examples/coap/Cargo.toml b/examples/coap/Cargo.toml index 9a47f5a6..d6e55c12 100644 --- a/examples/coap/Cargo.toml +++ b/examples/coap/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -edhoc-rs = { path = "../../lib", features = [ "rust-psa" ] } +edhoc-rs = { path = "../../lib", features = [ "cb-psa" ] } coap = { version = "0.13" } coap-lite = { version = "0.11.3" } diff --git a/examples/edhoc-rs-cc2538/Cargo.toml b/examples/edhoc-rs-cc2538/Cargo.toml index dd095641..ba0ebb1b 100644 --- a/examples/edhoc-rs-cc2538/Cargo.toml +++ b/examples/edhoc-rs-cc2538/Cargo.toml @@ -20,5 +20,5 @@ rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] default = [ "psa" ] -psa = [ "edhoc-rs/rust-psa-baremetal" ] +psa = [ "edhoc-rs/cb-psa-baremetal" ] diff --git a/examples/edhoc-rs-no_std/Cargo.toml b/examples/edhoc-rs-no_std/Cargo.toml index b9ce318c..0987cd05 100644 --- a/examples/edhoc-rs-no_std/Cargo.toml +++ b/examples/edhoc-rs-no_std/Cargo.toml @@ -21,8 +21,8 @@ rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] default = [ ] -rust-psa = [ "edhoc-rs/rust-psa-baremetal" ] rtt = [ ] -rust-cryptocell310 = [ "edhoc-rs/rust-cryptocell310" ] +cb-psa = [ "edhoc-rs/cb-psa-baremetal" ] +cb-cryptocell310 = [ "edhoc-rs/cb-cryptocell310" ] ead-none = [ "edhoc-rs/ead-none" ] ead-zeroconf = [ "edhoc-rs/ead-zeroconf" ] diff --git a/examples/edhoc-rs-no_std/src/main.rs b/examples/edhoc-rs-no_std/src/main.rs index a1026e28..3f90f3cf 100644 --- a/examples/edhoc-rs-no_std/src/main.rs +++ b/examples/edhoc-rs-no_std/src/main.rs @@ -32,8 +32,9 @@ fn main() -> ! { rtt_init_print!(); // Initialize the allocator BEFORE you use it - // The hacspec version does some allocations in the heap - #[cfg(any(feature = "hacspec-psa", feature = "hacspec-cryptocell310",))] + // The hacspec version does some heap allocations + // TODO: we still don't have a baremetal version with hacspec as crypto backend, so maybe remove `HEAP`. + #[cfg(any(feature = "cb-hacspec"))] { use core::mem::MaybeUninit; const HEAP_SIZE: usize = 1 << 10; @@ -42,9 +43,9 @@ fn main() -> ! { } // Memory buffer for mbedtls - #[cfg(any(feature = "hacspec-psa", feature = "rust-psa",))] + #[cfg(feature = "cb-psa")] let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - #[cfg(any(feature = "hacspec-psa", feature = "rust-psa",))] + #[cfg(feature = "cb-psa")] unsafe { mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); } @@ -84,12 +85,7 @@ fn main() -> ! { let g_xy = p256_ecdh(&x, &g_y); let g_yx = p256_ecdh(&y, &g_x); - // NOTE: application code is not supposed to distinguish between the rust and hacspec implementations - // however, it is valuable to test that the results are correct, so we distinguish it here as an exception. - #[cfg(any(feature = "rust-psa", feature = "rust-cryptocell310",))] assert_eq!(g_xy, g_yx); - #[cfg(any(feature = "hacspec-psa", feature = "hacspec-cryptocell310",))] - assert_eq!(g_xy.to_public_array(), g_yx.to_public_array()); } test_p256_keys(); println!("Test test_p256_keys passed."); diff --git a/lib/Cargo.toml b/lib/Cargo.toml index c7cfbf94..44a0efca 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -12,7 +12,7 @@ hex = { version = "0.4.3", default-features = false } hacspec-lib = { version = "0.1.0-beta.1", default-features = false, optional = true } edhoc-crypto = { path = "../crypto", default-features = false } -edhoc-consts = { path = "../consts", default-features = false } +edhoc-consts = { path = "../consts" } edhoc-ead = { path = "../ead", default-features = false } panic-semihosting = { version = "0.6.0", features = ["exit"], optional = true } @@ -21,10 +21,10 @@ cbindgen = "0.24.5" [features] default = [ "edhoc-ead/ead-none" ] -rust-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ] -rust-psa = [ "edhoc-consts/rust", "edhoc-crypto/psa-rust" ] -rust-psa-baremetal = [ "edhoc-crypto/psa-rust-baremetal", "edhoc-consts/rust", "panic-semihosting" ] -rust-cryptocell310 = [ "edhoc-consts/rust", "edhoc-crypto/cryptocell310-rust", "panic-semihosting" ] +cb-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ] +cb-psa = [ "edhoc-crypto/psa" ] +cb-psa-baremetal = [ "edhoc-crypto/psa-baremetal", "panic-semihosting" ] +cb-cryptocell310 = [ "edhoc-crypto/cryptocell310", "panic-semihosting" ] ead-none = [ "edhoc-ead/ead-none" ] ead-zeroconf = [ "edhoc-ead/ead-zeroconf" ] diff --git a/lib/src/c_wrapper.rs b/lib/src/c_wrapper.rs index 1ea2e54f..d0fd7e72 100644 --- a/lib/src/c_wrapper.rs +++ b/lib/src/c_wrapper.rs @@ -3,7 +3,7 @@ use core::{slice, str}; use edhoc_consts::*; // Panic handler for cortex-m targets -#[cfg(any(feature = "rust-cryptocell310", feature = "rust-psa-baremetal"))] +#[cfg(any(feature = "cb-cryptocell310", feature = "cb-psa-baremetal"))] use panic_semihosting as _; // This function is mainly used to test the C wrapper From 4efb16fccb87ca87a5914215b57a72f92d524eb9 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Wed, 4 Oct 2023 09:57:51 +0200 Subject: [PATCH 12/16] feat: adjust crypto backend feature names --- .github/workflows/build-and-test.yml | 12 ++++++------ README.md | 2 +- build_for_c.sh | 6 +++--- examples/c-wrapper-riot/README.md | 6 +++--- examples/coap/Cargo.toml | 2 +- examples/edhoc-rs-cc2538/Cargo.toml | 2 +- examples/edhoc-rs-no_std/Cargo.toml | 4 ++-- examples/edhoc-rs-no_std/src/main.rs | 6 +++--- lib/Cargo.toml | 8 ++++---- lib/src/c_wrapper.rs | 2 +- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 30cafee7..60f4a78a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - crypto_backend: [cb-hacspec, cb-psa] + crypto_backend: [crypto-hacspec, crypto-psa] ead: [ead-none, ead-zeroconf] steps: @@ -45,7 +45,7 @@ jobs: strategy: fail-fast: false matrix: - crypto_backend: [cb-hacspec, cb-psa, cb-psa-baremetal, cb-cryptocell310] + crypto_backend: [crypto-hacspec, crypto-psa, crypto-psa-baremetal, crypto-cryptocell310] ead: [ead-none, ead-zeroconf] steps: @@ -80,7 +80,7 @@ jobs: - name: Generate fstar code using the main library and the hacspec crypto backend run: | - docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs && cargo-hax -C -p edhoc-rs -p edhoc-crypto -p edhoc-ead --no-default-features --features='cb-hacspec, ead-none' --release \; into fstar" + docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs && cargo-hax -C -p edhoc-rs -p edhoc-crypto -p edhoc-ead --no-default-features --features='crypto-hacspec, ead-none' --release \; into fstar" zip -j -r edhoc-rs-fstar.zip $(find . -name *fst) - name: Upload artifact @@ -97,7 +97,7 @@ jobs: strategy: fail-fast: false matrix: - crypto_backend: [cb-psa-baremetal, cb-cryptocell310] + crypto_backend: [crypto-psa-baremetal, crypto-cryptocell310] steps: - name: Checkout repo @@ -125,7 +125,7 @@ jobs: strategy: fail-fast: false matrix: - crypto_backend: [cb-psa] + crypto_backend: [crypto-psa] ead: [ead-none, ead-zeroconf] steps: @@ -150,7 +150,7 @@ jobs: strategy: fail-fast: false matrix: - crypto_backend: [cb-psa, cb-cryptocell310] + crypto_backend: [crypto-psa, crypto-cryptocell310] ead: [ead-none, ead-zeroconf] steps: diff --git a/README.md b/README.md index ced5ea00..797f44ab 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ cd ./examples/edhoc-rs-no_std cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="hacspec-psa, rtt" --release # build using the rust version of the lib, and hardware-accelerated crypto -cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="cb-cryptocell310, rtt" +cargo build --target="thumbv7em-none-eabihf" --no-default-features --features="crypto-cryptocell310, rtt" ``` To build **and** flash to the board, replace the word `build` with `embed` in the commands above (you may need to `cargo install cargo-embed`). diff --git a/build_for_c.sh b/build_for_c.sh index 0c007709..aadf0a53 100755 --- a/build_for_c.sh +++ b/build_for_c.sh @@ -11,9 +11,9 @@ cargo_features=$1 -if [[ $cargo_features != "cb-cryptocell310" && $cargo_features != "cb-psa-baremetal" ]]; then - echo "Select one of: cb-cryptocell310, cb-psa-baremetal" - echo "Example: ./build_static_lib.sh cb-cryptocell310" +if [[ $cargo_features != "crypto-cryptocell310" && $cargo_features != "crypto-psa-baremetal" ]]; then + echo "Select one of: crypto-cryptocell310, crypto-psa-baremetal" + echo "Example: ./build_static_lib.sh crypto-cryptocell310" exit 1 fi diff --git a/examples/c-wrapper-riot/README.md b/examples/c-wrapper-riot/README.md index 758d16a8..9fc5ac7f 100644 --- a/examples/c-wrapper-riot/README.md +++ b/examples/c-wrapper-riot/README.md @@ -8,18 +8,18 @@ See [Requirements](#requirements) below. First, go to the top level directory and generate the headers and static library: ```bash -./build_for_c.sh cb-cryptocell310 # or cb-psa-baremetal +./build_for_c.sh crypto-cryptocell310 # or crypto-psa-baremetal ``` Then, compile and flash to the board (default is nRF52840), as shown below. -With `cb-cryptocell310`: +With `crypto-cryptocell310`: ```bash make flash term ``` -With `cb-psa-baremetal`: +With `crypto-psa-baremetal`: ```bash make flash term EDHOC_CRYPTO=CB_PSA diff --git a/examples/coap/Cargo.toml b/examples/coap/Cargo.toml index d6e55c12..0fe1785e 100644 --- a/examples/coap/Cargo.toml +++ b/examples/coap/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -edhoc-rs = { path = "../../lib", features = [ "cb-psa" ] } +edhoc-rs = { path = "../../lib", features = [ "crypto-psa" ] } coap = { version = "0.13" } coap-lite = { version = "0.11.3" } diff --git a/examples/edhoc-rs-cc2538/Cargo.toml b/examples/edhoc-rs-cc2538/Cargo.toml index ba0ebb1b..7a967f41 100644 --- a/examples/edhoc-rs-cc2538/Cargo.toml +++ b/examples/edhoc-rs-cc2538/Cargo.toml @@ -20,5 +20,5 @@ rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] default = [ "psa" ] -psa = [ "edhoc-rs/cb-psa-baremetal" ] +psa = [ "edhoc-rs/crypto-psa-baremetal" ] diff --git a/examples/edhoc-rs-no_std/Cargo.toml b/examples/edhoc-rs-no_std/Cargo.toml index 0987cd05..ee4245b6 100644 --- a/examples/edhoc-rs-no_std/Cargo.toml +++ b/examples/edhoc-rs-no_std/Cargo.toml @@ -22,7 +22,7 @@ rtt-target = { version = "0.3.1", features = ["cortex-m"] } [features] default = [ ] rtt = [ ] -cb-psa = [ "edhoc-rs/cb-psa-baremetal" ] -cb-cryptocell310 = [ "edhoc-rs/cb-cryptocell310" ] +crypto-psa = [ "edhoc-rs/crypto-psa-baremetal" ] +crypto-cryptocell310 = [ "edhoc-rs/crypto-cryptocell310" ] ead-none = [ "edhoc-rs/ead-none" ] ead-zeroconf = [ "edhoc-rs/ead-zeroconf" ] diff --git a/examples/edhoc-rs-no_std/src/main.rs b/examples/edhoc-rs-no_std/src/main.rs index 3f90f3cf..c86b6d33 100644 --- a/examples/edhoc-rs-no_std/src/main.rs +++ b/examples/edhoc-rs-no_std/src/main.rs @@ -34,7 +34,7 @@ fn main() -> ! { // Initialize the allocator BEFORE you use it // The hacspec version does some heap allocations // TODO: we still don't have a baremetal version with hacspec as crypto backend, so maybe remove `HEAP`. - #[cfg(any(feature = "cb-hacspec"))] + #[cfg(any(feature = "crypto-hacspec"))] { use core::mem::MaybeUninit; const HEAP_SIZE: usize = 1 << 10; @@ -43,9 +43,9 @@ fn main() -> ! { } // Memory buffer for mbedtls - #[cfg(feature = "cb-psa")] + #[cfg(feature = "crypto-psa")] let mut buffer: [c_char; 4096 * 2] = [0; 4096 * 2]; - #[cfg(feature = "cb-psa")] + #[cfg(feature = "crypto-psa")] unsafe { mbedtls_memory_buffer_alloc_init(buffer.as_mut_ptr(), buffer.len()); } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 44a0efca..d782b7e6 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -21,10 +21,10 @@ cbindgen = "0.24.5" [features] default = [ "edhoc-ead/ead-none" ] -cb-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ] -cb-psa = [ "edhoc-crypto/psa" ] -cb-psa-baremetal = [ "edhoc-crypto/psa-baremetal", "panic-semihosting" ] -cb-cryptocell310 = [ "edhoc-crypto/cryptocell310", "panic-semihosting" ] +crypto-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ] +crypto-psa = [ "edhoc-crypto/psa" ] +crypto-psa-baremetal = [ "edhoc-crypto/psa-baremetal", "panic-semihosting" ] +crypto-cryptocell310 = [ "edhoc-crypto/cryptocell310", "panic-semihosting" ] ead-none = [ "edhoc-ead/ead-none" ] ead-zeroconf = [ "edhoc-ead/ead-zeroconf" ] diff --git a/lib/src/c_wrapper.rs b/lib/src/c_wrapper.rs index d0fd7e72..1018f607 100644 --- a/lib/src/c_wrapper.rs +++ b/lib/src/c_wrapper.rs @@ -3,7 +3,7 @@ use core::{slice, str}; use edhoc_consts::*; // Panic handler for cortex-m targets -#[cfg(any(feature = "cb-cryptocell310", feature = "cb-psa-baremetal"))] +#[cfg(any(feature = "crypto-cryptocell310", feature = "crypto-psa-baremetal"))] use panic_semihosting as _; // This function is mainly used to test the C wrapper From c1ccb48c4e6d0de4a77a50ec0b0a3fc0dbd2a5fc Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Wed, 4 Oct 2023 10:11:27 +0200 Subject: [PATCH 13/16] refactor: use for instead of while when encoding suites --- lib/src/edhoc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 3f79f3d7..e8a1c5e8 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -936,8 +936,7 @@ fn encode_message_1( // several suites, will be encoded as an array output.content[1] = CBOR_MAJOR_ARRAY + (suites_len as u8); raw_suites_len += 1; - let mut i: usize = 0; - while i < suites_len { + for i in 0..suites_len { if suites[i] <= CBOR_UINT_1BYTE { output.content[1 + raw_suites_len] = suites[i]; raw_suites_len += 1; @@ -946,7 +945,6 @@ fn encode_message_1( output.content[2 + raw_suites_len] = suites[i]; raw_suites_len += 2; } - i += 1; } }; From 4b418c020b537eb54b784764771b5dbc63c96160 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Wed, 4 Oct 2023 10:29:28 +0200 Subject: [PATCH 14/16] feat: run fstar ci only on release or manual trigger --- .github/workflows/build-and-test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 60f4a78a..7830e5ab 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -5,6 +5,7 @@ on: branches: [main] tags: 'v*' pull_request: + workflow_dispatch: env: CARGO_TERM_COLOR: always @@ -64,6 +65,10 @@ jobs: generate-fstar: needs: unit-tests runs-on: ubuntu-latest + if: >- + (github.event_name == 'workflow_dispatch') || + (github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')) + steps: - name: Checkout edhoc-rs uses: actions/checkout@v3 @@ -187,6 +192,7 @@ jobs: if: >- github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + steps: - name: Checkout repo uses: actions/checkout@v3 From 914d14f89d38932414ba98c9d8254a2f06d4129c Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Wed, 4 Oct 2023 10:34:47 +0200 Subject: [PATCH 15/16] refactor: adjust makefile parameter name in riot example --- examples/c-wrapper-riot/Makefile | 6 +++--- examples/c-wrapper-riot/README.md | 2 +- examples/c-wrapper-riot/main.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/c-wrapper-riot/Makefile b/examples/c-wrapper-riot/Makefile index a692efea..e4f6a241 100644 --- a/examples/c-wrapper-riot/Makefile +++ b/examples/c-wrapper-riot/Makefile @@ -7,13 +7,13 @@ BOARD ?= nrf52840dk INCLUDES += -I$(CURDIR)/../../target/include ARCHIVES += $(CURDIR)/../../target/thumbv7em-none-eabihf/release/libedhoc_rs.a -ifeq ($(EDHOC_CRYPTO), CB_PSA) +ifeq ($(EDHOC_CRYPTO), CRYPTO_PSA) CFLAGS += -D$(EDHOC_CRYPTO) else - CFLAGS += -DCB_CRYPTOCELL310 + CFLAGS += -DCRYPTO_CRYPTOCELL310 endif -# This is actually only needed in the CB_CRYPTOCELL310 configuration +# This is actually only needed in the CRYPTO_CRYPTOCELL310 configuration CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=16384 -DISR_STACKSIZE=16384 USEMODULE += od diff --git a/examples/c-wrapper-riot/README.md b/examples/c-wrapper-riot/README.md index 9fc5ac7f..da5bf9c5 100644 --- a/examples/c-wrapper-riot/README.md +++ b/examples/c-wrapper-riot/README.md @@ -22,7 +22,7 @@ make flash term With `crypto-psa-baremetal`: ```bash -make flash term EDHOC_CRYPTO=CB_PSA +make flash term EDHOC_CRYPTO=CRYPTO_PSA ``` # Requirements diff --git a/examples/c-wrapper-riot/main.c b/examples/c-wrapper-riot/main.c index 2ee187d0..2b479f6a 100644 --- a/examples/c-wrapper-riot/main.c +++ b/examples/c-wrapper-riot/main.c @@ -3,7 +3,7 @@ #include "od.h" #include "edhoc_rs.h" -#ifdef CB_PSA +#ifdef CRYPTO_PSA extern void mbedtls_memory_buffer_alloc_init(uint8_t *buf, size_t len); #endif @@ -20,7 +20,7 @@ int main(void) { puts("Calling edhoc-rs from C!"); -#ifdef CB_PSA +#ifdef CRYPTO_PSA // Memory buffer for mbedtls uint8_t buffer[4096 * 2] = {0}; mbedtls_memory_buffer_alloc_init(buffer, 4096 * 2); From 4990f380a76d2ea24292564a367da3599dacbb33 Mon Sep 17 00:00:00 2001 From: Geovane Fedrecheski Date: Wed, 4 Oct 2023 10:39:23 +0200 Subject: [PATCH 16/16] fix: filter out c_wrapper during fstar generation --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7830e5ab..de5e0a08 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -85,7 +85,7 @@ jobs: - name: Generate fstar code using the main library and the hacspec crypto backend run: | - docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs && cargo-hax -C -p edhoc-rs -p edhoc-crypto -p edhoc-ead --no-default-features --features='crypto-hacspec, ead-none' --release \; into fstar" + docker run --rm -v ${{ github.workspace }}:/edhoc-rs hacspec-v2 bash -c "cd edhoc-rs && cargo-hax -C -p edhoc-rs -p edhoc-crypto -p edhoc-ead --no-default-features --features='crypto-hacspec, ead-none' --release \; into -i '-c_wrapper::**' fstar" zip -j -r edhoc-rs-fstar.zip $(find . -name *fst) - name: Upload artifact