diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md index 4a04f52a2e..63440b5576 100644 --- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -42,7 +42,7 @@ Use one of the available defines for this purpose. The available options are: ## CURL_SSLVERSION_DEFAULT The default acceptable version range. The minimum acceptable version is by -default TLS v1.0 since 7.39.0 (unless the TLS library has a stricter rule). +default TLS v1.2 since 8.16.0 (unless the TLS library has a stricter rule). ## CURL_SSLVERSION_TLSv1 diff --git a/lib/setopt.c b/lib/setopt.c index 1380c33db6..1be45dc05b 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -327,8 +327,8 @@ static CURLcode setopt_HTTP_VERSION(struct Curl_easy *data, long arg) #endif /* ! CURL_DISABLE_HTTP */ #ifdef USE_SSL -static CURLcode setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, - long arg) +CURLcode Curl_setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, + long arg) { /* * Set explicit SSL version to try to connect with, as some SSL @@ -353,6 +353,8 @@ static CURLcode setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, version_max < CURL_SSLVERSION_MAX_NONE || version_max >= CURL_SSLVERSION_MAX_LAST) return CURLE_BAD_FUNCTION_ARGUMENT; + if(version == CURL_SSLVERSION_DEFAULT) + version = CURL_SSLVERSION_TLSv1_2; primary->version = (unsigned char)version; primary->version_max = (unsigned int)version_max; @@ -624,11 +626,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLVERSION: #endif -#ifdef USE_SSL - return setopt_SSLVERSION(data, option, arg); -#else - return CURLE_NOT_BUILT_IN; -#endif + return Curl_setopt_SSLVERSION(data, option, arg); case CURLOPT_POSTFIELDSIZE: /* diff --git a/lib/setopt.h b/lib/setopt.h index b0237467bd..c323dd74a3 100644 --- a/lib/setopt.h +++ b/lib/setopt.h @@ -24,6 +24,13 @@ * ***************************************************************************/ +#ifdef USE_SSL +CURLcode Curl_setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, + long arg); +#else +#define Curl_setopt_SSLVERSION(a,b,c) CURLE_NOT_BUILT_IN +#endif + CURLcode Curl_setstropt(char **charp, const char *s) WARN_UNUSED_RESULT; CURLcode Curl_setblobopt(struct curl_blob **blobp, const struct curl_blob *blob) WARN_UNUSED_RESULT; diff --git a/lib/url.c b/lib/url.c index 68b3706679..0e90af429b 100644 --- a/lib/url.c +++ b/lib/url.c @@ -458,6 +458,14 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) #endif } + /* set default minimum TLS version */ +#ifdef USE_SSL + Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); +#ifndef CURL_DISABLE_PROXY + Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION, + CURL_SSLVERSION_DEFAULT); +#endif +#endif #ifndef CURL_DISABLE_FTP set->wildcard_enabled = FALSE; set->chunk_bgn = ZERO_NULL; diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 9f5ab46659..405c8e7ff3 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -334,12 +334,13 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data, if((ssl_version == CURL_SSLVERSION_DEFAULT) || (ssl_version == CURL_SSLVERSION_TLSv1)) ssl_version = CURL_SSLVERSION_TLSv1_0; - if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) - ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; + if((ssl_version_max == CURL_SSLVERSION_MAX_NONE) || + (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) + ssl_version_max = tls13support ? + CURL_SSLVERSION_MAX_TLSv1_3 : CURL_SSLVERSION_MAX_TLSv1_2; if(peer->transport == TRNSPRT_QUIC) { - if((ssl_version_max != CURL_SSLVERSION_MAX_DEFAULT) && - (ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3)) { + if(ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3) { failf(data, "QUIC needs at least TLS version 1.3"); return CURLE_SSL_CONNECT_ERROR; } @@ -347,19 +348,6 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data, return CURLE_OK; } - if(!tls13support) { - /* If the running GnuTLS does not support TLS 1.3, we must not specify a - prioritylist involving that since it will make GnuTLS return an en - error back at us */ - if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) || - (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) { - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - } - } - else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) { - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; - } - switch(ssl_version | ssl_version_max) { case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" @@ -910,11 +898,6 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, #if defined(GNUTLS_NO_TICKETS_TLS12) init_flags |= GNUTLS_NO_TICKETS_TLS12; -#elif defined(GNUTLS_NO_TICKETS) - /* Disable TLS session tickets for non 1.3 connections */ - if((config->version != CURL_SSLVERSION_TLSv1_3) && - (config->version != CURL_SSLVERSION_DEFAULT)) - init_flags |= GNUTLS_NO_TICKETS; #endif #if defined(GNUTLS_NO_STATUS_REQUEST) @@ -1144,9 +1127,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, else { infof(data, "SSL reusing session with ALPN '%s'", scs->alpn ? scs->alpn : "-"); - if(ssl_config->earlydata && scs->alpn && - !cf->conn->connect_only && - (gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3)) { + if(ssl_config->earlydata && scs->alpn && !cf->conn->connect_only) { bool do_early_data = FALSE; if(sess_reuse_cb) { result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data); diff --git a/src/config2setopts.c b/src/config2setopts.c index 55e30ee761..10c7b9a703 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -229,6 +229,53 @@ extern const unsigned char curl_ca_embed[]; #endif #endif +static long tlsversion(unsigned char mintls, + unsigned char maxtls) +{ + long tlsver = 0; + if(!mintls) { /* minimum is at default */ + /* minimum is set to default, which we want to be 1.2 */ + if(maxtls && (maxtls < 3)) + /* max is set lower than 1.2 and minimum is default, change minimum to + the same as max */ + mintls = maxtls; + } + switch(mintls) { + case 1: + tlsver = CURL_SSLVERSION_TLSv1_0; + break; + case 2: + tlsver = CURL_SSLVERSION_TLSv1_1; + break; + case 0: /* let default minimum be 1.2 */ + case 3: + tlsver = CURL_SSLVERSION_TLSv1_2; + break; + case 4: + default: /* just in case */ + tlsver = CURL_SSLVERSION_TLSv1_3; + break; + } + switch(maxtls) { + case 0: /* not set, leave it */ + break; + case 1: + tlsver |= CURL_SSLVERSION_MAX_TLSv1_0; + break; + case 2: + tlsver |= CURL_SSLVERSION_MAX_TLSv1_1; + break; + case 3: + tlsver |= CURL_SSLVERSION_MAX_TLSv1_2; + break; + case 4: + default: /* just in case */ + tlsver |= CURL_SSLVERSION_MAX_TLSv1_3; + break; + } + return tlsver; +} + /* only called if libcurl supports TLS */ static CURLcode ssl_setopts(struct OperationConfig *config, CURL *curl) { @@ -360,7 +407,8 @@ static CURLcode ssl_setopts(struct OperationConfig *config, CURL *curl) my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1); my_setopt_SSLVERSION(curl, CURLOPT_SSLVERSION, - config->ssl_version | config->ssl_version_max); + tlsversion(config->ssl_version, + config->ssl_version_max)); if(config->proxy) my_setopt_SSLVERSION(curl, CURLOPT_PROXY_SSLVERSION, config->proxy_ssl_version); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 62ca06ad1e..bd32ab2d42 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -196,8 +196,6 @@ struct OperationConfig { curl_off_t sendpersecond; /* send to peer */ curl_off_t recvpersecond; /* receive from peer */ - long ssl_version; - long ssl_version_max; long proxy_ssl_version; long ip_version; long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ @@ -241,6 +239,8 @@ struct OperationConfig { } file_clobber_mode; unsigned char upload_flags; /* Bitmask for --upload-flags */ unsigned short porttouse; + unsigned char ssl_version; /* 0 - 4, 0 being default */ + unsigned char ssl_version_max; /* 0 - 4, 0 being default */ BIT(remote_name_all); /* --remote-name-all */ BIT(remote_time); BIT(cookiesession); /* new session? */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 4766dade2f..3a1cc57fdd 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1682,10 +1682,23 @@ static void opt_depr(struct GlobalConfig *global, warnf(global, "--%s is deprecated and has no function anymore", a->lname); } +static ParameterError opt_sslver(struct OperationConfig *config, + unsigned char ver) +{ + if(config->ssl_version_max && + (config->ssl_version_max < ver)) { + errorf(config->global, "Minimum TLS version set higher than max"); + return PARAM_BAD_USE; + } + config->ssl_version = ver; + return PARAM_OK; +} + /* opt_none is the function that handles ARG_NONE options */ static ParameterError opt_none(struct OperationConfig *config, const struct LongShort *a) { + ParameterError err = PARAM_OK; switch(a->cmd) { case C_ANYAUTH: /* --anyauth */ config->authtype = CURLAUTH_ANY; @@ -1731,19 +1744,19 @@ static ParameterError opt_none(struct OperationConfig *config, sethttpver(config, CURL_HTTP_VERSION_3ONLY); break; case C_TLSV1: /* --tlsv1 */ - config->ssl_version = CURL_SSLVERSION_TLSv1; + err = opt_sslver(config, 1); break; case C_TLSV1_0: /* --tlsv1.0 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_0; + err = opt_sslver(config, 1); break; case C_TLSV1_1: /* --tlsv1.1 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_1; + err = opt_sslver(config, 2); break; case C_TLSV1_2: /* --tlsv1.2 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_2; + err = opt_sslver(config, 3); break; case C_TLSV1_3: /* --tlsv1.3 */ - config->ssl_version = CURL_SSLVERSION_TLSv1_3; + err = opt_sslver(config, 4); break; case C_IPV4: /* --ipv4 */ config->ip_version = CURL_IPRESOLVE_V4; @@ -1758,7 +1771,7 @@ static ParameterError opt_none(struct OperationConfig *config, config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; break; } - return PARAM_OK; + return err; } /* opt_bool is the function that handles boolean options */ @@ -2423,6 +2436,10 @@ static ParameterError opt_filestring(struct OperationConfig *config, break; case C_TLS_MAX: /* --tls-max */ err = str2tls_max(&config->ssl_version_max, nextarg); + if(!err && (config->ssl_version_max < config->ssl_version)) { + errorf(global, "--tls-max set lower than minimum accepted version"); + err = PARAM_BAD_USE; + } break; case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */ err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c index 97a6b6e2ee..c037189610 100644 --- a/src/tool_paramhlp.c +++ b/src/tool_paramhlp.c @@ -739,17 +739,17 @@ CURLcode get_args(struct OperationConfig *config, const size_t i) * data. */ -ParameterError str2tls_max(long *val, const char *str) +ParameterError str2tls_max(unsigned char *val, const char *str) { - static struct s_tls_max { + static struct s_tls_max { const char *tls_max_str; - long tls_max; + unsigned char tls_max; } const tls_max_array[] = { - { "default", CURL_SSLVERSION_MAX_DEFAULT }, - { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 }, - { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 }, - { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 }, - { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 } + { "default", 0 }, /* lets the library decide */ + { "1.0", 1 }, + { "1.1", 2 }, + { "1.2", 3 }, + { "1.3", 4 } }; size_t i = 0; if(!str) diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h index 136214bb20..0be9c8968c 100644 --- a/src/tool_paramhlp.h +++ b/src/tool_paramhlp.h @@ -64,6 +64,6 @@ int ftpcccmethod(struct OperationConfig *config, const char *str); long delegation(struct OperationConfig *config, const char *str); -ParameterError str2tls_max(long *val, const char *str); +ParameterError str2tls_max(unsigned char *val, const char *str); #endif /* HEADER_CURL_TOOL_PARAMHLP_H */ diff --git a/src/tool_setopt.c b/src/tool_setopt.c index 9e4f6e59fc..52c8010466 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -101,7 +101,7 @@ const struct NameValue setopt_nv_CURL_SSLVERSION[] = { }; const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[] = { - NV(CURL_SSLVERSION_MAX_NONE), + {"", CURL_SSLVERSION_MAX_NONE}, NV(CURL_SSLVERSION_MAX_DEFAULT), NV(CURL_SSLVERSION_MAX_TLSv1_0), NV(CURL_SSLVERSION_MAX_TLSv1_1), @@ -293,9 +293,16 @@ CURLcode tool_setopt_SSLVERSION(CURL *curl, struct OperationConfig *config, name, lval); } else { - ret = easysrc_addf(&easysrc_code, - "curl_easy_setopt(hnd, %s, (long)(%s | %s));", - name, nv->name, nv2->name); + if(nv2->name && *nv2->name) + /* if max is set */ + ret = easysrc_addf(&easysrc_code, + "curl_easy_setopt(hnd, %s, (long)(%s | %s));", + name, nv->name, nv2->name); + else + /* without a max */ + ret = easysrc_addf(&easysrc_code, + "curl_easy_setopt(hnd, %s, (long)%s);", + name, nv->name); } } diff --git a/tests/data/test1400 b/tests/data/test1400 index ee7a4d4ed4..4a9e1e66a5 100644 --- a/tests/data/test1400 +++ b/tests/data/test1400 @@ -55,6 +55,7 @@ s/(USERAGENT, \")[^\"]+/${1}stripped/ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ +$_ = '' if /CURLOPT_SSLVERSION/ $_ = '' if /CURLOPT_HTTP09_ALLOWED/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ diff --git a/tests/data/test1401 b/tests/data/test1401 index 265d99e3eb..bb5a7a97ac 100644 --- a/tests/data/test1401 +++ b/tests/data/test1401 @@ -66,6 +66,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ /********* Sample code generated by the curl command line tool ********** diff --git a/tests/data/test1402 b/tests/data/test1402 index 0c084d2878..c973e7d8f8 100644 --- a/tests/data/test1402 +++ b/tests/data/test1402 @@ -60,6 +60,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ /********* Sample code generated by the curl command line tool ********** diff --git a/tests/data/test1403 b/tests/data/test1403 index 643f4424b8..a03da1d6d6 100644 --- a/tests/data/test1403 +++ b/tests/data/test1403 @@ -57,6 +57,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ /********* Sample code generated by the curl command line tool ********** diff --git a/tests/data/test1404 b/tests/data/test1404 index aa88eed496..f3b31be1e5 100644 --- a/tests/data/test1404 +++ b/tests/data/test1404 @@ -99,6 +99,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ # CURL_DOES_CONVERSION generates an extra comment. $_ = '' if /\/\* "value" \*\// diff --git a/tests/data/test1405 b/tests/data/test1405 index ff95450f5c..0b1be439b4 100644 --- a/tests/data/test1405 +++ b/tests/data/test1405 @@ -145,6 +145,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_HTTP09_ALLOWED/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ diff --git a/tests/data/test1406 b/tests/data/test1406 index 6f734aa8a7..a41276c45d 100644 --- a/tests/data/test1406 +++ b/tests/data/test1406 @@ -129,6 +129,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_HTTP09_ALLOWED/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ diff --git a/tests/data/test1407 b/tests/data/test1407 index 09d8702c28..94724a6fae 100644 --- a/tests/data/test1407 +++ b/tests/data/test1407 @@ -107,6 +107,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_HTTP09_ALLOWED/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ diff --git a/tests/data/test1420 b/tests/data/test1420 index f93db9d5c7..2cc7039062 100644 --- a/tests/data/test1420 +++ b/tests/data/test1420 @@ -111,6 +111,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ diff --git a/tests/data/test1465 b/tests/data/test1465 index 786d98c5a6..b521d2f31f 100644 --- a/tests/data/test1465 +++ b/tests/data/test1465 @@ -63,6 +63,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/ $_ = '' if /CURLOPT_HTTP_VERSION/ $_ = '' if /CURLOPT_INTERLEAVEDATA/ +$_ = '' if /CURLOPT_SSLVERSION/ /********* Sample code generated by the curl command line tool ********** diff --git a/tests/data/test1481 b/tests/data/test1481 index b6793a3bad..87aada2873 100644 --- a/tests/data/test1481 +++ b/tests/data/test1481 @@ -80,8 +80,8 @@ int main(int argc, char *argv[]) curl_easy_setopt(hnd, CURLOPT_PROXY, "http://%HOSTIP:%HTTPPORT"); curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); - curl_easy_setopt(hnd, CURLOPT_SSLVERSION, (long)(CURL_SSLVERSION_DEFAULT | CURL_SSLVERSION_MAX_TLSv1_3)); - curl_easy_setopt(hnd, CURLOPT_PROXY_SSLVERSION, (long)(CURL_SSLVERSION_TLSv1 | CURL_SSLVERSION_MAX_NONE)); + curl_easy_setopt(hnd, CURLOPT_SSLVERSION, (long)(CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3)); + curl_easy_setopt(hnd, CURLOPT_PROXY_SSLVERSION, (long)CURL_SSLVERSION_TLSv1); curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); /* Here is a list of options the curl code used that cannot get generated diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index 348a649e06..d3a3fcb5a5 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -36,6 +36,31 @@ from testenv import Env, CurlClient, LocalClient log = logging.getLogger(__name__) +class TLSDefs: + TLS_VERSIONS = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] + TLS_VERSION_IDS = { + 'TLSv1': 0x301, + 'TLSv1.1': 0x302, + 'TLSv1.2': 0x303, + 'TLSv1.3': 0x304 + } + CURL_ARG_MIN_VERSION_ID = { + 'none': 0x0, + 'tlsv1': 0x301, + 'tlsv1.0': 0x301, + 'tlsv1.1': 0x302, + 'tlsv1.2': 0x303, + 'tlsv1.3': 0x304, + } + CURL_ARG_MAX_VERSION_ID = { + 'none': 0x0, + '1.0': 0x301, + '1.1': 0x302, + '1.2': 0x303, + '1.3': 0x304, + } + + class TestSSLUse: @pytest.fixture(autouse=True, scope='class') @@ -270,18 +295,54 @@ class TestSSLUse: @staticmethod def gen_test_17_09_list(): - return [[tls_proto, max_ver, min_ver] - for tls_proto in ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - for max_ver in range(5) - for min_ver in range(-2, 4)] + return [ + [server_tls, min_arg, max_arg] + for server_tls in TLSDefs.TLS_VERSIONS + for min_arg in TLSDefs.CURL_ARG_MIN_VERSION_ID + for max_arg in TLSDefs.CURL_ARG_MAX_VERSION_ID + ] - @pytest.mark.parametrize("tls_proto, max_ver, min_ver", gen_test_17_09_list()) - def test_17_09_ssl_min_max(self, env: Env, httpd, configures_httpd, tls_proto, max_ver, min_ver): + @pytest.mark.parametrize("server_tls, min_arg, max_arg", gen_test_17_09_list()) + def test_17_09_ssl_min_max(self, env: Env, httpd, configures_httpd, server_tls, min_arg, max_arg): + # We test if curl using min/max versions arguments (and defaults) can connect + # to a server using 'server_tls' version only httpd.set_extra_config('base', [ - f'SSLProtocol {tls_proto}', + f'SSLProtocol {server_tls}', 'SSLCipherSuite ALL:@SECLEVEL=0', ]) httpd.reload_if_config_changed() + # curl's TLS backend supported version + if env.curl_uses_lib('gnutls') or \ + env.curl_uses_lib('quiche') or \ + env.curl_uses_lib('aws-lc'): + curl_supported = [0x301, 0x302, 0x303, 0x304] + elif env.curl_uses_lib('openssl') and \ + env.curl_lib_version_before('openssl', '3.0.0'): + curl_supported = [0x301, 0x302, 0x303, 0x304] + else: # most SSL backends dropped support for TLSv1.0, TLSv1.1 + curl_supported = [0x303, 0x304] + + extra_args = ['--trace-config', 'ssl'] + + # determine effective min/max version used by curl with these args + if max_arg != 'none': + extra_args.extend(['--tls-max', max_arg]) + curl_max_ver = TLSDefs.CURL_ARG_MAX_VERSION_ID[max_arg] + else: + curl_max_ver = max(TLSDefs.TLS_VERSION_IDS.values()) + if min_arg != 'none': + extra_args.append(f'--{min_arg}') + curl_min_ver = TLSDefs.CURL_ARG_MIN_VERSION_ID[min_arg] + else: + curl_min_ver = min(0x303, curl_max_ver) # TLSv1.2 is the default now + + # collect all versions that curl is allowed with this command lines and supports + curl_allowed = [tid for tid in sorted(TLSDefs.TLS_VERSION_IDS.values()) + if curl_min_ver <= tid <= curl_max_ver and + tid in curl_supported] + # we expect a successful transfer, when the server TLS version is allowed + server_ver = TLSDefs.TLS_VERSION_IDS[server_tls] + # do the transfer proto = 'http/1.1' run_env = os.environ.copy() if env.curl_uses_lib('gnutls'): @@ -295,29 +356,14 @@ class TestSSLUse: run_env['GNUTLS_SYSTEM_PRIORITY_FILE'] = our_config curl = CurlClient(env=env, run_env=run_env) url = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo' - # SSL backend specifics - if env.curl_uses_lib('gnutls'): - supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - elif env.curl_uses_lib('quiche'): - supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - elif env.curl_uses_lib('aws-lc'): - supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - elif env.curl_uses_lib('openssl') and \ - env.curl_lib_version_before('openssl', '3.0.0'): - supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - else: # most SSL backends dropped support for TLSv1.0, TLSv1.1 - supported = [None, None, 'TLSv1.2', 'TLSv1.3'] - # test - extra_args = [[], ['--tlsv1'], ['--tlsv1.0'], ['--tlsv1.1'], ['--tlsv1.2'], ['--tlsv1.3']][min_ver+2] + \ - [['--tls-max', '1.0'], ['--tls-max', '1.1'], ['--tls-max', '1.2'], ['--tls-max', '1.3'], []][max_ver] - extra_args.extend(['--trace-config', 'ssl']) r = curl.http_get(url=url, alpn_proto=proto, extra_args=extra_args) - if max_ver >= min_ver and tls_proto in supported[max(0, min_ver):min(max_ver, 3)+1]: - assert r.exit_code == 0, f'extra_args={extra_args}\n{r.dump_logs()}' + + if server_ver in curl_allowed: + assert r.exit_code == 0, f'should succeed, server={server_ver:04x}, curl=[{curl_min_ver:04x}, {curl_max_ver:04x}], allowed={curl_allowed}\n{r.dump_logs()}' assert r.json['HTTPS'] == 'on', r.dump_logs() - assert r.json['SSL_PROTOCOL'] == tls_proto, r.dump_logs() + assert r.json['SSL_PROTOCOL'] == server_tls, r.dump_logs() else: - assert r.exit_code != 0, f'extra_args={extra_args}\n{r.dump_logs()}' + assert r.exit_code != 0, f'should fail, server={server_ver:04x}, curl=[{curl_min_ver:04x}, {curl_max_ver:04x}]\n{r.dump_logs()}' def test_17_10_h3_session_reuse(self, env: Env, httpd, nghttpx): if not env.have_h3():