diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md index e39159696b..cab2d61155 100644 --- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -77,7 +77,6 @@ TLS v1.3 or later (Added in 7.52.0) The maximum TLS version can be set by using *one* of the CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. -The MAX macros are not supported for wolfSSL. ## CURL_SSLVERSION_MAX_DEFAULT @@ -138,13 +137,17 @@ int main(void) # HISTORY -SSLv2 and SSLv3 are refused completely since curl 7.77.0 - SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may vary depending on which backend libcurl has been built to use. SSLv3 is disabled by default since 7.39.0. +SSLv2 and SSLv3 are refused completely since curl 7.77.0 + +Since 8.10.0 wolfSSL is fully supported. Before 8.10.0 the MAX macros were not +supported with wolfSSL and the other macros did not set a minimum, but +restricted the TLS version to only the specified one. + # %AVAILABILITY% # RETURN VALUE diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 8334d1e5cc..95476ffbff 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -36,6 +36,10 @@ #include #include +#if LIBWOLFSSL_VERSION_HEX < 0x03004006 /* wolfSSL 3.4.6 (2015) */ +#error "wolfSSL version should be at least 3.4.6" +#endif + /* To determine what functions are available we rely on one or both of: - the user's options.h generated by wolfSSL - the symbols detected by curl's configure @@ -656,6 +660,45 @@ wssl_get_default_ciphers(bool tls13, char *buf, size_t size) } #endif +#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */ +static int +wssl_legacy_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) +{ + int res; + switch(version) { + default: + case TLS1_VERSION: + res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1); + if(res == WOLFSSL_SUCCESS) + return res; + FALLTHROUGH(); + case TLS1_1_VERSION: + res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_1); + if(res == WOLFSSL_SUCCESS) + return res; + FALLTHROUGH(); + case TLS1_2_VERSION: + res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_2); +#ifdef WOLFSSL_TLS13 + if(res == WOLFSSL_SUCCESS) + return res; + FALLTHROUGH(); + case TLS1_3_VERSION: + res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3); +#endif + } + return res; +} +static int +wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) +{ + (void) ctx, (void) version; + return WOLFSSL_NOT_IMPLEMENTED; +} +#define wolfSSL_CTX_set_min_proto_version wssl_legacy_CTX_set_min_proto_version +#define wolfSSL_CTX_set_max_proto_version wssl_legacy_CTX_set_max_proto_version +#endif + /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. @@ -663,6 +706,7 @@ wssl_get_default_ciphers(bool tls13, char *buf, size_t size) static CURLcode wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { + int res; char *ciphers, *curves; struct ssl_connect_data *connssl = cf->ctx; struct wolfssl_ctx *backend = @@ -673,12 +717,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #ifdef WOLFSSL_HAVE_KYBER word16 pqkem = 0; size_t idx = 0; -#endif -#ifdef HAVE_SNI - bool sni = FALSE; -#define use_sni(x) sni = (x) -#else -#define use_sni(x) Curl_nop_stmt #endif DEBUGASSERT(backend); @@ -686,104 +724,76 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(connssl->state == ssl_connection_complete) return CURLE_OK; - if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) { - failf(data, "wolfSSL does not support to set maximum SSL/TLS version"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* check to see if we have been told to use an explicit SSL/TLS version */ - switch(conn_config->version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: -#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ - /* minimum protocol version is set later after the CTX object is created */ - req_method = SSLv23_client_method(); +#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */ + req_method = wolfSSLv23_client_method(); #else - infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " - "TLS 1.0 is used exclusively"); - req_method = TLSv1_client_method(); + req_method = wolfTLS_client_method(); #endif - use_sni(TRUE); - break; - case CURL_SSLVERSION_TLSv1_0: -#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS) - req_method = TLSv1_client_method(); - use_sni(TRUE); - break; -#else - failf(data, "wolfSSL does not support TLS 1.0"); - return CURLE_NOT_BUILT_IN; -#endif - case CURL_SSLVERSION_TLSv1_1: -#ifndef NO_OLD_TLS - req_method = TLSv1_1_client_method(); - use_sni(TRUE); - break; -#else - failf(data, "wolfSSL does not support TLS 1.1"); - return CURLE_NOT_BUILT_IN; -#endif - case CURL_SSLVERSION_TLSv1_2: -#ifndef WOLFSSL_NO_TLS12 - req_method = TLSv1_2_client_method(); - use_sni(TRUE); -#else - failf(data, "wolfSSL does not support TLS 1.2"); - return CURLE_NOT_BUILT_IN; -#endif - break; - case CURL_SSLVERSION_TLSv1_3: -#ifdef WOLFSSL_TLS13 - req_method = wolfTLSv1_3_client_method(); - use_sni(TRUE); - break; -#else - failf(data, "wolfSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; -#endif - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - if(!req_method) { - failf(data, "SSL: could not create a method"); + failf(data, "wolfSSL: could not create a client method"); return CURLE_OUT_OF_MEMORY; } if(backend->ctx) wolfSSL_CTX_free(backend->ctx); - backend->ctx = wolfSSL_CTX_new(req_method); + backend->ctx = wolfSSL_CTX_new(req_method); if(!backend->ctx) { - failf(data, "SSL: could not create a context"); + failf(data, "wolfSSL: could not create a context"); return CURLE_OUT_OF_MEMORY; } switch(conn_config->version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: -#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ - /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is - * whatever minimum version of TLS was built in and at least TLS 1.0. For - * later library versions that could change (eg TLS 1.0 built in but - * defaults to TLS 1.1) so we have this short circuit evaluation to find - * the minimum supported TLS version. - */ - if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) && - (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) && - (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1) -#ifdef WOLFSSL_TLS13 - && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1) -#endif - ) { - failf(data, "SSL: could not set the minimum protocol version"); - return CURLE_SSL_CONNECT_ERROR; - } -#endif - FALLTHROUGH(); - default: + res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_VERSION); break; + case CURL_SSLVERSION_TLSv1_1: + res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_1_VERSION); + break; + case CURL_SSLVERSION_TLSv1_2: + res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_2_VERSION); + break; +#ifdef WOLFSSL_TLS13 + case CURL_SSLVERSION_TLSv1_3: + res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_3_VERSION); + break; +#endif + default: + failf(data, "wolfSSL: unrecognized minimum TLS version value"); + return CURLE_SSL_CONNECT_ERROR; + } + if(res != WOLFSSL_SUCCESS) { + failf(data, "wolfSSL: failed set the minimum TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + + switch(conn_config->version_max) { +#ifdef WOLFSSL_TLS13 + case CURL_SSLVERSION_MAX_TLSv1_3: + res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION); + break; +#endif + case CURL_SSLVERSION_MAX_TLSv1_2: + res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_2_VERSION); + break; + case CURL_SSLVERSION_MAX_TLSv1_1: + res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_1_VERSION); + break; + case CURL_SSLVERSION_MAX_TLSv1_0: + res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_VERSION); + break; + case CURL_SSLVERSION_MAX_DEFAULT: + case CURL_SSLVERSION_MAX_NONE: + res = WOLFSSL_SUCCESS; + break; + default: + failf(data, "wolfSSL: unrecognized maximum TLS version value"); + return CURLE_SSL_CONNECT_ERROR; + } + if(res != WOLFSSL_SUCCESS) { + failf(data, "wolfSSL: failed set the maximum TLS version"); + return CURLE_SSL_CONNECT_ERROR; } #ifndef WOLFSSL_TLS13 @@ -953,7 +963,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI - if(sni && connssl->peer.sni) { + if(connssl->peer.sni) { size_t sni_len = strlen(connssl->peer.sni); if((sni_len < USHRT_MAX)) { if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, @@ -1284,7 +1294,6 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) } #endif } -#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { if(conn_config->verifypeer) { failf(data, " CA signer not available for verification"); @@ -1297,7 +1306,6 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) "continuing anyway"); } } -#endif #ifdef USE_ECH else if(-1 == detail) { /* try access a retry_config ECHConfigList for tracing */ diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index bc6fc05d5d..2d122d5012 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -70,7 +70,6 @@ class TestSSLUse: if tls_max == '1.3': exp_resumed = 'Initial' # 1.2 works in LibreSSL, but 1.3 does not, TODO if env.curl_uses_lib('wolfssl'): - xargs = ['--sessionid', f'--tlsv{tls_max}'] if tls_max == '1.3': exp_resumed = 'Initial' # 1.2 works in wolfSSL, but 1.3 does not, TODO if env.curl_uses_lib('rustls-ffi'): @@ -221,10 +220,6 @@ class TestSSLUse: # test setting TLSv1.2 ciphers if env.curl_uses_lib('schannel'): pytest.skip('Schannel does not support setting TLSv1.2 ciphers by name') - elif env.curl_uses_lib('wolfssl'): - # setting tls version is botched with wolfssl: setting max (--tls-max) - # is not supported, setting min (--tlsv1.*) actually also sets max - extra_args = ['--tlsv1.2', '--ciphers', ':'.join(cipher_names)] else: # the server supports TLSv1.3, so to test TLSv1.2 ciphers we set tls-max extra_args = ['--tls-max', '1.2', '--ciphers', ':'.join(cipher_names)]