libcoap  4.2.1
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-2019 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 #include "coap_internal.h"
23 
24 #ifdef HAVE_LIBGNUTLS
25 
26 #define MIN_GNUTLS_VERSION "3.3.0"
27 
28 #include <inttypes.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <gnutls/gnutls.h>
32 #include <gnutls/x509.h>
33 #include <gnutls/dtls.h>
34 #include <unistd.h>
35 
36 #ifdef __GNUC__
37 #define UNUSED __attribute__((unused))
38 #else /* __GNUC__ */
39 #define UNUSED
40 #endif /* __GNUC__ */
41 
42 typedef struct coap_ssl_t {
43  const uint8_t *pdu;
44  unsigned pdu_len;
45  unsigned peekmode;
46  coap_tick_t timeout;
47 } coap_ssl_t;
48 
49 /*
50  * This structure encapsulates the GnuTLS session object.
51  * It handles both TLS and DTLS.
52  * c_session->tls points to this.
53  */
54 typedef struct coap_gnutls_env_t {
55  gnutls_session_t g_session;
56  gnutls_psk_client_credentials_t psk_cl_credentials;
57  gnutls_psk_server_credentials_t psk_sv_credentials;
58  gnutls_certificate_credentials_t pki_credentials;
59  coap_ssl_t coap_ssl_data;
60  /* If not set, need to do gnutls_handshake */
61  int established;
62  int seen_client_hello;
63  int doing_dtls_timeout;
64 } coap_gnutls_env_t;
65 
66 #define IS_PSK (1 << 0)
67 #define IS_PKI (1 << 1)
68 #define IS_CLIENT (1 << 6)
69 #define IS_SERVER (1 << 7)
70 
71 typedef struct sni_entry {
72  char *sni;
73  coap_dtls_key_t pki_key;
74  gnutls_certificate_credentials_t pki_credentials;
75 } sni_entry;
76 
77 typedef struct coap_gnutls_context_t {
78  coap_dtls_pki_t setup_data;
79  int psk_pki_enabled;
80  size_t sni_count;
81  sni_entry *sni_entry_list;
82  gnutls_datum_t alpn_proto; /* Will be "coap", but that is a const */
83  char *root_ca_file;
84  char *root_ca_path;
85  gnutls_priority_t priority_cache;
86 } coap_gnutls_context_t;
87 
88 typedef enum coap_free_bye_t {
89  COAP_FREE_BYE_AS_TCP,
90  COAP_FREE_BYE_AS_UDP,
91  COAP_FREE_BYE_NONE
92 } coap_free_bye_t;
93 
94 #if (GNUTLS_VERSION_NUMBER >= 0x030505)
95 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8"
96 #else
97 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK"
98 #endif
99 
100 #define G_ACTION(xx) do { \
101  ret = (xx); \
102 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
103 
104 #define G_CHECK(xx,func) do { \
105  if ((ret = (xx)) < 0) { \
106  coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \
107  goto fail; \
108  } \
109 } while (0)
110 
111 #define G_ACTION_CHECK(xx,func) do { \
112  G_ACTION(xx); \
113  G_CHECK(xx, func); \
114 } while 0
115 
116 static int dtls_log_level = 0;
117 
118 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
119 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
120 
121 /*
122  * return 0 failed
123  * 1 passed
124  */
125 int
127  if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
128  coap_log(LOG_ERR, "GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
129  return 0;
130  }
131  return 1;
132 }
133 
134 /*
135  * return 0 failed
136  * 1 passed
137  */
138 int
139 coap_tls_is_supported(void) {
140  if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
141  coap_log(LOG_ERR, "GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
142  return 0;
143  }
144  return 1;
145 }
146 
149  static coap_tls_version_t version;
150  const char *vers = gnutls_check_version(NULL);
151 
152  version.version = 0;
153  if (vers) {
154  int p1, p2, p3;
155 
156  sscanf (vers, "%d.%d.%d", &p1, &p2, &p3);
157  version.version = (p1 << 16) | (p2 << 8) | p3;
158  }
159  version.built_version = GNUTLS_VERSION_NUMBER;
160  version.type = COAP_TLS_LIBRARY_GNUTLS;
161  return &version;
162 }
163 
164 static void
165 coap_gnutls_audit_log_func(gnutls_session_t g_session, const char* text)
166 {
167  if (g_session) {
168  coap_session_t *c_session =
169  (coap_session_t *)gnutls_transport_get_ptr(g_session);
170  coap_log(LOG_WARNING, "** %s: %s",
171  coap_session_str(c_session), text);
172  } else {
173  coap_log(LOG_WARNING, "** (null): %s", text);
174  }
175 }
176 
177 static void
178 coap_gnutls_log_func(int level, const char* text)
179 {
180  /* debug logging in gnutls starts at 2 */
181  if (level > 2)
182  level = 2;
183  coap_log(LOG_DEBUG + level - 2, "%s", text);
184 }
185 
186 /*
187  * return 0 failed
188  * 1 passed
189  */
190 int
192  coap_dtls_pki_t* setup_data,
194 {
195  coap_gnutls_context_t *g_context =
196  ((coap_gnutls_context_t *)c_context->dtls_context);
197 
198  if (!g_context || !setup_data)
199  return 0;
200 
201  g_context->setup_data = *setup_data;
202  g_context->psk_pki_enabled |= IS_PKI;
203  return 1;
204 }
205 
206 /*
207  * return 0 failed
208  * 1 passed
209  */
210 int
212  const char *ca_file,
213  const char *ca_path)
214 {
215  coap_gnutls_context_t *g_context =
216  ((coap_gnutls_context_t *)c_context->dtls_context);
217  if (!g_context) {
219  "coap_context_set_pki_root_cas: (D)TLS environment "
220  "not set up\n");
221  return 0;
222  }
223 
224  if (ca_file == NULL && ca_path == NULL) {
226  "coap_context_set_pki_root_cas: ca_file and/or ca_path "
227  "not defined\n");
228  return 0;
229  }
230  if (g_context->root_ca_file) {
231  gnutls_free(g_context->root_ca_file);
232  g_context->root_ca_file = NULL;
233  }
234  if (ca_file) {
235  g_context->root_ca_file = gnutls_strdup(ca_file);
236  }
237  if (g_context->root_ca_path) {
238  gnutls_free(g_context->root_ca_path);
239  g_context->root_ca_path = NULL;
240  }
241  if (ca_path) {
242 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
243  g_context->root_ca_path = gnutls_strdup(ca_path);
244 #else
245  coap_log(LOG_ERR, "ca_path not supported in GnuTLS < 3.3.6\n");
246 #endif
247  }
248  return 1;
249 }
250 
251 /*
252  * return 0 failed
253  * 1 passed
254  */
255 int
257  const char *identity_hint UNUSED,
258  coap_dtls_role_t role UNUSED
259 ) {
260  coap_gnutls_context_t *g_context =
261  ((coap_gnutls_context_t *)c_context->dtls_context);
262 
263  g_context->psk_pki_enabled |= IS_PSK;
264  return 1;
265 }
266 
267 /*
268  * return 0 failed
269  * 1 passed
270  */
271 int
273 {
274  coap_gnutls_context_t *g_context =
275  ((coap_gnutls_context_t *)c_context->dtls_context);
276  return g_context->psk_pki_enabled ? 1 : 0;
277 }
278 
279 void coap_dtls_startup(void) {
280  gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
281  gnutls_global_set_log_function(coap_gnutls_log_func);
282 }
283 
284 void
285 coap_dtls_set_log_level(int level) {
286  dtls_log_level = level;
287  if (level - LOG_DEBUG >= -2) {
288  /* debug logging in gnutls starts at 2 */
289  gnutls_global_set_log_level(2 + level - LOG_DEBUG);
290  }
291  else {
292  gnutls_global_set_log_level(0);
293  }
294 }
295 
296 /*
297  * return current logging level
298  */
299 int
301  return dtls_log_level;
302 }
303 
304 /*
305  * return +ve new g_context
306  * NULL failure
307  */
308 void *
309 coap_dtls_new_context(struct coap_context_t *c_context UNUSED) {
310  const char *err;
311  int ret;
312  struct coap_gnutls_context_t *g_context =
313  (struct coap_gnutls_context_t *)
314  gnutls_malloc(sizeof(coap_gnutls_context_t));
315 
316  if (g_context) {
317  G_CHECK(gnutls_global_init(), "gnutls_global_init");
318  memset(g_context, 0, sizeof(struct coap_gnutls_context_t));
319  g_context->alpn_proto.data = gnutls_malloc(4);
320  if (g_context->alpn_proto.data) {
321  memcpy(g_context->alpn_proto.data, "coap", 4);
322  g_context->alpn_proto.size = 4;
323  }
324  G_CHECK(gnutls_priority_init(&g_context->priority_cache, VARIANTS, &err),
325  "gnutls_priority_init");
326  }
327  return g_context;
328 
329 fail:
330  if (g_context)
331  coap_dtls_free_context(g_context);
332  return NULL;
333 }
334 
335 void
336 coap_dtls_free_context(void *handle) {
337  size_t i;
338  coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
339 
340  gnutls_free(g_context->alpn_proto.data);
341  gnutls_free(g_context->root_ca_file);
342  gnutls_free(g_context->root_ca_path);
343  for (i = 0; i < g_context->sni_count; i++) {
344  gnutls_free(g_context->sni_entry_list[i].sni);
345  if (g_context->psk_pki_enabled & IS_PKI) {
346  gnutls_certificate_free_credentials(
347  g_context->sni_entry_list[i].pki_credentials);
348  }
349  }
350  if (g_context->sni_count)
351  gnutls_free(g_context->sni_entry_list);
352 
353  gnutls_priority_deinit(g_context->priority_cache);
354 
355  gnutls_global_deinit();
356  gnutls_free(g_context);
357 }
358 
359 /*
360  * gnutls_psk_client_credentials_function return values
361  * (see gnutls_psk_set_client_credentials_function())
362  *
363  * return -1 failed
364  * 0 passed
365  */
366 static int
367 psk_client_callback(gnutls_session_t g_session,
368  char **username, gnutls_datum_t *key) {
369  coap_session_t *c_session =
370  (coap_session_t *)gnutls_transport_get_ptr(g_session);
371  uint8_t identity[64];
372  size_t identity_len;
373  uint8_t psk_key[64];
374  size_t psk_len;
375 
376  /* Constant passed to get_client_psk callback. The final byte is
377  * reserved for a terminating 0. */
378  const size_t max_identity_len = sizeof(identity) - 1;
379 
380  /* Initialize result parameters. */
381  *username = NULL;
382  key->data = NULL;
383 
384  if (c_session == NULL || c_session->context == NULL ||
385  c_session->context->get_client_psk == NULL) {
386  return -1;
387  }
388 
389  psk_len = c_session->context->get_client_psk(c_session,
390  NULL,
391  0,
392  identity,
393  &identity_len,
394  max_identity_len,
395  psk_key,
396  sizeof(psk_key));
397  assert(identity_len < sizeof(identity));
398 
399  /* Reserve dynamic memory to hold the identity and a terminating
400  * zero. */
401  *username = gnutls_malloc(identity_len+1);
402  if (*username) {
403  memcpy(*username, identity, identity_len);
404  (*username)[identity_len] = '\0';
405  }
406 
407  key->data = gnutls_malloc(psk_len);
408  if (key->data) {
409  memcpy(key->data, psk_key, psk_len);
410  key->size = psk_len;
411  }
412 
413  return (*username && key->data) ? 0 : -1;
414 }
415 
416 /*
417  * return +ve SAN or CN derived from certificate
418  * NULL failed
419  */
420 static char* get_san_or_cn(gnutls_session_t g_session)
421 {
422  unsigned int cert_list_size = 0;
423  const gnutls_datum_t *cert_list;
424  gnutls_x509_crt_t cert;
425  char dn[256];
426  size_t size;
427  int n;
428  char *cn;
429  int ret;
430 
431  if (gnutls_certificate_type_get(g_session) != GNUTLS_CRT_X509)
432  return NULL;
433 
434  cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
435  if (cert_list_size == 0) {
436  return NULL;
437  }
438 
439  G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
440 
441  /* Interested only in first cert in chain */
442  G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
443  "gnutls_x509_crt_import");
444 
445  size = sizeof(dn) -1;
446  /* See if there is a Subject Alt Name first */
447  ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
448  if (ret >= 0) {
449  dn[size] = '\000';
450  gnutls_x509_crt_deinit(cert);
451  return gnutls_strdup(dn);
452  }
453 
454  size = sizeof(dn);
455  G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size), "gnutls_x509_crt_get_dn");
456 
457  gnutls_x509_crt_deinit(cert);
458 
459  /* Need to emulate strcasestr() here. Looking for CN= */
460  n = strlen(dn) - 3;
461  cn = dn;
462  while (n > 0) {
463  if (((cn[0] == 'C') || (cn[0] == 'c')) &&
464  ((cn[1] == 'N') || (cn[1] == 'n')) &&
465  (cn[2] == '=')) {
466  cn += 3;
467  break;
468  }
469  cn++;
470  n--;
471  }
472  if (n > 0) {
473  char *ecn = strchr(cn, ',');
474  if (ecn) {
475  cn[ecn-cn] = '\000';
476  }
477  return gnutls_strdup(cn);
478  }
479  return NULL;
480 
481 fail:
482  return NULL;
483 }
484 
485 /*
486  * return 0 failed
487  * 1 passed
488  */
489 static int cert_verify_gnutls(gnutls_session_t g_session)
490 {
491  unsigned int status = 0;
492  coap_session_t *c_session =
493  (coap_session_t *)gnutls_transport_get_ptr(g_session);
494  coap_gnutls_context_t *g_context =
495  (coap_gnutls_context_t *)c_session->context->dtls_context;
496  char *cn = NULL;
497  int alert = GNUTLS_A_BAD_CERTIFICATE;
498  int ret;
499 
500  G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
501  "gnutls_certificate_verify_peers");
502 
503  cn = get_san_or_cn(g_session);
504 
505  if (status) {
506  status &= ~(GNUTLS_CERT_INVALID);
507  if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
508  if (g_context->setup_data.allow_expired_certs) {
509  status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
511  " %s: %s: overridden: '%s'\n",
512  coap_session_str(c_session),
513  "The certificate has an invalid usage date", cn ? cn : "?");
514  }
515  }
516  if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
517  GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
518  if (g_context->setup_data.allow_expired_crl) {
519  status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
520  GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
522  " %s: %s: overridden: '%s'\n",
523  coap_session_str(c_session),
524  "The certificate's CRL entry has an invalid usage date",
525  cn ? cn : "?");
526  }
527  }
528 
529  if (status) {
531  " %s: status 0x%x: '%s'\n",
532  coap_session_str(c_session),
533  status, cn ? cn : "?");
534  }
535  }
536 
537  if (status)
538  goto fail;
539 
540  if (g_context->setup_data.validate_cn_call_back) {
541  unsigned int cert_list_size = 0;
542  const gnutls_datum_t *cert_list;
543  gnutls_x509_crt_t cert;
544  uint8_t der[2048];
545  size_t size;
546  /* status == 0 indicates that the certificate passed to
547  * setup_data.validate_cn_call_back has been validated. */
548  const int cert_is_trusted = !status;
549 
550  cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
551  if (cert_list_size == 0) {
552  /* get_san_or_cn() should have caught this */
553  goto fail;
554  }
555 
556  G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
557 
558  /* Interested only in first cert in chain */
559  G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
560  "gnutls_x509_crt_import");
561 
562  size = sizeof(der);
563  G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
564  "gnutls_x509_crt_export");
565  gnutls_x509_crt_deinit(cert);
566  if (!g_context->setup_data.validate_cn_call_back(cn,
567  der,
568  size,
569  c_session,
570  0,
571  cert_is_trusted,
572  g_context->setup_data.cn_call_back_arg)) {
573  alert = GNUTLS_A_ACCESS_DENIED;
574  goto fail;
575  }
576  }
577 
578  if (g_context->setup_data.additional_tls_setup_call_back) {
579  /* Additional application setup wanted */
580  if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
581  &g_context->setup_data)) {
582  goto fail;
583  }
584  }
585 
586  if (cn)
587  gnutls_free(cn);
588 
589  return 1;
590 
591 fail:
592  if (cn)
593  gnutls_free(cn);
594 
595  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
596  return 0;
597 }
598 
599 /*
600  * gnutls_certificate_verify_function return values
601  * (see gnutls_certificate_set_verify_function())
602  *
603  * return -1 failed
604  * 0 passed
605  */
606 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
607 {
608  int ret;
609 
610  if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
611  if (cert_verify_gnutls(g_session) == 0) {
612  G_ACTION(gnutls_alert_send(g_session,
613  GNUTLS_AL_FATAL,
614  GNUTLS_A_ACCESS_DENIED));
615  return -1;
616  }
617  }
618  return 0;
619 }
620 
621 /*
622  * return 0 Success (GNUTLS_E_SUCCESS)
623  * neg GNUTLS_E_* error code
624  */
625 static int
626 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
627  coap_gnutls_context_t *g_context,
628  coap_dtls_pki_t *setup_data, coap_dtls_role_t role)
629 {
630  int ret;
631 
632  G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
633  "gnutls_certificate_allocate_credentials");
634 
635  switch (setup_data->pki_key.key_type) {
636  case COAP_PKI_KEY_PEM:
637  if (setup_data->pki_key.key.pem.public_cert &&
638  setup_data->pki_key.key.pem.public_cert[0] &&
639  setup_data->pki_key.key.pem.private_key &&
640  setup_data->pki_key.key.pem.private_key[0]) {
641  G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
642  setup_data->pki_key.key.pem.public_cert,
643  setup_data->pki_key.key.pem.private_key,
644  GNUTLS_X509_FMT_PEM),
645  "gnutls_certificate_set_x509_key_file");
646  }
647  else if (role == COAP_DTLS_ROLE_SERVER) {
649  "***setup_pki: (D)TLS: No %s Certificate + Private "
650  "Key defined\n",
651  role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client");
652  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
653  }
654  if (setup_data->pki_key.key.pem.ca_file &&
655  setup_data->pki_key.key.pem.ca_file[0]) {
656  G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
657  setup_data->pki_key.key.pem.ca_file,
658  GNUTLS_X509_FMT_PEM),
659  "gnutls_certificate_set_x509_trust_file");
660  }
661  break;
662 
663  case COAP_PKI_KEY_ASN1:
664  if (setup_data->pki_key.key.asn1.public_cert &&
665  setup_data->pki_key.key.asn1.public_cert_len &&
666  setup_data->pki_key.key.asn1.private_key &&
667  setup_data->pki_key.key.asn1.private_key_len > 0) {
668  gnutls_datum_t cert;
669  gnutls_datum_t key;
670 
671  /* Kludge to get around const parameters */
672  memcpy(&cert.data, &setup_data->pki_key.key.asn1.public_cert,
673  sizeof(cert.data));
674  cert.size = setup_data->pki_key.key.asn1.public_cert_len;
675  memcpy(&key.data, &setup_data->pki_key.key.asn1.private_key,
676  sizeof(key.data));
677  key.size = setup_data->pki_key.key.asn1.private_key_len;
678  G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
679  &cert,
680  &key,
681  GNUTLS_X509_FMT_DER),
682  "gnutls_certificate_set_x509_key_mem");
683  }
684  else if (role == COAP_DTLS_ROLE_SERVER) {
686  "***setup_pki: (D)TLS: No %s Certificate + Private "
687  "Key defined\n",
688  role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client");
689  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
690  }
691  if (setup_data->pki_key.key.asn1.ca_cert &&
692  setup_data->pki_key.key.asn1.ca_cert_len > 0) {
693  gnutls_datum_t ca_cert;
694 
695  /* Kludge to get around const parameters */
696  memcpy(&ca_cert.data, &setup_data->pki_key.key.asn1.ca_cert,
697  sizeof(ca_cert.data));
698  ca_cert.size = setup_data->pki_key.key.asn1.ca_cert_len;
699  G_CHECK(gnutls_certificate_set_x509_trust_mem(*pki_credentials,
700  &ca_cert,
701  GNUTLS_X509_FMT_DER),
702  "gnutls_certificate_set_x509_trust_mem");
703  }
704  break;
705  default:
707  "***setup_pki: (D)TLS: Unknown key type %d\n",
708  setup_data->pki_key.key_type);
709  return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
710  }
711 
712  if (g_context->root_ca_file) {
713  G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
714  g_context->root_ca_file,
715  GNUTLS_X509_FMT_PEM),
716  "gnutls_certificate_set_x509_trust_file");
717  }
718  if (g_context->root_ca_path) {
719 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
720  G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
721  g_context->root_ca_path,
722  GNUTLS_X509_FMT_PEM),
723  "gnutls_certificate_set_x509_trust_dir");
724 #endif
725  }
726  if (!(g_context->psk_pki_enabled & IS_PKI)) {
727  /* No PKI defined at all - still need a trust set up for 3.6.0 or later */
728  G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
729  "gnutls_certificate_set_x509_system_trust");
730  }
731 
732  /* Verify Peer */
733  if (setup_data->verify_peer_cert) {
734  gnutls_certificate_set_verify_function(*pki_credentials,
735  cert_verify_callback_gnutls);
736  }
737 
738  /* Cert chain checking (can raise GNUTLS_E_CONSTRAINT_ERROR) */
739  if (setup_data->cert_chain_validation) {
740  gnutls_certificate_set_verify_limits(*pki_credentials,
741  0,
742  setup_data->cert_chain_verify_depth);
743  }
744 
745  /* Check for self signed */
746  gnutls_certificate_set_verify_flags(*pki_credentials,
747  GNUTLS_VERIFY_DO_NOT_ALLOW_SAME);
748 
749  /* CRL checking (can raise GNUTLS_CERT_MISSING_OCSP_STATUS) */
750  if (setup_data->check_cert_revocation == 0) {
751  gnutls_certificate_set_verify_flags(*pki_credentials,
752  GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
753  GNUTLS_VERIFY_DISABLE_CRL_CHECKS);
754  }
755 
756  return GNUTLS_E_SUCCESS;
757 
758 fail:
759  return ret;
760 }
761 
762 /*
763  * return 0 Success (GNUTLS_E_SUCCESS)
764  * neg GNUTLS_E_* error code
765  */
766 static int
767 post_client_hello_gnutls_pki(gnutls_session_t g_session)
768 {
769  coap_session_t *c_session =
770  (coap_session_t *)gnutls_transport_get_ptr(g_session);
771  coap_gnutls_context_t *g_context =
772  (coap_gnutls_context_t *)c_session->context->dtls_context;
773  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
774  int ret = GNUTLS_E_SUCCESS;
775  char *name = NULL;
776 
777  g_env->seen_client_hello = 1;
778 
779  if (g_context->setup_data.validate_sni_call_back) {
780  /* DNS names (only type supported) may be at most 256 byte long */
781  size_t len = 256;
782  unsigned int type;
783  unsigned int i;
784  coap_dtls_pki_t sni_setup_data;
785 
786  name = gnutls_malloc(len);
787  if (name == NULL)
788  return GNUTLS_E_MEMORY_ERROR;
789 
790  for (i=0; ; ) {
791  ret = gnutls_server_name_get(g_session, name, &len, &type, i);
792  if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
793  char *new_name;
794  new_name = gnutls_realloc(name, len);
795  if (new_name == NULL) {
796  ret = GNUTLS_E_MEMORY_ERROR;
797  goto end;
798  }
799  name = new_name;
800  continue; /* retry call with same index */
801  }
802 
803  /* check if it is the last entry in list */
804  if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
805  break;
806  i++;
807  if (ret != GNUTLS_E_SUCCESS)
808  goto end;
809  /* unknown types need to be ignored */
810  if (type != GNUTLS_NAME_DNS)
811  continue;
812 
813  }
814  /* If no extension provided, make it a dummy entry */
815  if (i == 0) {
816  name[0] = '\000';
817  len = 0;
818  }
819 
820  /* Is this a cached entry? */
821  for (i = 0; i < g_context->sni_count; i++) {
822  if (strcmp(name, g_context->sni_entry_list[i].sni) == 0) {
823  break;
824  }
825  }
826  if (i == g_context->sni_count) {
827  /*
828  * New SNI request
829  */
830  coap_dtls_key_t *new_entry =
831  g_context->setup_data.validate_sni_call_back(name,
832  g_context->setup_data.sni_call_back_arg);
833  if (!new_entry) {
834  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
835  GNUTLS_A_UNRECOGNIZED_NAME));
836  ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
837  goto end;
838  }
839 
840  g_context->sni_entry_list = gnutls_realloc(g_context->sni_entry_list,
841  (i+1)*sizeof(sni_entry));
842  g_context->sni_entry_list[i].sni = gnutls_strdup(name);
843  g_context->sni_entry_list[i].pki_key = *new_entry;
844  sni_setup_data = g_context->setup_data;
845  sni_setup_data.pki_key = *new_entry;
846  if ((ret = setup_pki_credentials(
847  &g_context->sni_entry_list[i].pki_credentials,
848  g_context,
849  &sni_setup_data, COAP_DTLS_ROLE_CLIENT)) < 0) {
850  int keep_ret = ret;
851  G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
852  GNUTLS_A_BAD_CERTIFICATE));
853  ret = keep_ret;
854  goto end;
855  }
856  g_context->sni_count++;
857  }
858  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
859  g_context->sni_entry_list[i].pki_credentials),
860  "gnutls_credentials_set");
861  }
862 
863 end:
864  free(name);
865  return ret;
866 
867 fail:
868  return ret;
869 }
870 
871 /*
872  * return 0 Success (GNUTLS_E_SUCCESS)
873  * neg GNUTLS_E_* error code
874  */
875 static int
876 post_client_hello_gnutls_psk(gnutls_session_t g_session)
877 {
878  coap_session_t *c_session =
879  (coap_session_t *)gnutls_transport_get_ptr(g_session);
880  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
881 
882  g_env->seen_client_hello = 1;
883  return GNUTLS_E_SUCCESS;
884 }
885 
886 /*
887  * return 0 Success (GNUTLS_E_SUCCESS)
888  * neg GNUTLS_E_* error code
889  */
890 static int
891 setup_client_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env)
892 {
893  coap_gnutls_context_t *g_context =
894  (coap_gnutls_context_t *)c_session->context->dtls_context;
895  int ret;
896 
897  g_context->psk_pki_enabled |= IS_CLIENT;
898  if (g_context->psk_pki_enabled & IS_PSK) {
899  char *identity = NULL;
900  gnutls_datum_t psk_key;
901 
902  G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
903  "gnutls_psk_allocate_client_credentials");
904  psk_client_callback(g_env->g_session, &identity, &psk_key);
905  G_CHECK(gnutls_psk_set_client_credentials(g_env->psk_cl_credentials,
906  identity,
907  &psk_key,
908  GNUTLS_PSK_KEY_RAW),
909  "gnutls_psk_set_client_credentials");
910  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
911  g_env->psk_cl_credentials),
912  "gnutls_credentials_set");
913  gnutls_free(identity);
914  gnutls_free(psk_key.data);
915  }
916 
917  if ((g_context->psk_pki_enabled & IS_PKI) ||
918  (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
919  /*
920  * If neither PSK or PKI have been set up, use PKI basics.
921  * This works providing COAP_PKI_KEY_PEM has a value of 0.
922  */
923  coap_dtls_pki_t *setup_data = &g_context->setup_data;
924  G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
925  setup_data, COAP_DTLS_ROLE_CLIENT),
926  "setup_pki_credentials");
927 
928  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
929  g_env->pki_credentials),
930  "gnutls_credentials_set");
931 
932  if (c_session->proto == COAP_PROTO_TLS)
933  G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
934  &g_context->alpn_proto, 1, 0),
935  "gnutls_alpn_set_protocols");
936 
937  /* Issue SNI if requested (only happens if PKI defined) */
938  if (setup_data->client_sni) {
939  G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
940  setup_data->client_sni,
941  strlen(setup_data->client_sni)),
942  "gnutls_server_name_set");
943  }
944  }
945  return GNUTLS_E_SUCCESS;
946 
947 fail:
948  return ret;
949 }
950 
951 /*
952  * gnutls_psk_server_credentials_function return values
953  * (see gnutls_psk_set_server_credentials_function())
954  *
955  * return -1 failed
956  * 0 passed
957  */
958 static int
959 psk_server_callback(gnutls_session_t g_session,
960  const char *identity,
961  gnutls_datum_t *key)
962 {
963  coap_session_t *c_session =
964  (coap_session_t *)gnutls_transport_get_ptr(g_session);
965  size_t identity_len = 0;
966  uint8_t buf[64];
967  size_t psk_len;
968 
969  if (identity)
970  identity_len = strlen(identity);
971  else
972  identity = "";
973 
974  coap_log(LOG_DEBUG, "got psk_identity: '%.*s'\n",
975  (int)identity_len, identity);
976 
977  if (c_session == NULL || c_session->context == NULL ||
978  c_session->context->get_server_psk == NULL)
979  return -1;
980 
981  psk_len = c_session->context->get_server_psk(c_session,
982  (const uint8_t*)identity,
983  identity_len,
984  (uint8_t*)buf, sizeof(buf));
985  key->data = gnutls_malloc(psk_len);
986  memcpy(key->data, buf, psk_len);
987  key->size = psk_len;
988  return 0;
989 }
990 
991 /*
992  * return 0 Success (GNUTLS_E_SUCCESS)
993  * neg GNUTLS_E_* error code
994  */
995 static int
996 setup_server_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env)
997 {
998  coap_gnutls_context_t *g_context =
999  (coap_gnutls_context_t *)c_session->context->dtls_context;
1000  int ret = GNUTLS_E_SUCCESS;
1001 
1002  g_context->psk_pki_enabled |= IS_SERVER;
1003  if (g_context->psk_pki_enabled & IS_PSK) {
1004  G_CHECK(gnutls_psk_allocate_server_credentials(&g_env->psk_sv_credentials),
1005  "gnutls_psk_allocate_server_credentials");
1006  gnutls_psk_set_server_credentials_function(g_env->psk_sv_credentials,
1007  psk_server_callback);
1008 
1009  gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1010  post_client_hello_gnutls_psk);
1011 
1012  G_CHECK(gnutls_credentials_set(g_env->g_session,
1013  GNUTLS_CRD_PSK,
1014  g_env->psk_sv_credentials),
1015  "gnutls_credentials_set\n");
1016  }
1017 
1018  if (g_context->psk_pki_enabled & IS_PKI) {
1019  coap_dtls_pki_t *setup_data = &g_context->setup_data;
1020  G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
1021  setup_data, COAP_DTLS_ROLE_SERVER),
1022  "setup_pki_credentials");
1023 
1024  if (setup_data->require_peer_cert) {
1025  gnutls_certificate_server_set_request(g_env->g_session,
1026  GNUTLS_CERT_REQUIRE);
1027  }
1028  else {
1029  gnutls_certificate_server_set_request(g_env->g_session, GNUTLS_CERT_IGNORE);
1030  }
1031 
1032  gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1033  post_client_hello_gnutls_pki);
1034 
1035  G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1036  g_env->pki_credentials),
1037  "gnutls_credentials_set\n");
1038  }
1039  return GNUTLS_E_SUCCESS;
1040 
1041 fail:
1042  return ret;
1043 }
1044 
1045 /*
1046  * return +ve data amount
1047  * 0 no more
1048  * -1 error (error in errno)
1049  */
1050 static ssize_t
1051 coap_dgram_read(gnutls_transport_ptr_t context, void *out, size_t outl)
1052 {
1053  ssize_t ret = 0;
1054  coap_session_t *c_session = (struct coap_session_t *)context;
1055  coap_ssl_t *data = &((coap_gnutls_env_t *)c_session->tls)->coap_ssl_data;
1056 
1057  if (!c_session->tls) {
1058  errno = EAGAIN;
1059  return -1;
1060  }
1061 
1062  if (out != NULL) {
1063  if (data != NULL && data->pdu_len > 0) {
1064  if (outl < data->pdu_len) {
1065  memcpy(out, data->pdu, outl);
1066  ret = outl;
1067  data->pdu += outl;
1068  data->pdu_len -= outl;
1069  } else {
1070  memcpy(out, data->pdu, data->pdu_len);
1071  ret = data->pdu_len;
1072  if (!data->peekmode) {
1073  data->pdu_len = 0;
1074  data->pdu = NULL;
1075  }
1076  }
1077  }
1078  else {
1079  errno = EAGAIN;
1080  ret = -1;
1081  }
1082  }
1083  return ret;
1084 }
1085 
1086 /*
1087  * return +ve data amount
1088  * 0 no more
1089  * -1 error (error in errno)
1090  */
1091 /* callback function given to gnutls for sending data over socket */
1092 static ssize_t
1093 coap_dgram_write(gnutls_transport_ptr_t context, const void *send_buffer,
1094  size_t send_buffer_length) {
1095  ssize_t result = -1;
1096  coap_session_t *c_session = (struct coap_session_t *)context;
1097 
1098  if (c_session) {
1099  result = coap_session_send(c_session, send_buffer, send_buffer_length);
1100  if (result != (int)send_buffer_length) {
1101  coap_log(LOG_WARNING, "coap_network_send failed\n");
1102  result = 0;
1103  }
1104  } else {
1105  result = 0;
1106  }
1107  return result;
1108 }
1109 
1110 /*
1111  * return 1 fd has activity
1112  * 0 timeout
1113  * -1 error (error in errno)
1114  */
1115 static int
1116 receive_timeout(gnutls_transport_ptr_t context, unsigned int ms UNUSED) {
1117  coap_session_t *c_session = (struct coap_session_t *)context;
1118 
1119  if (c_session) {
1120  fd_set readfds, writefds, exceptfds;
1121  struct timeval tv;
1122  int nfds = c_session->sock.fd +1;
1123  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1124 
1125  /* If data has been read in by libcoap ahead of GnuTLS, say it is there */
1126  if (c_session->proto == COAP_PROTO_DTLS && g_env &&
1127  g_env->coap_ssl_data.pdu_len > 0) {
1128  return 1;
1129  }
1130 
1131  FD_ZERO(&readfds);
1132  FD_ZERO(&writefds);
1133  FD_ZERO(&exceptfds);
1134  FD_SET (c_session->sock.fd, &readfds);
1135  if (!(g_env && g_env->doing_dtls_timeout)) {
1136  FD_SET (c_session->sock.fd, &writefds);
1137  FD_SET (c_session->sock.fd, &exceptfds);
1138  }
1139  /* Polling */
1140  tv.tv_sec = 0;
1141  tv.tv_usec = 0;
1142 
1143  return select(nfds, &readfds, &writefds, &exceptfds, &tv);
1144  }
1145  return 1;
1146 }
1147 
1148 static coap_gnutls_env_t *
1149 coap_dtls_new_gnutls_env(coap_session_t *c_session, int type)
1150 {
1151  coap_gnutls_context_t *g_context =
1152  ((coap_gnutls_context_t *)c_session->context->dtls_context);
1153  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1154  int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
1155  int ret;
1156 
1157  if (g_env)
1158  return g_env;
1159 
1160  g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
1161  if (!g_env)
1162  return NULL;
1163 
1164  memset(g_env, 0, sizeof(struct coap_gnutls_env_t));
1165 
1166  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
1167 
1168  gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
1169  gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
1170  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1171  /* So we can track the coap_session_t in callbacks */
1172  gnutls_transport_set_ptr(g_env->g_session, c_session);
1173 
1174  if (type == GNUTLS_SERVER) {
1175  G_CHECK(setup_server_ssl_session(c_session, g_env),
1176  "setup_server_ssl_session");
1177  }
1178  else {
1179  G_CHECK(setup_client_ssl_session(c_session, g_env),
1180  "setup_client_ssl_session");
1181  }
1182 
1183  G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
1184  "gnutls_priority_set");
1185  gnutls_handshake_set_timeout(g_env->g_session,
1186  GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1187  gnutls_dtls_set_timeouts(g_env->g_session, 5000, 60000);
1188 
1189  return g_env;
1190 
1191 fail:
1192  if (g_env)
1193  gnutls_free(g_env);
1194  return NULL;
1195 }
1196 
1197 static void
1198 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
1199  coap_gnutls_env_t *g_env,
1200  coap_free_bye_t free_bye)
1201 {
1202  if (g_env) {
1203  /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS
1204  * connections because the peer's closure message might
1205  * be lost */
1206  if (free_bye != COAP_FREE_BYE_NONE) {
1207  /* Only do this if appropriate */
1208  gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
1209  GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
1210  }
1211  gnutls_deinit(g_env->g_session);
1212  g_env->g_session = NULL;
1213  if (g_context->psk_pki_enabled & IS_PSK) {
1214  if (g_context->psk_pki_enabled & IS_CLIENT) {
1215  gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
1216  g_env->psk_cl_credentials = NULL;
1217  }
1218  else {
1219  gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
1220  g_env->psk_sv_credentials = NULL;
1221  }
1222  }
1223  if ((g_context->psk_pki_enabled & IS_PKI) ||
1224  (g_context->psk_pki_enabled &
1225  (IS_PSK | IS_PKI | IS_CLIENT)) == IS_CLIENT) {
1226  gnutls_certificate_free_credentials(g_env->pki_credentials);
1227  g_env->pki_credentials = NULL;
1228  }
1229  gnutls_free(g_env);
1230  }
1231 }
1232 
1233 void *coap_dtls_new_server_session(coap_session_t *c_session) {
1234  coap_gnutls_env_t *g_env =
1235  (coap_gnutls_env_t *)c_session->tls;
1236 
1237  gnutls_transport_set_ptr(g_env->g_session, c_session);
1238 
1239  return g_env;
1240 }
1241 
1242 static void log_last_alert(gnutls_session_t g_session) {
1243  int last_alert = gnutls_alert_get(g_session);
1244 
1245  coap_log(LOG_WARNING, "Received alert '%d': '%s'\n",
1246  last_alert, gnutls_alert_get_name(last_alert));
1247 }
1248 
1249 /*
1250  * return -1 failure
1251  * 0 not completed
1252  * 1 established
1253  */
1254 static int
1255 do_gnutls_handshake(coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1256  int ret;
1257 
1258  ret = gnutls_handshake(g_env->g_session);
1259  switch (ret) {
1260  case GNUTLS_E_SUCCESS:
1261  g_env->established = 1;
1262  coap_log(LOG_DEBUG, "* %s: GnuTLS established\n",
1263  coap_session_str(c_session));
1264  ret = 1;
1265  break;
1266  case GNUTLS_E_INTERRUPTED:
1267  errno = EINTR;
1268  ret = 0;
1269  break;
1270  case GNUTLS_E_AGAIN:
1271  errno = EAGAIN;
1272  ret = 0;
1273  break;
1274  case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
1276  "Insufficient credentials provided.\n");
1277  ret = -1;
1278  break;
1279  case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
1280  case GNUTLS_E_FATAL_ALERT_RECEIVED:
1281  log_last_alert(g_env->g_session);
1282  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1283  ret = -1;
1284  break;
1285  case GNUTLS_E_WARNING_ALERT_RECEIVED:
1286  log_last_alert(g_env->g_session);
1287  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
1288  ret = 0;
1289  break;
1290  case GNUTLS_E_NO_CERTIFICATE_FOUND:
1292  "Client Certificate requested and required, but not provided\n"
1293  );
1294  G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1295  GNUTLS_A_BAD_CERTIFICATE));
1296  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1297  ret = -1;
1298  break;
1299  case GNUTLS_E_DECRYPTION_FAILED:
1301  "do_gnutls_handshake: session establish "
1302  "returned %d: '%s'\n",
1303  ret, gnutls_strerror(ret));
1304  G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1305  GNUTLS_A_DECRYPT_ERROR));
1306  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1307  ret = -1;
1308  break;
1309  case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
1310  /* fall through */
1311  case GNUTLS_E_TIMEDOUT:
1312  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1313  ret = -1;
1314  break;
1315  default:
1317  "do_gnutls_handshake: session establish "
1318  "returned %d: '%s'\n",
1319  ret, gnutls_strerror(ret));
1320  ret = -1;
1321  break;
1322  }
1323  return ret;
1324 }
1325 
1326 void *coap_dtls_new_client_session(coap_session_t *c_session) {
1327  coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
1328  int ret;
1329 
1330  if (g_env) {
1331  ret = do_gnutls_handshake(c_session, g_env);
1332  if (ret == -1) {
1333  coap_dtls_free_gnutls_env(c_session->context->dtls_context,
1334  g_env,
1335  COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
1336  COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1337  return NULL;
1338  }
1339  }
1340  return g_env;
1341 }
1342 
1343 void coap_dtls_free_session(coap_session_t *c_session) {
1344  if (c_session && c_session->context) {
1345  coap_dtls_free_gnutls_env(c_session->context->dtls_context,
1346  c_session->tls,
1347  COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
1348  COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1349  c_session->tls = NULL;
1350  coap_handle_event(c_session->context, COAP_EVENT_DTLS_CLOSED, c_session);
1351  }
1352 }
1353 
1355  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1356  int ret;
1357 
1358  if (g_env)
1359  G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session, c_session->mtu),
1360  "gnutls_dtls_set_data_mtu");
1361 fail:
1362  ;;
1363 }
1364 
1365 /*
1366  * return +ve data amount
1367  * 0 no more
1368  * -1 error
1369  */
1370 int coap_dtls_send(coap_session_t *c_session,
1371  const uint8_t *data, size_t data_len) {
1372  int ret;
1373  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1374 
1375  assert(g_env != NULL);
1376 
1377  c_session->dtls_event = -1;
1378  if (g_env->established) {
1379  ret = gnutls_record_send(g_env->g_session, data, data_len);
1380 
1381  if (ret <= 0) {
1382  switch (ret) {
1383  case GNUTLS_E_AGAIN:
1384  ret = 0;
1385  break;
1386  case GNUTLS_E_FATAL_ALERT_RECEIVED:
1387  log_last_alert(g_env->g_session);
1388  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
1389  ret = -1;
1390  break;
1391  default:
1392  ret = -1;
1393  break;
1394  }
1395  if (ret == -1) {
1396  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
1397  }
1398  }
1399  }
1400  else {
1401  ret = do_gnutls_handshake(c_session, g_env);
1402  if (ret == 1) {
1403  /* Just connected, so send the data */
1404  return coap_dtls_send(c_session, data, data_len);
1405  }
1406  ret = -1;
1407  }
1408 
1409  if (c_session->dtls_event >= 0) {
1410  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
1411  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
1412  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
1414  ret = -1;
1415  }
1416  }
1417 
1418  return ret;
1419 }
1420 
1421 int coap_dtls_is_context_timeout(void) {
1422  return 0;
1423 }
1424 
1425 coap_tick_t coap_dtls_get_context_timeout(void *dtls_context UNUSED) {
1426  return 0;
1427 }
1428 
1430  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1431 
1432  if (g_env && g_env->g_session) {
1433  unsigned int rem_ms = gnutls_dtls_get_timeout(g_env->g_session);
1434 
1435  return now + rem_ms;
1436  }
1437 
1438  return 0;
1439 }
1440 
1441 void coap_dtls_handle_timeout(coap_session_t *c_session) {
1442  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1443 
1444  assert(g_env != NULL);
1445  g_env->doing_dtls_timeout = 1;
1446  if (((c_session->state == COAP_SESSION_STATE_HANDSHAKE) &&
1447  (++c_session->dtls_timeout_count > c_session->max_retransmit)) ||
1448  (do_gnutls_handshake(c_session, g_env) < 0)) {
1449  /* Too many retries */
1450  g_env->doing_dtls_timeout = 0;
1452  }
1453  else {
1454  g_env->doing_dtls_timeout = 0;
1455  }
1456 }
1457 
1458 /*
1459  * return +ve data amount
1460  * 0 no more
1461  * -1 error
1462  */
1463 int
1465  const uint8_t *data,
1466  size_t data_len
1467 ) {
1468  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1469  int ret = 0;
1470  coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
1471 
1473 
1474  assert(g_env != NULL);
1475 
1476  if (ssl_data->pdu_len)
1477  coap_log(LOG_INFO, "** %s: Previous data not read %u bytes\n",
1478  coap_session_str(c_session), ssl_data->pdu_len);
1479  ssl_data->pdu = data;
1480  ssl_data->pdu_len = (unsigned)data_len;
1481 
1482  c_session->dtls_event = -1;
1483  if (g_env->established) {
1484  if (c_session->state == COAP_SESSION_STATE_HANDSHAKE) {
1486  c_session);
1487  gnutls_transport_set_ptr(g_env->g_session, c_session);
1488  coap_session_connected(c_session);
1489  }
1490  ret = gnutls_record_recv(g_env->g_session, pdu, (int)sizeof(pdu));
1491  if (ret > 0) {
1492  return coap_handle_dgram(c_session->context, c_session, pdu, (size_t)ret);
1493  }
1494  else if (ret == 0) {
1495  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1496  }
1497  else {
1499  "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
1500  ret = -1;
1501  }
1502  }
1503  else {
1504  ret = do_gnutls_handshake(c_session, g_env);
1505  if (ret == 1) {
1506  coap_session_connected(c_session);
1507  }
1508  else {
1509  ret = -1;
1510  }
1511  }
1512 
1513  if (c_session->dtls_event >= 0) {
1514  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
1515  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
1516  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
1518  ret = -1;
1519  }
1520  }
1521 
1522  return ret;
1523 }
1524 
1525 /*
1526  * return 0 failed
1527  * 1 passed
1528  */
1529 int
1530 coap_dtls_hello(coap_session_t *c_session,
1531  const uint8_t *data,
1532  size_t data_len
1533 ) {
1534  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1535  coap_ssl_t *ssl_data = g_env ? &g_env->coap_ssl_data : NULL;
1536  int ret;
1537 
1538  if (!g_env) {
1539  g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
1540  if (g_env) {
1541  c_session->tls = g_env;
1542  ssl_data = &g_env->coap_ssl_data;
1543  ssl_data->pdu = data;
1544  ssl_data->pdu_len = (unsigned)data_len;
1545  gnutls_dtls_set_data_mtu(g_env->g_session, c_session->mtu);
1546  ret = do_gnutls_handshake(c_session, g_env);
1547  if (ret == 1 || g_env->seen_client_hello) {
1548  /* The test for seen_client_hello gives the ability to setup a new
1549  coap_session to continue the gnutls_handshake past the client hello
1550  and safely allow updating of the g_env & g_session and separately
1551  letting a new session cleanly start up using endpoint->hello.
1552  */
1553  g_env->seen_client_hello = 0;
1554  return 1;
1555  }
1556  /*
1557  * as the above failed, need to remove g_env to clean up any
1558  * pollution of the information
1559  */
1560  coap_dtls_free_gnutls_env(
1561  ((coap_gnutls_context_t *)c_session->context->dtls_context),
1562  g_env, COAP_FREE_BYE_NONE);
1563  c_session->tls = NULL;
1564  }
1565  return 0;
1566  }
1567 
1568  ssl_data->pdu = data;
1569  ssl_data->pdu_len = (unsigned)data_len;
1570 
1571  ret = do_gnutls_handshake(c_session, g_env);
1572  if (ret == 1 || g_env->seen_client_hello) {
1573  /* The test for seen_client_hello gives the ability to setup a new
1574  coap_session to continue the gnutls_handshake past the client hello
1575  and safely allow updating of the g_env & g_session and separately
1576  letting a new session cleanly start up using endpoint->hello.
1577  */
1578  g_env->seen_client_hello = 0;
1579  return 1;
1580  }
1581  return 0;
1582 }
1583 
1584 unsigned int coap_dtls_get_overhead(coap_session_t *c_session UNUSED) {
1585  return 37;
1586 }
1587 
1588 /*
1589  * return +ve data amount
1590  * 0 no more
1591  * -1 error (error in errno)
1592  */
1593 static ssize_t
1594 coap_sock_read(gnutls_transport_ptr_t context, void *out, size_t outl) {
1595  int ret = 0;
1596  coap_session_t *c_session = (struct coap_session_t *)context;
1597 
1598  if (out != NULL) {
1599 #ifdef _WIN32
1600  ret = recv(c_session->sock.fd, (char *)out, (int)outl, 0);
1601 #else
1602  ret = recv(c_session->sock.fd, out, outl, 0);
1603 #endif
1604  if (ret > 0) {
1605  coap_log(LOG_DEBUG, "* %s: setup: received %d bytes\n",
1606  coap_session_str(c_session), ret);
1607  } else if (ret < 0 && errno != EAGAIN) {
1608  coap_log(LOG_DEBUG, "* %s: setup: failed to receive any bytes (%s)\n",
1609  coap_session_str(c_session), coap_socket_strerror());
1610  }
1611  if (ret == 0) {
1612  /* graceful shutdown */
1613  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
1614  return 0;
1615  } else if (ret == COAP_SOCKET_ERROR)
1616  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
1617  else if (ret < (ssize_t)outl)
1618  c_session->sock.flags &= ~COAP_SOCKET_CAN_READ;
1619  return ret;
1620  }
1621  return ret;
1622 }
1623 
1624 /*
1625  * return +ve data amount
1626  * 0 no more
1627  * -1 error (error in errno)
1628  */
1629 static ssize_t
1630 coap_sock_write(gnutls_transport_ptr_t context, const void *in, size_t inl) {
1631  int ret = 0;
1632  coap_session_t *c_session = (struct coap_session_t *)context;
1633 
1634  ret = (int)coap_socket_write(&c_session->sock, in, inl);
1635  if (ret > 0) {
1636  coap_log(LOG_DEBUG, "* %s: setup: sent %d bytes\n",
1637  coap_session_str(c_session), ret);
1638  } else if (ret < 0) {
1639  coap_log(LOG_DEBUG, "* %s: setup: failed to send %d bytes (%s)\n",
1640  coap_session_str(c_session), ret, coap_socket_strerror());
1641  }
1642  if (ret == 0) {
1643  errno = EAGAIN;
1644  ret = -1;
1645  }
1646  return ret;
1647 }
1648 
1649 void *coap_tls_new_client_session(coap_session_t *c_session, int *connected) {
1650  coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
1651  coap_gnutls_context_t *g_context =
1652  ((coap_gnutls_context_t *)c_session->context->dtls_context);
1653  int flags = GNUTLS_CLIENT;
1654  int ret;
1655 
1656  if (!g_env) {
1657  return NULL;
1658  }
1659  memset(g_env, 0, sizeof(struct coap_gnutls_env_t));
1660 
1661  *connected = 0;
1662  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
1663 
1664  gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1665  gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1666  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1667  /* So we can track the coap_session_t in callbacks */
1668  gnutls_transport_set_ptr(g_env->g_session, c_session);
1669 
1670  setup_client_ssl_session(c_session, g_env);
1671 
1672  gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1673  gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1674 
1675  ret = do_gnutls_handshake(c_session, g_env);
1676  if (ret == 1) {
1677  *connected = 1;
1678  coap_handle_event(c_session->context, COAP_EVENT_DTLS_CONNECTED, c_session);
1679  coap_session_connected(c_session);
1680  }
1681  return g_env;
1682 
1683 fail:
1684  if (g_env)
1685  gnutls_free(g_env);
1686  return NULL;
1687 }
1688 
1689 void *coap_tls_new_server_session(coap_session_t *c_session, int *connected) {
1690  coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
1691  coap_gnutls_context_t *g_context =
1692  ((coap_gnutls_context_t *)c_session->context->dtls_context);
1693  int flags = GNUTLS_SERVER;
1694  int ret;
1695 
1696  if (!g_env)
1697  return NULL;
1698  memset(g_env, 0, sizeof(struct coap_gnutls_env_t));
1699 
1700  *connected = 0;
1701  G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
1702 
1703  gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1704  gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1705  gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1706  /* So we can track the coap_session_t in callbacks */
1707  gnutls_transport_set_ptr(g_env->g_session, c_session);
1708 
1709  setup_server_ssl_session(c_session, g_env);
1710 
1711  gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1712  gnutls_handshake_set_timeout(g_env->g_session,
1713  GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1714 
1715  c_session->tls = g_env;
1716  ret = do_gnutls_handshake(c_session, g_env);
1717  if (ret == 1) {
1718  *connected = 1;
1719  }
1720  return g_env;
1721 
1722 fail:
1723  return NULL;
1724 }
1725 
1726 void coap_tls_free_session(coap_session_t *c_session) {
1727  coap_dtls_free_session(c_session);
1728  return;
1729 }
1730 
1731 /*
1732  * return +ve data amount
1733  * 0 no more
1734  * -1 error (error in errno)
1735  */
1736 ssize_t coap_tls_write(coap_session_t *c_session,
1737  const uint8_t *data,
1738  size_t data_len
1739 ) {
1740  int ret;
1741  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1742 
1743  assert(g_env != NULL);
1744 
1745  c_session->dtls_event = -1;
1746  if (g_env->established) {
1747  ret = gnutls_record_send(g_env->g_session, data, data_len);
1748 
1749  if (ret <= 0) {
1750  switch (ret) {
1751  case GNUTLS_E_AGAIN:
1752  ret = 0;
1753  break;
1754  case GNUTLS_E_FATAL_ALERT_RECEIVED:
1755  log_last_alert(g_env->g_session);
1756  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
1757  ret = -1;
1758  break;
1759  default:
1761  "coap_tls_write: gnutls_record_send "
1762  "returned %d: '%s'\n",
1763  ret, gnutls_strerror(ret));
1764  ret = -1;
1765  break;
1766  }
1767  if (ret == -1) {
1768  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
1769  }
1770  }
1771  }
1772  else {
1773  ret = do_gnutls_handshake(c_session, g_env);
1774  if (ret == 1) {
1776  c_session);
1777  coap_session_send_csm(c_session);
1778  }
1779  else {
1780  ret = -1;
1781  }
1782  }
1783 
1784  if (c_session->dtls_event >= 0) {
1785  /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
1786  if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
1787  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
1788  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
1789  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
1791  ret = -1;
1792  }
1793  }
1794 
1795  return ret;
1796 }
1797 
1798 /*
1799  * return +ve data amount
1800  * 0 no more
1801  * -1 error (error in errno)
1802  */
1803 ssize_t coap_tls_read(coap_session_t *c_session,
1804  uint8_t *data,
1805  size_t data_len
1806 ) {
1807  coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1808  int ret;
1809 
1810  if (!g_env)
1811  return -1;
1812 
1813  c_session->dtls_event = -1;
1814  if (!g_env->established) {
1815  ret = do_gnutls_handshake(c_session, g_env);
1816  if (ret == 1) {
1818  c_session);
1819  coap_session_send_csm(c_session);
1820  }
1821  }
1822  if (g_env->established) {
1823  ret = gnutls_record_recv(g_env->g_session, data, (int)data_len);
1824  if (ret <= 0) {
1825  switch (ret) {
1826  case 0:
1827  c_session->dtls_event = COAP_EVENT_DTLS_CLOSED;
1828  break;
1829  case GNUTLS_E_AGAIN:
1830  errno = EAGAIN;
1831  ret = 0;
1832  break;
1833  case GNUTLS_E_PULL_ERROR:
1834  c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
1835  break;
1836  default:
1838  "coap_tls_read: gnutls_record_recv "
1839  "returned %d: '%s'\n",
1840  ret, gnutls_strerror(ret));
1841  ret = -1;
1842  break;
1843  }
1844  }
1845  }
1846 
1847  if (c_session->dtls_event >= 0) {
1848  /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */
1849  if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
1850  coap_handle_event(c_session->context, c_session->dtls_event, c_session);
1851  if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
1852  c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
1854  ret = -1;
1855  }
1856  }
1857  return ret;
1858 }
1859 
1860 #else /* !HAVE_LIBGNUTLS */
1861 
1862 #ifdef __clang__
1863 /* Make compilers happy that do not like empty modules. As this function is
1864  * never used, we ignore -Wunused-function at the end of compiling this file
1865  */
1866 #pragma GCC diagnostic ignored "-Wunused-function"
1867 #endif
1868 static inline void dummy(void) {
1869 }
1870 
1871 #endif /* !HAVE_LIBGNUTLS */
unsigned mtu
path or CSM mtu
Definition: coap_session.h:65
void coap_dtls_set_log_level(int level)
Sets the log level to the specified value.
static void dummy(void)
Definition: coap_gnutls.c:1868
void coap_dtls_free_session(struct coap_dtls_context_t *dtls_context, struct coap_dtls_session_t *session)
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:288
int coap_dtls_hello(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:139
#define COAP_RXBUFFER_SIZE
Definition: coap_io.h:18
void coap_tls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:158
struct coap_context_t * context
session&#39;s context
Definition: coap_session.h:72
The PKI key type is ASN.1 (DER)
Definition: coap_dtls.h:135
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.
void * tls
security parameters
Definition: coap_session.h:73
coap_pki_key_t key_type
key format type
Definition: coap_dtls.h:164
#define COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:55
int coap_dtls_receive(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:131
coap_fd_t fd
Definition: coap_io.h:60
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx UNUSED)
Definition: coap_notls.c:63
ssize_t coap_tls_read(coap_session_t *session UNUSED, uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:168
int coap_dtls_get_log_level(void)
Returns the current log level.
#define COAP_PROTO_DTLS
Definition: pdu.h:345
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:96
Internal function invoked for server.
Definition: coap_dtls.h:268
#define COAP_SOCKET_ERROR
Definition: coap_io.h:38
static int psk_client_callback(gnutls_session_t session, char **username, gnutls_datum_t *key)
int coap_dtls_is_supported(void)
Returns 1 if support for DTLS is enabled, or 0 otherwise.
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, coap_dtls_pki_t *setup_data UNUSED, coap_dtls_role_t role UNUSED)
Definition: coap_notls.c:39
void * coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:154
ssize_t coap_tls_write(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:161
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
Definition: coap_io.h:84
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:216
int dtls_event
Tracking any (D)TLS events on this sesison.
Definition: coap_session.h:96
uint8_t verify_peer_cert
Set to 1 to support this version of the struct.
Definition: coap_dtls.h:197
Debug.
Definition: coap_debug.h:55
uint64_t version
(D)TLS runtime Library Version
Definition: coap_dtls.h:52
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:195
#define UNUSED
void * coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:150
const char * coap_session_str(const coap_session_t *session)
Get session description.
const char * coap_socket_strerror(void)
Definition: coap_io.c:1651
unsigned int max_retransmit
maximum re-transmit count (default 4)
Definition: coap_session.h:92
int coap_dtls_send(struct coap_context_t *coap_context, struct coap_dtls_session_t *session, const coap_pdu_t *pdu)
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:26
coap_tls_library_t type
Library type.
Definition: coap_dtls.h:53
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
Definition: coap_notls.c:31
const char * private_key
File location of Private Key in PEM format.
Definition: coap_dtls.h:144
uint8_t require_peer_cert
1 if peer cert is required
Definition: coap_dtls.h:198
coap_proto_t proto
protocol used
Definition: coap_session.h:60
coap_dtls_key_t pki_key
PKI key definition.
Definition: coap_dtls.h:242
coap_pki_key_pem_t pem
for PEM keys
Definition: coap_dtls.h:166
char * client_sni
If not NULL, SNI to use in client TLS setup.
Definition: coap_dtls.h:238
Warning.
Definition: coap_debug.h:52
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:93
The structure that holds the PKI key information.
Definition: coap_dtls.h:163
unsigned int coap_dtls_get_overhead(coap_session_t *session UNUSED)
Definition: coap_notls.c:146
const uint8_t * public_cert
ASN1 (DER) Public Cert.
Definition: coap_dtls.h:152
const char * ca_file
File location of Common CA in PEM format.
Definition: coap_dtls.h:142
size_t ca_cert_len
ASN1 CA Cert length.
Definition: coap_dtls.h:154
The PKI key type is PEM.
Definition: coap_dtls.h:134
coap_socket_t sock
socket object for the session, if any
Definition: coap_session.h:70
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:690
static int dtls_log_level
Definition: coap_notls.c:68
The structure used for returning the underlying (D)TLS library information.
Definition: coap_dtls.h:51
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
Definition: coap_event.h:33
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:1557
int coap_dtls_context_set_psk(coap_context_t *ctx UNUSED, const char *hint UNUSED, coap_dtls_role_t role UNUSED)
Definition: coap_notls.c:55
#define COAP_PROTO_TLS
Definition: pdu.h:347
uint8_t cert_chain_validation
1 if to check cert_chain_verify_depth
Definition: coap_dtls.h:201
Error.
Definition: coap_debug.h:51
void * dtls_context
Definition: net.h:199
union coap_dtls_key_t::@1 key
coap_session_state_t state
current state of relationaship with peer
Definition: coap_session.h:62
Internal function invoked for client.
Definition: coap_dtls.h:267
const uint8_t * private_key
ASN1 (DER) Private Key.
Definition: coap_dtls.h:153
Using GnuTLS library.
Definition: coap_dtls.h:44
uint8_t check_cert_revocation
1 if revocation checks wanted
Definition: coap_dtls.h:203
coap_dtls_role_t
Definition: coap_dtls.h:266
#define COAP_EVENT_DTLS_ERROR
Definition: coap_event.h:36
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:34
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:2542
void * coap_dtls_new_server_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:92
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
Definition: coap_session.c:330
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:193
int coap_dtls_context_set_pki_root_cas(struct coap_context_t *ctx UNUSED, const char *ca_file UNUSED, const char *ca_path UNUSED)
Definition: coap_notls.c:47
uint8_t cert_chain_verify_depth
recommended depth is 3
Definition: coap_dtls.h:202
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:196
void coap_dtls_handle_timeout(coap_session_t *session UNUSED)
Definition: coap_notls.c:127
const char * public_cert
File location of Public Cert in PEM format.
Definition: coap_dtls.h:143
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition: coap_notls.c:70
coap_tick_t coap_dtls_get_timeout(coap_session_t *session UNUSED, coap_tick_t now UNUSED)
Definition: coap_notls.c:123
#define COAP_PROTO_NOT_RELIABLE(p)
Definition: coap_session.h:38
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Releases the storage allocated for dtls_context.
coap_socket_flags_t flags
Definition: coap_io.h:62
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:387
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:129
const uint8_t * ca_cert
ASN1 (DER) Common CA Cert.
Definition: coap_dtls.h:151
unsigned char uint8_t
Definition: uthash.h:79
size_t public_cert_len
ASN1 Public Cert length.
Definition: coap_dtls.h:155
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context UNUSED)
Definition: coap_notls.c:118
uint64_t built_version
(D)TLS Built against Library Version
Definition: coap_dtls.h:54
void coap_dtls_session_update_mtu(coap_session_t *session UNUSED)
Definition: coap_notls.c:103
Information.
Definition: coap_debug.h:54
unsigned int dtls_timeout_count
dtls setup retry counter
Definition: coap_session.h:95
The CoAP stack&#39;s global state is stored in a coap_context_t object.
Definition: net.h:147
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition: coap_notls.c:114
size_t private_key_len
ASN1 Private Key length.
Definition: coap_dtls.h:156
Pulls together all the internal only header files.
coap_pki_key_asn1_t asn1
for ASN.1 (DER) keys
Definition: coap_dtls.h:167