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