/src/libcoap/src/coap_openssl.c
Line | Count | Source |
1 | | /* |
2 | | * coap_openssl.c -- Datagram Transport Layer Support for libcoap with openssl |
3 | | * |
4 | | * Copyright (C) 2017 Jean-Claude Michelou <jcm@spinetix.com> |
5 | | * Copyright (C) 2018-2026 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 | | * @file coap_openssl.c |
15 | | * @brief OpenSSL specific interface functions. |
16 | | */ |
17 | | |
18 | | #include "coap3/coap_libcoap_build.h" |
19 | | |
20 | | #if COAP_WITH_LIBOPENSSL |
21 | | |
22 | | /* |
23 | | * OpenSSL 1.1.0 has support for making decisions during receipt of |
24 | | * the Client Hello - the call back function is set up using |
25 | | * SSL_CTX_set_tlsext_servername_callback() which is called later in the |
26 | | * Client Hello processing - but called every Client Hello. |
27 | | * Certificates and Preshared Keys have to be set up in the SSL CTX before |
28 | | * SSL_accept() is called, making the code messy to decide whether this is a |
29 | | * PKI or PSK incoming request to handle things accordingly if both are |
30 | | * defined. SNI has to create a new SSL CTX to handle different server names |
31 | | * with different crtificates. |
32 | | * |
33 | | * OpenSSL 1.1.1 introduces a new function SSL_CTX_set_client_hello_cb(). |
34 | | * The call back is invoked early on in the Client Hello processing giving |
35 | | * the ability to easily use different Preshared Keys, Certificates etc. |
36 | | * Certificates do not have to be set up in the SSL CTX before SSL_accept is |
37 | | * called. |
38 | | * Later in the Client Hello code, the callback for |
39 | | * SSL_CTX_set_tlsext_servername_callback() is still called, but only if SNI |
40 | | * is being used by the client, so cannot be used for doing things the |
41 | | * OpenSSL 1.1.0 way. |
42 | | * |
43 | | * OpenSSL 1.1.1 supports TLS1.3. |
44 | | * |
45 | | * There is also support for OpenSSL 3. |
46 | | * |
47 | | * Consequently, this code has to have compile time options to include / |
48 | | * exclude code based on whether compiled against 1.1.0 or 1.1.1, as well as |
49 | | * have additional run time checks. |
50 | | * |
51 | | * It is possible to override the Ciphers, define the Algorithms or Groups, |
52 | | * and/or define the PKCS11 engine id to to use for the SSL negotiations at |
53 | | * compile time. This is done by the adding of the appropriate -D option to |
54 | | * the CPPFLAGS parameter that is used on the ./configure command line. |
55 | | * E.g. ./configure CPPFLAGS="-DXX='\"YY\"' -DUU='\"VV\"'" |
56 | | * The parameter value is case-sensitive. |
57 | | * |
58 | | * The ciphers can be overridden with (example) |
59 | | * -DCOAP_OPENSSL_CIPHERS='\"ECDHE-ECDSA-AES256-GCM-SHA384\"' |
60 | | * |
61 | | * The Algorithms can be defined by (example) |
62 | | * -DCOAP_OPENSSL_SIGALGS='\"ed25519\"' |
63 | | * |
64 | | * The Groups (OpenSSL 1.1.1 or later) can be defined by (example) |
65 | | * -DCOAP_OPENSSL_GROUPS='\"X25519\"' |
66 | | * |
67 | | * The PKCSLL engine ID can be defined by (example) |
68 | | + -DCOAP_OPENSSL_PKCS11_ENGINE_ID='\"pkcs11\"' |
69 | | * |
70 | | * The PSK security level can be defined by (example) |
71 | | + -DCOAP_OPENSSL_PSK_SECURITY_LEVEL=0 |
72 | | * |
73 | | */ |
74 | | #include <openssl/ssl.h> |
75 | | #include <openssl/engine.h> |
76 | | #include <openssl/err.h> |
77 | | #include <openssl/rand.h> |
78 | | #include <openssl/hmac.h> |
79 | | #include <openssl/x509v3.h> |
80 | | |
81 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
82 | | #ifdef __GNUC__ |
83 | | /* Ignore OpenSSL 3.0 deprecated warnings for now */ |
84 | | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
85 | | #endif |
86 | | #if defined(_WIN32) |
87 | | #if !defined(__MINGW32__) |
88 | | #pragma warning(disable : 4996) |
89 | | #endif /* ! __MINGW32__ */ |
90 | | #endif /* _WIN32 */ |
91 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
92 | | |
93 | | #ifdef COAP_EPOLL_SUPPORT |
94 | | # include <sys/epoll.h> |
95 | | #endif /* COAP_EPOLL_SUPPORT */ |
96 | | |
97 | | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
98 | | #error Must be compiled against OpenSSL 1.1.0 or later |
99 | | #endif |
100 | | |
101 | | #ifdef _WIN32 |
102 | | #define strcasecmp _stricmp |
103 | | #define strncasecmp _strnicmp |
104 | | #endif |
105 | | |
106 | | /* RFC6091/RFC7250 */ |
107 | | #ifndef TLSEXT_TYPE_client_certificate_type |
108 | 0 | #define TLSEXT_TYPE_client_certificate_type 19 |
109 | | #endif |
110 | | #ifndef TLSEXT_TYPE_server_certificate_type |
111 | | #define TLSEXT_TYPE_server_certificate_type 20 |
112 | | #endif |
113 | | |
114 | | #ifndef COAP_OPENSSL_CIPHERS |
115 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
116 | 0 | #define COAP_OPENSSL_CIPHERS "TLSv1.3:TLSv1.2:!NULL" |
117 | | #else /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
118 | | #define COAP_OPENSSL_CIPHERS "TLSv1.2:!NULL" |
119 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
120 | | #endif /*COAP_OPENSSL_CIPHERS */ |
121 | | |
122 | | #ifndef COAP_OPENSSL_PSK_CIPHERS |
123 | 0 | #define COAP_OPENSSL_PSK_CIPHERS "PSK:!NULL" |
124 | | #endif /*COAP_OPENSSL_PSK_CIPHERS */ |
125 | | |
126 | | #ifndef COAP_OPENSSL_PKCS11_ENGINE_ID |
127 | 0 | #define COAP_OPENSSL_PKCS11_ENGINE_ID "pkcs11" |
128 | | #endif /* COAP_OPENSSL_PKCS11_ENGINE_ID */ |
129 | | |
130 | | /* This structure encapsulates the OpenSSL context object. */ |
131 | | typedef struct coap_dtls_context_t { |
132 | | SSL_CTX *ctx; |
133 | | SSL *ssl; /* OpenSSL object for listening to connection requests */ |
134 | | HMAC_CTX *cookie_hmac; |
135 | | BIO_METHOD *meth; |
136 | | BIO_ADDR *bio_addr; |
137 | | } coap_dtls_context_t; |
138 | | |
139 | | typedef struct coap_tls_context_t { |
140 | | SSL_CTX *ctx; |
141 | | BIO_METHOD *meth; |
142 | | } coap_tls_context_t; |
143 | | |
144 | 0 | #define IS_PSK 0x1 |
145 | 0 | #define IS_PKI 0x2 |
146 | | |
147 | | typedef struct sni_entry { |
148 | | char *sni; |
149 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
150 | | SSL_CTX *ctx; |
151 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
152 | | coap_dtls_key_t pki_key; |
153 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
154 | | } sni_entry; |
155 | | |
156 | | typedef struct psk_sni_entry { |
157 | | char *sni; |
158 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
159 | | SSL_CTX *ctx; |
160 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
161 | | coap_dtls_spsk_info_t psk_info; |
162 | | } psk_sni_entry; |
163 | | |
164 | | typedef struct coap_openssl_context_t { |
165 | | coap_dtls_context_t dtls; |
166 | | #if !COAP_DISABLE_TCP |
167 | | coap_tls_context_t tls; |
168 | | #endif /* !COAP_DISABLE_TCP */ |
169 | | coap_dtls_pki_t setup_data; |
170 | | int psk_pki_enabled; |
171 | | size_t sni_count; |
172 | | sni_entry *sni_entry_list; |
173 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
174 | | size_t psk_sni_count; |
175 | | psk_sni_entry *psk_sni_entry_list; |
176 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
177 | | } coap_openssl_context_t; |
178 | | |
179 | | #if COAP_SERVER_SUPPORT |
180 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
181 | | static int psk_tls_server_name_call_back(SSL *ssl, int *sd, void *arg); |
182 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
183 | | static int psk_tls_client_hello_call_back(SSL *ssl, int *al, void *arg); |
184 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
185 | | #endif /* COAP_SERVER_SUPPORT */ |
186 | | |
187 | | int |
188 | 1 | coap_dtls_is_supported(void) { |
189 | 1 | if (SSLeay() < 0x10100000L) { |
190 | 0 | coap_log_warn("OpenSSL version 1.1.0 or later is required\n"); |
191 | 0 | return 0; |
192 | 0 | } |
193 | 1 | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
194 | | /* |
195 | | * For 1.1.1, we need to use SSL_CTX_set_client_hello_cb() |
196 | | * which is not in 1.1.0 instead of SSL_CTX_set_tlsext_servername_callback() |
197 | | * |
198 | | * However, there could be a runtime undefined external reference error |
199 | | * as SSL_CTX_set_client_hello_cb() is not there in 1.1.0. |
200 | | */ |
201 | 1 | if (SSLeay() < 0x10101000L) { |
202 | 0 | coap_log_warn("OpenSSL version 1.1.1 or later is required\n"); |
203 | 0 | return 0; |
204 | 0 | } |
205 | 1 | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
206 | 1 | return 1; |
207 | 1 | } |
208 | | |
209 | | int |
210 | 2 | coap_tls_is_supported(void) { |
211 | 2 | #if !COAP_DISABLE_TCP |
212 | 2 | if (SSLeay() < 0x10100000L) { |
213 | 0 | coap_log_warn("OpenSSL version 1.1.0 or later is required\n"); |
214 | 0 | return 0; |
215 | 0 | } |
216 | 2 | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
217 | 2 | if (SSLeay() < 0x10101000L) { |
218 | 0 | coap_log_warn("OpenSSL version 1.1.1 or later is required\n"); |
219 | 0 | return 0; |
220 | 0 | } |
221 | 2 | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
222 | 2 | return 1; |
223 | | #else /* COAP_DISABLE_TCP */ |
224 | | return 0; |
225 | | #endif /* COAP_DISABLE_TCP */ |
226 | 2 | } |
227 | | |
228 | | /* |
229 | | * return 0 failed |
230 | | * 1 passed |
231 | | */ |
232 | | int |
233 | 0 | coap_dtls_psk_is_supported(void) { |
234 | 0 | return 1; |
235 | 0 | } |
236 | | |
237 | | /* |
238 | | * return 0 failed |
239 | | * 1 passed |
240 | | */ |
241 | | int |
242 | 0 | coap_dtls_pki_is_supported(void) { |
243 | 0 | return 1; |
244 | 0 | } |
245 | | |
246 | | /* |
247 | | * return 0 failed |
248 | | * 1 passed |
249 | | */ |
250 | | int |
251 | 0 | coap_dtls_pkcs11_is_supported(void) { |
252 | 0 | return 1; |
253 | 0 | } |
254 | | |
255 | | /* |
256 | | * return 0 failed |
257 | | * 1 passed |
258 | | */ |
259 | | int |
260 | 0 | coap_dtls_rpk_is_supported(void) { |
261 | 0 | return 0; |
262 | 0 | } |
263 | | |
264 | | /* |
265 | | * return 0 failed |
266 | | * 1 passed |
267 | | */ |
268 | | int |
269 | 0 | coap_dtls_cid_is_supported(void) { |
270 | 0 | return 0; |
271 | 0 | } |
272 | | |
273 | | #if COAP_CLIENT_SUPPORT |
274 | | int |
275 | 0 | coap_dtls_set_cid_tuple_change(coap_context_t *c_context, uint8_t every) { |
276 | 0 | (void)c_context; |
277 | 0 | (void)every; |
278 | 0 | return 0; |
279 | 0 | } |
280 | | #endif /* COAP_CLIENT_SUPPORT */ |
281 | | |
282 | | coap_tls_version_t * |
283 | 0 | coap_get_tls_library_version(void) { |
284 | 0 | static coap_tls_version_t version; |
285 | 0 | version.version = SSLeay(); |
286 | 0 | version.built_version = OPENSSL_VERSION_NUMBER; |
287 | 0 | version.type = COAP_TLS_LIBRARY_OPENSSL; |
288 | 0 | return &version; |
289 | 0 | } |
290 | | |
291 | | static ENGINE *pkcs11_engine = NULL; |
292 | | static ENGINE *defined_engine = NULL; |
293 | | |
294 | | void |
295 | 0 | coap_dtls_startup(void) { |
296 | 0 | SSL_load_error_strings(); |
297 | 0 | SSL_library_init(); |
298 | 0 | ENGINE_load_dynamic(); |
299 | 0 | } |
300 | | |
301 | | void |
302 | 0 | coap_dtls_shutdown(void) { |
303 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
304 | 0 | if (pkcs11_engine) { |
305 | | /* Release the functional reference from ENGINE_init() */ |
306 | 0 | ENGINE_finish(pkcs11_engine); |
307 | 0 | pkcs11_engine = NULL; |
308 | 0 | } |
309 | 0 | if (defined_engine) { |
310 | | /* Release the functional reference from ENGINE_init() */ |
311 | 0 | ENGINE_finish(defined_engine); |
312 | 0 | defined_engine = NULL; |
313 | 0 | } |
314 | | #else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
315 | | pkcs11_engine = NULL; |
316 | | defined_engine = NULL; |
317 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
318 | 0 | ERR_free_strings(); |
319 | 0 | coap_dtls_set_log_level(COAP_LOG_EMERG); |
320 | 0 | } |
321 | | |
322 | | void |
323 | 0 | coap_dtls_thread_shutdown(void) { |
324 | 0 | } |
325 | | |
326 | | void * |
327 | | coap_dtls_get_tls(const coap_session_t *c_session, |
328 | 0 | coap_tls_library_t *tls_lib) { |
329 | 0 | if (tls_lib) |
330 | 0 | *tls_lib = COAP_TLS_LIBRARY_OPENSSL; |
331 | 0 | if (c_session) { |
332 | 0 | return c_session->tls; |
333 | 0 | } |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | | static int |
338 | | get_split_conf_entry(const uint8_t **start, size_t size, const char *get_keyword, |
339 | 0 | coap_str_const_t **p1, coap_str_const_t **p2) { |
340 | 0 | const uint8_t *begin = *start; |
341 | 0 | const uint8_t *end; |
342 | 0 | const uint8_t *kend; |
343 | 0 | const uint8_t *split; |
344 | |
|
345 | 0 | *p1 = NULL; |
346 | 0 | *p2 = NULL; |
347 | |
|
348 | 0 | retry: |
349 | 0 | kend = end = memchr(begin, '\n', size); |
350 | 0 | if (end == NULL) |
351 | 0 | return 0; |
352 | | |
353 | | /* Track beginning of next line */ |
354 | 0 | *start = end + 1; |
355 | 0 | if (end > begin && end[-1] == '\r') |
356 | 0 | end--; |
357 | |
|
358 | 0 | if (begin[0] == '#' || (end - begin) == 0) { |
359 | | /* Skip comment / blank line */ |
360 | 0 | size -= kend - begin + 1; |
361 | 0 | begin = *start; |
362 | 0 | goto retry; |
363 | 0 | } |
364 | | |
365 | | /* Get in the keyword */ |
366 | 0 | split = memchr(begin, ':', end - begin); |
367 | 0 | if (split == NULL) |
368 | 0 | goto bad_entry; |
369 | | |
370 | 0 | if ((size_t)(split - begin) != strlen(get_keyword)) { |
371 | 0 | size -= kend - begin + 1; |
372 | 0 | begin = *start; |
373 | 0 | goto retry; |
374 | 0 | } |
375 | 0 | if (memcmp(begin, get_keyword, split - begin)) { |
376 | 0 | size -= kend - begin + 1; |
377 | 0 | begin = *start; |
378 | 0 | goto retry; |
379 | 0 | } |
380 | | /* Found entry we are looking for */ |
381 | 0 | begin = split + 1; |
382 | | |
383 | | /* parameter 1 is mandatory */ |
384 | 0 | if ((end - begin) == 0) |
385 | 0 | goto bad_entry; |
386 | | /* Get in paramater #1 */ |
387 | 0 | split = memchr(begin, ':', end - begin); |
388 | 0 | if (split == NULL) { |
389 | | /* Single entry - no parameter #2 */ |
390 | 0 | *p1 = coap_new_str_const(begin, end - begin); |
391 | 0 | if (!(*p1)) { |
392 | 0 | goto bad_entry; |
393 | 0 | } |
394 | 0 | } else { |
395 | 0 | *p1 = coap_new_str_const(begin, split - begin); |
396 | 0 | if (!(*p1)) { |
397 | 0 | goto bad_entry; |
398 | 0 | } |
399 | 0 | if ((end - split) > 0) { |
400 | 0 | *p2 = coap_new_str_const(split + 1, end - split - 1); |
401 | 0 | if (!(*p2)) { |
402 | 0 | goto bad_entry; |
403 | 0 | } |
404 | 0 | } |
405 | 0 | } |
406 | | |
407 | 0 | return 1; |
408 | | |
409 | 0 | bad_entry: |
410 | 0 | coap_delete_str_const(*p1); |
411 | 0 | coap_delete_str_const(*p2); |
412 | 0 | return 0; |
413 | 0 | } |
414 | | |
415 | | /* |
416 | | * Formating of OpenSSL Engine configuration is:- |
417 | | * (Must be in this order) |
418 | | * |
419 | | * engine:XXX |
420 | | * pre-cmd:XXX:YYY |
421 | | * .... |
422 | | * pre-cmd:XXX:YYY |
423 | | * post-cmd:XXX:YYY |
424 | | * .... |
425 | | * post-cmd:XXX:YYY |
426 | | * enable-methods:unsigned-int |
427 | | * OR'd set of ENGINE_METHOD_* or ENGINE_METHOD_ALL |
428 | | * |
429 | | * pre-cmd and post-cmd are optional |
430 | | * YYY does not have to be defined for some pre-cmd or post-cmd |
431 | | */ |
432 | | int |
433 | 0 | coap_tls_engine_configure(coap_str_const_t *conf_mem) { |
434 | 0 | const uint8_t *start; |
435 | 0 | const uint8_t *end; |
436 | 0 | coap_str_const_t *p1 = NULL; |
437 | 0 | coap_str_const_t *p2 = NULL; |
438 | 0 | coap_str_const_t *engine_id = NULL; |
439 | 0 | unsigned int defaults = 0; |
440 | 0 | int done_engine_id = 0; |
441 | 0 | int done_engine_init = 0; |
442 | |
|
443 | 0 | if (!conf_mem) |
444 | 0 | return 0; |
445 | | |
446 | 0 | start = conf_mem->s; |
447 | 0 | end = start + conf_mem->length; |
448 | |
|
449 | 0 | if (defined_engine) { |
450 | 0 | coap_log_warn("coap_tls_engine_configure: Freeing off previous engine definition\n"); |
451 | 0 | ENGINE_finish(defined_engine); |
452 | 0 | defined_engine = NULL; |
453 | 0 | } |
454 | | |
455 | | /* Set up engine */ |
456 | 0 | if (!get_split_conf_entry(&start, end - start, "engine", &engine_id, &p2)) { |
457 | 0 | coap_log_warn("coap_tls_engine_configure: engine not defined\n"); |
458 | 0 | return 0; |
459 | 0 | } |
460 | 0 | defined_engine = ENGINE_by_id((const char *)engine_id->s); |
461 | 0 | if (!defined_engine) { |
462 | 0 | coap_log_warn("coap_tls_engine_configure: engine '%s' not known\n", engine_id->s); |
463 | 0 | goto fail_cleanup; |
464 | 0 | } else { |
465 | 0 | done_engine_id = 1; |
466 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "coap_tls_engine_configure: engine '%s' started\n", engine_id->s); |
467 | 0 | } |
468 | 0 | coap_delete_str_const(p2); |
469 | |
|
470 | 0 | start = conf_mem->s; |
471 | | /* process all the pre-cmd defined */ |
472 | 0 | while (get_split_conf_entry(&start, end - start, "pre-cmd", &p1, &p2)) { |
473 | 0 | if (!ENGINE_ctrl_cmd_string(defined_engine, (const char *)p1->s, p2 ? (const char *)p2->s : NULL, |
474 | 0 | 0)) { |
475 | 0 | coap_log_warn("coap_tls_engine_configure: engine %s pre-cmd '%s:%s' failed\n", |
476 | 0 | (const char *)engine_id->s, |
477 | 0 | (const char *)p1->s, p2 ? (const char *)p2->s : "(NULL)"); |
478 | 0 | goto fail_cleanup; |
479 | 0 | } else { |
480 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "coap_tls_engine_configure: engine '%s' pre-cmd '%s:%s' success\n", |
481 | 0 | engine_id->s, p1->s, p2 ? (const char *)p2->s : "(NULL)"); |
482 | 0 | } |
483 | 0 | coap_delete_str_const(p1); |
484 | 0 | coap_delete_str_const(p2); |
485 | 0 | } |
486 | | |
487 | 0 | p1 = NULL; |
488 | 0 | p2 = NULL; |
489 | | /* Start up the engine */ |
490 | 0 | if (!ENGINE_init(defined_engine)) { |
491 | 0 | coap_log_warn("coap_tls_engine_configure: %s failed initialization\n", (const char *)engine_id->s); |
492 | 0 | goto fail_cleanup; |
493 | 0 | } else { |
494 | 0 | done_engine_init = 1; |
495 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "coap_tls_engine_configure: %s initialized\n", |
496 | 0 | (const char *)engine_id->s); |
497 | 0 | } |
498 | | |
499 | 0 | start = conf_mem->s; |
500 | | /* process all the post-cmd defined */ |
501 | 0 | while (get_split_conf_entry(&start, end - start, "post-cmd", &p1, &p2)) { |
502 | 0 | if (!ENGINE_ctrl_cmd_string(defined_engine, (const char *)p1->s, p2 ? (const char *)p2->s : NULL, |
503 | 0 | 0)) { |
504 | 0 | coap_log_warn("coap_tls_engine_configure: %s post-cmd '%s:%s' failed\n", (const char *)engine_id->s, |
505 | 0 | (const char *)p1->s, p2 ? (const char *)p2->s : "(NULL)"); |
506 | 0 | goto fail_cleanup; |
507 | 0 | } else { |
508 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "coap_tls_engine_configure: %s post-cmd '%s:%s' success\n", |
509 | 0 | (const char *)engine_id->s, |
510 | 0 | (const char *)p1->s, p2 ? (const char *)p2->s : "(NULL)"); |
511 | 0 | } |
512 | 0 | coap_delete_str_const(p1); |
513 | 0 | coap_delete_str_const(p2); |
514 | 0 | } |
515 | | |
516 | 0 | start = conf_mem->s; |
517 | | /* See what we should be setting as the methods */ |
518 | 0 | if (!get_split_conf_entry(&start, end - start, "enable-methods", &p1, &p2)) { |
519 | 0 | coap_log_warn("coap_tls_engine_configure: enable-methods not found\n"); |
520 | 0 | goto fail_cleanup; |
521 | 0 | } |
522 | 0 | defaults = strtoul((const char *)p1->s, NULL, 0); |
523 | 0 | if (!ENGINE_set_default(defined_engine, defaults)) { |
524 | 0 | coap_log_warn("coap_tls_engine_configure: enable-methods 0x%x invalid\n", defaults); |
525 | 0 | goto fail_cleanup; |
526 | 0 | } else { |
527 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "coap_tls_engine_configure: enable-methods 0x%x successful\n", |
528 | 0 | defaults); |
529 | 0 | } |
530 | 0 | coap_delete_str_const(engine_id); |
531 | 0 | coap_delete_str_const(p1); |
532 | 0 | coap_delete_str_const(p2); |
533 | | /* Success */ |
534 | |
|
535 | 0 | return 1; |
536 | | |
537 | 0 | fail_cleanup: |
538 | 0 | if (done_engine_id) |
539 | 0 | ENGINE_free(defined_engine); |
540 | 0 | if (done_engine_init) |
541 | 0 | ENGINE_finish(defined_engine); |
542 | 0 | defined_engine = NULL; |
543 | 0 | coap_delete_str_const(engine_id); |
544 | 0 | coap_delete_str_const(p1); |
545 | 0 | coap_delete_str_const(p2); |
546 | 0 | return 0; |
547 | 0 | } |
548 | | |
549 | | int |
550 | 0 | coap_tls_engine_remove(void) { |
551 | 0 | if (defined_engine) { |
552 | 0 | ENGINE_finish(defined_engine); |
553 | 0 | defined_engine = NULL; |
554 | 0 | return 1; |
555 | 0 | } |
556 | 0 | return 0; |
557 | 0 | } |
558 | | |
559 | | /* |
560 | | * Logging levels use the standard CoAP logging levels |
561 | | */ |
562 | | static coap_log_t dtls_log_level = COAP_LOG_EMERG; |
563 | | |
564 | | void |
565 | 0 | coap_dtls_set_log_level(coap_log_t level) { |
566 | 0 | dtls_log_level = level; |
567 | 0 | } |
568 | | |
569 | | coap_log_t |
570 | 0 | coap_dtls_get_log_level(void) { |
571 | 0 | return dtls_log_level; |
572 | 0 | } |
573 | | |
574 | | typedef struct coap_ssl_data { |
575 | | coap_session_t *session; |
576 | | const void *pdu; |
577 | | unsigned pdu_len; |
578 | | unsigned peekmode; |
579 | | coap_tick_t timeout; |
580 | | } coap_ssl_data; |
581 | | |
582 | | static int |
583 | 0 | coap_dgram_create(BIO *a) { |
584 | 0 | coap_ssl_data *data = NULL; |
585 | 0 | data = malloc(sizeof(coap_ssl_data)); |
586 | 0 | if (data == NULL) |
587 | 0 | return 0; |
588 | 0 | BIO_set_init(a, 1); |
589 | 0 | BIO_set_data(a, data); |
590 | 0 | memset(data, 0x00, sizeof(coap_ssl_data)); |
591 | 0 | return 1; |
592 | 0 | } |
593 | | |
594 | | static int |
595 | 0 | coap_dgram_destroy(BIO *a) { |
596 | 0 | coap_ssl_data *data; |
597 | 0 | if (a == NULL) |
598 | 0 | return 0; |
599 | 0 | data = (coap_ssl_data *)BIO_get_data(a); |
600 | 0 | BIO_set_data(a, NULL); |
601 | 0 | if (data != NULL) |
602 | 0 | free(data); |
603 | 0 | return 1; |
604 | 0 | } |
605 | | |
606 | | static int |
607 | 0 | coap_dgram_read(BIO *a, char *out, int outl) { |
608 | 0 | int ret = 0; |
609 | 0 | coap_ssl_data *data = (coap_ssl_data *)BIO_get_data(a); |
610 | |
|
611 | 0 | if (out != NULL) { |
612 | 0 | if (data != NULL && data->pdu_len > 0) { |
613 | 0 | if (outl < (int)data->pdu_len) { |
614 | 0 | memcpy(out, data->pdu, outl); |
615 | 0 | ret = outl; |
616 | 0 | } else { |
617 | 0 | memcpy(out, data->pdu, data->pdu_len); |
618 | 0 | ret = (int)data->pdu_len; |
619 | 0 | } |
620 | 0 | if (!data->peekmode) { |
621 | 0 | data->pdu_len = 0; |
622 | 0 | data->pdu = NULL; |
623 | 0 | } |
624 | 0 | } else { |
625 | 0 | ret = -1; |
626 | 0 | } |
627 | 0 | BIO_clear_retry_flags(a); |
628 | 0 | if (ret < 0) |
629 | 0 | BIO_set_retry_read(a); |
630 | 0 | } |
631 | 0 | return ret; |
632 | 0 | } |
633 | | |
634 | | static int |
635 | 0 | coap_dgram_write(BIO *a, const char *in, int inl) { |
636 | 0 | int ret = 0; |
637 | 0 | coap_ssl_data *data = (coap_ssl_data *)BIO_get_data(a); |
638 | |
|
639 | 0 | if (data && data->session) { |
640 | 0 | if (!coap_netif_available(data->session) |
641 | 0 | #if COAP_SERVER_SUPPORT |
642 | 0 | && data->session->endpoint == NULL |
643 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
644 | 0 | ) { |
645 | | /* socket was closed on client due to error */ |
646 | 0 | BIO_clear_retry_flags(a); |
647 | 0 | errno = ECONNRESET; |
648 | 0 | return -1; |
649 | 0 | } |
650 | 0 | ret = (int)data->session->sock.lfunc[COAP_LAYER_TLS].l_write(data->session, |
651 | 0 | (const uint8_t *)in, |
652 | 0 | inl); |
653 | 0 | BIO_clear_retry_flags(a); |
654 | 0 | if (ret <= 0) { |
655 | 0 | if (ret < 0 && (errno == ENOTCONN || errno == ECONNREFUSED)) |
656 | 0 | data->session->dtls_event = COAP_EVENT_DTLS_ERROR; |
657 | 0 | BIO_set_retry_write(a); |
658 | 0 | } |
659 | 0 | } else { |
660 | 0 | BIO_clear_retry_flags(a); |
661 | 0 | ret = -1; |
662 | 0 | } |
663 | 0 | return ret; |
664 | 0 | } |
665 | | |
666 | | static int |
667 | 0 | coap_dgram_puts(BIO *a, const char *pstr) { |
668 | 0 | return coap_dgram_write(a, pstr, (int)strlen(pstr)); |
669 | 0 | } |
670 | | |
671 | | static long |
672 | 0 | coap_dgram_ctrl(BIO *a, int cmd, long num, void *ptr) { |
673 | 0 | long ret = 1; |
674 | 0 | coap_ssl_data *data = BIO_get_data(a); |
675 | |
|
676 | 0 | (void)ptr; |
677 | |
|
678 | 0 | switch (cmd) { |
679 | 0 | case BIO_CTRL_GET_CLOSE: |
680 | 0 | ret = BIO_get_shutdown(a); |
681 | 0 | break; |
682 | 0 | case BIO_CTRL_SET_CLOSE: |
683 | 0 | BIO_set_shutdown(a, (int)num); |
684 | 0 | break; |
685 | 0 | case BIO_CTRL_DGRAM_SET_PEEK_MODE: |
686 | 0 | if (data) |
687 | 0 | data->peekmode = (unsigned)num; |
688 | 0 | else |
689 | 0 | ret = 0; |
690 | 0 | break; |
691 | 0 | case BIO_CTRL_DGRAM_CONNECT: |
692 | 0 | case BIO_C_SET_FD: |
693 | 0 | case BIO_C_GET_FD: |
694 | 0 | case BIO_CTRL_DGRAM_SET_DONT_FRAG: |
695 | 0 | case BIO_CTRL_DGRAM_GET_MTU: |
696 | 0 | case BIO_CTRL_DGRAM_SET_MTU: |
697 | 0 | case BIO_CTRL_DGRAM_QUERY_MTU: |
698 | 0 | case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: |
699 | 0 | ret = -1; |
700 | 0 | break; |
701 | 0 | case BIO_CTRL_DUP: |
702 | 0 | case BIO_CTRL_FLUSH: |
703 | 0 | case BIO_CTRL_DGRAM_MTU_DISCOVER: |
704 | 0 | case BIO_CTRL_DGRAM_SET_CONNECTED: |
705 | 0 | break; |
706 | 0 | case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: |
707 | 0 | if (data) |
708 | 0 | data->timeout = coap_ticks_from_rt_us((uint64_t)((struct timeval *)ptr)->tv_sec * 1000000 + |
709 | 0 | ((struct timeval *)ptr)->tv_usec); |
710 | 0 | else |
711 | 0 | ret = 0; |
712 | 0 | break; |
713 | 0 | case BIO_CTRL_RESET: |
714 | 0 | case BIO_C_FILE_SEEK: |
715 | 0 | case BIO_C_FILE_TELL: |
716 | 0 | case BIO_CTRL_INFO: |
717 | 0 | case BIO_CTRL_PENDING: |
718 | 0 | case BIO_CTRL_WPENDING: |
719 | 0 | case BIO_CTRL_DGRAM_GET_PEER: |
720 | 0 | case BIO_CTRL_DGRAM_SET_PEER: |
721 | 0 | case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: |
722 | 0 | case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: |
723 | 0 | case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: |
724 | 0 | case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: |
725 | 0 | case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: |
726 | 0 | case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: |
727 | 0 | case BIO_CTRL_DGRAM_MTU_EXCEEDED: |
728 | 0 | case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: |
729 | 0 | default: |
730 | 0 | ret = 0; |
731 | 0 | break; |
732 | 0 | } |
733 | 0 | return ret; |
734 | 0 | } |
735 | | |
736 | | static int |
737 | | coap_dtls_generate_cookie(SSL *ssl, |
738 | | unsigned char *cookie, |
739 | 0 | unsigned int *cookie_len) { |
740 | 0 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
741 | 0 | coap_dtls_context_t *dtls = ctx ? (coap_dtls_context_t *)SSL_CTX_get_app_data(ctx) : NULL; |
742 | 0 | coap_ssl_data *data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(ssl)); |
743 | |
|
744 | 0 | if (dtls && data) { |
745 | 0 | int r = HMAC_Init_ex(dtls->cookie_hmac, NULL, 0, NULL, NULL); |
746 | 0 | r &= HMAC_Update(dtls->cookie_hmac, |
747 | 0 | (const uint8_t *)&data->session->addr_info.local.addr, |
748 | 0 | (size_t)data->session->addr_info.local.size); |
749 | 0 | r &= HMAC_Update(dtls->cookie_hmac, |
750 | 0 | (const uint8_t *)&data->session->addr_info.remote.addr, |
751 | 0 | (size_t)data->session->addr_info.remote.size); |
752 | 0 | r &= HMAC_Final(dtls->cookie_hmac, cookie, cookie_len); |
753 | 0 | return r; |
754 | 0 | } |
755 | 0 | return 0; |
756 | 0 | } |
757 | | |
758 | | static int |
759 | | coap_dtls_verify_cookie(SSL *ssl, |
760 | | const uint8_t *cookie, |
761 | 0 | unsigned int cookie_len) { |
762 | 0 | uint8_t hmac[32]; |
763 | 0 | unsigned len = 32; |
764 | 0 | if (coap_dtls_generate_cookie(ssl, hmac, &len) && |
765 | 0 | cookie_len == len && memcmp(cookie, hmac, len) == 0) |
766 | 0 | return 1; |
767 | 0 | else |
768 | 0 | return 0; |
769 | 0 | } |
770 | | |
771 | | #if COAP_CLIENT_SUPPORT |
772 | | static unsigned int |
773 | | coap_dtls_psk_client_callback(SSL *ssl, |
774 | | const char *hint, |
775 | | char *identity, |
776 | | unsigned int max_identity_len, |
777 | | unsigned char *psk, |
778 | 0 | unsigned int max_psk_len) { |
779 | 0 | coap_session_t *c_session; |
780 | 0 | coap_openssl_context_t *o_context; |
781 | 0 | coap_dtls_cpsk_t *setup_data; |
782 | 0 | coap_bin_const_t temp; |
783 | 0 | const coap_dtls_cpsk_info_t *cpsk_info; |
784 | 0 | const coap_bin_const_t *psk_key; |
785 | 0 | const coap_bin_const_t *psk_identity; |
786 | |
|
787 | 0 | c_session = (coap_session_t *)SSL_get_app_data(ssl); |
788 | 0 | if (c_session == NULL || c_session->context == NULL) |
789 | 0 | return 0; |
790 | 0 | o_context = (coap_openssl_context_t *)c_session->context->dtls_context; |
791 | 0 | if (o_context == NULL) |
792 | 0 | return 0; |
793 | 0 | setup_data = &c_session->cpsk_setup_data; |
794 | |
|
795 | 0 | temp.s = hint ? (const uint8_t *)hint : (const uint8_t *)""; |
796 | 0 | temp.length = strlen((const char *)temp.s); |
797 | 0 | coap_session_refresh_psk_hint(c_session, &temp); |
798 | |
|
799 | 0 | coap_log_debug("got psk_identity_hint: '%.*s'\n", (int)temp.length, |
800 | 0 | (const char *)temp.s); |
801 | |
|
802 | 0 | if (setup_data->validate_ih_call_back) { |
803 | 0 | coap_str_const_t lhint; |
804 | |
|
805 | 0 | lhint.s = temp.s; |
806 | 0 | lhint.length = temp.length; |
807 | 0 | coap_lock_callback_ret(cpsk_info, |
808 | 0 | setup_data->validate_ih_call_back(&lhint, |
809 | 0 | c_session, |
810 | 0 | setup_data->ih_call_back_arg)); |
811 | |
|
812 | 0 | if (cpsk_info == NULL) |
813 | 0 | return 0; |
814 | | |
815 | 0 | coap_session_refresh_psk_identity(c_session, &cpsk_info->identity); |
816 | 0 | coap_session_refresh_psk_key(c_session, &cpsk_info->key); |
817 | 0 | psk_identity = &cpsk_info->identity; |
818 | 0 | psk_key = &cpsk_info->key; |
819 | 0 | } else { |
820 | 0 | psk_identity = coap_get_session_client_psk_identity(c_session); |
821 | 0 | psk_key = coap_get_session_client_psk_key(c_session); |
822 | 0 | } |
823 | | |
824 | 0 | if (psk_identity == NULL || psk_key == NULL) { |
825 | 0 | coap_log_warn("no PSK available\n"); |
826 | 0 | return 0; |
827 | 0 | } |
828 | | |
829 | | /* identity has to be NULL terminated */ |
830 | 0 | if (!max_identity_len) |
831 | 0 | return 0; |
832 | 0 | max_identity_len--; |
833 | 0 | if (psk_identity->length > max_identity_len) { |
834 | 0 | coap_log_warn("psk_identity too large, truncated to %d bytes\n", |
835 | 0 | max_identity_len); |
836 | 0 | } else { |
837 | | /* Reduce to match */ |
838 | 0 | max_identity_len = (unsigned int)psk_identity->length; |
839 | 0 | } |
840 | 0 | memcpy(identity, psk_identity->s, max_identity_len); |
841 | 0 | identity[max_identity_len] = '\000'; |
842 | |
|
843 | 0 | if (psk_key->length > max_psk_len) { |
844 | 0 | coap_log_warn("psk_key too large, truncated to %d bytes\n", |
845 | 0 | max_psk_len); |
846 | 0 | } else { |
847 | | /* Reduce to match */ |
848 | 0 | max_psk_len = (unsigned int)psk_key->length; |
849 | 0 | } |
850 | 0 | memcpy(psk, psk_key->s, max_psk_len); |
851 | 0 | return max_psk_len; |
852 | 0 | } |
853 | | #endif /* COAP_CLIENT_SUPPORT */ |
854 | | |
855 | | #if COAP_SERVER_SUPPORT |
856 | | static unsigned int |
857 | | coap_dtls_psk_server_callback( |
858 | | SSL *ssl, |
859 | | const char *identity, |
860 | | unsigned char *psk, |
861 | | unsigned int max_psk_len |
862 | 0 | ) { |
863 | 0 | coap_session_t *c_session; |
864 | 0 | coap_dtls_spsk_t *setup_data; |
865 | 0 | coap_bin_const_t lidentity; |
866 | 0 | const coap_bin_const_t *psk_key; |
867 | |
|
868 | 0 | c_session = (coap_session_t *)SSL_get_app_data(ssl); |
869 | 0 | if (c_session == NULL || c_session->context == NULL) |
870 | 0 | return 0; |
871 | | |
872 | 0 | setup_data = &c_session->context->spsk_setup_data; |
873 | | |
874 | | /* Track the Identity being used */ |
875 | 0 | lidentity.s = identity ? (const uint8_t *)identity : (const uint8_t *)""; |
876 | 0 | lidentity.length = strlen((const char *)lidentity.s); |
877 | 0 | coap_session_refresh_psk_identity(c_session, &lidentity); |
878 | |
|
879 | 0 | coap_log_debug("got psk_identity: '%.*s'\n", |
880 | 0 | (int)lidentity.length, (const char *)lidentity.s); |
881 | |
|
882 | 0 | if (setup_data->validate_id_call_back) { |
883 | 0 | psk_key = setup_data->validate_id_call_back(&lidentity, |
884 | 0 | c_session, |
885 | 0 | setup_data->id_call_back_arg); |
886 | |
|
887 | 0 | coap_session_refresh_psk_key(c_session, psk_key); |
888 | 0 | } else { |
889 | 0 | psk_key = coap_get_session_server_psk_key(c_session); |
890 | 0 | } |
891 | |
|
892 | 0 | if (psk_key == NULL) |
893 | 0 | return 0; |
894 | | |
895 | 0 | if (psk_key->length > max_psk_len) { |
896 | 0 | coap_log_warn("psk_key too large, truncated to %d bytes\n", |
897 | 0 | max_psk_len); |
898 | 0 | } else { |
899 | | /* Reduce to match */ |
900 | 0 | max_psk_len = (unsigned int)psk_key->length; |
901 | 0 | } |
902 | 0 | memcpy(psk, psk_key->s, max_psk_len); |
903 | 0 | return max_psk_len; |
904 | 0 | } |
905 | | #endif /* COAP_SERVER_SUPPORT */ |
906 | | |
907 | | static const char * |
908 | 0 | ssl_function_definition(unsigned long e) { |
909 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
910 | | (void)e; |
911 | | return ""; |
912 | | #else /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
913 | 0 | static char buff[80]; |
914 | |
|
915 | 0 | snprintf(buff, sizeof(buff), " at %s:%s", |
916 | 0 | ERR_lib_error_string(e), ERR_func_error_string(e)); |
917 | 0 | return buff; |
918 | 0 | #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
919 | 0 | } |
920 | | |
921 | | static void |
922 | 0 | coap_dtls_info_callback(const SSL *ssl, int where, int ret) { |
923 | 0 | coap_session_t *session = (coap_session_t *)SSL_get_app_data(ssl); |
924 | 0 | const char *pstr; |
925 | 0 | int w = where &~SSL_ST_MASK; |
926 | |
|
927 | 0 | if (!session) { |
928 | 0 | coap_dtls_log(COAP_LOG_WARN, |
929 | 0 | "coap_dtls_info_callback: session not determined, where 0x%0x and ret 0x%0x\n", where, ret); |
930 | 0 | return; |
931 | 0 | } |
932 | 0 | if (w & SSL_ST_CONNECT) |
933 | 0 | pstr = "SSL_connect"; |
934 | 0 | else if (w & SSL_ST_ACCEPT) |
935 | 0 | pstr = "SSL_accept"; |
936 | 0 | else |
937 | 0 | pstr = "undefined"; |
938 | |
|
939 | 0 | if (where & SSL_CB_LOOP) { |
940 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "* %s: %s:%s\n", |
941 | 0 | coap_session_str(session), pstr, SSL_state_string_long(ssl)); |
942 | 0 | } else if (where & SSL_CB_ALERT) { |
943 | 0 | coap_log_t log_level = COAP_LOG_INFO; |
944 | 0 | pstr = (where & SSL_CB_READ) ? "read" : "write"; |
945 | 0 | if ((where & (SSL_CB_WRITE|SSL_CB_READ)) && (ret >> 8) == SSL3_AL_FATAL) { |
946 | 0 | session->dtls_event = COAP_EVENT_DTLS_ERROR; |
947 | 0 | if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY) |
948 | 0 | log_level = COAP_LOG_WARN; |
949 | 0 | } |
950 | | /* Need to let CoAP logging know why this session is dying */ |
951 | 0 | coap_log(log_level, "* %s: SSL3 alert %s:%s:%s\n", |
952 | 0 | coap_session_str(session), |
953 | 0 | pstr, |
954 | 0 | SSL_alert_type_string_long(ret), |
955 | 0 | SSL_alert_desc_string_long(ret)); |
956 | 0 | } else if (where & SSL_CB_EXIT) { |
957 | 0 | if (ret == 0) { |
958 | 0 | if (dtls_log_level >= COAP_LOG_WARN) { |
959 | 0 | unsigned long e; |
960 | 0 | coap_dtls_log(COAP_LOG_WARN, "* %s: %s:failed in %s\n", |
961 | 0 | coap_session_str(session), pstr, SSL_state_string_long(ssl)); |
962 | 0 | while ((e = ERR_get_error())) |
963 | 0 | coap_dtls_log(COAP_LOG_WARN, "* %s: %s%s\n", |
964 | 0 | coap_session_str(session), ERR_reason_error_string(e), |
965 | 0 | ssl_function_definition(e)); |
966 | 0 | } |
967 | 0 | } else if (ret < 0) { |
968 | 0 | if (dtls_log_level >= COAP_LOG_WARN) { |
969 | 0 | int err = SSL_get_error(ssl, ret); |
970 | 0 | if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE && |
971 | 0 | err != SSL_ERROR_WANT_CONNECT && err != SSL_ERROR_WANT_ACCEPT && |
972 | 0 | err != SSL_ERROR_WANT_X509_LOOKUP) { |
973 | 0 | long e; |
974 | 0 | coap_dtls_log(COAP_LOG_WARN, "* %s: %s:error in %s\n", |
975 | 0 | coap_session_str(session), pstr, SSL_state_string_long(ssl)); |
976 | 0 | while ((e = ERR_get_error())) |
977 | 0 | coap_dtls_log(COAP_LOG_WARN, "* %s: %s%s\n", |
978 | 0 | coap_session_str(session), ERR_reason_error_string(e), |
979 | 0 | ssl_function_definition(e)); |
980 | 0 | } |
981 | 0 | } |
982 | 0 | } |
983 | 0 | } |
984 | |
|
985 | 0 | if (where == SSL_CB_HANDSHAKE_START && SSL_get_state(ssl) == TLS_ST_OK) |
986 | 0 | session->dtls_event = COAP_EVENT_DTLS_RENEGOTIATE; |
987 | 0 | } |
988 | | |
989 | | #if !COAP_DISABLE_TCP |
990 | | static int |
991 | 0 | coap_sock_create(BIO *a) { |
992 | 0 | BIO_set_init(a, 1); |
993 | 0 | return 1; |
994 | 0 | } |
995 | | |
996 | | static int |
997 | 0 | coap_sock_destroy(BIO *a) { |
998 | 0 | (void)a; |
999 | 0 | return 1; |
1000 | 0 | } |
1001 | | |
1002 | | /* |
1003 | | * strm |
1004 | | * return +ve data amount |
1005 | | * 0 no more |
1006 | | * -1 error |
1007 | | */ |
1008 | | static int |
1009 | 0 | coap_sock_read(BIO *a, char *out, int outl) { |
1010 | 0 | int ret = 0; |
1011 | 0 | coap_session_t *session = (coap_session_t *)BIO_get_data(a); |
1012 | |
|
1013 | 0 | if (session && out != NULL) { |
1014 | 0 | ret =(int)session->sock.lfunc[COAP_LAYER_TLS].l_read(session, (uint8_t *)out, |
1015 | 0 | outl); |
1016 | | /* Translate layer returns into what OpenSSL expects */ |
1017 | 0 | if (ret == 0) { |
1018 | 0 | BIO_set_retry_read(a); |
1019 | 0 | ret = -1; |
1020 | 0 | } else { |
1021 | 0 | BIO_clear_retry_flags(a); |
1022 | 0 | } |
1023 | 0 | } |
1024 | 0 | return ret; |
1025 | 0 | } |
1026 | | |
1027 | | /* |
1028 | | * strm |
1029 | | * return +ve data amount |
1030 | | * 0 no more |
1031 | | * -1 error (error in errno) |
1032 | | */ |
1033 | | static int |
1034 | 0 | coap_sock_write(BIO *a, const char *in, int inl) { |
1035 | 0 | int ret = 0; |
1036 | 0 | coap_session_t *session = (coap_session_t *)BIO_get_data(a); |
1037 | |
|
1038 | 0 | if (!session) { |
1039 | 0 | errno = ENOMEM; |
1040 | 0 | return -1; |
1041 | 0 | } else { |
1042 | 0 | ret = (int)session->sock.lfunc[COAP_LAYER_TLS].l_write(session, |
1043 | 0 | (const uint8_t *)in, |
1044 | 0 | inl); |
1045 | 0 | } |
1046 | | /* Translate layer what returns into what OpenSSL expects */ |
1047 | 0 | BIO_clear_retry_flags(a); |
1048 | 0 | if (ret == 0) { |
1049 | 0 | BIO_set_retry_read(a); |
1050 | 0 | ret = -1; |
1051 | 0 | } else { |
1052 | 0 | BIO_clear_retry_flags(a); |
1053 | 0 | if (ret == -1) { |
1054 | 0 | if ((session->state == COAP_SESSION_STATE_CSM || |
1055 | 0 | session->state == COAP_SESSION_STATE_HANDSHAKE) && |
1056 | 0 | (errno == EPIPE || errno == ECONNRESET)) { |
1057 | | /* |
1058 | | * Need to handle a TCP timing window where an agent continues with |
1059 | | * the sending of the next handshake or a CSM. |
1060 | | * However, the peer does not like a certificate and so sends a |
1061 | | * fatal alert and closes the TCP session. |
1062 | | * The sending of the next handshake or CSM may get terminated because |
1063 | | * of the closed TCP session, but there is still an outstanding alert |
1064 | | * to be read in and reported on. |
1065 | | * In this case, pretend that sending the info was fine so that the |
1066 | | * alert can be read (which effectively is what happens with DTLS). |
1067 | | */ |
1068 | 0 | ret = inl; |
1069 | 0 | } |
1070 | 0 | } |
1071 | 0 | } |
1072 | 0 | return ret; |
1073 | 0 | } |
1074 | | |
1075 | | static int |
1076 | 0 | coap_sock_puts(BIO *a, const char *pstr) { |
1077 | 0 | return coap_sock_write(a, pstr, (int)strlen(pstr)); |
1078 | 0 | } |
1079 | | |
1080 | | static long |
1081 | 0 | coap_sock_ctrl(BIO *a, int cmd, long num, void *ptr) { |
1082 | 0 | int r = 1; |
1083 | 0 | (void)a; |
1084 | 0 | (void)ptr; |
1085 | 0 | (void)num; |
1086 | |
|
1087 | 0 | switch (cmd) { |
1088 | 0 | case BIO_C_SET_FD: |
1089 | 0 | case BIO_C_GET_FD: |
1090 | 0 | r = -1; |
1091 | 0 | break; |
1092 | 0 | case BIO_CTRL_SET_CLOSE: |
1093 | 0 | case BIO_CTRL_DUP: |
1094 | 0 | case BIO_CTRL_FLUSH: |
1095 | 0 | r = 1; |
1096 | 0 | break; |
1097 | 0 | default: |
1098 | 0 | case BIO_CTRL_GET_CLOSE: |
1099 | 0 | r = 0; |
1100 | 0 | break; |
1101 | 0 | } |
1102 | 0 | return r; |
1103 | 0 | } |
1104 | | #endif /* !COAP_DISABLE_TCP */ |
1105 | | |
1106 | | static void |
1107 | 0 | coap_set_user_prefs(SSL_CTX *ctx) { |
1108 | 0 | SSL_CTX_set_cipher_list(ctx, COAP_OPENSSL_CIPHERS); |
1109 | |
|
1110 | | #ifdef COAP_OPENSSL_SIGALGS |
1111 | | SSL_CTX_set1_sigalgs_list(ctx, COAP_OPENSSL_SIGALGS); |
1112 | | SSL_CTX_set1_client_sigalgs_list(ctx, COAP_OPENSSL_SIGALGS); |
1113 | | #endif |
1114 | |
|
1115 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L && defined(COAP_OPENSSL_GROUPS) |
1116 | | SSL_CTX_set1_groups_list(ctx, COAP_OPENSSL_GROUPS); |
1117 | | #endif |
1118 | 0 | } |
1119 | | |
1120 | | #if COAP_DTLS_RETRANSMIT_MS != 1000 |
1121 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
1122 | | static unsigned int |
1123 | | timer_cb(SSL *s, unsigned int timer_us) { |
1124 | | (void)s; |
1125 | | if (timer_us == 0) |
1126 | | return COAP_DTLS_RETRANSMIT_MS * 1000; |
1127 | | else |
1128 | | return 2 * timer_us; |
1129 | | } |
1130 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
1131 | | #endif /* COAP_DTLS_RETRANSMIT_MS != 1000 */ |
1132 | | |
1133 | | void * |
1134 | 0 | coap_dtls_new_context(coap_context_t *coap_context) { |
1135 | 0 | coap_openssl_context_t *context; |
1136 | 0 | (void)coap_context; |
1137 | |
|
1138 | 0 | context = (coap_openssl_context_t *)coap_malloc_type(COAP_STRING, sizeof(coap_openssl_context_t)); |
1139 | 0 | if (context) { |
1140 | 0 | uint8_t cookie_secret[32]; |
1141 | |
|
1142 | 0 | memset(context, 0, sizeof(coap_openssl_context_t)); |
1143 | | |
1144 | | /* Set up DTLS context */ |
1145 | 0 | context->dtls.ctx = SSL_CTX_new(DTLS_method()); |
1146 | 0 | if (!context->dtls.ctx) |
1147 | 0 | goto error; |
1148 | 0 | SSL_CTX_set_min_proto_version(context->dtls.ctx, DTLS1_2_VERSION); |
1149 | 0 | SSL_CTX_set_app_data(context->dtls.ctx, &context->dtls); |
1150 | 0 | SSL_CTX_set_read_ahead(context->dtls.ctx, 1); |
1151 | 0 | coap_set_user_prefs(context->dtls.ctx); |
1152 | 0 | memset(cookie_secret, 0, sizeof(cookie_secret)); |
1153 | 0 | if (!RAND_bytes(cookie_secret, (int)sizeof(cookie_secret))) { |
1154 | 0 | coap_dtls_log(COAP_LOG_WARN, |
1155 | 0 | "Insufficient entropy for random cookie generation"); |
1156 | 0 | coap_prng_lkd(cookie_secret, sizeof(cookie_secret)); |
1157 | 0 | } |
1158 | 0 | context->dtls.cookie_hmac = HMAC_CTX_new(); |
1159 | 0 | if (!context->dtls.cookie_hmac) |
1160 | 0 | goto error; |
1161 | 0 | if (!HMAC_Init_ex(context->dtls.cookie_hmac, cookie_secret, (int)sizeof(cookie_secret), |
1162 | 0 | EVP_sha256(), NULL)) |
1163 | 0 | goto error; |
1164 | 0 | SSL_CTX_set_cookie_generate_cb(context->dtls.ctx, coap_dtls_generate_cookie); |
1165 | 0 | SSL_CTX_set_cookie_verify_cb(context->dtls.ctx, coap_dtls_verify_cookie); |
1166 | 0 | SSL_CTX_set_info_callback(context->dtls.ctx, coap_dtls_info_callback); |
1167 | 0 | SSL_CTX_set_options(context->dtls.ctx, SSL_OP_NO_QUERY_MTU); |
1168 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
1169 | | SSL_CTX_set_options(context->dtls.ctx, SSL_OP_LEGACY_SERVER_CONNECT); |
1170 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
1171 | 0 | context->dtls.meth = BIO_meth_new(BIO_TYPE_DGRAM, "coapdgram"); |
1172 | 0 | if (!context->dtls.meth) |
1173 | 0 | goto error; |
1174 | 0 | context->dtls.bio_addr = BIO_ADDR_new(); |
1175 | 0 | if (!context->dtls.bio_addr) |
1176 | 0 | goto error; |
1177 | 0 | BIO_meth_set_write(context->dtls.meth, coap_dgram_write); |
1178 | 0 | BIO_meth_set_read(context->dtls.meth, coap_dgram_read); |
1179 | 0 | BIO_meth_set_puts(context->dtls.meth, coap_dgram_puts); |
1180 | 0 | BIO_meth_set_ctrl(context->dtls.meth, coap_dgram_ctrl); |
1181 | 0 | BIO_meth_set_create(context->dtls.meth, coap_dgram_create); |
1182 | 0 | BIO_meth_set_destroy(context->dtls.meth, coap_dgram_destroy); |
1183 | |
|
1184 | 0 | #if !COAP_DISABLE_TCP |
1185 | | /* Set up TLS context */ |
1186 | 0 | context->tls.ctx = SSL_CTX_new(TLS_method()); |
1187 | 0 | if (!context->tls.ctx) |
1188 | 0 | goto error; |
1189 | 0 | SSL_CTX_set_app_data(context->tls.ctx, &context->tls); |
1190 | 0 | SSL_CTX_set_min_proto_version(context->tls.ctx, TLS1_VERSION); |
1191 | 0 | coap_set_user_prefs(context->tls.ctx); |
1192 | 0 | SSL_CTX_set_info_callback(context->tls.ctx, coap_dtls_info_callback); |
1193 | 0 | context->tls.meth = BIO_meth_new(BIO_TYPE_SOCKET, "coapsock"); |
1194 | 0 | if (!context->tls.meth) |
1195 | 0 | goto error; |
1196 | 0 | BIO_meth_set_write(context->tls.meth, coap_sock_write); |
1197 | 0 | BIO_meth_set_read(context->tls.meth, coap_sock_read); |
1198 | 0 | BIO_meth_set_puts(context->tls.meth, coap_sock_puts); |
1199 | 0 | BIO_meth_set_ctrl(context->tls.meth, coap_sock_ctrl); |
1200 | 0 | BIO_meth_set_create(context->tls.meth, coap_sock_create); |
1201 | 0 | BIO_meth_set_destroy(context->tls.meth, coap_sock_destroy); |
1202 | 0 | #endif /* !COAP_DISABLE_TCP */ |
1203 | 0 | } |
1204 | | |
1205 | 0 | return context; |
1206 | | |
1207 | 0 | error: |
1208 | 0 | coap_dtls_free_context(context); |
1209 | 0 | return NULL; |
1210 | 0 | } |
1211 | | |
1212 | | #if COAP_SERVER_SUPPORT |
1213 | | int |
1214 | | coap_dtls_context_set_spsk(coap_context_t *c_context, |
1215 | | coap_dtls_spsk_t *setup_data |
1216 | 0 | ) { |
1217 | 0 | coap_openssl_context_t *o_context = |
1218 | 0 | ((coap_openssl_context_t *)c_context->dtls_context); |
1219 | 0 | BIO *bio; |
1220 | |
|
1221 | 0 | if (!setup_data || !o_context) |
1222 | 0 | return 0; |
1223 | | |
1224 | 0 | SSL_CTX_set_psk_server_callback(o_context->dtls.ctx, |
1225 | 0 | coap_dtls_psk_server_callback); |
1226 | 0 | #if !COAP_DISABLE_TCP |
1227 | 0 | SSL_CTX_set_psk_server_callback(o_context->tls.ctx, |
1228 | 0 | coap_dtls_psk_server_callback); |
1229 | 0 | #endif /* !COAP_DISABLE_TCP */ |
1230 | 0 | if (setup_data->psk_info.hint.s) { |
1231 | 0 | char hint[COAP_DTLS_HINT_LENGTH]; |
1232 | 0 | snprintf(hint, sizeof(hint), "%.*s", (int)setup_data->psk_info.hint.length, |
1233 | 0 | setup_data->psk_info.hint.s); |
1234 | 0 | SSL_CTX_use_psk_identity_hint(o_context->dtls.ctx, hint); |
1235 | 0 | #if !COAP_DISABLE_TCP |
1236 | 0 | SSL_CTX_use_psk_identity_hint(o_context->tls.ctx, hint); |
1237 | 0 | #endif /* !COAP_DISABLE_TCP */ |
1238 | 0 | } |
1239 | 0 | if (setup_data->validate_sni_call_back) { |
1240 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
1241 | | SSL_CTX_set_tlsext_servername_arg(o_context->dtls.ctx, |
1242 | | &c_context->spsk_setup_data); |
1243 | | SSL_CTX_set_tlsext_servername_callback(o_context->dtls.ctx, |
1244 | | psk_tls_server_name_call_back); |
1245 | | #if !COAP_DISABLE_TCP |
1246 | | SSL_CTX_set_tlsext_servername_arg(o_context->tls.ctx, |
1247 | | &c_context->spsk_setup_data); |
1248 | | SSL_CTX_set_tlsext_servername_callback(o_context->tls.ctx, |
1249 | | psk_tls_server_name_call_back); |
1250 | | #endif /* !COAP_DISABLE_TCP */ |
1251 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
1252 | 0 | SSL_CTX_set_client_hello_cb(o_context->dtls.ctx, |
1253 | 0 | psk_tls_client_hello_call_back, |
1254 | 0 | NULL); |
1255 | 0 | #if !COAP_DISABLE_TCP |
1256 | 0 | SSL_CTX_set_client_hello_cb(o_context->tls.ctx, |
1257 | 0 | psk_tls_client_hello_call_back, |
1258 | 0 | NULL); |
1259 | 0 | #endif /* !COAP_DISABLE_TCP */ |
1260 | 0 | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
1261 | 0 | } |
1262 | |
|
1263 | 0 | if (!o_context->dtls.ssl) { |
1264 | | /* This is set up to handle new incoming sessions to a server */ |
1265 | 0 | o_context->dtls.ssl = SSL_new(o_context->dtls.ctx); |
1266 | 0 | if (!o_context->dtls.ssl) |
1267 | 0 | return 0; |
1268 | 0 | bio = BIO_new(o_context->dtls.meth); |
1269 | 0 | if (!bio) { |
1270 | 0 | SSL_free(o_context->dtls.ssl); |
1271 | 0 | o_context->dtls.ssl = NULL; |
1272 | 0 | return 0; |
1273 | 0 | } |
1274 | 0 | SSL_set_bio(o_context->dtls.ssl, bio, bio); |
1275 | 0 | SSL_set_app_data(o_context->dtls.ssl, NULL); |
1276 | 0 | SSL_set_options(o_context->dtls.ssl, SSL_OP_COOKIE_EXCHANGE); |
1277 | 0 | SSL_set_mtu(o_context->dtls.ssl, COAP_DEFAULT_MTU); |
1278 | 0 | } |
1279 | 0 | if (setup_data->ec_jpake) { |
1280 | 0 | coap_log_warn("OpenSSL has no EC-JPAKE support\n"); |
1281 | 0 | } |
1282 | 0 | o_context->psk_pki_enabled |= IS_PSK; |
1283 | 0 | return 1; |
1284 | 0 | } |
1285 | | #endif /* COAP_SERVER_SUPPORT */ |
1286 | | |
1287 | | #if COAP_CLIENT_SUPPORT |
1288 | | int |
1289 | | coap_dtls_context_set_cpsk(coap_context_t *c_context, |
1290 | | coap_dtls_cpsk_t *setup_data |
1291 | 0 | ) { |
1292 | 0 | coap_openssl_context_t *o_context = |
1293 | 0 | ((coap_openssl_context_t *)c_context->dtls_context); |
1294 | 0 | BIO *bio; |
1295 | |
|
1296 | 0 | if (!setup_data || !o_context) |
1297 | 0 | return 0; |
1298 | | |
1299 | 0 | if (!o_context->dtls.ssl) { |
1300 | | /* This is set up to handle new incoming sessions to a server */ |
1301 | 0 | o_context->dtls.ssl = SSL_new(o_context->dtls.ctx); |
1302 | 0 | if (!o_context->dtls.ssl) |
1303 | 0 | return 0; |
1304 | 0 | bio = BIO_new(o_context->dtls.meth); |
1305 | 0 | if (!bio) { |
1306 | 0 | SSL_free(o_context->dtls.ssl); |
1307 | 0 | o_context->dtls.ssl = NULL; |
1308 | 0 | return 0; |
1309 | 0 | } |
1310 | 0 | SSL_set_bio(o_context->dtls.ssl, bio, bio); |
1311 | 0 | SSL_set_app_data(o_context->dtls.ssl, NULL); |
1312 | 0 | SSL_set_options(o_context->dtls.ssl, SSL_OP_COOKIE_EXCHANGE); |
1313 | 0 | SSL_set_mtu(o_context->dtls.ssl, COAP_DEFAULT_MTU); |
1314 | 0 | } |
1315 | 0 | if (setup_data->ec_jpake) { |
1316 | 0 | coap_log_warn("OpenSSL has no EC-JPAKE support\n"); |
1317 | 0 | } |
1318 | 0 | if (setup_data->use_cid) { |
1319 | 0 | coap_log_warn("OpenSSL has no Connection-ID support\n"); |
1320 | 0 | } |
1321 | 0 | o_context->psk_pki_enabled |= IS_PSK; |
1322 | 0 | return 1; |
1323 | 0 | } |
1324 | | #endif /* COAP_CLIENT_SUPPORT */ |
1325 | | |
1326 | | static int |
1327 | | map_key_type(int asn1_private_key_type |
1328 | 0 | ) { |
1329 | 0 | switch (asn1_private_key_type) { |
1330 | 0 | case COAP_ASN1_PKEY_NONE: |
1331 | 0 | return EVP_PKEY_NONE; |
1332 | 0 | case COAP_ASN1_PKEY_RSA: |
1333 | 0 | return EVP_PKEY_RSA; |
1334 | 0 | case COAP_ASN1_PKEY_RSA2: |
1335 | 0 | return EVP_PKEY_RSA2; |
1336 | 0 | case COAP_ASN1_PKEY_DSA: |
1337 | 0 | return EVP_PKEY_DSA; |
1338 | 0 | case COAP_ASN1_PKEY_DSA1: |
1339 | 0 | return EVP_PKEY_DSA1; |
1340 | 0 | case COAP_ASN1_PKEY_DSA2: |
1341 | 0 | return EVP_PKEY_DSA2; |
1342 | 0 | case COAP_ASN1_PKEY_DSA3: |
1343 | 0 | return EVP_PKEY_DSA3; |
1344 | 0 | case COAP_ASN1_PKEY_DSA4: |
1345 | 0 | return EVP_PKEY_DSA4; |
1346 | 0 | case COAP_ASN1_PKEY_DH: |
1347 | 0 | return EVP_PKEY_DH; |
1348 | 0 | case COAP_ASN1_PKEY_DHX: |
1349 | 0 | return EVP_PKEY_DHX; |
1350 | 0 | case COAP_ASN1_PKEY_EC: |
1351 | 0 | return EVP_PKEY_EC; |
1352 | 0 | case COAP_ASN1_PKEY_HMAC: |
1353 | 0 | return EVP_PKEY_HMAC; |
1354 | 0 | case COAP_ASN1_PKEY_CMAC: |
1355 | 0 | return EVP_PKEY_CMAC; |
1356 | 0 | case COAP_ASN1_PKEY_TLS1_PRF: |
1357 | 0 | return EVP_PKEY_TLS1_PRF; |
1358 | 0 | case COAP_ASN1_PKEY_HKDF: |
1359 | 0 | return EVP_PKEY_HKDF; |
1360 | 0 | default: |
1361 | 0 | coap_log_warn("*** setup_pki: DTLS: Unknown Private Key type %d for ASN1\n", |
1362 | 0 | asn1_private_key_type); |
1363 | 0 | break; |
1364 | 0 | } |
1365 | 0 | return 0; |
1366 | 0 | } |
1367 | | #if !COAP_DISABLE_TCP |
1368 | | static uint8_t coap_alpn[] = { 4, 'c', 'o', 'a', 'p' }; |
1369 | | |
1370 | | #if COAP_SERVER_SUPPORT |
1371 | | static int |
1372 | | server_alpn_callback(SSL *ssl COAP_UNUSED, |
1373 | | const unsigned char **out, |
1374 | | unsigned char *outlen, |
1375 | | const unsigned char *in, |
1376 | | unsigned int inlen, |
1377 | | void *arg COAP_UNUSED |
1378 | 0 | ) { |
1379 | 0 | unsigned char *tout = NULL; |
1380 | 0 | int ret; |
1381 | 0 | if (inlen == 0) |
1382 | 0 | return SSL_TLSEXT_ERR_NOACK; |
1383 | 0 | ret = SSL_select_next_proto(&tout, |
1384 | 0 | outlen, |
1385 | 0 | coap_alpn, |
1386 | 0 | sizeof(coap_alpn), |
1387 | 0 | in, |
1388 | 0 | inlen); |
1389 | 0 | *out = tout; |
1390 | 0 | return (ret != OPENSSL_NPN_NEGOTIATED) ? SSL_TLSEXT_ERR_NOACK : SSL_TLSEXT_ERR_OK; |
1391 | 0 | } |
1392 | | #endif /* COAP_SERVER_SUPPORT */ |
1393 | | #endif /* !COAP_DISABLE_TCP */ |
1394 | | |
1395 | | static void |
1396 | 0 | add_ca_to_cert_store(X509_STORE *st, X509 *x509) { |
1397 | 0 | long e; |
1398 | | |
1399 | | /* Flush out existing errors */ |
1400 | 0 | while (ERR_get_error() != 0) { |
1401 | 0 | } |
1402 | |
|
1403 | 0 | if (!X509_STORE_add_cert(st, x509)) { |
1404 | 0 | while ((e = ERR_get_error()) != 0) { |
1405 | 0 | int r = ERR_GET_REASON(e); |
1406 | 0 | if (r != X509_R_CERT_ALREADY_IN_HASH_TABLE) { |
1407 | | /* Not already added */ |
1408 | 0 | coap_log_warn("***setup_pki: (D)TLS: %s%s\n", |
1409 | 0 | ERR_reason_error_string(e), |
1410 | 0 | ssl_function_definition(e)); |
1411 | 0 | } |
1412 | 0 | } |
1413 | 0 | } |
1414 | 0 | } |
1415 | | |
1416 | | static X509 * |
1417 | 0 | missing_ENGINE_load_cert(ENGINE *engine, const char *cert_id) { |
1418 | 0 | struct { |
1419 | 0 | const char *cert_id; |
1420 | 0 | X509 *cert; |
1421 | 0 | } params; |
1422 | |
|
1423 | 0 | params.cert_id = cert_id; |
1424 | 0 | params.cert = NULL; |
1425 | | |
1426 | | /* There is no ENGINE_load_cert() */ |
1427 | 0 | if (!ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) { |
1428 | 0 | params.cert = NULL; |
1429 | 0 | } |
1430 | 0 | return params.cert; |
1431 | 0 | } |
1432 | | |
1433 | | static int |
1434 | 0 | check_pkcs11_engine(void) { |
1435 | 0 | static int already_tried = 0; |
1436 | |
|
1437 | 0 | if (already_tried) |
1438 | 0 | return 0; |
1439 | | |
1440 | 0 | if (!pkcs11_engine) { |
1441 | 0 | pkcs11_engine = ENGINE_by_id(COAP_OPENSSL_PKCS11_ENGINE_ID); |
1442 | 0 | if (!pkcs11_engine) { |
1443 | 0 | coap_log_err("*** setup_pki: (D)TLS: No PKCS11 support - need OpenSSL %s engine\n", |
1444 | 0 | COAP_OPENSSL_PKCS11_ENGINE_ID); |
1445 | 0 | already_tried = 1; |
1446 | 0 | return 0; |
1447 | 0 | } |
1448 | 0 | if (!ENGINE_init(pkcs11_engine)) { |
1449 | | /* the engine couldn't initialise, release 'pkcs11_engine' */ |
1450 | 0 | ENGINE_free(pkcs11_engine); |
1451 | 0 | pkcs11_engine = NULL; |
1452 | 0 | coap_log_err("*** setup_pki: (D)TLS: PKCS11 engine initialize failed\n"); |
1453 | 0 | already_tried = 1; |
1454 | 0 | return 0; |
1455 | 0 | } |
1456 | | /* |
1457 | | * ENGINE_init() returned a functional reference, so free the structural |
1458 | | * reference from ENGINE_by_id(). |
1459 | | */ |
1460 | 0 | ENGINE_free(pkcs11_engine); |
1461 | 0 | } |
1462 | 0 | return 1; |
1463 | 0 | } |
1464 | | |
1465 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L && COAP_SERVER_SUPPORT |
1466 | | |
1467 | | static int |
1468 | | install_engine_public_cert_ctx(ENGINE *engine, SSL_CTX *ctx, |
1469 | | const char *public_cert) { |
1470 | | X509 *x509; |
1471 | | |
1472 | | x509 = missing_ENGINE_load_cert(engine, public_cert); |
1473 | | if (!x509) { |
1474 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1475 | | "%s Certificate\n", |
1476 | | public_cert, |
1477 | | "Server"); |
1478 | | return 0; |
1479 | | } |
1480 | | if (!SSL_CTX_use_certificate(ctx, x509)) { |
1481 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1482 | | "%s Certificate\n", |
1483 | | public_cert, |
1484 | | "Server"); |
1485 | | X509_free(x509); |
1486 | | return 0; |
1487 | | } |
1488 | | X509_free(x509); |
1489 | | return 1; |
1490 | | } |
1491 | | |
1492 | | static int |
1493 | | install_engine_private_key_ctx(ENGINE *engine, SSL_CTX *ctx, |
1494 | | const char *private_key) { |
1495 | | EVP_PKEY *pkey = ENGINE_load_private_key(engine, |
1496 | | private_key, |
1497 | | NULL, NULL); |
1498 | | |
1499 | | if (!pkey) { |
1500 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1501 | | "%s Private Key\n", |
1502 | | private_key, |
1503 | | "Server"); |
1504 | | return 0; |
1505 | | } |
1506 | | if (!SSL_CTX_use_PrivateKey(ctx, pkey)) { |
1507 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1508 | | "%s Private Key\n", |
1509 | | private_key, |
1510 | | "Server"); |
1511 | | EVP_PKEY_free(pkey); |
1512 | | return 0; |
1513 | | } |
1514 | | EVP_PKEY_free(pkey); |
1515 | | return 1; |
1516 | | } |
1517 | | |
1518 | | static int |
1519 | | install_engine_ca_ctx(ENGINE *engine, SSL_CTX *ctx, const char *ca) { |
1520 | | X509 *x509; |
1521 | | X509_STORE *st; |
1522 | | |
1523 | | x509 = missing_ENGINE_load_cert(engine, |
1524 | | ca); |
1525 | | if (!x509) { |
1526 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1527 | | "%s CA Certificate\n", |
1528 | | ca, |
1529 | | "Server"); |
1530 | | return 0; |
1531 | | } |
1532 | | if (!SSL_CTX_add_client_CA(ctx, x509)) { |
1533 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1534 | | "%s CA Certificate\n", |
1535 | | ca, |
1536 | | "Server"); |
1537 | | X509_free(x509); |
1538 | | return 0; |
1539 | | } |
1540 | | st = SSL_CTX_get_cert_store(ctx); |
1541 | | add_ca_to_cert_store(st, x509); |
1542 | | X509_free(x509); |
1543 | | return 1; |
1544 | | } |
1545 | | |
1546 | | static int |
1547 | | load_in_cas_ctx(SSL_CTX *ctx, |
1548 | | const char *ca_file) { |
1549 | | STACK_OF(X509_NAME) *cert_names; |
1550 | | X509_STORE *st; |
1551 | | BIO *in; |
1552 | | X509 *x = NULL; |
1553 | | char *rw_var = NULL; |
1554 | | cert_names = SSL_load_client_CA_file(ca_file); |
1555 | | if (cert_names != NULL) |
1556 | | SSL_CTX_set_client_CA_list(ctx, cert_names); |
1557 | | else { |
1558 | | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1559 | | "client CA File\n", |
1560 | | ca_file); |
1561 | | return 0; |
1562 | | } |
1563 | | |
1564 | | /* Add CA to the trusted root CA store */ |
1565 | | st = SSL_CTX_get_cert_store(ctx); |
1566 | | in = BIO_new(BIO_s_file()); |
1567 | | if (!in) |
1568 | | return 0; |
1569 | | /* Need to do this to not get a compiler warning about const parameters */ |
1570 | | memcpy(&rw_var, &ca_file, sizeof(rw_var)); |
1571 | | if (!BIO_read_filename(in, rw_var)) { |
1572 | | BIO_free(in); |
1573 | | return 0; |
1574 | | } |
1575 | | |
1576 | | for (;;) { |
1577 | | if ((x = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) |
1578 | | break; |
1579 | | add_ca_to_cert_store(st, x); |
1580 | | X509_free(x); |
1581 | | } |
1582 | | BIO_free(in); |
1583 | | return 1; |
1584 | | } |
1585 | | |
1586 | | static int |
1587 | | setup_pki_server(SSL_CTX *ctx, |
1588 | | const coap_dtls_pki_t *setup_data) { |
1589 | | coap_dtls_key_t key; |
1590 | | |
1591 | | /* Map over to the new define format to save code duplication */ |
1592 | | coap_dtls_map_key_type_to_define(setup_data, &key); |
1593 | | |
1594 | | assert(key.key_type == COAP_PKI_KEY_DEFINE); |
1595 | | |
1596 | | /* |
1597 | | * Configure the Private Key |
1598 | | */ |
1599 | | if (key.key.define.private_key.u_byte && |
1600 | | key.key.define.private_key.u_byte[0]) { |
1601 | | switch (key.key.define.private_key_def) { |
1602 | | case COAP_PKI_KEY_DEF_PEM: /* define private key */ |
1603 | | if (!(SSL_CTX_use_PrivateKey_file(ctx, |
1604 | | key.key.define.private_key.s_byte, |
1605 | | SSL_FILETYPE_PEM))) { |
1606 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1607 | | COAP_DEFINE_FAIL_BAD, |
1608 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1609 | | } |
1610 | | break; |
1611 | | case COAP_PKI_KEY_DEF_PEM_BUF: /* define private key */ |
1612 | | if (key.key.define.private_key_len) { |
1613 | | BIO *bp = BIO_new_mem_buf(key.key.define.private_key.u_byte, |
1614 | | (int)key.key.define.private_key_len); |
1615 | | EVP_PKEY *pkey = bp ? PEM_read_bio_PrivateKey(bp, NULL, 0, NULL) : NULL; |
1616 | | |
1617 | | if (!pkey || !SSL_CTX_use_PrivateKey(ctx, pkey)) { |
1618 | | if (bp) |
1619 | | BIO_free(bp); |
1620 | | if (pkey) |
1621 | | EVP_PKEY_free(pkey); |
1622 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1623 | | COAP_DEFINE_FAIL_BAD, |
1624 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1625 | | } |
1626 | | if (bp) |
1627 | | BIO_free(bp); |
1628 | | if (pkey) |
1629 | | EVP_PKEY_free(pkey); |
1630 | | } else { |
1631 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1632 | | COAP_DEFINE_FAIL_NONE, |
1633 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1634 | | } |
1635 | | break; |
1636 | | case COAP_PKI_KEY_DEF_RPK_BUF: /* define private key */ |
1637 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1638 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1639 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1640 | | case COAP_PKI_KEY_DEF_DER: /* define private key */ |
1641 | | if (!(SSL_CTX_use_PrivateKey_file(ctx, |
1642 | | key.key.define.private_key.s_byte, |
1643 | | SSL_FILETYPE_ASN1))) { |
1644 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1645 | | COAP_DEFINE_FAIL_BAD, |
1646 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1647 | | } |
1648 | | break; |
1649 | | case COAP_PKI_KEY_DEF_DER_BUF: /* define private key */ |
1650 | | if (key.key.define.private_key_len == 0 || |
1651 | | !(SSL_CTX_use_PrivateKey_ASN1(map_key_type(key.key.define.private_key_type), |
1652 | | ctx, |
1653 | | key.key.define.private_key.u_byte, |
1654 | | (long)key.key.define.private_key_len))) { |
1655 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1656 | | COAP_DEFINE_FAIL_BAD, |
1657 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1658 | | } |
1659 | | break; |
1660 | | case COAP_PKI_KEY_DEF_PKCS11: /* define private key */ |
1661 | | if (!check_pkcs11_engine()) { |
1662 | | return 0; |
1663 | | } |
1664 | | if (key.key.define.user_pin) { |
1665 | | /* If not set, pin-value may be held in pkcs11: URI */ |
1666 | | if (ENGINE_ctrl_cmd_string(pkcs11_engine, |
1667 | | "PIN", |
1668 | | key.key.define.user_pin, 0) == 0) { |
1669 | | coap_log_warn("*** setup_pki: (D)TLS: PKCS11: %s: Unable to set pin\n", |
1670 | | key.key.define.user_pin); |
1671 | | return 0; |
1672 | | } |
1673 | | } |
1674 | | if (!install_engine_private_key_ctx(pkcs11_engine, ctx, |
1675 | | key.key.define.private_key.s_byte)) { |
1676 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1677 | | COAP_DEFINE_FAIL_BAD, |
1678 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1679 | | } |
1680 | | break; |
1681 | | case COAP_PKI_KEY_DEF_ENGINE: /* define private key */ |
1682 | | if (!defined_engine || |
1683 | | !install_engine_private_key_ctx(defined_engine, ctx, |
1684 | | key.key.define.private_key.s_byte)) { |
1685 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1686 | | COAP_DEFINE_FAIL_BAD, |
1687 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1688 | | } |
1689 | | break; |
1690 | | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define private key */ |
1691 | | default: |
1692 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1693 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1694 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1695 | | } |
1696 | | } else if (key.key.define.public_cert.u_byte && key.key.define.public_cert.u_byte[0]) { |
1697 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
1698 | | COAP_DEFINE_FAIL_NONE, |
1699 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1700 | | } |
1701 | | |
1702 | | /* |
1703 | | * Configure the Public Certificate / Key |
1704 | | * OpenSSL < 1.1.1 and Server |
1705 | | */ |
1706 | | if (key.key.define.public_cert.u_byte && |
1707 | | key.key.define.public_cert.u_byte[0]) { |
1708 | | switch (key.key.define.public_cert_def) { |
1709 | | case COAP_PKI_KEY_DEF_PEM: /* define public cert */ |
1710 | | if (key.key.define.ca.u_byte && |
1711 | | key.key.define.ca.u_byte[0]) { |
1712 | | if (!(SSL_CTX_use_certificate_file(ctx, |
1713 | | key.key.define.public_cert.s_byte, |
1714 | | SSL_FILETYPE_PEM))) { |
1715 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1716 | | COAP_DEFINE_FAIL_BAD, |
1717 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1718 | | } |
1719 | | } else { |
1720 | | if (!SSL_CTX_use_certificate_chain_file(ctx, |
1721 | | key.key.define.public_cert.s_byte)) { |
1722 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1723 | | COAP_DEFINE_FAIL_BAD, |
1724 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1725 | | } |
1726 | | } |
1727 | | break; |
1728 | | case COAP_PKI_KEY_DEF_PEM_BUF: /* define public cert */ |
1729 | | if (key.key.define.public_cert_len) { |
1730 | | BIO *bp = BIO_new_mem_buf(key.key.define.public_cert.u_byte, |
1731 | | (int)key.key.define.public_cert_len); |
1732 | | X509 *cert = bp ? PEM_read_bio_X509(bp, NULL, 0, NULL) : NULL; |
1733 | | |
1734 | | if (!cert || !SSL_CTX_use_certificate(ctx, cert)) { |
1735 | | if (bp) |
1736 | | BIO_free(bp); |
1737 | | if (cert) |
1738 | | X509_free(cert); |
1739 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1740 | | COAP_DEFINE_FAIL_BAD, |
1741 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1742 | | } |
1743 | | if (bp) |
1744 | | BIO_free(bp); |
1745 | | if (cert) |
1746 | | X509_free(cert); |
1747 | | } else { |
1748 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1749 | | COAP_DEFINE_FAIL_BAD, |
1750 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1751 | | } |
1752 | | break; |
1753 | | case COAP_PKI_KEY_DEF_RPK_BUF: /* define public cert */ |
1754 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1755 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1756 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1757 | | case COAP_PKI_KEY_DEF_DER: /* define public cert */ |
1758 | | if (!(SSL_CTX_use_certificate_file(ctx, |
1759 | | key.key.define.public_cert.s_byte, |
1760 | | SSL_FILETYPE_ASN1))) { |
1761 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1762 | | COAP_DEFINE_FAIL_BAD, |
1763 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1764 | | } |
1765 | | break; |
1766 | | case COAP_PKI_KEY_DEF_DER_BUF: /* define public cert */ |
1767 | | if (key.key.define.public_cert_len == 0 || |
1768 | | !(SSL_CTX_use_certificate_ASN1(ctx, |
1769 | | (int)key.key.define.public_cert_len, |
1770 | | key.key.define.public_cert.u_byte))) { |
1771 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1772 | | COAP_DEFINE_FAIL_BAD, |
1773 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1774 | | } |
1775 | | break; |
1776 | | case COAP_PKI_KEY_DEF_PKCS11: /* define public cert */ |
1777 | | if (!check_pkcs11_engine()) { |
1778 | | return 0; |
1779 | | } |
1780 | | if (!install_engine_public_cert_ctx(pkcs11_engine, ctx, |
1781 | | key.key.define.public_cert.s_byte)) { |
1782 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1783 | | COAP_DEFINE_FAIL_BAD, |
1784 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1785 | | } |
1786 | | break; |
1787 | | case COAP_PKI_KEY_DEF_ENGINE: /* define public cert */ |
1788 | | if (!defined_engine || |
1789 | | !install_engine_public_cert_ctx(defined_engine, ctx, |
1790 | | key.key.define.public_cert.s_byte)) { |
1791 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1792 | | COAP_DEFINE_FAIL_BAD, |
1793 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1794 | | } |
1795 | | break; |
1796 | | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define public cert */ |
1797 | | default: |
1798 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1799 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1800 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1801 | | } |
1802 | | } else if (key.key.define.private_key.u_byte && |
1803 | | key.key.define.private_key.u_byte[0]) { |
1804 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
1805 | | COAP_DEFINE_FAIL_NONE, |
1806 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1807 | | } |
1808 | | |
1809 | | /* |
1810 | | * Configure the CA |
1811 | | */ |
1812 | | if (key.key.define.ca.u_byte && |
1813 | | key.key.define.ca.u_byte[0]) { |
1814 | | switch (key.key.define.ca_def) { |
1815 | | case COAP_PKI_KEY_DEF_PEM: |
1816 | | if (!load_in_cas_ctx(ctx, key.key.define.ca.s_byte)) { |
1817 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1818 | | COAP_DEFINE_FAIL_BAD, |
1819 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1820 | | } |
1821 | | break; |
1822 | | case COAP_PKI_KEY_DEF_PEM_BUF: /* define ca */ |
1823 | | if (key.key.define.ca_len) { |
1824 | | BIO *bp = BIO_new_mem_buf(key.key.define.ca.s_byte, |
1825 | | (int)key.key.define.ca_len); |
1826 | | X509 *x; |
1827 | | X509_STORE *st = SSL_CTX_get_cert_store(ctx); |
1828 | | |
1829 | | if (bp) { |
1830 | | for (;;) { |
1831 | | if ((x = PEM_read_bio_X509(bp, NULL, NULL, NULL)) == NULL) |
1832 | | break; |
1833 | | add_ca_to_cert_store(st, x); |
1834 | | SSL_CTX_add_client_CA(ctx, x); |
1835 | | X509_free(x); |
1836 | | } |
1837 | | BIO_free(bp); |
1838 | | } |
1839 | | } else { |
1840 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1841 | | COAP_DEFINE_FAIL_BAD, |
1842 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1843 | | } |
1844 | | break; |
1845 | | case COAP_PKI_KEY_DEF_RPK_BUF: /* define ca */ |
1846 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1847 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1848 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1849 | | case COAP_PKI_KEY_DEF_DER: /* define ca */ |
1850 | | if (!(SSL_CTX_use_certificate_file(ctx, |
1851 | | key.key.define.ca.s_byte, |
1852 | | SSL_FILETYPE_ASN1))) { |
1853 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1854 | | COAP_DEFINE_FAIL_BAD, |
1855 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1856 | | } |
1857 | | break; |
1858 | | case COAP_PKI_KEY_DEF_DER_BUF: /* define ca */ |
1859 | | if (key.key.define.ca_len > 0) { |
1860 | | /* Need to use a temp variable as it gets incremented*/ |
1861 | | const uint8_t *p = key.key.define.ca.u_byte; |
1862 | | X509 *x509 = d2i_X509(NULL, &p, (long)key.key.define.ca_len); |
1863 | | X509_STORE *st; |
1864 | | |
1865 | | if (!x509 || !SSL_CTX_add_client_CA(ctx, x509)) { |
1866 | | X509_free(x509); |
1867 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1868 | | COAP_DEFINE_FAIL_BAD, |
1869 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1870 | | } |
1871 | | |
1872 | | /* Add CA to the trusted root CA store */ |
1873 | | st = SSL_CTX_get_cert_store(ctx); |
1874 | | add_ca_to_cert_store(st, x509); |
1875 | | X509_free(x509); |
1876 | | } |
1877 | | break; |
1878 | | case COAP_PKI_KEY_DEF_PKCS11: /* define ca */ |
1879 | | if (!check_pkcs11_engine()) { |
1880 | | return 0; |
1881 | | } |
1882 | | if (!install_engine_ca_ctx(pkcs11_engine, ctx, |
1883 | | key.key.define.ca.s_byte)) { |
1884 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1885 | | COAP_DEFINE_FAIL_BAD, |
1886 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1887 | | } |
1888 | | break; |
1889 | | case COAP_PKI_KEY_DEF_ENGINE: /* define ca */ |
1890 | | if (!defined_engine || |
1891 | | !install_engine_ca_ctx(defined_engine, ctx, |
1892 | | key.key.define.ca.s_byte)) { |
1893 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1894 | | COAP_DEFINE_FAIL_BAD, |
1895 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1896 | | } |
1897 | | break; |
1898 | | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define ca */ |
1899 | | default: |
1900 | | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
1901 | | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
1902 | | &key, COAP_DTLS_ROLE_SERVER, 0); |
1903 | | } |
1904 | | } |
1905 | | |
1906 | | return 1; |
1907 | | } |
1908 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
1909 | | |
1910 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L || COAP_CLIENT_SUPPORT |
1911 | | |
1912 | | static int |
1913 | | install_engine_public_cert(ENGINE *engine, SSL *ssl, const char *public_cert, |
1914 | 0 | coap_dtls_role_t role) { |
1915 | 0 | X509 *x509; |
1916 | |
|
1917 | 0 | x509 = missing_ENGINE_load_cert(engine, public_cert); |
1918 | 0 | if (!x509) { |
1919 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1920 | 0 | "%s Certificate\n", |
1921 | 0 | public_cert, |
1922 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1923 | 0 | return 0; |
1924 | 0 | } |
1925 | 0 | if (!SSL_use_certificate(ssl, x509)) { |
1926 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1927 | 0 | "%s Certificate\n", |
1928 | 0 | public_cert, |
1929 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1930 | 0 | X509_free(x509); |
1931 | 0 | return 0; |
1932 | 0 | } |
1933 | 0 | X509_free(x509); |
1934 | 0 | return 1; |
1935 | 0 | } |
1936 | | |
1937 | | static int |
1938 | | install_engine_private_key(ENGINE *engine, SSL *ssl, const char *private_key, |
1939 | 0 | coap_dtls_role_t role) { |
1940 | 0 | EVP_PKEY *pkey = ENGINE_load_private_key(engine, |
1941 | 0 | private_key, |
1942 | 0 | NULL, NULL); |
1943 | |
|
1944 | 0 | if (!pkey) { |
1945 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1946 | 0 | "%s Private Key\n", |
1947 | 0 | private_key, |
1948 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1949 | 0 | return 0; |
1950 | 0 | } |
1951 | 0 | if (!SSL_use_PrivateKey(ssl, pkey)) { |
1952 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1953 | 0 | "%s Private Key\n", |
1954 | 0 | private_key, |
1955 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1956 | 0 | EVP_PKEY_free(pkey); |
1957 | 0 | return 0; |
1958 | 0 | } |
1959 | 0 | EVP_PKEY_free(pkey); |
1960 | 0 | return 1; |
1961 | 0 | } |
1962 | | |
1963 | | static int |
1964 | | install_engine_ca(ENGINE *engine, SSL *ssl, const char *ca, |
1965 | 0 | coap_dtls_role_t role) { |
1966 | 0 | X509 *x509; |
1967 | 0 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
1968 | 0 | X509_STORE *st; |
1969 | |
|
1970 | 0 | if (!ctx) { |
1971 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1972 | 0 | "%s CA Certificate (no ctx)\n", |
1973 | 0 | ca, |
1974 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1975 | 0 | return 0; |
1976 | 0 | } |
1977 | 0 | x509 = missing_ENGINE_load_cert(engine, |
1978 | 0 | ca); |
1979 | 0 | if (!x509) { |
1980 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " |
1981 | 0 | "%s CA Certificate\n", |
1982 | 0 | ca, |
1983 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1984 | 0 | return 0; |
1985 | 0 | } |
1986 | 0 | if (!SSL_add_client_CA(ssl, x509)) { |
1987 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to configure " |
1988 | 0 | "%s CA Certificate\n", |
1989 | 0 | ca, |
1990 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
1991 | 0 | X509_free(x509); |
1992 | 0 | return 0; |
1993 | 0 | } |
1994 | 0 | st = SSL_CTX_get_cert_store(ctx); |
1995 | 0 | add_ca_to_cert_store(st, x509); |
1996 | 0 | X509_free(x509); |
1997 | 0 | return 1; |
1998 | 0 | } |
1999 | | |
2000 | | static int |
2001 | | load_in_cas(SSL *ssl, |
2002 | 0 | const char *ca_file, coap_dtls_role_t role) { |
2003 | 0 | X509_STORE *st; |
2004 | 0 | BIO *in; |
2005 | 0 | X509 *x = NULL; |
2006 | 0 | char *rw_var = NULL; |
2007 | 0 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
2008 | |
|
2009 | 0 | if (role == COAP_DTLS_ROLE_SERVER) { |
2010 | 0 | STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(ca_file); |
2011 | |
|
2012 | 0 | if (cert_names != NULL) |
2013 | 0 | SSL_set_client_CA_list(ssl, cert_names); |
2014 | 0 | else { |
2015 | 0 | return 0; |
2016 | 0 | } |
2017 | 0 | } |
2018 | | |
2019 | 0 | if (!ctx) |
2020 | 0 | return 0; |
2021 | | |
2022 | | /* Add CA to the trusted root CA store */ |
2023 | 0 | in = BIO_new(BIO_s_file()); |
2024 | 0 | if (!in) |
2025 | 0 | return 0; |
2026 | | /* Need to do this to not get a compiler warning about const parameters */ |
2027 | 0 | memcpy(&rw_var, &ca_file, sizeof(rw_var)); |
2028 | 0 | if (!BIO_read_filename(in, rw_var)) { |
2029 | 0 | BIO_free(in); |
2030 | 0 | return 0; |
2031 | 0 | } |
2032 | 0 | st = SSL_CTX_get_cert_store(ctx); |
2033 | 0 | for (;;) { |
2034 | 0 | if ((x = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) |
2035 | 0 | break; |
2036 | 0 | add_ca_to_cert_store(st, x); |
2037 | 0 | X509_free(x); |
2038 | 0 | } |
2039 | 0 | BIO_free(in); |
2040 | 0 | return 1; |
2041 | 0 | } |
2042 | | |
2043 | | static int |
2044 | | setup_pki_ssl(SSL *ssl, |
2045 | 0 | coap_dtls_pki_t *setup_data, coap_dtls_role_t role) { |
2046 | 0 | coap_dtls_key_t key; |
2047 | | |
2048 | | /* Map over to the new define format to save code duplication */ |
2049 | 0 | coap_dtls_map_key_type_to_define(setup_data, &key); |
2050 | |
|
2051 | 0 | assert(key.key_type == COAP_PKI_KEY_DEFINE); |
2052 | | |
2053 | | /* |
2054 | | * Configure the Private Key |
2055 | | */ |
2056 | 0 | if (key.key.define.private_key.u_byte && |
2057 | 0 | key.key.define.private_key.u_byte[0]) { |
2058 | 0 | switch (key.key.define.private_key_def) { |
2059 | 0 | case COAP_PKI_KEY_DEF_PEM: /* define private key */ |
2060 | 0 | if (!(SSL_use_PrivateKey_file(ssl, |
2061 | 0 | key.key.define.private_key.s_byte, |
2062 | 0 | SSL_FILETYPE_PEM))) { |
2063 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2064 | 0 | COAP_DEFINE_FAIL_BAD, |
2065 | 0 | &key, role, 0); |
2066 | 0 | } |
2067 | 0 | break; |
2068 | 0 | case COAP_PKI_KEY_DEF_PEM_BUF: /* define private key */ |
2069 | 0 | if (key.key.define.private_key_len) { |
2070 | 0 | BIO *bp = BIO_new_mem_buf(key.key.define.private_key.u_byte, |
2071 | 0 | (int)key.key.define.private_key_len); |
2072 | 0 | EVP_PKEY *pkey = bp ? PEM_read_bio_PrivateKey(bp, NULL, 0, NULL) : NULL; |
2073 | |
|
2074 | 0 | if (!pkey || !SSL_use_PrivateKey(ssl, pkey)) { |
2075 | 0 | if (bp) |
2076 | 0 | BIO_free(bp); |
2077 | 0 | if (pkey) |
2078 | 0 | EVP_PKEY_free(pkey); |
2079 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2080 | 0 | COAP_DEFINE_FAIL_BAD, |
2081 | 0 | &key, role, 0); |
2082 | 0 | } |
2083 | 0 | if (bp) |
2084 | 0 | BIO_free(bp); |
2085 | 0 | if (pkey) |
2086 | 0 | EVP_PKEY_free(pkey); |
2087 | 0 | } else { |
2088 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2089 | 0 | COAP_DEFINE_FAIL_NONE, |
2090 | 0 | &key, role, 0); |
2091 | 0 | } |
2092 | 0 | break; |
2093 | 0 | case COAP_PKI_KEY_DEF_RPK_BUF: /* define private key */ |
2094 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2095 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2096 | 0 | &key, role, 0); |
2097 | 0 | case COAP_PKI_KEY_DEF_DER: /* define private key */ |
2098 | 0 | if (!(SSL_use_PrivateKey_file(ssl, |
2099 | 0 | key.key.define.private_key.s_byte, |
2100 | 0 | SSL_FILETYPE_ASN1))) { |
2101 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2102 | 0 | COAP_DEFINE_FAIL_BAD, |
2103 | 0 | &key, role, 0); |
2104 | 0 | } |
2105 | 0 | break; |
2106 | 0 | case COAP_PKI_KEY_DEF_DER_BUF: /* define private key */ |
2107 | 0 | if (key.key.define.private_key_len == 0 || |
2108 | 0 | !(SSL_use_PrivateKey_ASN1(map_key_type(key.key.define.private_key_type), |
2109 | 0 | ssl, |
2110 | 0 | key.key.define.private_key.u_byte, |
2111 | 0 | (long)key.key.define.private_key_len))) { |
2112 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2113 | 0 | COAP_DEFINE_FAIL_BAD, |
2114 | 0 | &key, role, 0); |
2115 | 0 | } |
2116 | 0 | break; |
2117 | 0 | case COAP_PKI_KEY_DEF_PKCS11: /* define private key */ |
2118 | 0 | if (!check_pkcs11_engine()) { |
2119 | 0 | return 0; |
2120 | 0 | } |
2121 | 0 | if (key.key.define.user_pin) { |
2122 | | /* If not set, pin-value may be held in pkcs11: URI */ |
2123 | 0 | if (ENGINE_ctrl_cmd_string(pkcs11_engine, |
2124 | 0 | "PIN", |
2125 | 0 | key.key.define.user_pin, 0) == 0) { |
2126 | 0 | coap_log_warn("*** setup_pki: (D)TLS: PKCS11: %s: Unable to set pin\n", |
2127 | 0 | key.key.define.user_pin); |
2128 | 0 | return 0; |
2129 | 0 | } |
2130 | 0 | } |
2131 | 0 | if (!install_engine_private_key(pkcs11_engine, ssl, |
2132 | 0 | key.key.define.private_key.s_byte, |
2133 | 0 | role)) { |
2134 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2135 | 0 | COAP_DEFINE_FAIL_BAD, |
2136 | 0 | &key, role, 0); |
2137 | 0 | } |
2138 | 0 | break; |
2139 | 0 | case COAP_PKI_KEY_DEF_ENGINE: /* define private key */ |
2140 | 0 | if (!defined_engine || |
2141 | 0 | !install_engine_private_key(defined_engine, ssl, |
2142 | 0 | key.key.define.private_key.s_byte, |
2143 | 0 | role)) { |
2144 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2145 | 0 | COAP_DEFINE_FAIL_BAD, |
2146 | 0 | &key, role, 0); |
2147 | 0 | } |
2148 | 0 | break; |
2149 | 0 | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define private key */ |
2150 | 0 | default: |
2151 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2152 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2153 | 0 | &key, role, 0); |
2154 | 0 | } |
2155 | 0 | } else if (role == COAP_DTLS_ROLE_SERVER || |
2156 | 0 | (key.key.define.public_cert.u_byte && |
2157 | 0 | key.key.define.public_cert.u_byte[0])) { |
2158 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PRIVATE, |
2159 | 0 | COAP_DEFINE_FAIL_NONE, |
2160 | 0 | &key, role, 0); |
2161 | 0 | } |
2162 | | |
2163 | | /* |
2164 | | * Configure the Public Certificate / Key |
2165 | | */ |
2166 | 0 | if (key.key.define.public_cert.u_byte && |
2167 | 0 | key.key.define.public_cert.u_byte[0]) { |
2168 | 0 | switch (key.key.define.public_cert_def) { |
2169 | 0 | case COAP_PKI_KEY_DEF_PEM: /* define public cert */ |
2170 | 0 | if (key.key.define.ca.u_byte && |
2171 | 0 | key.key.define.ca.u_byte[0]) { |
2172 | | /* If CA is separately defined */ |
2173 | 0 | if (!(SSL_use_certificate_file(ssl, |
2174 | 0 | key.key.define.public_cert.s_byte, |
2175 | 0 | SSL_FILETYPE_PEM))) { |
2176 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2177 | 0 | COAP_DEFINE_FAIL_BAD, |
2178 | 0 | &key, role, 0); |
2179 | 0 | } |
2180 | 0 | } else { |
2181 | 0 | if (!SSL_use_certificate_chain_file(ssl, |
2182 | 0 | key.key.define.public_cert.s_byte)) { |
2183 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2184 | 0 | COAP_DEFINE_FAIL_BAD, |
2185 | 0 | &key, role, 0); |
2186 | 0 | } |
2187 | 0 | } |
2188 | 0 | break; |
2189 | 0 | case COAP_PKI_KEY_DEF_PEM_BUF: /* define public cert */ |
2190 | 0 | if (key.key.define.public_cert_len) { |
2191 | 0 | BIO *bp = BIO_new_mem_buf(key.key.define.public_cert.s_byte, |
2192 | 0 | (int)key.key.define.public_cert_len); |
2193 | 0 | X509 *cert = bp ? PEM_read_bio_X509(bp, NULL, 0, NULL) : NULL; |
2194 | |
|
2195 | 0 | if (!cert || !SSL_use_certificate(ssl, cert)) { |
2196 | 0 | if (bp) |
2197 | 0 | BIO_free(bp); |
2198 | 0 | if (cert) |
2199 | 0 | X509_free(cert); |
2200 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2201 | 0 | COAP_DEFINE_FAIL_BAD, |
2202 | 0 | &key, role, 0); |
2203 | 0 | } |
2204 | 0 | if (bp) |
2205 | 0 | BIO_free(bp); |
2206 | 0 | if (cert) |
2207 | 0 | X509_free(cert); |
2208 | 0 | } else { |
2209 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2210 | 0 | COAP_DEFINE_FAIL_BAD, |
2211 | 0 | &key, role, 0); |
2212 | 0 | } |
2213 | 0 | break; |
2214 | 0 | case COAP_PKI_KEY_DEF_RPK_BUF: /* define public cert */ |
2215 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2216 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2217 | 0 | &key, role, 0); |
2218 | 0 | case COAP_PKI_KEY_DEF_DER: /* define public cert */ |
2219 | 0 | if (!(SSL_use_certificate_file(ssl, |
2220 | 0 | key.key.define.public_cert.s_byte, |
2221 | 0 | SSL_FILETYPE_ASN1))) { |
2222 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2223 | 0 | COAP_DEFINE_FAIL_BAD, |
2224 | 0 | &key, role, 0); |
2225 | 0 | } |
2226 | 0 | break; |
2227 | 0 | case COAP_PKI_KEY_DEF_DER_BUF: /* define public cert */ |
2228 | 0 | if (key.key.define.public_cert_len == 0 || |
2229 | 0 | !(SSL_use_certificate_ASN1(ssl, |
2230 | 0 | key.key.define.public_cert.u_byte, |
2231 | 0 | (int)key.key.define.public_cert_len))) { |
2232 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2233 | 0 | COAP_DEFINE_FAIL_BAD, |
2234 | 0 | &key, role, 0); |
2235 | 0 | } |
2236 | 0 | break; |
2237 | 0 | case COAP_PKI_KEY_DEF_PKCS11: /* define public cert */ |
2238 | 0 | if (!check_pkcs11_engine()) { |
2239 | 0 | return 0; |
2240 | 0 | } |
2241 | 0 | if (!install_engine_public_cert(pkcs11_engine, ssl, |
2242 | 0 | key.key.define.public_cert.s_byte, |
2243 | 0 | role)) { |
2244 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2245 | 0 | COAP_DEFINE_FAIL_BAD, |
2246 | 0 | &key, role, 0); |
2247 | 0 | } |
2248 | 0 | break; |
2249 | 0 | case COAP_PKI_KEY_DEF_ENGINE: /* define public cert */ |
2250 | 0 | if (!defined_engine || |
2251 | 0 | !install_engine_public_cert(defined_engine, ssl, |
2252 | 0 | key.key.define.public_cert.s_byte, |
2253 | 0 | role)) { |
2254 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2255 | 0 | COAP_DEFINE_FAIL_BAD, |
2256 | 0 | &key, role, 0); |
2257 | 0 | } |
2258 | 0 | break; |
2259 | 0 | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define public cert */ |
2260 | 0 | default: |
2261 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2262 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2263 | 0 | &key, role, 0); |
2264 | 0 | } |
2265 | 0 | } else if (role == COAP_DTLS_ROLE_SERVER || |
2266 | 0 | (key.key.define.private_key.u_byte && |
2267 | 0 | key.key.define.private_key.u_byte[0])) { |
2268 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_PUBLIC, |
2269 | 0 | COAP_DEFINE_FAIL_NONE, |
2270 | 0 | &key, role, 0); |
2271 | 0 | } |
2272 | | |
2273 | | /* |
2274 | | * Configure the CA |
2275 | | */ |
2276 | 0 | if (key.key.define.ca.u_byte && |
2277 | 0 | key.key.define.ca.u_byte[0]) { |
2278 | 0 | switch (key.key.define.ca_def) { |
2279 | 0 | case COAP_PKI_KEY_DEF_PEM: |
2280 | 0 | if (!load_in_cas(ssl, key.key.define.ca.s_byte, role)) { |
2281 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2282 | 0 | COAP_DEFINE_FAIL_BAD, |
2283 | 0 | &key, role, 0); |
2284 | 0 | } |
2285 | 0 | break; |
2286 | 0 | case COAP_PKI_KEY_DEF_PEM_BUF: /* define ca */ |
2287 | 0 | if (key.key.define.ca_len) { |
2288 | 0 | BIO *bp = BIO_new_mem_buf(key.key.define.ca.u_byte, |
2289 | 0 | (int)key.key.define.ca_len); |
2290 | 0 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
2291 | 0 | X509 *x; |
2292 | 0 | X509_STORE *st = ctx? SSL_CTX_get_cert_store(ctx) : NULL; |
2293 | |
|
2294 | 0 | if (bp) { |
2295 | 0 | for (;;) { |
2296 | 0 | if ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)) == NULL) |
2297 | 0 | break; |
2298 | 0 | if (st) |
2299 | 0 | add_ca_to_cert_store(st, x); |
2300 | 0 | SSL_add_client_CA(ssl, x); |
2301 | 0 | X509_free(x); |
2302 | 0 | } |
2303 | 0 | BIO_free(bp); |
2304 | 0 | } |
2305 | 0 | } else { |
2306 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2307 | 0 | COAP_DEFINE_FAIL_BAD, |
2308 | 0 | &key, role, 0); |
2309 | 0 | } |
2310 | 0 | break; |
2311 | 0 | case COAP_PKI_KEY_DEF_RPK_BUF: /* define ca */ |
2312 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2313 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2314 | 0 | &key, role, 0); |
2315 | 0 | case COAP_PKI_KEY_DEF_DER: /* define ca */ |
2316 | 0 | if (!(SSL_use_certificate_file(ssl, |
2317 | 0 | key.key.define.ca.s_byte, |
2318 | 0 | SSL_FILETYPE_ASN1))) { |
2319 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2320 | 0 | COAP_DEFINE_FAIL_BAD, |
2321 | 0 | &key, role, 0); |
2322 | 0 | } |
2323 | 0 | break; |
2324 | 0 | case COAP_PKI_KEY_DEF_DER_BUF: /* define ca */ |
2325 | 0 | if (key.key.define.ca_len > 0) { |
2326 | | /* Need to use a temp variable as it gets incremented*/ |
2327 | 0 | const uint8_t *p = key.key.define.ca.u_byte; |
2328 | 0 | X509 *x509 = d2i_X509(NULL, &p, (long)key.key.define.ca_len); |
2329 | 0 | X509_STORE *st; |
2330 | 0 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
2331 | |
|
2332 | 0 | if (role == COAP_DTLS_ROLE_SERVER) { |
2333 | 0 | if (!x509 || !SSL_add_client_CA(ssl, x509)) { |
2334 | 0 | X509_free(x509); |
2335 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2336 | 0 | COAP_DEFINE_FAIL_BAD, |
2337 | 0 | &key, role, 0); |
2338 | 0 | } |
2339 | 0 | } |
2340 | | |
2341 | | /* Add CA to the trusted root CA store */ |
2342 | 0 | st = ctx ? SSL_CTX_get_cert_store(ctx) : NULL; |
2343 | 0 | if (st) |
2344 | 0 | add_ca_to_cert_store(st, x509); |
2345 | 0 | X509_free(x509); |
2346 | 0 | } |
2347 | 0 | break; |
2348 | 0 | case COAP_PKI_KEY_DEF_PKCS11: /* define ca */ |
2349 | 0 | if (!check_pkcs11_engine()) { |
2350 | 0 | return 0; |
2351 | 0 | } |
2352 | 0 | if (!install_engine_ca(pkcs11_engine, ssl, |
2353 | 0 | key.key.define.ca.s_byte, |
2354 | 0 | role)) { |
2355 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2356 | 0 | COAP_DEFINE_FAIL_BAD, |
2357 | 0 | &key, role, 0); |
2358 | 0 | } |
2359 | 0 | break; |
2360 | 0 | case COAP_PKI_KEY_DEF_ENGINE: /* define ca */ |
2361 | 0 | if (!defined_engine || |
2362 | 0 | !install_engine_ca(defined_engine, ssl, |
2363 | 0 | key.key.define.ca.s_byte, |
2364 | 0 | role)) { |
2365 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2366 | 0 | COAP_DEFINE_FAIL_BAD, |
2367 | 0 | &key, role, 0); |
2368 | 0 | } |
2369 | 0 | break; |
2370 | 0 | case COAP_PKI_KEY_DEF_PKCS11_RPK: /* define ca */ |
2371 | 0 | default: |
2372 | 0 | return coap_dtls_define_issue(COAP_DEFINE_KEY_CA, |
2373 | 0 | COAP_DEFINE_FAIL_NOT_SUPPORTED, |
2374 | 0 | &key, role, 0); |
2375 | 0 | } |
2376 | 0 | } |
2377 | | |
2378 | 0 | return 1; |
2379 | 0 | } |
2380 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L || COAP_CLIENT_SUPPORT */ |
2381 | | |
2382 | | static char * |
2383 | 0 | get_san_or_cn_from_cert(X509 *x509) { |
2384 | 0 | if (x509) { |
2385 | 0 | char *cn; |
2386 | 0 | int n; |
2387 | 0 | STACK_OF(GENERAL_NAME) *san_list; |
2388 | 0 | char buffer[256]; |
2389 | |
|
2390 | 0 | san_list = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); |
2391 | 0 | if (san_list) { |
2392 | 0 | int san_count = sk_GENERAL_NAME_num(san_list); |
2393 | |
|
2394 | 0 | for (n = 0; n < san_count; n++) { |
2395 | 0 | const GENERAL_NAME *name = sk_GENERAL_NAME_value(san_list, n); |
2396 | |
|
2397 | 0 | if (name && name->type == GEN_DNS) { |
2398 | 0 | const char *dns_name = (const char *)ASN1_STRING_get0_data(name->d.dNSName); |
2399 | | |
2400 | | /* Make sure that there is not an embedded NUL in the dns_name */ |
2401 | 0 | if (ASN1_STRING_length(name->d.dNSName) != (int)strlen(dns_name)) |
2402 | 0 | continue; |
2403 | 0 | cn = OPENSSL_strdup(dns_name); |
2404 | 0 | sk_GENERAL_NAME_pop_free(san_list, GENERAL_NAME_free); |
2405 | 0 | return cn; |
2406 | 0 | } |
2407 | 0 | } |
2408 | 0 | sk_GENERAL_NAME_pop_free(san_list, GENERAL_NAME_free); |
2409 | 0 | } |
2410 | | /* Otherwise look for the CN= field */ |
2411 | 0 | X509_NAME_oneline(X509_get_subject_name(x509), buffer, sizeof(buffer)); |
2412 | | |
2413 | | /* Need to emulate strcasestr() here. Looking for CN= */ |
2414 | 0 | n = (int)strlen(buffer) - 3; |
2415 | 0 | cn = buffer; |
2416 | 0 | while (n > 0) { |
2417 | 0 | if (((cn[0] == 'C') || (cn[0] == 'c')) && |
2418 | 0 | ((cn[1] == 'N') || (cn[1] == 'n')) && |
2419 | 0 | (cn[2] == '=')) { |
2420 | 0 | cn += 3; |
2421 | 0 | break; |
2422 | 0 | } |
2423 | 0 | cn++; |
2424 | 0 | n--; |
2425 | 0 | } |
2426 | 0 | if (n > 0) { |
2427 | 0 | char *ecn = strchr(cn, '/'); |
2428 | 0 | if (ecn) { |
2429 | 0 | return OPENSSL_strndup(cn, ecn-cn); |
2430 | 0 | } else { |
2431 | 0 | return OPENSSL_strdup(cn); |
2432 | 0 | } |
2433 | 0 | } |
2434 | 0 | } |
2435 | 0 | return NULL; |
2436 | 0 | } |
2437 | | |
2438 | | static int |
2439 | 0 | tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) { |
2440 | 0 | int index = SSL_get_ex_data_X509_STORE_CTX_idx(); |
2441 | 0 | SSL *ssl = index >= 0 ? X509_STORE_CTX_get_ex_data(ctx, index) : NULL; |
2442 | 0 | coap_session_t *session = ssl ? SSL_get_app_data(ssl) : NULL; |
2443 | 0 | coap_openssl_context_t *context = (session && session->context) ? |
2444 | 0 | ((coap_openssl_context_t *)session->context->dtls_context) : NULL; |
2445 | 0 | coap_dtls_pki_t *setup_data = context ? &context->setup_data : NULL; |
2446 | 0 | int depth = X509_STORE_CTX_get_error_depth(ctx); |
2447 | 0 | int err = X509_STORE_CTX_get_error(ctx); |
2448 | 0 | X509 *x509 = X509_STORE_CTX_get_current_cert(ctx); |
2449 | 0 | char *cn = x509 ? get_san_or_cn_from_cert(x509) : NULL; |
2450 | 0 | int keep_preverify_ok = preverify_ok; |
2451 | |
|
2452 | 0 | coap_dtls_log(COAP_LOG_DEBUG, "depth %d error %x preverify %d cert '%s'\n", |
2453 | 0 | depth, err, preverify_ok, cn); |
2454 | 0 | if (!setup_data) { |
2455 | 0 | X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNSPECIFIED); |
2456 | 0 | OPENSSL_free(cn); |
2457 | 0 | return 0; |
2458 | 0 | } |
2459 | 0 | if (!preverify_ok) { |
2460 | 0 | switch (err) { |
2461 | 0 | case X509_V_ERR_CERT_NOT_YET_VALID: |
2462 | 0 | case X509_V_ERR_CERT_HAS_EXPIRED: |
2463 | 0 | if (setup_data->allow_expired_certs) |
2464 | 0 | preverify_ok = 1; |
2465 | 0 | break; |
2466 | 0 | case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: |
2467 | 0 | if (setup_data->allow_self_signed && !setup_data->check_common_ca) |
2468 | 0 | preverify_ok = 1; |
2469 | 0 | break; |
2470 | 0 | case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* Set if the CA is not known */ |
2471 | 0 | if (!setup_data->verify_peer_cert) |
2472 | 0 | preverify_ok = 1; |
2473 | 0 | break; |
2474 | 0 | case X509_V_ERR_UNABLE_TO_GET_CRL: |
2475 | 0 | if (setup_data->allow_no_crl) |
2476 | 0 | preverify_ok = 1; |
2477 | 0 | break; |
2478 | 0 | case X509_V_ERR_CRL_NOT_YET_VALID: |
2479 | 0 | case X509_V_ERR_CRL_HAS_EXPIRED: |
2480 | 0 | if (setup_data->allow_expired_crl) |
2481 | 0 | preverify_ok = 1; |
2482 | 0 | break; |
2483 | 0 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: |
2484 | 0 | case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: |
2485 | 0 | case X509_V_ERR_AKID_SKID_MISMATCH: |
2486 | 0 | if (!setup_data->verify_peer_cert) |
2487 | 0 | preverify_ok = 1; |
2488 | 0 | break; |
2489 | 0 | default: |
2490 | 0 | break; |
2491 | 0 | } |
2492 | 0 | if (setup_data->cert_chain_validation && |
2493 | 0 | depth > (setup_data->cert_chain_verify_depth + 1)) { |
2494 | 0 | preverify_ok = 0; |
2495 | 0 | err = X509_V_ERR_CERT_CHAIN_TOO_LONG; |
2496 | 0 | X509_STORE_CTX_set_error(ctx, err); |
2497 | 0 | } |
2498 | 0 | if (!preverify_ok) { |
2499 | 0 | if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { |
2500 | 0 | coap_log_warn(" %s: %s: '%s' depth=%d\n", |
2501 | 0 | coap_session_str(session), |
2502 | 0 | "Unknown CA", cn ? cn : "?", depth); |
2503 | 0 | } else { |
2504 | 0 | coap_log_warn(" %s: %s: '%s' depth=%d\n", |
2505 | 0 | coap_session_str(session), |
2506 | 0 | X509_verify_cert_error_string(err), cn ? cn : "?", depth); |
2507 | 0 | } |
2508 | 0 | } else { |
2509 | 0 | coap_log_info(" %s: %s: overridden: '%s' depth=%d\n", |
2510 | 0 | coap_session_str(session), |
2511 | 0 | X509_verify_cert_error_string(err), cn ? cn : "?", depth); |
2512 | 0 | } |
2513 | 0 | } |
2514 | | /* Certificate - depth == 0 is the Client Cert */ |
2515 | 0 | if (setup_data->validate_cn_call_back && keep_preverify_ok) { |
2516 | 0 | int length = i2d_X509(x509, NULL); |
2517 | 0 | uint8_t *base_buf; |
2518 | 0 | uint8_t *base_buf2 = base_buf = length > 0 ? OPENSSL_malloc(length) : NULL; |
2519 | 0 | int ret; |
2520 | |
|
2521 | 0 | if (base_buf) { |
2522 | | /* base_buf2 gets moved to the end */ |
2523 | 0 | assert(i2d_X509(x509, &base_buf2) > 0); |
2524 | 0 | (void)base_buf2; |
2525 | 0 | coap_lock_callback_ret(ret, |
2526 | 0 | setup_data->validate_cn_call_back(cn, base_buf, length, session, |
2527 | 0 | depth, preverify_ok, |
2528 | 0 | setup_data->cn_call_back_arg)); |
2529 | 0 | if (!ret) { |
2530 | 0 | if (depth == 0) { |
2531 | 0 | X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); |
2532 | 0 | } else { |
2533 | 0 | X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_CA); |
2534 | 0 | } |
2535 | 0 | preverify_ok = 0; |
2536 | 0 | } |
2537 | 0 | OPENSSL_free(base_buf); |
2538 | 0 | } else { |
2539 | 0 | X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNSPECIFIED); |
2540 | 0 | preverify_ok = 0; |
2541 | 0 | } |
2542 | 0 | } |
2543 | 0 | OPENSSL_free(cn); |
2544 | 0 | return preverify_ok; |
2545 | 0 | } |
2546 | | |
2547 | | #if COAP_SERVER_SUPPORT |
2548 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
2549 | | /* OpenSSL < 1.1.1 */ |
2550 | | /* |
2551 | | * During the SSL/TLS initial negotiations, tls_secret_call_back() is called so |
2552 | | * it is possible to determine whether this is a PKI or PSK incoming |
2553 | | * request and adjust the ciphers if necessary |
2554 | | * |
2555 | | * Set up by SSL_set_session_secret_cb() in tls_server_name_call_back() |
2556 | | */ |
2557 | | static int |
2558 | | tls_secret_call_back(SSL *ssl, |
2559 | | void *secret, |
2560 | | int *secretlen, |
2561 | | STACK_OF(SSL_CIPHER) *peer_ciphers, |
2562 | | const SSL_CIPHER **cipher COAP_UNUSED, |
2563 | | void *arg) { |
2564 | | int ii; |
2565 | | int psk_requested = 0; |
2566 | | coap_session_t *session; |
2567 | | coap_dtls_pki_t *setup_data = (coap_dtls_pki_t *)arg; |
2568 | | |
2569 | | session = (coap_session_t *)SSL_get_app_data(ssl); |
2570 | | assert(session != NULL); |
2571 | | assert(session->context != NULL); |
2572 | | if (session == NULL || |
2573 | | session->context == NULL) |
2574 | | return 0; |
2575 | | |
2576 | | if ((session->psk_key) || |
2577 | | (session->context->spsk_setup_data.psk_info.key.s && |
2578 | | session->context->spsk_setup_data.psk_info.key.length)) { |
2579 | | /* Is PSK being requested - if so, we need to change algorithms */ |
2580 | | for (ii = 0; ii < sk_SSL_CIPHER_num(peer_ciphers); ii++) { |
2581 | | const SSL_CIPHER *peer_cipher = sk_SSL_CIPHER_value(peer_ciphers, ii); |
2582 | | |
2583 | | coap_dtls_log(COAP_LOG_INFO, "Client cipher: %s\n", |
2584 | | SSL_CIPHER_get_name(peer_cipher)); |
2585 | | if (strstr(SSL_CIPHER_get_name(peer_cipher), "PSK")) { |
2586 | | psk_requested = 1; |
2587 | | break; |
2588 | | } |
2589 | | } |
2590 | | } |
2591 | | if (!psk_requested) { |
2592 | | coap_log_debug(" %s: Using PKI ciphers\n", |
2593 | | coap_session_str(session)); |
2594 | | |
2595 | | if (setup_data->verify_peer_cert) { |
2596 | | SSL_set_verify(ssl, |
2597 | | SSL_VERIFY_PEER | |
2598 | | SSL_VERIFY_CLIENT_ONCE | |
2599 | | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
2600 | | tls_verify_call_back); |
2601 | | } else { |
2602 | | SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_call_back); |
2603 | | } |
2604 | | |
2605 | | /* Check CA Chain */ |
2606 | | if (setup_data->cert_chain_validation) |
2607 | | SSL_set_verify_depth(ssl, setup_data->cert_chain_verify_depth + 2); |
2608 | | |
2609 | | /* Certificate Revocation */ |
2610 | | if (setup_data->check_cert_revocation) { |
2611 | | X509_VERIFY_PARAM *param; |
2612 | | |
2613 | | param = X509_VERIFY_PARAM_new(); |
2614 | | if (param) { |
2615 | | X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); |
2616 | | SSL_set1_param(ssl, param); |
2617 | | X509_VERIFY_PARAM_free(param); |
2618 | | } |
2619 | | } |
2620 | | if (setup_data->additional_tls_setup_call_back) { |
2621 | | /* Additional application setup wanted */ |
2622 | | if (!setup_data->additional_tls_setup_call_back(ssl, setup_data)) |
2623 | | return 0; |
2624 | | } |
2625 | | } else { |
2626 | | if (session->psk_key) { |
2627 | | memcpy(secret, session->psk_key->s, session->psk_key->length); |
2628 | | *secretlen = session->psk_key->length; |
2629 | | } else if (session->context->spsk_setup_data.psk_info.key.s && |
2630 | | session->context->spsk_setup_data.psk_info.key.length) { |
2631 | | memcpy(secret, session->context->spsk_setup_data.psk_info.key.s, |
2632 | | session->context->spsk_setup_data.psk_info.key.length); |
2633 | | *secretlen = session->context->spsk_setup_data.psk_info.key.length; |
2634 | | } |
2635 | | coap_log_debug(" %s: Setting PSK ciphers\n", |
2636 | | coap_session_str(session)); |
2637 | | /* |
2638 | | * Force a PSK algorithm to be used, so we do PSK |
2639 | | */ |
2640 | | SSL_set_cipher_list(ssl, COAP_OPENSSL_PSK_CIPHERS); |
2641 | | #ifdef COAP_OPENSSL_PSK_SECURITY_LEVEL |
2642 | | /* |
2643 | | * Set to 0 if, for example, PSK-AES128-CCM8 is to be supported (64 bits). |
2644 | | * Potentially opens up security vulnerabilities. |
2645 | | * Default value is 1. |
2646 | | */ |
2647 | | SSL_set_security_level(ssl, COAP_OPENSSL_PSK_SECURITY_LEVEL); |
2648 | | #endif /* COAP_OPENSSL_PSK_SECURITY_LEVEL */ |
2649 | | SSL_set_psk_server_callback(ssl, coap_dtls_psk_server_callback); |
2650 | | } |
2651 | | return 0; |
2652 | | } |
2653 | | |
2654 | | /* OpenSSL < 1.1.1 */ |
2655 | | /* |
2656 | | * During the SSL/TLS initial negotiations, tls_server_name_call_back() is |
2657 | | * called so it is possible to set up an extra callback to determine whether |
2658 | | * this is a PKI or PSK incoming request and adjust the ciphers if necessary |
2659 | | * |
2660 | | * Set up by SSL_CTX_set_tlsext_servername_callback() in |
2661 | | * coap_dtls_context_set_pki() |
2662 | | */ |
2663 | | static int |
2664 | | tls_server_name_call_back(SSL *ssl, |
2665 | | int *sd COAP_UNUSED, |
2666 | | void *arg) { |
2667 | | coap_dtls_pki_t *setup_data = (coap_dtls_pki_t *)arg; |
2668 | | |
2669 | | if (!ssl) { |
2670 | | return SSL_TLSEXT_ERR_NOACK; |
2671 | | } |
2672 | | |
2673 | | if (setup_data->validate_sni_call_back) { |
2674 | | /* SNI checking requested */ |
2675 | | coap_session_t *session = (coap_session_t *)SSL_get_app_data(ssl); |
2676 | | coap_openssl_context_t *context = (session && session->context) ? |
2677 | | ((coap_openssl_context_t *)session->context->dtls_context) : NULL; |
2678 | | const char *sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); |
2679 | | size_t i; |
2680 | | |
2681 | | if (!context) |
2682 | | return SSL_TLSEXT_ERR_NOACK; |
2683 | | |
2684 | | if (!sni || !sni[0]) { |
2685 | | sni = ""; |
2686 | | } |
2687 | | for (i = 0; i < context->sni_count; i++) { |
2688 | | if (!strcasecmp(sni, context->sni_entry_list[i].sni)) { |
2689 | | break; |
2690 | | } |
2691 | | } |
2692 | | if (i == context->sni_count) { |
2693 | | SSL_CTX *ctx; |
2694 | | coap_dtls_pki_t sni_setup_data; |
2695 | | coap_dtls_key_t *new_entry; |
2696 | | |
2697 | | coap_lock_callback_ret(new_entry, |
2698 | | setup_data->validate_sni_call_back(sni, |
2699 | | setup_data->sni_call_back_arg)); |
2700 | | if (!new_entry) { |
2701 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
2702 | | } |
2703 | | /* Need to set up a new SSL_CTX to switch to */ |
2704 | | if (session->proto == COAP_PROTO_DTLS) { |
2705 | | /* Set up DTLS context */ |
2706 | | ctx = SSL_CTX_new(DTLS_method()); |
2707 | | if (!ctx) |
2708 | | goto error; |
2709 | | SSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION); |
2710 | | SSL_CTX_set_app_data(ctx, &context->dtls); |
2711 | | SSL_CTX_set_read_ahead(ctx, 1); |
2712 | | coap_set_user_prefs(ctx); |
2713 | | SSL_CTX_set_cookie_generate_cb(ctx, coap_dtls_generate_cookie); |
2714 | | SSL_CTX_set_cookie_verify_cb(ctx, coap_dtls_verify_cookie); |
2715 | | SSL_CTX_set_info_callback(ctx, coap_dtls_info_callback); |
2716 | | SSL_CTX_set_options(ctx, SSL_OP_NO_QUERY_MTU); |
2717 | | } |
2718 | | #if !COAP_DISABLE_TCP |
2719 | | else { |
2720 | | /* Set up TLS context */ |
2721 | | ctx = SSL_CTX_new(TLS_method()); |
2722 | | if (!ctx) |
2723 | | goto error; |
2724 | | SSL_CTX_set_app_data(ctx, &context->tls); |
2725 | | SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
2726 | | coap_set_user_prefs(ctx); |
2727 | | SSL_CTX_set_info_callback(ctx, coap_dtls_info_callback); |
2728 | | SSL_CTX_set_alpn_select_cb(ctx, server_alpn_callback, NULL); |
2729 | | } |
2730 | | #endif /* !COAP_DISABLE_TCP */ |
2731 | | sni_setup_data = *setup_data; |
2732 | | sni_setup_data.pki_key = *new_entry; |
2733 | | setup_pki_server(ctx, &sni_setup_data); |
2734 | | |
2735 | | context->sni_entry_list = OPENSSL_realloc(context->sni_entry_list, |
2736 | | (context->sni_count+1)*sizeof(sni_entry)); |
2737 | | context->sni_entry_list[context->sni_count].sni = OPENSSL_strdup(sni); |
2738 | | context->sni_entry_list[context->sni_count].ctx = ctx; |
2739 | | context->sni_count++; |
2740 | | } |
2741 | | SSL_set_SSL_CTX(ssl, context->sni_entry_list[i].ctx); |
2742 | | SSL_clear_options(ssl, 0xFFFFFFFFL); |
2743 | | SSL_set_options(ssl, SSL_CTX_get_options(context->sni_entry_list[i].ctx)); |
2744 | | } |
2745 | | |
2746 | | /* |
2747 | | * Have to do extra call back next to get client algorithms |
2748 | | * SSL_get_client_ciphers() does not work this early on |
2749 | | */ |
2750 | | SSL_set_session_secret_cb(ssl, tls_secret_call_back, arg); |
2751 | | return SSL_TLSEXT_ERR_OK; |
2752 | | |
2753 | | error: |
2754 | | return SSL_TLSEXT_ERR_ALERT_WARNING; |
2755 | | } |
2756 | | |
2757 | | /* OpenSSL < 1.1.1 */ |
2758 | | /* |
2759 | | * During the SSL/TLS initial negotiations, psk_tls_server_name_call_back() is |
2760 | | * called to see if SNI is being used. |
2761 | | * |
2762 | | * Set up by SSL_CTX_set_tlsext_servername_callback() |
2763 | | * in coap_dtls_context_set_spsk() |
2764 | | */ |
2765 | | static int |
2766 | | psk_tls_server_name_call_back(SSL *ssl, |
2767 | | int *sd COAP_UNUSED, |
2768 | | void *arg |
2769 | | ) { |
2770 | | coap_dtls_spsk_t *setup_data = (coap_dtls_spsk_t *)arg; |
2771 | | |
2772 | | if (!ssl) { |
2773 | | return SSL_TLSEXT_ERR_NOACK; |
2774 | | } |
2775 | | |
2776 | | if (setup_data->validate_sni_call_back) { |
2777 | | /* SNI checking requested */ |
2778 | | coap_session_t *c_session = (coap_session_t *)SSL_get_app_data(ssl); |
2779 | | coap_openssl_context_t *o_context = (c_session && c_session->context) ? |
2780 | | ((coap_openssl_context_t *)c_session->context->dtls_context) : NULL; |
2781 | | const char *sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); |
2782 | | size_t i; |
2783 | | char lhint[COAP_DTLS_HINT_LENGTH]; |
2784 | | |
2785 | | if (!o_context) |
2786 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
2787 | | |
2788 | | if (!sni || !sni[0]) { |
2789 | | sni = ""; |
2790 | | } |
2791 | | for (i = 0; i < o_context->psk_sni_count; i++) { |
2792 | | if (!strcasecmp(sni, (char *)o_context->psk_sni_entry_list[i].sni)) { |
2793 | | break; |
2794 | | } |
2795 | | } |
2796 | | if (i == o_context->psk_sni_count) { |
2797 | | SSL_CTX *ctx; |
2798 | | const coap_dtls_spsk_info_t *new_entry; |
2799 | | |
2800 | | coap_lock_callback_ret(new_entry, |
2801 | | setup_data->validate_sni_call_back(sni, |
2802 | | c_session, |
2803 | | setup_data->sni_call_back_arg)); |
2804 | | if (!new_entry) { |
2805 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
2806 | | } |
2807 | | /* Need to set up a new SSL_CTX to switch to */ |
2808 | | if (c_session->proto == COAP_PROTO_DTLS) { |
2809 | | /* Set up DTLS context */ |
2810 | | ctx = SSL_CTX_new(DTLS_method()); |
2811 | | if (!ctx) |
2812 | | goto error; |
2813 | | SSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION); |
2814 | | SSL_CTX_set_app_data(ctx, &o_context->dtls); |
2815 | | SSL_CTX_set_read_ahead(ctx, 1); |
2816 | | SSL_CTX_set_cipher_list(ctx, COAP_OPENSSL_CIPHERS); |
2817 | | SSL_CTX_set_cookie_generate_cb(ctx, coap_dtls_generate_cookie); |
2818 | | SSL_CTX_set_cookie_verify_cb(ctx, coap_dtls_verify_cookie); |
2819 | | SSL_CTX_set_info_callback(ctx, coap_dtls_info_callback); |
2820 | | SSL_CTX_set_options(ctx, SSL_OP_NO_QUERY_MTU); |
2821 | | } |
2822 | | #if !COAP_DISABLE_TCP |
2823 | | else { |
2824 | | /* Set up TLS context */ |
2825 | | ctx = SSL_CTX_new(TLS_method()); |
2826 | | if (!ctx) |
2827 | | goto error; |
2828 | | SSL_CTX_set_app_data(ctx, &o_context->tls); |
2829 | | SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
2830 | | SSL_CTX_set_cipher_list(ctx, COAP_OPENSSL_CIPHERS); |
2831 | | SSL_CTX_set_info_callback(ctx, coap_dtls_info_callback); |
2832 | | SSL_CTX_set_alpn_select_cb(ctx, server_alpn_callback, NULL); |
2833 | | } |
2834 | | #endif /* !COAP_DISABLE_TCP */ |
2835 | | |
2836 | | o_context->psk_sni_entry_list = |
2837 | | OPENSSL_realloc(o_context->psk_sni_entry_list, |
2838 | | (o_context->psk_sni_count+1)*sizeof(psk_sni_entry)); |
2839 | | o_context->psk_sni_entry_list[o_context->psk_sni_count].sni = |
2840 | | OPENSSL_strdup(sni); |
2841 | | o_context->psk_sni_entry_list[o_context->psk_sni_count].psk_info = |
2842 | | *new_entry; |
2843 | | o_context->psk_sni_entry_list[o_context->psk_sni_count].ctx = |
2844 | | ctx; |
2845 | | o_context->psk_sni_count++; |
2846 | | } |
2847 | | SSL_set_SSL_CTX(ssl, o_context->psk_sni_entry_list[i].ctx); |
2848 | | SSL_clear_options(ssl, 0xFFFFFFFFL); |
2849 | | SSL_set_options(ssl, |
2850 | | SSL_CTX_get_options(o_context->psk_sni_entry_list[i].ctx)); |
2851 | | coap_session_refresh_psk_key(c_session, |
2852 | | &o_context->psk_sni_entry_list[i].psk_info.key); |
2853 | | snprintf(lhint, sizeof(lhint), "%.*s", |
2854 | | (int)o_context->psk_sni_entry_list[i].psk_info.hint.length, |
2855 | | o_context->psk_sni_entry_list[i].psk_info.hint.s); |
2856 | | SSL_use_psk_identity_hint(ssl, lhint); |
2857 | | } |
2858 | | |
2859 | | /* |
2860 | | * Have to do extra call back next to get client algorithms |
2861 | | * SSL_get_client_ciphers() does not work this early on |
2862 | | */ |
2863 | | SSL_set_session_secret_cb(ssl, tls_secret_call_back, arg); |
2864 | | return SSL_TLSEXT_ERR_OK; |
2865 | | |
2866 | | error: |
2867 | | return SSL_TLSEXT_ERR_ALERT_WARNING; |
2868 | | } |
2869 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
2870 | | /* OpenSSL >= 1.1.1 */ |
2871 | | /* |
2872 | | * During the SSL/TLS initial negotiations, tls_client_hello_call_back() is |
2873 | | * called early in the Client Hello processing so it is possible to determine |
2874 | | * whether this is a PKI or PSK incoming request and adjust the ciphers if |
2875 | | * necessary. |
2876 | | * |
2877 | | * Set up by SSL_CTX_set_client_hello_cb(). |
2878 | | */ |
2879 | | static int |
2880 | | tls_client_hello_call_back(SSL *ssl, |
2881 | | int *al, |
2882 | | void *arg COAP_UNUSED |
2883 | 0 | ) { |
2884 | 0 | coap_session_t *session; |
2885 | 0 | coap_openssl_context_t *dtls_context; |
2886 | 0 | coap_dtls_pki_t *setup_data; |
2887 | 0 | int psk_requested = 0; |
2888 | 0 | const unsigned char *out; |
2889 | 0 | size_t outlen; |
2890 | |
|
2891 | 0 | if (!ssl) { |
2892 | 0 | *al = SSL_AD_INTERNAL_ERROR; |
2893 | 0 | return SSL_CLIENT_HELLO_ERROR; |
2894 | 0 | } |
2895 | 0 | session = (coap_session_t *)SSL_get_app_data(ssl); |
2896 | 0 | assert(session != NULL); |
2897 | 0 | assert(session->context != NULL); |
2898 | 0 | assert(session->context->dtls_context != NULL); |
2899 | 0 | if (session == NULL || |
2900 | 0 | session->context == NULL || |
2901 | 0 | session->context->dtls_context == NULL) { |
2902 | 0 | *al = SSL_AD_INTERNAL_ERROR; |
2903 | 0 | return SSL_CLIENT_HELLO_ERROR; |
2904 | 0 | } |
2905 | 0 | dtls_context = (coap_openssl_context_t *)session->context->dtls_context; |
2906 | 0 | setup_data = &dtls_context->setup_data; |
2907 | | |
2908 | | /* |
2909 | | * See if PSK being requested |
2910 | | */ |
2911 | 0 | if ((session->psk_key) || |
2912 | 0 | (session->context->spsk_setup_data.psk_info.key.s && |
2913 | 0 | session->context->spsk_setup_data.psk_info.key.length)) { |
2914 | 0 | size_t len = SSL_client_hello_get0_ciphers(ssl, &out); |
2915 | 0 | STACK_OF(SSL_CIPHER) *peer_ciphers = NULL; |
2916 | 0 | STACK_OF(SSL_CIPHER) *scsvc = NULL; |
2917 | |
|
2918 | 0 | if (len && SSL_bytes_to_cipher_list(ssl, out, len, |
2919 | 0 | SSL_client_hello_isv2(ssl), |
2920 | 0 | &peer_ciphers, &scsvc)) { |
2921 | 0 | int ii; |
2922 | 0 | for (ii = 0; ii < sk_SSL_CIPHER_num(peer_ciphers); ii++) { |
2923 | 0 | const SSL_CIPHER *peer_cipher = sk_SSL_CIPHER_value(peer_ciphers, ii); |
2924 | |
|
2925 | 0 | coap_dtls_log(COAP_LOG_INFO, |
2926 | 0 | "Client cipher: %s (%04x)\n", |
2927 | 0 | SSL_CIPHER_get_name(peer_cipher), |
2928 | 0 | SSL_CIPHER_get_protocol_id(peer_cipher)); |
2929 | 0 | if (strstr(SSL_CIPHER_get_name(peer_cipher), "PSK")) { |
2930 | 0 | psk_requested = 1; |
2931 | 0 | break; |
2932 | 0 | } |
2933 | 0 | } |
2934 | 0 | } |
2935 | 0 | sk_SSL_CIPHER_free(peer_ciphers); |
2936 | 0 | sk_SSL_CIPHER_free(scsvc); |
2937 | 0 | } |
2938 | |
|
2939 | 0 | if (psk_requested) { |
2940 | | /* |
2941 | | * Client has requested PSK and it is supported |
2942 | | */ |
2943 | 0 | coap_log_debug(" %s: PSK request\n", |
2944 | 0 | coap_session_str(session)); |
2945 | 0 | SSL_set_psk_server_callback(ssl, coap_dtls_psk_server_callback); |
2946 | 0 | if (setup_data->additional_tls_setup_call_back) { |
2947 | | /* Additional application setup wanted */ |
2948 | 0 | if (!setup_data->additional_tls_setup_call_back(ssl, setup_data)) |
2949 | 0 | return 0; |
2950 | 0 | } |
2951 | 0 | return SSL_CLIENT_HELLO_SUCCESS; |
2952 | 0 | } |
2953 | | |
2954 | | /* |
2955 | | * Handle Certificate requests |
2956 | | */ |
2957 | | |
2958 | | /* |
2959 | | * Determine what type of certificate is being requested |
2960 | | */ |
2961 | 0 | if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_client_certificate_type, |
2962 | 0 | &out, &outlen)) { |
2963 | 0 | size_t ii; |
2964 | 0 | for (ii = 0; ii < outlen; ii++) { |
2965 | 0 | switch (out[ii]) { |
2966 | 0 | case 0: |
2967 | | /* RFC6091 X.509 */ |
2968 | 0 | if (outlen >= 2) { |
2969 | | /* X.509 cannot be the singular entry. RFC6091 3.1. Client Hello */ |
2970 | 0 | goto is_x509; |
2971 | 0 | } |
2972 | 0 | break; |
2973 | 0 | case 2: |
2974 | | /* RFC7250 RPK - not yet supported */ |
2975 | 0 | break; |
2976 | 0 | default: |
2977 | 0 | break; |
2978 | 0 | } |
2979 | 0 | } |
2980 | 0 | *al = SSL_AD_UNSUPPORTED_EXTENSION; |
2981 | 0 | return SSL_CLIENT_HELLO_ERROR; |
2982 | 0 | } |
2983 | | |
2984 | 0 | is_x509: |
2985 | 0 | if (setup_data->validate_sni_call_back) { |
2986 | | /* |
2987 | | * SNI checking requested |
2988 | | */ |
2989 | 0 | coap_dtls_pki_t sni_setup_data; |
2990 | 0 | coap_openssl_context_t *context = |
2991 | 0 | ((coap_openssl_context_t *)session->context->dtls_context); |
2992 | 0 | const char *sni = ""; |
2993 | 0 | char *sni_tmp = NULL; |
2994 | 0 | size_t i; |
2995 | |
|
2996 | 0 | if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &out, &outlen) && |
2997 | 0 | outlen > 5 && |
2998 | 0 | (((out[0]<<8) + out[1] +2) == (int)outlen) && |
2999 | 0 | out[2] == TLSEXT_NAMETYPE_host_name && |
3000 | 0 | (((out[3]<<8) + out[4] +2 +3) == (int)outlen)) { |
3001 | | /* Skip over length, type and length */ |
3002 | 0 | out += 5; |
3003 | 0 | outlen -= 5; |
3004 | 0 | sni_tmp = OPENSSL_malloc(outlen+1); |
3005 | 0 | sni_tmp[outlen] = '\000'; |
3006 | 0 | memcpy(sni_tmp, out, outlen); |
3007 | 0 | sni = sni_tmp; |
3008 | 0 | } |
3009 | | /* Is this a cached entry? */ |
3010 | 0 | for (i = 0; i < context->sni_count; i++) { |
3011 | 0 | if (!strcasecmp(sni, context->sni_entry_list[i].sni)) { |
3012 | 0 | break; |
3013 | 0 | } |
3014 | 0 | } |
3015 | 0 | if (i == context->sni_count) { |
3016 | | /* |
3017 | | * New SNI request |
3018 | | */ |
3019 | 0 | coap_dtls_key_t *new_entry; |
3020 | |
|
3021 | 0 | coap_lock_callback_ret(new_entry, |
3022 | 0 | setup_data->validate_sni_call_back(sni, |
3023 | 0 | setup_data->sni_call_back_arg)); |
3024 | 0 | if (!new_entry) { |
3025 | 0 | *al = SSL_AD_UNRECOGNIZED_NAME; |
3026 | 0 | return SSL_CLIENT_HELLO_ERROR; |
3027 | 0 | } |
3028 | | |
3029 | | |
3030 | 0 | context->sni_entry_list = OPENSSL_realloc(context->sni_entry_list, |
3031 | 0 | (context->sni_count+1)*sizeof(sni_entry)); |
3032 | 0 | context->sni_entry_list[context->sni_count].sni = OPENSSL_strdup(sni); |
3033 | 0 | context->sni_entry_list[context->sni_count].pki_key = *new_entry; |
3034 | 0 | context->sni_count++; |
3035 | 0 | } |
3036 | 0 | if (sni_tmp) { |
3037 | 0 | OPENSSL_free(sni_tmp); |
3038 | 0 | } |
3039 | 0 | sni_setup_data = *setup_data; |
3040 | 0 | sni_setup_data.pki_key = context->sni_entry_list[i].pki_key; |
3041 | 0 | setup_pki_ssl(ssl, &sni_setup_data, COAP_DTLS_ROLE_SERVER); |
3042 | 0 | } else { |
3043 | 0 | setup_pki_ssl(ssl, setup_data, COAP_DTLS_ROLE_SERVER); |
3044 | 0 | } |
3045 | | |
3046 | 0 | coap_log_debug(" %s: Using PKI ciphers\n", |
3047 | 0 | coap_session_str(session)); |
3048 | |
|
3049 | 0 | if (setup_data->verify_peer_cert) { |
3050 | 0 | SSL_set_verify(ssl, |
3051 | 0 | SSL_VERIFY_PEER | |
3052 | 0 | SSL_VERIFY_CLIENT_ONCE | |
3053 | 0 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
3054 | 0 | tls_verify_call_back); |
3055 | 0 | } else { |
3056 | 0 | SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_call_back); |
3057 | 0 | } |
3058 | | |
3059 | | /* Check CA Chain */ |
3060 | 0 | if (setup_data->cert_chain_validation) |
3061 | 0 | SSL_set_verify_depth(ssl, setup_data->cert_chain_verify_depth + 2); |
3062 | | |
3063 | | /* Certificate Revocation */ |
3064 | 0 | if (setup_data->check_cert_revocation) { |
3065 | 0 | X509_VERIFY_PARAM *param; |
3066 | |
|
3067 | 0 | param = X509_VERIFY_PARAM_new(); |
3068 | 0 | if (param) { |
3069 | 0 | X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); |
3070 | 0 | SSL_set1_param(ssl, param); |
3071 | 0 | X509_VERIFY_PARAM_free(param); |
3072 | 0 | } |
3073 | 0 | } |
3074 | 0 | if (setup_data->additional_tls_setup_call_back) { |
3075 | | /* Additional application setup wanted */ |
3076 | 0 | if (!setup_data->additional_tls_setup_call_back(ssl, setup_data)) |
3077 | 0 | return 0; |
3078 | 0 | } |
3079 | 0 | return SSL_CLIENT_HELLO_SUCCESS; |
3080 | 0 | } |
3081 | | |
3082 | | /* OpenSSL >= 1.1.1 */ |
3083 | | /* |
3084 | | * During the SSL/TLS initial negotiations, psk_tls_client_hello_call_back() is |
3085 | | * called early in the Client Hello processing so it is possible to determine |
3086 | | * whether SNI needs to be handled |
3087 | | * |
3088 | | * Set up by SSL_CTX_set_client_hello_cb(). |
3089 | | */ |
3090 | | static int |
3091 | | psk_tls_client_hello_call_back(SSL *ssl, |
3092 | | int *al, |
3093 | | void *arg COAP_UNUSED |
3094 | 0 | ) { |
3095 | 0 | coap_session_t *c_session; |
3096 | 0 | coap_openssl_context_t *o_context; |
3097 | 0 | coap_dtls_spsk_t *setup_data; |
3098 | 0 | const unsigned char *out; |
3099 | 0 | size_t outlen; |
3100 | |
|
3101 | 0 | if (!ssl) |
3102 | 0 | goto int_err; |
3103 | 0 | c_session = (coap_session_t *)SSL_get_app_data(ssl); |
3104 | 0 | if (!c_session || !c_session->context) { |
3105 | 0 | goto int_err; |
3106 | 0 | } |
3107 | 0 | o_context = (coap_openssl_context_t *)c_session->context->dtls_context; |
3108 | 0 | if (!o_context) { |
3109 | 0 | goto int_err; |
3110 | 0 | } |
3111 | 0 | setup_data = &c_session->context->spsk_setup_data; |
3112 | |
|
3113 | 0 | if (setup_data->validate_sni_call_back) { |
3114 | | /* |
3115 | | * SNI checking requested |
3116 | | */ |
3117 | 0 | const char *sni = ""; |
3118 | 0 | char *sni_tmp = NULL; |
3119 | 0 | char lhint[COAP_DTLS_HINT_LENGTH]; |
3120 | |
|
3121 | 0 | if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &out, &outlen) && |
3122 | 0 | outlen > 5 && |
3123 | 0 | (((out[0]<<8) + out[1] +2) == (int)outlen) && |
3124 | 0 | out[2] == TLSEXT_NAMETYPE_host_name && |
3125 | 0 | (((out[3]<<8) + out[4] +2 +3) == (int)outlen)) { |
3126 | | /* Skip over length, type and length */ |
3127 | 0 | out += 5; |
3128 | 0 | outlen -= 5; |
3129 | 0 | sni_tmp = OPENSSL_malloc(outlen+1); |
3130 | 0 | if (sni_tmp) { |
3131 | 0 | sni_tmp[outlen] = '\000'; |
3132 | 0 | memcpy(sni_tmp, out, outlen); |
3133 | 0 | sni = sni_tmp; |
3134 | 0 | } |
3135 | 0 | } |
3136 | |
|
3137 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3138 | | size_t i; |
3139 | | /* Is this a cached entry? */ |
3140 | | for (i = 0; i < o_context->psk_sni_count; i++) { |
3141 | | if (strcasecmp(sni, o_context->psk_sni_entry_list[i].sni) == 0) { |
3142 | | break; |
3143 | | } |
3144 | | } |
3145 | | if (i == o_context->psk_sni_count) { |
3146 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3147 | | /* |
3148 | | * New SNI request |
3149 | | */ |
3150 | 0 | const coap_dtls_spsk_info_t *new_entry; |
3151 | |
|
3152 | 0 | coap_lock_callback_ret(new_entry, |
3153 | 0 | setup_data->validate_sni_call_back( |
3154 | 0 | sni, |
3155 | 0 | c_session, |
3156 | 0 | setup_data->sni_call_back_arg)); |
3157 | 0 | if (!new_entry) { |
3158 | 0 | *al = SSL_AD_UNRECOGNIZED_NAME; |
3159 | 0 | return SSL_CLIENT_HELLO_ERROR; |
3160 | 0 | } |
3161 | | |
3162 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3163 | | psk_sni_entry *tmp_entry; |
3164 | | tmp_entry = |
3165 | | OPENSSL_realloc(o_context->psk_sni_entry_list, |
3166 | | (o_context->psk_sni_count+1)*sizeof(sni_entry)); |
3167 | | if (tmp_entry) { |
3168 | | o_context->psk_sni_entry_list = tmp_entry; |
3169 | | o_context->psk_sni_entry_list[o_context->psk_sni_count] |
3170 | | .sni = |
3171 | | OPENSSL_strdup(sni); |
3172 | | if (o_context->psk_sni_entry_list[o_context->psk_sni_count].sni) { |
3173 | | o_context->psk_sni_entry_list[o_context->psk_sni_count].psk_info = |
3174 | | *new_entry; |
3175 | | o_context->psk_sni_count++; |
3176 | | } |
3177 | | } |
3178 | | } else { |
3179 | | new_entry = &o_context->psk_sni_entry_list[i].psk_info; |
3180 | | } |
3181 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3182 | | |
3183 | 0 | if (sni_tmp) { |
3184 | 0 | OPENSSL_free(sni_tmp); |
3185 | 0 | } |
3186 | 0 | if (coap_session_refresh_psk_hint(c_session, |
3187 | 0 | &new_entry->hint) |
3188 | 0 | == 0) { |
3189 | 0 | goto int_err; |
3190 | 0 | } |
3191 | 0 | if (coap_session_refresh_psk_key(c_session, |
3192 | 0 | &new_entry->key) |
3193 | 0 | == 0) { |
3194 | 0 | goto int_err; |
3195 | 0 | } |
3196 | 0 | if (new_entry->hint.s) { |
3197 | 0 | snprintf(lhint, sizeof(lhint), "%.*s", |
3198 | 0 | (int)new_entry->hint.length, |
3199 | 0 | new_entry->hint.s); |
3200 | 0 | SSL_use_psk_identity_hint(ssl, lhint); |
3201 | 0 | } |
3202 | 0 | } |
3203 | 0 | return SSL_CLIENT_HELLO_SUCCESS; |
3204 | | |
3205 | 0 | int_err: |
3206 | 0 | *al = SSL_AD_INTERNAL_ERROR; |
3207 | 0 | return SSL_CLIENT_HELLO_ERROR; |
3208 | 0 | } |
3209 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3210 | | #endif /* COAP_SERVER_SUPPORT */ |
3211 | | |
3212 | | int |
3213 | | coap_dtls_context_set_pki(coap_context_t *ctx, |
3214 | | const coap_dtls_pki_t *setup_data, |
3215 | 0 | const coap_dtls_role_t role) { |
3216 | 0 | coap_openssl_context_t *context = |
3217 | 0 | ((coap_openssl_context_t *)ctx->dtls_context); |
3218 | 0 | BIO *bio; |
3219 | 0 | if (!setup_data) |
3220 | 0 | return 0; |
3221 | 0 | context->setup_data = *setup_data; |
3222 | |
|
3223 | 0 | if (context->setup_data.pki_key.key_type == COAP_PKI_KEY_DEFINE) { |
3224 | 0 | if (context->setup_data.pki_key.key.define.ca_def == COAP_PKI_KEY_DEF_ENGINE || |
3225 | 0 | context->setup_data.pki_key.key.define.public_cert_def == COAP_PKI_KEY_DEF_ENGINE || |
3226 | 0 | context->setup_data.pki_key.key.define.private_key_def == COAP_PKI_KEY_DEF_ENGINE) { |
3227 | 0 | if (!defined_engine) { |
3228 | 0 | coap_log_warn("setup_pki: OpenSSL Engine not configured, PKI not set up\n"); |
3229 | 0 | return 0; |
3230 | 0 | } |
3231 | 0 | } |
3232 | 0 | } |
3233 | | |
3234 | 0 | if (!context->setup_data.verify_peer_cert) { |
3235 | | /* Needs to be clear so that no CA DNs are transmitted */ |
3236 | 0 | context->setup_data.check_common_ca = 0; |
3237 | | /* Allow all of these but warn if issue */ |
3238 | 0 | context->setup_data.allow_self_signed = 1; |
3239 | 0 | context->setup_data.allow_expired_certs = 1; |
3240 | 0 | context->setup_data.cert_chain_validation = 1; |
3241 | 0 | context->setup_data.cert_chain_verify_depth = 10; |
3242 | 0 | context->setup_data.check_cert_revocation = 1; |
3243 | 0 | context->setup_data.allow_no_crl = 1; |
3244 | 0 | context->setup_data.allow_expired_crl = 1; |
3245 | 0 | context->setup_data.allow_bad_md_hash = 1; |
3246 | 0 | context->setup_data.allow_short_rsa_length = 1; |
3247 | 0 | } |
3248 | 0 | #if COAP_SERVER_SUPPORT |
3249 | 0 | if (role == COAP_DTLS_ROLE_SERVER) { |
3250 | 0 | if (context->dtls.ctx) { |
3251 | | /* SERVER DTLS */ |
3252 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3253 | | if (!setup_pki_server(context->dtls.ctx, setup_data)) |
3254 | | return 0; |
3255 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3256 | | /* libcoap is managing TLS connection based on setup_data options */ |
3257 | | /* Need to set up logic to differentiate between a PSK or PKI session */ |
3258 | | /* |
3259 | | * For OpenSSL 1.1.1, we need to use SSL_CTX_set_client_hello_cb() |
3260 | | * which is not in 1.1.0 |
3261 | | */ |
3262 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3263 | | if (SSLeay() >= 0x10101000L) { |
3264 | | coap_log_warn("OpenSSL compiled with %lux, linked with %lux, so " |
3265 | | "no certificate checking\n", |
3266 | | OPENSSL_VERSION_NUMBER, SSLeay()); |
3267 | | } |
3268 | | SSL_CTX_set_tlsext_servername_arg(context->dtls.ctx, &context->setup_data); |
3269 | | SSL_CTX_set_tlsext_servername_callback(context->dtls.ctx, |
3270 | | tls_server_name_call_back); |
3271 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3272 | 0 | SSL_CTX_set_client_hello_cb(context->dtls.ctx, |
3273 | 0 | tls_client_hello_call_back, |
3274 | 0 | NULL); |
3275 | 0 | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3276 | 0 | } |
3277 | 0 | #if !COAP_DISABLE_TCP |
3278 | 0 | if (context->tls.ctx) { |
3279 | | /* SERVER TLS */ |
3280 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3281 | | if (!setup_pki_server(context->tls.ctx, setup_data)) |
3282 | | return 0; |
3283 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3284 | | /* libcoap is managing TLS connection based on setup_data options */ |
3285 | | /* Need to set up logic to differentiate between a PSK or PKI session */ |
3286 | | /* |
3287 | | * For OpenSSL 1.1.1, we need to use SSL_CTX_set_client_hello_cb() |
3288 | | * which is not in 1.1.0 |
3289 | | */ |
3290 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3291 | | if (SSLeay() >= 0x10101000L) { |
3292 | | coap_log_warn("OpenSSL compiled with %lux, linked with %lux, so " |
3293 | | "no certificate checking\n", |
3294 | | OPENSSL_VERSION_NUMBER, SSLeay()); |
3295 | | } |
3296 | | SSL_CTX_set_tlsext_servername_arg(context->tls.ctx, &context->setup_data); |
3297 | | SSL_CTX_set_tlsext_servername_callback(context->tls.ctx, |
3298 | | tls_server_name_call_back); |
3299 | | #else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3300 | 0 | SSL_CTX_set_client_hello_cb(context->tls.ctx, |
3301 | 0 | tls_client_hello_call_back, |
3302 | 0 | NULL); |
3303 | 0 | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3304 | | /* TLS Only */ |
3305 | 0 | SSL_CTX_set_alpn_select_cb(context->tls.ctx, server_alpn_callback, NULL); |
3306 | 0 | } |
3307 | 0 | #endif /* !COAP_DISABLE_TCP */ |
3308 | 0 | } |
3309 | | #else /* ! COAP_SERVER_SUPPORT */ |
3310 | | (void)role; |
3311 | | #endif /* ! COAP_SERVER_SUPPORT */ |
3312 | |
|
3313 | 0 | if (!context->dtls.ssl) { |
3314 | | /* This is set up to handle new incoming sessions to a server */ |
3315 | 0 | context->dtls.ssl = SSL_new(context->dtls.ctx); |
3316 | 0 | if (!context->dtls.ssl) |
3317 | 0 | return 0; |
3318 | 0 | bio = BIO_new(context->dtls.meth); |
3319 | 0 | if (!bio) { |
3320 | 0 | SSL_free(context->dtls.ssl); |
3321 | 0 | context->dtls.ssl = NULL; |
3322 | 0 | return 0; |
3323 | 0 | } |
3324 | 0 | SSL_set_bio(context->dtls.ssl, bio, bio); |
3325 | 0 | SSL_set_app_data(context->dtls.ssl, NULL); |
3326 | 0 | SSL_set_options(context->dtls.ssl, SSL_OP_COOKIE_EXCHANGE); |
3327 | 0 | SSL_set_mtu(context->dtls.ssl, COAP_DEFAULT_MTU); |
3328 | 0 | } |
3329 | 0 | context->psk_pki_enabled |= IS_PKI; |
3330 | 0 | if (setup_data->use_cid) { |
3331 | 0 | coap_log_warn("OpenSSL has no Connection-ID support\n"); |
3332 | 0 | } |
3333 | 0 | return 1; |
3334 | 0 | } |
3335 | | |
3336 | | int |
3337 | | coap_dtls_context_set_pki_root_cas(coap_context_t *ctx, |
3338 | | const char *ca_file, |
3339 | | const char *ca_dir |
3340 | 0 | ) { |
3341 | 0 | coap_openssl_context_t *context = |
3342 | 0 | ((coap_openssl_context_t *)ctx->dtls_context); |
3343 | 0 | if (context->dtls.ctx) { |
3344 | 0 | if (!SSL_CTX_load_verify_locations(context->dtls.ctx, ca_file, ca_dir)) { |
3345 | 0 | coap_log_warn("Unable to install root CAs (%s : %s)\n", |
3346 | 0 | ca_file ? ca_file : "NULL", ca_dir ? ca_dir : "NULL"); |
3347 | 0 | return 0; |
3348 | 0 | } |
3349 | 0 | } |
3350 | 0 | #if !COAP_DISABLE_TCP |
3351 | 0 | if (context->tls.ctx) { |
3352 | 0 | if (!SSL_CTX_load_verify_locations(context->tls.ctx, ca_file, ca_dir)) { |
3353 | 0 | coap_log_warn("Unable to install root CAs (%s : %s)\n", |
3354 | 0 | ca_file ? ca_file : "NULL", ca_dir ? ca_dir : "NULL"); |
3355 | 0 | return 0; |
3356 | 0 | } |
3357 | 0 | } |
3358 | 0 | #endif /* !COAP_DISABLE_TCP */ |
3359 | 0 | return 1; |
3360 | 0 | } |
3361 | | |
3362 | | int |
3363 | 0 | coap_dtls_context_load_pki_trust_store(coap_context_t *ctx) { |
3364 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
3365 | | coap_openssl_context_t *context = |
3366 | | ((coap_openssl_context_t *)ctx->dtls_context); |
3367 | | if (context->dtls.ctx) { |
3368 | | if (!SSL_CTX_set_default_verify_store(context->dtls.ctx)) { |
3369 | | coap_log_warn("Unable to load trusted root CAs\n"); |
3370 | | return 0; |
3371 | | } |
3372 | | } |
3373 | | #if !COAP_DISABLE_TCP |
3374 | | if (context->tls.ctx) { |
3375 | | if (!SSL_CTX_set_default_verify_store(context->tls.ctx)) { |
3376 | | coap_log_warn("Unable to load trusted root CAs\n"); |
3377 | | return 0; |
3378 | | } |
3379 | | } |
3380 | | #endif /* !COAP_DISABLE_TCP */ |
3381 | | return 1; |
3382 | | #else /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
3383 | 0 | (void)ctx; |
3384 | 0 | coap_log_warn("coap_context_set_pki_trust_store: (D)TLS environment " |
3385 | 0 | "not supported for OpenSSL < v3.0.0\n"); |
3386 | 0 | return 0; |
3387 | 0 | #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
3388 | 0 | } |
3389 | | |
3390 | | int |
3391 | 0 | coap_dtls_context_check_keys_enabled(coap_context_t *ctx) { |
3392 | 0 | coap_openssl_context_t *context = |
3393 | 0 | ((coap_openssl_context_t *)ctx->dtls_context); |
3394 | 0 | return context->psk_pki_enabled ? 1 : 0; |
3395 | 0 | } |
3396 | | |
3397 | | |
3398 | | void |
3399 | 0 | coap_dtls_free_context(void *handle) { |
3400 | 0 | size_t i; |
3401 | 0 | coap_openssl_context_t *context = (coap_openssl_context_t *)handle; |
3402 | |
|
3403 | 0 | if (context->dtls.ssl) |
3404 | 0 | SSL_free(context->dtls.ssl); |
3405 | 0 | if (context->dtls.ctx) |
3406 | 0 | SSL_CTX_free(context->dtls.ctx); |
3407 | 0 | if (context->dtls.cookie_hmac) |
3408 | 0 | HMAC_CTX_free(context->dtls.cookie_hmac); |
3409 | 0 | if (context->dtls.meth) |
3410 | 0 | BIO_meth_free(context->dtls.meth); |
3411 | 0 | if (context->dtls.bio_addr) |
3412 | 0 | BIO_ADDR_free(context->dtls.bio_addr); |
3413 | 0 | #if !COAP_DISABLE_TCP |
3414 | 0 | if (context->tls.ctx) |
3415 | 0 | SSL_CTX_free(context->tls.ctx); |
3416 | 0 | if (context->tls.meth) |
3417 | 0 | BIO_meth_free(context->tls.meth); |
3418 | 0 | #endif /* !COAP_DISABLE_TCP */ |
3419 | 0 | for (i = 0; i < context->sni_count; i++) { |
3420 | 0 | OPENSSL_free(context->sni_entry_list[i].sni); |
3421 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3422 | | SSL_CTX_free(context->sni_entry_list[i].ctx); |
3423 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3424 | 0 | } |
3425 | 0 | if (context->sni_count) |
3426 | 0 | OPENSSL_free(context->sni_entry_list); |
3427 | | #if OPENSSL_VERSION_NUMBER < 0x10101000L |
3428 | | for (i = 0; i < context->psk_sni_count; i++) { |
3429 | | OPENSSL_free((char *)context->psk_sni_entry_list[i].sni); |
3430 | | SSL_CTX_free(context->psk_sni_entry_list[i].ctx); |
3431 | | } |
3432 | | if (context->psk_sni_count) |
3433 | | OPENSSL_free(context->psk_sni_entry_list); |
3434 | | #endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ |
3435 | 0 | coap_free_type(COAP_STRING, context); |
3436 | 0 | } |
3437 | | |
3438 | | #if COAP_SERVER_SUPPORT |
3439 | | void * |
3440 | 0 | coap_dtls_new_server_session(coap_session_t *session) { |
3441 | 0 | BIO *nbio = NULL; |
3442 | 0 | SSL *nssl = NULL, *ssl = NULL; |
3443 | 0 | coap_ssl_data *data; |
3444 | 0 | coap_dtls_context_t *dtls = &((coap_openssl_context_t *)session->context->dtls_context)->dtls; |
3445 | 0 | int r; |
3446 | 0 | const coap_bin_const_t *psk_hint; |
3447 | 0 | BIO *rbio; |
3448 | |
|
3449 | 0 | nssl = SSL_new(dtls->ctx); |
3450 | 0 | if (!nssl) |
3451 | 0 | goto error; |
3452 | 0 | nbio = BIO_new(dtls->meth); |
3453 | 0 | if (!nbio) |
3454 | 0 | goto error; |
3455 | 0 | SSL_set_bio(nssl, nbio, nbio); |
3456 | 0 | SSL_set_app_data(nssl, NULL); |
3457 | 0 | SSL_set_options(nssl, SSL_OP_COOKIE_EXCHANGE); |
3458 | 0 | SSL_set_mtu(nssl, (long)session->mtu); |
3459 | 0 | ssl = dtls->ssl; |
3460 | 0 | dtls->ssl = nssl; |
3461 | 0 | nssl = NULL; |
3462 | 0 | SSL_set_app_data(ssl, session); |
3463 | |
|
3464 | 0 | rbio = SSL_get_rbio(ssl); |
3465 | 0 | data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; |
3466 | 0 | if (!data) |
3467 | 0 | goto error; |
3468 | 0 | data->session = session; |
3469 | | |
3470 | | /* hint may get updated if/when handling SNI callback */ |
3471 | 0 | psk_hint = coap_get_session_server_psk_hint(session); |
3472 | 0 | if (psk_hint != NULL && psk_hint->length) { |
3473 | 0 | char *hint = OPENSSL_malloc(psk_hint->length + 1); |
3474 | |
|
3475 | 0 | if (hint) { |
3476 | 0 | memcpy(hint, psk_hint->s, psk_hint->length); |
3477 | 0 | hint[psk_hint->length] = '\000'; |
3478 | 0 | SSL_use_psk_identity_hint(ssl, hint); |
3479 | 0 | OPENSSL_free(hint); |
3480 | 0 | } else { |
3481 | 0 | coap_log_warn("hint malloc failure\n"); |
3482 | 0 | } |
3483 | 0 | } |
3484 | |
|
3485 | 0 | r = SSL_accept(ssl); |
3486 | 0 | if (r == -1) { |
3487 | 0 | int err = SSL_get_error(ssl, r); |
3488 | 0 | if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) |
3489 | 0 | r = 0; |
3490 | 0 | } |
3491 | |
|
3492 | 0 | if (r == 0) { |
3493 | 0 | SSL_free(ssl); |
3494 | 0 | return NULL; |
3495 | 0 | } |
3496 | | |
3497 | 0 | return ssl; |
3498 | | |
3499 | 0 | error: |
3500 | 0 | if (nssl) |
3501 | 0 | SSL_free(nssl); |
3502 | 0 | return NULL; |
3503 | 0 | } |
3504 | | #endif /* COAP_SERVER_SUPPORT */ |
3505 | | |
3506 | | #if COAP_CLIENT_SUPPORT |
3507 | | static int |
3508 | | setup_client_ssl_session(coap_session_t *session, SSL *ssl |
3509 | 0 | ) { |
3510 | 0 | coap_openssl_context_t *context = |
3511 | 0 | ((coap_openssl_context_t *)session->context->dtls_context); |
3512 | |
|
3513 | 0 | if (context->psk_pki_enabled & IS_PSK) { |
3514 | 0 | coap_dtls_cpsk_t *setup_data = &session->cpsk_setup_data; |
3515 | | |
3516 | | /* Issue SNI if requested */ |
3517 | 0 | if (setup_data->client_sni && |
3518 | 0 | SSL_set_tlsext_host_name(ssl, setup_data->client_sni) != 1) { |
3519 | 0 | coap_log_warn("SSL_set_tlsext_host_name: set '%s' failed", |
3520 | 0 | setup_data->client_sni); |
3521 | 0 | } |
3522 | 0 | SSL_set_psk_client_callback(ssl, coap_dtls_psk_client_callback); |
3523 | 0 | #if COAP_SERVER_SUPPORT |
3524 | 0 | SSL_set_psk_server_callback(ssl, coap_dtls_psk_server_callback); |
3525 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
3526 | 0 | SSL_set_cipher_list(ssl, COAP_OPENSSL_PSK_CIPHERS); |
3527 | | #ifdef COAP_OPENSSL_PSK_SECURITY_LEVEL |
3528 | | /* |
3529 | | * Set to 0 if, for example, PSK-AES128-CCM8 is to be supported (64 bits). |
3530 | | * Potentially opens up security vulnerabilities. |
3531 | | * Default value is 1. |
3532 | | */ |
3533 | | SSL_set_security_level(ssl, COAP_OPENSSL_PSK_SECURITY_LEVEL); |
3534 | | #endif /* COAP_OPENSSL_PSK_SECURITY_LEVEL */ |
3535 | 0 | if (setup_data->validate_ih_call_back) { |
3536 | 0 | if (session->proto == COAP_PROTO_DTLS) { |
3537 | 0 | SSL_set_max_proto_version(ssl, DTLS1_2_VERSION); |
3538 | 0 | } |
3539 | 0 | #if !COAP_DISABLE_TCP |
3540 | 0 | else { |
3541 | 0 | SSL_set_max_proto_version(ssl, TLS1_2_VERSION); |
3542 | 0 | } |
3543 | 0 | #endif /* !COAP_DISABLE_TCP */ |
3544 | 0 | coap_log_debug("CoAP Client restricted to (D)TLS1.2 with Identity Hint callback\n"); |
3545 | 0 | } |
3546 | 0 | } |
3547 | 0 | if ((context->psk_pki_enabled & IS_PKI) || |
3548 | 0 | (context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) { |
3549 | | /* |
3550 | | * If neither PSK or PKI have been set up, use PKI basics. |
3551 | | * This works providing COAP_PKI_KEY_PEM has a value of 0. |
3552 | | */ |
3553 | 0 | coap_dtls_pki_t *setup_data = &context->setup_data; |
3554 | |
|
3555 | 0 | if (!(context->psk_pki_enabled & IS_PKI)) { |
3556 | | /* PKI not defined - set up some defaults */ |
3557 | 0 | setup_data->verify_peer_cert = 1; |
3558 | 0 | setup_data->check_common_ca = 0; |
3559 | 0 | setup_data->allow_self_signed = 1; |
3560 | 0 | setup_data->allow_expired_certs = 1; |
3561 | 0 | setup_data->cert_chain_validation = 1; |
3562 | 0 | setup_data->cert_chain_verify_depth = 2; |
3563 | 0 | setup_data->check_cert_revocation = 1; |
3564 | 0 | setup_data->allow_no_crl = 1; |
3565 | 0 | setup_data->allow_expired_crl = 1; |
3566 | 0 | setup_data->is_rpk_not_cert = 0; |
3567 | 0 | setup_data->use_cid = 0; |
3568 | 0 | } |
3569 | 0 | if (!setup_pki_ssl(ssl, setup_data, COAP_DTLS_ROLE_CLIENT)) |
3570 | 0 | return 0; |
3571 | | /* libcoap is managing (D)TLS connection based on setup_data options */ |
3572 | 0 | #if !COAP_DISABLE_TCP |
3573 | 0 | if (session->proto == COAP_PROTO_TLS) |
3574 | 0 | SSL_set_alpn_protos(ssl, coap_alpn, sizeof(coap_alpn)); |
3575 | 0 | #endif /* !COAP_DISABLE_TCP */ |
3576 | | |
3577 | | /* Issue SNI if requested */ |
3578 | 0 | if (setup_data->client_sni && |
3579 | 0 | SSL_set_tlsext_host_name(ssl, setup_data->client_sni) != 1) { |
3580 | 0 | coap_log_warn("SSL_set_tlsext_host_name: set '%s' failed", |
3581 | 0 | setup_data->client_sni); |
3582 | 0 | } |
3583 | | /* Certificate Revocation */ |
3584 | 0 | if (setup_data->check_cert_revocation) { |
3585 | 0 | X509_VERIFY_PARAM *param; |
3586 | |
|
3587 | 0 | param = X509_VERIFY_PARAM_new(); |
3588 | 0 | if (param) { |
3589 | 0 | X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); |
3590 | 0 | SSL_set1_param(ssl, param); |
3591 | 0 | X509_VERIFY_PARAM_free(param); |
3592 | 0 | } |
3593 | 0 | } |
3594 | | |
3595 | | /* Verify Peer */ |
3596 | 0 | if (setup_data->verify_peer_cert) |
3597 | 0 | SSL_set_verify(ssl, |
3598 | 0 | SSL_VERIFY_PEER | |
3599 | 0 | SSL_VERIFY_CLIENT_ONCE | |
3600 | 0 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
3601 | 0 | tls_verify_call_back); |
3602 | 0 | else |
3603 | 0 | SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_call_back); |
3604 | | |
3605 | | /* Check CA Chain */ |
3606 | 0 | if (setup_data->cert_chain_validation) |
3607 | 0 | SSL_set_verify_depth(ssl, setup_data->cert_chain_verify_depth + 1); |
3608 | |
|
3609 | 0 | } |
3610 | | #if COAP_DTLS_RETRANSMIT_MS != 1000 |
3611 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
3612 | | if (session->proto == COAP_PROTO_DTLS) { |
3613 | | DTLS_set_timer_cb(ssl, timer_cb); |
3614 | | } |
3615 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
3616 | | #endif /* COAP_DTLS_RETRANSMIT_MS != 1000 */ |
3617 | 0 | return 1; |
3618 | 0 | } |
3619 | | |
3620 | | void * |
3621 | 0 | coap_dtls_new_client_session(coap_session_t *session) { |
3622 | 0 | BIO *bio = NULL; |
3623 | 0 | SSL *ssl = NULL; |
3624 | 0 | coap_ssl_data *data; |
3625 | 0 | int r; |
3626 | 0 | coap_openssl_context_t *context = ((coap_openssl_context_t *)session->context->dtls_context); |
3627 | 0 | coap_dtls_context_t *dtls = &context->dtls; |
3628 | |
|
3629 | 0 | ssl = SSL_new(dtls->ctx); |
3630 | 0 | if (!ssl) |
3631 | 0 | goto error; |
3632 | 0 | bio = BIO_new(dtls->meth); |
3633 | 0 | if (!bio) |
3634 | 0 | goto error; |
3635 | 0 | data = (coap_ssl_data *)BIO_get_data(bio); |
3636 | 0 | if (!data) |
3637 | 0 | goto error; |
3638 | 0 | data->session = session; |
3639 | 0 | SSL_set_bio(ssl, bio, bio); |
3640 | 0 | SSL_set_app_data(ssl, session); |
3641 | 0 | SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); |
3642 | 0 | SSL_set_mtu(ssl, (long)session->mtu); |
3643 | |
|
3644 | 0 | if (!setup_client_ssl_session(session, ssl)) |
3645 | 0 | goto error; |
3646 | | |
3647 | 0 | session->dtls_timeout_count = 0; |
3648 | |
|
3649 | 0 | r = SSL_connect(ssl); |
3650 | 0 | if (r == -1) { |
3651 | 0 | int ret = SSL_get_error(ssl, r); |
3652 | 0 | if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) |
3653 | 0 | r = 0; |
3654 | 0 | } |
3655 | |
|
3656 | 0 | if (r == 0) |
3657 | 0 | goto error; |
3658 | | |
3659 | 0 | session->tls = ssl; |
3660 | 0 | return ssl; |
3661 | | |
3662 | 0 | error: |
3663 | 0 | if (ssl) |
3664 | 0 | SSL_free(ssl); |
3665 | 0 | return NULL; |
3666 | 0 | } |
3667 | | |
3668 | | void |
3669 | 0 | coap_dtls_session_update_mtu(coap_session_t *session) { |
3670 | 0 | SSL *ssl = (SSL *)session->tls; |
3671 | 0 | if (ssl) |
3672 | 0 | SSL_set_mtu(ssl, (long)session->mtu); |
3673 | 0 | } |
3674 | | #endif /* COAP_CLIENT_SUPPORT */ |
3675 | | |
3676 | | void |
3677 | 0 | coap_dtls_free_session(coap_session_t *session) { |
3678 | 0 | SSL *ssl = (SSL *)session->tls; |
3679 | 0 | if (ssl) { |
3680 | 0 | if (!SSL_in_init(ssl) && !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) { |
3681 | 0 | int r = SSL_shutdown(ssl); |
3682 | 0 | if (r == 0) |
3683 | 0 | SSL_shutdown(ssl); |
3684 | 0 | } |
3685 | 0 | SSL_free(ssl); |
3686 | 0 | session->tls = NULL; |
3687 | 0 | if (session->context) |
3688 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CLOSED, session); |
3689 | 0 | } |
3690 | 0 | } |
3691 | | |
3692 | | ssize_t |
3693 | | coap_dtls_send(coap_session_t *session, |
3694 | 0 | const uint8_t *data, size_t data_len) { |
3695 | 0 | int r; |
3696 | 0 | SSL *ssl = (SSL *)session->tls; |
3697 | |
|
3698 | 0 | if (ssl == NULL) { |
3699 | 0 | session->dtls_event = COAP_EVENT_DTLS_CLOSED; |
3700 | 0 | return -1; |
3701 | 0 | } |
3702 | | |
3703 | 0 | session->dtls_event = -1; |
3704 | 0 | coap_log_debug("* %s: dtls: sent %4d bytes\n", |
3705 | 0 | coap_session_str(session), (int)data_len); |
3706 | 0 | ERR_clear_error(); |
3707 | 0 | r = SSL_write(ssl, data, (int)data_len); |
3708 | |
|
3709 | 0 | if (r <= 0) { |
3710 | 0 | int err = SSL_get_error(ssl, r); |
3711 | 0 | if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { |
3712 | 0 | r = 0; |
3713 | 0 | } else { |
3714 | 0 | if (err == SSL_ERROR_ZERO_RETURN) |
3715 | 0 | session->dtls_event = COAP_EVENT_DTLS_CLOSED; |
3716 | 0 | else if (err == SSL_ERROR_SSL) { |
3717 | 0 | unsigned long e = ERR_get_error(); |
3718 | |
|
3719 | 0 | coap_log_info("***%s: coap_dtls_send: cannot send PDU: %d: %s\n", |
3720 | 0 | coap_session_str(session), |
3721 | 0 | ERR_GET_REASON(e), ERR_reason_error_string(e)); |
3722 | 0 | session->dtls_event = COAP_EVENT_DTLS_ERROR; |
3723 | 0 | } else { |
3724 | 0 | coap_log_info("***%s: coap_dtls_send: cannot send PDU: %d\n", |
3725 | 0 | coap_session_str(session), err); |
3726 | 0 | } |
3727 | 0 | r = -1; |
3728 | 0 | } |
3729 | 0 | } |
3730 | |
|
3731 | 0 | if (session->dtls_event >= 0) { |
3732 | 0 | coap_handle_event_lkd(session->context, session->dtls_event, session); |
3733 | 0 | if (session->dtls_event == COAP_EVENT_DTLS_ERROR || |
3734 | 0 | session->dtls_event == COAP_EVENT_DTLS_CLOSED) { |
3735 | 0 | r = -1; |
3736 | 0 | } |
3737 | 0 | } |
3738 | |
|
3739 | 0 | return r; |
3740 | 0 | } |
3741 | | |
3742 | | int |
3743 | 0 | coap_dtls_is_context_timeout(void) { |
3744 | 0 | return 0; |
3745 | 0 | } |
3746 | | |
3747 | | coap_tick_t |
3748 | 0 | coap_dtls_get_context_timeout(void *dtls_context) { |
3749 | 0 | (void)dtls_context; |
3750 | 0 | return 0; |
3751 | 0 | } |
3752 | | |
3753 | | coap_tick_t |
3754 | 0 | coap_dtls_get_timeout(coap_session_t *session, coap_tick_t now COAP_UNUSED) { |
3755 | 0 | SSL *ssl = (SSL *)session->tls; |
3756 | 0 | coap_ssl_data *ssl_data; |
3757 | 0 | BIO *rbio; |
3758 | |
|
3759 | 0 | assert(ssl != NULL && session->state == COAP_SESSION_STATE_HANDSHAKE); |
3760 | 0 | rbio = ssl ? SSL_get_rbio(ssl) : NULL; |
3761 | 0 | ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; |
3762 | 0 | return ssl_data ? ssl_data->timeout : 1000; |
3763 | 0 | } |
3764 | | |
3765 | | /* |
3766 | | * return 1 timed out |
3767 | | * 0 still timing out |
3768 | | */ |
3769 | | int |
3770 | 0 | coap_dtls_handle_timeout(coap_session_t *session) { |
3771 | 0 | SSL *ssl = (SSL *)session->tls; |
3772 | |
|
3773 | 0 | if (ssl != NULL && session->state == COAP_SESSION_STATE_HANDSHAKE) { |
3774 | 0 | if ((++session->dtls_timeout_count > session->max_retransmit) || |
3775 | 0 | (DTLSv1_handle_timeout(ssl) < 0)) { |
3776 | | /* Too many retries */ |
3777 | 0 | coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); |
3778 | 0 | return 1; |
3779 | 0 | } |
3780 | 0 | return 0; |
3781 | 0 | } |
3782 | 0 | return 1; |
3783 | 0 | } |
3784 | | |
3785 | | #if COAP_SERVER_SUPPORT |
3786 | | int |
3787 | | coap_dtls_hello(coap_session_t *session, |
3788 | 0 | const uint8_t *data, size_t data_len) { |
3789 | 0 | coap_dtls_context_t *dtls = &((coap_openssl_context_t *)session->context->dtls_context)->dtls; |
3790 | 0 | coap_ssl_data *ssl_data; |
3791 | 0 | int r; |
3792 | 0 | BIO *rbio; |
3793 | |
|
3794 | 0 | SSL_set_mtu(dtls->ssl, (long)session->mtu); |
3795 | 0 | rbio = dtls->ssl ? SSL_get_rbio(dtls->ssl) : NULL; |
3796 | 0 | ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; |
3797 | 0 | assert(ssl_data != NULL); |
3798 | 0 | if (!ssl_data) { |
3799 | 0 | errno = ENOMEM; |
3800 | 0 | return -1; |
3801 | 0 | } |
3802 | 0 | if (ssl_data->pdu_len) { |
3803 | 0 | coap_log_err("** %s: Previous data not read %u bytes\n", |
3804 | 0 | coap_session_str(session), ssl_data->pdu_len); |
3805 | 0 | } |
3806 | 0 | ssl_data->session = session; |
3807 | 0 | ssl_data->pdu = data; |
3808 | 0 | ssl_data->pdu_len = (unsigned)data_len; |
3809 | 0 | r = DTLSv1_listen(dtls->ssl, dtls->bio_addr); |
3810 | 0 | if (r <= 0) { |
3811 | 0 | int err = SSL_get_error(dtls->ssl, r); |
3812 | 0 | if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { |
3813 | | /* Got a ClientHello, sent-out a VerifyRequest */ |
3814 | 0 | r = 0; |
3815 | 0 | } |
3816 | 0 | } else { |
3817 | | /* Got a valid answer to a VerifyRequest */ |
3818 | 0 | r = 1; |
3819 | 0 | } |
3820 | | |
3821 | | /* |
3822 | | * Cannot check if data is left on the stack in error as DTLSv1_listen() |
3823 | | * only does a 'peek' read of the incoming data. |
3824 | | * |
3825 | | */ |
3826 | 0 | return r; |
3827 | 0 | } |
3828 | | #endif /* COAP_SERVER_SUPPORT */ |
3829 | | |
3830 | | int |
3831 | 0 | coap_dtls_receive(coap_session_t *session, const uint8_t *data, size_t data_len) { |
3832 | 0 | coap_ssl_data *ssl_data; |
3833 | 0 | SSL *ssl = (SSL *)session->tls; |
3834 | 0 | int r; |
3835 | 0 | BIO *rbio; |
3836 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
3837 | | int retry = 0; |
3838 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
3839 | |
|
3840 | 0 | assert(ssl != NULL); |
3841 | | |
3842 | 0 | int in_init = SSL_in_init(ssl); |
3843 | 0 | uint8_t pdu[COAP_RXBUFFER_SIZE]; |
3844 | 0 | rbio = ssl ? SSL_get_rbio(ssl) : NULL; |
3845 | 0 | ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; |
3846 | 0 | if (!ssl_data) { |
3847 | 0 | errno = ENOTCONN; |
3848 | 0 | return -1; |
3849 | 0 | } |
3850 | | |
3851 | 0 | if (ssl_data->pdu_len) { |
3852 | 0 | coap_log_err("** %s: Previous data not read %u bytes\n", |
3853 | 0 | coap_session_str(session), ssl_data->pdu_len); |
3854 | 0 | } |
3855 | 0 | ssl_data->pdu = data; |
3856 | 0 | ssl_data->pdu_len = (unsigned)data_len; |
3857 | |
|
3858 | 0 | session->dtls_event = -1; |
3859 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
3860 | | retry: |
3861 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
3862 | 0 | ERR_clear_error(); |
3863 | 0 | r = SSL_read(ssl, pdu, (int)sizeof(pdu)); |
3864 | 0 | if (r > 0) { |
3865 | 0 | coap_log_debug("* %s: dtls: recv %4d bytes\n", |
3866 | 0 | coap_session_str(session), r); |
3867 | 0 | r = coap_handle_dgram(session->context, session, pdu, (size_t)r); |
3868 | | /* Possible there was a DTLS error */ |
3869 | 0 | ssl_data = (coap_ssl_data *)BIO_get_data(rbio); |
3870 | 0 | goto finished; |
3871 | 0 | } else { |
3872 | 0 | int err = SSL_get_error(ssl, r); |
3873 | 0 | if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { |
3874 | 0 | if (in_init && SSL_is_init_finished(ssl)) { |
3875 | 0 | coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", |
3876 | 0 | coap_session_str(session), SSL_get_cipher_name(ssl)); |
3877 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
3878 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
3879 | 0 | } |
3880 | 0 | r = 0; |
3881 | 0 | } else { |
3882 | 0 | if (err == SSL_ERROR_ZERO_RETURN) /* Got a close notify alert from the remote side */ |
3883 | 0 | session->dtls_event = COAP_EVENT_DTLS_CLOSED; |
3884 | 0 | else if (err == SSL_ERROR_SSL) { |
3885 | 0 | unsigned long e = ERR_get_error(); |
3886 | |
|
3887 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
3888 | | #include <openssl/proverr.h> |
3889 | | if (ERR_GET_REASON(e) == PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES && !retry) { |
3890 | | /* Loading trust store - first access causes a directory read error */ |
3891 | | retry = 1; |
3892 | | goto retry; |
3893 | | } |
3894 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ |
3895 | 0 | coap_log_info("***%s: coap_dtls_receive: cannot recv PDU: %d: %s\n", |
3896 | 0 | coap_session_str(session), |
3897 | 0 | ERR_GET_REASON(e), ERR_reason_error_string(e)); |
3898 | 0 | session->dtls_event = COAP_EVENT_DTLS_ERROR; |
3899 | 0 | } else { |
3900 | 0 | coap_log_info("***%s: coap_dtls_receive: cannot send PDU %d\n", |
3901 | 0 | coap_session_str(session), err); |
3902 | 0 | } |
3903 | 0 | r = -1; |
3904 | 0 | } |
3905 | 0 | if (session->dtls_event >= 0) { |
3906 | 0 | coap_handle_event_lkd(session->context, session->dtls_event, session); |
3907 | 0 | if (session->dtls_event == COAP_EVENT_DTLS_ERROR || |
3908 | 0 | session->dtls_event == COAP_EVENT_DTLS_CLOSED) { |
3909 | | /* Cause disconnect on a read */ |
3910 | 0 | coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); |
3911 | 0 | ssl_data = NULL; |
3912 | 0 | r = -1; |
3913 | 0 | } |
3914 | 0 | } |
3915 | 0 | } |
3916 | | |
3917 | 0 | finished: |
3918 | 0 | if (ssl_data && ssl_data->pdu_len) { |
3919 | | /* pdu data is held on stack which will not stay there */ |
3920 | 0 | coap_log_debug("coap_dtls_receive: ret %d: remaining data %u\n", r, ssl_data->pdu_len); |
3921 | 0 | ssl_data->pdu_len = 0; |
3922 | 0 | ssl_data->pdu = NULL; |
3923 | 0 | } |
3924 | 0 | return r; |
3925 | 0 | } |
3926 | | |
3927 | | unsigned int |
3928 | 0 | coap_dtls_get_overhead(coap_session_t *session) { |
3929 | 0 | unsigned int overhead = 37; |
3930 | 0 | const SSL_CIPHER *s_ciph = NULL; |
3931 | 0 | if (session->tls != NULL) |
3932 | 0 | s_ciph = SSL_get_current_cipher(session->tls); |
3933 | 0 | if (s_ciph) { |
3934 | 0 | unsigned int ivlen, maclen, blocksize = 1, pad = 0; |
3935 | |
|
3936 | 0 | const EVP_CIPHER *e_ciph; |
3937 | 0 | const EVP_MD *e_md; |
3938 | 0 | char cipher[128]; |
3939 | |
|
3940 | 0 | e_ciph = EVP_get_cipherbynid(SSL_CIPHER_get_cipher_nid(s_ciph)); |
3941 | |
|
3942 | 0 | switch (EVP_CIPHER_mode(e_ciph)) { |
3943 | 0 | case EVP_CIPH_GCM_MODE: |
3944 | 0 | ivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN; |
3945 | 0 | maclen = EVP_GCM_TLS_TAG_LEN; |
3946 | 0 | break; |
3947 | | |
3948 | 0 | case EVP_CIPH_CCM_MODE: |
3949 | 0 | ivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN; |
3950 | 0 | SSL_CIPHER_description(s_ciph, cipher, sizeof(cipher)); |
3951 | 0 | if (strstr(cipher, "CCM8")) |
3952 | 0 | maclen = 8; |
3953 | 0 | else |
3954 | 0 | maclen = 16; |
3955 | 0 | break; |
3956 | | |
3957 | 0 | case EVP_CIPH_CBC_MODE: |
3958 | 0 | e_md = EVP_get_digestbynid(SSL_CIPHER_get_digest_nid(s_ciph)); |
3959 | 0 | blocksize = EVP_CIPHER_block_size(e_ciph); |
3960 | 0 | ivlen = EVP_CIPHER_iv_length(e_ciph); |
3961 | 0 | pad = 1; |
3962 | 0 | maclen = EVP_MD_size(e_md); |
3963 | 0 | break; |
3964 | | |
3965 | 0 | case EVP_CIPH_STREAM_CIPHER: |
3966 | | /* Seen with PSK-CHACHA20-POLY1305 */ |
3967 | 0 | ivlen = 8; |
3968 | 0 | maclen = 8; |
3969 | 0 | break; |
3970 | | |
3971 | 0 | default: |
3972 | 0 | SSL_CIPHER_description(s_ciph, cipher, sizeof(cipher)); |
3973 | 0 | coap_log_warn("Unknown overhead for DTLS with cipher %s\n", |
3974 | 0 | cipher); |
3975 | 0 | ivlen = 8; |
3976 | 0 | maclen = 16; |
3977 | 0 | break; |
3978 | 0 | } |
3979 | 0 | overhead = DTLS1_RT_HEADER_LENGTH + ivlen + maclen + blocksize - 1 + pad; |
3980 | 0 | } |
3981 | 0 | return overhead; |
3982 | 0 | } |
3983 | | |
3984 | | #if !COAP_DISABLE_TCP |
3985 | | #if COAP_CLIENT_SUPPORT |
3986 | | void * |
3987 | 0 | coap_tls_new_client_session(coap_session_t *session) { |
3988 | 0 | BIO *bio = NULL; |
3989 | 0 | SSL *ssl = NULL; |
3990 | 0 | int r; |
3991 | 0 | coap_openssl_context_t *context = ((coap_openssl_context_t *)session->context->dtls_context); |
3992 | 0 | coap_tls_context_t *tls = &context->tls; |
3993 | |
|
3994 | 0 | ssl = SSL_new(tls->ctx); |
3995 | 0 | if (!ssl) |
3996 | 0 | goto error; |
3997 | 0 | bio = BIO_new(tls->meth); |
3998 | 0 | if (!bio) |
3999 | 0 | goto error; |
4000 | 0 | BIO_set_data(bio, session); |
4001 | 0 | SSL_set_bio(ssl, bio, bio); |
4002 | 0 | SSL_set_app_data(ssl, session); |
4003 | |
|
4004 | 0 | if (!setup_client_ssl_session(session, ssl)) |
4005 | 0 | return 0; |
4006 | | |
4007 | 0 | r = SSL_connect(ssl); |
4008 | 0 | if (r == -1) { |
4009 | 0 | int ret = SSL_get_error(ssl, r); |
4010 | 0 | if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) |
4011 | 0 | r = 0; |
4012 | 0 | if (ret == SSL_ERROR_WANT_READ) |
4013 | 0 | session->sock.flags |= COAP_SOCKET_WANT_READ; |
4014 | 0 | if (ret == SSL_ERROR_WANT_WRITE) { |
4015 | 0 | session->sock.flags |= COAP_SOCKET_WANT_WRITE; |
4016 | 0 | #ifdef COAP_EPOLL_SUPPORT |
4017 | 0 | coap_epoll_ctl_mod(&session->sock, |
4018 | 0 | EPOLLOUT | |
4019 | 0 | ((session->sock.flags & COAP_SOCKET_WANT_READ) ? |
4020 | 0 | EPOLLIN : 0), |
4021 | 0 | __func__); |
4022 | 0 | #endif /* COAP_EPOLL_SUPPORT */ |
4023 | 0 | } |
4024 | 0 | } |
4025 | |
|
4026 | 0 | if (r == 0) |
4027 | 0 | goto error; |
4028 | | |
4029 | 0 | session->tls = ssl; |
4030 | 0 | if (SSL_is_init_finished(ssl)) { |
4031 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4032 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4033 | 0 | } |
4034 | |
|
4035 | 0 | return ssl; |
4036 | | |
4037 | 0 | error: |
4038 | 0 | if (ssl) |
4039 | 0 | SSL_free(ssl); |
4040 | 0 | return NULL; |
4041 | 0 | } |
4042 | | #endif /* COAP_CLIENT_SUPPORT */ |
4043 | | |
4044 | | #if COAP_SERVER_SUPPORT |
4045 | | void * |
4046 | 0 | coap_tls_new_server_session(coap_session_t *session) { |
4047 | 0 | BIO *bio = NULL; |
4048 | 0 | SSL *ssl = NULL; |
4049 | 0 | coap_tls_context_t *tls = &((coap_openssl_context_t *)session->context->dtls_context)->tls; |
4050 | 0 | int r; |
4051 | 0 | const coap_bin_const_t *psk_hint; |
4052 | |
|
4053 | 0 | ssl = SSL_new(tls->ctx); |
4054 | 0 | if (!ssl) |
4055 | 0 | goto error; |
4056 | 0 | bio = BIO_new(tls->meth); |
4057 | 0 | if (!bio) |
4058 | 0 | goto error; |
4059 | 0 | BIO_set_data(bio, session); |
4060 | 0 | SSL_set_bio(ssl, bio, bio); |
4061 | 0 | SSL_set_app_data(ssl, session); |
4062 | |
|
4063 | 0 | psk_hint = coap_get_session_server_psk_hint(session); |
4064 | 0 | if (psk_hint != NULL && psk_hint->length) { |
4065 | 0 | char *hint = OPENSSL_malloc(psk_hint->length + 1); |
4066 | |
|
4067 | 0 | if (hint) { |
4068 | 0 | memcpy(hint, psk_hint->s, psk_hint->length); |
4069 | 0 | hint[psk_hint->length] = '\000'; |
4070 | 0 | SSL_use_psk_identity_hint(ssl, hint); |
4071 | 0 | OPENSSL_free(hint); |
4072 | 0 | } else { |
4073 | 0 | coap_log_warn("hint malloc failure\n"); |
4074 | 0 | } |
4075 | 0 | } |
4076 | |
|
4077 | 0 | r = SSL_accept(ssl); |
4078 | 0 | if (r == -1) { |
4079 | 0 | int err = SSL_get_error(ssl, r); |
4080 | 0 | if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) |
4081 | 0 | r = 0; |
4082 | 0 | if (err == SSL_ERROR_WANT_READ) |
4083 | 0 | session->sock.flags |= COAP_SOCKET_WANT_READ; |
4084 | 0 | if (err == SSL_ERROR_WANT_WRITE) { |
4085 | 0 | session->sock.flags |= COAP_SOCKET_WANT_WRITE; |
4086 | 0 | #ifdef COAP_EPOLL_SUPPORT |
4087 | 0 | coap_epoll_ctl_mod(&session->sock, |
4088 | 0 | EPOLLOUT | |
4089 | 0 | ((session->sock.flags & COAP_SOCKET_WANT_READ) ? |
4090 | 0 | EPOLLIN : 0), |
4091 | 0 | __func__); |
4092 | 0 | #endif /* COAP_EPOLL_SUPPORT */ |
4093 | 0 | } |
4094 | 0 | } |
4095 | |
|
4096 | 0 | if (r == 0) |
4097 | 0 | goto error; |
4098 | | |
4099 | 0 | session->tls = ssl; |
4100 | 0 | if (SSL_is_init_finished(ssl)) { |
4101 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4102 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4103 | 0 | } |
4104 | |
|
4105 | | #if COAP_DTLS_RETRANSMIT_MS != 1000 |
4106 | | #if OPENSSL_VERSION_NUMBER >= 0x10101000L |
4107 | | if (session->proto == COAP_PROTO_DTLS) { |
4108 | | DTLS_set_timer_cb(ssl, timer_cb); |
4109 | | } |
4110 | | #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ |
4111 | | #endif /* COAP_DTLS_RETRANSMIT_MS != 1000 */ |
4112 | |
|
4113 | 0 | return ssl; |
4114 | | |
4115 | 0 | error: |
4116 | 0 | if (ssl) |
4117 | 0 | SSL_free(ssl); |
4118 | 0 | return NULL; |
4119 | 0 | } |
4120 | | #endif /* COAP_SERVER_SUPPORT */ |
4121 | | |
4122 | | void |
4123 | 0 | coap_tls_free_session(coap_session_t *session) { |
4124 | 0 | SSL *ssl = (SSL *)session->tls; |
4125 | 0 | if (ssl) { |
4126 | 0 | if (!SSL_in_init(ssl) && !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) { |
4127 | 0 | int r = SSL_shutdown(ssl); |
4128 | 0 | if (r == 0) |
4129 | 0 | SSL_shutdown(ssl); |
4130 | 0 | } |
4131 | 0 | SSL_free(ssl); |
4132 | 0 | session->tls = NULL; |
4133 | 0 | if (session->context) |
4134 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CLOSED, session); |
4135 | 0 | } |
4136 | 0 | } |
4137 | | |
4138 | | /* |
4139 | | * strm |
4140 | | * return +ve Number of bytes written. |
4141 | | * -1 Error (error in errno). |
4142 | | */ |
4143 | | ssize_t |
4144 | 0 | coap_tls_write(coap_session_t *session, const uint8_t *data, size_t data_len) { |
4145 | 0 | SSL *ssl = (SSL *)session->tls; |
4146 | 0 | int r, in_init; |
4147 | |
|
4148 | 0 | if (ssl == NULL) |
4149 | 0 | return -1; |
4150 | | |
4151 | 0 | in_init = !SSL_is_init_finished(ssl); |
4152 | 0 | session->dtls_event = -1; |
4153 | 0 | ERR_clear_error(); |
4154 | 0 | r = SSL_write(ssl, data, (int)data_len); |
4155 | |
|
4156 | 0 | if (r <= 0) { |
4157 | 0 | int err = SSL_get_error(ssl, r); |
4158 | 0 | if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { |
4159 | 0 | if (in_init && SSL_is_init_finished(ssl)) { |
4160 | 0 | coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", |
4161 | 0 | coap_session_str(session), SSL_get_cipher_name(ssl)); |
4162 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4163 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4164 | 0 | } |
4165 | 0 | if (err == SSL_ERROR_WANT_READ) |
4166 | 0 | session->sock.flags |= COAP_SOCKET_WANT_READ; |
4167 | 0 | else if (err == SSL_ERROR_WANT_WRITE) { |
4168 | 0 | session->sock.flags |= COAP_SOCKET_WANT_WRITE; |
4169 | 0 | #ifdef COAP_EPOLL_SUPPORT |
4170 | 0 | coap_epoll_ctl_mod(&session->sock, |
4171 | 0 | EPOLLOUT | |
4172 | 0 | ((session->sock.flags & COAP_SOCKET_WANT_READ) ? |
4173 | 0 | EPOLLIN : 0), |
4174 | 0 | __func__); |
4175 | 0 | #endif /* COAP_EPOLL_SUPPORT */ |
4176 | 0 | } |
4177 | 0 | r = 0; |
4178 | 0 | } else { |
4179 | 0 | if (err == SSL_ERROR_ZERO_RETURN) |
4180 | 0 | session->dtls_event = COAP_EVENT_DTLS_CLOSED; |
4181 | 0 | else if (err == SSL_ERROR_SSL) { |
4182 | 0 | unsigned long e = ERR_get_error(); |
4183 | |
|
4184 | 0 | coap_log_info("***%s: coap_tls_write: cannot send PDU: %d: %s\n", |
4185 | 0 | coap_session_str(session), |
4186 | 0 | ERR_GET_REASON(e), ERR_reason_error_string(e)); |
4187 | 0 | session->dtls_event = COAP_EVENT_DTLS_ERROR; |
4188 | 0 | } else { |
4189 | 0 | coap_log_info("***%s: coap_tls_send: cannot send PDU: %d\n", |
4190 | 0 | coap_session_str(session), err); |
4191 | 0 | } |
4192 | 0 | r = -1; |
4193 | 0 | } |
4194 | 0 | } else if (in_init && SSL_is_init_finished(ssl)) { |
4195 | 0 | coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", |
4196 | 0 | coap_session_str(session), SSL_get_cipher_name(ssl)); |
4197 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4198 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4199 | 0 | } |
4200 | |
|
4201 | 0 | if (session->dtls_event >= 0) { |
4202 | 0 | coap_handle_event_lkd(session->context, session->dtls_event, session); |
4203 | 0 | if (session->dtls_event == COAP_EVENT_DTLS_ERROR || |
4204 | 0 | session->dtls_event == COAP_EVENT_DTLS_CLOSED) { |
4205 | 0 | r = -1; |
4206 | 0 | } |
4207 | 0 | } |
4208 | |
|
4209 | 0 | if (r >= 0) { |
4210 | 0 | if (r == (ssize_t)data_len) |
4211 | 0 | coap_log_debug("* %s: tls: sent %4d bytes\n", |
4212 | 0 | coap_session_str(session), r); |
4213 | 0 | else |
4214 | 0 | coap_log_debug("* %s: tls: sent %4d of %4" PRIdS " bytes\n", |
4215 | 0 | coap_session_str(session), r, data_len); |
4216 | 0 | } |
4217 | 0 | return r; |
4218 | 0 | } |
4219 | | |
4220 | | /* |
4221 | | * strm |
4222 | | * return >=0 Number of bytes read. |
4223 | | * -1 Error (error in errno). |
4224 | | */ |
4225 | | ssize_t |
4226 | 0 | coap_tls_read(coap_session_t *session, uint8_t *data, size_t data_len) { |
4227 | 0 | SSL *ssl = (SSL *)session->tls; |
4228 | 0 | int r, in_init; |
4229 | |
|
4230 | 0 | if (ssl == NULL) { |
4231 | 0 | errno = ENXIO; |
4232 | 0 | return -1; |
4233 | 0 | } |
4234 | | |
4235 | 0 | in_init = !SSL_is_init_finished(ssl); |
4236 | 0 | session->dtls_event = -1; |
4237 | 0 | ERR_clear_error(); |
4238 | 0 | r = SSL_read(ssl, data, (int)data_len); |
4239 | 0 | if (r <= 0) { |
4240 | 0 | int err = SSL_get_error(ssl, r); |
4241 | 0 | if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { |
4242 | 0 | if (in_init && SSL_is_init_finished(ssl)) { |
4243 | 0 | coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", |
4244 | 0 | coap_session_str(session), SSL_get_cipher_name(ssl)); |
4245 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4246 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4247 | 0 | } |
4248 | 0 | if (err == SSL_ERROR_WANT_READ) |
4249 | 0 | session->sock.flags |= COAP_SOCKET_WANT_READ; |
4250 | 0 | if (err == SSL_ERROR_WANT_WRITE) { |
4251 | 0 | session->sock.flags |= COAP_SOCKET_WANT_WRITE; |
4252 | 0 | #ifdef COAP_EPOLL_SUPPORT |
4253 | 0 | coap_epoll_ctl_mod(&session->sock, |
4254 | 0 | EPOLLOUT | |
4255 | 0 | ((session->sock.flags & COAP_SOCKET_WANT_READ) ? |
4256 | 0 | EPOLLIN : 0), |
4257 | 0 | __func__); |
4258 | 0 | #endif /* COAP_EPOLL_SUPPORT */ |
4259 | 0 | } |
4260 | 0 | r = 0; |
4261 | 0 | } else { |
4262 | 0 | if (err == SSL_ERROR_ZERO_RETURN) /* Got a close notify alert from the remote side */ |
4263 | 0 | session->dtls_event = COAP_EVENT_DTLS_CLOSED; |
4264 | 0 | else if (err == SSL_ERROR_SSL) { |
4265 | 0 | unsigned long e = ERR_get_error(); |
4266 | |
|
4267 | 0 | coap_log_info("***%s: coap_tls_read: cannot recv PDU: %d: %s\n", |
4268 | 0 | coap_session_str(session), |
4269 | 0 | ERR_GET_REASON(e), ERR_reason_error_string(e)); |
4270 | 0 | session->dtls_event = COAP_EVENT_DTLS_ERROR; |
4271 | 0 | } else { |
4272 | 0 | coap_log_info("***%s: coap_tls_read: cannot read PDU %d\n", |
4273 | 0 | coap_session_str(session), err); |
4274 | 0 | } |
4275 | 0 | r = -1; |
4276 | 0 | } |
4277 | 0 | } else if (in_init && SSL_is_init_finished(ssl)) { |
4278 | 0 | coap_dtls_log(COAP_LOG_INFO, "* %s: Using cipher: %s\n", |
4279 | 0 | coap_session_str(session), SSL_get_cipher_name(ssl)); |
4280 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CONNECTED, session); |
4281 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_establish(session); |
4282 | 0 | } |
4283 | |
|
4284 | 0 | if (session->dtls_event >= 0) { |
4285 | 0 | coap_handle_event_lkd(session->context, session->dtls_event, session); |
4286 | 0 | if (session->dtls_event == COAP_EVENT_DTLS_ERROR || |
4287 | 0 | session->dtls_event == COAP_EVENT_DTLS_CLOSED) { |
4288 | | /* Cause disconnect on a read */ |
4289 | 0 | coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); |
4290 | 0 | r = -1; |
4291 | 0 | } |
4292 | 0 | } |
4293 | |
|
4294 | 0 | if (r > 0) { |
4295 | 0 | coap_log_debug("* %s: tls: recv %4d bytes\n", |
4296 | 0 | coap_session_str(session), r); |
4297 | 0 | } |
4298 | 0 | return r; |
4299 | 0 | } |
4300 | | #endif /* !COAP_DISABLE_TCP */ |
4301 | | |
4302 | | #if COAP_SERVER_SUPPORT |
4303 | | coap_digest_ctx_t * |
4304 | 0 | coap_digest_setup(void) { |
4305 | 0 | EVP_MD_CTX *digest_ctx = EVP_MD_CTX_new(); |
4306 | |
|
4307 | 0 | if (digest_ctx) { |
4308 | 0 | EVP_DigestInit_ex(digest_ctx, EVP_sha256(), NULL); |
4309 | 0 | } |
4310 | 0 | return digest_ctx; |
4311 | 0 | } |
4312 | | |
4313 | | void |
4314 | 0 | coap_digest_free(coap_digest_ctx_t *digest_ctx) { |
4315 | 0 | if (digest_ctx) |
4316 | 0 | EVP_MD_CTX_free(digest_ctx); |
4317 | 0 | } |
4318 | | |
4319 | | int |
4320 | | coap_digest_update(coap_digest_ctx_t *digest_ctx, |
4321 | | const uint8_t *data, |
4322 | 0 | size_t data_len) { |
4323 | 0 | return EVP_DigestUpdate(digest_ctx, data, data_len); |
4324 | 0 | } |
4325 | | |
4326 | | int |
4327 | | coap_digest_final(coap_digest_ctx_t *digest_ctx, |
4328 | 0 | coap_digest_t *digest_buffer) { |
4329 | 0 | unsigned int size = sizeof(coap_digest_t); |
4330 | 0 | int ret = EVP_DigestFinal_ex(digest_ctx, (uint8_t *)digest_buffer, &size); |
4331 | |
|
4332 | 0 | coap_digest_free(digest_ctx); |
4333 | 0 | return ret; |
4334 | 0 | } |
4335 | | #endif /* COAP_SERVER_SUPPORT */ |
4336 | | |
4337 | | #if COAP_WS_SUPPORT || COAP_OSCORE_SUPPORT |
4338 | | static void |
4339 | 0 | coap_crypto_output_errors(const char *prefix) { |
4340 | | #if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_WARN |
4341 | | (void)prefix; |
4342 | | #else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN */ |
4343 | 0 | unsigned long e; |
4344 | |
|
4345 | 0 | while ((e = ERR_get_error())) |
4346 | 0 | coap_log_warn("%s: %s%s\n", |
4347 | 0 | prefix, |
4348 | 0 | ERR_reason_error_string(e), |
4349 | 0 | ssl_function_definition(e)); |
4350 | 0 | #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN */ |
4351 | 0 | } |
4352 | | #endif /* COAP_WS_SUPPORT || COAP_OSCORE_SUPPORT */ |
4353 | | |
4354 | | #if COAP_WS_SUPPORT |
4355 | | /* |
4356 | | * The struct hash_algs and the function get_hash_alg() are used to |
4357 | | * determine which hash type to use for creating the required hash object. |
4358 | | */ |
4359 | | static struct hash_algs { |
4360 | | cose_alg_t alg; |
4361 | | const EVP_MD *(*get_hash)(void); |
4362 | | size_t length; /* in bytes */ |
4363 | | } hashs[] = { |
4364 | | {COSE_ALGORITHM_SHA_1, EVP_sha1, 20}, |
4365 | | {COSE_ALGORITHM_SHA_256_64, EVP_sha256, 8}, |
4366 | | {COSE_ALGORITHM_SHA_256_256, EVP_sha256, 32}, |
4367 | | {COSE_ALGORITHM_SHA_512, EVP_sha512, 64}, |
4368 | | }; |
4369 | | |
4370 | | static const EVP_MD * |
4371 | 0 | get_hash_alg(cose_alg_t alg, size_t *length) { |
4372 | 0 | size_t idx; |
4373 | |
|
4374 | 0 | for (idx = 0; idx < sizeof(hashs) / sizeof(struct hash_algs); idx++) { |
4375 | 0 | if (hashs[idx].alg == alg) { |
4376 | 0 | *length = hashs[idx].length; |
4377 | 0 | return hashs[idx].get_hash(); |
4378 | 0 | } |
4379 | 0 | } |
4380 | 0 | coap_log_debug("get_hash_alg: COSE hash %d not supported\n", alg); |
4381 | 0 | return NULL; |
4382 | 0 | } |
4383 | | |
4384 | | int |
4385 | | coap_crypto_hash(cose_alg_t alg, |
4386 | | const coap_bin_const_t *data, |
4387 | 0 | coap_bin_const_t **hash) { |
4388 | 0 | unsigned int length; |
4389 | 0 | const EVP_MD *evp_md; |
4390 | 0 | EVP_MD_CTX *evp_ctx = NULL; |
4391 | 0 | coap_binary_t *dummy = NULL; |
4392 | 0 | size_t hash_length; |
4393 | |
|
4394 | 0 | if ((evp_md = get_hash_alg(alg, &hash_length)) == NULL) { |
4395 | 0 | coap_log_debug("coap_crypto_hash: algorithm %d not supported\n", alg); |
4396 | 0 | return 0; |
4397 | 0 | } |
4398 | 0 | evp_ctx = EVP_MD_CTX_new(); |
4399 | 0 | if (evp_ctx == NULL) |
4400 | 0 | goto error; |
4401 | 0 | if (EVP_DigestInit_ex(evp_ctx, evp_md, NULL) == 0) |
4402 | 0 | goto error; |
4403 | 0 | ; |
4404 | 0 | if (EVP_DigestUpdate(evp_ctx, data->s, data->length) == 0) |
4405 | 0 | goto error; |
4406 | 0 | ; |
4407 | 0 | dummy = coap_new_binary(EVP_MAX_MD_SIZE); |
4408 | 0 | if (dummy == NULL) |
4409 | 0 | goto error; |
4410 | 0 | if (EVP_DigestFinal_ex(evp_ctx, dummy->s, &length) == 0) |
4411 | 0 | goto error; |
4412 | 0 | dummy->length = length; |
4413 | 0 | if (hash_length < dummy->length) |
4414 | 0 | dummy->length = hash_length; |
4415 | 0 | *hash = (coap_bin_const_t *)(dummy); |
4416 | 0 | EVP_MD_CTX_free(evp_ctx); |
4417 | 0 | return 1; |
4418 | | |
4419 | 0 | error: |
4420 | 0 | coap_crypto_output_errors("coap_crypto_hash"); |
4421 | 0 | coap_delete_binary(dummy); |
4422 | 0 | if (evp_ctx) |
4423 | 0 | EVP_MD_CTX_free(evp_ctx); |
4424 | 0 | return 0; |
4425 | 0 | } |
4426 | | #endif /* COAP_WS_SUPPORT */ |
4427 | | |
4428 | | #if COAP_OSCORE_SUPPORT |
4429 | | int |
4430 | 0 | coap_oscore_is_supported(void) { |
4431 | 0 | return 1; |
4432 | 0 | } |
4433 | | |
4434 | | #include <openssl/evp.h> |
4435 | | #include <openssl/hmac.h> |
4436 | | |
4437 | | /* |
4438 | | * The struct cipher_algs and the function get_cipher_alg() are used to |
4439 | | * determine which cipher type to use for creating the required cipher |
4440 | | * suite object. |
4441 | | */ |
4442 | | static struct cipher_algs { |
4443 | | cose_alg_t alg; |
4444 | | const EVP_CIPHER *(*get_cipher)(void); |
4445 | | } ciphers[] = {{COSE_ALGORITHM_AES_CCM_16_64_128, EVP_aes_128_ccm}, |
4446 | | {COSE_ALGORITHM_AES_CCM_16_64_256, EVP_aes_256_ccm} |
4447 | | }; |
4448 | | |
4449 | | static const EVP_CIPHER * |
4450 | 0 | get_cipher_alg(cose_alg_t alg) { |
4451 | 0 | size_t idx; |
4452 | |
|
4453 | 0 | for (idx = 0; idx < sizeof(ciphers) / sizeof(struct cipher_algs); idx++) { |
4454 | 0 | if (ciphers[idx].alg == alg) |
4455 | 0 | return ciphers[idx].get_cipher(); |
4456 | 0 | } |
4457 | 0 | coap_log_debug("get_cipher_alg: COSE cipher %d not supported\n", alg); |
4458 | 0 | return NULL; |
4459 | 0 | } |
4460 | | |
4461 | | /* |
4462 | | * The struct hmac_algs and the function get_hmac_alg() are used to |
4463 | | * determine which hmac type to use for creating the required hmac |
4464 | | * suite object. |
4465 | | */ |
4466 | | static struct hmac_algs { |
4467 | | cose_hmac_alg_t hmac_alg; |
4468 | | const EVP_MD *(*get_hmac)(void); |
4469 | | } hmacs[] = { |
4470 | | {COSE_HMAC_ALG_HMAC256_256, EVP_sha256}, |
4471 | | {COSE_HMAC_ALG_HMAC384_384, EVP_sha384}, |
4472 | | {COSE_HMAC_ALG_HMAC512_512, EVP_sha512}, |
4473 | | }; |
4474 | | |
4475 | | static const EVP_MD * |
4476 | 0 | get_hmac_alg(cose_hmac_alg_t hmac_alg) { |
4477 | 0 | size_t idx; |
4478 | |
|
4479 | 0 | for (idx = 0; idx < sizeof(hmacs) / sizeof(struct hmac_algs); idx++) { |
4480 | 0 | if (hmacs[idx].hmac_alg == hmac_alg) |
4481 | 0 | return hmacs[idx].get_hmac(); |
4482 | 0 | } |
4483 | 0 | coap_log_debug("get_hmac_alg: COSE HMAC %d not supported\n", hmac_alg); |
4484 | 0 | return NULL; |
4485 | 0 | } |
4486 | | |
4487 | | int |
4488 | 0 | coap_crypto_check_cipher_alg(cose_alg_t alg) { |
4489 | 0 | return get_cipher_alg(alg) != NULL; |
4490 | 0 | } |
4491 | | |
4492 | | int |
4493 | 0 | coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg) { |
4494 | 0 | cose_hmac_alg_t hmac_alg; |
4495 | |
|
4496 | 0 | if (!cose_get_hmac_alg_for_hkdf(hkdf_alg, &hmac_alg)) |
4497 | 0 | return 0; |
4498 | 0 | return get_hmac_alg(hmac_alg) != NULL; |
4499 | 0 | } |
4500 | | |
4501 | | #define C(Func) \ |
4502 | 0 | if (1 != (Func)) { \ |
4503 | 0 | goto error; \ |
4504 | 0 | } |
4505 | | |
4506 | | int |
4507 | | coap_crypto_aead_encrypt(const coap_crypto_param_t *params, |
4508 | | coap_bin_const_t *data, |
4509 | | coap_bin_const_t *aad, |
4510 | | uint8_t *result, |
4511 | 0 | size_t *max_result_len) { |
4512 | 0 | const EVP_CIPHER *cipher; |
4513 | 0 | const coap_crypto_aes_ccm_t *ccm; |
4514 | 0 | int tmp; |
4515 | 0 | int result_len = (int)(*max_result_len & INT_MAX); |
4516 | 0 | EVP_CIPHER_CTX *ctx; |
4517 | |
|
4518 | 0 | if (data == NULL) |
4519 | 0 | return 0; |
4520 | | |
4521 | 0 | assert(params != NULL); |
4522 | 0 | if (!params || ((cipher = get_cipher_alg(params->alg)) == NULL)) { |
4523 | 0 | return 0; |
4524 | 0 | } |
4525 | | |
4526 | | /* TODO: set evp_md depending on params->alg */ |
4527 | 0 | ccm = ¶ms->params.aes; |
4528 | |
|
4529 | 0 | ctx = EVP_CIPHER_CTX_new(); |
4530 | 0 | if (!ctx) |
4531 | 0 | return 0; |
4532 | | |
4533 | | /* EVP_CIPHER_CTX_init(ctx); */ |
4534 | 0 | C(EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)); |
4535 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, (int)ccm->l, NULL)); |
4536 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, |
4537 | 0 | EVP_CTRL_AEAD_SET_IVLEN, |
4538 | 0 | (int)(15 - ccm->l), |
4539 | 0 | NULL)); |
4540 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, (int)ccm->tag_len, NULL)); |
4541 | 0 | C(EVP_EncryptInit_ex(ctx, NULL, NULL, ccm->key.s, ccm->nonce)); |
4542 | | /* C(EVP_CIPHER_CTX_set_padding(ctx, 0)); */ |
4543 | |
|
4544 | 0 | C(EVP_EncryptUpdate(ctx, NULL, &result_len, NULL, (int)data->length)); |
4545 | 0 | if (aad && aad->s && (aad->length > 0)) { |
4546 | 0 | C(EVP_EncryptUpdate(ctx, NULL, &result_len, aad->s, (int)aad->length)); |
4547 | 0 | } |
4548 | 0 | C(EVP_EncryptUpdate(ctx, result, &result_len, data->s, (int)data->length)); |
4549 | | /* C(EVP_EncryptFinal_ex(ctx, result + result_len, &tmp)); */ |
4550 | 0 | tmp = result_len; |
4551 | 0 | C(EVP_EncryptFinal_ex(ctx, result + result_len, &tmp)); |
4552 | 0 | result_len += tmp; |
4553 | | |
4554 | | /* retrieve the tag */ |
4555 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, |
4556 | 0 | EVP_CTRL_CCM_GET_TAG, |
4557 | 0 | (int)ccm->tag_len, |
4558 | 0 | result + result_len)); |
4559 | |
|
4560 | 0 | *max_result_len = result_len + ccm->tag_len; |
4561 | 0 | EVP_CIPHER_CTX_free(ctx); |
4562 | 0 | return 1; |
4563 | | |
4564 | 0 | error: |
4565 | 0 | coap_crypto_output_errors("coap_crypto_aead_encrypt"); |
4566 | 0 | return 0; |
4567 | 0 | } |
4568 | | |
4569 | | int |
4570 | | coap_crypto_aead_decrypt(const coap_crypto_param_t *params, |
4571 | | coap_bin_const_t *data, |
4572 | | coap_bin_const_t *aad, |
4573 | | uint8_t *result, |
4574 | 0 | size_t *max_result_len) { |
4575 | 0 | const EVP_CIPHER *cipher; |
4576 | 0 | const coap_crypto_aes_ccm_t *ccm; |
4577 | 0 | int tmp; |
4578 | 0 | int len; |
4579 | 0 | const uint8_t *tag; |
4580 | 0 | uint8_t *rwtag; |
4581 | 0 | EVP_CIPHER_CTX *ctx; |
4582 | |
|
4583 | 0 | if (data == NULL) |
4584 | 0 | return 0; |
4585 | | |
4586 | 0 | assert(params != NULL); |
4587 | 0 | if (!params || ((cipher = get_cipher_alg(params->alg)) == NULL)) { |
4588 | 0 | return 0; |
4589 | 0 | } |
4590 | | |
4591 | 0 | ccm = ¶ms->params.aes; |
4592 | |
|
4593 | 0 | if (data->length < ccm->tag_len) { |
4594 | 0 | return 0; |
4595 | 0 | } else { |
4596 | 0 | tag = data->s + data->length - ccm->tag_len; |
4597 | 0 | data->length -= ccm->tag_len; |
4598 | | /* Kludge to stop compiler warning */ |
4599 | 0 | memcpy(&rwtag, &tag, sizeof(rwtag)); |
4600 | 0 | } |
4601 | | |
4602 | 0 | ctx = EVP_CIPHER_CTX_new(); |
4603 | 0 | if (!ctx) |
4604 | 0 | return 0; |
4605 | | |
4606 | 0 | C(EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL)); |
4607 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, |
4608 | 0 | EVP_CTRL_AEAD_SET_IVLEN, |
4609 | 0 | (int)(15 - ccm->l), |
4610 | 0 | NULL)); |
4611 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, (int)ccm->tag_len, rwtag)); |
4612 | 0 | C(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, (int)ccm->l, NULL)); |
4613 | | /* C(EVP_CIPHER_CTX_set_padding(ctx, 0)); */ |
4614 | 0 | C(EVP_DecryptInit_ex(ctx, NULL, NULL, ccm->key.s, ccm->nonce)); |
4615 | |
|
4616 | 0 | C(EVP_DecryptUpdate(ctx, NULL, &len, NULL, (int)data->length)); |
4617 | 0 | if (aad && aad->s && (aad->length > 0)) { |
4618 | 0 | C(EVP_DecryptUpdate(ctx, NULL, &len, aad->s, (int)aad->length)); |
4619 | 0 | } |
4620 | 0 | tmp = EVP_DecryptUpdate(ctx, result, &len, data->s, (int)data->length); |
4621 | 0 | EVP_CIPHER_CTX_free(ctx); |
4622 | 0 | if (tmp <= 0) { |
4623 | 0 | *max_result_len = 0; |
4624 | 0 | return 0; |
4625 | 0 | } |
4626 | 0 | *max_result_len = len; |
4627 | 0 | return 1; |
4628 | | |
4629 | 0 | error: |
4630 | 0 | coap_crypto_output_errors("coap_crypto_aead_decrypt"); |
4631 | 0 | return 0; |
4632 | 0 | } |
4633 | | |
4634 | | int |
4635 | | coap_crypto_hmac(cose_hmac_alg_t hmac_alg, |
4636 | | coap_bin_const_t *key, |
4637 | | coap_bin_const_t *data, |
4638 | 0 | coap_bin_const_t **hmac) { |
4639 | 0 | unsigned int result_len; |
4640 | 0 | const EVP_MD *evp_md; |
4641 | 0 | coap_binary_t *dummy = NULL; |
4642 | |
|
4643 | 0 | assert(key); |
4644 | 0 | assert(data); |
4645 | 0 | assert(hmac); |
4646 | | |
4647 | 0 | if ((evp_md = get_hmac_alg(hmac_alg)) == 0) { |
4648 | 0 | coap_log_debug("coap_crypto_hmac: algorithm %d not supported\n", hmac_alg); |
4649 | 0 | return 0; |
4650 | 0 | } |
4651 | 0 | dummy = coap_new_binary(EVP_MAX_MD_SIZE); |
4652 | 0 | if (dummy == NULL) |
4653 | 0 | return 0; |
4654 | 0 | result_len = (unsigned int)dummy->length; |
4655 | 0 | if (HMAC(evp_md, |
4656 | 0 | key->s, |
4657 | 0 | (int)key->length, |
4658 | 0 | data->s, |
4659 | 0 | (int)data->length, |
4660 | 0 | dummy->s, |
4661 | 0 | &result_len)) { |
4662 | 0 | dummy->length = result_len; |
4663 | 0 | *hmac = (coap_bin_const_t *)dummy; |
4664 | 0 | return 1; |
4665 | 0 | } |
4666 | | |
4667 | 0 | coap_delete_binary(dummy); |
4668 | 0 | coap_crypto_output_errors("coap_crypto_hmac"); |
4669 | 0 | return 0; |
4670 | 0 | } |
4671 | | |
4672 | | #endif /* COAP_OSCORE_SUPPORT */ |
4673 | | |
4674 | | #else /* ! COAP_WITH_LIBOPENSSL */ |
4675 | | |
4676 | | #ifdef __clang__ |
4677 | | /* Make compilers happy that do not like empty modules. As this function is |
4678 | | * never used, we ignore -Wunused-function at the end of compiling this file |
4679 | | */ |
4680 | | #pragma GCC diagnostic ignored "-Wunused-function" |
4681 | | #endif |
4682 | | static inline void |
4683 | | dummy(void) { |
4684 | | } |
4685 | | |
4686 | | #endif /* ! COAP_WITH_LIBOPENSSL */ |