Skip to content

Commit

Permalink
Merge pull request openwsn-berkeley#174 from geonnave/split-message-p…
Browse files Browse the repository at this point in the history
…rocessing

Split message processing
  • Loading branch information
geonnave authored Dec 26, 2023
2 parents 6a5f0bf + df6b9b9 commit 5e277d8
Show file tree
Hide file tree
Showing 15 changed files with 810 additions and 781 deletions.
21 changes: 16 additions & 5 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ jobs:
- name: Check if code is well formatted
run: cargo fmt --check

unit-tests: # run before build because it is faster
unit-tests-default:
needs: check-style
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
crypto_backend: [lakers-crypto/hacspec, lakers-crypto/psa, lakers-crypto/rustcrypto]
ead: [ead-none, ead-zeroconf]

steps:
- name: Checkout repo
Expand All @@ -38,6 +35,21 @@ jobs:
- name: Run unit tests with default features
run: RUST_BACKTRACE=1 cargo test


unit-tests:
needs: check-style
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
crypto_backend: [lakers-crypto/hacspec, lakers-crypto/psa, lakers-crypto/rustcrypto]
ead: [ead-none, ead-zeroconf]

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Run unit tests with feature matrix # note that we only add `--package lakers-ead-zeroconf` when testing with that config
run: RUST_BACKTRACE=1 cargo test -p lakers -p lakers-crypto -p lakers-shared ${{ matrix.ead == 'ead-zeroconf' && '-p lakers-ead-zeroconf' || '' }} --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}" --no-fail-fast -- --test-threads 1

Expand Down Expand Up @@ -66,7 +78,6 @@ jobs:


generate-fstar:
needs: unit-tests
runs-on: ubuntu-latest

