13.11 Some TLS options are not offered for HTTPS proxies
13.13 Make sure we forbid TLS 1.3 post-handshake authentication
13.14 Support the clienthello extension
- 13.15 Select signature algorithms
13.16 Share the CA cache
13.17 Add missing features to TLS backends
https://datatracker.ietf.org/doc/html/rfc7685
https://github.com/curl/curl/issues/2299
-13.15 Select signature algorithms
-
- Consider adding an option or a way for users to select TLS signature
- algorithm. The signature algorithms set by a client are used directly in the
- supported signature algorithm in the client hello message.
-
- https://github.com/curl/curl/issues/12982
-
13.16 Share the CA cache
For TLS backends that supports CA caching, it makes sense to allow the share
show-error.md \
show-headers.md \
silent.md \
+ sigalgs.md \
skip-existing.md \
socks4.md \
socks4a.md \
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Long: sigalgs
+Arg: <list>
+Help: TLS signature algorithms to use
+Protocols: TLS
+Added: 8.14.0
+Category: tls
+Multi: single
+See-also:
+ - ciphers
+Example:
+ - --sigalgs ecdsa_secp256r1_sha256 $URL
+---
+
+# `--sigalgs`
+
+Set specific signature algorithms to use during SSL session establishment according to RFC
+5246, 7.4.1.4.1.
+
+An algorithm can use either a signature algorithm and a hash algorithm pair separated by a
+`+` (e.g. `ECDSA+SHA224`), or its TLS 1.3 signature scheme name (e.g. `ed25519`).
+
+Multiple algorithms can be provided by separating them with `:`
+(e.g. `DSA+SHA256:rsa_pss_pss_sha256`). The parameter is available as `-sigalgs` in the
+OpenSSL `s_client` and `s_server` utilities.
+
+`--sigalgs` allows a OpenSSL powered curl to make SSL-connections with exactly
+the signature algorithms requested by the client, avoiding nontransparent client/server
+negotiations.
+
+If this option is set, the default signature algorithm list built into OpenSSL are ignored.
Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3)
+## CURLOPT_SSL_SIGNATURE_ALGORITHMS
+
+TLS signature algorithms to use. See CURLOPT_SSL_SIGNATURE_ALGORITHMS(3)
+
## CURLOPT_SSL_VERIFYHOST
Verify the hostname in the SSL certificate. See CURLOPT_SSL_VERIFYHOST(3)
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Title: CURLOPT_SSL_SIGNATURE_ALGORITHMS
+Section: 3
+Source: libcurl
+See-also:
+ - CURLOPT_SSL_CIPHER_LIST (3)
+ - CURLOPT_SSL_EC_CURVES (3)
+ - CURLOPT_SSLVERSION (3)
+ - CURLOPT_USE_SSL (3)
+Protocol:
+ - TLS
+TLS-backend:
+ - OpenSSL
+Added-in: 8.14.0
+---
+
+# NAME
+
+CURLOPT_SSL_SIGNATURE_ALGORITHMS - signature algorithms to use for TLS
+
+# SYNOPSIS
+
+~~~c
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_SIGNATURE_ALGORITHMS, char *list);
+~~~
+
+# DESCRIPTION
+
+Pass a char pointer, pointing to a null-terminated string holding the list of
+signature algorithms to use for the TLS connection. The list must be syntactically
+correct, it consists of one or more signature algorithm strings separated by colons.
+
+A valid example of a signature algorithms list with OpenSSL is:
+~~~
+"DSA+SHA256:rsa_pss_pss_sha256"
+~~~
+
+The application does not have to keep the string around after setting this
+option.
+
+Using this option multiple times makes the last set string override the
+previous ones. Set it to NULL to disable its use again.
+
+Works with OpenSSL and its BoringSSL fork (added in 8.14.0).
+
+# DEFAULT
+
+NULL, use built-in list
+
+# %PROTOCOLS%
+
+# EXAMPLE
+
+~~~c
+int main(void)
+{
+ CURL *curl = curl_easy_init();
+ if(curl) {
+ CURLcode res;
+ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
+ curl_easy_setopt(curl, CURLOPT_SSL_SIGNATURE_ALGORITHMS,
+ "DSA+SHA256:rsa_pss_pss_sha256");
+ res = curl_easy_perform(curl);
+ curl_easy_cleanup(curl);
+ }
+}
+~~~
+
+# HISTORY
+
+OpenSSL support added in 8.14.0.
+
+# %AVAILABILITY%
+
+# RETURN VALUE
+
+curl_easy_setopt(3) returns a CURLcode indicating success or error.
+
+CURLE_OK (0) means everything was OK, non-zero means an error occurred, see
+libcurl-errors(3).
CURLOPT_SSL_FALSESTART.3 \
CURLOPT_SSL_OPTIONS.3 \
CURLOPT_SSL_SESSIONID_CACHE.3 \
+ CURLOPT_SSL_SIGNATURE_ALGORITHMS.3 \
CURLOPT_SSL_VERIFYHOST.3 \
CURLOPT_SSL_VERIFYPEER.3 \
CURLOPT_SSL_VERIFYSTATUS.3 \
CURLOPT_SSL_FALSESTART 7.42.0
CURLOPT_SSL_OPTIONS 7.25.0
CURLOPT_SSL_SESSIONID_CACHE 7.16.0
+CURLOPT_SSL_SIGNATURE_ALGORITHMS 8.14.0
CURLOPT_SSL_VERIFYHOST 7.8.1
CURLOPT_SSL_VERIFYPEER 7.4.2
CURLOPT_SSL_VERIFYSTATUS 7.41.0
--show-error (-S) 5.9
--show-headers (-i) 4.8
--silent (-s) 4.0
+--sigalgs 8.14.0
--skip-existing 8.10.0
--socks4 7.15.2
--socks4a 7.18.0
CURLOPT(CURLOPT_UPLOAD_FLAGS, CURLOPTTYPE_LONG, 327),
+ /* set TLS supported signature algorithms */
+ CURLOPT(CURLOPT_SSL_SIGNATURE_ALGORITHMS, CURLOPTTYPE_STRINGPOINT, 328),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
(option) == CURLOPT_SSLKEY || \
(option) == CURLOPT_SSLKEYTYPE || \
(option) == CURLOPT_SSL_CIPHER_LIST || \
+ (option) == CURLOPT_SSL_EC_CURVES || \
+ (option) == CURLOPT_SSL_SIGNATURE_ALGORITHMS || \
(option) == CURLOPT_TLS13_CIPHERS || \
(option) == CURLOPT_TLSAUTH_PASSWORD || \
(option) == CURLOPT_TLSAUTH_TYPE || \
(option) == CURLOPT_AWS_SIGV4 || \
(option) == CURLOPT_USERPWD || \
(option) == CURLOPT_XOAUTH2_BEARER || \
- (option) == CURLOPT_SSL_EC_CURVES || \
0)
/* evaluates to true if option takes a curl_write_callback argument */
{"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0},
{"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0},
{"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0},
+ {"SSL_SIGNATURE_ALGORITHMS", CURLOPT_SSL_SIGNATURE_ALGORITHMS,
+ CURLOT_STRING, 0},
{"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0},
{"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0},
{"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
*/
int Curl_easyopts_check(void)
{
- return (CURLOPT_LASTENTRY % 10000) != (327 + 1);
+ return (CURLOPT_LASTENTRY % 10000) != (328 + 1);
}
#endif
*/
return Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], ptr);
+ case CURLOPT_SSL_SIGNATURE_ALGORITHMS:
+ /*
+ * Set accepted signature algorithms.
+ * Specify colon-delimited list of signature scheme names.
+ */
+ if(Curl_ssl_supports(data, SSLSUPP_SIGNATURE_ALGORITHMS))
+ return Curl_setstropt(&data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS],
+ ptr);
+ return CURLE_NOT_BUILT_IN;
#endif
#ifdef USE_SSH
case CURLOPT_SSH_PUBLIC_KEYFILE:
char *clientcert;
char *cipher_list; /* list of ciphers to use */
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
+ char *signature_algorithms; /* list of signature algorithms to use */
char *pinned_key;
char *CRLfile; /* CRL to check certificate revocation */
struct curl_blob *cert_blob;
#endif
STRING_ECH_CONFIG, /* CURLOPT_ECH_CONFIG */
STRING_ECH_PUBLIC, /* CURLOPT_ECH_PUBLIC */
+ STRING_SSL_SIGNATURE_ALGORITHMS, /* CURLOPT_SSL_SIGNATURE_ALGORITHMS */
/* -- end of null-terminated strings -- */
#endif
#endif
+/* Whether SSL_CTX_set1_sigalgs_list is available
+ * OpenSSL: supported since 1.0.2 (commit 0b362de5f575)
+ * BoringSSL: supported since 0.20240913.0 (commit 826ce15)
+ * LibreSSL: no
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L && \
+ !defined(LIBRESSL_VERSION_NUMBER))
+ #define HAVE_SSL_CTX_SET1_SIGALGS
+#endif
+
#ifdef LIBRESSL_VERSION_NUMBER
#define OSSL_PACKAGE "LibreSSL"
#elif defined(OPENSSL_IS_BORINGSSL)
}
}
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS
+#define OSSL_SIGALG_CAST(x) OSSL_CURVE_CAST(x)
+ {
+ const char *signature_algorithms = conn_config->signature_algorithms;
+ if(signature_algorithms) {
+ if(!SSL_CTX_set1_sigalgs_list(octx->ssl_ctx,
+ OSSL_SIGALG_CAST(signature_algorithms))) {
+ failf(data, "failed setting signature algorithms: '%s'",
+ signature_algorithms);
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
+#endif
+
#ifdef USE_OPENSSL_SRP
if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) {
char * const ssl_username = ssl_config->primary.username;
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS
+ SSLSUPP_SIGNATURE_ALGORITHMS |
+#endif
#ifdef USE_ECH_OPENSSL
SSLSUPP_ECH |
#endif
strcasecompare(c1->cipher_list, c2->cipher_list) &&
strcasecompare(c1->cipher_list13, c2->cipher_list13) &&
strcasecompare(c1->curves, c2->curves) &&
+ strcasecompare(c1->signature_algorithms, c2->signature_algorithms) &&
strcasecompare(c1->CRLfile, c2->CRLfile) &&
strcasecompare(c1->pinned_key, c2->pinned_key))
return TRUE;
CLONE_STRING(cipher_list13);
CLONE_STRING(pinned_key);
CLONE_STRING(curves);
+ CLONE_STRING(signature_algorithms);
CLONE_STRING(CRLfile);
#ifdef USE_TLS_SRP
CLONE_STRING(username);
Curl_safefree(sslc->ca_info_blob);
Curl_safefree(sslc->issuercert_blob);
Curl_safefree(sslc->curves);
+ Curl_safefree(sslc->signature_algorithms);
Curl_safefree(sslc->CRLfile);
#ifdef USE_TLS_SRP
Curl_safefree(sslc->username);
data->set.str[STRING_SSL_CIPHER_LIST];
data->set.ssl.primary.cipher_list13 =
data->set.str[STRING_SSL_CIPHER13_LIST];
+ data->set.ssl.primary.signature_algorithms =
+ data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS];
data->set.ssl.primary.pinned_key =
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
#define SSLSUPP_ECH (1<<7)
#define SSLSUPP_CA_CACHE (1<<8)
#define SSLSUPP_CIPHER_LIST (1<<9) /* supports TLS 1.0-1.2 ciphersuites */
+#define SSLSUPP_SIGNATURE_ALGORITHMS (1<<10) /* supports TLS sigalgs */
#ifdef USE_ECH
# include "../curl_base64.h"
CURLOPT_SSLKEYTYPE
CURLOPT_SSL_CIPHER_LIST
CURLOPT_SSL_EC_CURVES
+ CURLOPT_SSL_SIGNATURE_ALGORIHMS
CURLOPT_TLS13_CIPHERS
CURLOPT_TLSAUTH_PASSWORD
CURLOPT_TLSAUTH_TYPE
case CURLOPT_SSLKEYTYPE:
case CURLOPT_SSL_CIPHER_LIST:
case CURLOPT_SSL_EC_CURVES:
+ case CURLOPT_SSL_SIGNATURE_ALGORITHMS:
case CURLOPT_TLS13_CIPHERS:
case CURLOPT_TLSAUTH_PASSWORD:
case CURLOPT_TLSAUTH_TYPE:
char *etag_compare_file;
char *customrequest;
char *ssl_ec_curves;
+ char *ssl_signature_algorithms;
char *krblevel;
char *request_target;
char *writeout; /* %-styled format string to output */
{"sessionid", ARG_BOOL|ARG_NO, ' ', C_SESSIONID},
{"show-error", ARG_BOOL, 'S', C_SHOW_ERROR},
{"show-headers", ARG_BOOL, 'i', C_SHOW_HEADERS},
+ {"sigalgs", ARG_STRG|ARG_TLS, ' ',
+ C_SIGNATURE_ALGORITHMS},
{"silent", ARG_BOOL, 's', C_SILENT},
{"skip-existing", ARG_BOOL, ' ', C_SKIP_EXISTING},
{"socks4", ARG_STRG, ' ', C_SOCKS4},
case C_CURVES: /* --curves */
err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK);
break;
+ case C_SIGNATURE_ALGORITHMS: /* --sigalgs */
+ err = getstr(&config->ssl_signature_algorithms, nextarg, DENY_BLANK);
+ break;
case C_FAIL_EARLY: /* --fail-early */
global->fail_early = toggle;
break;
C_SHOW_ERROR,
C_SHOW_HEADERS,
C_SILENT,
+ C_SIGNATURE_ALGORITHMS,
C_SKIP_EXISTING,
C_SOCKS4,
C_SOCKS4A,
{"-i, --show-headers",
"Show response headers in output",
CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_OUTPUT},
+ {" --sigalgs <list>",
+ "TLS signature algorithms to use",
+ CURLHELP_TLS},
{"-s, --silent",
"Silent mode",
CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
if(config->ssl_ec_curves)
my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
+ if(config->ssl_signature_algorithms)
+ my_setopt_str(curl, CURLOPT_SSL_SIGNATURE_ALGORITHMS,
+ config->ssl_signature_algorithms);
+
if(config->writeout)
my_setopt_long(curl, CURLOPT_CERTINFO, 1);