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