Skip to content

Commit

Permalink
feat: prepare ead_2
Browse files Browse the repository at this point in the history
  • Loading branch information
geonnave committed Oct 12, 2023
1 parent f365e06 commit f680b8c
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 45 deletions.
93 changes: 85 additions & 8 deletions ead/edhoc-ead-zeroconf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
use edhoc_consts::*;
use edhoc_crypto::*;

// initiator side
// ---- initiator side (device)

#[derive(Default, PartialEq, Copy, Clone, Debug)]
pub enum EADInitiatorProtocolState {
#[default]
Expand Down Expand Up @@ -228,7 +229,8 @@ fn encode_ead_1(loc_w: &EdhocMessageBuffer, enc_id: &EdhocMessageBuffer) -> Edho
output
}

// responder side
// ---- responder side (authenticator)

#[derive(Default, PartialEq, Copy, Clone, Debug)]
pub enum EADResponderProtocolState {
#[default]
Expand Down Expand Up @@ -264,7 +266,7 @@ pub fn ead_responder_set_global_state(new_state: EADResponderState) {
}
}

// FIXME: receive opaque_state as parameter, but that requires changing the r_process_message_1 function signature
// FIXME: do some plumbing to receive opaque_state as parameter
use hexlit::hex;
const OPAQUE_STATE_TV: &[u8] =
&hex!("827819666538303a3a623833343a643630623a373936663a38646530198bed");
Expand All @@ -286,14 +288,15 @@ pub fn r_process_ead_1(ead_1: &EADItem, message_1: &BufferMessage1) -> Result<()
Ok(())
}

