libcoap 4.3.5-develop-3a2cdb1
Loading...
Searching...
No Matches
coap_oscore.c
Go to the documentation of this file.
1/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
3/*
4 * coap_oscore.c -- Object Security for Constrained RESTful Environments
5 * (OSCORE) support for libcoap
6 *
7 * Copyright (C) 2019-2021 Olaf Bergmann <bergmann@tzi.org>
8 * Copyright (C) 2021-2026 Jon Shallow <supjps-libcoap@jpshallow.com>
9 *
10 * SPDX-License-Identifier: BSD-2-Clause
11 *
12 * This file is part of the CoAP library libcoap. Please see README for terms
13 * of use.
14 */
15
20
22
23#if COAP_OSCORE_SUPPORT
24#include <ctype.h>
25
26#define AAD_BUF_LEN 200 /* length of aad_buffer */
27
28static oscore_ctx_t *coap_oscore_init(coap_context_t *c_context,
29 coap_oscore_conf_t *oscore_conf);
30
31#if COAP_CLIENT_SUPPORT
32
33int
35 if (oscore_conf) {
36 oscore_ctx_t *osc_ctx;
37
38 if (oscore_conf->recipient_chain == NULL) {
39 coap_log_warn("OSCORE: Recipient ID must be defined for a client\n");
40 coap_delete_oscore_conf(oscore_conf);
41 return 0;
42 }
43 if (oscore_conf->rfc8613_b_2) {
44 /* Need to replace id_context with random value */
45 coap_binary_t *id_context = coap_new_binary(8);
46
47 if (id_context == NULL) {
48 coap_delete_oscore_conf(oscore_conf);
49 return 0;
50 }
52 coap_prng_lkd(id_context->s, id_context->length);
53 oscore_conf->id_context = (coap_bin_const_t *)id_context;
54 session->b_2_step = COAP_OSCORE_B_2_STEP_1;
55 coap_log_oscore("Appendix B.2 client step 1 (Generated ID1)\n");
56 }
57
58 osc_ctx = coap_oscore_init(session->context, oscore_conf);
59 if (osc_ctx == NULL) {
60 return 0;
61 }
63 session->oscore_encryption = 1;
64 }
65 return 1;
66}
67
70 const coap_address_t *local_if,
71 const coap_address_t *server,
72 coap_proto_t proto,
73 coap_oscore_conf_t *oscore_conf) {
74 coap_session_t *session;
75
76 coap_lock_lock(return NULL);
77 session = coap_new_client_session_oscore3_lkd(ctx, local_if, server, proto, oscore_conf, NULL,
78 NULL, NULL);
80 return session;
81}
82
85 const coap_address_t *local_if,
86 const coap_address_t *server,
87 coap_proto_t proto,
88 coap_oscore_conf_t *oscore_conf,
89 void *app_data,
91 coap_str_const_t *ws_host) {
92 coap_session_t *session;
93
94 coap_lock_lock(return NULL);
95 session = coap_new_client_session_oscore3_lkd(ctx, local_if, server, proto, oscore_conf, app_data,
96 callback, ws_host);
98 return session;
99}
100
103 const coap_address_t *local_if,
104 const coap_address_t *server,
105 coap_proto_t proto,
106 coap_oscore_conf_t *oscore_conf,
107 void *app_data,
109 coap_str_const_t *ws_host) {
110 coap_session_t *session =
111 coap_new_client_session3_lkd(ctx, local_if, server, proto, app_data, callback, ws_host);
112
113 if (!session)
114 return NULL;
115
116 if (coap_oscore_initiate(session, oscore_conf) == 0) {
118 return NULL;
119 }
120 return session;
121}
122
125 const coap_address_t *local_if,
126 const coap_address_t *server,
127 coap_proto_t proto,
128 coap_dtls_cpsk_t *psk_data,
129 coap_oscore_conf_t *oscore_conf) {
130 coap_session_t *session;
131
132 coap_lock_lock(return NULL);
133 session = coap_new_client_session_oscore_psk3_lkd(ctx, local_if, server, proto, psk_data,
134 oscore_conf, NULL, NULL, NULL);
136 return session;
137}
138
141 const coap_address_t *local_if,
142 const coap_address_t *server,
143 coap_proto_t proto,
144 coap_dtls_cpsk_t *psk_data,
145 coap_oscore_conf_t *oscore_conf,
146 void *app_data,
148 coap_str_const_t *ws_host) {
149 coap_session_t *session;
150
151 coap_lock_lock(return NULL);
152 session = coap_new_client_session_oscore_psk3_lkd(ctx, local_if, server, proto, psk_data,
153 oscore_conf, app_data, callback, ws_host);
155 return session;
156}
157
160 const coap_address_t *local_if,
161 const coap_address_t *server,
162 coap_proto_t proto,
163 coap_dtls_cpsk_t *psk_data,
164 coap_oscore_conf_t *oscore_conf,
165 void *app_data,
167 coap_str_const_t *ws_host) {
168 coap_session_t *session;
169
171 session = coap_new_client_session_psk3_lkd(ctx, local_if, server, proto, psk_data,
172 app_data, callback, ws_host);
173
174 if (!session)
175 return NULL;
176
177 if (coap_oscore_initiate(session, oscore_conf) == 0) {
179 return NULL;
180 }
181 return session;
182}
183
186 const coap_address_t *local_if,
187 const coap_address_t *server,
188 coap_proto_t proto,
189 coap_dtls_pki_t *pki_data,
190 coap_oscore_conf_t *oscore_conf) {
191 coap_session_t *session;
192
193 coap_lock_lock(return NULL);
194 session = coap_new_client_session_oscore_pki3_lkd(ctx, local_if, server, proto, pki_data,
195 oscore_conf, NULL, NULL, NULL);
197 return session;
198}
199
202 const coap_address_t *local_if,
203 const coap_address_t *server,
204 coap_proto_t proto,
205 coap_dtls_pki_t *pki_data,
206 coap_oscore_conf_t *oscore_conf,
207 void *app_data,
209 coap_str_const_t *ws_host) {
210 coap_session_t *session;
211
212 coap_lock_lock(return NULL);
213 session = coap_new_client_session_oscore_pki3_lkd(ctx, local_if, server, proto, pki_data,
214 oscore_conf, app_data, callback, ws_host);
216 return session;
217}
218
221 const coap_address_t *local_if,
222 const coap_address_t *server,
223 coap_proto_t proto,
224 coap_dtls_pki_t *pki_data,
225 coap_oscore_conf_t *oscore_conf,
226 void *app_data,
228 coap_str_const_t *ws_host) {
229 coap_session_t *session;
230
232 session = coap_new_client_session_pki3_lkd(ctx, local_if, server, proto, pki_data,
233 app_data, callback, ws_host);
234
235 if (!session)
236 return NULL;
237
238 if (coap_oscore_initiate(session, oscore_conf) == 0) {
240 return NULL;
241 }
242 return session;
243}
244#endif /* COAP_CLIENT_SUPPORT */
245#if COAP_SERVER_SUPPORT
246
247COAP_API int
249 coap_oscore_conf_t *oscore_conf) {
250 int ret;
251
252 coap_lock_lock(return 0);
253 ret = coap_context_oscore_server_lkd(context, oscore_conf);
255 return ret;
256}
257
258int
260 coap_oscore_conf_t *oscore_conf) {
261 oscore_ctx_t *osc_ctx;
262
264 osc_ctx = coap_oscore_init(context, oscore_conf);
265 /* osc_ctx already added to context->osc_ctx */
266 if (osc_ctx)
267 return 1;
268 return 0;
269}
270
271#endif /* COAP_SERVER_SUPPORT */
272
273int
275 coap_uri_t uri;
276 coap_opt_iterator_t opt_iter;
277 coap_opt_t *option;
278 uint8_t option_value_buffer[15];
279 coap_optlist_t *optlist_chain = NULL;
280
281 if ((option =
282 coap_check_option(pdu, COAP_OPTION_PROXY_URI, &opt_iter)) == NULL)
283 return 1;
284
285 /* Need to break down into the component parts, but keep data safe */
286 memset(&uri, 0, sizeof(uri));
287
289 coap_opt_length(option),
290 &uri) < 0 || uri.scheme >= COAP_URI_SCHEME_LAST) {
291 coap_log_warn("Proxy URI '%.*s' not decodable\n",
292 coap_opt_length(option),
293 (const char *)coap_opt_value(option));
294 goto error;
295 }
297 goto error;
298
299 if (!coap_insert_option(pdu,
301 uri.host.length,
302 uri.host.s))
303 goto error;
307 coap_encode_var_safe(option_value_buffer,
308 sizeof(option_value_buffer),
309 uri.port & 0xffff),
310 option_value_buffer))
311 goto error;
312 if (uri.path.length) {
313 /* Add in the Uri-Path options */
315 &optlist_chain))
316 goto error;
317 }
318 if (uri.query.length) {
319 /* Add in the Uri-Query options */
321 &optlist_chain))
322 goto error;
323 }
324 if (!coap_add_optlist_pdu(pdu, &optlist_chain))
325 goto error;
326
327 if (!coap_insert_option(pdu,
329 strlen(coap_uri_scheme[uri.scheme].name),
330 (const uint8_t *)coap_uri_scheme[uri.scheme].name))
331 goto error;
332
333 coap_delete_optlist(optlist_chain);
334 return 1;
335
336error:
337 coap_delete_optlist(optlist_chain);
338 return 0;
339}
340
341static void
342dump_cose(cose_encrypt0_t *cose, const char *message) {
343#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_OSCORE
344 (void)cose;
345 (void)message;
346#else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
348 char buffer[30];
349
350 coap_log_oscore("%s COSE information\n", message);
352 cose_get_alg_name(cose->alg, buffer, sizeof(buffer)));
354 oscore_log_hex_value(COAP_LOG_OSCORE, "partial_iv", &cose->partial_iv);
356 oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
358 "oscore_option",
359 &cose->oscore_option);
361 oscore_log_hex_value(COAP_LOG_OSCORE, "external_aad", &cose->external_aad);
363 }
364#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
365}
366
369 coap_pdu_t *pdu,
370 coap_bin_const_t *kid_context,
371 oscore_partial_iv_t send_partial_iv) {
372 coap_pdu_t *ret_pdu;
373
374 coap_lock_lock(return NULL);
375 ret_pdu = coap_oscore_new_pdu_encrypted_lkd(session, pdu, kid_context, send_partial_iv);
377
378 return ret_pdu;
379}
380
381/*
382 * Take current PDU, create a new one appropriately separated as per RFC8613
383 * and then encrypt / integrity check the OSCORE data
384 */
387 coap_pdu_t *pdu,
388 coap_bin_const_t *kid_context,
389 oscore_partial_iv_t send_partial_iv) {
390 uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu) || COAP_PDU_IS_PING(pdu);
391 coap_pdu_code_t code =
392 coap_request ? COAP_REQUEST_CODE_POST : COAP_RESPONSE_CODE(204);
393 coap_pdu_t *osc_pdu;
394 coap_pdu_t *plain_pdu = NULL;
395 coap_bin_const_t pdu_token;
396 coap_opt_iterator_t opt_iter;
397 coap_opt_t *option;
398 uint8_t pdu_code = pdu->code;
399 size_t length;
400 const uint8_t *data;
401 uint8_t *ciphertext_buffer = NULL;
402 size_t ciphertext_len = 0;
403 uint8_t aad_buffer[AAD_BUF_LEN];
404 uint8_t nonce_buffer[13];
406 coap_bin_const_t nonce;
407 oscore_recipient_ctx_t *rcp_ctx;
408 oscore_ctx_t *osc_ctx;
409 cose_encrypt0_t cose[1];
410 uint8_t group_flag = 0;
411 int show_pdu = 0;
412 int doing_observe = 0;
413 uint32_t observe_value = 0;
414 oscore_association_t *association = NULL;
415 oscore_sender_ctx_t *snd_ctx;
416 uint8_t external_aad_buffer[200];
417 coap_bin_const_t external_aad;
418 uint8_t oscore_option[255];
419 ssize_t oscore_option_len;
420
421 /* Check that OSCORE has not already been done */
422 if (coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter))
423 return NULL;
424
425 if (coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter))
426 doing_observe = 1;
427
428 coap_log_debug("PDU to encrypt\n");
430 osc_pdu = coap_pdu_init(pdu->type == COAP_MESSAGE_NON &&
431 session->b_2_step != COAP_OSCORE_B_2_NONE ?
432 COAP_MESSAGE_CON : pdu->type,
433 code,
434 pdu->mid,
435 pdu->used_size + coap_oscore_overhead(session, pdu));
436 if (osc_pdu == NULL)
437 return NULL;
438
439 cose_encrypt0_init(cose); /* clears cose memory */
440 pdu_token = coap_pdu_get_token(pdu);
441 if (coap_request) {
442 /*
443 * RFC8613 8.1 Step 1. Protecting the client's request
444 * Get the Sender Context
445 */
446 rcp_ctx = session->recipient_ctx;
447 if (rcp_ctx == NULL)
448 goto error;
449 osc_ctx = rcp_ctx->osc_ctx;
450 assert(osc_ctx);
451 snd_ctx = osc_ctx->sender_context;
452 } else {
453 /*
454 * RFC8613 8.3 Step 1. Protecting the server's response
455 * Get the Sender Context
456 */
457 association = oscore_find_association(session, &pdu_token);
458 if (association == NULL)
459 goto error;
460
461 rcp_ctx = association->recipient_ctx;
462 osc_ctx = rcp_ctx->osc_ctx;
463 snd_ctx = osc_ctx->sender_context;
464 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
465 cose_encrypt0_set_aad(cose, association->aad);
466 }
467
468 cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
469
470 if (coap_request || doing_observe ||
471 send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
472 uint8_t partial_iv_buffer[8];
473 size_t partial_iv_len;
474 coap_bin_const_t partial_iv;
475 partial_iv_len = coap_encode_var_safe8(partial_iv_buffer,
476 sizeof(partial_iv_buffer),
477 snd_ctx->seq);
478 if (snd_ctx->seq == 0) {
479 /* Need to special case */
480 partial_iv_buffer[0] = '\000';
481 partial_iv_len = 1;
482 }
483 partial_iv.s = partial_iv_buffer;
484 partial_iv.length = partial_iv_len;
485 cose_encrypt0_set_partial_iv(cose, &partial_iv);
486 }
487
488 if (coap_request)
490
491 cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
492
493 /* nonce (needs to have sender information correctly set up) */
494
495 if (coap_request || doing_observe ||
496 send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
497 /*
498 * 8.1 Step 3 or RFC8613 8.3.1 Step A
499 * Compose the AEAD nonce
500 *
501 * Requires in COSE object as appropriate
502 * key_id (kid) (sender)
503 * partial_iv (sender)
504 * common_iv (already in osc_ctx)
505 */
506 nonce.s = nonce_buffer;
507 nonce.length = 13;
508 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
509 cose_encrypt0_set_nonce(cose, &nonce);
510 if (!oscore_increment_sender_seq(osc_ctx))
511 goto error;
512 if (osc_ctx->save_seq_num_func) {
513 if (osc_ctx->sender_context->seq > osc_ctx->sender_context->next_seq) {
514 /* Only update at ssn_freq rate */
515 osc_ctx->sender_context->next_seq += osc_ctx->ssn_freq;
516 osc_ctx->save_seq_num_func(osc_ctx->sender_context->next_seq,
517 osc_ctx->save_seq_num_func_param);
518 }
519 }
520 } else {
521 /*
522 * 8.3 Step 3.
523 * Use nonce from request
524 */
525 cose_encrypt0_set_nonce(cose, association->nonce);
526 }
527
528 /* OSCORE_option (needs to be before AAD as included in AAD if group) */
529
530 /* cose is modified for encode option in response message */
531 if (!coap_request) {
532 /* no kid on response */
534 if (!doing_observe && send_partial_iv == OSCORE_SEND_NO_IV)
536 }
537 if (kid_context) {
538 cose_encrypt0_set_kid_context(cose, kid_context);
539 }
540 oscore_option_len =
541 oscore_encode_option_value(oscore_option, sizeof(oscore_option), cose,
542 group_flag,
543 session->b_2_step != COAP_OSCORE_B_2_NONE);
544 if (oscore_option_len < 0) {
545 coap_log_oscore("Invalid parameters for creating OSCORE option\n");
546 goto error;
547 }
548 if (!coap_request) {
549 /* Reset what was just unset as appropriate for AAD */
551 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
552 }
553 if (kid_context)
555
556 /*
557 * RFC8613 8.1/8.3 Step 2(a) (5.4).
558 * Compose the External AAD and then AAD
559 *
560 * OSCORE_option requires
561 * partial_iv (cose partial_iv)
562 * kid_context (cose kid_context)
563 * key_id (cose key_id)
564 * group_flag
565 *
566 * Non Group requires the following
567 * RFC8613 5.4
568 * oscore_version 1
569 * algorithms [
570 * aead_alg (osc_ctx)
571 * ]
572 * request_kid (request key_id using cose)
573 * request_piv (request partial_iv using cose)
574 * options (none at present)
575 *
576 * Note: No I options at present
577 */
578 if (coap_request || send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
579 /* External AAD */
580 external_aad.s = external_aad_buffer;
581 external_aad.length = oscore_prepare_e_aad(osc_ctx,
582 cose,
583 NULL,
584 0,
585 NULL,
586 external_aad_buffer,
587 sizeof(external_aad_buffer));
588 if (external_aad.length == 0)
589 goto error;
590 cose_encrypt0_set_external_aad(cose, &external_aad);
591
592 /* AAD */
593 aad.s = aad_buffer;
594 aad.length = oscore_prepare_aad(external_aad_buffer,
595 external_aad.length,
596 aad_buffer,
597 sizeof(aad_buffer));
598 if (aad.length == 0)
599 goto error;
600 assert(aad.length < AAD_BUF_LEN);
601 cose_encrypt0_set_aad(cose, &aad);
602 }
603
604 /*
605 * RFC8613 8.1/8.3 Step 2(b) (5.3).
606 *
607 * Set up temp plaintext pdu, the data including token, options and
608 * optional payload will get encrypted as COSE ciphertext.
609 */
610 plain_pdu = coap_pdu_init(pdu->type,
611 pdu->code,
612 pdu->mid,
613 pdu->used_size + 1 /* pseudo-token with actual code */);
614 if (plain_pdu == NULL)
615 goto error;
616
617 coap_add_token(osc_pdu, pdu_token.length, pdu_token.s);
618
619 /* First byte of plain is real CoAP code. Pretend it is token */
620 coap_add_token(plain_pdu, 1, &pdu_code);
621
622 /* Copy across the Outer/Inner Options to respective PDUs */
624 while ((option = coap_option_next(&opt_iter))) {
625 switch ((coap_code_opt_num_t)opt_iter.number) {
631 /* Outer only */
632 if (!coap_insert_option(osc_pdu,
633 opt_iter.number,
634 coap_opt_length(option),
635 coap_opt_value(option)))
636 goto error;
637 break;
639 /* Make as Outer option as-is */
640 if (!coap_insert_option(osc_pdu,
641 opt_iter.number,
642 coap_opt_length(option),
643 coap_opt_value(option)))
644 goto error;
645 if (coap_request) {
646 /* Make as Inner option (unchanged) */
647 if (!coap_insert_option(plain_pdu,
648 opt_iter.number,
649 coap_opt_length(option),
650 coap_opt_value(option)))
651 goto error;
652 osc_pdu->code = COAP_REQUEST_CODE_FETCH;
653 } else {
654 /* Make as Inner option but empty */
655 if (!coap_insert_option(plain_pdu, opt_iter.number, 0, NULL))
656 goto error;
657 osc_pdu->code = COAP_RESPONSE_CODE(205);
658 }
659 show_pdu = 1;
660 doing_observe = 1;
661 observe_value = coap_decode_var_bytes(coap_opt_value(option),
662 coap_opt_length(option));
663 break;
665 /*
666 * Should have already been caught by doing
667 * coap_rebuild_pdu_for_proxy() before calling
668 * coap_oscore_new_pdu_encrypted_lkd()
669 */
670 assert(0);
671 break;
673 /* Dealt with separately */
674 break;
676 case COAP_OPTION_ETAG:
693 case COAP_OPTION_ECHO:
694 case COAP_OPTION_RTAG:
695 default:
696 /* Make as Inner option */
697 if (!coap_insert_option(plain_pdu,
698 opt_iter.number,
699 coap_opt_length(option),
700 coap_opt_value(option)))
701 goto error;
702 break;
703 }
704 }
705 /* Add in data to plain */
706 if (coap_get_data(pdu, &length, &data)) {
707 if (!coap_add_data(plain_pdu, length, data))
708 goto error;
709 }
710 if (show_pdu) {
711 coap_log_oscore("OSCORE payload\n");
712 coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
713 }
714
715 /*
716 * 8.1/8.3 Step 4.
717 * Encrypt the COSE object.
718 *
719 * Requires in COSE object as appropriate
720 * alg (already set)
721 * key (sender key)
722 * nonce (already set)
723 * aad (already set)
724 * plaintext
725 */
726 cose_encrypt0_set_key(cose, snd_ctx->sender_key);
727 cose_encrypt0_set_plaintext(cose, plain_pdu->token, plain_pdu->used_size);
728 dump_cose(cose, "Pre encrypt");
729 ciphertext_buffer =
730 coap_malloc_type(COAP_OSCORE_BUF, OSCORE_CRYPTO_BUFFER_SIZE);
731 if (ciphertext_buffer == NULL)
732 goto error;
733 ciphertext_len = cose_encrypt0_encrypt(cose,
734 ciphertext_buffer,
735 plain_pdu->used_size + AES_CCM_TAG);
736 if ((int)ciphertext_len <= 0) {
737 coap_log_warn("OSCORE: Encryption Failure, result code: %d \n",
738 (int)ciphertext_len);
739 goto error;
740 }
741 assert(ciphertext_len < OSCORE_CRYPTO_BUFFER_SIZE);
742
743 /* Add in OSCORE option (previously computed) */
744 if (!coap_insert_option(osc_pdu,
746 oscore_option_len,
747 oscore_option))
748 goto error;
749
750 /* Add now encrypted payload */
751 if (!coap_add_data(osc_pdu, ciphertext_len, ciphertext_buffer))
752 goto error;
753
754 coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
755 ciphertext_buffer = NULL;
756
757 coap_delete_pdu_lkd(plain_pdu);
758 plain_pdu = NULL;
759
760 if (association && (association->is_observe == 0 || (COAP_RESPONSE_CLASS(pdu->code) != 2 &&
761 pdu->code != COAP_RESPONSE_CODE(401))))
762 oscore_delete_association(session, association);
763 association = NULL;
764
765 if (!coap_pdu_encode_header(osc_pdu, session->proto)) {
766 goto error;
767 }
768
769 /*
770 * Set up an association for handling a response if this is a request
771 */
772 if (coap_request) {
773 association = oscore_find_association(session, &pdu_token);
774 if (association) {
775 /* Refresh the association */
776 coap_delete_bin_const(association->nonce);
777 association->nonce =
778 coap_new_bin_const(cose->nonce.s, cose->nonce.length);
779 if (association->nonce == NULL)
780 goto error;
781 coap_delete_bin_const(association->aad);
782 association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
783 if (association->aad == NULL)
784 goto error;
785 if (doing_observe && observe_value == 1) {
787 association->obs_partial_iv = association->partial_iv;
788 } else {
789 coap_delete_bin_const(association->partial_iv);
790 }
791 association->partial_iv =
793 if (association->partial_iv == NULL)
794 goto error;
795 coap_oscore_association_set_recipient_ctx(association, rcp_ctx);
796 coap_delete_pdu_lkd(association->sent_pdu);
797 if (session->b_2_step != COAP_OSCORE_B_2_NONE || association->just_set_up) {
798 size_t size;
799
800 association->sent_pdu = coap_pdu_duplicate_lkd(pdu, session,
801 pdu_token.length,
802 pdu_token.s, NULL,
804 if (association->sent_pdu == NULL)
805 goto error;
806 if (coap_get_data(pdu, &size, &data)) {
807 coap_add_data(association->sent_pdu, size, data);
808 }
809 association->just_set_up = 0;
810 } else {
811 association->sent_pdu = NULL;
812 }
813 } else if (!oscore_new_association(session,
814 pdu,
815 &pdu_token,
816 rcp_ctx,
817 &cose->aad,
818 &cose->nonce,
819 &cose->partial_iv,
820 doing_observe)) {
821 goto error;
822 }
823 }
824 return osc_pdu;
825
826error:
827 if (association && (association->is_observe == 0 || (COAP_RESPONSE_CLASS(pdu->code) != 2 &&
828 pdu->code != COAP_RESPONSE_CODE(401))))
829 oscore_delete_association(session, association);
830 if (ciphertext_buffer)
831 coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
832 coap_delete_pdu_lkd(osc_pdu);
833 coap_delete_pdu_lkd(plain_pdu);
834 return NULL;
835}
836
837static void
838build_and_send_error_pdu(coap_session_t *session,
839 coap_pdu_t *rcvd,
840 coap_pdu_code_t code,
841 const char *diagnostic,
842 uint8_t *echo_data,
843 coap_bin_const_t *kid_context,
844 int encrypt_oscore) {
845 coap_pdu_t *err_pdu = NULL;
846 coap_bin_const_t token;
847 int oscore_encryption = session->oscore_encryption;
848 unsigned char buf[4];
849
850 token = coap_pdu_get_token(rcvd);
853 code,
854 rcvd->mid,
855 token.length + 2 + 8 +
856 (diagnostic ? strlen(diagnostic) : 0));
857 if (!err_pdu)
858 return;
859 coap_add_token(err_pdu, token.length, token.s);
860 if (echo_data) {
861 coap_add_option_internal(err_pdu, COAP_OPTION_ECHO, 8, echo_data);
862 } else if (kid_context == NULL) {
865 coap_encode_var_safe(buf, sizeof(buf), 0),
866 buf);
867 }
868 if (diagnostic)
869 coap_add_data(err_pdu, strlen(diagnostic), (const uint8_t *)diagnostic);
870 session->oscore_encryption = encrypt_oscore;
871
872 if ((echo_data || kid_context) && encrypt_oscore) {
873 coap_pdu_t *osc_pdu;
874
875 osc_pdu =
876 coap_oscore_new_pdu_encrypted_lkd(session, err_pdu, kid_context,
877 echo_data ? 1 : 0);
878 if (!osc_pdu)
879 goto fail_resp;
880 session->oscore_encryption = 0;
881 coap_send_internal(session, osc_pdu, NULL);
882 coap_delete_pdu_lkd(err_pdu);
883 err_pdu = NULL;
884 } else {
885 coap_send_internal(session, err_pdu, NULL);
886 err_pdu = NULL;
887 }
888fail_resp:
889 session->oscore_encryption = oscore_encryption;
890 coap_delete_pdu_lkd(err_pdu);
891 return;
892}
893
896 oscore_ctx_t *oscore_ctx = oscore_derive_ctx_from_conf(oscore_conf);
897
898 if (oscore_ctx == NULL) {
899 goto error;
900 }
901
902 /* As all is stored in osc_ctx, oscore_conf is no longer needed */
903 coap_free_type(COAP_STRING, oscore_conf);
904
905 return oscore_ctx;
906error:
907 coap_delete_oscore_conf(oscore_conf);
908 return NULL;
909}
910
911/* pdu contains incoming message with encrypted COSE ciphertext payload
912 * function returns decrypted message
913 * and verifies signature, if present
914 * returns NULL when decryption,verification fails
915 */
918 coap_pdu_t *pdu) {
919 coap_pdu_t *decrypt_pdu = NULL;
920 coap_pdu_t *plain_pdu = NULL;
921 const uint8_t *osc_value; /* value of OSCORE option */
922 uint8_t osc_size; /* size of OSCORE OPTION */
923 coap_opt_iterator_t opt_iter;
924 coap_opt_t *opt = NULL;
925 cose_encrypt0_t cose[1];
926 oscore_ctx_t *osc_ctx = NULL;
927 uint8_t aad_buffer[AAD_BUF_LEN];
928 uint8_t nonce_buffer[13];
930 coap_bin_const_t nonce;
931 int pltxt_size = 0;
932 int got_resp_piv = 0;
933 int doing_resp_observe = 0;
934 uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu);
935 coap_bin_const_t pdu_token;
936 uint8_t *st_encrypt;
937 size_t encrypt_len;
938 size_t tag_len;
939 oscore_recipient_ctx_t *rcp_ctx = NULL;
940 oscore_association_t *association = NULL;
941 oscore_association_t *decrypt_request_association = NULL;
942 uint8_t external_aad_buffer[100];
943 coap_bin_const_t external_aad;
944 oscore_sender_ctx_t *snd_ctx = NULL;
945#if COAP_CLIENT_SUPPORT
946 coap_pdu_t *sent_pdu = NULL;
947#endif /* COAP_CLIENT_SUPPORT */
948
949 opt = coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter);
950 assert(opt);
951 if (opt == NULL)
952 return NULL;
953
954 if (session->context->p_osc_ctx == NULL && session->context->oscore_find_cb == NULL) {
955 coap_log_warn("OSCORE: Not enabled\n");
956 if (!coap_request)
959 session);
960 return NULL;
961 }
962
963 if (pdu->data == NULL) {
964 coap_log_warn("OSCORE: No protected payload\n");
965 if (!coap_request)
968 session);
969 return NULL;
970 }
971
972 osc_size = coap_opt_length(opt);
973 osc_value = coap_opt_value(opt);
974
975 cose_encrypt0_init(cose); /* clear cose memory */
976
977 /* PDU code will be filled in after decryption */
978 decrypt_pdu =
979 coap_pdu_init(pdu->type, 0, pdu->mid, pdu->used_size);
980 if (decrypt_pdu == NULL) {
981 if (!coap_request)
984 session);
985 goto error;
986 }
987
988 /* Copy across the Token */
989 pdu_token = coap_pdu_get_token(pdu);
990 coap_add_token(decrypt_pdu, pdu_token.length, pdu_token.s);
991
992 /*
993 * 8.2/8.4 Step 1.
994 * Copy outer options across, except E and OSCORE options
995 */
997 while ((opt = coap_option_next(&opt_iter))) {
998 switch ((coap_code_opt_num_t)opt_iter.number) {
999 /* 'E' options skipped */
1001 case COAP_OPTION_ETAG:
1008 case COAP_OPTION_MAXAGE:
1010 case COAP_OPTION_ACCEPT:
1013 case COAP_OPTION_BLOCK2:
1014 case COAP_OPTION_BLOCK1:
1015 case COAP_OPTION_SIZE2:
1017 case COAP_OPTION_SIZE1:
1019 case COAP_OPTION_ECHO:
1020 case COAP_OPTION_RTAG:
1021 /* OSCORE does not get copied across */
1022 case COAP_OPTION_OSCORE:
1023 break;
1024 /* 'U' options included */
1028 case COAP_OPTION_EDHOC:
1031 default:
1032 if (!coap_add_option_internal(decrypt_pdu,
1033 opt_iter.number,
1034 coap_opt_length(opt),
1035 coap_opt_value(opt))) {
1036 if (!coap_request)
1039 session);
1040 goto error;
1041 }
1042 break;
1043 }
1044 }
1045
1046 if (coap_request) {
1047 uint64_t incoming_seq;
1048 /*
1049 * 8.2 Step 2
1050 * Decompress COSE object
1051 * Get Recipient Context based on kid and optional kid_context
1052 */
1053 if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
1054 coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
1055 build_and_send_error_pdu(session,
1056 pdu,
1057 COAP_RESPONSE_CODE(402),
1058 "Failed to decode COSE",
1059 NULL,
1060 NULL,
1061 0);
1062 goto error_no_ack;
1063 }
1064 osc_ctx = oscore_find_context(session,
1065 cose->key_id,
1066 &cose->kid_context,
1067 NULL,
1068 &rcp_ctx);
1069 if (!osc_ctx) {
1070 if (cose->kid_context.length > 0) {
1071 const uint8_t *ptr;
1072 size_t length;
1073 /* Appendix B.2 protocol check - Is the recipient key_id known */
1074 osc_ctx = oscore_find_context(session,
1075 cose->key_id,
1076 NULL,
1077 session->oscore_r2 != 0 ? (uint8_t *)&session->oscore_r2 : NULL,
1078 &rcp_ctx);
1079 ptr = cose->kid_context.s;
1080 length = cose->kid_context.length;
1081 if (ptr && osc_ctx && osc_ctx->rfc8613_b_2) {
1082 /* Processing Appendix B.2 protocol */
1083 /* Need to CBOR unwrap kid_context */
1084 coap_bin_const_t kid_context;
1085
1086 kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
1087 if (kid_context.length > length)
1088 goto error;
1089 /* This has to fit into an OSCORE option max 255.
1090 * Initial byte, kid_context size, partial IV size and kid size have to be there
1091 */
1092 if (kid_context.length >= 255 - 1 - 1 - cose->partial_iv.length - cose->key_id.length)
1093 goto error;
1094 kid_context.s = ptr;
1095 cose_encrypt0_set_kid_context(cose, (coap_bin_const_t *)&kid_context);
1096
1097 if (session->oscore_r2 != 0) {
1098 /* B.2 step 4 */
1100 cose->kid_context.length);
1101
1102 if (kc == NULL)
1103 goto error;
1104
1105 session->b_2_step = COAP_OSCORE_B_2_STEP_4;
1106 coap_log_oscore("Appendix B.2 server step 4 (R2 || R3)\n");
1107 oscore_update_ctx(osc_ctx, kc);
1108 } else {
1109 session->b_2_step = COAP_OSCORE_B_2_STEP_2;
1110 coap_log_oscore("Appendix B.2 server step 2 (ID1)\n");
1111 osc_ctx = oscore_duplicate_ctx(session->context,
1112 osc_ctx,
1113 osc_ctx->sender_context->sender_id,
1114 &cose->key_id,
1115 &cose->kid_context);
1116 if (osc_ctx == NULL)
1117 goto error;
1118 /*
1119 * Complete the Verify (B.2 step 2)
1120 * before sending back the response
1121 */
1122 rcp_ctx = osc_ctx->recipient_chain;
1123 }
1124 } else {
1125 osc_ctx = NULL;
1126 }
1127 }
1128 } else if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1129 session->b_2_step = COAP_OSCORE_B_2_NONE;
1130 coap_log_oscore("Appendix B.2 server finished\n");
1131 }
1132 if (!osc_ctx) {
1133 coap_log_err("OSCORE: Security Context not found\n");
1134 oscore_log_hex_value(COAP_LOG_OSCORE, "key_id", &cose->key_id);
1135 oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
1136 build_and_send_error_pdu(session,
1137 pdu,
1138 COAP_RESPONSE_CODE(401),
1139 "Security context not found",
1140 NULL,
1141 NULL,
1142 0);
1143 goto error_no_ack;
1144 }
1145 /* to be used for encryption of returned response later */
1146 coap_oscore_session_set_recipient_ctx(session, rcp_ctx);
1147 snd_ctx = osc_ctx->sender_context;
1148
1149 /*
1150 * 8.2 Step 3.
1151 * Verify Partial IV is not duplicated.
1152 *
1153 * Requires in COSE object as appropriate
1154 * partial_iv (as received)
1155 */
1156 if ((rcp_ctx->initial_state == 0 || osc_ctx->rfc8613_b_1_2 == 0) &&
1157 !oscore_validate_sender_seq(rcp_ctx, cose)) {
1158 coap_log_warn("OSCORE: Replayed or old message\n");
1159 build_and_send_error_pdu(session,
1160 pdu,
1161 COAP_RESPONSE_CODE(401),
1162 "Replay detected",
1163 NULL,
1164 NULL,
1165 0);
1166 goto error_no_ack;
1167 }
1168 if (rcp_ctx->initial_state == 1) {
1169 incoming_seq =
1171 rcp_ctx->last_seq = incoming_seq;
1172 }
1173 } else { /* !coap_request */
1174 /*
1175 * 8.4 Step 2
1176 * Decompress COSE object
1177 * Get Recipient Context based on token
1178 */
1179 if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
1180 coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
1183 session);
1184 goto error;
1185 }
1186 got_resp_piv = cose->partial_iv.length ? 1 : 0;
1187
1188 association = oscore_find_association(session, &pdu_token);
1189 if (association) {
1190 rcp_ctx = association->recipient_ctx;
1191 osc_ctx = rcp_ctx->osc_ctx;
1192 snd_ctx = osc_ctx->sender_context;
1193#if COAP_CLIENT_SUPPORT
1194 sent_pdu = association->sent_pdu;
1195 if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1196 const uint8_t *ptr = cose->kid_context.s;
1197 size_t length = cose->kid_context.length;
1198
1199 if (ptr) {
1200 /* Need to CBOR unwrap kid_context */
1201 coap_bin_const_t kid_context;
1202
1203 kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
1204 if (kid_context.length > length)
1205 goto error;
1206 /* This has to fit into an OSCORE option max 255.
1207 * Initial byte, kid_context size, partial IV size and kid size have to be there
1208 */
1209 if (kid_context.length >= 255 - 1 - 1 - cose->partial_iv.length - cose->key_id.length)
1210 goto error;
1211 kid_context.s = ptr;
1212 cose_encrypt0_set_kid_context(cose, &kid_context);
1213 }
1214 if (ptr && !coap_binary_equal(osc_ctx->id_context, &cose->kid_context)) {
1215 /* If Appendix B.2 step 3 is in operation */
1216 /* Need to update Security Context with new (R2 || ID1) ID Context */
1218 osc_ctx->id_context->length);
1219
1220 if (kc == NULL) {
1223 session);
1224 goto error;
1225 }
1226
1227 memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
1228 memcpy(&kc->s[cose->kid_context.length],
1229 osc_ctx->id_context->s,
1230 osc_ctx->id_context->length);
1231
1232 session->b_2_step = COAP_OSCORE_B_2_STEP_3;
1233 coap_log_oscore("Appendix B.2 client step 3 (R2 || ID1)\n");
1234 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1235 } else {
1236 session->b_2_step = COAP_OSCORE_B_2_STEP_5;
1237 coap_log_oscore("Appendix B.2 client step 5 (R2 || R3)\n");
1238 }
1239 }
1240#endif /* COAP_CLIENT_SUPPORT */
1241 } else {
1242 coap_log_crit("OSCORE: Security Context association not found\n");
1245 session);
1246 goto error;
1247 }
1248 }
1249
1250 cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
1251
1252 if (coap_request) {
1253 /*
1254 * RFC8613 8.2 Step 4.
1255 * Compose the External AAD and then AAD
1256 *
1257 * OSCORE_option requires
1258 * partial_iv (cose partial_iv)
1259 * kid_context (cose kid_context)
1260 * key_id (cose key_id)
1261 * group_flag
1262 *
1263 * Non Group requires the following
1264 * RFC8613 5.4
1265 * oscore_version 1
1266 * algorithms [
1267 * aead_alg (osc_ctx)
1268 * ]
1269 * request_kid (request key_id using cose)
1270 * request_piv (request partial_iv using cose)
1271 * options (none at present)
1272 *
1273 * Note: No I options at present
1274 */
1275
1276 /* External AAD */
1277 external_aad.s = external_aad_buffer;
1278 external_aad.length = oscore_prepare_e_aad(osc_ctx,
1279 cose,
1280 osc_value,
1281 osc_size,
1282 NULL,
1283 external_aad_buffer,
1284 sizeof(external_aad_buffer));
1285 if (external_aad.length == 0)
1286 goto error;
1287 cose_encrypt0_set_external_aad(cose, &external_aad);
1288
1289 /* AAD */
1290 aad.s = aad_buffer;
1291 aad.length = oscore_prepare_aad(external_aad_buffer,
1292 external_aad.length,
1293 aad_buffer,
1294 sizeof(aad_buffer));
1295 if (aad.length == 0)
1296 goto error;
1297 assert(aad.length < AAD_BUF_LEN);
1298 cose_encrypt0_set_aad(cose, &aad);
1299
1300 /*
1301 * RFC8613 8.2 Step 5.
1302 * Compute the AEAD nonce.
1303 *
1304 * Requires in COSE object as appropriate
1305 * key_id (kid) (Recipient ID)
1306 * partial_iv (as received in request)
1307 * common_iv (already in osc_ctx)
1308 */
1309 nonce.s = nonce_buffer;
1310 nonce.length = 13;
1311 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
1312 cose_encrypt0_set_nonce(cose, &nonce);
1313 /*
1314 * Set up an association for use in the response
1315 */
1316 association = oscore_find_association(session, &pdu_token);
1317 if (association) {
1318 /* Refresh the association */
1319 coap_delete_bin_const(association->nonce);
1320 association->nonce =
1321 coap_new_bin_const(cose->nonce.s, cose->nonce.length);
1322 if (association->nonce == NULL)
1323 goto error;
1324 coap_delete_bin_const(association->partial_iv);
1325 association->partial_iv =
1327 if (association->partial_iv == NULL)
1328 goto error;
1329 coap_delete_bin_const(association->aad);
1330 association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
1331 if (association->aad == NULL)
1332 goto error;
1333 coap_oscore_association_set_recipient_ctx(association, rcp_ctx);
1334 /* So association is not released when handling decrypt */
1335 association = NULL;
1336 } else {
1337 if (!oscore_new_association(session,
1338 NULL,
1339 &pdu_token,
1340 rcp_ctx,
1341 &cose->aad,
1342 &cose->nonce,
1343 &cose->partial_iv,
1344 0)) {
1345 goto error;
1346 }
1347 /*
1348 * New association for this request; delete on failure below if no
1349 * OSCORE-protected response will be sent. Refreshed associations are
1350 * left on the session (association cleared above).
1351 */
1352 decrypt_request_association =
1353 oscore_find_association(session, &pdu_token);
1354 }
1355 /* So association is not released when handling decrypt */
1356 association = NULL;
1357 } else { /* ! coap_request */
1358 /* Need to do nonce before AAD because of different partial_iv */
1359 /*
1360 * 8.4 Step 4.
1361 * Compose the AEAD nonce.
1362 */
1363 cose_encrypt0_set_key_id(cose, rcp_ctx->recipient_id);
1364 if (cose->partial_iv.length == 0) {
1365 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
1366 cose_encrypt0_set_nonce(cose, association->nonce);
1367 } else {
1368 uint64_t last_seq;
1369
1370 if ((rcp_ctx->initial_state == 0 || osc_ctx->rfc8613_b_1_2 == 0) &&
1371 !oscore_validate_sender_seq(rcp_ctx, cose)) {
1372 coap_log_warn("OSCORE: Replayed or old message\n");
1373 goto error;
1374 }
1375 last_seq =
1377 if (rcp_ctx->last_seq>= OSCORE_SEQ_MAX) {
1378 coap_log_warn("OSCORE Replay protection, SEQ larger than SEQ_MAX.\n");
1379 goto error;
1380 }
1381 if (last_seq > rcp_ctx->last_seq)
1382 rcp_ctx->last_seq = last_seq;
1383 /*
1384 * Requires in COSE object as appropriate
1385 * kid (set above)
1386 * partial_iv (as received)
1387 * common_iv (already in osc_ctx)
1388 */
1389 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
1390 nonce.s = nonce_buffer;
1391 nonce.length = 13;
1392 cose_encrypt0_set_nonce(cose, &nonce);
1393 }
1394#ifdef OSCORE_EXTRA_DEBUG
1395 dump_cose(cose, "!req post set nonce");
1396#endif /* OSCORE_EXTRA_DEBUG */
1397 /*
1398 * 8.4 Step 3.
1399 * Compose the External AAD and then AAD
1400 *
1401 * OSCORE_option requires
1402 * partial_iv (cose partial_iv)
1403 * kid_context (cose kid_context)
1404 * key_id (cose key_id)
1405 * group_flag
1406 *
1407 * Non Group requires the following
1408 * RFC8613 5.4
1409 * oscore_version 1
1410 * algorithms [
1411 * aead_alg (osc_ctx)
1412 * ]
1413 * request_kid (request key_id using cose)
1414 * request_piv (request partial_iv using cose)
1415 * options (none at present)
1416 *
1417 * Note: No I options at present
1418 */
1419
1420 /* External AAD */
1421 cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
1422 if (association->is_observe && association->obs_partial_iv && got_resp_piv) {
1423 cose_encrypt0_set_partial_iv(cose, association->obs_partial_iv);
1424 } else {
1425 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
1426 }
1427#ifdef OSCORE_EXTRA_DEBUG
1428 dump_cose(cose, "!req pre aad");
1429#endif /* OSCORE_EXTRA_DEBUG */
1430 external_aad.s = external_aad_buffer;
1431 external_aad.length = oscore_prepare_e_aad(osc_ctx,
1432 cose,
1433 NULL,
1434 0,
1435 NULL,
1436 external_aad_buffer,
1437 sizeof(external_aad_buffer));
1438 if (external_aad.length == 0)
1439 goto error;
1440 cose_encrypt0_set_external_aad(cose, &external_aad);
1441
1442 /* AAD */
1443 aad.s = aad_buffer;
1444 aad.length = oscore_prepare_aad(external_aad_buffer,
1445 external_aad.length,
1446 aad_buffer,
1447 sizeof(aad_buffer));
1448 if (aad.length == 0)
1449 goto error;
1450 assert(aad.length < AAD_BUF_LEN);
1451 cose_encrypt0_set_aad(cose, &aad);
1452#ifdef OSCORE_EXTRA_DEBUG
1453 dump_cose(cose, "!req post set aad");
1454#endif /* OSCORE_EXTRA_DEBUG */
1455 }
1456
1457 /*
1458 * 8.2 Step 6 / 8.4 Step 5.
1459 * Decrypt the COSE object.
1460 *
1461 * Requires in COSE object as appropriate
1462 * alg (already set)
1463 * key
1464 * nonce (already set)
1465 * aad (already set)
1466 * ciphertext
1467 */
1468 st_encrypt = pdu->data;
1469 encrypt_len = pdu->used_size - (pdu->data - pdu->token);
1470 if (encrypt_len <= 0) {
1471 coap_log_warn("OSCORE: No protected payload\n");
1472 if (!coap_request)
1475 session);
1476 goto error;
1477 }
1478 cose_encrypt0_set_key(cose, rcp_ctx->recipient_key);
1479 cose_encrypt0_set_ciphertext(cose, st_encrypt, encrypt_len);
1480
1481 tag_len = cose_tag_len(cose->alg);
1482 if (encrypt_len <= tag_len) {
1483 /* Too short to hold the AEAD tag plus a 1 byte inner code; a shorter
1484 value would underflow encrypt_len - tag_len below */
1485 coap_log_warn("OSCORE: Ciphertext too short\n");
1486 if (coap_request) {
1487 build_and_send_error_pdu(session,
1488 pdu,
1489 COAP_RESPONSE_CODE(400),
1490 "Decryption failed",
1491 NULL,
1492 NULL,
1493 0);
1494 oscore_roll_back_seq(rcp_ctx);
1495 decrypt_request_association = NULL;
1496 goto error_no_ack;
1497 }
1500 session);
1501 goto error;
1502 }
1503 /* Decrypt into plain_pdu, so code (token), options and data are in place */
1504 plain_pdu = coap_pdu_init(pdu->type, 0, 0, encrypt_len /* - tag_len */);
1505 if (plain_pdu == NULL) {
1506 if (!coap_request)
1509 session);
1510 goto error;
1511 }
1512
1513 /* need the tag_len on the end for TinyDTLS to do its work - yuk */
1514 if (!coap_pdu_resize(plain_pdu, encrypt_len /* - tag_len */)) {
1515 if (!coap_request)
1518 session);
1519 goto error;
1520 }
1521
1522 /* Account for 1 byte 'code' used as token */
1523 plain_pdu->e_token_length = 1;
1524 plain_pdu->actual_token.length = 1;
1525 /* Account for the decrypted data */
1526 plain_pdu->used_size = encrypt_len - tag_len;
1527
1528 dump_cose(cose, "Pre decrypt");
1529 pltxt_size =
1530 cose_encrypt0_decrypt(cose, plain_pdu->token, encrypt_len - tag_len);
1531 if (pltxt_size <= 0) {
1532 coap_log_warn("OSCORE: Decryption Failure, result code: %d \n",
1533 (int)pltxt_size);
1534 if (coap_request) {
1535 build_and_send_error_pdu(session,
1536 pdu,
1537 COAP_RESPONSE_CODE(400),
1538 "Decryption failed",
1539 NULL,
1540 NULL,
1541 0);
1542 oscore_roll_back_seq(rcp_ctx);
1543 decrypt_request_association = NULL;
1544 goto error_no_ack;
1545 } else {
1548 session);
1549 oscore_roll_back_seq(rcp_ctx);
1550 }
1551 goto error;
1552 }
1553 /* Replay window update is now verified */
1554 rcp_ctx->rollback_valid = 0;
1555 if (coap_request && rcp_ctx->initial_state == 0 &&
1556 session->context->oscore_update_seq_num_cb != NULL) {
1557 /* notify custom credential storage */
1558 coap_lock_callback(session->context->oscore_update_seq_num_cb(session,
1559 rcp_ctx->recipient_id,
1560 osc_ctx->id_context,
1561 rcp_ctx->last_seq,
1562 rcp_ctx->sliding_window));
1563 }
1564
1565 assert((size_t)pltxt_size < pdu->alloc_size + pdu->max_hdr_size);
1566
1567 /* Appendix B.2 Trap */
1568 if (session->b_2_step == COAP_OSCORE_B_2_STEP_2) {
1569 /* Need to update Security Context with new (R2 || ID1) ID Context */
1570 coap_binary_t *kc =
1571 coap_new_binary(sizeof(session->oscore_r2) + cose->kid_context.length);
1572 coap_bin_const_t oscore_r2;
1573
1574 if (kc == NULL) {
1575 if (!coap_request)
1578 session);
1579 goto error;
1580 }
1581
1582 coap_prng_lkd(&session->oscore_r2, sizeof(session->oscore_r2));
1583 memcpy(kc->s, &session->oscore_r2, sizeof(session->oscore_r2));
1584 memcpy(&kc->s[sizeof(session->oscore_r2)],
1585 cose->kid_context.s,
1586 cose->kid_context.length);
1587
1588 coap_log_oscore("Appendix B.2 server step 2 (R2 || ID1)\n");
1589 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1590
1591 oscore_r2.length = sizeof(session->oscore_r2);
1592 oscore_r2.s = (const uint8_t *)&session->oscore_r2;
1593 coap_log_oscore("Appendix B.2 server step 2 plain response\n");
1594 build_and_send_error_pdu(session,
1595 pdu,
1596 COAP_RESPONSE_CODE(401),
1597 NULL,
1598 NULL,
1599 &oscore_r2,
1600 1);
1601 decrypt_request_association = NULL;
1602 goto error_no_ack;
1603 }
1604#if COAP_CLIENT_SUPPORT
1605 if (session->b_2_step == COAP_OSCORE_B_2_STEP_3) {
1606 coap_log_oscore("Appendix B.2 client step 3 (R2 || R3)\n");
1607 coap_pdu_encode_header(plain_pdu, session->proto);
1608 plain_pdu->actual_token.s = plain_pdu->token;
1609 plain_pdu->code = plain_pdu->token[0];
1610 if (plain_pdu->code != COAP_RESPONSE_CODE(401)) {
1611 coap_log_warn("OSCORE Appendix B.2: Expected 4.01 response\n");
1612 }
1613 /* Skip the options */
1614 coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
1615 while (coap_option_next(&opt_iter)) {
1616 }
1617 if (opt_iter.length > 0 && opt_iter.next_option &&
1618 opt_iter.next_option[0] == COAP_PAYLOAD_START) {
1619 plain_pdu->data = &opt_iter.next_option[1];
1620 }
1621 coap_log_oscore("Inner Response PDU (plaintext)\n");
1622 coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
1623 /*
1624 * Need to update Security Context with new (R2 || R3) ID Context
1625 * and retransmit the request
1626 */
1628
1629 if (kc == NULL) {
1630 if (!coap_request)
1633 session);
1634 goto error;
1635 }
1636 memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
1637 coap_prng_lkd(&kc->s[cose->kid_context.length], 8);
1638
1639 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1640
1642 session,
1643 &pdu->actual_token);
1644 if (session->con_active)
1645 session->con_active--;
1646 coap_send_ack_lkd(session, pdu);
1647 if (sent_pdu) {
1648 coap_log_oscore("Appendix B.2 retransmit pdu\n");
1649 if (!session->b_2_retransmit_token) {
1650 session->b_2_retransmit_token = coap_new_str_const(sent_pdu->actual_token.s,
1651 sent_pdu->actual_token.length);
1652 }
1653 if (coap_retransmit_oscore_pdu(session, sent_pdu, NULL) ==
1655 goto error_no_ack;
1656 }
1657 goto error_no_ack;
1658 }
1659#endif /* COAP_CLIENT_SUPPORT */
1660
1661#if COAP_SERVER_SUPPORT
1662 /* Appendix B.1.2 request Trap */
1663 if (coap_request && osc_ctx->rfc8613_b_1_2) {
1664 if (rcp_ctx->initial_state == 1) {
1665 opt = coap_check_option(plain_pdu, COAP_OPTION_ECHO, &opt_iter);
1666 if (opt) {
1667 /* Verify Client is genuine */
1668 if (coap_opt_length(opt) == 8 &&
1669 memcmp(coap_opt_value(opt), rcp_ctx->echo_value, 8) == 0) {
1670 /* This clears rcp_ctx->initial_state */
1671 if (!oscore_validate_sender_seq(rcp_ctx, cose)) {
1672 coap_log_warn("OSCORE: Replayed or old message\n");
1673 build_and_send_error_pdu(session,
1674 pdu,
1675 COAP_RESPONSE_CODE(401),
1676 "Replay detected",
1677 NULL,
1678 NULL,
1679 0);
1680 goto error_no_ack;
1681 decrypt_request_association = NULL;
1682 } else {
1683 if (session->context->oscore_update_seq_num_cb != NULL) {
1684 /* notify echo challenge changed */
1685 coap_lock_callback(session->context->oscore_update_seq_num_cb(session,
1686 rcp_ctx->recipient_id,
1687 osc_ctx->id_context,
1688 rcp_ctx->last_seq,
1689 rcp_ctx->sliding_window));
1690 }
1691 }
1692 } else
1693 goto error;
1694 } else {
1695 /* RFC 8163 Appendix B.1.2 */
1696 if (session->b_2_step == COAP_OSCORE_B_2_STEP_4) {
1697 session->b_2_step = COAP_OSCORE_B_2_NONE;
1698 coap_log_oscore("Appendix B.2 server finished\n");
1699 }
1700 coap_prng_lkd(rcp_ctx->echo_value, sizeof(rcp_ctx->echo_value));
1701 coap_log_oscore("Appendix B.1.2 server plain response\n");
1702
1703 build_and_send_error_pdu(session,
1704 pdu,
1705 COAP_RESPONSE_CODE(401),
1706 NULL,
1707 rcp_ctx->echo_value,
1708 NULL,
1709 1);
1710 decrypt_request_association = NULL;
1711 goto error_no_ack;
1712 }
1713 }
1714 }
1715#endif /* COAP_SERVER_SUPPORT */
1716
1717 /*
1718 * 8.2 Step 7 / 8.4 Step 6.
1719 * Add decrypted Code, options and payload
1720 * [OSCORE option not copied across previously]
1721 */
1722
1723 /* PDU code is pseudo plain_pdu token */
1724 decrypt_pdu->code = plain_pdu->token[0];
1725
1726 /* Copy inner decrypted options across */
1727 coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
1728 while ((opt = coap_option_next(&opt_iter))) {
1729 size_t len;
1730 size_t bias;
1731
1732 switch (opt_iter.number) {
1733 case COAP_OPTION_OSCORE:
1734 break;
1736 if (!coap_request) {
1737 bias = cose->partial_iv.length > 3 ? cose->partial_iv.length - 3 : 0;
1738 len = cose->partial_iv.length > 3 ? 3 : cose->partial_iv.length;
1739 /* Make Observe option reflect last 3 bytes of partial_iv */
1741 decrypt_pdu,
1742 opt_iter.number,
1743 len,
1744 cose->partial_iv.s ? &cose->partial_iv.s[bias] : NULL)) {
1747 session);
1748 goto error;
1749 }
1750 doing_resp_observe = 1;
1751 break;
1752 }
1753 association = oscore_find_association(session, &pdu_token);
1754 if (association) {
1755 association->is_observe = 1;
1756 association = NULL;
1757 }
1758 /* Fall Through */
1759 default:
1760 if (!coap_insert_option(decrypt_pdu,
1761 opt_iter.number,
1762 coap_opt_length(opt),
1763 coap_opt_value(opt))) {
1764 if (!coap_request)
1767 session);
1768 goto error;
1769 }
1770 break;
1771 }
1772 }
1773 if (!coap_request && !doing_resp_observe) {
1774 if (association) {
1775 association->is_observe = 0;
1776 }
1777 }
1778 /* Need to copy across any data */
1779 if (opt_iter.length > 0 && opt_iter.next_option &&
1780 opt_iter.next_option[0] == COAP_PAYLOAD_START) {
1781 plain_pdu->data = &opt_iter.next_option[1];
1782 if (!coap_add_data(decrypt_pdu,
1783 plain_pdu->used_size -
1784 (plain_pdu->data - plain_pdu->token),
1785 plain_pdu->data)) {
1786 if (!coap_request)
1789 session);
1790 goto error;
1791 }
1792 }
1793 coap_delete_pdu_lkd(plain_pdu);
1794 plain_pdu = NULL;
1795
1796 /* Make sure headers are correctly set up */
1797 if (!coap_pdu_encode_header(decrypt_pdu, session->proto)) {
1798 if (!coap_request)
1801 session);
1802 goto error;
1803 }
1804
1805 if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1806 session->b_2_step = COAP_OSCORE_B_2_NONE;
1807 coap_log_oscore("Appendix B.2 client finished\n");
1808 if (session->b_2_retransmit_token) {
1809 coap_update_token(decrypt_pdu, session->b_2_retransmit_token->length,
1810 session->b_2_retransmit_token->s);
1811 coap_delete_str_const(session->b_2_retransmit_token);
1812 session->b_2_retransmit_token = NULL;
1813 }
1814 }
1815#if COAP_CLIENT_SUPPORT
1816 if (decrypt_pdu->code == COAP_RESPONSE_CODE(401) &&
1817 (opt = coap_check_option(decrypt_pdu, COAP_OPTION_ECHO, &opt_iter))) {
1818 /* Server is requesting Echo refresh check */
1820 session,
1821 &pdu->actual_token);
1822 if (session->con_active)
1823 session->con_active--;
1824 if (!sent_pdu) {
1825 coap_lg_crcv_t *lg_crcv = coap_find_lg_crcv(session, pdu);
1826
1827 if (lg_crcv)
1828 sent_pdu = lg_crcv->sent_pdu;
1829 }
1830 if (sent_pdu) {
1831 coap_send_ack_lkd(session, pdu);
1832 coap_log_debug("PDU requesting re-transmit\n");
1833 coap_show_pdu(COAP_LOG_DEBUG, decrypt_pdu);
1834 coap_log_oscore("RFC9175 retransmit pdu\n");
1835 /* Do not care if this fails */
1836 if (coap_retransmit_oscore_pdu(session, sent_pdu, opt) != COAP_INVALID_MID) {
1837 session->doing_b_1_2 = 1;
1838 }
1839 goto error_no_ack;
1840 }
1841 } else if (session->doing_b_1_2) {
1842 coap_lg_crcv_t *lg_crcv = coap_find_lg_crcv(session, pdu);
1843
1844 if (lg_crcv) {
1845 if (!coap_binary_equal(&decrypt_pdu->actual_token, lg_crcv->app_token)) {
1846 coap_update_token(decrypt_pdu, lg_crcv->app_token->length, lg_crcv->app_token->s);
1847 }
1848 }
1849 session->doing_b_1_2 = 0;
1850 }
1851#endif /* COAP_CLIENT_SUPPORT */
1852 if (association && association->is_observe == 0)
1853 oscore_delete_association(session, association);
1854 return decrypt_pdu;
1855
1856error:
1857 coap_send_ack_lkd(session, pdu);
1858error_no_ack:
1859 if (decrypt_request_association) {
1860 oscore_delete_association(session, decrypt_request_association);
1861 decrypt_request_association = NULL;
1862 }
1863 if (association && association->is_observe == 0)
1864 oscore_delete_association(session, association);
1865 coap_delete_pdu_lkd(decrypt_pdu);
1866 coap_delete_pdu_lkd(plain_pdu);
1867 return NULL;
1868}
1869
1870typedef enum {
1871 COAP_ENC_ASCII = 0x001,
1872 COAP_ENC_HEX = 0x002,
1873 COAP_ENC_CONFIG = 0x0200,
1874 COAP_ENC_INTEGER = 0x400,
1875 COAP_ENC_TEXT = 0x800,
1876 COAP_ENC_BOOL = 0x1000,
1877 COAP_ENC_UNSIGNED64 = 0x2000,
1878 COAP_ENC_LAST
1879} coap_oscore_coding_t;
1880
1881#undef TEXT_MAPPING
1882#define TEXT_MAPPING(t, v) \
1883 { { sizeof(#t)-1, (const uint8_t *)#t }, v }
1884
1885static struct coap_oscore_encoding_t {
1886 coap_str_const_t name;
1887 coap_oscore_coding_t encoding;
1888} oscore_encoding[] = {
1889 TEXT_MAPPING(ascii, COAP_ENC_ASCII),
1890 TEXT_MAPPING(hex, COAP_ENC_HEX),
1891 TEXT_MAPPING(config, COAP_ENC_CONFIG),
1892 TEXT_MAPPING(integer, COAP_ENC_INTEGER),
1893 TEXT_MAPPING(unsigned64, COAP_ENC_UNSIGNED64),
1894 TEXT_MAPPING(text, COAP_ENC_TEXT),
1895 TEXT_MAPPING(bool, COAP_ENC_BOOL),
1896 {{0, NULL}, COAP_ENC_LAST}
1897};
1898
1899typedef struct {
1900 coap_oscore_coding_t encoding;
1901 const char *encoding_name;
1902 union {
1903 int value_int;
1904 uint64_t value_int64;
1905 coap_bin_const_t *value_bin;
1906 coap_str_const_t value_str;
1907 } u;
1908} oscore_value_t;
1909
1910/*
1911 * Return 1 if hex character
1912 * 0 not hex character
1913 */
1914static int
1915hex_to_char(char c, uint8_t *value) {
1916 if ('a' <= c && c <= 'f') {
1917 *value = c - 'a' + 10;
1918 } else if ('A' <= c && c <= 'F') {
1919 *value = c - 'A' + 10;
1920 } else if ('0' <= c && c <= '9') {
1921 *value = c - '0';
1922 } else {
1923 *value = 0;
1924 return 0;
1925 }
1926 return 1;
1927}
1928
1929/* Parse the hex into binary */
1930static coap_bin_const_t *
1931parse_hex_bin(const char *begin, const char *end) {
1932 coap_binary_t *binary = NULL;
1933 size_t i;
1934 size_t o = 0;
1935
1936 binary = coap_new_binary((end - begin) / 2);
1937 if (binary == NULL)
1938 goto bad_entry;
1939 for (i = 0; (i < (size_t)(end - begin)); i++) {
1940 while ((i < (size_t)(end - begin)) &&
1941 (begin[i] == '\r' || begin[i] == '\n' || begin[i] == ' ')) {
1942 i++;
1943 }
1944 if (i == (size_t)(end - begin))
1945 break;
1946 if (isxdigit((uint8_t)begin[i])) {
1947 uint8_t value;
1948
1949 if (!hex_to_char(begin[i], &value)) {
1950 goto bad_entry;
1951 }
1952 binary->s[o] = value << 4;
1953 i++;
1954 while ((i < (size_t)(end - begin)) &&
1955 (begin[i] == '\r' || begin[i] == '\n' || begin[i] == ' ')) {
1956 i++;
1957 }
1958 if (i == (size_t)(end - begin))
1959 goto bad_entry;
1960 if (!hex_to_char(begin[i], &value)) {
1961 goto bad_entry;
1962 }
1963 binary->s[o++] += value;
1964 } else {
1965 break;
1966 }
1967 }
1968 if (i != (size_t)(end - begin))
1969 goto bad_entry;
1970 return (coap_bin_const_t *)binary;
1971
1972bad_entry:
1973 coap_delete_binary(binary);
1974 return NULL;
1975}
1976
1977/*
1978 * Break up each OSCORE Configuration line entry into the 3 parts which
1979 * are comma separated
1980 *
1981 * keyword,encoding,value
1982 */
1983static int
1984get_split_entry(const char **start,
1985 size_t size,
1986 coap_str_const_t *keyword,
1987 oscore_value_t *value,
1988 cose_curve_t sign_curve) {
1989 const char *begin = *start;
1990 const char *keep_start = *start;
1991 const char *end;
1992 const char *kend;
1993 const char *tend;
1994 const char *split;
1995 size_t i;
1996 size_t len;
1997 (void)sign_curve;
1998
1999retry:
2000 kend = end = memchr(begin, '\n', size);
2001 if (end == NULL)
2002 return 0;
2003
2004 /* Check for multi-line */
2005 if ((tend = memchr(begin, '"', end - begin))) {
2006 /* See if " terminator is on the same line */
2007 if (!memchr(tend + 1, '"', end - tend -1)) {
2008 /* Over multiple lines */
2009 kend = end = memchr(end, '"', size - (end - begin));
2010 if (end == NULL)
2011 return 0;
2012 kend = end = memchr(kend, '\n', size - (kend - begin));
2013 if (end == NULL)
2014 return 0;
2015 }
2016 }
2017
2018 /* Track beginning of next line */
2019 *start = end + 1;
2020 if (end > begin && end[-1] == '\r')
2021 end--;
2022
2023 if (begin[0] == '#' || (end - begin) == 0) {
2024 /* Skip comment / blank line */
2025 size -= kend - begin + 1;
2026 begin = *start;
2027 keep_start = *start;
2028 goto retry;
2029 }
2030
2031 /* Get in the keyword */
2032 split = memchr(begin, ',', end - begin);
2033 if (split == NULL)
2034 goto bad_entry;
2035
2036 keyword->s = (const uint8_t *)begin;
2037 keyword->length = split - begin;
2038
2039 begin = split + 1;
2040 if ((end - begin) == 0)
2041 goto bad_entry;
2042 /* Get in the encoding */
2043 split = memchr(begin, ',', end - begin);
2044 if (split == NULL)
2045 goto bad_entry;
2046
2047 for (i = 0; oscore_encoding[i].name.s; i++) {
2048 coap_str_const_t temp = { split - begin, (const uint8_t *)begin };
2049
2050 if (coap_string_equal(&temp, &oscore_encoding[i].name)) {
2051 value->encoding = oscore_encoding[i].encoding;
2052 value->encoding_name = (const char *)oscore_encoding[i].name.s;
2053 break;
2054 }
2055 }
2056 if (oscore_encoding[i].name.s == NULL)
2057 goto bad_entry;
2058
2059 begin = split + 1;
2060 if ((end - begin) == 0)
2061 goto bad_entry;
2062 /* Get in the keyword's value */
2063 if (value->encoding == COAP_ENC_CONFIG && begin[0] == '\'') {
2064 split = memchr(&begin[1], '\'', size - (begin - keep_start) - 1);
2065 if (split == NULL)
2066 goto bad_entry;
2067 end = memchr(split, '\n', size - (split - keep_start));
2068 if (end == NULL)
2069 return 0;
2070 *start = end + 1;
2071 end = split;
2072 begin++;
2073 } else {
2074 if (begin[0] == '"') {
2075 split = memchr(&begin[1], '"', end - split - 1);
2076 if (split == NULL)
2077 goto bad_entry;
2078 end = split;
2079 begin++;
2080 }
2081 }
2082 switch (value->encoding) {
2083 case COAP_ENC_CONFIG:
2084 case COAP_ENC_ASCII:
2085 value->u.value_bin =
2086 coap_new_bin_const((const uint8_t *)begin, end - begin);
2087 if (value->u.value_bin == NULL)
2088 goto bad_entry;
2089 break;
2090 case COAP_ENC_HEX:
2091 /* Parse the hex into binary */
2092 value->u.value_bin = parse_hex_bin(begin, end);
2093 if (value->u.value_bin == NULL)
2094 goto bad_entry;
2095 break;
2096 case COAP_ENC_INTEGER:
2097 value->u.value_int = atoi(begin);
2098 break;
2099 case COAP_ENC_UNSIGNED64: {
2100 value->u.value_int64 = strtoull(begin, NULL, 10);
2101 break;
2102 }
2103 case COAP_ENC_TEXT:
2104 value->u.value_str.s = (const uint8_t *)begin;
2105 value->u.value_str.length = end - begin;
2106 break;
2107 case COAP_ENC_BOOL:
2108 len = (size_t)(end - begin);
2109 if (len == 4 && memcmp("true", begin, len) == 0)
2110 value->u.value_int = 1;
2111 else if (len == 5 && memcmp("false", begin, len) == 0)
2112 value->u.value_int = 0;
2113 else
2114 goto bad_entry;
2115 break;
2116 case COAP_ENC_LAST:
2117 default:
2118 goto bad_entry;
2119 }
2120 return 1;
2121
2122bad_entry:
2123 coap_log_warn("oscore_conf: Unrecognized configuration entry '%.*s'\n",
2124 (int)(end - begin),
2125 begin);
2126 return -1;
2127
2128}
2129
2130#undef CONFIG_ENTRY
2131#define CONFIG_ENTRY(n, e, t) \
2132 { { sizeof(#n)-1, (const uint8_t *)#n }, e, \
2133 offsetof(coap_oscore_conf_t, n), t }
2134
2135#undef CONFIG_SND_ENTRY
2136#define CONFIG_SND_ENTRY(n, e, t) \
2137 { { sizeof(#n)-1, (const uint8_t *)#n }, e, \
2138 offsetof(coap_oscore_snd_conf_t, n), t }
2139
2140#undef CONFIG_RCP_ENTRY
2141#define CONFIG_RCP_ENTRY(n, e, t) \
2142 { { sizeof(#n)-1, (const uint8_t *)#n }, e, \
2143 offsetof(coap_oscore_rcp_conf_t, n), t }
2144
2145#undef CONFIG_DUMMY_ENTRY
2146#define CONFIG_DUMMY_ENTRY(n, e, t) \
2147 { { sizeof(#n)-1, (const uint8_t *)#n }, e, 0, t }
2148
2149typedef struct oscore_text_mapping_t {
2150 coap_str_const_t text;
2151 int value;
2152} oscore_text_mapping_t;
2153
2154/* Naming as per https://www.iana.org/assignments/cose/cose.xhtml#algorithms */
2155static oscore_text_mapping_t text_aead_alg[] = {
2156 TEXT_MAPPING(AES-CCM-16-64-128, COSE_ALGORITHM_AES_CCM_16_64_128),
2157 TEXT_MAPPING(AES-CCM-16-64-256, COSE_ALGORITHM_AES_CCM_16_64_256),
2158 {{0, NULL}, 0}
2159};
2160
2161static oscore_text_mapping_t text_hkdf_alg[] = {
2162 TEXT_MAPPING(direct+HKDF-SHA-256, COSE_HKDF_ALG_HKDF_SHA_256),
2163 {{0, NULL}, 0}
2164};
2165
2166typedef struct oscore_config_t {
2167 coap_str_const_t str_keyword;
2168 coap_oscore_coding_t encoding;
2169 size_t offset;
2170 oscore_text_mapping_t *text_mapping;
2171} oscore_config_t;
2172
2173static oscore_config_t oscore_config[] = {
2174 CONFIG_ENTRY(aead_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_aead_alg),
2175 CONFIG_ENTRY(hkdf_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_hkdf_alg),
2176 CONFIG_ENTRY(master_secret, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2177 CONFIG_ENTRY(master_salt, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2178 CONFIG_ENTRY(id_context, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2179
2180 CONFIG_DUMMY_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2181
2182 CONFIG_DUMMY_ENTRY(recipient_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2183
2184 CONFIG_ENTRY(replay_window, COAP_ENC_INTEGER, NULL),
2185 CONFIG_ENTRY(ssn_freq, COAP_ENC_INTEGER, NULL),
2186 CONFIG_ENTRY(rfc8613_b_1_2, COAP_ENC_BOOL, NULL),
2187 CONFIG_ENTRY(rfc8613_b_2, COAP_ENC_BOOL, NULL),
2188 CONFIG_ENTRY(break_sender_key, COAP_ENC_BOOL, NULL),
2189 CONFIG_ENTRY(break_recipient_key, COAP_ENC_BOOL, NULL),
2190 CONFIG_DUMMY_ENTRY(complex_sender, COAP_ENC_CONFIG, NULL),
2191 CONFIG_DUMMY_ENTRY(complex_recipient, COAP_ENC_CONFIG, NULL),
2192};
2193
2194static oscore_config_t oscore_snd_config[] = {
2195 CONFIG_SND_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2196};
2197
2198static oscore_config_t oscore_rcp_config[] = {
2199 CONFIG_RCP_ENTRY(recipient_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
2200 CONFIG_RCP_ENTRY(silent_server, COAP_ENC_BOOL, NULL),
2201 CONFIG_DUMMY_ENTRY(last_seq, COAP_ENC_UNSIGNED64, NULL),
2202 CONFIG_DUMMY_ENTRY(sliding_window, COAP_ENC_UNSIGNED64, NULL),
2203};
2204
2205
2206int
2208 if (snd_conf == NULL)
2209 return 0;
2210
2212 coap_free_type(COAP_STRING, snd_conf);
2213 return 1;
2214}
2215
2216int
2218 if (rcp_conf == NULL)
2219 return 0;
2220
2222 coap_free_type(COAP_STRING, rcp_conf);
2223 return 1;
2224}
2225
2226int
2228 coap_oscore_rcp_conf_t *rcp_conf;
2229 if (oscore_conf == NULL)
2230 return 0;
2231
2233 coap_delete_bin_const(oscore_conf->master_salt);
2234 coap_delete_bin_const(oscore_conf->id_context);
2235 coap_delete_oscore_snd_conf(oscore_conf->sender);
2236
2237 rcp_conf = oscore_conf->recipient_chain;
2238 while (rcp_conf) {
2239 coap_oscore_rcp_conf_t *rcp_next = rcp_conf->next_recipient;
2240
2242 rcp_conf = rcp_next;
2243 }
2244
2245 coap_free_type(COAP_STRING, oscore_conf);
2246 return 1;
2247}
2248
2250coap_parse_oscore_snd_conf_mem(coap_bin_const_t conf_mem) {
2251 const char *start = (const char *)conf_mem.s;
2252 const char *end = start + conf_mem.length;
2253 coap_str_const_t keyword;
2254 oscore_value_t value;
2255 coap_oscore_snd_conf_t *snd_conf;
2256
2258 if (snd_conf == NULL)
2259 return NULL;
2260 memset(snd_conf, 0, sizeof(coap_oscore_snd_conf_t));
2261
2262 memset(&value, 0, sizeof(value));
2263
2264 while (end > start &&
2265 get_split_entry(&start, end - start, &keyword, &value, 0) > 0) {
2266 size_t i;
2267 size_t j;
2268
2269 for (i = 0; i < sizeof(oscore_snd_config) / sizeof(oscore_snd_config[0]); i++) {
2270 if (coap_string_equal(&oscore_snd_config[i].str_keyword, &keyword) != 0 &&
2271 value.encoding & oscore_snd_config[i].encoding) {
2272 coap_bin_const_t *unused_check;
2273
2274 switch (value.encoding) {
2275 case COAP_ENC_HEX:
2276 case COAP_ENC_ASCII:
2277 memcpy(&unused_check,
2278 &(((char *)snd_conf)[oscore_snd_config[i].offset]),
2279 sizeof(unused_check));
2280 if (unused_check != NULL) {
2281 coap_log_warn("oscore_snd_conf: Keyword '%.*s' duplicated\n",
2282 (int)keyword.length,
2283 (const char *)keyword.s);
2284 coap_delete_bin_const(value.u.value_bin);
2285 goto error;
2286 }
2287 memcpy(&(((char *)snd_conf)[oscore_snd_config[i].offset]),
2288 &value.u.value_bin,
2289 sizeof(value.u.value_bin));
2290 break;
2291 case COAP_ENC_INTEGER:
2292 case COAP_ENC_BOOL:
2293 memcpy(&(((char *)snd_conf)[oscore_snd_config[i].offset]),
2294 &value.u.value_int,
2295 sizeof(value.u.value_int));
2296 break;
2297 case COAP_ENC_TEXT:
2298 for (j = 0; oscore_snd_config[i].text_mapping[j].text.s != NULL; j++) {
2299 if (memcmp(value.u.value_str.s,
2300 oscore_snd_config[i].text_mapping[j].text.s,
2301 value.u.value_str.length) == 0) {
2302 memcpy(&(((char *)snd_conf)[oscore_snd_config[i].offset]),
2303 &oscore_snd_config[i].text_mapping[j].value,
2304 sizeof(oscore_snd_config[i].text_mapping[j].value));
2305 break;
2306 }
2307 }
2308 if (oscore_snd_config[i].text_mapping[j].text.s == NULL) {
2309 coap_log_warn("oscore_snd_conf: Keyword '%.*s': value '%.*s' unknown\n",
2310 (int)keyword.length,
2311 (const char *)keyword.s,
2312 (int)value.u.value_str.length,
2313 (const char *)value.u.value_str.s);
2314 goto error;
2315 }
2316 break;
2317 case COAP_ENC_CONFIG:
2318 case COAP_ENC_UNSIGNED64:
2319 case COAP_ENC_LAST:
2320 default:
2321 assert(0);
2322 break;
2323 }
2324 break;
2325 }
2326 }
2327 if (i == sizeof(oscore_snd_config) / sizeof(oscore_snd_config[0])) {
2328 coap_log_warn("oscore_snd_conf: Keyword '%.*s', type '%s' unknown\n",
2329 (int)keyword.length,
2330 (const char *)keyword.s,
2331 value.encoding_name);
2332 if (value.encoding == COAP_ENC_HEX || value.encoding == COAP_ENC_ASCII ||
2333 value.encoding == COAP_ENC_CONFIG)
2334 coap_delete_bin_const(value.u.value_bin);
2335 goto error;
2336 }
2337 }
2338 if (!snd_conf->sender_id) {
2339 coap_log_warn("oscore_snd_conf: sender_id not defined\n");
2340 goto error;
2341 }
2342 if (snd_conf->sender_id->length > 7) {
2343 coap_log_warn("oscore_snd_conf: Maximum size of sender_id is 7 bytes\n");
2344 goto error;
2345 }
2346 return snd_conf;
2347
2348error:
2350 return NULL;
2351}
2352
2354coap_parse_oscore_rcp_conf_mem(coap_bin_const_t conf_mem) {
2355 const char *start = (const char *)conf_mem.s;
2356 const char *end = start + conf_mem.length;
2357 coap_str_const_t keyword;
2358 oscore_value_t value;
2359 coap_oscore_rcp_conf_t *rcp_conf;
2360
2362 if (rcp_conf == NULL)
2363 return NULL;
2364 memset(rcp_conf, 0, sizeof(coap_oscore_rcp_conf_t));
2365
2366 memset(&value, 0, sizeof(value));
2367
2368 while (end > start &&
2369 get_split_entry(&start, end - start, &keyword, &value, 0) > 0) {
2370 size_t i;
2371 size_t j;
2372
2373 for (i = 0; i < sizeof(oscore_rcp_config) / sizeof(oscore_rcp_config[0]); i++) {
2374 if (coap_string_equal(&oscore_rcp_config[i].str_keyword, &keyword) != 0 &&
2375 value.encoding & oscore_rcp_config[i].encoding) {
2376 if (coap_string_equal(coap_make_str_const("last_seq"), &keyword)) {
2377 rcp_conf->last_seq = value.u.value_int64;
2378 rcp_conf->window_initialized = 1;
2379 } else if (coap_string_equal(coap_make_str_const("sliding_window"), &keyword)) {
2380 rcp_conf->sliding_window = value.u.value_int64;
2381 rcp_conf->window_initialized = 1;
2382 } else {
2383 coap_bin_const_t *unused_check;
2384
2385 switch (value.encoding) {
2386 case COAP_ENC_HEX:
2387 case COAP_ENC_ASCII:
2388 memcpy(&unused_check,
2389 &(((char *)rcp_conf)[oscore_rcp_config[i].offset]),
2390 sizeof(unused_check));
2391 if (unused_check != NULL) {
2392 coap_log_warn("oscore_rcp_conf: Keyword '%.*s' duplicated\n",
2393 (int)keyword.length,
2394 (const char *)keyword.s);
2395 coap_delete_bin_const(value.u.value_bin);
2396 goto error;
2397 }
2398 memcpy(&(((char *)rcp_conf)[oscore_rcp_config[i].offset]),
2399 &value.u.value_bin,
2400 sizeof(value.u.value_bin));
2401 break;
2402 case COAP_ENC_INTEGER:
2403 case COAP_ENC_BOOL:
2404 memcpy(&(((char *)rcp_conf)[oscore_rcp_config[i].offset]),
2405 &value.u.value_int,
2406 sizeof(value.u.value_int));
2407 break;
2408 case COAP_ENC_TEXT:
2409 for (j = 0; oscore_rcp_config[i].text_mapping[j].text.s != NULL; j++) {
2410 if (memcmp(value.u.value_str.s,
2411 oscore_rcp_config[i].text_mapping[j].text.s,
2412 value.u.value_str.length) == 0) {
2413 memcpy(&(((char *)rcp_conf)[oscore_rcp_config[i].offset]),
2414 &oscore_rcp_config[i].text_mapping[j].value,
2415 sizeof(oscore_rcp_config[i].text_mapping[j].value));
2416 break;
2417 }
2418 }
2419 if (oscore_rcp_config[i].text_mapping[j].text.s == NULL) {
2420 coap_log_warn("oscore_rcp_conf: Keyword '%.*s': value '%.*s' unknown\n",
2421 (int)keyword.length,
2422 (const char *)keyword.s,
2423 (int)value.u.value_str.length,
2424 (const char *)value.u.value_str.s);
2425 goto error;
2426 }
2427 break;
2428 case COAP_ENC_CONFIG:
2429 case COAP_ENC_UNSIGNED64:
2430 case COAP_ENC_LAST:
2431 default:
2432 assert(0);
2433 break;
2434 }
2435 }
2436 break;
2437 }
2438 }
2439 if (i == sizeof(oscore_rcp_config) / sizeof(oscore_rcp_config[0])) {
2440 coap_log_warn("oscore_rcp_conf: Keyword '%.*s', type '%s' unknown\n",
2441 (int)keyword.length,
2442 (const char *)keyword.s,
2443 value.encoding_name);
2444 if (value.encoding == COAP_ENC_HEX || value.encoding == COAP_ENC_ASCII ||
2445 value.encoding == COAP_ENC_CONFIG)
2446 coap_delete_bin_const(value.u.value_bin);
2447 goto error;
2448 }
2449 }
2450 if (!rcp_conf->recipient_id) {
2451 coap_log_warn("oscore_rcp_conf: recipient_id not defined\n");
2452 goto error;
2453 }
2454 if (rcp_conf->recipient_id->length > 7) {
2455 coap_log_warn("oscore_rcp_conf: Maximum size of recipient_id is 7 bytes\n");
2456 goto error;
2457 }
2458 return rcp_conf;
2459
2460error:
2462 return NULL;
2463}
2464
2465static coap_oscore_conf_t *
2466coap_parse_oscore_conf_mem(coap_str_const_t conf_mem) {
2467 const char *start = (const char *)conf_mem.s;
2468 const char *end = start + conf_mem.length;
2469 coap_str_const_t keyword;
2470 oscore_value_t value;
2471 coap_oscore_conf_t *oscore_conf;
2472 int split_ok = -1;
2473
2474 oscore_conf = coap_malloc_type(COAP_STRING, sizeof(coap_oscore_conf_t));
2475 if (oscore_conf == NULL)
2476 return NULL;
2477 memset(oscore_conf, 0, sizeof(coap_oscore_conf_t));
2478
2479 memset(&value, 0, sizeof(value));
2480 /* Preset with defaults RFC8612 3.2 */
2482 oscore_conf->ssn_freq = 1;
2484 oscore_conf->hkdf_alg = COSE_HKDF_ALG_HKDF_SHA_256;
2485
2486 oscore_conf->rfc8613_b_1_2 = 1;
2487 oscore_conf->rfc8613_b_2 = 0;
2488 /* For debugging only */
2489 oscore_conf->break_sender_key = 0;
2490 oscore_conf->break_recipient_key = 0;
2491
2492 while (end > start &&
2493 (split_ok = get_split_entry(&start, end - start, &keyword, &value, 0)) > 0) {
2494 size_t i;
2495 size_t j;
2496
2497 for (i = 0; i < sizeof(oscore_config) / sizeof(oscore_config[0]); i++) {
2498 if (coap_string_equal(&oscore_config[i].str_keyword, &keyword) != 0 &&
2499 value.encoding & oscore_config[i].encoding) {
2500 if (coap_string_equal(coap_make_str_const("sender_id"), &keyword)) {
2501 if (value.u.value_bin->length > 7) {
2502 coap_log_warn("oscore_conf: Maximum size of sender_id is 7 bytes\n");
2503 goto error_free_value_bin;
2504 }
2505 if (oscore_conf->sender) {
2506 coap_log_warn("oscore_conf: sender_id duplicated\n");
2507 goto error_free_value_bin;
2508 }
2510 if (!oscore_conf->sender)
2511 goto error_free_value_bin;
2512
2513 memset(oscore_conf->sender, 0, sizeof(coap_oscore_snd_conf_t));
2514 oscore_conf->sender->sender_id = value.u.value_bin;
2515 } else if (coap_string_equal(coap_make_str_const("recipient_id"), &keyword)) {
2516 coap_oscore_rcp_conf_t *rcp_conf;
2517
2518 if (value.u.value_bin->length > 7) {
2519 coap_log_warn("oscore_conf: Maximum size of recipient_id is 7 bytes\n");
2520 goto error_free_value_bin;
2521 }
2522 /* Special case as there are potentially multiple entries */
2524 if (!rcp_conf)
2525 goto error_free_value_bin;
2526
2527 memset(rcp_conf, 0, sizeof(coap_oscore_rcp_conf_t));
2528 rcp_conf->recipient_id = value.u.value_bin;
2529 rcp_conf->next_recipient = oscore_conf->recipient_chain;
2530 oscore_conf->recipient_chain = rcp_conf;
2531 } else {
2532 coap_bin_const_t *unused_check;
2533
2534 switch (value.encoding) {
2535 case COAP_ENC_CONFIG:
2536 if (keyword.length == sizeof("complex_sender") - 1 &&
2537 memcmp(keyword.s, "complex_sender", keyword.length) == 0) {
2538 coap_oscore_snd_conf_t *snd_conf =
2539 coap_parse_oscore_snd_conf_mem(*value.u.value_bin);
2540
2541 if (!snd_conf) {
2542 coap_log_warn("oscore_conf: Keyword '%.*s' invalid\n",
2543 (int)keyword.length,
2544 (const char *)keyword.s);
2545 goto error_free_value_bin;
2546 }
2547 if (oscore_conf->sender) {
2548 coap_log_warn("oscore_conf: complex_sender duplicated\n");
2550 goto error_free_value_bin;
2551 }
2552 oscore_conf->sender = snd_conf;
2553 coap_delete_bin_const(value.u.value_bin);
2554 break;
2555 }
2556 if (keyword.length == sizeof("complex_recipient") - 1 &&
2557 memcmp(keyword.s, "complex_recipient", keyword.length) == 0) {
2558 coap_oscore_rcp_conf_t *rcp_conf =
2559 coap_parse_oscore_rcp_conf_mem(*value.u.value_bin);
2560
2561 if (!rcp_conf) {
2562 coap_log_warn("oscore_conf: Keyword '%.*s' invalid\n",
2563 (int)keyword.length,
2564 (const char *)keyword.s);
2565 goto error_free_value_bin;
2566 }
2567 rcp_conf->next_recipient = oscore_conf->recipient_chain;
2568 oscore_conf->recipient_chain = rcp_conf;
2569 coap_delete_bin_const(value.u.value_bin);
2570 }
2571 break;
2572 case COAP_ENC_ASCII:
2573 case COAP_ENC_HEX:
2574 memcpy(&unused_check,
2575 &(((char *)oscore_conf)[oscore_config[i].offset]),
2576 sizeof(unused_check));
2577 if (unused_check != NULL) {
2578 coap_log_warn("oscore_conf: Keyword '%.*s' duplicated\n",
2579 (int)keyword.length,
2580 (const char *)keyword.s);
2581 goto error_free_value_bin;
2582 }
2583 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2584 &value.u.value_bin,
2585 sizeof(value.u.value_bin));
2586 break;
2587 case COAP_ENC_INTEGER:
2588 case COAP_ENC_BOOL:
2589 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2590 &value.u.value_int,
2591 sizeof(value.u.value_int));
2592 break;
2593 case COAP_ENC_TEXT:
2594 for (j = 0; oscore_config[i].text_mapping[j].text.s != NULL; j++) {
2595 if (coap_string_equal(&value.u.value_str,
2596 &oscore_config[i].text_mapping[j].text)) {
2597 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2598 &oscore_config[i].text_mapping[j].value,
2599 sizeof(oscore_config[i].text_mapping[j].value));
2600 break;
2601 }
2602 }
2603 if (oscore_config[i].text_mapping[j].text.s == NULL) {
2604 coap_log_warn("oscore_conf: Keyword '%.*s': value '%.*s' unknown\n",
2605 (int)keyword.length,
2606 (const char *)keyword.s,
2607 (int)value.u.value_str.length,
2608 (const char *)value.u.value_str.s);
2609 goto error;
2610 }
2611 break;
2612 case COAP_ENC_UNSIGNED64:
2613 case COAP_ENC_LAST:
2614 default:
2615 assert(0);
2616 break;
2617 }
2618 }
2619 break;
2620 }
2621 }
2622 if (i == sizeof(oscore_config) / sizeof(oscore_config[0])) {
2623 coap_log_warn("oscore_conf: Keyword '%.*s', type '%s' unknown\n",
2624 (int)keyword.length,
2625 (const char *)keyword.s,
2626 value.encoding_name);
2627 if (value.encoding == COAP_ENC_HEX || value.encoding == COAP_ENC_ASCII ||
2628 value.encoding == COAP_ENC_CONFIG) {
2629 coap_delete_bin_const(value.u.value_bin);
2630 }
2631 goto error;
2632 }
2633 }
2634 if (split_ok == -1)
2635 goto error;
2636 if (!oscore_conf->master_secret) {
2637 coap_log_warn("oscore_conf: master_secret not defined\n");
2638 goto error;
2639 }
2640 if (!oscore_conf->sender) {
2641 coap_log_warn("oscore_conf: sender_id not defined\n");
2642 goto error;
2643 }
2644 return oscore_conf;
2645
2646error_free_value_bin:
2647 coap_delete_bin_const(value.u.value_bin);
2648error:
2649 coap_delete_oscore_conf(oscore_conf);
2650 return NULL;
2651}
2652
2653static oscore_ctx_t *
2654coap_oscore_init(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf) {
2655 oscore_ctx_t *osc_ctx = NULL;
2656
2657 if (!coap_crypto_check_cipher_alg(oscore_conf->aead_alg)) {
2658 coap_log_warn("COSE: Cipher Algorithm %d not supported\n",
2659 oscore_conf->aead_alg);
2660 goto error;
2661 }
2662 if (!coap_crypto_check_hkdf_alg(oscore_conf->hkdf_alg)) {
2663 coap_log_warn("COSE: HKDF Algorithm %d not supported\n",
2664 oscore_conf->hkdf_alg);
2665 goto error;
2666 }
2667
2668 osc_ctx = oscore_derive_ctx(c_context, oscore_conf);
2669 if (!osc_ctx) {
2670 coap_log_crit("OSCORE: Could not create Security Context!\n");
2671 coap_free_type(COAP_STRING, oscore_conf);
2672 return NULL;
2673 }
2674
2675 /* As all is stored in osc_ctx, oscore_conf is no longer needed */
2676 coap_free_type(COAP_STRING, oscore_conf);
2677
2678 /* return default first context */
2679 return osc_ctx;
2680
2681error:
2682 /* Remove from linked chain */
2683 oscore_remove_context(c_context, osc_ctx);
2684
2685 coap_delete_oscore_conf(oscore_conf);
2686 return NULL;
2687}
2688
2689void
2691 oscore_free_contexts(c_context);
2692}
2693
2694void
2697}
2698
2699void
2701 oscore_recipient_ctx_t *recipient_ctx) {
2702 oscore_recipient_ctx_t *old_ctx;
2703
2704 if (session == NULL || recipient_ctx == NULL)
2705 return;
2706
2707 if (session->recipient_ctx == recipient_ctx) {
2708 /* already attached */
2709 return;
2710 }
2711
2712 old_ctx = session->recipient_ctx;
2713
2714 if (old_ctx != NULL) {
2717 session);
2718 }
2719
2720 /* attach recipient context */
2721 session->recipient_ctx = recipient_ctx;
2722 session->recipient_ctx->ref++;
2723
2724 if (old_ctx != NULL) {
2726 }
2727}
2728
2729void
2731 oscore_recipient_ctx_t *recipient_ctx) {
2732 oscore_recipient_ctx_t *old_ctx;
2733
2734 if (association == NULL)
2735 return;
2736
2737 if (association->recipient_ctx == recipient_ctx)
2738 return;
2739
2740 old_ctx = association->recipient_ctx;
2741 association->recipient_ctx = recipient_ctx;
2742
2743 if (recipient_ctx != NULL)
2744 oscore_reference_recipient_ctx(recipient_ctx);
2745
2746 if (old_ctx != NULL)
2748}
2749
2752 coap_oscore_save_seq_num_t save_seq_num_func,
2753 void *save_seq_num_func_param,
2754 uint64_t start_seq_num) {
2755 coap_oscore_conf_t *oscore_conf = coap_parse_oscore_conf_mem(conf_mem);
2756
2757 if (oscore_conf == NULL)
2758 return NULL;
2759
2760 oscore_conf->save_seq_num_func = save_seq_num_func;
2761 oscore_conf->save_seq_num_func_param = save_seq_num_func_param;
2762 oscore_conf->start_seq_num = start_seq_num;
2763 coap_log_oscore("Start Seq no %" PRIu64 "\n", start_seq_num);
2764 return oscore_conf;
2765}
2766
2767/*
2768 * Compute the size of the potential OSCORE overhead
2769 */
2770size_t
2772 size_t overhead = 0;
2773 oscore_recipient_ctx_t *rcp_ctx = session->recipient_ctx;
2774 oscore_ctx_t *osc_ctx = rcp_ctx ? rcp_ctx->osc_ctx : NULL;
2775 coap_opt_iterator_t opt_iter;
2776 coap_opt_t *option;
2777
2778 if (osc_ctx == NULL)
2779 return 0;
2780
2781 /* Protected code held in inner PDU as token */
2782 overhead += 1;
2783
2784 /* Observe option (creates inner and outer */
2785 option = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
2786 if (option) {
2787 /* Assume delta is small */
2788 overhead += 2 + coap_opt_length(option);
2789 }
2790
2791 /* Proxy URI option Split - covered by coap_rebuild_pdu_for_proxy () */
2792
2793 /* OSCORE option */
2794 /* Option header */
2795 overhead += 1 +
2796 /* Partial IV (64 bits max)*/
2797 8 +
2798 /* kid context */
2799 (osc_ctx->id_context ? osc_ctx->id_context->length : 0) +
2800 /* kid */
2801 osc_ctx->sender_context->sender_id->length;
2802
2803 /* AAD overhead */
2804 overhead += AES_CCM_TAG;
2805
2806 /* Extended Token Overhead */
2807 if (session->max_token_size)
2808 overhead += session->max_token_size - pdu->actual_token.length;
2809
2810 /* End of options marker */
2811 overhead += 1;
2812
2813 return overhead;
2814}
2815
2816COAP_API int
2818 coap_bin_const_t *recipient_id) {
2819 int ret;
2820
2821 coap_lock_lock(return 0);
2822 ret = coap_new_oscore_recipient_lkd(context, recipient_id);
2824 return ret;
2825}
2826
2827int
2829 coap_bin_const_t *recipient_id) {
2830 coap_oscore_rcp_conf_t *rcp_conf;
2831 oscore_recipient_ctx_t *rcp_ctx;
2832
2834
2835 if (context->p_osc_ctx == NULL) {
2836 coap_delete_bin_const(recipient_id);
2837 return 0;
2838 }
2840 if (rcp_conf == NULL) {
2841 coap_delete_bin_const(recipient_id);
2842 return 0;
2843 }
2844 memset(rcp_conf, 0, sizeof(coap_oscore_rcp_conf_t));
2845 rcp_conf->recipient_id = recipient_id;
2846 /* rcp_conf is released in oscore_add_recipient() */
2847 rcp_ctx = oscore_add_recipient(context->p_osc_ctx, rcp_conf, 0);
2848 if (rcp_ctx == NULL)
2849 return 0;
2850 return 1;
2851}
2852
2853COAP_API int
2855 coap_bin_const_t *recipient_id) {
2856 int ret;
2857
2858 if (!context || !recipient_id)
2859 return 0;
2860 coap_lock_lock(return 0);
2861 ret = coap_delete_oscore_recipient_lkd(context, recipient_id);
2863 return ret;
2864}
2865
2866int
2868 coap_bin_const_t *recipient_id) {
2870 if (context->p_osc_ctx == NULL)
2871 return 0;
2872 return oscore_delete_recipient(context->p_osc_ctx, recipient_id);
2873}
2874
2875void
2877 coap_oscore_find_handler_t find_handler,
2878 coap_oscore_update_seq_num_handler_t update_seq_num_handler) {
2879 if (context == NULL)
2880 return;
2881
2882 coap_lock_lock(return);
2883 context->oscore_find_cb = find_handler;
2884 context->oscore_update_seq_num_cb = update_seq_num_handler;
2886}
2887
2889coap_oscore_get_recipient_conf(coap_oscore_conf_t *oscore_conf,
2890 const coap_bin_const_t *rid) {
2891 coap_oscore_rcp_conf_t *next = oscore_conf->recipient_chain;
2892
2893 while (next) {
2894 if (coap_binary_equal(next->recipient_id, rid)) {
2895 return next;
2896 }
2897 next = next->next_recipient;
2898 }
2899 return NULL;
2900}
2901
2902
2903COAP_API int
2905 const coap_bin_const_t *recipient_id,
2906 uint64_t last_seq, uint64_t seq_window) {
2907 int ret;
2908
2909 coap_lock_lock(return 0);
2910 ret = coap_oscore_recipient_set_latest_seq_lkd(oscore_conf, recipient_id, last_seq,
2911 seq_window);
2913 return ret;
2914}
2915
2916int
2918 const coap_bin_const_t *recipient_id,
2919 uint64_t last_seq, uint64_t seq_window) {
2920 coap_oscore_rcp_conf_t *rcp_conf;
2921
2922 rcp_conf = coap_oscore_get_recipient_conf(oscore_conf, recipient_id);
2923 if (rcp_conf) {
2924 rcp_conf->last_seq = last_seq;
2925 rcp_conf->sliding_window = seq_window;
2926 return 1;
2927 }
2928 return 0;
2929}
2930
2932
2933#else /* !COAP_OSCORE_SUPPORT */
2934int
2936 return 0;
2937}
2938
2941 const coap_address_t *local_if,
2942 const coap_address_t *server,
2943 coap_proto_t proto,
2944 coap_oscore_conf_t *oscore_conf) {
2945 (void)ctx;
2946 (void)local_if;
2947 (void)server;
2948 (void)proto;
2949 (void)oscore_conf;
2950 return NULL;
2951}
2952
2955 const coap_address_t *local_if,
2956 const coap_address_t *server,
2957 coap_proto_t proto,
2958 coap_oscore_conf_t *oscore_conf,
2959 void *app_data,
2961 coap_str_const_t *ws_host) {
2962 (void)ctx;
2963 (void)local_if;
2964 (void)server;
2965 (void)proto;
2966 (void)oscore_conf;
2967 (void)app_data;
2968 (void)callback;
2969 (void)ws_host;
2970 return NULL;
2971}
2972
2975 const coap_address_t *local_if,
2976 const coap_address_t *server,
2977 coap_proto_t proto,
2978 coap_dtls_cpsk_t *psk_data,
2979 coap_oscore_conf_t *oscore_conf) {
2980 (void)ctx;
2981 (void)local_if;
2982 (void)server;
2983 (void)proto;
2984 (void)psk_data;
2985 (void)oscore_conf;
2986 return NULL;
2987}
2988
2991 const coap_address_t *local_if,
2992 const coap_address_t *server,
2993 coap_proto_t proto,
2994 coap_dtls_cpsk_t *psk_data,
2995 coap_oscore_conf_t *oscore_conf,
2996 void *app_data,
2998 coap_str_const_t *ws_host) {
2999 (void)ctx;
3000 (void)local_if;
3001 (void)server;
3002 (void)proto;
3003 (void)psk_data;
3004 (void)oscore_conf;
3005 (void)app_data;
3006 (void)callback;
3007 (void)ws_host;
3008 return NULL;
3009}
3010
3013 const coap_address_t *local_if,
3014 const coap_address_t *server,
3015 coap_proto_t proto,
3016 coap_dtls_pki_t *pki_data,
3017 coap_oscore_conf_t *oscore_conf) {
3018 (void)ctx;
3019 (void)local_if;
3020 (void)server;
3021 (void)proto;
3022 (void)pki_data;
3023 (void)oscore_conf;
3024 return NULL;
3025}
3026
3029 const coap_address_t *local_if,
3030 const coap_address_t *server,
3031 coap_proto_t proto,
3032 coap_dtls_pki_t *pki_data,
3033 coap_oscore_conf_t *oscore_conf,
3034 void *app_data,
3036 coap_str_const_t *ws_host) {
3037 (void)ctx;
3038 (void)local_if;
3039 (void)server;
3040 (void)proto;
3041 (void)pki_data;
3042 (void)oscore_conf;
3043 (void)app_data;
3044 (void)callback;
3045 (void)ws_host;
3046 return NULL;
3047}
3048
3049int
3051 coap_oscore_conf_t *oscore_conf) {
3052 (void)context;
3053 (void)oscore_conf;
3054 return 0;
3055}
3056
3059 coap_oscore_save_seq_num_t save_seq_num_func,
3060 void *save_seq_num_func_param,
3061 uint64_t start_seq_num) {
3062 (void)conf_mem;
3063 (void)save_seq_num_func;
3064 (void)save_seq_num_func_param;
3065 (void)start_seq_num;
3066 return NULL;
3067}
3068
3069int
3071 (void)oscore_conf;
3072 return 0;
3073}
3074
3075int
3077 coap_bin_const_t *recipient_id) {
3078 (void)context;
3079 (void)recipient_id;
3080 return 0;
3081}
3082
3083int
3085 coap_bin_const_t *recipient_id) {
3086 (void)context;
3087 (void)recipient_id;
3088 return 0;
3089}
3090
3091void
3093 coap_oscore_find_handler_t find_handler,
3094 coap_oscore_update_seq_num_handler_t update_seq_num_handler) {
3095 (void)context;
3096 (void)find_handler;
3097 (void)update_seq_num_handler;
3098}
3099
3100COAP_API int
3102 const coap_bin_const_t *recipient_id,
3103 uint64_t last_seq, uint64_t seq_window) {
3104 (void)oscore_conf;
3105 (void)recipient_id;
3106 (void)last_seq;
3107 (void)seq_window;
3108 return 0;
3109}
3110
3111#endif /* !COAP_OSCORE_SUPPORT */
struct coap_lg_crcv_t coap_lg_crcv_t
#define PRIu64
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ COAP_OSCORE_BUF
Definition coap_mem.h:60
@ COAP_STRING
Definition coap_mem.h:33
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
#define NULL
Definition coap_option.h:30
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
coap_code_opt_num_t
Definition coap_option.h:70
@ COAP_OPTION_OBSERVE
Definition coap_option.h:75
@ COAP_OPTION_IF_NONE_MATCH
Definition coap_option.h:74
@ COAP_OPTION_ETAG
Definition coap_option.h:73
@ COAP_OPTION_EDHOC
Definition coap_option.h:89
@ COAP_OPTION_NORESPONSE
Definition coap_option.h:98
@ COAP_OPTION_MAXAGE
Definition coap_option.h:83
@ COAP_OPTION_SIZE2
Definition coap_option.h:92
@ COAP_OPTION_Q_BLOCK2
Definition coap_option.h:93
@ COAP_OPTION_PROXY_SCHEME
Definition coap_option.h:95
@ COAP_OPTION_HOP_LIMIT
Definition coap_option.h:85
@ COAP_OPTION_URI_PORT
Definition coap_option.h:76
@ COAP_OPTION_URI_HOST
Definition coap_option.h:72
@ COAP_OPTION_BLOCK2
Definition coap_option.h:90
@ COAP_OPTION_IF_MATCH
Definition coap_option.h:71
@ COAP_OPTION_SIZE1
Definition coap_option.h:96
@ COAP_OPTION_ECHO
Definition coap_option.h:97
@ COAP_OPTION_RTAG
Definition coap_option.h:99
@ COAP_OPTION_BLOCK1
Definition coap_option.h:91
@ COAP_OPTION_URI_PATH
Definition coap_option.h:79
@ COAP_OPTION_Q_BLOCK1
Definition coap_option.h:87
@ COAP_OPTION_OSCORE
Definition coap_option.h:78
@ COAP_OPTION_CONTENT_FORMAT
Definition coap_option.h:80
@ COAP_OPTION_LOCATION_QUERY
Definition coap_option.h:88
@ COAP_OPTION_URI_QUERY
Definition coap_option.h:84
@ COAP_OPTION_PROXY_URI
Definition coap_option.h:94
@ COAP_OPTION_LOCATION_PATH
Definition coap_option.h:77
@ COAP_OPTION_URI_PATH_ABB
Definition coap_option.h:81
@ COAP_OPTION_ACCEPT
Definition coap_option.h:86
static int coap_uri_scheme_is_secure(const coap_uri_t *uri)
Definition coap_uri.h:92
@ COAP_URI_SCHEME_LAST
Definition coap_uri.h:39
coap_mid_t coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request)
Sends an ACK message with code 0 for the specified request to dst.
Definition coap_net.c:1252
int coap_prng_lkd(void *buf, size_t len)
Fills buf with len random bytes using the default pseudo random number generator.
Definition coap_prng.c:198
int coap_handle_event_lkd(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:5475
coap_mid_t coap_send_internal(coap_session_t *session, coap_pdu_t *pdu, coap_pdu_t *request_pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:2151
void coap_cancel_all_messages(coap_context_t *context, coap_session_t *session, coap_bin_const_t *token)
Cancels all outstanding messages for session session that have the specified token.
Definition coap_net.c:3428
#define COAP_OSCORE_DEFAULT_REPLAY_WINDOW
int coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg)
Check whether the defined hkdf algorithm is supported by the underlying crypto library.
int coap_crypto_check_cipher_alg(cose_alg_t alg)
Check whether the defined cipher algorithm is supported by the underlying crypto library.
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:47
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
uint64_t coap_decode_var_bytes8(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:71
unsigned int coap_encode_var_safe8(uint8_t *buf, size_t length, uint64_t val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:81
@ COAP_EVENT_OSCORE_DECODE_ERROR
Triggered when there is an OSCORE decode of OSCORE option failure.
Definition coap_event.h:130
@ COAP_EVENT_OSCORE_INTERNAL_ERROR
Triggered when there is an OSCORE internal error i.e malloc failed.
Definition coap_event.h:128
@ COAP_EVENT_OSCORE_NOT_ENABLED
Triggered when trying to use OSCORE to decrypt, but it is not enabled.
Definition coap_event.h:122
@ COAP_EVENT_OSCORE_RECIPIENT_CHANGED
Triggered when coap_oscore_session_set_recipient_ctx() replaces the recipient context bound to a sess...
Definition coap_event.h:136
@ COAP_EVENT_OSCORE_NO_SECURITY
Triggered when there is no OSCORE security definition found.
Definition coap_event.h:126
@ COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD
Triggered when there is no OSCORE encrypted payload provided.
Definition coap_event.h:124
@ COAP_EVENT_OSCORE_DECRYPTION_FAILURE
Triggered when there is an OSCORE decryption failure.
Definition coap_event.h:120
#define coap_lock_callback(func)
Dummy for no thread-safe code.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition coap_debug.c:103
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition coap_debug.c:813
#define coap_log_oscore(...)
Definition coap_debug.h:132
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_err(...)
Definition coap_debug.h:102
#define coap_log_crit(...)
Definition coap_debug.h:96
@ COAP_LOG_OSCORE
Definition coap_debug.h:65
@ COAP_LOG_DEBUG
Definition coap_debug.h:64
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
void coap_delete_optlist(coap_optlist_t *queue)
Removes all entries from the optlist_chain, freeing off their memory usage.
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
int coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t **options)
The current optlist of optlist_chain is first sorted (as per RFC7272 ordering requirements) and then ...
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
uint64_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_size)
void cose_encrypt0_set_plaintext(cose_encrypt0_t *ptr, uint8_t *buffer, size_t size)
int cose_encrypt0_set_key(cose_encrypt0_t *ptr, coap_bin_const_t *key)
void cose_encrypt0_set_kid_context(cose_encrypt0_t *ptr, coap_bin_const_t *kid_context)
const char * cose_get_alg_name(cose_alg_t id, char *buffer, size_t buflen)
void cose_encrypt0_set_ciphertext(cose_encrypt0_t *ptr, uint8_t *buffer, size_t size)
int cose_encrypt0_decrypt(cose_encrypt0_t *ptr, uint8_t *plaintext_buffer, size_t plaintext_len)
size_t cose_tag_len(cose_alg_t cose_alg)
void cose_encrypt0_set_aad(cose_encrypt0_t *ptr, coap_bin_const_t *aad)
cose_curve_t
Definition oscore_cose.h:62
int cose_encrypt0_encrypt(cose_encrypt0_t *ptr, uint8_t *ciphertext_buffer, size_t ciphertext_len)
void cose_encrypt0_set_partial_iv(cose_encrypt0_t *ptr, coap_bin_const_t *partial_iv)
void cose_encrypt0_set_external_aad(cose_encrypt0_t *ptr, coap_bin_const_t *external_aad)
void cose_encrypt0_init(cose_encrypt0_t *ptr)
void cose_encrypt0_set_alg(cose_encrypt0_t *ptr, uint8_t alg)
void cose_encrypt0_set_key_id(cose_encrypt0_t *ptr, coap_bin_const_t *key_id)
void cose_encrypt0_set_nonce(cose_encrypt0_t *ptr, coap_bin_const_t *nonce)
@ COSE_HKDF_ALG_HKDF_SHA_256
@ COSE_ALGORITHM_AES_CCM_16_64_128
@ COSE_ALGORITHM_AES_CCM_16_64_256
size_t oscore_prepare_aad(const uint8_t *external_aad_buffer, size_t external_aad_len, uint8_t *aad_buffer, size_t aad_size)
void oscore_reference_recipient_ctx(oscore_recipient_ctx_t *recipient_ctx)
Increment the recipient context reference count.
void coap_oscore_association_set_recipient_ctx(oscore_association_t *association, oscore_recipient_ctx_t *recipient_ctx)
Set the recipient context of an association.
oscore_ctx_t * oscore_derive_ctx_from_conf(coap_oscore_conf_t *oscore_conf)
oscore_derive_ctx_from_conf - derive a osc_ctx from oscore_conf information
int coap_delete_oscore_recipient_lkd(coap_context_t *context, coap_bin_const_t *recipient_id)
Release all the information associated for the specific Recipient ID (and hence and stop any further ...
int oscore_delete_association(coap_session_t *session, oscore_association_t *association)
coap_session_t * coap_new_client_session_oscore3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, protecting the data using OSCORE,...
uint8_t oscore_validate_sender_seq(oscore_recipient_ctx_t *ctx, cose_encrypt0_t *cose)
oscore_recipient_ctx_t * oscore_add_recipient(oscore_ctx_t *ctx, coap_oscore_rcp_conf_t *rcp_conf, uint32_t break_key)
oscore_add_recipient - add in recipient information
#define OSCORE_SEQ_MAX
oscore_ctx_t * coap_init_oscore_context_from_conf(coap_oscore_conf_t *oscore_conf)
Initializes an OSCORE context from the given configuration.
#define AES_CCM_TAG
void coap_oscore_session_set_recipient_ctx(coap_session_t *session, oscore_recipient_ctx_t *recipient_ctx)
Attach the OSCORE recipient context information to the session.
int oscore_decode_option_value(const uint8_t *option_value, size_t option_len, cose_encrypt0_t *cose)
int coap_delete_oscore_snd_conf(coap_oscore_snd_conf_t *oscore_snd_conf)
Release all the information associated with the OSCORE complex Sender configuration.
coap_pdu_t * coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, coap_pdu_t *pdu, coap_bin_const_t *kid_context, oscore_partial_iv_t send_partial_iv)
Encrypts the specified pdu when OSCORE encryption is required on session.
int oscore_delete_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid)
uint8_t oscore_increment_sender_seq(oscore_ctx_t *ctx)
void oscore_update_ctx(oscore_ctx_t *osc_ctx, coap_bin_const_t *id_context)
oscore_update_ctx - update a osc_ctx with a new id_context
coap_session_t * coap_new_client_session_oscore_psk3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *psk_data, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PSK credentials protecting the data using...
oscore_ctx_t * oscore_derive_ctx(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf)
oscore_derive_ctx - derive a osc_ctx from oscore_conf information
COAP_API coap_pdu_t * coap_oscore_new_pdu_encrypted(coap_session_t *session, coap_pdu_t *pdu, coap_bin_const_t *kid_context, oscore_partial_iv_t send_partial_iv)
Encrypts the specified pdu when OSCORE encryption is required on session.
void oscore_roll_back_seq(oscore_recipient_ctx_t *ctx)
int oscore_new_association(coap_session_t *session, coap_pdu_t *sent_pdu, coap_bin_const_t *token, oscore_recipient_ctx_t *recipient_ctx, coap_bin_const_t *aad, coap_bin_const_t *nonce, coap_bin_const_t *partial_iv, int is_observe)
size_t oscore_prepare_e_aad(oscore_ctx_t *ctx, cose_encrypt0_t *cose, const uint8_t *oscore_option, size_t oscore_option_len, coap_bin_const_t *sender_public_key, uint8_t *external_aad_ptr, size_t external_aad_size)
void oscore_delete_server_associations(coap_session_t *session)
void oscore_log_char_value(coap_log_t level, const char *name, const char *value)
oscore_ctx_t * oscore_find_context(coap_session_t *session, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
struct coap_pdu_t * coap_oscore_decrypt_pdu(coap_session_t *session, coap_pdu_t *pdu)
Decrypts the OSCORE-encrypted parts of pdu when OSCORE is used.
int coap_oscore_recipient_set_latest_seq_lkd(coap_oscore_conf_t *oscore_conf, const coap_bin_const_t *recipient_id, uint64_t last_seq, uint64_t seq_window)
Set the latest sequence number and sliding window for the specified recipient id in the compiled conf...
int coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu)
Convert PDU to use Proxy-Scheme option if Proxy-Uri option is present.
void oscore_free_contexts(coap_context_t *c_context)
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
void coap_delete_oscore_associations(coap_session_t *session)
Cleanup all allocated OSCORE association information.
int coap_oscore_initiate(coap_session_t *session, coap_oscore_conf_t *oscore_conf)
Initiate an OSCORE session.
int coap_new_oscore_recipient_lkd(coap_context_t *context, coap_bin_const_t *recipient_id)
Add in the specific Recipient ID into the OSCORE context (server only).
oscore_ctx_t * oscore_duplicate_ctx(coap_context_t *c_context, oscore_ctx_t *o_osc_ctx, coap_bin_const_t *sender_id, coap_bin_const_t *recipient_id, coap_bin_const_t *id_context)
oscore_duplicate_ctx - duplicate a osc_ctx
oscore_partial_iv_t
void coap_delete_all_oscore(coap_context_t *context)
Cleanup all allocated OSCORE information.
void oscore_generate_nonce(cose_encrypt0_t *ptr, oscore_ctx_t *ctx, uint8_t *buffer, uint8_t size)
int oscore_remove_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx)
oscore_association_t * oscore_find_association(coap_session_t *session, coap_bin_const_t *token)
int coap_context_oscore_server_lkd(coap_context_t *context, coap_oscore_conf_t *oscore_conf)
Set the context's default OSCORE configuration for a server.
int coap_delete_oscore_rcp_conf(coap_oscore_rcp_conf_t *oscore_rcp_conf)
Release all the information associated with the OSCORE complex Recipient configuration.
void oscore_release_recipient_ctx(oscore_recipient_ctx_t **recipient_ctx)
Cleanup recipient context, including releasing the oscore context if the oscore context referenced is...
coap_session_t * coap_new_client_session_oscore_pki3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *pki_data, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PKI credentials protecting the data using...
ssize_t oscore_encode_option_value(uint8_t *option_buffer, size_t option_buf_len, cose_encrypt0_t *cose, uint8_t group_flag, uint8_t appendix_b_2)
Encode the OSCORE option.
size_t coap_oscore_overhead(coap_session_t *session, coap_pdu_t *pdu)
Determine the additional data size requirements for adding in OSCORE.
@ OSCORE_SEND_PARTIAL_IV
Send partial IV with encrypted PDU.
@ OSCORE_SEND_NO_IV
Do not send partial IV unless added by a response.
COAP_API int coap_oscore_recipient_set_latest_seq(coap_oscore_conf_t *oscore_conf, const coap_bin_const_t *recipient_id, uint64_t last_seq, uint64_t seq_window)
Set the latest sequence number and sliding window for the specified recipient id in the compiled conf...
coap_oscore_conf_t * coap_new_oscore_conf(coap_str_const_t conf_mem, coap_oscore_save_seq_num_t save_seq_num_func, void *save_seq_num_func_param, uint64_t start_seq_num)
Parse an OSCORE configuration (held in memory) and populate a OSCORE configuration structure.
coap_session_t * coap_new_client_session_oscore_psk(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *psk_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PSK credentials as well as protecting the ...
coap_session_t * coap_new_client_session_oscore_psk3(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *psk_data, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PSK credentials protecting the data using...
int(* coap_oscore_update_seq_num_handler_t)(const coap_session_t *session, const coap_bin_const_t *rcpkey_id, const coap_bin_const_t *ctxkey_id, uint64_t receiver_seq_num, uint64_t seq_num_window)
Callback function type for persisting the OSCORE receiver sequence number and anti-replay sliding win...
Definition coap_oscore.h:77
int coap_delete_oscore_conf(coap_oscore_conf_t *oscore_conf)
Release all the information associated with the OSCORE configuration.
coap_session_t * coap_new_client_session_oscore(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server, protecting the data using OSCORE.
int coap_context_oscore_server(coap_context_t *context, coap_oscore_conf_t *oscore_conf)
Set the context's default OSCORE configuration for a server.
coap_oscore_conf_t *(* coap_oscore_find_handler_t)(const coap_session_t *session, const coap_bin_const_t *rcpkey_id, const coap_bin_const_t *ctxkey_id)
Callback function type for overriding oscore_find_context().
Definition coap_oscore.h:54
coap_session_t * coap_new_client_session_oscore_pki(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *pki_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PKI credentials as well as protecting the ...
coap_session_t * coap_new_client_session_oscore3(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, protecting the data using OSCORE,...
int coap_new_oscore_recipient(coap_context_t *context, coap_bin_const_t *recipient_id)
Add in the specific Recipient ID into the OSCORE context (server only).
int(* coap_oscore_save_seq_num_t)(uint64_t sender_seq_num, void *param)
Definition of the function used to save the current Sender Sequence Number.
int coap_delete_oscore_recipient(coap_context_t *context, coap_bin_const_t *recipient_id)
Release all the information associated for the specific Recipient ID (and hence stop any further OSCO...
void coap_oscore_register_external_handlers(coap_context_t *context, coap_oscore_find_handler_t find_handler, coap_oscore_update_seq_num_handler_t update_seq_num_handler)
Register external storage handlers for OSCORE session state.
coap_session_t * coap_new_client_session_oscore_pki3(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *pki_data, coap_oscore_conf_t *oscore_conf, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PKI credentials protecting the data using...
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:197
size_t coap_insert_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Inserts option of given number in the pdu with the appropriate data.
Definition coap_pdu.c:696
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition coap_pdu.c:550
int coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Updates token in pdu with length len and data.
Definition coap_pdu.c:474
#define COAP_PDU_IS_PING(pdu)
coap_pdu_t * coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options, coap_bool_t expand_opt_abb)
Duplicate an existing PDU.
Definition coap_pdu.c:237
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition coap_pdu.c:1635
#define COAP_PAYLOAD_START
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition coap_pdu.c:340
#define COAP_PDU_IS_REQUEST(pdu)
size_t coap_add_option_internal(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition coap_pdu.c:863
#define COAP_DEFAULT_PORT
Definition coap_pdu.h:39
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:96
#define COAP_RESPONSE_CLASS(C)
Definition coap_pdu.h:99
coap_proto_t
CoAP protocol types Note: coap_layers_coap[] needs updating if extended.
Definition coap_pdu.h:234
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:248
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition coap_pdu.c:417
#define COAPS_DEFAULT_PORT
Definition coap_pdu.h:40
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition coap_pdu.c:966
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition coap_pdu.c:104
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:187
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition coap_pdu.c:935
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1755
@ COAP_BOOL_FALSE
Definition coap_pdu.h:295
@ COAP_REQUEST_CODE_POST
Definition coap_pdu.h:252
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:255
@ COAP_MESSAGE_NON
Definition coap_pdu.h:72
@ COAP_MESSAGE_ACK
Definition coap_pdu.h:73
@ COAP_MESSAGE_CON
Definition coap_pdu.h:71
coap_session_t * coap_new_client_session_pki3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *setup_data, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PKI credentials along with app_data infor...
coap_session_t * coap_new_client_session_psk3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *setup_data, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PSK credentials along with app_data infor...
void coap_session_release_lkd(coap_session_t *session)
Decrement reference counter on a session.
coap_session_t * coap_new_client_session3_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, void *app_data, coap_app_data_free_callback_t callback, coap_str_const_t *ws_host)
Creates a new client session to the designated server, with PSK credentials along with app_data infor...
@ COAP_OSCORE_B_2_NONE
@ COAP_OSCORE_B_2_STEP_3
@ COAP_OSCORE_B_2_STEP_1
@ COAP_OSCORE_B_2_STEP_4
@ COAP_OSCORE_B_2_STEP_5
@ COAP_OSCORE_B_2_STEP_2
void(* coap_app_data_free_callback_t)(void *data)
Callback to free off the app data when the entry is being deleted / freed off.
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition coap_str.c:130
void coap_delete_str_const(coap_str_const_t *s)
Deletes the given const string and releases any memory allocated.
Definition coap_str.c:65
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition coap_str.c:81
coap_str_const_t * coap_make_str_const(const char *string)
Take the specified byte array (text) and create a coap_str_const_t *.
Definition coap_str.c:70
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition coap_str.c:119
struct coap_str_const_t coap_str_const_t
CoAP string data definition with const data.
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:114
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition coap_str.h:222
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition coap_str.h:208
coap_str_const_t * coap_new_str_const(const uint8_t *data, size_t size)
Returns a new const string object with at least size+1 bytes storage allocated, and the provided data...
Definition coap_str.c:55
int coap_oscore_is_supported(void)
Check whether OSCORE is available.
int coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI query into '&' separate segments, and then adds the Uri-Query / Location-Query o...
Definition coap_uri.c:993
int coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI path into '/' separate segments, and then adds the Uri-Path / Location-Path opti...
Definition coap_uri.c:873
int coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition coap_uri.c:357
coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST]
Definition coap_uri.c:59
Multi-purpose address abstraction.
CoAP binary data definition with const data.
Definition coap_str.h:65
size_t length
length of binary data
Definition coap_str.h:66
const uint8_t * s
read-only binary data
Definition coap_str.h:67
CoAP binary data definition.
Definition coap_str.h:57
size_t length
length of binary data
Definition coap_str.h:58
uint8_t * s
binary data
Definition coap_str.h:59
The CoAP stack's global state is stored in a coap_context_t object.
The structure used for defining the Client PSK setup data to be used.
Definition coap_dtls.h:418
The structure used for defining the PKI setup data to be used.
Definition coap_dtls.h:317
Iterator to run through PDU options.
coap_opt_t * next_option
pointer to the unparsed next option
size_t length
remaining length of PDU
coap_option_num_t number
decoded option number
Representation of chained list of CoAP options to install.
The structure used to hold the OSCORE configuration information.
void * save_seq_num_func_param
Passed to save_seq_num_func().
uint32_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
cose_hkdf_alg_t hkdf_alg
Set to one of COSE_HKDF_ALG_*.
uint32_t break_sender_key
1 if sender key to be broken, else 0
coap_oscore_snd_conf_t * sender
The sender - i.e.
coap_oscore_rcp_conf_t * recipient_chain
The recipients as a chain.
uint32_t ssn_freq
Sender Seq Num update frequency.
coap_oscore_save_seq_num_t save_seq_num_func
Called every seq num change.
uint32_t rfc8613_b_1_2
1 if rfc8613 B.1.2 enabled else 0
uint64_t start_seq_num
Used for ssn_freq updating.
uint32_t break_recipient_key
1 if recipient key to be broken, else 0
coap_bin_const_t * master_secret
Common Master Secret.
cose_alg_t aead_alg
Set to one of COSE_ALGORITHM_AES*.
coap_bin_const_t * master_salt
Common Master Salt.
uint32_t replay_window
Replay window size Use COAP_OSCORE_DEFAULT_REPLAY_WINDOW.
coap_bin_const_t * id_context
Common ID context.
The structure used to hold the OSCORE Recipient configuration.
coap_bin_const_t * recipient_id
Recipient ID (i.e.
uint64_t last_seq
Highest sequence number used for this recipient.
uint8_t window_initialized
Contains if the sliding window is initialized 1 if initialized, 0 otherwise.
struct coap_oscore_rcp_conf_t * next_recipient
Used to maintain the chain.
uint64_t sliding_window
bitfield sequence counter window
The structure used to hold the OSCORE Sender configuration information.
coap_bin_const_t * sender_id
Sender ID (i.e.
structure for CoAP PDUs
uint8_t max_hdr_size
space reserved for protocol-specific header
uint8_t * token
first byte of token (or extended length bytes prefix), if any, or options
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
coap_bin_const_t actual_token
Actual token in pdu.
uint8_t * data
first byte of payload, if any
coap_mid_t mid
message id, if any, in regular host byte order
uint32_t e_token_length
length of Token space (includes leading extended bytes
size_t used_size
used bytes of storage for token, options and payload
coap_pdu_type_t type
message type
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
uint32_t max_token_size
Largest token size supported RFC8974.
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
uint8_t con_active
Active CON request sent.
coap_context_t * context
session's context
CoAP string data definition with const data.
Definition coap_str.h:47
const uint8_t * s
read-only string data
Definition coap_str.h:49
size_t length
length of string
Definition coap_str.h:48
Representation of parsed URI.
Definition coap_uri.h:70
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition coap_uri.h:82
coap_str_const_t path
The complete path if present or {0, NULL}.
Definition coap_uri.h:73
uint16_t port
The port in host byte order.
Definition coap_uri.h:72
coap_str_const_t query
The complete query if present or {0, NULL}.
Definition coap_uri.h:77
coap_str_const_t host
The host part of the URI.
Definition coap_uri.h:71
coap_bin_const_t aad
coap_bin_const_t key
coap_bin_const_t partial_iv
coap_bin_const_t kid_context
coap_bin_const_t nonce
coap_bin_const_t external_aad
coap_bin_const_t key_id
coap_bin_const_t oscore_option
cose_alg_t alg
coap_bin_const_t * obs_partial_iv
coap_bin_const_t * partial_iv
coap_bin_const_t * aad
coap_bin_const_t * nonce
oscore_recipient_ctx_t * recipient_ctx
uint8_t rfc8613_b_1_2
1 if rfc8613 B.1.2 enabled else 0
void * save_seq_num_func_param
Passed to save_seq_num_func().
oscore_sender_ctx_t * sender_context
cose_alg_t aead_alg
Set to one of COSE_ALGORITHM_AES*.
uint8_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
coap_oscore_save_seq_num_t save_seq_num_func
Called every seq num change.
oscore_recipient_ctx_t * recipient_chain
coap_bin_const_t * id_context
contains GID in case of group
uint32_t ssn_freq
Sender Seq Num update frequency.
coap_bin_const_t * recipient_key
coap_bin_const_t * recipient_id
coap_bin_const_t * sender_id
uint64_t seq
Sender Sequence Number.
coap_bin_const_t * sender_key
uint64_t next_seq
Used for ssn_freq updating.