• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * coap_tinydtls.c -- Datagram Transport Layer Support for libcoap with tinydtls
3  *
4  * Copyright (C) 2016-2020 Olaf Bergmann <bergmann@tzi.org>
5  * Copyright (C) 2020-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * This file is part of the CoAP library libcoap. Please see README for terms
10  * of use.
11  */
12 
13 /**
14  * @file coap_tinydtls.c
15  * @brief TinyDTLS specific handling functions
16  */
17 
18 #include "coap3/coap_internal.h"
19 
20 #ifdef COAP_WITH_LIBTINYDTLS
21 
22 /* We want TinyDTLS versions of these, not libcoap versions */
23 #undef PACKAGE_BUGREPORT
24 #undef PACKAGE_NAME
25 #undef PACKAGE_STRING
26 #undef PACKAGE_TARNAME
27 #undef PACKAGE_URL
28 #undef PACKAGE_VERSION
29 
30 #ifndef  RIOT_VERSION
31 #include <tinydtls/tinydtls.h>
32 #include <tinydtls/dtls.h>
33 #include <tinydtls/dtls_debug.h>
34 #include <tinydtls/dtls_time.h>
35 #else /* RIOT_VERSION */
36 #include <tinydtls.h>
37 #include <dtls.h>
38 #include <dtls_debug.h>
39 #include <dtls_time.h>
40 #endif /* RIOT_VERSION */
41 
42 typedef struct coap_tiny_context_t {
43   struct dtls_context_t *dtls_context;
44   coap_context_t *coap_context;
45 #ifdef DTLS_ECC
46   coap_dtls_pki_t setup_data;
47   coap_binary_t *priv_key;
48   coap_binary_t *pub_key;
49 #endif /* DTLS_ECC */
50 } coap_tiny_context_t;
51 
52 #if ! defined(DTLS_PSK) && ! defined(DTLS_ECC)
53 #error Neither DTLS_PSK or DTLS_ECC defined
54 #endif /* ! DTLS_PSK && ! DTLS_ECC */
55 
56 static dtls_tick_t dtls_tick_0 = 0;
57 static coap_tick_t coap_tick_0 = 0;
58 
59 int
coap_dtls_is_supported(void)60 coap_dtls_is_supported(void) {
61   return 1;
62 }
63 
64 /*
65  * return 0 failed
66  *        1 passed
67  */
68 int
coap_dtls_psk_is_supported(void)69 coap_dtls_psk_is_supported(void) {
70 #ifdef DTLS_PSK
71   return 1;
72 #else /* ! DTLS_PSK */
73   return 0;
74 #endif /* ! DTLS_PSK */
75 }
76 
77 /*
78  * return 0 failed
79  *        1 passed
80  */
81 int
coap_dtls_pki_is_supported(void)82 coap_dtls_pki_is_supported(void) {
83   return 0;
84 }
85 
86 /*
87  * return 0 failed
88  *        1 passed
89  */
90 int
coap_dtls_pkcs11_is_supported(void)91 coap_dtls_pkcs11_is_supported(void) {
92   return 0;
93 }
94 
95 /*
96  * return 0 failed
97  *        1 passed
98  */
99 int
coap_dtls_rpk_is_supported(void)100 coap_dtls_rpk_is_supported(void) {
101 #ifdef DTLS_ECC
102   return 1;
103 #else /* ! DTLS_ECC */
104   return 0;
105 #endif /* ! DTLS_ECC */
106 }
107 
108 static coap_log_t
dtls_map_logging(log_t d_level)109 dtls_map_logging(log_t d_level) {
110   /* DTLS_LOG_ERR is missing, so account for the gap */
111   switch (d_level) {
112   case DTLS_LOG_EMERG:
113     return COAP_LOG_EMERG;
114     break;
115   case DTLS_LOG_ALERT:
116     return COAP_LOG_ALERT;
117     break;
118   case DTLS_LOG_CRIT:
119     return COAP_LOG_CRIT;
120     break;
121   case DTLS_LOG_WARN:
122     return COAP_LOG_WARN;
123     break;
124   case DTLS_LOG_NOTICE:
125     return COAP_LOG_NOTICE;
126     break;
127   case DTLS_LOG_INFO:
128     return COAP_LOG_INFO;
129     break;
130   case DTLS_LOG_DEBUG:
131   default:
132     return COAP_LOG_DEBUG;
133     break;
134   }
135   return COAP_LOG_DEBUG;
136 }
137 #ifdef HAVE_DTLS_SET_LOG_HANDLER
138 /* Valid after TinyDTLS submodule has been updated */
139 static void
dtls_logging(log_t d_level,const char * message)140 dtls_logging(log_t d_level, const char *message) {
141   coap_log_t c_level = dtls_map_logging(d_level);
142 
143   coap_dtls_log(c_level, "%s", message);
144 }
145 #endif /* HAVE_DTLS_SET_LOG_HANDLER */
146 
147 void
coap_dtls_startup(void)148 coap_dtls_startup(void) {
149   dtls_init();
150   dtls_ticks(&dtls_tick_0);
151   coap_ticks(&coap_tick_0);
152 #ifdef HAVE_DTLS_SET_LOG_HANDLER
153   /* Valid after TinyDTLS submodule has been updated */
154   dtls_set_log_handler(dtls_logging);
155 #endif /* HAVE_DTLS_SET_LOG_HANDLER */
156   coap_dtls_set_log_level(COAP_LOG_EMERG);
157 }
158 
159 void
coap_dtls_shutdown(void)160 coap_dtls_shutdown(void) {
161   coap_dtls_set_log_level(COAP_LOG_EMERG);
162 }
163 
164 void *
coap_dtls_get_tls(const coap_session_t * c_session,coap_tls_library_t * tls_lib)165 coap_dtls_get_tls(const coap_session_t *c_session,
166                   coap_tls_library_t *tls_lib) {
167   if (tls_lib)
168     *tls_lib = COAP_TLS_LIBRARY_TINYDTLS;
169   if (c_session && c_session->context && c_session->context->dtls_context) {
170     const coap_tiny_context_t *t_context =
171         (const coap_tiny_context_t *)c_session->context->dtls_context;
172 
173     return t_context->dtls_context;
174   }
175   return NULL;
176 }
177 
178 void
coap_dtls_set_log_level(coap_log_t c_level)179 coap_dtls_set_log_level(coap_log_t c_level) {
180   log_t d_level;
181 
182   /* DTLS_LOG_ERR is missing, so account for the gap */
183   switch (c_level) {
184   case COAP_LOG_EMERG:
185     d_level = DTLS_LOG_EMERG;
186     break;
187   case COAP_LOG_ALERT:
188     d_level = DTLS_LOG_ALERT;
189     break;
190   case COAP_LOG_CRIT:
191   case COAP_LOG_ERR:
192     d_level = DTLS_LOG_CRIT;
193     break;
194   case COAP_LOG_WARN:
195     d_level = DTLS_LOG_WARN;
196     break;
197   case COAP_LOG_NOTICE:
198     d_level = DTLS_LOG_NOTICE;
199     break;
200   case COAP_LOG_INFO:
201     d_level = DTLS_LOG_INFO;
202     break;
203   case COAP_LOG_DEBUG:
204   case COAP_LOG_OSCORE:
205   case COAP_LOG_DTLS_BASE:
206   default:
207     d_level = DTLS_LOG_DEBUG;
208     break;
209   }
210   dtls_set_log_level(d_level);
211 }
212 
213 coap_log_t
coap_dtls_get_log_level(void)214 coap_dtls_get_log_level(void) {
215   log_t d_level = dtls_get_log_level();
216 
217   return dtls_map_logging(d_level);
218 }
219 
220 static void
get_session_addr(const session_t * s,coap_address_t * a)221 get_session_addr(const session_t *s, coap_address_t *a) {
222 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
223   a->addr = s->addr;
224   a->port = s->port;
225 #elif defined(WITH_RIOT_SOCK)
226   if (s->addr.family == AF_INET6) {
227     a->size = (socklen_t)sizeof(a->addr.sin6);
228     a->addr.sa.sa_family = s->addr.family;
229     memcpy(&a->addr.sin6.sin6_addr, &s->addr.ipv6,
230            sizeof(a->addr.sin6.sin6_addr));
231     a->addr.sin6.sin6_port = s->addr.port;
232 #ifdef SOCK_HAS_IPV4
233   } else if (s->addr.family == AF_INET) {
234     a->addr.sa.sa_family = s->addr.family;
235     a->size = (socklen_t)sizeof(a->addr.sin);
236     memcpy(&a->addr.sin.sin_addr, &s->addr.ipv4, sizeof(a->addr.sin.sin_addr));
237     a->addr.sin.sin_port = s->addr.port;
238 #endif /* SOCK_HAS_IPV4 */
239   }
240 #else /* ! WITH_CONTIKI && ! WITH_LWIP && ! WITH_RIOT_SOCK */
241   if (s->addr.sa.sa_family == AF_INET6) {
242     a->size = (socklen_t)sizeof(a->addr.sin6);
243     a->addr.sin6 = s->addr.sin6;
244   } else if (s->addr.sa.sa_family == AF_INET) {
245     a->size = (socklen_t)sizeof(a->addr.sin);
246     a->addr.sin = s->addr.sin;
247   } else {
248     a->size = (socklen_t)s->size;
249     a->addr.sa = s->addr.sa;
250   }
251 #endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! WITH_RIOT_SOCK */
252 }
253 
254 static void
put_session_addr(const coap_address_t * a,session_t * s)255 put_session_addr(const coap_address_t *a, session_t *s) {
256 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
257   s->size = (unsigned char)sizeof(s->addr);
258   s->addr = a->addr;
259   s->port = a->port;
260 #elif defined(WITH_RIOT_SOCK)
261   if (a->addr.sa.sa_family == AF_INET6) {
262     s->size = (socklen_t)sizeof(s->addr.ipv6);
263     s->addr.family = a->addr.sa.sa_family;
264     memcpy(&s->addr.ipv6, &a->addr.sin6.sin6_addr,
265            sizeof(s->addr.ipv6));
266     s->addr.port = a->addr.sin6.sin6_port;
267 #ifdef SOCK_HAS_IPV4
268   } else if (a->addr.sa.sa_family == AF_INET) {
269     s->size = (socklen_t)sizeof(s->addr.ipv4);
270     s->addr.family = a->addr.sa.sa_family;
271     memcpy(&a->addr.ipv4, &s->addr.sin.sin_addr, sizeof(a->addr.ipv4));
272     s->addr.port = a->addr.sin.sin_port;
273 #endif /* SOCK_HAS_IPV4 */
274   }
275 #else /* ! WITH_CONTIKI && ! WITH_LWIP && ! WITH_RIOT_SOCK */
276   if (a->addr.sa.sa_family == AF_INET6) {
277     s->size = (socklen_t)sizeof(s->addr.sin6);
278     s->addr.sin6 = a->addr.sin6;
279   } else if (a->addr.sa.sa_family == AF_INET) {
280     s->size = (socklen_t)sizeof(s->addr.sin);
281     s->addr.sin = a->addr.sin;
282   } else {
283     s->size = (socklen_t)a->size;
284     s->addr.sa = a->addr.sa;
285   }
286 #endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! WITH_RIOT_SOCK */
287 }
288 
289 static int
dtls_send_to_peer(struct dtls_context_t * dtls_context,session_t * dtls_session,uint8 * data,size_t len)290 dtls_send_to_peer(struct dtls_context_t *dtls_context,
291                   session_t *dtls_session, uint8 *data, size_t len) {
292   coap_tiny_context_t *t_context =
293       (coap_tiny_context_t *)dtls_get_app_data(dtls_context);
294   coap_context_t *coap_context = t_context ? t_context->coap_context : NULL;
295   coap_session_t *coap_session;
296   coap_address_t remote_addr;
297 
298   assert(coap_context);
299   get_session_addr(dtls_session, &remote_addr);
300   coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
301   if (!coap_session) {
302     coap_log_warn("dtls_send_to_peer: cannot find local interface\n");
303     return -3;
304   }
305   return (int)coap_session->sock.lfunc[COAP_LAYER_TLS].l_write(coap_session,
306          data, len);
307 }
308 
309 static int
dtls_application_data(struct dtls_context_t * dtls_context,session_t * dtls_session,uint8 * data,size_t len)310 dtls_application_data(struct dtls_context_t *dtls_context,
311                       session_t *dtls_session, uint8 *data, size_t len) {
312   coap_tiny_context_t *t_context =
313       (coap_tiny_context_t *)dtls_get_app_data(dtls_context);
314   coap_context_t *coap_context = t_context ? t_context->coap_context : NULL;
315   coap_session_t *coap_session;
316   coap_address_t remote_addr;
317 
318   assert(coap_context);
319   get_session_addr(dtls_session, &remote_addr);
320   coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
321   if (!coap_session) {
322     coap_log_debug("dropped message that was received on invalid interface\n");
323     return -1;
324   }
325 
326   return coap_handle_dgram(coap_context, coap_session, data, len);
327 }
328 
329 static int coap_event_dtls = 0;
330 
331 static int
dtls_event(struct dtls_context_t * dtls_context,session_t * dtls_session,dtls_alert_level_t level,uint16_t code)332 dtls_event(struct dtls_context_t *dtls_context,
333            session_t *dtls_session,
334            dtls_alert_level_t level,
335            uint16_t code) {
336   (void)dtls_context;
337   (void)dtls_session;
338 
339   if (level == DTLS_ALERT_LEVEL_FATAL)
340     coap_event_dtls = COAP_EVENT_DTLS_ERROR;
341 
342   /* handle DTLS events */
343   switch (code) {
344   case DTLS_ALERT_CLOSE_NOTIFY: {
345     coap_event_dtls = COAP_EVENT_DTLS_CLOSED;
346     break;
347   }
348   case DTLS_EVENT_CONNECTED: {
349     coap_event_dtls = COAP_EVENT_DTLS_CONNECTED;
350     break;
351   }
352 #ifdef DTLS_EVENT_RENEGOTIATE
353   case DTLS_EVENT_RENEGOTIATE: {
354     coap_event_dtls = COAP_EVENT_DTLS_RENEGOTIATE;
355     break;
356   }
357 #endif
358   default:
359     ;
360   }
361 
362   return 0;
363 }
364 
365 #ifdef DTLS_PSK
366 /* This function is the "key store" for tinyDTLS. It is called to
367  * retrieve a key for the given identity within this particular
368  * session. */
369 static int
get_psk_info(struct dtls_context_t * dtls_context,const session_t * dtls_session,dtls_credentials_type_t type,const uint8_t * id,size_t id_len,unsigned char * result,size_t result_length)370 get_psk_info(struct dtls_context_t *dtls_context,
371              const session_t *dtls_session,
372              dtls_credentials_type_t type,
373              const uint8_t *id, size_t id_len,
374              unsigned char *result, size_t result_length) {
375 
376   coap_tiny_context_t *t_context =
377       (coap_tiny_context_t *)dtls_get_app_data(dtls_context);
378   coap_context_t *coap_context = t_context ? t_context->coap_context : NULL;
379   coap_session_t *coap_session;
380   int fatal_error = DTLS_ALERT_INTERNAL_ERROR;
381   coap_address_t remote_addr;
382 #if COAP_CLIENT_SUPPORT
383   coap_dtls_cpsk_t *setup_cdata;
384   const coap_bin_const_t *psk_identity;
385   const coap_dtls_cpsk_info_t *cpsk_info;
386 #endif /* COAP_CLIENT_SUPPORT */
387   const coap_bin_const_t *psk_key;
388 #if COAP_SERVER_SUPPORT
389   coap_dtls_spsk_t *setup_sdata;
390   const coap_bin_const_t *psk_hint;
391 #endif /* COAP_SERVER_SUPPORT */
392 
393   assert(coap_context);
394   get_session_addr(dtls_session, &remote_addr);
395   coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
396   if (!coap_session) {
397     coap_log_debug("cannot get PSK, session not found\n");
398     goto error;
399   }
400 
401   switch (type) {
402   case DTLS_PSK_IDENTITY:
403 
404 #if COAP_CLIENT_SUPPORT
405     if (coap_session->type != COAP_SESSION_TYPE_CLIENT)
406       goto error;
407 
408     setup_cdata = &coap_session->cpsk_setup_data;
409 
410     coap_bin_const_t temp;
411     temp.s = id;
412     temp.length = id_len;
413     coap_session_refresh_psk_hint(coap_session, &temp);
414 
415     coap_log_debug("got psk_identity_hint: '%.*s'\n", (int)id_len,
416                    id ? (const char *)id : "");
417 
418     if (setup_cdata->validate_ih_call_back) {
419       coap_str_const_t lhint;
420 
421       lhint.length = id_len;
422       lhint.s = id;
423       cpsk_info =
424           setup_cdata->validate_ih_call_back(&lhint,
425                                              coap_session,
426                                              setup_cdata->ih_call_back_arg);
427       if (cpsk_info) {
428         psk_identity = &cpsk_info->identity;
429         coap_session_refresh_psk_identity(coap_session, &cpsk_info->identity);
430         coap_session_refresh_psk_key(coap_session, &cpsk_info->key);
431       } else {
432         psk_identity = NULL;
433       }
434     } else {
435       psk_identity = coap_get_session_client_psk_identity(coap_session);
436     }
437     if (psk_identity == NULL) {
438       coap_log_warn("no PSK identity given\n");
439       fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
440       goto error;
441     }
442     if (psk_identity->length > result_length) {
443       coap_log_warn("psk_identity too large, truncated to %zd bytes\n",
444                     result_length);
445     } else {
446       /* Reduce to match */
447       result_length = psk_identity->length;
448     }
449     memcpy(result, psk_identity->s, result_length);
450     return result_length;
451 #else /* ! COAP_CLIENT_SUPPORT */
452     return 0;
453 #endif /* ! COAP_CLIENT_SUPPORT */
454 
455   case DTLS_PSK_KEY:
456 #if COAP_CLIENT_SUPPORT
457     if (coap_session->type == COAP_SESSION_TYPE_CLIENT) {
458       psk_key = coap_get_session_client_psk_key(coap_session);
459       if (psk_key == NULL) {
460         coap_log_warn("no PSK key given\n");
461         fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
462         goto error;
463       }
464       if (psk_key->length > result_length) {
465         coap_log_warn("psk_key too large, truncated to %zd bytes\n",
466                       result_length);
467       } else {
468         /* Reduce to match */
469         result_length = psk_key->length;
470       }
471       memcpy(result, psk_key->s, result_length);
472       return result_length;
473     }
474 #endif /* COAP_CLIENT_SUPPORT */
475 #if COAP_SERVER_SUPPORT
476     if (coap_session->type != COAP_SESSION_TYPE_CLIENT) {
477       coap_bin_const_t lidentity;
478 
479       lidentity.length = id ? id_len : 0;
480       lidentity.s = id ? (const uint8_t *)id : (const uint8_t *)"";
481       setup_sdata = &coap_session->context->spsk_setup_data;
482 
483       /* Track the Identity being used */
484       coap_session_refresh_psk_identity(coap_session, &lidentity);
485 
486       coap_log_debug("got psk_identity: '%.*s'\n",
487                      (int)lidentity.length, lidentity.s);
488 
489       if (setup_sdata->validate_id_call_back) {
490         psk_key =
491             setup_sdata->validate_id_call_back(&lidentity,
492                                                coap_session,
493                                                setup_sdata->id_call_back_arg);
494       } else {
495         psk_key = coap_get_session_server_psk_key(coap_session);
496       }
497 
498       if (psk_key == NULL) {
499         coap_log_warn("no PSK key given\n");
500         return 0;
501       }
502       if (setup_sdata->validate_id_call_back)
503         coap_session_refresh_psk_key(coap_session, psk_key);
504       if (psk_key->length > result_length) {
505         coap_log_warn("psk_key too large, truncated to %zd bytes\n",
506                       result_length);
507       } else {
508         /* Reduce to match */
509         result_length = psk_key->length;
510       }
511       memcpy(result, psk_key->s, result_length);
512       return result_length;
513     }
514 #endif /* COAP_SERVER_SUPPORT */
515     return 0;
516 
517   case DTLS_PSK_HINT:
518 #if COAP_SERVER_SUPPORT
519     psk_hint = coap_get_session_server_psk_hint(coap_session);
520     if (psk_hint == NULL)
521       return 0;
522     if (psk_hint->length > result_length) {
523       coap_log_warn("psk_hint too large, truncated to %zd bytes\n",
524                     result_length);
525     } else {
526       /* Reduce to match */
527       result_length = psk_hint->length;
528     }
529     memcpy(result, psk_hint->s, result_length);
530     return result_length;
531 #else /* COAP_SERVER_SUPPORT */
532     return 0;
533 #endif /* COAP_SERVER_SUPPORT */
534 
535   default:
536     coap_log_warn("unsupported request type: %d\n", type);
537   }
538 
539 error:
540   return dtls_alert_fatal_create(fatal_error);
541 }
542 #endif /* DTLS_PSK */
543 
544 #ifdef DTLS_ECC
545 static int
get_ecdsa_key(struct dtls_context_t * dtls_context,const session_t * dtls_session COAP_UNUSED,const dtls_ecdsa_key_t ** result)546 get_ecdsa_key(struct dtls_context_t *dtls_context,
547               const session_t *dtls_session COAP_UNUSED,
548               const dtls_ecdsa_key_t **result) {
549   static dtls_ecdsa_key_t ecdsa_key;
550   coap_tiny_context_t *t_context =
551       (coap_tiny_context_t *)dtls_get_app_data(dtls_context);
552 
553   ecdsa_key.curve = DTLS_ECDH_CURVE_SECP256R1;
554   ecdsa_key.priv_key = t_context->priv_key->s;
555   ecdsa_key.pub_key_x = t_context->pub_key->s;
556   ecdsa_key.pub_key_y = &t_context->pub_key->s[DTLS_EC_KEY_SIZE];
557 
558   *result = &ecdsa_key;
559   return 0;
560 }
561 
562 /* first part of Raw public key, the is the start of the Subject Public Key */
563 static const unsigned char cert_asn1_header[] = {
564   0x30, 0x59, /* SEQUENCE, length 89 bytes */
565   0x30, 0x13, /* SEQUENCE, length 19 bytes */
566   0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */
567   0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
568   0x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */
569   0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
570   0x03, 0x42, 0x00, /* BIT STRING, length 66 bytes, 0 bits unused */
571   0x04 /* uncompressed, followed by the r and s values of the public key */
572 };
573 #define DTLS_CE_LENGTH (sizeof(cert_asn1_header) + key_size + key_size)
574 
575 static int
verify_ecdsa_key(struct dtls_context_t * dtls_context COAP_UNUSED,const session_t * dtls_session COAP_UNUSED,const uint8_t * other_pub_x,const uint8_t * other_pub_y,size_t key_size)576 verify_ecdsa_key(struct dtls_context_t *dtls_context COAP_UNUSED,
577                  const session_t *dtls_session COAP_UNUSED,
578                  const uint8_t *other_pub_x,
579                  const uint8_t *other_pub_y,
580                  size_t key_size) {
581   coap_tiny_context_t *t_context =
582       (coap_tiny_context_t *)dtls_get_app_data(dtls_context);
583   if (t_context && t_context->setup_data.validate_cn_call_back) {
584     /* Need to build asn.1 certificate - code taken from tinydtls */
585     uint8 *p;
586     uint8 buf[DTLS_CE_LENGTH];
587     coap_session_t *c_session;
588     coap_address_t remote_addr;
589 
590     /* Certificate
591      *
592      * Start message construction at beginning of buffer. */
593     p = buf;
594 
595     memcpy(p, &cert_asn1_header, sizeof(cert_asn1_header));
596     p += sizeof(cert_asn1_header);
597 
598     memcpy(p, other_pub_x, key_size);
599     p += key_size;
600 
601     memcpy(p, other_pub_y, key_size);
602     p += key_size;
603 
604     assert(p <= (buf + sizeof(buf)));
605 
606     get_session_addr(dtls_session, &remote_addr);
607     c_session = coap_session_get_by_peer(t_context->coap_context,
608                                          &remote_addr, dtls_session->ifindex);
609     if (!c_session)
610       return -3;
611     if (!t_context->setup_data.validate_cn_call_back(COAP_DTLS_RPK_CERT_CN,
612                                                      buf, p-buf, c_session, 0, 1, t_context->setup_data.cn_call_back_arg)) {
613       return -1;
614     }
615   }
616   return 0;
617 }
618 static dtls_handler_t ec_cb = {
619   .write = dtls_send_to_peer,
620   .read = dtls_application_data,
621   .event = dtls_event,
622 #ifdef DTLS_PSK
623   .get_psk_info = NULL,
624 #endif /* DTLS_PSK */
625   .get_ecdsa_key = get_ecdsa_key,
626   .verify_ecdsa_key = verify_ecdsa_key
627 };
628 #endif /* DTLS_ECC */
629 
630 static dtls_handler_t psk_cb = {
631   .write = dtls_send_to_peer,
632   .read = dtls_application_data,
633   .event = dtls_event,
634 #ifdef DTLS_PSK
635   .get_psk_info = get_psk_info,
636 #endif /* DTLS_PSK */
637 #ifdef DTLS_ECC
638   .get_ecdsa_key = NULL,
639   .verify_ecdsa_key = NULL
640 #endif /* DTLS_ECC */
641 };
642 
643 void *
coap_dtls_new_context(coap_context_t * coap_context)644 coap_dtls_new_context(coap_context_t *coap_context) {
645   coap_tiny_context_t *t_context = coap_malloc_type(COAP_DTLS_CONTEXT, sizeof(coap_tiny_context_t));
646   struct dtls_context_t *dtls_context = t_context ? dtls_new_context(t_context) : NULL;
647   if (!dtls_context)
648     goto error;
649   memset(t_context, 0, sizeof(coap_tiny_context_t));
650   t_context->coap_context = coap_context;
651   t_context->dtls_context = dtls_context;
652   dtls_set_handler(dtls_context, &psk_cb);
653   return t_context;
654 error:
655   if (t_context)
656     coap_free_type(COAP_DTLS_CONTEXT, t_context);
657   if (dtls_context)
658     coap_dtls_free_context(dtls_context);
659   return NULL;
660 }
661 
662 void
coap_dtls_free_context(void * handle)663 coap_dtls_free_context(void *handle) {
664   if (handle) {
665     coap_tiny_context_t *t_context = (coap_tiny_context_t *)handle;
666 #ifdef DTLS_ECC
667     if (t_context->priv_key) {
668       coap_delete_binary(t_context->priv_key);
669       t_context->priv_key = NULL;
670     }
671     if (t_context->pub_key) {
672       coap_delete_binary(t_context->pub_key);
673       t_context->pub_key = NULL;
674     }
675 #endif /* DTLS_ECC */
676     if (t_context->dtls_context)
677       dtls_free_context(t_context->dtls_context);
678     coap_free_type(COAP_DTLS_CONTEXT, t_context);
679   }
680 }
681 
682 static session_t *
coap_dtls_new_session(coap_session_t * session)683 coap_dtls_new_session(coap_session_t *session) {
684   session_t *dtls_session = coap_malloc_type(COAP_DTLS_SESSION, sizeof(session_t));
685 
686   if (dtls_session) {
687     /* create tinydtls session object from remote address and local
688     * endpoint handle */
689     dtls_session_init(dtls_session);
690     put_session_addr(&session->addr_info.remote, dtls_session);
691     dtls_session->ifindex = session->ifindex;
692     coap_log_debug("***new session %p\n", (void *)dtls_session);
693   }
694 
695   return dtls_session;
696 }
697 
698 #if COAP_SERVER_SUPPORT
699 void *
coap_dtls_new_server_session(coap_session_t * session)700 coap_dtls_new_server_session(coap_session_t *session) {
701   return coap_dtls_new_session(session);
702 }
703 #endif /* COAP_SERVER_SUPPORT */
704 
705 #if COAP_CLIENT_SUPPORT
706 void *
coap_dtls_new_client_session(coap_session_t * session)707 coap_dtls_new_client_session(coap_session_t *session) {
708   dtls_peer_t *peer;
709   coap_tiny_context_t *t_context = (coap_tiny_context_t *)session->context->dtls_context;
710   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
711   session_t *dtls_session = dtls_context ? coap_dtls_new_session(session) : NULL;
712 
713   if (!dtls_session)
714     return NULL;
715   peer =
716       dtls_get_peer(dtls_context, dtls_session);
717 
718   if (!peer) {
719     /* The peer connection does not yet exist. */
720     /* dtls_connect() returns a value greater than zero if a new
721     * connection attempt is made, 0 for session reuse. */
722     if (dtls_connect(dtls_context, dtls_session) >= 0) {
723       peer =
724           dtls_get_peer(dtls_context, dtls_session);
725     }
726   }
727 
728   if (!peer) {
729     /* delete existing session because the peer object has been invalidated */
730     coap_free_type(COAP_DTLS_SESSION, dtls_session);
731     dtls_session = NULL;
732   }
733 
734   return dtls_session;
735 }
736 #endif /* COAP_CLIENT_SUPPORT */
737 
738 void
coap_dtls_session_update_mtu(coap_session_t * session)739 coap_dtls_session_update_mtu(coap_session_t *session) {
740   (void)session;
741 }
742 
743 void
coap_dtls_free_session(coap_session_t * coap_session)744 coap_dtls_free_session(coap_session_t *coap_session) {
745   coap_tiny_context_t *t_context =
746       (coap_tiny_context_t *)coap_session->context->dtls_context;
747   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
748 
749   if (dtls_context == NULL)
750     return;
751   if (coap_session->tls && dtls_context) {
752     dtls_peer_t *peer = dtls_get_peer(dtls_context, (session_t *)coap_session->tls);
753     if (peer)
754       dtls_reset_peer(dtls_context, peer);
755     else
756       dtls_close(dtls_context, (session_t *)coap_session->tls);
757     coap_log_debug("***removed session %p\n", coap_session->tls);
758     coap_free_type(COAP_DTLS_SESSION, coap_session->tls);
759     coap_session->tls = NULL;
760     coap_handle_event(coap_session->context, COAP_EVENT_DTLS_CLOSED, coap_session);
761   }
762 }
763 
764 ssize_t
coap_dtls_send(coap_session_t * session,const uint8_t * data,size_t data_len)765 coap_dtls_send(coap_session_t *session,
766                const uint8_t *data,
767                size_t data_len) {
768   int res;
769   uint8_t *data_rw;
770   coap_tiny_context_t *t_context = (coap_tiny_context_t *)session->context->dtls_context;
771   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
772 
773   assert(dtls_context);
774 
775   coap_event_dtls = -1;
776   /* Need to do this to not get a compiler warning about const parameters */
777   memcpy(&data_rw, &data, sizeof(data_rw));
778   res = dtls_write(dtls_context,
779                    (session_t *)session->tls, data_rw, data_len);
780 
781   if (res < 0)
782     coap_log_warn("coap_dtls_send: cannot send PDU\n");
783 
784   if (coap_event_dtls >= 0) {
785     /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
786     if (coap_event_dtls != COAP_EVENT_DTLS_CLOSED)
787       coap_handle_event(session->context, coap_event_dtls, session);
788     if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
789       coap_session_connected(session);
790     else if (coap_event_dtls == COAP_EVENT_DTLS_CLOSED || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
791       coap_session_disconnected(session, COAP_NACK_TLS_FAILED);
792   }
793 
794   if (res > 0) {
795     if (res == (ssize_t)data_len)
796       coap_log_debug("*  %s: dtls:  sent %4d bytes\n",
797                      coap_session_str(session), res);
798     else
799       coap_log_debug("*  %s: dtls:  sent %4d of %4zd bytes\n",
800                      coap_session_str(session), res, data_len);
801   }
802   return res;
803 }
804 
805 int
coap_dtls_is_context_timeout(void)806 coap_dtls_is_context_timeout(void) {
807   return 1;
808 }
809 
810 coap_tick_t
coap_dtls_get_context_timeout(void * tiny_context)811 coap_dtls_get_context_timeout(void *tiny_context) {
812   clock_time_t next = 0;
813   coap_tiny_context_t *t_context = (coap_tiny_context_t *)tiny_context;
814   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
815   if (tiny_context)
816     dtls_check_retransmit(dtls_context, &next);
817   if (next > 0)
818     return ((coap_tick_t)(next - dtls_tick_0)) * COAP_TICKS_PER_SECOND / DTLS_TICKS_PER_SECOND +
819            coap_tick_0;
820   return 0;
821 }
822 
823 coap_tick_t
coap_dtls_get_timeout(coap_session_t * session,coap_tick_t now)824 coap_dtls_get_timeout(coap_session_t *session, coap_tick_t now) {
825   (void)session;
826   (void)now;
827   return 0;
828 }
829 
830 /*
831  * return 1 timed out
832  *        0 still timing out
833  */
834 int
coap_dtls_handle_timeout(coap_session_t * session)835 coap_dtls_handle_timeout(coap_session_t *session) {
836   (void)session;
837   return 0;
838 }
839 
840 int
coap_dtls_receive(coap_session_t * session,const uint8_t * data,size_t data_len)841 coap_dtls_receive(coap_session_t *session,
842                   const uint8_t *data,
843                   size_t data_len
844                  ) {
845   session_t *dtls_session = (session_t *)session->tls;
846   int err;
847   uint8_t *data_rw;
848   coap_tiny_context_t *t_context = (coap_tiny_context_t *)session->context->dtls_context;
849   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
850 
851   assert(dtls_context);
852   coap_event_dtls = -1;
853   /* Need to do this to not get a compiler warning about const parameters */
854   memcpy(&data_rw, &data, sizeof(data_rw));
855   err = dtls_handle_message(dtls_context, dtls_session, data_rw, (int)data_len);
856 
857   if (err) {
858     coap_event_dtls = COAP_EVENT_DTLS_ERROR;
859   }
860 
861   if (coap_event_dtls >= 0) {
862     /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
863     if (coap_event_dtls != COAP_EVENT_DTLS_CLOSED)
864       coap_handle_event(session->context, coap_event_dtls, session);
865     if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
866       coap_session_connected(session);
867     else if (coap_event_dtls == COAP_EVENT_DTLS_CLOSED || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
868       coap_session_disconnected(session, COAP_NACK_TLS_FAILED);
869   }
870 
871   return err;
872 }
873 
874 #if COAP_SERVER_SUPPORT
875 int
coap_dtls_hello(coap_session_t * session,const uint8_t * data,size_t data_len)876 coap_dtls_hello(coap_session_t *session,
877                 const uint8_t *data,
878                 size_t data_len
879                ) {
880   session_t dtls_session;
881   coap_tiny_context_t *t_context = (coap_tiny_context_t *)session->context->dtls_context;
882   dtls_context_t *dtls_context = t_context ? t_context->dtls_context : NULL;
883   uint8_t *data_rw;
884 
885   assert(dtls_context);
886   dtls_session_init(&dtls_session);
887   put_session_addr(&session->addr_info.remote, &dtls_session);
888   dtls_session.ifindex = session->ifindex;
889   /* Need to do this to not get a compiler warning about const parameters */
890   memcpy(&data_rw, &data, sizeof(data_rw));
891   int res = dtls_handle_message(dtls_context, &dtls_session,
892                                 data_rw, (int)data_len);
893   if (res >= 0) {
894     if (dtls_get_peer(dtls_context, &dtls_session))
895       res = 1;
896     else
897       res = 0;
898   }
899   return res;
900 }
901 #endif /* COAP_SERVER_SUPPORT */
902 
903 unsigned int
coap_dtls_get_overhead(coap_session_t * session)904 coap_dtls_get_overhead(coap_session_t *session) {
905   (void)session;
906   return 13 + 8 + 8;
907 }
908 
909 int
coap_tls_is_supported(void)910 coap_tls_is_supported(void) {
911   return 0;
912 }
913 
914 coap_tls_version_t *
coap_get_tls_library_version(void)915 coap_get_tls_library_version(void) {
916   static coap_tls_version_t version;
917   const char *vers = dtls_package_version();
918 
919   version.version = 0;
920   if (vers) {
921     long int p1, p2 = 0, p3 = 0;
922     char *endptr;
923 
924     p1 = strtol(vers, &endptr, 10);
925     if (*endptr == '.') {
926       p2 = strtol(endptr+1, &endptr, 10);
927       if (*endptr == '.') {
928         p3 = strtol(endptr+1, &endptr, 10);
929       }
930     }
931     version.version = (p1 << 16) | (p2 << 8) | p3;
932   }
933   version.built_version = version.version;
934   version.type = COAP_TLS_LIBRARY_TINYDTLS;
935   return &version;
936 }
937 
938 #ifdef DTLS_ECC
939 static const uint8_t b64_6[256] = {
940   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
941   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
942   /*                                           +               / */
943   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
944   /* 0 1   2   3   4   5   6   7   8   9               =         */
945   52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
946   /*   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O */
947   64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
948   /* P Q   R   S   T   U   V   W   X   Y   Z                     */
949   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
950   /*   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o */
951   64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
952   /* p q   r   s   t   u   v   w   x   y   z                     */
953   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
954   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
955   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
956   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
957   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
958   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
959   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
960   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
961   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
962 };
963 
964 /* caller must free off returned coap_binary_t* */
965 static coap_binary_t *
pem_base64_decode(const uint8_t * data,size_t size)966 pem_base64_decode(const uint8_t *data, size_t size) {
967   uint8_t *tbuf = coap_malloc_type(COAP_STRING, size);
968   size_t nbytesdecoded;
969   size_t i;
970   coap_binary_t *decoded;
971   uint8_t *ptr;
972   uint8_t *out;
973   size_t nb64bytes = 0;
974 
975   for (i = 0; i < size; i++) {
976     switch (data[i]) {
977     case ' ':
978     case '\r':
979     case '\n':
980     case '\t':
981       break;
982     default:
983       if (b64_6[data[i]] == 64)
984         goto end;
985       tbuf[nb64bytes++] = data[i];
986       break;
987     }
988   }
989 
990 end:
991   nbytesdecoded = ((nb64bytes + 3) / 4) * 3;
992   decoded = coap_new_binary(nbytesdecoded + 1);
993   if (!decoded)
994     return NULL;
995 
996   out = decoded->s;
997   ptr = tbuf;
998 
999   while (nb64bytes > 4) {
1000     *(out++) = b64_6[ptr[0]] << 2 | b64_6[ptr[1]] >> 4;
1001     *(out++) = b64_6[ptr[1]] << 4 | b64_6[ptr[2]] >> 2;
1002     *(out++) = b64_6[ptr[2]] << 6 | b64_6[ptr[3]];
1003     ptr += 4;
1004     nb64bytes -= 4;
1005   }
1006 
1007   /* Note: (nb64bytes == 1) is an error */
1008   if (nb64bytes > 1) {
1009     *(out++) = b64_6[ptr[0]] << 2 | b64_6[ptr[1]] >> 4;
1010   }
1011   if (nb64bytes > 2) {
1012     *(out++) = b64_6[ptr[1]] << 4 | b64_6[ptr[2]] >> 2;
1013   }
1014   if (nb64bytes > 3) {
1015     *(out++) = b64_6[ptr[2]] << 6 | b64_6[ptr[3]];
1016   }
1017 
1018   decoded->length = nbytesdecoded - ((4 - nb64bytes) & 3);
1019   coap_free_type(COAP_STRING, tbuf);
1020   return decoded;
1021 }
1022 
1023 typedef coap_binary_t *(*asn1_callback)(const uint8_t *data, size_t size);
1024 
1025 static int
asn1_verify_privkey(const uint8_t * data,size_t size)1026 asn1_verify_privkey(const uint8_t *data, size_t size) {
1027   /* Check if we have the private key (with optional leading 0x00) */
1028   /* skip leading 0x00 */
1029   if (size - 1 == DTLS_EC_KEY_SIZE && *data == '\000') {
1030     --size;
1031     ++data;
1032   }
1033 
1034   /* Check if we have the private key */
1035   if (size != DTLS_EC_KEY_SIZE)
1036     return 0;
1037 
1038   return 1;
1039 }
1040 
1041 static int
asn1_verify_pubkey(const uint8_t * data,size_t size)1042 asn1_verify_pubkey(const uint8_t *data, size_t size) {
1043   (void)data;
1044 
1045   /* We have the public key
1046      (with a leading 0x00 (no unused bits) 0x04 (not compressed() */
1047   if (size - 2 != 2 * DTLS_EC_KEY_SIZE)
1048     return 0;
1049 
1050   return 1;
1051 }
1052 
1053 static int
asn1_verify_curve(const uint8_t * data,size_t size)1054 asn1_verify_curve(const uint8_t *data, size_t size) {
1055   static uint8_t prime256v1_oid[] =
1056       /* OID 1.2.840.10045.3.1.7 */
1057   { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 };
1058 
1059   /* Check that we have the correct EC (only one supported) */
1060   if (size != sizeof(prime256v1_oid) ||
1061       memcmp(data, prime256v1_oid, size) != 0)
1062     return 0;
1063 
1064   return 1;
1065 }
1066 
1067 static int
asn1_verify_pkcs8_version(const uint8_t * data,size_t size)1068 asn1_verify_pkcs8_version(const uint8_t *data, size_t size) {
1069   /* Check that we have the version */
1070   if (size != 1 || *data != 0)
1071     return 0;
1072 
1073   return 1;
1074 }
1075 
1076 static int
asn1_verify_ec_identifier(const uint8_t * data,size_t size)1077 asn1_verify_ec_identifier(const uint8_t *data, size_t size) {
1078   static uint8_t ec_public_key_oid[] =
1079       /* OID 1.2.840.10045.2.1 */
1080   { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 };
1081 
1082   /* Check that we have the correct ecPublicKey */
1083   if (size != sizeof(ec_public_key_oid) ||
1084       memcmp(data, ec_public_key_oid, size) != 0)
1085     return 0;
1086 
1087   return 1;
1088 }
1089 
1090 static int
asn1_verify_ec_key(const uint8_t * data,size_t size)1091 asn1_verify_ec_key(const uint8_t *data, size_t size) {
1092   (void)data;
1093 
1094   if (size == 0)
1095     return 0;
1096 
1097   return 1;
1098 }
1099 
1100 static int
asn1_derive_keys(coap_tiny_context_t * t_context,const uint8_t * priv_data,size_t priv_len,const uint8_t * pub_data,size_t pub_len,int is_pkcs8)1101 asn1_derive_keys(coap_tiny_context_t *t_context,
1102                  const uint8_t *priv_data, size_t priv_len,
1103                  const uint8_t *pub_data, size_t pub_len,
1104                  int is_pkcs8) {
1105   coap_binary_t *test;
1106 
1107   t_context->priv_key = get_asn1_tag(COAP_ASN1_OCTETSTRING, priv_data,
1108                                      priv_len, asn1_verify_privkey);
1109   if (!t_context->priv_key) {
1110     coap_log_info("EC Private Key (RPK) invalid\n");
1111     return 0;
1112   }
1113   /* skip leading 0x00 */
1114   if (t_context->priv_key->length - 1 == DTLS_EC_KEY_SIZE &&
1115       t_context->priv_key->s[0] == '\000') {
1116     t_context->priv_key->length--;
1117     t_context->priv_key->s++;
1118   }
1119 
1120   if (!is_pkcs8) {
1121     /* pkcs8 abstraction tested for valid eliptic curve */
1122     test = get_asn1_tag(COAP_ASN1_IDENTIFIER, priv_data, priv_len,
1123                         asn1_verify_curve);
1124     if (!test) {
1125       coap_log_info("EC Private Key (RPK) invalid elliptic curve\n");
1126       coap_delete_binary(t_context->priv_key);
1127       t_context->priv_key = NULL;
1128       return 0;
1129     }
1130     coap_delete_binary(test);
1131   }
1132 
1133   t_context->pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, pub_data, pub_len,
1134                                     asn1_verify_pubkey);
1135   if (!t_context->pub_key) {
1136     coap_log_info("EC Public Key (RPK) invalid\n");
1137     coap_delete_binary(t_context->priv_key);
1138     t_context->priv_key = NULL;
1139     return 0;
1140   }
1141   /* Drop leading 0x00 and 0x04 */
1142   t_context->pub_key->s += 2;
1143   t_context->pub_key->length -= 2;
1144   dtls_set_handler(t_context->dtls_context, &ec_cb);
1145   return 1;
1146 }
1147 
1148 static coap_binary_t *
ec_abstract_pkcs8_asn1(const uint8_t * asn1_ptr,size_t asn1_length)1149 ec_abstract_pkcs8_asn1(const uint8_t *asn1_ptr, size_t asn1_length) {
1150   coap_binary_t *test;
1151 
1152   test = get_asn1_tag(COAP_ASN1_INTEGER, asn1_ptr, asn1_length,
1153                       asn1_verify_pkcs8_version);
1154   if (!test)
1155     return 0;
1156 
1157   coap_delete_binary(test);
1158 
1159   test = get_asn1_tag(COAP_ASN1_IDENTIFIER, asn1_ptr, asn1_length,
1160                       asn1_verify_ec_identifier);
1161   if (!test)
1162     return 0;
1163   coap_delete_binary(test);
1164 
1165   test = get_asn1_tag(COAP_ASN1_IDENTIFIER, asn1_ptr, asn1_length,
1166                       asn1_verify_curve);
1167   if (!test) {
1168     coap_log_info("EC Private Key (RPK) invalid elliptic curve\n");
1169     return 0;
1170   }
1171   coap_delete_binary(test);
1172 
1173   test = get_asn1_tag(COAP_ASN1_OCTETSTRING, asn1_ptr, asn1_length,
1174                       asn1_verify_ec_key);
1175   return test;
1176 }
1177 
1178 static coap_binary_t *
pem_decode_mem_asn1(const char * begstr,const uint8_t * str)1179 pem_decode_mem_asn1(const char *begstr, const uint8_t *str) {
1180   char *bcp = str ? strstr((const char *)str, begstr) : NULL;
1181   char *tcp = bcp ? strstr(bcp, "-----END ") : NULL;
1182 
1183   if (bcp && tcp) {
1184     bcp += strlen(begstr);
1185     return pem_base64_decode((const uint8_t *)bcp, tcp - bcp);
1186   }
1187   return NULL;
1188 }
1189 
1190 #endif /* DTLS_ECC */
1191 
1192 int
coap_dtls_context_set_pki(coap_context_t * ctx,const coap_dtls_pki_t * setup_data,const coap_dtls_role_t role COAP_UNUSED)1193 coap_dtls_context_set_pki(coap_context_t *ctx,
1194                           const coap_dtls_pki_t *setup_data,
1195                           const coap_dtls_role_t role COAP_UNUSED) {
1196 #ifdef DTLS_ECC
1197   coap_tiny_context_t *t_context;
1198   coap_binary_t *asn1_priv;
1199   coap_binary_t *asn1_pub;
1200   coap_binary_t *asn1_temp;
1201   int is_pkcs8 = 0;
1202 
1203   if (!setup_data)
1204     return 0;
1205   if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION)
1206     return 0;
1207   if (!setup_data->is_rpk_not_cert) {
1208     coap_log_warn("Only RPK, not full PKI is supported\n");
1209     return 0;
1210   }
1211   if (!ctx)
1212     return 0;
1213   t_context = (coap_tiny_context_t *)ctx->dtls_context;
1214   if (!t_context)
1215     return 0;
1216   if (t_context->priv_key) {
1217     coap_delete_binary(t_context->priv_key);
1218     t_context->priv_key = NULL;
1219   }
1220   if (t_context->pub_key) {
1221     coap_delete_binary(t_context->pub_key);
1222     t_context->pub_key = NULL;
1223   }
1224   t_context->setup_data = *setup_data;
1225 
1226   /* All should be RPK only now */
1227   switch (setup_data->pki_key.key_type) {
1228   case COAP_PKI_KEY_PEM:
1229     coap_log_warn("RPK keys cannot be in COAP_PKI_KEY_PEM format\n");
1230     break;
1231   case COAP_PKI_KEY_PEM_BUF:
1232     if (setup_data->pki_key.key.pem_buf.public_cert &&
1233         setup_data->pki_key.key.pem_buf.public_cert[0] &&
1234         setup_data->pki_key.key.pem_buf.private_key &&
1235         setup_data->pki_key.key.pem_buf.private_key[0]) {
1236       /* Need to take PEM memory information and convert to binary */
1237       asn1_priv = pem_decode_mem_asn1("-----BEGIN EC PRIVATE KEY-----",
1238                                       setup_data->pki_key.key.pem_buf.private_key);
1239       if (!asn1_priv) {
1240         asn1_priv = pem_decode_mem_asn1("-----BEGIN PRIVATE KEY-----",
1241                                         setup_data->pki_key.key.pem_buf.private_key);
1242         if (!asn1_priv) {
1243           coap_log_info("Private Key (RPK) invalid\n");
1244           return 0;
1245         }
1246         asn1_temp = ec_abstract_pkcs8_asn1(asn1_priv->s, asn1_priv->length);
1247         if (!asn1_temp) {
1248           coap_log_info("PKCS#8 Private Key (RPK) invalid\n");
1249           coap_delete_binary(asn1_priv);
1250           return 0;
1251         }
1252         coap_delete_binary(asn1_priv);
1253         asn1_priv = asn1_temp;
1254         is_pkcs8 = 1;
1255       }
1256       asn1_pub = pem_decode_mem_asn1(
1257                      "-----BEGIN PUBLIC KEY-----",
1258                      setup_data->pki_key.key.pem_buf.public_cert);
1259       if (!asn1_pub) {
1260         asn1_pub = pem_decode_mem_asn1("-----BEGIN EC PRIVATE KEY-----",
1261                                        setup_data->pki_key.key.pem_buf.private_key);
1262         if (!asn1_pub) {
1263           asn1_pub = pem_decode_mem_asn1("-----BEGIN PRIVATE KEY-----",
1264                                          setup_data->pki_key.key.pem_buf.private_key);
1265           if (!asn1_pub) {
1266             coap_log_info("Public Key (RPK) invalid\n");
1267             coap_delete_binary(asn1_priv);
1268             return 0;
1269           }
1270           asn1_temp = ec_abstract_pkcs8_asn1(asn1_pub->s, asn1_pub->length);
1271           if (!asn1_temp) {
1272             coap_log_info("PKCS#8 Private Key (RPK) invalid\n");
1273             coap_delete_binary(asn1_priv);
1274             coap_delete_binary(asn1_pub);
1275             return 0;
1276           }
1277           coap_delete_binary(asn1_pub);
1278           asn1_pub = asn1_temp;
1279           is_pkcs8 = 1;
1280         }
1281       }
1282       if (!asn1_derive_keys(t_context, asn1_priv->s, asn1_priv->length,
1283                             asn1_pub->s, asn1_pub->length, is_pkcs8)) {
1284         coap_log_info("Unable to derive Public/Private Keys\n");
1285         coap_delete_binary(asn1_priv);
1286         coap_delete_binary(asn1_pub);
1287         return 0;
1288       }
1289       coap_delete_binary(asn1_priv);
1290       coap_delete_binary(asn1_pub);
1291       return 1;
1292     }
1293     break;
1294   case COAP_PKI_KEY_ASN1:
1295     if (setup_data->pki_key.key.asn1.private_key &&
1296         setup_data->pki_key.key.asn1.private_key_len &&
1297         setup_data->pki_key.key.asn1.private_key_type == COAP_ASN1_PKEY_EC) {
1298       const uint8_t *private_key = setup_data->pki_key.key.asn1.private_key;
1299       size_t private_key_len = setup_data->pki_key.key.asn1.private_key_len;
1300 
1301       /* Check to see whether this is in pkcs8 format or not */
1302       asn1_temp = ec_abstract_pkcs8_asn1(
1303                       setup_data->pki_key.key.asn1.private_key,
1304                       setup_data->pki_key.key.asn1.private_key_len);
1305       if (asn1_temp) {
1306         private_key = asn1_temp->s;
1307         private_key_len = asn1_temp->length;
1308         is_pkcs8 = 1;
1309       }
1310       /* Need to take ASN1 memory information and convert to binary */
1311       if (setup_data->pki_key.key.asn1.public_cert &&
1312           setup_data->pki_key.key.asn1.public_cert_len) {
1313         if (!asn1_derive_keys(t_context,
1314                               private_key,
1315                               private_key_len,
1316                               setup_data->pki_key.key.asn1.public_cert,
1317                               setup_data->pki_key.key.asn1.public_cert_len,
1318                               is_pkcs8)) {
1319           coap_log_info("Unable to derive Public/Private Keys\n");
1320           if (asn1_temp)
1321             coap_delete_binary(asn1_temp);
1322           return 0;
1323         }
1324       } else {
1325         if (!asn1_derive_keys(t_context,
1326                               private_key,
1327                               private_key_len,
1328                               private_key,
1329                               private_key_len,
1330                               is_pkcs8)) {
1331           coap_log_info("Unable to derive Public/Private Keys\n");
1332           if (asn1_temp)
1333             coap_delete_binary(asn1_temp);
1334           return 0;
1335         }
1336       }
1337       return 1;
1338     }
1339     break;
1340   case COAP_PKI_KEY_PKCS11:
1341     coap_log_warn("RPK keys cannot be in COAP_PKI_KEY_PCKS11 format\n");
1342     break;
1343   default:
1344     break;
1345   }
1346 #else /* ! DTLS_ECC */
1347   (void)ctx;
1348   (void)setup_data;
1349 #endif /* ! DTLS_ECC */
1350   coap_log_warn("TinyDTLS not compiled with ECC support\n");
1351   return 0;
1352 }
1353 
1354 int
coap_dtls_context_set_pki_root_cas(coap_context_t * ctx COAP_UNUSED,const char * ca_file COAP_UNUSED,const char * ca_path COAP_UNUSED)1355 coap_dtls_context_set_pki_root_cas(coap_context_t *ctx COAP_UNUSED,
1356                                    const char *ca_file COAP_UNUSED,
1357                                    const char *ca_path COAP_UNUSED
1358                                   ) {
1359   coap_log_warn("Root CAs PKI not supported\n");
1360   return 0;
1361 }
1362 
1363 #if COAP_CLIENT_SUPPORT
1364 int
coap_dtls_context_set_cpsk(coap_context_t * coap_context COAP_UNUSED,coap_dtls_cpsk_t * setup_data)1365 coap_dtls_context_set_cpsk(coap_context_t *coap_context COAP_UNUSED,
1366                            coap_dtls_cpsk_t *setup_data
1367                           ) {
1368   if (!setup_data)
1369     return 0;
1370 
1371 #ifdef DTLS_PSK
1372   return 1;
1373 #else /* ! DTLS_PSK */
1374   coap_log_warn("TinyDTLS not compiled with PSK support\n");
1375   return 0;
1376 #endif /* ! DTLS_PSK */
1377 }
1378 #endif /* COAP_CLIENT_SUPPORT */
1379 
1380 #if COAP_SERVER_SUPPORT
1381 int
coap_dtls_context_set_spsk(coap_context_t * coap_context COAP_UNUSED,coap_dtls_spsk_t * setup_data)1382 coap_dtls_context_set_spsk(coap_context_t *coap_context COAP_UNUSED,
1383                            coap_dtls_spsk_t *setup_data
1384                           ) {
1385   if (!setup_data)
1386     return 0;
1387 
1388 #ifdef DTLS_PSK
1389   if (setup_data->validate_sni_call_back) {
1390     coap_log_warn("CoAP Server with TinyDTLS does not support SNI selection\n");
1391   }
1392 
1393   return 1;
1394 #else /* ! DTLS_PSK */
1395   coap_log_warn("TinyDTLS not compiled with PSK support\n");
1396   return 0;
1397 #endif /* ! DTLS_PSK */
1398 }
1399 #endif /* COAP_SERVER_SUPPORT */
1400 
1401 int
coap_dtls_context_check_keys_enabled(coap_context_t * ctx COAP_UNUSED)1402 coap_dtls_context_check_keys_enabled(coap_context_t *ctx COAP_UNUSED) {
1403   return 1;
1404 }
1405 
1406 #if !COAP_DISABLE_TCP
1407 #if COAP_CLIENT_SUPPORT
1408 void *
coap_tls_new_client_session(coap_session_t * session COAP_UNUSED)1409 coap_tls_new_client_session(coap_session_t *session COAP_UNUSED) {
1410   return NULL;
1411 }
1412 #endif /* COAP_CLIENT_SUPPORT */
1413 
1414 #if COAP_SERVER_SUPPORT
1415 void *
coap_tls_new_server_session(coap_session_t * session COAP_UNUSED)1416 coap_tls_new_server_session(coap_session_t *session COAP_UNUSED) {
1417   return NULL;
1418 }
1419 #endif /* COAP_SERVER_SUPPORT */
1420 
1421 void
coap_tls_free_session(coap_session_t * coap_session COAP_UNUSED)1422 coap_tls_free_session(coap_session_t *coap_session COAP_UNUSED) {
1423 }
1424 
1425 /*
1426  * strm
1427  * return +ve Number of bytes written.
1428  *         -1 Error (error in errno).
1429  */
1430 ssize_t
coap_tls_write(coap_session_t * session COAP_UNUSED,const uint8_t * data COAP_UNUSED,size_t data_len COAP_UNUSED)1431 coap_tls_write(coap_session_t *session COAP_UNUSED,
1432                const uint8_t *data COAP_UNUSED,
1433                size_t data_len COAP_UNUSED
1434               ) {
1435   return -1;
1436 }
1437 
1438 /*
1439  * strm
1440  * return >=0 Number of bytes read.
1441  *         -1 Error (error in errno).
1442  */
1443 ssize_t
coap_tls_read(coap_session_t * session COAP_UNUSED,uint8_t * data COAP_UNUSED,size_t data_len COAP_UNUSED)1444 coap_tls_read(coap_session_t *session COAP_UNUSED,
1445               uint8_t *data COAP_UNUSED,
1446               size_t data_len COAP_UNUSED) {
1447   errno = ENODEV;
1448   return -1;
1449 }
1450 #endif /* !COAP_DISABLE_TCP */
1451 
1452 #if COAP_SERVER_SUPPORT
1453 coap_digest_ctx_t *
coap_digest_setup(void)1454 coap_digest_setup(void) {
1455   dtls_sha256_ctx *digest_ctx = coap_malloc_type(COAP_STRING, sizeof(dtls_sha256_ctx));
1456 
1457   if (digest_ctx) {
1458     dtls_sha256_init(digest_ctx);
1459   }
1460 
1461   return digest_ctx;
1462 }
1463 
1464 void
coap_digest_free(coap_digest_ctx_t * digest_ctx)1465 coap_digest_free(coap_digest_ctx_t *digest_ctx) {
1466   coap_free_type(COAP_STRING, digest_ctx);
1467 }
1468 
1469 int
coap_digest_update(coap_digest_ctx_t * digest_ctx,const uint8_t * data,size_t data_len)1470 coap_digest_update(coap_digest_ctx_t *digest_ctx,
1471                    const uint8_t *data,
1472                    size_t data_len) {
1473   dtls_sha256_update(digest_ctx, data, data_len);
1474 
1475   return 1;
1476 }
1477 
1478 int
coap_digest_final(coap_digest_ctx_t * digest_ctx,coap_digest_t * digest_buffer)1479 coap_digest_final(coap_digest_ctx_t *digest_ctx,
1480                   coap_digest_t *digest_buffer) {
1481   dtls_sha256_final((uint8_t *)digest_buffer, digest_ctx);
1482 
1483   coap_digest_free(digest_ctx);
1484   return 1;
1485 }
1486 #endif /* COAP_SERVER_SUPPORT */
1487 
1488 #if COAP_WS_SUPPORT
1489 int
coap_crypto_hash(cose_alg_t alg,const coap_bin_const_t * data,coap_bin_const_t ** hash)1490 coap_crypto_hash(cose_alg_t alg,
1491                  const coap_bin_const_t *data,
1492                  coap_bin_const_t **hash) {
1493   (void)alg;
1494   (void)data;
1495   (void)hash;
1496   return 0;
1497 }
1498 #endif /* COAP_WS_SUPPORT */
1499 
1500 #if COAP_OSCORE_SUPPORT
1501 
1502 int
coap_oscore_is_supported(void)1503 coap_oscore_is_supported(void) {
1504   return 1;
1505 }
1506 
1507 /*
1508  * The struct cipher_algs and the function get_cipher_alg() are used to
1509  * determine which cipher type to use for creating the required cipher
1510  * suite object.
1511  */
1512 static struct cipher_algs {
1513   cose_alg_t alg;
1514   u_int cipher_type;
1515 } ciphers[] = {
1516   { COSE_ALGORITHM_AES_CCM_16_64_128, 1 },
1517 };
1518 
1519 static u_int
get_cipher_alg(cose_alg_t alg)1520 get_cipher_alg(cose_alg_t alg) {
1521   size_t idx;
1522 
1523   for (idx = 0; idx < sizeof(ciphers)/sizeof(struct cipher_algs); idx++) {
1524     if (ciphers[idx].alg == alg)
1525       return ciphers[idx].cipher_type;
1526   }
1527   coap_log_debug("get_cipher_alg: COSE cipher %d not supported\n", alg);
1528   return 0;
1529 }
1530 
1531 /*
1532  * The struct hmac_algs and the function get_hmac_alg() are used to
1533  * determine which hmac type to use for creating the required hmac
1534  * suite object.
1535  */
1536 static struct hmac_algs {
1537   cose_hmac_alg_t hmac_alg;
1538   u_int hmac_type;
1539 } hmacs[] = {
1540   {COSE_HMAC_ALG_HMAC256_256, 1},
1541 };
1542 
1543 static u_int
get_hmac_alg(cose_hmac_alg_t hmac_alg)1544 get_hmac_alg(cose_hmac_alg_t hmac_alg) {
1545   size_t idx;
1546 
1547   for (idx = 0; idx < sizeof(hmacs)/sizeof(struct hmac_algs); idx++) {
1548     if (hmacs[idx].hmac_alg == hmac_alg)
1549       return hmacs[idx].hmac_type;
1550   }
1551   coap_log_debug("get_hmac_alg: COSE HMAC %d not supported\n", hmac_alg);
1552   return 0;
1553 }
1554 
1555 int
coap_crypto_check_cipher_alg(cose_alg_t alg)1556 coap_crypto_check_cipher_alg(cose_alg_t alg) {
1557   return get_cipher_alg(alg);
1558 }
1559 
1560 int
coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg)1561 coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg) {
1562   cose_hmac_alg_t hmac_alg;
1563 
1564   if (!cose_get_hmac_alg_for_hkdf(hkdf_alg, &hmac_alg))
1565     return 0;
1566   return get_hmac_alg(hmac_alg);
1567 }
1568 
1569 int
coap_crypto_aead_encrypt(const coap_crypto_param_t * params,coap_bin_const_t * data,coap_bin_const_t * aad,uint8_t * result,size_t * max_result_len)1570 coap_crypto_aead_encrypt(const coap_crypto_param_t *params,
1571                          coap_bin_const_t *data,
1572                          coap_bin_const_t *aad,
1573                          uint8_t *result, size_t *max_result_len) {
1574   int num_bytes;
1575   const coap_crypto_aes_ccm_t *ccm;
1576   dtls_ccm_params_t dtls_params;
1577   coap_bin_const_t laad;
1578 
1579   if (data == NULL)
1580     return 0;
1581 
1582   assert(params);
1583 
1584   if (get_cipher_alg(params->alg) == 0) {
1585     coap_log_debug("coap_crypto_encrypt: algorithm %d not supported\n",
1586                    params->alg);
1587     return 0;
1588   }
1589 
1590   ccm = &params->params.aes;
1591   if (*max_result_len < (data->length + ccm->tag_len)) {
1592     coap_log_warn("coap_encrypt: result buffer too small\n");
1593     return 0;
1594   }
1595 
1596   dtls_params.nonce = ccm->nonce;
1597   dtls_params.tag_length = ccm->tag_len;
1598   dtls_params.l = ccm->l;
1599 
1600   if (aad) {
1601     laad = *aad;
1602   } else {
1603     laad.s = NULL;
1604     laad.length = 0;
1605   }
1606 
1607   num_bytes = dtls_encrypt_params(&dtls_params,
1608                                   data->s, data->length,
1609                                   result,
1610                                   ccm->key.s, ccm->key.length,
1611                                   laad.s, laad.length);
1612   if (num_bytes < 0) {
1613     return 0;
1614   }
1615   *max_result_len = num_bytes;
1616   return 1;
1617 }
1618 
1619 int
coap_crypto_aead_decrypt(const coap_crypto_param_t * params,coap_bin_const_t * data,coap_bin_const_t * aad,uint8_t * result,size_t * max_result_len)1620 coap_crypto_aead_decrypt(const coap_crypto_param_t *params,
1621                          coap_bin_const_t *data,
1622                          coap_bin_const_t *aad,
1623                          uint8_t *result, size_t *max_result_len) {
1624   int num_bytes;
1625   const coap_crypto_aes_ccm_t *ccm;
1626   dtls_ccm_params_t dtls_params;
1627   coap_bin_const_t laad;
1628 
1629   if (data == NULL)
1630     return 0;
1631 
1632   assert(params);
1633 
1634   if (get_cipher_alg(params->alg) == 0) {
1635     coap_log_debug("coap_crypto_decrypt: algorithm %d not supported\n",
1636                    params->alg);
1637     return 0;
1638   }
1639 
1640   ccm = &params->params.aes;
1641 
1642   if ((*max_result_len + ccm->tag_len) < data->length) {
1643     coap_log_warn("coap_decrypt: result buffer too small\n");
1644     return 0;
1645   }
1646 
1647   dtls_params.nonce = ccm->nonce;
1648   dtls_params.tag_length = ccm->tag_len;
1649   dtls_params.l = ccm->l;
1650 
1651   if (aad) {
1652     laad = *aad;
1653   } else {
1654     laad.s = NULL;
1655     laad.length = 0;
1656   }
1657 
1658   num_bytes = dtls_decrypt_params(&dtls_params,
1659                                   data->s, data->length,
1660                                   result,
1661                                   ccm->key.s, ccm->key.length,
1662                                   laad.s, laad.length);
1663   if (num_bytes < 0) {
1664     return 0;
1665   }
1666   *max_result_len = num_bytes;
1667   return 1;
1668 }
1669 
1670 int
coap_crypto_hmac(cose_hmac_alg_t hmac_alg,coap_bin_const_t * key,coap_bin_const_t * data,coap_bin_const_t ** hmac)1671 coap_crypto_hmac(cose_hmac_alg_t hmac_alg, coap_bin_const_t *key,
1672                  coap_bin_const_t *data, coap_bin_const_t **hmac) {
1673   dtls_hmac_context_t hmac_context;
1674   int num_bytes;
1675   coap_binary_t *dummy;
1676 
1677   if (data == NULL)
1678     return 0;
1679 
1680   if (get_hmac_alg(hmac_alg) == 0) {
1681     coap_log_debug("coap_crypto_hmac: algorithm %d not supported\n", hmac_alg);
1682     return 0;
1683   }
1684 
1685   dummy = coap_new_binary(DTLS_SHA256_DIGEST_LENGTH);
1686   if (dummy == NULL)
1687     return 0;
1688 
1689   dtls_hmac_init(&hmac_context, key->s, key->length);
1690   dtls_hmac_update(&hmac_context, data->s, data->length);
1691   num_bytes = dtls_hmac_finalize(&hmac_context, dummy->s);
1692 
1693   if (num_bytes != DTLS_SHA256_DIGEST_LENGTH) {
1694     coap_delete_binary(dummy);
1695     return 0;
1696   }
1697   *hmac = (coap_bin_const_t *)dummy;
1698   return 1;
1699 }
1700 
1701 #endif /* COAP_OSCORE_SUPPORT */
1702 
1703 #else /* !COAP_WITH_LIBTINYDTLS */
1704 
1705 #ifdef __clang__
1706 /* Make compilers happy that do not like empty modules. As this function is
1707  * never used, we ignore -Wunused-function at the end of compiling this file
1708  */
1709 #pragma GCC diagnostic ignored "-Wunused-function"
1710 #endif
1711 static inline void
dummy(void)1712 dummy(void) {
1713 }
1714 
1715 #endif /* COAP_WITH_LIBTINYDTLS */
1716