Contiki-NG
Loading...
Searching...
No Matches
edhoc-client.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024, RISE Research Institutes of Sweden AB
3 * Copyright (c) 2020, Industrial Systems Institute (ISI), Patras, Greece
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holder nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 */
31
32/**
33 * \file
34 * EDHOC client API [RFC9528] with CoAP Block-Wise Transfer [RFC7959]
35 * \author
36 * Lidia Pocero <pocero@isi.gr>, Peter A Jonsson, Rikard Höglund,
37 * Marco Tiloca, Niclas Finne, and Nicolas Tsiftes
38 */
39
40#include "contiki.h"
41#include "coap-callback-api.h"
42#include "coap-timer.h"
43#include "edhoc-client.h"
45#include "edhoc-msg-handlers.h"
46#include "edhoc-trace.h"
47#include "lib/memb.h"
48#include <assert.h>
49
50#include "sys/log.h"
51#define LOG_MODULE "EDHOC"
52#define LOG_LEVEL LOG_LEVEL_EDHOC
53
54/*---------------------------------------------------------------------------*/
55/* Protocol states (stored in client->state). */
56enum edhoc_protocol_state {
57 PROTO_IDLE = 0,
58 PROTO_RX_MSG2 = 1,
59 PROTO_RX_RSP_MSG3 = 2,
60 PROTO_EXP_READY = 3,
61};
62
63/* Event types (stored in edhoc_state.val). */
64enum edhoc_event_type {
65 EVT_RESTART = 0,
66 EVT_FINISHED = 1,
67 EVT_TIMEOUT = 2,
68 EVT_BLOCK1 = 3,
69 EVT_POST = 4,
70 EVT_TRIES_EXPIRE = 5,
71 EVT_BLOCKING = 6,
72};
73/*---------------------------------------------------------------------------*/
74/* For use of block-wise post and answer */
75static coap_callback_request_state_t state;
76static uint8_t msg_num;
77static size_t send_sz;
78static uint8_t *rx_ptr;
79static size_t rx_sz;
80static edhoc_client_t *client;
81static coap_timer_t timer;
82static edhoc_data_event_t edhoc_state;
83static process_event_t edhoc_event = PROCESS_EVENT_NONE;
84
85static uint8_t attempt = 0;
86static int err = 0;
87static edhoc_msg_2_t msg2;
88/*---------------------------------------------------------------------------*/
89PROCESS(edhoc_client, "EDHOC Client");
90/*---------------------------------------------------------------------------*/
91#if EDHOC_TEST == EDHOC_TEST_VECTOR_TRACE_DH
92/* Hard-wired ephemeral keys from RFC 9529 for verifying that all operations yield the same
93 intermediate results as the test vectors. */
94
95/* Initiator's ephemeral public key, 'x'-coordinate. G_X */
96static const uint8_t eph_pub_x_i[ECC_KEY_LEN] = { 0x8a, 0xf6, 0xf4, 0x30, 0xeb, 0xe1, 0x8d, 0x34, 0x18, 0x40, 0x17, 0xa9, 0xa1, 0x1b, 0xf5, 0x11, 0xc8, 0xdf, 0xf8, 0xf8, 0x34, 0x73, 0x0b,
97 0x96, 0xc1, 0xb7, 0xc8, 0xdb, 0xca, 0x2f, 0xc3, 0xb6 };
98
99/* Initiator's ephemeral public key, one 'y'-coordinate. */
100static const uint8_t eph_pub_y_i[ECC_KEY_LEN] = { 0x51, 0xe8, 0xaf, 0x6c, 0x6e, 0xdb, 0x78, 0x16, 0x01, 0xad, 0x1d, 0x9c, 0x5f, 0xa8, 0xbf, 0x7a, 0xa1, 0x57, 0x16, 0xc7, 0xc0, 0x6a, 0x5d,
101 0x03, 0x85, 0x03, 0xc6, 0x14, 0xff, 0x80, 0xc9, 0xb3 };
102
103/* Initiator's ephemeral private key. X */
104static const uint8_t eph_private_i[ECC_KEY_LEN] = { 0x36, 0x8e, 0xc1, 0xf6, 0x9a, 0xeb, 0x65, 0x9b, 0xa3, 0x7d, 0x5a, 0x8d, 0x45, 0xb2, 0x1b, 0xdc, 0x02, 0x99, 0xdc, 0xea, 0xa8, 0xef, 0x23,
105 0x5f, 0x3c, 0xa4, 0x2c, 0xe3, 0x53, 0x0f, 0x95, 0x25 };
106#endif
107/*---------------------------------------------------------------------------*/
108int8_t
109edhoc_client_callback(process_event_t ev, void *data)
110{
111 if(ev == edhoc_event && data == &edhoc_state) {
112 LOG_DBG("client callback: ev=%d, state=%d\n", ev, edhoc_state.val);
113 if(edhoc_state.val == EVT_FINISHED) {
114 LOG_INFO("client callback: CL_FINISHED\n");
115 return 1;
116 }
117 if(edhoc_state.val == EVT_TRIES_EXPIRE) {
118 LOG_WARN("client callback: CL_TRIES_EXPIRE\n");
119 return -1;
120 }
121 }
122 return 0;
123}
124/*---------------------------------------------------------------------------*/
125void
127{
129}
130/*---------------------------------------------------------------------------*/
131void
132edhoc_client_set_ad_1(const void *data_buffer, uint8_t buffer_size)
133{
134 if(buffer_size > EDHOC_MAX_AD_SZ) {
135 LOG_ERR("AD_1 size (%d) exceeds maximum allowed (%d)\n", buffer_size, EDHOC_MAX_AD_SZ);
136 return;
137 }
138 if(data_buffer == NULL) {
139 LOG_ERR("Invalid buffer pointer for AD_1\n");
140 return;
141 }
142 memcpy(edhoc_state.ad.ad_1, data_buffer, buffer_size);
143 edhoc_state.ad.ad_1_sz = buffer_size;
144}
145/*---------------------------------------------------------------------------*/
146void
147edhoc_client_set_ad_3(const void *data_buffer, uint8_t buffer_size)
148{
149 if(buffer_size > EDHOC_MAX_AD_SZ) {
150 LOG_ERR("AD_3 size (%d) exceeds maximum allowed (%d)\n", buffer_size, EDHOC_MAX_AD_SZ);
151 return;
152 }
153 if(data_buffer == NULL) {
154 LOG_ERR("Invalid buffer pointer for AD_3\n");
155 return;
156 }
157 memcpy(edhoc_state.ad.ad_3, data_buffer, buffer_size);
158 edhoc_state.ad.ad_3_sz = buffer_size;
159}
160/*---------------------------------------------------------------------------*/
161uint8_t
162edhoc_client_get_ad_2(char *buf, size_t buf_sz)
163{
164 if(buf == NULL) {
165 LOG_ERR("Invalid buffer pointer for getting AD_2\n");
166 return 0;
167 }
168 if(edhoc_state.ad.ad_2_sz > buf_sz) {
169 LOG_ERR("Destination buffer size (%zu) too small for AD_2 (%d)\n", buf_sz, edhoc_state.ad.ad_2_sz);
170 return 0;
171 }
172 memcpy(buf, edhoc_state.ad.ad_2, edhoc_state.ad.ad_2_sz);
173 return edhoc_state.ad.ad_2_sz;
174}
175/*---------------------------------------------------------------------------*/
176static void
177client_timeout_callback(coap_timer_t *timer)
178{
179 LOG_ERR("EDHOC client timeout: no response received\n");
181 edhoc_state.val = EVT_TIMEOUT;
182 process_post(&edhoc_client, edhoc_event, &edhoc_state);
183}
184/*---------------------------------------------------------------------------*/
185MEMB(edhoc_client_storage, edhoc_client_t, 1);
186/*---------------------------------------------------------------------------*/
187static int handle_exp_ready(edhoc_client_t *client);
188/*---------------------------------------------------------------------------*/
189static inline edhoc_client_t *
190client_context_new(void)
191{
192 edhoc_client_t *c = memb_alloc(&edhoc_client_storage);
193 if(c) {
194 memset(c, 0, sizeof(edhoc_client_t));
195 }
196 return c;
197}
198/*---------------------------------------------------------------------------*/
199static inline void
200client_context_free(edhoc_client_t *c)
201{
202 memset(c, 0, sizeof(edhoc_client_t));
203 memb_free(&edhoc_client_storage, c);
204}
205/*---------------------------------------------------------------------------*/
206static int
207client_block2_handler(coap_message_t *response, uint8_t *target,
208 size_t *len, size_t max_len)
209{
210 const uint8_t *payload = NULL;
211 int pay_len = coap_get_payload(response, &payload);
212
213 if(response->block2_offset + pay_len > max_len) {
214 LOG_ERR("EDHOC message size (%d) exceeds max buffer (%d)\n", (int)pay_len, EDHOC_MAX_BUFFER);
215 coap_status_code = REQUEST_ENTITY_TOO_LARGE_4_13;
216 coap_error_message = "Message too big";
217 return -1;
218 }
219
220 if(target && len) {
221 memcpy(target + response->block2_offset, payload, pay_len);
222 *len = response->block2_offset + pay_len;
223 LOG_DBG_BYTES((uint8_t *)payload, (unsigned long)pay_len);
224 LOG_DBG_("\n");
225 }
226 return 0;
227}
228/*---------------------------------------------------------------------------*/
229static bool
230validate_response(coap_callback_request_state_t *callback_state)
231{
232 if(callback_state->state.response == NULL) {
233 LOG_WARN("Request timed out\n");
234 return false;
235 }
236
237 if(memcmp(callback_state->state.request->token,
238 callback_state->state.response->token,
239 callback_state->state.request->token_len) != 0) {
240 LOG_ERR("Response token mismatch\n");
241 } else if(memcmp(&client->server_ep.ipaddr,
242 &callback_state->state.remote_endpoint->ipaddr,
243 sizeof(uip_ipaddr_t)) != 0) {
244 LOG_ERR("Response from unexpected server\n");
245 } else {
246 return true;
247 }
248
249 edhoc_state.val = EVT_RESTART;
251 process_post(&edhoc_client, edhoc_event, &edhoc_state);
252 return false;
253}
254/*---------------------------------------------------------------------------*/
255static void
256client_response_handler(coap_callback_request_state_t *callback_state)
257{
258 if(!validate_response(callback_state)) {
259 return;
260 }
261
262 if(callback_state->state.response->code != CHANGED_2_04) {
263 LOG_WARN("Response code is not CHANGED_2_04\n");
264 }
265
266 coap_set_option(callback_state->state.response, COAP_OPTION_BLOCK2);
267
268 client_block2_handler(callback_state->state.response,
269 rx_ptr, &rx_sz, EDHOC_MAX_PAYLOAD_LEN);
270 if(!callback_state->state.more) {
271 edhoc_ctx->buffers.rx_sz = rx_sz;
272 edhoc_state.val = EVT_BLOCKING;
273 process_post(PROCESS_BROADCAST, edhoc_event, &edhoc_state);
274 }
275}
276/*---------------------------------------------------------------------------*/
277static void
278client_chunk_handler(coap_callback_request_state_t *callback_state)
279{
280 if(!validate_response(callback_state)) {
281 return;
282 }
283
284 edhoc_state.val = EVT_BLOCK1;
285 process_post(&edhoc_client, edhoc_event, &edhoc_state);
286}
287/*---------------------------------------------------------------------------*/
288static void
289edhoc_client_post(void)
290{
291 coap_init_message(state.state.request, COAP_TYPE_CON, COAP_POST, 0);
292 coap_set_header_uri_path(state.state.request, EDHOC_COAP_URI_PATH);
293
294 send_sz = 0;
295 msg_num = 0;
296 state.state.block_num = 0;
297}
298/*---------------------------------------------------------------------------*/
299static int
300edhoc_client_post_blocks(void)
301{
302 if(edhoc_ctx->buffers.tx_sz - send_sz > COAP_MAX_CHUNK_SIZE) {
303 coap_set_payload(state.state.request,
304 (uint8_t *)edhoc_ctx->buffers.msg_tx + send_sz,
305 COAP_MAX_CHUNK_SIZE);
306 coap_set_header_block1(state.state.request, msg_num,
307 1, COAP_MAX_CHUNK_SIZE);
308 msg_num++;
309 send_sz += COAP_MAX_CHUNK_SIZE;
310 coap_send_request(&state, state.state.remote_endpoint,
311 state.state.request, client_chunk_handler);
312 return 0;
313 } else if(edhoc_ctx->buffers.tx_sz < COAP_MAX_CHUNK_SIZE) {
314 coap_set_payload(state.state.request,
315 (uint8_t *)edhoc_ctx->buffers.msg_tx,
316 edhoc_ctx->buffers.tx_sz);
317 rx_ptr = edhoc_ctx->buffers.msg_rx;
318 rx_sz = 0;
319 state.state.block_num = 0;
320 coap_send_request(&state, state.state.remote_endpoint,
321 state.state.request, client_response_handler);
322 return 1;
323 } else {
324 coap_set_payload(state.state.request,
325 (uint8_t *)edhoc_ctx->buffers.msg_tx + send_sz,
326 edhoc_ctx->buffers.tx_sz - send_sz);
327 coap_set_header_block1(state.state.request, msg_num, 0,
328 COAP_MAX_CHUNK_SIZE);
329 send_sz += (edhoc_ctx->buffers.tx_sz - send_sz);
330 rx_ptr = edhoc_ctx->buffers.msg_rx;
331 rx_sz = 0;
332 coap_send_request(&state, state.state.remote_endpoint,
333 state.state.request, client_response_handler);
334 return 1;
335 }
336}
337/*---------------------------------------------------------------------------*/
338static int
339generate_msg3_response(void)
340{
341 EDHOC_TRACE_STEP("message_3 generation");
342 edhoc_error_t result = edhoc_generate_message_3(edhoc_ctx, (uint8_t *)edhoc_state.ad.ad_3,
343 edhoc_state.ad.ad_3_sz);
344 if(result != EDHOC_SUCCESS) {
345 LOG_ERR("Failed to generate MSG3: %s\n", edhoc_error_string(result));
346 return -1;
347 }
348 edhoc_trace_message(3, edhoc_ctx->buffers.msg_tx, edhoc_ctx->buffers.tx_sz, true);
349 return 0;
350}
351
352static void
353handle_msg2_error(int err)
354{
355 LOG_ERR("Client: Send MSG error with code (%d)\n", err);
356 edhoc_ctx->buffers.tx_sz = edhoc_generate_error_message(edhoc_ctx->buffers.msg_tx,
358 edhoc_ctx, err);
359 if(edhoc_ctx->buffers.tx_sz == 0) {
360 LOG_ERR("Failed to generate error message\n");
361 }
362 client->state = PROTO_IDLE;
363 edhoc_client_post();
364 edhoc_client_post_blocks();
365}
366
367/*---------------------------------------------------------------------------*/
368static int
369edhoc_send_msg1(uint8_t *ad, uint8_t ad_sz, bool suite_array)
370{
371 EDHOC_TRACE_STEP("message_1 generation");
372 edhoc_error_t result = edhoc_generate_message_1(edhoc_ctx, ad, ad_sz, suite_array);
373 if(result != EDHOC_SUCCESS) {
374 LOG_ERR("Failed to generate MSG1: %s\n", edhoc_error_string(result));
375 return -1;
376 }
377 edhoc_client_post();
378 client->state = PROTO_RX_MSG2;
379 return edhoc_client_post_blocks();
380}
381/*---------------------------------------------------------------------------*/
382/* Protocol state handlers */
383static int
384handle_rx_msg2(edhoc_client_t *client, edhoc_msg_2_t *msg2)
385{
386 edhoc_trace_message(2, edhoc_ctx->buffers.msg_rx, edhoc_ctx->buffers.rx_sz, false);
387
388 err = edhoc_handler_msg_2(msg2, edhoc_ctx, edhoc_ctx->buffers.msg_rx,
389 edhoc_ctx->buffers.rx_sz);
390
391 if(err == EDHOC_ERR_SEQUENCE_ERROR) {
392 edhoc_send_msg1((uint8_t *)edhoc_state.ad.ad_1, edhoc_state.ad.ad_1_sz, true);
393 return 0;
394 }
395
396 if(err > 0) {
397 assert(msg2->gy_ciphertext_2_sz >= ECC_KEY_LEN);
398 assert(msg2->gy_ciphertext_2_sz - ECC_KEY_LEN <= EDHOC_MAX_BUFFER);
399 err = edhoc_authenticate_msg(edhoc_ctx, (uint8_t *)edhoc_state.ad.ad_2, true);
400 }
401
402 if(err == EDHOC_ERR_MSG_MALFORMED) {
403 LOG_ERR("error code (%d)\n", err);
404 return -1;
405 } else if(err < EDHOC_ERR_MSG_MALFORMED) {
406 handle_msg2_error(err);
407 return -1;
408 }
409
410 /* Handle AD_2 */
411 edhoc_state.ad.ad_2_sz = err;
412 if(edhoc_state.ad.ad_2_sz > 0) {
413 EDHOC_DBG_VALUE("AD_2", edhoc_state.ad.ad_2, edhoc_state.ad.ad_2_sz);
414 }
415
416 /* Generate MSG3 */
417 if(generate_msg3_response() < 0) {
418 client->state = PROTO_IDLE;
419 return -1;
420 }
421
422 client->rx_msg2 = true;
423 client->state = PROTO_RX_RSP_MSG3;
424 client->tx_msg3 = true;
425 edhoc_client_post();
426 edhoc_client_post_blocks();
427 return 0;
428}
429
430static int
431handle_rx_response_msg3(edhoc_client_t *client)
432{
433 if(edhoc_ctx->buffers.rx_sz > 0) {
434 edhoc_error_t error = edhoc_check_err_rx_msg(3, edhoc_ctx->buffers.msg_rx,
435 edhoc_ctx->buffers.rx_sz);
436 if(error != EDHOC_SUCCESS) {
437 edhoc_state.val = EVT_RESTART;
438 client->state = PROTO_IDLE;
440 process_post(&edhoc_client, edhoc_event, &edhoc_state);
441 return -1;
442 }
443 }
444
445 /* Check every protocol step successfully */
446 if(client->tx_msg1 && client->rx_msg2) {
447 client->rx_msg3_response = true;
448 } else {
449 LOG_ERR("The EDHOC process escape steps\n");
450 edhoc_state.val = EVT_RESTART;
452 process_post(&edhoc_client, edhoc_event, &edhoc_state);
453 return -1;
454 }
455
456 /* Fall through to PROTO_EXP_READY - execute it immediately */
457 client->state = PROTO_EXP_READY;
458 return handle_exp_ready(client);
459}
460
461static int
462handle_exp_ready(edhoc_client_t *client)
463{
464 EDHOC_TRACE_STEP("key export ready");
466 edhoc_state.val = EVT_FINISHED;
468 process_post(PROCESS_BROADCAST, edhoc_event, &edhoc_state);
469 return 0;
470}
471
472/*---------------------------------------------------------------------------*/
473static void
474edhoc_client_protocol_run(void)
475{
476 switch(client->state) {
477 case PROTO_RX_MSG2:
478 handle_rx_msg2(client, &msg2);
479 break;
480 case PROTO_RX_RSP_MSG3:
481 handle_rx_response_msg3(client);
482 break;
483 case PROTO_EXP_READY:
484 handle_exp_ready(client);
485 break;
486 default:
487 break;
488 }
489}
490/*---------------------------------------------------------------------------*/
491static void
492edhoc_client_init(void)
493{
494 if(edhoc_event == PROCESS_EVENT_NONE) {
495 edhoc_event = process_alloc_event();
496 }
497 client = client_context_new();
498 if(client == NULL) {
499 LOG_ERR("Failed to allocate client context\n");
500 return;
501 }
503 edhoc_ctx = edhoc_new();
504 if(edhoc_ctx == NULL) {
505 LOG_ERR("Failed to create EDHOC context\n");
506 return;
507 }
508 coap_endpoint_parse(SERVER_EP, strlen(SERVER_EP), &client->server_ep);
509 state.state.request = client->request;
510 state.state.response = client->response;
511 state.state.remote_endpoint = &client->server_ep;
512}
513/*---------------------------------------------------------------------------*/
514static int
515edhoc_client_start(uint8_t *ad, uint8_t ad_sz)
516{
517 client->tx_msg3 = false;
518 client->rx_msg3_response = false;
519 client->tx_msg1 = true;
520
521 coap_timer_set_callback(&timer, client_timeout_callback);
523
524 return edhoc_send_msg1(ad, ad_sz, false);
525}
526/*---------------------------------------------------------------------------*/
527static void
528generate_ephemeral_key(uint8_t curve_id, uint8_t *pub_x,
529 uint8_t *pub_y, uint8_t *priv)
530{
531 if(!ecdh_generate_keypair(curve_id, pub_x, pub_y, priv)) {
532 LOG_ERR("Failed to generate ephemeral key pair\n");
533 return;
534 }
535
536#if EDHOC_TEST == EDHOC_TEST_VECTOR_TRACE_DH
537 memcpy(edhoc_ctx->creds.ephemeral_key.pub.x, eph_pub_x_i, ECC_KEY_LEN);
538 memcpy(edhoc_ctx->creds.ephemeral_key.pub.y, eph_pub_y_i, ECC_KEY_LEN);
539 memcpy(edhoc_ctx->creds.ephemeral_key.priv, eph_private_i, ECC_KEY_LEN);
540#endif
541
542 edhoc_trace_ephemeral_key("Initiator",
543 edhoc_ctx->creds.ephemeral_key.pub.x,
544 edhoc_ctx->creds.ephemeral_key.pub.y,
545 edhoc_ctx->creds.ephemeral_key.priv);
546}
547/*---------------------------------------------------------------------------*/
548/* Unified retry handler */
549static void
550handle_retry(struct etimer *wait_timer, uint8_t *attempt)
551{
552 if(*attempt < EDHOC_CONF_ATTEMPTS) {
553 LOG_INFO("Attempt %d\n", *attempt);
554 etimer_set(wait_timer, CLOCK_SECOND * (CL_TIMEOUT_VAL / 1000));
555 (*attempt)++;
556 } else {
557 LOG_ERR("Expire EDHOC client attempts\n");
558 edhoc_state.val = EVT_TRIES_EXPIRE;
559 process_post(PROCESS_BROADCAST, edhoc_event, &edhoc_state);
560 }
561}
562
563
564/*---------------------------------------------------------------------------*/
565void
567{
569 client_context_free(client);
571}
572/*---------------------------------------------------------------------------*/
574{
576
577 static struct etimer wait_timer;
578 edhoc_client_init();
579
581 PROCESS_EXIT();
582 }
583
584 /* Generate ephemeral key */
585 generate_ephemeral_key(edhoc_ctx->config.ecdh_curve,
586 edhoc_ctx->creds.ephemeral_key.pub.x,
587 edhoc_ctx->creds.ephemeral_key.pub.y,
588 edhoc_ctx->creds.ephemeral_key.priv);
589
590 edhoc_client_start((uint8_t *)edhoc_state.ad.ad_1, edhoc_state.ad.ad_1_sz);
591
592 while(1) {
594 if(ev == edhoc_event && data == &edhoc_state) {
595 if(edhoc_state.val == EVT_RESTART || edhoc_state.val == EVT_TIMEOUT) {
596 LOG_ERR("%s\n", edhoc_state.val == EVT_RESTART ? "Error" : "Expire timeout");
597 handle_retry(&wait_timer, &attempt);
598 if(attempt < EDHOC_CONF_ATTEMPTS) {
600 etimer_stop(&wait_timer);
601 edhoc_client_start((uint8_t *)edhoc_state.ad.ad_1,
602 edhoc_state.ad.ad_1_sz);
603 } else {
604 break;
605 }
606 } else if(edhoc_state.val == EVT_FINISHED) {
607 LOG_INFO("Client has finished\n");
608 break;
609 } else if(edhoc_state.val == EVT_BLOCK1) {
610 edhoc_client_post_blocks();
611 } else if(edhoc_state.val == EVT_POST) {
612 edhoc_client_post();
613 edhoc_client_post_blocks();
614 } else if(edhoc_state.val == EVT_BLOCKING) {
615 edhoc_client_protocol_run();
616 } else if(edhoc_state.val == EVT_TRIES_EXPIRE) {
617 break;
618 }
619 }
620 }
621 PROCESS_END();
622}
623/*---------------------------------------------------------------------------*/
Callback API for doing CoAP requests Adapted from the blocking API.
CoAP timer API.
bool ecdh_generate_keypair(uint8_t curve_id, uint8_t *pub_x, uint8_t *pub_y, uint8_t *priv)
Generates a fresh ECDH key pair.
Definition ecdh.c:91
EDHOC client functionality [RFC9528].
const char * edhoc_error_string(edhoc_error_t error)
Get a human-readable error message for an error code.
Definition edhoc-error.c:44
edhoc_error_t
Unified error type for EDHOC operations.
Definition edhoc-error.h:60
@ EDHOC_ERR_MSG_MALFORMED
Malformed message received.
Definition edhoc-error.h:84
@ EDHOC_ERR_SEQUENCE_ERROR
Message sequence error.
Definition edhoc-error.h:90
Declarations for EDHOC message generators.
Declarations for the EDHOC message handlers.
void edhoc_trace_ephemeral_key(const char *role_label, const uint8_t *pub_x, const uint8_t *pub_y, const uint8_t *priv)
Print ephemeral key generation step.
Definition edhoc-trace.c:64
void edhoc_trace_message(uint8_t msg_num, const uint8_t *msg_data, size_t msg_len, bool is_tx)
Print EDHOC message in RFC 9529 trace format.
Definition edhoc-trace.c:48
void edhoc_trace_session_summary(const edhoc_context_t *ctx)
Print session summary at protocol completion.
EDHOC tracing and logging header.
#define EDHOC_TRACE_STEP(step_name)
Print protocol step header in RFC 9529 style.
Definition edhoc-trace.h:50
#define EDHOC_DBG_VALUE(label, data, len)
Print detailed debug value (only at DBG level).
Definition edhoc-trace.h:90
uint8_t edhoc_initialize_context(edhoc_context_t *ctx)
Internal API functions.
Definition edhoc.c:688
int edhoc_authenticate_msg(edhoc_context_t *ctx, uint8_t *ad, bool msg2)
Authenticate the rx message.
Definition edhoc.c:867
edhoc_context_t * edhoc_ctx
EDHOC context struct used in the EDHOC protocol.
Definition edhoc.c:62
void edhoc_storage_init(void)
Reserve memory for the EDHOC context struct.
Definition edhoc.c:67
uint8_t edhoc_generate_error_message(uint8_t *msg_er, size_t msg_er_sz, const edhoc_context_t *ctx, int8_t err)
Generate the EDHOC ERROR Message.
Definition edhoc.c:784
void edhoc_finalize(edhoc_context_t *ctx)
Close the EDHOC context.
Definition edhoc.c:83
#define CLOCK_SECOND
A second, measured in system clock time.
Definition clock.h:105
void coap_timer_stop(coap_timer_t *timer)
Stop a pending CoAP timer.
Definition coap-timer.c:92
void coap_timer_set(coap_timer_t *timer, uint64_t time)
Set a CoAP timer to expire after the specified time.
Definition coap-timer.c:103
static void coap_timer_set_callback(coap_timer_t *timer, void(*callback)(coap_timer_t *))
Set a callback function to be called when a CoAP timer expires.
Definition coap-timer.h:105
int coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep)
Parse a CoAP endpoint.
Definition coap-uip.c:206
int coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint, coap_message_t *request, void(*callback)(coap_callback_request_state_t *callback_state))
Send a CoAP request to a remote endpoint.
#define CL_TIMEOUT_VAL
Time limit value to EDHOC protocol finished.
void edhoc_client_run(void)
Run the EDHOC Initiator role.
#define SERVER_EP
The CoAP Server IP where run the EDHOC Responder.
#define EDHOC_MAX_AD_SZ
The max length of the Application Data.
#define EDHOC_MAX_PAYLOAD_LEN
The max length of the EDHOC message.
struct edhoc_data_event edhoc_data_event_t
EDHOC data event struct.
int edhoc_handler_msg_2(edhoc_msg_2_t *msg2, edhoc_context_t *ctx, uint8_t *payload, size_t payload_size)
Handle the EDHOC Message 2 received.
void edhoc_client_set_ad_1(const void *data_buffer, uint8_t buffer_size)
Set the Application Data to be carried in EDHOC message 1.
void edhoc_client_set_ad_3(const void *data_buffer, uint8_t buffer_size)
Set the Application Data to be carried in EDHOC message 3.
int8_t edhoc_client_callback(process_event_t ev, void *data)
Check if the EDHOC client have finished.
edhoc_error_t edhoc_generate_message_1(edhoc_context_t *ctx, uint8_t *ad, size_t ad_sz, bool suite_array)
Generate the EDHOC Message 1 and set it in the EDHOC context.
#define EDHOC_CONF_ATTEMPTS
The number of attempts to try to connect with the EDHOC server successfully.
edhoc_error_t edhoc_check_err_rx_msg(uint8_t message, const uint8_t *data, size_t data_size)
Try to deserialize data as an EDHOC error message.
uint8_t edhoc_client_get_ad_2(char *buf, size_t buf_sz)
Get the Application Data received in EDHOC message 2.
void edhoc_client_close(void)
Close the EDHOC context.
#define EDHOC_COAP_URI_PATH
EDHOC resource CoAP URI path.
edhoc_error_t edhoc_generate_message_3(edhoc_context_t *ctx, const uint8_t *auth_data, size_t auth_data_size)
Generate the EDHOC Message 3 and set it in the EDHOC context.
#define EDHOC_MAX_BUFFER
The max size of the buffers.
struct edhoc_client edhoc_client_t
EDHOC client struct.
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Definition etimer.c:237
static bool etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition etimer.h:201
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition etimer.c:177
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition memb.c:59
#define MEMB(name, structure, num)
Declare a memory block.
Definition memb.h:91
#define PROCESS(name, strname)
Declare a process.
Definition process.h:309
#define PROCESS_EXIT()
Exit the currently running process.
Definition process.h:202
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition process.h:143
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition process.c:325
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition process.c:111
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:122
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition process.h:159
#define PROCESS_END()
Define the end of a process.
Definition process.h:133
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:121
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:275
Header file for the logging system.
Memory block allocation routines.
EDHOC client struct.
A timer.
Definition etimer.h:79
A timer.
Definition timer.h:84