Skip to content

Commit

Permalink
refactor: split responder's handling of message 1 and 2
Browse files Browse the repository at this point in the history
  • Loading branch information
geonnave committed Dec 19, 2023
1 parent 6770265 commit f133afb
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 103 deletions.
116 changes: 39 additions & 77 deletions lib/src/edhoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,47 +109,30 @@ pub fn edhoc_key_update_new(
}

pub fn r_process_message_1(
state: State<Start>,
state: Start,
crypto: &mut impl CryptoTrait,
message_1: &BufferMessage1,
) -> Result<State<ProcessedMessage1>, EDHOCError> {
) -> Result<(ProcessingM1, Option<EADItem>), EDHOCError> {
// Step 1: decode message_1
// g_x will be saved to the state
let res = parse_message_1(message_1);

if let Ok((method, suites_i, suites_i_len, g_x, c_i, ead_1)) = res {
if let Ok((method, suites_i, suites_i_len, g_x, c_i, ead_1)) = parse_message_1(message_1) {
// verify that the method is supported
if method == EDHOC_METHOD {
// Step 2: verify that the selected cipher suite is supported
if suites_i[suites_i_len - 1] == EDHOC_SUPPORTED_SUITES[0] {
// 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(crypto, &ead_1, message_1).is_ok()
} else {
true
};
if ead_success {
// hash message_1 and save the hash to the state to avoid saving the whole message
let mut message_1_buf: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN];
message_1_buf[..message_1.len].copy_from_slice(message_1.as_slice());
let h_message_1 = crypto.sha256_digest(&message_1_buf, message_1.len);

let state = State {
current_state: PhantomData,
x_or_y: state.x_or_y,
// hash message_1 and save the hash to the state to avoid saving the whole message
let mut message_1_buf: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN];
message_1_buf[..message_1.len].copy_from_slice(message_1.as_slice());
let h_message_1 = crypto.sha256_digest(&message_1_buf, message_1.len);

Ok((
ProcessingM1 {
c_i,
gy_or_gx: g_x,
prk_3e2m: state.prk_3e2m,
prk_4e3m: state.prk_4e3m,
prk_out: state.prk_out,
prk_exporter: state.prk_exporter,
g_x,
h_message_1,
th_3: state.th_3,
};
Ok(state)
} else {
Err(EDHOCError::EADError)
}
},
ead_1,
))
} else {
Err(EDHOCError::UnsupportedCipherSuite)
}
Expand All @@ -162,35 +145,27 @@ pub fn r_process_message_1(
}

pub fn r_prepare_message_2(
state: State<ProcessedMessage1>,
state: ProcessingM1,
crypto: &mut impl CryptoTrait,
cred_r: &[u8],
r: &BytesP256ElemLen, // R's static private DH key
y: BytesP256ElemLen,
g_y: BytesP256ElemLen,
c_r: u8,
) -> Result<(State<WaitMessage3>, BufferMessage2), EDHOCError> {
id_cred_r: &IdCred,
ead_2: &Option<EADItem>,
) -> Result<(WaitM3, BufferMessage2), EDHOCError> {
// compute TH_2
let th_2 = compute_th_2(crypto, &g_y, &state.h_message_1);

// compute prk_3e2m
let prk_2e = compute_prk_2e(crypto, &y, &state.gy_or_gx, &th_2);
let prk_2e = compute_prk_2e(crypto, &y, &state.g_x, &th_2);
let salt_3e2m = compute_salt_3e2m(crypto, &prk_2e, &th_2);
let prk_3e2m = compute_prk_3e2m(crypto, &salt_3e2m, r, &state.gy_or_gx);
let prk_3e2m = compute_prk_3e2m(crypto, &salt_3e2m, r, &state.g_x);

// compute MAC_2
let mac_2 = compute_mac_2(crypto, &prk_3e2m, &get_id_cred(cred_r)?, cred_r, &th_2);

let ead_2 = r_prepare_ead_2();

let id_cred_r = if ead_2.is_some() {
// NOTE: assume EAD_2 is for zeroconf
IdCred::FullCredential(cred_r)
} else {
let (_g_r, kid) = parse_cred(cred_r)?;
IdCred::CompactKid(kid)
};

// compute ciphertext_2
let plaintext_2 = encode_plaintext_2(c_r, id_cred_r, &mac_2, &ead_2)?;

Expand All @@ -207,29 +182,23 @@ pub fn r_prepare_message_2(

let message_2 = encode_message_2(&g_y, &ct);

let state = State {
current_state: PhantomData,
x_or_y: y,
c_i: state.c_i,
gy_or_gx: state.gy_or_gx,
prk_3e2m: prk_3e2m,
prk_4e3m: state.prk_4e3m,
prk_out: state.prk_out,
prk_exporter: state.prk_exporter,
h_message_1: state.h_message_1,
th_3: th_3,
};

Ok((state, message_2))
Ok((
WaitM3 {
y: y,
prk_3e2m: prk_3e2m,
th_3: th_3,
},
message_2,
))
}

// FIXME fetch ID_CRED_I and CRED_I based on kid
pub fn r_process_message_3(
state: &mut State<WaitMessage3>,
state: &mut WaitM3,
crypto: &mut impl CryptoTrait,
message_3: &BufferMessage3,
cred_i_expected: Option<&[u8]>,
) -> Result<(State<Completed>, BytesHashLen), EDHOCError> {
) -> Result<(CompletedNew, BytesHashLen), EDHOCError> {
let plaintext_3 = decrypt_message_3(crypto, &state.prk_3e2m, &state.th_3, message_3);

if let Ok(plaintext_3) = plaintext_3 {
Expand Down Expand Up @@ -266,7 +235,7 @@ pub fn r_process_message_3(
// compute salt_4e3m
let salt_4e3m = compute_salt_4e3m(crypto, &state.prk_3e2m, &state.th_3);
// TODO compute prk_4e3m
let prk_4e3m = compute_prk_4e3m(crypto, &salt_4e3m, &state.x_or_y, &g_i);
let prk_4e3m = compute_prk_4e3m(crypto, &salt_4e3m, &state.y, &g_i);

// compute mac_3
let expected_mac_3 = compute_mac_3(
Expand Down Expand Up @@ -307,20 +276,13 @@ pub fn r_process_message_3(
0,
SHA256_DIGEST_LEN,
);
state.prk_exporter[..SHA256_DIGEST_LEN]
let mut prk_exporter = BytesHashLen::default();
prk_exporter[..SHA256_DIGEST_LEN]
.copy_from_slice(&prk_exporter_buf[..SHA256_DIGEST_LEN]);

let state = State {
current_state: PhantomData,
x_or_y: state.x_or_y,
c_i: state.c_i,
gy_or_gx: state.gy_or_gx,
prk_3e2m: state.prk_3e2m,
prk_4e3m: state.prk_4e3m,
prk_out: prk_out,
prk_exporter: state.prk_exporter,
h_message_1: state.h_message_1,
th_3: state.th_3,
let state = CompletedNew {
prk_out,
prk_exporter,
};
Ok((state, prk_out))
} else {
Expand Down Expand Up @@ -980,7 +942,7 @@ fn compute_mac_2(

fn encode_plaintext_2(
c_r: u8,
id_cred_r: IdCred,
id_cred_r: &IdCred,
mac_2: &BytesMac2,
ead_2: &Option<EADItem>,
) -> Result<BufferPlaintext2, EDHOCError> {
Expand All @@ -989,7 +951,7 @@ fn encode_plaintext_2(

let offset_cred = match id_cred_r {
IdCred::CompactKid(kid) => {
plaintext_2.content[1] = kid;
plaintext_2.content[1] = *kid;
2
}
IdCred::FullCredential(cred) => {
Expand Down Expand Up @@ -1507,7 +1469,7 @@ mod tests {
let plaintext_2_tv = BufferPlaintext2::from_hex(PLAINTEXT_2_TV);
let plaintext_2 = encode_plaintext_2(
C_R_TV,
IdCred::CompactKid(ID_CRED_R_TV[ID_CRED_R_TV.len() - 1]),
&IdCred::CompactKid(ID_CRED_R_TV[ID_CRED_R_TV.len() - 1]),
&MAC_2_TV,
&None::<EADItem>,
)
Expand Down
58 changes: 33 additions & 25 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,38 +68,38 @@ pub struct EdhocInitiatorDone<Crypto: CryptoTrait> {

#[derive(Debug)]
pub struct EdhocResponder<'a, Crypto: CryptoTrait> {
state: EdhocState<Start>, // opaque state
state: Start, // opaque state
r: &'a [u8], // private authentication key of R
cred_r: &'a [u8], // R's full credential
cred_i: Option<&'a [u8]>, // I's full credential (if provided)
crypto: Crypto,
}

#[derive(Debug)]
pub struct EdhocResponderBuildM2<'a, Crypto: CryptoTrait> {
state: EdhocState<ProcessedMessage1>, // opaque state
r: &'a [u8], // private authentication key of R
cred_r: &'a [u8], // R's full credential
cred_i: Option<&'a [u8]>, // I's full credential (if provided)
pub struct EdhocResponderProcessingM1<'a, Crypto: CryptoTrait> {
state: ProcessingM1, // opaque state
r: &'a [u8], // private authentication key of R
cred_r: &'a [u8], // R's full credential
cred_i: Option<&'a [u8]>, // I's full credential (if provided)
crypto: Crypto,
}

#[derive(Debug)]
pub struct EdhocResponderWaitM3<'a, Crypto: CryptoTrait> {
state: EdhocState<WaitMessage3>, // opaque state
cred_i: Option<&'a [u8]>, // I's full credential (if provided)
state: WaitM3, // opaque state
cred_i: Option<&'a [u8]>, // I's full credential (if provided)
crypto: Crypto,
}

#[derive(Debug)]
pub struct EdhocResponderDone<Crypto: CryptoTrait> {
state: EdhocState<Completed>,
state: CompletedNew,
crypto: Crypto,
}

impl<'a, Crypto: CryptoTrait> EdhocResponder<'a, Crypto> {
pub fn new(
state: EdhocState<Start>,
state: Start,
crypto: Crypto,
r: &'a [u8],
cred_r: &'a [u8],
Expand All @@ -119,23 +119,28 @@ impl<'a, Crypto: CryptoTrait> EdhocResponder<'a, Crypto> {
pub fn process_message_1(
mut self,
message_1: &BufferMessage1,
) -> Result<EdhocResponderBuildM2<'a, Crypto>, EDHOCError> {
let state = r_process_message_1(self.state, &mut self.crypto, message_1)?;
) -> Result<(EdhocResponderProcessingM1<'a, Crypto>, Option<EADItem>), EDHOCError> {
let (state, ead_1) = r_process_message_1(self.state, &mut self.crypto, message_1)?;

Ok(EdhocResponderBuildM2 {
state,
r: self.r,
cred_r: self.cred_r,
cred_i: self.cred_i,
crypto: self.crypto,
})
Ok((
EdhocResponderProcessingM1 {
state,
r: self.r,
cred_r: self.cred_r,
cred_i: self.cred_i,
crypto: self.crypto,
},
ead_1,
))
}
}

impl<'a, Crypto: CryptoTrait> EdhocResponderBuildM2<'a, Crypto> {
impl<'a, Crypto: CryptoTrait> EdhocResponderProcessingM1<'a, Crypto> {
pub fn prepare_message_2(
mut self,
c_r: u8,
id_cred_r: &IdCred,
ead_2: &Option<EADItem>,
) -> Result<(EdhocResponderWaitM3<'a, Crypto>, BufferMessage2), EDHOCError> {
let (y, g_y) = self.crypto.p256_generate_key_pair();

Expand All @@ -147,6 +152,8 @@ impl<'a, Crypto: CryptoTrait> EdhocResponderBuildM2<'a, Crypto> {
y,
g_y,
c_r,
id_cred_r,
ead_2,
) {
Ok((state, message_2)) => Ok((
EdhocResponderWaitM3 {
Expand Down Expand Up @@ -189,7 +196,7 @@ impl<Crypto: CryptoTrait> EdhocResponderDone<Crypto> {
let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN];
context_buf[..context.len()].copy_from_slice(context);

edhoc_exporter(
edhoc_exporter_new(
&self.state,
&mut self.crypto,
label,
Expand All @@ -203,7 +210,7 @@ impl<Crypto: CryptoTrait> EdhocResponderDone<Crypto> {
let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN];
context_buf[..context.len()].copy_from_slice(context);

edhoc_key_update(
edhoc_key_update_new(
&mut self.state,
&mut self.crypto,
&context_buf,
Expand Down Expand Up @@ -587,13 +594,14 @@ mod test {
// e.g. let ead_1 = i_prepare_ead_1(crypto, &x, suites_i[suites_i_len - 1]);
let (initiator, result) = initiator.prepare_message_1b(&None).unwrap();

let responder = responder.process_message_1(&result).unwrap();
let (responder, _ead_1) = responder.process_message_1(&result).unwrap();

let c_r = generate_connection_identifier_cbor(&mut default_crypto());
let (responder, message_2) = responder.prepare_message_2(c_r).unwrap();
let kid = IdCred::CompactKid(parse_cred(CRED_R).unwrap().1);
let (responder, message_2) = responder.prepare_message_2(c_r, &kid, &None).unwrap();

assert!(c_r != 0xff);
let (initiator, c_r, id_cred_r, ead_2) = initiator.process_message_2a(&message_2).unwrap();
let (initiator, c_r, id_cred_r, _ead_2) = initiator.process_message_2a(&message_2).unwrap();
let (valid_cred_r, g_r) =
credential_check_or_fetch_new(Some(CRED_R.try_into().unwrap()), id_cred_r).unwrap();
// Phase 2: Process EAD_X items that have not been processed yet, and that can be processed before message verification
Expand Down
16 changes: 15 additions & 1 deletion shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,26 @@ pub struct PreparingM1 {
pub suites_i_len: usize,
}

#[derive(Debug)]
pub struct ProcessingM1 {
pub c_i: u8,
pub g_x: BytesP256ElemLen, // ephemeral public key of the initiator
pub h_message_1: BytesHashLen,
}

#[derive(Debug)]
pub struct WaitM2 {
pub x_or_y: BytesP256ElemLen,
pub x_or_y: BytesP256ElemLen, // ephemeral private key of the initiator
pub h_message_1: BytesHashLen,
}

#[derive(Debug)]
pub struct WaitM3 {
pub y: BytesP256ElemLen, // ephemeral private key of the responder
pub prk_3e2m: BytesHashLen,
pub th_3: BytesHashLen,
}

#[derive(Debug)]
pub struct ProcessingM2 {
pub mac_2: BytesMac2,
Expand Down

0 comments on commit f133afb

Please sign in to comment.