• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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