mirror of
https://github.com/curl/curl.git
synced 2026-01-18 17:21:26 +01:00
schannel: Add TLS 1.3 support
- Support TLS 1.3 as the default max TLS version for Windows Server 2022 and Windows 11. - Support specifying TLS 1.3 ciphers via existing option CURLOPT_TLS13_CIPHERS (tool: --tls13-ciphers). Closes https://github.com/curl/curl/pull/8419
This commit is contained in:
@@ -6,7 +6,8 @@ and
|
||||
[`--ciphers`](https://curl.se/docs/manpage.html#--ciphers)
|
||||
users can control which ciphers to consider when negotiating TLS connections.
|
||||
|
||||
TLS 1.3 ciphers are supported since curl 7.61 for OpenSSL 1.1.1+ with options
|
||||
TLS 1.3 ciphers are supported since curl 7.61 for OpenSSL 1.1.1+, and since
|
||||
curl 7.85 for SChannel with options
|
||||
[`CURLOPT_TLS13_CIPHERS`](https://curl.se/libcurl/c/CURLOPT_TLS13_CIPHERS.html)
|
||||
and
|
||||
[`--tls13-ciphers`](https://curl.se/docs/manpage.html#--tls13-ciphers)
|
||||
@@ -521,6 +522,16 @@ documentation](https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-ciphe
|
||||
Note that the supported ciphers in this case follow the OS version, so if you
|
||||
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`)
|
||||
|
||||
`TLS_AES_256_GCM_SHA384`
|
||||
`TLS_AES_128_GCM_SHA256`
|
||||
`TLS_CHACHA20_POLY1305_SHA256`
|
||||
`TLS_AES_128_CCM_8_SHA256`
|
||||
`TLS_AES_128_CCM_SHA256`
|
||||
|
||||
## 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`).
|
||||
|
||||
@@ -58,7 +58,7 @@ CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||
curl_easy_setopt(curl, CURLOPT_PROXY_TLS13_CIPHERS,
|
||||
"TLS13-CHACHA20-POLY1305-SHA256");
|
||||
"TLS_CHACHA20_POLY1305_SHA256");
|
||||
ret = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ 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. If you are using a different SSL backend you can try setting TLS 1.3
|
||||
cipher suites by using the CURLOPT_SSL_CIPHER_LIST option.
|
||||
later or SChannel. If you are using a different SSL backend you can try
|
||||
setting TLS 1.3 cipher suites by using the CURLOPT_SSL_CIPHER_LIST option.
|
||||
|
||||
The application does not have to keep the string around after setting this
|
||||
option.
|
||||
@@ -56,14 +56,15 @@ CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||
curl_easy_setopt(curl, CURLOPT_TLS13_CIPHERS,
|
||||
"TLS13-CHACHA20-POLY1305-SHA256");
|
||||
"TLS_CHACHA20_POLY1305_SHA256");
|
||||
ret = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in 7.61.0.
|
||||
Available when built with OpenSSL >= 1.1.1.
|
||||
Added in 7.61.0 for OpenSSL. Available when built with OpenSSL >= 1.1.1.
|
||||
|
||||
Added in 7.85.0 for SChannel.
|
||||
.SH RETURN VALUE
|
||||
Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise.
|
||||
.SH "SEE ALSO"
|
||||
|
||||
@@ -84,7 +84,39 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
|
||||
#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
|
||||
#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_CHAIN_MODE_CCM
|
||||
#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_CHAIN_MODE_GCM
|
||||
#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_AES_ALGORITHM
|
||||
#define BCRYPT_AES_ALGORITHM L"AES"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_SHA256_ALGORITHM
|
||||
#define BCRYPT_SHA256_ALGORITHM L"SHA256"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_SHA384_ALGORITHM
|
||||
#define BCRYPT_SHA384_ALGORITHM L"SHA384"
|
||||
#endif
|
||||
|
||||
/* Workaround broken compilers like MingW.
|
||||
Return the number of elements in a statically sized array.
|
||||
*/
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \
|
||||
&& !defined(DISABLE_SCHANNEL_CLIENT_CERT)
|
||||
#define HAS_CLIENT_CERT_PATH
|
||||
#endif
|
||||
|
||||
@@ -120,6 +152,10 @@
|
||||
#define SP_PROT_TLS1_2_CLIENT 0x00000800
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_3_CLIENT
|
||||
#define SP_PROT_TLS1_3_CLIENT 0x00002000
|
||||
#endif
|
||||
|
||||
#ifndef SCH_USE_STRONG_CRYPTO
|
||||
#define SCH_USE_STRONG_CRYPTO 0x00400000
|
||||
#endif
|
||||
@@ -174,7 +210,7 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data,
|
||||
set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
long ssl_version = SSL_CONN_CONFIG(version);
|
||||
@@ -184,23 +220,45 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data,
|
||||
switch(ssl_version_max) {
|
||||
case CURL_SSLVERSION_MAX_NONE:
|
||||
case CURL_SSLVERSION_MAX_DEFAULT:
|
||||
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
|
||||
|
||||
/* Windows Server 2022 and newer (including Windows 11)
|
||||
support TLS 1.3 built-in. Previous builds of Windows 10
|
||||
had broken TLS 1.3 implementations that could be enabled
|
||||
via registry.
|
||||
*/
|
||||
if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL)) {
|
||||
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
|
||||
}
|
||||
else /* Windows 10 and older */
|
||||
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for(; i <= (ssl_version_max >> 16); ++i) {
|
||||
switch(i) {
|
||||
case CURL_SSLVERSION_TLSv1_0:
|
||||
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
|
||||
(*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT;
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_1:
|
||||
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
|
||||
(*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT;
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
|
||||
(*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT;
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
failf(data, "schannel: TLS 1.3 is not yet supported");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
/* Windows Server 2022 and newer */
|
||||
if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL)) {
|
||||
(*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT;
|
||||
break;
|
||||
}
|
||||
else { /* Windows 10 and older */
|
||||
failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
@@ -217,8 +275,12 @@ get_alg_id_by_name(char *name)
|
||||
{
|
||||
char tmp[LONGEST_ALG_ID] = { 0 };
|
||||
char *nameEnd = strchr(name, ':');
|
||||
size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
|
||||
min(strlen(name), LONGEST_ALG_ID - 1);
|
||||
size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
|
||||
|
||||
/* reject too-long alg names */
|
||||
if(n > (LONGEST_ALG_ID - 1))
|
||||
return 0;
|
||||
|
||||
strncpy(tmp, name, n);
|
||||
tmp[n] = 0;
|
||||
CIPHEROPTION(CALG_MD2);
|
||||
@@ -422,49 +484,51 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
int sockindex)
|
||||
{
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
SCHANNEL_CRED schannel_cred;
|
||||
ALG_ID algIds[NUM_CIPHERS];
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
PCCERT_CONTEXT client_certs[1] = { NULL };
|
||||
#endif
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
CURLcode result;
|
||||
|
||||
/* setup Schannel API options */
|
||||
DWORD flags = 0;
|
||||
DWORD enabled_protocols = 0;
|
||||
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
/* setup Schannel API options */
|
||||
memset(&schannel_cred, 0, sizeof(schannel_cred));
|
||||
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
|
||||
if(conn->ssl_config.verifypeer) {
|
||||
#ifdef HAS_MANUAL_VERIFY_API
|
||||
if(backend->use_manual_cred_validation)
|
||||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
flags = SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
else
|
||||
#endif
|
||||
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
|
||||
flags = SCH_CRED_AUTO_CRED_VALIDATION;
|
||||
|
||||
if(SSL_SET_OPTION(no_revoke)) {
|
||||
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
|
||||
DEBUGF(infof(data, "schannel: disabled server certificate revocation "
|
||||
"checks"));
|
||||
}
|
||||
else if(SSL_SET_OPTION(revoke_best_effort)) {
|
||||
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
|
||||
DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
|
||||
}
|
||||
else {
|
||||
schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
flags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
|
||||
DEBUGF(infof(data,
|
||||
"schannel: checking server certificate revocation"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
|
||||
flags = SCH_CRED_MANUAL_CRED_VALIDATION |
|
||||
SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
DEBUGF(infof(data,
|
||||
@@ -472,15 +536,15 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(!conn->ssl_config.verifyhost) {
|
||||
schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
|
||||
flags |= SCH_CRED_NO_SERVERNAME_CHECK;
|
||||
DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
|
||||
"comparing the supplied target name with the subject "
|
||||
"names in server certificates."));
|
||||
}
|
||||
|
||||
if(!SSL_SET_OPTION(auto_client_cert)) {
|
||||
schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
|
||||
schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||
flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
|
||||
flags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||
infof(data, "schannel: disabled automatic use of client certificate");
|
||||
}
|
||||
else
|
||||
@@ -494,7 +558,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
{
|
||||
result = set_ssl_version_min_max(&schannel_cred, data, conn);
|
||||
result = set_ssl_version_min_max(&enabled_protocols, data, conn);
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
break;
|
||||
@@ -508,16 +572,6 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if(SSL_CONN_CONFIG(cipher_list)) {
|
||||
result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
|
||||
algIds);
|
||||
if(CURLE_OK != result) {
|
||||
failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
/* client certificate */
|
||||
if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
|
||||
@@ -651,9 +705,6 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
CertCloseStore(cert_store, 0);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
|
||||
schannel_cred.cCreds = 1;
|
||||
schannel_cred.paCred = client_certs;
|
||||
}
|
||||
else {
|
||||
cert_store =
|
||||
@@ -691,11 +742,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
|
||||
curlx_unicodefree(cert_path);
|
||||
|
||||
if(client_certs[0]) {
|
||||
schannel_cred.cCreds = 1;
|
||||
schannel_cred.paCred = client_certs;
|
||||
}
|
||||
else {
|
||||
if(!client_certs[0]) {
|
||||
/* CRYPT_E_NOT_FOUND / E_INVALIDARG */
|
||||
CertCloseStore(cert_store, 0);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
@@ -716,22 +763,270 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
|
||||
if(!backend->cred) {
|
||||
failf(data, "schannel: unable to allocate memory");
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
if(client_certs[0])
|
||||
CertFreeCertificateContext(client_certs[0]);
|
||||
#endif
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
backend->cred->refcount = 1;
|
||||
|
||||
sspi_status =
|
||||
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL,
|
||||
&schannel_cred, NULL, NULL,
|
||||
&backend->cred->cred_handle,
|
||||
&backend->cred->time_stamp);
|
||||
/* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */
|
||||
if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL)) {
|
||||
|
||||
char *ciphers13 = 0;
|
||||
|
||||
bool disable_aes_gcm_sha384 = FALSE;
|
||||
bool disable_aes_gcm_sha256 = FALSE;
|
||||
bool disable_chacha_poly = FALSE;
|
||||
bool disable_aes_ccm_8_sha256 = FALSE;
|
||||
bool disable_aes_ccm_sha256 = FALSE;
|
||||
|
||||
SCH_CREDENTIALS credentials = { 0 };
|
||||
TLS_PARAMETERS tls_parameters = { 0 };
|
||||
CRYPTO_SETTINGS crypto_settings[4] = { 0 };
|
||||
UNICODE_STRING blocked_ccm_modes[1] = { 0 };
|
||||
UNICODE_STRING blocked_gcm_modes[1] = { 0 };
|
||||
|
||||
int crypto_settings_idx = 0;
|
||||
|
||||
|
||||
/* If TLS 1.3 ciphers are explictly listed, then
|
||||
* disable all the ciphers and re-enable which
|
||||
* ciphers the user has provided.
|
||||
*/
|
||||
ciphers13 = SSL_CONN_CONFIG(cipher_list13);
|
||||
if(ciphers13) {
|
||||
const int remaining_ciphers = 5;
|
||||
|
||||
/* detect which remaining ciphers to enable
|
||||
and then disable everything else.
|
||||
*/
|
||||
|
||||
char *startCur = ciphers13;
|
||||
int algCount = 0;
|
||||
char tmp[LONGEST_ALG_ID] = { 0 };
|
||||
char *nameEnd;
|
||||
size_t n;
|
||||
|
||||
disable_aes_gcm_sha384 = TRUE;
|
||||
disable_aes_gcm_sha256 = TRUE;
|
||||
disable_chacha_poly = TRUE;
|
||||
disable_aes_ccm_8_sha256 = TRUE;
|
||||
disable_aes_ccm_sha256 = TRUE;
|
||||
|
||||
while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
|
||||
nameEnd = strchr(startCur, ':');
|
||||
n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
|
||||
|
||||
/* reject too-long cipher names */
|
||||
if(n > (LONGEST_ALG_ID - 1)) {
|
||||
failf(data, "Cipher name too long, not checked.");
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
strncpy(tmp, startCur, n);
|
||||
tmp[n] = 0;
|
||||
|
||||
if(disable_aes_gcm_sha384
|
||||
&& !strcmp("TLS_AES_256_GCM_SHA384", tmp)) {
|
||||
disable_aes_gcm_sha384 = FALSE;
|
||||
}
|
||||
else if(disable_aes_gcm_sha256
|
||||
&& !strcmp("TLS_AES_128_GCM_SHA256", tmp)) {
|
||||
disable_aes_gcm_sha256 = FALSE;
|
||||
}
|
||||
else if(disable_chacha_poly
|
||||
&& !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) {
|
||||
disable_chacha_poly = FALSE;
|
||||
}
|
||||
else if(disable_aes_ccm_8_sha256
|
||||
&& !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) {
|
||||
disable_aes_ccm_8_sha256 = FALSE;
|
||||
}
|
||||
else if(disable_aes_ccm_sha256
|
||||
&& !strcmp("TLS_AES_128_CCM_SHA256", tmp)) {
|
||||
disable_aes_ccm_sha256 = FALSE;
|
||||
}
|
||||
else {
|
||||
failf(data, "Passed in an unknown TLS 1.3 cipher.");
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
startCur = nameEnd;
|
||||
if(startCur)
|
||||
startCur++;
|
||||
|
||||
algCount++;
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
/* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */
|
||||
if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) {
|
||||
/*
|
||||
Disallow AES_CCM algorithm.
|
||||
*/
|
||||
blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM);
|
||||
blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM);
|
||||
blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM;
|
||||
|
||||
crypto_settings[crypto_settings_idx].eAlgorithmUsage =
|
||||
TlsParametersCngAlgUsageCipher;
|
||||
crypto_settings[crypto_settings_idx].rgstrChainingModes =
|
||||
blocked_ccm_modes;
|
||||
crypto_settings[crypto_settings_idx].cChainingModes =
|
||||
ARRAYSIZE(blocked_ccm_modes);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Length =
|
||||
sizeof(BCRYPT_AES_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
|
||||
sizeof(BCRYPT_AES_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
|
||||
(PWSTR)BCRYPT_AES_ALGORITHM;
|
||||
|
||||
/* only disabling one of the CCM modes */
|
||||
if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) {
|
||||
if(disable_aes_ccm_8_sha256)
|
||||
crypto_settings[crypto_settings_idx].dwMinBitLength = 128;
|
||||
else /* disable_aes_ccm_sha256 */
|
||||
crypto_settings[crypto_settings_idx].dwMaxBitLength = 64;
|
||||
}
|
||||
|
||||
crypto_settings_idx++;
|
||||
}
|
||||
|
||||
/* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */
|
||||
if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) {
|
||||
|
||||
/*
|
||||
Disallow AES_GCM algorithm
|
||||
*/
|
||||
blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM);
|
||||
blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM);
|
||||
blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM;
|
||||
|
||||
/* if only one is disabled, then explictly disable the
|
||||
digest cipher suite (sha384 or sha256) */
|
||||
if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) {
|
||||
crypto_settings[crypto_settings_idx].eAlgorithmUsage =
|
||||
TlsParametersCngAlgUsageDigest;
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Length =
|
||||
sizeof(disable_aes_gcm_sha384 ?
|
||||
BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
|
||||
sizeof(disable_aes_gcm_sha384 ?
|
||||
BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
|
||||
(PWSTR)(disable_aes_gcm_sha384 ?
|
||||
BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
|
||||
}
|
||||
else { /* Disable both AES_GCM ciphers */
|
||||
crypto_settings[crypto_settings_idx].eAlgorithmUsage =
|
||||
TlsParametersCngAlgUsageCipher;
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Length =
|
||||
sizeof(BCRYPT_AES_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
|
||||
sizeof(BCRYPT_AES_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
|
||||
(PWSTR)BCRYPT_AES_ALGORITHM;
|
||||
}
|
||||
|
||||
crypto_settings[crypto_settings_idx].rgstrChainingModes =
|
||||
blocked_gcm_modes;
|
||||
crypto_settings[crypto_settings_idx].cChainingModes = 1;
|
||||
|
||||
crypto_settings_idx++;
|
||||
}
|
||||
|
||||
/*
|
||||
Disable ChaCha20-Poly1305.
|
||||
*/
|
||||
if(disable_chacha_poly) {
|
||||
crypto_settings[crypto_settings_idx].eAlgorithmUsage =
|
||||
TlsParametersCngAlgUsageCipher;
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Length =
|
||||
sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
|
||||
sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
|
||||
crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
|
||||
(PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
|
||||
crypto_settings_idx++;
|
||||
}
|
||||
|
||||
tls_parameters.pDisabledCrypto = crypto_settings;
|
||||
|
||||
/* The number of blocked suites */
|
||||
tls_parameters.cDisabledCrypto = crypto_settings_idx;
|
||||
credentials.pTlsParameters = &tls_parameters;
|
||||
credentials.cTlsParameters = 1;
|
||||
|
||||
credentials.dwVersion = SCH_CREDENTIALS_VERSION;
|
||||
credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
|
||||
|
||||
credentials.pTlsParameters->grbitDisabledProtocols =
|
||||
(DWORD)~enabled_protocols;
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
if(client_certs[0]) {
|
||||
credentials.cCreds = 1;
|
||||
credentials.paCred = client_certs;
|
||||
}
|
||||
#endif
|
||||
|
||||
sspi_status =
|
||||
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL,
|
||||
&credentials, NULL, NULL,
|
||||
&backend->cred->cred_handle,
|
||||
&backend->cred->time_stamp);
|
||||
}
|
||||
else {
|
||||
/* Pre-Windows 10 1809 */
|
||||
ALG_ID algIds[NUM_CIPHERS];
|
||||
char *ciphers = SSL_CONN_CONFIG(cipher_list);
|
||||
SCHANNEL_CRED schannel_cred = { 0 };
|
||||
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
schannel_cred.dwFlags = flags;
|
||||
schannel_cred.grbitEnabledProtocols = enabled_protocols;
|
||||
|
||||
if(ciphers) {
|
||||
result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
|
||||
if(CURLE_OK != result) {
|
||||
failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
|
||||
}
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
if(client_certs[0]) {
|
||||
schannel_cred.cCreds = 1;
|
||||
schannel_cred.paCred = client_certs;
|
||||
}
|
||||
#endif
|
||||
|
||||
sspi_status =
|
||||
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL,
|
||||
&schannel_cred, NULL, NULL,
|
||||
&backend->cred->cred_handle,
|
||||
&backend->cred->time_stamp);
|
||||
}
|
||||
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
if(client_certs[0])
|
||||
CertFreeCertificateContext(client_certs[0]);
|
||||
#endif
|
||||
|
||||
if(sspi_status != SEC_E_OK) {
|
||||
char buffer[STRERROR_LEN];
|
||||
@@ -1993,12 +2288,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
|
||||
infof(data, "schannel: can't renegotiate, an error is pending");
|
||||
goto cleanup;
|
||||
}
|
||||
if(backend->encdata_offset) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
infof(data, "schannel: can't renegotiate, "
|
||||
"encrypted data available");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* begin renegotiation */
|
||||
infof(data, "schannel: renegotiating SSL/TLS connection");
|
||||
connssl->state = ssl_connection_negotiating;
|
||||
@@ -2448,7 +2738,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
|
||||
#ifdef HAS_MANUAL_VERIFY_API
|
||||
SSLSUPP_CAINFO_BLOB |
|
||||
#endif
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_TLS13_CIPHERSUITES,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
|
||||
#define SCHANNEL_USE_BLACKLISTS 1
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
#endif
|
||||
#include <subauth.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
/* Wincrypt must be included before anything that could include OpenSSL. */
|
||||
#if defined(USE_WIN32_CRYPTO)
|
||||
#include <wincrypt.h>
|
||||
@@ -84,6 +94,63 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SCH_CREDENTIALS_VERSION
|
||||
|
||||
#define SCH_CREDENTIALS_VERSION 0x00000005
|
||||
|
||||
typedef enum _eTlsAlgorithmUsage
|
||||
{
|
||||
TlsParametersCngAlgUsageKeyExchange,
|
||||
TlsParametersCngAlgUsageSignature,
|
||||
TlsParametersCngAlgUsageCipher,
|
||||
TlsParametersCngAlgUsageDigest,
|
||||
TlsParametersCngAlgUsageCertSig
|
||||
} eTlsAlgorithmUsage;
|
||||
|
||||
typedef struct _CRYPTO_SETTINGS
|
||||
{
|
||||
eTlsAlgorithmUsage eAlgorithmUsage;
|
||||
UNICODE_STRING strCngAlgId;
|
||||
DWORD cChainingModes;
|
||||
PUNICODE_STRING rgstrChainingModes;
|
||||
DWORD dwMinBitLength;
|
||||
DWORD dwMaxBitLength;
|
||||
} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS;
|
||||
|
||||
typedef struct _TLS_PARAMETERS
|
||||
{
|
||||
DWORD cAlpnIds;
|
||||
PUNICODE_STRING rgstrAlpnIds;
|
||||
DWORD grbitDisabledProtocols;
|
||||
DWORD cDisabledCrypto;
|
||||
PCRYPTO_SETTINGS pDisabledCrypto;
|
||||
DWORD dwFlags;
|
||||
} TLS_PARAMETERS, * PTLS_PARAMETERS;
|
||||
|
||||
typedef struct _SCH_CREDENTIALS
|
||||
{
|
||||
DWORD dwVersion;
|
||||
DWORD dwCredFormat;
|
||||
DWORD cCreds;
|
||||
PCCERT_CONTEXT* paCred;
|
||||
HCERTSTORE hRootStore;
|
||||
|
||||
DWORD cMappers;
|
||||
struct _HMAPPER **aphMappers;
|
||||
|
||||
DWORD dwSessionLifespan;
|
||||
DWORD dwFlags;
|
||||
DWORD cTlsParameters;
|
||||
PTLS_PARAMETERS pTlsParameters;
|
||||
} SCH_CREDENTIALS, * PSCH_CREDENTIALS;
|
||||
|
||||
#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16
|
||||
|
||||
#endif
|
||||
|
||||
struct Curl_schannel_cred {
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
|
||||
Reference in New Issue
Block a user