]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tls: add CURLOPT_SSL_EC_CURVES and --curves
authorMichael Baentsch <57787676+baentsch@users.noreply.github.com>
Sat, 29 Aug 2020 12:09:24 +0000 (14:09 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 30 Aug 2020 15:24:04 +0000 (17:24 +0200)
Closes #5892

20 files changed:
docs/cmdline-opts/Makefile.inc
docs/cmdline-opts/curves.d [new file with mode: 0644]
docs/libcurl/curl_easy_setopt.3
docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3 [new file with mode: 0644]
docs/libcurl/opts/Makefile.inc
docs/libcurl/symbols-in-versions
docs/options-in-versions
include/curl/curl.h
include/curl/typecheck-gcc.h
lib/doh.c
lib/easyoptions.c
lib/setopt.c
lib/url.c
lib/urldata.h
lib/vtls/openssl.c
lib/vtls/vtls.c
src/tool_cfgable.h
src/tool_getparam.c
src/tool_help.c
src/tool_operate.c

index aa1acabe0702c6b14dfed28876f94a9d54b06a7a..792cadb3c3ccc5e6be2b63f9639718d139b94dc0 100644 (file)
@@ -41,6 +41,7 @@ DPAGES =                                      \
   cookie.d                                     \
   create-dirs.d                                        \
   crlf.d crlfile.d                             \
+  curves.d                                     \
   data-ascii.d                                 \
   data-binary.d                                        \
   data-urlencode.d                             \
diff --git a/docs/cmdline-opts/curves.d b/docs/cmdline-opts/curves.d
new file mode 100644 (file)
index 0000000..03264c0
--- /dev/null
@@ -0,0 +1,17 @@
+Long: curves
+Arg: <algorithm list>
+Help: (EC) TLS key exchange algorithm(s) to request
+Protocols: TLS
+Added: 7.73.0
+---
+Tells curl to request specific curves to use during SSL session establishment
+according to RFC 8422, 5.1.  Multiple algorithms can be provided by separating
+them with ":" (e.g.  "X25519:P-521").  The parameter is available identically
+in the "openssl s_client/s_server" utilities.
+
+--curves allows a OpenSSL powered curl to make SSL-connections with exactly
+the (EC) curve requested by the client, avoiding intransparent client/server
+negotiations.
+
+If this option is set, the default curves list built into openssl will be
+ignored.
index a64375e0c7b88266cfc545d6ceb54b2e26414d4c..7f60166145830352f22f7181d35c2eba191a2b71 100644 (file)
@@ -532,6 +532,8 @@ Proxy client key type. See \fICURLOPT_PROXY_SSLKEYTYPE(3)\fP
 Client key password. See \fICURLOPT_KEYPASSWD(3)\fP
 .IP CURLOPT_PROXY_KEYPASSWD
 Proxy client key password. See \fICURLOPT_PROXY_KEYPASSWD(3)\fP
+.IP CURLOPT_SSL_EC_CURVES
+Set key exchange curves. See \fICURLOPT_SSL_EC_CURVES(3)\fP
 .IP CURLOPT_SSL_ENABLE_ALPN
 Enable use of ALPN. See \fICURLOPT_SSL_ENABLE_ALPN(3)\fP
 .IP CURLOPT_SSL_ENABLE_NPN
diff --git a/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3 b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3
new file mode 100644 (file)
index 0000000..f98f0c1
--- /dev/null
@@ -0,0 +1,54 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" *
+.\" * 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.haxx.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.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_SSL_EC_CURVES 3 "29 Aug 2020" "libcurl 7.73.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_SSL_EC_CURVES \- set key exchange curves
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_EC_CURVES, char *alg_list);
+.SH DESCRIPTION
+Pass a string as parameter with a colon delimited list of (EC) algorithms. This
+option defines the client's key exchange algorithms in the SSL handshake (if
+the SSL backend libcurl is built to use supports it).
+.SH DEFAULT
+"", embedded in SSL backend
+.SH PROTOCOLS
+HTTP
+.SH EXAMPLE
+.nf
+CURL *curl = curl_easy_init();
+if(curl) {
+  curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
+  curl_easy_setopt(curl, CURLOPT_SSL_EC_CURVES, "X25519:P-521");
+  ret = curl_easy_perform(curl);
+  curl_easy_cleanup(curl);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.73.0. Supported by the OpenSSL backend.
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_SSL_OPTIONS "(3), " CURLOPT_SSL_CIPHER_LIST "(3), "
+.BR CURLOPT_TLS13_CIPHERS "(3), "
index ebf23400208511ff9796547b3f44e8453f2648d4..fe417757968ef5f3f3fbbe16b4c96c59736ca9d1 100644 (file)
@@ -331,6 +331,7 @@ man_MANS =                                      \
   CURLOPT_SSL_CIPHER_LIST.3                     \
   CURLOPT_SSL_CTX_DATA.3                        \
   CURLOPT_SSL_CTX_FUNCTION.3                    \
+  CURLOPT_SSL_EC_CURVES.3                      \
   CURLOPT_SSL_ENABLE_ALPN.3                     \
   CURLOPT_SSL_ENABLE_NPN.3                      \
   CURLOPT_SSL_FALSESTART.3                      \
index 82a8e8b3ddd896a5b116e05cbeb7dab585d07999..74b95509325bf33a91ca6a064d84798344447292 100644 (file)
@@ -616,6 +616,7 @@ CURLOPT_SSLVERSION              7.1
 CURLOPT_SSL_CIPHER_LIST         7.9
 CURLOPT_SSL_CTX_DATA            7.10.6
 CURLOPT_SSL_CTX_FUNCTION        7.10.6
+CURLOPT_SSL_EC_CURVES           7.73.0
 CURLOPT_SSL_ENABLE_ALPN         7.36.0
 CURLOPT_SSL_ENABLE_NPN          7.36.0
 CURLOPT_SSL_FALSESTART          7.42.0
index ba070a47f7f29b54c410176b474d0428ecf49e7b..683363239447e2580fcc1b2f1fc9ccd541b0614e 100644 (file)
@@ -32,6 +32,7 @@
 --create-dirs                        7.10.3
 --crlf                               5.7
 --crlfile                            7.19.7
+--curves                             7.73.0
 --data (-d)                          4.0
 --data-ascii                         7.2
 --data-binary                        7.2
index 32d9bd4a73b2d3ce844b12e5e6a64620185af4f2..9026aa5c167cc434453c624464a586d64ddff67e 100644 (file)
@@ -2025,6 +2025,12 @@ typedef enum {
   CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296),
   CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297),
 
