libcoap 4.3.5-develop-0a48cee
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
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_id_count == 0) {
39 coap_log_warn("OSCORE: Recipient ID must be defined for a client\n");
40 return 0;
41 }
42 if (oscore_conf->rfc8613_b_2) {
43 /* Need to replace id_context with random value */
44 coap_binary_t *id_context = coap_new_binary(8);
45
46 if (id_context == NULL)
47 return 0;
49 coap_prng_lkd(id_context->s, id_context->length);
50 oscore_conf->id_context = (coap_bin_const_t *)id_context;
51 session->b_2_step = COAP_OSCORE_B_2_STEP_1;
52 coap_log_oscore("Appendix B.2 client step 1 (Generated ID1)\n");
53 }
54
55 osc_ctx = coap_oscore_init(session->context, oscore_conf);
56 if (osc_ctx == NULL) {
57 return 0;
58 }
59 session->recipient_ctx = osc_ctx->recipient_chain;
60 session->oscore_encryption = 1;
61 }
62 return 1;
63}
64
67 const coap_address_t *local_if,
68 const coap_address_t *server,
69 coap_proto_t proto,
70 coap_oscore_conf_t *oscore_conf) {
71 coap_session_t *session;
72
73 coap_lock_lock(return NULL);
74 session = coap_new_client_session_oscore3_lkd(ctx, local_if, server, proto, oscore_conf, NULL,
75 NULL, NULL);
77 return session;
78}
79
82 const coap_address_t *local_if,
83 const coap_address_t *server,
84 coap_proto_t proto,
85 coap_oscore_conf_t *oscore_conf,
86 void *app_data,
88 coap_str_const_t *ws_host) {
89 coap_session_t *session;
90
91 coap_lock_lock(return NULL);
92 session = coap_new_client_session_oscore3_lkd(ctx, local_if, server, proto, oscore_conf, app_data,
93 callback, ws_host);
95 return session;
96}
97
100 const coap_address_t *local_if,
101 const coap_address_t *server,
102 coap_proto_t proto,
103 coap_oscore_conf_t *oscore_conf,
104 void *app_data,
106 coap_str_const_t *ws_host) {
107 coap_session_t *session =
108 coap_new_client_session3_lkd(ctx, local_if, server, proto, app_data, callback, ws_host);
109
110 if (!session)
111 return NULL;
112
113 if (coap_oscore_initiate(session, oscore_conf) == 0) {
115 return NULL;
116 }
117 return session;
118}
119
122 const coap_address_t *local_if,
123 const coap_address_t *server,
124 coap_proto_t proto,
125 coap_dtls_cpsk_t *psk_data,
126 coap_oscore_conf_t *oscore_conf) {
127 coap_session_t *session;
128
129 coap_lock_lock(return NULL);
130 session = coap_new_client_session_oscore_psk3_lkd(ctx, local_if, server, proto, psk_data,
131 oscore_conf, NULL, NULL, NULL);
133 return session;
134}
135
138 const coap_address_t *local_if,
139 const coap_address_t *server,
140 coap_proto_t proto,
141 coap_dtls_cpsk_t *psk_data,
142 coap_oscore_conf_t *oscore_conf,
143 void *app_data,
145 coap_str_const_t *ws_host) {
146 coap_session_t *session;
147
148 coap_lock_lock(return NULL);
149 session = coap_new_client_session_oscore_psk3_lkd(ctx, local_if, server, proto, psk_data,
150 oscore_conf, app_data, callback, ws_host);
152 return session;
153}
154
157 const coap_address_t *local_if,
158 const coap_address_t *server,
159 coap_proto_t proto,
160 coap_dtls_cpsk_t *psk_data,
161 coap_oscore_conf_t *oscore_conf,
162 void *app_data,
164 coap_str_const_t *ws_host) {
165 coap_session_t *session;
166
168 session = coap_new_client_session_psk3_lkd(ctx, local_if, server, proto, psk_data,
169 app_data, callback, ws_host);
170
171 if (!session)
172 return NULL;
173
174 if (coap_oscore_initiate(session, oscore_conf) == 0) {
176 return NULL;
177 }
178 return session;
179}
180
183 const coap_address_t *local_if,
184 const coap_address_t *server,
185 coap_proto_t proto,
186 coap_dtls_pki_t *pki_data,
187 coap_oscore_conf_t *oscore_conf) {
188 coap_session_t *session;
189
190 coap_lock_lock(return NULL);
191 session = coap_new_client_session_oscore_pki3_lkd(ctx, local_if, server, proto, pki_data,
192 oscore_conf, NULL, NULL, NULL);
194 return session;
195}
196
199 const coap_address_t *local_if,
200 const coap_address_t *server,
201 coap_proto_t proto,
202 coap_dtls_pki_t *pki_data,
203 coap_oscore_conf_t *oscore_conf,
204 void *app_data,
206 coap_str_const_t *ws_host) {
207 coap_session_t *session;
208
209 coap_lock_lock(return NULL);
210 session = coap_new_client_session_oscore_pki3_lkd(ctx, local_if, server, proto, pki_data,
211 oscore_conf, app_data, callback, ws_host);
213 return session;
214}
215
218 const coap_address_t *local_if,
219 const coap_address_t *server,
220 coap_proto_t proto,
221 coap_dtls_pki_t *pki_data,
222 coap_oscore_conf_t *oscore_conf,
223 void *app_data,
225 coap_str_const_t *ws_host) {
226 coap_session_t *session;
227
229 session = coap_new_client_session_pki3_lkd(ctx, local_if, server, proto, pki_data,
230 app_data, callback, ws_host);
231
232 if (!session)
233 return NULL;
234
235 if (coap_oscore_initiate(session, oscore_conf) == 0) {
237 return NULL;
238 }
239 return session;
240}
241#endif /* COAP_CLIENT_SUPPORT */
242#if COAP_SERVER_SUPPORT
243
244COAP_API int
246 coap_oscore_conf_t *oscore_conf) {
247 int ret;
248
249 coap_lock_lock(return 0);
250 ret = coap_context_oscore_server_lkd(context, oscore_conf);
252 return ret;
253}
254
255int
257 coap_oscore_conf_t *oscore_conf) {
258 oscore_ctx_t *osc_ctx;
259
261 osc_ctx = coap_oscore_init(context, oscore_conf);
262 /* osc_ctx already added to context->osc_ctx */
263 if (osc_ctx)
264 return 1;
265 return 0;
266}
267
268#endif /* COAP_SERVER_SUPPORT */
269
270int
272 coap_uri_t uri;
273 coap_opt_iterator_t opt_iter;
274 coap_opt_t *option;
275 uint8_t option_value_buffer[15];
276 coap_optlist_t *optlist_chain = NULL;
277
278 if ((option =
279 coap_check_option(pdu, COAP_OPTION_PROXY_URI, &opt_iter)) == NULL)
280 return 1;
281
282 /* Need to break down into the component parts, but keep data safe */
283 memset(&uri, 0, sizeof(uri));
284
286 coap_opt_length(option),
287 &uri) < 0 || uri.scheme >= COAP_URI_SCHEME_LAST) {
288 coap_log_warn("Proxy URI '%.*s' not decodable\n",
289 coap_opt_length(option),
290 (const char *)coap_opt_value(option));
291 goto error;
292 }
294 goto error;
295
296 if (!coap_insert_option(pdu,
298 uri.host.length,
299 uri.host.s))
300 goto error;
304 coap_encode_var_safe(option_value_buffer,
305 sizeof(option_value_buffer),
306 uri.port & 0xffff),
307 option_value_buffer))
308 goto error;
309 if (uri.path.length) {
310 /* Add in the Uri-Path options */
312 &optlist_chain))
313 goto error;
314 }
315 if (uri.query.length) {
316 /* Add in the Uri-Query options */
318 &optlist_chain))
319 goto error;
320 }
321 if (!coap_add_optlist_pdu(pdu, &optlist_chain))
322 goto error;
323
324 if (!coap_insert_option(pdu,
326 strlen(coap_uri_scheme[uri.scheme].name),
327 (const uint8_t *)coap_uri_scheme[uri.scheme].name))
328 goto error;
329
330 coap_delete_optlist(optlist_chain);
331 return 1;
332
333error:
334 coap_delete_optlist(optlist_chain);
335 return 0;
336}
337
338static void
339dump_cose(cose_encrypt0_t *cose, const char *message) {
340#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_OSCORE
341 (void)cose;
342 (void)message;
343#else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
345 char buffer[30];
346
347 coap_log_oscore("%s Cose information\n", message);
349 cose_get_alg_name(cose->alg, buffer, sizeof(buffer)));
351 oscore_log_hex_value(COAP_LOG_OSCORE, "partial_iv", &cose->partial_iv);
353 oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
355 "oscore_option",
356 &cose->oscore_option);
358 oscore_log_hex_value(COAP_LOG_OSCORE, "external_aad", &cose->external_aad);
360 }
361#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
362}
363
366 coap_pdu_t *pdu,
367 coap_bin_const_t *kid_context,
368 oscore_partial_iv_t send_partial_iv) {
369 coap_pdu_t *ret_pdu;
370
371 coap_lock_lock(return NULL);
372 ret_pdu = coap_oscore_new_pdu_encrypted_lkd(session, pdu, kid_context, send_partial_iv);
374
375 return ret_pdu;
376}
377
378/*
379 * Take current PDU, create a new one approriately separated as per RFC8613
380 * and then encrypt / integrity check the OSCORE data
381 */
384 coap_pdu_t *pdu,
385 coap_bin_const_t *kid_context,
386 oscore_partial_iv_t send_partial_iv) {
387 uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu) || COAP_PDU_IS_PING(pdu);
388 coap_pdu_code_t code =
389 coap_request ? COAP_REQUEST_CODE_POST : COAP_RESPONSE_CODE(204);
390 coap_pdu_t *osc_pdu;
391 coap_pdu_t *plain_pdu = NULL;
392 coap_bin_const_t pdu_token;
393 coap_opt_iterator_t opt_iter;
394 coap_opt_t *option;
395 uint8_t pdu_code = pdu->code;
396 size_t length;
397 const uint8_t *data;
398 uint8_t *ciphertext_buffer = NULL;
399 size_t ciphertext_len = 0;
400 uint8_t aad_buffer[AAD_BUF_LEN];
401 uint8_t nonce_buffer[13];
403 coap_bin_const_t nonce;
404 oscore_recipient_ctx_t *rcp_ctx;
405 oscore_ctx_t *osc_ctx;
406 cose_encrypt0_t cose[1];
407 uint8_t group_flag = 0;
408 int show_pdu = 0;
409 int doing_observe = 0;
410 uint32_t observe_value = 0;
411 oscore_association_t *association = NULL;
412 oscore_sender_ctx_t *snd_ctx;
413 uint8_t external_aad_buffer[200];
414 coap_bin_const_t external_aad;
415 uint8_t oscore_option[48];
416 size_t oscore_option_len;
417
418 /* Check that OSCORE has not already been done */
419 if (coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter))
420 return NULL;
421
422 if (coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter))
423 doing_observe = 1;
424
425 coap_log_debug("PDU to encrypt\n");
427 osc_pdu = coap_pdu_init(pdu->type == COAP_MESSAGE_NON &&
428 session->b_2_step != COAP_OSCORE_B_2_NONE ?
429 COAP_MESSAGE_CON : pdu->type,
430 code,
431 pdu->mid,
432 pdu->used_size + coap_oscore_overhead(session, pdu));
433 if (osc_pdu == NULL)
434 return NULL;
435
436 cose_encrypt0_init(cose); /* clears cose memory */
437 pdu_token = coap_pdu_get_token(pdu);
438 if (coap_request) {
439 /*
440 * RFC8613 8.1 Step 1. Protecting the client's request
441 * Get the Sender Context
442 */
443 rcp_ctx = session->recipient_ctx;
444 if (rcp_ctx == NULL)
445 goto error;
446 osc_ctx = rcp_ctx->osc_ctx;
447 assert(osc_ctx);
448 snd_ctx = osc_ctx->sender_context;
449 } else {
450 /*
451 * RFC8613 8.3 Step 1. Protecting the server's response
452 * Get the Sender Context
453 */
454 association = oscore_find_association(session, &pdu_token);
455 if (association == NULL)
456 goto error;
457
458 rcp_ctx = association->recipient_ctx;
459 osc_ctx = rcp_ctx->osc_ctx;
460 snd_ctx = osc_ctx->sender_context;
461 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
462 cose_encrypt0_set_aad(cose, association->aad);
463 }
464
465 cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
466
467 if (coap_request || doing_observe ||
468 send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
469 uint8_t partial_iv_buffer[8];
470 size_t partial_iv_len;
471 coap_bin_const_t partial_iv;
472 partial_iv_len = coap_encode_var_safe8(partial_iv_buffer,
473 sizeof(partial_iv_buffer),
474 snd_ctx->seq);
475 if (snd_ctx->seq == 0) {
476 /* Need to special case */
477 partial_iv_buffer[0] = '\000';
478 partial_iv_len = 1;
479 }
480 partial_iv.s = partial_iv_buffer;
481 partial_iv.length = partial_iv_len;
482 cose_encrypt0_set_partial_iv(cose, &partial_iv);
483 }
484
485 if (coap_request)
487
488 cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
489
490 /* nonce (needs to have sender information correctly set up) */
491
492 if (coap_request || doing_observe ||
493 send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
494 /*
495 * 8.1 Step 3 or RFC8613 8.3.1 Step A
496 * Compose the AEAD nonce
497 *
498 * Requires in COSE object as appropriate
499 * key_id (kid) (sender)
500 * partial_iv (sender)
501 * common_iv (already in osc_ctx)
502 */
503 nonce.s = nonce_buffer;
504 nonce.length = 13;
505 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
506 cose_encrypt0_set_nonce(cose, &nonce);
507 if (!oscore_increment_sender_seq(osc_ctx))
508 goto error;
509 if (osc_ctx->save_seq_num_func) {
510 if (osc_ctx->sender_context->seq > osc_ctx->sender_context->next_seq) {
511 /* Only update at ssn_freq rate */
512 osc_ctx->sender_context->next_seq += osc_ctx->ssn_freq;
513 osc_ctx->save_seq_num_func(osc_ctx->sender_context->next_seq,
514 osc_ctx->save_seq_num_func_param);
515 }
516 }
517 } else {
518 /*
519 * 8.3 Step 3.
520 * Use nonce from request
521 */
522 cose_encrypt0_set_nonce(cose, association->nonce);
523 }
524
525 /* OSCORE_option (needs to be before AAD as included in AAD if group) */
526
527 /* cose is modified for encode option in response message */
528 if (!coap_request) {
529 /* no kid on response */
531 if (!doing_observe && send_partial_iv == OSCORE_SEND_NO_IV)
533 }
534 if (kid_context) {
535 cose_encrypt0_set_kid_context(cose, kid_context);
536 }
537 oscore_option_len =
538 oscore_encode_option_value(oscore_option, sizeof(oscore_option), cose,
539 group_flag,
540 session->b_2_step != COAP_OSCORE_B_2_NONE);
541 if (!coap_request) {
542 /* Reset what was just unset as appropriate for AAD */
544 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
545 }
546 if (kid_context)
548
549 /*
550 * RFC8613 8.1/8.3 Step 2(a) (5.4).
551 * Compose the External AAD and then AAD
552 *
553 * OSCORE_option requires
554 * partial_iv (cose partial_iv)
555 * kid_context (cose kid_context)
556 * key_id (cose key_id)
557 * group_flag
558 *
559 * Non Group (based on osc_tx->mode) requires the following
560 * aead_alg (osc_ctx)
561 * request_kid (request key_id using cose)
562 * request_piv (request partial_iv using cose)
563 * options (none at present)
564 * Group (based on osc_tx->mode) requires the following
565 * aead_alg (osc_ctx) (pairwise mode)
566 * sign_enc_alg (osc_ctx) (group mode)
567 * sign_alg (osc_ctx) (group mode)
568 * alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
569 * request_kid (request key_id using cose)
570 * request_piv (request partial_iv using cose)
571 * options (none at present)
572 * request_kid_context (osc_ctx id_context)
573 * OSCORE_option (parameter)
574 * test_gs_public_key (osc_ctx sender_context public_key)
575 * gm_public_key (osc_ctx gm_public_key)
576 *
577 * Note: No I options at present
578 */
579 if (coap_request || osc_ctx->mode != OSCORE_MODE_SINGLE ||
580 send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
581 /* External AAD */
582 external_aad.s = external_aad_buffer;
583 external_aad.length = oscore_prepare_e_aad(osc_ctx,
584 cose,
585 NULL,
586 0,
587 NULL,
588 external_aad_buffer,
589 sizeof(external_aad_buffer));
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 assert(aad.length < AAD_BUF_LEN);
599 cose_encrypt0_set_aad(cose, &aad);
600 }
601
602 /*
603 * RFC8613 8.1/8.3 Step 2(b) (5.3).
604 *
605 * Set up temp plaintext pdu, the data including token, options and
606 * optional payload will get encrypted as COSE ciphertext.
607 */
608 plain_pdu = coap_pdu_init(pdu->type,
609 pdu->code,
610 pdu->mid,
611 pdu->used_size + 1 /* pseudo-token with actual code */);
612 if (plain_pdu == NULL)
613 goto error;
614
615 coap_add_token(osc_pdu, pdu_token.length, pdu_token.s);
616
617 /* First byte of plain is real CoAP code. Pretend it is token */
618 coap_add_token(plain_pdu, 1, &pdu_code);
619
620 /* Copy across the Outer/Inner Options to respective PDUs */
622 while ((option = coap_option_next(&opt_iter))) {
623 switch (opt_iter.number) {
628 /* Outer only */
629 if (!coap_insert_option(osc_pdu,
630 opt_iter.number,
631 coap_opt_length(option),
632 coap_opt_value(option)))
633 goto error;
634 break;
636 /* Make as Outer option as-is */
637 if (!coap_insert_option(osc_pdu,
638 opt_iter.number,
639 coap_opt_length(option),
640 coap_opt_value(option)))
641 goto error;
642 if (coap_request) {
643 /* Make as Inner option (unchanged) */
644 if (!coap_insert_option(plain_pdu,
645 opt_iter.number,
646 coap_opt_length(option),
647 coap_opt_value(option)))
648 goto error;
649 osc_pdu->code = COAP_REQUEST_CODE_FETCH;
650 } else {
651 /* Make as Inner option but empty */
652 if (!coap_insert_option(plain_pdu, opt_iter.number, 0, NULL))
653 goto error;
654 osc_pdu->code = COAP_RESPONSE_CODE(205);
655 }
656 show_pdu = 1;
657 doing_observe = 1;
658 observe_value = coap_decode_var_bytes(coap_opt_value(option),
659 coap_opt_length(option));
660 break;
662 /*
663 * Should have already been caught by doing
664 * coap_rebuild_pdu_for_proxy() before calling
665 * coap_oscore_new_pdu_encrypted_lkd()
666 */
667 assert(0);
668 break;
669 default:
670 /* Make as Inner option */
671 if (!coap_insert_option(plain_pdu,
672 opt_iter.number,
673 coap_opt_length(option),
674 coap_opt_value(option)))
675 goto error;
676 break;
677 }
678 }
679 /* Add in data to plain */
680 if (coap_get_data(pdu, &length, &data)) {
681 if (!coap_add_data(plain_pdu, length, data))
682 goto error;
683 }
684 if (show_pdu) {
685 coap_log_oscore("OSCORE payload\n");
686 coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
687 }
688
689 /*
690 * 8.1/8.3 Step 4.
691 * Encrypt the COSE object.
692 *
693 * Requires in COSE object as appropriate
694 * alg (already set)
695 * key (sender key)
696 * nonce (already set)
697 * aad (already set)
698 * plaintext
699 */
700 cose_encrypt0_set_key(cose, snd_ctx->sender_key);
701 cose_encrypt0_set_plaintext(cose, plain_pdu->token, plain_pdu->used_size);
702 dump_cose(cose, "Pre encrypt");
703 ciphertext_buffer =
704 coap_malloc_type(COAP_OSCORE_BUF, OSCORE_CRYPTO_BUFFER_SIZE);
705 if (ciphertext_buffer == NULL)
706 goto error;
707 ciphertext_len = cose_encrypt0_encrypt(cose,
708 ciphertext_buffer,
709 plain_pdu->used_size + AES_CCM_TAG);
710 if ((int)ciphertext_len <= 0) {
711 coap_log_warn("OSCORE: Encryption Failure, result code: %d \n",
712 (int)ciphertext_len);
713 goto error;
714 }
715 assert(ciphertext_len < OSCORE_CRYPTO_BUFFER_SIZE);
716
717 /* Add in OSCORE option (previously computed) */
718 if (!coap_insert_option(osc_pdu,
720 oscore_option_len,
721 oscore_option))
722 goto error;
723
724 /* Add now encrypted payload */
725 if (!coap_add_data(osc_pdu, ciphertext_len, ciphertext_buffer))
726 goto error;
727
728 coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
729 ciphertext_buffer = NULL;
730
731 coap_delete_pdu_lkd(plain_pdu);
732 plain_pdu = NULL;
733
734 if (association && association->is_observe == 0)
735 oscore_delete_association(session, association);
736 association = NULL;
737
738 if (!(session->block_mode & COAP_BLOCK_CACHE_RESPONSE)) {
739 /*
740 * If this is a response ACK with data, make it a separate response
741 * by sending an Empty ACK and changing osc_pdu's MID and type. This
742 * then allows lost response ACK (now CON) with data to be recovered.
743 */
744 if (coap_request == 0 && osc_pdu->type == COAP_MESSAGE_ACK &&
745 COAP_RESPONSE_CLASS(pdu->code) == 2 &&
746 COAP_PROTO_NOT_RELIABLE(session->proto)) {
748 0,
749 osc_pdu->mid,
750 0);
751 if (empty) {
752 if (coap_send_internal(session, empty, NULL) != COAP_INVALID_MID) {
753 osc_pdu->mid = coap_new_message_id_lkd(session);
754 osc_pdu->type = COAP_MESSAGE_CON;
755 }
756 }
757 }
758 }
759
760 if (!coap_pdu_encode_header(osc_pdu, session->proto)) {
761 goto error;
762 }
763
764 /*
765 * Set up an association for handling a response if this is a request
766 */
767 if (coap_request) {
768 association = oscore_find_association(session, &pdu_token);
769 if (association) {
770 /* Refresh the association */
771 coap_delete_bin_const(association->nonce);
772 association->nonce =
773 coap_new_bin_const(cose->nonce.s, cose->nonce.length);
774 if (association->nonce == NULL)
775 goto error;
776 coap_delete_bin_const(association->aad);
777 association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
778 if (association->aad == NULL)
779 goto error;
780 if (doing_observe && observe_value == 1) {
782 association->obs_partial_iv = association->partial_iv;
783 } else {
784 coap_delete_bin_const(association->partial_iv);
785 }
786 association->partial_iv =
788 if (association->partial_iv == NULL)
789 goto error;
790 association->recipient_ctx = rcp_ctx;
791 coap_delete_pdu_lkd(association->sent_pdu);
792 if (session->b_2_step != COAP_OSCORE_B_2_NONE || association->just_set_up) {
793 size_t size;
794
795 association->sent_pdu = coap_pdu_duplicate_lkd(pdu, session,
796 pdu_token.length,
797 pdu_token.s, NULL);
798 if (association->sent_pdu == NULL)
799 goto error;
800 if (coap_get_data(pdu, &size, &data)) {
801 coap_add_data(association->sent_pdu, size, data);
802 }
803 association->just_set_up = 0;
804 } else {
805 association->sent_pdu = NULL;
806 }
807 } else if (!oscore_new_association(session,
808 pdu,
809 &pdu_token,
810 rcp_ctx,
811 &cose->aad,
812 &cose->nonce,
813 &cose->partial_iv,
814 doing_observe)) {
815 goto error;
816 }
817 }
818 return osc_pdu;
819
820error:
821 if (ciphertext_buffer)
822 coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
823 coap_delete_pdu_lkd(osc_pdu);
824 coap_delete_pdu_lkd(plain_pdu);
825 return NULL;
826}
827
828static void
829build_and_send_error_pdu(coap_session_t *session,
830 coap_pdu_t *rcvd,
831 coap_pdu_code_t code,
832 const char *diagnostic,
833 uint8_t *echo_data,
834 coap_bin_const_t *kid_context,
835 int encrypt_oscore) {
836 coap_pdu_t *err_pdu = NULL;
837 coap_bin_const_t token;
838 int oscore_encryption = session->oscore_encryption;
839 unsigned char buf[4];
840
841 token = coap_pdu_get_token(rcvd);
844 code,
845 rcvd->mid,
846 token.length + 2 + 8 +
847 (diagnostic ? strlen(diagnostic) : 0));
848 if (!err_pdu)
849 return;
850 coap_add_token(err_pdu, token.length, token.s);
851 if (echo_data) {
852 coap_add_option_internal(err_pdu, COAP_OPTION_ECHO, 8, echo_data);
853 } else if (kid_context == NULL) {
856 coap_encode_var_safe(buf, sizeof(buf), 0),
857 buf);
858 }
859 if (diagnostic)
860 coap_add_data(err_pdu, strlen(diagnostic), (const uint8_t *)diagnostic);
861 session->oscore_encryption = encrypt_oscore;
862
863 if ((echo_data || kid_context) && encrypt_oscore) {
864 coap_pdu_t *osc_pdu;
865
866 osc_pdu =
867 coap_oscore_new_pdu_encrypted_lkd(session, err_pdu, kid_context,
868 echo_data ? 1 : 0);
869 if (!osc_pdu)
870 goto fail_resp;
871 session->oscore_encryption = 0;
872 coap_send_internal(session, osc_pdu, NULL);
873 coap_delete_pdu_lkd(err_pdu);
874 err_pdu = NULL;
875 } else {
876 coap_send_internal(session, err_pdu, NULL);
877 err_pdu = NULL;
878 }
879fail_resp:
880 session->oscore_encryption = oscore_encryption;
881 coap_delete_pdu_lkd(err_pdu);
882 return;
883}
884
885/* pdu contains incoming message with encrypted COSE ciphertext payload
886 * function returns decrypted message
887 * and verifies signature, if present
888 * returns NULL when decryption,verification fails
889 */
892 coap_pdu_t *pdu) {
893 coap_pdu_t *decrypt_pdu = NULL;
894 coap_pdu_t *plain_pdu = NULL;
895 const uint8_t *osc_value; /* value of OSCORE option */
896 uint8_t osc_size; /* size of OSCORE OPTION */
897 coap_opt_iterator_t opt_iter;
898 coap_opt_t *opt = NULL;
899 cose_encrypt0_t cose[1];
900 oscore_ctx_t *osc_ctx = NULL;
901 uint8_t aad_buffer[AAD_BUF_LEN];
902 uint8_t nonce_buffer[13];
904 coap_bin_const_t nonce;
905 int pltxt_size = 0;
906 int got_resp_piv = 0;
907 int doing_resp_observe = 0;
908 uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu);
909 coap_bin_const_t pdu_token;
910 uint8_t *st_encrypt;
911 size_t encrypt_len;
912 size_t tag_len;
913 oscore_recipient_ctx_t *rcp_ctx = NULL;
914 oscore_association_t *association = NULL;
915 uint8_t external_aad_buffer[100];
916 coap_bin_const_t external_aad;
917 oscore_sender_ctx_t *snd_ctx = NULL;
918#if COAP_CLIENT_SUPPORT
919 coap_pdu_t *sent_pdu = NULL;
920#endif /* COAP_CLIENT_SUPPORT */
921
922 opt = coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter);
923 assert(opt);
924 if (opt == NULL)
925 return NULL;
926
927 if (session->context->p_osc_ctx == NULL) {
928 coap_log_warn("OSCORE: Not enabled\n");
929 if (!coap_request)
932 session);
933 return NULL;
934 }
935
936 if (pdu->data == NULL) {
937 coap_log_warn("OSCORE: No protected payload\n");
938 if (!coap_request)
941 session);
942 return NULL;
943 }
944
945 osc_size = coap_opt_length(opt);
946 osc_value = coap_opt_value(opt);
947
948 cose_encrypt0_init(cose); /* clear cose memory */
949
950 /* PDU code will be filled in after decryption */
951 decrypt_pdu =
952 coap_pdu_init(pdu->type, 0, pdu->mid, pdu->used_size);
953 if (decrypt_pdu == NULL) {
954 if (!coap_request)
957 session);
958 goto error;
959 }
960
961 /* Copy across the Token */
962 pdu_token = coap_pdu_get_token(pdu);
963 coap_add_token(decrypt_pdu, pdu_token.length, pdu_token.s);
964
965 /*
966 * 8.2/8.4 Step 1.
967 * Copy outer options across, except E and OSCORE options
968 */
970 while ((opt = coap_option_next(&opt_iter))) {
971 switch (opt_iter.number) {
972 /* 'E' options skipped */
974 case COAP_OPTION_ETAG:
989 case COAP_OPTION_ECHO:
990 case COAP_OPTION_RTAG:
991 /* OSCORE does not get copied across */
993 break;
994 default:
995 if (!coap_add_option_internal(decrypt_pdu,
996 opt_iter.number,
997 coap_opt_length(opt),
998 coap_opt_value(opt))) {
999 if (!coap_request)
1002 session);
1003 goto error;
1004 }
1005 break;
1006 }
1007 }
1008
1009 if (coap_request) {
1010 uint64_t incoming_seq;
1011 /*
1012 * 8.2 Step 2
1013 * Decompress COSE object
1014 * Get Recipient Context based on kid and optional kid_context
1015 */
1016 if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
1017 coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
1018 build_and_send_error_pdu(session,
1019 pdu,
1020 COAP_RESPONSE_CODE(402),
1021 "Failed to decode COSE",
1022 NULL,
1023 NULL,
1024 0);
1025 goto error_no_ack;
1026 }
1027 osc_ctx = oscore_find_context(session->context,
1028 cose->key_id,
1029 &cose->kid_context,
1030 NULL,
1031 &rcp_ctx);
1032 if (!osc_ctx) {
1033 if (cose->kid_context.length > 0) {
1034 const uint8_t *ptr;
1035 size_t length;
1036 /* Appendix B.2 protocol check - Is the recipient key_id known */
1037 osc_ctx = oscore_find_context(session->context,
1038 cose->key_id,
1039 NULL,
1040 session->oscore_r2 != 0 ? (uint8_t *)&session->oscore_r2 : NULL,
1041 &rcp_ctx);
1042 ptr = cose->kid_context.s;
1043 length = cose->kid_context.length;
1044 if (ptr && osc_ctx && osc_ctx->rfc8613_b_2 &&
1045 osc_ctx->mode == OSCORE_MODE_SINGLE) {
1046 /* Processing Appendix B.2 protocol */
1047 /* Need to CBOR unwrap kid_context */
1048 coap_bin_const_t kid_context;
1049
1050 kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
1051 kid_context.s = ptr;
1052 cose_encrypt0_set_kid_context(cose, (coap_bin_const_t *)&kid_context);
1053
1054 if (session->oscore_r2 != 0) {
1055 /* B.2 step 4 */
1057 cose->kid_context.length);
1058
1059 if (kc == NULL)
1060 goto error;
1061
1062 session->b_2_step = COAP_OSCORE_B_2_STEP_4;
1063 coap_log_oscore("Appendix B.2 server step 4 (R2 || R3)\n");
1064 oscore_update_ctx(osc_ctx, kc);
1065 } else {
1066 session->b_2_step = COAP_OSCORE_B_2_STEP_2;
1067 coap_log_oscore("Appendix B.2 server step 2 (ID1)\n");
1068 osc_ctx = oscore_duplicate_ctx(session->context,
1069 osc_ctx,
1070 osc_ctx->sender_context->sender_id,
1071 &cose->key_id,
1072 &cose->kid_context);
1073 if (osc_ctx == NULL)
1074 goto error;
1075 /*
1076 * Complete the Verify (B.2 step 2)
1077 * before sending back the response
1078 */
1079 rcp_ctx = osc_ctx->recipient_chain;
1080 }
1081 } else {
1082 osc_ctx = NULL;
1083 }
1084 }
1085 } else if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1086 session->b_2_step = COAP_OSCORE_B_2_NONE;
1087 coap_log_oscore("Appendix B.2 server finished\n");
1088 }
1089 if (!osc_ctx) {
1090 coap_log_crit("OSCORE: Security Context not found\n");
1091 oscore_log_hex_value(COAP_LOG_OSCORE, "key_id", &cose->key_id);
1092 oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
1093 build_and_send_error_pdu(session,
1094 pdu,
1095 COAP_RESPONSE_CODE(401),
1096 "Security context not found",
1097 NULL,
1098 NULL,
1099 0);
1100 goto error_no_ack;
1101 }
1102 /* to be used for encryption of returned response later */
1103 session->recipient_ctx = rcp_ctx;
1104 snd_ctx = osc_ctx->sender_context;
1105
1106 /*
1107 * 8.2 Step 3.
1108 * Verify Partial IV is not duplicated.
1109 *
1110 * Requires in COSE object as appropriate
1111 * partial_iv (as received)
1112 */
1113 if (rcp_ctx->initial_state == 0 &&
1114 !oscore_validate_sender_seq(rcp_ctx, cose)) {
1115 coap_log_warn("OSCORE: Replayed or old message\n");
1116 build_and_send_error_pdu(session,
1117 pdu,
1118 COAP_RESPONSE_CODE(401),
1119 "Replay detected",
1120 NULL,
1121 NULL,
1122 0);
1123 goto error_no_ack;
1124 }
1125 if (rcp_ctx->initial_state == 1) {
1126 incoming_seq =
1128 rcp_ctx->last_seq = incoming_seq;
1129 }
1130 } else { /* !coap_request */
1131 /*
1132 * 8.4 Step 2
1133 * Decompress COSE object
1134 * Get Recipient Context based on token
1135 */
1136 if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
1137 coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
1140 session);
1141 goto error;
1142 }
1143 got_resp_piv = cose->partial_iv.length ? 1 : 0;
1144
1145 association = oscore_find_association(session, &pdu_token);
1146 if (association) {
1147 rcp_ctx = association->recipient_ctx;
1148 osc_ctx = rcp_ctx->osc_ctx;
1149 snd_ctx = osc_ctx->sender_context;
1150#if COAP_CLIENT_SUPPORT
1151 sent_pdu = association->sent_pdu;
1152 if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1153 const uint8_t *ptr = cose->kid_context.s;
1154 size_t length = cose->kid_context.length;
1155
1156 if (ptr) {
1157 /* Need to CBOR unwrap kid_context */
1158 coap_bin_const_t kid_context;
1159
1160 kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
1161 kid_context.s = ptr;
1162 cose_encrypt0_set_kid_context(cose, &kid_context);
1163 }
1164 if (ptr && !coap_binary_equal(osc_ctx->id_context, &cose->kid_context)) {
1165 /* If Appendix B.2 step 3 is in operation */
1166 /* Need to update Security Context with new (R2 || ID1) ID Context */
1168 osc_ctx->id_context->length);
1169
1170 if (kc == NULL) {
1173 session);
1174 goto error;
1175 }
1176
1177 memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
1178 memcpy(&kc->s[cose->kid_context.length],
1179 osc_ctx->id_context->s,
1180 osc_ctx->id_context->length);
1181
1182 session->b_2_step = COAP_OSCORE_B_2_STEP_3;
1183 coap_log_oscore("Appendix B.2 client step 3 (R2 || ID1)\n");
1184 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1185 } else {
1186 session->b_2_step = COAP_OSCORE_B_2_STEP_5;
1187 coap_log_oscore("Appendix B.2 client step 5 (R2 || R3)\n");
1188 }
1189 }
1190#endif /* COAP_CLIENT_SUPPORT */
1191 } else {
1192 coap_log_crit("OSCORE: Security Context association not found\n");
1195 session);
1196 goto error;
1197 }
1198 }
1199
1200 cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
1201
1202 if (coap_request) {
1203 /*
1204 * RFC8613 8.2 Step 4.
1205 * Compose the External AAD and then AAD
1206 *
1207 * Non Group (based on osc_tx->mode) requires the following
1208 * aead_alg (osc_ctx)
1209 * request_kid (request key_id using cose)
1210 * request_piv (request partial_iv using cose)
1211 * options (none at present)
1212 * Group (based on osc_tx->mode) requires the following
1213 * aead_alg (osc_ctx) (pairwise mode)
1214 * sign_enc_alg (osc_ctx) (group mode)
1215 * sign_alg (osc_ctx) (group mode)
1216 * alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
1217 * request_kid (request key_id using cose)
1218 * request_piv (request partial_iv using cose)
1219 * options (none at present)
1220 * request_kid_context (osc_ctx id_context)
1221 * OSCORE_option (as received in request)
1222 * test_gs_public_key (recipient public key)
1223 * gm_public_key (osc_ctx gm_public_key)
1224 *
1225 * Note: No I options at present
1226 */
1227
1228 /* External AAD */
1229 external_aad.s = external_aad_buffer;
1230 external_aad.length = oscore_prepare_e_aad(osc_ctx,
1231 cose,
1232 osc_value,
1233 osc_size,
1234 NULL,
1235 external_aad_buffer,
1236 sizeof(external_aad_buffer));
1237 cose_encrypt0_set_external_aad(cose, &external_aad);
1238
1239 /* AAD */
1240 aad.s = aad_buffer;
1241 aad.length = oscore_prepare_aad(external_aad_buffer,
1242 external_aad.length,
1243 aad_buffer,
1244 sizeof(aad_buffer));
1245 assert(aad.length < AAD_BUF_LEN);
1246 cose_encrypt0_set_aad(cose, &aad);
1247
1248 /*
1249 * RFC8613 8.2 Step 5.
1250 * Compute the AEAD nonce.
1251 *
1252 * Requires in COSE object as appropriate
1253 * key_id (kid) (Recipient ID)
1254 * partial_iv (as received in request)
1255 * common_iv (already in osc_ctx)
1256 */
1257 nonce.s = nonce_buffer;
1258 nonce.length = 13;
1259 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
1260 cose_encrypt0_set_nonce(cose, &nonce);
1261 /*
1262 * Set up an association for use in the response
1263 */
1264 association = oscore_find_association(session, &pdu_token);
1265 if (association) {
1266 /* Refresh the association */
1267 coap_delete_bin_const(association->nonce);
1268 association->nonce =
1269 coap_new_bin_const(cose->nonce.s, cose->nonce.length);
1270 if (association->nonce == NULL)
1271 goto error;
1272 coap_delete_bin_const(association->partial_iv);
1273 association->partial_iv =
1275 if (association->partial_iv == NULL)
1276 goto error;
1277 coap_delete_bin_const(association->aad);
1278 association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
1279 if (association->aad == NULL)
1280 goto error;
1281 association->recipient_ctx = rcp_ctx;
1282 } else if (!oscore_new_association(session,
1283 NULL,
1284 &pdu_token,
1285 rcp_ctx,
1286 &cose->aad,
1287 &cose->nonce,
1288 &cose->partial_iv,
1289 0)) {
1290 goto error;
1291 }
1292 /* So association is not released when handling decrypt */
1293 association = NULL;
1294 } else { /* ! coap_request */
1295 /* Need to do nonce before AAD because of different partial_iv */
1296 /*
1297 * 8.4 Step 4.
1298 * Compose the AEAD nonce.
1299 */
1300 cose_encrypt0_set_key_id(cose, rcp_ctx->recipient_id);
1301 if (cose->partial_iv.length == 0) {
1302 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
1303 cose_encrypt0_set_nonce(cose, association->nonce);
1304 } else {
1305 uint64_t last_seq;
1306
1307 if (rcp_ctx->initial_state == 0 &&
1308 !oscore_validate_sender_seq(rcp_ctx, cose)) {
1309 coap_log_warn("OSCORE: Replayed or old message\n");
1310 goto error;
1311 }
1312 last_seq =
1314 if (rcp_ctx->last_seq>= OSCORE_SEQ_MAX) {
1315 coap_log_warn("OSCORE Replay protection, SEQ larger than SEQ_MAX.\n");
1316 goto error;
1317 }
1318 if (last_seq > rcp_ctx->last_seq)
1319 rcp_ctx->last_seq = last_seq;
1320 /*
1321 * Requires in COSE object as appropriate
1322 * kid (set above)
1323 * partial_iv (as received)
1324 * common_iv (already in osc_ctx)
1325 */
1326 oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
1327 nonce.s = nonce_buffer;
1328 nonce.length = 13;
1329 cose_encrypt0_set_nonce(cose, &nonce);
1330 }
1331#ifdef OSCORE_EXTRA_DEBUG
1332 dump_cose(cose, "!req post set nonce");
1333#endif /* OSCORE_EXTRA_DEBUG */
1334 /*
1335 * 8.4 Step 3.
1336 * Compose the External AAD and then AAD (same as request non-group (5.4)
1337 *
1338 * Non Group (based on osc_tx->mode) requires the following
1339 * aead_alg (osc_ctx)
1340 * request_kid (request key_id using cose)
1341 * request_piv (request partial_iv using cose)
1342 * options (none at present)
1343 * Group (based on osc_tx->mode) requires the following
1344 * aead_alg (osc_ctx) (pairwise mode)
1345 * sign_enc_alg (osc_ctx) (group mode)
1346 * sign_alg (osc_ctx) (group mode)
1347 * alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
1348 * request_kid (request key_id using cose)
1349 * request_piv (request partial_iv using cose)
1350 * options (none at present)
1351 * request_kid_context (osc_ctx id_context)
1352 * OSCORE_option (as received in request)
1353 * test_gs_public_key (recipient public key)
1354 * gm_public_key (osc_ctx gm_public_key)
1355 *
1356 * Note: No I options at present
1357 */
1358
1359 /* External AAD */
1360 cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
1361 if (association->is_observe && association->obs_partial_iv && got_resp_piv) {
1362 cose_encrypt0_set_partial_iv(cose, association->obs_partial_iv);
1363 } else {
1364 cose_encrypt0_set_partial_iv(cose, association->partial_iv);
1365 }
1366#ifdef OSCORE_EXTRA_DEBUG
1367 dump_cose(cose, "!req pre aad");
1368#endif /* OSCORE_EXTRA_DEBUG */
1369 external_aad.s = external_aad_buffer;
1370 external_aad.length = oscore_prepare_e_aad(osc_ctx,
1371 cose,
1372 NULL,
1373 0,
1374 NULL,
1375 external_aad_buffer,
1376 sizeof(external_aad_buffer));
1377 cose_encrypt0_set_external_aad(cose, &external_aad);
1378
1379 /* AAD */
1380 aad.s = aad_buffer;
1381 aad.length = oscore_prepare_aad(external_aad_buffer,
1382 external_aad.length,
1383 aad_buffer,
1384 sizeof(aad_buffer));
1385 assert(aad.length < AAD_BUF_LEN);
1386 cose_encrypt0_set_aad(cose, &aad);
1387#ifdef OSCORE_EXTRA_DEBUG
1388 dump_cose(cose, "!req post set aad");
1389#endif /* OSCORE_EXTRA_DEBUG */
1390 }
1391
1392 /*
1393 * 8.2 Step 6 / 8.4 Step 5.
1394 * Decrypt the COSE object.
1395 *
1396 * Requires in COSE object as appropriate
1397 * alg (already set)
1398 * key
1399 * nonce (already set)
1400 * aad (already set)
1401 * ciphertext
1402 */
1403 st_encrypt = pdu->data;
1404 encrypt_len = pdu->used_size - (pdu->data - pdu->token);
1405 if (encrypt_len <= 0) {
1406 coap_log_warn("OSCORE: No protected payload\n");
1407 if (!coap_request)
1410 session);
1411 goto error;
1412 }
1413 cose_encrypt0_set_key(cose, rcp_ctx->recipient_key);
1414 cose_encrypt0_set_ciphertext(cose, st_encrypt, encrypt_len);
1415
1416 tag_len = cose_tag_len(cose->alg);
1417 /* Decrypt into plain_pdu, so code (token), options and data are in place */
1418 plain_pdu = coap_pdu_init(0, 0, 0, encrypt_len /* - tag_len */);
1419 if (plain_pdu == NULL) {
1420 if (!coap_request)
1423 session);
1424 goto error;
1425 }
1426
1427 /* need the tag_len on the end for TinyDTLS to do its work - yuk */
1428 if (!coap_pdu_resize(plain_pdu, encrypt_len /* - tag_len */)) {
1429 if (!coap_request)
1432 session);
1433 goto error;
1434 }
1435
1436 /* Account for 1 byte 'code' used as token */
1437 plain_pdu->e_token_length = 1;
1438 plain_pdu->actual_token.length = 1;
1439 /* Account for the decrypted data */
1440 plain_pdu->used_size = encrypt_len - tag_len;
1441
1442 dump_cose(cose, "Pre decrypt");
1443 pltxt_size =
1444 cose_encrypt0_decrypt(cose, plain_pdu->token, encrypt_len - tag_len);
1445 if (pltxt_size <= 0) {
1446 coap_log_warn("OSCORE: Decryption Failure, result code: %d \n",
1447 (int)pltxt_size);
1448 if (coap_request) {
1449 build_and_send_error_pdu(session,
1450 pdu,
1451 COAP_RESPONSE_CODE(400),
1452 "Decryption failed",
1453 NULL,
1454 NULL,
1455 0);
1456 oscore_roll_back_seq(rcp_ctx);
1457 goto error_no_ack;
1458 } else {
1461 session);
1462 }
1463 goto error;
1464 }
1465
1466 assert((size_t)pltxt_size < pdu->alloc_size + pdu->max_hdr_size);
1467
1468 /* Appendix B.2 Trap */
1469 if (session->b_2_step == COAP_OSCORE_B_2_STEP_2) {
1470 /* Need to update Security Context with new (R2 || ID1) ID Context */
1471 coap_binary_t *kc =
1472 coap_new_binary(sizeof(session->oscore_r2) + cose->kid_context.length);
1473 coap_bin_const_t oscore_r2;
1474
1475 if (kc == NULL) {
1476 if (!coap_request)
1479 session);
1480 goto error;
1481 }
1482
1483 coap_prng_lkd(&session->oscore_r2, sizeof(session->oscore_r2));
1484 memcpy(kc->s, &session->oscore_r2, sizeof(session->oscore_r2));
1485 memcpy(&kc->s[sizeof(session->oscore_r2)],
1486 cose->kid_context.s,
1487 cose->kid_context.length);
1488
1489 coap_log_oscore("Appendix B.2 server step 2 (R2 || ID1)\n");
1490 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1491
1492 oscore_r2.length = sizeof(session->oscore_r2);
1493 oscore_r2.s = (const uint8_t *)&session->oscore_r2;
1494 coap_log_oscore("Appendix B.2 server step 2 plain response\n");
1495 build_and_send_error_pdu(session,
1496 pdu,
1497 COAP_RESPONSE_CODE(401),
1498 NULL,
1499 NULL,
1500 &oscore_r2,
1501 1);
1502 goto error_no_ack;
1503 }
1504#if COAP_CLIENT_SUPPORT
1505 if (session->b_2_step == COAP_OSCORE_B_2_STEP_3) {
1506 coap_log_oscore("Appendix B.2 client step 3 (R2 || R3)\n");
1507 coap_pdu_encode_header(plain_pdu, session->proto);
1508 plain_pdu->actual_token.s = plain_pdu->token;
1509 plain_pdu->code = plain_pdu->token[0];
1510 if (plain_pdu->code != COAP_RESPONSE_CODE(401)) {
1511 coap_log_warn("OSCORE Appendix B.2: Expected 4.01 response\n");
1512 }
1513 /* Skip the options */
1514 coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
1515 while (coap_option_next(&opt_iter)) {
1516 }
1517 if (opt_iter.length > 0 && opt_iter.next_option &&
1518 opt_iter.next_option[0] == COAP_PAYLOAD_START) {
1519 plain_pdu->data = &opt_iter.next_option[1];
1520 }
1521 coap_log_oscore("Inner Response PDU (plaintext)\n");
1522 coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
1523 /*
1524 * Need to update Security Context with new (R2 || R3) ID Context
1525 * and retransmit the request
1526 */
1528
1529 if (kc == NULL) {
1530 if (!coap_request)
1533 session);
1534 goto error;
1535 }
1536 memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
1537 coap_prng_lkd(&kc->s[cose->kid_context.length], 8);
1538
1539 oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
1540
1542 session,
1543 &pdu->actual_token);
1544 if (session->con_active)
1545 session->con_active--;
1546 coap_send_ack_lkd(session, pdu);
1547 if (sent_pdu) {
1548 coap_log_oscore("Appendix B.2 retransmit pdu\n");
1549 if (coap_retransmit_oscore_pdu(session, sent_pdu, NULL) ==
1551 goto error_no_ack;
1552 }
1553 goto error_no_ack;
1554 }
1555#endif /* COAP_CLIENT_SUPPORT */
1556
1557#if COAP_SERVER_SUPPORT
1558 /* Appendix B.1.2 request Trap */
1559 if (coap_request && osc_ctx->rfc8613_b_1_2) {
1560 if (rcp_ctx->initial_state == 1) {
1561 opt = coap_check_option(plain_pdu, COAP_OPTION_ECHO, &opt_iter);
1562 if (opt) {
1563 /* Verify Client is genuine */
1564 if (coap_opt_length(opt) == 8 &&
1565 memcmp(coap_opt_value(opt), rcp_ctx->echo_value, 8) == 0) {
1566 if (!oscore_validate_sender_seq(rcp_ctx, cose)) {
1567 coap_log_warn("OSCORE: Replayed or old message\n");
1568 build_and_send_error_pdu(session,
1569 pdu,
1570 COAP_RESPONSE_CODE(401),
1571 "Replay detected",
1572 NULL,
1573 NULL,
1574 0);
1575 goto error_no_ack;
1576 }
1577 } else
1578 goto error;
1579 } else {
1580 /* RFC 8163 Appendix B.1.2 */
1581 if (session->b_2_step == COAP_OSCORE_B_2_STEP_4) {
1582 session->b_2_step = COAP_OSCORE_B_2_NONE;
1583 coap_log_oscore("Appendix B.2 server finished\n");
1584 }
1585 coap_prng_lkd(rcp_ctx->echo_value, sizeof(rcp_ctx->echo_value));
1586 coap_log_oscore("Appendix B.1.2 server plain response\n");
1587 build_and_send_error_pdu(session,
1588 pdu,
1589 COAP_RESPONSE_CODE(401),
1590 NULL,
1591 rcp_ctx->echo_value,
1592 NULL,
1593 1);
1594 goto error_no_ack;
1595 }
1596 }
1597 }
1598#endif /* COAP_SERVER_SUPPORT */
1599
1600 /*
1601 * 8.2 Step 7 / 8.4 Step 6.
1602 * Add decrypted Code, options and payload
1603 * [OSCORE option not copied across previously]
1604 */
1605
1606 /* PDU code is pseudo plain_pdu token */
1607 decrypt_pdu->code = plain_pdu->token[0];
1608
1609 /* Copy inner decrypted options across */
1610 coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
1611 while ((opt = coap_option_next(&opt_iter))) {
1612 size_t len;
1613 size_t bias;
1614
1615 switch (opt_iter.number) {
1616 case COAP_OPTION_OSCORE:
1617 break;
1619 if (!coap_request) {
1620 bias = cose->partial_iv.length > 3 ? cose->partial_iv.length - 3 : 0;
1621 len = cose->partial_iv.length > 3 ? 3 : cose->partial_iv.length;
1622 /* Make Observe option reflect last 3 bytes of partial_iv */
1624 decrypt_pdu,
1625 opt_iter.number,
1626 len,
1627 cose->partial_iv.s ? &cose->partial_iv.s[bias] : NULL)) {
1630 session);
1631 goto error;
1632 }
1633 doing_resp_observe = 1;
1634 break;
1635 }
1636 association = oscore_find_association(session, &pdu_token);
1637 if (association) {
1638 association->is_observe = 1;
1639 association = NULL;
1640 }
1641 /* Fall Through */
1642 default:
1643 if (!coap_insert_option(decrypt_pdu,
1644 opt_iter.number,
1645 coap_opt_length(opt),
1646 coap_opt_value(opt))) {
1647 if (!coap_request)
1650 session);
1651 goto error;
1652 }
1653 break;
1654 }
1655 }
1656 if (!coap_request && !doing_resp_observe) {
1657 if (association) {
1658 association->is_observe = 0;
1659 }
1660 }
1661 /* Need to copy across any data */
1662 if (opt_iter.length > 0 && opt_iter.next_option &&
1663 opt_iter.next_option[0] == COAP_PAYLOAD_START) {
1664 plain_pdu->data = &opt_iter.next_option[1];
1665 if (!coap_add_data(decrypt_pdu,
1666 plain_pdu->used_size -
1667 (plain_pdu->data - plain_pdu->token),
1668 plain_pdu->data)) {
1669 if (!coap_request)
1672 session);
1673 goto error;
1674 }
1675 }
1676 coap_delete_pdu_lkd(plain_pdu);
1677 plain_pdu = NULL;
1678
1679 /* Make sure headers are correctly set up */
1680 if (!coap_pdu_encode_header(decrypt_pdu, session->proto)) {
1681 if (!coap_request)
1684 session);
1685 goto error;
1686 }
1687
1688 if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
1689 session->b_2_step = COAP_OSCORE_B_2_NONE;
1690 coap_log_oscore("Appendix B.2 client finished\n");
1691 }
1692#if COAP_CLIENT_SUPPORT
1693 if (decrypt_pdu->code == COAP_RESPONSE_CODE(401) &&
1694 (opt = coap_check_option(decrypt_pdu, COAP_OPTION_ECHO, &opt_iter))) {
1695 /* Server is requesting Echo refresh check */
1697 session,
1698 &pdu->actual_token);
1699 if (session->con_active)
1700 session->con_active--;
1701 if (!sent_pdu) {
1702 coap_lg_crcv_t *lg_crcv = coap_find_lg_crcv(session, pdu);
1703
1704 if (lg_crcv)
1705 sent_pdu = lg_crcv->sent_pdu;
1706 }
1707 if (sent_pdu) {
1708 coap_send_ack_lkd(session, pdu);
1709 coap_log_debug("PDU requesting re-transmit\n");
1710 coap_show_pdu(COAP_LOG_DEBUG, decrypt_pdu);
1711 coap_log_oscore("RFC9175 retransmit pdu\n");
1712 /* Do not care if this fails */
1713 if (coap_retransmit_oscore_pdu(session, sent_pdu, opt) != COAP_INVALID_MID) {
1714 session->doing_b_1_2 = 1;
1715 }
1716 goto error_no_ack;
1717 }
1718 } else if (session->doing_b_1_2) {
1719 coap_lg_crcv_t *lg_crcv = coap_find_lg_crcv(session, pdu);
1720
1721 if (lg_crcv) {
1722 if (!coap_binary_equal(&decrypt_pdu->actual_token, lg_crcv->app_token)) {
1723 coap_update_token(decrypt_pdu, lg_crcv->app_token->length, lg_crcv->app_token->s);
1724 }
1725 }
1726 session->doing_b_1_2 = 0;
1727 }
1728#endif /* COAP_CLIENT_SUPPORT */
1729 if (association && association->is_observe == 0)
1730 oscore_delete_association(session, association);
1731 return decrypt_pdu;
1732
1733error:
1734 coap_send_ack_lkd(session, pdu);
1735error_no_ack:
1736 if (association && association->is_observe == 0)
1737 oscore_delete_association(session, association);
1738 coap_delete_pdu_lkd(decrypt_pdu);
1739 coap_delete_pdu_lkd(plain_pdu);
1740 return NULL;
1741}
1742
1743typedef enum {
1744 COAP_ENC_ASCII = 0x01,
1745 COAP_ENC_HEX = 0x02,
1746 COAP_ENC_INTEGER = 0x08,
1747 COAP_ENC_TEXT = 0x10,
1748 COAP_ENC_BOOL = 0x20,
1749 COAP_ENC_LAST
1750} coap_oscore_coding_t;
1751
1752#undef TEXT_MAPPING
1753#define TEXT_MAPPING(t, v) \
1754 { { sizeof(#t)-1, (const uint8_t *)#t }, v }
1755
1756static struct coap_oscore_encoding_t {
1757 coap_str_const_t name;
1758 coap_oscore_coding_t encoding;
1759} oscore_encoding[] = {
1760 TEXT_MAPPING(ascii, COAP_ENC_ASCII),
1761 TEXT_MAPPING(hex, COAP_ENC_HEX),
1762 TEXT_MAPPING(integer, COAP_ENC_INTEGER),
1763 TEXT_MAPPING(text, COAP_ENC_TEXT),
1764 TEXT_MAPPING(bool, COAP_ENC_BOOL),
1765 {{0, NULL}, COAP_ENC_LAST}
1766};
1767
1768typedef struct {
1769 coap_oscore_coding_t encoding;
1770 const char *encoding_name;
1771 union {
1772 int value_int;
1773 coap_bin_const_t *value_bin;
1774 coap_str_const_t value_str;
1775 } u;
1776} oscore_value_t;
1777
1778static uint8_t
1779hex_to_char(char c) {
1780 assert(isxdigit(c));
1781 if ('a' <= c && c <= 'f')
1782 return c - 'a' + 10;
1783 else if ('A' <= c && c <= 'F')
1784 return c - 'A' + 10;
1785 else
1786 return c - '0';
1787}
1788
1789/* Parse the hex into binary */
1790static coap_bin_const_t *
1791parse_hex_bin(const char *begin, const char *end) {
1792 coap_binary_t *binary = NULL;
1793 size_t i;
1794
1795 if ((end - begin) % 2 != 0)
1796 goto bad_entry;
1797 binary = coap_new_binary((end - begin) / 2);
1798 if (binary == NULL)
1799 goto bad_entry;
1800 for (i = 0; (i < (size_t)(end - begin)) && isxdigit((uint8_t)begin[i]) &&
1801 isxdigit((uint8_t)begin[i + 1]);
1802 i += 2) {
1803 binary->s[i / 2] = (hex_to_char(begin[i]) << 4) + hex_to_char(begin[i + 1]);
1804 }
1805 if (i != (size_t)(end - begin))
1806 goto bad_entry;
1807 return (coap_bin_const_t *)binary;
1808
1809bad_entry:
1810 coap_delete_binary(binary);
1811 return NULL;
1812}
1813
1814/*
1815 * Break up each OSCORE Configuration line entry into the 3 parts which
1816 * are comma separated
1817 *
1818 * keyword,encoding,value
1819 */
1820static int
1821get_split_entry(const char **start,
1822 size_t size,
1823 coap_str_const_t *keyword,
1824 oscore_value_t *value) {
1825 const char *begin = *start;
1826 const char *end;
1827 const char *kend;
1828 const char *split;
1829 size_t i;
1830 size_t len;
1831
1832retry:
1833 kend = end = memchr(begin, '\n', size);
1834 if (end == NULL)
1835 return 0;
1836
1837 /* Track beginning of next line */
1838 *start = end + 1;
1839 if (end > begin && end[-1] == '\r')
1840 end--;
1841
1842 if (begin[0] == '#' || (end - begin) == 0) {
1843 /* Skip comment / blank line */
1844 size -= kend - begin + 1;
1845 begin = *start;
1846 goto retry;
1847 }
1848
1849 /* Get in the keyword */
1850 split = memchr(begin, ',', end - begin);
1851 if (split == NULL)
1852 goto bad_entry;
1853
1854 keyword->s = (const uint8_t *)begin;
1855 keyword->length = split - begin;
1856
1857 begin = split + 1;
1858 if ((end - begin) == 0)
1859 goto bad_entry;
1860 /* Get in the encoding */
1861 split = memchr(begin, ',', end - begin);
1862 if (split == NULL)
1863 goto bad_entry;
1864
1865 for (i = 0; oscore_encoding[i].name.s; i++) {
1866 coap_str_const_t temp = { split - begin, (const uint8_t *)begin };
1867
1868 if (coap_string_equal(&temp, &oscore_encoding[i].name)) {
1869 value->encoding = oscore_encoding[i].encoding;
1870 value->encoding_name = (const char *)oscore_encoding[i].name.s;
1871 break;
1872 }
1873 }
1874 if (oscore_encoding[i].name.s == NULL)
1875 goto bad_entry;
1876
1877 begin = split + 1;
1878 if ((end - begin) == 0)
1879 goto bad_entry;
1880 /* Get in the keyword's value */
1881 if (begin[0] == '"') {
1882 split = memchr(&begin[1], '"', end - split - 1);
1883 if (split == NULL)
1884 goto bad_entry;
1885 end = split;
1886 begin++;
1887 }
1888 switch (value->encoding) {
1889 case COAP_ENC_ASCII:
1890 value->u.value_bin =
1891 coap_new_bin_const((const uint8_t *)begin, end - begin);
1892 break;
1893 case COAP_ENC_HEX:
1894 /* Parse the hex into binary */
1895 value->u.value_bin = parse_hex_bin(begin, end);
1896 if (value->u.value_bin == NULL)
1897 goto bad_entry;
1898 break;
1899 case COAP_ENC_INTEGER:
1900 value->u.value_int = atoi(begin);
1901 break;
1902 case COAP_ENC_TEXT:
1903 value->u.value_str.s = (const uint8_t *)begin;
1904 value->u.value_str.length = end - begin;
1905 break;
1906 case COAP_ENC_BOOL:
1907 len = (size_t)(end - begin);
1908 if (len == 4 && memcmp("true", begin, len) == 0)
1909 value->u.value_int = 1;
1910 else if (len == 5 && memcmp("false", begin, len) == 0)
1911 value->u.value_int = 0;
1912 else
1913 goto bad_entry;
1914 break;
1915 case COAP_ENC_LAST:
1916 default:
1917 goto bad_entry;
1918 }
1919 return 1;
1920
1921bad_entry:
1922 coap_log_warn("oscore_conf: Unrecognized configuration entry '%.*s'\n",
1923 (int)(end - begin),
1924 begin);
1925 return -1;
1926}
1927
1928#undef CONFIG_ENTRY
1929#define CONFIG_ENTRY(n, e, t) \
1930 { { sizeof(#n)-1, (const uint8_t *)#n }, e, \
1931 offsetof(coap_oscore_conf_t, n), t }
1932
1933typedef struct oscore_text_mapping_t {
1934 coap_str_const_t text;
1935 int value;
1936} oscore_text_mapping_t;
1937
1938/* Naming as per https://www.iana.org/assignments/cose/cose.xhtml#algorithms */
1939static oscore_text_mapping_t text_aead_alg[] = {
1940 TEXT_MAPPING(AES-CCM-16-64-128, COSE_ALGORITHM_AES_CCM_16_64_128),
1941 TEXT_MAPPING(AES-CCM-16-64-256, COSE_ALGORITHM_AES_CCM_16_64_256),
1942 {{0, NULL}, 0}
1943};
1944
1945static oscore_text_mapping_t text_hkdf_alg[] = {
1946 TEXT_MAPPING(direct+HKDF-SHA-256, COSE_HKDF_ALG_HKDF_SHA_256),
1947 {{0, NULL}, 0}
1948};
1949
1950static struct oscore_config_t {
1951 coap_str_const_t str_keyword;
1952 coap_oscore_coding_t encoding;
1953 size_t offset;
1954 oscore_text_mapping_t *text_mapping;
1955} oscore_config[] = {
1956 CONFIG_ENTRY(master_secret, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
1957 CONFIG_ENTRY(master_salt, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
1958 CONFIG_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
1959 CONFIG_ENTRY(id_context, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
1960 CONFIG_ENTRY(recipient_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
1961 CONFIG_ENTRY(replay_window, COAP_ENC_INTEGER, NULL),
1962 CONFIG_ENTRY(ssn_freq, COAP_ENC_INTEGER, NULL),
1963 CONFIG_ENTRY(aead_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_aead_alg),
1964 CONFIG_ENTRY(hkdf_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_hkdf_alg),
1965 CONFIG_ENTRY(rfc8613_b_1_2, COAP_ENC_BOOL, NULL),
1966 CONFIG_ENTRY(rfc8613_b_2, COAP_ENC_BOOL, NULL),
1967 CONFIG_ENTRY(break_sender_key, COAP_ENC_BOOL, NULL),
1968 CONFIG_ENTRY(break_recipient_key, COAP_ENC_BOOL, NULL),
1969};
1970
1971int
1973 uint32_t i;
1974
1975 if (oscore_conf == NULL)
1976 return 0;
1977
1979 coap_delete_bin_const(oscore_conf->master_salt);
1980 coap_delete_bin_const(oscore_conf->id_context);
1981 coap_delete_bin_const(oscore_conf->sender_id);
1982 for (i = 0; i < oscore_conf->recipient_id_count; i++) {
1983 coap_delete_bin_const(oscore_conf->recipient_id[i]);
1984 }
1986 coap_free_type(COAP_STRING, oscore_conf);
1987 return 1;
1988}
1989
1990static coap_oscore_conf_t *
1991coap_parse_oscore_conf_mem(coap_str_const_t conf_mem) {
1992 const char *start = (const char *)conf_mem.s;
1993 const char *end = start + conf_mem.length;
1994 coap_str_const_t keyword;
1995 oscore_value_t value;
1996 coap_oscore_conf_t *oscore_conf;
1997 int split_ok = -1;
1998
1999 oscore_conf = coap_malloc_type(COAP_STRING, sizeof(coap_oscore_conf_t));
2000 if (oscore_conf == NULL)
2001 return NULL;
2002 memset(oscore_conf, 0, sizeof(coap_oscore_conf_t));
2003
2004 memset(&value, 0, sizeof(value));
2005 /* Preset with defaults */
2007 oscore_conf->ssn_freq = 1;
2009 oscore_conf->hkdf_alg = COSE_HKDF_ALG_HKDF_SHA_256;
2010 oscore_conf->rfc8613_b_1_2 = 1;
2011 oscore_conf->rfc8613_b_2 = 0;
2012 oscore_conf->break_sender_key = 0;
2013 oscore_conf->break_recipient_key = 0;
2014
2015 while (end > start &&
2016 (split_ok = get_split_entry(&start, end - start, &keyword, &value)) > 0) {
2017 size_t i;
2018 size_t j;
2019
2020 for (i = 0; i < sizeof(oscore_config) / sizeof(oscore_config[0]); i++) {
2021 if (coap_string_equal(&oscore_config[i].str_keyword, &keyword) != 0 &&
2022 value.encoding & oscore_config[i].encoding) {
2023 if (coap_string_equal(coap_make_str_const("recipient_id"), &keyword)) {
2024 if (value.u.value_bin->length > 7) {
2025 coap_log_warn("oscore_conf: Maximum size of recipient_id is 7 bytes\n");
2026 goto error_free_value_bin;
2027 }
2028 /* Special case as there are potentially multiple entries */
2029 oscore_conf->recipient_id =
2031 oscore_conf->recipient_id,
2032 sizeof(oscore_conf->recipient_id[0]) *
2033 (oscore_conf->recipient_id_count + 1));
2034 if (oscore_conf->recipient_id == NULL) {
2035 goto error_free_value_bin;
2036 }
2037 oscore_conf->recipient_id[oscore_conf->recipient_id_count++] =
2038 value.u.value_bin;
2039 } else {
2040 coap_bin_const_t *unused_check;
2041
2042 switch (value.encoding) {
2043 case COAP_ENC_HEX:
2044 case COAP_ENC_ASCII:
2045 memcpy(&unused_check,
2046 &(((char *)oscore_conf)[oscore_config[i].offset]),
2047 sizeof(unused_check));
2048 if (unused_check != NULL) {
2049 coap_log_warn("oscore_conf: Keyword '%.*s' duplicated\n",
2050 (int)keyword.length,
2051 (const char *)keyword.s);
2052 goto error_free_value_bin;
2053 }
2054 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2055 &value.u.value_bin,
2056 sizeof(value.u.value_bin));
2057 break;
2058 case COAP_ENC_INTEGER:
2059 case COAP_ENC_BOOL:
2060 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2061 &value.u.value_int,
2062 sizeof(value.u.value_int));
2063 break;
2064 case COAP_ENC_TEXT:
2065 for (j = 0; oscore_config[i].text_mapping[j].text.s != NULL; j++) {
2066 if (coap_string_equal(&value.u.value_str,
2067 &oscore_config[i].text_mapping[j].text)) {
2068 memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
2069 &oscore_config[i].text_mapping[j].value,
2070 sizeof(oscore_config[i].text_mapping[j].value));
2071 break;
2072 }
2073 }
2074 if (oscore_config[i].text_mapping[j].text.s == NULL) {
2075 coap_log_warn("oscore_conf: Keyword '%.*s': value '%.*s' unknown\n",
2076 (int)keyword.length,
2077 (const char *)keyword.s,
2078 (int)value.u.value_str.length,
2079 (const char *)value.u.value_str.s);
2080 goto error;
2081 }
2082 break;
2083 case COAP_ENC_LAST:
2084 default:
2085 assert(0);
2086 break;
2087 }
2088 }
2089 break;
2090 }
2091 }
2092 if (i == sizeof(oscore_config) / sizeof(oscore_config[0])) {
2093 coap_log_warn("oscore_conf: Keyword '%.*s', type '%s' unknown\n",
2094 (int)keyword.length,
2095 (const char *)keyword.s,
2096 value.encoding_name);
2097 if (value.encoding == COAP_ENC_HEX || value.encoding == COAP_ENC_ASCII)
2098 coap_delete_bin_const(value.u.value_bin);
2099 goto error;
2100 }
2101 }
2102 if (split_ok == -1)
2103 goto error;
2104 if (!oscore_conf->master_secret) {
2105 coap_log_warn("oscore_conf: master_secret not defined\n");
2106 goto error;
2107 }
2108 if (!oscore_conf->sender_id) {
2109 coap_log_warn("oscore_conf: sender_id not defined\n");
2110 goto error;
2111 }
2112 if (oscore_conf->sender_id->length > 7) {
2113 coap_log_warn("oscore_conf: Maximum size of sender_id is 7 bytes\n");
2114 goto error;
2115 }
2116 if (oscore_conf->recipient_id && oscore_conf->recipient_id[0]->length > 7) {
2117 coap_log_warn("oscore_conf: Maximum size of recipient_id is 7 bytes\n");
2118 goto error;
2119 }
2120 return oscore_conf;
2121
2122error_free_value_bin:
2123 coap_delete_bin_const(value.u.value_bin);
2124error:
2125 coap_delete_oscore_conf(oscore_conf);
2126 return NULL;
2127}
2128
2129static oscore_ctx_t *
2130coap_oscore_init(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf) {
2131 oscore_ctx_t *osc_ctx = NULL;
2132
2133 if (!coap_crypto_check_cipher_alg(oscore_conf->aead_alg)) {
2134 coap_log_warn("COSE: Cipher Algorithm %d not supported\n",
2135 oscore_conf->aead_alg);
2136 goto error;
2137 }
2138 if (!coap_crypto_check_hkdf_alg(oscore_conf->hkdf_alg)) {
2139 coap_log_warn("COSE: HKDF Algorithm %d not supported\n",
2140 oscore_conf->hkdf_alg);
2141 goto error;
2142 }
2143
2144 osc_ctx = oscore_derive_ctx(c_context, oscore_conf);
2145 if (!osc_ctx) {
2146 coap_log_crit("OSCORE: Could not create Security Context!\n");
2147 goto error;
2148 }
2149
2150 /* Free off the recipient_id array */
2152 oscore_conf->recipient_id = NULL;
2153
2154 /* As all is stored in osc_ctx, oscore_conf is no longer needed */
2155 coap_free_type(COAP_STRING, oscore_conf);
2156
2157 /* return default first context */
2158 return osc_ctx;
2159
2160error:
2161 /* Remove from linked chain */
2162 oscore_remove_context(c_context, osc_ctx);
2163
2164 coap_delete_oscore_conf(oscore_conf);
2165 return NULL;
2166}
2167
2168void
2170 oscore_free_contexts(c_context);
2171}
2172
2173void
2176}
2177
2180 coap_oscore_save_seq_num_t save_seq_num_func,
2181 void *save_seq_num_func_param,
2182 uint64_t start_seq_num) {
2183 coap_oscore_conf_t *oscore_conf = coap_parse_oscore_conf_mem(conf_mem);
2184
2185 if (oscore_conf == NULL)
2186 return NULL;
2187
2188 oscore_conf->save_seq_num_func = save_seq_num_func;
2189 oscore_conf->save_seq_num_func_param = save_seq_num_func_param;
2190 oscore_conf->start_seq_num = start_seq_num;
2191 coap_log_oscore("Start Seq no %" PRIu64 "\n", start_seq_num);
2192 return oscore_conf;
2193}
2194
2195/*
2196 * Compute the size of the potential OSCORE overhead
2197 */
2198size_t
2200 size_t overhead = 0;
2201 oscore_recipient_ctx_t *rcp_ctx = session->recipient_ctx;
2202 oscore_ctx_t *osc_ctx = rcp_ctx ? rcp_ctx->osc_ctx : NULL;
2203 coap_opt_iterator_t opt_iter;
2204 coap_opt_t *option;
2205
2206 if (osc_ctx == NULL)
2207 return 0;
2208
2209 /* Protected code held in inner PDU as token */
2210 overhead += 1;
2211
2212 /* Observe option (creates inner and outer */
2213 option = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
2214 if (option) {
2215 /* Assume delta is small */
2216 overhead += 2 + coap_opt_length(option);
2217 }
2218
2219 /* Proxy URI option Split - covered by coap_rebuild_pdu_for_proxy () */
2220
2221 /* OSCORE option */
2222 /* Option header */
2223 overhead += 1 +
2224 /* Partial IV (64 bits max)*/
2225 8 +
2226 /* kid context */
2227 (osc_ctx->id_context ? osc_ctx->id_context->length : 0) +
2228 /* kid */
2229 osc_ctx->sender_context->sender_id->length;
2230
2231 /* AAD overhead */
2232 overhead += AES_CCM_TAG;
2233
2234 /* End of options marker */
2235 overhead += 1;
2236
2237 return overhead;
2238}
2239
2240COAP_API int
2242 coap_bin_const_t *recipient_id) {
2243 int ret;
2244
2245 coap_lock_lock(return 0);
2246 ret = coap_new_oscore_recipient_lkd(context, recipient_id);
2248 return ret;
2249}
2250
2251int
2253 coap_bin_const_t *recipient_id) {
2255 if (context->p_osc_ctx == NULL)
2256 return 0;
2257 if (oscore_add_recipient(context->p_osc_ctx, recipient_id, 0) == NULL)
2258 return 0;
2259 return 1;
2260}
2261
2262COAP_API int
2264 coap_bin_const_t *recipient_id) {
2265 int ret;
2266
2267 if (!context || !recipient_id)
2268 return 0;
2269 coap_lock_lock(return 0);
2270 ret = coap_delete_oscore_recipient_lkd(context, recipient_id);
2272 return ret;
2273}
2274
2275int
2277 coap_bin_const_t *recipient_id) {
2279 if (context->p_osc_ctx == NULL)
2280 return 0;
2281 return oscore_delete_recipient(context->p_osc_ctx, recipient_id);
2282}
2283
2286#else /* !COAP_OSCORE_SUPPORT */
2287int
2289 return 0;
2290}
2291
2294 const coap_address_t *local_if,
2295 const coap_address_t *server,
2296 coap_proto_t proto,
2297 coap_oscore_conf_t *oscore_conf) {
2298 (void)ctx;
2299 (void)local_if;
2300 (void)server;
2301 (void)proto;
2302 (void)oscore_conf;
2303 return NULL;
2304}
2305
2308 const coap_address_t *local_if,
2309 const coap_address_t *server,
2310 coap_proto_t proto,
2311 coap_oscore_conf_t *oscore_conf,
2312 void *app_data,
2314 coap_str_const_t *ws_host) {
2315 (void)ctx;
2316 (void)local_if;
2317 (void)server;
2318 (void)proto;
2319 (void)oscore_conf;
2320 (void)app_data;
2321 (void)callback;
2322 (void)ws_host;
2323 return NULL;
2324}
2325
2328 const coap_address_t *local_if,
2329 const coap_address_t *server,
2330 coap_proto_t proto,
2331 coap_dtls_cpsk_t *psk_data,
2332 coap_oscore_conf_t *oscore_conf) {
2333 (void)ctx;
2334 (void)local_if;
2335 (void)server;
2336 (void)proto;
2337 (void)psk_data;
2338 (void)oscore_conf;
2339 return NULL;
2340}
2341
2344 const coap_address_t *local_if,
2345 const coap_address_t *server,
2346 coap_proto_t proto,
2347 coap_dtls_cpsk_t *psk_data,
2348 coap_oscore_conf_t *oscore_conf,
2349 void *app_data,
2351 coap_str_const_t *ws_host) {
2352 (void)ctx;
2353 (void)local_if;
2354 (void)server;
2355 (void)proto;
2356 (void)psk_data;
2357 (void)oscore_conf;
2358 (void)app_data;
2359 (void)callback;
2360 (void)ws_host;
2361 return NULL;
2362}
2363
2366 const coap_address_t *local_if,
2367 const coap_address_t *server,
2368 coap_proto_t proto,
2369 coap_dtls_pki_t *pki_data,
2370 coap_oscore_conf_t *oscore_conf) {
2371 (void)ctx;
2372 (void)local_if;
2373 (void)server;
2374 (void)proto;
2375 (void)pki_data;
2376 (void)oscore_conf;
2377 return NULL;
2378}
2379
2382 const coap_address_t *local_if,
2383 const coap_address_t *server,
2384 coap_proto_t proto,
2385 coap_dtls_pki_t *pki_data,
2386 coap_oscore_conf_t *oscore_conf,
2387 void *app_data,
2389 coap_str_const_t *ws_host) {
2390 (void)ctx;
2391 (void)local_if;
2392 (void)server;
2393 (void)proto;
2394 (void)pki_data;
2395 (void)oscore_conf;
2396 (void)app_data;
2397 (void)callback;
2398 (void)ws_host;
2399 return NULL;
2400}
2401
2402int
2404 coap_oscore_conf_t *oscore_conf) {
2405 (void)context;
2406 (void)oscore_conf;
2407 return 0;
2408}
2409
2412 coap_oscore_save_seq_num_t save_seq_num_func,
2413 void *save_seq_num_func_param,
2414 uint64_t start_seq_num) {
2415 (void)conf_mem;
2416 (void)save_seq_num_func;
2417 (void)save_seq_num_func_param;
2418 (void)start_seq_num;
2419 return NULL;
2420}
2421
2422int
2424 (void)oscore_conf;
2425 return 0;
2426}
2427
2428int
2430 coap_bin_const_t *recipient_id) {
2431 (void)context;
2432 (void)recipient_id;
2433 return 0;
2434}
2435
2436int
2438 coap_bin_const_t *recipient_id) {
2439 (void)context;
2440 (void)recipient_id;
2441 return 0;
2442}
2443
2444#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_realloc_type(coap_memory_tag_t type, void *p, size_t size)
Reallocates a chunk p of bytes created by coap_malloc_type() or coap_realloc_type() and returns a poi...
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...
Definition coap_option.h:43
static int coap_uri_scheme_is_secure(const coap_uri_t *uri)
Definition coap_uri.h:86
@ 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:1108
#define COAP_BLOCK_CACHE_RESPONSE
Definition coap_block.h:73
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:190
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:5036
uint16_t coap_new_message_id_lkd(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
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:1885
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:3154
#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_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_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:793
#define coap_log_oscore(...)
Definition coap_debug.h:132
#define coap_log_warn(...)
Definition coap_debug.h:108
#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.
size_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)
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)
size_t oscore_encode_option_value(uint8_t *option_buffer, size_t option_buf_len, cose_encrypt0_t *cose, uint8_t group, uint8_t appendix_b_2)
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_bin_const_t *rid, uint32_t break_key)
oscore_add_recipient - add in recipient information
#define OSCORE_SEQ_MAX
#define AES_CCM_TAG
int oscore_decode_option_value(const uint8_t *option_value, size_t option_len, cose_encrypt0_t *cose)
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)
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_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.
oscore_ctx_t * oscore_find_context(const coap_context_t *c_context, 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)
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...
size_t coap_oscore_overhead(coap_session_t *session, coap_pdu_t *pdu)
Determine the additional data size requirements for adding in OSCORE.
@ OSCORE_MODE_SINGLE
Vanilla RFC8613 support.
@ 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_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_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_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 and stop any further ...
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:194
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:641
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:501
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:425
#define COAP_PDU_IS_PING(pdu)
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:1531
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)
Duplicate an existing PDU.
Definition coap_pdu.c:234
#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:307
#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:796
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:135
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:148
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:122
#define COAP_OPTION_IF_MATCH
Definition coap_pdu.h:121
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:140
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:130
#define COAP_OPTION_SIZE2
Definition coap_pdu.h:142
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:141
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:145
#define COAP_DEFAULT_PORT
Definition coap_pdu.h:39
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:134
#define COAP_OPTION_IF_NONE_MATCH
Definition coap_pdu.h:124
#define COAP_OPTION_LOCATION_PATH
Definition coap_pdu.h:127
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:129
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:163
#define COAP_RESPONSE_CLASS(C)
Definition coap_pdu.h:166
coap_proto_t
CoAP protocol types Note: coap_layers_coap[] needs updating if extended.
Definition coap_pdu.h:316
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:330
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:128
#define COAP_OPTION_SIZE1
Definition coap_pdu.h:146
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:368
#define COAP_OPTION_LOCATION_QUERY
Definition coap_pdu.h:138
#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:892
#define COAP_OPTION_RTAG
Definition coap_pdu.h:149
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:126
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:102
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:136
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:269
#define COAP_OPTION_MAXAGE
Definition coap_pdu.h:133
#define COAP_OPTION_ETAG
Definition coap_pdu.h:123
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:144
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:125
#define COAP_OPTION_ECHO
Definition coap_pdu.h:147
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:861
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1651
@ COAP_REQUEST_CODE_POST
Definition coap_pdu.h:334
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:337
@ 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
#define COAP_PROTO_NOT_RELIABLE(p)
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:129
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
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
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:854
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:758
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:299
coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST]
Definition coap_uri.c:56
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:414
The structure used for defining the PKI setup data to be used.
Definition coap_dtls.h:316
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
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.
coap_bin_const_t * sender_id
Sender ID (i.e.
coap_bin_const_t ** recipient_id
Recipient ID (i.e.
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.
uint32_t recipient_id_count
Number of recipient_id entries.
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 block_mode
Zero or more COAP_BLOCK_ or'd options.
coap_proto_t proto
protocol used
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
const char * name
scheme name
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
oscore_mode_t mode
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
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
coap_bin_const_t * sender_key
uint64_t next_seq
Used for ssn_freq updating.