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:
Wyatt O'Day
2022-07-22 10:45:28 -04:00
committed by Jay Satiro
parent 92179353e5
commit 8beff43559
5 changed files with 434 additions and 64 deletions

View File

@@ -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`).

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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),

View File

@@ -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;