From ede125b7b7ca8fc5a1fe3d7c1aee6bff2ea0bf24 Mon Sep 17 00:00:00 2001 From: Michael Baentsch <57787676+baentsch@users.noreply.github.com> Date: Sat, 29 Aug 2020 14:09:24 +0200 Subject: tls: add CURLOPT_SSL_EC_CURVES and --curves Closes #5892 --- docs/cmdline-opts/Makefile.inc | 1 + docs/cmdline-opts/curves.d | 17 ++++++++++ docs/libcurl/curl_easy_setopt.3 | 2 ++ docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3 | 54 +++++++++++++++++++++++++++++++ docs/libcurl/opts/Makefile.inc | 1 + docs/libcurl/symbols-in-versions | 1 + docs/options-in-versions | 1 + include/curl/curl.h | 6 ++++ include/curl/typecheck-gcc.h | 1 + lib/doh.c | 4 +++ lib/easyoptions.c | 3 +- lib/setopt.c | 8 +++++ lib/url.c | 1 + lib/urldata.h | 2 ++ lib/vtls/openssl.c | 16 +++++++++ lib/vtls/vtls.c | 3 ++ src/tool_cfgable.h | 1 + src/tool_getparam.c | 5 +++ src/tool_help.c | 2 ++ src/tool_operate.c | 3 ++ 20 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 docs/cmdline-opts/curves.d create mode 100644 docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3 diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index aa1acabe0..792cadb3c 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -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 index 000000000..03264c05a --- /dev/null +++ b/docs/cmdline-opts/curves.d @@ -0,0 +1,17 @@ +Long: curves +Arg: +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. diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index a64375e0c..7f6016614 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -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 index 000000000..f98f0c17a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.3 @@ -0,0 +1,54 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , 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 + +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), " diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index ebf234002..fe4177579 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -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 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 82a8e8b3d..74b955093 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -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 diff --git a/docs/options-in-versions b/docs/options-in-versions index ba070a47f..683363239 100644 --- a/docs/options-in-versions +++ b/docs/options-in-versions @@ -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 diff --git a/include/curl/curl.h b/include/curl/curl.h index 32d9bd4a7..9026aa5c1 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -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; diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index 4f99ca778..318ab0abb 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -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 */ diff --git a/lib/doh.c b/lib/doh.c index 31c243883..e8b080110 100644 --- 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 */ diff --git a/lib/easyoptions.c b/lib/easyoptions.c index 3294c1d0b..9145ba7fc 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -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 diff --git a/lib/setopt.c b/lib/setopt.c index 6631c13fe..ef6c7cb9a 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -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); diff --git a/lib/url.c b/lib/url.c index 086de88af..2f879a61c 100644 --- 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]; diff --git a/lib/urldata.h b/lib/urldata.h index 86f8af42c..f9ac93a86 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 -- */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 09f331418..ce6f8445a 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -200,6 +200,10 @@ !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); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 281043aa6..9db4fd0ef 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -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 diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 620bfef3e..a3b8dd51b 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -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; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 74b6b7369..64c988122 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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; } diff --git a/src/tool_help.c b/src/tool_help.c index 29680d05a..c8b2f52c9 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -94,6 +94,8 @@ static const struct helptxt helptext[] = { "Convert LF to CRLF in upload"}, {" --crlfile ", "Get a CRL list in PEM format from the given file"}, + {" --curves ", + "(EC) TLS key exchange algorithm(s) to request "}, {"-d, --data ", "HTTP POST data"}, {" --data-ascii ", diff --git a/src/tool_operate.c b/src/tool_operate.c index aaadeeb9d..1fe7637d2 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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 */ -- cgit v1.2.1