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
84typedef 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 */
96typedef 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
114typedef 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
120typedef 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
126typedef 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
139typedef 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
168static int dtls_log_level = 0;
169
170#if COAP_SERVER_SUPPORT
171static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
172static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
173static 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 */
182int
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 */
195int
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;
222 return &version;
223}
224
225static void
226coap_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
238static void
239coap_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 */
251int
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 */
299int
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 */
345int
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 */
365int
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 */
384int
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
392void 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
397void coap_dtls_shutdown(void) {
398}
399
400void *
401coap_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
413void
414coap_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 */
428int
430 return dtls_log_level;
431}
432
433/*
434 * return +ve new g_context
435 * NULL failure
436 */
437void *
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
479fail:
480 if (g_context)
481 coap_dtls_free_context(g_context);
482 return NULL;
483}
484
485void
486coap_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 */
524static int
525psk_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
603typedef 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 */
615static 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
689fail:
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)
704static int
705check_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;
734fail:
735 return 0;
736}
737#endif /* >= 3.6.6 */
738
739/*
740 * return 0 failed
741 * 1 passed
742 */
743static 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
906ok:
907 if (cert_info.san_or_cn)
908 gnutls_free(cert_info.san_or_cn);
909
910 return 1;
911
912fail:
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 }
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 */
931static 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
945static int
946pin_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 */
966static 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
977static 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
982static gnutls_datum_t *
983get_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 */
1022static int
1023setup_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) {
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
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 */
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) {
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 */
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) {
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
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 */
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) {
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:
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
1424fail:
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 */
1433static int
1434setup_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
1454fail:
1455 return ret;
1456}
1457
1458/*
1459 * return 0 Success (GNUTLS_E_SUCCESS)
1460 * neg GNUTLS_E_* error code
1461 */
1462static int
1463post_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);
1562 &g_context->psk_sni_entry_list[i].psk_info.key);
1563 }
1564
1565end:
1566 free(name);
1567 return ret;
1568
1569fail:
1570 return ret;
1571}
1572
1573/*
1574 * return 0 Success (GNUTLS_E_SUCCESS)
1575 * neg GNUTLS_E_* error code
1576 */
1577static int
1578post_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
1676end:
1677 free(name);
1678 return ret;
1679
1680fail:
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 */
1690static int
1691setup_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
1774fail:
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 */
1787static int
1788psk_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 */
1842static int
1843setup_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
1893fail:
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 */
1903static ssize_t
1904coap_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 */
1948static ssize_t
1949coap_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 */
1971static int
1972receive_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
2004static coap_gnutls_env_t *
2005coap_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
2061fail:
2062 if (g_env)
2063 gnutls_free(g_env);
2064 return NULL;
2065}
2066
2067static void
2068coap_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
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
2118static 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 */
2137static int
2138do_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:
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;
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;
2199 ret = -1;
2200 break;
2201 case GNUTLS_E_CERTIFICATE_ERROR:
2202 if (g_env->sent_alert) {
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 }
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:
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
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
2260void 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");
2279fail:
2280 ;;
2281}
2282
2283/*
2284 * return +ve data amount
2285 * 0 no more
2286 * -1 error
2287 */
2288int 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);
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
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 */
2382int
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 */
2406int
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) {
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);
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 */
2506int
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
2584unsigned 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 */
2594static ssize_t
2595coap_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",
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 */
2630static ssize_t
2631coap_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
2670void *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
2709fail:
2710 if (g_env)
2711 gnutls_free(g_env);
2712 return NULL;
2713}
2714#endif /* COAP_CLIENT_SUPPORT */
2715
2716#if COAP_SERVER_SUPPORT
2717void *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
2754fail:
2755 return NULL;
2756}
2757#endif /* COAP_SERVER_SUPPORT */
2758
2759void 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 */
2769ssize_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:
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);
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 */
2844ssize_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:
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);
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
2916coap_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
2925void
2927 gnutls_hash_deinit(digest_ctx, NULL);
2928}
2929
2930int
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
2939int
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
2957static 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.
const char * coap_socket_strerror(void)
Definition: coap_io.c:1604
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:483
#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
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
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
void * coap_dtls_get_tls(const coap_session_t *c_session COAP_UNUSED, coap_tls_library_t *tls_lib)
Definition: coap_notls.c:86
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_new_context(coap_context_t *coap_context COAP_UNUSED)
Definition: coap_notls.c:107
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.
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
coap_digest_ctx_t * coap_digest_setup(void)
Initialize a coap_digest.
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
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition: coap_notls.c:82
void * coap_dtls_new_client_session(coap_session_t *coap_session)
Create a new client-side session.
void * coap_tls_new_client_session(coap_session_t *coap_session, int *connected)
Create a new TLS client-side session.
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.
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
const coap_bin_const_t * coap_get_session_client_psk_key(const coap_session_t *coap_session)
Get the current client's PSK key.
#define COAP_DTLS_RETRANSMIT_COAP_TICKS
const coap_bin_const_t * coap_get_session_server_psk_key(const coap_session_t *coap_session)
Get the current server's PSK key.
#define COAP_DTLS_HINT_LENGTH
Definition: coap_dtls.h:34
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
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
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
#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
const char * coap_session_str(const coap_session_t *session)
Get session description.
#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
const uint32_t n
Definition: murmur3.c:56
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