Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / vtls / mbedtls.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9  * Copyright (C) 2010 - 2011, 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 #include <mbedtls/version.h>
40 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
41 #include <mbedtls/net_sockets.h>
42 #else
43 #include <mbedtls/net.h>
44 #endif
45 #include <mbedtls/ssl.h>
46 #include <mbedtls/x509.h>
47
48 #include <mbedtls/error.h>
49 #include <mbedtls/entropy.h>
50 #include <mbedtls/ctr_drbg.h>
51 #include <mbedtls/sha256.h>
52
53 #if MBEDTLS_VERSION_MAJOR >= 2
54 #  ifdef MBEDTLS_DEBUG
55 #    include <mbedtls/debug.h>
56 #  endif
57 #endif
58
59 #include "urldata.h"
60 #include "sendf.h"
61 #include "inet_pton.h"
62 #include "mbedtls.h"
63 #include "vtls.h"
64 #include "parsedate.h"
65 #include "connect.h" /* for the connect timeout */
66 #include "select.h"
67 #include "multiif.h"
68 #include "mbedtls_threadlock.h"
69
70 /* The last 3 #include files should be in this order */
71 #include "curl_printf.h"
72 #include "curl_memory.h"
73 #include "memdebug.h"
74
75 /* ALPN for http2 */
76 #ifdef USE_HTTP2
77 #  undef HAS_ALPN
78 #  ifdef MBEDTLS_SSL_ALPN
79 #    define HAS_ALPN
80 #  endif
81 #endif
82
83 struct ssl_backend_data {
84   mbedtls_ctr_drbg_context ctr_drbg;
85   mbedtls_entropy_context entropy;
86   mbedtls_ssl_context ssl;
87   mbedtls_x509_crt cacert;
88   mbedtls_x509_crt clicert;
89 #ifdef MBEDTLS_X509_CRL_PARSE_C
90   mbedtls_x509_crl crl;
91 #endif
92   mbedtls_pk_context pk;
93   mbedtls_ssl_config config;
94 #ifdef HAS_ALPN
95   const char *protocols[3];
96 #endif
97 };
98
99 /* apply threading? */
100 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
101 #define THREADING_SUPPORT
102 #endif
103
104 #ifndef MBEDTLS_ERROR_C
105 #define mbedtls_strerror(a,b,c) b[0] = 0
106 #endif
107
108 #if defined(THREADING_SUPPORT)
109 static mbedtls_entropy_context ts_entropy;
110
111 static int entropy_init_initialized = 0;
112
113 /* start of entropy_init_mutex() */
114 static void entropy_init_mutex(mbedtls_entropy_context *ctx)
115 {
116   /* lock 0 = entropy_init_mutex() */
117   Curl_mbedtlsthreadlock_lock_function(0);
118   if(entropy_init_initialized == 0) {
119     mbedtls_entropy_init(ctx);
120     entropy_init_initialized = 1;
121   }
122   Curl_mbedtlsthreadlock_unlock_function(0);
123 }
124 /* end of entropy_init_mutex() */
125
126 /* start of entropy_func_mutex() */
127 static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
128 {
129   int ret;
130   /* lock 1 = entropy_func_mutex() */
131   Curl_mbedtlsthreadlock_lock_function(1);
132   ret = mbedtls_entropy_func(data, output, len);
133   Curl_mbedtlsthreadlock_unlock_function(1);
134
135   return ret;
136 }
137 /* end of entropy_func_mutex() */
138
139 #endif /* THREADING_SUPPORT */
140
141 #ifdef MBEDTLS_DEBUG
142 static void mbed_debug(void *context, int level, const char *f_name,
143                        int line_nb, const char *line)
144 {
145   struct Curl_easy *data = NULL;
146
147   if(!context)
148     return;
149
150   data = (struct Curl_easy *)context;
151
152   infof(data, "%s", line);
153   (void) level;
154 }
155 #else
156 #endif
157
158 /*
159  *  profile
160  */
161 static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
162 {
163   /* Hashes from SHA-1 and above */
164   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
165   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
166   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
167   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
168   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
169   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
170   0xFFFFFFF, /* Any PK alg    */
171   0xFFFFFFF, /* Any curve     */
172   1024,      /* RSA min key len */
173 };
174
175 /* See https://tls.mbed.org/discussions/generic/
176    howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
177 */
178 #define RSA_PUB_DER_MAX_BYTES   (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
179 #define ECP_PUB_DER_MAX_BYTES   (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
180
181 #define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
182                              RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
183
184 static Curl_recv mbed_recv;
185 static Curl_send mbed_send;
186
187 static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
188 {
189 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
190   switch(version) {
191     case CURL_SSLVERSION_TLSv1_0:
192     case CURL_SSLVERSION_TLSv1_1:
193     case CURL_SSLVERSION_TLSv1_2:
194       *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
195       return CURLE_OK;
196     case CURL_SSLVERSION_TLSv1_3:
197       break;
198   }
199 #else
200   switch(version) {
201     case CURL_SSLVERSION_TLSv1_0:
202       *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
203       return CURLE_OK;
204     case CURL_SSLVERSION_TLSv1_1:
205       *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
206       return CURLE_OK;
207     case CURL_SSLVERSION_TLSv1_2:
208       *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
209       return CURLE_OK;
210     case CURL_SSLVERSION_TLSv1_3:
211       break;
212   }
213 #endif
214
215   return CURLE_SSL_CONNECT_ERROR;
216 }
217
218 static CURLcode
219 set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
220                         int sockindex)
221 {
222   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
223   struct ssl_backend_data *backend = connssl->backend;
224 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
225   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
226   int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
227 #else
228   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
229   int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
230 #endif
231   long ssl_version = SSL_CONN_CONFIG(version);
232   long ssl_version_max = SSL_CONN_CONFIG(version_max);
233   CURLcode result = CURLE_OK;
234
235   DEBUGASSERT(backend);
236
237   switch(ssl_version) {
238     case CURL_SSLVERSION_DEFAULT:
239     case CURL_SSLVERSION_TLSv1:
240       ssl_version = CURL_SSLVERSION_TLSv1_0;
241       break;
242   }
243
244   switch(ssl_version_max) {
245     case CURL_SSLVERSION_MAX_NONE:
246     case CURL_SSLVERSION_MAX_DEFAULT:
247       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
248       break;
249   }
250
251   result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
252   if(result) {
253     failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
254     return result;
255   }
256   result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
257   if(result) {
258     failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
259     return result;
260   }
261
262   mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
263                                mbedtls_ver_min);
264   mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
265                                mbedtls_ver_max);
266
267   return result;
268 }
269
270 static CURLcode
271 mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
272                    int sockindex)
273 {
274   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
275   struct ssl_backend_data *backend = connssl->backend;
276   const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
277   const char * const ssl_cafile =
278     /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
279     (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
280   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
281   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
282   char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
283   const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
284   const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile);
285   const char * const hostname = SSL_HOST_NAME();
286 #ifndef CURL_DISABLE_VERBOSE_STRINGS
287   const long int port = SSL_HOST_PORT();
288 #endif
289   int ret = -1;
290   char errorbuf[128];
291
292   DEBUGASSERT(backend);
293
294   if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) ||
295      (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) {
296     failf(data, "Not supported SSL version");
297     return CURLE_NOT_BUILT_IN;
298   }
299
300 #ifdef THREADING_SUPPORT
301   entropy_init_mutex(&ts_entropy);
302   mbedtls_ctr_drbg_init(&backend->ctr_drbg);
303
304   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
305                               &ts_entropy, NULL, 0);
306   if(ret) {
307     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
308     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
309           -ret, errorbuf);
310     return CURLE_FAILED_INIT;
311   }
312 #else
313   mbedtls_entropy_init(&backend->entropy);
314   mbedtls_ctr_drbg_init(&backend->ctr_drbg);
315
316   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func,
317                               &backend->entropy, NULL, 0);
318   if(ret) {
319     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
320     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
321           -ret, errorbuf);
322     return CURLE_FAILED_INIT;
323   }
324 #endif /* THREADING_SUPPORT */
325
326   /* Load the trusted CA */
327   mbedtls_x509_crt_init(&backend->cacert);
328
329   if(ca_info_blob && verifypeer) {
330     /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
331        terminated even when provided the exact length, forcing us to waste
332        extra memory here. */
333     unsigned char *newblob = malloc(ca_info_blob->len + 1);
334     if(!newblob)
335       return CURLE_OUT_OF_MEMORY;
336     memcpy(newblob, ca_info_blob->data, ca_info_blob->len);
337     newblob[ca_info_blob->len] = 0; /* null terminate */
338     ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
339                                  ca_info_blob->len + 1);
340     free(newblob);
341     if(ret<0) {
342       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
343       failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
344             -ret, errorbuf);
345       return CURLE_SSL_CERTPROBLEM;
346     }
347   }
348
349   if(ssl_cafile && verifypeer) {
350 #ifdef MBEDTLS_FS_IO
351     ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
352
353     if(ret<0) {
354       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
355       failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
356             ssl_cafile, -ret, errorbuf);
357       return CURLE_SSL_CACERT_BADFILE;
358     }
359 #else
360     failf(data, "mbedtls: functions that use the filesystem not built in");
361     return CURLE_NOT_BUILT_IN;
362 #endif
363   }
364
365   if(ssl_capath) {
366 #ifdef MBEDTLS_FS_IO
367     ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
368
369     if(ret<0) {
370       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
371       failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
372             ssl_capath, -ret, errorbuf);
373
374       if(verifypeer)
375         return CURLE_SSL_CACERT_BADFILE;
376     }
377 #else
378     failf(data, "mbedtls: functions that use the filesystem not built in");
379     return CURLE_NOT_BUILT_IN;
380 #endif
381   }
382
383   /* Load the client certificate */
384   mbedtls_x509_crt_init(&backend->clicert);
385
386   if(ssl_cert) {
387 #ifdef MBEDTLS_FS_IO
388     ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert);
389
390     if(ret) {
391       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
392       failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
393             ssl_cert, -ret, errorbuf);
394
395       return CURLE_SSL_CERTPROBLEM;
396     }
397 #else
398     failf(data, "mbedtls: functions that use the filesystem not built in");
399     return CURLE_NOT_BUILT_IN;
400 #endif
401   }
402
403   if(ssl_cert_blob) {
404     /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
405        terminated even when provided the exact length, forcing us to waste
406        extra memory here. */
407     unsigned char *newblob = malloc(ssl_cert_blob->len + 1);
408     if(!newblob)
409       return CURLE_OUT_OF_MEMORY;
410     memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len);
411     newblob[ssl_cert_blob->len] = 0; /* null terminate */
412     ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
413                                  ssl_cert_blob->len + 1);
414     free(newblob);
415
416     if(ret) {
417       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
418       failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
419             SSL_SET_OPTION(key), -ret, errorbuf);
420       return CURLE_SSL_CERTPROBLEM;
421     }
422   }
423
424   /* Load the client private key */
425   mbedtls_pk_init(&backend->pk);
426
427   if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
428     if(SSL_SET_OPTION(key)) {
429 #ifdef MBEDTLS_FS_IO
430 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
431       ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
432                                      SSL_SET_OPTION(key_passwd),
433                                      mbedtls_ctr_drbg_random,
434                                      &backend->ctr_drbg);
435 #else
436       ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
437                                      SSL_SET_OPTION(key_passwd));
438 #endif
439
440       if(ret) {
441         mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
442         failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
443               SSL_SET_OPTION(key), -ret, errorbuf);
444         return CURLE_SSL_CERTPROBLEM;
445       }
446 #else
447       failf(data, "mbedtls: functions that use the filesystem not built in");
448       return CURLE_NOT_BUILT_IN;
449 #endif
450     }
451     else {
452       const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob);
453       const unsigned char *key_data =
454         (const unsigned char *)ssl_key_blob->data;
455       const char *passwd = SSL_SET_OPTION(key_passwd);
456 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
457       ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
458                                  (const unsigned char *)passwd,
459                                  passwd ? strlen(passwd) : 0,
460                                  mbedtls_ctr_drbg_random,
461                                  &backend->ctr_drbg);
462 #else
463       ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
464                                  (const unsigned char *)passwd,
465                                  passwd ? strlen(passwd) : 0);
466 #endif
467
468       if(ret) {
469         mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
470         failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s",
471               -ret, errorbuf);
472         return CURLE_SSL_CERTPROBLEM;
473       }
474     }
475
476     if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
477                      mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
478       ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
479   }
480
481   /* Load the CRL */
482 #ifdef MBEDTLS_X509_CRL_PARSE_C
483   mbedtls_x509_crl_init(&backend->crl);
484
485   if(ssl_crlfile) {
486 #ifdef MBEDTLS_FS_IO
487     ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile);
488
489     if(ret) {
490       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
491       failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
492             ssl_crlfile, -ret, errorbuf);
493
494       return CURLE_SSL_CRL_BADFILE;
495     }
496 #else
497     failf(data, "mbedtls: functions that use the filesystem not built in");
498     return CURLE_NOT_BUILT_IN;
499 #endif
500   }
501 #else
502   if(ssl_crlfile) {
503     failf(data, "mbedtls: crl support not built in");
504     return CURLE_NOT_BUILT_IN;
505   }
506 #endif
507
508   infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port);
509
510   mbedtls_ssl_config_init(&backend->config);
511   ret = mbedtls_ssl_config_defaults(&backend->config,
512                                     MBEDTLS_SSL_IS_CLIENT,
513                                     MBEDTLS_SSL_TRANSPORT_STREAM,
514                                     MBEDTLS_SSL_PRESET_DEFAULT);
515   if(ret) {
516     failf(data, "mbedTLS: ssl_config failed");
517     return CURLE_SSL_CONNECT_ERROR;
518   }
519
520   mbedtls_ssl_init(&backend->ssl);
521   if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) {
522     failf(data, "mbedTLS: ssl_init failed");
523     return CURLE_SSL_CONNECT_ERROR;
524   }
525
526   /* new profile with RSA min key len = 1024 ... */
527   mbedtls_ssl_conf_cert_profile(&backend->config,
528                                 &mbedtls_x509_crt_profile_fr);
529
530   switch(SSL_CONN_CONFIG(version)) {
531   case CURL_SSLVERSION_DEFAULT:
532   case CURL_SSLVERSION_TLSv1:
533 #if MBEDTLS_VERSION_NUMBER < 0x03000000
534     mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
535                                  MBEDTLS_SSL_MINOR_VERSION_1);
536     infof(data, "mbedTLS: Set min SSL version to TLS 1.0");
537     break;
538 #endif
539   case CURL_SSLVERSION_TLSv1_0:
540   case CURL_SSLVERSION_TLSv1_1:
541   case CURL_SSLVERSION_TLSv1_2:
542   case CURL_SSLVERSION_TLSv1_3:
543     {
544       CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
545       if(result != CURLE_OK)
546         return result;
547       break;
548     }
549   default:
550     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
551     return CURLE_SSL_CONNECT_ERROR;
552   }
553
554   mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
555
556   mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
557                        &backend->ctr_drbg);
558   mbedtls_ssl_set_bio(&backend->ssl, &conn->sock[sockindex],
559                       mbedtls_net_send,
560                       mbedtls_net_recv,
561                       NULL /*  rev_timeout() */);
562
563   mbedtls_ssl_conf_ciphersuites(&backend->config,
564                                 mbedtls_ssl_list_ciphersuites());
565
566 #if defined(MBEDTLS_SSL_RENEGOTIATION)
567   mbedtls_ssl_conf_renegotiation(&backend->config,
568                                  MBEDTLS_SSL_RENEGOTIATION_ENABLED);
569 #endif
570
571 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
572   mbedtls_ssl_conf_session_tickets(&backend->config,
573                                    MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
574 #endif
575
576   /* Check if there's a cached ID we can/should use here! */
577   if(SSL_SET_OPTION(primary.sessionid)) {
578     void *old_session = NULL;
579
580     Curl_ssl_sessionid_lock(data);
581     if(!Curl_ssl_getsessionid(data, conn,
582                               SSL_IS_PROXY() ? TRUE : FALSE,
583                               &old_session, NULL, sockindex)) {
584       ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
585       if(ret) {
586         Curl_ssl_sessionid_unlock(data);
587         failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
588         return CURLE_SSL_CONNECT_ERROR;
589       }
590       infof(data, "mbedTLS re-using session");
591     }
592     Curl_ssl_sessionid_unlock(data);
593   }
594
595   mbedtls_ssl_conf_ca_chain(&backend->config,
596                             &backend->cacert,
597 #ifdef MBEDTLS_X509_CRL_PARSE_C
598                             &backend->crl);
599 #else
600                             NULL);
601 #endif
602
603   if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
604     mbedtls_ssl_conf_own_cert(&backend->config,
605                               &backend->clicert, &backend->pk);
606   }
607   {
608     char *snihost = Curl_ssl_snihost(data, hostname, NULL);
609     if(!snihost || mbedtls_ssl_set_hostname(&backend->ssl, snihost)) {
610       /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
611          the name to set in the SNI extension. So even if curl connects to a
612          host specified as an IP address, this function must be used. */
613       failf(data, "Failed to set SNI");
614       return CURLE_SSL_CONNECT_ERROR;
615     }
616   }
617
618 #ifdef HAS_ALPN
619   if(conn->bits.tls_enable_alpn) {
620     const char **p = &backend->protocols[0];
621 #ifdef USE_HTTP2
622     if(data->state.httpwant >= CURL_HTTP_VERSION_2)
623       *p++ = ALPN_H2;
624 #endif
625     *p++ = ALPN_HTTP_1_1;
626     *p = NULL;
627     /* this function doesn't clone the protocols array, which is why we need
628        to keep it around */
629     if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
630                                        &backend->protocols[0])) {
631       failf(data, "Failed setting ALPN protocols");
632       return CURLE_SSL_CONNECT_ERROR;
633     }
634     for(p = &backend->protocols[0]; *p; ++p)
635       infof(data, VTLS_INFOF_ALPN_OFFER_1STR, *p);
636   }
637 #endif
638
639 #ifdef MBEDTLS_DEBUG
640   /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
641   mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data);
642   /* - 0 No debug
643    * - 1 Error
644    * - 2 State change
645    * - 3 Informational
646    * - 4 Verbose
647    */
648   mbedtls_debug_set_threshold(4);
649 #endif
650
651   /* give application a chance to interfere with mbedTLS set up. */
652   if(data->set.ssl.fsslctx) {
653     ret = (*data->set.ssl.fsslctx)(data, &backend->config,
654                                    data->set.ssl.fsslctxp);
655     if(ret) {
656       failf(data, "error signaled by ssl ctx callback");
657       return ret;
658     }
659   }
660
661   connssl->connecting_state = ssl_connect_2;
662
663   return CURLE_OK;
664 }
665
666 static CURLcode
667 mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
668                    int sockindex)
669 {
670   int ret;
671   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
672   struct ssl_backend_data *backend = connssl->backend;
673   const mbedtls_x509_crt *peercert;
674   const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
675
676   DEBUGASSERT(backend);
677
678   conn->recv[sockindex] = mbed_recv;
679   conn->send[sockindex] = mbed_send;
680
681   ret = mbedtls_ssl_handshake(&backend->ssl);
682
683   if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
684     connssl->connecting_state = ssl_connect_2_reading;
685     return CURLE_OK;
686   }
687   else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
688     connssl->connecting_state = ssl_connect_2_writing;
689     return CURLE_OK;
690   }
691   else if(ret) {
692     char errorbuf[128];
693     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
694     failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
695           -ret, errorbuf);
696     return CURLE_SSL_CONNECT_ERROR;
697   }
698
699   infof(data, "mbedTLS: Handshake complete, cipher is %s",
700         mbedtls_ssl_get_ciphersuite(&backend->ssl));
701
702   ret = mbedtls_ssl_get_verify_result(&backend->ssl);
703
704   if(!SSL_CONN_CONFIG(verifyhost))
705     /* Ignore hostname errors if verifyhost is disabled */
706     ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
707
708   if(ret && SSL_CONN_CONFIG(verifypeer)) {
709     if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
710       failf(data, "Cert verify failed: BADCERT_EXPIRED");
711
712     else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
713       failf(data, "Cert verify failed: BADCERT_REVOKED");
714
715     else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
716       failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
717
718     else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
719       failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
720
721     else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
722       failf(data, "Cert verify failed: BADCERT_FUTURE");
723
724     return CURLE_PEER_FAILED_VERIFICATION;
725   }
726
727   peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
728
729   if(peercert && data->set.verbose) {
730     const size_t bufsize = 16384;
731     char *buffer = malloc(bufsize);
732
733     if(!buffer)
734       return CURLE_OUT_OF_MEMORY;
735
736     if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
737       infof(data, "Dumping cert info: %s", buffer);
738     else
739       infof(data, "Unable to dump certificate information");
740
741     free(buffer);
742   }
743
744   if(pinnedpubkey) {
745     int size;
746     CURLcode result;
747     mbedtls_x509_crt *p = NULL;
748     unsigned char *pubkey = NULL;
749
750 #if MBEDTLS_VERSION_NUMBER == 0x03000000
751     if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
752        !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
753 #else
754     if(!peercert || !peercert->raw.p || !peercert->raw.len) {
755 #endif
756       failf(data, "Failed due to missing peer certificate");
757       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
758     }
759
760     p = calloc(1, sizeof(*p));
761
762     if(!p)
763       return CURLE_OUT_OF_MEMORY;
764
765     pubkey = malloc(PUB_DER_MAX_BYTES);
766
767     if(!pubkey) {
768       result = CURLE_OUT_OF_MEMORY;
769       goto pinnedpubkey_error;
770     }
771
772     mbedtls_x509_crt_init(p);
773
774     /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
775        needs a non-const key, for now.
776        https://github.com/ARMmbed/mbedtls/issues/396 */
777 #if MBEDTLS_VERSION_NUMBER == 0x03000000
778     if(mbedtls_x509_crt_parse_der(p,
779                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
780                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
781 #else
782     if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
783 #endif
784       failf(data, "Failed copying peer certificate");
785       result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
786       goto pinnedpubkey_error;
787     }
788
789 #if MBEDTLS_VERSION_NUMBER == 0x03000000
790     size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
791                                        PUB_DER_MAX_BYTES);
792 #else
793     size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
794 #endif
795
796     if(size <= 0) {
797       failf(data, "Failed copying public key from peer certificate");
798       result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
799       goto pinnedpubkey_error;
800     }
801
802     /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
803     result = Curl_pin_peer_pubkey(data,
804                                   pinnedpubkey,
805                                   &pubkey[PUB_DER_MAX_BYTES - size], size);
806     pinnedpubkey_error:
807     mbedtls_x509_crt_free(p);
808     free(p);
809     free(pubkey);
810     if(result) {
811       return result;
812     }
813   }
814
815 #ifdef HAS_ALPN
816   if(conn->bits.tls_enable_alpn) {
817     const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
818
819     if(next_protocol) {
820       infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, next_protocol);
821 #ifdef USE_HTTP2
822       if(!strncmp(next_protocol, ALPN_H2, ALPN_H2_LENGTH) &&
823          !next_protocol[ALPN_H2_LENGTH]) {
824         conn->alpn = CURL_HTTP_VERSION_2;
825       }
826       else
827 #endif
828         if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
829            !next_protocol[ALPN_HTTP_1_1_LENGTH]) {
830           conn->alpn = CURL_HTTP_VERSION_1_1;
831         }
832     }
833     else {
834       infof(data, VTLS_INFOF_NO_ALPN);
835     }
836     Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
837                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
838   }
839 #endif
840
841   connssl->connecting_state = ssl_connect_3;
842   infof(data, "SSL connected");
843
844   return CURLE_OK;
845 }
846
847 static CURLcode
848 mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
849                    int sockindex)
850 {
851   CURLcode retcode = CURLE_OK;
852   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
853   struct ssl_backend_data *backend = connssl->backend;
854
855   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
856   DEBUGASSERT(backend);
857
858   if(SSL_SET_OPTION(primary.sessionid)) {
859     int ret;
860     mbedtls_ssl_session *our_ssl_sessionid;
861     void *old_ssl_sessionid = NULL;
862     bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
863     bool added = FALSE;
864
865     our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
866     if(!our_ssl_sessionid)
867       return CURLE_OUT_OF_MEMORY;
868
869     mbedtls_ssl_session_init(our_ssl_sessionid);
870
871     ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
872     if(ret) {
873       if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
874         mbedtls_ssl_session_free(our_ssl_sessionid);
875       free(our_ssl_sessionid);
876       failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
877       return CURLE_SSL_CONNECT_ERROR;
878     }
879
880     /* If there's already a matching session in the cache, delete it */
881     Curl_ssl_sessionid_lock(data);
882     if(!Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
883                               sockindex))
884       Curl_ssl_delsessionid(data, old_ssl_sessionid);
885
886     retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
887                                     0, sockindex, &added);
888     Curl_ssl_sessionid_unlock(data);
889     if(!added) {
890       mbedtls_ssl_session_free(our_ssl_sessionid);
891       free(our_ssl_sessionid);
892     }
893     if(retcode) {
894       failf(data, "failed to store ssl session");
895       return retcode;
896     }
897   }
898
899   connssl->connecting_state = ssl_connect_done;
900
901   return CURLE_OK;
902 }
903
904 static ssize_t mbed_send(struct Curl_easy *data, int sockindex,
905                          const void *mem, size_t len,
906                          CURLcode *curlcode)
907 {
908   struct connectdata *conn = data->conn;
909   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
910   struct ssl_backend_data *backend = connssl->backend;
911   int ret = -1;
912
913   DEBUGASSERT(backend);
914
915   ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
916
917   if(ret < 0) {
918     *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
919       CURLE_AGAIN : CURLE_SEND_ERROR;
920     ret = -1;
921   }
922
923   return ret;
924 }
925
926 static void mbedtls_close_all(struct Curl_easy *data)
927 {
928   (void)data;
929 }
930
931 static void mbedtls_close(struct Curl_easy *data,
932                           struct connectdata *conn, int sockindex)
933 {
934   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
935   struct ssl_backend_data *backend = connssl->backend;
936   char buf[32];
937   (void) data;
938
939   DEBUGASSERT(backend);
940
941   /* Maybe the server has already sent a close notify alert.
942      Read it to avoid an RST on the TCP connection. */
943   (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
944
945   mbedtls_pk_free(&backend->pk);
946   mbedtls_x509_crt_free(&backend->clicert);
947   mbedtls_x509_crt_free(&backend->cacert);
948 #ifdef MBEDTLS_X509_CRL_PARSE_C
949   mbedtls_x509_crl_free(&backend->crl);
950 #endif
951   mbedtls_ssl_config_free(&backend->config);
952   mbedtls_ssl_free(&backend->ssl);
953   mbedtls_ctr_drbg_free(&backend->ctr_drbg);
954 #ifndef THREADING_SUPPORT
955   mbedtls_entropy_free(&backend->entropy);
956 #endif /* THREADING_SUPPORT */
957 }
958
959 static ssize_t mbed_recv(struct Curl_easy *data, int num,
960                          char *buf, size_t buffersize,
961                          CURLcode *curlcode)
962 {
963   struct connectdata *conn = data->conn;
964   struct ssl_connect_data *connssl = &conn->ssl[num];
965   struct ssl_backend_data *backend = connssl->backend;
966   int ret = -1;
967   ssize_t len = -1;
968
969   DEBUGASSERT(backend);
970
971   ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
972                          buffersize);
973
974   if(ret <= 0) {
975     if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
976       return 0;
977
978     *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
979       CURLE_AGAIN : CURLE_RECV_ERROR;
980     return -1;
981   }
982
983   len = ret;
984
985   return len;
986 }
987
988 static void mbedtls_session_free(void *ptr)
989 {
990   mbedtls_ssl_session_free(ptr);
991   free(ptr);
992 }
993
994 static size_t mbedtls_version(char *buffer, size_t size)
995 {
996 #ifdef MBEDTLS_VERSION_C
997   /* if mbedtls_version_get_number() is available it is better */
998   unsigned int version = mbedtls_version_get_number();
999   return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
1000                    (version>>16)&0xff, (version>>8)&0xff);
1001 #else
1002   return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
1003 #endif
1004 }
1005
1006 static CURLcode mbedtls_random(struct Curl_easy *data,
1007                                unsigned char *entropy, size_t length)
1008 {
1009 #if defined(MBEDTLS_CTR_DRBG_C)
1010   int ret = -1;
1011   char errorbuf[128];
1012   mbedtls_entropy_context ctr_entropy;
1013   mbedtls_ctr_drbg_context ctr_drbg;
1014   mbedtls_entropy_init(&ctr_entropy);
1015   mbedtls_ctr_drbg_init(&ctr_drbg);
1016
1017   ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
1018                               &ctr_entropy, NULL, 0);
1019
1020   if(ret) {
1021     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
1022     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
1023           -ret, errorbuf);
1024   }
1025   else {
1026     ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
1027
1028     if(ret) {
1029       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
1030       failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s",
1031             -ret, errorbuf);
1032     }
1033   }
1034
1035   mbedtls_ctr_drbg_free(&ctr_drbg);
1036   mbedtls_entropy_free(&ctr_entropy);
1037
1038   return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT;
1039 #elif defined(MBEDTLS_HAVEGE_C)
1040   mbedtls_havege_state hs;
1041   mbedtls_havege_init(&hs);
1042   mbedtls_havege_random(&hs, entropy, length);
1043   mbedtls_havege_free(&hs);
1044   return CURLE_OK;
1045 #else
1046   return CURLE_NOT_BUILT_IN;
1047 #endif
1048 }
1049
1050 static CURLcode
1051 mbed_connect_common(struct Curl_easy *data,
1052                     struct connectdata *conn,
1053                     int sockindex,
1054                     bool nonblocking,
1055                     bool *done)
1056 {
1057   CURLcode retcode;
1058   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1059   curl_socket_t sockfd = conn->sock[sockindex];
1060   timediff_t timeout_ms;
1061   int what;
1062
1063   /* check if the connection has already been established */
1064   if(ssl_connection_complete == connssl->state) {
1065     *done = TRUE;
1066     return CURLE_OK;
1067   }
1068
1069   if(ssl_connect_1 == connssl->connecting_state) {
1070     /* Find out how much more time we're allowed */
1071     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1072
1073     if(timeout_ms < 0) {
1074       /* no need to continue if time already is up */
1075       failf(data, "SSL connection timeout");
1076       return CURLE_OPERATION_TIMEDOUT;
1077     }
1078     retcode = mbed_connect_step1(data, conn, sockindex);
1079     if(retcode)
1080       return retcode;
1081   }
1082
1083   while(ssl_connect_2 == connssl->connecting_state ||
1084         ssl_connect_2_reading == connssl->connecting_state ||
1085         ssl_connect_2_writing == connssl->connecting_state) {
1086
1087     /* check allowed time left */
1088     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1089
1090     if(timeout_ms < 0) {
1091       /* no need to continue if time already is up */
1092       failf(data, "SSL connection timeout");
1093       return CURLE_OPERATION_TIMEDOUT;
1094     }
1095
1096     /* if ssl is expecting something, check if it's available. */
1097     if(connssl->connecting_state == ssl_connect_2_reading
1098        || connssl->connecting_state == ssl_connect_2_writing) {
1099
1100       curl_socket_t writefd = ssl_connect_2_writing ==
1101         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1102       curl_socket_t readfd = ssl_connect_2_reading ==
1103         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1104
1105       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1106                                nonblocking ? 0 : timeout_ms);
1107       if(what < 0) {
1108         /* fatal error */
1109         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1110         return CURLE_SSL_CONNECT_ERROR;
1111       }
1112       else if(0 == what) {
1113         if(nonblocking) {
1114           *done = FALSE;
1115           return CURLE_OK;
1116         }
1117         else {
1118           /* timeout */
1119           failf(data, "SSL connection timeout");
1120           return CURLE_OPERATION_TIMEDOUT;
1121         }
1122       }
1123       /* socket is readable or writable */
1124     }
1125
1126     /* Run transaction, and return to the caller if it failed or if
1127      * this connection is part of a multi handle and this loop would
1128      * execute again. This permits the owner of a multi handle to
1129      * abort a connection attempt before step2 has completed while
1130      * ensuring that a client using select() or epoll() will always
1131      * have a valid fdset to wait on.
1132      */
1133     retcode = mbed_connect_step2(data, conn, sockindex);
1134     if(retcode || (nonblocking &&
1135                    (ssl_connect_2 == connssl->connecting_state ||
1136                     ssl_connect_2_reading == connssl->connecting_state ||
1137                     ssl_connect_2_writing == connssl->connecting_state)))
1138       return retcode;
1139
1140   } /* repeat step2 until all transactions are done. */
1141
1142   if(ssl_connect_3 == connssl->connecting_state) {
1143     retcode = mbed_connect_step3(data, conn, sockindex);
1144     if(retcode)
1145       return retcode;
1146   }
1147
1148   if(ssl_connect_done == connssl->connecting_state) {
1149     connssl->state = ssl_connection_complete;
1150     conn->recv[sockindex] = mbed_recv;
1151     conn->send[sockindex] = mbed_send;
1152     *done = TRUE;
1153   }
1154   else
1155     *done = FALSE;
1156
1157   /* Reset our connect state machine */
1158   connssl->connecting_state = ssl_connect_1;
1159
1160   return CURLE_OK;
1161 }
1162
1163 static CURLcode mbedtls_connect_nonblocking(struct Curl_easy *data,
1164                                             struct connectdata *conn,
1165                                             int sockindex, bool *done)
1166 {
1167   return mbed_connect_common(data, conn, sockindex, TRUE, done);
1168 }
1169
1170
1171 static CURLcode mbedtls_connect(struct Curl_easy *data,
1172                                 struct connectdata *conn, int sockindex)
1173 {
1174   CURLcode retcode;
1175   bool done = FALSE;
1176
1177   retcode = mbed_connect_common(data, conn, sockindex, FALSE, &done);
1178   if(retcode)
1179     return retcode;
1180
1181   DEBUGASSERT(done);
1182
1183   return CURLE_OK;
1184 }
1185
1186 /*
1187  * return 0 error initializing SSL
1188  * return 1 SSL initialized successfully
1189  */
1190 static int mbedtls_init(void)
1191 {
1192   return Curl_mbedtlsthreadlock_thread_setup();
1193 }
1194
1195 static void mbedtls_cleanup(void)
1196 {
1197   (void)Curl_mbedtlsthreadlock_thread_cleanup();
1198 }
1199
1200 static bool mbedtls_data_pending(const struct connectdata *conn,
1201                                  int sockindex)
1202 {
1203   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1204   struct ssl_backend_data *backend = connssl->backend;
1205   DEBUGASSERT(backend);
1206   return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
1207 }
1208
1209 static CURLcode mbedtls_sha256sum(const unsigned char *input,
1210                                   size_t inputlen,
1211                                   unsigned char *sha256sum,
1212                                   size_t sha256len UNUSED_PARAM)
1213 {
1214   /* TODO: explain this for different mbedtls 2.x vs 3 version */
1215   (void)sha256len;
1216 #if MBEDTLS_VERSION_NUMBER < 0x02070000
1217   mbedtls_sha256(input, inputlen, sha256sum, 0);
1218 #else
1219   /* returns 0 on success, otherwise failure */
1220 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
1221   if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0)
1222 #else
1223   if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
1224 #endif
1225     return CURLE_BAD_FUNCTION_ARGUMENT;
1226 #endif
1227   return CURLE_OK;
1228 }
1229
1230 static void *mbedtls_get_internals(struct ssl_connect_data *connssl,
1231                                    CURLINFO info UNUSED_PARAM)
1232 {
1233   struct ssl_backend_data *backend = connssl->backend;
1234   (void)info;
1235   DEBUGASSERT(backend);
1236   return &backend->ssl;
1237 }
1238
1239 const struct Curl_ssl Curl_ssl_mbedtls = {
1240   { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
1241
1242   SSLSUPP_CA_PATH |
1243   SSLSUPP_CAINFO_BLOB |
1244   SSLSUPP_PINNEDPUBKEY |
1245   SSLSUPP_SSL_CTX,
1246
1247   sizeof(struct ssl_backend_data),
1248
1249   mbedtls_init,                     /* init */
1250   mbedtls_cleanup,                  /* cleanup */
1251   mbedtls_version,                  /* version */
1252   Curl_none_check_cxn,              /* check_cxn */
1253   Curl_none_shutdown,               /* shutdown */
1254   mbedtls_data_pending,             /* data_pending */
1255   mbedtls_random,                   /* random */
1256   Curl_none_cert_status_request,    /* cert_status_request */
1257   mbedtls_connect,                  /* connect */
1258   mbedtls_connect_nonblocking,      /* connect_nonblocking */
1259   Curl_ssl_getsock,                 /* getsock */
1260   mbedtls_get_internals,            /* get_internals */
1261   mbedtls_close,                    /* close_one */
1262   mbedtls_close_all,                /* close_all */
1263   mbedtls_session_free,             /* session_free */
1264   Curl_none_set_engine,             /* set_engine */
1265   Curl_none_set_engine_default,     /* set_engine_default */
1266   Curl_none_engines_list,           /* engines_list */
1267   Curl_none_false_start,            /* false_start */
1268   mbedtls_sha256sum,                /* sha256sum */
1269   NULL,                             /* associate_connection */
1270   NULL                              /* disassociate_connection */
1271 };
1272
1273 #endif /* USE_MBEDTLS */