Contiki-NG
Loading...
Searching...
No Matches
edhoc.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, an implementation of Ephemeral Diffie-Hellman Over COSE (EDHOC) (IETF RFC9528)
35 * \author
36 * Lidia Pocero <pocero@isi.gr>
37 * Peter A Jonsson
38 * Rikard Höglund
39 * Marco Tiloca
40 * Niclas Finne <niclas.finne@ri.se>
41 * Nicolas Tsiftes <nicolas.tsiftes@ri.se>
42 */
43
44#include "contiki.h"
45#include "lib/sha-256.h"
46#include "lib/cbor.h"
47#include "edhoc.h"
48#include "edhoc-config.h"
49#include "edhoc-msgs.h"
50#include "edhoc-trace.h"
51#include "cose.h"
52#include <assert.h>
53
54#include "sys/log.h"
55#define LOG_MODULE "EDHOC"
56#define LOG_LEVEL LOG_LEVEL_EDHOC
57
58#if HASH_LEN != SHA_256_DIGEST_LENGTH
59#error Only SHA256 supported. Please update HASH_LEN.
60#endif /* HASH_LEN != SHA_256_DIGEST_LENGTH */
61
62edhoc_context_t *edhoc_ctx;
63
64MEMB(edhoc_context_storage, edhoc_context_t, 1);
65/*---------------------------------------------------------------------------*/
66void
68{
69 memb_init(&edhoc_context_storage);
70}
71/*---------------------------------------------------------------------------*/
72edhoc_context_t *
73edhoc_new(void)
74{
75 edhoc_context_t *ctx = memb_alloc(&edhoc_context_storage);
76 if(ctx) {
77 memset(ctx, 0, sizeof(edhoc_context_t));
78 }
79 return ctx;
80}
81/*---------------------------------------------------------------------------*/
82void
83edhoc_finalize(edhoc_context_t *ctx)
84{
85 memb_free(&edhoc_context_storage, ctx);
86}
87/*---------------------------------------------------------------------------*/
88uint8_t
89edhoc_setup_suites(edhoc_context_t *ctx)
90{
91 /* Reverse order for the suite values */
92 ctx->config.suite_num = 0;
93 if(EDHOC_SUPPORTED_SUITE_4 > -1) {
94 ctx->config.suite[ctx->config.suite_num] = EDHOC_SUPPORTED_SUITE_4;
95 ctx->config.suite_num++;
96 }
97 if(EDHOC_SUPPORTED_SUITE_3 > -1) {
98 ctx->config.suite[ctx->config.suite_num] = EDHOC_SUPPORTED_SUITE_3;
99 ctx->config.suite_num++;
100 }
101 if(EDHOC_SUPPORTED_SUITE_2 > -1) {
102 ctx->config.suite[ctx->config.suite_num] = EDHOC_SUPPORTED_SUITE_2;
103 ctx->config.suite_num++;
104 }
105 if(EDHOC_SUPPORTED_SUITE_1 > -1) {
106 ctx->config.suite[ctx->config.suite_num] = EDHOC_SUPPORTED_SUITE_1;
107 ctx->state.suite_selected = EDHOC_SUPPORTED_SUITE_1;
108 ctx->config.suite_num++;
109 }
110
111 if(ctx->config.suite_num == 0) {
112 LOG_ERR("No cipher suites configured (error: %d)\n", EDHOC_ERR_SUITE_NOT_SUPPORTED);
113 return 0;
114 }
115 return 1;
116}
117/*---------------------------------------------------------------------------*/
118static int8_t
119get_edhoc_mac_len(uint8_t ciphersuite_id)
120{
121 switch(ciphersuite_id) {
122 case EDHOC_CIPHERSUITE_1:
123 case EDHOC_CIPHERSUITE_3:
124 case EDHOC_CIPHERSUITE_4:
125 case EDHOC_CIPHERSUITE_5:
126 case EDHOC_CIPHERSUITE_6:
127 case EDHOC_CIPHERSUITE_24:
128 case EDHOC_CIPHERSUITE_25:
129 return EDHOC_MAC_LEN_16;
130 case EDHOC_CIPHERSUITE_0:
131 case EDHOC_CIPHERSUITE_2:
132 return EDHOC_MAC_LEN_8;
133 default:
134 LOG_ERR("Invalid cipher suite for MAC length (%d)\n",
136 return 0;
137 }
138}
139/*---------------------------------------------------------------------------*/
140static int8_t
141get_edhoc_aead_enc_alg(uint8_t ciphersuite_id)
142{
143 switch(ciphersuite_id) {
144 case EDHOC_CIPHERSUITE_1:
145 case EDHOC_CIPHERSUITE_3:
146 return COSE_ALG_AES_CCM_16_128_128;
147 case EDHOC_CIPHERSUITE_0:
148 case EDHOC_CIPHERSUITE_2:
149 return COSE_ALG_AES_CCM_16_64_128;
150 default:
151 LOG_ERR("Invalid cipher suite for encryption alg (%d)\n",
153 return 0;
154 }
155}
156/*---------------------------------------------------------------------------*/
157static int8_t
158get_edhoc_curve(uint8_t ciphersuite_id)
159{
160 switch(ciphersuite_id) {
161 case EDHOC_CIPHERSUITE_2:
162 case EDHOC_CIPHERSUITE_3:
163 case EDHOC_CIPHERSUITE_5:
164 return EDHOC_CURVE_P256;
165 default:
166 LOG_ERR("Invalid cipher suite for curve (%d)\n", EDHOC_ERR_SUITE_NOT_SUPPORTED);
167 return 0;
168 }
169}
170/*---------------------------------------------------------------------------*/
171static int8_t
172get_edhoc_sign_alg(uint8_t ciphersuite_id)
173{
174 switch(ciphersuite_id) {
175 case EDHOC_CIPHERSUITE_2:
176 case EDHOC_CIPHERSUITE_3:
177 case EDHOC_CIPHERSUITE_5:
178 case EDHOC_CIPHERSUITE_6:
179 return ES256;
180 default:
181 LOG_ERR("Invalid cipher suite for curve (%d)\n",
183 return 0;
184 }
185}
186/*---------------------------------------------------------------------------*/
187int8_t
188edhoc_set_config_from_suite(edhoc_context_t *ctx, uint8_t suite)
189{
190 if((ctx->config.ecdh_curve = get_edhoc_curve(suite)) == 0) {
191 return 0;
192 }
193
194 if((ctx->config.mac_len = get_edhoc_mac_len(ctx->state.suite_selected)) == 0) {
195 return 0;
196 }
197
198 if((ctx->config.aead_alg = get_edhoc_aead_enc_alg(ctx->state.suite_selected)) == 0) {
199 return 0;
200 }
201
202 if((ctx->config.sign_alg = get_edhoc_sign_alg(ctx->state.suite_selected)) == 0) {
203 return 0;
204 }
205
206 return 1;
207}
208/*---------------------------------------------------------------------------*/
209size_t
210edhoc_generate_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
211{
212 cbor_writer_state_t writer;
213 cbor_init_writer(&writer, cred, cred_sz);
214 cbor_open_map(&writer);
215 cbor_write_unsigned(&writer, 2);
216 cbor_write_text(&writer, cose->identity, cose->identity_sz);
217 cbor_write_unsigned(&writer, 8);
218
219 cbor_open_map(&writer);
220 cbor_write_unsigned(&writer, 1);
221
222 cbor_open_map(&writer);
223 cbor_write_unsigned(&writer, 1);
224 cbor_write_unsigned(&writer, cose->kty);
225 cbor_write_unsigned(&writer, 2);
226 cbor_write_data(&writer, cose->kid, cose->kid_sz);
227 cbor_write_signed(&writer, -1);
228 cbor_write_unsigned(&writer, cose->crv);
229 cbor_write_signed(&writer, -2);
230 cbor_write_data(&writer, cose->ecc.pub.x, ECC_KEY_LEN);
231 if(cose->crv == 1) {
232 cbor_write_signed(&writer, -3);
233 cbor_write_data(&writer, cose->ecc.pub.y, ECC_KEY_LEN);
234 }
235 cbor_close_map(&writer);
236 cbor_close_map(&writer);
237 cbor_close_map(&writer);
238 return cbor_end_writer(&writer);
239}
240/*---------------------------------------------------------------------------*/
241size_t
242edhoc_generate_id_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
243{
244 LOG_DBG("kid (%i bytes): ", cose->kid_sz);
245 LOG_DBG_BYTES(cose->kid, cose->kid_sz);
246 LOG_DBG_("\n");
247
248 /* Include KID */
249 if(EDHOC_AUTHENT_TYPE == EDHOC_CRED_KID) {
250 cbor_writer_state_t writer;
251 cbor_init_writer(&writer, cred, cred_sz);
252 cbor_open_map(&writer);
253 cbor_write_unsigned(&writer, 4);
254 cbor_write_data(&writer, cose->kid, cose->kid_sz);
255 cbor_close_map(&writer);
256 return cbor_end_writer(&writer);
257 }
258
259 /* Include directly the credential used for authentication ID_CRED_X = CRED_X */
260 if(EDHOC_AUTHENT_TYPE == EDHOC_CRED_INCLUDE) {
261 return edhoc_generate_cred_x(cose, cred, cred_sz);
262 }
263 return 0;
264}
265/*---------------------------------------------------------------------------*/
266static size_t
267generate_info(uint8_t info_label, const uint8_t *context, uint8_t context_sz,
268 uint8_t length, uint8_t *info, size_t info_sz)
269{
270 cbor_writer_state_t writer;
271 cbor_init_writer(&writer, info, info_sz);
272 cbor_write_object(&writer, &info_label, 1);
273 cbor_write_data(&writer, context, context_sz);
274 cbor_write_unsigned(&writer, length);
275 return cbor_end_writer(&writer);
276}
277/*---------------------------------------------------------------------------*/
278int8_t
279edhoc_generate_transcript_hash_2(edhoc_context_t *ctx, const uint8_t *eph_pub,
280 uint8_t *msg, uint16_t msg_sz)
281{
282 /* Create the input for TH_2 = H(G_Y, H(msg)), msg1 is in msg_rx */
283 uint8_t h[CBOR_BYTE_STRING_SIZE(HASH_LEN) + CBOR_BYTE_STRING_SIZE(ECC_KEY_LEN)];
284
285 EDHOC_DBG_VALUE("Input MSG_1", msg, msg_sz);
286
287 uint8_t msg_1_hash[HASH_LEN];
288 sha_256_hash(msg + 1, msg_sz - 1, msg_1_hash); /*FIXME: Improve skipping of CBOR true for TH */
289
290 EDHOC_TRACE_VALUE("H(MSG_1)", msg_1_hash, HASH_LEN);
291 EDHOC_TRACE_VALUE("G_Y", eph_pub, ECC_KEY_LEN);
292
293 cbor_writer_state_t writer;
294 cbor_init_writer(&writer, h, sizeof(h));
295 cbor_write_data(&writer, eph_pub, ECC_KEY_LEN);
296 cbor_write_data(&writer, msg_1_hash, HASH_LEN);
297 size_t h_buf_sz = cbor_end_writer(&writer);
298
299 /* Compute TH_2 */
300 sha_256_hash(h, h_buf_sz, ctx->state.th);
301 edhoc_trace_transcript_hash("TH_2", ctx->state.th, h, h_buf_sz);
302 return 0;
303}
304/*---------------------------------------------------------------------------*/
305uint8_t
306edhoc_generate_transcript_hash_3(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz,
307 const uint8_t *plaintext, uint16_t plaintext_sz)
308{
309 /* Check for potential buffer overflow */
310 uint16_t required_size = CBOR_BYTE_STRING_SIZE(HASH_LEN) + plaintext_sz + cred_sz;
311 if(required_size > EDHOC_MAX_BUFFER || plaintext_sz > EDHOC_MAX_BUFFER || cred_sz > EDHOC_MAX_BUFFER) {
312 LOG_ERR("Buffer sizes exceed maximum allowed\n");
313 return 1;
314 }
315
316 /* TH_3 = H(TH_2, PLAINTEXT_2, CRED_R) */
317 uint8_t h[EDHOC_MAX_BUFFER];
318 cbor_writer_state_t writer;
319 cbor_init_writer(&writer, h, sizeof(h));
320 cbor_write_data(&writer, ctx->state.th, HASH_LEN);
321 EDHOC_DBG_VALUE("TH_2 for TH_3", ctx->state.th, HASH_LEN);
322 cbor_write_object(&writer, plaintext, plaintext_sz);
323 EDHOC_TRACE_VALUE("PLAINTEXT_2", plaintext, plaintext_sz);
324 cbor_write_object(&writer, cred, cred_sz);
325 EDHOC_TRACE_VALUE("CRED_R", cred, cred_sz);
326 size_t h_sz = cbor_end_writer(&writer);
327
328 /* Compute TH_3 */
329 sha_256_hash(h, h_sz, ctx->state.th);
330 edhoc_trace_transcript_hash("TH_3", ctx->state.th, h, h_sz);
331 return 0;
332}
333/*---------------------------------------------------------------------------*/
334uint8_t
335edhoc_generate_transcript_hash_4(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz,
336 const uint8_t *plaintext, uint16_t plaintext_sz)
337{
338 /* Check for potential buffer overflow */
339 uint16_t required_size = CBOR_BYTE_STRING_SIZE(HASH_LEN) + plaintext_sz + cred_sz;
340 if(required_size > EDHOC_MAX_BUFFER || plaintext_sz > EDHOC_MAX_BUFFER || cred_sz > EDHOC_MAX_BUFFER) {
341 LOG_ERR("Buffer sizes exceed maximum allowed\n");
342 return 1;
343 }
344
345 /* TH_4 = H(TH_3, PLAINTEXT_3, CRED_I) */
346 uint8_t h[EDHOC_MAX_BUFFER];
347 cbor_writer_state_t writer;
348 cbor_init_writer(&writer, h, sizeof(h));
349 cbor_write_data(&writer, ctx->state.th, HASH_LEN);
350 EDHOC_DBG_VALUE("TH_3 for TH_4", ctx->state.th, HASH_LEN);
351
352 cbor_write_object(&writer, plaintext, plaintext_sz);
353 EDHOC_TRACE_VALUE("PLAINTEXT_3", plaintext, plaintext_sz);
354
355 cbor_write_object(&writer, cred, cred_sz);
356 EDHOC_TRACE_VALUE("CRED_I", cred, cred_sz);
357 size_t h_sz = cbor_end_writer(&writer);
358
359 /* Compute TH_4 */
360 sha_256_hash(h, h_sz, ctx->state.th);
361 edhoc_trace_transcript_hash("TH_4", ctx->state.th, h, h_sz);
362 return 0;
363}
364/*---------------------------------------------------------------------------*/
365void
366edhoc_print_session_info(const edhoc_context_t *ctx)
367{
368 /* Use the enhanced session summary instead */
370}
371/*---------------------------------------------------------------------------*/
372int16_t
373edhoc_kdf(const uint8_t *prk, uint8_t info_label, const uint8_t *context,
374 uint8_t context_sz, uint16_t length, uint8_t *result)
375{
376 LOG_DBG("edhoc_kdf label=%d, length=%d\n", info_label, length);
377 LOG_DBG("PRK (%d bytes): ", ECC_KEY_LEN);
378 LOG_DBG_BYTES(prk, ECC_KEY_LEN);
379 LOG_DBG_("\n");
380 if(context && context_sz > 0) {
381 LOG_DBG("Context (%d bytes): ", context_sz);
382 LOG_DBG_BYTES(context, context_sz);
383 LOG_DBG_("\n");
384 }
385
386 uint8_t info_buf[CBOR_UNSIGNED_SIZE((unsigned)info_label)
387 + CBOR_BYTE_STRING_SIZE((unsigned)context_sz)
388 + CBOR_UNSIGNED_SIZE((unsigned)length)];
389 uint16_t info_sz = generate_info(info_label, context, context_sz,
390 length, info_buf, sizeof(info_buf));
391 if(info_sz == 0) {
392 LOG_ERR("Error generating INFO\n");
393 return info_sz;
394 }
395
396 int16_t ret = edhoc_expand(prk, info_buf, info_sz, length, result);
397 if(ret > 0) {
398 LOG_DBG("KDF Result (%d bytes): ", length);
399 LOG_DBG_BYTES(result, length);
400 LOG_DBG_("\n");
401 }
402 return ret;
403}
404/*---------------------------------------------------------------------------*/
405int16_t
406edhoc_expand(const uint8_t *prk, const uint8_t *info, uint16_t info_sz,
407 uint16_t length, uint8_t *result)
408{
409 LOG_DBG("INFO for HKDF_Expand (%d bytes): ", info_sz);
410 LOG_DBG_BYTES(info, info_sz);
411 LOG_DBG_("\n");
412 sha_256_hkdf_expand(prk, ECC_KEY_LEN, info, info_sz, result, length);
413 return length;
414}
415/*---------------------------------------------------------------------------*/
416uint8_t
417edhoc_calc_mac(const edhoc_context_t *ctx, uint8_t mac_num,
418 uint8_t mac_len, uint8_t *mac)
419{
420 if(mac_num == EDHOC_MAC_2) {
421 LOG_DBG("Calculating MAC_2\n");
422 /* Build context_2 */
423 uint8_t context_2[EDHOC_MAX_CID_LEN + ctx->buffers.id_cred_x_sz +
424 CBOR_BYTE_STRING_SIZE(HASH_LEN) + ctx->buffers.cred_x_sz];
425 cbor_writer_state_t writer;
426 cbor_init_writer(&writer, context_2, sizeof(context_2));
427
428 /* Add C_R */
429 if(EDHOC_ROLE == EDHOC_INITIATOR) {
430 cbor_write_object(&writer, ctx->state.cid_rx, ctx->state.cid_rx_len);
431 LOG_DBG("C_R (%d bytes): ", ctx->state.cid_rx_len);
432 LOG_DBG_BYTES(ctx->state.cid_rx, ctx->state.cid_rx_len);
433 LOG_DBG_("\n");
434 } else {
435 cbor_write_object(&writer, ctx->state.cid, ctx->state.cid_len);
436 LOG_DBG("C_R (%d bytes): ", ctx->state.cid_len);
437 LOG_DBG_BYTES(ctx->state.cid, ctx->state.cid_len);
438 LOG_DBG_("\n");
439 }
440
441 cbor_write_object(&writer, ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
442 LOG_DBG("ID_CRED_X (%zu bytes): ", ctx->buffers.id_cred_x_sz);
443 LOG_DBG_BYTES(ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
444 LOG_DBG_("\n");
445
446 cbor_write_data(&writer, ctx->state.th, HASH_LEN);
447 LOG_DBG("TH_2 for MAC_2 (%d bytes): ", HASH_LEN);
448 LOG_DBG_BYTES(ctx->state.th, HASH_LEN);
449 LOG_DBG_("\n");
450
451 cbor_write_object(&writer, ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
452 LOG_DBG("CRED_X (%zu bytes): ", ctx->buffers.cred_x_sz);
453 LOG_DBG_BYTES(ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
454 LOG_DBG_("\n");
455
456 size_t context_2_buffer_size = cbor_end_writer(&writer);
457 LOG_DBG("CONTEXT_2 (%zu bytes): ", context_2_buffer_size);
458 LOG_DBG_BYTES(context_2, context_2_buffer_size);
459 LOG_DBG_("\n");
460
461 /* Use edhoc_kdf to generate MAC_2 */
462 int16_t err = edhoc_kdf(ctx->state.prk_3e2m, MAC_2_LABEL,
463 context_2, context_2_buffer_size, mac_len, mac);
464 if(err < 0) {
465 LOG_ERR("Failed to expand MAC_2\n");
466 return 0;
467 }
468 } else if(mac_num == EDHOC_MAC_3) {
469 /* Build context_3 */
470 uint8_t context_3[ctx->buffers.id_cred_x_sz +
471 CBOR_BYTE_STRING_SIZE(HASH_LEN) + ctx->buffers.cred_x_sz];
472 cbor_writer_state_t writer;
473 cbor_init_writer(&writer, context_3, sizeof(context_3));
474
475 cbor_write_object(&writer, ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
476 cbor_write_data(&writer, ctx->state.th, HASH_LEN);
477 cbor_write_object(&writer, ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
478 size_t context_3_buffer_size = cbor_end_writer(&writer);
479 LOG_DBG("CONTEXT_3 (%zu bytes): ", context_3_buffer_size);
480 LOG_DBG_BYTES(context_3, context_3_buffer_size);
481 LOG_DBG_("\n");
482
483 /* Use edhoc_kdf to generate MAC_3 */
484 int16_t err = edhoc_kdf(ctx->state.prk_4e3m, MAC_3_LABEL,
485 context_3, context_3_buffer_size, mac_len, mac);
486 if(err < 0) {
487 LOG_ERR("Failed to expand MAC_3\n");
488 return 0;
489 }
490 } else {
491 LOG_ERR("Wrong MAC value\n");
492 return 0;
493 }
494
495 return 1;
496}
497/*---------------------------------------------------------------------------*/
498#if (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2
499static uint16_t
500check_mac(const edhoc_context_t *ctx, const uint8_t *received_mac,
501 uint16_t received_mac_sz)
502{
503 uint8_t mac_num;
504 if(EDHOC_ROLE == EDHOC_INITIATOR) {
505 mac_num = EDHOC_MAC_2;
506 } else if(EDHOC_ROLE == EDHOC_RESPONDER) {
507 mac_num = EDHOC_MAC_3;
508 }
509
510 uint8_t edhoc_mac_len = ctx->config.mac_len;
511 uint8_t mac[edhoc_mac_len];
512 if(!edhoc_calc_mac(ctx, mac_num, edhoc_mac_len, mac)) {
513 LOG_ERR("Set MAC error\n");
514 return 0;
515 }
516
517 LOG_DBG("Received MAC (%d): ", (int)received_mac_sz);
518 LOG_DBG_BYTES(received_mac, received_mac_sz);
519 LOG_DBG_("\n");
520
521 LOG_DBG("Recalculated MAC (%d): ", (int)edhoc_mac_len);
522 LOG_DBG_BYTES(mac, edhoc_mac_len);
523 LOG_DBG_("\n");
524
525 /* Verify the MAC value */
526 uint16_t mac_sz = edhoc_mac_len;
527 uint8_t diff = 0;
528 for(int i = 0; i < edhoc_mac_len; i++) {
529 diff |= (mac[i] ^ received_mac[i]);
530 }
531
532 if(diff != 0) {
533 LOG_ERR("error code in check mac (%d)\n", EDHOC_ERR_CRYPTO_AUTHENTICATION);
534 return 0;
535 }
536
537 return mac_sz;
538}
539#endif /* (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2 */
540/*---------------------------------------------------------------------------*/
541bool
542edhoc_generate_prk_2e(edhoc_context_t *ctx)
543{
544 uint8_t ikm[ECC_KEY_LEN];
545
546 if(!ecdh_generate_ikm(ctx->config.ecdh_curve, ctx->state.gx,
547 ctx->creds.ephemeral_key.priv, ikm)) {
548 LOG_ERR("Failed to generate shared secret for PRK_2e\n");
549 return false;
550 }
551 EDHOC_DBG_VALUE("GXY", ikm, ECC_KEY_LEN);
552
553 sha_256_hkdf_extract(ctx->state.th, HASH_LEN, ikm, ECC_KEY_LEN,
554 ctx->state.prk_2e);
555 edhoc_trace_prk_derivation("PRK_2e", ctx->state.prk_2e, ctx->state.th, ikm);
556 return true;
557}
558/*---------------------------------------------------------------------------*/
559/* Derive KEYSTREAM_2 */
560int16_t
561edhoc_generate_keystream_2e(edhoc_context_t *ctx, uint16_t length, uint8_t *ks_2e)
562{
563 int err = edhoc_kdf(ctx->state.prk_2e, KEYSTREAM_2_LABEL,
564 ctx->state.th, HASH_LEN, length, ks_2e);
565 if(err < 0) {
566 return err;
567 }
568 EDHOC_DBG_VALUE("KEYSTREAM_2", ks_2e, length);
569 return 1;
570}
571/*---------------------------------------------------------------------------*/
572#if (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2
573bool
574edhoc_generate_prk_3e2m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
575{
576 uint8_t grx[ECC_KEY_LEN];
577 bool success;
578
579 EDHOC_TRACE_COMPUTE(gen ? "PRK_3e2m (ephemeral DH)" : "PRK_3e2m (static DH)");
580
581 if(gen) {
582 success = ecdh_generate_ikm(ctx->config.ecdh_curve,
583 ctx->state.gx,
584 auth_key->priv,
585 grx);
586 } else {
587 EDHOC_DBG_VALUE("Static auth key X", auth_key->pub.x, ECC_KEY_LEN);
588 EDHOC_DBG_VALUE("Static auth key Y", auth_key->pub.y, ECC_KEY_LEN);
589 success = ecdh_generate_ikm(ctx->config.ecdh_curve,
590 auth_key->pub.x,
591 ctx->creds.ephemeral_key.priv,
592 grx);
593 }
594 if(!success) {
595 LOG_ERR("Failed to generate shared secret for PRK_3e2m\n");
596 return false;
597 }
598
599 EDHOC_DBG_VALUE("G_RX (DH secret)", grx, ECC_KEY_LEN);
600
601 /* Use edhoc_kdf to generate SALT_3e2m */
602 uint8_t salt[HASH_LEN];
603 int16_t err = edhoc_kdf(ctx->state.prk_2e, SALT_3E2M_LABEL, ctx->state.th,
604 HASH_LEN, HASH_LEN, salt);
605 if(err < 1) {
606 LOG_ERR("Error calculating SALT_3e2m (%d)\n", err);
607 return false;
608 }
609
610 /* Extract PRK_3e2m */
611 sha_256_hkdf_extract(salt, HASH_LEN, grx, ECC_KEY_LEN, ctx->state.prk_3e2m);
612 edhoc_trace_prk_derivation("PRK_3e2m", ctx->state.prk_3e2m, salt, grx);
613 return true;
614}
615#endif /* (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2 */
616/*---------------------------------------------------------------------------*/
617#if (EDHOC_METHOD == EDHOC_METHOD2) || (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2
618bool
619edhoc_generate_prk_4e3m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
620{
621 uint8_t giy[ECC_KEY_LEN];
622 bool success;
623
624 if(gen) {
625 success = ecdh_generate_ikm(ctx->config.ecdh_curve,
626 auth_key->pub.x,
627 ctx->creds.ephemeral_key.priv,
628 giy);
629 } else {
630 success = ecdh_generate_ikm(ctx->config.ecdh_curve,
631 ctx->state.gx,
632 auth_key->priv,
633 giy);
634 }
635 if(!success) {
636 LOG_ERR("Failed to generate shared secret for PRK_4e3m\n");
637 return false;
638 }
639 LOG_DBG("G_IY (ECDH shared secret) (%d bytes): ", ECC_KEY_LEN);
640 LOG_DBG_BYTES(giy, ECC_KEY_LEN);
641 LOG_DBG_("\n");
642
643 /* Use edhoc_kdf to generate SALT_4e3m */
644 uint8_t salt[HASH_LEN];
645 int16_t err = edhoc_kdf(ctx->state.prk_3e2m, SALT_4E3M_LABEL, ctx->state.th,
646 HASH_LEN, HASH_LEN, salt);
647 if(err < 1) {
648 LOG_ERR("Error calculating SALT_4e3m (%d)\n", err);
649 return false;
650 }
651 LOG_DBG("SALT_4e3m (%d bytes): ", HASH_LEN);
652 LOG_DBG_BYTES(salt, HASH_LEN);
653 LOG_DBG_("\n");
654
655 sha_256_hkdf_extract(salt, HASH_LEN, giy, ECC_KEY_LEN, ctx->state.prk_4e3m);
656 LOG_DBG("PRK_4e3m (%d bytes): ", HASH_LEN);
657 LOG_DBG_BYTES(ctx->state.prk_4e3m, HASH_LEN);
658 LOG_DBG_("\n");
659 return true;
660}
661#endif /* (EDHOC_METHOD == EDHOC_METHOD2) || (EDHOC_METHOD == EDHOC_METHOD3) ||
662INITIATOR_METHOD1 || RESPONDER_METHOD2 */
663/*---------------------------------------------------------------------------*/
664int16_t
665edhoc_enc_dec_ciphertext_2(const edhoc_context_t *ctx, const uint8_t *ks_2e,
666 uint8_t *plaintext, uint16_t plaintext_sz)
667{
668 LOG_DBG("Cipher/Plaintext (%d bytes): ", plaintext_sz);
669 LOG_DBG_BYTES(plaintext, plaintext_sz);
670 LOG_DBG_("\n");
671
672 LOG_DBG("**** ks_2e in enc func (%d bytes): ", plaintext_sz);
673 LOG_DBG_BYTES(ks_2e, plaintext_sz);
674 LOG_DBG_("\n");
675
676 for(int i = 0; i < plaintext_sz; i++) {
677 plaintext[i] = plaintext[i] ^ ks_2e[i];
678 }
679
680 LOG_DBG("Plain/Ciphertext (%d bytes): ", plaintext_sz);
681 LOG_DBG_BYTES(plaintext, plaintext_sz);
682 LOG_DBG_("\n");
683
684 return plaintext_sz;
685}
686/*---------------------------------------------------------------------------*/
687uint8_t
688edhoc_initialize_context(edhoc_context_t *ctx)
689{
690 /* Retrieve a pointer to own auth key */
691 cose_key_t *key = NULL;
692 if(!edhoc_get_own_auth_key(ctx, &key)) {
693 return 0;
694 }
695
696 /* Set pointer to found key */
697 ctx->creds.authen_key = key;
698
699 /* Set up the cipher suites selection logic */
700 if(!edhoc_setup_suites(ctx)) {
701 return 0;
702 }
703
704 /* Set CID */
705#ifdef EDHOC_CID_BYTES
706 /* Variable-length CID for testing */
707 {
708 const uint8_t cid_bytes[] = EDHOC_CID_BYTES;
709 ctx->state.cid_len = sizeof(cid_bytes);
710 if(ctx->state.cid_len > EDHOC_MAX_CID_LEN) {
711 LOG_ERR("CID length (%d) exceeds maximum (%d)\n", ctx->state.cid_len, EDHOC_MAX_CID_LEN);
712 return 0;
713 }
714 memcpy(ctx->state.cid, cid_bytes, ctx->state.cid_len);
715 LOG_INFO("Variable CID initialized: length %d bytes\n", ctx->state.cid_len);
716 LOG_DBG("Variable CID bytes: ");
717 for(int i = 0; i < ctx->state.cid_len; i++) {
718 LOG_DBG_("%02x ", ctx->state.cid[i]);
719 }
720 LOG_DBG_("\n");
721 }
722#else
723 /* Default single-byte CID */
724 ctx->state.cid[0] = EDHOC_CID;
725 ctx->state.cid_len = EDHOC_DEFAULT_CID_LEN;
726 LOG_INFO("Default CID: 0x%02x (len %d)\n", ctx->state.cid[0], ctx->state.cid_len);
727#endif
728
729 /* Set role and method */
730 ctx->config.role = EDHOC_ROLE;
731 ctx->config.method = EDHOC_METHOD;
732
733 /* Initiator sets config to use based on selected suite */
734 int8_t err = edhoc_set_config_from_suite(ctx, ctx->state.suite_selected);
735 if(err != 1) {
736 return 0;
737 }
738
739 return 1;
740}
741/*---------------------------------------------------------------------------*/
742uint8_t
743edhoc_get_own_auth_key(edhoc_context_t *ctx, cose_key_t **key)
744{
745#ifdef EDHOC_AUTH_SUBJECT_NAME
746 if(edhoc_check_key_list_identity(EDHOC_AUTH_SUBJECT_NAME,
747 strlen(EDHOC_AUTH_SUBJECT_NAME), key) == EDHOC_SUCCESS) {
748 /* Key found using identity */
749 return 1;
750 } else {
751 LOG_ERR("Auth key identity not found\n");
752 }
753#endif
754
755#ifdef EDHOC_AUTH_KID
756 if(*key == NULL) {
757 uint8_t key_id[sizeof(int)];
758 int kid = EDHOC_AUTH_KID;
759 int quotient = (EDHOC_AUTH_KID) / 256;
760 uint8_t key_id_sz = 1;
761 while(quotient != 0) {
762 key_id_sz++;
763 quotient /= 256;
764 }
765 memcpy(key_id, (uint8_t *)&kid, key_id_sz);
766
767 LOG_DBG("Looking for auth key KID 0x%02x (sz=%d)\n", key_id[0], key_id_sz);
768
769 if(edhoc_check_key_list_kid(key_id, key_id_sz, key) == EDHOC_SUCCESS) {
770 /* Key found using KID */
771 LOG_DBG("Auth key found with KID 0x%02x\n", key_id[0]);
772 return 1;
773 } else {
774 LOG_ERR("Does not contain a key for the key ID 0x%02x\n", key_id[0]);
775 }
776 }
777#endif
778
779 LOG_ERR("No matching key found in the storage\n");
780 return 0;
781}
782/*---------------------------------------------------------------------------*/
783uint8_t
784edhoc_generate_error_message(uint8_t *msg_er, size_t msg_er_sz,
785 const edhoc_context_t *ctx, int8_t err)
786{
787 edhoc_msg_error_t msg;
788 memset(&msg, 0, sizeof(edhoc_msg_error_t));
789 msg.err_code = EDHOC_MSG_ERR_CODE_UNSPECIFIED_ERROR;
790 switch(err) {
791 default:
792 msg.info.tstr.err_info = "Unknown error";
793 break;
795 msg.err_code = EDHOC_MSG_ERR_CODE_WRONG_CIPHER_SUITE;
796 msg.info.suites.suites_num = MIN(sizeof(msg.info.suites.suites), ctx->config.suite_num);
797 memcpy(msg.info.suites.suites, ctx->config.suite, msg.info.suites.suites_num);
798 break;
800 msg.info.tstr.err_info = "Malformed message";
801 break;
803 msg.info.tstr.err_info = "Method not supported";
804 break;
806 msg.info.tstr.err_info = "Invalid connection ID";
807 break;
809 msg.info.tstr.err_info = "Wrong connection ID";
810 break;
812 msg.info.tstr.err_info = "Malformed credential ID";
813 break;
815 msg.info.tstr.err_info = "Authentication failed";
816 break;
818 msg.info.tstr.err_info = "Decryption failed";
819 break;
821 msg.info.tstr.err_info = "Internal error";
822 break;
824 msg.info.tstr.err_info = "Identity not allowed";
825 break;
826 case EDHOC_ERR_CREDENTIAL_NOT_FOUND: /* Unknown credential referenced */
827 case EDHOC_ERR_KEY_NOT_FOUND: /* Key not found - maps to unknown credential */
828 msg.err_code = EDHOC_MSG_ERR_CODE_UNKNOWN_CREDENTIAL_SELECTION;
829 /* RFC 9528: ERR_INFO for error code 3 should be boolean true */
830 /* This will be handled in serialization as cbor_write_bool(&writer, true) */
831 break;
833 msg.info.tstr.err_info = "Network timeout";
834 break;
836 msg.info.tstr.err_info = "Message correlation error";
837 break;
839 msg.info.tstr.err_info = "Message sequence error";
840 break;
842 msg.info.tstr.err_info = "Buffer overflow";
843 break;
845 msg.info.tstr.err_info = "Critical EAD item cannot be processed";
846 break;
847 }
848 LOG_ERR("ERR MSG (%d): ", msg.err_code);
849 if(msg.err_code == EDHOC_MSG_ERR_CODE_UNSPECIFIED_ERROR) {
850 msg.info.tstr.err_info_sz = strlen(msg.info.tstr.err_info);
851 LOG_ERR_STRING(msg.info.tstr.err_info, msg.info.tstr.err_info_sz);
852 } else if(msg.err_code == EDHOC_MSG_ERR_CODE_WRONG_CIPHER_SUITE) {
853 LOG_ERR("Wrong cipher suite, proposing %d suites", msg.info.suites.suites_num);
854 } else if(msg.err_code == EDHOC_MSG_ERR_CODE_UNKNOWN_CREDENTIAL_SELECTION) {
855 LOG_ERR("Unknown credential referenced");
856 }
857 LOG_ERR_("\n");
858
859 size_t err_sz = edhoc_serialize_err(&msg, msg_er, msg_er_sz);
860 LOG_DBG("ERR MSG CBOR: ");
861 LOG_DBG_BYTES(msg_er, err_sz);
862 LOG_DBG_("\n");
863 return err_sz;
864}
865/*---------------------------------------------------------------------------*/
866int
867edhoc_authenticate_msg(edhoc_context_t *ctx, uint8_t *ad, bool msg2)
868{
869 /* Point to decrypted plaintext for key retrieval */
870 uint8_t *plaintext_ptr = NULL;
871 size_t parse_size = ctx->buffers.plaintext_sz;
872 if(msg2) {
873 /* Skip C_R at beginning of plaintext_2 */
874 cbor_reader_state_t skip_reader;
875 cbor_init_reader(&skip_reader, ctx->buffers.plaintext, ctx->buffers.plaintext_sz);
876 size_t cid_size;
877 edhoc_read_byte_identifier(&skip_reader, &cid_size);
878 plaintext_ptr = (uint8_t *)cbor_get_position(&skip_reader);
879 parse_size = ctx->buffers.plaintext_sz - (plaintext_ptr - ctx->buffers.plaintext);
880 } else {
881 plaintext_ptr = ctx->buffers.plaintext;
882 }
883
884 /* Retrieve the peer credential from msg info and cred storage */
885 cose_key_t peer_key;
886 cose_key_t *key = &peer_key;
887
888 /* Initialize shared CBOR reader for sequential parsing */
889 cbor_reader_state_t reader;
890 cbor_init_reader(&reader, plaintext_ptr, parse_size);
891
892 /* Parse ID_CRED_X using shared reader state */
893 int8_t key_result = edhoc_get_key_id_cred_x(&reader, NULL, 0, key);
894 if(key_result < 0) {
895 LOG_ERR("Failed to parse ID_CRED_X (error: %d)\n", key_result);
896 return key_result;
897 }
898
899 /* Get MAC from the decrypted message using shared reader state */
900 uint8_t *received_mac = NULL;
901 uint16_t received_mac_sz = edhoc_get_sign(&reader, &received_mac);
902 if(received_mac_sz == 0) {
903 LOG_ERR("Failed to parse signature/MAC: invalid CBOR\n");
905 }
906
907 /* Get the additional data from the decrypted message if present */
908 uint16_t ad_sz = 0;
909 if(cbor_get_remaining(&reader) > 0 && ad) {
910 ad_sz = edhoc_get_ad(&reader, ad, EDHOC_MAX_AD_SZ);
911 if(ad_sz == 0) {
912 LOG_WARN("Failed to parse additional data\n");
913 ad = NULL;
914 }
915 } else {
916 ad = NULL;
917 }
918
919 /* generate cred_x and id_cred_x */
920 ctx->buffers.cred_x_sz = edhoc_generate_cred_x(key, ctx->buffers.cred_x,
921 sizeof(ctx->buffers.cred_x));
922 LOG_DBG("CRED_X auth (%zu): ", ctx->buffers.cred_x_sz);
923 LOG_DBG_BYTES(ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
924 LOG_DBG_("\n");
925
926 ctx->buffers.id_cred_x_sz =
927 edhoc_generate_id_cred_x(key, ctx->buffers.id_cred_x,
928 sizeof(ctx->buffers.id_cred_x));
929 LOG_DBG("ID_CRED_X auth (%zu): ", ctx->buffers.id_cred_x_sz);
930 LOG_DBG_BYTES(ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
931 LOG_DBG_("\n");
932
933#if (EDHOC_METHOD == EDHOC_METHOD3) || INITIATOR_METHOD1 || RESPONDER_METHOD2
934 /* Generate prk_3e2m or prk_4e3m */
935 if(msg2 == true) {
936 edhoc_generate_prk_3e2m(ctx, &key->ecc, 0);
937 } else { /* msg3 */
938 edhoc_generate_prk_4e3m(ctx, &key->ecc, 1);
939 }
940
941 if(check_mac(ctx, received_mac, received_mac_sz) == 0) {
942 LOG_ERR("error code in handler (%d)\n", EDHOC_ERR_CRYPTO_AUTHENTICATION);
944 }
945#endif
946
947#if (EDHOC_METHOD == EDHOC_METHOD0) || INITIATOR_METHOD2 || RESPONDER_METHOD1
948 if(msg2 == true) {
949 /* prk_3e2m is prk_2e */
950 memcpy(ctx->state.prk_3e2m, ctx->state.prk_2e, HASH_LEN);
951 } else { /* msg3 */
952 /* prk_4e3m is prk_3e2m */
953 memcpy(ctx->state.prk_4e3m, ctx->state.prk_3e2m, HASH_LEN);
954 }
955
956 /* Verify peer signature using COSE_Sign1. */
957
958 /* External AAD (TH_2/3, CRED_X, ? EAD_2/3) */
959 uint8_t external_aad[HASH_LEN + EDHOC_MAX_CRED_LEN];
960 cbor_writer_state_t writer;
961 cbor_init_writer(&writer, external_aad, sizeof(external_aad));
962 cbor_write_data(&writer, ctx->state.th, HASH_LEN);
963 cbor_write_object(&writer, ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
964 size_t external_aad_sz = cbor_end_writer(&writer);
965 if(external_aad_sz == 0) {
966 LOG_ERR("Failed to encode external AAD for COSE_Sign1 verification\n");
968 }
969
970 /* Recompute the local MAC that the peer is supposed to have signed. */
971 uint8_t mac_num = msg2 ? EDHOC_MAC_2 : EDHOC_MAC_3;
972 uint8_t mac[HASH_LEN];
973 edhoc_calc_mac(ctx, mac_num, HASH_LEN, mac);
974 LOG_DBG("MAC_%d (%d bytes): ", msg2 ? 2 : 3, HASH_LEN);
975 LOG_DBG_BYTES(mac, HASH_LEN);
976 LOG_DBG_("\n");
977
978 uint8_t other_public_key[ECC_KEY_LEN * 2];
979 memcpy(other_public_key, key->ecc.pub.x, ECC_KEY_LEN);
980 memcpy(other_public_key + ECC_KEY_LEN, key->ecc.pub.y, ECC_KEY_LEN);
981
982 if(!cose_sign1_verify(ctx->config.sign_alg, other_public_key,
983 ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz,
984 external_aad, external_aad_sz,
985 mac, HASH_LEN,
986 received_mac, received_mac_sz)) {
987 LOG_ERR("COSE_Sign1 signature verification failed\n");
989 }
990#endif
991
992 /* Compute TH_4 WIP (after verifying MAC_3) */
993 if(msg2 == false) { /* msg 3 */
994 /* Calculate TH_4 */
995 edhoc_generate_transcript_hash_4(ctx, ctx->buffers.cred_x, ctx->buffers.cred_x_sz,
996 ctx->buffers.plaintext, ctx->buffers.plaintext_sz);
997 }
998
999 return ad_sz;
1000}
1001/*---------------------------------------------------------------------------*/
1002void
1003edhoc_print_config_summary(const edhoc_context_t *ctx)
1004{
1005 if(ctx == NULL) {
1006 LOG_ERR("Cannot print config summary: NULL context\n");
1007 return;
1008 }
1009
1010 LOG_INFO("\n=== EDHOC Session Configuration ===\n");
1011 LOG_INFO("Role: %s\n", ctx->config.role == EDHOC_INITIATOR ? "Initiator" : "Responder");
1012 LOG_INFO("Method: %d\n", ctx->config.method);
1013 LOG_INFO("Suite Selected: %d\n", ctx->state.suite_selected);
1014 LOG_INFO("ECDH Curve: %s\n", ctx->config.ecdh_curve == 1 ? "P-256" : "Unknown");
1015 LOG_INFO("AEAD Algorithm: %d\n", ctx->config.aead_alg);
1016 LOG_INFO("MAC Length: %d\n", ctx->config.mac_len);
1017
1018 if(ctx->creds.authen_key != NULL) {
1019 LOG_INFO("Own Authentication Key: KID=%02x, Identity=%.*s\n",
1020 ctx->creds.authen_key->kid[0],
1021 ctx->creds.authen_key->identity_sz,
1022 ctx->creds.authen_key->identity);
1023 } else {
1024 LOG_INFO("Own Authentication Key: Not set\n");
1025 }
1026
1027 LOG_INFO("Own Connection ID: ");
1028 if(ctx->state.cid_len > 0) {
1029 for(int i = 0; i < ctx->state.cid_len; i++) {
1030 LOG_INFO_("%02x", ctx->state.cid[i]);
1031 }
1032 LOG_INFO_("\n");
1033 } else {
1034 LOG_INFO_("Not set\n");
1035 }
1036
1037 LOG_INFO("Peer Connection ID: ");
1038 if(ctx->state.cid_rx_len > 0) {
1039 for(int i = 0; i < ctx->state.cid_rx_len; i++) {
1040 LOG_INFO_("%02x", ctx->state.cid_rx[i]);
1041 }
1042 LOG_INFO_("\n");
1043 } else {
1044 LOG_INFO_("Not set\n");
1045 }
1046
1047 LOG_INFO("===================================\n");
1048}
1049/*---------------------------------------------------------------------------*/
CBOR API.
Public API declarations for COSE (RFC 9052).
bool ecdh_generate_ikm(uint8_t curve_id, const uint8_t *peer_x, const uint8_t *private_key, uint8_t *ikm)
Computes an ECDH shared secret.
Definition ecdh.c:123
EDHOC configuration file.
@ EDHOC_ERR_CRYPTO_DECRYPT
Decryption operation failed.
Definition edhoc-error.h:76
@ EDHOC_ERR_CREDENTIAL_NOT_FOUND
Credential not found.
Definition edhoc-error.h:97
@ EDHOC_ERR_NETWORK_TIMEOUT
Network operation timeout.
@ EDHOC_ERR_ID_CRED_MALFORMED
Malformed credential identifier.
Definition edhoc-error.h:89
@ EDHOC_ERR_CRITICAL_EAD_UNSUPPORTED
Critical EAD item cannot be processed (RFC 9528 Section 6).
Definition edhoc-error.h:92
@ EDHOC_ERR_INTERNAL_ERROR
Internal implementation error.
@ EDHOC_ERR_WRONG_CID
Wrong connection identifier.
Definition edhoc-error.h:87
@ EDHOC_ERR_CRYPTO_AUTHENTICATION
Authentication failed.
Definition edhoc-error.h:79
@ EDHOC_ERR_KEY_NOT_FOUND
Key not found in storage.
Definition edhoc-error.h:95
@ EDHOC_ERR_BUFFER_OVERFLOW
Buffer overflow detected.
Definition edhoc-error.h:67
@ EDHOC_ERR_SUITE_NOT_SUPPORTED
Cipher suite not supported.
Definition edhoc-error.h:83
@ EDHOC_ERR_MSG_MALFORMED
Malformed message received.
Definition edhoc-error.h:84
@ EDHOC_ERR_CORRELATION
Message correlation error.
Definition edhoc-error.h:91
@ EDHOC_ERR_CID_INVALID
Invalid connection identifier.
Definition edhoc-error.h:86
@ EDHOC_ERR_NOT_ALLOWED_IDENTITY
Identity not allowed.
@ EDHOC_ERR_METHOD_NOT_SUPPORTED
EDHOC method not supported.
Definition edhoc-error.h:85
@ EDHOC_ERR_SEQUENCE_ERROR
Message sequence error.
Definition edhoc-error.h:90
edhoc_error_t edhoc_check_key_list_kid(uint8_t *key_id, uint8_t key_id_size, cose_key_t **authentication_key)
Check in the keys repository for the key with the specific KID.
edhoc_error_t edhoc_check_key_list_identity(char *identity, uint8_t identity_size, cose_key_t **authentication_key)
Check in the keys repository for the key with the specific identity.
struct cose_key cose_key_t
KEY length in bytes.
size_t edhoc_serialize_err(const edhoc_msg_error_t *msg, unsigned char *buffer, size_t buffer_sz)
Serialize EDHOC error message to CBOR format.
Definition edhoc-msgs.c:201
const uint8_t * edhoc_read_byte_identifier(cbor_reader_state_t *reader, size_t *size)
Read byte identifier from CBOR reader.
Definition edhoc-msgs.c:85
uint8_t edhoc_get_ad(cbor_reader_state_t *reader, uint8_t *ad, size_t ad_buffer_size)
Parse Additional Data (AD) from CBOR reader.
Definition edhoc-msgs.c:734
int8_t edhoc_get_key_id_cred_x(cbor_reader_state_t *reader, uint8_t *out_id_cred_x, size_t id_cred_x_buffer_size, cose_key_t *key)
Parse ID_CRED_X from CBOR data and extract authentication key.
Definition edhoc-msgs.c:670
uint8_t edhoc_get_sign(cbor_reader_state_t *reader, uint8_t **sign)
Parse signature data from CBOR reader.
Definition edhoc-msgs.c:709
EDHOC message serialization and parsing API.
void edhoc_trace_transcript_hash(const char *th_label, const uint8_t *th_data, const uint8_t *input_data, size_t input_len)
Print transcript hash computation.
Definition edhoc-trace.c:97
void edhoc_trace_session_summary(const edhoc_context_t *ctx)
Print session summary at protocol completion.
void edhoc_trace_prk_derivation(const char *prk_label, const uint8_t *prk_data, const uint8_t *salt_data, const uint8_t *ikm_data)
Print PRK derivation step.
EDHOC tracing and logging header.
#define EDHOC_TRACE_VALUE(label, data, len)
Print cryptographic value in RFC 9529 trace format.
Definition edhoc-trace.h:59
#define EDHOC_TRACE_COMPUTE(description)
Print computation step description.
Definition edhoc-trace.h:81
#define EDHOC_DBG_VALUE(label, data, len)
Print detailed debug value (only at DBG level).
Definition edhoc-trace.h:90
An implementation of Ephemeral Diffie-Hellman Over COSE (EDHOC) (RFC9528).
bool cose_sign1_verify(int8_t alg, const uint8_t *public_key, const uint8_t *protected_hdr, size_t protected_hdr_len, const uint8_t *external_aad, size_t external_aad_len, const uint8_t *payload, size_t payload_len, const uint8_t *signature, size_t signature_len)
Verify a COSE_Sign1 signature.
Definition cose.c:242
void edhoc_print_session_info(const edhoc_context_t *ctx)
Print current EDHOC session information for debugging.
Definition edhoc.c:366
int8_t edhoc_generate_transcript_hash_2(edhoc_context_t *ctx, const uint8_t *eph_pub, uint8_t *msg, uint16_t msg_sz)
Generate transcript hash TH_2.
Definition edhoc.c:279
int8_t edhoc_set_config_from_suite(edhoc_context_t *ctx, uint8_t suite)
Set EDHOC configuration parameters based on cipher suite.
Definition edhoc.c:188
uint8_t edhoc_calc_mac(const edhoc_context_t *ctx, uint8_t mac_num, uint8_t mac_len, uint8_t *mac)
Calculate message authentication code (MAC).
Definition edhoc.c:417
uint8_t edhoc_setup_suites(edhoc_context_t *ctx)
Initialize the EDHOC Context with the defined EDHOC parameters.
Definition edhoc.c:89
size_t edhoc_generate_id_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
Generate credential identifier ID_CRED_X.
Definition edhoc.c:242
bool edhoc_generate_prk_2e(edhoc_context_t *ctx)
Generate pseudorandom key PRK_2e.
Definition edhoc.c:542
uint8_t edhoc_get_own_auth_key(edhoc_context_t *ctx, cose_key_t **key)
Retrieve own authentication key from key storage.
Definition edhoc.c:743
int16_t edhoc_kdf(const uint8_t *prk, uint8_t info_label, const uint8_t *context, uint8_t context_sz, uint16_t length, uint8_t *result)
EDHOC Key Derivation Function (KDF) based on HMAC-based Expand (RFC 5869).
Definition edhoc.c:373
void edhoc_print_config_summary(const edhoc_context_t *ctx)
Print EDHOC session configuration summary.
Definition edhoc.c:1003
int16_t edhoc_enc_dec_ciphertext_2(const edhoc_context_t *ctx, const uint8_t *ks_2e, uint8_t *plaintext, uint16_t plaintext_sz)
Encrypt/decrypt ciphertext 2 using XOR with keystream.
Definition edhoc.c:665
int16_t edhoc_expand(const uint8_t *prk, const uint8_t *info, uint16_t info_sz, uint16_t length, uint8_t *result)
HMAC-based Key Expansion Function for EDHOC context using HKDF (RFC 5869).
Definition edhoc.c:406
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
bool edhoc_generate_prk_4e3m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
Generate pseudorandom key PRK_4e3m.
bool edhoc_generate_prk_3e2m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
Generate pseudorandom key PRK_3e2m.
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
size_t edhoc_generate_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
Generate CBOR-encoded credential CRED_X.
Definition edhoc.c:210
uint8_t edhoc_generate_transcript_hash_3(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz, const uint8_t *plaintext, uint16_t plaintext_sz)
Generate transcript hash TH_3.
Definition edhoc.c:306
int16_t edhoc_generate_keystream_2e(edhoc_context_t *ctx, uint16_t length, uint8_t *ks_2e)
Generate keystream KS_2e for encryption.
Definition edhoc.c:561
void edhoc_finalize(edhoc_context_t *ctx)
Close the EDHOC context.
Definition edhoc.c:83
uint8_t edhoc_generate_transcript_hash_4(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz, const uint8_t *plaintext, uint16_t plaintext_sz)
Generate transcript hash TH_4.
Definition edhoc.c:335
size_t cbor_end_writer(cbor_writer_state_t *state)
Finishes writing CBOR output.
Definition cbor.c:54
size_t cbor_get_remaining(cbor_reader_state_t *state)
Gets the remaining bytes in the CBOR buffer.
Definition cbor.c:475
void cbor_open_map(cbor_writer_state_t *state)
Adds subsequent entries to a map.
Definition cbor.c:276
void cbor_write_text(cbor_writer_state_t *state, const char *text, size_t text_size)
Appends a text string.
Definition cbor.c:196
void cbor_write_unsigned(cbor_writer_state_t *state, uint64_t value)
Appends an unsigned integer.
Definition cbor.c:169
void cbor_close_map(cbor_writer_state_t *state)
Stops adding subsequent entries to the innermost map.
Definition cbor.c:282
void cbor_write_object(cbor_writer_state_t *state, const void *object, size_t object_size)
Appends an arbitrary CBOR object.
Definition cbor.c:106
void cbor_init_writer(cbor_writer_state_t *state, uint8_t *buffer, size_t buffer_size)
Prepares for writing CBOR output.
Definition cbor.c:44
const uint8_t * cbor_get_position(cbor_reader_state_t *state)
Gets the current position in the CBOR buffer.
Definition cbor.c:469
void cbor_init_reader(cbor_reader_state_t *state, const uint8_t *cbor, size_t cbor_size)
Prepares for reading CBOR input.
Definition cbor.c:293
void cbor_write_data(cbor_writer_state_t *state, const uint8_t *data, size_t data_size)
Appends a byte string.
Definition cbor.c:187
void cbor_write_signed(cbor_writer_state_t *state, int64_t value)
Appends a signed integer.
Definition cbor.c:176
void sha_256_hkdf_expand(const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, uint8_t *okm, uint_fast16_t okm_len)
Expands a key as per RFC 5869.
Definition sha-256.c:415
#define EDHOC_METHOD
Set the Authentication method.
#define EDHOC_DEFAULT_CID_LEN
Default CID length for backward compatibility.
#define EDHOC_MAX_CRED_LEN
Optimized buffer sizes for credentials based on COSE standard analysis CRED_X: 84-120 bytes typical →...
#define EDHOC_AUTHENT_TYPE
Set the authentication credential type/usage.
#define EDHOC_MAX_AD_SZ
The max length of the Application Data.
#define EDHOC_SUPPORTED_SUITE_1
Set EDHOC cipher suite config.
#define EDHOC_ROLE
Set the EDHOC Protocol role.
#define EDHOC_MAX_BUFFER
The max size of the buffers.
#define EDHOC_MAX_CID_LEN
Maximum length of connection identifiers RFC 9528 allows variable-length CIDs including negative inte...
#define EDHOC_CID
Set EDHOC connection identifier.
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
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition memb.h:91
Header file for the logging system.
Platform-independent SHA-256 API.
Structure of the internal state of a CBOR reader.
Definition cbor.h:130
Structure of the internal state of a CBOR writer.
Definition cbor.h:119