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