From 742a66f88dc42687963a80d8ad5ed05a7cdc7748 Mon Sep 17 00:00:00 2001 From: Wyatt O'Day Date: Mon, 4 Aug 2025 07:38:05 -0400 Subject: [PATCH] mbedTLS: clean-up insecure/deprecated code, and other fixes --- docs/libcurl/libcurl-thread.md | 7 + lib/vtls/cipher_suite.c | 3 +- lib/vtls/cipher_suite.h | 3 +- lib/vtls/mbedtls.c | 484 +++++++++++++++++---------------- lib/vtls/mbedtls_threadlock.c | 134 --------- lib/vtls/mbedtls_threadlock.h | 50 ---- 6 files changed, 256 insertions(+), 425 deletions(-) delete mode 100644 lib/vtls/mbedtls_threadlock.c delete mode 100644 lib/vtls/mbedtls_threadlock.h diff --git a/docs/libcurl/libcurl-thread.md b/docs/libcurl/libcurl-thread.md index ef7ae9b7d9..1ba2483b36 100644 --- a/docs/libcurl/libcurl-thread.md +++ b/docs/libcurl/libcurl-thread.md @@ -61,6 +61,13 @@ does this cleanup automatically and there is no leak (added in libcurl 8.8.0). Please review the OpenSSL documentation for a full list of circumstances: https://docs.openssl.org/3.0/man3/OPENSSL_init_crypto/#notes +## mbedTLS + +mbedTLS can be used safely in a multi-threaded environment provided that mbedTLS is +compiled with MBEDTLS_THREADING_C enabled. + +https://mbed-tls.readthedocs.io/en/latest/kb/development/thread-safety-and-multi-threading + # Signals Signals are used for timing out name resolves (during DNS lookup) - when built diff --git a/lib/vtls/cipher_suite.c b/lib/vtls/cipher_suite.c index 4bf60c1a4a..690ac464ba 100644 --- a/lib/vtls/cipher_suite.c +++ b/lib/vtls/cipher_suite.c @@ -23,7 +23,8 @@ ***************************************************************************/ #include "../curl_setup.h" -#if defined(USE_MBEDTLS) || defined(USE_RUSTLS) +#if !defined(CURL_DISABLE_CERTINFO) && \ + (defined(USE_MBEDTLS) || defined(USE_RUSTLS)) #include "cipher_suite.h" #include "../curl_printf.h" #include diff --git a/lib/vtls/cipher_suite.h b/lib/vtls/cipher_suite.h index a1dcbc524f..34dd2daada 100644 --- a/lib/vtls/cipher_suite.h +++ b/lib/vtls/cipher_suite.h @@ -26,7 +26,8 @@ #include "../curl_setup.h" -#if defined(USE_MBEDTLS) || defined(USE_RUSTLS) +#if !defined(CURL_DISABLE_CERTINFO) && \ + (defined(USE_MBEDTLS) || defined(USE_RUSTLS)) #include /* Lookup IANA id for cipher suite string, returns 0 if not recognized */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 3280d9057c..fe546e93db 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -33,15 +33,8 @@ #ifdef USE_MBEDTLS -/* Define this to enable lots of debugging for mbedTLS */ -/* #define MBEDTLS_DEBUG */ - #include -#if MBEDTLS_VERSION_NUMBER >= 0x02040000 #include -#else -#include -#endif #include #include @@ -50,11 +43,13 @@ #include #include -#if MBEDTLS_VERSION_MAJOR >= 2 -# ifdef MBEDTLS_DEBUG -# include -# endif -#endif /* MBEDTLS_VERSION_MAJOR >= 2 */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3) +#include +#endif + +#ifdef MBEDTLS_DEBUG_C +# include +#endif #include "cipher_suite.h" #include "../urldata.h" @@ -69,7 +64,6 @@ #include "../connect.h" /* for the connect timeout */ #include "../select.h" #include "../multiif.h" -#include "mbedtls_threadlock.h" #include "../strdup.h" /* The last 3 #include files should be in this order */ @@ -103,10 +97,20 @@ struct mbed_ssl_backend_data { BIT(send_blocked); }; -/* apply threading? */ -#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || defined(_WIN32) -#define HAS_THREADING_SUPPORT +/** A context for random number generation (RNG). + */ +struct rng_context_t { + mbedtls_entropy_context entropy; +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_context drbg; +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_context drbg; +#else +#error "No DRBG available" #endif +}; + +static struct rng_context_t rng; #ifndef MBEDTLS_ERROR_C #define mbedtls_strerror(a,b,c) b[0] = 0 @@ -125,47 +129,7 @@ struct mbed_ssl_backend_data { #define HAS_SESSION_TICKETS #endif -#ifdef HAS_THREADING_SUPPORT -static mbedtls_entropy_context ts_entropy; - -static int entropy_init_initialized = 0; - -static void entropy_init_mutex(mbedtls_entropy_context *ctx) -{ - /* lock 0 = entropy_init_mutex() */ - Curl_mbedtlsthreadlock_lock_function(0); - if(entropy_init_initialized == 0) { - mbedtls_entropy_init(ctx); - entropy_init_initialized = 1; - } - Curl_mbedtlsthreadlock_unlock_function(0); -} - -static void entropy_cleanup_mutex(mbedtls_entropy_context *ctx) -{ - /* lock 0 = use same lock as init */ - Curl_mbedtlsthreadlock_lock_function(0); - if(entropy_init_initialized == 1) { - mbedtls_entropy_free(ctx); - entropy_init_initialized = 0; - } - Curl_mbedtlsthreadlock_unlock_function(0); -} - -static int entropy_func_mutex(void *data, unsigned char *output, size_t len) -{ - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_mbedtlsthreadlock_lock_function(1); - ret = mbedtls_entropy_func(data, output, len); - Curl_mbedtlsthreadlock_unlock_function(1); - - return ret; -} - -#endif /* HAS_THREADING_SUPPORT */ - -#ifdef MBEDTLS_DEBUG +#ifdef MBEDTLS_DEBUG_C static void mbed_debug(void *context, int level, const char *f_name, int line_nb, const char *line) { @@ -215,6 +179,7 @@ static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) DEBUGASSERT(data); if(!data) return 0; + /* OpenSSL catches this case, so should we. */ if(!buf) return 0; @@ -227,22 +192,6 @@ static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) return result ? -1 : (int)nread; } -/* - * profile - */ -static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = -{ - /* Hashes from SHA-1 and above */ - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), - 0xFFFFFFF, /* Any PK alg */ - 0xFFFFFFF, /* Any curve */ - 1024, /* RSA min key len */ -}; /* See https://web.archive.org/web/20200921194007/tls.mbed.org/discussions/ generic/howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der @@ -261,14 +210,20 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, /* TLS 1.0 and TLS 1.1 were dropped with mbedTLS 3.0.0 (2021). So, since * then, and before the introduction of TLS 1.3 in 3.6.0 (2024), this * function basically always sets TLS 1.2 as min/max, unless given - * unsupported option values. */ + * unsupported option values, of if TLS 1.2 support is not compiled. */ #if MBEDTLS_VERSION_NUMBER < 0x03020000 int ver_min = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ int ver_max = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ #else /* mbedTLS 3.2.0 (2022) introduced new methods for setting TLS version */ - mbedtls_ssl_protocol_version ver_min = MBEDTLS_SSL_VERSION_TLS1_2; + mbedtls_ssl_protocol_version ver_min = +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + MBEDTLS_SSL_VERSION_TLS1_2 +#else + MBEDTLS_SSL_VERSION_TLS1_3 +#endif + ; mbedtls_ssl_protocol_version ver_max = #ifdef HAS_TLS13_SUPPORT MBEDTLS_SSL_VERSION_TLS1_3 @@ -280,26 +235,18 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, switch(conn_config->version) { case CURL_SSLVERSION_DEFAULT: -#if MBEDTLS_VERSION_NUMBER < 0x03000000 - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - ver_min = MBEDTLS_SSL_MINOR_VERSION_1; - break; - case CURL_SSLVERSION_TLSv1_1: - ver_min = MBEDTLS_SSL_MINOR_VERSION_2; - break; -#else case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: -#endif case CURL_SSLVERSION_TLSv1_2: +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if MBEDTLS_VERSION_NUMBER < 0x03020000 ver_min = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ #else ver_min = MBEDTLS_SSL_VERSION_TLS1_2; #endif break; +#endif case CURL_SSLVERSION_TLSv1_3: #ifdef HAS_TLS13_SUPPORT ver_min = MBEDTLS_SSL_VERSION_TLS1_3; @@ -320,23 +267,16 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, break; #endif case CURL_SSLVERSION_MAX_TLSv1_2: +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if MBEDTLS_VERSION_NUMBER < 0x03020000 ver_max = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ #else ver_max = MBEDTLS_SSL_VERSION_TLS1_2; #endif break; -#if MBEDTLS_VERSION_NUMBER < 0x03000000 - case CURL_SSLVERSION_MAX_TLSv1_1: - ver_max = MBEDTLS_SSL_MINOR_VERSION_2; - break; - case CURL_SSLVERSION_MAX_TLSv1_0: - ver_max = MBEDTLS_SSL_MINOR_VERSION_1; - break; -#else - case CURL_SSLVERSION_MAX_TLSv1_1: - case CURL_SSLVERSION_MAX_TLSv1_0: #endif + case CURL_SSLVERSION_MAX_TLSv1_1: + case CURL_SSLVERSION_MAX_TLSv1_0: default: failf(data, "mbedTLS: unsupported maximum TLS version value"); return CURLE_SSL_CONNECT_ERROR; @@ -355,6 +295,8 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, return CURLE_OK; } + +#ifndef CURL_DISABLE_CIPHER_SELECT /* TLS_ECJPAKE_WITH_AES_128_CCM_8 (0xC0FF) is marked experimental in mbedTLS. The number is not reserved by IANA nor is the cipher suite present in other SSL implementations. Provide @@ -495,12 +437,14 @@ add_ciphers: mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites); return CURLE_OK; } +#endif +#ifndef CURL_DISABLE_CERTINFO static void mbed_dump_cert_info(struct Curl_easy *data, const mbedtls_x509_crt *crt) { #if defined(CURL_DISABLE_VERBOSE_STRINGS) || \ - (MBEDTLS_VERSION_NUMBER >= 0x03000000 && defined(MBEDTLS_X509_REMOVE_INFO)) + (defined(MBEDTLS_X509_REMOVE_INFO)) (void)data, (void)crt; #else const size_t bufsize = 16384; @@ -558,7 +502,7 @@ static int mbed_verify_cb(void *ptr, mbedtls_x509_crt *crt, *flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; if(*flags) { -#if MBEDTLS_VERSION_NUMBER < 0x03000000 || !defined(MBEDTLS_X509_REMOVE_INFO) +#if !defined(MBEDTLS_X509_REMOVE_INFO) char buf[128]; mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags); failf(data, "mbedTLS: %s", buf); @@ -569,6 +513,7 @@ static int mbed_verify_cb(void *ptr, mbedtls_x509_crt *crt, return 0; } +#endif static CURLcode mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) @@ -586,6 +531,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) const char * const ssl_capath = conn_config->CApath; char * const ssl_cert = ssl_config->primary.clientcert; const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; +#ifdef MBEDTLS_PEM_PARSE_C + const char* const ssl_cert_type = ssl_config->cert_type; +#endif const char * const ssl_crlfile = ssl_config->primary.CRLfile; const char *hostname = connssl->peer.hostname; int ret = -1; @@ -600,45 +548,49 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_NOT_BUILT_IN; } -#ifdef HAS_THREADING_SUPPORT - mbedtls_ctr_drbg_init(&backend->ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, - &ts_entropy, NULL, 0); - if(ret) { - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s", - -ret, errorbuf); - return CURLE_FAILED_INIT; - } -#else - mbedtls_entropy_init(&backend->entropy); - mbedtls_ctr_drbg_init(&backend->ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, - &backend->entropy, NULL, 0); - if(ret) { - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s", - -ret, errorbuf); - return CURLE_FAILED_INIT; - } -#endif /* HAS_THREADING_SUPPORT */ - /* Load the trusted CA */ mbedtls_x509_crt_init(&backend->cacert); - if(ca_info_blob && verifypeer) { - /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null - terminated even when provided the exact length, forcing us to waste - extra memory here. */ - unsigned char *newblob = Curl_memdup0(ca_info_blob->data, - ca_info_blob->len); - if(!newblob) - return CURLE_OUT_OF_MEMORY; - ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, - ca_info_blob->len + 1); - free(newblob); + if(ca_info_blob && verifypeer) + { +#ifdef MBEDTLS_PEM_PARSE_C + /* if DER or a null-terminated PEM just process using + * mbedtls_x509_crt_parse(). + * */ + if(strcmp(ssl_cert_type, "DER") == 0 + || ((char*)(ca_info_blob->data))[ca_info_blob->len - 1] == '\0' + ) + { + ret = mbedtls_x509_crt_parse(&backend->cacert, + ca_info_blob->data, + ca_info_blob->len); + } + else /* they say it's PEM and it's not null-terminated */ + { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to + be null-terminated if the data is PEM encoded (even when + provided the exact length). The function accepts PEM or DER + formats, but we can't assume if the user passed in a PEM + format cert that it's null-terminated. */ + unsigned char *newblob = Curl_memdup0(ca_info_blob->data, + ca_info_blob->len); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + + ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, + ca_info_blob->len + 1); + free(newblob); + } +#else + /* DER encoded certs don't need to be null terminated + because it's a binary format. So if we're not compiling + with PEM_PARSE we can avoid the extra memory copies + altogether. */ + ret = mbedtls_x509_crt_parse_der(&backend->cacert, + ca_info_blob->data, + ca_info_blob->len); +#endif + if(ret < 0) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s", @@ -702,20 +654,46 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } if(ssl_cert_blob) { - /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null - terminated even when provided the exact length, forcing us to waste - extra memory here. */ - unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data, - ssl_cert_blob->len); - if(!newblob) - return CURLE_OUT_OF_MEMORY; - ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, - ssl_cert_blob->len + 1); - free(newblob); +#ifdef MBEDTLS_PEM_PARSE_C + /* if DER or a null-terminated PEM just process using + * mbedtls_x509_crt_parse(). + * */ + if(strcmp(ssl_cert_type, "DER") == 0 + || ((char*)(ssl_cert_blob->data))[ssl_cert_blob->len - 1] == '\0' + ) + { + ret = mbedtls_x509_crt_parse(&backend->clicert, + ssl_cert_blob->data, + ssl_cert_blob->len); + } + else /* they say it's PEM and it's not null-terminated */ + { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to + be null-terminated if the data is PEM encoded (even when + provided the exact length). The function accepts PEM or DER + formats, but we can't assume if the user passed in a PEM + format cert that it's null-terminated. */ + unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data, + ssl_cert_blob->len); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, + ssl_cert_blob->len + 1); + free(newblob); + } +#else + /* DER encoded certs don't need to be null terminated + because it's a binary format. So if we're not compiling + with PEM_PARSE we can avoid the extra memory copies + altogether. */ + ret = mbedtls_x509_crt_parse_der(&backend->clicert, + ssl_cert_blob->data, + ssl_cert_blob->len); +#endif if(ret) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading client cert data %s - mbedTLS: (-0x%04X) %s", + failf(data, "Error reading SSL cert blob %s - mbedTLS: (-0x%04X) %s", ssl_config->key, -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } @@ -727,15 +705,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(ssl_config->key || ssl_config->key_blob) { if(ssl_config->key) { #ifdef MBEDTLS_FS_IO -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, ssl_config->key_passwd, mbedtls_ctr_drbg_random, &backend->ctr_drbg); -#else - ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, - ssl_config->key_passwd); -#endif + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; @@ -756,17 +730,13 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) const unsigned char *key_data = (const unsigned char *)ssl_key_blob->data; const char *passwd = ssl_config->key_passwd; -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, (const unsigned char *)passwd, passwd ? strlen(passwd) : 0, mbedtls_ctr_drbg_random, &backend->ctr_drbg); -#else - ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, - (const unsigned char *)passwd, - passwd ? strlen(passwd) : 0); -#endif + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; @@ -819,6 +789,19 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CONNECT_ERROR; } +#ifdef MBEDTLS_DEBUG_C + /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ + mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); + /* - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ + mbedtls_debug_set_threshold(4); +#endif + + #if defined(HAS_SESSION_TICKETS) && MBEDTLS_VERSION_NUMBER >= 0x03060100 /* New in mbedTLS 3.6.1, need to enable, default is now disabled */ mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(&backend->config, @@ -828,22 +811,25 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Always let mbedTLS verify certificates, if verifypeer or verifyhost are * disabled we clear the corresponding error flags in the verify callback * function. That is also where we log verification errors. */ + +#ifndef CURL_DISABLE_CERTINFO mbedtls_ssl_conf_verify(&backend->config, mbed_verify_cb, cf); +#endif mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_init(&backend->ssl); backend->initialized = TRUE; - /* new profile with RSA min key len = 1024 ... */ + /* use the default secure profile baked into mbedTLS */ mbedtls_ssl_conf_cert_profile(&backend->config, - &mbedtls_x509_crt_profile_fr); + &mbedtls_x509_crt_profile_next); ret = mbed_set_ssl_version_min_max(data, backend, conn_config); if(ret != CURLE_OK) return ret; mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, - &backend->ctr_drbg); + &rng.drbg); ret = mbedtls_ssl_setup(&backend->ssl, &backend->config); if(ret) { @@ -858,6 +844,13 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_bio_cf_read, NULL /* rev_timeout() */); + + /* Allow the user to select TLS 1.2/1.3 ciphersuites. + If the user doesn't supply ciphersuites, the default + secure ciphersuites are used (thus no need to call + mbedtls_ssl_conf_ciphersuites() ). + */ +#ifndef CURL_DISABLE_CIPHER_SELECT #ifndef HAS_TLS13_SUPPORT if(conn_config->cipher_list) { CURLcode result = mbed_set_selected_ciphers(data, backend, @@ -878,7 +871,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_ssl_conf_ciphersuites(&backend->config, mbedtls_ssl_list_ciphersuites()); } - +#endif #ifdef MBEDTLS_SSL_RENEGOTIATION mbedtls_ssl_conf_renegotiation(&backend->config, @@ -960,18 +953,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } #endif -#ifdef MBEDTLS_DEBUG - /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ - mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); - /* - 0 No debug - * - 1 Error - * - 2 State change - * - 3 Informational - * - 4 Verbose - */ - mbedtls_debug_set_threshold(4); -#endif - /* give application a chance to interfere with mbedTLS set up. */ if(data->set.ssl.fsslctx) { CURLcode result = (*data->set.ssl.fsslctx)(data, &backend->config, @@ -994,12 +975,14 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) struct ssl_connect_data *connssl = cf->ctx; struct mbed_ssl_backend_data *backend = (struct mbed_ssl_backend_data *)connssl->backend; +#ifdef MBEDTLS_PK_WRITE_C #ifndef CURL_DISABLE_PROXY const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY]; #else const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; +#endif #endif DEBUGASSERT(backend); @@ -1030,7 +1013,9 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CONNECT_ERROR; } -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 + +#if (MBEDTLS_VERSION_NUMBER >= 0x03020000) && \ + !defined(CURL_DISABLE_VERBOSE_STRINGS) && !defined(CURL_DISABLE_CIPHER_SELECT) { char cipher_str[64]; uint16_t cipher_id; @@ -1045,6 +1030,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_ssl_get_version(&backend->ssl)); #endif +#ifdef MBEDTLS_PK_WRITE_C if(pinnedpubkey) { int size; CURLcode result; @@ -1053,12 +1039,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) unsigned char *pubkey = NULL; peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || - !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { -#else if(!peercert || !peercert->raw.p || !peercert->raw.len) { -#endif failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } @@ -1080,24 +1061,13 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/Mbed-TLS/mbedtls/issues/396 */ -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - if(mbedtls_x509_crt_parse_der(p, - peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), - peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { -#else if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { -#endif failf(data, "Failed copying peer certificate"); result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; goto pinnedpubkey_error; } -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, - PUB_DER_MAX_BYTES); -#else size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); -#endif if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); @@ -1117,6 +1087,7 @@ pinnedpubkey_error: return result; } } +#endif #ifdef HAS_ALPN_MBEDTLS if(connssl->alpn) { @@ -1359,9 +1330,6 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_ssl_config_free(&backend->config); mbedtls_ssl_free(&backend->ssl); mbedtls_ctr_drbg_free(&backend->ctr_drbg); -#ifndef HAS_THREADING_SUPPORT - mbedtls_entropy_free(&backend->entropy); -#endif /* HAS_THREADING_SUPPORT */ backend->initialized = FALSE; } } @@ -1427,29 +1395,24 @@ static CURLcode mbedtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { #ifdef MBEDTLS_CTR_DRBG_C - int ret; - mbedtls_entropy_context ctr_entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_init(&ctr_entropy); - mbedtls_ctr_drbg_init(&ctr_drbg); - (void)data; + int ret = -1; + char errorbuf[128]; - ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, - &ctr_entropy, NULL, 0); +#if defined(MBEDTLS_CTR_DRBG_C) + ret = mbedtls_ctr_drbg_random(&rng.drbg, entropy, length); +#elif defined(MBEDTLS_HMAC_DRBG_C) + ret = mbedtls_hmac_drbg_random(&rng.drbg, entropy, length); +#else +#error "No DRBG available" +#endif - if(!ret) - ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); - - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&ctr_entropy); + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s", + -ret, errorbuf); + } return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; -#elif defined(MBEDTLS_HAVEGE_C) - mbedtls_havege_state hs; - mbedtls_havege_init(&hs); - mbedtls_havege_random(&hs, entropy, length); - mbedtls_havege_free(&hs); - return CURLE_OK; #else return CURLE_NOT_BUILT_IN; #endif @@ -1516,34 +1479,78 @@ static CURLcode mbedtls_connect(struct Curl_cfilter *cf, */ static int mbedtls_init(void) { - if(!Curl_mbedtlsthreadlock_thread_setup()) +#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3) + psa_status_t status = psa_crypto_init(); + if (status != PSA_SUCCESS) return 0; -#ifdef HAS_THREADING_SUPPORT - entropy_init_mutex(&ts_entropy); +#endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */ + + + /* initialize the RNG context & entropy */ +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_init(&rng.drbg); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_init(&rng.drbg); +#else +#error "No DRBG available" #endif -#ifdef HAS_PSA_SUPPORT - { - int ret; -#ifdef HAS_THREADING_SUPPORT - Curl_mbedtlsthreadlock_lock_function(0); + + mbedtls_entropy_init(&rng.entropy); + + +#if defined(MBEDTLS_CTR_DRBG_C) + int ret = mbedtls_ctr_drbg_seed(&rng.drbg, + mbedtls_entropy_func, &rng.entropy, + NULL, 0); +#elif defined(MBEDTLS_HMAC_DRBG_C) +#if defined(MBEDTLS_SHA256_C) + const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; +#elif defined(MBEDTLS_SHA512_C) + const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA512; +#else +#error "No message digest available for HMAC_DRBG" #endif - ret = psa_crypto_init(); -#ifdef HAS_THREADING_SUPPORT - Curl_mbedtlsthreadlock_unlock_function(0); -#endif - if(ret != PSA_SUCCESS) - return 0; + int ret = mbedtls_hmac_drbg_seed(&rng.drbg, + mbedtls_md_info_from_type(md_type), + mbedtls_entropy_func, &rng.entropy, + NULL, 0); +#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */ +#error "No DRBG available" +#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */ + + if(ret != 0) { + //TODO: write an error without a `data` param + //failf(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", + // (unsigned int)-ret); + return 0; } -#endif /* HAS_PSA_SUPPORT */ + + /* To prevent an adversary from reading your random data, + you can enable prediction resistance. + + Entropy is gathered before each mbedtls_ctr_drbg_random() call. + Only use this if you have ample supply of good entropy.*/ + mbedtls_ctr_drbg_set_prediction_resistance(&rng.drbg, + MBEDTLS_CTR_DRBG_PR_ON); + return 1; } static void mbedtls_cleanup(void) { -#ifdef HAS_THREADING_SUPPORT - entropy_cleanup_mutex(&ts_entropy); +#if (defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)) + mbedtls_psa_crypto_free(); #endif - (void)Curl_mbedtlsthreadlock_thread_cleanup(); + +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_free(&rng.drbg); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_free(&rng.drbg); +#else +#error "No DRBG available" +#endif + + mbedtls_entropy_free(&rng.entropy); } static bool mbedtls_data_pending(struct Curl_cfilter *cf, @@ -1564,17 +1571,9 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input, size_t sha256len UNUSED_PARAM) { (void)sha256len; -#if MBEDTLS_VERSION_NUMBER < 0x02070000 - mbedtls_sha256(input, inputlen, sha256sum, 0); -#else /* returns 0 on success, otherwise failure */ -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) -#else - if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) -#endif return CURLE_BAD_FUNCTION_ARGUMENT; -#endif return CURLE_OK; } @@ -1593,14 +1592,21 @@ const struct Curl_ssl Curl_ssl_mbedtls = { SSLSUPP_CA_PATH | SSLSUPP_CAINFO_BLOB | +#ifndef CURL_DISABLE_CERTINFO SSLSUPP_CERTINFO | +#endif +#ifdef MBEDTLS_PK_WRITE_C SSLSUPP_PINNEDPUBKEY | +#endif SSLSUPP_SSL_CTX | -#ifdef HAS_TLS13_SUPPORT +#if defined(HAS_TLS13_SUPPORT) && !defined(CURL_DISABLE_CIPHER_SELECT) SSLSUPP_TLS13_CIPHERSUITES | #endif - SSLSUPP_HTTPS_PROXY | - SSLSUPP_CIPHER_LIST, + SSLSUPP_HTTPS_PROXY +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(CURL_DISABLE_CIPHER_SELECT) + | SSLSUPP_CIPHER_LIST +#endif + , sizeof(struct mbed_ssl_backend_data), diff --git a/lib/vtls/mbedtls_threadlock.c b/lib/vtls/mbedtls_threadlock.c deleted file mode 100644 index 682c221852..0000000000 --- a/lib/vtls/mbedtls_threadlock.c +++ /dev/null @@ -1,134 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * Copyright (C) Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ -#include "../curl_setup.h" - -#if defined(USE_MBEDTLS) && \ - ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ - defined(_WIN32)) - -#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) -# include -# define MBEDTLS_MUTEX_T pthread_mutex_t -#elif defined(_WIN32) -# define MBEDTLS_MUTEX_T HANDLE -#endif - -#include "mbedtls_threadlock.h" -#include "../curl_printf.h" -#include "../curl_memory.h" -/* The last #include file should be: */ -#include "../memdebug.h" - -/* number of thread locks */ -#define NUMT 2 - -/* This array will store all of the mutexes available to Mbedtls. */ -static MBEDTLS_MUTEX_T *mutex_buf = NULL; - -int Curl_mbedtlsthreadlock_thread_setup(void) -{ - int i; - - mutex_buf = calloc(1, NUMT * sizeof(MBEDTLS_MUTEX_T)); - if(!mutex_buf) - return 0; /* error, no number of threads defined */ - - for(i = 0; i < NUMT; i++) { -#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - if(pthread_mutex_init(&mutex_buf[i], NULL)) - return 0; /* pthread_mutex_init failed */ -#elif defined(_WIN32) - mutex_buf[i] = CreateMutex(0, FALSE, 0); - if(mutex_buf[i] == 0) - return 0; /* CreateMutex failed */ -#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ - } - - return 1; /* OK */ -} - -int Curl_mbedtlsthreadlock_thread_cleanup(void) -{ - int i; - - if(!mutex_buf) - return 0; /* error, no threads locks defined */ - - for(i = 0; i < NUMT; i++) { -#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - if(pthread_mutex_destroy(&mutex_buf[i])) - return 0; /* pthread_mutex_destroy failed */ -#elif defined(_WIN32) - if(!CloseHandle(mutex_buf[i])) - return 0; /* CloseHandle failed */ -#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ - } - free(mutex_buf); - mutex_buf = NULL; - - return 1; /* OK */ -} - -int Curl_mbedtlsthreadlock_lock_function(int n) -{ - if(n < NUMT) { -#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - if(pthread_mutex_lock(&mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_lock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } -#elif defined(_WIN32) - if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_lock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } -#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ - } - return 1; /* OK */ -} - -int Curl_mbedtlsthreadlock_unlock_function(int n) -{ - if(n < NUMT) { -#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - if(pthread_mutex_unlock(&mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_unlock_function failed\n")); - return 0; /* pthread_mutex_unlock failed */ - } -#elif defined(_WIN32) - if(!ReleaseMutex(mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_unlock_function failed\n")); - return 0; /* pthread_mutex_lock failed */ - } -#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ - } - return 1; /* OK */ -} - -#endif /* USE_MBEDTLS */ diff --git a/lib/vtls/mbedtls_threadlock.h b/lib/vtls/mbedtls_threadlock.h deleted file mode 100644 index 9402af6e41..0000000000 --- a/lib/vtls/mbedtls_threadlock.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef HEADER_CURL_MBEDTLS_THREADLOCK_H -#define HEADER_CURL_MBEDTLS_THREADLOCK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * Copyright (C) Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ -#include "../curl_setup.h" - -#ifdef USE_MBEDTLS - -#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ - defined(_WIN32) - -int Curl_mbedtlsthreadlock_thread_setup(void); -int Curl_mbedtlsthreadlock_thread_cleanup(void); -int Curl_mbedtlsthreadlock_lock_function(int n); -int Curl_mbedtlsthreadlock_unlock_function(int n); - -#else - -#define Curl_mbedtlsthreadlock_thread_setup() 1 -#define Curl_mbedtlsthreadlock_thread_cleanup() 1 -#define Curl_mbedtlsthreadlock_lock_function(x) 1 -#define Curl_mbedtlsthreadlock_unlock_function(x) 1 - -#endif /* (USE_THREADS_POSIX && HAVE_PTHREAD_H) || _WIN32 */ - -#endif /* USE_MBEDTLS */ - -#endif /* HEADER_CURL_MBEDTLS_THREADLOCK_H */