pub fn r_prepare_ead_2() -> Option<EADItem> {
pub fn r_prepare_ead_2(voucher_response: &EdhocMessageBuffer) -> Option<EADItem> {
let mut ead_2 = EADItem::new();

// add the label to the buffer (non-critical)
// FIXME: we probably don't want to parse the voucher response here, but rather receive only the 'voucher' already parsed
let (_message_1, voucher, _opaque_state) = parse_voucher_response(voucher_response).unwrap();

ead_2.label = EAD_ZEROCONF_LABEL;
ead_2.is_critical = true;

// TODO: append Voucher (H(message_1), CRED_V) to the buffer
ead_2.value = Some(voucher);

// NOTE: see the note in lib.rs::test_ead
// state.protocol_state = EADResponderProtocolState::WaitMessage3;
Expand All @@ -312,6 +315,43 @@ pub fn r_process_ead_3(_ead_3: EADItem) -> Result<(), ()> {
Ok(())
}

fn parse_voucher_response(
voucher_response: &EdhocMessageBuffer,
) -> Result<(EdhocMessageBuffer, EdhocMessageBuffer, EdhocMessageBuffer), ()> {
let mut message_1 = EdhocMessageBuffer::new();
let mut voucher = EdhocMessageBuffer::new();
let mut opaque_state = EdhocMessageBuffer::new();

let array_size = voucher_response.content[0] - CBOR_MAJOR_ARRAY;

if !(array_size == 2 || array_size == 3) || voucher_response.content[1] != CBOR_BYTE_STRING {
return Err(());
}

message_1.len = voucher_response.content[2] as usize;
message_1.content[..message_1.len]
.copy_from_slice(&voucher_response.content[3..3 + message_1.len]);

if voucher_response.content[3 + message_1.len] != CBOR_BYTE_STRING {
return Err(());
}
voucher.len = voucher_response.content[4 + message_1.len] as usize;
voucher.content[..voucher.len].copy_from_slice(
&voucher_response.content[5 + message_1.len..5 + message_1.len + voucher.len],
);

if voucher_response.content[5 + message_1.len + voucher.len] != CBOR_BYTE_STRING {
return Err(());
}
opaque_state.len = voucher_response.content[6 + message_1.len + voucher.len] as usize;
opaque_state.content[..opaque_state.len].copy_from_slice(
&voucher_response.content
[7 + message_1.len + voucher.len..7 + message_1.len + voucher.len + opaque_state.len],
);

Ok((message_1, voucher, opaque_state))
}

fn parse_ead_1_value(
ead_1_value: &Option<EdhocMessageBuffer>,
) -> Result<(EdhocMessageBuffer, EdhocMessageBuffer), ()> {
Expand Down Expand Up @@ -347,7 +387,8 @@ pub fn encode_voucher_request(
output
}

// enrollment server
// ---- enrollment server side

fn handle_voucher_request(
vreq: &EdhocMessageBuffer,
cred_v: &EdhocMessageBuffer,
Expand Down Expand Up @@ -514,6 +555,10 @@ mod test_vectors {
&hex!("d99c86cf666f614d82cc3cfd0fb53cfa393f463f42ece49e38b056808ad5dfc9");
pub const VOUCHER_TV: &[u8] =
&hex!("5820d99c86cf666f614d82cc3cfd0fb53cfa393f463f42ece49e38b056808ad5dfc9");

// EAD_2
pub const EAD2_VALUE_TV: &[u8] =
&hex!("5820d99c86cf666f614d82cc3cfd0fb53cfa393f463f42ece49e38b056808ad5dfc9");
}

#[cfg(test)]
Expand Down Expand Up @@ -619,6 +664,38 @@ mod test_responder {
EADResponderProtocolState::ProcessedEAD1
);
}

#[test]
fn test_parse_voucher_response() {
let voucher_response_tv: EdhocMessageBuffer = VOUCHER_RESPONSE_TV.try_into().unwrap();
let message_1_tv: EdhocMessageBuffer = MESSAGE_1_WITH_EAD_TV.try_into().unwrap();
let voucher_tv: EdhocMessageBuffer = VOUCHER_TV.try_into().unwrap();
let opaque_state_tv: EdhocMessageBuffer = OPAQUE_STATE_TV.try_into().unwrap();

let res = parse_voucher_response(&voucher_response_tv);
assert!(res.is_ok());
let (message_1, voucher, opaque_state) = res.unwrap();
assert_eq!(message_1.content, message_1_tv.content);
assert_eq!(voucher.content, voucher_tv.content);
assert_eq!(opaque_state.content, opaque_state_tv.content);
}

#[test]
fn test_r_prepare_ead_2() {
let voucher_response_tv: EdhocMessageBuffer = VOUCHER_RESPONSE_TV.try_into().unwrap();
let ead_2_value_tv: EdhocMessageBuffer = EAD2_VALUE_TV.try_into().unwrap();

ead_responder_set_global_state(EADResponderState::new());

let ead_2 = r_prepare_ead_2(&voucher_response_tv).unwrap();
assert_eq!(
ead_responder_get_global_state().protocol_state,
EADResponderProtocolState::Completed
);
assert_eq!(ead_2.label, EAD_ZEROCONF_LABEL);
assert_eq!(ead_2.is_critical, true);
assert_eq!(ead_2.value.unwrap().content, ead_2_value_tv.content);
}
}

#[cfg(test)]
Expand Down
104 changes: 68 additions & 36 deletions examples/traces-zeroconf.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
{
"cell_type": "code",
"execution_count": 69,
"execution_count": 94,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -38,7 +38,7 @@
},
{
"cell_type": "code",
"execution_count": 70,
"execution_count": 95,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -171,9 +171,31 @@
},
{
"cell_type": "code",
"execution_count": 71,
"execution_count": 104,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.002s\n",
"\n",
"OK\n"
]
},
{
"data": {
"text/plain": [
"<unittest.main.TestProgram at 0x7f6102440340>"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def p256_ecdh(d_hex, x_hex, y_hex):\n",
" private_key = ec.derive_private_key(int(d_hex, 16), ec.SECP256R1(), default_backend())\n",
Expand All @@ -192,7 +214,19 @@
" return hkdf.hkdf_expand(unhexlify(prk), unhexlify(info), length, hash=hashlib.sha256).hex()\n",
"\n",
"def aes_ccm_encrypt_tag_8(key, iv, enc_structure, plaintext):\n",
" return aead.AESCCM(unhexlify(key), tag_length=8).encrypt(unhexlify(iv), unhexlify(plaintext), unhexlify(enc_structure)).hex()\n"
" return aead.AESCCM(unhexlify(key), tag_length=8).encrypt(unhexlify(iv), unhexlify(plaintext), unhexlify(enc_structure)).hex()\n",
"\n",
"def sha256_digest(message):\n",
" return hashlib.sha256(unhexlify(message)).hexdigest()\n",
"\n",
"import unittest\n",
"class Test(unittest.TestCase):\n",
" def test_ecdh(self):\n",
" self.assertEqual(\n",
" p256_ecdh(keys_tv[\"ephemeral_keys\"][\"X\"], keys_tv[\"static_keys\"][\"G_W\"], keys_tv[\"static_keys\"][\"G_W_y\"]), \n",
" p256_ecdh(keys_tv[\"static_keys\"][\"W\"], keys_tv[\"ephemeral_keys\"][\"G_X\"], keys_tv[\"ephemeral_keys\"][\"G_X_y\"]), \n",
" )\n",
"unittest.main(argv=[''], exit=False)"
]
},
{
Expand All @@ -206,7 +240,7 @@
},
{
"cell_type": "code",
"execution_count": 72,
"execution_count": 97,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -329,7 +363,7 @@
},
{
"cell_type": "code",
"execution_count": 73,
"execution_count": 98,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -384,7 +418,7 @@
},
{
"cell_type": "code",
"execution_count": 89,
"execution_count": 99,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -413,9 +447,6 @@
}
],
"source": [
"def sha256_digest(message):\n",
" return hashlib.sha256(unhexlify(message)).hexdigest()\n",
"\n",
"def add_voucher_response(tv):\n",
" h_message_1 = sha256_digest(tv[\"input\"][\"MESSAGE_1_WITH_EAD\"])\n",
" voucher_input = (cbor2.dumps(unhexlify(h_message_1)) + cbor2.dumps(unhexlify(tv[\"input\"][\"CRED_V\"]))).hex()\n",
Expand Down Expand Up @@ -463,47 +494,48 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unit tests"
"### EAD_2 traces\n",
"\n",
"This one is rather unecessary, sinde EAD_2 = Voucher.\n",
"\n",
"See https://www.ietf.org/archive/id/draft-selander-lake-authz-03.html#name-voucher"
]
},
{
"cell_type": "code",
"execution_count": 75,
"execution_count": 105,
"metadata": {},
"outputs": [
{
"name": "stderr",
"name": "stdout",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.001s\n",
"\n",
"OK\n"
"# input\n",
"const VOUCHER_TV: &[u8] = &hex!(\"5820d99c86cf666f614d82cc3cfd0fb53cfa393f463f42ece49e38b056808ad5dfc9\");\n",
"\n",
"# ead2\n",
"const EAD2_VALUE_TV: &[u8] = &hex!(\"5820d99c86cf666f614d82cc3cfd0fb53cfa393f463f42ece49e38b056808ad5dfc9\");\n"
]
},
{
"data": {
"text/plain": [
"<unittest.main.TestProgram at 0x7f61024982e0>"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import unittest\n",
"def add_ead2(tv):\n",
" tv.update({\n",
" \"ead2\": {\n",
" \"ead2_value\": tv[\"input\"][\"VOUCHER\"],\n",
" }\n",
" })\n",
" return tv\n",
"\n",
"class Test(unittest.TestCase):\n",
" def test_ead_1(self):\n",
" self.assertEqual(\n",
" p256_ecdh(keys_tv[\"ephemeral_keys\"][\"X\"], keys_tv[\"static_keys\"][\"G_W\"], keys_tv[\"static_keys\"][\"G_W_y\"]), \n",
" p256_ecdh(keys_tv[\"static_keys\"][\"W\"], keys_tv[\"ephemeral_keys\"][\"G_X\"], keys_tv[\"ephemeral_keys\"][\"G_X_y\"]), \n",
" )\n",
"ead2_tv = {\n",
" \"input\": {\n",
" \"VOUCHER\": voucher_tv[\"voucher_response\"][\"voucher\"],\n",
" }\n",
"}\n",
"ead2_tv = add_ead2(ead2_tv)\n",
"\n",
"unittest.main(argv=[''], exit=False)"
"format_tv(ead2_tv, \"rust\")"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion lib/src/edhoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ 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
/// Check for: a bstr denoted by two bytes, one for type the other for content length
#[inline(always)]
fn is_cbor_bstr_2bytes_prefix(byte: u8) -> bool {
return byte == CBOR_BYTE_STRING;
Expand Down

0 comments on commit f680b8c

Please sign in to comment.