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