• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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