libcoap 4.3.5a
Loading...
Searching...
No Matches
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-2025 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
17
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
52
53#ifdef COAP_WITH_LIBGNUTLS
54
55#define MIN_GNUTLS_VERSION "3.3.0"
56
57#include <stdio.h>
58#include <gnutls/gnutls.h>
59#include <gnutls/x509.h>
60#include <gnutls/dtls.h>
61#include <gnutls/pkcs11.h>
62#include <gnutls/crypto.h>
63#include <gnutls/abstract.h>
64#include <unistd.h>
65#if (GNUTLS_VERSION_NUMBER >= 0x030606)
66#define COAP_GNUTLS_KEY_RPK GNUTLS_KEY_DIGITAL_SIGNATURE | \
67 GNUTLS_KEY_NON_REPUDIATION | \
68 GNUTLS_KEY_KEY_ENCIPHERMENT | \
69 GNUTLS_KEY_DATA_ENCIPHERMENT | \
70 GNUTLS_KEY_KEY_AGREEMENT | \
71 GNUTLS_KEY_KEY_CERT_SIGN
72#endif /* GNUTLS_VERSION_NUMBER >= 0x030606 */
73
74#ifndef GNUTLS_CRT_RAW
75#define GNUTLS_CRT_RAW GNUTLS_CRT_RAWPK
76#endif /* GNUTLS_CRT_RAW */
77
78#ifdef _WIN32
79#define strcasecmp _stricmp
80#endif
81
82typedef struct coap_ssl_t {
83 const uint8_t *pdu;
84 unsigned pdu_len;
85 unsigned peekmode;
86 gnutls_datum_t cookie_key;
87} coap_ssl_t;
88
89/*
90 * This structure encapsulates the GnuTLS session object.
91 * It handles both TLS and DTLS.
92 * c_session->tls points to this.
93 */
94typedef struct coap_gnutls_env_t {
95 gnutls_session_t g_session;
96 gnutls_psk_client_credentials_t psk_cl_credentials;
97 gnutls_psk_server_credentials_t psk_sv_credentials;
98 gnutls_certificate_credentials_t pki_credentials;
99 coap_ssl_t coap_ssl_data;
100 /* If not set, need to do gnutls_handshake */
101 int established;
102 int doing_dtls_timeout;
103 coap_tick_t last_timeout;
104 int sent_alert;
105} coap_gnutls_env_t;
106
107#define IS_PSK (1 << 0)
108#define IS_PKI (1 << 1)
109#define IS_CLIENT (1 << 6)
110#define IS_SERVER (1 << 7)
111
112typedef struct pki_sni_entry {
113 char *sni;
114 coap_dtls_key_t pki_key;
115 gnutls_certificate_credentials_t pki_credentials;
116} pki_sni_entry;
117
118typedef struct psk_sni_entry {
119 char *sni;
120 coap_dtls_spsk_info_t psk_info;
121 gnutls_psk_server_credentials_t psk_credentials;
122} psk_sni_entry;
123
124typedef struct coap_gnutls_context_t {
125 coap_dtls_pki_t setup_data;
126 int psk_pki_enabled;
127 size_t pki_sni_count;
128 pki_sni_entry *pki_sni_entry_list;
129 size_t psk_sni_count;
130 psk_sni_entry *psk_sni_entry_list;
131 gnutls_datum_t alpn_proto; /* Will be "coap", but that is a const */
132 char *root_ca_file;
133 char *root_ca_path;
134 gnutls_priority_t priority_cache;
135} coap_gnutls_context_t;
136
137typedef enum coap_free_bye_t {
138 COAP_FREE_BYE_AS_TCP,
139 COAP_FREE_BYE_AS_UDP,
140 COAP_FREE_BYE_NONE
141} coap_free_bye_t;
142
143#define VARIANTS_3_6_6 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8:+CTYPE-CLI-ALL:+CTYPE-SRV-ALL:+SHA256"
144#define VARIANTS_3_5_5 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8"
145#define VARIANTS_BASE "NORMAL:+ECDHE-PSK:+PSK"
146
147#define VARIANTS_NO_TLS13_3_6_6 VARIANTS_3_6_6 ":-VERS-TLS1.3"
148#define VARIANTS_NO_TLS13_3_6_4 VARIANTS_3_5_5 ":-VERS-TLS1.3"
149
150#define G_ACTION(xx) do { \
151 ret = (xx); \
152 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
153
154#define G_CHECK(xx,func) do { \
155 if ((ret = (xx)) < 0) { \
156 coap_log_warn("%s: '%s'\n", func, gnutls_strerror(ret)); \
157 goto fail; \
158 } \
159 } while (0)
160
161#define G_ACTION_CHECK(xx,func) do { \
162 G_ACTION(xx); \
163 G_CHECK(xx, func); \
164 } while 0
165
167
168#if COAP_SERVER_SUPPORT
169static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
170static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
171static int psk_server_callback(gnutls_session_t g_session,
172 const char *identity,
173 gnutls_datum_t *key);
174#endif /* COAP_SERVER_SUPPORT */
175
176/*
177 * return 0 failed
178 * 1 passed
179 */
180int
182 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
183 coap_log_err("GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
184 return 0;
185 }
186 return 1;
187}
188
189/*
190 * return 0 failed
191 * 1 passed
192 */
193int
195#if !COAP_DISABLE_TCP
196 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
197 coap_log_err("GnuTLS " MIN_GNUTLS_VERSION " or later is required\n");
198 return 0;
199 }
200 return 1;
201#else /* COAP_DISABLE_TCP */
202 return 0;
203#endif /* COAP_DISABLE_TCP */
204}
205
206/*
207 * return 0 failed
208 * 1 passed
209 */
210int
212 return 1;
213}
214
215/*
216 * return 0 failed
217 * 1 passed
218 */
219int
221 return 1;
222}
223
224/*
225 * return 0 failed
226 * 1 passed
227 */
228int
230 return 1;
231}
232
233/*
234 * return 0 failed
235 * 1 passed
236 */
237int
239#if (GNUTLS_VERSION_NUMBER >= 0x030606)
240 return 1;
241#else /* GNUTLS_VERSION_NUMBER < 0x030606 */
242 return 0;
243#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
244}
245
246/*
247 * return 0 failed
248 * 1 passed
249 */
250int
252 return 0;
253}
254
255#if COAP_CLIENT_SUPPORT
256int
257coap_dtls_set_cid_tuple_change(coap_context_t *c_context, uint8_t every) {
258 (void)c_context;
259 (void)every;
260 return 0;
261}
262#endif /* COAP_CLIENT_SUPPORT */
263
266 static coap_tls_version_t version;
267 const char *vers = gnutls_check_version(NULL);
268
269 version.version = 0;
270 if (vers) {
271 int p1, p2, p3;
272
273 sscanf(vers, "%d.%d.%d", &p1, &p2, &p3);
274 version.version = (p1 << 16) | (p2 << 8) | p3;
275 }
276 version.built_version = GNUTLS_VERSION_NUMBER;
278 return &version;
279}
280
281static void
282coap_gnutls_audit_log_func(gnutls_session_t g_session, const char *text) {
283#if COAP_MAX_LOGGING_LEVEL > 0
284 if (g_session) {
285 coap_session_t *c_session =
286 (coap_session_t *)gnutls_transport_get_ptr(g_session);
287 coap_log_warn("** %s: %s",
288 coap_session_str(c_session), text);
289 } else {
290 coap_log_warn("** (null): %s", text);
291 }
292#else /* COAP_MAX_LOGGING_LEVEL == 0 */
293 (void)g_session;
294 (void)text;
295#endif /* COAP_MAX_LOGGING_LEVEL == 0 */
296}
297
298static void
299coap_gnutls_log_func(int level, const char *text) {
300 /* Things get noisy, even at level 1 */
301 if (level > 0)
302 level += COAP_LOG_WARN;
303 if (level > COAP_LOG_DEBUG)
304 level = COAP_LOG_DEBUG;
305 coap_dtls_log(level, "%s", text);
306}
307
308/*
309 * return 0 failed
310 * 1 passed
311 */
312int
314 const coap_dtls_pki_t *setup_data,
315 const coap_dtls_role_t role COAP_UNUSED) {
316 coap_dtls_key_t key;
317 coap_gnutls_context_t *g_context =
318 ((coap_gnutls_context_t *)c_context->dtls_context);
319
320 if (!g_context || !setup_data)
321 return 0;
322
323 g_context->setup_data = *setup_data;
324 if (!g_context->setup_data.verify_peer_cert) {
325 /* Needs to be clear so that no CA DNs are transmitted */
326 g_context->setup_data.check_common_ca = 0;
327 if (g_context->setup_data.is_rpk_not_cert) {
328 /* Disable all of these as they cannot be checked */
329 g_context->setup_data.allow_self_signed = 0;
330 g_context->setup_data.allow_expired_certs = 0;
331 g_context->setup_data.cert_chain_validation = 0;
332 g_context->setup_data.cert_chain_verify_depth = 0;
333 g_context->setup_data.check_cert_revocation = 0;
334 g_context->setup_data.allow_no_crl = 0;
335 g_context->setup_data.allow_expired_crl = 0;
336 g_context->setup_data.allow_bad_md_hash = 0;
337 g_context->setup_data.allow_short_rsa_length = 0;
338 } else {
339 /* Allow all of these but warn if issue */
340 g_context->setup_data.allow_self_signed = 1;
341 g_context->setup_data.allow_expired_certs = 1;
342 g_context->setup_data.cert_chain_validation = 1;
343 g_context->setup_data.cert_chain_verify_depth = 10;
344 g_context->setup_data.check_cert_revocation = 1;
345 g_context->setup_data.allow_no_crl = 1;
346 g_context->setup_data.allow_expired_crl = 1;
347 g_context->setup_data.allow_bad_md_hash = 1;
348 g_context->setup_data.allow_short_rsa_length = 1;
349 }
350 }
351 /* Map over to the new define format to save code duplication */
352 coap_dtls_map_key_type_to_define(&g_context->setup_data, &key);
353 g_context->setup_data.pki_key = key;
354 g_context->psk_pki_enabled |= IS_PKI;
355 if (setup_data->use_cid) {
356 coap_log_warn("GnuTLS has no Connection-ID support\n");
357 }
358 return 1;
359}
360
361/*
362 * return 0 failed
363 * 1 passed
364 */
365int
367 const char *ca_file,
368 const char *ca_path) {
369 coap_gnutls_context_t *g_context =
370 ((coap_gnutls_context_t *)c_context->dtls_context);
371 if (!g_context) {
372 coap_log_warn("coap_context_set_pki_root_cas: (D)TLS environment "
373 "not set up\n");
374 return 0;
375 }
376
377 if (ca_file == NULL && ca_path == NULL) {
378 coap_log_warn("coap_context_set_pki_root_cas: ca_file and/or ca_path "
379 "not defined\n");
380 return 0;
381 }
382 if (g_context->root_ca_file) {
383 gnutls_free(g_context->root_ca_file);
384 g_context->root_ca_file = NULL;
385 }
386 if (ca_file) {
387 g_context->root_ca_file = gnutls_strdup(ca_file);
388 }
389 if (g_context->root_ca_path) {
390 gnutls_free(g_context->root_ca_path);
391 g_context->root_ca_path = NULL;
392 }
393 if (ca_path) {
394#if (GNUTLS_VERSION_NUMBER >= 0x030306)
395 g_context->root_ca_path = gnutls_strdup(ca_path);
396#else
397 coap_log_err("ca_path not supported in GnuTLS < 3.3.6\n");
398#endif
399 }
400 return 1;
401}
402
403#if COAP_SERVER_SUPPORT
404/*
405 * return 0 failed
406 * 1 passed
407 */
408int
410 coap_dtls_spsk_t *setup_data
411 ) {
412 coap_gnutls_context_t *g_context =
413 ((coap_gnutls_context_t *)c_context->dtls_context);
414
415 if (!g_context || !setup_data)
416 return 0;
417
418 if (setup_data->ec_jpake) {
419 coap_log_warn("GnuTLS has no EC-JPAKE support\n");
420 }
421 g_context->psk_pki_enabled |= IS_PSK;
422 return 1;
423}
424#endif /* COAP_SERVER_SUPPORT */
425
426#if COAP_CLIENT_SUPPORT
427/*
428 * return 0 failed
429 * 1 passed
430 */
431int
433 coap_dtls_cpsk_t *setup_data
434 ) {
435 coap_gnutls_context_t *g_context =
436 ((coap_gnutls_context_t *)c_context->dtls_context);
437
438 if (!g_context || !setup_data)
439 return 0;
440
441 if (setup_data->ec_jpake) {
442 coap_log_warn("GnuTLS has no EC-JPAKE support\n");
443 }
444 if (setup_data->use_cid) {
445 coap_log_warn("GnuTLS has no Connection-ID support\n");
446 }
447 g_context->psk_pki_enabled |= IS_PSK;
448 return 1;
449}
450#endif /* COAP_CLIENT_SUPPORT */
451
452/*
453 * return 0 failed
454 * 1 passed
455 */
456int
458 coap_gnutls_context_t *g_context =
459 ((coap_gnutls_context_t *)c_context->dtls_context);
460 return g_context->psk_pki_enabled ? 1 : 0;
461}
462
463void
464coap_dtls_startup(void) {
465 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
466 gnutls_global_set_log_function(coap_gnutls_log_func);
467}
468
469void
470coap_dtls_shutdown(void) {
472}
473
474void *
475coap_dtls_get_tls(const coap_session_t *c_session,
476 coap_tls_library_t *tls_lib) {
477 if (tls_lib)
478 *tls_lib = COAP_TLS_LIBRARY_GNUTLS;
479 if (c_session && c_session->tls) {
480 const coap_gnutls_env_t *g_env = (const coap_gnutls_env_t *)c_session->tls;
481
482 return g_env->g_session;
483 }
484 return NULL;
485}
486
487void
489 dtls_log_level = level;
490 gnutls_global_set_log_level(dtls_log_level);
491}
492
493/*
494 * return current logging level
495 */
498 return dtls_log_level;
499}
500
501/*
502 * return +ve new g_context
503 * NULL failure
504 */
505void *
507 const char *err = "Unknown Error";
508 int ret;
509 coap_gnutls_context_t *g_context =
510 (coap_gnutls_context_t *)
511 gnutls_malloc(sizeof(coap_gnutls_context_t));
512
513 if (g_context) {
515 const char *priority;
516
517 memset(g_context, 0, sizeof(coap_gnutls_context_t));
518 G_CHECK(gnutls_global_init(), "gnutls_global_init");
519 g_context->alpn_proto.data = gnutls_malloc(4);
520 if (g_context->alpn_proto.data) {
521 memcpy(g_context->alpn_proto.data, "coap", 4);
522 g_context->alpn_proto.size = 4;
523 }
524
525 if (tls_version->version >= 0x030606) {
526 priority = VARIANTS_3_6_6;
527 } else if (tls_version->version >= 0x030505) {
528 priority = VARIANTS_3_5_5;
529 } else {
530 priority = VARIANTS_BASE;
531 }
532 ret = gnutls_priority_init(&g_context->priority_cache, priority, &err);
533 if (ret != GNUTLS_E_SUCCESS) {
534 if (ret == GNUTLS_E_INVALID_REQUEST)
535 coap_log_warn("gnutls_priority_init: Syntax error at: %s\n", err);
536 else
537 coap_log_warn("gnutls_priority_init: %s\n", gnutls_strerror(ret));
538 goto fail;
539 }
540 }
541 return g_context;
542
543fail:
544 if (g_context)
545 coap_dtls_free_context(g_context);
546 return NULL;
547}
548
549void
550coap_dtls_free_context(void *handle) {
551 size_t i;
552 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
553
554 gnutls_free(g_context->alpn_proto.data);
555 gnutls_free(g_context->root_ca_file);
556 gnutls_free(g_context->root_ca_path);
557 for (i = 0; i < g_context->pki_sni_count; i++) {
558 gnutls_free(g_context->pki_sni_entry_list[i].sni);
559 gnutls_certificate_free_credentials(
560 g_context->pki_sni_entry_list[i].pki_credentials);
561 }
562 if (g_context->pki_sni_entry_list)
563 gnutls_free(g_context->pki_sni_entry_list);
564
565 for (i = 0; i < g_context->psk_sni_count; i++) {
566 gnutls_free(g_context->psk_sni_entry_list[i].sni);
567 /* YUK - A memory leak in 3.3.0 (fixed by 3.3.26) of hint */
568 gnutls_psk_free_server_credentials(
569 g_context->psk_sni_entry_list[i].psk_credentials);
570 }
571 if (g_context->psk_sni_entry_list)
572 gnutls_free(g_context->psk_sni_entry_list);
573
574 gnutls_priority_deinit(g_context->priority_cache);
575
576 gnutls_global_deinit();
577 gnutls_free(g_context);
578}
579
580#if COAP_CLIENT_SUPPORT
581/*
582 * gnutls_psk_client_credentials_function return values
583 * (see gnutls_psk_set_client_credentials_function())
584 *
585 * return -1 failed
586 * 0 passed
587 */
588static int
589psk_client_callback(gnutls_session_t g_session,
590 char **username, gnutls_datum_t *key) {
591 coap_session_t *c_session =
592 (coap_session_t *)gnutls_transport_get_ptr(g_session);
593 coap_gnutls_context_t *g_context;
594 coap_dtls_cpsk_t *setup_data;
595 const char *hint = gnutls_psk_client_get_hint(g_session);
596 coap_bin_const_t temp;
597 const coap_bin_const_t *psk_key;
598 const coap_bin_const_t *psk_identity;
599 const coap_dtls_cpsk_info_t *cpsk_info;
600
601 /* Initialize result parameters. */
602 *username = NULL;
603 key->data = NULL;
604
605 if (c_session == NULL)
606 return -1;
607
608 g_context = (coap_gnutls_context_t *)c_session->context->dtls_context;
609 if (g_context == NULL)
610 return -1;
611
612 setup_data = &c_session->cpsk_setup_data;
613
614 temp.s = hint ? (const uint8_t *)hint : (const uint8_t *)"";
615 temp.length = strlen((const char *)temp.s);
616 coap_session_refresh_psk_hint(c_session, &temp);
617
618 coap_log_debug("got psk_identity_hint: '%.*s'\n", (int)temp.length,
619 (const char *)temp.s);
620
621 if (setup_data->validate_ih_call_back) {
622 coap_str_const_t lhint;
623
624 lhint.length = temp.length;
625 lhint.s = temp.s;
626 coap_lock_callback_ret(cpsk_info, c_session->context,
627 setup_data->validate_ih_call_back(&lhint,
628 c_session,
629 setup_data->ih_call_back_arg));
630
631 if (cpsk_info == NULL)
632 return -1;
633
634 coap_session_refresh_psk_identity(c_session, &cpsk_info->identity);
635 coap_session_refresh_psk_key(c_session, &cpsk_info->key);
636 psk_identity = &cpsk_info->identity;
637 psk_key = &cpsk_info->key;
638 } else {
639 psk_identity = coap_get_session_client_psk_identity(c_session);
640 psk_key = coap_get_session_client_psk_key(c_session);
641 }
642
643 if (psk_identity == NULL || psk_key == NULL) {
644 coap_log_warn("no PSK available\n");
645 return -1;
646 }
647
648 *username = gnutls_malloc(psk_identity->length+1);
649 if (*username == NULL)
650 return -1;
651 memcpy(*username, psk_identity->s, psk_identity->length);
652 (*username)[psk_identity->length] = '\000';
653
654 key->data = gnutls_malloc(psk_key->length);
655 if (key->data == NULL) {
656 gnutls_free(*username);
657 *username = NULL;
658 return -1;
659 }
660 memcpy(key->data, psk_key->s, psk_key->length);
661 key->size = psk_key->length;
662 return 0;
663}
664#endif /* COAP_CLIENT_SUPPORT */
665
666typedef struct {
667 gnutls_certificate_type_t certificate_type;
668 char *san_or_cn;
669 const gnutls_datum_t *cert_list;
670 unsigned int cert_list_size;
671 int self_signed; /* 1 if cert self-signed, 0 otherwise */
672} coap_gnutls_certificate_info_t;
673
674/*
675 * return Type of certificate and SAN or CN if appropriate derived from
676 * certificate. GNUTLS_CRT_UNKNOWN if failure.
677 */
678static gnutls_certificate_type_t
679get_san_or_cn(gnutls_session_t g_session,
680 coap_gnutls_certificate_info_t *cert_info) {
681 gnutls_x509_crt_t cert;
682 char dn[256];
683 size_t size;
684 int n;
685 char *cn;
686 int ret;
687
688#if (GNUTLS_VERSION_NUMBER >= 0x030606)
689 cert_info->certificate_type = gnutls_certificate_type_get2(g_session,
690 GNUTLS_CTYPE_PEERS);
691#else /* < 3.6.6 */
692 cert_info->certificate_type = gnutls_certificate_type_get(g_session);
693#endif /* < 3.6.6 */
694
695 cert_info->san_or_cn = NULL;
696
697 cert_info->cert_list = gnutls_certificate_get_peers(g_session,
698 &cert_info->cert_list_size);
699 if (cert_info->cert_list_size == 0) {
700 return GNUTLS_CRT_UNKNOWN;
701 }
702
703 if (cert_info->certificate_type != GNUTLS_CRT_X509)
704 return cert_info->certificate_type;
705
706 G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
707
708 /* Interested only in first cert in chain */
709 G_CHECK(gnutls_x509_crt_import(cert, &cert_info->cert_list[0],
710 GNUTLS_X509_FMT_DER), "gnutls_x509_crt_import");
711
712 cert_info->self_signed = gnutls_x509_crt_check_issuer(cert, cert);
713
714 size = sizeof(dn) -1;
715 /* See if there is a Subject Alt Name first */
716 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
717 if (ret >= 0) {
718 dn[size] = '\000';
719 gnutls_x509_crt_deinit(cert);
720 cert_info->san_or_cn = gnutls_strdup(dn);
721 return cert_info->certificate_type;
722 }
723
724 size = sizeof(dn);
725 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size), "gnutls_x509_crt_get_dn");
726
727 gnutls_x509_crt_deinit(cert);
728
729 /* Need to emulate strcasestr() here. Looking for CN= */
730 n = strlen(dn) - 3;
731 cn = dn;
732 while (n > 0) {
733 if (((cn[0] == 'C') || (cn[0] == 'c')) &&
734 ((cn[1] == 'N') || (cn[1] == 'n')) &&
735 (cn[2] == '=')) {
736 cn += 3;
737 break;
738 }
739 cn++;
740 n--;
741 }
742 if (n > 0) {
743 char *ecn = strchr(cn, ',');
744 if (ecn) {
745 cn[ecn-cn] = '\000';
746 }
747 cert_info->san_or_cn = gnutls_strdup(cn);
748 return cert_info->certificate_type;
749 }
750 return GNUTLS_CRT_UNKNOWN;
751
752fail:
753 return GNUTLS_CRT_UNKNOWN;
754}
755
756#if (GNUTLS_VERSION_NUMBER >= 0x030606)
757#define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
758 cert_info.san_or_cn : \
759 cert_type == GNUTLS_CRT_RAW ? \
760 COAP_DTLS_RPK_CERT_CN : "?")
761#else /* GNUTLS_VERSION_NUMBER < 0x030606 */
762#define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
763 cert_info.san_or_cn : "?")
764#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
765
766#if (GNUTLS_VERSION_NUMBER >= 0x030606)
767static int
768check_rpk_cert(coap_gnutls_context_t *g_context,
769 coap_gnutls_certificate_info_t *cert_info,
770 coap_session_t *c_session) {
771 int ret;
772
773 if (g_context->setup_data.validate_cn_call_back) {
774 gnutls_pcert_st pcert;
775 uint8_t der[2048];
776 size_t size;
777
778 G_CHECK(gnutls_pcert_import_rawpk_raw(&pcert, &cert_info->cert_list[0],
779 GNUTLS_X509_FMT_DER, 0, 0),
780 "gnutls_pcert_import_rawpk_raw");
781
782 size = sizeof(der);
783 G_CHECK(gnutls_pubkey_export(pcert.pubkey, GNUTLS_X509_FMT_DER, der, &size),
784 "gnutls_pubkey_export");
785 gnutls_pcert_deinit(&pcert);
786 coap_lock_callback_ret(ret, c_session->context,
787 g_context->setup_data.validate_cn_call_back(COAP_DTLS_RPK_CERT_CN,
788 der,
789 size,
790 c_session,
791 0,
792 1,
793 g_context->setup_data.cn_call_back_arg));
794 if (!ret) {
795 return 0;
796 }
797 }
798 return 1;
799fail:
800 return 0;
801}
802#endif /* >= 3.6.6 */
803
804/*
805 * return 0 failed
806 * 1 passed
807 */
808static int
809cert_verify_gnutls(gnutls_session_t g_session) {
810 unsigned int status = 0;
811 unsigned int fail = 0;
812 coap_session_t *c_session =
813 (coap_session_t *)gnutls_transport_get_ptr(g_session);
814 coap_gnutls_context_t *g_context =
815 (coap_gnutls_context_t *)c_session->context->dtls_context;
816 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
817 int alert = GNUTLS_A_BAD_CERTIFICATE;
818 int ret;
819 coap_gnutls_certificate_info_t cert_info;
820 gnutls_certificate_type_t cert_type;
821
822 memset(&cert_info, 0, sizeof(cert_info));
823 cert_type = get_san_or_cn(g_session, &cert_info);
824#if (GNUTLS_VERSION_NUMBER >= 0x030606)
825 if (cert_type == GNUTLS_CRT_RAW) {
826 if (!check_rpk_cert(g_context, &cert_info, c_session)) {
827 alert = GNUTLS_A_ACCESS_DENIED;
828 goto fail;
829 }
830 goto ok;
831 }
832#endif /* >= 3.6.6 */
833
834 if (cert_info.cert_list_size == 0) {
835 if (!g_context->setup_data.verify_peer_cert)
836 goto ok;
837 else
838 goto fail;
839 }
840
841 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
842 "gnutls_certificate_verify_peers");
843
844 if (status) {
845 status &= ~(GNUTLS_CERT_INVALID);
846 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
847 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
848 if (g_context->setup_data.allow_expired_certs) {
849 coap_log_info(" %s: %s: overridden: '%s'\n",
850 coap_session_str(c_session),
851 "The certificate has an invalid usage date",
852 OUTPUT_CERT_NAME);
853 } else {
854 fail = 1;
855 coap_log_warn(" %s: %s: '%s'\n",
856 coap_session_str(c_session),
857 "The certificate has an invalid usage date",
858 OUTPUT_CERT_NAME);
859 }
860 }
861 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
862 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
863 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
864 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
865 if (g_context->setup_data.allow_expired_crl) {
866 coap_log_info(" %s: %s: overridden: '%s'\n",
867 coap_session_str(c_session),
868 "The certificate's CRL entry has an invalid usage date",
869 OUTPUT_CERT_NAME);
870 } else {
871 fail = 1;
872 coap_log_warn(" %s: %s: '%s'\n",
873 coap_session_str(c_session),
874 "The certificate's CRL entry has an invalid usage date",
875 OUTPUT_CERT_NAME);
876 }
877 }
878 if (status & (GNUTLS_CERT_SIGNER_NOT_FOUND)) {
879 status &= ~(GNUTLS_CERT_SIGNER_NOT_FOUND);
880 if (cert_info.self_signed) {
881 if (g_context->setup_data.allow_self_signed &&
882 !g_context->setup_data.check_common_ca) {
883 coap_log_info(" %s: %s: overridden: '%s'\n",
884 coap_session_str(c_session),
885 "Self-signed",
886 OUTPUT_CERT_NAME);
887 } else {
888 fail = 1;
889 alert = GNUTLS_A_UNKNOWN_CA;
890 coap_log_warn(" %s: %s: '%s'\n",
891 coap_session_str(c_session),
892 "Self-signed",
893 OUTPUT_CERT_NAME);
894 }
895 } else {
896 if (!g_context->setup_data.verify_peer_cert) {
897 coap_log_info(" %s: %s: overridden: '%s'\n",
898 coap_session_str(c_session),
899 "The peer certificate's CA is unknown",
900 OUTPUT_CERT_NAME);
901 } else {
902 fail = 1;
903 alert = GNUTLS_A_UNKNOWN_CA;
904 coap_log_warn(" %s: %s: '%s'\n",
905 coap_session_str(c_session),
906 "The peer certificate's CA is unknown",
907 OUTPUT_CERT_NAME);
908 }
909 }
910 }
911 if (status & (GNUTLS_CERT_INSECURE_ALGORITHM)) {
912 status &= ~(GNUTLS_CERT_INSECURE_ALGORITHM);
913 fail = 1;
914 coap_log_warn(" %s: %s: '%s'\n",
915 coap_session_str(c_session),
916 "The certificate uses an insecure algorithm",
917 OUTPUT_CERT_NAME);
918 }
919
920 if (status) {
921 fail = 1;
922 coap_log_warn(" %s: gnutls_certificate_verify_peers() status 0x%x: '%s'\n",
923 coap_session_str(c_session),
924 status, OUTPUT_CERT_NAME);
925 }
926 }
927
928 if (fail)
929 goto fail;
930
931 if (g_context->setup_data.validate_cn_call_back) {
932 gnutls_x509_crt_t cert;
933 uint8_t der[2048];
934 size_t size;
935 /* status == 0 indicates that the certificate passed to
936 * setup_data.validate_cn_call_back has been validated. */
937 const int cert_is_trusted = !status;
938
939 G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
940
941 /* Interested only in first cert in chain */
942 G_CHECK(gnutls_x509_crt_import(cert, &cert_info.cert_list[0],
943 GNUTLS_X509_FMT_DER), "gnutls_x509_crt_import");
944
945 size = sizeof(der);
946 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
947 "gnutls_x509_crt_export");
948 gnutls_x509_crt_deinit(cert);
949 coap_lock_callback_ret(ret, c_session->context,
950 g_context->setup_data.validate_cn_call_back(OUTPUT_CERT_NAME,
951 der,
952 size,
953 c_session,
954 0,
955 cert_is_trusted,
956 g_context->setup_data.cn_call_back_arg));
957 if (!ret) {
958 alert = GNUTLS_A_ACCESS_DENIED;
959 goto fail;
960 }
961 }
962
963 if (g_context->setup_data.additional_tls_setup_call_back) {
964 /* Additional application setup wanted */
965 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
966 &g_context->setup_data)) {
967 goto fail;
968 }
969 }
970
971ok:
972 if (cert_info.san_or_cn)
973 gnutls_free(cert_info.san_or_cn);
974
975 return 1;
976
977fail:
978 if (cert_info.san_or_cn)
979 gnutls_free(cert_info.san_or_cn);
980
981 if (!g_env->sent_alert) {
982 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
983 g_env->sent_alert = 1;
984 }
986 return 0;
987}
988
989/*
990 * gnutls_certificate_verify_function return values
991 * (see gnutls_certificate_set_verify_function())
992 *
993 * return -1 failed
994 * 0 passed
995 */
996static int
997cert_verify_callback_gnutls(gnutls_session_t g_session) {
998 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
999 if (cert_verify_gnutls(g_session) == 0) {
1000 return -1;
1001 }
1002 }
1003 return 0;
1004}
1005
1006#ifndef min
1007#define min(a,b) ((a) < (b) ? (a) : (b))
1008#endif
1009
1010static int
1011pin_callback(void *user_data, int attempt,
1012 const char *token_url COAP_UNUSED,
1013 const char *token_label COAP_UNUSED,
1014 unsigned int flags COAP_UNUSED,
1015 char *pin,
1016 size_t pin_max) {
1017 coap_dtls_key_t *key = (coap_dtls_key_t *)user_data;
1018
1019 /* Only do this on first attempt to prevent token lockout */
1020 if (attempt == 0 && key && key->key.define.user_pin) {
1021 int len = min(pin_max - 1, strlen(key->key.define.user_pin));
1022
1023 memcpy(pin, key->key.define.user_pin, len);
1024 pin[len] = 0;
1025 return 0;
1026 }
1027 return -1;
1028}
1029
1030static int
1031check_null_memory(gnutls_datum_t *datum,
1032 const uint8_t *buf, size_t len, int *alloced) {
1033 datum->size = len;
1034 *alloced = 0;
1035 if (buf[len-1] != '\000') {
1036 /* Need to allocate memory, rather than just copying pointers across */
1037 *alloced = 1;
1038 datum->data = gnutls_malloc(len + 1);
1039 if (!datum->data) {
1040 coap_log_err("gnutls_malloc failure\n");
1041 return GNUTLS_E_MEMORY_ERROR;
1042 }
1043 memcpy(datum->data, buf, len);
1044 datum->data[len] = '\000';
1045 datum->size++;
1046 } else {
1047 /* To get around const issue */
1048 memcpy(&datum->data,
1049 &buf, sizeof(datum->data));
1050 }
1051 return 0;
1052}
1053
1054/*
1055 * return 0 Success (GNUTLS_E_SUCCESS)
1056 * neg GNUTLS_E_* error code
1057 */
1058static int
1059setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
1060 gnutls_session_t g_session,
1061 coap_gnutls_context_t *g_context,
1062 coap_dtls_pki_t *setup_data, coap_dtls_role_t role) {
1063 coap_dtls_key_t key;
1064 int ret;
1065 gnutls_datum_t cert;
1066 gnutls_datum_t pkey;
1067 gnutls_datum_t ca;
1068 int alloced_cert_memory = 0;
1069 int alloced_pkey_memory = 0;
1070 int alloced_ca_memory = 0;
1071 int have_done_key = 0;
1072
1073 /* Map over to the new define format to save code duplication */
1074 coap_dtls_map_key_type_to_define(setup_data, &key);
1075
1076 assert(key.key_type == COAP_PKI_KEY_DEFINE);
1077
1078 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
1079 "gnutls_certificate_allocate_credentials");
1080
1081 /*
1082 * Configure the Private Key
1083 */
1084 if (key.key.define.private_key.u_byte &&
1085 key.key.define.private_key.u_byte[0]) {
1086 switch (key.key.define.private_key_def) {
1087 case COAP_PKI_KEY_DEF_PEM: /* define private key */
1088 case COAP_PKI_KEY_DEF_PEM_BUF: /* define private key */
1089 case COAP_PKI_KEY_DEF_DER: /* define private key */
1090 case COAP_PKI_KEY_DEF_DER_BUF: /* define private key */
1091 case COAP_PKI_KEY_DEF_PKCS11: /* define private key */
1092 case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define private key */
1093 /* Handled under public key */
1094 break;
1095 case COAP_PKI_KEY_DEF_RPK_BUF: /* define private key */
1096#if (GNUTLS_VERSION_NUMBER >= 0x030606)
1097 /* Handled under public key */
1098 break;
1099#else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1100 coap_log_err("RPK Support not available (needs gnutls 3.6.6 or later)\n");
1103 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1104#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1105 case COAP_PKI_KEY_DEF_ENGINE: /* define private key */
1106 default:
1109 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1110 }
1111 } else if (role == COAP_DTLS_ROLE_SERVER ||
1113 key.key.define.public_cert.u_byte[0])) {
1116 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1117 }
1118
1119 /*
1120 * Configure the Public Certificate / Key
1121 */
1122 if (key.key.define.public_cert.u_byte &&
1123 key.key.define.public_cert.u_byte[0]) {
1124 /* Both Public and Private keys are handled here and MUST be the same type */
1125 if (!(key.key.define.private_key.s_byte &&
1126 key.key.define.private_key.s_byte[0] &&
1130 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1131 }
1132 switch (key.key.define.public_cert_def) {
1133 case COAP_PKI_KEY_DEF_PEM: /* define public cert */
1134 if ((ret = gnutls_certificate_set_x509_key_file(*pki_credentials,
1137 GNUTLS_X509_FMT_PEM) < 0)) {
1140 &key, role, ret);
1141 }
1142 break;
1143 case COAP_PKI_KEY_DEF_PEM_BUF: /* define public cert */
1144 if ((ret = check_null_memory(&cert,
1147 &alloced_cert_memory)) < 0) {
1150 &key, role, ret);
1151 }
1152 if ((ret = check_null_memory(&pkey,
1155 &alloced_pkey_memory)) < 0) {
1156 if (alloced_cert_memory)
1157 gnutls_free(cert.data);
1160 &key, role, ret);
1161 }
1162 if ((ret = gnutls_certificate_set_x509_key_mem(*pki_credentials,
1163 &cert,
1164 &pkey,
1165 GNUTLS_X509_FMT_PEM)) < 0) {
1166 if (alloced_cert_memory)
1167 gnutls_free(cert.data);
1168 if (alloced_pkey_memory)
1169 gnutls_free(pkey.data);
1172 &key, role, ret);
1173 }
1174 if (alloced_cert_memory)
1175 gnutls_free(cert.data);
1176 if (alloced_pkey_memory)
1177 gnutls_free(pkey.data);
1178 break;
1179 case COAP_PKI_KEY_DEF_RPK_BUF: /* define public cert */
1180#if (GNUTLS_VERSION_NUMBER >= 0x030606)
1181 if ((ret = check_null_memory(&cert,
1184 &alloced_cert_memory)) < 0) {
1187 &key, role, ret);
1188 }
1189 if ((ret = check_null_memory(&pkey,
1192 &alloced_pkey_memory)) < 0) {
1193 if (alloced_cert_memory)
1194 gnutls_free(cert.data);
1197 &key, role, ret);
1198 }
1199 if (strstr((char *)pkey.data, "-----BEGIN EC PRIVATE KEY-----")) {
1200 gnutls_datum_t der_private;
1201
1202 if (gnutls_pem_base64_decode2("EC PRIVATE KEY", &pkey,
1203 &der_private) == 0) {
1204 coap_binary_t *spki = get_asn1_spki(der_private.data,
1205 der_private.size);
1206
1207 if (spki) {
1208 gnutls_datum_t tspki;
1209
1210 tspki.data = spki->s;
1211 tspki.size = spki->length;
1212 ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1213 &tspki,
1214 &der_private,
1215 GNUTLS_X509_FMT_DER, NULL,
1216 COAP_GNUTLS_KEY_RPK,
1217 NULL, 0, 0);
1218 if (ret >= 0) {
1219 have_done_key = 1;
1220 }
1221 coap_delete_binary(spki);
1222 }
1223 gnutls_free(der_private.data);
1224 }
1225 }
1226 if (!have_done_key) {
1227 if ((ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1228 &cert,
1229 &pkey,
1230 GNUTLS_X509_FMT_PEM, NULL,
1231 COAP_GNUTLS_KEY_RPK,
1232 NULL, 0, 0)) < 0) {
1233 if (alloced_cert_memory)
1234 gnutls_free(cert.data);
1235 if (alloced_pkey_memory)
1236 gnutls_free(pkey.data);
1239 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1240 }
1241 }
1242 if (alloced_cert_memory)
1243 gnutls_free(cert.data);
1244 if (alloced_pkey_memory)
1245 gnutls_free(pkey.data);
1246 break;
1247#else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1248 coap_log_err("RPK Support not available (needs gnutls 3.6.6 or later)\n");
1251 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1252#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1253 case COAP_PKI_KEY_DEF_DER: /* define public cert */
1254 if ((ret = gnutls_certificate_set_x509_key_file(*pki_credentials,
1257 GNUTLS_X509_FMT_DER) < 0)) {
1260 &key, role, ret);
1261 }
1262 break;
1263 case COAP_PKI_KEY_DEF_DER_BUF: /* define public cert */
1264 if ((ret = check_null_memory(&cert,
1267 &alloced_cert_memory)) < 0) {
1270 &key, role, ret);
1271 }
1272 if ((ret = check_null_memory(&pkey,
1275 &alloced_pkey_memory)) < 0) {
1276 if (alloced_cert_memory)
1277 gnutls_free(cert.data);
1280 &key, role, ret);
1281 }
1282 if ((ret = gnutls_certificate_set_x509_key_mem(*pki_credentials,
1283 &cert,
1284 &pkey,
1285 GNUTLS_X509_FMT_DER)) < 0) {
1286 if (alloced_cert_memory)
1287 gnutls_free(cert.data);
1288 if (alloced_pkey_memory)
1289 gnutls_free(pkey.data);
1292 &key, role, ret);
1293 }
1294 if (alloced_cert_memory)
1295 gnutls_free(cert.data);
1296 if (alloced_pkey_memory)
1297 gnutls_free(pkey.data);
1298 break;
1299 case COAP_PKI_KEY_DEF_PKCS11: /* define public cert */
1300 gnutls_pkcs11_set_pin_function(pin_callback, &setup_data->pki_key);
1301 if ((ret = gnutls_certificate_set_x509_key_file(*pki_credentials,
1304 GNUTLS_X509_FMT_DER)) < 0) {
1307 &key, role, ret);
1308 }
1309 break;
1310 case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define public cert */
1311#if (GNUTLS_VERSION_NUMBER >= 0x030606)
1312 gnutls_pkcs11_set_pin_function(pin_callback, setup_data);
1313 if ((ret = gnutls_certificate_set_rawpk_key_file(*pki_credentials,
1316 GNUTLS_X509_FMT_PEM, NULL,
1317 COAP_GNUTLS_KEY_RPK,
1318 NULL, 0, GNUTLS_PKCS_PLAIN, 0))) {
1321 &key, role, ret);
1322 }
1323#else /* GNUTLS_VERSION_NUMBER < 0x030606 */
1324 coap_log_err("RPK Support not available (needs gnutls 3.6.6 or later)\n");
1325 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1326#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
1327 break;
1328 case COAP_PKI_KEY_DEF_ENGINE: /* define public cert */
1329 default:
1332 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1333 }
1334 }
1335
1336 /*
1337 * Configure the CA
1338 */
1339 if (setup_data->check_common_ca && key.key.define.ca.u_byte &&
1340 key.key.define.ca.u_byte[0]) {
1341 switch (key.key.define.ca_def) {
1343 if ((ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1344 key.key.define.ca.s_byte,
1345 GNUTLS_X509_FMT_PEM) < 0)) {
1348 &key, role, ret);
1349 }
1350 break;
1351 case COAP_PKI_KEY_DEF_PEM_BUF: /* define ca */
1352 if ((ret = check_null_memory(&ca,
1353 key.key.define.ca.u_byte,
1354 key.key.define.ca_len,
1355 &alloced_ca_memory)) < 0) {
1358 &key, role, ret);
1359 }
1360 if ((ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1361 &ca,
1362 GNUTLS_X509_FMT_PEM)) < 0) {
1363 if (alloced_ca_memory)
1364 gnutls_free(ca.data);
1367 &key, role, ret);
1368 }
1369 if (alloced_ca_memory)
1370 gnutls_free(ca.data);
1371 break;
1372 case COAP_PKI_KEY_DEF_RPK_BUF: /* define ca */
1373 /* Ignore if set */
1374 break;
1375 case COAP_PKI_KEY_DEF_DER: /* define ca */
1376 if ((ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1377 key.key.define.ca.s_byte,
1378 GNUTLS_X509_FMT_DER) < 0)) {
1381 &key, role, ret);
1382 }
1383 break;
1384 case COAP_PKI_KEY_DEF_DER_BUF: /* define ca */
1385 if ((ret = check_null_memory(&ca,
1386 key.key.define.ca.u_byte,
1387 key.key.define.ca_len,
1388 &alloced_ca_memory)) < 0) {
1391 &key, role, ret);
1392 }
1393 if ((ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1394 &ca,
1395 GNUTLS_X509_FMT_DER)) <= 0) {
1396 if (alloced_ca_memory)
1397 gnutls_free(ca.data);
1400 &key, role, ret);
1401 }
1402 if (alloced_ca_memory)
1403 gnutls_free(ca.data);
1404 break;
1405 case COAP_PKI_KEY_DEF_PKCS11: /* define ca */
1406 if ((ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1407 key.key.define.ca.s_byte,
1408 GNUTLS_X509_FMT_DER)) <= 0) {
1411 &key, role, ret);
1412 }
1413 break;
1414 case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define ca */
1415 /* Ignore if set */
1416 break;
1417 case COAP_PKI_KEY_DEF_ENGINE: /* define ca */
1418 default:
1421 &key, role, GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1422 }
1423 }
1424
1425 if (g_context->root_ca_file) {
1426 ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1427 g_context->root_ca_file,
1428 GNUTLS_X509_FMT_PEM);
1429 if (ret == 0) {
1430 coap_log_warn("gnutls_certificate_set_x509_trust_file: Root CA: No certificates found\n");
1431 }
1432 }
1433 if (g_context->root_ca_path) {
1434#if (GNUTLS_VERSION_NUMBER >= 0x030306)
1435 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
1436 g_context->root_ca_path,
1437 GNUTLS_X509_FMT_PEM),
1438 "gnutls_certificate_set_x509_trust_dir");
1439#endif
1440 }
1441 gnutls_certificate_send_x509_rdn_sequence(g_session,
1442 setup_data->check_common_ca ? 0 : 1);
1443 if (!(g_context->psk_pki_enabled & IS_PKI)) {
1444 /* No PKI defined at all - still need a trust set up for 3.6.0 or later */
1445 G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
1446 "gnutls_certificate_set_x509_system_trust");
1447 }
1448
1449 /* Verify Peer */
1450 gnutls_certificate_set_verify_function(*pki_credentials,
1451 cert_verify_callback_gnutls);
1452
1453 /* Cert chain checking (can raise GNUTLS_E_CONSTRAINT_ERROR) */
1454 if (setup_data->cert_chain_validation) {
1455 gnutls_certificate_set_verify_limits(*pki_credentials,
1456 0,
1457 setup_data->cert_chain_verify_depth + 2);
1458 }
1459
1460 /*
1461 * Check for self signed
1462 * CRL checking (can raise GNUTLS_CERT_MISSING_OCSP_STATUS)
1463 */
1464 gnutls_certificate_set_verify_flags(*pki_credentials,
1465 (setup_data->check_cert_revocation == 0 ?
1466 GNUTLS_VERIFY_DISABLE_CRL_CHECKS : 0)
1467 );
1468
1469 return GNUTLS_E_SUCCESS;
1470
1471fail:
1472 return ret;
1473}
1474
1475#if COAP_SERVER_SUPPORT
1476/*
1477 * return 0 Success (GNUTLS_E_SUCCESS)
1478 * neg GNUTLS_E_* error code
1479 */
1480static int
1481setup_psk_credentials(gnutls_psk_server_credentials_t *psk_credentials,
1482 coap_gnutls_context_t *g_context COAP_UNUSED,
1483 coap_dtls_spsk_t *setup_data) {
1484 int ret;
1485 char hint[COAP_DTLS_HINT_LENGTH];
1486
1487 G_CHECK(gnutls_psk_allocate_server_credentials(psk_credentials),
1488 "gnutls_psk_allocate_server_credentials");
1489 gnutls_psk_set_server_credentials_function(*psk_credentials,
1490 psk_server_callback);
1491 if (setup_data->psk_info.hint.s) {
1492 snprintf(hint, sizeof(hint), "%.*s", (int)setup_data->psk_info.hint.length,
1493 setup_data->psk_info.hint.s);
1494 G_CHECK(gnutls_psk_set_server_credentials_hint(*psk_credentials, hint),
1495 "gnutls_psk_set_server_credentials_hint");
1496 }
1497
1498 return GNUTLS_E_SUCCESS;
1499
1500fail:
1501 return ret;
1502}
1503
1504/*
1505 * return 0 Success (GNUTLS_E_SUCCESS)
1506 * neg GNUTLS_E_* error code
1507 */
1508static int
1509post_client_hello_gnutls_psk(gnutls_session_t g_session) {
1510 coap_session_t *c_session =
1511 (coap_session_t *)gnutls_transport_get_ptr(g_session);
1512 coap_gnutls_context_t *g_context =
1513 (coap_gnutls_context_t *)c_session->context->dtls_context;
1514 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1515 int ret = GNUTLS_E_SUCCESS;
1516 char *name = NULL;
1517
1519 coap_dtls_spsk_t sni_setup_data;
1520 /* DNS names (only type supported) may be at most 256 byte long */
1521 size_t len = 256;
1522 unsigned int type;
1523 unsigned int i;
1524
1525 name = gnutls_malloc(len);
1526 if (name == NULL)
1527 return GNUTLS_E_MEMORY_ERROR;
1528
1529 for (i=0; ;) {
1530 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1531 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1532 char *new_name;
1533 new_name = gnutls_realloc(name, len);
1534 if (new_name == NULL) {
1535 ret = GNUTLS_E_MEMORY_ERROR;
1536 goto end;
1537 }
1538 name = new_name;
1539 continue; /* retry call with same index */
1540 }
1541
1542 /* check if it is the last entry in list */
1543 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1544 break;
1545 i++;
1546 if (ret != GNUTLS_E_SUCCESS)
1547 goto end;
1548 /* unknown types need to be ignored */
1549 if (type != GNUTLS_NAME_DNS)
1550 continue;
1551
1552 }
1553 /* If no extension provided, make it a dummy entry */
1554 if (i == 0) {
1555 name[0] = '\000';
1556 len = 0;
1557 }
1558
1559 /* Is this a cached entry? */
1560 for (i = 0; i < g_context->psk_sni_count; i++) {
1561 if (strcasecmp(name, g_context->psk_sni_entry_list[i].sni) == 0) {
1562 break;
1563 }
1564 }
1565 if (i == g_context->psk_sni_count) {
1566 /*
1567 * New SNI request
1568 */
1569 const coap_dtls_spsk_info_t *new_entry;
1570
1571 coap_lock_callback_ret(new_entry, c_session->context,
1573 c_session,
1575 if (!new_entry) {
1576 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1577 GNUTLS_A_UNRECOGNIZED_NAME));
1578 g_env->sent_alert = 1;
1579 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1580 goto end;
1581 }
1582
1583 g_context->psk_sni_entry_list =
1584 gnutls_realloc(g_context->psk_sni_entry_list,
1585 (i+1)*sizeof(psk_sni_entry));
1586 g_context->psk_sni_entry_list[i].sni = gnutls_strdup(name);
1587 g_context->psk_sni_entry_list[i].psk_info = *new_entry;
1588 sni_setup_data = c_session->context->spsk_setup_data;
1589 sni_setup_data.psk_info = *new_entry;
1590 if ((ret = setup_psk_credentials(
1591 &g_context->psk_sni_entry_list[i].psk_credentials,
1592 g_context,
1593 &sni_setup_data)) < 0) {
1594 int keep_ret = ret;
1595 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1596 GNUTLS_A_BAD_CERTIFICATE));
1597 g_env->sent_alert = 1;
1598 ret = keep_ret;
1599 goto end;
1600 }
1601 g_context->psk_sni_count++;
1602 }
1603 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1604 g_context->psk_sni_entry_list[i].psk_credentials),
1605 "gnutls_credentials_set");
1607 &g_context->psk_sni_entry_list[i].psk_info.hint);
1609 &g_context->psk_sni_entry_list[i].psk_info.key);
1610 }
1611
1612end:
1613 free(name);
1614 return ret;
1615
1616fail:
1617 return ret;
1618}
1619
1620/*
1621 * return 0 Success (GNUTLS_E_SUCCESS)
1622 * neg GNUTLS_E_* error code
1623 */
1624static int
1625post_client_hello_gnutls_pki(gnutls_session_t g_session) {
1626 coap_session_t *c_session =
1627 (coap_session_t *)gnutls_transport_get_ptr(g_session);
1628 coap_gnutls_context_t *g_context =
1629 (coap_gnutls_context_t *)c_session->context->dtls_context;
1630 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
1631 int ret = GNUTLS_E_SUCCESS;
1632 char *name = NULL;
1633
1634 if (g_context->setup_data.validate_sni_call_back) {
1635 /* DNS names (only type supported) may be at most 256 byte long */
1636 size_t len = 256;
1637 unsigned int type;
1638 unsigned int i;
1639 coap_dtls_pki_t sni_setup_data;
1640
1641 name = gnutls_malloc(len);
1642 if (name == NULL)
1643 return GNUTLS_E_MEMORY_ERROR;
1644
1645 for (i=0; ;) {
1646 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1647 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1648 char *new_name;
1649 new_name = gnutls_realloc(name, len);
1650 if (new_name == NULL) {
1651 ret = GNUTLS_E_MEMORY_ERROR;
1652 goto end;
1653 }
1654 name = new_name;
1655 continue; /* retry call with same index */
1656 }
1657
1658 /* check if it is the last entry in list */
1659 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1660 break;
1661 i++;
1662 if (ret != GNUTLS_E_SUCCESS)
1663 goto end;
1664 /* unknown types need to be ignored */
1665 if (type != GNUTLS_NAME_DNS)
1666 continue;
1667
1668 }
1669 /* If no extension provided, make it a dummy entry */
1670 if (i == 0) {
1671 name[0] = '\000';
1672 len = 0;
1673 }
1674
1675 /* Is this a cached entry? */
1676 for (i = 0; i < g_context->pki_sni_count; i++) {
1677 if (strcasecmp(name, g_context->pki_sni_entry_list[i].sni) == 0) {
1678 break;
1679 }
1680 }
1681 if (i == g_context->pki_sni_count) {
1682 /*
1683 * New SNI request
1684 */
1685 coap_dtls_key_t *new_entry;
1686
1687 coap_lock_callback_ret(new_entry, c_session->context,
1688 g_context->setup_data.validate_sni_call_back(name,
1689 g_context->setup_data.sni_call_back_arg));
1690 if (!new_entry) {
1691 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1692 GNUTLS_A_UNRECOGNIZED_NAME));
1693 g_env->sent_alert = 1;
1694 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1695 goto end;
1696 }
1697
1698 g_context->pki_sni_entry_list = gnutls_realloc(
1699 g_context->pki_sni_entry_list,
1700 (i+1)*sizeof(pki_sni_entry));
1701 g_context->pki_sni_entry_list[i].sni = gnutls_strdup(name);
1702 g_context->pki_sni_entry_list[i].pki_key = *new_entry;
1703 sni_setup_data = g_context->setup_data;
1704 sni_setup_data.pki_key = *new_entry;
1705 if ((ret = setup_pki_credentials(&g_context->pki_sni_entry_list[i].pki_credentials,
1706 g_session,
1707 g_context,
1708 &sni_setup_data, COAP_DTLS_ROLE_SERVER)) < 0) {
1709 int keep_ret = ret;
1710 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1711 GNUTLS_A_BAD_CERTIFICATE));
1712 g_env->sent_alert = 1;
1713 ret = keep_ret;
1714 goto end;
1715 }
1716 g_context->pki_sni_count++;
1717 }
1718 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1719 g_context->pki_sni_entry_list[i].pki_credentials),
1720 "gnutls_credentials_set");
1721 }
1722
1723end:
1724 free(name);
1725 return ret;
1726
1727fail:
1728 return ret;
1729}
1730#endif /* COAP_SERVER_SUPPORT */
1731
1732#if COAP_CLIENT_SUPPORT
1733/*
1734 * return 0 Success (GNUTLS_E_SUCCESS)
1735 * neg GNUTLS_E_* error code
1736 */
1737static int
1738setup_client_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1739 coap_gnutls_context_t *g_context =
1740 (coap_gnutls_context_t *)c_session->context->dtls_context;
1741 int ret;
1742
1743 g_context->psk_pki_enabled |= IS_CLIENT;
1744 if (g_context->psk_pki_enabled & IS_PSK) {
1745 coap_dtls_cpsk_t *setup_data = &c_session->cpsk_setup_data;
1746 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
1747 "gnutls_psk_allocate_client_credentials");
1748 gnutls_psk_set_client_credentials_function(g_env->psk_cl_credentials,
1749 psk_client_callback);
1750 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1751 g_env->psk_cl_credentials),
1752 "gnutls_credentials_set");
1753 /* Issue SNI if requested */
1754 if (setup_data->client_sni) {
1755 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1756 setup_data->client_sni,
1757 strlen(setup_data->client_sni)),
1758 "gnutls_server_name_set");
1759 }
1760 if (setup_data->validate_ih_call_back) {
1761 const char *err;
1763
1764 if (tls_version->version >= 0x030604) {
1765 /* Disable TLS1.3 if Identity Hint Callback set */
1766 const char *priority;
1767
1768 if (tls_version->version >= 0x030606) {
1769 priority = VARIANTS_NO_TLS13_3_6_6;
1770 } else {
1771 priority = VARIANTS_NO_TLS13_3_6_4;
1772 }
1773 ret = gnutls_priority_set_direct(g_env->g_session,
1774 priority, &err);
1775 if (ret < 0) {
1776 if (ret == GNUTLS_E_INVALID_REQUEST)
1777 coap_log_warn("gnutls_priority_set_direct: Syntax error at: %s\n", err);
1778 else
1779 coap_log_warn("gnutls_priority_set_direct: %s\n", gnutls_strerror(ret));
1780 goto fail;
1781 }
1782 }
1783 }
1784 }
1785
1786 if ((g_context->psk_pki_enabled & IS_PKI) ||
1787 (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
1788 /*
1789 * If neither PSK or PKI have been set up, use PKI basics.
1790 * This works providing COAP_PKI_KEY_PEM has a value of 0.
1791 */
1792 coap_dtls_pki_t *setup_data = &g_context->setup_data;
1793 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1794 g_context, setup_data,
1796 "setup_pki_credentials");
1797
1798 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1799 g_env->pki_credentials),
1800 "gnutls_credentials_set");
1801
1802 if (c_session->proto == COAP_PROTO_TLS)
1803 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
1804 &g_context->alpn_proto, 1, 0),
1805 "gnutls_alpn_set_protocols");
1806
1807 /* Issue SNI if requested (only happens if PKI defined) */
1808 if (setup_data->client_sni) {
1809 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1810 setup_data->client_sni,
1811 strlen(setup_data->client_sni)),
1812 "gnutls_server_name_set");
1813 }
1814 }
1815 return GNUTLS_E_SUCCESS;
1816
1817fail:
1818 return ret;
1819}
1820#endif /* COAP_CLIENT_SUPPORT */
1821
1822#if COAP_SERVER_SUPPORT
1823/*
1824 * gnutls_psk_server_credentials_function return values
1825 * (see gnutls_psk_set_server_credentials_function())
1826 *
1827 * return -1 failed
1828 * 0 passed
1829 */
1830static int
1831psk_server_callback(gnutls_session_t g_session,
1832 const char *identity,
1833 gnutls_datum_t *key) {
1834 coap_session_t *c_session =
1835 (coap_session_t *)gnutls_transport_get_ptr(g_session);
1836 coap_gnutls_context_t *g_context;
1837 coap_dtls_spsk_t *setup_data;
1838 coap_bin_const_t lidentity;
1839 const coap_bin_const_t *psk_key;
1840
1841 if (c_session == NULL)
1842 return -1;
1843
1844 g_context = (coap_gnutls_context_t *)c_session->context->dtls_context;
1845 if (g_context == NULL)
1846 return -1;
1847 setup_data = &c_session->context->spsk_setup_data;
1848
1849
1850 /* Track the Identity being used */
1851 lidentity.s = identity ? (const uint8_t *)identity : (const uint8_t *)"";
1852 lidentity.length = strlen((const char *)lidentity.s);
1853 coap_session_refresh_psk_identity(c_session, &lidentity);
1854
1855 coap_log_debug("got psk_identity: '%.*s'\n",
1856 (int)lidentity.length, (const char *)lidentity.s);
1857
1858 if (setup_data->validate_id_call_back) {
1859 psk_key = setup_data->validate_id_call_back(&lidentity,
1860 c_session,
1861 setup_data->id_call_back_arg);
1862
1863 coap_session_refresh_psk_key(c_session, psk_key);
1864 } else {
1865 psk_key = coap_get_session_server_psk_key(c_session);
1866 }
1867
1868 if (psk_key == NULL)
1869 return -1;
1870
1871 key->data = gnutls_malloc(psk_key->length);
1872 if (key->data == NULL)
1873 return -1;
1874 memcpy(key->data, psk_key->s, psk_key->length);
1875 key->size = psk_key->length;
1876 return 0;
1877}
1878
1879/*
1880 * return 0 Success (GNUTLS_E_SUCCESS)
1881 * neg GNUTLS_E_* error code
1882 */
1883static int
1884setup_server_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1885 coap_gnutls_context_t *g_context =
1886 (coap_gnutls_context_t *)c_session->context->dtls_context;
1887 int ret = GNUTLS_E_SUCCESS;
1888
1889 g_context->psk_pki_enabled |= IS_SERVER;
1890 if (g_context->psk_pki_enabled & IS_PSK) {
1891 G_CHECK(setup_psk_credentials(
1892 &g_env->psk_sv_credentials,
1893 g_context,
1894 &c_session->context->spsk_setup_data),
1895 "setup_psk_credentials\n");
1896 G_CHECK(gnutls_credentials_set(g_env->g_session,
1897 GNUTLS_CRD_PSK,
1898 g_env->psk_sv_credentials),
1899 "gnutls_credentials_set\n");
1900 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1901 post_client_hello_gnutls_psk);
1902 }
1903
1904 if (g_context->psk_pki_enabled & IS_PKI) {
1905 coap_dtls_pki_t *setup_data = &g_context->setup_data;
1906 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1907 g_context, setup_data,
1909 "setup_pki_credentials");
1910
1911 if (setup_data->verify_peer_cert) {
1912 gnutls_certificate_server_set_request(g_env->g_session,
1913 GNUTLS_CERT_REQUIRE);
1914 } else if (setup_data->is_rpk_not_cert) {
1915 gnutls_certificate_server_set_request(g_env->g_session,
1916 GNUTLS_CERT_REQUEST);
1917 } else {
1918 gnutls_certificate_server_set_request(g_env->g_session,
1919 GNUTLS_CERT_IGNORE);
1920 }
1921
1922 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1923 post_client_hello_gnutls_pki);
1924
1925 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1926 g_env->pki_credentials),
1927 "gnutls_credentials_set\n");
1928 }
1929 return GNUTLS_E_SUCCESS;
1930
1931fail:
1932 return ret;
1933}
1934#endif /* COAP_SERVER_SUPPORT */
1935
1936/*
1937 * return +ve data amount
1938 * 0 no more
1939 * -1 error (error in errno)
1940 */
1941static ssize_t
1942coap_dgram_read(gnutls_transport_ptr_t context, void *out, size_t outl) {
1943 ssize_t ret = 0;
1944 coap_session_t *c_session = (coap_session_t *)context;
1945 coap_ssl_t *data;
1946
1947 if (!c_session->tls) {
1948 errno = EAGAIN;
1949 return -1;
1950 }
1951 data = &((coap_gnutls_env_t *)c_session->tls)->coap_ssl_data;
1952
1953 if (out != NULL) {
1954 if (data != NULL && data->pdu_len > 0) {
1955 if (outl < data->pdu_len) {
1956 memcpy(out, data->pdu, outl);
1957 ret = outl;
1958 if (!data->peekmode) {
1959 data->pdu += outl;
1960 data->pdu_len -= outl;
1961 }
1962 } else {
1963 memcpy(out, data->pdu, data->pdu_len);
1964 ret = data->pdu_len;
1965 if (!data->peekmode) {
1966 data->pdu_len = 0;
1967 data->pdu = NULL;
1968 }
1969 }
1970 } else {
1971 errno = EAGAIN;
1972 ret = -1;
1973 }
1974 }
1975 return ret;
1976}
1977
1978/*
1979 * return +ve data amount
1980 * 0 no more
1981 * -1 error (error in errno)
1982 */
1983/* callback function given to gnutls for sending data over socket */
1984static ssize_t
1985coap_dgram_write(gnutls_transport_ptr_t context, const void *send_buffer,
1986 size_t send_buffer_length) {
1987 ssize_t result = -1;
1988 coap_session_t *c_session = (coap_session_t *)context;
1989
1990 if (c_session) {
1991 if (!coap_netif_available(c_session)
1993 && c_session->endpoint == NULL
1994#endif /* COAP_SERVER_SUPPORT */
1995 ) {
1996 /* socket was closed on client due to error */
1997 errno = ECONNRESET;
1998 return -1;
1999 }
2000 result = c_session->sock.lfunc[COAP_LAYER_TLS].l_write(c_session,
2001 send_buffer, send_buffer_length);
2002 if (result != (int)send_buffer_length) {
2003 int keep_errno = errno;
2004
2005 coap_log_warn("coap_netif_dgrm_write failed (%zd != %zu)\n",
2006 result, send_buffer_length);
2007 errno = keep_errno;
2008 if (result < 0) {
2009 return -1;
2010 } else {
2011 result = 0;
2012 }
2013 }
2014 } else {
2015 result = 0;
2016 }
2017 return result;
2018}
2019
2020/*
2021 * return 1 fd has activity
2022 * 0 timeout
2023 * -1 error (error in errno)
2024 */
2025static int
2026receive_timeout(gnutls_transport_ptr_t context, unsigned int ms COAP_UNUSED) {
2027 coap_session_t *c_session = (coap_session_t *)context;
2028
2029 if (c_session) {
2030 fd_set readfds, writefds, exceptfds;
2031 struct timeval tv;
2032 int nfds = c_session->sock.fd +1;
2033 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2034
2035 /* If data has been read in by libcoap ahead of GnuTLS, say it is there */
2036 if (c_session->proto == COAP_PROTO_DTLS && g_env &&
2037 g_env->coap_ssl_data.pdu_len > 0) {
2038 return 1;
2039 }
2040
2041 FD_ZERO(&readfds);
2042 FD_ZERO(&writefds);
2043 FD_ZERO(&exceptfds);
2044 FD_SET(c_session->sock.fd, &readfds);
2045 if (!(g_env && g_env->doing_dtls_timeout)) {
2046 FD_SET(c_session->sock.fd, &writefds);
2047 FD_SET(c_session->sock.fd, &exceptfds);
2048 }
2049 /* Polling */
2050 tv.tv_sec = 0;
2051 tv.tv_usec = 0;
2052
2053 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
2054 }
2055 return 1;
2056}
2057
2058static coap_gnutls_env_t *
2059coap_dtls_new_gnutls_env(coap_session_t *c_session, int type) {
2060 coap_gnutls_context_t *g_context =
2061 ((coap_gnutls_context_t *)c_session->context->dtls_context);
2062 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2063#if (GNUTLS_VERSION_NUMBER >= 0x030606)
2064 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2065#else /* < 3.6.6 */
2066 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
2067#endif /* < 3.6.6 */
2068 int ret;
2069
2070 if (g_env)
2071 return g_env;
2072
2073 g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2074 if (!g_env)
2075 return NULL;
2076
2077 memset(g_env, 0, sizeof(coap_gnutls_env_t));
2078
2079 G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2080
2081 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
2082 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
2083 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2084 /* So we can track the coap_session_t in callbacks */
2085 gnutls_transport_set_ptr(g_env->g_session, c_session);
2086
2087 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
2088 "gnutls_priority_set");
2089
2090 if (type == GNUTLS_SERVER) {
2091#if COAP_SERVER_SUPPORT
2092 G_CHECK(setup_server_ssl_session(c_session, g_env),
2093 "setup_server_ssl_session");
2094#else /* ! COAP_SERVER_SUPPORT */
2095 goto fail;
2096#endif /* ! COAP_SERVER_SUPPORT */
2097 } else {
2098#if COAP_CLIENT_SUPPORT
2099 G_CHECK(setup_client_ssl_session(c_session, g_env),
2100 "setup_client_ssl_session");
2101#else /* COAP_CLIENT_SUPPORT */
2102 goto fail;
2103#endif /* COAP_CLIENT_SUPPORT */
2104 }
2105
2106 gnutls_handshake_set_timeout(g_env->g_session,
2107 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2108 gnutls_dtls_set_timeouts(g_env->g_session, COAP_DTLS_RETRANSMIT_MS,
2109 COAP_DTLS_RETRANSMIT_TOTAL_MS);
2110
2111 return g_env;
2112
2113fail:
2114 if (g_env)
2115 gnutls_free(g_env);
2116 return NULL;
2117}
2118
2119static void
2120coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
2121 coap_gnutls_env_t *g_env,
2122 coap_free_bye_t free_bye) {
2123 if (g_env) {
2124 /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS
2125 * connections because the peer's closure message might
2126 * be lost */
2127 if (free_bye != COAP_FREE_BYE_NONE && !g_env->sent_alert) {
2128 /* Only do this if appropriate */
2129 gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
2130 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
2131 }
2132 gnutls_deinit(g_env->g_session);
2133 g_env->g_session = NULL;
2134 if (g_context->psk_pki_enabled & IS_PSK) {
2135 if ((g_context->psk_pki_enabled & IS_CLIENT) &&
2136 g_env->psk_cl_credentials != NULL) {
2137 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
2138 g_env->psk_cl_credentials = NULL;
2139 } else {
2140 /* YUK - A memory leak in 3.3.0 (fixed by 3.3.26) of hint */
2141 if (g_env->psk_sv_credentials != NULL)
2142 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
2143 g_env->psk_sv_credentials = NULL;
2144 }
2145 }
2146 if ((g_context->psk_pki_enabled & IS_PKI) ||
2147 (g_context->psk_pki_enabled &
2148 (IS_PSK | IS_PKI | IS_CLIENT)) == IS_CLIENT) {
2149 gnutls_certificate_free_credentials(g_env->pki_credentials);
2150 g_env->pki_credentials = NULL;
2151 }
2152 gnutls_free(g_env->coap_ssl_data.cookie_key.data);
2153 gnutls_free(g_env);
2154 }
2155}
2156
2157#if COAP_SERVER_SUPPORT
2158void *
2160 coap_gnutls_env_t *g_env =
2161 (coap_gnutls_env_t *)c_session->tls;
2162
2163 gnutls_transport_set_ptr(g_env->g_session, c_session);
2164
2165 return g_env;
2166}
2167#endif /* COAP_SERVER_SUPPORT */
2168
2169static void
2170log_last_alert(coap_session_t *c_session,
2171 gnutls_session_t g_session) {
2172#if COAP_MAX_LOGGING_LEVEL > 0
2173 int last_alert = gnutls_alert_get(g_session);
2174
2175 if (last_alert == GNUTLS_A_CLOSE_NOTIFY)
2176 coap_log_debug("***%s: Alert '%d': %s\n",
2177 coap_session_str(c_session),
2178 last_alert, gnutls_alert_get_name(last_alert));
2179 else
2180 coap_log_warn("***%s: Alert '%d': %s\n",
2181 coap_session_str(c_session),
2182 last_alert, gnutls_alert_get_name(last_alert));
2183#else /* COAP_MAX_LOGGING_LEVEL == 0 */
2184 (void)c_session;
2185 (void)g_session;
2186#endif /* COAP_MAX_LOGGING_LEVEL == 0 */
2187}
2188
2189/*
2190 * return -1 failure
2191 * 0 not completed
2192 * 1 established
2193 */
2194static int
2195do_gnutls_handshake(coap_session_t *c_session, coap_gnutls_env_t *g_env) {
2196 int ret;
2197
2198 ret = gnutls_handshake(g_env->g_session);
2199 switch (ret) {
2200 case GNUTLS_E_SUCCESS:
2201 g_env->established = 1;
2202 coap_log_debug("* %s: GnuTLS established\n",
2203 coap_session_str(c_session));
2204 ret = 1;
2205 break;
2206 case GNUTLS_E_INTERRUPTED:
2207 errno = EINTR;
2208 ret = 0;
2209 break;
2210 case GNUTLS_E_AGAIN:
2211 errno = EAGAIN;
2212 ret = 0;
2213 break;
2214 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
2215 coap_log_warn("Insufficient credentials provided.\n");
2216 ret = -1;
2217 break;
2218 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2219 /* Stop the sending of an alert on closedown */
2220 g_env->sent_alert = 1;
2221 log_last_alert(c_session, g_env->g_session);
2222 /* Fall through */
2223 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
2224 case GNUTLS_E_UNEXPECTED_PACKET:
2226 ret = -1;
2227 break;
2228 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2229 log_last_alert(c_session, g_env->g_session);
2230 c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2231 ret = 0;
2232 break;
2233 case GNUTLS_E_NO_CERTIFICATE_FOUND:
2234#if (GNUTLS_VERSION_NUMBER > 0x030606)
2235 case GNUTLS_E_CERTIFICATE_REQUIRED:
2236#endif /* GNUTLS_VERSION_NUMBER > 0x030606 */
2237 coap_log_warn("Client Certificate requested and required, but not provided\n"
2238 );
2239 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2240 GNUTLS_A_BAD_CERTIFICATE));
2241 g_env->sent_alert = 1;
2243 ret = -1;
2244 break;
2245 case GNUTLS_E_DECRYPTION_FAILED:
2246 coap_log_warn("do_gnutls_handshake: session establish "
2247 "returned '%s'\n",
2248 gnutls_strerror(ret));
2249 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2250 GNUTLS_A_DECRYPT_ERROR));
2251 g_env->sent_alert = 1;
2253 ret = -1;
2254 break;
2255 case GNUTLS_E_CERTIFICATE_ERROR:
2256 if (g_env->sent_alert) {
2258 ret = -1;
2259 break;
2260 }
2261 /* Fall through */
2262 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
2263 case GNUTLS_E_NO_CIPHER_SUITES:
2264 case GNUTLS_E_INVALID_SESSION:
2265 coap_log_warn("do_gnutls_handshake: session establish "
2266 "returned '%s'\n",
2267 gnutls_strerror(ret));
2268 if (!g_env->sent_alert) {
2269 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2270 GNUTLS_A_HANDSHAKE_FAILURE));
2271 g_env->sent_alert = 1;
2272 }
2274 ret = -1;
2275 break;
2276 case GNUTLS_E_SESSION_EOF:
2277 case GNUTLS_E_PREMATURE_TERMINATION:
2278 case GNUTLS_E_TIMEDOUT:
2279 case GNUTLS_E_PULL_ERROR:
2280 case GNUTLS_E_PUSH_ERROR:
2282 ret = -1;
2283 break;
2284 default:
2285 coap_log_warn("do_gnutls_handshake: session establish "
2286 "returned %d: '%s'\n",
2287 ret, gnutls_strerror(ret));
2288 ret = -1;
2289 break;
2290 }
2291 return ret;
2292}
2293
2294#if COAP_CLIENT_SUPPORT
2295void *
2297 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
2298 int ret;
2299
2300 if (g_env) {
2301 ret = do_gnutls_handshake(c_session, g_env);
2302 if (ret == -1) {
2303 coap_dtls_free_gnutls_env(c_session->context->dtls_context,
2304 g_env,
2305 COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
2306 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2307 return NULL;
2308 }
2309 }
2310 return g_env;
2311}
2312#endif /* COAP_CLIENT_SUPPORT */
2313
2314void
2316 if (c_session && c_session->context && c_session->tls) {
2317 coap_dtls_free_gnutls_env(c_session->context->dtls_context,
2318 c_session->tls,
2319 COAP_PROTO_NOT_RELIABLE(c_session->proto) ?
2320 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2321 c_session->tls = NULL;
2323 }
2324}
2325
2326void
2328 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2329 int ret;
2330
2331 if (g_env)
2332 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session,
2333 (unsigned int)c_session->mtu),
2334 "gnutls_dtls_set_data_mtu");
2335fail:
2336 ;;
2337}
2338
2339/*
2340 * return +ve data amount
2341 * 0 no more
2342 * -1 error
2343 */
2344ssize_t
2346 const uint8_t *data, size_t data_len) {
2347 int ret;
2348 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2349
2350 assert(g_env != NULL);
2351
2352 c_session->dtls_event = -1;
2353 coap_log_debug("* %s: dtls: sent %4d bytes\n",
2354 coap_session_str(c_session), (int)data_len);
2355 if (g_env->established) {
2356 ret = gnutls_record_send(g_env->g_session, data, data_len);
2357
2358 if (ret <= 0) {
2359 switch (ret) {
2360 case GNUTLS_E_AGAIN:
2361 ret = 0;
2362 break;
2363 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2364 /* Stop the sending of an alert on closedown */
2365 g_env->sent_alert = 1;
2366 log_last_alert(c_session, g_env->g_session);
2368 ret = -1;
2369 break;
2370 default:
2371 coap_log_debug("coap_dtls_send: gnutls_record_send "
2372 "returned %d: '%s'\n",
2373 ret, gnutls_strerror(ret));
2374 ret = -1;
2375 break;
2376 }
2377 if (ret == -1) {
2378 coap_log_warn("coap_dtls_send: cannot send PDU\n");
2379 }
2380 }
2381 } else {
2382 ret = do_gnutls_handshake(c_session, g_env);
2383 if (ret == 1) {
2384 /* Just connected, so send the data */
2385 return coap_dtls_send(c_session, data, data_len);
2386 }
2387 ret = -1;
2388 }
2389
2390 if (c_session->dtls_event >= 0) {
2391 coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session);
2392 if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2393 c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2395 ret = -1;
2396 }
2397 }
2398
2399 return ret;
2400}
2401
2402int
2404 return 0;
2405}
2406
2408coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED) {
2409 return 0;
2410}
2411
2414 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2415
2416 assert(c_session->state == COAP_SESSION_STATE_HANDSHAKE);
2417 if (g_env && g_env->g_session) {
2418 unsigned int rem_ms = gnutls_dtls_get_timeout(g_env->g_session);
2419
2420 if (rem_ms == 0) {
2421 /*
2422 * Need to make sure that we do not do this too frequently as some
2423 * versions of gnutls reset retransmit if a spurious packet is received
2424 * (e.g. duplicate Client Hello), but last_transmit does not get updated
2425 * when gnutls_handshake() is called and there is 'nothing' to resend.
2426 */
2427 if (g_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS > now)
2428 return g_env->last_timeout + COAP_DTLS_RETRANSMIT_COAP_TICKS;
2429 }
2430 /* Reset for the next time */
2431 g_env->last_timeout = now;
2432 return now + rem_ms;
2433 }
2434
2435 return 0;
2436}
2437
2438/*
2439 * return 1 timed out
2440 * 0 still timing out
2441 */
2442int
2444 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2445
2446 assert(g_env != NULL && c_session->state == COAP_SESSION_STATE_HANDSHAKE);
2447 g_env->doing_dtls_timeout = 1;
2448 if ((++c_session->dtls_timeout_count > c_session->max_retransmit) ||
2449 (do_gnutls_handshake(c_session, g_env) < 0)) {
2450 /* Too many retries */
2451 g_env->doing_dtls_timeout = 0;
2453 return 1;
2454 } else {
2455 g_env->doing_dtls_timeout = 0;
2456 return 0;
2457 }
2458}
2459
2460/*
2461 * return +ve data amount
2462 * 0 no more
2463 * -1 error
2464 */
2465int
2466coap_dtls_receive(coap_session_t *c_session, const uint8_t *data,
2467 size_t data_len) {
2468 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2469 int ret = 0;
2470 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
2471
2472 uint8_t pdu[COAP_RXBUFFER_SIZE];
2473
2474 assert(g_env != NULL);
2475
2476 if (ssl_data->pdu_len)
2477 coap_log_err("** %s: Previous data not read %u bytes\n",
2478 coap_session_str(c_session), ssl_data->pdu_len);
2479 ssl_data->pdu = data;
2480 ssl_data->pdu_len = data_len;
2481
2482 c_session->dtls_event = -1;
2483 if (g_env->established) {
2484 if (c_session->state == COAP_SESSION_STATE_HANDSHAKE) {
2486 c_session);
2487 gnutls_transport_set_ptr(g_env->g_session, c_session);
2488 c_session->sock.lfunc[COAP_LAYER_TLS].l_establish(c_session);
2489 }
2490 ret = gnutls_record_recv(g_env->g_session, pdu, (int)sizeof(pdu));
2491 if (ret > 0) {
2492 return coap_handle_dgram(c_session->context, c_session, pdu, (size_t)ret);
2493 } else if (ret == 0) {
2495 } else {
2496 switch (ret) {
2497 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2498 /* Stop the sending of an alert on closedown */
2499 g_env->sent_alert = 1;
2500 log_last_alert(c_session, g_env->g_session);
2502 ret = -1;
2503 break;
2504 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2505 log_last_alert(c_session, g_env->g_session);
2506 c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2507 ret = 0;
2508 break;
2509 default:
2510 coap_log_warn("coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
2511 ret = -1;
2512 break;
2513 }
2514 }
2515 } else {
2516 ret = do_gnutls_handshake(c_session, g_env);
2517 if (ret == 1) {
2518 coap_session_connected(c_session);
2519 } else {
2520 ret = -1;
2521 if (ssl_data->pdu_len && !g_env->sent_alert) {
2522 /* Do the handshake again incase of internal timeout */
2523 ret = do_gnutls_handshake(c_session, g_env);
2524 if (ret == 1) {
2525 /* Just connected, so send the data */
2526 coap_session_connected(c_session);
2527 }
2528 }
2529 }
2530 }
2531
2532 if (c_session->dtls_event >= 0) {
2533 /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */
2534 if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2535 coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session);
2536 if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2537 c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2539 ssl_data = NULL;
2540 ret = -1;
2541 }
2542 }
2543 if (ssl_data && ssl_data->pdu_len) {
2544 /* pdu data is held on stack which will not stay there */
2545 coap_log_debug("coap_dtls_receive: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2546 ssl_data->pdu_len = 0;
2547 ssl_data->pdu = NULL;
2548 }
2549 if (ret > 0) {
2550 coap_log_debug("* %s: dtls: recv %4d bytes\n",
2551 coap_session_str(c_session), ret);
2552 }
2553 return ret;
2554}
2555
2556#if COAP_SERVER_SUPPORT
2557/*
2558 * return -1 failure
2559 * 0 not completed
2560 * 1 client hello seen
2561 */
2562int
2564 const uint8_t *data,
2565 size_t data_len
2566 ) {
2567 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2568 coap_ssl_t *ssl_data;
2569 int ret;
2570
2571 if (!g_env) {
2572 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
2573 if (g_env) {
2574 c_session->tls = g_env;
2575 gnutls_key_generate(&g_env->coap_ssl_data.cookie_key,
2576 GNUTLS_COOKIE_KEY_SIZE);
2577 } else {
2578 /* error should have already been reported */
2579 return -1;
2580 }
2581 }
2582 if (data_len > 0) {
2583 gnutls_dtls_prestate_st prestate;
2584 uint8_t *data_rw;
2585
2586 memset(&prestate, 0, sizeof(prestate));
2587 /* Need to do this to not get a compiler warning about const parameters */
2588 memcpy(&data_rw, &data, sizeof(data_rw));
2589 ret = gnutls_dtls_cookie_verify(&g_env->coap_ssl_data.cookie_key,
2590 &c_session->addr_info,
2591 sizeof(c_session->addr_info),
2592 data_rw, data_len,
2593 &prestate);
2594 if (ret < 0) { /* cookie not valid */
2595 coap_log_debug("Invalid Cookie - sending Hello Verify\n");
2596 gnutls_dtls_cookie_send(&g_env->coap_ssl_data.cookie_key,
2597 &c_session->addr_info,
2598 sizeof(c_session->addr_info),
2599 &prestate,
2600 c_session,
2601 coap_dgram_write);
2602 return 0;
2603 }
2604 gnutls_dtls_prestate_set(g_env->g_session, &prestate);
2605 }
2606
2607 ssl_data = &g_env->coap_ssl_data;
2608 ssl_data->pdu = data;
2609 ssl_data->pdu_len = data_len;
2610
2611 ret = do_gnutls_handshake(c_session, g_env);
2612 if (ret < 0) {
2613 /*
2614 * as the above failed, need to remove g_env to clean up any
2615 * pollution of the information
2616 */
2617 coap_dtls_free_gnutls_env(((coap_gnutls_context_t *)c_session->context->dtls_context),
2618 g_env, COAP_FREE_BYE_NONE);
2619 c_session->tls = NULL;
2620 ssl_data = NULL;
2621 ret = -1;
2622 } else {
2623 /* Client Hello has been seen */
2624 ret = 1;
2625 }
2626
2627 if (ssl_data && ssl_data->pdu_len) {
2628 /* pdu data is held on stack which will not stay there */
2629 coap_log_debug("coap_dtls_hello: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2630 ssl_data->pdu_len = 0;
2631 ssl_data->pdu = NULL;
2632 }
2633 return ret;
2634}
2635#endif /* COAP_SERVER_SUPPORT */
2636
2637unsigned int
2639 return 37;
2640}
2641
2642#if !COAP_DISABLE_TCP
2643/*
2644 * strm
2645 * return +ve data amount
2646 * 0 connection closed
2647 * -1 error (error in errno)
2648 */
2649static ssize_t
2650coap_sock_read(gnutls_transport_ptr_t context, void *out, size_t outl) {
2651 int ret = 0;
2652 coap_session_t *c_session = (coap_session_t *)context;
2653
2654 if (out != NULL) {
2655 ret = (int)c_session->sock.lfunc[COAP_LAYER_TLS].l_read(c_session, out, outl);
2656 /* Translate layer returns into what GnuTLS expects */
2657 if (ret == 0) {
2658 errno = EAGAIN;
2659 ret = -1;
2660 }
2661 }
2662 return ret;
2663}
2664
2665/*
2666 * strm
2667 * return +ve data amount
2668 * 0 no more
2669 * -1 error (error in errno)
2670 */
2671static ssize_t
2672coap_sock_write(gnutls_transport_ptr_t context, const void *in, size_t inl) {
2673 int ret = 0;
2674 coap_session_t *c_session = (coap_session_t *)context;
2675
2676 ret = (int)c_session->sock.lfunc[COAP_LAYER_TLS].l_write(c_session, in, inl);
2677 /* Translate layer what returns into what GnuTLS expects */
2678 if (ret < 0) {
2679 if ((c_session->state == COAP_SESSION_STATE_CSM ||
2680 c_session->state == COAP_SESSION_STATE_HANDSHAKE) &&
2681 (errno == EPIPE || errno == ECONNRESET)) {
2682 /*
2683 * Need to handle a TCP timing window where an agent continues with
2684 * the sending of the next handshake or a CSM.
2685 * However, the peer does not like a certificate and so sends a
2686 * fatal alert and closes the TCP session.
2687 * The sending of the next handshake or CSM may get terminated because
2688 * of the closed TCP session, but there is still an outstanding alert
2689 * to be read in and reported on.
2690 * In this case, pretend that sending the info was fine so that the
2691 * alert can be read (which effectively is what happens with DTLS).
2692 */
2693 ret = inl;
2694 } else {
2695 coap_log_debug("* %s: failed to send %zd bytes (%s) state %d\n",
2696 coap_session_str(c_session), inl, coap_socket_strerror(),
2697 c_session->state);
2698 }
2699 }
2700 if (ret == 0) {
2701 errno = EAGAIN;
2702 ret = -1;
2703 }
2704 return ret;
2705}
2706
2707#if COAP_CLIENT_SUPPORT
2708void *
2710 coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2711 coap_gnutls_context_t *g_context =
2712 ((coap_gnutls_context_t *)c_session->context->dtls_context);
2713#if (GNUTLS_VERSION_NUMBER >= 0x030606)
2714 int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2715#else /* < 3.6.6 */
2716 int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK;
2717#endif /* < 3.6.6 */
2718 int ret;
2719
2720 if (!g_env) {
2721 return NULL;
2722 }
2723 memset(g_env, 0, sizeof(coap_gnutls_env_t));
2724
2725 G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2726
2727 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2728 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2729 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2730 /* So we can track the coap_session_t in callbacks */
2731 gnutls_transport_set_ptr(g_env->g_session, c_session);
2732
2733 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2734 setup_client_ssl_session(c_session, g_env);
2735
2736 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2737
2738 c_session->tls = g_env;
2739 ret = do_gnutls_handshake(c_session, g_env);
2740 if (ret == 1) {
2742 c_session->sock.lfunc[COAP_LAYER_TLS].l_establish(c_session);
2743 }
2744 return g_env;
2745
2746fail:
2747 if (g_env)
2748 gnutls_free(g_env);
2749 return NULL;
2750}
2751#endif /* COAP_CLIENT_SUPPORT */
2752
2753#if COAP_SERVER_SUPPORT
2754void *
2756 coap_gnutls_env_t *g_env = gnutls_malloc(sizeof(coap_gnutls_env_t));
2757 coap_gnutls_context_t *g_context =
2758 ((coap_gnutls_context_t *)c_session->context->dtls_context);
2759#if (GNUTLS_VERSION_NUMBER >= 0x030606)
2760 int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2761#else /* < 3.6.6 */
2762 int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK;
2763#endif /* < 3.6.6 */
2764 int ret;
2765
2766 if (!g_env)
2767 return NULL;
2768 memset(g_env, 0, sizeof(coap_gnutls_env_t));
2769
2770 G_CHECK(gnutls_init(&g_env->g_session, flags), "gnutls_init");
2771
2772 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2773 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2774 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2775 /* So we can track the coap_session_t in callbacks */
2776 gnutls_transport_set_ptr(g_env->g_session, c_session);
2777
2778 setup_server_ssl_session(c_session, g_env);
2779
2780 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2781 gnutls_handshake_set_timeout(g_env->g_session,
2782 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2783
2784 c_session->tls = g_env;
2785 ret = do_gnutls_handshake(c_session, g_env);
2786 if (ret == 1) {
2788 c_session->sock.lfunc[COAP_LAYER_TLS].l_establish(c_session);
2789 }
2790 return g_env;
2791
2792fail:
2793 return NULL;
2794}
2795#endif /* COAP_SERVER_SUPPORT */
2796
2797void
2799 coap_dtls_free_session(c_session);
2800 return;
2801}
2802
2803/*
2804 * strm
2805 * return +ve Number of bytes written.
2806 * -1 Error (error in errno).
2807 */
2808ssize_t
2809coap_tls_write(coap_session_t *c_session, const uint8_t *data,
2810 size_t data_len) {
2811 int ret;
2812 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2813
2814 assert(g_env != NULL);
2815
2816 c_session->dtls_event = -1;
2817 if (g_env->established) {
2818 ret = gnutls_record_send(g_env->g_session, data, data_len);
2819
2820 if (ret <= 0) {
2821 switch (ret) {
2822 case GNUTLS_E_AGAIN:
2823 ret = 0;
2824 break;
2825 case GNUTLS_E_PUSH_ERROR:
2826 case GNUTLS_E_PULL_ERROR:
2827 case GNUTLS_E_PREMATURE_TERMINATION:
2829 break;
2830 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2831 /* Stop the sending of an alert on closedown */
2832 g_env->sent_alert = 1;
2833 log_last_alert(c_session, g_env->g_session);
2835 break;
2836 default:
2837 coap_log_warn("coap_tls_write: gnutls_record_send "
2838 "returned %d: '%s'\n",
2839 ret, gnutls_strerror(ret));
2840 ret = -1;
2841 break;
2842 }
2843 if (ret == -1) {
2844 coap_log_info("coap_tls_write: cannot send PDU\n");
2845 }
2846 }
2847 } else {
2848 ret = do_gnutls_handshake(c_session, g_env);
2849 if (ret == 1) {
2851 c_session);
2852 c_session->sock.lfunc[COAP_LAYER_TLS].l_establish(c_session);
2853 ret = 0;
2854 } else {
2855 ret = -1;
2856 }
2857 }
2858
2859 if (c_session->dtls_event >= 0) {
2860 /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */
2861 if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2862 coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session);
2863 if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2864 c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2866 ret = -1;
2867 }
2868 }
2869
2870 if (ret > 0) {
2871 if (ret == (ssize_t)data_len)
2872 coap_log_debug("* %s: tls: sent %4d bytes\n",
2873 coap_session_str(c_session), ret);
2874 else
2875 coap_log_debug("* %s: tls: sent %4d of %4zd bytes\n",
2876 coap_session_str(c_session), ret, data_len);
2877 }
2878 return ret;
2879}
2880
2881/*
2882 * strm
2883 * return >=0 Number of bytes read.
2884 * -1 Error (error in errno).
2885 */
2886ssize_t
2887coap_tls_read(coap_session_t *c_session, uint8_t *data, size_t data_len) {
2888 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->tls;
2889 int ret = -1;
2890
2891 if (!g_env) {
2892 errno = ENXIO;
2893 return -1;
2894 }
2895
2896 c_session->dtls_event = -1;
2897 if (!g_env->established && !g_env->sent_alert) {
2898 ret = do_gnutls_handshake(c_session, g_env);
2899 if (ret == 1) {
2901 c_session);
2902 c_session->sock.lfunc[COAP_LAYER_TLS].l_establish(c_session);
2903 ret = 0;
2904 }
2905 }
2906 if (c_session->state != COAP_SESSION_STATE_NONE && g_env->established) {
2907 ret = gnutls_record_recv(g_env->g_session, data, (int)data_len);
2908 if (ret <= 0) {
2909 switch (ret) {
2910 case 0:
2912 break;
2913 case GNUTLS_E_AGAIN:
2914 errno = EAGAIN;
2915 ret = 0;
2916 break;
2917 case GNUTLS_E_PULL_ERROR:
2918 c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2919 break;
2920 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2921 /* Stop the sending of an alert on closedown */
2922 g_env->sent_alert = 1;
2923 log_last_alert(c_session, g_env->g_session);
2925 break;
2926 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2927 log_last_alert(c_session, g_env->g_session);
2928 c_session->dtls_event = COAP_EVENT_DTLS_ERROR;
2929 break;
2930 default:
2931 coap_log_warn("coap_tls_read: gnutls_record_recv "
2932 "returned %d: '%s'\n",
2933 ret, gnutls_strerror(ret));
2934 ret = -1;
2935 break;
2936 }
2937 }
2938 }
2939
2940 if (c_session->dtls_event >= 0) {
2941 /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */
2942 if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED)
2943 coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session);
2944 if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR ||
2945 c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) {
2947 ret = -1;
2948 }
2949 }
2950 if (ret > 0) {
2951 coap_log_debug("* %s: tls: recv %4d bytes\n",
2952 coap_session_str(c_session), ret);
2953 }
2954 return ret;
2955}
2956#endif /* !COAP_DISABLE_TCP */
2957
2958#if COAP_SERVER_SUPPORT
2960coap_digest_setup(void) {
2961 gnutls_hash_hd_t digest_ctx;
2962
2963 if (gnutls_hash_init(&digest_ctx, GNUTLS_DIG_SHA256)) {
2964 return NULL;
2965 }
2966 return digest_ctx;
2967}
2968
2969void
2971 if (digest_ctx)
2972 gnutls_hash_deinit(digest_ctx, NULL);
2973}
2974
2975int
2977 const uint8_t *data,
2978 size_t data_len) {
2979 int ret = gnutls_hash(digest_ctx, data, data_len);
2980
2981 return ret == 0;
2982}
2983
2984int
2986 coap_digest_t *digest_buffer) {
2987 gnutls_hash_output(digest_ctx, (uint8_t *)digest_buffer);
2988
2989 coap_digest_free(digest_ctx);
2990 return 1;
2991}
2992#endif /* COAP_SERVER_SUPPORT */
2993
2994#if COAP_WS_SUPPORT
2995/*
2996 * The struct hash_algs and the function get_hash_alg() are used to
2997 * determine which hash type to use for creating the required hash object.
2998 */
2999static struct hash_algs {
3000 cose_alg_t alg;
3001 gnutls_digest_algorithm_t dig_type;
3002 size_t dig_size;
3003} hashs[] = {
3004 {COSE_ALGORITHM_SHA_1, GNUTLS_DIG_SHA1, 20},
3005 {COSE_ALGORITHM_SHA_256_256, GNUTLS_DIG_SHA256, 32},
3006 {COSE_ALGORITHM_SHA_512, GNUTLS_DIG_SHA512, 64},
3007};
3008
3009static gnutls_digest_algorithm_t
3010get_hash_alg(cose_alg_t alg, size_t *hash_len) {
3011 size_t idx;
3012
3013 for (idx = 0; idx < sizeof(hashs) / sizeof(struct hash_algs); idx++) {
3014 if (hashs[idx].alg == alg) {
3015 *hash_len = hashs[idx].dig_size;
3016 return hashs[idx].dig_type;
3017 }
3018 }
3019 coap_log_debug("get_hash_alg: COSE hash %d not supported\n", alg);
3020 return GNUTLS_DIG_UNKNOWN;
3021}
3022
3023int
3025 const coap_bin_const_t *data,
3026 coap_bin_const_t **hash) {
3027 size_t hash_length;
3028 gnutls_digest_algorithm_t dig_type = get_hash_alg(alg, &hash_length);
3029 gnutls_hash_hd_t digest_ctx;
3030 coap_binary_t *dummy = NULL;
3031 int ret;
3032
3033 if (dig_type == GNUTLS_DIG_UNKNOWN) {
3034 coap_log_debug("coap_crypto_hash: algorithm %d not supported\n", alg);
3035 return 0;
3036 }
3037
3038 if (gnutls_hash_init(&digest_ctx, dig_type)) {
3039 return 0;
3040 }
3041 ret = gnutls_hash(digest_ctx, data->s, data->length);
3042 if (ret != 0)
3043 goto error;
3044
3045 dummy = coap_new_binary(hash_length);
3046 if (!dummy)
3047 goto error;
3048 gnutls_hash_output(digest_ctx, dummy->s);
3049
3050 *hash = (coap_bin_const_t *)(dummy);
3051 gnutls_hash_deinit(digest_ctx, NULL);
3052 return 1;
3053
3054error:
3056 gnutls_hash_deinit(digest_ctx, NULL);
3057 return 0;
3058}
3059#endif /* COAP_WS_SUPPORT */
3060
3061#if COAP_OSCORE_SUPPORT
3062int
3064 return 1;
3065}
3066
3067/*
3068 * The struct cipher_algs and the function get_cipher_alg() are used to
3069 * determine which cipher type to use for creating the required cipher
3070 * suite object.
3071 */
3072static struct cipher_algs {
3073 cose_alg_t alg;
3074 gnutls_cipher_algorithm_t cipher_type;
3075} ciphers[] = {{COSE_ALGORITHM_AES_CCM_16_64_128, GNUTLS_CIPHER_AES_128_CCM_8},
3076 {COSE_ALGORITHM_AES_CCM_16_64_256, GNUTLS_CIPHER_AES_256_CCM_8}
3077};
3078
3079static gnutls_cipher_algorithm_t
3080get_cipher_alg(cose_alg_t alg) {
3081 size_t idx;
3082
3083 for (idx = 0; idx < sizeof(ciphers) / sizeof(struct cipher_algs); idx++) {
3084 if (ciphers[idx].alg == alg)
3085 return ciphers[idx].cipher_type;
3086 }
3087 coap_log_debug("get_cipher_alg: COSE cipher %d not supported\n", alg);
3088 return 0;
3089}
3090
3091/*
3092 * The struct hmac_algs and the function get_hmac_alg() are used to
3093 * determine which hmac type to use for creating the required hmac
3094 * suite object.
3095 */
3096static struct hmac_algs {
3097 cose_hmac_alg_t hmac_alg;
3098 gnutls_mac_algorithm_t hmac_type;
3099} hmacs[] = {
3100 {COSE_HMAC_ALG_HMAC256_256, GNUTLS_MAC_SHA256},
3101 {COSE_HMAC_ALG_HMAC512_512, GNUTLS_MAC_SHA512},
3102};
3103
3104static gnutls_mac_algorithm_t
3105get_hmac_alg(cose_hmac_alg_t hmac_alg) {
3106 size_t idx;
3107
3108 for (idx = 0; idx < sizeof(hmacs) / sizeof(struct hmac_algs); idx++) {
3109 if (hmacs[idx].hmac_alg == hmac_alg)
3110 return hmacs[idx].hmac_type;
3111 }
3112 coap_log_debug("get_hmac_alg: COSE HMAC %d not supported\n", hmac_alg);
3113 return 0;
3114}
3115
3116int
3118 return get_cipher_alg(alg);
3119}
3120
3121int
3123 cose_hmac_alg_t hmac_alg;
3124
3125 if (!cose_get_hmac_alg_for_hkdf(hkdf_alg, &hmac_alg))
3126 return 0;
3127 return get_hmac_alg(hmac_alg);
3128}
3129
3130int
3132 coap_bin_const_t *data,
3133 coap_bin_const_t *aad,
3134 uint8_t *result,
3135 size_t *max_result_len) {
3136 gnutls_aead_cipher_hd_t ctx;
3137 gnutls_datum_t key;
3138 const coap_crypto_aes_ccm_t *ccm;
3139 int ret = 0;
3140 size_t result_len = *max_result_len;
3141 gnutls_cipher_algorithm_t algo;
3142 unsigned tag_size;
3143 uint8_t *key_data_rw;
3144 coap_bin_const_t laad;
3145
3146 if (data == NULL)
3147 return 0;
3148
3149 assert(params != NULL);
3150 if (!params) {
3151 return 0;
3152 }
3153 if ((algo = get_cipher_alg(params->alg)) == 0) {
3154 coap_log_debug("coap_crypto_encrypt: algorithm %d not supported\n",
3155 params->alg);
3156 return 0;
3157 }
3158 tag_size = gnutls_cipher_get_tag_size(algo);
3159 ccm = &params->params.aes;
3160
3161 /* Get a RW copy of data */
3162 memcpy(&key_data_rw, &ccm->key.s, sizeof(key_data_rw));
3163 key.data = key_data_rw;
3164 key.size = ccm->key.length;
3165
3166 if (aad) {
3167 laad = *aad;
3168 } else {
3169 laad.s = NULL;
3170 laad.length = 0;
3171 }
3172
3173 G_CHECK(gnutls_aead_cipher_init(&ctx, algo, &key), "gnutls_aead_cipher_init");
3174
3175 G_CHECK(gnutls_aead_cipher_encrypt(ctx,
3176 ccm->nonce,
3177 15 - ccm->l, /* iv */
3178 laad.s,
3179 laad.length, /* ad */
3180 tag_size,
3181 data->s,
3182 data->length, /* input */
3183 result,
3184 &result_len), /* output */
3185 "gnutls_aead_cipher_encrypt");
3186 *max_result_len = result_len;
3187 ret = 1;
3188fail:
3189 gnutls_aead_cipher_deinit(ctx);
3190 return ret == 1 ? 1 : 0;
3191}
3192
3193int
3195 coap_bin_const_t *data,
3196 coap_bin_const_t *aad,
3197 uint8_t *result,
3198 size_t *max_result_len) {
3199 gnutls_aead_cipher_hd_t ctx;
3200 gnutls_datum_t key;
3201 const coap_crypto_aes_ccm_t *ccm;
3202 int ret = 0;
3203 size_t result_len = *max_result_len;
3204 gnutls_cipher_algorithm_t algo;
3205 unsigned tag_size;
3206 uint8_t *key_data_rw;
3207 coap_bin_const_t laad;
3208
3209 if (data == NULL)
3210 return 0;
3211
3212 assert(params != NULL);
3213
3214 if (!params) {
3215 return 0;
3216 }
3217 if ((algo = get_cipher_alg(params->alg)) == 0) {
3218 coap_log_debug("coap_crypto_decrypt: algorithm %d not supported\n",
3219 params->alg);
3220 return 0;
3221 }
3222 tag_size = gnutls_cipher_get_tag_size(algo);
3223 ccm = &params->params.aes;
3224
3225 /* Get a RW copy of data */
3226 memcpy(&key_data_rw, &ccm->key.s, sizeof(key_data_rw));
3227 key.data = key_data_rw;
3228 key.size = ccm->key.length;
3229
3230 if (aad) {
3231 laad = *aad;
3232 } else {
3233 laad.s = NULL;
3234 laad.length = 0;
3235 }
3236
3237 G_CHECK(gnutls_aead_cipher_init(&ctx, algo, &key), "gnutls_aead_cipher_init");
3238
3239 G_CHECK(gnutls_aead_cipher_decrypt(ctx,
3240 ccm->nonce,
3241 15 - ccm->l, /* iv */
3242 laad.s,
3243 laad.length, /* ad */
3244 tag_size,
3245 data->s,
3246 data->length, /* input */
3247 result,
3248 &result_len), /* output */
3249 "gnutls_aead_cipher_decrypt");
3250 *max_result_len = result_len;
3251 ret = 1;
3252fail:
3253 gnutls_aead_cipher_deinit(ctx);
3254 return ret == 1 ? 1 : 0;
3255}
3256
3257int
3259 coap_bin_const_t *key,
3260 coap_bin_const_t *data,
3261 coap_bin_const_t **hmac) {
3262 gnutls_hmac_hd_t ctx;
3263 int ret = 0;
3264 unsigned len;
3265 gnutls_mac_algorithm_t mac_algo;
3266 coap_binary_t *dummy = NULL;
3267
3268 if (data == NULL)
3269 return 0;
3270
3271 if ((mac_algo = get_hmac_alg(hmac_alg)) == 0) {
3272 coap_log_debug("coap_crypto_hmac: algorithm %d not supported\n", hmac_alg);
3273 return 0;
3274 }
3275 len = gnutls_hmac_get_len(mac_algo);
3276 if (len == 0)
3277 return 0;
3278
3279 dummy = coap_new_binary(len);
3280 if (dummy == NULL)
3281 return 0;
3282 G_CHECK(gnutls_hmac_init(&ctx, mac_algo, key->s, key->length),
3283 "gnutls_hmac_init");
3284 G_CHECK(gnutls_hmac(ctx, data->s, data->length), "gnutls_hmac");
3285 gnutls_hmac_output(ctx, dummy->s);
3286 *hmac = (coap_bin_const_t *)dummy;
3287 dummy = NULL;
3288 ret = 1;
3289fail:
3291 gnutls_hmac_deinit(ctx, NULL);
3292 return ret == 1 ? 1 : 0;
3293}
3294
3295#endif /* COAP_OSCORE_SUPPORT */
3296
3297#else /* !COAP_WITH_LIBGNUTLS */
3298
3299#ifdef __clang__
3300/* Make compilers happy that do not like empty modules. As this function is
3301 * never used, we ignore -Wunused-function at the end of compiling this file
3302 */
3303#pragma GCC diagnostic ignored "-Wunused-function"
3304#endif
3305static inline void
3306dummy(void) {
3307}
3308
3309#endif /* !COAP_WITH_LIBGNUTLS */
#define min(a, b)
Definition coap_block.c:19
#define COAP_SERVER_SUPPORT
static void dummy(void)
const char * coap_socket_strerror(void)
Definition coap_io.c:1899
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:29
@ COAP_NACK_TLS_FAILED
Definition coap_io.h:66
@ COAP_LAYER_TLS
Library specific build wrapper for coap_internal.h.
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:108
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition coap_notls.c:224
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:296
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:219
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:238
void * coap_dtls_get_tls(const coap_session_t *c_session COAP_UNUSED, coap_tls_library_t *tls_lib)
Definition coap_notls.c:153
unsigned int coap_dtls_get_overhead(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:256
static coap_log_t dtls_log_level
Definition coap_notls.c:146
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx COAP_UNUSED)
Definition coap_notls.c:142
ssize_t 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:207
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:284
void coap_dtls_session_update_mtu(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:203
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:116
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:233
void coap_dtls_free_context(void *handle COAP_UNUSED)
Definition coap_notls.c:181
void coap_dtls_free_session(coap_session_t *coap_session COAP_UNUSED)
Definition coap_notls.c:199
void * coap_dtls_new_context(coap_context_t *coap_context COAP_UNUSED)
Definition coap_notls.c:176
void coap_tls_free_session(coap_session_t *coap_session COAP_UNUSED)
Definition coap_notls.c:275
coap_binary_t * get_asn1_spki(const uint8_t *data, size_t size)
Abstract SPKI public key from the ASN1.
Definition coap_asn1.c:122
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:143
int coap_handle_event_lkd(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 coap_net.c:4363
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 coap_net.c:2488
int coap_crypto_hmac(cose_hmac_alg_t hmac_alg, coap_bin_const_t *key, coap_bin_const_t *data, coap_bin_const_t **hmac)
Create a HMAC hash of the provided data.
int coap_crypto_aead_decrypt(const coap_crypto_param_t *params, coap_bin_const_t *data, coap_bin_const_t *aad, uint8_t *result, size_t *max_result_len)
Decrypt the provided encrypted data into plaintext.
int coap_crypto_aead_encrypt(const coap_crypto_param_t *params, coap_bin_const_t *data, coap_bin_const_t *aad, uint8_t *result, size_t *max_result_len)
Encrypt the provided plaintext data.
int coap_crypto_hash(cose_alg_t alg, const coap_bin_const_t *data, coap_bin_const_t **hash)
Create a hash of the provided data.
int coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg)
Check whether the defined hkdf algorithm is supported by the underlying crypto library.
int coap_crypto_check_cipher_alg(cose_alg_t alg)
Check whether the defined cipher algorithm is supported by the underlying crypto library.
void * coap_tls_new_server_session(coap_session_t *coap_session)
Create a TLS new server-side session.
const coap_bin_const_t * coap_get_session_client_psk_identity(const coap_session_t *coap_session)
Get the current client's PSK identity.
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition coap_notls.c:149
int coap_dtls_define_issue(coap_define_issue_key_t type, coap_define_issue_fail_t fail, coap_dtls_key_t *key, const coap_dtls_role_t role, int ret)
Report PKI DEFINE type issue.
Definition coap_dtls.c:165
void * coap_dtls_new_client_session(coap_session_t *coap_session)
Create a new client-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_set_cid_tuple_change(coap_context_t *context, uint8_t every)
Set the Connection ID client tuple frequency change for testing CIDs.
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition coap_notls.c:214
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:161
const coap_bin_const_t * coap_get_session_client_psk_key(const coap_session_t *coap_session)
Get the current client's PSK key.
void * coap_tls_new_client_session(coap_session_t *coap_session)
Create a new TLS client-side session.
#define COAP_DTLS_RETRANSMIT_COAP_TICKS
void coap_dtls_map_key_type_to_define(const coap_dtls_pki_t *setup_data, coap_dtls_key_t *key)
Map the PKI key definitions to the new DEFINE format.
Definition coap_dtls.c:26
const coap_bin_const_t * coap_get_session_server_psk_key(const coap_session_t *coap_session)
Get the current server's PSK key.
@ COAP_DEFINE_KEY_PRIVATE
@ COAP_DEFINE_KEY_CA
@ COAP_DEFINE_KEY_PUBLIC
@ COAP_DEFINE_FAIL_NONE
@ COAP_DEFINE_FAIL_NOT_SUPPORTED
@ COAP_DEFINE_FAIL_BAD
#define COAP_DTLS_HINT_LENGTH
Definition coap_dtls.h:35
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:100
struct coap_dtls_key_t coap_dtls_key_t
The structure that holds the PKI key information.
coap_dtls_role_t
Definition coap_dtls.h:44
#define COAP_DTLS_RPK_CERT_CN
Definition coap_dtls.h:49
struct coap_dtls_spsk_info_t coap_dtls_spsk_info_t
The structure that holds the Server Pre-Shared Key and Identity Hint information.
coap_tls_library_t
Definition coap_dtls.h:70
struct coap_dtls_pki_t coap_dtls_pki_t
Definition coap_dtls.h:32
@ COAP_PKI_KEY_DEF_PKCS11
The PKI key type is PKCS11 (pkcs11:...).
Definition coap_dtls.h:245
@ COAP_PKI_KEY_DEF_DER_BUF
The PKI key type is DER buffer (ASN.1).
Definition coap_dtls.h:242
@ COAP_PKI_KEY_DEF_PEM_BUF
The PKI key type is PEM buffer.
Definition coap_dtls.h:236
@ COAP_PKI_KEY_DEF_PEM
The PKI key type is PEM file.
Definition coap_dtls.h:234
@ COAP_PKI_KEY_DEF_ENGINE
The PKI key type is to be passed to ENGINE.
Definition coap_dtls.h:251
@ COAP_PKI_KEY_DEF_RPK_BUF
The PKI key type is RPK in buffer.
Definition coap_dtls.h:238
@ COAP_PKI_KEY_DEF_DER
The PKI key type is DER file.
Definition coap_dtls.h:240
@ COAP_PKI_KEY_DEF_PKCS11_RPK
The PKI key type is PKCS11 w/ RPK (pkcs11:...).
Definition coap_dtls.h:248
@ COAP_DTLS_ROLE_SERVER
Internal function invoked for server.
Definition coap_dtls.h:46
@ COAP_DTLS_ROLE_CLIENT
Internal function invoked for client.
Definition coap_dtls.h:45
@ COAP_PKI_KEY_DEFINE
The individual PKI key types are Definable.
Definition coap_dtls.h:172
@ COAP_TLS_LIBRARY_GNUTLS
Using GnuTLS library.
Definition coap_dtls.h:74
@ 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
#define coap_lock_callback_ret(r, c, func)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:120
coap_log_t
Logging type.
Definition coap_debug.h:50
coap_log_t coap_dtls_get_log_level(void)
Get the current (D)TLS logging.
Definition coap_notls.c:171
#define coap_dtls_log(level,...)
Logging function.
Definition coap_debug.h:300
void coap_dtls_set_log_level(coap_log_t level)
Sets the (D)TLS logging level to the specified level.
Definition coap_notls.c:166
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_info(...)
Definition coap_debug.h:108
#define coap_log_warn(...)
Definition coap_debug.h:102
#define coap_log_err(...)
Definition coap_debug.h:96
@ COAP_LOG_EMERG
Definition coap_debug.h:51
@ COAP_LOG_DEBUG
Definition coap_debug.h:58
@ COAP_LOG_WARN
Definition coap_debug.h:55
int coap_netif_available(coap_session_t *session)
Function interface to check whether netif for session is still available.
Definition coap_netif.c:25
int cose_get_hmac_alg_for_hkdf(cose_hkdf_alg_t hkdf_alg, cose_hmac_alg_t *hmac_alg)
cose_hkdf_alg_t
cose_hmac_alg_t
cose_alg_t
@ COSE_HMAC_ALG_HMAC256_256
@ COSE_HMAC_ALG_HMAC512_512
@ COSE_ALGORITHM_SHA_256_256
@ COSE_ALGORITHM_SHA_1
@ COSE_ALGORITHM_AES_CCM_16_64_128
@ COSE_ALGORITHM_SHA_512
@ COSE_ALGORITHM_AES_CCM_16_64_256
@ COAP_PROTO_DTLS
Definition coap_pdu.h:316
@ COAP_PROTO_TLS
Definition coap_pdu.h:318
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).
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.
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).
void coap_session_disconnected_lkd(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
#define COAP_PROTO_NOT_RELIABLE(p)
@ COAP_SESSION_STATE_HANDSHAKE
@ COAP_SESSION_STATE_CSM
@ COAP_SESSION_STATE_NONE
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition coap_str.c:77
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:105
int coap_dtls_cid_is_supported(void)
Check whether (D)TLS CID is available.
Definition coap_notls.c:86
int coap_dtls_psk_is_supported(void)
Check whether (D)TLS PSK is available.
Definition coap_notls.c:50
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition coap_notls.c:41
int coap_oscore_is_supported(void)
Check whether OSCORE is available.
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition coap_notls.c:36
int coap_dtls_pki_is_supported(void)
Check whether (D)TLS PKI is available.
Definition coap_notls.c:59
int coap_dtls_rpk_is_supported(void)
Check whether (D)TLS RPK is available.
Definition coap_notls.c:77
int coap_dtls_pkcs11_is_supported(void)
Check whether (D)TLS PKCS11 is available.
Definition coap_notls.c:68
#define COAP_UNUSED
Definition libcoap.h:70
CoAP binary data definition with const data.
Definition coap_str.h:64
size_t length
length of binary data
Definition coap_str.h:65
const uint8_t * s
read-only binary data
Definition coap_str.h:66
CoAP binary data definition.
Definition coap_str.h:56
size_t length
length of binary data
Definition coap_str.h:57
uint8_t * s
binary data
Definition coap_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 AES Crypto information.
size_t l
The number of bytes in the length field.
const uint8_t * nonce
must be exactly 15 - l bytes
coap_crypto_key_t key
The Key to use.
The common structure that holds the Crypto information.
union coap_crypto_param_t::@347070033161156116347020364174372227171250157130 params
coap_crypto_aes_ccm_t aes
Used if AES type encryption.
cose_alg_t alg
The COSE algorith to use.
The structure that holds the Client PSK information.
Definition coap_dtls.h:379
coap_bin_const_t key
Definition coap_dtls.h:381
coap_bin_const_t identity
Definition coap_dtls.h:380
The structure used for defining the Client PSK setup data to be used.
Definition coap_dtls.h:410
uint8_t use_cid
Set to 1 if DTLS Connection ID is to be used.
Definition coap_dtls.h:417
void * ih_call_back_arg
Passed in to the Identity Hint callback function.
Definition coap_dtls.h:434
char * client_sni
If not NULL, SNI to use in client TLS setup.
Definition coap_dtls.h:437
coap_dtls_ih_callback_t validate_ih_call_back
Identity Hint check callback function.
Definition coap_dtls.h:433
uint8_t ec_jpake
Set to COAP_DTLS_CPSK_SETUP_VERSION to support this version of the struct.
Definition coap_dtls.h:415
The structure that holds the PKI key information.
Definition coap_dtls.h:279
coap_pki_key_define_t define
for definable type keys
Definition coap_dtls.h:286
coap_pki_key_t key_type
key format type
Definition coap_dtls.h:280
union coap_dtls_key_t::@113076155176127235351156302031377057233373343157 key
The structure used for defining the PKI setup data to be used.
Definition coap_dtls.h:312
uint8_t cert_chain_validation
1 if to check cert_chain_verify_depth
Definition coap_dtls.h:323
uint8_t use_cid
1 if DTLS Connection ID is to be used (Client only, server always enabled) if supported
Definition coap_dtls.h:333
uint8_t check_cert_revocation
1 if revocation checks wanted
Definition coap_dtls.h:325
uint8_t cert_chain_verify_depth
recommended depth is 3
Definition coap_dtls.h:324
uint8_t verify_peer_cert
Set to COAP_DTLS_PKI_SETUP_VERSION to support this version of the struct.
Definition coap_dtls.h:317
char * client_sni
If not NULL, SNI to use in client TLS setup.
Definition coap_dtls.h:368
uint8_t is_rpk_not_cert
1 is RPK instead of Public Certificate.
Definition coap_dtls.h:330
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:318
coap_dtls_key_t pki_key
PKI key definition.
Definition coap_dtls.h:373
The structure that holds the Server Pre-Shared Key and Identity Hint information.
Definition coap_dtls.h:450
coap_bin_const_t hint
Definition coap_dtls.h:451
The structure used for defining the Server PSK setup data to be used.
Definition coap_dtls.h:501
coap_dtls_psk_sni_callback_t validate_sni_call_back
SNI check callback function.
Definition coap_dtls.h:530
coap_dtls_id_callback_t validate_id_call_back
Identity check callback function.
Definition coap_dtls.h:522
void * id_call_back_arg
Passed in to the Identity callback function.
Definition coap_dtls.h:523
uint8_t ec_jpake
Set to COAP_DTLS_SPSK_SETUP_VERSION to support this version of the struct.
Definition coap_dtls.h:506
void * sni_call_back_arg
Passed in to the SNI callback function.
Definition coap_dtls.h:531
coap_dtls_spsk_info_t psk_info
Server PSK definition.
Definition coap_dtls.h:533
coap_layer_read_t l_read
coap_layer_write_t l_write
coap_layer_establish_t l_establish
coap_const_char_ptr_t public_cert
define: Public Cert
Definition coap_dtls.h:261
const char * user_pin
define: User pin to access type PKCS11.
Definition coap_dtls.h:271
coap_const_char_ptr_t private_key
define: Private Key
Definition coap_dtls.h:262
coap_const_char_ptr_t ca
define: Common CA Certificate
Definition coap_dtls.h:260
size_t public_cert_len
define Public Cert length (if needed)
Definition coap_dtls.h:264
size_t ca_len
define CA Cert length (if needed)
Definition coap_dtls.h:263
coap_pki_define_t private_key_def
define: Private Key type definition
Definition coap_dtls.h:268
size_t private_key_len
define Private Key length (if needed)
Definition coap_dtls.h:265
coap_pki_define_t ca_def
define: Common CA type definition
Definition coap_dtls.h:266
coap_pki_define_t public_cert_def
define: Public Cert type definition
Definition coap_dtls.h:267
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_endpoint_t * endpoint
session's endpoint
coap_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationship with peer
coap_addr_tuple_t addr_info
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 session.
void * tls
security parameters
uint16_t max_retransmit
maximum re-transmit count (default 4)
coap_context_t * context
session's context
coap_layer_func_t lfunc[COAP_LAYER_LAST]
Layer functions to use.
CoAP string data definition with const data.
Definition coap_str.h:46
const uint8_t * s
read-only string data
Definition coap_str.h:48
size_t length
length of string
Definition coap_str.h:47
The structure used for returning the underlying (D)TLS library information.
Definition coap_dtls.h:83
uint64_t built_version
(D)TLS Built against Library Version
Definition coap_dtls.h:86
coap_tls_library_t type
Library type.
Definition coap_dtls.h:85
uint64_t version
(D)TLS runtime Library Version
Definition coap_dtls.h:84
const char * s_byte
signed char ptr
Definition coap_str.h:73
const uint8_t * u_byte
unsigned char ptr
Definition coap_str.h:74