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