Skip to content

Commit

Permalink
Merge pull request #222 from geonnave/add-python-authz-device
Browse files Browse the repository at this point in the history
Add authz device to Python wrapper
  • Loading branch information
geonnave authored Feb 16, 2024
2 parents 0071db1 + e617dbb commit 206db22
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 12 deletions.
12 changes: 6 additions & 6 deletions ead/lakers-ead-authz/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ use super::shared::*;
use crate::ZeroTouchError;
use lakers_shared::{Crypto as CryptoTrait, *};

#[derive(Debug)]
#[derive(Default, Debug)]
#[repr(C)]
pub struct ZeroTouchDevice {
pub(crate) id_u: EdhocMessageBuffer, // identifier of the device (U), equivalent to ID_CRED_I in EDHOC
pub g_w: BytesP256ElemLen, // public key of the enrollment server (W)
pub(crate) loc_w: EdhocMessageBuffer, // address of the enrollment server (W)
pub id_u: EdhocMessageBuffer, // identifier of the device (U), equivalent to ID_CRED_I in EDHOC
pub g_w: BytesP256ElemLen, // public key of the enrollment server (W)
pub loc_w: EdhocMessageBuffer, // address of the enrollment server (W)
}

#[derive(Debug)]
#[derive(Default, Debug)]
#[repr(C)]
pub struct ZeroTouchDeviceWaitEAD2 {
prk: BytesHashLen,
pub h_message_1: BytesHashLen,
}

#[derive(Debug)]
#[derive(Default, Debug)]
#[repr(C)]
pub struct ZeroTouchDeviceDone {
pub voucher: BytesMac,
Expand Down
2 changes: 1 addition & 1 deletion lakers-python/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "lakers-python" # this will be the name of the package on pypi
edition = "2021"
version ="0.1.3"
version ="0.2.0"
repository.workspace = true
license.workspace = true

Expand Down
15 changes: 10 additions & 5 deletions lakers-python/src/ead_authz/authenticator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use lakers::*;
use pyo3::prelude::*;
use pyo3::{
prelude::*,
types::{PyBytes, PyString},
};

#[pyclass(name = "AuthzAutenticator")]
pub struct PyAuthzAutenticator {
Expand All @@ -17,18 +20,20 @@ impl PyAuthzAutenticator {
}
}

pub fn process_ead_1(
pub fn process_ead_1<'a>(
&mut self,
py: Python<'a>,
ead_1: EADItem,
message_1: Vec<u8>,
) -> PyResult<(Vec<u8>, Vec<u8>)> {
) -> PyResult<(&'a PyString, &'a PyBytes)> {
let message_1 = EdhocMessageBuffer::new_from_slice(message_1.as_slice())?;
let (state, loc_w, voucher_request) =
self.authenticator.process_ead_1(&ead_1, &message_1)?;
self.authenticator_wait = state;
let loc_w = std::str::from_utf8(loc_w.as_slice()).unwrap();
Ok((
Vec::from(loc_w.as_slice()),
Vec::from(voucher_request.as_slice()),
PyString::new(py, loc_w),
PyBytes::new(py, voucher_request.as_slice()),
))
}

Expand Down
63 changes: 63 additions & 0 deletions lakers-python/src/ead_authz/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use lakers::*;
use lakers_crypto::default_crypto;
use pyo3::{exceptions::PyBaseException, prelude::*, types::PyBytes};

#[pyclass(name = "AuthzDevice")]
pub struct PyAuthzDevice {
device: ZeroTouchDevice,
device_wait: ZeroTouchDeviceWaitEAD2,
device_done: ZeroTouchDeviceDone,
}

#[pymethods]
impl PyAuthzDevice {
#[new]
fn new(id_u: Vec<u8>, g_w: Vec<u8>, loc_w: &str) -> Self {
let id_u = EdhocMessageBuffer::new_from_slice(id_u.as_slice()).unwrap();
let loc_w = EdhocMessageBuffer::new_from_slice(loc_w.as_bytes()).unwrap();
let mut g_w_arr = BytesP256ElemLen::default();
g_w_arr.copy_from_slice(&g_w[..]);
Self {
device: ZeroTouchDevice {
id_u,
g_w: g_w_arr,
loc_w,
},
device_wait: ZeroTouchDeviceWaitEAD2::default(),
device_done: ZeroTouchDeviceDone::default(),
}
}

pub fn prepare_ead_1(&mut self, secret: Vec<u8>, ss: u8) -> PyResult<EADItem> {
let mut secret_arr = BytesP256ElemLen::default();
secret_arr.copy_from_slice(&secret[..]);
let (device_wait, ead_1) = self
.device
.prepare_ead_1(&mut default_crypto(), secret_arr, ss);
self.device_wait = device_wait;
Ok(ead_1)
}

pub fn process_ead_2(&mut self, ead_2: EADItem, cred_v: &[u8]) -> PyResult<bool> {
match self
.device_wait
.process_ead_2(&mut default_crypto(), ead_2, cred_v)
{
Ok(device_done) => {
self.device_done = device_done;
Ok(true)
}
Err(error) => Err(PyBaseException::new_err(error as i8)),
}
}

pub fn set_h_message_1(&mut self, h_message_1: Vec<u8>) {
let mut h_message_1_arr = BytesHashLen::default();
h_message_1_arr.copy_from_slice(&h_message_1[..]);
self.device_wait.set_h_message_1(h_message_1_arr);
}

pub fn get_g_w<'a>(&self, py: Python<'a>) -> PyResult<&'a PyBytes> {
Ok(PyBytes::new(py, &self.device.g_w[..]))
}
}
2 changes: 2 additions & 0 deletions lakers-python/src/ead_authz/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod authenticator;
pub use authenticator::*;
mod device;
pub use device::*;
mod server;
pub use server::*;
19 changes: 19 additions & 0 deletions lakers-python/src/initiator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,23 @@ impl PyEdhocInitiator {
);
Ok(PyBytes::new(py, &res[..SHA256_DIGEST_LEN]))
}