+  /* the EC curves requested by the TLS client (RFC 8422, 5.1);
+   * OpenSSL support via 'set_groups'/'set_curves':
+   * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+   */
+  CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 4f99ca7786ec0bade0f333b50c9cd5b8081d77c9..318ab0abb3f110ccf6a27d0003d2d0980e366c61 100644 (file)
@@ -335,6 +335,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_USERNAME ||                                            \
    (option) == CURLOPT_USERPWD ||                                             \
    (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
+   (option) == CURLOPT_SSL_EC_CURVES ||                                       \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
index 31c243883336271379ba32fa119aae3398f1df14..e8b0801109b2204f069e06118e8acbb857a58674 100644 (file)
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -349,6 +349,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
     if(data->set.ssl.fsslctxp)
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
+    if(data->set.str[STRING_SSL_EC_CURVES]) {
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
+        data->set.str[STRING_SSL_EC_CURVES]);
+    }
 
     doh->set.fmultidone = Curl_doh_done;
     doh->set.dohfor = data; /* identify for which transfer this is done */
index 3294c1d0be6fc2a47dedd529fa6a3e9cfc1d8b76..9145ba7fc4c84d96487f75cacf9f5f2c1201fde9 100644 (file)
@@ -278,6 +278,7 @@ struct curl_easyoption Curl_easyopts[] = {
   {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0},
   {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0},
   {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0},
+  {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0},
   {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0},
   {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0},
   {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0},
@@ -341,6 +342,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return (CURLOPT_LASTENTRY != (297 + 1));
+  return (CURLOPT_LASTENTRY != (298 + 1));
 }
 #endif
index 6631c13fe31e042ce53c78efebcdd358b8dab12e..ef6c7cb9ae15a2cfd08427bce50273e4e0fb49e8 100644 (file)
@@ -2241,6 +2241,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
 #endif
 
+  case CURLOPT_SSL_EC_CURVES:
+    /*
+     * Set accepted curves in SSL connection setup.
+     * Specify colon-delimited list of curve algorithm names.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES],
+                            va_arg(param, char *));
+    break;
 #endif
   case CURLOPT_IPRESOLVE:
     arg = va_arg(param, long);
index 086de88af82b5a2eda848a8a57243fc4ff4d96ed..2f879a61c8b12fcfed0d023c2993b5e82a62305f 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -3616,6 +3616,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.ssl.primary.pinned_key =
     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
   data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+  data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
 
 #ifndef CURL_DISABLE_PROXY
   data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
index 86f8af42c432dc6c8f7ea3b355fd3c9c0f70ee5a..f9ac93a866f3a2a58a059f8a59e6c681da83bc00 100644 (file)
@@ -230,6 +230,7 @@ struct ssl_primary_config {
   char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
   char *pinned_key;
   struct curl_blob *cert_blob;
+  char *curves;          /* list of curves to use */
   BIT(verifypeer);       /* set TRUE if this is desired */
   BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
   BIT(verifystatus);     /* set TRUE if certificate status must be checked */
