1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9 * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
10 * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
12 * This software is licensed as described in the file COPYING, which
13 * you should have received as part of this distribution. The terms
14 * are also available at https://curl.se/docs/copyright.html.
16 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 * copies of the Software, and permit persons to whom the Software is
18 * furnished to do so, under the terms of the COPYING file.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 * SPDX-License-Identifier: curl
25 ***************************************************************************/
28 * Source file for all Schannel-specific code for the TLS/SSL layer. No code
29 * but vtls.c should ever call or use these functions.
32 #include "curl_setup.h"
36 #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
38 #ifndef USE_WINDOWS_SSPI
39 # error "Can't compile SCHANNEL support without SSPI."
46 #include "connect.h" /* for the connect timeout */
48 #include "select.h" /* for the socket readiness */
49 #include "inet_pton.h" /* for IP addr SNI check */
50 #include "curl_multibyte.h"
53 #include "curl_printf.h"
55 #include "version_win32.h"
58 /* The last #include file should be: */
59 #include "curl_memory.h"
62 /* ALPN requires version 8.1 of the Windows SDK, which was
63 shipped with Visual Studio 2013, aka _MSC_VER 1800:
65 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
67 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
72 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
76 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
81 #define UNISP_NAME UNISP_NAME_W
83 #define UNISP_NAME UNISP_NAME_A
87 #ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
88 #define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
91 #ifndef BCRYPT_CHAIN_MODE_CCM
92 #define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM"
95 #ifndef BCRYPT_CHAIN_MODE_GCM
96 #define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM"
99 #ifndef BCRYPT_AES_ALGORITHM
100 #define BCRYPT_AES_ALGORITHM L"AES"
103 #ifndef BCRYPT_SHA256_ALGORITHM
104 #define BCRYPT_SHA256_ALGORITHM L"SHA256"
107 #ifndef BCRYPT_SHA384_ALGORITHM
108 #define BCRYPT_SHA384_ALGORITHM L"SHA384"
111 /* Workaround broken compilers like MinGW.
112 Return the number of elements in a statically sized array.
115 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
118 #ifdef HAS_CLIENT_CERT_PATH
120 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
122 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
126 #ifndef SP_PROT_SSL2_CLIENT
127 #define SP_PROT_SSL2_CLIENT 0x00000008
130 #ifndef SP_PROT_SSL3_CLIENT
131 #define SP_PROT_SSL3_CLIENT 0x00000008
134 #ifndef SP_PROT_TLS1_CLIENT
135 #define SP_PROT_TLS1_CLIENT 0x00000080
138 #ifndef SP_PROT_TLS1_0_CLIENT
139 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
142 #ifndef SP_PROT_TLS1_1_CLIENT
143 #define SP_PROT_TLS1_1_CLIENT 0x00000200
146 #ifndef SP_PROT_TLS1_2_CLIENT
147 #define SP_PROT_TLS1_2_CLIENT 0x00000800
150 #ifndef SP_PROT_TLS1_3_CLIENT
151 #define SP_PROT_TLS1_3_CLIENT 0x00002000
154 #ifndef SCH_USE_STRONG_CRYPTO
155 #define SCH_USE_STRONG_CRYPTO 0x00400000
158 #ifndef SECBUFFER_ALERT
159 #define SECBUFFER_ALERT 17
162 /* Both schannel buffer sizes must be > 0 */
163 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
164 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
166 #define CERT_THUMBPRINT_STR_LEN 40
167 #define CERT_THUMBPRINT_DATA_LEN 20
169 /* Uncomment to force verbose output
170 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
171 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
175 # define CALG_SHA_256 0x0000800c
178 /* Work around typo in classic MinGW's w32api up to version 5.0,
179 see https://osdn.net/projects/mingw/ticket/38391 */
180 #if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH)
181 #define ALG_CLASS_DHASH ALG_CLASS_HASH
184 #ifndef PKCS12_NO_PERSIST_KEY
185 #define PKCS12_NO_PERSIST_KEY 0x00008000
188 static Curl_recv schannel_recv;
189 static Curl_send schannel_send;
191 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
192 struct connectdata *conn, int sockindex,
193 const char *pinnedpubkey);
195 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
196 void *BufDataPtr, unsigned long BufByteSize)
198 buffer->cbBuffer = BufByteSize;
199 buffer->BufferType = BufType;
200 buffer->pvBuffer = BufDataPtr;
203 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
204 unsigned long NumArrElem)
206 desc->ulVersion = SECBUFFER_VERSION;
207 desc->pBuffers = BufArr;
208 desc->cBuffers = NumArrElem;
212 set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
213 struct connectdata *conn)
215 long ssl_version = SSL_CONN_CONFIG(version);
216 long ssl_version_max = SSL_CONN_CONFIG(version_max);
217 long i = ssl_version;
219 switch(ssl_version_max) {
220 case CURL_SSLVERSION_MAX_NONE:
221 case CURL_SSLVERSION_MAX_DEFAULT:
223 #if 0 /* Disabled in CMake due to issue 24147 (curl issue 9431) */
224 /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3
225 built-in. Previous builds of Windows 10 had broken TLS 1.3
226 implementations that could be enabled via registry.
228 if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
229 VERSION_GREATER_THAN_EQUAL)) {
230 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
232 else /* Windows 10 and older */
234 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
239 for(; i <= (ssl_version_max >> 16); ++i) {
241 case CURL_SSLVERSION_TLSv1_0:
242 (*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT;
244 case CURL_SSLVERSION_TLSv1_1:
245 (*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT;
247 case CURL_SSLVERSION_TLSv1_2:
248 (*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT;
250 case CURL_SSLVERSION_TLSv1_3:
252 #if 0 /* Disabled in CMake due to issue 24147 (curl issue 9431) */
253 /* Windows Server 2022 and newer */
254 if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
255 VERSION_GREATER_THAN_EQUAL)) {
256 (*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT;
259 else { /* Windows 10 and older */
260 failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11");
261 return CURLE_SSL_CONNECT_ERROR;
264 failf(data, "schannel: TLS 1.3 is not yet supported");
265 return CURLE_SSL_CONNECT_ERROR;
272 /*longest is 26, buffer is slightly bigger*/
273 #define LONGEST_ALG_ID 32
274 #define CIPHEROPTION(X) \
275 if(strcmp(#X, tmp) == 0) \
279 get_alg_id_by_name(char *name)
281 char tmp[LONGEST_ALG_ID] = { 0 };
282 char *nameEnd = strchr(name, ':');
283 size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
285 /* reject too-long alg names */
286 if(n > (LONGEST_ALG_ID - 1))
289 strncpy(tmp, name, n);
291 CIPHEROPTION(CALG_MD2);
292 CIPHEROPTION(CALG_MD4);
293 CIPHEROPTION(CALG_MD5);
294 CIPHEROPTION(CALG_SHA);
295 CIPHEROPTION(CALG_SHA1);
296 CIPHEROPTION(CALG_MAC);
297 CIPHEROPTION(CALG_RSA_SIGN);
298 CIPHEROPTION(CALG_DSS_SIGN);
299 /*ifdefs for the options that are defined conditionally in wincrypt.h*/
301 CIPHEROPTION(CALG_NO_SIGN);
303 CIPHEROPTION(CALG_RSA_KEYX);
304 CIPHEROPTION(CALG_DES);
306 CIPHEROPTION(CALG_3DES_112);
308 CIPHEROPTION(CALG_3DES);
309 CIPHEROPTION(CALG_DESX);
310 CIPHEROPTION(CALG_RC2);
311 CIPHEROPTION(CALG_RC4);
312 CIPHEROPTION(CALG_SEAL);
314 CIPHEROPTION(CALG_DH_SF);
316 CIPHEROPTION(CALG_DH_EPHEM);
317 #ifdef CALG_AGREEDKEY_ANY
318 CIPHEROPTION(CALG_AGREEDKEY_ANY);
320 #ifdef CALG_HUGHES_MD5
321 CIPHEROPTION(CALG_HUGHES_MD5);
323 CIPHEROPTION(CALG_SKIPJACK);
325 CIPHEROPTION(CALG_TEK);
327 CIPHEROPTION(CALG_CYLINK_MEK);
328 CIPHEROPTION(CALG_SSL3_SHAMD5);
329 #ifdef CALG_SSL3_MASTER
330 CIPHEROPTION(CALG_SSL3_MASTER);
332 #ifdef CALG_SCHANNEL_MASTER_HASH
333 CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
335 #ifdef CALG_SCHANNEL_MAC_KEY
336 CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
338 #ifdef CALG_SCHANNEL_ENC_KEY
339 CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
341 #ifdef CALG_PCT1_MASTER
342 CIPHEROPTION(CALG_PCT1_MASTER);
344 #ifdef CALG_SSL2_MASTER
345 CIPHEROPTION(CALG_SSL2_MASTER);
347 #ifdef CALG_TLS1_MASTER
348 CIPHEROPTION(CALG_TLS1_MASTER);
351 CIPHEROPTION(CALG_RC5);
354 CIPHEROPTION(CALG_HMAC);
357 CIPHEROPTION(CALG_TLS1PRF);
359 #ifdef CALG_HASH_REPLACE_OWF
360 CIPHEROPTION(CALG_HASH_REPLACE_OWF);
363 CIPHEROPTION(CALG_AES_128);
366 CIPHEROPTION(CALG_AES_192);
369 CIPHEROPTION(CALG_AES_256);
372 CIPHEROPTION(CALG_AES);
375 CIPHEROPTION(CALG_SHA_256);
378 CIPHEROPTION(CALG_SHA_384);
381 CIPHEROPTION(CALG_SHA_512);
384 CIPHEROPTION(CALG_ECDH);
387 CIPHEROPTION(CALG_ECMQV);
390 CIPHEROPTION(CALG_ECDSA);
392 #ifdef CALG_ECDH_EPHEM
393 CIPHEROPTION(CALG_ECDH_EPHEM);
398 #define NUM_CIPHERS 47 /* There are 47 options listed above */
401 set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
404 char *startCur = ciphers;
406 while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
407 long alg = strtol(startCur, 0, 0);
409 alg = get_alg_id_by_name(startCur);
411 algIds[algCount++] = alg;
412 else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
413 sizeof("USE_STRONG_CRYPTO") - 1) ||
414 !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
415 sizeof("SCH_USE_STRONG_CRYPTO") - 1))
416 schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
418 return CURLE_SSL_CIPHER;
419 startCur = strchr(startCur, ':');
423 schannel_cred->palgSupportedAlgs = algIds;
424 schannel_cred->cSupportedAlgs = algCount;
428 #ifdef HAS_CLIENT_CERT_PATH
430 /* Function allocates memory for store_path only if CURLE_OK is returned */
432 get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
436 TCHAR *store_path_start;
437 size_t store_name_len;
439 sep = _tcschr(path, TEXT('\\'));
441 return CURLE_SSL_CERTPROBLEM;
443 store_name_len = sep - path;
445 if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
446 *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
447 else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
448 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
449 else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
450 *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
451 else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
452 *store_name = CERT_SYSTEM_STORE_SERVICES;
453 else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
454 *store_name = CERT_SYSTEM_STORE_USERS;
455 else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
456 store_name_len) == 0)
457 *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
458 else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
459 store_name_len) == 0)
460 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
461 else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
462 store_name_len) == 0)
463 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
465 return CURLE_SSL_CERTPROBLEM;
467 store_path_start = sep + 1;
469 sep = _tcschr(store_path_start, TEXT('\\'));
471 return CURLE_SSL_CERTPROBLEM;
473 *thumbprint = sep + 1;
474 if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
475 return CURLE_SSL_CERTPROBLEM;
478 *store_path = _tcsdup(store_path_start);
481 return CURLE_OUT_OF_MEMORY;
487 schannel_acquire_credential_handle(struct Curl_easy *data,
488 struct connectdata *conn,
491 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
493 #ifdef HAS_CLIENT_CERT_PATH
494 PCCERT_CONTEXT client_certs[1] = { NULL };
495 HCERTSTORE client_cert_store = NULL;
497 SECURITY_STATUS sspi_status = SEC_E_OK;
500 /* setup Schannel API options */
502 DWORD enabled_protocols = 0;
504 struct ssl_backend_data *backend = connssl->backend;
506 DEBUGASSERT(backend);
508 if(conn->ssl_config.verifypeer) {
509 #ifdef HAS_MANUAL_VERIFY_API
510 if(backend->use_manual_cred_validation)
511 flags = SCH_CRED_MANUAL_CRED_VALIDATION;
514 flags = SCH_CRED_AUTO_CRED_VALIDATION;
516 if(SSL_SET_OPTION(no_revoke)) {
517 flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
518 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
520 DEBUGF(infof(data, "schannel: disabled server certificate revocation "
523 else if(SSL_SET_OPTION(revoke_best_effort)) {
524 flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
525 SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
527 DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
530 flags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
533 "schannel: checking server certificate revocation"));
537 flags = SCH_CRED_MANUAL_CRED_VALIDATION |
538 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
539 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
541 "schannel: disabled server cert revocation checks"));
544 if(!conn->ssl_config.verifyhost) {
545 flags |= SCH_CRED_NO_SERVERNAME_CHECK;
546 DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
547 "comparing the supplied target name with the subject "
548 "names in server certificates."));
551 if(!SSL_SET_OPTION(auto_client_cert)) {
552 flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
553 flags |= SCH_CRED_NO_DEFAULT_CREDS;
554 infof(data, "schannel: disabled automatic use of client certificate");
557 infof(data, "schannel: enabled automatic use of client certificate");
559 switch(conn->ssl_config.version) {
560 case CURL_SSLVERSION_DEFAULT:
561 case CURL_SSLVERSION_TLSv1:
562 case CURL_SSLVERSION_TLSv1_0:
563 case CURL_SSLVERSION_TLSv1_1:
564 case CURL_SSLVERSION_TLSv1_2:
565 case CURL_SSLVERSION_TLSv1_3:
567 result = set_ssl_version_min_max(&enabled_protocols, data, conn);
568 if(result != CURLE_OK)
572 case CURL_SSLVERSION_SSLv3:
573 case CURL_SSLVERSION_SSLv2:
574 failf(data, "SSL versions not supported");
575 return CURLE_NOT_BUILT_IN;
577 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
578 return CURLE_SSL_CONNECT_ERROR;
581 #ifdef HAS_CLIENT_CERT_PATH
582 /* client certificate */
583 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
584 DWORD cert_store_name = 0;
585 TCHAR *cert_store_path = NULL;
586 TCHAR *cert_thumbprint_str = NULL;
587 CRYPT_HASH_BLOB cert_thumbprint;
588 BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
589 HCERTSTORE cert_store = NULL;
590 FILE *fInCert = NULL;
591 void *certdata = NULL;
593 bool blob = data->set.ssl.primary.cert_blob != NULL;
594 TCHAR *cert_path = NULL;
596 certdata = data->set.ssl.primary.cert_blob->data;
597 certsize = data->set.ssl.primary.cert_blob->len;
600 cert_path = curlx_convert_UTF8_to_tchar(
601 data->set.ssl.primary.clientcert);
603 return CURLE_OUT_OF_MEMORY;
605 result = get_cert_location(cert_path, &cert_store_name,
606 &cert_store_path, &cert_thumbprint_str);
608 if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
609 fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
611 if(result && !fInCert) {
612 failf(data, "schannel: Failed to get certificate location"
614 data->set.ssl.primary.clientcert);
615 curlx_unicodefree(cert_path);
620 if((fInCert || blob) && (data->set.ssl.cert_type) &&
621 (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
622 failf(data, "schannel: certificate format compatibility error "
624 blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
625 curlx_unicodefree(cert_path);
626 return CURLE_SSL_CERTPROBLEM;
629 if(fInCert || blob) {
630 /* Reading a .P12 or .pfx file, like the example at bottom of
631 https://social.msdn.microsoft.com/Forums/windowsdesktop/
632 en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
634 CRYPT_DATA_BLOB datablob;
638 const char *cert_showfilename_error = blob ?
639 "(memory blob)" : data->set.ssl.primary.clientcert;
640 curlx_unicodefree(cert_path);
643 bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
645 cert_tell = ftell(fInCert);
647 continue_reading = FALSE;
649 certsize = (size_t)cert_tell;
651 continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
653 certdata = malloc(certsize + 1);
655 ((int) fread(certdata, certsize, 1, fInCert) != 1))
656 continue_reading = FALSE;
658 if(!continue_reading) {
659 failf(data, "schannel: Failed to read cert file %s",
660 data->set.ssl.primary.clientcert);
662 return CURLE_SSL_CERTPROBLEM;
666 /* Convert key-pair data to the in-memory certificate store */
667 datablob.pbData = (BYTE*)certdata;
668 datablob.cbData = (DWORD)certsize;
670 if(data->set.ssl.key_passwd)
671 pwd_len = strlen(data->set.ssl.key_passwd);
672 pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
675 str_w_len = MultiByteToWideChar(CP_UTF8,
676 MB_ERR_INVALID_CHARS,
677 data->set.ssl.key_passwd,
679 pszPassword, (int)(pwd_len + 1));
681 if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
682 pszPassword[str_w_len] = 0;
686 if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
687 VERSION_GREATER_THAN_EQUAL))
688 cert_store = PFXImportCertStore(&datablob, pszPassword,
689 PKCS12_NO_PERSIST_KEY);
691 cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
698 DWORD errorcode = GetLastError();
699 if(errorcode == ERROR_INVALID_PASSWORD)
700 failf(data, "schannel: Failed to import cert file %s, "
702 cert_showfilename_error);
704 failf(data, "schannel: Failed to import cert file %s, "
705 "last error is 0x%x",
706 cert_showfilename_error, errorcode);
707 return CURLE_SSL_CERTPROBLEM;
710 client_certs[0] = CertFindCertificateInStore(
711 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
712 CERT_FIND_ANY, NULL, NULL);
714 if(!client_certs[0]) {
715 failf(data, "schannel: Failed to get certificate from file %s"
716 ", last error is 0x%x",
717 cert_showfilename_error, GetLastError());
718 CertCloseStore(cert_store, 0);
719 return CURLE_SSL_CERTPROBLEM;
724 CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
726 CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
729 failf(data, "schannel: Failed to open cert store %x %s, "
730 "last error is 0x%x",
731 cert_store_name, cert_store_path, GetLastError());
732 free(cert_store_path);
733 curlx_unicodefree(cert_path);
734 return CURLE_SSL_CERTPROBLEM;
736 free(cert_store_path);
738 cert_thumbprint.pbData = cert_thumbprint_data;
739 cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
741 if(!CryptStringToBinary(cert_thumbprint_str,
742 CERT_THUMBPRINT_STR_LEN,
744 cert_thumbprint_data,
745 &cert_thumbprint.cbData,
747 curlx_unicodefree(cert_path);
748 CertCloseStore(cert_store, 0);
749 return CURLE_SSL_CERTPROBLEM;
752 client_certs[0] = CertFindCertificateInStore(
753 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
754 CERT_FIND_HASH, &cert_thumbprint, NULL);
756 curlx_unicodefree(cert_path);
758 if(!client_certs[0]) {
759 /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
760 CertCloseStore(cert_store, 0);
761 return CURLE_SSL_CERTPROBLEM;
764 client_cert_store = cert_store;
767 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
768 failf(data, "schannel: client cert support not built in");
769 return CURLE_NOT_BUILT_IN;
773 /* allocate memory for the re-usable credential handle */
774 backend->cred = (struct Curl_schannel_cred *)
775 calloc(1, sizeof(struct Curl_schannel_cred));
777 failf(data, "schannel: unable to allocate memory");
779 #ifdef HAS_CLIENT_CERT_PATH
781 CertFreeCertificateContext(client_certs[0]);
782 if(client_cert_store)
783 CertCloseStore(client_cert_store, 0);
786 return CURLE_OUT_OF_MEMORY;
788 backend->cred->refcount = 1;
790 #ifdef HAS_CLIENT_CERT_PATH
791 /* Since we did not persist the key, we need to extend the store's
792 * lifetime until the end of the connection
794 backend->cred->client_cert_store = client_cert_store;
797 /* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */
798 if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
799 VERSION_GREATER_THAN_EQUAL)) {
803 bool disable_aes_gcm_sha384 = FALSE;
804 bool disable_aes_gcm_sha256 = FALSE;
805 bool disable_chacha_poly = FALSE;
806 bool disable_aes_ccm_8_sha256 = FALSE;
807 bool disable_aes_ccm_sha256 = FALSE;
809 SCH_CREDENTIALS credentials = { 0 };
810 TLS_PARAMETERS tls_parameters = { 0 };
811 CRYPTO_SETTINGS crypto_settings[4] = { 0 };
812 UNICODE_STRING blocked_ccm_modes[1] = { 0 };
813 UNICODE_STRING blocked_gcm_modes[1] = { 0 };
815 int crypto_settings_idx = 0;
818 /* If TLS 1.3 ciphers are explicitly listed, then
819 * disable all the ciphers and re-enable which
820 * ciphers the user has provided.
822 ciphers13 = SSL_CONN_CONFIG(cipher_list13);
824 const int remaining_ciphers = 5;
826 /* detect which remaining ciphers to enable
827 and then disable everything else.
830 char *startCur = ciphers13;
832 char tmp[LONGEST_ALG_ID] = { 0 };
836 disable_aes_gcm_sha384 = TRUE;
837 disable_aes_gcm_sha256 = TRUE;
838 disable_chacha_poly = TRUE;
839 disable_aes_ccm_8_sha256 = TRUE;
840 disable_aes_ccm_sha256 = TRUE;
842 while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
843 nameEnd = strchr(startCur, ':');
844 n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
846 /* reject too-long cipher names */
847 if(n > (LONGEST_ALG_ID - 1)) {
848 failf(data, "Cipher name too long, not checked.");
849 return CURLE_SSL_CIPHER;
852 strncpy(tmp, startCur, n);
855 if(disable_aes_gcm_sha384
856 && !strcmp("TLS_AES_256_GCM_SHA384", tmp)) {
857 disable_aes_gcm_sha384 = FALSE;
859 else if(disable_aes_gcm_sha256
860 && !strcmp("TLS_AES_128_GCM_SHA256", tmp)) {
861 disable_aes_gcm_sha256 = FALSE;
863 else if(disable_chacha_poly
864 && !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) {
865 disable_chacha_poly = FALSE;
867 else if(disable_aes_ccm_8_sha256
868 && !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) {
869 disable_aes_ccm_8_sha256 = FALSE;
871 else if(disable_aes_ccm_sha256
872 && !strcmp("TLS_AES_128_CCM_SHA256", tmp)) {
873 disable_aes_ccm_sha256 = FALSE;
876 failf(data, "Passed in an unknown TLS 1.3 cipher.");
877 return CURLE_SSL_CIPHER;
888 if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
889 && disable_chacha_poly && disable_aes_ccm_8_sha256
890 && disable_aes_ccm_sha256) {
891 failf(data, "All available TLS 1.3 ciphers were disabled.");
892 return CURLE_SSL_CIPHER;
895 /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */
896 if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) {
898 Disallow AES_CCM algorithm.
900 blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM);
901 blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM);
902 blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM;
904 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
905 TlsParametersCngAlgUsageCipher;
906 crypto_settings[crypto_settings_idx].rgstrChainingModes =
908 crypto_settings[crypto_settings_idx].cChainingModes =
909 ARRAYSIZE(blocked_ccm_modes);
910 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
911 sizeof(BCRYPT_AES_ALGORITHM);
912 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
913 sizeof(BCRYPT_AES_ALGORITHM);
914 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
915 (PWSTR)BCRYPT_AES_ALGORITHM;
917 /* only disabling one of the CCM modes */
918 if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) {
919 if(disable_aes_ccm_8_sha256)
920 crypto_settings[crypto_settings_idx].dwMinBitLength = 128;
921 else /* disable_aes_ccm_sha256 */
922 crypto_settings[crypto_settings_idx].dwMaxBitLength = 64;
925 crypto_settings_idx++;
928 /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */
929 if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) {
932 Disallow AES_GCM algorithm
934 blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM);
935 blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM);
936 blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM;
938 /* if only one is disabled, then explicitly disable the
939 digest cipher suite (sha384 or sha256) */
940 if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) {
941 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
942 TlsParametersCngAlgUsageDigest;
943 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
944 sizeof(disable_aes_gcm_sha384 ?
945 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
946 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
947 sizeof(disable_aes_gcm_sha384 ?
948 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
949 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
950 (PWSTR)(disable_aes_gcm_sha384 ?
951 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
953 else { /* Disable both AES_GCM ciphers */
954 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
955 TlsParametersCngAlgUsageCipher;
956 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
957 sizeof(BCRYPT_AES_ALGORITHM);
958 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
959 sizeof(BCRYPT_AES_ALGORITHM);
960 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
961 (PWSTR)BCRYPT_AES_ALGORITHM;
964 crypto_settings[crypto_settings_idx].rgstrChainingModes =
966 crypto_settings[crypto_settings_idx].cChainingModes = 1;
968 crypto_settings_idx++;
972 Disable ChaCha20-Poly1305.
974 if(disable_chacha_poly) {
975 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
976 TlsParametersCngAlgUsageCipher;
977 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
978 sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
979 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
980 sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
981 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
982 (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
983 crypto_settings_idx++;
986 tls_parameters.pDisabledCrypto = crypto_settings;
988 /* The number of blocked suites */
989 tls_parameters.cDisabledCrypto = crypto_settings_idx;
990 credentials.pTlsParameters = &tls_parameters;
991 credentials.cTlsParameters = 1;
993 credentials.dwVersion = SCH_CREDENTIALS_VERSION;
994 credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
996 credentials.pTlsParameters->grbitDisabledProtocols =
997 (DWORD)~enabled_protocols;
999 #ifdef HAS_CLIENT_CERT_PATH
1000 if(client_certs[0]) {
1001 credentials.cCreds = 1;
1002 credentials.paCred = client_certs;
1007 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
1008 SECPKG_CRED_OUTBOUND, NULL,
1009 &credentials, NULL, NULL,
1010 &backend->cred->cred_handle,
1011 &backend->cred->time_stamp);
1014 /* Pre-Windows 10 1809 */
1015 ALG_ID algIds[NUM_CIPHERS];
1016 char *ciphers = SSL_CONN_CONFIG(cipher_list);
1017 SCHANNEL_CRED schannel_cred = { 0 };
1018 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
1019 schannel_cred.dwFlags = flags;
1020 schannel_cred.grbitEnabledProtocols = enabled_protocols;
1023 result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
1024 if(CURLE_OK != result) {
1025 failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
1030 schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
1033 #ifdef HAS_CLIENT_CERT_PATH
1034 if(client_certs[0]) {
1035 schannel_cred.cCreds = 1;
1036 schannel_cred.paCred = client_certs;
1041 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
1042 SECPKG_CRED_OUTBOUND, NULL,
1043 &schannel_cred, NULL, NULL,
1044 &backend->cred->cred_handle,
1045 &backend->cred->time_stamp);
1048 #ifdef HAS_CLIENT_CERT_PATH
1050 CertFreeCertificateContext(client_certs[0]);
1053 if(sspi_status != SEC_E_OK) {
1054 char buffer[STRERROR_LEN];
1055 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
1056 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1057 Curl_safefree(backend->cred);
1058 switch(sspi_status) {
1059 case SEC_E_INSUFFICIENT_MEMORY:
1060 return CURLE_OUT_OF_MEMORY;
1061 case SEC_E_NO_CREDENTIALS:
1062 case SEC_E_SECPKG_NOT_FOUND:
1063 case SEC_E_NOT_OWNER:
1064 case SEC_E_UNKNOWN_CREDENTIALS:
1065 case SEC_E_INTERNAL_ERROR:
1067 return CURLE_SSL_CONNECT_ERROR;
1075 schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
1078 ssize_t written = -1;
1079 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1081 SecBufferDesc outbuf_desc;
1083 SecBufferDesc inbuf_desc;
1085 unsigned char alpn_buffer[128];
1087 SECURITY_STATUS sspi_status = SEC_E_OK;
1088 struct Curl_schannel_cred *old_cred = NULL;
1089 struct in_addr addr;
1091 struct in6_addr addr6;
1094 char * const hostname = SSL_HOST_NAME();
1095 struct ssl_backend_data *backend = connssl->backend;
1097 DEBUGASSERT(backend);
1100 "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
1101 hostname, conn->remote_port));
1103 if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
1104 VERSION_LESS_THAN_EQUAL)) {
1105 /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
1106 algorithms that may not be supported by all servers. */
1107 infof(data, "schannel: Windows version is old and may not be able to "
1108 "connect to some servers due to lack of SNI, algorithms, etc.");
1112 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
1113 Also it doesn't seem to be supported for Wine, see curl bug #983. */
1114 backend->use_alpn = conn->bits.tls_enable_alpn &&
1115 !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
1116 "wine_get_version") &&
1117 curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
1118 VERSION_GREATER_THAN_EQUAL);
1120 backend->use_alpn = false;
1124 #ifdef HAS_MANUAL_VERIFY_API
1125 /* certificate validation on CE doesn't seem to work right; we'll
1126 * do it following a more manual process. */
1127 backend->use_manual_cred_validation = true;
1129 #error "compiler too old to support requisite manual cert verify for Win CE"
1132 #ifdef HAS_MANUAL_VERIFY_API
1133 if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
1134 if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
1135 VERSION_GREATER_THAN_EQUAL)) {
1136 backend->use_manual_cred_validation = true;
1139 failf(data, "schannel: this version of Windows is too old to support "
1140 "certificate verification via CA bundle file.");
1141 return CURLE_SSL_CACERT_BADFILE;
1145 backend->use_manual_cred_validation = false;
1147 if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
1148 failf(data, "schannel: CA cert support not built in");
1149 return CURLE_NOT_BUILT_IN;
1154 backend->cred = NULL;
1156 /* check for an existing re-usable credential handle */
1157 if(SSL_SET_OPTION(primary.sessionid)) {
1158 Curl_ssl_sessionid_lock(data);
1159 if(!Curl_ssl_getsessionid(data, conn,
1160 SSL_IS_PROXY() ? TRUE : FALSE,
1161 (void **)&old_cred, NULL, sockindex)) {
1162 backend->cred = old_cred;
1163 DEBUGF(infof(data, "schannel: re-using existing credential handle"));
1165 /* increment the reference counter of the credential/session handle */
1166 backend->cred->refcount++;
1168 "schannel: incremented credential handle refcount = %d",
1169 backend->cred->refcount));
1171 Curl_ssl_sessionid_unlock(data);
1174 if(!backend->cred) {
1176 result = schannel_acquire_credential_handle(data, conn, sockindex);
1177 if(result != CURLE_OK) {
1180 /* A hostname associated with the credential is needed by
1181 InitializeSecurityContext for SNI and other reasons. */
1182 snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
1184 failf(data, "Failed to set SNI");
1185 return CURLE_SSL_CONNECT_ERROR;
1187 backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
1188 if(!backend->cred->sni_hostname)
1189 return CURLE_OUT_OF_MEMORY;
1192 /* Warn if SNI is disabled due to use of an IP address */
1193 if(Curl_inet_pton(AF_INET, hostname, &addr)
1195 || Curl_inet_pton(AF_INET6, hostname, &addr6)
1198 infof(data, "schannel: using IP address, SNI is not supported by OS.");
1202 if(backend->use_alpn) {
1204 int list_start_index = 0;
1205 unsigned int *extension_len = NULL;
1206 unsigned short* list_len = NULL;
1208 /* The first four bytes will be an unsigned int indicating number
1209 of bytes of data in the rest of the buffer. */
1210 extension_len = (unsigned int *)(&alpn_buffer[cur]);
1211 cur += sizeof(unsigned int);
1213 /* The next four bytes are an indicator that this buffer will contain
1214 ALPN data, as opposed to NPN, for example. */
1215 *(unsigned int *)&alpn_buffer[cur] =
1216 SecApplicationProtocolNegotiationExt_ALPN;
1217 cur += sizeof(unsigned int);
1219 /* The next two bytes will be an unsigned short indicating the number
1220 of bytes used to list the preferred protocols. */
1221 list_len = (unsigned short*)(&alpn_buffer[cur]);
1222 cur += sizeof(unsigned short);
1224 list_start_index = cur;
1227 if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
1228 alpn_buffer[cur++] = ALPN_H2_LENGTH;
1229 memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
1230 cur += ALPN_H2_LENGTH;
1231 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
1235 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
1236 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
1237 cur += ALPN_HTTP_1_1_LENGTH;
1238 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
1240 *list_len = curlx_uitous(cur - list_start_index);
1241 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
1243 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
1244 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1247 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1248 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1250 #else /* HAS_ALPN */
1251 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1252 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1255 /* setup output buffer */
1256 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1257 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1259 /* security request flags */
1260 backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1261 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
1264 if(!SSL_SET_OPTION(auto_client_cert)) {
1265 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1268 /* allocate memory for the security context handle */
1269 backend->ctxt = (struct Curl_schannel_ctxt *)
1270 calloc(1, sizeof(struct Curl_schannel_ctxt));
1271 if(!backend->ctxt) {
1272 failf(data, "schannel: unable to allocate memory");
1273 return CURLE_OUT_OF_MEMORY;
1276 /* Schannel InitializeSecurityContext:
1277 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
1279 At the moment we don't pass inbuf unless we're using ALPN since we only
1280 use it for that, and Wine (for which we currently disable ALPN) is giving
1281 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
1283 sspi_status = s_pSecFn->InitializeSecurityContext(
1284 &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
1285 backend->req_flags, 0, 0,
1286 (backend->use_alpn ? &inbuf_desc : NULL),
1287 0, &backend->ctxt->ctxt_handle,
1288 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1290 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
1291 char buffer[STRERROR_LEN];
1292 Curl_safefree(backend->ctxt);
1293 switch(sspi_status) {
1294 case SEC_E_INSUFFICIENT_MEMORY:
1295 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1296 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1297 return CURLE_OUT_OF_MEMORY;
1298 case SEC_E_WRONG_PRINCIPAL:
1299 failf(data, "schannel: SNI or certificate check failed: %s",
1300 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1301 return CURLE_PEER_FAILED_VERIFICATION;
1303 case SEC_E_INVALID_HANDLE:
1304 case SEC_E_INVALID_TOKEN:
1305 case SEC_E_LOGON_DENIED:
1306 case SEC_E_TARGET_UNKNOWN:
1307 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1308 case SEC_E_INTERNAL_ERROR:
1309 case SEC_E_NO_CREDENTIALS:
1310 case SEC_E_UNSUPPORTED_FUNCTION:
1311 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1314 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1315 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1316 return CURLE_SSL_CONNECT_ERROR;
1320 DEBUGF(infof(data, "schannel: sending initial handshake data: "
1321 "sending %lu bytes.", outbuf.cbBuffer));
1323 /* send initial handshake data which is now stored in output buffer */
1324 result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
1325 outbuf.cbBuffer, &written);
1326 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1327 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1328 failf(data, "schannel: failed to send initial handshake data: "
1329 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
1330 return CURLE_SSL_CONNECT_ERROR;
1333 DEBUGF(infof(data, "schannel: sent initial handshake data: "
1334 "sent %zd bytes", written));
1336 backend->recv_unrecoverable_err = CURLE_OK;
1337 backend->recv_sspi_close_notify = false;
1338 backend->recv_connection_closed = false;
1339 backend->recv_renegotiating = false;
1340 backend->encdata_is_incomplete = false;
1342 /* continue to second handshake step */
1343 connssl->connecting_state = ssl_connect_2;
1349 schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
1353 ssize_t nread = -1, written = -1;
1354 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1355 unsigned char *reallocated_buffer;
1356 SecBuffer outbuf[3];
1357 SecBufferDesc outbuf_desc;
1359 SecBufferDesc inbuf_desc;
1360 SECURITY_STATUS sspi_status = SEC_E_OK;
1363 const char *pubkey_ptr;
1364 struct ssl_backend_data *backend = connssl->backend;
1366 DEBUGASSERT(backend);
1368 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1371 "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
1372 SSL_HOST_NAME(), conn->remote_port));
1374 if(!backend->cred || !backend->ctxt)
1375 return CURLE_SSL_CONNECT_ERROR;
1377 /* buffer to store previously received and decrypted data */
1378 if(!backend->decdata_buffer) {
1379 backend->decdata_offset = 0;
1380 backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1381 backend->decdata_buffer = malloc(backend->decdata_length);
1382 if(!backend->decdata_buffer) {
1383 failf(data, "schannel: unable to allocate memory");
1384 return CURLE_OUT_OF_MEMORY;
1388 /* buffer to store previously received and encrypted data */
1389 if(!backend->encdata_buffer) {
1390 backend->encdata_is_incomplete = false;
1391 backend->encdata_offset = 0;
1392 backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1393 backend->encdata_buffer = malloc(backend->encdata_length);
1394 if(!backend->encdata_buffer) {
1395 failf(data, "schannel: unable to allocate memory");
1396 return CURLE_OUT_OF_MEMORY;
1400 /* if we need a bigger buffer to read a full message, increase buffer now */
1401 if(backend->encdata_length - backend->encdata_offset <
1402 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1403 /* increase internal encrypted data buffer */
1404 size_t reallocated_length = backend->encdata_offset +
1405 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1406 reallocated_buffer = realloc(backend->encdata_buffer,
1407 reallocated_length);
1409 if(!reallocated_buffer) {
1410 failf(data, "schannel: unable to re-allocate memory");
1411 return CURLE_OUT_OF_MEMORY;
1414 backend->encdata_buffer = reallocated_buffer;
1415 backend->encdata_length = reallocated_length;
1421 /* read encrypted handshake data from socket */
1422 result = Curl_read_plain(conn->sock[sockindex],
1423 (char *) (backend->encdata_buffer +
1424 backend->encdata_offset),
1425 backend->encdata_length -
1426 backend->encdata_offset,
1428 if(result == CURLE_AGAIN) {
1429 if(connssl->connecting_state != ssl_connect_2_writing)
1430 connssl->connecting_state = ssl_connect_2_reading;
1431 DEBUGF(infof(data, "schannel: failed to receive handshake, "
1435 else if((result != CURLE_OK) || (nread == 0)) {
1436 failf(data, "schannel: failed to receive handshake, "
1437 "SSL/TLS connection failed");
1438 return CURLE_SSL_CONNECT_ERROR;
1441 /* increase encrypted data buffer offset */
1442 backend->encdata_offset += nread;
1443 backend->encdata_is_incomplete = false;
1444 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1448 "schannel: encrypted data buffer: offset %zu length %zu",
1449 backend->encdata_offset, backend->encdata_length));
1451 /* setup input buffers */
1452 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
1453 curlx_uztoul(backend->encdata_offset));
1454 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1455 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1457 /* setup output buffers */
1458 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1459 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1460 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1461 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1463 if(!inbuf[0].pvBuffer) {
1464 failf(data, "schannel: unable to allocate memory");
1465 return CURLE_OUT_OF_MEMORY;
1468 /* copy received handshake data into input buffer */
1469 memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
1470 backend->encdata_offset);
1472 sspi_status = s_pSecFn->InitializeSecurityContext(
1473 &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
1474 backend->cred->sni_hostname, backend->req_flags,
1475 0, 0, &inbuf_desc, 0, NULL,
1476 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1478 /* free buffer for received handshake data */
1479 Curl_safefree(inbuf[0].pvBuffer);
1481 /* check if the handshake was incomplete */
1482 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1483 backend->encdata_is_incomplete = true;
1484 connssl->connecting_state = ssl_connect_2_reading;
1486 "schannel: received incomplete message, need more data"));
1490 /* If the server has requested a client certificate, attempt to continue
1491 the handshake without one. This will allow connections to servers which
1492 request a client certificate but do not require it. */
1493 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1494 !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1495 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1496 connssl->connecting_state = ssl_connect_2_writing;
1498 "schannel: a client certificate has been requested"));
1502 /* check if the handshake needs to be continued */
1503 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1504 for(i = 0; i < 3; i++) {
1505 /* search for handshake tokens that need to be send */
1506 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1507 DEBUGF(infof(data, "schannel: sending next handshake data: "
1508 "sending %lu bytes.", outbuf[i].cbBuffer));
1510 /* send handshake token to server */
1511 result = Curl_write_plain(data, conn->sock[sockindex],
1512 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1514 if((result != CURLE_OK) ||
1515 (outbuf[i].cbBuffer != (size_t) written)) {
1516 failf(data, "schannel: failed to send next handshake data: "
1517 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1518 return CURLE_SSL_CONNECT_ERROR;
1522 /* free obsolete buffer */
1523 if(outbuf[i].pvBuffer) {
1524 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1529 char buffer[STRERROR_LEN];
1530 switch(sspi_status) {
1531 case SEC_E_INSUFFICIENT_MEMORY:
1532 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1533 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1534 return CURLE_OUT_OF_MEMORY;
1535 case SEC_E_WRONG_PRINCIPAL:
1536 failf(data, "schannel: SNI or certificate check failed: %s",
1537 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1538 return CURLE_PEER_FAILED_VERIFICATION;
1539 case SEC_E_UNTRUSTED_ROOT:
1540 failf(data, "schannel: %s",
1541 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1542 return CURLE_PEER_FAILED_VERIFICATION;
1544 case SEC_E_INVALID_HANDLE:
1545 case SEC_E_INVALID_TOKEN:
1546 case SEC_E_LOGON_DENIED:
1547 case SEC_E_TARGET_UNKNOWN:
1548 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1549 case SEC_E_INTERNAL_ERROR:
1550 case SEC_E_NO_CREDENTIALS:
1551 case SEC_E_UNSUPPORTED_FUNCTION:
1552 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1555 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1556 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1557 return CURLE_SSL_CONNECT_ERROR;
1561 /* check if there was additional remaining encrypted data */
1562 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1563 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1564 inbuf[1].cbBuffer));
1566 There are two cases where we could be getting extra data here:
1567 1) If we're renegotiating a connection and the handshake is already
1568 complete (from the server perspective), it can encrypted app data
1569 (not handshake data) in an extra buffer at this point.
1570 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1571 connection and this extra data is part of the handshake.
1572 We should process the data immediately; waiting for the socket to
1573 be ready may fail since the server is done sending handshake data.
1575 /* check if the remaining data is less than the total amount
1576 and therefore begins after the already processed data */
1577 if(backend->encdata_offset > inbuf[1].cbBuffer) {
1578 memmove(backend->encdata_buffer,
1579 (backend->encdata_buffer + backend->encdata_offset) -
1580 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1581 backend->encdata_offset = inbuf[1].cbBuffer;
1582 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1589 backend->encdata_offset = 0;
1594 /* check if the handshake needs to be continued */
1595 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1596 connssl->connecting_state = ssl_connect_2_reading;
1600 /* check if the handshake is complete */
1601 if(sspi_status == SEC_E_OK) {
1602 connssl->connecting_state = ssl_connect_3;
1603 DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1606 pubkey_ptr = SSL_PINNED_PUB_KEY();
1608 result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
1610 failf(data, "SSL: public key does not match pinned public key");
1615 #ifdef HAS_MANUAL_VERIFY_API
1616 if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
1617 return Curl_verify_certificate(data, conn, sockindex);
1625 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1627 return (cert_context != NULL) &&
1628 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1629 (cert_context->pbCertEncoded != NULL) &&
1630 (cert_context->cbCertEncoded > 0);
1633 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1636 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1639 const CERT_CONTEXT *current_context = NULL;
1640 bool should_continue = true;
1641 while(should_continue &&
1642 (current_context = CertEnumCertificatesInStore(
1643 context->hCertStore,
1644 current_context)) != NULL)
1645 should_continue = func(current_context, arg);
1648 CertFreeCertificateContext(current_context);
1652 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1654 if(valid_cert_encoding(ccert_context))
1655 (*(int *)certs_count)++;
1661 struct Curl_easy *data;
1668 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1670 struct Adder_args *args = (struct Adder_args*)raw_arg;
1671 args->result = CURLE_OK;
1672 if(valid_cert_encoding(ccert_context)) {
1673 const char *beg = (const char *) ccert_context->pbCertEncoded;
1674 const char *end = beg + ccert_context->cbCertEncoded;
1675 int insert_index = (args->certs_count - 1) - args->idx;
1676 args->result = Curl_extract_certinfo(args->data, insert_index,
1680 return args->result == CURLE_OK;
1684 schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
1687 CURLcode result = CURLE_OK;
1688 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1689 SECURITY_STATUS sspi_status = SEC_E_OK;
1690 CERT_CONTEXT *ccert_context = NULL;
1691 bool isproxy = SSL_IS_PROXY();
1692 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1693 const char * const hostname = SSL_HOST_NAME();
1696 SecPkgContext_ApplicationProtocol alpn_result;
1698 struct ssl_backend_data *backend = connssl->backend;
1700 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1701 DEBUGASSERT(backend);
1704 "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
1705 hostname, conn->remote_port));
1708 return CURLE_SSL_CONNECT_ERROR;
1710 /* check if the required context attributes are met */
1711 if(backend->ret_flags != backend->req_flags) {
1712 if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
1713 failf(data, "schannel: failed to setup sequence detection");
1714 if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
1715 failf(data, "schannel: failed to setup replay detection");
1716 if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
1717 failf(data, "schannel: failed to setup confidentiality");
1718 if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1719 failf(data, "schannel: failed to setup memory allocation");
1720 if(!(backend->ret_flags & ISC_RET_STREAM))
1721 failf(data, "schannel: failed to setup stream orientation");
1722 return CURLE_SSL_CONNECT_ERROR;
1726 if(backend->use_alpn) {
1728 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1729 SECPKG_ATTR_APPLICATION_PROTOCOL,
1732 if(sspi_status != SEC_E_OK) {
1733 failf(data, "schannel: failed to retrieve ALPN result");
1734 return CURLE_SSL_CONNECT_ERROR;
1737 if(alpn_result.ProtoNegoStatus ==
1738 SecApplicationProtocolNegotiationStatus_Success) {
1739 unsigned char alpn = 0;
1741 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR,
1742 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1745 if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH &&
1746 !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) {
1747 alpn = CURL_HTTP_VERSION_2;
1751 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1752 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1753 ALPN_HTTP_1_1_LENGTH)) {
1754 alpn = CURL_HTTP_VERSION_1_1;
1756 if(backend->recv_renegotiating) {
1757 if(alpn != conn->alpn) {
1758 failf(data, "schannel: server selected an ALPN protocol too late");
1759 return CURLE_SSL_CONNECT_ERROR;
1766 if(!backend->recv_renegotiating)
1767 infof(data, VTLS_INFOF_NO_ALPN);
1770 if(!backend->recv_renegotiating) {
1771 Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
1772 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1777 /* save the current session data for possible re-use */
1778 if(SSL_SET_OPTION(primary.sessionid)) {
1781 struct Curl_schannel_cred *old_cred = NULL;
1783 Curl_ssl_sessionid_lock(data);
1784 incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
1787 if(old_cred != backend->cred) {
1789 "schannel: old credential handle is stale, removing"));
1790 /* we're not taking old_cred ownership here, no refcount++ is needed */
1791 Curl_ssl_delsessionid(data, (void *)old_cred);
1796 result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
1797 sizeof(struct Curl_schannel_cred),
1800 Curl_ssl_sessionid_unlock(data);
1801 failf(data, "schannel: failed to store credential handle");
1805 /* this cred session is now also referenced by sessionid cache */
1806 backend->cred->refcount++;
1808 "schannel: stored credential handle in session cache"));
1811 Curl_ssl_sessionid_unlock(data);
1814 if(data->set.ssl.certinfo) {
1815 int certs_count = 0;
1817 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1818 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1821 if((sspi_status != SEC_E_OK) || !ccert_context) {
1822 failf(data, "schannel: failed to retrieve remote cert context");
1823 return CURLE_PEER_FAILED_VERIFICATION;
1826 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1828 result = Curl_ssl_init_certinfo(data, certs_count);
1830 struct Adder_args args;
1833 args.certs_count = certs_count;
1834 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1835 result = args.result;
1837 CertFreeCertificateContext(ccert_context);
1842 connssl->connecting_state = ssl_connect_done;
1848 schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
1849 int sockindex, bool nonblocking, bool *done)
1852 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1853 curl_socket_t sockfd = conn->sock[sockindex];
1854 timediff_t timeout_ms;
1857 /* check if the connection has already been established */
1858 if(ssl_connection_complete == connssl->state) {
1863 if(ssl_connect_1 == connssl->connecting_state) {
1864 /* check out how much more time we're allowed */
1865 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1867 if(timeout_ms < 0) {
1868 /* no need to continue if time already is up */
1869 failf(data, "SSL/TLS connection timeout");
1870 return CURLE_OPERATION_TIMEDOUT;
1873 result = schannel_connect_step1(data, conn, sockindex);
1878 while(ssl_connect_2 == connssl->connecting_state ||
1879 ssl_connect_2_reading == connssl->connecting_state ||
1880 ssl_connect_2_writing == connssl->connecting_state) {
1882 /* check out how much more time we're allowed */
1883 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1885 if(timeout_ms < 0) {
1886 /* no need to continue if time already is up */
1887 failf(data, "SSL/TLS connection timeout");
1888 return CURLE_OPERATION_TIMEDOUT;
1891 /* if ssl is expecting something, check if it's available. */
1892 if(connssl->connecting_state == ssl_connect_2_reading
1893 || connssl->connecting_state == ssl_connect_2_writing) {
1895 curl_socket_t writefd = ssl_connect_2_writing ==
1896 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1897 curl_socket_t readfd = ssl_connect_2_reading ==
1898 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1900 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1901 nonblocking ? 0 : timeout_ms);
1904 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1905 return CURLE_SSL_CONNECT_ERROR;
1907 else if(0 == what) {
1914 failf(data, "SSL/TLS connection timeout");
1915 return CURLE_OPERATION_TIMEDOUT;
1918 /* socket is readable or writable */
1921 /* Run transaction, and return to the caller if it failed or if
1922 * this connection is part of a multi handle and this loop would
1923 * execute again. This permits the owner of a multi handle to
1924 * abort a connection attempt before step2 has completed while
1925 * ensuring that a client using select() or epoll() will always
1926 * have a valid fdset to wait on.
1928 result = schannel_connect_step2(data, conn, sockindex);
1929 if(result || (nonblocking &&
1930 (ssl_connect_2 == connssl->connecting_state ||
1931 ssl_connect_2_reading == connssl->connecting_state ||
1932 ssl_connect_2_writing == connssl->connecting_state)))
1935 } /* repeat step2 until all transactions are done. */
1937 if(ssl_connect_3 == connssl->connecting_state) {
1938 result = schannel_connect_step3(data, conn, sockindex);
1943 if(ssl_connect_done == connssl->connecting_state) {
1944 connssl->state = ssl_connection_complete;
1945 if(!connssl->backend->recv_renegotiating) {
1946 /* On renegotiation, we don't want to reset the existing recv/send
1947 * function pointers. They will have been set after the initial TLS
1948 * handshake was completed. If they were subsequently modified, as
1949 * is the case with HTTP/2, we don't want to override that change.
1951 conn->recv[sockindex] = schannel_recv;
1952 conn->send[sockindex] = schannel_send;
1955 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1956 /* When SSPI is used in combination with Schannel
1957 * we need the Schannel context to create the Schannel
1958 * binding to pass the IIS extended protection checks.
1959 * Available on Windows 7 or later.
1962 struct ssl_backend_data *backend = connssl->backend;
1963 DEBUGASSERT(backend);
1964 conn->sslContext = &backend->ctxt->ctxt_handle;
1973 /* reset our connection state machine */
1974 connssl->connecting_state = ssl_connect_1;
1980 schannel_send(struct Curl_easy *data, int sockindex,
1981 const void *buf, size_t len, CURLcode *err)
1983 ssize_t written = -1;
1984 size_t data_len = 0;
1985 unsigned char *ptr = NULL;
1986 struct connectdata *conn = data->conn;
1987 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1988 SecBuffer outbuf[4];
1989 SecBufferDesc outbuf_desc;
1990 SECURITY_STATUS sspi_status = SEC_E_OK;
1992 struct ssl_backend_data *backend = connssl->backend;
1994 DEBUGASSERT(backend);
1996 /* check if the maximum stream sizes were queried */
1997 if(backend->stream_sizes.cbMaximumMessage == 0) {
1998 sspi_status = s_pSecFn->QueryContextAttributes(
1999 &backend->ctxt->ctxt_handle,
2000 SECPKG_ATTR_STREAM_SIZES,
2001 &backend->stream_sizes);
2002 if(sspi_status != SEC_E_OK) {
2003 *err = CURLE_SEND_ERROR;
2008 /* check if the buffer is longer than the maximum message length */
2009 if(len > backend->stream_sizes.cbMaximumMessage) {
2010 len = backend->stream_sizes.cbMaximumMessage;
2013 /* calculate the complete message length and allocate a buffer for it */
2014 data_len = backend->stream_sizes.cbHeader + len +
2015 backend->stream_sizes.cbTrailer;
2016 ptr = (unsigned char *) malloc(data_len);
2018 *err = CURLE_OUT_OF_MEMORY;
2022 /* setup output buffers (header, data, trailer, empty) */
2023 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
2024 ptr, backend->stream_sizes.cbHeader);
2025 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
2026 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
2027 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
2028 ptr + backend->stream_sizes.cbHeader + len,
2029 backend->stream_sizes.cbTrailer);
2030 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
2031 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
2033 /* copy data into output buffer */
2034 memcpy(outbuf[1].pvBuffer, buf, len);
2036 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
2037 sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
2040 /* check if the message was encrypted */
2041 if(sspi_status == SEC_E_OK) {
2044 /* send the encrypted message including header, data and trailer */
2045 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
2048 It's important to send the full message which includes the header,
2049 encrypted payload, and trailer. Until the client receives all the
2050 data a coherent message has not been delivered and the client
2051 can't read any of it.
2053 If we wanted to buffer the unwritten encrypted bytes, we would
2054 tell the client that all data it has requested to be sent has been
2055 sent. The unwritten encrypted bytes would be the first bytes to
2056 send on the next invocation.
2057 Here's the catch with this - if we tell the client that all the
2058 bytes have been sent, will the client call this method again to
2059 send the buffered data? Looking at who calls this function, it
2060 seems the answer is NO.
2063 /* send entire message or fail */
2064 while(len > (size_t)written) {
2065 ssize_t this_write = 0;
2067 timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
2068 if(timeout_ms < 0) {
2069 /* we already got the timeout */
2070 failf(data, "schannel: timed out sending data "
2071 "(bytes sent: %zd)", written);
2072 *err = CURLE_OPERATION_TIMEDOUT;
2076 else if(!timeout_ms)
2077 timeout_ms = TIMEDIFF_T_MAX;
2078 what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
2081 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2082 *err = CURLE_SEND_ERROR;
2086 else if(0 == what) {
2087 failf(data, "schannel: timed out sending data "
2088 "(bytes sent: %zd)", written);
2089 *err = CURLE_OPERATION_TIMEDOUT;
2093 /* socket is writable */
2095 result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
2096 len - written, &this_write);
2097 if(result == CURLE_AGAIN)
2099 else if(result != CURLE_OK) {
2105 written += this_write;
2108 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
2109 *err = CURLE_OUT_OF_MEMORY;
2112 *err = CURLE_SEND_ERROR;
2117 if(len == (size_t)written)
2118 /* Encrypted message including header, data and trailer entirely sent.
2119 The return value is the number of unencrypted bytes that were sent. */
2120 written = outbuf[1].cbBuffer;
2126 schannel_recv(struct Curl_easy *data, int sockindex,
2127 char *buf, size_t len, CURLcode *err)
2131 struct connectdata *conn = data->conn;
2132 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2133 unsigned char *reallocated_buffer;
2134 size_t reallocated_length;
2137 SecBufferDesc inbuf_desc;
2138 SECURITY_STATUS sspi_status = SEC_E_OK;
2139 /* we want the length of the encrypted buffer to be at least large enough
2140 that it can hold all the bytes requested and some TLS record overhead. */
2141 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
2142 struct ssl_backend_data *backend = connssl->backend;
2144 DEBUGASSERT(backend);
2146 /****************************************************************************
2147 * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
2148 * The pattern for return error is set *err, optional infof, goto cleanup.
2150 * Our priority is to always return as much decrypted data to the caller as
2151 * possible, even if an error occurs. The state of the decrypted buffer must
2152 * always be valid. Transfer of decrypted data to the caller's buffer is
2153 * handled in the cleanup.
2156 DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
2159 if(len && len <= backend->decdata_offset) {
2160 infof(data, "schannel: enough decrypted data is already available");
2163 else if(backend->recv_unrecoverable_err) {
2164 *err = backend->recv_unrecoverable_err;
2165 infof(data, "schannel: an unrecoverable error occurred in a prior call");
2168 else if(backend->recv_sspi_close_notify) {
2169 /* once a server has indicated shutdown there is no more encrypted data */
2170 infof(data, "schannel: server indicated shutdown in a prior call");
2174 /* It's debatable what to return when !len. Regardless we can't return
2175 immediately because there may be data to decrypt (in the case we want to
2176 decrypt all encrypted cached data) so handle !len later in cleanup.
2178 else if(len && !backend->recv_connection_closed) {
2179 /* increase enc buffer in order to fit the requested amount of data */
2180 size = backend->encdata_length - backend->encdata_offset;
2181 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2182 backend->encdata_length < min_encdata_length) {
2183 reallocated_length = backend->encdata_offset +
2184 CURL_SCHANNEL_BUFFER_FREE_SIZE;
2185 if(reallocated_length < min_encdata_length) {
2186 reallocated_length = min_encdata_length;
2188 reallocated_buffer = realloc(backend->encdata_buffer,
2189 reallocated_length);
2190 if(!reallocated_buffer) {
2191 *err = CURLE_OUT_OF_MEMORY;
2192 failf(data, "schannel: unable to re-allocate memory");
2196 backend->encdata_buffer = reallocated_buffer;
2197 backend->encdata_length = reallocated_length;
2198 size = backend->encdata_length - backend->encdata_offset;
2199 DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
2200 backend->encdata_length));
2204 "schannel: encrypted data buffer: offset %zu length %zu",
2205 backend->encdata_offset, backend->encdata_length));
2207 /* read encrypted data from socket */
2208 *err = Curl_read_plain(conn->sock[sockindex],
2209 (char *)(backend->encdata_buffer +
2210 backend->encdata_offset),
2214 if(*err == CURLE_AGAIN)
2216 "schannel: Curl_read_plain returned CURLE_AGAIN"));
2217 else if(*err == CURLE_RECV_ERROR)
2218 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
2220 infof(data, "schannel: Curl_read_plain returned error %d", *err);
2222 else if(nread == 0) {
2223 backend->recv_connection_closed = true;
2224 DEBUGF(infof(data, "schannel: server closed the connection"));
2226 else if(nread > 0) {
2227 backend->encdata_offset += (size_t)nread;
2228 backend->encdata_is_incomplete = false;
2229 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
2234 "schannel: encrypted data buffer: offset %zu length %zu",
2235 backend->encdata_offset, backend->encdata_length));
2238 while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
2239 (!len || backend->decdata_offset < len ||
2240 backend->recv_connection_closed)) {
2241 /* prepare data buffer for DecryptMessage call */
2242 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
2243 curlx_uztoul(backend->encdata_offset));
2245 /* we need 3 more empty input buffers for possible output */
2246 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
2247 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
2248 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
2249 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
2251 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
2253 sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
2254 &inbuf_desc, 0, NULL);
2256 /* check if everything went fine (server may want to renegotiate
2257 or shutdown the connection context) */
2258 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
2259 sspi_status == SEC_I_CONTEXT_EXPIRED) {
2260 /* check for successfully decrypted data, even before actual
2261 renegotiation or shutdown of the connection context */
2262 if(inbuf[1].BufferType == SECBUFFER_DATA) {
2263 DEBUGF(infof(data, "schannel: decrypted data length: %lu",
2264 inbuf[1].cbBuffer));
2266 /* increase buffer in order to fit the received amount of data */
2267 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
2268 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
2269 if(backend->decdata_length - backend->decdata_offset < size ||
2270 backend->decdata_length < len) {
2271 /* increase internal decrypted data buffer */
2272 reallocated_length = backend->decdata_offset + size;
2273 /* make sure that the requested amount of data fits */
2274 if(reallocated_length < len) {
2275 reallocated_length = len;
2277 reallocated_buffer = realloc(backend->decdata_buffer,
2278 reallocated_length);
2279 if(!reallocated_buffer) {
2280 *err = CURLE_OUT_OF_MEMORY;
2281 failf(data, "schannel: unable to re-allocate memory");
2284 backend->decdata_buffer = reallocated_buffer;
2285 backend->decdata_length = reallocated_length;
2288 /* copy decrypted data to internal buffer */
2289 size = inbuf[1].cbBuffer;
2291 memcpy(backend->decdata_buffer + backend->decdata_offset,
2292 inbuf[1].pvBuffer, size);
2293 backend->decdata_offset += size;
2296 DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
2298 "schannel: decrypted cached: offset %zu length %zu",
2299 backend->decdata_offset, backend->decdata_length));
2302 /* check for remaining encrypted data */
2303 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
2304 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
2305 inbuf[3].cbBuffer));
2307 /* check if the remaining data is less than the total amount
2308 * and therefore begins after the already processed data
2310 if(backend->encdata_offset > inbuf[3].cbBuffer) {
2311 /* move remaining encrypted data forward to the beginning of
2313 memmove(backend->encdata_buffer,
2314 (backend->encdata_buffer + backend->encdata_offset) -
2315 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
2316 backend->encdata_offset = inbuf[3].cbBuffer;
2320 "schannel: encrypted cached: offset %zu length %zu",
2321 backend->encdata_offset, backend->encdata_length));
2324 /* reset encrypted buffer offset, because there is no data remaining */
2325 backend->encdata_offset = 0;
2328 /* check if server wants to renegotiate the connection context */
2329 if(sspi_status == SEC_I_RENEGOTIATE) {
2330 infof(data, "schannel: remote party requests renegotiation");
2331 if(*err && *err != CURLE_AGAIN) {
2332 infof(data, "schannel: can't renegotiate, an error is pending");
2336 /* begin renegotiation */
2337 infof(data, "schannel: renegotiating SSL/TLS connection");
2338 connssl->state = ssl_connection_negotiating;
2339 connssl->connecting_state = ssl_connect_2_writing;
2340 backend->recv_renegotiating = true;
2341 *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
2342 backend->recv_renegotiating = false;
2344 infof(data, "schannel: renegotiation failed");
2347 /* now retry receiving data */
2348 sspi_status = SEC_E_OK;
2349 infof(data, "schannel: SSL/TLS connection renegotiated");
2352 /* check if the server closed the connection */
2353 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2354 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2355 returned so we have to work around that in cleanup. */
2356 backend->recv_sspi_close_notify = true;
2357 if(!backend->recv_connection_closed) {
2358 backend->recv_connection_closed = true;
2359 infof(data, "schannel: server closed the connection");
2364 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2365 backend->encdata_is_incomplete = true;
2368 infof(data, "schannel: failed to decrypt data, need more data");
2372 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2373 char buffer[STRERROR_LEN];
2375 *err = CURLE_RECV_ERROR;
2376 infof(data, "schannel: failed to read data from server: %s",
2377 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2383 "schannel: encrypted data buffer: offset %zu length %zu",
2384 backend->encdata_offset, backend->encdata_length));
2387 "schannel: decrypted data buffer: offset %zu length %zu",
2388 backend->decdata_offset, backend->decdata_length));
2391 /* Warning- there is no guarantee the encdata state is valid at this point */
2392 DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2394 /* Error if the connection has closed without a close_notify.
2396 The behavior here is a matter of debate. We don't want to be vulnerable
2397 to a truncation attack however there's some browser precedent for
2398 ignoring the close_notify for compatibility reasons.
2400 Additionally, Windows 2000 (v5.0) is a special case since it seems it
2401 doesn't return close_notify. In that case if the connection was closed we
2402 assume it was graceful (close_notify) since there doesn't seem to be a
2405 if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2406 !backend->recv_sspi_close_notify) {
2407 bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2410 if(isWin2k && sspi_status == SEC_E_OK)
2411 backend->recv_sspi_close_notify = true;
2413 *err = CURLE_RECV_ERROR;
2414 infof(data, "schannel: server closed abruptly (missing close_notify)");
2418 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2419 if(*err && *err != CURLE_AGAIN)
2420 backend->recv_unrecoverable_err = *err;
2422 size = len < backend->decdata_offset ? len : backend->decdata_offset;
2424 memcpy(buf, backend->decdata_buffer, size);
2425 memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2426 backend->decdata_offset - size);
2427 backend->decdata_offset -= size;
2428 DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2430 "schannel: decrypted data buffer: offset %zu length %zu",
2431 backend->decdata_offset, backend->decdata_length));
2433 return (ssize_t)size;
2436 if(!*err && !backend->recv_connection_closed)
2439 /* It's debatable what to return when !len. We could return whatever error
2440 we got from decryption but instead we override here so the return is
2446 return *err ? -1 : 0;
2449 static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
2450 struct connectdata *conn,
2451 int sockindex, bool *done)
2453 return schannel_connect_common(data, conn, sockindex, TRUE, done);
2456 static CURLcode schannel_connect(struct Curl_easy *data,
2457 struct connectdata *conn, int sockindex)
2462 result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
2471 static bool schannel_data_pending(const struct connectdata *conn,
2474 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2475 struct ssl_backend_data *backend = connssl->backend;
2477 DEBUGASSERT(backend);
2479 if(connssl->use) /* SSL/TLS is in use */
2480 return (backend->decdata_offset > 0 ||
2481 (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
2486 static void schannel_session_free(void *ptr)
2488 /* this is expected to be called under sessionid lock */
2489 struct Curl_schannel_cred *cred = ptr;
2493 if(cred->refcount == 0) {
2494 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
2495 curlx_unicodefree(cred->sni_hostname);
2496 #ifdef HAS_CLIENT_CERT_PATH
2497 if(cred->client_cert_store) {
2498 CertCloseStore(cred->client_cert_store, 0);
2499 cred->client_cert_store = NULL;
2502 Curl_safefree(cred);
2507 /* shut down the SSL connection and clean up related memory.
2508 this function can be called multiple times on the same connection including
2509 if the SSL connection failed (eg connection made but failed handshake). */
2510 static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
2513 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2514 * Shutting Down an Schannel Connection
2516 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2517 char * const hostname = SSL_HOST_NAME();
2518 struct ssl_backend_data *backend = connssl->backend;
2521 DEBUGASSERT(backend);
2524 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
2525 hostname, conn->remote_port);
2528 if(connssl->use && backend->cred && backend->ctxt) {
2529 SecBufferDesc BuffDesc;
2531 SECURITY_STATUS sspi_status;
2533 SecBufferDesc outbuf_desc;
2535 DWORD dwshut = SCHANNEL_SHUTDOWN;
2537 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2538 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2540 sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2543 if(sspi_status != SEC_E_OK) {
2544 char buffer[STRERROR_LEN];
2545 failf(data, "schannel: ApplyControlToken failure: %s",
2546 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2549 /* setup output buffer */
2550 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2551 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2553 sspi_status = s_pSecFn->InitializeSecurityContext(
2554 &backend->cred->cred_handle,
2555 &backend->ctxt->ctxt_handle,
2556 backend->cred->sni_hostname,
2562 &backend->ctxt->ctxt_handle,
2564 &backend->ret_flags,
2565 &backend->ctxt->time_stamp);
2567 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2568 /* send close message which is in output buffer */
2570 result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
2571 outbuf.cbBuffer, &written);
2573 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2574 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2575 infof(data, "schannel: failed to send close msg: %s"
2576 " (bytes written: %zd)", curl_easy_strerror(result), written);
2581 /* free SSPI Schannel API security context handle */
2583 DEBUGF(infof(data, "schannel: clear security context handle"));
2584 s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2585 Curl_safefree(backend->ctxt);
2588 /* free SSPI Schannel API credential handle */
2590 Curl_ssl_sessionid_lock(data);
2591 schannel_session_free(backend->cred);
2592 Curl_ssl_sessionid_unlock(data);
2593 backend->cred = NULL;
2596 /* free internal buffer for received encrypted data */
2597 if(backend->encdata_buffer) {
2598 Curl_safefree(backend->encdata_buffer);
2599 backend->encdata_length = 0;
2600 backend->encdata_offset = 0;
2601 backend->encdata_is_incomplete = false;
2604 /* free internal buffer for received decrypted data */
2605 if(backend->decdata_buffer) {
2606 Curl_safefree(backend->decdata_buffer);
2607 backend->decdata_length = 0;
2608 backend->decdata_offset = 0;
2614 static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
2617 if(conn->ssl[sockindex].use)
2618 /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
2619 Curl_ssl_shutdown(data, conn, sockindex);
2621 schannel_shutdown(data, conn, sockindex);
2624 static int schannel_init(void)
2626 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2629 static void schannel_cleanup(void)
2631 Curl_sspi_global_cleanup();
2634 static size_t schannel_version(char *buffer, size_t size)
2636 size = msnprintf(buffer, size, "Schannel");
2641 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2642 unsigned char *entropy, size_t length)
2646 return Curl_win32_random(entropy, length);
2649 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
2650 struct connectdata *conn, int sockindex,
2651 const char *pinnedpubkey)
2653 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2654 struct ssl_backend_data *backend = connssl->backend;
2655 CERT_CONTEXT *pCertContextServer = NULL;
2657 /* Result is returned to caller */
2658 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2660 DEBUGASSERT(backend);
2662 /* if a path wasn't specified, don't pin */
2667 SECURITY_STATUS sspi_status;
2668 const char *x509_der;
2670 struct Curl_X509certificate x509_parsed;
2671 struct Curl_asn1Element *pubkey;
2674 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2675 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2676 &pCertContextServer);
2678 if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2679 char buffer[STRERROR_LEN];
2680 failf(data, "schannel: Failed to read remote certificate context: %s",
2681 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2686 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2687 (pCertContextServer->cbCertEncoded > 0)))
2690 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2691 x509_der_len = pCertContextServer->cbCertEncoded;
2692 memset(&x509_parsed, 0, sizeof(x509_parsed));
2693 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2696 pubkey = &x509_parsed.subjectPublicKeyInfo;
2697 if(!pubkey->header || pubkey->end <= pubkey->header) {
2698 failf(data, "SSL: failed retrieving public key from server certificate");
2702 result = Curl_pin_peer_pubkey(data,
2704 (const unsigned char *)pubkey->header,
2705 (size_t)(pubkey->end - pubkey->header));
2707 failf(data, "SSL: public key does not match pinned public key");
2711 if(pCertContextServer)
2712 CertFreeCertificateContext(pCertContextServer);
2717 static void schannel_checksum(const unsigned char *input,
2719 unsigned char *checksum,
2722 const unsigned int algId)
2724 HCRYPTPROV hProv = 0;
2725 HCRYPTHASH hHash = 0;
2726 DWORD cbHashSize = 0;
2727 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2728 DWORD dwChecksumLen = (DWORD)checksumlen;
2730 /* since this can fail in multiple ways, zero memory first so we never
2733 memset(checksum, 0, checksumlen);
2735 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2736 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2737 return; /* failed */
2740 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2743 /* workaround for original MinGW, should be (const BYTE*) */
2744 if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2748 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2752 /* check hash size */
2753 if(checksumlen < cbHashSize)
2756 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2761 CryptDestroyHash(hHash);
2764 CryptReleaseContext(hProv, 0);
2767 static CURLcode schannel_sha256sum(const unsigned char *input,
2769 unsigned char *sha256sum,
2772 schannel_checksum(input, inputlen, sha256sum, sha256len,
2773 PROV_RSA_AES, CALG_SHA_256);
2777 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2778 CURLINFO info UNUSED_PARAM)
2780 struct ssl_backend_data *backend = connssl->backend;
2782 DEBUGASSERT(backend);
2783 return &backend->ctxt->ctxt_handle;
2786 const struct Curl_ssl Curl_ssl_schannel = {
2787 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2790 #ifdef HAS_MANUAL_VERIFY_API
2791 SSLSUPP_CAINFO_BLOB |
2793 SSLSUPP_PINNEDPUBKEY |
2794 SSLSUPP_TLS13_CIPHERSUITES,
2796 sizeof(struct ssl_backend_data),
2798 schannel_init, /* init */
2799 schannel_cleanup, /* cleanup */
2800 schannel_version, /* version */
2801 Curl_none_check_cxn, /* check_cxn */
2802 schannel_shutdown, /* shutdown */
2803 schannel_data_pending, /* data_pending */
2804 schannel_random, /* random */
2805 Curl_none_cert_status_request, /* cert_status_request */
2806 schannel_connect, /* connect */
2807 schannel_connect_nonblocking, /* connect_nonblocking */
2808 Curl_ssl_getsock, /* getsock */
2809 schannel_get_internals, /* get_internals */
2810 schannel_close, /* close_one */
2811 Curl_none_close_all, /* close_all */
2812 schannel_session_free, /* session_free */
2813 Curl_none_set_engine, /* set_engine */
2814 Curl_none_set_engine_default, /* set_engine_default */
2815 Curl_none_engines_list, /* engines_list */
2816 Curl_none_false_start, /* false_start */
2817 schannel_sha256sum, /* sha256sum */
2818 NULL, /* associate_connection */
2819 NULL /* disassociate_connection */
2822 #endif /* USE_SCHANNEL */