1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com>
10 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at https://curl.se/docs/copyright.html.
14 *
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 * SPDX-License-Identifier: curl
23 *
24 ***************************************************************************/
25
26 /*
27 * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code
28 * but vtls.c should ever call or use these functions.
29 *
30 */
31
32 #include "curl_setup.h"
33
34 #ifdef USE_MBEDTLS
35
36 /* Define this to enable lots of debugging for mbedTLS */
37 /* #define MBEDTLS_DEBUG */
38
39 #ifdef __GNUC__
40 #pragma GCC diagnostic push
41 /* mbedTLS (as of v3.5.1) has a duplicate function declaration
42 in its public headers. Disable the warning that detects it. */
43 #pragma GCC diagnostic ignored "-Wredundant-decls"
44 #endif
45
46 #include <mbedtls/version.h>
47 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
48 #include <mbedtls/net_sockets.h>
49 #else
50 #include <mbedtls/net.h>
51 #endif
52 #include <mbedtls/ssl.h>
53 #include <mbedtls/x509.h>
54
55 #include <mbedtls/error.h>
56 #include <mbedtls/entropy.h>
57 #include <mbedtls/ctr_drbg.h>
58 #include <mbedtls/sha256.h>
59
60 #if MBEDTLS_VERSION_MAJOR >= 2
61 # ifdef MBEDTLS_DEBUG
62 # include <mbedtls/debug.h>
63 # endif
64 #endif
65
66 #ifdef __GNUC__
67 #pragma GCC diagnostic pop
68 #endif
69
70 #include "cipher_suite.h"
71 #include "strcase.h"
72 #include "urldata.h"
73 #include "sendf.h"
74 #include "inet_pton.h"
75 #include "mbedtls.h"
76 #include "vtls.h"
77 #include "vtls_int.h"
78 #include "parsedate.h"
79 #include "connect.h" /* for the connect timeout */
80 #include "select.h"
81 #include "multiif.h"
82 #include "mbedtls_threadlock.h"
83 #include "strdup.h"
84
85 /* The last 3 #include files should be in this order */
86 #include "curl_printf.h"
87 #include "curl_memory.h"
88 #include "memdebug.h"
89
90 /* ALPN for http2 */
91 #ifdef USE_HTTP2
92 # undef HAS_ALPN
93 # ifdef MBEDTLS_SSL_ALPN
94 # define HAS_ALPN
95 # endif
96 #endif
97
98 struct mbed_ssl_backend_data {
99 mbedtls_ctr_drbg_context ctr_drbg;
100 mbedtls_entropy_context entropy;
101 mbedtls_ssl_context ssl;
102 mbedtls_x509_crt cacert;
103 mbedtls_x509_crt clicert;
104 #ifdef MBEDTLS_X509_CRL_PARSE_C
105 mbedtls_x509_crl crl;
106 #endif
107 mbedtls_pk_context pk;
108 mbedtls_ssl_config config;
109 #ifdef HAS_ALPN
110 const char *protocols[3];
111 #endif
112 int *ciphersuites;
113 };
114
115 /* apply threading? */
116 #if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
117 defined(_WIN32)
118 #define THREADING_SUPPORT
119 #endif
120
121 #ifndef MBEDTLS_ERROR_C
122 #define mbedtls_strerror(a,b,c) b[0] = 0
123 #endif
124
125 #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && MBEDTLS_VERSION_NUMBER >= 0x03060000
126 #define TLS13_SUPPORT
127 #endif
128
129 #if defined(THREADING_SUPPORT)
130 static mbedtls_entropy_context ts_entropy;
131
132 static int entropy_init_initialized = 0;
133
entropy_init_mutex(mbedtls_entropy_context * ctx)134 static void entropy_init_mutex(mbedtls_entropy_context *ctx)
135 {
136 /* lock 0 = entropy_init_mutex() */
137 Curl_mbedtlsthreadlock_lock_function(0);
138 if(entropy_init_initialized == 0) {
139 mbedtls_entropy_init(ctx);
140 entropy_init_initialized = 1;
141 }
142 Curl_mbedtlsthreadlock_unlock_function(0);
143 }
144
entropy_cleanup_mutex(mbedtls_entropy_context * ctx)145 static void entropy_cleanup_mutex(mbedtls_entropy_context *ctx)
146 {
147 /* lock 0 = use same lock as init */
148 Curl_mbedtlsthreadlock_lock_function(0);
149 if(entropy_init_initialized == 1) {
150 mbedtls_entropy_free(ctx);
151 entropy_init_initialized = 0;
152 }
153 Curl_mbedtlsthreadlock_unlock_function(0);
154 }
155
entropy_func_mutex(void * data,unsigned char * output,size_t len)156 static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
157 {
158 int ret;
159 /* lock 1 = entropy_func_mutex() */
160 Curl_mbedtlsthreadlock_lock_function(1);
161 ret = mbedtls_entropy_func(data, output, len);
162 Curl_mbedtlsthreadlock_unlock_function(1);
163
164 return ret;
165 }
166
167 #endif /* THREADING_SUPPORT */
168
169 #ifdef MBEDTLS_DEBUG
mbed_debug(void * context,int level,const char * f_name,int line_nb,const char * line)170 static void mbed_debug(void *context, int level, const char *f_name,
171 int line_nb, const char *line)
172 {
173 struct Curl_easy *data = (struct Curl_easy *)context;
174 (void) level;
175 (void) line_nb;
176 (void) f_name;
177
178 if(data) {
179 size_t len = strlen(line);
180 if(len && (line[len - 1] == '\n'))
181 /* discount any trailing newline */
182 len--;
183 infof(data, "%.*s", (int)len, line);
184 }
185 }
186 #endif
187
mbedtls_bio_cf_write(void * bio,const unsigned char * buf,size_t blen)188 static int mbedtls_bio_cf_write(void *bio,
189 const unsigned char *buf, size_t blen)
190 {
191 struct Curl_cfilter *cf = bio;
192 struct Curl_easy *data = CF_DATA_CURRENT(cf);
193 ssize_t nwritten;
194 CURLcode result;
195
196 DEBUGASSERT(data);
197 if(!data)
198 return 0;
199
200 nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
201 CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
202 blen, nwritten, result);
203 if(nwritten < 0 && CURLE_AGAIN == result) {
204 nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
205 }
206 return (int)nwritten;
207 }
208
mbedtls_bio_cf_read(void * bio,unsigned char * buf,size_t blen)209 static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen)
210 {
211 struct Curl_cfilter *cf = bio;
212 struct Curl_easy *data = CF_DATA_CURRENT(cf);
213 ssize_t nread;
214 CURLcode result;
215
216 DEBUGASSERT(data);
217 if(!data)
218 return 0;
219 /* OpenSSL catches this case, so should we. */
220 if(!buf)
221 return 0;
222
223 nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
224 CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d",
225 blen, nread, result);
226 if(nread < 0 && CURLE_AGAIN == result) {
227 nread = MBEDTLS_ERR_SSL_WANT_READ;
228 }
229 return (int)nread;
230 }
231
232 /*
233 * profile
234 */
235 static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
236 {
237 /* Hashes from SHA-1 and above */
238 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
239 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
240 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
241 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
242 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
243 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
244 0xFFFFFFF, /* Any PK alg */
245 0xFFFFFFF, /* Any curve */
246 1024, /* RSA min key len */
247 };
248
249 /* See https://tls.mbed.org/discussions/generic/
250 howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
251 */
252 #define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
253 #define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
254
255 #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
256 RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
257
258 #if MBEDTLS_VERSION_NUMBER >= 0x03020000
mbedtls_version_from_curl(mbedtls_ssl_protocol_version * mbedver,long version)259 static CURLcode mbedtls_version_from_curl(
260 mbedtls_ssl_protocol_version* mbedver, long version)
261 {
262 switch(version) {
263 case CURL_SSLVERSION_TLSv1_0:
264 case CURL_SSLVERSION_TLSv1_1:
265 case CURL_SSLVERSION_TLSv1_2:
266 *mbedver = MBEDTLS_SSL_VERSION_TLS1_2;
267 return CURLE_OK;
268 case CURL_SSLVERSION_TLSv1_3:
269 #ifdef TLS13_SUPPORT
270 *mbedver = MBEDTLS_SSL_VERSION_TLS1_3;
271 return CURLE_OK;
272 #else
273 break;
274 #endif
275 }
276
277 return CURLE_SSL_CONNECT_ERROR;
278 }
279 #else
mbedtls_version_from_curl(int * mbedver,long version)280 static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
281 {
282 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
283 switch(version) {
284 case CURL_SSLVERSION_TLSv1_0:
285 case CURL_SSLVERSION_TLSv1_1:
286 case CURL_SSLVERSION_TLSv1_2:
287 *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
288 return CURLE_OK;
289 case CURL_SSLVERSION_TLSv1_3:
290 break;
291 }
292 #else
293 switch(version) {
294 case CURL_SSLVERSION_TLSv1_0:
295 *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
296 return CURLE_OK;
297 case CURL_SSLVERSION_TLSv1_1:
298 *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
299 return CURLE_OK;
300 case CURL_SSLVERSION_TLSv1_2:
301 *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
302 return CURLE_OK;
303 case CURL_SSLVERSION_TLSv1_3:
304 break;
305 }
306 #endif
307
308 return CURLE_SSL_CONNECT_ERROR;
309 }
310 #endif
311
312 static CURLcode
set_ssl_version_min_max(struct Curl_cfilter * cf,struct Curl_easy * data)313 set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
314 {
315 struct ssl_connect_data *connssl = cf->ctx;
316 struct mbed_ssl_backend_data *backend =
317 (struct mbed_ssl_backend_data *)connssl->backend;
318 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
319 #if MBEDTLS_VERSION_NUMBER >= 0x03020000
320 mbedtls_ssl_protocol_version mbedtls_ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
321 #ifdef TLS13_SUPPORT
322 mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_3;
323 #else
324 mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
325 #endif
326 #elif MBEDTLS_VERSION_NUMBER >= 0x03000000
327 int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
328 int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
329 #else
330 int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
331 int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
332 #endif
333 long ssl_version = conn_config->version;
334 long ssl_version_max = conn_config->version_max;
335 CURLcode result = CURLE_OK;
336
337 DEBUGASSERT(backend);
338
339 switch(ssl_version) {
340 case CURL_SSLVERSION_DEFAULT:
341 case CURL_SSLVERSION_TLSv1:
342 ssl_version = CURL_SSLVERSION_TLSv1_0;
343 break;
344 }
345
346 switch(ssl_version_max) {
347 case CURL_SSLVERSION_MAX_NONE:
348 case CURL_SSLVERSION_MAX_DEFAULT:
349 #ifdef TLS13_SUPPORT
350 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
351 #else
352 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
353 #endif
354 break;
355 }
356
357 result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
358 if(result) {
359 failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
360 return result;
361 }
362 result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
363 if(result) {
364 failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
365 return result;
366 }
367
368 #if MBEDTLS_VERSION_NUMBER >= 0x03020000
369 mbedtls_ssl_conf_min_tls_version(&backend->config, mbedtls_ver_min);
370 mbedtls_ssl_conf_max_tls_version(&backend->config, mbedtls_ver_max);
371 #else
372 mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
373 mbedtls_ver_min);
374 mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
375 mbedtls_ver_max);
376 #endif
377
378 #ifdef TLS13_SUPPORT
379 if(mbedtls_ver_min == MBEDTLS_SSL_VERSION_TLS1_3) {
380 mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_REQUIRED);
381 }
382 else {
383 mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
384 }
385 #else
386 mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
387 #endif
388
389 return result;
390 }
391
392 /* TLS_ECJPAKE_WITH_AES_128_CCM_8 (0xC0FF) is marked experimental
393 in mbedTLS. The number is not reserved by IANA nor is the
394 cipher suite present in other SSL implementations. Provide
395 provisional support for specifying the cipher suite here. */
396 #ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
397 static int
mbed_cipher_suite_get_str(uint16_t id,char * buf,size_t buf_size,bool prefer_rfc)398 mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
399 bool prefer_rfc)
400 {
401 if(id == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
402 msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8");
403 else
404 return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
405 return 0;
406 }
407
408 static uint16_t
mbed_cipher_suite_walk_str(const char ** str,const char ** end)409 mbed_cipher_suite_walk_str(const char **str, const char **end)
410 {
411 uint16_t id = Curl_cipher_suite_walk_str(str, end);
412 size_t len = *end - *str;
413
414 if(!id) {
415 if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
416 id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
417 }
418 return id;
419 }
420 #else
421 #define mbed_cipher_suite_get_str Curl_cipher_suite_get_str
422 #define mbed_cipher_suite_walk_str Curl_cipher_suite_walk_str
423 #endif
424
425 static CURLcode
mbed_set_selected_ciphers(struct Curl_easy * data,struct mbed_ssl_backend_data * backend,const char * ciphers)426 mbed_set_selected_ciphers(struct Curl_easy *data,
427 struct mbed_ssl_backend_data *backend,
428 const char *ciphers)
429 {
430 const int *supported;
431 int *selected;
432 size_t supported_len, count = 0, i;
433 const char *ptr, *end;
434
435 supported = mbedtls_ssl_list_ciphersuites();
436 for(i = 0; supported[i] != 0; i++);
437 supported_len = i;
438
439 selected = malloc(sizeof(int) * (supported_len + 1));
440 if(!selected)
441 return CURLE_OUT_OF_MEMORY;
442
443 for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
444 uint16_t id = mbed_cipher_suite_walk_str(&ptr, &end);
445
446 /* Check if cipher is supported */
447 if(id) {
448 for(i = 0; i < supported_len && supported[i] != id; i++);
449 if(i == supported_len)
450 id = 0;
451 }
452 if(!id) {
453 if(ptr[0] != '\0')
454 infof(data, "mbedTLS: unknown cipher in list: \"%.*s\"",
455 (int) (end - ptr), ptr);
456 continue;
457 }
458
459 /* No duplicates allowed (so selected cannot overflow) */
460 for(i = 0; i < count && selected[i] != id; i++);
461 if(i < count) {
462 infof(data, "mbedTLS: duplicate cipher in list: \"%.*s\"",
463 (int) (end - ptr), ptr);
464 continue;
465 }
466
467 selected[count++] = id;
468 }
469
470 selected[count] = 0;
471
472 if(count == 0) {
473 free(selected);
474 failf(data, "mbedTLS: no supported cipher in list");
475 return CURLE_SSL_CIPHER;
476 }
477
478 /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
479 It must remain valid for the lifetime of the SSL configuration */
480 backend->ciphersuites = selected;
481 mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
482 return CURLE_OK;
483 }
484
485 static CURLcode
mbed_connect_step1(struct Curl_cfilter * cf,struct Curl_easy * data)486 mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
487 {
488 struct ssl_connect_data *connssl = cf->ctx;
489 struct mbed_ssl_backend_data *backend =
490 (struct mbed_ssl_backend_data *)connssl->backend;
491 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
492 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
493 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
494 const char * const ssl_cafile =
495 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
496 (ca_info_blob ? NULL : conn_config->CAfile);
497 const bool verifypeer = conn_config->verifypeer;
498 const char * const ssl_capath = conn_config->CApath;
499 char * const ssl_cert = ssl_config->primary.clientcert;
500 const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
501 const char * const ssl_crlfile = ssl_config->primary.CRLfile;
502 const char *hostname = connssl->peer.hostname;
503 int ret = -1;
504 char errorbuf[128];
505
506 DEBUGASSERT(backend);
507
508 if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
509 (conn_config->version == CURL_SSLVERSION_SSLv3)) {
510 failf(data, "Not supported SSL version");
511 return CURLE_NOT_BUILT_IN;
512 }
513
514 #ifdef TLS13_SUPPORT
515 ret = psa_crypto_init();
516 if(ret != PSA_SUCCESS) {
517 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
518 failf(data, "mbedTLS psa_crypto_init returned (-0x%04X) %s",
519 -ret, errorbuf);
520 return CURLE_SSL_CONNECT_ERROR;
521 }
522 #endif /* TLS13_SUPPORT */
523
524 #ifdef THREADING_SUPPORT
525 mbedtls_ctr_drbg_init(&backend->ctr_drbg);
526
527 ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
528 &ts_entropy, NULL, 0);
529 if(ret) {
530 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
531 failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
532 -ret, errorbuf);
533 return CURLE_FAILED_INIT;
534 }
535 #else
536 mbedtls_entropy_init(&backend->entropy);
537 mbedtls_ctr_drbg_init(&backend->ctr_drbg);
538
539 ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func,
540 &backend->entropy, NULL, 0);
541 if(ret) {
542 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
543 failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
544 -ret, errorbuf);
545 return CURLE_FAILED_INIT;
546 }
547 #endif /* THREADING_SUPPORT */
548
549 /* Load the trusted CA */
550 mbedtls_x509_crt_init(&backend->cacert);
551
552 if(ca_info_blob && verifypeer) {
553 /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
554 terminated even when provided the exact length, forcing us to waste
555 extra memory here. */
556 unsigned char *newblob = Curl_memdup0(ca_info_blob->data,
557 ca_info_blob->len);
558 if(!newblob)
559 return CURLE_OUT_OF_MEMORY;
560 ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
561 ca_info_blob->len + 1);
562 free(newblob);
563 if(ret<0) {
564 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
565 failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
566 -ret, errorbuf);
567 return CURLE_SSL_CERTPROBLEM;
568 }
569 }
570
571 if(ssl_cafile && verifypeer) {
572 #ifdef MBEDTLS_FS_IO
573 ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
574
575 if(ret<0) {
576 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
577 failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
578 ssl_cafile, -ret, errorbuf);
579 return CURLE_SSL_CACERT_BADFILE;
580 }
581 #else
582 failf(data, "mbedtls: functions that use the filesystem not built in");
583 return CURLE_NOT_BUILT_IN;
584 #endif
585 }
586
587 if(ssl_capath) {
588 #ifdef MBEDTLS_FS_IO
589 ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
590
591 if(ret<0) {
592 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
593 failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
594 ssl_capath, -ret, errorbuf);
595
596 if(verifypeer)
597 return CURLE_SSL_CACERT_BADFILE;
598 }
599 #else
600 failf(data, "mbedtls: functions that use the filesystem not built in");
601 return CURLE_NOT_BUILT_IN;
602 #endif
603 }
604
605 /* Load the client certificate */
606 mbedtls_x509_crt_init(&backend->clicert);
607
608 if(ssl_cert) {
609 #ifdef MBEDTLS_FS_IO
610 ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert);
611
612 if(ret) {
613 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
614 failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
615 ssl_cert, -ret, errorbuf);
616
617 return CURLE_SSL_CERTPROBLEM;
618 }
619 #else
620 failf(data, "mbedtls: functions that use the filesystem not built in");
621 return CURLE_NOT_BUILT_IN;
622 #endif
623 }
624
625 if(ssl_cert_blob) {
626 /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
627 terminated even when provided the exact length, forcing us to waste
628 extra memory here. */
629 unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data,
630 ssl_cert_blob->len);
631 if(!newblob)
632 return CURLE_OUT_OF_MEMORY;
633 ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
634 ssl_cert_blob->len + 1);
635 free(newblob);
636
637 if(ret) {
638 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
639 failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
640 ssl_config->key, -ret, errorbuf);
641 return CURLE_SSL_CERTPROBLEM;
642 }
643 }
644
645 /* Load the client private key */
646 mbedtls_pk_init(&backend->pk);
647
648 if(ssl_config->key || ssl_config->key_blob) {
649 if(ssl_config->key) {
650 #ifdef MBEDTLS_FS_IO
651 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
652 ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
653 ssl_config->key_passwd,
654 mbedtls_ctr_drbg_random,
655 &backend->ctr_drbg);
656 #else
657 ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
658 ssl_config->key_passwd);
659 #endif
660
661 if(ret) {
662 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
663 failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
664 ssl_config->key, -ret, errorbuf);
665 return CURLE_SSL_CERTPROBLEM;
666 }
667 #else
668 failf(data, "mbedtls: functions that use the filesystem not built in");
669 return CURLE_NOT_BUILT_IN;
670 #endif
671 }
672 else {
673 const struct curl_blob *ssl_key_blob = ssl_config->key_blob;
674 const unsigned char *key_data =
675 (const unsigned char *)ssl_key_blob->data;
676 const char *passwd = ssl_config->key_passwd;
677 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
678 ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
679 (const unsigned char *)passwd,
680 passwd ? strlen(passwd) : 0,
681 mbedtls_ctr_drbg_random,
682 &backend->ctr_drbg);
683 #else
684 ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
685 (const unsigned char *)passwd,
686 passwd ? strlen(passwd) : 0);
687 #endif
688
689 if(ret) {
690 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
691 failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s",
692 -ret, errorbuf);
693 return CURLE_SSL_CERTPROBLEM;
694 }
695 }
696
697 if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
698 mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
699 ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
700 }
701
702 /* Load the CRL */
703 #ifdef MBEDTLS_X509_CRL_PARSE_C
704 mbedtls_x509_crl_init(&backend->crl);
705
706 if(ssl_crlfile) {
707 #ifdef MBEDTLS_FS_IO
708 ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile);
709
710 if(ret) {
711 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
712 failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
713 ssl_crlfile, -ret, errorbuf);
714
715 return CURLE_SSL_CRL_BADFILE;
716 }
717 #else
718 failf(data, "mbedtls: functions that use the filesystem not built in");
719 return CURLE_NOT_BUILT_IN;
720 #endif
721 }
722 #else
723 if(ssl_crlfile) {
724 failf(data, "mbedtls: crl support not built in");
725 return CURLE_NOT_BUILT_IN;
726 }
727 #endif
728
729 infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->peer.port);
730
731 mbedtls_ssl_config_init(&backend->config);
732 ret = mbedtls_ssl_config_defaults(&backend->config,
733 MBEDTLS_SSL_IS_CLIENT,
734 MBEDTLS_SSL_TRANSPORT_STREAM,
735 MBEDTLS_SSL_PRESET_DEFAULT);
736 if(ret) {
737 failf(data, "mbedTLS: ssl_config failed");
738 return CURLE_SSL_CONNECT_ERROR;
739 }
740
741 mbedtls_ssl_init(&backend->ssl);
742
743 /* new profile with RSA min key len = 1024 ... */
744 mbedtls_ssl_conf_cert_profile(&backend->config,
745 &mbedtls_x509_crt_profile_fr);
746
747 switch(conn_config->version) {
748 case CURL_SSLVERSION_DEFAULT:
749 case CURL_SSLVERSION_TLSv1:
750 #if MBEDTLS_VERSION_NUMBER < 0x03000000
751 mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
752 MBEDTLS_SSL_MINOR_VERSION_1);
753 infof(data, "mbedTLS: Set min SSL version to TLS 1.0");
754 break;
755 #endif
756 case CURL_SSLVERSION_TLSv1_0:
757 case CURL_SSLVERSION_TLSv1_1:
758 case CURL_SSLVERSION_TLSv1_2:
759 case CURL_SSLVERSION_TLSv1_3:
760 {
761 CURLcode result = set_ssl_version_min_max(cf, data);
762 if(result != CURLE_OK)
763 return result;
764 break;
765 }
766 default:
767 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
768 return CURLE_SSL_CONNECT_ERROR;
769 }
770
771 mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
772 &backend->ctr_drbg);
773
774 ret = mbedtls_ssl_setup(&backend->ssl, &backend->config);
775 if(ret) {
776 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
777 failf(data, "ssl_setup failed - mbedTLS: (-0x%04X) %s",
778 -ret, errorbuf);
779 return CURLE_SSL_CONNECT_ERROR;
780 }
781
782 mbedtls_ssl_set_bio(&backend->ssl, cf,
783 mbedtls_bio_cf_write,
784 mbedtls_bio_cf_read,
785 NULL /* rev_timeout() */);
786
787 if(conn_config->cipher_list) {
788 ret = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list);
789 if(ret) {
790 failf(data, "mbedTLS: failed to set cipher suites");
791 return ret;
792 }
793 }
794 else {
795 mbedtls_ssl_conf_ciphersuites(&backend->config,
796 mbedtls_ssl_list_ciphersuites());
797 }
798
799
800 #if defined(MBEDTLS_SSL_RENEGOTIATION)
801 mbedtls_ssl_conf_renegotiation(&backend->config,
802 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
803 #endif
804
805 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
806 mbedtls_ssl_conf_session_tickets(&backend->config,
807 MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
808 #endif
809
810 /* Check if there's a cached ID we can/should use here! */
811 if(ssl_config->primary.sessionid) {
812 void *old_session = NULL;
813
814 Curl_ssl_sessionid_lock(data);
815 if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
816 ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
817 if(ret) {
818 Curl_ssl_sessionid_unlock(data);
819 failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
820 return CURLE_SSL_CONNECT_ERROR;
821 }
822 infof(data, "mbedTLS reusing session");
823 }
824 Curl_ssl_sessionid_unlock(data);
825 }
826
827 mbedtls_ssl_conf_ca_chain(&backend->config,
828 &backend->cacert,
829 #ifdef MBEDTLS_X509_CRL_PARSE_C
830 &backend->crl);
831 #else
832 NULL);
833 #endif
834
835 if(ssl_config->key || ssl_config->key_blob) {
836 mbedtls_ssl_conf_own_cert(&backend->config,
837 &backend->clicert, &backend->pk);
838 }
839
840 if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
841 connssl->peer.sni : connssl->peer.hostname)) {
842 /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
843 the name to set in the SNI extension. So even if curl connects to a
844 host specified as an IP address, this function must be used. */
845 failf(data, "Failed to set SNI");
846 return CURLE_SSL_CONNECT_ERROR;
847 }
848
849 #ifdef HAS_ALPN
850 if(connssl->alpn) {
851 struct alpn_proto_buf proto;
852 size_t i;
853
854 for(i = 0; i < connssl->alpn->count; ++i) {
855 backend->protocols[i] = connssl->alpn->entries[i];
856 }
857 /* this function doesn't clone the protocols array, which is why we need
858 to keep it around */
859 if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
860 &backend->protocols[0])) {
861 failf(data, "Failed setting ALPN protocols");
862 return CURLE_SSL_CONNECT_ERROR;
863 }
864 Curl_alpn_to_proto_str(&proto, connssl->alpn);
865 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
866 }
867 #endif
868
869 #ifdef MBEDTLS_DEBUG
870 /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
871 mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data);
872 /* - 0 No debug
873 * - 1 Error
874 * - 2 State change
875 * - 3 Informational
876 * - 4 Verbose
877 */
878 mbedtls_debug_set_threshold(4);
879 #endif
880
881 /* give application a chance to interfere with mbedTLS set up. */
882 if(data->set.ssl.fsslctx) {
883 ret = (*data->set.ssl.fsslctx)(data, &backend->config,
884 data->set.ssl.fsslctxp);
885 if(ret) {
886 failf(data, "error signaled by ssl ctx callback");
887 return ret;
888 }
889 }
890
891 connssl->connecting_state = ssl_connect_2;
892
893 return CURLE_OK;
894 }
895
896 static CURLcode
mbed_connect_step2(struct Curl_cfilter * cf,struct Curl_easy * data)897 mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
898 {
899 int ret;
900 struct ssl_connect_data *connssl = cf->ctx;
901 struct mbed_ssl_backend_data *backend =
902 (struct mbed_ssl_backend_data *)connssl->backend;
903 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
904 const mbedtls_x509_crt *peercert;
905 char cipher_str[64];
906 uint16_t cipher_id;
907 #ifndef CURL_DISABLE_PROXY
908 const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
909 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
910 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
911 #else
912 const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
913 #endif
914
915 DEBUGASSERT(backend);
916
917 ret = mbedtls_ssl_handshake(&backend->ssl);
918
919 if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
920 connssl->connecting_state = ssl_connect_2_reading;
921 return CURLE_OK;
922 }
923 else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
924 connssl->connecting_state = ssl_connect_2_writing;
925 return CURLE_OK;
926 }
927 else if(ret) {
928 char errorbuf[128];
929 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
930 failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
931 -ret, errorbuf);
932 return CURLE_SSL_CONNECT_ERROR;
933 }
934
935 cipher_id = (uint16_t)
936 mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
937 mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
938 infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);
939
940 ret = mbedtls_ssl_get_verify_result(&backend->ssl);
941
942 if(!conn_config->verifyhost)
943 /* Ignore hostname errors if verifyhost is disabled */
944 ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
945
946 if(ret && conn_config->verifypeer) {
947 if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
948 failf(data, "Cert verify failed: BADCERT_EXPIRED");
949
950 else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
951 failf(data, "Cert verify failed: BADCERT_REVOKED");
952
953 else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
954 failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
955
956 else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
957 failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
958
959 else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
960 failf(data, "Cert verify failed: BADCERT_FUTURE");
961
962 return CURLE_PEER_FAILED_VERIFICATION;
963 }
964
965 peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
966
967 if(peercert && data->set.verbose) {
968 #ifndef MBEDTLS_X509_REMOVE_INFO
969 const size_t bufsize = 16384;
970 char *buffer = malloc(bufsize);
971
972 if(!buffer)
973 return CURLE_OUT_OF_MEMORY;
974
975 if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
976 infof(data, "Dumping cert info: %s", buffer);
977 else
978 infof(data, "Unable to dump certificate information");
979
980 free(buffer);
981 #else
982 infof(data, "Unable to dump certificate information");
983 #endif
984 }
985
986 if(pinnedpubkey) {
987 int size;
988 CURLcode result;
989 mbedtls_x509_crt *p = NULL;
990 unsigned char *pubkey = NULL;
991
992 #if MBEDTLS_VERSION_NUMBER == 0x03000000
993 if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
994 !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
995 #else
996 if(!peercert || !peercert->raw.p || !peercert->raw.len) {
997 #endif
998 failf(data, "Failed due to missing peer certificate");
999 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1000 }
1001
1002 p = calloc(1, sizeof(*p));
1003
1004 if(!p)
1005 return CURLE_OUT_OF_MEMORY;
1006
1007 pubkey = malloc(PUB_DER_MAX_BYTES);
1008
1009 if(!pubkey) {
1010 result = CURLE_OUT_OF_MEMORY;
1011 goto pinnedpubkey_error;
1012 }
1013
1014 mbedtls_x509_crt_init(p);
1015
1016 /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
1017 needs a non-const key, for now.
1018 https://github.com/ARMmbed/mbedtls/issues/396 */
1019 #if MBEDTLS_VERSION_NUMBER == 0x03000000
1020 if(mbedtls_x509_crt_parse_der(p,
1021 peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
1022 peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
1023 #else
1024 if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
1025 #endif
1026 failf(data, "Failed copying peer certificate");
1027 result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1028 goto pinnedpubkey_error;
1029 }
1030
1031 #if MBEDTLS_VERSION_NUMBER == 0x03000000
1032 size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
1033 PUB_DER_MAX_BYTES);
1034 #else
1035 size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
1036 #endif
1037
1038 if(size <= 0) {
1039 failf(data, "Failed copying public key from peer certificate");
1040 result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1041 goto pinnedpubkey_error;
1042 }
1043
1044 /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
1045 result = Curl_pin_peer_pubkey(data,
1046 pinnedpubkey,
1047 &pubkey[PUB_DER_MAX_BYTES - size], size);
1048 pinnedpubkey_error:
1049 mbedtls_x509_crt_free(p);
1050 free(p);
1051 free(pubkey);
1052 if(result) {
1053 return result;
1054 }
1055 }
1056
1057 #ifdef HAS_ALPN
1058 if(connssl->alpn) {
1059 const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
1060
1061 Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
1062 proto? strlen(proto) : 0);
1063 }
1064 #endif
1065
1066 connssl->connecting_state = ssl_connect_3;
1067 infof(data, "SSL connected");
1068
1069 return CURLE_OK;
1070 }
1071
1072 static void mbedtls_session_free(void *sessionid, size_t idsize)
1073 {
1074 (void)idsize;
1075 mbedtls_ssl_session_free(sessionid);
1076 free(sessionid);
1077 }
1078
1079 static CURLcode
1080 mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
1081 {
1082 CURLcode retcode = CURLE_OK;
1083 struct ssl_connect_data *connssl = cf->ctx;
1084 struct mbed_ssl_backend_data *backend =
1085 (struct mbed_ssl_backend_data *)connssl->backend;
1086 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1087
1088 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1089 DEBUGASSERT(backend);
1090
1091 if(ssl_config->primary.sessionid) {
1092 int ret;
1093 mbedtls_ssl_session *our_ssl_sessionid;
1094 void *old_ssl_sessionid = NULL;
1095
1096 our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
1097 if(!our_ssl_sessionid)
1098 return CURLE_OUT_OF_MEMORY;
1099
1100 mbedtls_ssl_session_init(our_ssl_sessionid);
1101
1102 ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
1103 if(ret) {
1104 if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
1105 mbedtls_ssl_session_free(our_ssl_sessionid);
1106 free(our_ssl_sessionid);
1107 failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
1108 return CURLE_SSL_CONNECT_ERROR;
1109 }
1110
1111 /* If there's already a matching session in the cache, delete it */
1112 Curl_ssl_sessionid_lock(data);
1113 if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
1114 &old_ssl_sessionid, NULL))
1115 Curl_ssl_delsessionid(data, old_ssl_sessionid);
1116
1117 retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
1118 our_ssl_sessionid, 0,
1119 mbedtls_session_free);
1120 Curl_ssl_sessionid_unlock(data);
1121 if(retcode)
1122 return retcode;
1123 }
1124
1125 connssl->connecting_state = ssl_connect_done;
1126
1127 return CURLE_OK;
1128 }
1129
1130 static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1131 const void *mem, size_t len,
1132 CURLcode *curlcode)
1133 {
1134 struct ssl_connect_data *connssl = cf->ctx;
1135 struct mbed_ssl_backend_data *backend =
1136 (struct mbed_ssl_backend_data *)connssl->backend;
1137 int ret = -1;
1138
1139 (void)data;
1140 DEBUGASSERT(backend);
1141 ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
1142
1143 if(ret < 0) {
1144 *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
1145 CURLE_AGAIN : CURLE_SEND_ERROR;
1146 ret = -1;
1147 }
1148
1149 return ret;
1150 }
1151
1152 static void mbedtls_close_all(struct Curl_easy *data)
1153 {
1154 (void)data;
1155 }
1156
1157 static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1158 {
1159 struct ssl_connect_data *connssl = cf->ctx;
1160 struct mbed_ssl_backend_data *backend =
1161 (struct mbed_ssl_backend_data *)connssl->backend;
1162 char buf[32];
1163
1164 (void)data;
1165 DEBUGASSERT(backend);
1166
1167 /* Maybe the server has already sent a close notify alert.
1168 Read it to avoid an RST on the TCP connection. */
1169 (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
1170
1171 mbedtls_pk_free(&backend->pk);
1172 mbedtls_x509_crt_free(&backend->clicert);
1173 mbedtls_x509_crt_free(&backend->cacert);
1174 #ifdef MBEDTLS_X509_CRL_PARSE_C
1175 mbedtls_x509_crl_free(&backend->crl);
1176 #endif
1177 Curl_safefree(backend->ciphersuites);
1178 mbedtls_ssl_config_free(&backend->config);
1179 mbedtls_ssl_free(&backend->ssl);
1180 mbedtls_ctr_drbg_free(&backend->ctr_drbg);
1181 #ifndef THREADING_SUPPORT
1182 mbedtls_entropy_free(&backend->entropy);
1183 #endif /* THREADING_SUPPORT */
1184 }
1185
1186 static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1187 char *buf, size_t buffersize,
1188 CURLcode *curlcode)
1189 {
1190 struct ssl_connect_data *connssl = cf->ctx;
1191 struct mbed_ssl_backend_data *backend =
1192 (struct mbed_ssl_backend_data *)connssl->backend;
1193 int ret = -1;
1194 ssize_t len = -1;
1195
1196 (void)data;
1197 DEBUGASSERT(backend);
1198
1199 ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
1200 buffersize);
1201
1202 if(ret <= 0) {
1203 if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
1204 return 0;
1205
1206 *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
1207 #ifdef TLS13_SUPPORT
1208 || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
1209 #endif
1210 ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
1211 return -1;
1212 }
1213
1214 len = ret;
1215
1216 return len;
1217 }
1218
1219 static size_t mbedtls_version(char *buffer, size_t size)
1220 {
1221 #ifdef MBEDTLS_VERSION_C
1222 /* if mbedtls_version_get_number() is available it is better */
1223 unsigned int version = mbedtls_version_get_number();
1224 return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
1225 (version>>16)&0xff, (version>>8)&0xff);
1226 #else
1227 return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
1228 #endif
1229 }
1230
1231 static CURLcode mbedtls_random(struct Curl_easy *data,
1232 unsigned char *entropy, size_t length)
1233 {
1234 #if defined(MBEDTLS_CTR_DRBG_C)
1235 int ret = -1;
1236 char errorbuf[128];
1237 mbedtls_entropy_context ctr_entropy;
1238 mbedtls_ctr_drbg_context ctr_drbg;
1239 mbedtls_entropy_init(&ctr_entropy);
1240 mbedtls_ctr_drbg_init(&ctr_drbg);
1241
1242 ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
1243 &ctr_entropy, NULL, 0);
1244
1245 if(ret) {
1246 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
1247 failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
1248 -ret, errorbuf);
1249 }
1250 else {
1251 ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
1252
1253 if(ret) {
1254 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
1255 failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s",
1256 -ret, errorbuf);
1257 }
1258 }
1259
1260 mbedtls_ctr_drbg_free(&ctr_drbg);
1261 mbedtls_entropy_free(&ctr_entropy);
1262
1263 return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT;
1264 #elif defined(MBEDTLS_HAVEGE_C)
1265 mbedtls_havege_state hs;
1266 mbedtls_havege_init(&hs);
1267 mbedtls_havege_random(&hs, entropy, length);
1268 mbedtls_havege_free(&hs);
1269 return CURLE_OK;
1270 #else
1271 return CURLE_NOT_BUILT_IN;
1272 #endif
1273 }
1274
1275 static CURLcode
1276 mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
1277 bool nonblocking,
1278 bool *done)
1279 {
1280 CURLcode retcode;
1281 struct ssl_connect_data *connssl = cf->ctx;
1282 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1283 timediff_t timeout_ms;
1284 int what;
1285
1286 /* check if the connection has already been established */
1287 if(ssl_connection_complete == connssl->state) {
1288 *done = TRUE;
1289 return CURLE_OK;
1290 }
1291
1292 if(ssl_connect_1 == connssl->connecting_state) {
1293 /* Find out how much more time we're allowed */
1294 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1295
1296 if(timeout_ms < 0) {
1297 /* no need to continue if time already is up */
1298 failf(data, "SSL connection timeout");
1299 return CURLE_OPERATION_TIMEDOUT;
1300 }
1301 retcode = mbed_connect_step1(cf, data);
1302 if(retcode)
1303 return retcode;
1304 }
1305
1306 while(ssl_connect_2 == connssl->connecting_state ||
1307 ssl_connect_2_reading == connssl->connecting_state ||
1308 ssl_connect_2_writing == connssl->connecting_state) {
1309
1310 /* check allowed time left */
1311 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1312
1313 if(timeout_ms < 0) {
1314 /* no need to continue if time already is up */
1315 failf(data, "SSL connection timeout");
1316 return CURLE_OPERATION_TIMEDOUT;
1317 }
1318
1319 /* if ssl is expecting something, check if it's available. */
1320 if(connssl->connecting_state == ssl_connect_2_reading
1321 || connssl->connecting_state == ssl_connect_2_writing) {
1322
1323 curl_socket_t writefd = ssl_connect_2_writing ==
1324 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1325 curl_socket_t readfd = ssl_connect_2_reading ==
1326 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1327
1328 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1329 nonblocking ? 0 : timeout_ms);
1330 if(what < 0) {
1331 /* fatal error */
1332 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1333 return CURLE_SSL_CONNECT_ERROR;
1334 }
1335 else if(0 == what) {
1336 if(nonblocking) {
1337 *done = FALSE;
1338 return CURLE_OK;
1339 }
1340 else {
1341 /* timeout */
1342 failf(data, "SSL connection timeout");
1343 return CURLE_OPERATION_TIMEDOUT;
1344 }
1345 }
1346 /* socket is readable or writable */
1347 }
1348
1349 /* Run transaction, and return to the caller if it failed or if
1350 * this connection is part of a multi handle and this loop would
1351 * execute again. This permits the owner of a multi handle to
1352 * abort a connection attempt before step2 has completed while
1353 * ensuring that a client using select() or epoll() will always
1354 * have a valid fdset to wait on.
1355 */
1356 retcode = mbed_connect_step2(cf, data);
1357 if(retcode || (nonblocking &&
1358 (ssl_connect_2 == connssl->connecting_state ||
1359 ssl_connect_2_reading == connssl->connecting_state ||
1360 ssl_connect_2_writing == connssl->connecting_state)))
1361 return retcode;
1362
1363 } /* repeat step2 until all transactions are done. */
1364
1365 if(ssl_connect_3 == connssl->connecting_state) {
1366 retcode = mbed_connect_step3(cf, data);
1367 if(retcode)
1368 return retcode;
1369 }
1370
1371 if(ssl_connect_done == connssl->connecting_state) {
1372 connssl->state = ssl_connection_complete;
1373 *done = TRUE;
1374 }
1375 else
1376 *done = FALSE;
1377
1378 /* Reset our connect state machine */
1379 connssl->connecting_state = ssl_connect_1;
1380
1381 return CURLE_OK;
1382 }
1383
1384 static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf,
1385 struct Curl_easy *data,
1386 bool *done)
1387 {
1388 return mbed_connect_common(cf, data, TRUE, done);
1389 }
1390
1391
1392 static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
1393 struct Curl_easy *data)
1394 {
1395 CURLcode retcode;
1396 bool done = FALSE;
1397
1398 retcode = mbed_connect_common(cf, data, FALSE, &done);
1399 if(retcode)
1400 return retcode;
1401
1402 DEBUGASSERT(done);
1403
1404 return CURLE_OK;
1405 }
1406
1407 /*
1408 * return 0 error initializing SSL
1409 * return 1 SSL initialized successfully
1410 */
1411 static int mbedtls_init(void)
1412 {
1413 if(!Curl_mbedtlsthreadlock_thread_setup())
1414 return 0;
1415 #ifdef THREADING_SUPPORT
1416 entropy_init_mutex(&ts_entropy);
1417 #endif
1418 return 1;
1419 }
1420
1421 static void mbedtls_cleanup(void)
1422 {
1423 #ifdef THREADING_SUPPORT
1424 entropy_cleanup_mutex(&ts_entropy);
1425 #endif
1426 (void)Curl_mbedtlsthreadlock_thread_cleanup();
1427 }
1428
1429 static bool mbedtls_data_pending(struct Curl_cfilter *cf,
1430 const struct Curl_easy *data)
1431 {
1432 struct ssl_connect_data *ctx = cf->ctx;
1433 struct mbed_ssl_backend_data *backend;
1434
1435 (void)data;
1436 DEBUGASSERT(ctx && ctx->backend);
1437 backend = (struct mbed_ssl_backend_data *)ctx->backend;
1438 return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
1439 }
1440
1441 static CURLcode mbedtls_sha256sum(const unsigned char *input,
1442 size_t inputlen,
1443 unsigned char *sha256sum,
1444 size_t sha256len UNUSED_PARAM)
1445 {
1446 /* TODO: explain this for different mbedtls 2.x vs 3 version */
1447 (void)sha256len;
1448 #if MBEDTLS_VERSION_NUMBER < 0x02070000
1449 mbedtls_sha256(input, inputlen, sha256sum, 0);
1450 #else
1451 /* returns 0 on success, otherwise failure */
1452 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
1453 if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0)
1454 #else
1455 if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
1456 #endif
1457 return CURLE_BAD_FUNCTION_ARGUMENT;
1458 #endif
1459 return CURLE_OK;
1460 }
1461
1462 static void *mbedtls_get_internals(struct ssl_connect_data *connssl,
1463 CURLINFO info UNUSED_PARAM)
1464 {
1465 struct mbed_ssl_backend_data *backend =
1466 (struct mbed_ssl_backend_data *)connssl->backend;
1467 (void)info;
1468 DEBUGASSERT(backend);
1469 return &backend->ssl;
1470 }
1471
1472 const struct Curl_ssl Curl_ssl_mbedtls = {
1473 { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
1474
1475 SSLSUPP_CA_PATH |
1476 SSLSUPP_CAINFO_BLOB |
1477 SSLSUPP_PINNEDPUBKEY |
1478 SSLSUPP_SSL_CTX |
1479 SSLSUPP_HTTPS_PROXY,
1480
1481 sizeof(struct mbed_ssl_backend_data),
1482
1483 mbedtls_init, /* init */
1484 mbedtls_cleanup, /* cleanup */
1485 mbedtls_version, /* version */
1486 Curl_none_check_cxn, /* check_cxn */
1487 Curl_none_shutdown, /* shutdown */
1488 mbedtls_data_pending, /* data_pending */
1489 mbedtls_random, /* random */
1490 Curl_none_cert_status_request, /* cert_status_request */
1491 mbedtls_connect, /* connect */
1492 mbedtls_connect_nonblocking, /* connect_nonblocking */
1493 Curl_ssl_adjust_pollset, /* adjust_pollset */
1494 mbedtls_get_internals, /* get_internals */
1495 mbedtls_close, /* close_one */
1496 mbedtls_close_all, /* close_all */
1497 Curl_none_set_engine, /* set_engine */
1498 Curl_none_set_engine_default, /* set_engine_default */
1499 Curl_none_engines_list, /* engines_list */
1500 Curl_none_false_start, /* false_start */
1501 mbedtls_sha256sum, /* sha256sum */
1502 NULL, /* associate_connection */
1503 NULL, /* disassociate_connection */
1504 NULL, /* free_multi_ssl_backend_data */
1505 mbed_recv, /* recv decrypted data */
1506 mbed_send, /* send data to encrypt */
1507 };
1508
1509 #endif /* USE_MBEDTLS */
1510