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