lakers_ead_authz/
authenticator.rs

1use crate::consts::*;
2use crate::shared::*;
3use defmt_or_log::trace;
4use lakers_shared::*;
5
6#[derive(Debug, Default)]
7pub struct ZeroTouchAuthenticator;
8#[derive(Debug, Default)]
9pub struct ZeroTouchAuthenticatorWaitVoucherResp;
10
11impl ZeroTouchAuthenticator {
12    pub fn process_ead_1(
13        &self,
14        ead_1: &EADItem,
15        message_1: &EdhocMessageBuffer,
16    ) -> Result<
17        (
18            ZeroTouchAuthenticatorWaitVoucherResp,
19            EdhocMessageBuffer,
20            EdhocMessageBuffer,
21        ),
22        EDHOCError,
23    > {
24        trace!("Enter process_ead_1");
25        let opaque_state: Option<EdhocMessageBuffer> = None; // TODO: receive as parameter
26
27        if ead_1.label != EAD_AUTHZ_LABEL || ead_1.value.is_none() {
28            return Err(EDHOCError::EADUnprocessable);
29        }
30
31        let (loc_w, _enc_id) = parse_ead_1_value(&ead_1.value.unwrap())?;
32        let voucher_request = encode_voucher_request(message_1, &opaque_state);
33
34        Ok((
35            ZeroTouchAuthenticatorWaitVoucherResp::default(),
36            loc_w,
37            voucher_request,
38        ))
39    }
40}
41
42impl ZeroTouchAuthenticatorWaitVoucherResp {
43    pub fn prepare_ead_2(
44        &self,
45        voucher_response: &EdhocMessageBuffer,
46    ) -> Result<EADItem, EDHOCError> {
47        trace!("Enter prepare_ead_2");
48        let (_message_1, voucher, _opaque_state) = parse_voucher_response(&voucher_response)?;
49
50        Ok(EADItem {
51            label: EAD_AUTHZ_LABEL,
52            is_critical: true,
53            value: Some(voucher[..].try_into().unwrap()),
54        })
55    }
56}
57
58pub fn encode_voucher_request(
59    message_1: &EdhocMessageBuffer,
60    opaque_state: &Option<EdhocMessageBuffer>,
61) -> EdhocMessageBuffer {
62    let mut output = EdhocMessageBuffer::new();
63
64    output.content[1] = CBOR_BYTE_STRING;
65    output.content[2] = message_1.len as u8;
66    output.content[3..3 + message_1.len].copy_from_slice(message_1.as_slice());
67
68    if let Some(opaque_state) = opaque_state {
69        output.content[0] = CBOR_MAJOR_ARRAY | 2;
70
71        output.content[3 + message_1.len] = CBOR_BYTE_STRING;
72        output.content[4 + message_1.len] = opaque_state.len as u8;
73        output.content[5 + message_1.len..5 + message_1.len + opaque_state.len]
74            .copy_from_slice(opaque_state.as_slice());
75
76        output.len = 5 + message_1.len + opaque_state.len;
77    } else {
78        output.content[0] = CBOR_MAJOR_ARRAY | 1;
79        output.len = 3 + message_1.len;
80    }
81
82    output
83}
84
85fn parse_voucher_response(
86    voucher_response: &EdhocMessageBuffer,
87) -> Result<
88    (
89        EdhocMessageBuffer,
90        BytesEncodedVoucher,
91        Option<EdhocMessageBuffer>,
92    ),
93    EDHOCError,
94> {
95    let mut decoder = CBORDecoder::new(voucher_response.as_slice());
96
97    let array_size = decoder.array()?;
98    if !(2..=3).contains(&array_size) {
99        return Err(EDHOCError::EADUnprocessable);
100    }
101
102    let message_1: EdhocMessageBuffer = decoder.bytes()?.try_into().unwrap();
103    let voucher: BytesEncodedVoucher = decoder
104        .bytes_sized(ENCODED_VOUCHER_LEN)?
105        .try_into()
106        .unwrap();
107
108    if array_size == 3 {
109        let opaque_state: EdhocMessageBuffer = decoder.bytes()?.try_into().unwrap();
110        return Ok((message_1, voucher, Some(opaque_state)));
111    } else {
112        return Ok((message_1, voucher, None));
113    }
114}
115
116#[cfg(test)]
117mod test_authenticator {
118    use super::*;
119    use crate::test_vectors::*;
120
121    #[test]
122    fn test_parse_ead_1_value() {
123        let loc_w_tv: EdhocMessageBuffer = LOC_W_TV.try_into().unwrap();
124        let enc_id_tv: EdhocMessageBuffer = ENC_ID_TV.try_into().unwrap();
125
126        let res = parse_ead_1_value(&EAD1_VALUE_TV.try_into().unwrap());
127        assert!(res.is_ok());
128        let (loc_w, enc_id) = res.unwrap();
129        assert_eq!(loc_w.content, loc_w_tv.content);
130        assert_eq!(enc_id.content, enc_id_tv.content);
131    }
132
133    #[test]
134    fn test_encode_voucher_request() {
135        let voucher_request_tv: EdhocMessageBuffer = VOUCHER_REQUEST_TV.try_into().unwrap();
136
137        let voucher_request =
138            encode_voucher_request(&MESSAGE_1_WITH_EAD_TV.try_into().unwrap(), &None);
139        assert_eq!(voucher_request.content, voucher_request_tv.content);
140    }
141
142    #[test]
143    fn test_process_ead_1() {
144        let ead_1 = EADItem {
145            label: EAD_AUTHZ_LABEL,
146            is_critical: true,
147            value: Some(EAD1_VALUE_TV.try_into().unwrap()),
148        };
149
150        let ead_authenticator = ZeroTouchAuthenticator::default();
151        let res =
152            ead_authenticator.process_ead_1(&ead_1, &MESSAGE_1_WITH_EAD_TV.try_into().unwrap());
153        assert!(res.is_ok());
154    }
155
156    #[test]
157    fn test_parse_voucher_response() {
158        let voucher_response_tv: EdhocMessageBuffer = VOUCHER_RESPONSE_TV.try_into().unwrap();
159        let message_1_tv: EdhocMessageBuffer = MESSAGE_1_WITH_EAD_TV.try_into().unwrap();
160        let voucher_tv: BytesEncodedVoucher = VOUCHER_TV.try_into().unwrap();
161
162        let res = parse_voucher_response(&voucher_response_tv);
163        assert!(res.is_ok());
164        let (message_1, voucher, opaque_state) = res.unwrap();
165        assert_eq!(message_1.content, message_1_tv.content);
166        assert_eq!(voucher, voucher_tv);
167        assert!(opaque_state.is_none());
168    }
169
170    #[test]
171    fn test_r_prepare_ead_2() {
172        let voucher_response_tv: EdhocMessageBuffer = VOUCHER_RESPONSE_TV.try_into().unwrap();
173        let ead_2_value_tv: EdhocMessageBuffer = EAD2_VALUE_TV.try_into().unwrap();
174
175        let ead_authenticator = ZeroTouchAuthenticatorWaitVoucherResp::default();
176
177        let ead_2 = ead_authenticator
178            .prepare_ead_2(&voucher_response_tv)
179            .unwrap();
180        assert_eq!(ead_2.label, EAD_AUTHZ_LABEL);
181        assert_eq!(ead_2.is_critical, true);
182        assert_eq!(ead_2.value.unwrap().content, ead_2_value_tv.content);
183    }
184}
185
186#[cfg(test)]
187mod test_responder_stateless_operation {
188    use super::*;
189    use crate::test_vectors::*;
190
191    #[test]
192    fn test_slo_encode_voucher_request() {
193        let message_1_tv: EdhocMessageBuffer = MESSAGE_1_WITH_EAD_TV.try_into().unwrap();
194        let opaque_state_tv: EdhocMessageBuffer = SLO_OPAQUE_STATE_TV.try_into().unwrap();
195        let voucher_request_tv: EdhocMessageBuffer = SLO_VOUCHER_REQUEST_TV.try_into().unwrap();
196
197        let voucher_request = encode_voucher_request(&message_1_tv, &Some(opaque_state_tv));
198        assert_eq!(voucher_request.content, voucher_request_tv.content);
199    }
200
201    #[test]
202    fn test_slo_parse_voucher_response() {
203        let voucher_response_tv: EdhocMessageBuffer = SLO_VOUCHER_RESPONSE_TV.try_into().unwrap();
204        let message_1_tv: EdhocMessageBuffer = MESSAGE_1_WITH_EAD_TV.try_into().unwrap();
205        let voucher_tv: BytesEncodedVoucher = VOUCHER_TV.try_into().unwrap();
206        let opaque_state_tv: EdhocMessageBuffer = SLO_OPAQUE_STATE_TV.try_into().unwrap();
207
208        let res = parse_voucher_response(&voucher_response_tv);
209        assert!(res.is_ok());
210        let (message_1, voucher, opaque_state) = res.unwrap();
211        assert_eq!(message_1.content, message_1_tv.content);
212        assert_eq!(voucher, voucher_tv);
213        assert_eq!(opaque_state.unwrap().content, opaque_state_tv.content);
214    }
215}