schannel: fix user-set legacy algorithms in Windows 10 & 11

- If the user set a legacy algorithm list (CURLOPT_SSL_CIPHER_LIST) then
  use the SCHANNEL_CRED legacy structure to pass the list to Schannel.

- If the user set both a legacy algorithm list and a TLS 1.3 cipher list
  then abort.

Although MS doesn't document it, Schannel will not negotiate TLS 1.3
when SCHANNEL_CRED is used. That means setting a legacy algorithm list
limits the user to earlier versions of TLS.

Prior to this change, since 8beff435 (precedes 7.85.0), libcurl would
ignore legacy algorithms in Windows 10 1809 and later.

Reported-by: zhihaoy@users.noreply.github.com

Fixes https://github.com/curl/curl/pull/10741
Closes https://github.com/curl/curl/pull/10746
This commit is contained in:
Jay Satiro 2023-03-19 04:05:08 -04:00
parent 4169943d15
commit b4f9ae5126
5 changed files with 45 additions and 13 deletions

View File

@ -346,10 +346,13 @@ maps them to the following case-insensitive names.
## Schannel
Schannel allows the enabling and disabling of encryption algorithms, but not
specific cipher suites. They are
specific cipher suites, prior to TLS 1.3. The algorithms are
[defined](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) by
Microsoft.
The algorithms below are for TLS 1.2 and earlier. TLS 1.3 is covered in the
next section.
There is also the case that the selected algorithm is not supported by the
protocol or does not match the ciphers offered by the server during the SSL
negotiation. In this case curl will return error
@ -412,7 +415,12 @@ are running an outdated OS you might still be supporting weak ciphers.
### TLS 1.3 cipher suites
(Note these ciphers are set with `CURLOPT_TLS13_CIPHERS` and `--tls13-ciphers`)
You can set TLS 1.3 ciphers for Schannel by using `CURLOPT_TLS13_CIPHERS` or
`--tls13-ciphers` with the names below.
If TLS 1.3 cipher suites are set then libcurl will add or restrict Schannel TLS
1.3 algorithms automatically. Essentially, libcurl is emulating support for
individual TLS 1.3 cipher suites since Schannel does not support it directly.
`TLS_AES_256_GCM_SHA384`
`TLS_AES_128_GCM_SHA256`
@ -420,6 +428,11 @@ are running an outdated OS you might still be supporting weak ciphers.
`TLS_AES_128_CCM_8_SHA256`
`TLS_AES_128_CCM_SHA256`
Note if you set TLS 1.3 ciphers without also setting the minimum TLS version to
1.3 then it's possible Schannel may negotiate an earlier TLS version and cipher
suite if your libcurl and OS settings allow it. You can set the minimum TLS
version by using `CURLOPT_SSLVERSION` or `--tlsv1.3`.
## BearSSL
BearSSL ciphers can be specified by either the OpenSSL name (`ECDHE-RSA-AES128-GCM-SHA256`) or the IANA name (`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`).

View File

@ -17,5 +17,5 @@ cipher suite details on this URL:
https://curl.se/docs/ssl-ciphers.html
This option is currently used only when curl is built to use OpenSSL 1.1.1 or
later or Schannel. If you are using a different SSL backend you can try
later, or Schannel. If you are using a different SSL backend you can try
setting TLS 1.3 cipher suites by using the --ciphers option.

View File

@ -52,7 +52,10 @@ etc.
With BearSSL you do not add/remove ciphers. If one uses this option then all
known ciphers are disabled and only those passed in are enabled.
you will find more details about cipher lists on this URL:
For Schannel, you can use this option to set algorithms but not specific cipher
suites. Refer to the ciphers lists document for algorithms.
You will find more details about cipher lists on this URL:
https://curl.se/docs/ssl-ciphers.html

View File

@ -36,12 +36,12 @@ Pass a char *, pointing to a null-terminated string holding the list of cipher
suites to use for the TLS 1.3 connection. The list must be syntactically
correct, it consists of one or more cipher suite strings separated by colons.
you will find more details about cipher lists on this URL:
You will find more details about cipher lists on this URL:
https://curl.se/docs/ssl-ciphers.html
This option is currently used only when curl is built to use OpenSSL 1.1.1 or
later or Schannel. If you are using a different SSL backend you can try
later, or Schannel. If you are using a different SSL backend you can try
setting TLS 1.3 cipher suites by using the \fICURLOPT_SSL_CIPHER_LIST(3)\fP
option.

View File

@ -793,8 +793,11 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
backend->cred->client_cert_store = client_cert_store;
#endif
/* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */
if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
/* We support TLS 1.3 starting in Windows 10 version 1809 (OS build 17763) as
long as the user did not set a legacy algorithm list
(CURLOPT_SSL_CIPHER_LIST). */
if(!conn_config->cipher_list &&
curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
char *ciphers13 = 0;
@ -844,7 +847,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
/* reject too-long cipher names */
if(n > (LONGEST_ALG_ID - 1)) {
failf(data, "Cipher name too long, not checked.");
failf(data, "schannel: Cipher name too long, not checked");
return CURLE_SSL_CIPHER;
}
@ -872,7 +875,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
disable_aes_ccm_sha256 = FALSE;
}
else {
failf(data, "Passed in an unknown TLS 1.3 cipher.");
failf(data, "schannel: Unknown TLS 1.3 cipher: %s", tmp);
return CURLE_SSL_CIPHER;
}
@ -887,7 +890,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
&& disable_chacha_poly && disable_aes_ccm_8_sha256
&& disable_aes_ccm_sha256) {
failf(data, "All available TLS 1.3 ciphers were disabled.");
failf(data, "schannel: All available TLS 1.3 ciphers were disabled");
return CURLE_SSL_CIPHER;
}
@ -1010,7 +1013,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
&backend->cred->time_stamp);
}
else {
/* Pre-Windows 10 1809 */
/* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
doesn't document it, currently Schannel will not negotiate TLS 1.3 when
SCHANNEL_CRED is used. */
ALG_ID algIds[NUM_CIPHERS];
char *ciphers = conn_config->cipher_list;
SCHANNEL_CRED schannel_cred = { 0 };
@ -1019,9 +1024,20 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
schannel_cred.grbitEnabledProtocols = enabled_protocols;
if(ciphers) {
if((enabled_protocols & SP_PROT_TLS1_3_CLIENT)) {
infof(data, "schannel: WARNING: This version of Schannel may "
"negotiate a less-secure TLS version than TLS 1.3 because the "
"user set an algorithm cipher list.");
}
if(conn_config->cipher_list13) {
failf(data, "schannel: This version of Schannel does not support "
"setting an algorithm cipher list and TLS 1.3 cipher list at "
"the same time");
return CURLE_SSL_CIPHER;
}
result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
if(CURLE_OK != result) {
failf(data, "Unable to set ciphers to from connection ssl config");
failf(data, "schannel: Failed setting algorithm cipher list");
return result;
}
}