tls: make default TLS version be minimum 1.2

This still allows users to explictily ask for 1.0 or 1.1 as the minimum
version. If the TLS library allows it.

Starting with this change, the CURL_SSLVERSION_DEFAULT value is no
longer used as minimum version when the TLS backend are called.

This also makes curl set the minimum version to 1.2 independently of
libcurl for the rare case where a newer curl tool would use an older
libcurl.

URL: https://curl.se/mail/lib-2025-07/0007.html
Assisted-by: Stefan Eissing
Closes #17894
This commit is contained in:
Daniel Stenberg 2025-07-11 08:14:42 +02:00
parent 0e022d4241
commit 9d8998c994
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
23 changed files with 206 additions and 84 deletions

View file

@ -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);

View file

@ -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? */

View file

@ -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);

View file

@ -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)

View file

@ -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 */

View file

@ -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);
}
}