Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
34e12dc
Refactoring to support future methods
ElsaLopez133 Feb 19, 2026
65859e6
Added helper functions where method-states are used because of hax er…
ElsaLopez133 Feb 23, 2026
c557ed2
Added helper functions for all functions for clarity
ElsaLopez133 Feb 23, 2026
ded1c64
Adding a separate submodule for _statstat functions
ElsaLopez133 Feb 23, 2026
63781d0
Replacing outer/inner states for method_specific entry
ElsaLopez133 Feb 24, 2026
086f95f
Removing method from state ProcessingM3 and ProcessingM2
ElsaLopez133 Feb 26, 2026
f8da180
Removing method from state ProcessingM3 and ProcessingM2
ElsaLopez133 Feb 26, 2026
3fcbf30
Refactor method-specific identity/state
ElsaLopez133 Feb 27, 2026
c9a7380
Correcting verify_message_2 for future PSK
ElsaLopez133 Mar 4, 2026
5570119
Fixing errors after review
ElsaLopez133 Mar 5, 2026
fb49f4b
Fixing reviewing comments pt2.
ElsaLopez133 Mar 5, 2026
a1d2693
Modifying lakers-c
ElsaLopez133 Mar 6, 2026
d43018a
Modifications after review
ElsaLopez133 Mar 11, 2026
0c8e163
Adding PSK method
ElsaLopez133 Feb 25, 2026
02b948e
Adding test vectors for PSK
ElsaLopez133 Mar 4, 2026
d0192ec
TEMP: PSA lot exhaustion fix to make tests work
ElsaLopez133 Mar 4, 2026
cf72cd5
refactor: unify stat/psk helper functions using options
ElsaLopez133 Mar 16, 2026
1469828
factor shared EDHOC message flow out of statstat and psk
ElsaLopez133 Mar 17, 2026
0755dc5
make lakers-c/initiator method-aware and add psk e2e tests
ElsaLopez133 Mar 18, 2026
bfe7991
Adding test_handshake_psk in lakers-no_std
ElsaLopez133 Mar 19, 2026
9e8bb4c
Fix lakers-c statstat verification by repsecting EAD item count
ElsaLopez133 Mar 19, 2026
51ac9ad
Add PSK native C example and fix lakers-c FFI state conversion
ElsaLopez133 Mar 19, 2026
cb918be
Add PSK Python bindings for initiator and responder
ElsaLopez133 Mar 20, 2026
64013ff
Fixing review comments
ElsaLopez133 Apr 5, 2026
86aeaa7
Fixing wrong key in encrytp/decrypt message_3
ElsaLopez133 Apr 7, 2026
f7aad96
adding -psk coap examples
ElsaLopez133 Apr 7, 2026
54e98ef
Merge branch 'main' into refactoring-adding-psk-method
WilliamTakeshi Jul 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crypto/lakers-crypto-cryptocell310-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ impl CryptoTrait for Crypto {
output
}

fn hkdf_extract_psk(&mut self, salt: &BytesHashLen, ikm: &BytesElemLenPSK) -> BytesHashLen {
// TODO
// TODO generalize if salt is not provided
let output = self.hmac_sha256(&mut ikm.clone()[..], *salt);

output
}

fn aes_ccm_encrypt<const N: usize, Tag: CcmTagLen>(
&mut self,
key: &BytesCcmKeyLen,
Expand Down
13 changes: 12 additions & 1 deletion crypto/lakers-crypto-psa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ impl CryptoTrait for Crypto {
output
}

// added for PSK
fn hkdf_extract_psk(&mut self, salt: &BytesHashLen, ikm: &BytesElemLenPSK) -> BytesHashLen {
// TODO
// TODO generalize if salt is not provided
let output = self.hmac_sha256(&mut ikm.clone()[..], salt);
Comment thread
ElsaLopez133 marked this conversation as resolved.
Outdated

output
}

fn aes_ccm_encrypt<const N: usize, Tag: CcmTagLen>(
&mut self,
key: &BytesCcmKeyLen,
Expand Down Expand Up @@ -208,7 +217,9 @@ impl CryptoTrait for Crypto {

key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer)
.unwrap();

// SAFETY: The function demands that the Id is not used while destroyed.
// We did not hand out the Id `my_key` in the last few lines, so we can destroy it.
unsafe { key_management::destroy(my_key).unwrap() };
output_buffer
}

Expand Down
12 changes: 10 additions & 2 deletions crypto/lakers-crypto-rustcrypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use lakers_shared::CcmTagLen;
use lakers_shared::{
BytesCcmIvLen, BytesCcmKeyLen, BytesHashLen, BytesP256ElemLen, Crypto as CryptoTrait,
EDHOCError, EDHOCSuite, EdhocBuffer, MAX_SUITES_LEN,
BytesCcmIvLen, BytesCcmKeyLen, BytesElemLenPSK, BytesHashLen, BytesP256ElemLen,
Crypto as CryptoTrait, EDHOCError, EDHOCSuite, EdhocBuffer, MAX_SUITES_LEN,
};

use ccm::AeadInPlace;
Expand Down Expand Up @@ -74,6 +74,14 @@ impl<Rng: rand_core::RngCore + rand_core::CryptoRng> CryptoTrait for Crypto<Rng>
extracted.finalize().0.into()
}

