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