libcoap 4.3.5-develop-5ce12ab
Loading...
Searching...
No Matches
oscore_context.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 * Copyright (c) 2018, SICS, RISE AB
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Institute nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
45
47
48#if COAP_OSCORE_SUPPORT
49
50#include <stdio.h>
51
52/* Move ptr from b to a, and then clear b */
53#define OSC_MOVE_PTR(a,b) do { (a) = (b); (b) = NULL; } while(0)
54
55static int oscore_context_release_recipients(oscore_ctx_t *osc_ctx);
56
57static size_t
58compose_info(uint8_t *buffer,
59 size_t buf_size,
60 cose_alg_t alg,
62 coap_bin_const_t *id_context,
63 coap_str_const_t *type,
64 size_t out_len) {
65 size_t ret = 0;
66 size_t rem_size = buf_size;
67
68 ret += oscore_cbor_put_array(&buffer, &rem_size, 5);
69 ret += oscore_cbor_put_bytes(&buffer,
70 &rem_size,
71 id ? id->s : NULL,
72 id ? id->length : 0);
73 if (id_context != NULL && id_context->length > 0) {
74 ret += oscore_cbor_put_bytes(&buffer,
75 &rem_size,
76 id_context->s,
77 id_context->length);
78 } else {
79 ret += oscore_cbor_put_nil(&buffer, &rem_size);
80 }
81 ret += oscore_cbor_put_unsigned(&buffer, &rem_size, alg);
82 ret += oscore_cbor_put_text(&buffer,
83 &rem_size,
84 (const char *)type->s,
85 type->length);
86 ret += oscore_cbor_put_unsigned(&buffer, &rem_size, out_len);
87 return ret;
88}
89
90uint8_t
91oscore_bytes_equal(uint8_t *a_ptr,
92 uint8_t a_len,
93 uint8_t *b_ptr,
94 uint8_t b_len) {
95 if (a_len != b_len) {
96 return 0;
97 }
98
99 if (memcmp(a_ptr, b_ptr, a_len) == 0) {
100 return 1;
101 } else {
102 return 0;
103 }
104}
105
106static void
107oscore_enter_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx) {
108 if (c_context->p_osc_ctx) {
109 oscore_ctx_t *head = c_context->p_osc_ctx;
110 oscore_ctx_t *prev = head;
111 oscore_ctx_t *next = head->next;
112
113 /* verify if oscore context is already attached */
114 if (head == osc_ctx) {
115 return;
116 }
117 while (next != head) {
118 if (next == osc_ctx) {
119 return;
120 }
121 prev = next;
122 next = next->next;
123 }
124 prev->next = osc_ctx;
125 osc_ctx->next = head;
126 } else {
127 c_context->p_osc_ctx = osc_ctx;
128 osc_ctx->next = osc_ctx;
129 }
130}
131
132static void
133oscore_free_recipient_ctx(oscore_recipient_ctx_t *rcp_ctx) {
134 if (rcp_ctx == NULL)
135 return;
136
137 assert(rcp_ctx->ref > 0);
138 if (--rcp_ctx->ref > 0) {
139 return;
140 }
141
142 /* remove recipient from oscore context chain if attached */
143 if (rcp_ctx->osc_ctx) {
144 if (rcp_ctx->osc_ctx->recipient_chain == rcp_ctx) {
145 rcp_ctx->osc_ctx->recipient_chain = rcp_ctx->next_recipient;
146 } else {
148
149 while (prev && prev->next_recipient != rcp_ctx) {
150 prev = prev->next_recipient;
151 }
152 if (prev) {
153 prev->next_recipient = rcp_ctx->next_recipient;
154 }
155 }
156 }
157
161}
162
163void
165
166 if (snd_ctx == NULL)
167 return;
171}
172
173void
175 if (osc_ctx == NULL)
176 return;
177
179
180 while (osc_ctx->recipient_chain) {
182
183 oscore_free_recipient_ctx(osc_ctx->recipient_chain);
184 osc_ctx->recipient_chain = next;
185 }
186
192}
193
194void
196 while (c_context->p_osc_ctx) {
197 oscore_ctx_t *osc_ctx = c_context->p_osc_ctx;
198
199 if (osc_ctx->next == osc_ctx) {
200 c_context->p_osc_ctx = NULL;
201 } else {
202 oscore_ctx_t *tail = osc_ctx;
203 c_context->p_osc_ctx = osc_ctx->next;
204 while (tail->next != osc_ctx) {
205 tail = tail->next;
206 }
207 tail->next = c_context->p_osc_ctx;
208 }
209 osc_ctx->next = NULL;
210
211 /*
212 * Verify if all recipients can be released, if not
213 * defer freeing of context until later when all recipients are released.
214 * The oscore context is flagged as ready to be freed by removing
215 * the oscore context from the coap context.
216 */
217 if (oscore_context_release_recipients(osc_ctx) > 0) {
218 oscore_free_context(osc_ctx);
219 }
220 }
221}
222
235static int
236oscore_context_release_recipients(oscore_ctx_t *osc_ctx) {
237 int ok = 1;
238
241
242 while (next != NULL) {
243 /* if reference is 1 or lower, ready to be freed */
244 if (next->ref <= 1) {
245 oscore_recipient_ctx_t *to_free = next;
246 next = next->next_recipient;
247 oscore_free_recipient_ctx(to_free);
248 continue;
249 }
250
251 /*
252 * Recipient is still attached to an oscore association or session,
253 * can not be freed yet. Decrease ref counter and keep in chain.
254 */
255 next->ref--;
256 ok = 0;
257
258 /* keep recipient in chain, since still referenced by other
259 session or association */
260 if (prev != NULL) {
261 prev->next_recipient = next;
262 } else {
263 osc_ctx->recipient_chain = next;
264 }
265 prev = next;
266 next = next->next_recipient;
267 }
268 return ok;
269}
270
271int
273 oscore_ctx_t *head = c_context->p_osc_ctx;
274 oscore_ctx_t *prev;
275 oscore_ctx_t *next;
276
277 if (head == NULL)
278 return 0;
279
280 prev = head;
281 next = head;
282 do {
283 if (next == osc_ctx) {
284 if (next->next == next) {
285 c_context->p_osc_ctx = NULL;
286 } else {
287 while (prev->next != next) {
288 prev = prev->next;
289 }
290 prev->next = next->next;
291 if (next == c_context->p_osc_ctx)
292 c_context->p_osc_ctx = next->next;
293 }
294 next->next = NULL;
295 /*
296 * Only free context if no recipient is still referenced by
297 * an association or session. Otherwise defer context to be
298 * freed after all references are resolved.
299 */
300 if (oscore_context_release_recipients(osc_ctx) <= 0) {
301 return 2;
302 }
303
304 /* all related recipient ctx attachments are released */
305 osc_ctx->recipient_chain = NULL;
306 oscore_free_context(osc_ctx);
307 return 1;
308 }
309 next = next->next;
310 } while (next != head);
311 return 0;
312}
313
314/*
315 * oscore_find_context
316 * Finds OSCORE context for rcpkey_id and optional ctxkey_id
317 * rcpkey_id can be 0 length.
318 * Updates recipient_ctx.
319 */
322 const coap_bin_const_t rcpkey_id,
323 const coap_bin_const_t *ctxkey_id,
324 uint8_t *oscore_r2,
325 oscore_recipient_ctx_t **recipient_ctx) {
326 if (session->context->oscore_find_cb != NULL) {
327 oscore_ctx_t *tmp_ctx = NULL;
328 coap_oscore_conf_t *oscore_conf;
329
330 if (session->recipient_ctx) {
331 tmp_ctx = session->recipient_ctx->osc_ctx;
332 if (!tmp_ctx) {
333 return NULL;
334 }
335 if (coap_binary_equal(session->recipient_ctx->recipient_id, &rcpkey_id)) {
336 if (oscore_r2) {
337 if (tmp_ctx->id_context != NULL &&
338 tmp_ctx->id_context->length > 8) {
339 if (memcmp(tmp_ctx->id_context->s, oscore_r2, 8) == 0) {
340 goto match;
341 }
342 }
343 } else if (ctxkey_id) {
344 if (session->recipient_ctx->osc_ctx->id_context != NULL) {
345 if (!coap_binary_equal(tmp_ctx->id_context, ctxkey_id)) {
346 return NULL;
347 }
348 } else if (ctxkey_id->length > 0) {
349 return NULL;
350 }
351 }
352match:
353 *recipient_ctx = session->recipient_ctx;
354 return session->recipient_ctx->osc_ctx;
355 }
356 }
357 coap_lock_callback_ret(oscore_conf, session->context->oscore_find_cb(session,
358 &rcpkey_id,
359 ctxkey_id));
360
361 if (oscore_conf) {
362 tmp_ctx = coap_init_oscore_context_from_conf(oscore_conf);
363 }
364
365 if (tmp_ctx != NULL) {
366 /*
367 * find matching recipient and remove others if multiple recipients
368 * have been provided. ensures unneeded memory is freed early
369 * to prevent memory leaks and unnecessary memory usage.
370 */
371 if (tmp_ctx->recipient_chain != NULL &&
372 tmp_ctx->recipient_chain->next_recipient != NULL) {
373 oscore_recipient_ctx_t *rcp_ctx = tmp_ctx->recipient_chain;
374 oscore_recipient_ctx_t *ref_ctx = NULL;
375 while (rcp_ctx != NULL) {
376 ref_ctx = rcp_ctx;
377 rcp_ctx = rcp_ctx->next_recipient;
378 if (coap_binary_equal(ref_ctx->recipient_id, &rcpkey_id)) {
379 ref_ctx->next_recipient = NULL;
380 *recipient_ctx = ref_ctx;
381 } else {
384 coap_free_type(COAP_OSCORE_REC, (void *)ref_ctx);
385 }
386 }
387 } else {
388 *recipient_ctx = tmp_ctx->recipient_chain;
389 }
390 tmp_ctx->recipient_chain = *recipient_ctx;
391 const coap_bool_t already_attached = session->recipient_ctx == *recipient_ctx;
392 coap_oscore_session_set_recipient_ctx(session, *recipient_ctx);
393 /* Remove the tmp_ctx reference */
394 if (*recipient_ctx && !already_attached)
395 (*recipient_ctx)->ref--;
396 return tmp_ctx;
397 }
398 }
399
400 oscore_ctx_t *pt = session->context->p_osc_ctx;
401
402 *recipient_ctx = NULL;
403 assert(rcpkey_id.length == 0 || rcpkey_id.s != NULL);
404 if (pt == NULL)
405 return NULL;
406 do {
407 int ok = 0;
409
410 while (rpt) {
411 ok = 0;
412 if (rpt->recipient_id && rcpkey_id.length == rpt->recipient_id->length) {
413 if (rcpkey_id.length != 0)
414 ok = memcmp(rpt->recipient_id->s, rcpkey_id.s, rcpkey_id.length) != 0;
415 if (oscore_r2) {
416 if (pt->id_context != NULL && pt->id_context->length > 8) {
417 ok = ok + (memcmp(pt->id_context->s, oscore_r2, 8) != 0);
418 } else {
419 ok += 1;
420 }
421 } else if (ctxkey_id) {
422 if (pt->id_context != NULL) {
423 if (ctxkey_id->length != pt->id_context->length)
424 ok += 1;
425 else
426 ok = ok + (memcmp(pt->id_context->s,
427 ctxkey_id->s,
428 ctxkey_id->length) != 0);
429 } else if (ctxkey_id->length > 0)
430 ok += 1;
431 }
432 if (ok == 0) {
433 /* optional id context and recipient id are the same */
434 *recipient_ctx = rpt;
435 return pt; /* OSCORE context found */
436 }
437 }
438 rpt = rpt->next_recipient;
439 } /* while rpt */
440 pt = pt->next;
441 } while (pt != session->context->p_osc_ctx);
442 return NULL;
443}
444
445#define OSCORE_LOG_SIZE 16
446void
448 const char *name,
449 coap_bin_const_t *value) {
450 size_t i;
451
452 if (value == NULL) {
453 coap_log(level, " %-16s\n", name);
454 return;
455 }
456 if (value->length == 0) {
457 coap_log(level, " %-16s <>\n", name);
458 return;
459 }
460 if (coap_get_log_level() >= level) {
461 for (i = 0; i < value->length; i += OSCORE_LOG_SIZE) {
462 char number[3 * OSCORE_LOG_SIZE + 4];
463
464 oscore_convert_to_hex(&value->s[i],
465 value->length - i > OSCORE_LOG_SIZE ?
466 OSCORE_LOG_SIZE : value->length - i,
467 number,
468 sizeof(number));
469 coap_log(level, " %-16s %s\n", i == 0 ? name : "", number);
470 }
471 }
472}
473
474void
475oscore_log_int_value(coap_log_t level, const char *name, int value) {
476 coap_log(level, " %-16s %2d\n", name, value);
477}
478
479void
480oscore_log_char_value(coap_log_t level, const char *name, const char *value) {
481 coap_log(level, " %-16s %s\n", name, value);
482}
483
484void
485oscore_convert_to_hex(const uint8_t *src,
486 size_t src_len,
487 char *dest,
488 size_t dst_len) {
489 /*
490 * Last output character will be '\000'
491 * (If output undersized, add trailing ... to indicate this.
492 */
493 size_t space = (dst_len - 4) / 3;
494 uint32_t qq;
495
496 for (qq = 0; qq < src_len && qq < space; qq++) {
497 char tmp = src[qq] >> 4;
498 if (tmp > 9)
499 tmp = tmp + 0x61 - 10;
500 else
501 tmp = tmp + 0x30;
502 dest[qq * 3] = tmp;
503 tmp = src[qq] & 0xf;
504 if (tmp > 9)
505 tmp = tmp + 0x61 - 10;
506 else
507 tmp = tmp + 0x30;
508 dest[qq * 3 + 1] = tmp;
509 dest[qq * 3 + 2] = 0x20;
510 }
511 if (qq != src_len) {
512 dest[qq * 3] = '.';
513 dest[qq * 3 + 1] = '.';
514 dest[qq * 3 + 2] = '.';
515 qq++;
516 }
517 dest[qq * 3] = 0;
518}
519
522 coap_bin_const_t *salt,
523 coap_bin_const_t *ikm,
524 cose_alg_t aead_alg,
526 coap_str_const_t *type,
527 size_t out_len) {
528 uint8_t info_buffer[80];
529 size_t info_len;
530 coap_bin_const_t *hkdf;
531 uint8_t *hkdf_tmp = coap_malloc_type(COAP_STRING, out_len);
532
533 if (hkdf_tmp == NULL)
534 return NULL;
535
536 info_len = compose_info(info_buffer,
537 sizeof(info_buffer),
538 aead_alg,
539 id,
540 osc_ctx->id_context,
541 type,
542 out_len);
543 if (info_len == 0 || info_len > sizeof(info_buffer)) {
544 coap_free_type(COAP_STRING, hkdf_tmp);
545 return NULL;
546 }
547
548 oscore_hkdf(osc_ctx->hkdf_alg,
549 salt,
550 ikm,
551 info_buffer,
552 info_len,
553 hkdf_tmp,
554 out_len);
555 hkdf = coap_new_bin_const(hkdf_tmp, out_len);
556 coap_free_type(COAP_STRING, hkdf_tmp);
557 return hkdf;
558}
559
560static void
561oscore_log_context(oscore_ctx_t *osc_ctx, const char *heading) {
562#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_OSCORE
563 (void)osc_ctx;
564 (void)heading;
565#else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
567 char buffer[30];
569 size_t count = 0;
570
571 coap_log_oscore("%s\n", heading);
573 cose_get_alg_name(osc_ctx->aead_alg, buffer,
574 sizeof(buffer)));
576 cose_get_hkdf_alg_name(osc_ctx->hkdf_alg, buffer,
577 sizeof(buffer)));
578 oscore_log_hex_value(COAP_LOG_OSCORE, "ID Context", osc_ctx->id_context);
580 "Master Secret",
581 osc_ctx->master_secret);
582 oscore_log_hex_value(COAP_LOG_OSCORE, "Master Salt", osc_ctx->master_salt);
583 oscore_log_hex_value(COAP_LOG_OSCORE, "Common IV", osc_ctx->common_iv);
585 "Sender ID",
586 osc_ctx->sender_context->sender_id);
588 "Sender Key",
589 osc_ctx->sender_context->sender_key);
590 while (next) {
591 snprintf(buffer, sizeof(buffer), "Recipient ID[%zu]", count);
593 buffer,
594 next->recipient_id);
595 snprintf(buffer, sizeof(buffer), "Recipient Key[%zu]", count);
597 buffer,
598 next->recipient_key);
599 count++;
600 next = next->next_recipient;
601 }
602 }
603#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
604}
605
606void
607oscore_update_ctx(oscore_ctx_t *osc_ctx, coap_bin_const_t *id_context) {
608 coap_bin_const_t *temp;
609
610 /* Update with new ID Context */
612 osc_ctx->id_context = id_context;
613
614 /* Update sender_key, recipient_key and common_iv */
615 temp = osc_ctx->sender_context->sender_key;
616 osc_ctx->sender_context->sender_key =
617 oscore_build_key(osc_ctx,
618 osc_ctx->master_salt,
619 osc_ctx->master_secret,
620 osc_ctx->aead_alg,
621 osc_ctx->sender_context->sender_id,
622 coap_make_str_const("Key"),
623 cose_key_len(osc_ctx->aead_alg));
624 if (!osc_ctx->sender_context->sender_key)
625 osc_ctx->sender_context->sender_key = temp;
626 else
628 temp = osc_ctx->recipient_chain->recipient_key;
630 oscore_build_key(osc_ctx,
631 osc_ctx->master_salt,
632 osc_ctx->master_secret,
633 osc_ctx->aead_alg,
635 coap_make_str_const("Key"),
636 cose_key_len(osc_ctx->aead_alg));
637 if (!osc_ctx->recipient_chain->recipient_key)
638 osc_ctx->recipient_chain->recipient_key = temp;
639 else
641 temp = osc_ctx->common_iv;
642 osc_ctx->common_iv = oscore_build_key(osc_ctx,
643 osc_ctx->master_salt,
644 osc_ctx->master_secret,
645 osc_ctx->aead_alg,
646 NULL,
648 cose_nonce_len(osc_ctx->aead_alg));
649 if (!osc_ctx->common_iv)
650 osc_ctx->common_iv = temp;
651 else
653
654 oscore_log_context(osc_ctx, "Updated Common context");
655}
656
659 oscore_ctx_t *o_osc_ctx,
660 coap_bin_const_t *sender_id,
661 coap_bin_const_t *recipient_id,
662 coap_bin_const_t *id_context) {
663 oscore_ctx_t *osc_ctx = NULL;
664 oscore_sender_ctx_t *sender_ctx = NULL;
665 coap_oscore_rcp_conf_t *rcp_conf;
666
668 if (osc_ctx == NULL)
669 goto error;
670 memset(osc_ctx, 0, sizeof(oscore_ctx_t));
671
673 if (sender_ctx == NULL)
674 goto error;
675 memset(sender_ctx, 0, sizeof(oscore_sender_ctx_t));
676
677 osc_ctx->sender_context = sender_ctx;
678 if (o_osc_ctx->master_secret)
679 osc_ctx->master_secret =
681 o_osc_ctx->master_secret->length);
682 if (o_osc_ctx->master_salt)
683 osc_ctx->master_salt = coap_new_bin_const(o_osc_ctx->master_salt->s,
684 o_osc_ctx->master_salt->length);
685 osc_ctx->aead_alg = o_osc_ctx->aead_alg;
686 osc_ctx->hkdf_alg = o_osc_ctx->hkdf_alg;
687 if (id_context)
688 osc_ctx->id_context = coap_new_bin_const(id_context->s, id_context->length);
689 osc_ctx->ssn_freq = o_osc_ctx->ssn_freq;
690 osc_ctx->replay_window_size = o_osc_ctx->replay_window_size;
691 osc_ctx->rfc8613_b_1_2 = o_osc_ctx->rfc8613_b_1_2;
692 osc_ctx->rfc8613_b_2 = o_osc_ctx->rfc8613_b_2;
693 osc_ctx->save_seq_num_func = o_osc_ctx->save_seq_num_func;
695
696 if (o_osc_ctx->master_secret) {
697 /* sender_ key */
698 sender_ctx->sender_key = oscore_build_key(osc_ctx,
699 osc_ctx->master_salt,
700 osc_ctx->master_secret,
701 osc_ctx->aead_alg,
702 sender_id,
703 coap_make_str_const("Key"),
704 cose_key_len(osc_ctx->aead_alg));
705 if (!sender_ctx->sender_key)
706 goto error;
707
708 /* common IV */
709 osc_ctx->common_iv = oscore_build_key(osc_ctx,
710 osc_ctx->master_salt,
711 osc_ctx->master_secret,
712 osc_ctx->aead_alg,
713 NULL,
715 cose_nonce_len(osc_ctx->aead_alg));
716 if (!osc_ctx->common_iv)
717 goto error;
718
719 }
720
721 /*
722 * Need to set the last Sender Seq Num based on ssn_freq
723 * The value should only change if there is a change to ssn_freq
724 * and (potentially) be lower than seq, then save_seq_num_func() is
725 * immediately called on next SSN update.
726 */
727 sender_ctx->next_seq = 0;
728 sender_ctx->seq = 0;
729
730 sender_ctx->sender_id = coap_new_bin_const(sender_id->s, sender_id->length);
731
733 if (rcp_conf == NULL)
734 goto error;
735 memset(rcp_conf, 0, sizeof(coap_oscore_rcp_conf_t));
736 rcp_conf->recipient_id = coap_new_bin_const(recipient_id->s, recipient_id->length);
737 if (rcp_conf->recipient_id == NULL)
738 goto error;
739 /* rcp_conf is released in oscore_add_recipient() */
740 if (oscore_add_recipient(osc_ctx, rcp_conf, 0) == NULL)
741 goto error;
742
743 oscore_log_context(osc_ctx, "New Common context");
744 oscore_enter_context(c_context, osc_ctx);
745
746 return osc_ctx;
747
748error:
749 oscore_free_context(osc_ctx);
750 return NULL;
751}
752
755 oscore_ctx_t *osc_ctx = NULL;
756 oscore_sender_ctx_t *sender_ctx = NULL;
757 coap_oscore_rcp_conf_t *rcp_conf;
758 int ok;
759
761 if (osc_ctx == NULL)
762 goto error;
763 memset(osc_ctx, 0, sizeof(oscore_ctx_t));
764
766 if (sender_ctx == NULL)
767 goto error;
768 memset(sender_ctx, 0, sizeof(oscore_sender_ctx_t));
769
770 osc_ctx->sender_context = sender_ctx;
771 OSC_MOVE_PTR(osc_ctx->master_secret, oscore_conf->master_secret);
772 OSC_MOVE_PTR(osc_ctx->master_salt, oscore_conf->master_salt);
773 osc_ctx->aead_alg = oscore_conf->aead_alg;
774 osc_ctx->hkdf_alg = oscore_conf->hkdf_alg;
775 OSC_MOVE_PTR(osc_ctx->id_context, oscore_conf->id_context);
776 osc_ctx->ssn_freq = oscore_conf->ssn_freq ? oscore_conf->ssn_freq : 1;
777 osc_ctx->replay_window_size = oscore_conf->replay_window ?
778 oscore_conf->replay_window :
780 osc_ctx->rfc8613_b_1_2 = oscore_conf->rfc8613_b_1_2;
781 osc_ctx->rfc8613_b_2 = oscore_conf->rfc8613_b_2;
782 osc_ctx->save_seq_num_func = oscore_conf->save_seq_num_func;
783 osc_ctx->save_seq_num_func_param = oscore_conf->save_seq_num_func_param;
784
785 if (osc_ctx->master_secret) {
786 /* sender_ key */
787 if (oscore_conf->break_sender_key)
788 /* Interop testing */
789 sender_ctx->sender_key = oscore_build_key(osc_ctx,
790 osc_ctx->master_salt,
791 osc_ctx->master_secret,
792 osc_ctx->aead_alg,
793 oscore_conf->sender->sender_id,
794 coap_make_str_const("BAD"),
795 cose_key_len(osc_ctx->aead_alg));
796 else
797 sender_ctx->sender_key = oscore_build_key(osc_ctx,
798 osc_ctx->master_salt,
799 osc_ctx->master_secret,
800 osc_ctx->aead_alg,
801 oscore_conf->sender->sender_id,
802 coap_make_str_const("Key"),
803 cose_key_len(osc_ctx->aead_alg));
804 if (!sender_ctx->sender_key)
805 goto error;
806
807 /* common IV */
808 osc_ctx->common_iv = oscore_build_key(osc_ctx,
809 osc_ctx->master_salt,
810 osc_ctx->master_secret,
811 osc_ctx->aead_alg,
812 NULL,
814 cose_nonce_len(osc_ctx->aead_alg));
815 if (!osc_ctx->common_iv)
816 goto error;
817
818 }
819
820 /*
821 * Need to set the last Sender Seq Num based on ssn_freq
822 * The value should only change if there is a change to ssn_freq
823 * and (potentially) be lower than seq, then save_seq_num_func() is
824 * immediately called on next SSN update.
825 */
826 sender_ctx->next_seq = oscore_conf->start_seq_num -
827 (oscore_conf->start_seq_num % (oscore_conf->ssn_freq > 0 ? oscore_conf->ssn_freq : 1));
828
829 sender_ctx->seq = oscore_conf->start_seq_num;
830 if (oscore_conf->sender) {
831 OSC_MOVE_PTR(sender_ctx->sender_id, oscore_conf->sender->sender_id);
832 coap_free_type(COAP_STRING, oscore_conf->sender);
833 oscore_conf->sender = NULL;
834 }
835
836 rcp_conf = oscore_conf->recipient_chain;
837 ok = 1;
838 while (rcp_conf) {
839 coap_oscore_rcp_conf_t *rcp_next = rcp_conf->next_recipient;
840
841 /* rcp_conf is released in oscore_add_recipient() */
842 if (oscore_add_recipient(osc_ctx, rcp_conf,
843 oscore_conf->break_recipient_key) == NULL) {
844 coap_log_warn("OSCORE: Failed to add Client ID\n");
845 ok = 0;
846 }
847 rcp_conf = rcp_next;
848 }
849 oscore_conf->recipient_chain = NULL;
850 if (!ok)
851 goto error;
852
853 oscore_log_context(osc_ctx, "Common context");
854 return osc_ctx;
855error:
856 oscore_free_context(osc_ctx);
857 return NULL;
858}
859
860int
861oscore_add_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx) {
862 oscore_enter_context(c_context, osc_ctx);
863 return 1;
864}
865
866int
868 return osc_ctx->next != NULL;
869}
870
872oscore_derive_ctx(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf) {
873 oscore_ctx_t *osc_ctx = oscore_derive_ctx_from_conf(oscore_conf);
874 oscore_enter_context(c_context, osc_ctx);
875 return osc_ctx;
876}
877
880 uint32_t break_key) {
881 oscore_recipient_ctx_t *rcp_chain = osc_ctx->recipient_chain;
882 oscore_recipient_ctx_t *rcp_ctx = NULL;
883
884 if (rcp_conf->recipient_id->length > 7) {
885 coap_log_warn("oscore_add_recipient: Maximum size of recipient_id is 7 bytes\n");
886 goto free_rcp_conf;
887 }
888 /* Check this is not a duplicate recipient id */
889 while (rcp_chain) {
890 if (rcp_chain->recipient_id->length == rcp_conf->recipient_id->length &&
891 memcmp(rcp_chain->recipient_id->s, rcp_conf->recipient_id->s,
892 rcp_conf->recipient_id->length) == 0) {
893 goto free_rcp_conf;
894 }
895 rcp_chain = rcp_chain->next_recipient;
896 }
898 sizeof(oscore_recipient_ctx_t));
899 if (rcp_ctx == NULL) {
900 goto free_rcp_conf;
901 }
902 memset(rcp_ctx, 0, sizeof(oscore_recipient_ctx_t));
903
904 if (osc_ctx->master_secret) {
905 if (break_key)
906 /* Interop testing */
907 rcp_ctx->recipient_key = oscore_build_key(osc_ctx,
908 osc_ctx->master_salt,
909 osc_ctx->master_secret,
910 osc_ctx->aead_alg,
911 rcp_conf->recipient_id,
912 coap_make_str_const("BAD"),
913 cose_key_len(osc_ctx->aead_alg));
914 else
915 rcp_ctx->recipient_key = oscore_build_key(osc_ctx,
916 osc_ctx->master_salt,
917 osc_ctx->master_secret,
918 osc_ctx->aead_alg,
919 rcp_conf->recipient_id,
920 coap_make_str_const("Key"),
921 cose_key_len(osc_ctx->aead_alg));
922 if (!rcp_ctx->recipient_key) {
923 goto free_rcp_conf;
924 }
925 }
926 rcp_ctx->silent_server = rcp_conf->silent_server;
927 OSC_MOVE_PTR(rcp_ctx->recipient_id, rcp_conf->recipient_id);
928 if (rcp_conf->window_initialized) {
929 rcp_ctx->last_seq = rcp_conf->last_seq;
930 rcp_ctx->sliding_window = rcp_conf->sliding_window;
931 }
932
933 rcp_ctx->initial_state = 1;
934 rcp_ctx->osc_ctx = osc_ctx;
935
936 rcp_chain = osc_ctx->recipient_chain;
937 rcp_ctx->next_recipient = rcp_chain;
938 osc_ctx->recipient_chain = rcp_ctx;
940 /* All configured values are now in rcp_ctx */
941 coap_free_type(COAP_STRING, rcp_conf);
942 return rcp_ctx;
943
944free_rcp_conf:
947 return NULL;
948}
949
950int
954 while (next) {
955 if (next->recipient_id->length == rid->length &&
956 memcmp(next->recipient_id->s, rid->s, rid->length) == 0) {
957 if (prev != NULL)
958 prev->next_recipient = next->next_recipient;
959 else
960 osc_ctx->recipient_chain = next->next_recipient;
961 oscore_free_recipient_ctx(next);
962 return 1;
963 }
964 prev = next;
965 next = next->next_recipient;
966 }
967 return 0;
968}
969
970void
972 recipient_ctx->ref++;
973}
974
975void
977 oscore_ctx_t *osc_ctx;
978
979 if (recipient_ctx == NULL || *recipient_ctx == NULL)
980 return;
981
982 /* ensure oscore context is freed if not attached to coap context */
983 osc_ctx = (*recipient_ctx)->osc_ctx;
984 oscore_free_recipient_ctx(*recipient_ctx);
985 /*
986 * Free temporary oscore context if not attached to a coap context
987 * and no recipients attached anymore.
988 */
989 if (!oscore_is_context_attached(osc_ctx) && osc_ctx->recipient_chain == NULL) {
990 oscore_free_context(osc_ctx);
991 }
992 *recipient_ctx = NULL;
993}
994
995void
997 if (association) {
999
1000 coap_delete_pdu_lkd(association->sent_pdu);
1001 coap_delete_bin_const(association->token);
1002 coap_delete_bin_const(association->aad);
1003 coap_delete_bin_const(association->nonce);
1004 coap_delete_bin_const(association->partial_iv);
1006 coap_free_type(COAP_STRING, association);
1007 }
1008}
1009
1010int
1012 coap_pdu_t *sent_pdu,
1013 coap_bin_const_t *token,
1014 oscore_recipient_ctx_t *recipient_ctx,
1015 coap_bin_const_t *aad,
1016 coap_bin_const_t *nonce,
1017 coap_bin_const_t *partial_iv,
1018 int is_observe) {
1019 oscore_association_t *association;
1020
1021 association = coap_malloc_type(COAP_STRING, sizeof(oscore_association_t));
1022 if (association == NULL)
1023 return 0;
1024
1025 coap_log_oscore("Association %p created\n", (void *)association);
1026 memset(association, 0, sizeof(oscore_association_t));
1027 coap_oscore_association_set_recipient_ctx(association, recipient_ctx);
1028 association->is_observe = is_observe;
1029 association->just_set_up = 1;
1030
1031 if (sent_pdu) {
1032 size_t size;
1033 const uint8_t *data;
1034
1035 association->sent_pdu = coap_pdu_duplicate_lkd(sent_pdu, session,
1036 token->length, token->s,
1038 if (association->sent_pdu == NULL)
1039 goto error;
1040 if (coap_get_data(sent_pdu, &size, &data)) {
1041 coap_add_data(association->sent_pdu, size, data);
1042 }
1043 }
1044 association->token = coap_new_bin_const(token->s, token->length);
1045 if (association->token == NULL)
1046 goto error;
1047
1048 if (aad) {
1049 association->aad = coap_new_bin_const(aad->s, aad->length);
1050 if (association->aad == NULL)
1051 goto error;
1052 }
1053
1054 if (nonce) {
1055 association->nonce = coap_new_bin_const(nonce->s, nonce->length);
1056 if (association->nonce == NULL)
1057 goto error;
1058 }
1059
1060 if (partial_iv) {
1061 association->partial_iv =
1062 coap_new_bin_const(partial_iv->s, partial_iv->length);
1063 if (association->partial_iv == NULL)
1064 goto error;
1065 }
1066
1067 OSCORE_ASSOCIATIONS_ADD(session->associations, association);
1068 return 1;
1069
1070error:
1071 oscore_free_association(association);
1072 return 0;
1073}
1074
1077 oscore_association_t *association;
1078
1079 OSCORE_ASSOCIATIONS_FIND(session->associations, token, association);
1080 return association;
1081}
1082
1083int
1085 oscore_association_t *association) {
1086 if (association) {
1087 OSCORE_ASSOCIATIONS_DELETE(session->associations, association);
1088 coap_log_oscore("Association %p deleted\n", (void *)association);
1089 oscore_free_association(association);
1090 return 1;
1091 }
1092 return 0;
1093}
1094
1095void
1097 if (session) {
1098 oscore_association_t *association;
1100
1101 OSCORE_ASSOCIATIONS_ITER_SAFE(session->associations, association, tmp) {
1102 OSCORE_ASSOCIATIONS_DELETE(session->associations, association);
1103 coap_log_oscore("Association %p deleted\n", (void *)association);
1104 oscore_free_association(association);
1105 }
1106 session->associations = NULL;
1107 }
1108}
1109
1110#else /* ! COAP_OSCORE_SUPPORT */
1111
1112#ifdef __clang__
1113/* Make compilers happy that do not like empty modules. As this function is
1114 * never used, we ignore -Wunused-function at the end of compiling this file
1115 */
1116#pragma GCC diagnostic ignored "-Wunused-function"
1117#endif
1118static inline void
1119dummy(void) {
1120}
1121
1122#endif /* ! COAP_OSCORE_SUPPORT */
Library specific build wrapper for coap_internal.h.
@ COAP_OSCORE_COM
Definition coap_mem.h:55
@ COAP_OSCORE_SEN
Definition coap_mem.h:56
@ COAP_OSCORE_REC
Definition coap_mem.h:57
@ COAP_STRING
Definition coap_mem.h:33
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
#define NULL
Definition coap_option.h:30
#define COAP_OSCORE_DEFAULT_REPLAY_WINDOW
#define coap_lock_callback_ret(r, func)
Dummy for no thread-safe code.
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition coap_debug.c:103
#define coap_log_oscore(...)
Definition coap_debug.h:132
coap_log_t
Logging type.
Definition coap_debug.h:56
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log(level,...)
Logging function.
Definition coap_debug.h:290
@ COAP_LOG_OSCORE
Definition coap_debug.h:65
size_t oscore_cbor_put_text(uint8_t **buffer, size_t *buf_size, const char *text, size_t text_len)
size_t oscore_cbor_put_nil(uint8_t **buffer, size_t *buf_size)
size_t oscore_cbor_put_unsigned(uint8_t **buffer, size_t *buf_size, uint64_t value)
size_t oscore_cbor_put_bytes(uint8_t **buffer, size_t *buf_size, const uint8_t *bytes, size_t bytes_len)
size_t oscore_cbor_put_array(uint8_t **buffer, size_t *buf_size, size_t elements)
const char * cose_get_hkdf_alg_name(cose_hkdf_alg_t id, char *buffer, size_t buflen)
size_t cose_nonce_len(cose_alg_t cose_alg)
size_t cose_key_len(cose_alg_t cose_alg)
const char * cose_get_alg_name(cose_alg_t id, char *buffer, size_t buflen)
cose_alg_t
void oscore_reference_recipient_ctx(oscore_recipient_ctx_t *recipient_ctx)
Increment the recipient context reference count.
#define OSCORE_ASSOCIATIONS_ITER_SAFE(e, el, rtmp)
void oscore_convert_to_hex(const uint8_t *src, size_t src_len, char *dest, size_t dst_len)
void coap_oscore_association_set_recipient_ctx(oscore_association_t *association, oscore_recipient_ctx_t *recipient_ctx)
Set the recipient context of an association.
oscore_ctx_t * oscore_derive_ctx_from_conf(coap_oscore_conf_t *oscore_conf)
oscore_derive_ctx_from_conf - derive a osc_ctx from oscore_conf information
int oscore_delete_association(coap_session_t *session, oscore_association_t *association)
oscore_recipient_ctx_t * oscore_add_recipient(oscore_ctx_t *ctx, coap_oscore_rcp_conf_t *rcp_conf, uint32_t break_key)
oscore_add_recipient - add in recipient information
oscore_ctx_t * coap_init_oscore_context_from_conf(coap_oscore_conf_t *oscore_conf)
Initializes an OSCORE context from the given configuration.
int oscore_add_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx)
void oscore_free_sender(oscore_sender_ctx_t *snd_ctx)
void coap_oscore_session_set_recipient_ctx(coap_session_t *session, oscore_recipient_ctx_t *recipient_ctx)
Attach the OSCORE recipient context information to the session.
coap_bin_const_t * oscore_build_key(oscore_ctx_t *osc_ctx, coap_bin_const_t *salt, coap_bin_const_t *ikm, cose_alg_t aead_alg, coap_bin_const_t *id, coap_str_const_t *type, size_t out_len)
int oscore_delete_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid)
#define OSCORE_ASSOCIATIONS_DELETE(r, obj)
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
void oscore_free_context(oscore_ctx_t *osc_ctx)
#define OSCORE_ASSOCIATIONS_ADD(r, obj)
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_free_association(oscore_association_t *association)
int oscore_hkdf(cose_hkdf_alg_t hkdf_alg, coap_bin_const_t *salt, coap_bin_const_t *ikm, uint8_t *info, size_t info_len, uint8_t *okm, size_t okm_len)
Derive the key using HKDF() function.
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)
void oscore_delete_server_associations(coap_session_t *session)
void oscore_log_char_value(coap_log_t level, const char *name, const char *value)
oscore_ctx_t * oscore_find_context(coap_session_t *session, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
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 oscore_log_int_value(coap_log_t level, const char *name, int value)
int oscore_is_context_attached(const oscore_ctx_t *osc_ctx)
Check if oscore context is attached to a the provided context.
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
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_delete_oscore_rcp_conf(coap_oscore_rcp_conf_t *oscore_rcp_conf)
Release all the information associated with the OSCORE complex Recipient configuration.
#define OSCORE_ASSOCIATIONS_FIND(r, k, res)
uint8_t oscore_bytes_equal(uint8_t *a_ptr, uint8_t a_len, uint8_t *b_ptr, uint8_t b_len)
void oscore_release_recipient_ctx(oscore_recipient_ctx_t **recipient_ctx)
Cleanup recipient context, including releasing the oscore context if the oscore context referenced is...
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:197
coap_pdu_t * coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options, coap_bool_t expand_opt_abb)
Duplicate an existing PDU.
Definition coap_pdu.c:237
coap_bool_t
Definition coap_pdu.h:294
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition coap_pdu.c:966
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition coap_pdu.c:935
@ COAP_BOOL_FALSE
Definition coap_pdu.h:295
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition coap_str.c:130
coap_str_const_t * coap_make_str_const(const char *string)
Take the specified byte array (text) and create a coap_str_const_t *.
Definition coap_str.c:70
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition coap_str.c:119
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition coap_str.h:222
static void dummy(void)
CoAP binary data definition with const data.
Definition coap_str.h:65
size_t length
length of binary data
Definition coap_str.h:66
const uint8_t * s
read-only binary data
Definition coap_str.h:67
The CoAP stack's global state is stored in a coap_context_t object.
The structure used to hold the OSCORE configuration information.
void * save_seq_num_func_param
Passed to save_seq_num_func().
uint32_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
cose_hkdf_alg_t hkdf_alg
Set to one of COSE_HKDF_ALG_*.
uint32_t break_sender_key
1 if sender key to be broken, else 0
coap_oscore_snd_conf_t * sender
The sender - i.e.
coap_oscore_rcp_conf_t * recipient_chain
The recipients as a chain.
uint32_t ssn_freq
Sender Seq Num update frequency.
coap_oscore_save_seq_num_t save_seq_num_func
Called every seq num change.
uint32_t rfc8613_b_1_2
1 if rfc8613 B.1.2 enabled else 0
uint64_t start_seq_num
Used for ssn_freq updating.
uint32_t break_recipient_key
1 if recipient key to be broken, else 0
coap_bin_const_t * master_secret
Common Master Secret.
cose_alg_t aead_alg
Set to one of COSE_ALGORITHM_AES*.
coap_bin_const_t * master_salt
Common Master Salt.
uint32_t replay_window
Replay window size Use COAP_OSCORE_DEFAULT_REPLAY_WINDOW.
coap_bin_const_t * id_context
Common ID context.
The structure used to hold the OSCORE Recipient configuration.
int silent_server
1 if server is likely to be silent else 0
coap_bin_const_t * recipient_id
Recipient ID (i.e.
uint64_t last_seq
Highest sequence number used for this recipient.
uint8_t window_initialized
Contains if the sliding window is initialized 1 if initialized, 0 otherwise.
struct coap_oscore_rcp_conf_t * next_recipient
Used to maintain the chain.
uint64_t sliding_window
bitfield sequence counter window
coap_bin_const_t * sender_id
Sender ID (i.e.
structure for CoAP PDUs
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_context_t * context
session's context
CoAP string data definition with const data.
Definition coap_str.h:47
const uint8_t * s
read-only string data
Definition coap_str.h:49
size_t length
length of string
Definition coap_str.h:48
coap_bin_const_t * obs_partial_iv
coap_bin_const_t * partial_iv
coap_bin_const_t * aad
coap_bin_const_t * nonce
oscore_recipient_ctx_t * recipient_ctx
coap_bin_const_t * token
coap_bin_const_t * master_secret
uint32_t replay_window_size
coap_bin_const_t * common_iv
Derived from Master Secret, Master Salt, and ID Context.
struct oscore_ctx_t * next
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_hkdf_alg_t hkdf_alg
Set to one of COSE_HKDF_ALG_*.
cose_alg_t aead_alg
Set to one of COSE_ALGORITHM_AES*.
uint8_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
coap_bin_const_t * master_salt
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.
oscore_recipient_ctx_t * next_recipient
This field allows recipient chaining.
unsigned ref
Reference counter to keep track of linked associations / active sessions.
coap_bin_const_t * recipient_key
coap_bin_const_t * recipient_id
coap_bin_const_t * sender_id
uint64_t seq
Sender Sequence Number.
coap_bin_const_t * sender_key
uint64_t next_seq
Used for ssn_freq updating.