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