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
33 /**
34 * @file oscore_context.c
35 * @brief An implementation of the Object Security for Constrained RESTful
36 * Environments (RFC 8613).
37 *
38 * \author Martin Gunnarsson <martin.gunnarsson@ri.se>
39 * adapted for libcoap
40 * Peter van der Stok <consultancy@vanderstok.org>
41 * on request of Fairhair alliance
42 * adapted for libcoap integration
43 * Jon Shallow <supjps-libcoap@jpshallow.com>
44 */
45
46 #include "coap3/coap_internal.h"
47
48 #include <stdio.h>
49
50 static void oscore_enter_context(coap_context_t *c_context,
51 oscore_ctx_t *osc_ctx);
52
53 static size_t
compose_info(uint8_t * buffer,size_t buf_size,uint8_t alg,coap_bin_const_t * id,coap_bin_const_t * id_context,coap_str_const_t * type,size_t out_len)54 compose_info(uint8_t *buffer,
55 size_t buf_size,
56 uint8_t alg,
57 coap_bin_const_t *id,
58 coap_bin_const_t *id_context,
59 coap_str_const_t *type,
60 size_t out_len) {
61 size_t ret = 0;
62 size_t rem_size = buf_size;
63
64 ret += oscore_cbor_put_array(&buffer, &rem_size, 5);
65 ret += oscore_cbor_put_bytes(&buffer,
66 &rem_size,
67 id ? id->s : NULL,
68 id ? id->length : 0);
69 if (id_context != NULL && id_context->length > 0) {
70 ret += oscore_cbor_put_bytes(&buffer,
71 &rem_size,
72 id_context->s,
73 id_context->length);
74 } else {
75 ret += oscore_cbor_put_nil(&buffer, &rem_size);
76 }
77 ret += oscore_cbor_put_unsigned(&buffer, &rem_size, alg);
78 ret += oscore_cbor_put_text(&buffer,
79 &rem_size,
80 (const char *)type->s,
81 type->length);
82 ret += oscore_cbor_put_unsigned(&buffer, &rem_size, out_len);
83 return ret;
84 }
85
86 uint8_t
oscore_bytes_equal(uint8_t * a_ptr,uint8_t a_len,uint8_t * b_ptr,uint8_t b_len)87 oscore_bytes_equal(uint8_t *a_ptr,
88 uint8_t a_len,
89 uint8_t *b_ptr,
90 uint8_t b_len) {
91 if (a_len != b_len) {
92 return 0;
93 }
94
95 if (memcmp(a_ptr, b_ptr, a_len) == 0) {
96 return 1;
97 } else {
98 return 0;
99 }
100 }
101
102 static void
oscore_enter_context(coap_context_t * c_context,oscore_ctx_t * osc_ctx)103 oscore_enter_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx) {
104 if (c_context->p_osc_ctx) {
105 oscore_ctx_t *prev = c_context->p_osc_ctx;
106 oscore_ctx_t *next = c_context->p_osc_ctx->next;
107
108 while (next) {
109 prev = next;
110 next = next->next;
111 }
112 prev->next = osc_ctx;
113 } else
114 c_context->p_osc_ctx = osc_ctx;
115 }
116
117 static void
oscore_free_recipient(oscore_recipient_ctx_t * recipient)118 oscore_free_recipient(oscore_recipient_ctx_t *recipient) {
119 coap_delete_bin_const(recipient->recipient_id);
120 coap_delete_bin_const(recipient->recipient_key);
121 coap_free_type(COAP_OSCORE_REC, recipient);
122 }
123
124 void
oscore_free_context(oscore_ctx_t * osc_ctx)125 oscore_free_context(oscore_ctx_t *osc_ctx) {
126 if (osc_ctx == NULL)
127 return;
128 if (osc_ctx->sender_context) {
129 coap_delete_bin_const(osc_ctx->sender_context->sender_id);
130 coap_delete_bin_const(osc_ctx->sender_context->sender_key);
131 coap_free_type(COAP_OSCORE_SEN, osc_ctx->sender_context);
132 }
133
134 while (osc_ctx->recipient_chain) {
135 oscore_recipient_ctx_t *next = osc_ctx->recipient_chain->next_recipient;
136
137 oscore_free_recipient(osc_ctx->recipient_chain);
138 osc_ctx->recipient_chain = next;
139 }
140
141 coap_delete_bin_const(osc_ctx->master_secret);
142 coap_delete_bin_const(osc_ctx->master_salt);
143 coap_delete_bin_const(osc_ctx->id_context);
144 coap_delete_bin_const(osc_ctx->common_iv);
145 coap_free_type(COAP_OSCORE_COM, osc_ctx);
146 }
147
148 void
oscore_free_contexts(coap_context_t * c_context)149 oscore_free_contexts(coap_context_t *c_context) {
150 while (c_context->p_osc_ctx) {
151 oscore_ctx_t *osc_ctx = c_context->p_osc_ctx;
152
153 c_context->p_osc_ctx = osc_ctx->next;
154
155 oscore_free_context(osc_ctx);
156 }
157 }
158
159 int
oscore_remove_context(coap_context_t * c_context,oscore_ctx_t * osc_ctx)160 oscore_remove_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx) {
161 oscore_ctx_t *prev = NULL;
162 oscore_ctx_t *next = c_context->p_osc_ctx;
163 while (next) {
164 if (next == osc_ctx) {
165 if (prev != NULL)
166 prev->next = next->next;
167 else
168 c_context->p_osc_ctx = next->next;
169 oscore_free_context(next);
170 return 1;
171 }
172 prev = next;
173 next = next->next;
174 }
175 return 0;
176 }
177
178 /*
179 * oscore_find_context
180 * Finds OSCORE context for rcpkey_id and optional ctxkey_id
181 * rcpkey_id can be 0 length.
182 * Updates recipient_ctx.
183 */
184 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)185 oscore_find_context(const coap_context_t *c_context,
186 const coap_bin_const_t rcpkey_id,
187 const coap_bin_const_t *ctxkey_id,
188 uint8_t *oscore_r2,
189 oscore_recipient_ctx_t **recipient_ctx) {
190 oscore_ctx_t *pt = c_context->p_osc_ctx;
191
192 *recipient_ctx = NULL;
193 assert(rcpkey_id.length == 0 || rcpkey_id.s != NULL);
194 while (pt != NULL) {
195 int ok = 0;
196 oscore_recipient_ctx_t *rpt = pt->recipient_chain;
197
198 while (rpt) {
199 ok = 0;
200 if (rcpkey_id.length == rpt->recipient_id->length) {
201 if (rcpkey_id.length != 0)
202 ok = memcmp(rpt->recipient_id->s, rcpkey_id.s, rcpkey_id.length) != 0;
203 if (oscore_r2) {
204 if (pt->id_context != NULL && pt->id_context->length > 8) {
205 ok = ok + (memcmp(pt->id_context->s, oscore_r2, 8) != 0);
206 } else {
207 ok += 1;
208 }
209 } else if (ctxkey_id) {
210 if (pt->id_context != NULL) {
211 if (ctxkey_id->length != pt->id_context->length)
212 ok += 1;
213 else
214 ok = ok + (memcmp(pt->id_context->s,
215 ctxkey_id->s,
216 ctxkey_id->length) != 0);
217 } else if (ctxkey_id->length > 0)
218 ok += 1;
219 }
220 if (ok == 0) {
221 /* optional id context and recipient id are the same */
222 *recipient_ctx = rpt;
223 return pt; /* OSCORE context found */
224 }
225 }
226 rpt = rpt->next_recipient;
227 } /* while rpt */
228 pt = pt->next;
229 } /* end while */
230 return NULL;
231 }
232
233 #define OSCORE_LOG_SIZE 16
234 void
oscore_log_hex_value(coap_log_t level,const char * name,coap_bin_const_t * value)235 oscore_log_hex_value(coap_log_t level,
236 const char *name,
237 coap_bin_const_t *value) {
238 size_t i;
239
240 if (value == NULL) {
241 coap_log(level, " %-16s\n", name);
242 return;
243 }
244 if (value->length == 0) {
245 coap_log(level, " %-16s <>\n", name);
246 return;
247 }
248 if (coap_get_log_level() >= level) {
249 for (i = 0; i < value->length; i += OSCORE_LOG_SIZE) {
250 char number[3 * OSCORE_LOG_SIZE + 4];
251
252 oscore_convert_to_hex(&value->s[i],
253 value->length - i > OSCORE_LOG_SIZE ?
254 OSCORE_LOG_SIZE : value->length - i,
255 number,
256 sizeof(number));
257 coap_log(level, " %-16s %s\n", i == 0 ? name : "", number);
258 }
259 }
260 }
261
262 void
oscore_log_int_value(coap_log_t level,const char * name,int value)263 oscore_log_int_value(coap_log_t level, const char *name, int value) {
264 coap_log(level, " %-16s %2d\n", name, value);
265 }
266
267 void
oscore_log_char_value(coap_log_t level,const char * name,const char * value)268 oscore_log_char_value(coap_log_t level, const char *name, const char *value) {
269 coap_log(level, " %-16s %s\n", name, value);
270 }
271
272 void
oscore_convert_to_hex(const uint8_t * src,size_t src_len,char * dest,size_t dst_len)273 oscore_convert_to_hex(const uint8_t *src,
274 size_t src_len,
275 char *dest,
276 size_t dst_len) {
277 /*
278 * Last output character will be '\000'
279 * (If output undersized, add trailing ... to indicate this.
280 */
281 size_t space = (dst_len - 4) / 3;
282 uint32_t qq;
283
284 for (qq = 0; qq < src_len && qq < space; qq++) {
285 char tmp = src[qq] >> 4;
286 if (tmp > 9)
287 tmp = tmp + 0x61 - 10;
288 else
289 tmp = tmp + 0x30;
290 dest[qq * 3] = tmp;
291 tmp = src[qq] & 0xf;
292 if (tmp > 9)
293 tmp = tmp + 0x61 - 10;
294 else
295 tmp = tmp + 0x30;
296 dest[qq * 3 + 1] = tmp;
297 dest[qq * 3 + 2] = 0x20;
298 }
299 if (qq != src_len) {
300 dest[qq * 3] = '.';
301 dest[qq * 3 + 1] = '.';
302 dest[qq * 3 + 2] = '.';
303 qq++;
304 }
305 dest[qq * 3] = 0;
306 }
307
308 static coap_bin_const_t *
oscore_build_key(oscore_ctx_t * osc_ctx,coap_bin_const_t * id,coap_str_const_t * type,size_t out_len)309 oscore_build_key(oscore_ctx_t *osc_ctx,
310 coap_bin_const_t *id,
311 coap_str_const_t *type,
312 size_t out_len) {
313 uint8_t info_buffer[80];
314 size_t info_len;
315 uint8_t hkdf_tmp[CONTEXT_KEY_LEN > CONTEXT_INIT_VECT_LEN ?
316 CONTEXT_KEY_LEN :
317 CONTEXT_INIT_VECT_LEN];
318
319 info_len = compose_info(info_buffer,
320 sizeof(info_buffer),
321 osc_ctx->aead_alg,
322 id,
323 osc_ctx->id_context,
324 type,
325 out_len);
326 if (info_len == 0 || info_len > sizeof(info_buffer))
327 return NULL;
328
329 if (!oscore_hkdf(osc_ctx->hkdf_alg,
330 osc_ctx->master_salt,
331 osc_ctx->master_secret,
332 info_buffer,
333 info_len,
334 hkdf_tmp,
335 out_len))
336 return NULL;
337 return coap_new_bin_const(hkdf_tmp, out_len);
338 }
339
340 static void
oscore_log_context(oscore_ctx_t * osc_ctx,const char * heading)341 oscore_log_context(oscore_ctx_t *osc_ctx, const char *heading) {
342 #if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_OSCORE
343 (void)osc_ctx;
344 (void)heading;
345 #else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
346 if (coap_get_log_level() >= COAP_LOG_OSCORE) {
347 char buffer[30];
348 oscore_recipient_ctx_t *next = osc_ctx->recipient_chain;
349 size_t count = 0;
350
351 coap_log_oscore("%s\n", heading);
352 oscore_log_char_value(COAP_LOG_OSCORE, "AEAD alg",
353 cose_get_alg_name(osc_ctx->aead_alg, buffer,
354 sizeof(buffer)));
355 oscore_log_char_value(COAP_LOG_OSCORE, "HKDF alg",
356 cose_get_hkdf_alg_name(osc_ctx->hkdf_alg, buffer,
357 sizeof(buffer)));
358 oscore_log_hex_value(COAP_LOG_OSCORE, "ID Context", osc_ctx->id_context);
359 oscore_log_hex_value(COAP_LOG_OSCORE,
360 "Master Secret",
361 osc_ctx->master_secret);
362 oscore_log_hex_value(COAP_LOG_OSCORE, "Master Salt", osc_ctx->master_salt);
363 oscore_log_hex_value(COAP_LOG_OSCORE, "Common IV", osc_ctx->common_iv);
364 oscore_log_hex_value(COAP_LOG_OSCORE,
365 "Sender ID",
366 osc_ctx->sender_context->sender_id);
367 oscore_log_hex_value(COAP_LOG_OSCORE,
368 "Sender Key",
369 osc_ctx->sender_context->sender_key);
370 while (next) {
371 snprintf(buffer, sizeof(buffer), "Recipient ID[%zu]", count);
372 oscore_log_hex_value(COAP_LOG_OSCORE,
373 buffer,
374 next->recipient_id);
375 snprintf(buffer, sizeof(buffer), "Recipient Key[%zu]", count);
376 oscore_log_hex_value(COAP_LOG_OSCORE,
377 buffer,
378 next->recipient_key);
379 count++;
380 next = next->next_recipient;
381 }
382 }
383 #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
384 }
385
386 void
oscore_update_ctx(oscore_ctx_t * osc_ctx,coap_bin_const_t * id_context)387 oscore_update_ctx(oscore_ctx_t *osc_ctx, coap_bin_const_t *id_context) {
388 coap_bin_const_t *temp;
389
390 /* Update with new ID Context */
391 coap_delete_bin_const(osc_ctx->id_context);
392 osc_ctx->id_context = id_context;
393
394 /* Update sender_key, recipient_key and common_iv */
395 temp = osc_ctx->sender_context->sender_key;
396 osc_ctx->sender_context->sender_key =
397 oscore_build_key(osc_ctx,
398 osc_ctx->sender_context->sender_id,
399 coap_make_str_const("Key"),
400 CONTEXT_KEY_LEN);
401 if (!osc_ctx->sender_context->sender_key)
402 osc_ctx->sender_context->sender_key = temp;
403 else
404 coap_delete_bin_const(temp);
405 temp = osc_ctx->recipient_chain->recipient_key;
406 osc_ctx->recipient_chain->recipient_key =
407 oscore_build_key(osc_ctx,
408 osc_ctx->recipient_chain->recipient_id,
409 coap_make_str_const("Key"),
410 CONTEXT_KEY_LEN);
411 if (!osc_ctx->recipient_chain->recipient_key)
412 osc_ctx->recipient_chain->recipient_key = temp;
413 else
414 coap_delete_bin_const(temp);
415 temp = osc_ctx->common_iv;
416 osc_ctx->common_iv = oscore_build_key(osc_ctx,
417 NULL,
418 coap_make_str_const("IV"),
419 CONTEXT_INIT_VECT_LEN);
420 if (!osc_ctx->common_iv)
421 osc_ctx->common_iv = temp;
422 else
423 coap_delete_bin_const(temp);
424
425 oscore_log_context(osc_ctx, "Updated Common context");
426 }
427
428 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)429 oscore_duplicate_ctx(coap_context_t *c_context,
430 oscore_ctx_t *o_osc_ctx,
431 coap_bin_const_t *sender_id,
432 coap_bin_const_t *recipient_id,
433 coap_bin_const_t *id_context) {
434 oscore_ctx_t *osc_ctx = NULL;
435 oscore_sender_ctx_t *sender_ctx = NULL;
436 coap_bin_const_t *copy_rid = NULL;
437
438 osc_ctx = coap_malloc_type(COAP_OSCORE_COM, sizeof(oscore_ctx_t));
439 if (osc_ctx == NULL)
440 goto error;
441 memset(osc_ctx, 0, sizeof(oscore_ctx_t));
442
443 sender_ctx = coap_malloc_type(COAP_OSCORE_SEN, sizeof(oscore_sender_ctx_t));
444 if (sender_ctx == NULL)
445 goto error;
446 memset(sender_ctx, 0, sizeof(oscore_sender_ctx_t));
447
448 osc_ctx->sender_context = sender_ctx;
449 if (o_osc_ctx->master_secret)
450 osc_ctx->master_secret =
451 coap_new_bin_const(o_osc_ctx->master_secret->s,
452 o_osc_ctx->master_secret->length);
453 if (o_osc_ctx->master_salt)
454 osc_ctx->master_salt = coap_new_bin_const(o_osc_ctx->master_salt->s,
455 o_osc_ctx->master_salt->length);
456 osc_ctx->aead_alg = o_osc_ctx->aead_alg;
457 osc_ctx->hkdf_alg = o_osc_ctx->hkdf_alg;
458 if (id_context)
459 osc_ctx->id_context = coap_new_bin_const(id_context->s, id_context->length);
460 osc_ctx->ssn_freq = o_osc_ctx->ssn_freq;
461 osc_ctx->replay_window_size = o_osc_ctx->replay_window_size;
462 osc_ctx->rfc8613_b_1_2 = o_osc_ctx->rfc8613_b_1_2;
463 osc_ctx->rfc8613_b_2 = o_osc_ctx->rfc8613_b_2;
464 osc_ctx->save_seq_num_func = o_osc_ctx->save_seq_num_func;
465 osc_ctx->save_seq_num_func_param = o_osc_ctx->save_seq_num_func_param;
466
467 if (o_osc_ctx->master_secret) {
468 /* sender_ key */
469 sender_ctx->sender_key = oscore_build_key(osc_ctx,
470 sender_id,
471 coap_make_str_const("Key"),
472 CONTEXT_KEY_LEN);
473 if (!sender_ctx->sender_key)
474 goto error;
475
476 /* common IV */
477 osc_ctx->common_iv = oscore_build_key(osc_ctx,
478 NULL,
479 coap_make_str_const("IV"),
480 CONTEXT_INIT_VECT_LEN);
481 if (!osc_ctx->common_iv)
482 goto error;
483 }
484
485 /*
486 * Need to set the last Sender Seq Num based on ssn_freq
487 * The value should only change if there is a change to ssn_freq
488 * and (potentially) be lower than seq, then save_seq_num_func() is
489 * immediately called on next SSN update.
490 */
491 sender_ctx->next_seq = 0;
492 sender_ctx->seq = 0;
493
494 sender_ctx->sender_id = coap_new_bin_const(sender_id->s, sender_id->length);
495
496 copy_rid = coap_new_bin_const(recipient_id->s, recipient_id->length);
497 if (copy_rid == NULL)
498 goto error;
499 if (oscore_add_recipient(osc_ctx, copy_rid, 0) == NULL)
500 goto error;
501
502 oscore_log_context(osc_ctx, "New Common context");
503 oscore_enter_context(c_context, osc_ctx);
504
505 return osc_ctx;
506
507 error:
508 oscore_free_context(osc_ctx);
509 return NULL;
510 }
511
512 oscore_ctx_t *
oscore_derive_ctx(coap_context_t * c_context,coap_oscore_conf_t * oscore_conf)513 oscore_derive_ctx(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf) {
514 oscore_ctx_t *osc_ctx = NULL;
515 oscore_sender_ctx_t *sender_ctx = NULL;
516 size_t i;
517
518 osc_ctx = coap_malloc_type(COAP_OSCORE_COM, sizeof(oscore_ctx_t));
519 if (osc_ctx == NULL)
520 goto error;
521 memset(osc_ctx, 0, sizeof(oscore_ctx_t));
522
523 sender_ctx = coap_malloc_type(COAP_OSCORE_SEN, sizeof(oscore_sender_ctx_t));
524 if (sender_ctx == NULL)
525 goto error;
526 memset(sender_ctx, 0, sizeof(oscore_sender_ctx_t));
527
528 osc_ctx->sender_context = sender_ctx;
529 osc_ctx->master_secret = oscore_conf->master_secret;
530 osc_ctx->master_salt = oscore_conf->master_salt;
531 osc_ctx->aead_alg = oscore_conf->aead_alg;
532 osc_ctx->hkdf_alg = oscore_conf->hkdf_alg;
533 osc_ctx->id_context = oscore_conf->id_context;
534 osc_ctx->ssn_freq = oscore_conf->ssn_freq ? oscore_conf->ssn_freq : 1;
535 osc_ctx->replay_window_size = oscore_conf->replay_window ?
536 oscore_conf->replay_window :
537 COAP_OSCORE_DEFAULT_REPLAY_WINDOW;
538 osc_ctx->rfc8613_b_1_2 = oscore_conf->rfc8613_b_1_2;
539 osc_ctx->rfc8613_b_2 = oscore_conf->rfc8613_b_2;
540 osc_ctx->save_seq_num_func = oscore_conf->save_seq_num_func;
541 osc_ctx->save_seq_num_func_param = oscore_conf->save_seq_num_func_param;
542
543 if (oscore_conf->master_secret) {
544 /* sender_ key */
545 if (oscore_conf->break_sender_key)
546 /* Interop testing */
547 sender_ctx->sender_key = oscore_build_key(osc_ctx,
548 oscore_conf->sender_id,
549 coap_make_str_const("BAD"),
550 CONTEXT_KEY_LEN);
551 else
552 sender_ctx->sender_key = oscore_build_key(osc_ctx,
553 oscore_conf->sender_id,
554 coap_make_str_const("Key"),
555 CONTEXT_KEY_LEN);
556 if (!sender_ctx->sender_key)
557 goto error;
558
559 /* common IV */
560 osc_ctx->common_iv = oscore_build_key(osc_ctx,
561 NULL,
562 coap_make_str_const("IV"),
563 CONTEXT_INIT_VECT_LEN);
564 if (!osc_ctx->common_iv)
565 goto error;
566 }
567
568 /*
569 * Need to set the last Sender Seq Num based on ssn_freq
570 * The value should only change if there is a change to ssn_freq
571 * and (potentially) be lower than seq, then save_seq_num_func() is
572 * immediately called on next SSN update.
573 */
574 sender_ctx->next_seq = oscore_conf->start_seq_num -
575 (oscore_conf->start_seq_num % (oscore_conf->ssn_freq > 0 ? oscore_conf->ssn_freq : 1));
576
577 sender_ctx->sender_id = oscore_conf->sender_id;
578 sender_ctx->seq = oscore_conf->start_seq_num;
579
580 for (i = 0; i < oscore_conf->recipient_id_count; i++) {
581 if (oscore_add_recipient(osc_ctx, oscore_conf->recipient_id[i],
582 oscore_conf->break_recipient_key) == NULL) {
583 coap_log_warn("OSCORE: Failed to add Client ID\n");
584 goto error;
585 }
586 }
587 oscore_log_context(osc_ctx, "Common context");
588
589 oscore_enter_context(c_context, osc_ctx);
590
591 return osc_ctx;
592
593 error:
594 coap_free_type(COAP_OSCORE_COM, osc_ctx);
595 coap_free_type(COAP_OSCORE_SEN, sender_ctx);
596 return NULL;
597 }
598
599 oscore_recipient_ctx_t *
oscore_add_recipient(oscore_ctx_t * osc_ctx,coap_bin_const_t * rid,uint32_t break_key)600 oscore_add_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid,
601 uint32_t break_key) {
602 oscore_recipient_ctx_t *rcp_ctx = osc_ctx->recipient_chain;
603 oscore_recipient_ctx_t *recipient_ctx = NULL;
604
605 if (rid->length > 7) {
606 coap_log_warn("oscore_add_recipient: Maximum size of recipient_id is 7 bytes\n");
607 return NULL;
608 }
609 /* Check this is not a duplicate recipient id */
610 while (rcp_ctx) {
611 if (rcp_ctx->recipient_id->length == rid->length &&
612 memcmp(rcp_ctx->recipient_id->s, rid->s, rid->length) == 0) {
613 coap_delete_bin_const(rid);
614 return NULL;
615 }
616 rcp_ctx = rcp_ctx->next_recipient;
617 }
618 recipient_ctx = (oscore_recipient_ctx_t *)coap_malloc_type(
619 COAP_OSCORE_REC,
620 sizeof(oscore_recipient_ctx_t));
621 if (recipient_ctx == NULL)
622 return NULL;
623 memset(recipient_ctx, 0, sizeof(oscore_recipient_ctx_t));
624
625 if (osc_ctx->master_secret) {
626 if (break_key)
627 /* Interop testing */
628 recipient_ctx->recipient_key = oscore_build_key(osc_ctx,
629 rid,
630 coap_make_str_const("BAD"),
631 CONTEXT_KEY_LEN);
632 else
633 recipient_ctx->recipient_key = oscore_build_key(osc_ctx,
634 rid,
635 coap_make_str_const("Key"),
636 CONTEXT_KEY_LEN);
637 if (!recipient_ctx->recipient_key) {
638 coap_free_type(COAP_OSCORE_REC, recipient_ctx);
639 return NULL;
640 }
641 }
642
643 recipient_ctx->recipient_id = rid;
644 recipient_ctx->initial_state = 1;
645 recipient_ctx->osc_ctx = osc_ctx;
646
647 rcp_ctx = osc_ctx->recipient_chain;
648 recipient_ctx->next_recipient = rcp_ctx;
649 osc_ctx->recipient_chain = recipient_ctx;
650 return recipient_ctx;
651 }
652
653 int
oscore_delete_recipient(oscore_ctx_t * osc_ctx,coap_bin_const_t * rid)654 oscore_delete_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid) {
655 oscore_recipient_ctx_t *prev = NULL;
656 oscore_recipient_ctx_t *next = osc_ctx->recipient_chain;
657 while (next) {
658 if (next->recipient_id->length == rid->length &&
659 memcmp(next->recipient_id->s, rid->s, rid->length) == 0) {
660 if (prev != NULL)
661 prev->next_recipient = next->next_recipient;
662 else
663 osc_ctx->recipient_chain = next->next_recipient;
664 oscore_free_recipient(next);
665 return 1;
666 }
667 prev = next;
668 next = next->next_recipient;
669 }
670 return 0;
671 }
672
673 void
oscore_free_association(oscore_association_t * association)674 oscore_free_association(oscore_association_t *association) {
675 if (association) {
676 coap_delete_pdu(association->sent_pdu);
677 coap_delete_bin_const(association->token);
678 coap_delete_bin_const(association->aad);
679 coap_delete_bin_const(association->nonce);
680 coap_delete_bin_const(association->partial_iv);
681 coap_free_type(COAP_STRING, association);
682 }
683 }
684
685 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)686 oscore_new_association(coap_session_t *session,
687 coap_pdu_t *sent_pdu,
688 coap_bin_const_t *token,
689 oscore_recipient_ctx_t *recipient_ctx,
690 coap_bin_const_t *aad,
691 coap_bin_const_t *nonce,
692 coap_bin_const_t *partial_iv,
693 int is_observe) {
694 oscore_association_t *association;
695
696 association = coap_malloc_type(COAP_STRING, sizeof(oscore_association_t));
697 if (association == NULL)
698 return 0;
699
700 memset(association, 0, sizeof(oscore_association_t));
701 association->recipient_ctx = recipient_ctx;
702 association->is_observe = is_observe;
703
704 if (sent_pdu) {
705 size_t size;
706 const uint8_t *data;
707
708 association->sent_pdu = coap_pdu_duplicate(sent_pdu, session,
709 token->length, token->s, NULL);
710 if (association->sent_pdu == NULL)
711 goto error;
712 if (coap_get_data(sent_pdu, &size, &data)) {
713 coap_add_data(association->sent_pdu, size, data);
714 }
715 }
716 association->token = coap_new_bin_const(token->s, token->length);
717 if (association->token == NULL)
718 goto error;
719
720 if (aad) {
721 association->aad = coap_new_bin_const(aad->s, aad->length);
722 if (association->aad == NULL)
723 goto error;
724 }
725
726 if (nonce) {
727 association->nonce = coap_new_bin_const(nonce->s, nonce->length);
728 if (association->nonce == NULL)
729 goto error;
730 }
731
732 if (partial_iv) {
733 association->partial_iv =
734 coap_new_bin_const(partial_iv->s, partial_iv->length);
735 if (association->partial_iv == NULL)
736 goto error;
737 }
738
739 OSCORE_ASSOCIATIONS_ADD(session->associations, association);
740 return 1;
741
742 error:
743 oscore_free_association(association);
744 return 0;
745 }
746
747 oscore_association_t *
oscore_find_association(coap_session_t * session,coap_bin_const_t * token)748 oscore_find_association(coap_session_t *session, coap_bin_const_t *token) {
749 oscore_association_t *association;
750
751 OSCORE_ASSOCIATIONS_FIND(session->associations, token, association);
752 return association;
753 }
754
755 int
oscore_delete_association(coap_session_t * session,oscore_association_t * association)756 oscore_delete_association(coap_session_t *session,
757 oscore_association_t *association) {
758 if (association) {
759 OSCORE_ASSOCIATIONS_DELETE(session->associations, association);
760 oscore_free_association(association);
761 return 1;
762 }
763 return 0;
764 }
765
766 void
oscore_delete_server_associations(coap_session_t * session)767 oscore_delete_server_associations(coap_session_t *session) {
768 if (session) {
769 oscore_association_t *association;
770 oscore_association_t *tmp;
771
772 OSCORE_ASSOCIATIONS_ITER_SAFE(session->associations, association, tmp) {
773 OSCORE_ASSOCIATIONS_DELETE(session->associations, association);
774 oscore_free_association(association);
775 }
776 session->associations = NULL;
777 }
778 }
779