]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tls: make default TLS version be minimum 1.2
authorDaniel Stenberg <daniel@haxx.se>
Fri, 11 Jul 2025 06:14:42 +0000 (08:14 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 27 Jul 2025 16:23:04 +0000 (18:23 +0200)
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

23 files changed:
docs/libcurl/opts/CURLOPT_SSLVERSION.md
lib/setopt.c
lib/setopt.h
lib/url.c
lib/vtls/gtls.c
src/config2setopts.c
src/tool_cfgable.h
src/tool_getparam.c
src/tool_paramhlp.c
src/tool_paramhlp.h
src/tool_setopt.c
tests/data/test1400
tests/data/test1401
tests/data/test1402
tests/data/test1403
tests/data/test1404
tests/data/test1405
tests/data/test1406
tests/data/test1407
tests/data/test1420
tests/data/test1465
tests/data/test1481
tests/http/test_17_ssl_use.py

index 4a04f52a2eb046ace8fe9457c25d7e17ac9413f8..63440b5576a62d6b0912c77af4eeef61f064bfd7 100644 (file)
@@ -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
 
index 1380c33db6faeb0de0e2e5693e466d619476e2ae..1be45dc05bc66611e3ef87e190b575aceedf660a 100644 (file)
@@ -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:
     /*
index b0237467bd67a6a9cf0c796e1b9b24977f312e73..c323dd74a37936b93747722e7ec05e1af55caf14 100644 (file)
  *
  ***************************************************************************/
 
+#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;
index 68b370667913fbd000d5db2a51060cad89c1b329..0e90af429baecf0414b148ca9607170cd25ddb55 100644 (file)
--- 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;
index 9f5ab46659fda58dcba9afa51f27a07b14516589..405c8e7ff3bd84912ad245c9da6b21249e139818 100644 (file)
@@ -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);
index 55e30ee761b1be77a8322765c9d118eec2d44030..10c7b9a703855d2f6e5c6982400c1f66682217a6 100644 (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);
index 62ca06ad1e521574ecb8b60c7a51b92575a6cd93..bd32ab2d42a7d548216d00574b581772d25fbf8d 100644 (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? */
index 4766dade2f08df2fdc863679e5e46ea88ca71cd6..3a1cc57fdd3a5e9cb9d0344026e5820940110de9 100644 (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);
index 97a6b6e2eef1cc8b71c17e032a076671e494be07..c037189610c26a56963338af24f45fab442b35f9 100644 (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)
index 136214bb203674f8915d60d9bd4e11963a99a8c7..0be9c8968cb9d8b054834007e1611f6294983eb1 100644 (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 */
index 9e4f6e59fcec82870ab520b626a61c89fbae7553..52c80104662c1a1acb14c3c585d6c994388873c0 100644 (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);
     }
   }
 
index ee7a4d4ed48db7ebfbfb80da6a41c7be203aa984..4a9e1e66a5fceb7e74b59c526e2036a67977dedf 100644 (file)
@@ -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/
 </stripfile>
index 265d99e3ebda85d55c7fc6898fc47d78b049679c..bb5a7a97ac25b769b9d7536b1ddbb4c3325ead8a 100644 (file)
@@ -66,6 +66,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/
 $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 <file name="%LOGDIR/test%TESTNUMBER.c" mode="text">
 /********* Sample code generated by the curl command line tool **********
index 0c084d2878926c4556d0150b2eec322b391fde35..c973e7d8f8cae1002cfe9023555da9201112c08a 100644 (file)
@@ -60,6 +60,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/
 $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 <file name="%LOGDIR/test%TESTNUMBER.c" mode="text">
 /********* Sample code generated by the curl command line tool **********
index 643f4424b8bf4444837b5556fbc592023d090f45..a03da1d6d648d1bc4eb533d7043ee946f6e2037a 100644 (file)
@@ -57,6 +57,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/
 $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 <file name="%LOGDIR/test%TESTNUMBER.c" mode="text">
 /********* Sample code generated by the curl command line tool **********
index aa88eed496246b669f1c67d25e52f66da8f22931..f3b31be1e568df76eaeb310af3586762ee933d1b 100644 (file)
@@ -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" \*\//
 </stripfile>
index ff95450f5c935c41b70d7def90be3537d08eb4dc..0b1be439b44d6fb6f153d122bfe3b030e8e9f80a 100644 (file)
@@ -145,6 +145,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_HTTP09_ALLOWED/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 </verify>
 </testcase>
index 6f734aa8a7f0b9eec22e88ab29044f6d35a7c99e..a41276c45dce24b23f17e3072d1074a22ec172ca 100644 (file)
@@ -129,6 +129,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_HTTP09_ALLOWED/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 </verify>
 </testcase>
index 09d8702c284bd1adf0b198afe671d7067bf103fe..94724a6faed9b4b2db443c87a47668352c946f4a 100644 (file)
@@ -107,6 +107,7 @@ $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_HTTP09_ALLOWED/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 </verify>
 </testcase>
index f93db9d5c7a7a17c2058e3c5a25a8d50cfa2b96f..2cc70390629caaad6656dab2baeba4ff018bd2b5 100644 (file)
@@ -111,6 +111,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/
 $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 </verify>
 </testcase>
index 786d98c5a6214779998a589c3b7887add59716c1..b521d2f31f0151526b7d18815fba0920b8e3550e 100644 (file)
@@ -63,6 +63,7 @@ $_ = '' if /CURLOPT_SSL_VERIFYPEER/
 $_ = '' if /CURLOPT_SSH_KNOWNHOSTS/
 $_ = '' if /CURLOPT_HTTP_VERSION/
 $_ = '' if /CURLOPT_INTERLEAVEDATA/
+$_ = '' if /CURLOPT_SSLVERSION/
 </stripfile>
 <file name="%LOGDIR/test%TESTNUMBER.c" mode="text">
 /********* Sample code generated by the curl command line tool **********
index b6793a3bade915dcf3f0202d67709894b8f5a01c..87aada2873e007eab4236490a710250b3e3bea7e 100644 (file)
@@ -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
index 348a649e0603e76bc1fb85d9ff20a9aa31d67a3e..d3a3fcb5a564a0bdca706a78ce33e94ac0ae73d1 100644 (file)
@@ -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():