xref: /third_party/libcoap/src/coap_tinydtls.c (revision c87c5fba)
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
42typedef 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
56static dtls_tick_t dtls_tick_0 = 0;
57static coap_tick_t coap_tick_0 = 0;
58
59int
60coap_dtls_is_supported(void) {
61  return 1;
62}
63
64/*
65 * return 0 failed
66 *        1 passed
67 */
68int
69coap_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 */
81int
82coap_dtls_pki_is_supported(void) {
83  return 0;
84}
85
86/*
87 * return 0 failed
88 *        1 passed
89 */
90int
91coap_dtls_pkcs11_is_supported(void) {
92  return 0;
93}
94
95/*
96 * return 0 failed
97 *        1 passed
98 */
99int
100coap_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
108static coap_log_t
109dtls_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 */
139static void
140dtls_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
147void
148coap_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
159void
160coap_dtls_shutdown(void) {
161  coap_dtls_set_log_level(COAP_LOG_EMERG);
162}
163
164void *
165coap_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
178void
179coap_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
213coap_log_t
214coap_dtls_get_log_level(void) {
215  log_t d_level = dtls_get_log_level();
216
217  return dtls_map_logging(d_level);
218}
219
220static void
221get_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
254static void
255put_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
289static int
290dtls_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
309static int
310dtls_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
329static int coap_event_dtls = 0;
330
331static int
332dtls_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. */
369static int
370get_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
539error:
540  return dtls_alert_fatal_create(fatal_error);
541}
542#endif /* DTLS_PSK */
543
544#ifdef DTLS_ECC
545static int
546get_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 */
563static 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
575static int
576verify_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}
618static 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
630static 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
643void *
644coap_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;
654error:
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
662void
663coap_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
682static session_t *
683coap_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
699void *
700coap_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
706void *
707coap_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
738void
739coap_dtls_session_update_mtu(coap_session_t *session) {
740  (void)session;
741}
742
743void
744coap_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
764ssize_t
765coap_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
805int
806coap_dtls_is_context_timeout(void) {
807  return 1;
808}
809
810coap_tick_t
811coap_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
823coap_tick_t
824coap_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 */
834int
835coap_dtls_handle_timeout(coap_session_t *session) {
836  (void)session;
837  return 0;
838}
839
840int
841coap_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
875int
876coap_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
903unsigned int
904coap_dtls_get_overhead(coap_session_t *session) {
905  (void)session;
906  return 13 + 8 + 8;
907}
908
909int
910coap_tls_is_supported(void) {
911  return 0;
912}
913
914coap_tls_version_t *
915coap_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
939static 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* */
965static coap_binary_t *
966pem_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
990end:
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
1023typedef coap_binary_t *(*asn1_callback)(const uint8_t *data, size_t size);
1024
1025static int
1026asn1_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
1041static int
1042asn1_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
1053static int
1054asn1_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
1067static int
1068asn1_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
1076static int
1077asn1_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
1090static int
1091asn1_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
1100static int
1101asn1_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
1148static coap_binary_t *
1149ec_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
1178static coap_binary_t *
1179pem_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
1192int
1193coap_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
1354int
1355coap_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
1364int
1365coap_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
1381int
1382coap_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
1401int
1402coap_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
1408void *
1409coap_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
1415void *
1416coap_tls_new_server_session(coap_session_t *session COAP_UNUSED) {
1417  return NULL;
1418}
1419#endif /* COAP_SERVER_SUPPORT */
1420
1421void
1422coap_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 */
1430ssize_t
1431coap_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 */
1443ssize_t
1444coap_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
1453coap_digest_ctx_t *
1454coap_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
1464void
1465coap_digest_free(coap_digest_ctx_t *digest_ctx) {
1466  coap_free_type(COAP_STRING, digest_ctx);
1467}
1468
1469int
1470coap_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
1478int
1479coap_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
1489int
1490coap_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
1502int
1503coap_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 */
1512static 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
1519static u_int
1520get_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 */
1536static 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
1543static u_int
1544get_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
1555int
1556coap_crypto_check_cipher_alg(cose_alg_t alg) {
1557  return get_cipher_alg(alg);
1558}
1559
1560int
1561coap_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
1569int
1570coap_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
1619int
1620coap_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
1670int
1671coap_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
1711static inline void
1712dummy(void) {
1713}
1714
1715#endif /* COAP_WITH_LIBTINYDTLS */
1716