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