• 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_cose.c
35  * @brief An implementation of the CBOR Object Signing and Encryption (RFC).
36  *
37  * \author
38  *      Martin Gunnarsson  <martin.gunnarsson@ri.se>
39  * added sign1 addition for coaplib
40  *      Peter van der Stok <consultancy@vanderstok.org >
41  * adapted for libcoap integration
42  *      Jon Shallow <supjps-libcoap@jpshallow.com>
43  *
44  */
45 
46 #include "coap3/coap_internal.h"
47 #include "stdio.h"
48 
49 struct cose_curve_desc {
50   const char *name;
51   cose_curve_t id;
52 };
53 
54 static struct cose_curve_desc curve_mapping[] = {
55   { "P-256", COSE_CURVE_P_256 },
56   { "X25519", COSE_CURVE_X25519 },
57   { "X448", COSE_CURVE_X448 },
58   { "Ed25519", COSE_CURVE_ED25519 },
59   { "Ed448", COSE_CURVE_ED448 },
60   { "secp256k1", COSE_CURVE_SECP256K1 },
61 };
62 
63 const char *
cose_get_curve_name(cose_curve_t id,char * buffer,size_t buflen)64 cose_get_curve_name(cose_curve_t id, char *buffer, size_t buflen) {
65   for (size_t i = 0; i < sizeof(curve_mapping)/sizeof(curve_mapping[0]); i++) {
66     if (id == curve_mapping[i].id) {
67       snprintf(buffer, buflen, "%s (%d)", curve_mapping[i].name, id);
68       return buffer;
69     }
70   }
71   snprintf(buffer, buflen, "curve Fix me (%d)", id);
72   return buffer;
73 }
74 
75 cose_curve_t
cose_get_curve_id(const char * name)76 cose_get_curve_id(const char *name) {
77   for (size_t i = 0; i < sizeof(curve_mapping)/sizeof(curve_mapping[0]); i++) {
78     if (strcmp(name, curve_mapping[i].name) == 0)
79       return curve_mapping[i].id;
80   }
81   return 0;
82 }
83 
84 struct cose_alg_desc {
85   const char *name;
86   cose_alg_t id;
87 };
88 
89 static struct cose_alg_desc alg_mapping[] = {
90   { "ES256K", COSE_ALGORITHM_ES256K },
91   { "SHA-512", COSE_ALGORITHM_SHA_512 },
92   { "SHA-384", COSE_ALGORITHM_SHA_384 },
93   { "ES512", COSE_ALGORITHM_ES512 },
94   { "ES384", COSE_ALGORITHM_ES384 },
95   { "ECDH-SS + HKDF-256", COSE_ALGORITHM_ECDH_SS_HKDF_256 },
96   { "SHA-512/256", COSE_ALGORITHM_SHA_512_256 },
97   { "SHA-256", COSE_ALGORITHM_SHA_256_256 },
98   { "SHA-256/64", COSE_ALGORITHM_SHA_256_64 },
99   { "SHA-1", COSE_ALGORITHM_SHA_1 },
100   { "direct+HKDF-SHA-512", COSE_ALGORITHM_HKDF_SHA_512 },
101   { "direct+HKDF-SHA-256", COSE_ALGORITHM_HKDF_SHA_256 },
102   { "EdDSA", COSE_ALGORITHM_EDDSA },
103   { "ES256", COSE_ALGORITHM_ES256 },
104   { "HMAC 256/64", COSE_ALGORITHM_HMAC256_64 },
105   { "HMAC 256/256", COSE_ALGORITHM_HMAC256_256 },
106   { "HMAC 384/384", COSE_ALGORITHM_HMAC384_384 },
107   { "HMAC 512/512", COSE_ALGORITHM_HMAC512_512 },
108   { "AES-CCM-16-64-128", COSE_ALGORITHM_AES_CCM_16_64_128 },
109   { "AES-CCM-16-64-256", COSE_ALGORITHM_AES_CCM_16_64_256 },
110   { "AES-CCM-64-64-128", COSE_ALGORITHM_AES_CCM_64_64_128 },
111   { "AES-CCM-64-64-256", COSE_ALGORITHM_AES_CCM_64_64_256 },
112   { "ChaCha20/Poly1305", COSE_ALGORITHM_CHACHA20_P1035 },
113   { "AES-CCM-16-128-128", COSE_ALGORITHM_AES_CCM_16_128_128 },
114   { "AES-CCM-16-128-256", COSE_ALGORITHM_AES_CCM_16_128_256 },
115   { "AES-CCM-64-128-128", COSE_ALGORITHM_AES_CCM_64_128_128 },
116   { "AES-CCM-64-128-256", COSE_ALGORITHM_AES_CCM_64_128_256 },
117 };
118 
119 const char *
cose_get_alg_name(cose_alg_t id,char * buffer,size_t buflen)120 cose_get_alg_name(cose_alg_t id, char *buffer, size_t buflen) {
121   for (size_t i = 0; i < sizeof(alg_mapping)/sizeof(alg_mapping[0]); i++) {
122     if (id == alg_mapping[i].id) {
123       snprintf(buffer, buflen, "%s (%d)", alg_mapping[i].name, id);
124       return buffer;
125     }
126   }
127   snprintf(buffer, buflen, "alg Fix me (%d)", id);
128   return buffer;
129 }
130 
131 cose_alg_t
cose_get_alg_id(const char * name)132 cose_get_alg_id(const char *name) {
133   for (size_t i = 0; i < sizeof(alg_mapping)/sizeof(alg_mapping[0]); i++) {
134     if (strcmp(name, alg_mapping[i].name) == 0)
135       return alg_mapping[i].id;
136   }
137   return 0;
138 }
139 
140 struct cose_hkdf_alg_desc {
141   const char *name;
142   cose_hkdf_alg_t id;
143 };
144 
145 static struct cose_hkdf_alg_desc hkdf_alg_mapping[] = {
146   { "direct+HKDF-SHA-512", COSE_HKDF_ALG_HKDF_SHA_512 },
147   { "direct+HKDF-SHA-256", COSE_HKDF_ALG_HKDF_SHA_256 },
148 };
149 
150 const char *
cose_get_hkdf_alg_name(cose_hkdf_alg_t id,char * buffer,size_t buflen)151 cose_get_hkdf_alg_name(cose_hkdf_alg_t id, char *buffer, size_t buflen) {
152   for (size_t i = 0; i < sizeof(hkdf_alg_mapping)/sizeof(hkdf_alg_mapping[0]); i++) {
153     if (id == hkdf_alg_mapping[i].id) {
154       snprintf(buffer, buflen, "%s (%d)", hkdf_alg_mapping[i].name, id);
155       return buffer;
156     }
157   }
158   snprintf(buffer, buflen, "hkdf_alg Fix me (%d)", id);
159   return buffer;
160 }
161 
162 /*
163  * The struct hmac_algs and the function cose_get_hmac_alg_for_hkdf() are
164  * used to determine which hmac type to use for the appropriate hkdf
165  */
166 static struct hkdf_hmac_algs {
167   cose_hkdf_alg_t hkdf_alg;
168   cose_hmac_alg_t hmac_alg;
169 } hkdf_hmacs[] = {
170   {COSE_HKDF_ALG_HKDF_SHA_256, COSE_HMAC_ALG_HMAC256_256},
171   {COSE_HKDF_ALG_HKDF_SHA_512, COSE_HMAC_ALG_HMAC512_512},
172 };
173 
174 /*
175  * return 0 fail
176  *        1 OK
177  */
178 int
cose_get_hmac_alg_for_hkdf(cose_hkdf_alg_t hkdf_alg,cose_hmac_alg_t * hmac_alg)179 cose_get_hmac_alg_for_hkdf(cose_hkdf_alg_t hkdf_alg, cose_hmac_alg_t *hmac_alg) {
180   size_t idx;
181 
182   for (idx = 0; idx < sizeof(hkdf_hmacs) / sizeof(struct hkdf_hmac_algs);
183        idx++) {
184     if (hkdf_hmacs[idx].hkdf_alg == hkdf_alg) {
185       *hmac_alg = hkdf_hmacs[idx].hmac_alg;
186       return 1;
187     }
188   }
189   coap_log_debug("cose_get_hmac_alg_for_hkdf: COSE HKDF %d not supported\n",
190                  hkdf_alg);
191   return 0;
192 }
193 
194 /* return tag length belonging to cose algorithm */
195 size_t
cose_tag_len(cose_alg_t cose_alg)196 cose_tag_len(cose_alg_t cose_alg) {
197   switch ((int)cose_alg) {
198   case COSE_ALGORITHM_AES_CCM_16_64_128:
199     return COSE_ALGORITHM_AES_CCM_16_64_128_TAG_LEN;
200   case COSE_ALGORITHM_AES_CCM_64_64_128:
201     return COSE_ALGORITHM_AES_CCM_64_64_128_TAG_LEN;
202   case COSE_ALGORITHM_AES_CCM_16_128_128:
203     return COSE_ALGORITHM_AES_CCM_16_128_128_TAG_LEN;
204   case COSE_ALGORITHM_AES_CCM_64_128_128:
205     return COSE_ALGORITHM_AES_CCM_64_128_128_TAG_LEN;
206   default:
207     return 0;
208   }
209 }
210 
211 /* return hash length belonging to cose algorithm */
212 size_t
cose_hash_len(cose_alg_t cose_alg)213 cose_hash_len(cose_alg_t cose_alg) {
214   switch ((int)cose_alg) {
215   case COSE_ALGORITHM_ES256:
216     return COSE_ALGORITHM_HMAC256_256_HASH_LEN;
217   case COSE_ALGORITHM_ES512:
218     return COSE_ALGORITHM_ES512_HASH_LEN;
219   case COSE_ALGORITHM_ES384:
220     return COSE_ALGORITHM_ES384_HASH_LEN;
221   case COSE_ALGORITHM_HMAC256_64:
222     return COSE_ALGORITHM_HMAC256_64_HASH_LEN;
223   case COSE_ALGORITHM_HMAC256_256:
224     return COSE_ALGORITHM_HMAC256_256_HASH_LEN;
225   case COSE_ALGORITHM_HMAC384_384:
226     return COSE_ALGORITHM_HMAC384_384_HASH_LEN;
227   case COSE_ALGORITHM_HMAC512_512:
228     return COSE_ALGORITHM_HMAC512_512_HASH_LEN;
229   case COSE_ALGORITHM_SHA_256_64:
230     return COSE_ALGORITHM_SHA_256_64_LEN;
231   case COSE_ALGORITHM_SHA_256_256:
232     return COSE_ALGORITHM_SHA_256_256_LEN;
233   case COSE_ALGORITHM_SHA_512_256:
234     return COSE_ALGORITHM_SHA_512_256_LEN;
235   case COSE_ALGORITHM_SHA_512:
236     return COSE_ALGORITHM_SHA_512_LEN;
237   default:
238     return 0;
239   }
240 }
241 
242 /* return nonce length belonging to cose algorithm */
243 size_t
cose_nonce_len(cose_alg_t cose_alg)244 cose_nonce_len(cose_alg_t cose_alg) {
245   switch ((int)cose_alg) {
246   case COSE_ALGORITHM_AES_CCM_16_64_128:
247     return COSE_ALGORITHM_AES_CCM_16_64_128_NONCE_LEN;
248   case COSE_ALGORITHM_AES_CCM_64_64_128:
249     return COSE_ALGORITHM_AES_CCM_64_64_128_NONCE_LEN;
250   case COSE_ALGORITHM_AES_CCM_16_128_128:
251     return COSE_ALGORITHM_AES_CCM_16_128_128_NONCE_LEN;
252   case COSE_ALGORITHM_AES_CCM_64_128_128:
253     return COSE_ALGORITHM_AES_CCM_64_128_128_NONCE_LEN;
254   default:
255     return 0;
256   }
257 }
258 
259 /* return key length belonging to cose algorithm */
260 size_t
cose_key_len(cose_alg_t cose_alg)261 cose_key_len(cose_alg_t cose_alg) {
262   switch ((int)cose_alg) {
263   case COSE_ALGORITHM_AES_CCM_16_64_128:
264     return COSE_ALGORITHM_AES_CCM_16_64_128_KEY_LEN;
265   case COSE_ALGORITHM_AES_CCM_64_64_128:
266     return COSE_ALGORITHM_AES_CCM_64_64_128_KEY_LEN;
267   case COSE_ALGORITHM_AES_CCM_16_128_128:
268     return COSE_ALGORITHM_AES_CCM_16_128_128_KEY_LEN;
269   case COSE_ALGORITHM_AES_CCM_64_128_128:
270     return COSE_ALGORITHM_AES_CCM_64_128_128_KEY_LEN;
271   default:
272     return 0;
273   }
274 }
275 
276 /* Return length */
277 size_t
cose_encrypt0_encode(cose_encrypt0_t * ptr,uint8_t * buffer,size_t buf_len)278 cose_encrypt0_encode(cose_encrypt0_t *ptr, uint8_t *buffer, size_t buf_len) {
279   size_t ret = 0;
280   size_t rem_size = buf_len;
281 
282   ret += oscore_cbor_put_array(&buffer, &rem_size, 3);
283   ret += oscore_cbor_put_bytes(&buffer, &rem_size, NULL, 0);
284   /* ret += cose encode attributyes */
285   ret += oscore_cbor_put_bytes(&buffer,
286                                &rem_size,
287                                ptr->ciphertext.s,
288                                ptr->ciphertext.length);
289   return ret;
290 }
291 
292 /*Return status */
293 int cose_encrypt0_decode(cose_encrypt0_t *ptr, uint8_t *buffer, size_t size);
294 
295 /* Initiate a new COSE Encrypt0 object. */
296 void
cose_encrypt0_init(cose_encrypt0_t * ptr)297 cose_encrypt0_init(cose_encrypt0_t *ptr) {
298   memset(ptr, 0, sizeof(cose_encrypt0_t));
299 }
300 
301 void
cose_encrypt0_set_alg(cose_encrypt0_t * ptr,uint8_t alg)302 cose_encrypt0_set_alg(cose_encrypt0_t *ptr, uint8_t alg) {
303   ptr->alg = alg;
304 }
305 
306 void
cose_encrypt0_set_ciphertext(cose_encrypt0_t * ptr,uint8_t * buffer,size_t size)307 cose_encrypt0_set_ciphertext(cose_encrypt0_t *ptr,
308                              uint8_t *buffer,
309                              size_t size) {
310   ptr->ciphertext.s = buffer;
311   ptr->ciphertext.length = size;
312 }
313 
314 void
cose_encrypt0_set_plaintext(cose_encrypt0_t * ptr,uint8_t * buffer,size_t size)315 cose_encrypt0_set_plaintext(cose_encrypt0_t *ptr,
316                             uint8_t *buffer,
317                             size_t size) {
318   ptr->plaintext.s = buffer;
319   ptr->plaintext.length = size;
320 }
321 /* Return length */
322 int cose_encrypt0_get_plaintext(cose_encrypt0_t *ptr, uint8_t **buffer);
323 
324 void
cose_encrypt0_set_partial_iv(cose_encrypt0_t * ptr,coap_bin_const_t * partial_iv)325 cose_encrypt0_set_partial_iv(cose_encrypt0_t *ptr,
326                              coap_bin_const_t *partial_iv) {
327   if (partial_iv == NULL || partial_iv->length == 0) {
328     ptr->partial_iv.s = NULL;
329     ptr->partial_iv.length = 0;
330   } else {
331     if (partial_iv->length > (int)sizeof(ptr->partial_iv_data))
332       partial_iv->length = sizeof(ptr->partial_iv_data);
333     memcpy(ptr->partial_iv_data, partial_iv->s, partial_iv->length);
334     ptr->partial_iv.s = ptr->partial_iv_data;
335     ptr->partial_iv.length = partial_iv->length;
336   }
337 }
338 
339 /* Return length */
340 coap_bin_const_t
cose_encrypt0_get_partial_iv(cose_encrypt0_t * ptr)341 cose_encrypt0_get_partial_iv(cose_encrypt0_t *ptr) {
342   return ptr->partial_iv;
343 }
344 
345 void
cose_encrypt0_set_key_id(cose_encrypt0_t * ptr,coap_bin_const_t * key_id)346 cose_encrypt0_set_key_id(cose_encrypt0_t *ptr, coap_bin_const_t *key_id) {
347   if (key_id) {
348     ptr->key_id = *key_id;
349   } else {
350     ptr->key_id.length = 0;
351     ptr->key_id.s = NULL;
352   }
353 }
354 /* Return length */
355 size_t
cose_encrypt0_get_key_id(cose_encrypt0_t * ptr,const uint8_t ** buffer)356 cose_encrypt0_get_key_id(cose_encrypt0_t *ptr, const uint8_t **buffer) {
357   *buffer = ptr->key_id.s;
358   return ptr->key_id.length;
359 }
360 
361 size_t
cose_encrypt0_get_kid_context(cose_encrypt0_t * ptr,const uint8_t ** buffer)362 cose_encrypt0_get_kid_context(cose_encrypt0_t *ptr, const uint8_t **buffer) {
363   *buffer = ptr->kid_context.s;
364   return ptr->kid_context.length;
365 }
366 
367 void
cose_encrypt0_set_kid_context(cose_encrypt0_t * ptr,coap_bin_const_t * kid_context)368 cose_encrypt0_set_kid_context(cose_encrypt0_t *ptr,
369                               coap_bin_const_t *kid_context) {
370   if (kid_context) {
371     ptr->kid_context = *kid_context;
372   } else {
373     ptr->kid_context.length = 0;
374     ptr->kid_context.s = NULL;
375   }
376 }
377 
378 void
cose_encrypt0_set_external_aad(cose_encrypt0_t * ptr,coap_bin_const_t * external_aad)379 cose_encrypt0_set_external_aad(cose_encrypt0_t *ptr,
380                                coap_bin_const_t *external_aad) {
381   if (external_aad) {
382     ptr->external_aad = *external_aad;
383   } else {
384     ptr->external_aad.length = 0;
385     ptr->external_aad.s = NULL;
386   }
387 }
388 
389 void
cose_encrypt0_set_aad(cose_encrypt0_t * ptr,coap_bin_const_t * aad)390 cose_encrypt0_set_aad(cose_encrypt0_t *ptr, coap_bin_const_t *aad) {
391   if (aad) {
392     ptr->aad = *aad;
393   } else {
394     ptr->aad.length = 0;
395     ptr->aad.s = NULL;
396   }
397 }
398 
399 /* Returns 1 if successfull, 0 if key is of incorrect length. */
400 int
cose_encrypt0_set_key(cose_encrypt0_t * ptr,coap_bin_const_t * key)401 cose_encrypt0_set_key(cose_encrypt0_t *ptr, coap_bin_const_t *key) {
402   if (key == NULL || key->length != 16) {
403     return 0;
404   }
405 
406   ptr->key = *key;
407   return 1;
408 }
409 
410 void
cose_encrypt0_set_nonce(cose_encrypt0_t * ptr,coap_bin_const_t * nonce)411 cose_encrypt0_set_nonce(cose_encrypt0_t *ptr, coap_bin_const_t *nonce) {
412   if (nonce) {
413     ptr->nonce = *nonce;
414   } else {
415     ptr->nonce.length = 0;
416     ptr->nonce.s = NULL;
417   }
418 }
419 
420 int
cose_encrypt0_encrypt(cose_encrypt0_t * ptr,uint8_t * ciphertext_buffer,size_t ciphertext_len)421 cose_encrypt0_encrypt(cose_encrypt0_t *ptr,
422                       uint8_t *ciphertext_buffer,
423                       size_t ciphertext_len) {
424   coap_crypto_param_t params;
425   size_t tag_len = cose_tag_len(ptr->alg);
426   size_t max_result_len = ptr->plaintext.length + tag_len;
427 
428   if (ptr->key.s == NULL || ptr->key.length != (size_t)cose_key_len(ptr->alg)) {
429     return -1;
430   }
431   if (ptr->nonce.s == NULL ||
432       ptr->nonce.length != (size_t)cose_nonce_len(ptr->alg)) {
433     return -2;
434   }
435   if (ptr->aad.s == NULL || ptr->aad.length == 0) {
436     return -3;
437   }
438   if (ptr->plaintext.s == NULL ||
439       (ptr->plaintext.length + tag_len) > ciphertext_len) {
440     return -4;
441   }
442 
443   memset(&params, 0, sizeof(params));
444   params.alg = ptr->alg;
445   params.params.aes.key = ptr->key;
446   params.params.aes.nonce = ptr->nonce.s;
447   params.params.aes.tag_len = tag_len;
448   params.params.aes.l = 15 - ptr->nonce.length;
449   if (!coap_crypto_aead_encrypt(&params,
450                                 &ptr->plaintext,
451                                 &ptr->aad,
452                                 ciphertext_buffer,
453                                 &max_result_len)) {
454     return -5;
455   }
456   return (int)max_result_len;
457 }
458 
459 int
cose_encrypt0_decrypt(cose_encrypt0_t * ptr,uint8_t * plaintext_buffer,size_t plaintext_len)460 cose_encrypt0_decrypt(cose_encrypt0_t *ptr,
461                       uint8_t *plaintext_buffer,
462                       size_t plaintext_len) {
463   int ret_len = 0;
464   coap_crypto_param_t params;
465   size_t tag_len = cose_tag_len(ptr->alg);
466   size_t max_result_len = ptr->ciphertext.length - tag_len;
467 
468   if (ptr->key.s == NULL || ptr->key.length != (size_t)cose_key_len(ptr->alg)) {
469     return -1;
470   }
471   if (ptr->nonce.s == NULL ||
472       ptr->nonce.length != (size_t)cose_nonce_len(ptr->alg)) {
473     return -2;
474   }
475   if (ptr->aad.s == NULL || ptr->aad.length == 0) {
476     return -3;
477   }
478   if (ptr->ciphertext.s == NULL ||
479       ptr->ciphertext.length > (plaintext_len + tag_len)) {
480     return -4;
481   }
482 
483   memset(&params, 0, sizeof(params));
484   params.alg = ptr->alg;
485   params.params.aes.key = ptr->key;
486   params.params.aes.nonce = ptr->nonce.s;
487   params.params.aes.tag_len = tag_len;
488   params.params.aes.l = 15 - ptr->nonce.length;
489   if (!coap_crypto_aead_decrypt(&params,
490                                 &ptr->ciphertext,
491                                 &ptr->aad,
492                                 plaintext_buffer,
493                                 &max_result_len)) {
494     return -5;
495   }
496   ret_len = (int)max_result_len;
497   return ret_len;
498 }
499