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