fn hkdf_extract_psk(&mut self, salt: &BytesHashLen, ikm: &BytesElemLenPSK) -> BytesHashLen {
// While it'd be nice to just pass around an Hkdf, the extract output is not a type generic
// of this trait (yet?).
let mut extracted = hkdf::HkdfExtract::<sha2::Sha256>::new(Some(salt));
extracted.input_ikm(ikm);
extracted.finalize().0.into()
}

fn aes_ccm_encrypt<const N: usize, Tag: CcmTagLen>(
&mut self,
key: &BytesCcmKeyLen,
Expand Down
12 changes: 10 additions & 2 deletions examples/coap/src/bin/coapclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,18 @@ fn client_handshake() -> Result<(), EDHOCError> {
println!("message_2 len = {}", response.message.payload.len());

let message_2 = EdhocBuffer::new_from_slice(&response.message.payload[..]).unwrap();
let (mut initiator, c_r, id_cred_r, ead_2) = initiator.parse_message_2(&message_2)?;
let (mut initiator, c_r, details, ead_2) = initiator.parse_message_2(&message_2)?;
let ParsedMessage2Details::StatStat { id_cred_r } = details else {
return Err(EDHOCError::UnsupportedMethod);
};
Comment thread
ElsaLopez133 marked this conversation as resolved.
Outdated
ead_2.processed_critical_items().unwrap();
let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap();
initiator.set_identity(I.try_into().unwrap(), cred_i)?;
initiator.set_identity(
InitiatorIdentity::StatStat {
i: I.try_into().unwrap(),
},
cred_i,
)?;
let initiator = initiator.verify_message_2(valid_cred_r)?;

let mut msg_3 = Vec::from(c_r.as_cbor());
Expand Down
4 changes: 3 additions & 1 deletion examples/coap/src/bin/coapserver-coaphandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ impl coap_handler::Handler for EdhocHandler {

let (responder, _c_i, mut ead_1) = EdhocResponder::new(
lakers_crypto::default_crypto(),
R.try_into().expect("Wrong length of responder private key"),
ResponderIdentity::StatStat {
r: R.try_into().expect("Wrong length of responder private key"),
},
cred_r,
)
.process_message_1(message_1)
Expand Down
4 changes: 3 additions & 1 deletion examples/coap/src/bin/coapserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ fn main() {
let cred_r: Credential = Credential::parse_ccs(CRED_R.try_into().unwrap()).unwrap();
let responder = EdhocResponder::new(
lakers_crypto::default_crypto(),
R.try_into().unwrap(),
ResponderIdentity::StatStat {
r: R.try_into().unwrap(),
},
cred_r,
);

Expand Down
14 changes: 10 additions & 4 deletions examples/lakers-no_std/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ fn main() -> ! {
);
let responder = EdhocResponder::new(
lakers_crypto::default_crypto(),
R.try_into().expect("Wrong length of responder private key"),
ResponderIdentity::StatStat {
r: R.try_into().expect("Wrong length of responder private key"),
},
cred_r.clone(),
);

Expand All @@ -119,12 +121,16 @@ fn main() -> ! {
.prepare_message_2(CredentialTransfer::ByReference, None, &EadItems::new())
.unwrap();

let (mut initiator, _c_r, id_cred_r, _ead_2) =
initiator.parse_message_2(&message_2).unwrap();
let (mut initiator, _c_r, details, _ead_2) = initiator.parse_message_2(&message_2).unwrap();
let ParsedMessage2Details::StatStat { id_cred_r } = details else {
panic!("Expected StatStat details");
};
let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap();
initiator
.set_identity(
I.try_into().expect("Wrong length of initiator private key"),
InitiatorIdentity::StatStat {
i: I.try_into().expect("Wrong length of initiator private key"),
},
cred_i.clone(),
)
.unwrap(); // exposing own identity only after validating cred_r
Expand Down
5 changes: 4 additions & 1 deletion examples/lakers-nrf52840/src/bin/initiator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ async fn main(spawner: Spawner) {
// starts in 1 to consider only the content and not the metadata
pckt_2.pdu[1..pckt_2.len].try_into().expect("wrong length");
info!("message_2 :{:?}", message_2.content);
let (initiator, c_r, id_cred_r, ead_2) = initiator.parse_message_2(&message_2).unwrap();
let (initiator, c_r, details) = initiator.parse_message_2(&message_2).unwrap();
let ParsedMessage2Details::StatStat { id_cred_r, ead_2 } = details else {
panic!("Expected stat-stat details");
};
let valid_cred_r = credential_check_or_fetch(Some(cred_r), id_cred_r).unwrap();
let initiator = initiator.verify_message_2(valid_cred_r).unwrap();

Expand Down
4 changes: 3 additions & 1 deletion examples/lakers-nrf52840/src/bin/responder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ async fn main(spawner: Spawner) {
let cred_r = Credential::parse_ccs(common::CRED_R.try_into().unwrap()).unwrap();
let responder = EdhocResponder::new(
lakers_crypto::default_crypto(),
common::R.try_into().unwrap(),
ResponderIdentity::StatStat {
r: common::R.try_into().unwrap(),
},
cred_r,
);

Expand Down
21 changes: 15 additions & 6 deletions lakers-c/src/initiator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ use crate::*;

/// structs compatible with the C FFI

#[derive(Debug)]
#[repr(C)]
pub struct EdhocInitiator {
pub start: InitiatorStart,
pub wait_m2: WaitM2,
pub processing_m2: ProcessingM2C,
pub processed_m2: ProcessedM2,
pub processed_m2: ProcessedM2C,
pub wait_m4: WaitM4,
pub cred_i: *mut CredentialC,
pub completed: Completed,
Expand Down Expand Up @@ -106,11 +105,15 @@ pub unsafe extern "C" fn initiator_parse_message_2(
let state = core::ptr::read(&(*initiator_c).wait_m2);

let result = match i_parse_message_2(&state, crypto, &(*message_2)) {
Ok((state, c_r, id_cred_r, ead_2)) => {
Ok((state, c_r, details, ead_2)) => {
ProcessingM2C::copy_into_c(state, &mut (*initiator_c).processing_m2);
let c_r = c_r.as_slice();
assert_eq!(c_r.len(), 1, "C API only supports short C_R");
*c_r_out = c_r[0];
let id_cred_r = match details {
ParsedMessage2Details::StatStat { id_cred_r } => id_cred_r,
ParsedMessage2Details::Psk {} => IdCred::new(),
};
*id_cred_r_out = id_cred_r;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the PSK case, why write an empty id_cred_r in id_cred_r_out. I thought we would just do nothing.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I addressed that by adding a flag has_id_cred_r_out. The flag now tells whether ID_CRED_R is present. I still initialize id_cred_r_out to a default empty value in the PSK case just to avoid leaving output memory undefined on the C side, but maybe this is not strictly needed?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, I don't know what is the right thing to do on C, but I guess better than adding a flag has_id_cred_r_out it should be something like method and be a 3 for Statstat and 4 for Psk.

And yes, reading again I think your code is correct, they sohuld still have the empty value initialized in the PSK case, we just ignore it.


EadItemsC::copy_into_c(ead_2, ead_2_c_out);
Expand Down Expand Up @@ -140,9 +143,15 @@ pub unsafe extern "C" fn initiator_verify_message_2(

let state = core::ptr::read(&(*initiator_c).processing_m2).to_rust();

match i_verify_message_2(&state, crypto, (*valid_cred_r).to_rust(), &(*i)) {
// FIXME
Comment thread
WilliamTakeshi marked this conversation as resolved.
Outdated
match i_verify_message_2(
&state,
crypto,
(*valid_cred_r).to_rust(),
InitiatorIdentity::StatStat { i: *i },
) {
Ok(state) => {
(*initiator_c).processed_m2 = state;
ProcessedM2C::copy_into_c(state, &mut (*initiator_c).processed_m2);
(*initiator_c).cred_i = cred_i;
0
}
Expand All @@ -165,7 +174,7 @@ pub unsafe extern "C" fn initiator_prepare_message_3(
}
let crypto = &mut default_crypto();

let state = core::ptr::read(&(*initiator_c).processed_m2);
let state = core::ptr::read(&(*initiator_c).processed_m2).to_rust();

let ead_3 = if ead_3_c.is_null() {
EadItems::new()
Expand Down
Loading
Loading