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