pub fn get_h_message_1<'a>(&self, py: Python<'a>) -> PyResult<&'a PyBytes> {
Ok(PyBytes::new(py, &self.wait_m2.h_message_1[..]))
}

pub fn compute_ephemeral_secret<'a>(
&self,
py: Python<'a>,
g_a: Vec<u8>,
) -> PyResult<&'a PyBytes> {
let mut g_a_arr = BytesP256ElemLen::default();
g_a_arr.copy_from_slice(&g_a[..]);
let secret = default_crypto().p256_ecdh(&self.start.x, &g_a_arr);
Ok(PyBytes::new(py, &secret[..]))
}

pub fn selected_cipher_suite(&self) -> PyResult<u8> {
Ok(self.start.suites_i[self.start.suites_i_len - 1])
}
}
1 change: 1 addition & 0 deletions lakers-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fn lakers_python(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<lakers::CredentialTransfer>()?;
m.add_class::<lakers::EADItem>()?;
// ead-authz items
m.add_class::<ead_authz::PyAuthzDevice>()?;
m.add_class::<ead_authz::PyAuthzAutenticator>()?;
m.add_class::<ead_authz::PyAuthzEnrollmentServer>()?;
Ok(())
Expand Down
55 changes: 55 additions & 0 deletions lakers-python/test/test_ead_authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
import pytest

# values from traces-zeroconf.ipynb
ID_U = bytes.fromhex("a104412b")
G_W = bytes.fromhex("FFA4F102134029B3B156890B88C9D9619501196574174DCB68A07DB0588E4D41")
LOC_W = "coap://enrollment.server"
W = bytes.fromhex("4E5E15AB35008C15B89E91F9F329164D4AACD53D9923672CE0019F9ACD98573F")
KID_I = 0x2b
CRED_I = bytes.fromhex("A2027734322D35302D33312D46462D45462D33372D33322D333908A101A5010202412B2001215820AC75E9ECE3E50BFC8ED60399889522405C47BF16DF96660A41298CB4307F7EB62258206E5DE611388A4B8A8211334AC7D37ECB52A387D257E6DB3C2A93DF21FF3AFFC8")
I = bytes.fromhex("fb13adeb6518cee5f88417660841142e830a81fe334380a953406a1305e8706b")
CRED_V = bytes.fromhex("a2026b6578616d706c652e65647508a101a501020241322001215820bbc34960526ea4d32e940cad2a234148ddc21791a12afbcbac93622046dd44f02258204519e257236b2a0ce2023f0931f1f386ca7afda64fcde0108c224c51eabf6072")
V = bytes.fromhex("72cc4761dbd4c78f758931aa589d348d1ef874a7e303ede2f140dcf3e6aa4aac")
EAD_1_VALUE = bytes.fromhex("58287818636f61703a2f2f656e726f6c6c6d656e742e7365727665724dda9784962883c96ed01ff122c3")
MESSAGE_1_WITH_EAD = bytes.fromhex("0382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b6370158287818636f61703a2f2f656e726f6c6c6d656e742e7365727665724dda9784962883c96ed01ff122c3")
VOUCHER_RESPONSE = bytes.fromhex("8258520382060258208af6f430ebe18d34184017a9a11bf511c8dff8f834730b96c1b7c8dbca2fc3b6370158287818636f61703a2f2f656e726f6c6c6d656e742e7365727665724dda9784962883c96ed01ff122c34948c783671337f75bd5")
Expand All @@ -20,10 +26,59 @@ def test_authenticator_and_server():

ead_1 = lakers.EADItem(1, True, EAD_1_VALUE)
loc_w, voucher_request = authenticator.process_ead_1(ead_1, MESSAGE_1_WITH_EAD)
assert type(loc_w) == str
voucher_response = enrollment_server.handle_voucher_request(voucher_request)
assert type(voucher_response) == bytes

ead_2 = authenticator.prepare_ead_2(voucher_response)
assert ead_2.label() == 1
assert ead_2.is_critical() == True
assert ead_2.value() == EAD_2_VALUE

def test_handshake_with_authz():
initiator = lakers.EdhocInitiator()
responder = lakers.EdhocResponder(V, CRED_V)

device = lakers.AuthzDevice(
ID_U,
G_W,
LOC_W,
)
authenticator = lakers.AuthzAutenticator()
enrollment_server = lakers.AuthzEnrollmentServer(
W,
CRED_V,
[KID_I],
)

# initiator
ead_1 = device.prepare_ead_1(
initiator.compute_ephemeral_secret(device.get_g_w()),
initiator.selected_cipher_suite(),
)
message_1 = initiator.prepare_message_1(c_i=None, ead_1=ead_1)
device.set_h_message_1(initiator.get_h_message_1())

# responder
ead_1 = responder.process_message_1(message_1)
loc_w, voucher_request = authenticator.process_ead_1(ead_1, message_1)
voucher_response = enrollment_server.handle_voucher_request(voucher_request)
ead_2 = authenticator.prepare_ead_2(voucher_response)
message_2 = responder.prepare_message_2(lakers.CredentialTransfer.ByReference, None, ead_2)
assert type(message_2) == bytes

# initiator
c_r, id_cred_r, ead_2 = initiator.parse_message_2(message_2)
valid_cred_r = lakers.credential_check_or_fetch(id_cred_r, CRED_V)
assert device.process_ead_2(ead_2, CRED_V) # voucher is valid!
initiator.verify_message_2(I, CRED_I, valid_cred_r)
message_3, i_prk_out = initiator.prepare_message_3(lakers.CredentialTransfer.ByReference, None)
assert type(message_3) == bytes

# responder
id_cred_i, ead_3 = responder.parse_message_3(message_3)
assert ead_3 == None
valid_cred_i = lakers.credential_check_or_fetch(id_cred_i, CRED_I)
r_prk_out = responder.verify_message_3(valid_cred_i)

assert i_prk_out == r_prk_out

0 comments on commit 206db22

Please sign in to comment.