libcoap  4.3.0
coap_gnutls.c
Go to the documentation of this file.
1 /*
2  * coap_gnutls.c -- GnuTLS Datagram Transport Layer Support for libcoap
3  *
4  * Copyright (C) 2017 Dag Bjorklund <dag.bjorklund@comsel.fi>
5  * Copyright (C) 2018-2021 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  * Naming used to prevent confusion between coap sessions, gnutls sessions etc.
15  * when reading the code.
16  *
17  * c_context A coap_context_t *
18  * c_session A coap_session_t *
19  * g_context A coap_gnutls_context_t * (held in c_context->dtls_context)
20  * g_session A gnutls_session_t (which has the * in the typedef)
21  * g_env A coap_gnutls_env_t * (held in c_session->tls)
22  */
23 
24 /*
25  * Notes
26  *
27  * There is a memory leak in GnuTLS prior to 3.3.26 when hint is not freed off
28  * when server psk credentials are freed off.
29  *
30  * ca_path in coap_dtls_context_set_pki_root_cas() is not supported until 3.3.6
31  *
32  * Identity Hint is not provided if using DH and versions prior to 3.4.4
33  *
34  * 3.5.5 or later is required to interoperate with TinyDTLS as CCM algorithm
35  * support is required.
36  *
37  * TLS 1.3 is properly supported from 3.6.5 onwards
38  * (but is not enabled by default in 3.6.4)
39  *
40  * Starting with 3.6.3, fixed in 3.6.13, Client Hellos may fail with some
41  * server implementations (e.g. Californium) as random value is all zeros
42  * - CVE-2020-11501 - a security weakness.
43  * 3.6.6 or later is required to support Raw Public Key(RPK)
44  */
45 
46 #include "coap3/coap_internal.h"
47 
48 #ifdef HAVE_LIBGNUTLS
49 
50 #define MIN_GNUTLS_VERSION "3.3.0"
51 
52 #include <inttypes.h>
53 #include <stdio.h>
54 #include <errno.h>
55 #include <gnutls/gnutls.h>
56 #include <gnutls/x509.h>
57 #include <gnutls/dtls.h>
58 #include <gnutls/pkcs11.h>
59 #include <gnutls/crypto.h>
60 #include <gnutls/abstract.h>
61 #include <unistd.h>
62 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
63 #define COAP_GNUTLS_KEY_RPK GNUTLS_KEY_DIGITAL_SIGNATURE | \
64  GNUTLS_KEY_NON_REPUDIATION | \
65  GNUTLS_KEY_KEY_ENCIPHERMENT | \
66  GNUTLS_KEY_DATA_ENCIPHERMENT | \
67  GNUTLS_KEY_KEY_AGREEMENT | \
68  GNUTLS_KEY_KEY_CERT_SIGN
69 #endif /* GNUTLS_VERSION_NUMBER >= 0x030606 */
70 
71 #ifdef _WIN32
72 #define strcasecmp _stricmp
73 #endif
74 
75 typedef struct coap_ssl_t {
76  const uint8_t *pdu;
77  unsigned pdu_len;
78  unsigned peekmode;
79  gnutls_datum_t cookie_key;
80 } coap_ssl_t;
81 
82 /*
83  * This structure encapsulates the GnuTLS session object.
84  * It handles both TLS and DTLS.
85  * c_session->tls points to this.
86  */
87 typedef struct coap_gnutls_env_t {
88  gnutls_session_t g_session;
89  gnutls_psk_client_credentials_t psk_cl_credentials;
90  gnutls_psk_server_credentials_t psk_sv_credentials;
91  gnutls_certificate_credentials_t pki_credentials;
92  coap_ssl_t coap_ssl_data;
93  /* If not set, need to do gnutls_handshake */
94  int established;
95  int doing_dtls_timeout;
96  coap_tick_t last_timeout;
97  int sent_alert;
98 } coap_gnutls_env_t;
99 
100 #define IS_PSK (1 << 0)
101 #define IS_PKI (1 << 1)
102 #define IS_CLIENT (1 << 6)
103 #define IS_SERVER (1 << 7)
104 
105 typedef struct pki_sni_entry {
106  char *sni;
107  coap_dtls_key_t pki_key;
108  gnutls_certificate_credentials_t pki_credentials;
109 } pki_sni_entry;
110 
111 typedef struct psk_sni_entry {
112  char *sni;
113  coap_dtls_spsk_info_t psk_info;
114  gnutls_psk_server_credentials_t psk_credentials;
115 } psk_sni_entry;
116 
117 typedef struct coap_gnutls_context_t {
118  coap_dtls_pki_t setup_data;
119  int psk_pki_enabled;
120  size_t pki_sni_count;
121  pki_sni_entry *pki_sni_entry_list;
122  size_t psk_sni_count;
123  psk_sni_entry *psk_sni_entry_list;
124  gnutls_datum_t alpn_proto; /* Will be "coap", but that is a const */
125  char *root_ca_file;
126  char *root_ca_path;
127  gnutls_priority_t priority_cache;
128 } coap_gnutls_context_t;
129 
130 typedef enum coap_free_bye_t {
131  COAP_FREE_BYE_AS_TCP,
132  COAP_FREE_BYE_AS_UDP,
133  COAP_FREE_BYE_NONE
134 } coap_free_bye_t;
135 
136 #define VARIANTS_3_6_6 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8:+CTYPE-CLI-ALL:+CTYPE-SRV-ALL:+SHA256"
137 #define VARIANTS_3_5_5 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8"
138 #define VARIANTS_BASE "NORMAL:+ECDHE-PSK:+PSK"
139 
140 #define VARIANTS_NO_TLS13_3_6_6 VARIANTS_3_6_6 ":-VERS-TLS1.3"
141 #define VARIANTS_NO_TLS13_3_6_4 VARIANTS_3_5_5 ":-VERS-TLS1.3"
142 
143 #define G_ACTION(xx) do { \
144  ret = (xx); \
145 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
146 
147 #define G_CHECK(xx,func) do { \
148  if ((ret = (xx)) < 0) { \
149  coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \
150  goto fail; \
151  } \
152 } while (0)
153 
154 #define G_ACTION_CHECK(xx,func) do { \
155  G_ACTION(xx); \
156  G_CHECK(xx, func); \
157 } while 0
158 
159 static int dtls_log_level = 0;
160 
161 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
162 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
163 static int psk_server_callback(gnutls_session_t g_session,
164  const char *identity,
165  gnutls_datum_t *key);
166 
167 /*
168  * return 0 failed
169  * 1 passed
170  */
171 int
173  if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
174  coap_log(LOG_ERR, "GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
175  return 0;
176  }
177  return 1;
178 }
179 
180 /*
181  * return 0 failed
182  * 1 passed
183  */
184 int
185 coap_tls_is_supported(void) {
186 #if !COAP_DISABLE_TCP
187  if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
188  coap_log(LOG_ERR, "GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
189  return 0;
190  }
191  return 1;
192 #else /* COAP_DISABLE_TCP */
193  return 0;
194 #endif /* COAP_DISABLE_TCP */
195 }
196 
199  static coap_tls_version_t version;
200  const char *vers = gnutls_check_version(NULL);
201 
202  version.version = 0;
203  if (vers) {
204  int p1, p2, p3;
205 
206  sscanf (vers, "%d.%d.%d", &p1, &p2, &p3);
207  version.version = (p1 << 16) | (p2 << 8) | p3;
208  }
209  version.built_version = GNUTLS_VERSION_NUMBER;
210  version.type = COAP_TLS_LIBRARY_GNUTLS;
211  return &version;
212 }
213 
214 static void
215 coap_gnutls_audit_log_func(gnutls_session_t g_session, const char* text)
216 {
217  if (g_session) {
218  coap_session_t *c_session =
219  (coap_session_t *)gnutls_transport_get_ptr(g_session);
220  coap_log(LOG_WARNING, "** %s: %s",
221  coap_session_str(c_session), text);
222  } else {
223  coap_log(LOG_WARNING, "** (null): %s", text);
224  }
225 }
226 
227 static void
228 coap_gnutls_log_func(int level, const char* text)
229 {
230  /* debug logging in gnutls starts at 2 */
231  if (level > 2)
232  level = 2;
233  coap_log(LOG_DEBUG + level - 2, "%s", text);
234 }
235 
236 /*
237  * return 0 failed
238  * 1 passed
239  */
240 int
242  const coap_dtls_pki_t* setup_data,
243  const coap_dtls_role_t role COAP_UNUSED)
244 {
245  coap_gnutls_context_t *g_context =
246  ((coap_gnutls_context_t *)c_context->dtls_context);
247 
248  if (!g_context || !setup_data)
249  return 0;
250 
251  g_context->setup_data = *setup_data;
252  if (!g_context->setup_data.verify_peer_cert) {
253  /* Needs to be clear so that no CA DNs are transmitted */
254  g_context->setup_data.check_common_ca = 0;
255  if (g_context->setup_data.is_rpk_not_cert) {
256  /* Disable all of these as they cannot be checked */
257  g_context->setup_data.allow_self_signed = 0;
258  g_context->setup_data.allow_expired_certs = 0;
259  g_context->setup_data.cert_chain_validation = 0;
260  g_context->setup_data.cert_chain_verify_depth = 0;
261  g_context->setup_data.check_cert_revocation = 0;
262  g_context->setup_data.allow_no_crl = 0;
263  g_context->setup_data.allow_expired_crl = 0;
264  g_context->setup_data.allow_bad_md_hash = 0;
265  g_context->setup_data.allow_short_rsa_length = 0;
266  }
267  else {
268  /* Allow all of these but warn if issue */
269  g_context->setup_data.allow_self_signed = 1;
270  g_context->setup_data.allow_expired_certs = 1;
271  g_context->setup_data.cert_chain_validation = 1;
272  g_context->setup_data.cert_chain_verify_depth = 10;
273  g_context->setup_data.check_cert_revocation = 1;
274  g_context->setup_data.allow_no_crl = 1;
275  g_context->setup_data.allow_expired_crl = 1;
276  g_context->setup_data.allow_bad_md_hash = 1;
277  g_context->setup_data.allow_short_rsa_length = 1;
278  }
279  }
280  g_context->psk_pki_enabled |= IS_PKI;
281  return 1;
282 }
283 
284 /*
285  * return 0 failed
286  * 1 passed
287  */
288 int
290  const char *ca_file,
291  const char *ca_path)
292 {
293  coap_gnutls_context_t *g_context =
294  ((coap_gnutls_context_t *)c_context->dtls_context);
295  if (!g_context) {
297  "coap_context_set_pki_root_cas: (D)TLS environment "
298  "not set up\n");
299  return 0;
300  }
301 
302  if (ca_file == NULL && ca_path == NULL) {
304  "coap_context_set_pki_root_cas: ca_file and/or ca_path "
305  "not defined\n");
306  return 0;
307  }
308  if (g_context->root_ca_file) {
309  gnutls_free(g_context->root_ca_file);
310  g_context->root_ca_file = NULL;
311  }
312  if (ca_file) {
313  g_context->root_ca_file = gnutls_strdup(ca_file);
314  }
315  if (g_context->root_ca_path) {
316  gnutls_free(g_context->root_ca_path);
317  g_context->root_ca_path = NULL;
318  }
319  if (ca_path) {
320 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
321  g_context->root_ca_path = gnutls_strdup(ca_path);
322 #else
323  coap_log(LOG_ERR, "ca_path not supported in GnuTLS < 3.3.6\n");
324 #endif
325  }
326  return 1;
327 }
328 
329 /*
330  * return 0 failed
331  * 1 passed
332  */
333 int
335  coap_dtls_spsk_t *setup_data
336 ) {
337  coap_gnutls_context_t *g_context =
338  ((coap_gnutls_context_t *)c_context->dtls_context);
339 
340  if (!g_context || !setup_data)
341  return 0;
342 
343  g_context->psk_pki_enabled |= IS_PSK;
344  return 1;
345 }
346 
347 /*
348  * return 0 failed
349  * 1 passed
350  */
351 int
353  coap_dtls_cpsk_t *setup_data
354 ) {
355  coap_gnutls_context_t *g_context =
356  ((coap_gnutls_context_t *)c_context->dtls_context);
357 
358  if (!g_context || !setup_data)
359  return 0;
360 
361  g_context->psk_pki_enabled |= IS_PSK;
362  return 1;
363 }
364 
365 /*
366  * return 0 failed
367  * 1 passed
368  */
369 int
371 {
372  coap_gnutls_context_t *g_context =
373  ((coap_gnutls_context_t *)c_context->dtls_context);
374  return g_context->psk_pki_enabled ? 1 : 0;
375 }
376 
377 void coap_dtls_startup(void) {
378  gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
379  gnutls_global_set_log_function(coap_gnutls_log_func);
380 }
381 
382 void coap_dtls_shutdown(void) {
383 }
384 
385 void *
386 coap_dtls_get_tls(const coap_session_t *c_session,
387  coap_tls_library_t *tls_lib) {
388  if (tls_lib)
389  *tls_lib = COAP_TLS_LIBRARY_GNUTLS;
390  if (c_session && c_session->tls) {
391  const coap_gnutls_env_t *g_env = (const coap_gnutls_env_t *)c_session->tls;
392 
393  return g_env->g_session;
394  }
395  return NULL;
396 }
397 
398 void
399 coap_dtls_set_log_level(int level) {
400  dtls_log_level = level;
401  if (level - LOG_DEBUG >= -2) {
402  /* debug logging in gnutls starts at 2 */
403  gnutls_global_set_log_level(2 + level - LOG_DEBUG);
404  }
405  else {
406  gnutls_global_set_log_level(0);
407  }
408 }
409 
410 /*
411  * return current logging level
412  */
413 int
415  return dtls_log_level;
416 }
417 
418 /*
419  * return +ve new g_context
420  * NULL failure
421  */
422 void *
424  const char *err;
425  int ret;
426  coap_gnutls_context_t *g_context =
427  (coap_gnutls_context_t *)
428  gnutls_malloc(sizeof(coap_gnutls_context_t));
429 
430  if (g_context) {
432  const char *priority;
433 
434  G_CHECK(gnutls_global_init(), "gnutls_global_init");
435  memset(g_context, 0, sizeof(coap_gnutls_context_t));
436  g_context->alpn_proto.data = gnutls_malloc(4);
437  if (g_context->alpn_proto.data) {
438  memcpy(g_context->alpn_proto.data, "coap", 4);
439  g_context->alpn_proto.size = 4;
440  }
441 
442  if (tls_version->version >= 0x030606) {
443  priority = VARIANTS_3_6_6;
444  }
445  else if (tls_version->version >= 0x030505) {
446  priority = VARIANTS_3_5_5;
447  }
448  else {
449  priority = VARIANTS_BASE;
450  }
451  ret = gnutls_priority_init(&g_context->priority_cache, priority, &err);
452  if (ret != GNUTLS_E_SUCCESS) {
453  if (ret == GNUTLS_E_INVALID_REQUEST)
455  "gnutls_priority_init: Syntax error at: %s\n", err);
456  else
458  "gnutls_priority_init: %s\n", gnutls_strerror(ret));
459  goto fail;
460  }
461  }
462  return g_context;
463 
464 fail:
465  if (g_context)
466  coap_dtls_free_context(g_context);
467  return NULL;
468 }
469 
470 void
471 coap_dtls_free_context(void *handle) {
472  size_t i;
473  coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
474 
475  gnutls_free(g_context->alpn_proto.data);
476  gnutls_free(g_context->root_ca_file);
477  gnutls_free(g_context->root_ca_path);
478  for (i = 0; i < g_context->pki_sni_count; i++) {
479  gnutls_free(g_context->pki_sni_entry_list[i].sni);
480  gnutls_certificate_free_credentials(
481  g_context->pki_sni_entry_list[i].pki_credentials);
482  }
483  if (g_context->pki_sni_entry_list)
484  gnutls_free(g_context->pki_sni_entry_list);
485 
486  for (i = 0; i < g_context->psk_sni_count; i++) {
487  gnutls_free(g_context->psk_sni_entry_list[i].sni);
488  /* YUK - A memory leak in 3.3.0 (fixed by 3.3.26) of hint */
489  gnutls_psk_free_server_credentials(
490  g_context->psk_sni_entry_list[i].psk_credentials);
491  }
492  if (g_context->psk_sni_entry_list)
493  gnutls_free(g_context->psk_sni_entry_list);
494 
495  gnutls_priority_deinit(g_context->priority_cache);
496 
497  gnutls_global_deinit();
498  gnutls_free(g_context);
499 }
500 
501 /*
502  * gnutls_psk_client_credentials_function return values
503  * (see gnutls_psk_set_client_credentials_function())
504  *
505  * return -1 failed
506  * 0 passed
507  */
508 static int
509 psk_client_callback(gnutls_session_t g_session,
510  char **username, gnutls_datum_t *key) {
511  coap_session_t *c_session =
512  (coap_session_t *)gnutls_transport_get_ptr(g_session);
513  coap_gnutls_context_t *g_context;
514  coap_dtls_cpsk_t *setup_data;
515  uint8_t identity[64];
516  size_t identity_len;
517  uint8_t psk[64];
518  size_t psk_len;
519  const char *hint = gnutls_psk_client_get_hint(g_session);
520  size_t hint_len = 0;
521 
522  /* Constant passed to get_client_psk callback. The final byte is
523  * reserved for a terminating 0. */
524  const size_t max_identity_len = sizeof(identity) - 1;
525 
526  /* Initialize result parameters. */
527  *username = NULL;
528  key->data = NULL;
529 
530  if (c_session == NULL || c_session->context == NULL ||
531  c_session->context->get_client_psk == NULL) {
532  return -1;
533  }
534 
535  g_context = (coap_gnutls_context_t *)c_session->context->dtls_context;
536  if (g_context == NULL)
537  return -1;
538 
539  setup_data = &c_session->cpsk_setup_data;
540 
541  if (hint)
542  hint_len = strlen(hint);
543  else
544  hint = "";
545 
546  coap_log(LOG_DEBUG, "got psk_identity_hint: '%.*s'\n", (int)hint_len, hint);
547 
548  if (setup_data->validate_ih_call_back) {
549  coap_str_const_t lhint;
550  lhint.length = hint_len;
551  lhint.s = (const uint8_t*)hint;
552  const coap_dtls_cpsk_info_t *psk_info =
553  setup_data->validate_ih_call_back(&lhint,
554  c_session,
555  setup_data->ih_call_back_arg);
556 
557  if (psk_info == NULL)
558  return -1;
559 
560  *username = gnutls_malloc(psk_info->identity.length+1);
561  if (*username == NULL)
562  return -1;
563  memcpy(*username, psk_info->identity.s, psk_info->identity.length);
564  (*username)[psk_info->identity.length] = '\000';
565 
566  key->data = gnutls_malloc(psk_info->key.length);
567  if (key->data == NULL) {
568  gnutls_free(*username);
569  *username = NULL;
570  return -1;
571  }
572  memcpy(key->data, psk_info->key.s, psk_info->key.length);
573  key->size = psk_info->key.length;
574  return 0;
575  }
576 
577  psk_len = c_session->context->get_client_psk(c_session,
578  NULL,
579  0,
580  identity,
581  &identity_len,
582  max_identity_len,
583  psk,
584  sizeof(psk));
585  assert(identity_len < sizeof(identity));
586 
587  /* Reserve dynamic memory to hold the identity and a terminating
588  * zero. */
589  *username = gnutls_malloc(identity_len+1);
590  if (*username == NULL)
591  return -1;
592  memcpy(*username, identity, identity_len);
593  (*username)[identity_len] = '\0';
594 
595  key->data = gnutls_malloc(psk_len);
596  if (key->data == NULL) {
597  gnutls_free(*username);
598  *username = NULL;
599  return -1;
600  }
601  memcpy(key->data, psk, psk_len);
602  key->size = psk_len;
603 
604  return 0;
605 }
606 
607 typedef struct {
608  gnutls_certificate_type_t certificate_type;
609  char *san_or_cn;
610  const gnutls_datum_t *cert_list;
611  unsigned int cert_list_size;
612  int self_signed; /* 1 if cert self-signed, 0 otherwise */
613 } coap_gnutls_certificate_info_t;
614 
615 /*
616  * return Type of certificate and SAN or CN if appropriate derived from
617  * certificate. GNUTLS_CRT_UNKNOWN if failure.
618  */
619 static gnutls_certificate_type_t get_san_or_cn(gnutls_session_t g_session,
620  coap_gnutls_certificate_info_t *cert_info)
621 {
622  gnutls_x509_crt_t cert;
623  char dn[256];
624  size_t size;
625  int n;
626  char *cn;
627  int ret;
628 
629 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
630  cert_info->certificate_type = gnutls_certificate_type_get2(g_session,
631  GNUTLS_CTYPE_PEERS);
632 #else /* < 3.6.6 */
633  cert_info->certificate_type = gnutls_certificate_type_get(g_session);
634 #endif /* < 3.6.6 */
635 
636  cert_info->san_or_cn = NULL;
637 
638  cert_info->cert_list = gnutls_certificate_get_peers(g_session,
639  &cert_info->cert_list_size);
640  if (cert_info->cert_list_size == 0) {
641  return GNUTLS_CRT_UNKNOWN;
642  }
643 
644  if (cert_info->certificate_type != GNUTLS_CRT_X509)
645  return cert_info->certificate_type;
646 
647  G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
648 
649  /* Interested only in first cert in chain */
650  G_CHECK(gnutls_x509_crt_import(cert, &cert_info->cert_list[0],
651  GNUTLS_X509_FMT_DER), "gnutls_x509_crt_import");
652 
653  cert_info->self_signed = gnutls_x509_crt_check_issuer(cert, cert);
654 
655  size = sizeof(dn) -1;
656  /* See if there is a Subject Alt Name first */
657  ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
658  if (ret >= 0) {
659  dn[size] = '\000';
660  gnutls_x509_crt_deinit(cert);
661  cert_info->san_or_cn = gnutls_strdup(dn);
662  return cert_info->certificate_type;
663  }
664 
665  size = sizeof(dn);
666  G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size), "gnutls_x509_crt_get_dn");
667 
668  gnutls_x509_crt_deinit(cert);
669 
670  /* Need to emulate strcasestr() here. Looking for CN= */
671  n = strlen(dn) - 3;
672  cn = dn;
673  while (n > 0) {
674  if (((cn[0] == 'C') || (cn[0] == 'c')) &&
675  ((cn[1] == 'N') || (cn[1] == 'n')) &&
676  (cn[2] == '=')) {
677  cn += 3;
678  break;
679  }
680  cn++;
681  n--;
682  }
683  if (n > 0) {
684  char *ecn = strchr(cn, ',');
685  if (ecn) {
686  cn[ecn-cn] = '\000';
687  }
688  cert_info->san_or_cn = gnutls_strdup(cn);
689  return cert_info->certificate_type;
690  }
691  return GNUTLS_CRT_UNKNOWN;
692 
693 fail:
694  return GNUTLS_CRT_UNKNOWN;
695 }
696 
697 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
698 #define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
699  cert_info.san_or_cn : \
700  cert_type == GNUTLS_CRT_RAW ? \
701  COAP_DTLS_RPK_CERT_CN : "?")
702 #else /* GNUTLS_VERSION_NUMBER < 0x030606 */
703 #define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
704  cert_info.san_or_cn : "?")
705 #endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
706 
707 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
708 static int
709 check_rpk_cert(coap_gnutls_context_t *g_context,
710  coap_gnutls_certificate_info_t *cert_info,
711  coap_session_t *c_session) {
712  int ret;
713 
714  if (g_context->setup_data.validate_cn_call_back) {
715  gnutls_pcert_st pcert;
716  uint8_t der[2048];
717  size_t size;
718 
719  G_CHECK(gnutls_pcert_import_rawpk_raw(&pcert, &cert_info->cert_list[0],
720  GNUTLS_X509_FMT_DER, 0, 0),
721  "gnutls_pcert_import_rawpk_raw");
722 
723  size = sizeof(der);
724  G_CHECK(gnutls_pubkey_export(pcert.pubkey, GNUTLS_X509_FMT_DER, der, &size),
725  "gnutls_pubkey_export");
726  gnutls_pcert_deinit(&pcert);
727  if (!g_context->setup_data.validate_cn_call_back(COAP_DTLS_RPK_CERT_CN,
728  der,
729  size,
730  c_session,
731  0,
732  1,
733  g_context->setup_data.cn_call_back_arg)) {
734  return 0;
735  }
736  }
737  return 1;
738 fail:
739  return 0;
740 }
741 #endif /* >= 3.6.6 */
742 
743 /*
744  * return 0 failed
745  * 1 passed
746  */
747 static int cert_verify_gnutls(gnutls_session_t g_session)
748 {
749  unsigned int status = 0;
750  unsigned int fail = 0;
751  coap_session_t *c_session =
752  (coap_session_t *)gnutls_transport_get_ptr(g_session);
753  coap_gnutls_context_t *g_context =
754  (coap_gnutls_context_t *)c_session->context->dtls_context;
755  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
756  int alert = GNUTLS_A_BAD_CERTIFICATE;
757  int ret;
758  coap_gnutls_certificate_info_t cert_info;
759  gnutls_certificate_type_t cert_type;
760 
761  memset(&cert_info, 0, sizeof(cert_info));
762  cert_type = get_san_or_cn(g_session, &cert_info);
763 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
764  if (cert_type == GNUTLS_CRT_RAW) {
765  if (!check_rpk_cert(g_context, &cert_info, c_session)) {
766  alert = GNUTLS_A_ACCESS_DENIED;
767  goto fail;
768  }
769  goto ok;
770  }
771 #endif /* >= 3.6.6 */
772 
773  if (cert_info.cert_list_size == 0 && !g_context->setup_data.verify_peer_cert)
774  goto ok;
775 
776  G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
777  "gnutls_certificate_verify_peers");
778 
779  if (status) {
780  status &= ~(GNUTLS_CERT_INVALID);
781  if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
782  status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
783  if (g_context->setup_data.allow_expired_certs) {
785  " %s: %s: overridden: '%s'\n",
786  coap_session_str(c_session),
787  "The certificate has an invalid usage date",
788  OUTPUT_CERT_NAME);
789  }
790  else {
791  fail = 1;
793  " %s: %s: '%s'\n",
794  coap_session_str(c_session),
795  "The certificate has an invalid usage date",
796  OUTPUT_CERT_NAME);
797  }
798  }
799  if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
800  GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
801  status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
802  GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
803  if (g_context->setup_data.allow_expired_crl) {
805  " %s: %s: overridden: '%s'\n",
806  coap_session_str(c_session),
807  "The certificate's CRL entry has an invalid usage date",
808  OUTPUT_CERT_NAME);
809  }
810  else {
811  fail = 1;
813  " %s: %s: '%s'\n",
814  coap_session_str(c_session),
815  "The certificate's CRL entry has an invalid usage date",
816  OUTPUT_CERT_NAME);
817  }
818  }
819  if (status & (GNUTLS_CERT_SIGNER_NOT_FOUND)) {
820  status &= ~(GNUTLS_CERT_SIGNER_NOT_FOUND);
821  if (cert_info.self_signed) {
822  if (g_context->setup_data.allow_self_signed &&
823  !g_context->setup_data.check_common_ca) {
825  " %s: %s: overridden: '%s'\n",
826  coap_session_str(c_session),
827  "Self-signed",
828  OUTPUT_CERT_NAME);
829  }
830  else {
831  fail = 1;
832  alert = GNUTLS_A_UNKNOWN_CA;
834  " %s: %s: '%s'\n",
835  coap_session_str(c_session),
836  "Self-signed",
837  OUTPUT_CERT_NAME);
838  }
839  }
840  else {
841  if (!g_context->setup_data.verify_peer_cert) {
843  " %s: %s: overridden: '%s'\n",
844  coap_session_str(c_session),
845  "The peer certificate's CA is unknown",
846  OUTPUT_CERT_NAME);
847  }
848  else {
849  fail = 1;
850  alert = GNUTLS_A_UNKNOWN_CA;
852  " %s: %s: '%s'\n",
853  coap_session_str(c_session),
854  "The peer certificate's CA is unknown",
855  OUTPUT_CERT_NAME);
856  }
857  }
858  }
859 
860  if (status) {
861  fail = 1;
863  " %s: gnutls_certificate_verify_peers() status 0x%x: '%s'\n",
864  coap_session_str(c_session),
865  status, OUTPUT_CERT_NAME);
866  }
867  }
868 
869  if (fail)
870  goto fail;
871 
872  if (g_context->setup_data.validate_cn_call_back) {
873  gnutls_x509_crt_t cert;
874  uint8_t der[2048];
875  size_t size;
876  /* status == 0 indicates that the certificate passed to
877  * setup_data.validate_cn_call_back has been validated. */
878  const int cert_is_trusted = !status;
879 
880  G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
881 
882  /* Interested only in first cert in chain */
883  G_CHECK(gnutls_x509_crt_import(cert, &cert_info.cert_list[0],
884  GNUTLS_X509_FMT_DER), "gnutls_x509_crt_import");
885 
886  size = sizeof(der);
887  G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
888  "gnutls_x509_crt_export");
889  gnutls_x509_crt_deinit(cert);
890  if (!g_context->setup_data.validate_cn_call_back(OUTPUT_CERT_NAME,
891  der,
892  size,
893  c_session,
894  0,
895  cert_is_trusted,
896  g_context->setup_data.cn_call_back_arg)) {
897  alert = GNUTLS_A_ACCESS_DENIED;
898  goto fail;
899  }
900  }
901 
902  if (g_context->setup_data.additional_tls_setup_call_back) {
903  /* Additional application setup wanted */
904  if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
905  &g_context->setup_data)) {
906  goto fail;
907  }
908  }
909 
910 ok:
911  if (cert_info.san_or_cn)
912  gnutls_free(cert_info.san_or_cn);
913 
914  return 1;
915 
916 fail:
917  if (cert_info.san_or_cn)
918  gnutls_free(cert_info.san_or_cn);
919 
920  if (!g_env->sent_alert) {
921  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
922  g_env->sent_alert = 1;
923  }
924  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
925  return 0;
926 }
927 
928 /*
929  * gnutls_certificate_verify_function return values
930  * (see gnutls_certificate_set_verify_function())
931  *
932  * return -1 failed
933  * 0 passed
934  */
935 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
936 {
937  if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
938  if (cert_verify_gnutls(g_session) == 0) {
939  return -1;
940  }
941  }
942  return 0;
943 }
944 
945 #ifndef min
946 #define min(a,b) ((a) < (b) ? (a) : (b))
947 #endif
948 
949 static int
950 pin_callback(void *user_data, int attempt,
951  const char *token_url COAP_UNUSED,
952  const char *token_label COAP_UNUSED,
953  unsigned int flags COAP_UNUSED,
954  char *pin,
955  size_t pin_max)
956 {
957  coap_dtls_pki_t *setup_data = (coap_dtls_pki_t *)user_data;
958 
959  /* Only do this on first attempt to prevent token lockout */
960  if (attempt == 0 && setup_data && setup_data->pki_key.key.pkcs11.user_pin) {
961  int len = min(pin_max - 1, strlen(setup_data->pki_key.key.pkcs11.user_pin));
962  memcpy(pin, setup_data->pki_key.key.pkcs11.user_pin, len);
963  pin[len] = 0;
964  return 0;
965  }
966  return -1;
967 }
968 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
969 /* first part of Raw public key, this is the start of the Subject Public Key */
970 static const unsigned char cert_asn1_header1[] = {
971  0x30, 0x59, /* SEQUENCE, length 89 bytes */
972  0x30, 0x13, /* SEQUENCE, length 19 bytes */
973  0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */
974  0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
975 };
976 /* PrimeX will get inserted */
977 #if 0
978  0x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */
979  0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
980 #endif
981 static const unsigned char cert_asn1_header2[] = {
982  0x03, 0x42, /* BIT STRING, length 66 bytes */
983 /* Note: 0 bits (0x00) and no compression (0x04) are already in the certificate */
984 };
985 
986 static gnutls_datum_t *
987 get_asn1_spki(const uint8_t *data, size_t size)
988 {
989  coap_binary_t *pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, data, size, NULL);
990  coap_binary_t *prime = get_asn1_tag(COAP_ASN1_IDENTIFIER, data, size, NULL);
991  gnutls_datum_t *spki = NULL;
992 
993  if (pub_key && prime) {
994  size_t header_size = sizeof(cert_asn1_header1) +
995  2 +
996  prime->length +
997  sizeof(cert_asn1_header2);
998  uint8_t *tmp = gnutls_malloc(sizeof(gnutls_datum_t) +
999  header_size +
1000  pub_key->length);
1001 
1002  if (tmp) {
1003  spki = (gnutls_datum_t *)tmp;
1004  spki->data = &tmp[sizeof(gnutls_datum_t)];
1005  memcpy(&spki->data[header_size], pub_key->s, pub_key->length);
1006  memcpy(spki->data, cert_asn1_header1, sizeof(cert_asn1_header1));
1007  spki->data[sizeof(cert_asn1_header1)] = COAP_ASN1_IDENTIFIER;
1008  spki->data[sizeof(cert_asn1_header1)+1] = prime->length;
1009  memcpy(&spki->data[sizeof(cert_asn1_header1)+2],
1010  prime->s, prime->length);
1011  memcpy(&spki->data[sizeof(cert_asn1_header1)+2+prime->length],
1012  cert_asn1_header2, sizeof(cert_asn1_header2));
1013  spki->size = header_size + pub_key->length;
1014  }
1015  }
1016  if (pub_key) coap_delete_binary(pub_key);
1017  if (prime) coap_delete_binary(prime);
1018  return spki;
1019 }
1020 #endif /* GNUTLS_VERSION_NUMBER >= 0x030606 */
1021 
1022 /*
1023  * return 0 Success (GNUTLS_E_SUCCESS)
1024  * neg GNUTLS_E_* error code
1025  */
1026 static int
1027 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
1028  gnutls_session_t g_session,
1029  coap_gnutls_context_t *g_context,
1030  coap_dtls_pki_t *setup_data, coap_dtls_role_t role)
1031 {
1032  int ret;
1033 
1034  G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
1035  "gnutls_certificate_allocate_credentials");
1036 
1037  switch (setup_data->pki_key.key_type) {
1038  case COAP_PKI_KEY_PEM:
1039  if (setup_data->pki_key.key.pem.public_cert &&
1040  setup_data->pki_key.key.pem.public_cert[0] &&
1041  setup_data->pki_key.key.pem.private_key &&
1042  setup_data->pki_key.key.pem.private_key[0]) {
1043  if (setup_data->is_rpk_not_cert) {
1045  "RPK keys cannot be in COAP_PKI_KEY_PEM format\n");
1046  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1047  }
1048  else {
1049  G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
1050  setup_data->pki_key.key.pem.public_cert,
1051  setup_data->pki_key.key.pem.private_key,
1052  GNUTLS_X509_FMT_PEM),
1053  "gnutls_certificate_set_x509_key_file");
1054  }
1055  }
1056  else if (role == COAP_DTLS_ROLE_SERVER) {
1057  coap_log(LOG_ERR,
1058  "***setup_pki: (D)TLS: No %s Certificate + Private "
1059  "Key defined\n",
1060  role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client");
1061  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1062  }
1063  if (setup_data->pki_key.key.pem.ca_file &&
1064  setup_data->pki_key.key.pem.ca_file[0]) {
1065  ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1066  setup_data->pki_key.key.pem.ca_file,
1067  GNUTLS_X509_FMT_PEM);
1068  if (ret == 0) {
1070  "gnutls_certificate_set_x509_trust_file: No certificates found\n");
1071  }
1072  else if (ret < 0) {
1073  coap_log(LOG_WARNING, "%s: '%s'\n",
1074  "gnutls_certificate_set_x509_trust_file",
1075  gnutls_strerror(ret));
1076  goto fail;
1077  }
1078  }
1079  break;
1080 
1081  case COAP_PKI_KEY_PEM_BUF:
1082  if (setup_data->pki_key.key.pem_buf.public_cert &&
1083  setup_data->pki_key.key.pem_buf.public_cert_len &&
1084  setup_data->pki_key.key.pem_buf.private_key &&
1085  setup_data->pki_key.key.pem_buf.private_key_len) {
1086  gnutls_datum_t cert;
1087  gnutls_datum_t key;
1088  int alloced_cert_memory = 0;
1089  int alloced_key_memory = 0;
1090 
1091  cert.size = setup_data->pki_key.key.pem_buf.public_cert_len;
1092  if (setup_data->pki_key.key.pem_buf.public_cert[cert.size-1] != '\000') {
1093  /* Need to allocate memory, rather than just copying pointers across */
1094  alloced_cert_memory = 1;
1095  cert.data = gnutls_malloc(cert.size + 1);
1096  if (!cert.data) {
1097  coap_log(LOG_ERR, "gnutls_malloc failure\n");
1098  return GNUTLS_E_MEMORY_ERROR;
1099  }
1100  memcpy(cert.data, setup_data->pki_key.key.pem_buf.public_cert,
1101  cert.size);
1102  cert.data[cert.size] = '\000';
1103  cert.size++;
1104  }
1105  else {
1106  /* To get around const issue */
1107  memcpy(&cert.data,
1108  &setup_data->pki_key.key.pem_buf.public_cert, sizeof(cert.data));
1109  }
1110  key.size = setup_data->pki_key.key.pem_buf.private_key_len;
1111  if (setup_data->pki_key.key.pem_buf.private_key[key.size-1] != '\000') {
1112  /* Need to allocate memory, rather than just copying pointers across */
1113  alloced_key_memory = 1;
1114  key.data = gnutls_malloc(key.size + 1);
1115  if (!key.data) {
1116  coap_log(LOG_ERR, "gnutls_malloc failure\n");
1117  if (alloced_cert_memory) gnutls_free(cert.data);
1118  return GNUTLS_E_MEMORY_ERROR;
1119  }
1120  memcpy(key.data, setup_data->pki_key.key.pem_buf.private_key, key.size);
1121  key.data[key.size] = '\000';
1122  key.size++;
1123  }
1124  else {
1125  /* To get around const issue */
1126  memcpy(&key.data,
1127  &setup_data->pki_key.key.pem_buf.private_key, sizeof(key.data));
1128  }
1129  if (setup_data->is_rpk_not_cert) {
1130 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1131  int have_done_key = 0;
1132  if (strstr ((char*)key.data, "-----BEGIN EC PRIVATE KEY-----")) {
1133  gnutls_datum_t der_private;
1134 
1135  if (gnutls_pem_base64_decode2("EC PRIVATE KEY", &key,
1136  &der_private) == 0) {
1137  gnutls_datum_t *spki = get_asn1_spki(der_private.data,
1138  der_private.size);
1139 
1140  if (spki) {
1141  ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1142  spki,
1143  &der_private,
1144  GNUTLS_X509_FMT_DER, NULL,
1145  COAP_GNUTLS_KEY_RPK,
1146  NULL, 0, 0);
1147  if (ret >= 0) {
1148  have_done_key = 1;
1149  }
1150  gnutls_free(spki);
1151  }
1152  gnutls_free(der_private.data);
1153  }
1154  }
1155  if (!have_done_key) {
1156  G_CHECK(gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1157  &cert,
1158  &key,
1159  GNUTLS_X509_FMT_PEM, NULL,
1160  COAP_GNUTLS_KEY_RPK,
1161  NULL, 0, 0),
1162  "gnutls_certificate_set_rawpk_key_mem");
1163  }
1164 #else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1165  coap_log(LOG_ERR,
1166  "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1167  if (alloced_cert_memory) gnutls_free(cert.data);
1168  if (alloced_key_memory) gnutls_free(key.data);
1169  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1170 #endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1171  }
1172  else {
1173  G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
1174  &cert,
1175  &key,
1176  GNUTLS_X509_FMT_PEM),
1177  "gnutls_certificate_set_x509_key_mem");
1178  }
1179  if (alloced_cert_memory) gnutls_free(cert.data);
1180  if (alloced_key_memory) gnutls_free(key.data);
1181  }
1182  else if (role == COAP_DTLS_ROLE_SERVER) {
1183  coap_log(LOG_ERR,
1184  "***setup_pki: (D)TLS: No Server Certificate + Private "
1185  "Key defined\n");
1186  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1187  }
1188  if (setup_data->pki_key.key.pem_buf.ca_cert &&
1189  setup_data->pki_key.key.pem_buf.ca_cert_len) {
1190  gnutls_datum_t ca;
1191  int alloced_ca_memory = 0;
1192 
1193  ca.size = setup_data->pki_key.key.pem_buf.ca_cert_len;
1194  if (setup_data->pki_key.key.pem_buf.ca_cert[ca.size-1] != '\000') {
1195  /* Need to allocate memory, rather than just copying pointers across */
1196  alloced_ca_memory = 1;
1197  ca.data = gnutls_malloc(ca.size + 1);
1198  if (!ca.data) {
1199  coap_log(LOG_ERR, "gnutls_malloc failure\n");
1200  return GNUTLS_E_MEMORY_ERROR;
1201  }
1202  memcpy(ca.data, setup_data->pki_key.key.pem_buf.ca_cert, ca.size);
1203  ca.data[ca.size] = '\000';
1204  ca.size++;
1205  }
1206  else {
1207  /* To get around const issue */
1208  memcpy(&ca.data,
1209  &setup_data->pki_key.key.pem_buf.ca_cert, sizeof(ca.data));
1210  }
1211  ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1212  &ca,
1213  GNUTLS_X509_FMT_PEM);
1214  if (ret == 0) {
1216  "gnutls_certificate_set_x509_trust_mem: No certificates found\n");
1217  }
1218  else if (ret < 0) {
1219  coap_log(LOG_WARNING, "%s: '%s'\n",
1220  "gnutls_certificate_set_x509_trust_mem",
1221  gnutls_strerror(ret));
1222  if (alloced_ca_memory) gnutls_free(ca.data);
1223  goto fail;
1224  }
1225  if (alloced_ca_memory) gnutls_free(ca.data);
1226  }
1227  break;
1228 
1229  case COAP_PKI_KEY_ASN1:
1230  if (setup_data->pki_key.key.asn1.public_cert &&
1231  setup_data->pki_key.key.asn1.public_cert_len &&
1232  setup_data->pki_key.key.asn1.private_key &&
1233  setup_data->pki_key.key.asn1.private_key_len > 0) {
1234  gnutls_datum_t cert;
1235  gnutls_datum_t key;
1236 
1237  /* Kludge to get around const parameters */
1238  memcpy(&cert.data, &setup_data->pki_key.key.asn1.public_cert,
1239  sizeof(cert.data));
1240  cert.size = setup_data->pki_key.key.asn1.public_cert_len;
1241  memcpy(&key.data, &setup_data->pki_key.key.asn1.private_key,
1242  sizeof(key.data));
1243  key.size = setup_data->pki_key.key.asn1.private_key_len;
1244  if (setup_data->is_rpk_not_cert) {
1245 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1246  int have_done_key = 0;
1247  if (setup_data->pki_key.key.asn1.private_key_type ==
1249  gnutls_datum_t *spki = get_asn1_spki(key.data,
1250  key.size);
1251 
1252  if (spki) {
1253  ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1254  spki,
1255  &key,
1256  GNUTLS_X509_FMT_DER, NULL,
1257  COAP_GNUTLS_KEY_RPK,
1258  NULL, 0, 0);
1259  if (ret >= 0) {
1260  have_done_key = 1;
1261  }
1262  gnutls_free(spki);
1263  }
1264  }
1265  if (!have_done_key) {
1266  G_CHECK(gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1267  &cert,
1268  &key,
1269  GNUTLS_X509_FMT_DER, NULL,
1270  COAP_GNUTLS_KEY_RPK,
1271  NULL, 0, 0),
1272  "gnutls_certificate_set_rawpk_key_mem");
1273  }
1274 #else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1275  coap_log(LOG_ERR,
1276  "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1277  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1278 #endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1279  }
1280  else {
1281  G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
1282  &cert,
1283  &key,
1284  GNUTLS_X509_FMT_DER),
1285  "gnutls_certificate_set_x509_key_mem");
1286  }
1287  }
1288  else if (role == COAP_DTLS_ROLE_SERVER) {
1289  coap_log(LOG_ERR,
1290  "***setup_pki: (D)TLS: No %s Certificate + Private "
1291  "Key defined\n",
1292  role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client");
1293  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1294  }
1295  if (setup_data->pki_key.key.asn1.ca_cert &&
1296  setup_data->pki_key.key.asn1.ca_cert_len > 0) {
1297  gnutls_datum_t ca_cert;
1298 
1299  /* Kludge to get around const parameters */
1300  memcpy(&ca_cert.data, &setup_data->pki_key.key.asn1.ca_cert,
1301  sizeof(ca_cert.data));
1302  ca_cert.size = setup_data->pki_key.key.asn1.ca_cert_len;
1303  ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1304  &ca_cert,
1305  GNUTLS_X509_FMT_DER);
1306  if (ret == 0) {
1308  "gnutls_certificate_set_x509_trust_mem: No certificates found\n");
1309  }
1310  else if (ret < 0) {
1311  coap_log(LOG_WARNING, "%s: '%s'\n",
1312  "gnutls_certificate_set_x509_trust_mem",
1313  gnutls_strerror(ret));
1314  goto fail;
1315  }
1316  }
1317  break;
1318 
1319  case COAP_PKI_KEY_PKCS11:
1320  if (setup_data->pki_key.key.pkcs11.public_cert &&
1321  setup_data->pki_key.key.pkcs11.public_cert[0] &&
1322  setup_data->pki_key.key.pkcs11.private_key &&
1323  setup_data->pki_key.key.pkcs11.private_key[0]) {
1324 
1325  gnutls_pkcs11_set_pin_function(pin_callback, setup_data);
1326  if (setup_data->is_rpk_not_cert) {
1327 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1328  G_CHECK(gnutls_certificate_set_rawpk_key_file(*pki_credentials,
1329  setup_data->pki_key.key.pkcs11.public_cert,
1330  setup_data->pki_key.key.pkcs11.private_key,
1331  GNUTLS_X509_FMT_PEM, NULL,
1332  COAP_GNUTLS_KEY_RPK,
1333  NULL, 0, GNUTLS_PKCS_PLAIN, 0),
1334  "gnutls_certificate_set_rawpk_key_file");
1335 #else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1336  coap_log(LOG_ERR,
1337  "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1338  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1339 #endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1340  }
1341  else {
1342  G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
1343  setup_data->pki_key.key.pkcs11.public_cert,
1344  setup_data->pki_key.key.pkcs11.private_key,
1345  GNUTLS_X509_FMT_DER),
1346  "gnutls_certificate_set_x509_key_file");
1347  }
1348  }
1349  else if (role == COAP_DTLS_ROLE_SERVER) {
1350  coap_log(LOG_ERR,
1351  "***setup_pki: (D)TLS: No %s Certificate + Private "
1352  "Key defined\n",
1353  role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client");
1354  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1355  }
1356  if (setup_data->pki_key.key.pkcs11.ca &&
1357  setup_data->pki_key.key.pkcs11.ca[0]) {
1358  ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1359  setup_data->pki_key.key.pkcs11.ca,
1360  GNUTLS_X509_FMT_DER);
1361  if (ret == 0) {
1363  "gnutls_certificate_set_x509_trust_file: No certificates found\n");
1364  }
1365  else if (ret < 0) {
1366  coap_log(LOG_WARNING, "%s: '%s'\n",
1367  "gnutls_certificate_set_x509_trust_file",
1368  gnutls_strerror(ret));
1369  goto fail;
1370  }
1371  }
1372  break;
1373 
1374  default:
1375  coap_log(LOG_ERR,
1376  "***setup_pki: (D)TLS: Unknown key type %d\n",
1377  setup_data->pki_key.key_type);
1378  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1379  }
1380 
1381  if (g_context->root_ca_file) {
1382  ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1383  g_context->root_ca_file,
1384  GNUTLS_X509_FMT_PEM);
1385  if (ret == 0) {
1387  "gnutls_certificate_set_x509_trust_file: Root CA: No certificates found\n");
1388  }
1389  }
1390  if (g_context->root_ca_path) {
1391 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
1392  G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
1393  g_context->root_ca_path,
1394  GNUTLS_X509_FMT_PEM),
1395  "gnutls_certificate_set_x509_trust_dir");
1396 #endif
1397  }
1398  gnutls_certificate_send_x509_rdn_sequence(g_session,
1399  setup_data->check_common_ca ? 0 : 1);
1400  if (!(g_context->psk_pki_enabled & IS_PKI)) {
1401  /* No PKI defined at all - still need a trust set up for 3.6.0 or later */
1402  G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
1403  "gnutls_certificate_set_x509_system_trust");
1404  }
1405 
1406  /* Verify Peer */
1407  gnutls_certificate_set_verify_function(*pki_credentials,
1408  cert_verify_callback_gnutls);
1409 
1410  /* Cert chain checking (can raise GNUTLS_E_CONSTRAINT_ERROR) */
1411  if (setup_data->cert_chain_validation) {
1412  gnutls_certificate_set_verify_limits(*pki_credentials,
1413  0,
1414  setup_data->cert_chain_verify_depth + 2);
1415  }
1416 
1417  /*
1418  * Check for self signed
1419  * CRL checking (can raise GNUTLS_CERT_MISSING_OCSP_STATUS)
1420  */
1421  gnutls_certificate_set_verify_flags(*pki_credentials,
1422  (setup_data->check_cert_revocation == 0 ?
1423  GNUTLS_VERIFY_DISABLE_CRL_CHECKS : 0)
1424  );
1425 
1426  return GNUTLS_E_SUCCESS;
1427 
1428 fail:
1429  return ret;
1430 }
1431 
1432 /*
1433  * return 0 Success (GNUTLS_E_SUCCESS)
1434  * neg GNUTLS_E_* error code
1435  */
1436 static int
1437 setup_psk_credentials(gnutls_psk_server_credentials_t *psk_credentials,
1438  coap_gnutls_context_t *g_context COAP_UNUSED,
1439  coap_dtls_spsk_t *setup_data)
1440 {
1441  int ret;
1442  char hint[COAP_DTLS_HINT_LENGTH];
1443 
1444  G_CHECK(gnutls_psk_allocate_server_credentials(psk_credentials),
1445  "gnutls_psk_allocate_server_credentials");
1446  gnutls_psk_set_server_credentials_function(*psk_credentials,
1447  psk_server_callback);
1448  if (setup_data->psk_info.hint.s) {
1449  snprintf(hint, sizeof(hint), "%.*s", (int)setup_data->psk_info.hint.length,
1450  setup_data->psk_info.hint.s);
1451  G_CHECK(gnutls_psk_set_server_credentials_hint(*psk_credentials, hint),
1452  "gnutls_psk_set_server_credentials_hint");
1453  }
1454 
1455  return GNUTLS_E_SUCCESS;
1456 
1457 fail:
1458  return ret;
1459 }
1460 
1461 
1462 /*
1463  * return 0 Success (GNUTLS_E_SUCCESS)
1464  * neg GNUTLS_E_* error code
1465  */
1466 static int
1467 post_client_hello_gnutls_psk(gnutls_session_t g_session)
1468 {
1469  coap_session_t *c_session =
1470  (coap_session_t *)gnutls_transport_get_ptr(g_session);
1471  coap_gnutls_context_t *g_context =
1472  (coap_gnutls_context_t *)c_session->context->dtls_context;
1473  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1474  int ret = GNUTLS_E_SUCCESS;
1475  char *name = NULL;
1476 
1478  coap_dtls_spsk_t sni_setup_data;
1479  /* DNS names (only type supported) may be at most 256 byte long */
1480  size_t len = 256;
1481  unsigned int type;
1482  unsigned int i;
1483 
1484  name = gnutls_malloc(len);
1485  if (name == NULL)
1486  return GNUTLS_E_MEMORY_ERROR;
1487 
1488  for (i=0; ; ) {
1489  ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1490  if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1491  char *new_name;
1492  new_name = gnutls_realloc(name, len);
1493  if (new_name == NULL) {
1494  ret = GNUTLS_E_MEMORY_ERROR;
1495  goto end;
1496  }
1497  name = new_name;
1498  continue; /* retry call with same index */
1499  }
1500 
1501  /* check if it is the last entry in list */
1502  if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1503  break;
1504  i++;
1505  if (ret != GNUTLS_E_SUCCESS)
1506  goto end;
1507  /* unknown types need to be ignored */
1508  if (type != GNUTLS_NAME_DNS)
1509  continue;
1510 
1511  }
1512  /* If no extension provided, make it a dummy entry */
1513  if (i == 0) {
1514  name[0] = '\000';
1515  len = 0;
1516  }
1517 
1518  /* Is this a cached entry? */
1519  for (i = 0; i < g_context->psk_sni_count; i++) {
1520  if (strcasecmp(name, g_context->psk_sni_entry_list[i].sni) == 0) {
1521  break;
1522  }
1523  }
1524  if (i == g_context->psk_sni_count) {
1525  /*
1526  * New SNI request
1527  */
1528  const coap_dtls_spsk_info_t *new_entry =
1530  c_session,
1532  if (!new_entry) {
1533  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1534  GNUTLS_A_UNRECOGNIZED_NAME));
1535  g_env->sent_alert = 1;
1536  ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1537  goto end;
1538  }
1539 
1540  g_context->psk_sni_entry_list =
1541  gnutls_realloc(g_context->psk_sni_entry_list,
1542  (i+1)*sizeof(psk_sni_entry));
1543  g_context->psk_sni_entry_list[i].sni = gnutls_strdup(name);
1544  g_context->psk_sni_entry_list[i].psk_info = *new_entry;
1545  sni_setup_data = c_session->context->spsk_setup_data;
1546  sni_setup_data.psk_info = *new_entry;
1547  if ((ret = setup_psk_credentials(
1548  &g_context->psk_sni_entry_list[i].psk_credentials,
1549  g_context,
1550  &sni_setup_data)) < 0) {
1551  int keep_ret = ret;
1552  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1553  GNUTLS_A_BAD_CERTIFICATE));
1554  g_env->sent_alert = 1;
1555  ret = keep_ret;
1556  goto end;
1557  }
1558  g_context->psk_sni_count++;
1559  }
1560  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1561  g_context->psk_sni_entry_list[i].psk_credentials),
1562  "gnutls_credentials_set");
1564  &g_context->psk_sni_entry_list[i].psk_info.hint);
1565  coap_session_refresh_psk_key(c_session,
1566  &g_context->psk_sni_entry_list[i].psk_info.key);
1567  }
1568 
1569 end:
1570  free(name);
1571  return ret;
1572 
1573 fail:
1574  return ret;
1575 }
1576 
1577 /*
1578  * return 0 Success (GNUTLS_E_SUCCESS)
1579  * neg GNUTLS_E_* error code
1580  */
1581 static int
1582 post_client_hello_gnutls_pki(gnutls_session_t g_session)
1583 {
1584  coap_session_t *c_session =
1585  (coap_session_t *)gnutls_transport_get_ptr(g_session);
1586  coap_gnutls_context_t *g_context =
1587  (coap_gnutls_context_t *)c_session->context->dtls_context;
1588  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1589  int ret = GNUTLS_E_SUCCESS;
1590  char *name = NULL;
1591 
1592  if (g_context->setup_data.validate_sni_call_back) {
1593  /* DNS names (only type supported) may be at most 256 byte long */
1594  size_t len = 256;
1595  unsigned int type;
1596  unsigned int i;
1597  coap_dtls_pki_t sni_setup_data;
1598 
1599  name = gnutls_malloc(len);
1600  if (name == NULL)
1601  return GNUTLS_E_MEMORY_ERROR;
1602 
1603  for (i=0; ; ) {
1604  ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1605  if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1606  char *new_name;
1607  new_name = gnutls_realloc(name, len);
1608  if (new_name == NULL) {
1609  ret = GNUTLS_E_MEMORY_ERROR;
1610  goto end;
1611  }
1612  name = new_name;
1613  continue; /* retry call with same index */
1614  }
1615 
1616  /* check if it is the last entry in list */
1617  if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1618  break;
1619  i++;
1620  if (ret != GNUTLS_E_SUCCESS)
1621  goto end;
1622  /* unknown types need to be ignored */
1623  if (type != GNUTLS_NAME_DNS)
1624  continue;
1625 
1626  }
1627  /* If no extension provided, make it a dummy entry */
1628  if (i == 0) {
1629  name[0] = '\000';
1630  len = 0;
1631  }
1632 
1633  /* Is this a cached entry? */
1634  for (i = 0; i < g_context->pki_sni_count; i++) {
1635  if (strcasecmp(name, g_context->pki_sni_entry_list[i].sni) == 0) {
1636  break;
1637  }
1638  }
1639  if (i == g_context->pki_sni_count) {
1640  /*
1641  * New SNI request
1642  */
1643  coap_dtls_key_t *new_entry =
1644  g_context->setup_data.validate_sni_call_back(name,
1645  g_context->setup_data.sni_call_back_arg);
1646  if (!new_entry) {
1647  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1648  GNUTLS_A_UNRECOGNIZED_NAME));
1649  g_env->sent_alert = 1;
1650  ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1651  goto end;
1652  }
1653 
1654  g_context->pki_sni_entry_list = gnutls_realloc(
1655  g_context->pki_sni_entry_list,
1656  (i+1)*sizeof(pki_sni_entry));
1657  g_context->pki_sni_entry_list[i].sni = gnutls_strdup(name);
1658  g_context->pki_sni_entry_list[i].pki_key = *new_entry;
1659  sni_setup_data = g_context->setup_data;
1660  sni_setup_data.pki_key = *new_entry;
1661  if ((ret = setup_pki_credentials(
1662  &g_context->pki_sni_entry_list[i].pki_credentials,
1663  g_session,
1664  g_context,
1665  &sni_setup_data, COAP_DTLS_ROLE_SERVER)) < 0) {
1666  int keep_ret = ret;
1667  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1668  GNUTLS_A_BAD_CERTIFICATE));
1669  g_env->sent_alert = 1;
1670  ret = keep_ret;
1671  goto end;
1672  }
1673  g_context->pki_sni_count++;
1674  }
1675  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1676  g_context->pki_sni_entry_list[i].pki_credentials),
1677  "gnutls_credentials_set");
1678  }
1679 
1680 end:
1681  free(name);
1682  return ret;
1683 
1684 fail:
1685  return ret;
1686 }
1687 
1688 /*
1689  * return 0 Success (GNUTLS_E_SUCCESS)
1690  * neg GNUTLS_E_* error code
1691  */
1692 static int
1693 setup_client_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env)
1694 {
1695  coap_gnutls_context_t *g_context =
1696  (coap_gnutls_context_t *)c_session->context->dtls_context;
1697  int ret;
1698 
1699  g_context->psk_pki_enabled |= IS_CLIENT;
1700  if (g_context->psk_pki_enabled & IS_PSK) {
1701  coap_dtls_cpsk_t *setup_data = &c_session->cpsk_setup_data;
1702  G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
1703  "gnutls_psk_allocate_client_credentials");
1704  gnutls_psk_set_client_credentials_function(g_env->psk_cl_credentials,
1705  psk_client_callback);
1706  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1707  g_env->psk_cl_credentials),
1708  "gnutls_credentials_set");
1709  /* Issue SNI if requested */
1710  if (setup_data->client_sni) {
1711  G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1712  setup_data->client_sni,
1713  strlen(setup_data->client_sni)),
1714  "gnutls_server_name_set");
1715  }
1716  if (setup_data->validate_ih_call_back) {
1717  const char *err;
1719 
1720  if (tls_version->version >= 0x030604) {
1721  /* Disable TLS1.3 if Identity Hint Callback set */
1722  const char *priority;
1723 
1724  if (tls_version->version >= 0x030606) {
1725  priority = VARIANTS_NO_TLS13_3_6_6;
1726  }
1727  else {
1728  priority = VARIANTS_NO_TLS13_3_6_4;
1729  }
1730  ret = gnutls_priority_set_direct(g_env->g_session,
1731  priority, &err);
1732  if (ret < 0) {
1733  if (ret == GNUTLS_E_INVALID_REQUEST)
1735  "gnutls_priority_set_direct: Syntax error at: %s\n", err);
1736  else
1738  "gnutls_priority_set_direct: %s\n", gnutls_strerror(ret));
1739  goto fail;
1740  }
1741  }
1742  }
1743  }
1744 
1745  if ((g_context->psk_pki_enabled & IS_PKI) ||
1746  (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
1747  /*
1748  * If neither PSK or PKI have been set up, use PKI basics.
1749  * This works providing COAP_PKI_KEY_PEM has a value of 0.
1750  */
1751  coap_dtls_pki_t *setup_data = &g_context->setup_data;
1752  G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1753  g_context, setup_data,
1755  "setup_pki_credentials");
1756 
1757  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1758  g_env->pki_credentials),
1759  "gnutls_credentials_set");
1760 
1761  if (c_session->proto == COAP_PROTO_TLS)
1762  G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
1763  &g_context->alpn_proto, 1, 0),
1764  "gnutls_alpn_set_protocols");
1765 
1766  /* Issue SNI if requested (only happens if PKI defined) */
1767  if (setup_data->client_sni) {
1768  G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1769  setup_data->client_sni,
1770  strlen(setup_data->client_sni)),
1771  "gnutls_server_name_set");
1772  }
1773  }
1774  return GNUTLS_E_SUCCESS;
1775 
1776 fail:
1777  return ret;
1778 }
1779 
1780 /*
1781  * gnutls_psk_server_credentials_function return values
1782  * (see gnutls_psk_set_server_credentials_function())
1783  *
1784  * return -1 failed
1785  * 0 passed
1786  */
1787 static int
1788 psk_server_callback(gnutls_session_t g_session,
1789  const char *identity,
1790  gnutls_datum_t *key)
1791 {
1792  coap_session_t *c_session =
1793  (coap_session_t *)gnutls_transport_get_ptr(g_session);
1794  coap_gnutls_context_t *g_context;
1795  coap_dtls_spsk_t *setup_data;
1796  size_t identity_len = 0;
1797  uint8_t buf[64];
1798  size_t psk_len;
1799 
1800  if (c_session == NULL || c_session->context == NULL ||
1801  c_session->context->get_server_psk == NULL)
1802  return -1;
1803 
1804  g_context = (coap_gnutls_context_t *)c_session->context->dtls_context;
1805  if (g_context == NULL)
1806  return -1;
1807  setup_data = &c_session->context->spsk_setup_data;
1808 
1809  if (identity)
1810  identity_len = strlen(identity);
1811  else
1812  identity = "";
1813 
1814  /* Track the Identity being used */
1815  if (c_session->psk_identity)
1816  coap_delete_bin_const(c_session->psk_identity);
1817  c_session->psk_identity = coap_new_bin_const((const uint8_t *)identity,
1818  identity_len);
1819 
1820  coap_log(LOG_DEBUG, "got psk_identity: '%.*s'\n",
1821  (int)identity_len, identity);
1822 
1823  if (setup_data->validate_id_call_back) {
1824  coap_bin_const_t lidentity;
1825  lidentity.length = identity_len;
1826  lidentity.s = (const uint8_t*)identity;
1827  const coap_bin_const_t *psk_key =
1828  setup_data->validate_id_call_back(&lidentity,
1829  c_session,
1830  setup_data->id_call_back_arg);
1831 
1832  if (psk_key == NULL)
1833  return -1;
1834  key->data = gnutls_malloc(psk_key->length);
1835  if (key->data == NULL)
1836  return -1;
1837  memcpy(key->data, psk_key->s, psk_key->length);
1838  key->size = psk_key->length;
1839  coap_session_refresh_psk_key(c_session, psk_key);
1840  return 0;
1841  }
1842 
1843  psk_len = c_session->context->get_server_psk(c_session,
1844  (const uint8_t*)identity,
1845  identity_len,
1846  (uint8_t*)buf, sizeof(buf));
1847  key->data = gnutls_malloc(psk_len);
1848  memcpy(key->data, buf, psk_len);
1849  key->size = psk_len;
1850  return 0;
1851 }
1852 
1853 /*
1854  * return 0 Success (GNUTLS_E_SUCCESS)
1855  * neg GNUTLS_E_* error code
1856  */
1857 static int
1858 setup_server_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env)
1859 {
1860  coap_gnutls_context_t *g_context =
1861  (coap_gnutls_context_t *)c_session->context->dtls_context;
1862  int ret = GNUTLS_E_SUCCESS;
1863 
1864  g_context->psk_pki_enabled |= IS_SERVER;
1865  if (g_context->psk_pki_enabled & IS_PSK) {
1866  G_CHECK(setup_psk_credentials(
1867  &g_env->psk_sv_credentials,
1868  g_context,
1869  &c_session->context->spsk_setup_data),
1870  "setup_psk_credentials\n");
1871  G_CHECK(gnutls_credentials_set(g_env->g_session,
1872  GNUTLS_CRD_PSK,
1873  g_env->psk_sv_credentials),
1874  "gnutls_credentials_set\n");
1875  gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1876  post_client_hello_gnutls_psk);
1877  }
1878 
1879  if (g_context->psk_pki_enabled & IS_PKI) {
1880  coap_dtls_pki_t *setup_data = &g_context->setup_data;
1881  G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1882  g_context, setup_data,
1884  "setup_pki_credentials");
1885 
1886  if (setup_data->verify_peer_cert) {
1887  gnutls_certificate_server_set_request(g_env->g_session,
1888  GNUTLS_CERT_REQUIRE);
1889  }
1890  else if (setup_data->is_rpk_not_cert) {
1891  gnutls_certificate_server_set_request(g_env->g_session,
1892  GNUTLS_CERT_REQUEST);
1893  }
1894  else {
1895  gnutls_certificate_server_set_request(g_env->g_session,
1896  GNUTLS_CERT_IGNORE);
1897  }
1898 
1899  gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1900  post_client_hello_gnutls_pki);
1901 
1902  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1903  g_env->pki_credentials),
1904  "gnutls_credentials_set\n");
1905  }
1906  return GNUTLS_E_SUCCESS;
1907 
1908 fail:
1909  return ret;
1910 }
1911 
1912 /*
1913  * return +ve data amount
1914  * 0 no more
1915  * -1 error (error in errno)
1916  */
1917 static ssize_t
1918 coap_dgram_read(gnutls_transport_ptr_t context, void *out, size_t outl)
1919 {
1920  ssize_t ret = 0;
1921  coap_session_t *c_session = (coap_session_t *)context;
1922  coap_ssl_t *data;
1923 
1924  if (!c_session->tls) {
1925  errno = EAGAIN;
1926  return -1;
1927  }
1928  data = &((coap_gnutls_env_t *)c_session->tls)->coap_ssl_data;
1929 
1930  if (out != NULL) {
1931  if (data != NULL && data->pdu_len > 0) {
1932  if (outl < data->pdu_len) {
1933  memcpy(out, data->pdu, outl);
1934  ret = outl;
1935  if (!data->peekmode) {
1936  data->pdu += outl;
1937  data->pdu_len -= outl;
1938  }
1939  } else {
1940  memcpy(out, data->pdu, data->pdu_len);
1941  ret = data->pdu_len;
1942  if (!data->peekmode) {
1943  data->pdu_len = 0;
1944  data->pdu = NULL;
1945  }
1946  }
1947  }
1948  else {
1949  errno = EAGAIN;
1950  ret = -1;
1951  }
1952  }
1953  return ret;
1954 }
1955 
1956 /*
1957  * return +ve data amount
1958  * 0 no more
1959  * -1 error (error in errno)
1960  */
1961 /* callback function given to gnutls for sending data over socket */
1962 static ssize_t
1963 coap_dgram_write(gnutls_transport_ptr_t context, const void *send_buffer,
1964  size_t send_buffer_length) {
1965  ssize_t result = -1;
1966  coap_session_t *c_session = (coap_session_t *)context;
1967 
1968  if (c_session) {
1969  result = coap_session_send(c_session, send_buffer, send_buffer_length);
1970  if (result != (int)send_buffer_length) {
1971  coap_log(LOG_WARNING, "coap_network_send failed\n");
1972  result = 0;
1973  }
1974  } else {
1975  result = 0;
1976  }
1977  return result;
1978 }
1979 
1980 /*
1981  * return 1 fd has activity
1982  * 0 timeout
1983  * -1 error (error in errno)
1984  */
1985 static int
1986 receive_timeout(gnutls_transport_ptr_t context, unsigned int ms COAP_UNUSED) {
1987  coap_session_t *c_session = (coap_session_t *)context;
1988 
1989  if (c_session) {
1990  fd_set readfds, writefds, exceptfds;
1991  struct timeval tv;
1992  int nfds = c_session->sock.fd +1;
1993  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1994 
1995  /* If data has been read in by libcoap ahead of GnuTLS, say it is there */
1996  if (c_session->proto == COAP_PROTO_DTLS && g_env &&
1997  g_env->coap_ssl_data.pdu_len > 0) {
1998  return 1;
1999  }
2000 
2001  FD_ZERO(&readfds);
2002  FD_ZERO(&writefds);
2003  FD_ZERO(&exceptfds);
2004  FD_SET (c_session->sock.fd, &readfds);
2005  if (!(g_env && g_env->doing_dtls_timeout)) {
2006  FD_SET (c_session->sock.fd, &writefds);
2007  FD_SET (c_session->sock.fd, &exceptfds);
2008  }
2009  /* Polling */
2010  tv.tv_sec = 0;
2011  tv.tv_usec = 0;
2012 
2013  return select(nfds, &readfds, &writefds, &exceptfds, &tv);
2014  }
2015  return 1;
2016 }
2017 
2018 static coap_gnutls_env_t *
2019 coap_dtls_new_gnutls_env(coap_session_t *c_session, int type)
2020 {
2021  coap_gnutls_context_t *g_context =
2022  ((coap_gnutls_context_t *)c_session->context->dtls_context);
2023  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2024 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2025  int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2026 #else /* < 3.6.6 */
2027  int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
2028 #endif /* < 3.6.6 */
2029  int ret;
2030 
2031  if (g_env)
2032  return g_env;
2033 
2034  g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2035  if (!g_env)
2036  return NULL;
2037 
2038  memset(g_env, 0, sizeof(coap_gnutls_env_t));
2039 
2040  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2041 
2042  gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
2043  gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
2044  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2045  /* So we can track the coap_session_t in callbacks */
2046  gnutls_transport_set_ptr(g_env->g_session, c_session);
2047 
2048  G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
2049  "gnutls_priority_set");
2050 
2051  if (type == GNUTLS_SERVER) {
2052  G_CHECK(setup_server_ssl_session(c_session, g_env),
2053  "setup_server_ssl_session");
2054  }
2055  else {
2056  G_CHECK(setup_client_ssl_session(c_session, g_env),
2057  "setup_client_ssl_session");
2058  }
2059 
2060  gnutls_handshake_set_timeout(g_env->g_session,
2061  GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2062  gnutls_dtls_set_timeouts(g_env->g_session, COAP_DTLS_RETRANSMIT_MS,
2064 
2065  return g_env;
2066 
2067 fail:
2068  if (g_env)
2069  gnutls_free(g_env);
2070  return NULL;
2071 }
2072 
2073 static void
2074 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
2075  coap_gnutls_env_t *g_env,
2076  coap_free_bye_t free_bye)
2077 {
2078  if (g_env) {
2079  /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS
2080  * connections because the peer's closure message might
2081  * be lost */
2082  if (free_bye != COAP_FREE_BYE_NONE && !g_env->sent_alert) {
2083  /* Only do this if appropriate */
2084  gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
2085  GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
2086  }
2087  gnutls_deinit(g_env->g_session);
2088  g_env->g_session = NULL;
2089  if (g_context->psk_pki_enabled & IS_PSK) {
2090  if ((g_context->psk_pki_enabled & IS_CLIENT) &&
2091  g_env->psk_cl_credentials != NULL) {
2092  gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
2093  g_env->psk_cl_credentials = NULL;
2094  }
2095  else {
2096  /* YUK - A memory leak in 3.3.0 (fixed by 3.3.26) of hint */
2097  if (g_env->psk_sv_credentials != NULL)
2098  gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
2099  g_env->psk_sv_credentials = NULL;
2100  }
2101  }
2102  if ((g_context->psk_pki_enabled & IS_PKI) ||
2103  (g_context->psk_pki_enabled &
2104  (IS_PSK | IS_PKI | IS_CLIENT)) == IS_CLIENT) {
2105  gnutls_certificate_free_credentials(g_env->pki_credentials);
2106  g_env->pki_credentials = NULL;
2107  }
2108  gnutls_free(g_env->coap_ssl_data.cookie_key.data);
2109  gnutls_free(g_env);
2110  }
2111 }
2112 
2113 void *coap_dtls_new_server_session(coap_session_t *c_session) {
2114  coap_gnutls_env_t *g_env =
2115  (coap_gnutls_env_t *)c_session->tls;
2116 
2117  gnutls_transport_set_ptr(g_env->g_session, c_session);
2118 
2119  return g_env;
2120 }
2121 
2122 static void log_last_alert(coap_session_t *c_session,
2123  gnutls_session_t g_session) {
2124  int last_alert = gnutls_alert_get(g_session);
2125 
2126  if (last_alert == GNUTLS_A_CLOSE_NOTIFY)
2127  coap_log(LOG_DEBUG, "***%s: Alert '%d': %s\n",
2128  coap_session_str(c_session),
2129  last_alert, gnutls_alert_get_name(last_alert));
2130  else
2131  coap_log(LOG_WARNING, "***%s: Alert '%d': %s\n",
2132  coap_session_str(c_session),
2133  last_alert, gnutls_alert_get_name(last_alert));
2134 }
2135 
2136 /*
2137  * return -1 failure
2138  * 0 not completed
2139  * 1 established
2140  */
2141 static int
2142 do_gnutls_handshake(coap_session_t *c_session, coap_gnutls_env_t *g_env) {
2143  int ret;
2144 
2145  ret = gnutls_handshake(g_env->g_session);
2146  switch (ret) {
2147  case GNUTLS_E_SUCCESS:
2148  g_env->established = 1;
2149  coap_log(LOG_DEBUG, "* %s: GnuTLS established\n",
2150  coap_session_str(c_session));
2151  ret = 1;
2152  break;
2153  case GNUTLS_E_INTERRUPTED:
2154  errno = EINTR;
2155  ret = 0;
2156  break;
2157  case GNUTLS_E_AGAIN:
2158  errno = EAGAIN;
2159  ret = 0;
2160  break;
2161  case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
2163  "Insufficient credentials provided.\n");
2164  ret = -1;
2165  break;
2166  case GNUTLS_E_FATAL_ALERT_RECEIVED:
2167  /* Stop the sending of an alert on closedown */
2168  g_env->sent_alert = 1;
2169  log_last_alert(c_session, g_env->g_session);
2170  /* Fall through */
2171  case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
2172  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2173  ret = -1;
2174  break;
2175  case GNUTLS_E_WARNING_ALERT_RECEIVED:
2176  log_last_alert(c_session, g_env->g_session);
2177  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2178  ret = 0;
2179  break;
2180  case GNUTLS_E_NO_CERTIFICATE_FOUND:
2181 #if (GNUTLS_VERSION_NUMBER > 0x030606)
2182  case GNUTLS_E_CERTIFICATE_REQUIRED:
2183 #endif /* GNUTLS_VERSION_NUMBER > 0x030606 */
2185  "Client Certificate requested and required, but not provided\n"
2186  );
2187  G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2188  GNUTLS_A_BAD_CERTIFICATE));
2189  g_env->sent_alert = 1;
2190  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2191  ret = -1;
2192  break;
2193  case GNUTLS_E_DECRYPTION_FAILED:
2195  "do_gnutls_handshake: session establish "
2196  "returned '%s'\n",
2197  gnutls_strerror(ret));
2198  G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2199  GNUTLS_A_DECRYPT_ERROR));
2200  g_env->sent_alert = 1;
2201  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2202  ret = -1;
2203  break;
2204  case GNUTLS_E_CERTIFICATE_ERROR:
2205  if (g_env->sent_alert) {
2206  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2207  ret = -1;
2208  break;
2209  }
2210  /* Fall through */
2211  case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
2212  case GNUTLS_E_NO_CIPHER_SUITES:
2213  case GNUTLS_E_INVALID_SESSION:
2215  "do_gnutls_handshake: session establish "
2216  "returned '%s'\n",
2217  gnutls_strerror(ret));
2218  if (!g_env->sent_alert) {
2219  G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2220  GNUTLS_A_HANDSHAKE_FAILURE));
2221  g_env->sent_alert = 1;
2222  }
2223  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2224  ret = -1;
2225  break;
2226  case GNUTLS_E_SESSION_EOF:
2227  case GNUTLS_E_TIMEDOUT:
2228  case GNUTLS_E_PULL_ERROR:
2229  case GNUTLS_E_PUSH_ERROR:
2230  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2231  ret = -1;
2232  break;
2233  default:
2235  "do_gnutls_handshake: session establish "
2236  "returned %d: '%s'\n",
2237  ret, gnutls_strerror(ret));
2238  ret = -1;
2239  break;
2240  }
2241  return ret;
2242 }
2243 
2244 void *coap_dtls_new_client_session(coap_session_t *c_session) {
2245  coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
2246  int ret;
2247 
2248  if (g_env) {
2249  ret = do_gnutls_handshake(c_session, g_env);
2250  if (ret == -1) {
2251  coap_dtls_free_gnutls_env(c_session->context->dtls_context,
2252  g_env,
2253  COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
2254  COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2255  return NULL;
2256  }
2257  }
2258  return g_env;
2259 }
2260 
2261 void coap_dtls_free_session(coap_session_t *c_session) {
2262  if (c_session && c_session->context && c_session->tls) {
2263  coap_dtls_free_gnutls_env(c_session->context->dtls_context,
2264  c_session->tls,
2265  COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
2266  COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2267  c_session->tls = NULL;
2268  coap_handle_event(c_session->context, COAP_EVENT_DTLS_CLOSED, c_session);
2269  }
2270 }
2271 
2273  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2274  int ret;
2275 
2276  if (g_env)
2277  G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session,
2278  (unsigned int)c_session->mtu),
2279  "gnutls_dtls_set_data_mtu");
2280 fail:
2281  ;;
2282 }
2283 
2284 /*
2285  * return +ve data amount
2286  * 0 no more
2287  * -1 error
2288  */
2289 int coap_dtls_send(coap_session_t *c_session,
2290  const uint8_t *data, size_t data_len) {
2291  int ret;
2292  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2293 
2294  assert(g_env != NULL);
2295 
2296  c_session->dtls_event = -1;
2297  if (g_env->established) {
2298  ret = gnutls_record_send(g_env->g_session, data, data_len);
2299 
2300  if (ret <= 0) {
2301  switch (ret) {
2302  case GNUTLS_E_AGAIN:
2303  ret = 0;
2304  break;
2305  case GNUTLS_E_FATAL_ALERT_RECEIVED:
2306  /* Stop the sending of an alert on closedown */
2307  g_env->sent_alert = 1;
2308  log_last_alert(c_session, g_env->g_session);
2309  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2310  ret = -1;
2311  break;
2312  default:
2314  "coap_dtls_send: gnutls_record_send "
2315  "returned %d: '%s'\n",
2316  ret, gnutls_strerror(ret));
2317  ret = -1;
2318  break;
2319  }
2320  if (ret == -1) {
2321  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
2322  }
2323  }
2324  }
2325  else {
2326  ret = do_gnutls_handshake(c_session, g_env);
2327  if (ret == 1) {
2328  /* Just connected, so send the data */
2329  return coap_dtls_send(c_session, data, data_len);
2330  }
2331  ret = -1;
2332  }
2333 
2334  if (c_session->dtls_event >= 0) {
2335  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
2336  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2337  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2339  ret = -1;
2340  }
2341  }
2342 
2343  return ret;
2344 }
2345 
2346 int coap_dtls_is_context_timeout(void) {
2347  return 0;
2348 }
2349 
2351  return 0;
2352 }
2353 
2355  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2356 
2357  assert(c_session->state == COAP_SESSION_STATE_HANDSHAKE);
2358  if (g_env && g_env->g_session) {
2359  unsigned int rem_ms = gnutls_dtls_get_timeout(g_env->g_session);
2360 
2361  if (rem_ms == 0) {
2362  /*
2363  * Need to make sure that we do not do this too frequently as some
2364  * versions of gnutls reset retransmit if a spurious packet is received
2365  * (e.g. duplicate Client Hello), but last_transmit does not get updated
2366  * when gnutls_handshake() is called and there is 'nothing' to resend.
2367  */
2368  if (g_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS > now)
2369  return g_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS;
2370  }
2371  /* Reset for the next time */
2372  g_env->last_timeout = now;
2373  return now + rem_ms;
2374  }
2375 
2376  return 0;
2377 }
2378 
2379 void coap_dtls_handle_timeout(coap_session_t *c_session) {
2380  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2381 
2382  assert(g_env != NULL && c_session->state == COAP_SESSION_STATE_HANDSHAKE);
2383  g_env->doing_dtls_timeout = 1;
2384  if ((++c_session->dtls_timeout_count > c_session->max_retransmit) ||
2385  (do_gnutls_handshake(c_session, g_env) < 0)) {
2386  /* Too many retries */
2387  g_env->doing_dtls_timeout = 0;
2389  }
2390  else {
2391  g_env->doing_dtls_timeout = 0;
2392  }
2393 }
2394 
2395 /*
2396  * return +ve data amount
2397  * 0 no more
2398  * -1 error
2399  */
2400 int
2402  const uint8_t *data,
2403  size_t data_len
2404 ) {
2405  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2406  int ret = 0;
2407  coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
2408 
2409  uint8_t pdu[COAP_RXBUFFER_SIZE];
2410 
2411  assert(g_env != NULL);
2412 
2413  if (ssl_data->pdu_len)
2414  coap_log(LOG_ERR, "** %s: Previous data not read %u bytes\n",
2415  coap_session_str(c_session), ssl_data->pdu_len);
2416  ssl_data->pdu = data;
2417  ssl_data->pdu_len = data_len;
2418 
2419  c_session->dtls_event = -1;
2420  if (g_env->established) {
2421  if (c_session->state == COAP_SESSION_STATE_HANDSHAKE) {
2423  c_session);
2424  gnutls_transport_set_ptr(g_env->g_session, c_session);
2425  coap_session_connected(c_session);
2426  }
2427  ret = gnutls_record_recv(g_env->g_session, pdu, (int)sizeof(pdu));
2428  if (ret > 0) {
2429  return coap_handle_dgram(c_session->context, c_session, pdu, (size_t)ret);
2430  }
2431  else if (ret == 0) {
2432  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2433  }
2434  else {
2435  switch (ret) {
2436  case GNUTLS_E_FATAL_ALERT_RECEIVED:
2437  /* Stop the sending of an alert on closedown */
2438  g_env->sent_alert = 1;
2439  log_last_alert(c_session, g_env->g_session);
2440  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2441  ret = -1;
2442  break;
2443  case GNUTLS_E_WARNING_ALERT_RECEIVED:
2444  log_last_alert(c_session, g_env->g_session);
2445  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2446  ret = 0;
2447  break;
2448  default:
2450  "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
2451  ret = -1;
2452  break;
2453  }
2454  }
2455  }
2456  else {
2457  ret = do_gnutls_handshake(c_session, g_env);
2458  if (ret == 1) {
2459  coap_session_connected(c_session);
2460  }
2461  else {
2462  ret = -1;
2463  if (ssl_data->pdu_len && !g_env->sent_alert) {
2464  /* Do the handshake again incase of internal timeout */
2465  ret = do_gnutls_handshake(c_session, g_env);
2466  if (ret == 1) {
2467  /* Just connected, so send the data */
2468  coap_session_connected(c_session);
2469  }
2470  }
2471  }
2472  }
2473 
2474  if (c_session->dtls_event >= 0) {
2475  /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
2476  if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2477  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
2478  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2479  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2481  ssl_data = NULL;
2482  ret = -1;
2483  }
2484  }
2485  if (ssl_data && ssl_data->pdu_len) {
2486  /* pdu data is held on stack which will not stay there */
2487  coap_log(LOG_DEBUG, "coap_dtls_receive: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2488  ssl_data->pdu_len = 0;
2489  ssl_data->pdu = NULL;
2490  }
2491  return ret;
2492 }
2493 
2494 /*
2495  * return -1 failure
2496  * 0 not completed
2497  * 1 client hello seen
2498  */
2499 int
2500 coap_dtls_hello(coap_session_t *c_session,
2501  const uint8_t *data,
2502  size_t data_len
2503 ) {
2504  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2505  coap_ssl_t *ssl_data;
2506  int ret;
2507 
2508  if (!g_env) {
2509  g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
2510  if (g_env) {
2511  c_session->tls = g_env;
2512  gnutls_key_generate(&g_env->coap_ssl_data.cookie_key,
2513  GNUTLS_COOKIE_KEY_SIZE);
2514  }
2515  else {
2516  /* error should have already been reported */
2517  return -1;
2518  }
2519  }
2520  if (data_len > 0) {
2521  gnutls_dtls_prestate_st prestate;
2522  uint8_t *data_rw;
2523 
2524  memset(&prestate, 0, sizeof(prestate));
2525  /* Need to do this to not get a compiler warning about const parameters */
2526  memcpy (&data_rw, &data, sizeof(data_rw));
2527  ret = gnutls_dtls_cookie_verify(&g_env->coap_ssl_data.cookie_key,
2528  &c_session->addr_info,
2529  sizeof(c_session->addr_info),
2530  data_rw, data_len,
2531  &prestate);
2532  if (ret < 0) { /* cookie not valid */
2533  coap_log(LOG_DEBUG, "Invalid Cookie - sending Hello Verify\n");
2534  gnutls_dtls_cookie_send(&g_env->coap_ssl_data.cookie_key,
2535  &c_session->addr_info,
2536  sizeof(c_session->addr_info),
2537  &prestate,
2538  c_session,
2539  coap_dgram_write);
2540  return 0;
2541  }
2542  gnutls_dtls_prestate_set(g_env->g_session, &prestate);
2543  }
2544 
2545  ssl_data = &g_env->coap_ssl_data;
2546  ssl_data->pdu = data;
2547  ssl_data->pdu_len = data_len;
2548 
2549  ret = do_gnutls_handshake(c_session, g_env);
2550  if (ret < 0) {
2551  /*
2552  * as the above failed, need to remove g_env to clean up any
2553  * pollution of the information
2554  */
2555  coap_dtls_free_gnutls_env(
2556  ((coap_gnutls_context_t *)c_session->context->dtls_context),
2557  g_env, COAP_FREE_BYE_NONE);
2558  c_session->tls = NULL;
2559  ssl_data = NULL;
2560  ret = -1;
2561  }
2562  else {
2563  /* Client Hello has been seen */
2564  ret = 1;
2565  }
2566 
2567  if (ssl_data && ssl_data->pdu_len) {
2568  /* pdu data is held on stack which will not stay there */
2569  coap_log(LOG_DEBUG, "coap_dtls_hello: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2570  ssl_data->pdu_len = 0;
2571  ssl_data->pdu = NULL;
2572  }
2573  return ret;
2574 }
2575 
2576 unsigned int coap_dtls_get_overhead(coap_session_t *c_session COAP_UNUSED) {
2577  return 37;
2578 }
2579 
2580 #if !COAP_DISABLE_TCP
2581 /*
2582  * return +ve data amount
2583  * 0 no more
2584  * -1 error (error in errno)
2585  */
2586 static ssize_t
2587 coap_sock_read(gnutls_transport_ptr_t context, void *out, size_t outl) {
2588  int ret = 0;
2589  coap_session_t *c_session = (coap_session_t *)context;
2590 
2591  if (out != NULL) {
2592 #ifdef _WIN32
2593  ret = recv(c_session->sock.fd, (char *)out, (int)outl, 0);
2594 #else
2595  ret = recv(c_session->sock.fd, out, outl, 0);
2596 #endif
2597  if (ret > 0) {
2598  coap_log(LOG_DEBUG, "* %s: received %d bytes\n",
2599  coap_session_str(c_session), ret);
2600  } else if (ret < 0 && errno != EAGAIN) {
2601  coap_log(LOG_DEBUG, "* %s: failed to receive any bytes (%s)\n",
2602  coap_session_str(c_session), coap_socket_strerror());
2603  }
2604  if (ret == 0) {
2605  /* graceful shutdown */
2606  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
2607  return 0;
2608  } else if (ret == COAP_SOCKET_ERROR)
2609  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
2610  else if (ret < (ssize_t)outl)
2611  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
2612  return ret;
2613  }
2614  return ret;
2615 }
2616 
2617 /*
2618  * return +ve data amount
2619  * 0 no more
2620  * -1 error (error in errno)
2621  */
2622 static ssize_t
2623 coap_sock_write(gnutls_transport_ptr_t context, const void *in, size_t inl) {
2624  int ret = 0;
2625  coap_session_t *c_session = (coap_session_t *)context;
2626 
2627  ret = (int)coap_socket_write(&c_session->sock, in, inl);
2628  if (ret > 0) {
2629  coap_log(LOG_DEBUG, "* %s: sent %d bytes\n",
2630  coap_session_str(c_session), ret);
2631  } else if (ret < 0) {
2632  if ((c_session->state == COAP_SESSION_STATE_CSM ||
2633  c_session->state == COAP_SESSION_STATE_HANDSHAKE) &&
2634  (errno == EPIPE || errno == ECONNRESET)) {
2635  /*
2636  * Need to handle a TCP timing window where an agent continues with
2637  * the sending of the next handshake or a CSM.
2638  * However, the peer does not like a certificate and so sends a
2639  * fatal alert and closes the TCP session.
2640  * The sending of the next handshake or CSM may get terminated because
2641  * of the closed TCP session, but there is still an outstanding alert
2642  * to be read in and reported on.
2643  * In this case, pretend that sending the info was fine so that the
2644  * alert can be read (which effectively is what happens with DTLS).
2645  */
2646  ret = inl;
2647  }
2648  else {
2649  coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes (%s) state %d\n",
2650  coap_session_str(c_session), inl, coap_socket_strerror(),
2651  c_session->state);
2652  }
2653  }
2654  if (ret == 0) {
2655  errno = EAGAIN;
2656  ret = -1;
2657  }
2658  return ret;
2659 }
2660 
2661 void *coap_tls_new_client_session(coap_session_t *c_session, int *connected) {
2662  coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2663  coap_gnutls_context_t *g_context =
2664  ((coap_gnutls_context_t *)c_session->context->dtls_context);
2665 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2666  int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2667 #else /* < 3.6.6 */
2668  int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK;
2669 #endif /* < 3.6.6 */
2670  int ret;
2671 
2672  if (!g_env) {
2673  return NULL;
2674  }
2675  memset(g_env, 0, sizeof(coap_gnutls_env_t));
2676 
2677  *connected = 0;
2678  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2679 
2680  gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2681  gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2682  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2683  /* So we can track the coap_session_t in callbacks */
2684  gnutls_transport_set_ptr(g_env->g_session, c_session);
2685 
2686  gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2687  setup_client_ssl_session(c_session, g_env);
2688 
2689  gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2690 
2691  c_session->tls = g_env;
2692  ret = do_gnutls_handshake(c_session, g_env);
2693  if (ret == 1) {
2694  *connected = 1;
2695  coap_handle_event(c_session->context, COAP_EVENT_DTLS_CONNECTED, c_session);
2696  coap_session_send_csm(c_session);
2697  }
2698  return g_env;
2699 
2700 fail:
2701  if (g_env)
2702  gnutls_free(g_env);
2703  return NULL;
2704 }
2705 
2706 void *coap_tls_new_server_session(coap_session_t *c_session, int *connected) {
2707  coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2708  coap_gnutls_context_t *g_context =
2709  ((coap_gnutls_context_t *)c_session->context->dtls_context);
2710 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2711  int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2712 #else /* < 3.6.6 */
2713  int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK;
2714 #endif /* < 3.6.6 */
2715  int ret;
2716 
2717  if (!g_env)
2718  return NULL;
2719  memset(g_env, 0, sizeof(coap_gnutls_env_t));
2720 
2721  *connected = 0;
2722  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2723 
2724  gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2725  gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2726  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2727  /* So we can track the coap_session_t in callbacks */
2728  gnutls_transport_set_ptr(g_env->g_session, c_session);
2729 
2730  setup_server_ssl_session(c_session, g_env);
2731 
2732  gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2733  gnutls_handshake_set_timeout(g_env->g_session,
2734  GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2735 
2736  c_session->tls = g_env;
2737  ret = do_gnutls_handshake(c_session, g_env);
2738  if (ret == 1) {
2739  *connected = 1;
2740  }
2741  return g_env;
2742 
2743 fail:
2744  return NULL;
2745 }
2746 
2747 void coap_tls_free_session(coap_session_t *c_session) {
2748  coap_dtls_free_session(c_session);
2749  return;
2750 }
2751 
2752 /*
2753  * return +ve data amount
2754  * 0 no more
2755  * -1 error (error in errno)
2756  */
2757 ssize_t coap_tls_write(coap_session_t *c_session,
2758  const uint8_t *data,
2759  size_t data_len
2760 ) {
2761  int ret;
2762  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2763 
2764  assert(g_env != NULL);
2765 
2766  c_session->dtls_event = -1;
2767  if (g_env->established) {
2768  ret = gnutls_record_send(g_env->g_session, data, data_len);
2769 
2770  if (ret <= 0) {
2771  switch (ret) {
2772  case GNUTLS_E_AGAIN:
2773  ret = 0;
2774  break;
2775  case GNUTLS_E_PUSH_ERROR:
2776  case GNUTLS_E_PULL_ERROR:
2777  case GNUTLS_E_PREMATURE_TERMINATION:
2778  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2779  ret = -1;
2780  break;
2781  case GNUTLS_E_FATAL_ALERT_RECEIVED:
2782  /* Stop the sending of an alert on closedown */
2783  g_env->sent_alert = 1;
2784  log_last_alert(c_session, g_env->g_session);
2785  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2786  ret = -1;
2787  break;
2788  default:
2790  "coap_tls_write: gnutls_record_send "
2791  "returned %d: '%s'\n",
2792  ret, gnutls_strerror(ret));
2793  ret = -1;
2794  break;
2795  }
2796  if (ret == -1) {
2797  coap_log(LOG_INFO, "coap_tls_write: cannot send PDU\n");
2798  }
2799  }
2800  }
2801  else {
2802  ret = do_gnutls_handshake(c_session, g_env);
2803  if (ret == 1) {
2805  c_session);
2806  coap_session_send_csm(c_session);
2807  }
2808  else {
2809  ret = -1;
2810  }
2811  }
2812 
2813  if (c_session->dtls_event >= 0) {
2814  /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
2815  if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2816  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
2817  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2818  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2820  ret = -1;
2821  }
2822  }
2823 
2824  return ret;
2825 }
2826 
2827 /*
2828  * return +ve data amount
2829  * 0 no more
2830  * -1 error (error in errno)
2831  */
2832 ssize_t coap_tls_read(coap_session_t *c_session,
2833  uint8_t *data,
2834  size_t data_len
2835 ) {
2836  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2837  int ret = -1;
2838 
2839  if (!g_env)
2840  return -1;
2841 
2842  c_session->dtls_event = -1;
2843  if (!g_env->established && !g_env->sent_alert) {
2844  ret = do_gnutls_handshake(c_session, g_env);
2845  if (ret == 1) {
2847  c_session);
2848  coap_session_send_csm(c_session);
2849  }
2850  }
2851  if (c_session->state != COAP_SESSION_STATE_NONE && g_env->established) {
2852  ret = gnutls_record_recv(g_env->g_session, data, (int)data_len);
2853  if (ret <= 0) {
2854  switch (ret) {
2855  case 0:
2856  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2857  break;
2858  case GNUTLS_E_AGAIN:
2859  errno = EAGAIN;
2860  ret = 0;
2861  break;
2862  case GNUTLS_E_PULL_ERROR:
2863  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2864  break;
2865  case GNUTLS_E_FATAL_ALERT_RECEIVED:
2866  /* Stop the sending of an alert on closedown */
2867  g_env->sent_alert = 1;
2868  log_last_alert(c_session, g_env->g_session);
2869  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
2870  ret = -1;
2871  break;
2872  case GNUTLS_E_WARNING_ALERT_RECEIVED:
2873  log_last_alert(c_session, g_env->g_session);
2874  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2875  ret = 0;
2876  break;
2877  default:
2879  "coap_tls_read: gnutls_record_recv "
2880  "returned %d: '%s'\n",
2881  ret, gnutls_strerror(ret));
2882  ret = -1;
2883  break;
2884  }
2885  }
2886  }
2887 
2888  if (c_session->dtls_event >= 0) {
2889  /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
2890  if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2891  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
2892  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2893  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2895  ret = -1;
2896  }
2897  }
2898  return ret;
2899 }
2900 #endif /* !COAP_DISABLE_TCP */
2901 
2903 coap_digest_setup(void) {
2904  gnutls_hash_hd_t digest_ctx;
2905 
2906  if (gnutls_hash_init(&digest_ctx, GNUTLS_DIG_SHA256)) {
2907  return NULL;
2908  }
2909  return digest_ctx;
2910 }
2911 
2912 void
2913 coap_digest_free(coap_digest_ctx_t *digest_ctx) {
2914  gnutls_hash_deinit(digest_ctx, NULL);
2915 }
2916 
2917 int
2919  const uint8_t *data,
2920  size_t data_len) {
2921  int ret = gnutls_hash(digest_ctx, data, data_len);
2922 
2923  return ret == 0;
2924 }
2925 
2926 int
2928  coap_digest_t *digest_buffer) {
2929  gnutls_hash_output(digest_ctx, (uint8_t*)digest_buffer);
2930 
2931  coap_digest_free(digest_ctx);
2932  return 1;
2933 }
2934 
2935 #else /* !HAVE_LIBGNUTLS */
2936 
2937 #ifdef __clang__
2938 /* Make compilers happy that do not like empty modules. As this function is
2939  * never used, we ignore -Wunused-function at the end of compiling this file
2940  */
2941 #pragma GCC diagnostic ignored "-Wunused-function"
2942 #endif
2943 static inline void dummy(void) {
2944 }
2945 
2946 #endif /* !HAVE_LIBGNUTLS */
#define min(a, b)
Definition: block.c:14
static void dummy(void)
Definition: coap_gnutls.c:2943
Pulls together all the internal only header files.
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:427
const char * coap_socket_strerror(void)
Definition: coap_io.c:1502
#define COAP_RXBUFFER_SIZE
Definition: coap_io.h:24
#define COAP_SOCKET_ERROR
Definition: coap_io.h:44
@ COAP_NACK_TLS_FAILED
Definition: coap_io.h:68
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
void * coap_dtls_new_server_session(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:105
int coap_dtls_context_set_spsk(coap_context_t *ctx COAP_UNUSED, coap_dtls_spsk_t *setup_data COAP_UNUSED)
Definition: coap_notls.c:58
void coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:140
int coap_dtls_context_set_pki(coap_context_t *ctx COAP_UNUSED, const coap_dtls_pki_t *setup_data COAP_UNUSED, const coap_dtls_role_t role COAP_UNUSED)
Definition: coap_notls.c:35
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition: coap_notls.c:136
void * coap_dtls_new_context(coap_context_t *coap_context COAP_UNUSED)
Definition: coap_notls.c:97
int coap_dtls_send(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition: coap_notls.c:120
void * coap_dtls_new_client_session(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:109
ssize_t coap_tls_read(coap_session_t *session COAP_UNUSED, uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition: coap_notls.c:181
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition: coap_notls.c:131
int coap_dtls_receive(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition: coap_notls.c:144
unsigned int coap_dtls_get_overhead(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:159
void * coap_tls_new_client_session(coap_session_t *session COAP_UNUSED, int *connected COAP_UNUSED)
Definition: coap_notls.c:163
void * coap_tls_new_server_session(coap_session_t *session COAP_UNUSED, int *connected COAP_UNUSED)
Definition: coap_notls.c:167
int coap_dtls_hello(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition: coap_notls.c:152
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx COAP_UNUSED)
Definition: coap_notls.c:65
static int dtls_log_level
Definition: coap_notls.c:70
int coap_dtls_context_set_cpsk(coap_context_t *ctx COAP_UNUSED, coap_dtls_cpsk_t *setup_data COAP_UNUSED)
Definition: coap_notls.c:51
ssize_t coap_tls_write(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition: coap_notls.c:174
void coap_dtls_session_update_mtu(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:116
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)
Definition: coap_notls.c:43
void coap_dtls_free_context(void *handle COAP_UNUSED)
Definition: coap_notls.c:102
void coap_dtls_free_session(coap_session_t *coap_session COAP_UNUSED)
Definition: coap_notls.c:113
void * coap_dtls_get_tls(const coap_session_t *c_session COAP_UNUSED, coap_tls_library_t *tls_lib)
Definition: coap_notls.c:76
void coap_tls_free_session(coap_session_t *coap_session COAP_UNUSED)
Definition: coap_notls.c:171
coap_binary_t * get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, asn1_validate validate)
Get the asn1 tag and data from the current ptr.
Definition: coap_asn1.c:63
@ COAP_ASN1_BITSTRING
@ COAP_ASN1_IDENTIFIER
void coap_digest_free(coap_digest_ctx_t *digest_ctx)
Free off coap_digest_ctx_t.
Definition: coap_notls.c:205
coap_digest_ctx_t * coap_digest_setup(void)
Initialize a coap_digest.
Definition: coap_notls.c:194
int coap_digest_final(coap_digest_ctx_t *digest_ctx, coap_digest_t *digest_buffer)
Finalize the coap_digest information into the provided digest_buffer.
Definition: coap_notls.c:222
int coap_digest_update(coap_digest_ctx_t *digest_ctx, const uint8_t *data, size_t data_len)
Update the coap_digest information with the next chunk of data.
Definition: coap_notls.c:210
void coap_digest_ctx_t
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:122
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *msg, size_t msg_len)
Parses and interprets a CoAP datagram with context ctx.
Definition: net.c:1898
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition: net.c:3163
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition: coap_notls.c:72
#define COAP_DTLS_RETRANSMIT_MS
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition: coap_notls.c:127
void coap_dtls_shutdown(void)
Close down the underlying (D)TLS Library layer.
Definition: coap_notls.c:83
#define COAP_DTLS_RETRANSMIT_COAP_TICKS
#define COAP_DTLS_RETRANSMIT_TOTAL_MS
#define COAP_DTLS_HINT_LENGTH
Definition: coap_dtls.h:28
coap_dtls_role_t
Definition: coap_dtls.h:31
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:22
#define COAP_DTLS_RPK_CERT_CN
Definition: coap_dtls.h:36
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
Definition: coap_notls.c:27
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition: coap_notls.c:17
coap_tls_library_t
Definition: coap_dtls.h:52
@ COAP_DTLS_ROLE_SERVER
Internal function invoked for server.
Definition: coap_dtls.h:33
@ COAP_DTLS_ROLE_CLIENT
Internal function invoked for client.
Definition: coap_dtls.h:32
@ COAP_PKI_KEY_PKCS11
The PKI key type is PKCS11 (DER)
Definition: coap_dtls.h:152
@ COAP_PKI_KEY_PEM_BUF
The PKI key type is PEM buffer.
Definition: coap_dtls.h:151
@ COAP_PKI_KEY_PEM
The PKI key type is PEM file.
Definition: coap_dtls.h:149
@ COAP_PKI_KEY_ASN1
The PKI key type is ASN.1 (DER) buffer.
Definition: coap_dtls.h:150
@ COAP_ASN1_PKEY_EC
EC type.
Definition: coap_dtls.h:138
@ COAP_TLS_LIBRARY_GNUTLS
Using GnuTLS library.
Definition: coap_dtls.h:56
#define COAP_EVENT_DTLS_ERROR
Definition: coap_event.h:35
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
Definition: coap_event.h:32
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:33
void coap_dtls_set_log_level(int level)
Sets the (D)TLS logging level to the specified level.
Definition: coap_notls.c:87
const char * coap_session_str(const coap_session_t *session)
Get session description.
int coap_dtls_get_log_level(void)
Get the current (D)TLS logging.
Definition: coap_notls.c:92
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:152
@ LOG_ERR
Error.
Definition: coap_debug.h:55
@ LOG_INFO
Information.
Definition: coap_debug.h:58
@ LOG_WARNING
Warning.
Definition: coap_debug.h:56
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:59
@ COAP_PROTO_DTLS
Definition: pdu.h:283
@ COAP_PROTO_TLS
Definition: pdu.h:285
int coap_session_refresh_psk_hint(coap_session_t *session, const coap_bin_const_t *psk_hint)
Refresh the session's current Identity Hint (PSK).
Definition: coap_session.c:996
void coap_session_send_csm(coap_session_t *session)
Notify session transport has just connected and CSM exchange can now start.
Definition: coap_session.c:351
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for datagram data transmission.
Definition: coap_session.c:277
int coap_session_refresh_psk_key(coap_session_t *session, const coap_bin_const_t *psk_key)
Refresh the session's current pre-shared key (PSK).
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
Definition: coap_session.c:399
#define COAP_PROTO_NOT_RELIABLE(p)
Definition: coap_session.h:35
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:456
@ COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:55
@ COAP_SESSION_STATE_CSM
Definition: coap_session.h:56
@ COAP_SESSION_STATE_NONE
Definition: coap_session.h:53
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition: str.c:104
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition: str.c:91
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition: str.c:95
#define COAP_UNUSED
Definition: libcoap.h:55
const uint32_t n
Definition: murmur3.c:56
CoAP binary data definition with const data.
Definition: str.h:58
size_t length
length of binary data
Definition: str.h:59
const uint8_t * s
read-only binary data
Definition: str.h:60
CoAP binary data definition.
Definition: str.h:50
size_t length
length of binary data
Definition: str.h:51
uint8_t * s
binary data
Definition: str.h:52
The CoAP stack's global state is stored in a coap_context_t object.
size_t(* get_server_psk)(const coap_session_t *session, const uint8_t *identity, size_t identity_len, uint8_t *psk, size_t max_psk_len)
size_t(* get_client_psk)(const coap_session_t *session, const uint8_t *hint, size_t hint_len, uint8_t *identity, size_t *identity_len, size_t max_identity_len, uint8_t *psk, size_t max_psk_len)
coap_dtls_spsk_t spsk_setup_data
Contains the initial PSK server setup data.
The structure that holds the Client PSK information.
Definition: coap_dtls.h:307
coap_bin_const_t key
Definition: coap_dtls.h:309
coap_bin_const_t identity
Definition: coap_dtls.h:308
The structure used for defining the Client PSK setup data to be used.
Definition: coap_dtls.h:338
void * ih_call_back_arg
Passed in to the Identity Hint callback function.
Definition: coap_dtls.h:359
char * client_sni
If not NULL, SNI to use in client TLS setup.
Definition: coap_dtls.h:362
coap_dtls_ih_callback_t validate_ih_call_back
Identity Hint check callback function.
Definition: coap_dtls.h:358
The structure that holds the PKI key information.
Definition: coap_dtls.h:212
coap_pki_key_pem_t pem
for PEM file keys
Definition: coap_dtls.h:215
coap_pki_key_pkcs11_t pkcs11
for PKCS11 keys
Definition: coap_dtls.h:218
union coap_dtls_key_t::@2 key
coap_pki_key_pem_buf_t pem_buf
for PEM memory keys
Definition: coap_dtls.h:216
coap_pki_key_t key_type
key format type
Definition: coap_dtls.h:213
coap_pki_key_asn1_t asn1
for ASN.1 (DER) memory keys
Definition: coap_dtls.h:217
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:244
uint8_t cert_chain_validation
1 if to check cert_chain_verify_depth
Definition: coap_dtls.h:255
uint8_t check_cert_revocation
1 if revocation checks wanted
Definition: coap_dtls.h:257
uint8_t cert_chain_verify_depth
recommended depth is 3
Definition: coap_dtls.h:256
uint8_t verify_peer_cert
Set to COAP_DTLS_PKI_SETUP_VERSION to support this version of the struct.
Definition: coap_dtls.h:249
char * client_sni
If not NULL, SNI to use in client TLS setup.
Definition: coap_dtls.h:297
uint8_t is_rpk_not_cert
1 is RPK instead of Public Certificate.
Definition: coap_dtls.h:262
uint8_t check_common_ca
1 if peer cert is to be signed by the same CA as the local cert
Definition: coap_dtls.h:250
coap_dtls_key_t pki_key
PKI key definition.
Definition: coap_dtls.h:301
The structure that holds the Server Pre-Shared Key and Identity Hint information.
Definition: coap_dtls.h:374
coap_bin_const_t hint
Definition: coap_dtls.h:375
The structure used for defining the Server PSK setup data to be used.
Definition: coap_dtls.h:425
coap_dtls_psk_sni_callback_t validate_sni_call_back
SNI check callback function.
Definition: coap_dtls.h:452
coap_dtls_id_callback_t validate_id_call_back
Identity check callback function.
Definition: coap_dtls.h:444
void * id_call_back_arg
Passed in to the Identity callback function.
Definition: coap_dtls.h:445
void * sni_call_back_arg
Passed in to the SNI callback function.
Definition: coap_dtls.h:453
coap_dtls_spsk_info_t psk_info
Server PSK definition.
Definition: coap_dtls.h:455
const uint8_t * private_key
ASN1 (DER) Private Key.
Definition: coap_dtls.h:190
coap_asn1_privatekey_type_t private_key_type
Private Key Type.
Definition: coap_dtls.h:194
size_t public_cert_len
ASN1 Public Cert length.
Definition: coap_dtls.h:192
size_t private_key_len
ASN1 Private Key length.
Definition: coap_dtls.h:193
const uint8_t * ca_cert
ASN1 (DER) Common CA Cert.
Definition: coap_dtls.h:188
size_t ca_cert_len
ASN1 CA Cert length.
Definition: coap_dtls.h:191
const uint8_t * public_cert
ASN1 (DER) Public Cert, or Public Key if RPK.
Definition: coap_dtls.h:189
size_t ca_cert_len
PEM buffer CA Cert length.
Definition: coap_dtls.h:179
const uint8_t * ca_cert
PEM buffer Common CA Cert.
Definition: coap_dtls.h:174
size_t private_key_len
PEM buffer Private Key length.
Definition: coap_dtls.h:181
const uint8_t * private_key
PEM buffer Private Key If RPK and 'EC PRIVATE KEY' this can be used for both the public_cert and priv...
Definition: coap_dtls.h:176
size_t public_cert_len
PEM buffer Public Cert length.
Definition: coap_dtls.h:180
const uint8_t * public_cert
PEM buffer Public Cert, or Public Key if RPK.
Definition: coap_dtls.h:175
const char * ca_file
File location of Common CA in PEM format.
Definition: coap_dtls.h:159
const char * public_cert
File location of Public Cert.
Definition: coap_dtls.h:160
const char * private_key
File location of Private Key in PEM format.
Definition: coap_dtls.h:161
const char * private_key
pkcs11: URI for Private Key
Definition: coap_dtls.h:203
const char * ca
pkcs11: URI for Common CA Certificate
Definition: coap_dtls.h:201
const char * user_pin
User pin to access PKCS11.
Definition: coap_dtls.h:204
const char * public_cert
pkcs11: URI for Public Cert
Definition: coap_dtls.h:202
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
unsigned int dtls_timeout_count
dtls setup retry counter
coap_socket_t sock
socket object for the session, if any
unsigned int max_retransmit
maximum re-transmit count (default 4)
coap_bin_const_t * psk_identity
If client, this field contains the current identity for server; When this field is NULL,...
coap_session_state_t state
current state of relationaship with peer
coap_addr_tuple_t addr_info
key: remote/local address info
coap_proto_t proto
protocol used
coap_dtls_cpsk_t cpsk_setup_data
client provided PSK initial setup data
size_t mtu
path or CSM mtu
int dtls_event
Tracking any (D)TLS events on this sesison.
void * tls
security parameters
coap_context_t * context
session's context
coap_socket_flags_t flags
CoAP string data definition with const data.
Definition: str.h:40
const uint8_t * s
read-only string data
Definition: str.h:42
size_t length
length of string
Definition: str.h:41
The structure used for returning the underlying (D)TLS library information.
Definition: coap_dtls.h:64
uint64_t built_version
(D)TLS Built against Library Version
Definition: coap_dtls.h:67
coap_tls_library_t type
Library type.
Definition: coap_dtls.h:66
uint64_t version
(D)TLS runtime Library Version
Definition: coap_dtls.h:65