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 ***************************************************************************/
26 * Source file for all Schannel-specific code for the TLS/SSL layer. No code
27 * but vtls.c should ever call or use these functions.
30 #include "curl_setup.h"
34 #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
36 #ifndef USE_WINDOWS_SSPI
37 # error "Can't compile SCHANNEL support without SSPI."
44 #include "connect.h" /* for the connect timeout */
46 #include "select.h" /* for the socket readiness */
47 #include "inet_pton.h" /* for IP addr SNI check */
48 #include "curl_multibyte.h"
51 #include "curl_printf.h"
53 #include "version_win32.h"
55 /* The last #include file should be: */
56 #include "curl_memory.h"
59 /* ALPN requires version 8.1 of the Windows SDK, which was
60 shipped with Visual Studio 2013, aka _MSC_VER 1800:
62 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
64 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
69 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
73 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
78 #define UNISP_NAME UNISP_NAME_W
80 #define UNISP_NAME UNISP_NAME_A
84 #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
85 #define HAS_CLIENT_CERT_PATH
88 #ifdef HAS_CLIENT_CERT_PATH
90 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
92 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
96 #ifndef SP_PROT_SSL2_CLIENT
97 #define SP_PROT_SSL2_CLIENT 0x00000008
100 #ifndef SP_PROT_SSL3_CLIENT
101 #define SP_PROT_SSL3_CLIENT 0x00000008
104 #ifndef SP_PROT_TLS1_CLIENT
105 #define SP_PROT_TLS1_CLIENT 0x00000080
108 #ifndef SP_PROT_TLS1_0_CLIENT
109 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
112 #ifndef SP_PROT_TLS1_1_CLIENT
113 #define SP_PROT_TLS1_1_CLIENT 0x00000200
116 #ifndef SP_PROT_TLS1_2_CLIENT
117 #define SP_PROT_TLS1_2_CLIENT 0x00000800
120 #ifndef SCH_USE_STRONG_CRYPTO
121 #define SCH_USE_STRONG_CRYPTO 0x00400000
124 #ifndef SECBUFFER_ALERT
125 #define SECBUFFER_ALERT 17
128 /* Both schannel buffer sizes must be > 0 */
129 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
130 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
132 #define CERT_THUMBPRINT_STR_LEN 40
133 #define CERT_THUMBPRINT_DATA_LEN 20
135 /* Uncomment to force verbose output
136 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
137 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
141 # define CALG_SHA_256 0x0000800c
144 /* Work around typo in classic MinGW's w32api up to version 5.0,
145 see https://osdn.net/projects/mingw/ticket/38391 */
146 #if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH)
147 #define ALG_CLASS_DHASH ALG_CLASS_HASH
150 static Curl_recv schannel_recv;
151 static Curl_send schannel_send;
153 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
154 struct connectdata *conn, int sockindex,
155 const char *pinnedpubkey);
157 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
158 void *BufDataPtr, unsigned long BufByteSize)
160 buffer->cbBuffer = BufByteSize;
161 buffer->BufferType = BufType;
162 buffer->pvBuffer = BufDataPtr;
165 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
166 unsigned long NumArrElem)
168 desc->ulVersion = SECBUFFER_VERSION;
169 desc->pBuffers = BufArr;
170 desc->cBuffers = NumArrElem;
174 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data,
175 struct connectdata *conn)
177 long ssl_version = SSL_CONN_CONFIG(version);
178 long ssl_version_max = SSL_CONN_CONFIG(version_max);
179 long i = ssl_version;
181 switch(ssl_version_max) {
182 case CURL_SSLVERSION_MAX_NONE:
183 case CURL_SSLVERSION_MAX_DEFAULT:
184 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
187 for(; i <= (ssl_version_max >> 16); ++i) {
189 case CURL_SSLVERSION_TLSv1_0:
190 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
192 case CURL_SSLVERSION_TLSv1_1:
193 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
195 case CURL_SSLVERSION_TLSv1_2:
196 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
198 case CURL_SSLVERSION_TLSv1_3:
199 failf(data, "schannel: TLS 1.3 is not yet supported");
200 return CURLE_SSL_CONNECT_ERROR;
206 /*longest is 26, buffer is slightly bigger*/
207 #define LONGEST_ALG_ID 32
208 #define CIPHEROPTION(X) \
209 if(strcmp(#X, tmp) == 0) \
213 get_alg_id_by_name(char *name)
215 char tmp[LONGEST_ALG_ID] = { 0 };
216 char *nameEnd = strchr(name, ':');
217 size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
218 min(strlen(name), LONGEST_ALG_ID - 1);
219 strncpy(tmp, name, n);
221 CIPHEROPTION(CALG_MD2);
222 CIPHEROPTION(CALG_MD4);
223 CIPHEROPTION(CALG_MD5);
224 CIPHEROPTION(CALG_SHA);
225 CIPHEROPTION(CALG_SHA1);
226 CIPHEROPTION(CALG_MAC);
227 CIPHEROPTION(CALG_RSA_SIGN);
228 CIPHEROPTION(CALG_DSS_SIGN);
229 /*ifdefs for the options that are defined conditionally in wincrypt.h*/
231 CIPHEROPTION(CALG_NO_SIGN);
233 CIPHEROPTION(CALG_RSA_KEYX);
234 CIPHEROPTION(CALG_DES);
236 CIPHEROPTION(CALG_3DES_112);
238 CIPHEROPTION(CALG_3DES);
239 CIPHEROPTION(CALG_DESX);
240 CIPHEROPTION(CALG_RC2);
241 CIPHEROPTION(CALG_RC4);
242 CIPHEROPTION(CALG_SEAL);
244 CIPHEROPTION(CALG_DH_SF);
246 CIPHEROPTION(CALG_DH_EPHEM);
247 #ifdef CALG_AGREEDKEY_ANY
248 CIPHEROPTION(CALG_AGREEDKEY_ANY);
250 #ifdef CALG_HUGHES_MD5
251 CIPHEROPTION(CALG_HUGHES_MD5);
253 CIPHEROPTION(CALG_SKIPJACK);
255 CIPHEROPTION(CALG_TEK);
257 CIPHEROPTION(CALG_CYLINK_MEK);
258 CIPHEROPTION(CALG_SSL3_SHAMD5);
259 #ifdef CALG_SSL3_MASTER
260 CIPHEROPTION(CALG_SSL3_MASTER);
262 #ifdef CALG_SCHANNEL_MASTER_HASH
263 CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
265 #ifdef CALG_SCHANNEL_MAC_KEY
266 CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
268 #ifdef CALG_SCHANNEL_ENC_KEY
269 CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
271 #ifdef CALG_PCT1_MASTER
272 CIPHEROPTION(CALG_PCT1_MASTER);
274 #ifdef CALG_SSL2_MASTER
275 CIPHEROPTION(CALG_SSL2_MASTER);
277 #ifdef CALG_TLS1_MASTER
278 CIPHEROPTION(CALG_TLS1_MASTER);
281 CIPHEROPTION(CALG_RC5);
284 CIPHEROPTION(CALG_HMAC);
287 CIPHEROPTION(CALG_TLS1PRF);
289 #ifdef CALG_HASH_REPLACE_OWF
290 CIPHEROPTION(CALG_HASH_REPLACE_OWF);
293 CIPHEROPTION(CALG_AES_128);
296 CIPHEROPTION(CALG_AES_192);
299 CIPHEROPTION(CALG_AES_256);
302 CIPHEROPTION(CALG_AES);
305 CIPHEROPTION(CALG_SHA_256);
308 CIPHEROPTION(CALG_SHA_384);
311 CIPHEROPTION(CALG_SHA_512);
314 CIPHEROPTION(CALG_ECDH);
317 CIPHEROPTION(CALG_ECMQV);
320 CIPHEROPTION(CALG_ECDSA);
322 #ifdef CALG_ECDH_EPHEM
323 CIPHEROPTION(CALG_ECDH_EPHEM);
328 #define NUM_CIPHERS 47 /* There are 47 options listed above */
331 set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
334 char *startCur = ciphers;
336 while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
337 long alg = strtol(startCur, 0, 0);
339 alg = get_alg_id_by_name(startCur);
341 algIds[algCount++] = alg;
342 else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
343 sizeof("USE_STRONG_CRYPTO") - 1) ||
344 !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
345 sizeof("SCH_USE_STRONG_CRYPTO") - 1))
346 schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
348 return CURLE_SSL_CIPHER;
349 startCur = strchr(startCur, ':');
353 schannel_cred->palgSupportedAlgs = algIds;
354 schannel_cred->cSupportedAlgs = algCount;
358 #ifdef HAS_CLIENT_CERT_PATH
360 /* Function allocates memory for store_path only if CURLE_OK is returned */
362 get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
366 TCHAR *store_path_start;
367 size_t store_name_len;
369 sep = _tcschr(path, TEXT('\\'));
371 return CURLE_SSL_CERTPROBLEM;
373 store_name_len = sep - path;
375 if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
376 *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
377 else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
378 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
379 else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
380 *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
381 else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
382 *store_name = CERT_SYSTEM_STORE_SERVICES;
383 else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
384 *store_name = CERT_SYSTEM_STORE_USERS;
385 else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
386 store_name_len) == 0)
387 *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
388 else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
389 store_name_len) == 0)
390 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
391 else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
392 store_name_len) == 0)
393 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
395 return CURLE_SSL_CERTPROBLEM;
397 store_path_start = sep + 1;
399 sep = _tcschr(store_path_start, TEXT('\\'));
401 return CURLE_SSL_CERTPROBLEM;
403 *thumbprint = sep + 1;
404 if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
405 return CURLE_SSL_CERTPROBLEM;
408 *store_path = _tcsdup(store_path_start);
411 return CURLE_OUT_OF_MEMORY;
417 schannel_acquire_credential_handle(struct Curl_easy *data,
418 struct connectdata *conn,
421 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
422 SCHANNEL_CRED schannel_cred;
423 ALG_ID algIds[NUM_CIPHERS];
424 PCCERT_CONTEXT client_certs[1] = { NULL };
425 SECURITY_STATUS sspi_status = SEC_E_OK;
427 struct ssl_backend_data *backend = connssl->backend;
429 DEBUGASSERT(backend);
431 /* setup Schannel API options */
432 memset(&schannel_cred, 0, sizeof(schannel_cred));
433 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
435 if(conn->ssl_config.verifypeer) {
436 #ifdef HAS_MANUAL_VERIFY_API
437 if(backend->use_manual_cred_validation)
438 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
441 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
443 if(SSL_SET_OPTION(no_revoke)) {
444 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
445 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
447 DEBUGF(infof(data, "schannel: disabled server certificate revocation "
450 else if(SSL_SET_OPTION(revoke_best_effort)) {
451 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
452 SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
454 DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
457 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
460 "schannel: checking server certificate revocation"));
464 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
465 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
466 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
468 "schannel: disabled server cert revocation checks"));
471 if(!conn->ssl_config.verifyhost) {
472 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
473 DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
474 "comparing the supplied target name with the subject "
475 "names in server certificates."));
478 if(!SSL_SET_OPTION(auto_client_cert)) {
479 schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
480 schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
481 infof(data, "schannel: disabled automatic use of client certificate");
484 infof(data, "schannel: enabled automatic use of client certificate");
486 switch(conn->ssl_config.version) {
487 case CURL_SSLVERSION_DEFAULT:
488 case CURL_SSLVERSION_TLSv1:
489 case CURL_SSLVERSION_TLSv1_0:
490 case CURL_SSLVERSION_TLSv1_1:
491 case CURL_SSLVERSION_TLSv1_2:
492 case CURL_SSLVERSION_TLSv1_3:
494 result = set_ssl_version_min_max(&schannel_cred, data, conn);
495 if(result != CURLE_OK)
499 case CURL_SSLVERSION_SSLv3:
500 case CURL_SSLVERSION_SSLv2:
501 failf(data, "SSL versions not supported");
502 return CURLE_NOT_BUILT_IN;
504 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
505 return CURLE_SSL_CONNECT_ERROR;
508 if(SSL_CONN_CONFIG(cipher_list)) {
509 result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
511 if(CURLE_OK != result) {
512 failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
518 #ifdef HAS_CLIENT_CERT_PATH
519 /* client certificate */
520 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
521 DWORD cert_store_name = 0;
522 TCHAR *cert_store_path = NULL;
523 TCHAR *cert_thumbprint_str = NULL;
524 CRYPT_HASH_BLOB cert_thumbprint;
525 BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
526 HCERTSTORE cert_store = NULL;
527 FILE *fInCert = NULL;
528 void *certdata = NULL;
530 bool blob = data->set.ssl.primary.cert_blob != NULL;
531 TCHAR *cert_path = NULL;
533 certdata = data->set.ssl.primary.cert_blob->data;
534 certsize = data->set.ssl.primary.cert_blob->len;
537 cert_path = curlx_convert_UTF8_to_tchar(
538 data->set.ssl.primary.clientcert);
540 return CURLE_OUT_OF_MEMORY;
542 result = get_cert_location(cert_path, &cert_store_name,
543 &cert_store_path, &cert_thumbprint_str);
545 if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
546 fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
548 if(result && !fInCert) {
549 failf(data, "schannel: Failed to get certificate location"
551 data->set.ssl.primary.clientcert);
552 curlx_unicodefree(cert_path);
557 if((fInCert || blob) && (data->set.ssl.cert_type) &&
558 (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
559 failf(data, "schannel: certificate format compatibility error "
561 blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
562 curlx_unicodefree(cert_path);
563 return CURLE_SSL_CERTPROBLEM;
566 if(fInCert || blob) {
567 /* Reading a .P12 or .pfx file, like the example at bottom of
568 https://social.msdn.microsoft.com/Forums/windowsdesktop/
569 en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
571 CRYPT_DATA_BLOB datablob;
575 const char *cert_showfilename_error = blob ?
576 "(memory blob)" : data->set.ssl.primary.clientcert;
577 curlx_unicodefree(cert_path);
580 bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
582 cert_tell = ftell(fInCert);
584 continue_reading = FALSE;
586 certsize = (size_t)cert_tell;
588 continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
590 certdata = malloc(certsize + 1);
592 ((int) fread(certdata, certsize, 1, fInCert) != 1))
593 continue_reading = FALSE;
595 if(!continue_reading) {
596 failf(data, "schannel: Failed to read cert file %s",
597 data->set.ssl.primary.clientcert);
599 return CURLE_SSL_CERTPROBLEM;
603 /* Convert key-pair data to the in-memory certificate store */
604 datablob.pbData = (BYTE*)certdata;
605 datablob.cbData = (DWORD)certsize;
607 if(data->set.ssl.key_passwd)
608 pwd_len = strlen(data->set.ssl.key_passwd);
609 pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
612 str_w_len = MultiByteToWideChar(CP_UTF8,
613 MB_ERR_INVALID_CHARS,
614 data->set.ssl.key_passwd, (int)pwd_len,
615 pszPassword, (int)(pwd_len + 1));
617 if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
618 pszPassword[str_w_len] = 0;
622 cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
628 DWORD errorcode = GetLastError();
629 if(errorcode == ERROR_INVALID_PASSWORD)
630 failf(data, "schannel: Failed to import cert file %s, "
632 cert_showfilename_error);
634 failf(data, "schannel: Failed to import cert file %s, "
635 "last error is 0x%x",
636 cert_showfilename_error, errorcode);
637 return CURLE_SSL_CERTPROBLEM;
640 client_certs[0] = CertFindCertificateInStore(
641 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
642 CERT_FIND_ANY, NULL, NULL);
644 if(!client_certs[0]) {
645 failf(data, "schannel: Failed to get certificate from file %s"
646 ", last error is 0x%x",
647 cert_showfilename_error, GetLastError());
648 CertCloseStore(cert_store, 0);
649 return CURLE_SSL_CERTPROBLEM;
652 schannel_cred.cCreds = 1;
653 schannel_cred.paCred = client_certs;
657 CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
659 CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
662 failf(data, "schannel: Failed to open cert store %x %s, "
663 "last error is 0x%x",
664 cert_store_name, cert_store_path, GetLastError());
665 free(cert_store_path);
666 curlx_unicodefree(cert_path);
667 return CURLE_SSL_CERTPROBLEM;
669 free(cert_store_path);
671 cert_thumbprint.pbData = cert_thumbprint_data;
672 cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
674 if(!CryptStringToBinary(cert_thumbprint_str,
675 CERT_THUMBPRINT_STR_LEN,
677 cert_thumbprint_data,
678 &cert_thumbprint.cbData,
680 curlx_unicodefree(cert_path);
681 CertCloseStore(cert_store, 0);
682 return CURLE_SSL_CERTPROBLEM;
685 client_certs[0] = CertFindCertificateInStore(
686 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
687 CERT_FIND_HASH, &cert_thumbprint, NULL);
689 curlx_unicodefree(cert_path);
691 if(client_certs[0]) {
692 schannel_cred.cCreds = 1;
693 schannel_cred.paCred = client_certs;
696 /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
697 CertCloseStore(cert_store, 0);
698 return CURLE_SSL_CERTPROBLEM;
701 CertCloseStore(cert_store, 0);
704 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
705 failf(data, "schannel: client cert support not built in");
706 return CURLE_NOT_BUILT_IN;
710 /* allocate memory for the re-usable credential handle */
711 backend->cred = (struct Curl_schannel_cred *)
712 calloc(1, sizeof(struct Curl_schannel_cred));
714 failf(data, "schannel: unable to allocate memory");
717 CertFreeCertificateContext(client_certs[0]);
719 return CURLE_OUT_OF_MEMORY;
721 backend->cred->refcount = 1;
724 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
725 SECPKG_CRED_OUTBOUND, NULL,
726 &schannel_cred, NULL, NULL,
727 &backend->cred->cred_handle,
728 &backend->cred->time_stamp);
731 CertFreeCertificateContext(client_certs[0]);
733 if(sspi_status != SEC_E_OK) {
734 char buffer[STRERROR_LEN];
735 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
736 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
737 Curl_safefree(backend->cred);
738 switch(sspi_status) {
739 case SEC_E_INSUFFICIENT_MEMORY:
740 return CURLE_OUT_OF_MEMORY;
741 case SEC_E_NO_CREDENTIALS:
742 case SEC_E_SECPKG_NOT_FOUND:
743 case SEC_E_NOT_OWNER:
744 case SEC_E_UNKNOWN_CREDENTIALS:
745 case SEC_E_INTERNAL_ERROR:
747 return CURLE_SSL_CONNECT_ERROR;
755 schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
758 ssize_t written = -1;
759 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
761 SecBufferDesc outbuf_desc;
763 SecBufferDesc inbuf_desc;
765 unsigned char alpn_buffer[128];
767 SECURITY_STATUS sspi_status = SEC_E_OK;
768 struct Curl_schannel_cred *old_cred = NULL;
771 struct in6_addr addr6;
774 char * const hostname = SSL_HOST_NAME();
775 struct ssl_backend_data *backend = connssl->backend;
777 DEBUGASSERT(backend);
780 "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
781 hostname, conn->remote_port));
783 if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
784 VERSION_LESS_THAN_EQUAL)) {
785 /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
786 algorithms that may not be supported by all servers. */
787 infof(data, "schannel: Windows version is old and may not be able to "
788 "connect to some servers due to lack of SNI, algorithms, etc.");
792 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
793 Also it doesn't seem to be supported for Wine, see curl bug #983. */
794 backend->use_alpn = conn->bits.tls_enable_alpn &&
795 !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
796 "wine_get_version") &&
797 curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
798 VERSION_GREATER_THAN_EQUAL);
800 backend->use_alpn = false;
804 #ifdef HAS_MANUAL_VERIFY_API
805 /* certificate validation on CE doesn't seem to work right; we'll
806 * do it following a more manual process. */
807 backend->use_manual_cred_validation = true;
809 #error "compiler too old to support requisite manual cert verify for Win CE"
812 #ifdef HAS_MANUAL_VERIFY_API
813 if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
814 if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
815 VERSION_GREATER_THAN_EQUAL)) {
816 backend->use_manual_cred_validation = true;
819 failf(data, "schannel: this version of Windows is too old to support "
820 "certificate verification via CA bundle file.");
821 return CURLE_SSL_CACERT_BADFILE;
825 backend->use_manual_cred_validation = false;
827 if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
828 failf(data, "schannel: CA cert support not built in");
829 return CURLE_NOT_BUILT_IN;
834 backend->cred = NULL;
836 /* check for an existing re-usable credential handle */
837 if(SSL_SET_OPTION(primary.sessionid)) {
838 Curl_ssl_sessionid_lock(data);
839 if(!Curl_ssl_getsessionid(data, conn,
840 SSL_IS_PROXY() ? TRUE : FALSE,
841 (void **)&old_cred, NULL, sockindex)) {
842 backend->cred = old_cred;
843 DEBUGF(infof(data, "schannel: re-using existing credential handle"));
845 /* increment the reference counter of the credential/session handle */
846 backend->cred->refcount++;
848 "schannel: incremented credential handle refcount = %d",
849 backend->cred->refcount));
851 Curl_ssl_sessionid_unlock(data);
856 result = schannel_acquire_credential_handle(data, conn, sockindex);
857 if(result != CURLE_OK) {
860 /* A hostname associated with the credential is needed by
861 InitializeSecurityContext for SNI and other reasons. */
862 snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
864 failf(data, "Failed to set SNI");
865 return CURLE_SSL_CONNECT_ERROR;
867 backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
868 if(!backend->cred->sni_hostname)
869 return CURLE_OUT_OF_MEMORY;
872 /* Warn if SNI is disabled due to use of an IP address */
873 if(Curl_inet_pton(AF_INET, hostname, &addr)
875 || Curl_inet_pton(AF_INET6, hostname, &addr6)
878 infof(data, "schannel: using IP address, SNI is not supported by OS.");
882 if(backend->use_alpn) {
884 int list_start_index = 0;
885 unsigned int *extension_len = NULL;
886 unsigned short* list_len = NULL;
888 /* The first four bytes will be an unsigned int indicating number
889 of bytes of data in the rest of the buffer. */
890 extension_len = (unsigned int *)(&alpn_buffer[cur]);
891 cur += sizeof(unsigned int);
893 /* The next four bytes are an indicator that this buffer will contain
894 ALPN data, as opposed to NPN, for example. */
895 *(unsigned int *)&alpn_buffer[cur] =
896 SecApplicationProtocolNegotiationExt_ALPN;
897 cur += sizeof(unsigned int);
899 /* The next two bytes will be an unsigned short indicating the number
900 of bytes used to list the preferred protocols. */
901 list_len = (unsigned short*)(&alpn_buffer[cur]);
902 cur += sizeof(unsigned short);
904 list_start_index = cur;
907 if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
908 alpn_buffer[cur++] = ALPN_H2_LENGTH;
909 memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
910 cur += ALPN_H2_LENGTH;
911 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
915 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
916 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
917 cur += ALPN_HTTP_1_1_LENGTH;
918 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
920 *list_len = curlx_uitous(cur - list_start_index);
921 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
923 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
924 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
927 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
928 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
931 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
932 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
935 /* setup output buffer */
936 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
937 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
939 /* security request flags */
940 backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
941 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
944 if(!SSL_SET_OPTION(auto_client_cert)) {
945 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
948 /* allocate memory for the security context handle */
949 backend->ctxt = (struct Curl_schannel_ctxt *)
950 calloc(1, sizeof(struct Curl_schannel_ctxt));
952 failf(data, "schannel: unable to allocate memory");
953 return CURLE_OUT_OF_MEMORY;
956 /* Schannel InitializeSecurityContext:
957 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
959 At the moment we don't pass inbuf unless we're using ALPN since we only
960 use it for that, and Wine (for which we currently disable ALPN) is giving
961 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
963 sspi_status = s_pSecFn->InitializeSecurityContext(
964 &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
965 backend->req_flags, 0, 0,
966 (backend->use_alpn ? &inbuf_desc : NULL),
967 0, &backend->ctxt->ctxt_handle,
968 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
970 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
971 char buffer[STRERROR_LEN];
972 Curl_safefree(backend->ctxt);
973 switch(sspi_status) {
974 case SEC_E_INSUFFICIENT_MEMORY:
975 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
976 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
977 return CURLE_OUT_OF_MEMORY;
978 case SEC_E_WRONG_PRINCIPAL:
979 failf(data, "schannel: SNI or certificate check failed: %s",
980 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
981 return CURLE_PEER_FAILED_VERIFICATION;
983 case SEC_E_INVALID_HANDLE:
984 case SEC_E_INVALID_TOKEN:
985 case SEC_E_LOGON_DENIED:
986 case SEC_E_TARGET_UNKNOWN:
987 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
988 case SEC_E_INTERNAL_ERROR:
989 case SEC_E_NO_CREDENTIALS:
990 case SEC_E_UNSUPPORTED_FUNCTION:
991 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
994 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
995 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
996 return CURLE_SSL_CONNECT_ERROR;
1000 DEBUGF(infof(data, "schannel: sending initial handshake data: "
1001 "sending %lu bytes.", outbuf.cbBuffer));
1003 /* send initial handshake data which is now stored in output buffer */
1004 result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
1005 outbuf.cbBuffer, &written);
1006 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1007 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1008 failf(data, "schannel: failed to send initial handshake data: "
1009 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
1010 return CURLE_SSL_CONNECT_ERROR;
1013 DEBUGF(infof(data, "schannel: sent initial handshake data: "
1014 "sent %zd bytes", written));
1016 backend->recv_unrecoverable_err = CURLE_OK;
1017 backend->recv_sspi_close_notify = false;
1018 backend->recv_connection_closed = false;
1019 backend->encdata_is_incomplete = false;
1021 /* continue to second handshake step */
1022 connssl->connecting_state = ssl_connect_2;
1028 schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
1032 ssize_t nread = -1, written = -1;
1033 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1034 unsigned char *reallocated_buffer;
1035 SecBuffer outbuf[3];
1036 SecBufferDesc outbuf_desc;
1038 SecBufferDesc inbuf_desc;
1039 SECURITY_STATUS sspi_status = SEC_E_OK;
1042 const char *pubkey_ptr;
1043 struct ssl_backend_data *backend = connssl->backend;
1045 DEBUGASSERT(backend);
1047 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1050 "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
1051 SSL_HOST_NAME(), conn->remote_port));
1053 if(!backend->cred || !backend->ctxt)
1054 return CURLE_SSL_CONNECT_ERROR;
1056 /* buffer to store previously received and decrypted data */
1057 if(!backend->decdata_buffer) {
1058 backend->decdata_offset = 0;
1059 backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1060 backend->decdata_buffer = malloc(backend->decdata_length);
1061 if(!backend->decdata_buffer) {
1062 failf(data, "schannel: unable to allocate memory");
1063 return CURLE_OUT_OF_MEMORY;
1067 /* buffer to store previously received and encrypted data */
1068 if(!backend->encdata_buffer) {
1069 backend->encdata_is_incomplete = false;
1070 backend->encdata_offset = 0;
1071 backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1072 backend->encdata_buffer = malloc(backend->encdata_length);
1073 if(!backend->encdata_buffer) {
1074 failf(data, "schannel: unable to allocate memory");
1075 return CURLE_OUT_OF_MEMORY;
1079 /* if we need a bigger buffer to read a full message, increase buffer now */
1080 if(backend->encdata_length - backend->encdata_offset <
1081 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1082 /* increase internal encrypted data buffer */
1083 size_t reallocated_length = backend->encdata_offset +
1084 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1085 reallocated_buffer = realloc(backend->encdata_buffer,
1086 reallocated_length);
1088 if(!reallocated_buffer) {
1089 failf(data, "schannel: unable to re-allocate memory");
1090 return CURLE_OUT_OF_MEMORY;
1093 backend->encdata_buffer = reallocated_buffer;
1094 backend->encdata_length = reallocated_length;
1100 /* read encrypted handshake data from socket */
1101 result = Curl_read_plain(conn->sock[sockindex],
1102 (char *) (backend->encdata_buffer +
1103 backend->encdata_offset),
1104 backend->encdata_length -
1105 backend->encdata_offset,
1107 if(result == CURLE_AGAIN) {
1108 if(connssl->connecting_state != ssl_connect_2_writing)
1109 connssl->connecting_state = ssl_connect_2_reading;
1110 DEBUGF(infof(data, "schannel: failed to receive handshake, "
1114 else if((result != CURLE_OK) || (nread == 0)) {
1115 failf(data, "schannel: failed to receive handshake, "
1116 "SSL/TLS connection failed");
1117 return CURLE_SSL_CONNECT_ERROR;
1120 /* increase encrypted data buffer offset */
1121 backend->encdata_offset += nread;
1122 backend->encdata_is_incomplete = false;
1123 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1127 "schannel: encrypted data buffer: offset %zu length %zu",
1128 backend->encdata_offset, backend->encdata_length));
1130 /* setup input buffers */
1131 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
1132 curlx_uztoul(backend->encdata_offset));
1133 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1134 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1136 /* setup output buffers */
1137 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1138 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1139 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1140 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1142 if(!inbuf[0].pvBuffer) {
1143 failf(data, "schannel: unable to allocate memory");
1144 return CURLE_OUT_OF_MEMORY;
1147 /* copy received handshake data into input buffer */
1148 memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
1149 backend->encdata_offset);
1151 sspi_status = s_pSecFn->InitializeSecurityContext(
1152 &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
1153 backend->cred->sni_hostname, backend->req_flags,
1154 0, 0, &inbuf_desc, 0, NULL,
1155 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1157 /* free buffer for received handshake data */
1158 Curl_safefree(inbuf[0].pvBuffer);
1160 /* check if the handshake was incomplete */
1161 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1162 backend->encdata_is_incomplete = true;
1163 connssl->connecting_state = ssl_connect_2_reading;
1165 "schannel: received incomplete message, need more data"));
1169 /* If the server has requested a client certificate, attempt to continue
1170 the handshake without one. This will allow connections to servers which
1171 request a client certificate but do not require it. */
1172 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1173 !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1174 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1175 connssl->connecting_state = ssl_connect_2_writing;
1177 "schannel: a client certificate has been requested"));
1181 /* check if the handshake needs to be continued */
1182 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1183 for(i = 0; i < 3; i++) {
1184 /* search for handshake tokens that need to be send */
1185 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1186 DEBUGF(infof(data, "schannel: sending next handshake data: "
1187 "sending %lu bytes.", outbuf[i].cbBuffer));
1189 /* send handshake token to server */
1190 result = Curl_write_plain(data, conn->sock[sockindex],
1191 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1193 if((result != CURLE_OK) ||
1194 (outbuf[i].cbBuffer != (size_t) written)) {
1195 failf(data, "schannel: failed to send next handshake data: "
1196 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1197 return CURLE_SSL_CONNECT_ERROR;
1201 /* free obsolete buffer */
1202 if(outbuf[i].pvBuffer) {
1203 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1208 char buffer[STRERROR_LEN];
1209 switch(sspi_status) {
1210 case SEC_E_INSUFFICIENT_MEMORY:
1211 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1212 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1213 return CURLE_OUT_OF_MEMORY;
1214 case SEC_E_WRONG_PRINCIPAL:
1215 failf(data, "schannel: SNI or certificate check failed: %s",
1216 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1217 return CURLE_PEER_FAILED_VERIFICATION;
1218 case SEC_E_UNTRUSTED_ROOT:
1219 failf(data, "schannel: %s",
1220 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1221 return CURLE_PEER_FAILED_VERIFICATION;
1223 case SEC_E_INVALID_HANDLE:
1224 case SEC_E_INVALID_TOKEN:
1225 case SEC_E_LOGON_DENIED:
1226 case SEC_E_TARGET_UNKNOWN:
1227 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1228 case SEC_E_INTERNAL_ERROR:
1229 case SEC_E_NO_CREDENTIALS:
1230 case SEC_E_UNSUPPORTED_FUNCTION:
1231 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1234 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1235 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1236 return CURLE_SSL_CONNECT_ERROR;
1240 /* check if there was additional remaining encrypted data */
1241 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1242 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1243 inbuf[1].cbBuffer));
1245 There are two cases where we could be getting extra data here:
1246 1) If we're renegotiating a connection and the handshake is already
1247 complete (from the server perspective), it can encrypted app data
1248 (not handshake data) in an extra buffer at this point.
1249 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1250 connection and this extra data is part of the handshake.
1251 We should process the data immediately; waiting for the socket to
1252 be ready may fail since the server is done sending handshake data.
1254 /* check if the remaining data is less than the total amount
1255 and therefore begins after the already processed data */
1256 if(backend->encdata_offset > inbuf[1].cbBuffer) {
1257 memmove(backend->encdata_buffer,
1258 (backend->encdata_buffer + backend->encdata_offset) -
1259 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1260 backend->encdata_offset = inbuf[1].cbBuffer;
1261 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1268 backend->encdata_offset = 0;
1273 /* check if the handshake needs to be continued */
1274 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1275 connssl->connecting_state = ssl_connect_2_reading;
1279 /* check if the handshake is complete */
1280 if(sspi_status == SEC_E_OK) {
1281 connssl->connecting_state = ssl_connect_3;
1282 DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1285 pubkey_ptr = SSL_PINNED_PUB_KEY();
1287 result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
1289 failf(data, "SSL: public key does not match pinned public key");
1294 #ifdef HAS_MANUAL_VERIFY_API
1295 if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
1296 return Curl_verify_certificate(data, conn, sockindex);
1304 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1306 return (cert_context != NULL) &&
1307 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1308 (cert_context->pbCertEncoded != NULL) &&
1309 (cert_context->cbCertEncoded > 0);
1312 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1315 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1318 const CERT_CONTEXT *current_context = NULL;
1319 bool should_continue = true;
1320 while(should_continue &&
1321 (current_context = CertEnumCertificatesInStore(
1322 context->hCertStore,
1323 current_context)) != NULL)
1324 should_continue = func(current_context, arg);
1327 CertFreeCertificateContext(current_context);
1331 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1333 if(valid_cert_encoding(ccert_context))
1334 (*(int *)certs_count)++;
1340 struct Curl_easy *data;
1347 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1349 struct Adder_args *args = (struct Adder_args*)raw_arg;
1350 args->result = CURLE_OK;
1351 if(valid_cert_encoding(ccert_context)) {
1352 const char *beg = (const char *) ccert_context->pbCertEncoded;
1353 const char *end = beg + ccert_context->cbCertEncoded;
1354 int insert_index = (args->certs_count - 1) - args->idx;
1355 args->result = Curl_extract_certinfo(args->data, insert_index,
1359 return args->result == CURLE_OK;
1363 schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
1366 CURLcode result = CURLE_OK;
1367 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1368 SECURITY_STATUS sspi_status = SEC_E_OK;
1369 CERT_CONTEXT *ccert_context = NULL;
1370 bool isproxy = SSL_IS_PROXY();
1371 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1372 const char * const hostname = SSL_HOST_NAME();
1375 SecPkgContext_ApplicationProtocol alpn_result;
1377 struct ssl_backend_data *backend = connssl->backend;
1379 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1380 DEBUGASSERT(backend);
1383 "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
1384 hostname, conn->remote_port));
1387 return CURLE_SSL_CONNECT_ERROR;
1389 /* check if the required context attributes are met */
1390 if(backend->ret_flags != backend->req_flags) {
1391 if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
1392 failf(data, "schannel: failed to setup sequence detection");
1393 if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
1394 failf(data, "schannel: failed to setup replay detection");
1395 if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
1396 failf(data, "schannel: failed to setup confidentiality");
1397 if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1398 failf(data, "schannel: failed to setup memory allocation");
1399 if(!(backend->ret_flags & ISC_RET_STREAM))
1400 failf(data, "schannel: failed to setup stream orientation");
1401 return CURLE_SSL_CONNECT_ERROR;
1405 if(backend->use_alpn) {
1407 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1408 SECPKG_ATTR_APPLICATION_PROTOCOL,
1411 if(sspi_status != SEC_E_OK) {
1412 failf(data, "schannel: failed to retrieve ALPN result");
1413 return CURLE_SSL_CONNECT_ERROR;
1416 if(alpn_result.ProtoNegoStatus ==
1417 SecApplicationProtocolNegotiationStatus_Success) {
1419 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR,
1420 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1423 if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH &&
1424 !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) {
1425 conn->negnpn = CURL_HTTP_VERSION_2;
1429 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1430 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1431 ALPN_HTTP_1_1_LENGTH)) {
1432 conn->negnpn = CURL_HTTP_VERSION_1_1;
1436 infof(data, VTLS_INFOF_NO_ALPN);
1437 Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
1438 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1442 /* save the current session data for possible re-use */
1443 if(SSL_SET_OPTION(primary.sessionid)) {
1446 struct Curl_schannel_cred *old_cred = NULL;
1448 Curl_ssl_sessionid_lock(data);
1449 incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
1452 if(old_cred != backend->cred) {
1454 "schannel: old credential handle is stale, removing"));
1455 /* we're not taking old_cred ownership here, no refcount++ is needed */
1456 Curl_ssl_delsessionid(data, (void *)old_cred);
1461 result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
1462 sizeof(struct Curl_schannel_cred),
1465 Curl_ssl_sessionid_unlock(data);
1466 failf(data, "schannel: failed to store credential handle");
1470 /* this cred session is now also referenced by sessionid cache */
1471 backend->cred->refcount++;
1473 "schannel: stored credential handle in session cache"));
1476 Curl_ssl_sessionid_unlock(data);
1479 if(data->set.ssl.certinfo) {
1480 int certs_count = 0;
1482 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1483 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1486 if((sspi_status != SEC_E_OK) || !ccert_context) {
1487 failf(data, "schannel: failed to retrieve remote cert context");
1488 return CURLE_PEER_FAILED_VERIFICATION;
1491 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1493 result = Curl_ssl_init_certinfo(data, certs_count);
1495 struct Adder_args args;
1498 args.certs_count = certs_count;
1499 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1500 result = args.result;
1502 CertFreeCertificateContext(ccert_context);
1507 connssl->connecting_state = ssl_connect_done;
1513 schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
1514 int sockindex, bool nonblocking, bool *done)
1517 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1518 curl_socket_t sockfd = conn->sock[sockindex];
1519 timediff_t timeout_ms;
1522 /* check if the connection has already been established */
1523 if(ssl_connection_complete == connssl->state) {
1528 if(ssl_connect_1 == connssl->connecting_state) {
1529 /* check out how much more time we're allowed */
1530 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1532 if(timeout_ms < 0) {
1533 /* no need to continue if time already is up */
1534 failf(data, "SSL/TLS connection timeout");
1535 return CURLE_OPERATION_TIMEDOUT;
1538 result = schannel_connect_step1(data, conn, sockindex);
1543 while(ssl_connect_2 == connssl->connecting_state ||
1544 ssl_connect_2_reading == connssl->connecting_state ||
1545 ssl_connect_2_writing == connssl->connecting_state) {
1547 /* check out how much more time we're allowed */
1548 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1550 if(timeout_ms < 0) {
1551 /* no need to continue if time already is up */
1552 failf(data, "SSL/TLS connection timeout");
1553 return CURLE_OPERATION_TIMEDOUT;
1556 /* if ssl is expecting something, check if it's available. */
1557 if(connssl->connecting_state == ssl_connect_2_reading
1558 || connssl->connecting_state == ssl_connect_2_writing) {
1560 curl_socket_t writefd = ssl_connect_2_writing ==
1561 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1562 curl_socket_t readfd = ssl_connect_2_reading ==
1563 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1565 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1566 nonblocking ? 0 : timeout_ms);
1569 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1570 return CURLE_SSL_CONNECT_ERROR;
1572 else if(0 == what) {
1579 failf(data, "SSL/TLS connection timeout");
1580 return CURLE_OPERATION_TIMEDOUT;
1583 /* socket is readable or writable */
1586 /* Run transaction, and return to the caller if it failed or if
1587 * this connection is part of a multi handle and this loop would
1588 * execute again. This permits the owner of a multi handle to
1589 * abort a connection attempt before step2 has completed while
1590 * ensuring that a client using select() or epoll() will always
1591 * have a valid fdset to wait on.
1593 result = schannel_connect_step2(data, conn, sockindex);
1594 if(result || (nonblocking &&
1595 (ssl_connect_2 == connssl->connecting_state ||
1596 ssl_connect_2_reading == connssl->connecting_state ||
1597 ssl_connect_2_writing == connssl->connecting_state)))
1600 } /* repeat step2 until all transactions are done. */
1602 if(ssl_connect_3 == connssl->connecting_state) {
1603 result = schannel_connect_step3(data, conn, sockindex);
1608 if(ssl_connect_done == connssl->connecting_state) {
1609 connssl->state = ssl_connection_complete;
1610 conn->recv[sockindex] = schannel_recv;
1611 conn->send[sockindex] = schannel_send;
1613 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1614 /* When SSPI is used in combination with Schannel
1615 * we need the Schannel context to create the Schannel
1616 * binding to pass the IIS extended protection checks.
1617 * Available on Windows 7 or later.
1620 struct ssl_backend_data *backend = connssl->backend;
1621 DEBUGASSERT(backend);
1622 conn->sslContext = &backend->ctxt->ctxt_handle;
1631 /* reset our connection state machine */
1632 connssl->connecting_state = ssl_connect_1;
1638 schannel_send(struct Curl_easy *data, int sockindex,
1639 const void *buf, size_t len, CURLcode *err)
1641 ssize_t written = -1;
1642 size_t data_len = 0;
1643 unsigned char *ptr = NULL;
1644 struct connectdata *conn = data->conn;
1645 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1646 SecBuffer outbuf[4];
1647 SecBufferDesc outbuf_desc;
1648 SECURITY_STATUS sspi_status = SEC_E_OK;
1650 struct ssl_backend_data *backend = connssl->backend;
1652 DEBUGASSERT(backend);
1654 /* check if the maximum stream sizes were queried */
1655 if(backend->stream_sizes.cbMaximumMessage == 0) {
1656 sspi_status = s_pSecFn->QueryContextAttributes(
1657 &backend->ctxt->ctxt_handle,
1658 SECPKG_ATTR_STREAM_SIZES,
1659 &backend->stream_sizes);
1660 if(sspi_status != SEC_E_OK) {
1661 *err = CURLE_SEND_ERROR;
1666 /* check if the buffer is longer than the maximum message length */
1667 if(len > backend->stream_sizes.cbMaximumMessage) {
1668 len = backend->stream_sizes.cbMaximumMessage;
1671 /* calculate the complete message length and allocate a buffer for it */
1672 data_len = backend->stream_sizes.cbHeader + len +
1673 backend->stream_sizes.cbTrailer;
1674 ptr = (unsigned char *) malloc(data_len);
1676 *err = CURLE_OUT_OF_MEMORY;
1680 /* setup output buffers (header, data, trailer, empty) */
1681 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1682 ptr, backend->stream_sizes.cbHeader);
1683 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1684 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
1685 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1686 ptr + backend->stream_sizes.cbHeader + len,
1687 backend->stream_sizes.cbTrailer);
1688 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1689 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1691 /* copy data into output buffer */
1692 memcpy(outbuf[1].pvBuffer, buf, len);
1694 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1695 sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
1698 /* check if the message was encrypted */
1699 if(sspi_status == SEC_E_OK) {
1702 /* send the encrypted message including header, data and trailer */
1703 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1706 It's important to send the full message which includes the header,
1707 encrypted payload, and trailer. Until the client receives all the
1708 data a coherent message has not been delivered and the client
1709 can't read any of it.
1711 If we wanted to buffer the unwritten encrypted bytes, we would
1712 tell the client that all data it has requested to be sent has been
1713 sent. The unwritten encrypted bytes would be the first bytes to
1714 send on the next invocation.
1715 Here's the catch with this - if we tell the client that all the
1716 bytes have been sent, will the client call this method again to
1717 send the buffered data? Looking at who calls this function, it
1718 seems the answer is NO.
1721 /* send entire message or fail */
1722 while(len > (size_t)written) {
1723 ssize_t this_write = 0;
1725 timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
1726 if(timeout_ms < 0) {
1727 /* we already got the timeout */
1728 failf(data, "schannel: timed out sending data "
1729 "(bytes sent: %zd)", written);
1730 *err = CURLE_OPERATION_TIMEDOUT;
1734 else if(!timeout_ms)
1735 timeout_ms = TIMEDIFF_T_MAX;
1736 what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
1739 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1740 *err = CURLE_SEND_ERROR;
1744 else if(0 == what) {
1745 failf(data, "schannel: timed out sending data "
1746 "(bytes sent: %zd)", written);
1747 *err = CURLE_OPERATION_TIMEDOUT;
1751 /* socket is writable */
1753 result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
1754 len - written, &this_write);
1755 if(result == CURLE_AGAIN)
1757 else if(result != CURLE_OK) {
1763 written += this_write;
1766 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1767 *err = CURLE_OUT_OF_MEMORY;
1770 *err = CURLE_SEND_ERROR;
1775 if(len == (size_t)written)
1776 /* Encrypted message including header, data and trailer entirely sent.
1777 The return value is the number of unencrypted bytes that were sent. */
1778 written = outbuf[1].cbBuffer;
1784 schannel_recv(struct Curl_easy *data, int sockindex,
1785 char *buf, size_t len, CURLcode *err)
1789 struct connectdata *conn = data->conn;
1790 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1791 unsigned char *reallocated_buffer;
1792 size_t reallocated_length;
1795 SecBufferDesc inbuf_desc;
1796 SECURITY_STATUS sspi_status = SEC_E_OK;
1797 /* we want the length of the encrypted buffer to be at least large enough
1798 that it can hold all the bytes requested and some TLS record overhead. */
1799 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1800 struct ssl_backend_data *backend = connssl->backend;
1802 DEBUGASSERT(backend);
1804 /****************************************************************************
1805 * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
1806 * The pattern for return error is set *err, optional infof, goto cleanup.
1808 * Our priority is to always return as much decrypted data to the caller as
1809 * possible, even if an error occurs. The state of the decrypted buffer must
1810 * always be valid. Transfer of decrypted data to the caller's buffer is
1811 * handled in the cleanup.
1814 DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
1817 if(len && len <= backend->decdata_offset) {
1818 infof(data, "schannel: enough decrypted data is already available");
1821 else if(backend->recv_unrecoverable_err) {
1822 *err = backend->recv_unrecoverable_err;
1823 infof(data, "schannel: an unrecoverable error occurred in a prior call");
1826 else if(backend->recv_sspi_close_notify) {
1827 /* once a server has indicated shutdown there is no more encrypted data */
1828 infof(data, "schannel: server indicated shutdown in a prior call");
1832 /* It's debatable what to return when !len. Regardless we can't return
1833 immediately because there may be data to decrypt (in the case we want to
1834 decrypt all encrypted cached data) so handle !len later in cleanup.
1836 else if(len && !backend->recv_connection_closed) {
1837 /* increase enc buffer in order to fit the requested amount of data */
1838 size = backend->encdata_length - backend->encdata_offset;
1839 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1840 backend->encdata_length < min_encdata_length) {
1841 reallocated_length = backend->encdata_offset +
1842 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1843 if(reallocated_length < min_encdata_length) {
1844 reallocated_length = min_encdata_length;
1846 reallocated_buffer = realloc(backend->encdata_buffer,
1847 reallocated_length);
1848 if(!reallocated_buffer) {
1849 *err = CURLE_OUT_OF_MEMORY;
1850 failf(data, "schannel: unable to re-allocate memory");
1854 backend->encdata_buffer = reallocated_buffer;
1855 backend->encdata_length = reallocated_length;
1856 size = backend->encdata_length - backend->encdata_offset;
1857 DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
1858 backend->encdata_length));
1862 "schannel: encrypted data buffer: offset %zu length %zu",
1863 backend->encdata_offset, backend->encdata_length));
1865 /* read encrypted data from socket */
1866 *err = Curl_read_plain(conn->sock[sockindex],
1867 (char *)(backend->encdata_buffer +
1868 backend->encdata_offset),
1872 if(*err == CURLE_AGAIN)
1874 "schannel: Curl_read_plain returned CURLE_AGAIN"));
1875 else if(*err == CURLE_RECV_ERROR)
1876 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
1878 infof(data, "schannel: Curl_read_plain returned error %d", *err);
1880 else if(nread == 0) {
1881 backend->recv_connection_closed = true;
1882 DEBUGF(infof(data, "schannel: server closed the connection"));
1884 else if(nread > 0) {
1885 backend->encdata_offset += (size_t)nread;
1886 backend->encdata_is_incomplete = false;
1887 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1892 "schannel: encrypted data buffer: offset %zu length %zu",
1893 backend->encdata_offset, backend->encdata_length));
1896 while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1897 (!len || backend->decdata_offset < len ||
1898 backend->recv_connection_closed)) {
1899 /* prepare data buffer for DecryptMessage call */
1900 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
1901 curlx_uztoul(backend->encdata_offset));
1903 /* we need 3 more empty input buffers for possible output */
1904 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1905 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1906 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1907 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1909 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1911 sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
1912 &inbuf_desc, 0, NULL);
1914 /* check if everything went fine (server may want to renegotiate
1915 or shutdown the connection context) */
1916 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1917 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1918 /* check for successfully decrypted data, even before actual
1919 renegotiation or shutdown of the connection context */
1920 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1921 DEBUGF(infof(data, "schannel: decrypted data length: %lu",
1922 inbuf[1].cbBuffer));
1924 /* increase buffer in order to fit the received amount of data */
1925 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1926 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1927 if(backend->decdata_length - backend->decdata_offset < size ||
1928 backend->decdata_length < len) {
1929 /* increase internal decrypted data buffer */
1930 reallocated_length = backend->decdata_offset + size;
1931 /* make sure that the requested amount of data fits */
1932 if(reallocated_length < len) {
1933 reallocated_length = len;
1935 reallocated_buffer = realloc(backend->decdata_buffer,
1936 reallocated_length);
1937 if(!reallocated_buffer) {
1938 *err = CURLE_OUT_OF_MEMORY;
1939 failf(data, "schannel: unable to re-allocate memory");
1942 backend->decdata_buffer = reallocated_buffer;
1943 backend->decdata_length = reallocated_length;
1946 /* copy decrypted data to internal buffer */
1947 size = inbuf[1].cbBuffer;
1949 memcpy(backend->decdata_buffer + backend->decdata_offset,
1950 inbuf[1].pvBuffer, size);
1951 backend->decdata_offset += size;
1954 DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
1956 "schannel: decrypted cached: offset %zu length %zu",
1957 backend->decdata_offset, backend->decdata_length));
1960 /* check for remaining encrypted data */
1961 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1962 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1963 inbuf[3].cbBuffer));
1965 /* check if the remaining data is less than the total amount
1966 * and therefore begins after the already processed data
1968 if(backend->encdata_offset > inbuf[3].cbBuffer) {
1969 /* move remaining encrypted data forward to the beginning of
1971 memmove(backend->encdata_buffer,
1972 (backend->encdata_buffer + backend->encdata_offset) -
1973 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1974 backend->encdata_offset = inbuf[3].cbBuffer;
1978 "schannel: encrypted cached: offset %zu length %zu",
1979 backend->encdata_offset, backend->encdata_length));
1982 /* reset encrypted buffer offset, because there is no data remaining */
1983 backend->encdata_offset = 0;
1986 /* check if server wants to renegotiate the connection context */
1987 if(sspi_status == SEC_I_RENEGOTIATE) {
1988 infof(data, "schannel: remote party requests renegotiation");
1989 if(*err && *err != CURLE_AGAIN) {
1990 infof(data, "schannel: can't renegotiate, an error is pending");
1993 if(backend->encdata_offset) {
1994 *err = CURLE_RECV_ERROR;
1995 infof(data, "schannel: can't renegotiate, "
1996 "encrypted data available");
1999 /* begin renegotiation */
2000 infof(data, "schannel: renegotiating SSL/TLS connection");
2001 connssl->state = ssl_connection_negotiating;
2002 connssl->connecting_state = ssl_connect_2_writing;
2003 *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
2005 infof(data, "schannel: renegotiation failed");
2008 /* now retry receiving data */
2009 sspi_status = SEC_E_OK;
2010 infof(data, "schannel: SSL/TLS connection renegotiated");
2013 /* check if the server closed the connection */
2014 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2015 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2016 returned so we have to work around that in cleanup. */
2017 backend->recv_sspi_close_notify = true;
2018 if(!backend->recv_connection_closed) {
2019 backend->recv_connection_closed = true;
2020 infof(data, "schannel: server closed the connection");
2025 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2026 backend->encdata_is_incomplete = true;
2029 infof(data, "schannel: failed to decrypt data, need more data");
2033 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2034 char buffer[STRERROR_LEN];
2036 *err = CURLE_RECV_ERROR;
2037 infof(data, "schannel: failed to read data from server: %s",
2038 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2044 "schannel: encrypted data buffer: offset %zu length %zu",
2045 backend->encdata_offset, backend->encdata_length));
2048 "schannel: decrypted data buffer: offset %zu length %zu",
2049 backend->decdata_offset, backend->decdata_length));
2052 /* Warning- there is no guarantee the encdata state is valid at this point */
2053 DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2055 /* Error if the connection has closed without a close_notify.
2057 The behavior here is a matter of debate. We don't want to be vulnerable
2058 to a truncation attack however there's some browser precedent for
2059 ignoring the close_notify for compatibility reasons.
2061 Additionally, Windows 2000 (v5.0) is a special case since it seems it
2062 doesn't return close_notify. In that case if the connection was closed we
2063 assume it was graceful (close_notify) since there doesn't seem to be a
2066 if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2067 !backend->recv_sspi_close_notify) {
2068 bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2071 if(isWin2k && sspi_status == SEC_E_OK)
2072 backend->recv_sspi_close_notify = true;
2074 *err = CURLE_RECV_ERROR;
2075 infof(data, "schannel: server closed abruptly (missing close_notify)");
2079 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2080 if(*err && *err != CURLE_AGAIN)
2081 backend->recv_unrecoverable_err = *err;
2083 size = len < backend->decdata_offset ? len : backend->decdata_offset;
2085 memcpy(buf, backend->decdata_buffer, size);
2086 memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2087 backend->decdata_offset - size);
2088 backend->decdata_offset -= size;
2089 DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2091 "schannel: decrypted data buffer: offset %zu length %zu",
2092 backend->decdata_offset, backend->decdata_length));
2094 return (ssize_t)size;
2097 if(!*err && !backend->recv_connection_closed)
2100 /* It's debatable what to return when !len. We could return whatever error
2101 we got from decryption but instead we override here so the return is
2107 return *err ? -1 : 0;
2110 static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
2111 struct connectdata *conn,
2112 int sockindex, bool *done)
2114 return schannel_connect_common(data, conn, sockindex, TRUE, done);
2117 static CURLcode schannel_connect(struct Curl_easy *data,
2118 struct connectdata *conn, int sockindex)
2123 result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
2132 static bool schannel_data_pending(const struct connectdata *conn,
2135 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2136 struct ssl_backend_data *backend = connssl->backend;
2138 DEBUGASSERT(backend);
2140 if(connssl->use) /* SSL/TLS is in use */
2141 return (backend->decdata_offset > 0 ||
2142 (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
2147 static void schannel_session_free(void *ptr)
2149 /* this is expected to be called under sessionid lock */
2150 struct Curl_schannel_cred *cred = ptr;
2154 if(cred->refcount == 0) {
2155 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
2156 curlx_unicodefree(cred->sni_hostname);
2157 Curl_safefree(cred);
2162 /* shut down the SSL connection and clean up related memory.
2163 this function can be called multiple times on the same connection including
2164 if the SSL connection failed (eg connection made but failed handshake). */
2165 static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
2168 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2169 * Shutting Down an Schannel Connection
2171 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2172 char * const hostname = SSL_HOST_NAME();
2173 struct ssl_backend_data *backend = connssl->backend;
2176 DEBUGASSERT(backend);
2179 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
2180 hostname, conn->remote_port);
2183 if(connssl->use && backend->cred && backend->ctxt) {
2184 SecBufferDesc BuffDesc;
2186 SECURITY_STATUS sspi_status;
2188 SecBufferDesc outbuf_desc;
2190 DWORD dwshut = SCHANNEL_SHUTDOWN;
2192 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2193 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2195 sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2198 if(sspi_status != SEC_E_OK) {
2199 char buffer[STRERROR_LEN];
2200 failf(data, "schannel: ApplyControlToken failure: %s",
2201 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2204 /* setup output buffer */
2205 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2206 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2208 sspi_status = s_pSecFn->InitializeSecurityContext(
2209 &backend->cred->cred_handle,
2210 &backend->ctxt->ctxt_handle,
2211 backend->cred->sni_hostname,
2217 &backend->ctxt->ctxt_handle,
2219 &backend->ret_flags,
2220 &backend->ctxt->time_stamp);
2222 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2223 /* send close message which is in output buffer */
2225 result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
2226 outbuf.cbBuffer, &written);
2228 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2229 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2230 infof(data, "schannel: failed to send close msg: %s"
2231 " (bytes written: %zd)", curl_easy_strerror(result), written);
2236 /* free SSPI Schannel API security context handle */
2238 DEBUGF(infof(data, "schannel: clear security context handle"));
2239 s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2240 Curl_safefree(backend->ctxt);
2243 /* free SSPI Schannel API credential handle */
2245 Curl_ssl_sessionid_lock(data);
2246 schannel_session_free(backend->cred);
2247 Curl_ssl_sessionid_unlock(data);
2248 backend->cred = NULL;
2251 /* free internal buffer for received encrypted data */
2252 if(backend->encdata_buffer) {
2253 Curl_safefree(backend->encdata_buffer);
2254 backend->encdata_length = 0;
2255 backend->encdata_offset = 0;
2256 backend->encdata_is_incomplete = false;
2259 /* free internal buffer for received decrypted data */
2260 if(backend->decdata_buffer) {
2261 Curl_safefree(backend->decdata_buffer);
2262 backend->decdata_length = 0;
2263 backend->decdata_offset = 0;
2269 static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
2272 if(conn->ssl[sockindex].use)
2273 /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
2274 Curl_ssl_shutdown(data, conn, sockindex);
2276 schannel_shutdown(data, conn, sockindex);
2279 static int schannel_init(void)
2281 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2284 static void schannel_cleanup(void)
2286 Curl_sspi_global_cleanup();
2289 static size_t schannel_version(char *buffer, size_t size)
2291 size = msnprintf(buffer, size, "Schannel");
2296 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2297 unsigned char *entropy, size_t length)
2299 HCRYPTPROV hCryptProv = 0;
2303 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2304 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2305 return CURLE_FAILED_INIT;
2307 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2308 CryptReleaseContext(hCryptProv, 0UL);
2309 return CURLE_FAILED_INIT;
2312 CryptReleaseContext(hCryptProv, 0UL);
2316 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
2317 struct connectdata *conn, int sockindex,
2318 const char *pinnedpubkey)
2320 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2321 struct ssl_backend_data *backend = connssl->backend;
2322 CERT_CONTEXT *pCertContextServer = NULL;
2324 /* Result is returned to caller */
2325 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2327 DEBUGASSERT(backend);
2329 /* if a path wasn't specified, don't pin */
2334 SECURITY_STATUS sspi_status;
2335 const char *x509_der;
2337 struct Curl_X509certificate x509_parsed;
2338 struct Curl_asn1Element *pubkey;
2341 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2342 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2343 &pCertContextServer);
2345 if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2346 char buffer[STRERROR_LEN];
2347 failf(data, "schannel: Failed to read remote certificate context: %s",
2348 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2353 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2354 (pCertContextServer->cbCertEncoded > 0)))
2357 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2358 x509_der_len = pCertContextServer->cbCertEncoded;
2359 memset(&x509_parsed, 0, sizeof(x509_parsed));
2360 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2363 pubkey = &x509_parsed.subjectPublicKeyInfo;
2364 if(!pubkey->header || pubkey->end <= pubkey->header) {
2365 failf(data, "SSL: failed retrieving public key from server certificate");
2369 result = Curl_pin_peer_pubkey(data,
2371 (const unsigned char *)pubkey->header,
2372 (size_t)(pubkey->end - pubkey->header));
2374 failf(data, "SSL: public key does not match pinned public key");
2378 if(pCertContextServer)
2379 CertFreeCertificateContext(pCertContextServer);
2384 static void schannel_checksum(const unsigned char *input,
2386 unsigned char *checksum,
2389 const unsigned int algId)
2391 HCRYPTPROV hProv = 0;
2392 HCRYPTHASH hHash = 0;
2393 DWORD cbHashSize = 0;
2394 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2395 DWORD dwChecksumLen = (DWORD)checksumlen;
2397 /* since this can fail in multiple ways, zero memory first so we never
2400 memset(checksum, 0, checksumlen);
2402 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2403 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2404 return; /* failed */
2407 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2410 /* workaround for original MinGW, should be (const BYTE*) */
2411 if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2415 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2419 /* check hash size */
2420 if(checksumlen < cbHashSize)
2423 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2428 CryptDestroyHash(hHash);
2431 CryptReleaseContext(hProv, 0);
2434 static CURLcode schannel_sha256sum(const unsigned char *input,
2436 unsigned char *sha256sum,
2439 schannel_checksum(input, inputlen, sha256sum, sha256len,
2440 PROV_RSA_AES, CALG_SHA_256);
2444 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2445 CURLINFO info UNUSED_PARAM)
2447 struct ssl_backend_data *backend = connssl->backend;
2449 DEBUGASSERT(backend);
2450 return &backend->ctxt->ctxt_handle;
2453 const struct Curl_ssl Curl_ssl_schannel = {
2454 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2457 #ifdef HAS_MANUAL_VERIFY_API
2458 SSLSUPP_CAINFO_BLOB |
2460 SSLSUPP_PINNEDPUBKEY,
2462 sizeof(struct ssl_backend_data),
2464 schannel_init, /* init */
2465 schannel_cleanup, /* cleanup */
2466 schannel_version, /* version */
2467 Curl_none_check_cxn, /* check_cxn */
2468 schannel_shutdown, /* shutdown */
2469 schannel_data_pending, /* data_pending */
2470 schannel_random, /* random */
2471 Curl_none_cert_status_request, /* cert_status_request */
2472 schannel_connect, /* connect */
2473 schannel_connect_nonblocking, /* connect_nonblocking */
2474 Curl_ssl_getsock, /* getsock */
2475 schannel_get_internals, /* get_internals */
2476 schannel_close, /* close_one */
2477 Curl_none_close_all, /* close_all */
2478 schannel_session_free, /* session_free */
2479 Curl_none_set_engine, /* set_engine */
2480 Curl_none_set_engine_default, /* set_engine_default */
2481 Curl_none_engines_list, /* engines_list */
2482 Curl_none_false_start, /* false_start */
2483 schannel_sha256sum, /* sha256sum */
2484 NULL, /* associate_connection */
2485 NULL /* disassociate_connection */
2488 #endif /* USE_SCHANNEL */