steps:
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ lakers-shared = { package = "lakers-shared", path = "shared/", version = "^0.4.1
lakers-ead = { package = "lakers-ead-dispatch", path = "ead/", version = "^0.4.1", default-features = false }
lakers-ead-none = { package = "lakers-ead-none", path = "ead/lakers-ead-none/", version = "^0.4.1" }
lakers-ead-zeroconf = { package = "lakers-ead-zeroconf", path = "ead/lakers-ead-zeroconf/", version = "^0.4.1" }
lakers-ead-authz = { package = "lakers-ead-authz", path = "ead/lakers-ead-authz/", version = "^0.4.1" }
lakers-crypto = { path = "crypto/" }

lakers-crypto-cc2538 = { path = "crypto/lakers-crypto-cc2538/" }
Expand Down
2 changes: 2 additions & 0 deletions ead/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ lakers-shared.workspace = true

lakers-ead-none = { workspace = true, optional = true }
lakers-ead-zeroconf = { workspace = true, optional = true }
lakers-ead-authz = { workspace = true, optional = true }

[features]
default = [ "ead-none" ]
ead-none = [ "lakers-ead-none" ]
ead-zeroconf = [ "lakers-ead-zeroconf" ]
ead-authz = [ "lakers-ead-authz" ]
4 changes: 1 addition & 3 deletions ead/lakers-ead-authz/src/authenticator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::shared::*;
use lakers_shared::{Crypto as CryptoTrait, *};
use lakers_shared::*;

#[derive(Debug, Default)]
pub struct ZeroTouchAuthenticator;
Expand Down Expand Up @@ -113,7 +113,6 @@ fn parse_voucher_response(
mod test_authenticator {
use super::*;
use crate::test_vectors::*;
use lakers_crypto::default_crypto;

#[test]
fn test_parse_ead_1_value() {
Expand Down Expand Up @@ -184,7 +183,6 @@ mod test_authenticator {
mod test_responder_stateless_operation {
use super::*;
use crate::test_vectors::*;
use lakers_crypto::default_crypto;

#[test]
fn test_slo_encode_voucher_request() {
Expand Down
18 changes: 14 additions & 4 deletions ead/lakers-ead-authz/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct ZeroTouchDevice {
#[derive(Debug)]
pub struct ZeroTouchDeviceWaitEAD2 {
prk: BytesHashLen,
pub h_message_1: BytesHashLen,
}

#[derive(Debug)]
Expand Down Expand Up @@ -43,25 +44,34 @@ impl ZeroTouchDevice {
value,
};

(ead_1, ZeroTouchDeviceWaitEAD2 { prk })
(
ead_1,
ZeroTouchDeviceWaitEAD2 {
prk,
h_message_1: [0; SHA256_DIGEST_LEN],
},
)
}
}

impl ZeroTouchDeviceWaitEAD2 {
pub fn set_h_message_1(&mut self, h_message_1: BytesHashLen) {
self.h_message_1 = h_message_1;
}

pub fn process_ead_2<Crypto: CryptoTrait>(
&self,
crypto: &mut Crypto,
ead_2: EADItem,
cred_v: &[u8],
h_message_1: &BytesHashLen,
) -> Result<ZeroTouchDeviceDone, ()> {
if ead_2.label != EAD_ZEROCONF_LABEL || ead_2.value.is_none() {
return Err(());
}
let mut ead_2_value: BytesEncodedVoucher = Default::default();
ead_2_value[..].copy_from_slice(&ead_2.value.unwrap().content[..ENCODED_VOUCHER_LEN]);

match verify_voucher(crypto, &ead_2_value, h_message_1, cred_v, &self.prk) {
match verify_voucher(crypto, &ead_2_value, &self.h_message_1, cred_v, &self.prk) {
Ok(voucher) => Ok(ZeroTouchDeviceDone { voucher }),
Err(_) => Err(()),
}
Expand Down Expand Up @@ -179,13 +189,13 @@ mod test_device {

let ead_device = ZeroTouchDeviceWaitEAD2 {
prk: PRK_TV.try_into().unwrap(),
h_message_1: H_MESSAGE_1_TV.try_into().unwrap(),
};

let res = ead_device.process_ead_2(
&mut default_crypto(),
ead_2_tv,
CRED_V_TV.try_into().unwrap(),
&H_MESSAGE_1_TV.try_into().unwrap(),
);
assert!(res.is_ok());
let ead_device = res.unwrap();
Expand Down
38 changes: 31 additions & 7 deletions ead/lakers-ead-authz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod test_authz {
test_vectors::*,
};
use lakers_crypto::default_crypto;
use lakers_shared::EDHOCError;

#[test]
fn test_complete_flow() {
Expand All @@ -35,8 +36,9 @@ mod test_authz {

// using .unwrap below since detailed errors are tested in each entity's tests

let (ead_1, device) =
let (ead_1, mut device) =
device.prepare_ead_1(&mut default_crypto(), &X_TV.try_into().unwrap(), SS_TV);
device.set_h_message_1(H_MESSAGE_1_TV.try_into().unwrap());

// ead_1 will be transported within message_1

Expand All @@ -54,12 +56,34 @@ mod test_authz {

// ead_2 will be transported within message_2

let result = device.process_ead_2(
&mut default_crypto(),
ead_2,
CRED_V_TV,
H_MESSAGE_1_TV.try_into().unwrap(),
);
let result = device.process_ead_2(&mut default_crypto(), ead_2, CRED_V_TV);
assert!(result.is_ok());
}

#[test]
fn test_complete_flow_unauthorized() {
let device = ZeroTouchDevice::new(
ID_U_TV.try_into().unwrap(),
G_W_TV.try_into().unwrap(),
LOC_W_TV.try_into().unwrap(),
);
let authenticator = ZeroTouchAuthenticator::default();
let server = ZeroTouchServer::new(
W_TV.try_into().unwrap(),
CRED_V_TV.try_into().unwrap(),
Some(ACL_INVALID_TV.try_into().unwrap()),
);

let (ead_1, mut device) =
device.prepare_ead_1(&mut default_crypto(), &X_TV.try_into().unwrap(), SS_TV);
device.set_h_message_1(H_MESSAGE_1_TV.try_into().unwrap());

let (_loc_w, voucher_request, _authenticator) = authenticator
.process_ead_1(&ead_1, &MESSAGE_1_WITH_EAD_TV.try_into().unwrap())
.unwrap();

let voucher_response =
server.handle_voucher_request(&mut default_crypto(), &voucher_request);
assert_eq!(voucher_response.unwrap_err(), EDHOCError::EADError);
}
}
3 changes: 3 additions & 0 deletions ead/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ pub use lakers_ead_none::*;

#[cfg(feature = "ead-zeroconf")]
pub use lakers_ead_zeroconf::*;

#[cfg(feature = "ead-authz")]
pub use lakers_ead_authz::*;
81 changes: 40 additions & 41 deletions examples/coap/src/bin/coapclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ const CRED_R: &[u8] = &hex!("A2026008A101A5010202410A2001215820BBC34960526EA4D32
const _G_R: &[u8] = &hex!("bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f0");

fn main() {
match client_handshake() {
Ok(_) => println!("Handshake completed"),
Err(e) => panic!("Handshake failed with error: {:?}", e),
}
}

fn client_handshake() -> Result<(), EDHOCError> {
let url = "coap://127.0.0.1:5683/.well-known/edhoc";
let timeout = Duration::new(5, 0);
println!("Client request: {}", url);

let state = Default::default();
let initiator = EdhocInitiator::new(
state,
lakers_crypto::default_crypto(),
&I,
&CRED_I,
Some(&CRED_R),
);
let initiator =
EdhocInitiator::new(lakers_crypto::default_crypto(), &I, &CRED_I, Some(&CRED_R));

// 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 c_i = generate_connection_identifier_cbor(&mut lakers_crypto::default_crypto());
let (initiator, message_1) = initiator.prepare_message_1(c_i).unwrap();
let (initiator, message_1) = initiator.prepare_message_1(Some(c_i), &None)?;
msg_1_buf.extend_from_slice(message_1.as_slice());
println!("message_1 len = {}", msg_1_buf.len());

Expand All @@ -43,45 +44,43 @@ fn main() {
println!("response_vec = {:02x?}", response.message.payload);
println!("message_2 len = {}", response.message.payload.len());

let m2result = initiator.process_message_2(
&response.message.payload[..]
.try_into()
.expect("wrong length"),
);
let message_2 = EdhocMessageBuffer::new_from_slice(&response.message.payload[..]).unwrap();
let (initiator, c_r, id_cred_r, _ead_2) = initiator.parse_message_2(&message_2)?;
let (valid_cred_r, _g_r) =
credential_check_or_fetch(Some(CRED_R.try_into().unwrap()), id_cred_r).unwrap();
let initiator = initiator.verify_message_2(valid_cred_r.as_slice())?;

if let Ok((initiator, c_r)) = m2result {
let mut msg_3 = Vec::from([c_r]);
let (mut initiator, message_3, prk_out) = initiator.prepare_message_3().unwrap();
msg_3.extend_from_slice(message_3.as_slice());
println!("message_3 len = {}", msg_3.len());
let mut msg_3 = Vec::from([c_r]);
let (mut initiator, message_3, prk_out) = initiator.prepare_message_3(&None)?;
msg_3.extend_from_slice(message_3.as_slice());
println!("message_3 len = {}", msg_3.len());

let _response = CoAPClient::post_with_timeout(url, msg_3, timeout).unwrap();
// we don't care about the response to message_3 for now
let _response = CoAPClient::post_with_timeout(url, msg_3, timeout).unwrap();
// we don't care about the response to message_3 for now

println!("EDHOC exchange successfully completed");
println!("PRK_out: {:02x?}", prk_out);
println!("EDHOC exchange successfully completed");
println!("PRK_out: {:02x?}", prk_out);

let mut _oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0
let mut _oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1
let mut oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0
let mut oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1

println!("OSCORE secret: {:02x?}", _oscore_secret);
println!("OSCORE salt: {:02x?}", _oscore_salt);
println!("OSCORE secret: {:02x?}", oscore_secret);
println!("OSCORE salt: {:02x?}", oscore_salt);

// context of key update is a test vector from draft-ietf-lake-traces
let prk_out_new = initiator.edhoc_key_update(&[
0xa0, 0x11, 0x58, 0xfd, 0xb8, 0x20, 0x89, 0x0c, 0xd6, 0xbe, 0x16, 0x96, 0x02, 0xb8,
0xbc, 0xea,
]);
// context of key update is a test vector from draft-ietf-lake-traces
let prk_out_new = initiator.edhoc_key_update(&[
0xa0, 0x11, 0x58, 0xfd, 0xb8, 0x20, 0x89, 0x0c, 0xd6, 0xbe, 0x16, 0x96, 0x02, 0xb8, 0xbc,
0xea,
]);

println!("PRK_out after key update: {:02x?}?", prk_out_new);
println!("PRK_out after key update: {:02x?}?", prk_out_new);

// compute OSCORE secret and salt after key update
_oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0
_oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1
// compute OSCORE secret and salt after key update
oscore_secret = initiator.edhoc_exporter(0u8, &[], 16); // label is 0
oscore_salt = initiator.edhoc_exporter(1u8, &[], 8); // label is 1

println!("OSCORE secret after key update: {:02x?}", _oscore_secret);
println!("OSCORE salt after key update: {:02x?}", _oscore_salt);
} else {
panic!("Message 2 processing error: {:#?}", m2result);
}
println!("OSCORE secret after key update: {:02x?}", oscore_secret);
println!("OSCORE salt after key update: {:02x?}", oscore_salt);

Ok(())
}
33 changes: 18 additions & 15 deletions examples/coap/src/bin/coapserver-coaphandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use lakers_crypto::Crypto;
use embedded_nal::UdpFullStack;

const _ID_CRED_I: &[u8] = &hex!("a104412b");
const _ID_CRED_R: &[u8] = &hex!("a104410a");
const ID_CRED_R: &[u8] = &hex!("a104410a");
const CRED_I: &[u8] = &hex!("A2027734322D35302D33312D46462D45462D33372D33322D333908A101A5010202412B2001215820AC75E9ECE3E50BFC8ED60399889522405C47BF16DF96660A41298CB4307F7EB62258206E5DE611388A4B8A8211334AC7D37ECB52A387D257E6DB3C2A93DF21FF3AFFC8");
const _G_I: &[u8] = &hex!("ac75e9ece3e50bfc8ed60399889522405c47bf16df96660a41298cb4307f7eb6");
const _G_I_Y_COORD: &[u8] =
Expand Down Expand Up @@ -46,7 +46,7 @@ enum EdhocResponse {
// take up a slot there anyway) if we make it an enum.
OkSend2 {
c_r: u8,
responder: EdhocResponderBuildM2<'static, Crypto>,
responder: EdhocResponderProcessedM1<'static, Crypto>,
},
Message3Processed,
}
Expand All @@ -60,20 +60,13 @@ impl coap_handler::Handler for EdhocHandler {
let starts_with_true = request.payload().get(0) == Some(&0xf5);

if starts_with_true {
let state = EdhocState::default();

let responder = EdhocResponder::new(
state,
lakers_crypto::default_crypto(),
&R,
&CRED_R,
Some(&CRED_I),
);
let responder =
EdhocResponder::new(lakers_crypto::default_crypto(), &R, &CRED_R, Some(&CRED_I));

let response = responder
.process_message_1(&request.payload()[1..].try_into().expect("wrong length"));

if let Ok(responder) = response {
if let Ok((responder, _ead_1)) = response {
let c_r = self.new_c_r();
EdhocResponse::OkSend2 { c_r, responder }
} else {
Expand All @@ -87,9 +80,17 @@ impl coap_handler::Handler for EdhocHandler {
.expect("No such C_R found");

println!("Found state with connection identifier {:?}", c_r_rcvd);
let result = responder
.process_message_3(&request.payload()[1..].try_into().expect("wrong length"));

let message_3 = EdhocMessageBuffer::new_from_slice(&request.payload()[1..]).unwrap();
let result = responder.parse_message_3(&message_3);
let Ok((responder, id_cred_i, _ead_3)) = result else {
println!("EDHOC processing error: {:?}", result);
// FIXME remove state from edhoc_connections
panic!("Handler can't just not respond");
};
let (valid_cred_i, _g_i) =
credential_check_or_fetch(Some(CRED_I.try_into().unwrap()), id_cred_i).unwrap();
let result = responder.verify_message_3(valid_cred_i.as_slice());
let Ok((mut responder, prk_out)) = result else {
println!("EDHOC processing error: {:?}", result);
// FIXME remove state from edhoc_connections
Expand Down Expand Up @@ -130,7 +131,9 @@ impl coap_handler::Handler for EdhocHandler {
response.set_code(coap_numbers::code::CHANGED.try_into().ok().unwrap());
match req {
EdhocResponse::OkSend2 { c_r, responder } => {
let (responder, message_2) = responder.prepare_message_2(c_r).unwrap();
let kid = IdCred::CompactKid(ID_CRED_R[3]);
let (responder, message_2) =
responder.prepare_message_2(&kid, Some(c_r), &None).unwrap();
self.connections.push((c_r, responder));
response.set_payload(message_2.as_slice());
}
Expand Down
Loading

0 comments on commit 5e277d8

Please sign in to comment.