summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/vtls/schannel.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/schannel.c')
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c74
1 files changed, 56 insertions, 18 deletions
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 5dcf5ba..f6a5d44 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -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;
@@ -807,9 +810,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
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 };
+ 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;
@@ -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;
}
}
@@ -1158,7 +1174,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
backend->cred = old_cred;
- DEBUGF(infof(data, "schannel: re-using existing credential handle"));
+ DEBUGF(infof(data, "schannel: reusing existing credential handle"));
/* increment the reference counter of the credential/session handle */
backend->cred->refcount++;
@@ -1618,10 +1634,16 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_MANUAL_VERIFY_API
if(conn_config->verifypeer && backend->use_manual_cred_validation) {
+ /* Certificate verification also verifies the hostname if verifyhost */
return Curl_verify_certificate(cf, data);
}
#endif
+ /* Verify the hostname manually when certificate verification is disabled,
+ because in that case Schannel won't verify it. */
+ if(!conn_config->verifypeer && conn_config->verifyhost)
+ return Curl_verify_host(cf, data);
+
return CURLE_OK;
}
@@ -1634,7 +1656,8 @@ valid_cert_encoding(const CERT_CONTEXT *cert_context)
(cert_context->cbCertEncoded > 0);
}
-typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
+typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context,
+ bool reverse_order, void *arg);
static void
traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
@@ -1642,19 +1665,32 @@ traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
{
const CERT_CONTEXT *current_context = NULL;
bool should_continue = true;
+ bool first = true;
+ bool reverse_order = false;
while(should_continue &&
(current_context = CertEnumCertificatesInStore(
context->hCertStore,
- current_context)) != NULL)
- should_continue = func(current_context, arg);
+ current_context)) != NULL) {
+ /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in
+ leaf-to-root order while all previous versions of Windows enumerate
+ certificates in root-to-leaf order. Determine the order of enumeration
+ by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
+ first certificate's pbCertContext. */
+ if(first && context->pbCertEncoded != current_context->pbCertEncoded)
+ reverse_order = true;
+ should_continue = func(current_context, reverse_order, arg);
+ first = false;
+ }
if(current_context)
CertFreeCertificateContext(current_context);
}
static bool
-cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
+cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
+ void *certs_count)
{
+ (void)reverse_order; /* unused */
if(valid_cert_encoding(ccert_context))
(*(int *)certs_count)++;
return true;
@@ -1669,14 +1705,16 @@ struct Adder_args
};
static bool
-add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
+add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
+ void *raw_arg)
{
struct Adder_args *args = (struct Adder_args*)raw_arg;
args->result = CURLE_OK;
if(valid_cert_encoding(ccert_context)) {
const char *beg = (const char *) ccert_context->pbCertEncoded;
const char *end = beg + ccert_context->cbCertEncoded;
- int insert_index = (args->certs_count - 1) - args->idx;
+ int insert_index = reverse_order ? (args->certs_count - 1) - args->idx :
+ args->idx;
args->result = Curl_extract_certinfo(args->data, insert_index,
beg, end);
args->idx++;
@@ -1758,7 +1796,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
- /* save the current session data for possible re-use */
+ /* save the current session data for possible reuse */
if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;