@@ -1565,6 +1566,7 @@ enum dupstring {
   STRING_DNS_INTERFACE,
   STRING_DNS_LOCAL_IP4,
   STRING_DNS_LOCAL_IP6,
+  STRING_SSL_EC_CURVES,
 
   /* -- end of null-terminated strings -- */
 
index 09f331418b5afa46a97d57906af1a53a4a2d71fd..ce6f8445a71dee7f1bcb4ec42fe044d14eb91cd2 100644 (file)
      !defined(OPENSSL_IS_BORINGSSL))
 #define HAVE_SSL_CTX_SET_CIPHERSUITES
 #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
+/* SET_EC_CURVES available under the same preconditions: see
+ * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+ */
+#define HAVE_SSL_CTX_SET_EC_CURVES
 #endif
 
 #if defined(LIBRESSL_VERSION_NUMBER)
@@ -2800,6 +2804,18 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
 #endif
 
+#ifdef HAVE_SSL_CTX_SET_EC_CURVES
+  {
+    char *curves = SSL_CONN_CONFIG(curves);
+    if(curves) {
+      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+        failf(data, "failed setting curves list: '%s'", curves);
+        return CURLE_SSL_CIPHER;
+      }
+    }
+  }
+#endif
+
 #ifdef HAVE_OPENSSL_SRP
   if(ssl_authtype == CURL_TLSAUTH_SRP) {
     char * const ssl_username = SSL_SET_OPTION(username);
index 281043aa63c0770948b330b9988af929d6db4a4c..9db4fd0ef69d0b316af5eedb9d282991e90fffc5 100644 (file)
@@ -138,6 +138,7 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
      Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
      Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
      Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
+     Curl_safe_strcasecompare(data->curves, needle->curves) &&
      Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
     return TRUE;
 
@@ -164,6 +165,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
   CLONE_STRING(cipher_list);
   CLONE_STRING(cipher_list13);
   CLONE_STRING(pinned_key);
+  CLONE_STRING(curves);
 
   return TRUE;
 }
@@ -179,6 +181,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
   Curl_safefree(sslc->cipher_list13);
   Curl_safefree(sslc->pinned_key);
   Curl_safefree(sslc->cert_blob);
+  Curl_safefree(sslc->curves);
 }
 
 #ifdef USE_SSL
index 620bfef3ef449577dfc8e498520682364a6307b9..a3b8dd51b32d6357fb11b7b354ba809d874b9f8f 100644 (file)
@@ -162,6 +162,7 @@ struct OperationConfig {
   char *etag_compare_file;
   bool crlf;
   char *customrequest;
+  char *ssl_ec_curves;
   char *krblevel;
   char *request_target;
   long httpversion;
index 74b6b7369925d875eab6b58e8626f55fd5518694..64c988122f95a4c839ed958b8e5f31b6d7aacea2 100644 (file)
@@ -272,6 +272,7 @@ static const struct LongShort aliases[]= {
   {"EB", "socks5-gssapi",            ARG_BOOL},
   {"EC", "etag-save",                ARG_FILENAME},
   {"ED", "etag-compare",             ARG_FILENAME},
+  {"EE", "curves",                   ARG_STRING},
   {"f",  "fail",                     ARG_BOOL},
   {"fa", "fail-early",               ARG_BOOL},
   {"fb", "styled-output",            ARG_BOOL},
@@ -1726,6 +1727,10 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
         GetStr(&config->etag_compare_file, nextarg);
         break;
 
+      case 'E':
+        GetStr(&config->ssl_ec_curves, nextarg);
+        break;
+
       default: /* unknown flag */
         return PARAM_OPTION_UNKNOWN;
       }
index 29680d05ac150f7c8e42c1ea24ff7a8de659855d..c8b2f52c9f9ca7505214ae00f81e033265590684 100644 (file)
@@ -94,6 +94,8 @@ static const struct helptxt helptext[] = {
    "Convert LF to CRLF in upload"},
   {"    --crlfile <file>",
    "Get a CRL list in PEM format from the given file"},
+  {"    --curves <algorithm list>",
+   "(EC) TLS key exchange algorithm(s) to request "},
   {"-d, --data <data>",
    "HTTP POST data"},
   {"    --data-ascii <data>",
index aaadeeb9dd5e7753b1a70299abb2785be2c8cdc2..1fe7637d20411be9977af64fff7a456d96bbe925 100644 (file)
@@ -1520,6 +1520,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         if(config->pinnedpubkey)
           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
 
+        if(config->ssl_ec_curves)
+          my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
+
         if(curlinfo->features & CURL_VERSION_SSL) {
           /* Check if config->cert is a PKCS#11 URI and set the
            * config->cert_type if necessary */