VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/vtls/schannel.c@ 98326

最後變更 在這個檔案從98326是 98326,由 vboxsync 提交於 2 年 前

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • 屬性 svn:eol-style 設為 native
檔案大小: 91.9 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2012 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 * Copyright (C) 2012 - 2016, Marc Hoersken, <[email protected]>
10 * Copyright (C) 2012, Mark Salisbury, <[email protected]>
11 *
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.
15 *
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.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 * SPDX-License-Identifier: curl
24 *
25 ***************************************************************************/
26
27/*
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.
30 */
31
32#include "curl_setup.h"
33
34#ifdef USE_SCHANNEL
35
36#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
37
38#ifndef USE_WINDOWS_SSPI
39# error "Can't compile SCHANNEL support without SSPI."
40#endif
41
42#include "schannel.h"
43#include "vtls.h"
44#include "vtls_int.h"
45#include "strcase.h"
46#include "sendf.h"
47#include "connect.h" /* for the connect timeout */
48#include "strerror.h"
49#include "select.h" /* for the socket readiness */
50#include "inet_pton.h" /* for IP addr SNI check */
51#include "curl_multibyte.h"
52#include "warnless.h"
53#include "x509asn1.h"
54#include "curl_printf.h"
55#include "multiif.h"
56#include "version_win32.h"
57#include "rand.h"
58
59/* The last #include file should be: */
60#include "curl_memory.h"
61#include "memdebug.h"
62
63/* ALPN requires version 8.1 of the Windows SDK, which was
64 shipped with Visual Studio 2013, aka _MSC_VER 1800:
65
66 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
67*/
68#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
69# define HAS_ALPN 1
70#endif
71
72#ifndef UNISP_NAME_A
73#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
74#endif
75
76#ifndef UNISP_NAME_W
77#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
78#endif
79
80#ifndef UNISP_NAME
81#ifdef UNICODE
82#define UNISP_NAME UNISP_NAME_W
83#else
84#define UNISP_NAME UNISP_NAME_A
85#endif
86#endif
87
88#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
89#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
90#endif
91
92#ifndef BCRYPT_CHAIN_MODE_CCM
93#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM"
94#endif
95
96#ifndef BCRYPT_CHAIN_MODE_GCM
97#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM"
98#endif
99
100#ifndef BCRYPT_AES_ALGORITHM
101#define BCRYPT_AES_ALGORITHM L"AES"
102#endif
103
104#ifndef BCRYPT_SHA256_ALGORITHM
105#define BCRYPT_SHA256_ALGORITHM L"SHA256"
106#endif
107
108#ifndef BCRYPT_SHA384_ALGORITHM
109#define BCRYPT_SHA384_ALGORITHM L"SHA384"
110#endif
111
112/* Workaround broken compilers like MinGW.
113 Return the number of elements in a statically sized array.
114*/
115#ifndef ARRAYSIZE
116#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
117#endif
118
119#ifdef HAS_CLIENT_CERT_PATH
120#ifdef UNICODE
121#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
122#else
123#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
124#endif
125#endif
126
127#ifndef SP_PROT_SSL2_CLIENT
128#define SP_PROT_SSL2_CLIENT 0x00000008
129#endif
130
131#ifndef SP_PROT_SSL3_CLIENT
132#define SP_PROT_SSL3_CLIENT 0x00000008
133#endif
134
135#ifndef SP_PROT_TLS1_CLIENT
136#define SP_PROT_TLS1_CLIENT 0x00000080
137#endif
138
139#ifndef SP_PROT_TLS1_0_CLIENT
140#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
141#endif
142
143#ifndef SP_PROT_TLS1_1_CLIENT
144#define SP_PROT_TLS1_1_CLIENT 0x00000200
145#endif
146
147#ifndef SP_PROT_TLS1_2_CLIENT
148#define SP_PROT_TLS1_2_CLIENT 0x00000800
149#endif
150
151#ifndef SP_PROT_TLS1_3_CLIENT
152#define SP_PROT_TLS1_3_CLIENT 0x00002000
153#endif
154
155#ifndef SCH_USE_STRONG_CRYPTO
156#define SCH_USE_STRONG_CRYPTO 0x00400000
157#endif
158
159#ifndef SECBUFFER_ALERT
160#define SECBUFFER_ALERT 17
161#endif
162
163/* Both schannel buffer sizes must be > 0 */
164#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
165#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
166
167#define CERT_THUMBPRINT_STR_LEN 40
168#define CERT_THUMBPRINT_DATA_LEN 20
169
170/* Uncomment to force verbose output
171 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
172 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
173 */
174
175#ifndef CALG_SHA_256
176# define CALG_SHA_256 0x0000800c
177#endif
178
179/* Work around typo in classic MinGW's w32api up to version 5.0,
180 see https://osdn.net/projects/mingw/ticket/38391 */
181#if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH)
182#define ALG_CLASS_DHASH ALG_CLASS_HASH
183#endif
184
185#ifndef PKCS12_NO_PERSIST_KEY
186#define PKCS12_NO_PERSIST_KEY 0x00008000
187#endif
188
189static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
190 struct Curl_easy *data,
191 const char *pinnedpubkey);
192
193static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
194 void *BufDataPtr, unsigned long BufByteSize)
195{
196 buffer->cbBuffer = BufByteSize;
197 buffer->BufferType = BufType;
198 buffer->pvBuffer = BufDataPtr;
199}
200
201static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
202 unsigned long NumArrElem)
203{
204 desc->ulVersion = SECBUFFER_VERSION;
205 desc->pBuffers = BufArr;
206 desc->cBuffers = NumArrElem;
207}
208
209static CURLcode
210set_ssl_version_min_max(DWORD *enabled_protocols,
211 struct Curl_cfilter *cf,
212 struct Curl_easy *data)
213{
214 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
215 long ssl_version = conn_config->version;
216 long ssl_version_max = conn_config->version_max;
217 long i = ssl_version;
218
219 switch(ssl_version_max) {
220 case CURL_SSLVERSION_MAX_NONE:
221 case CURL_SSLVERSION_MAX_DEFAULT:
222
223 /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3
224 built-in. Previous builds of Windows 10 had broken TLS 1.3
225 implementations that could be enabled via registry.
226 */
227 if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
228 VERSION_GREATER_THAN_EQUAL)) {
229 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
230 }
231 else /* Windows 10 and older */
232 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
233
234 break;
235 }
236
237 for(; i <= (ssl_version_max >> 16); ++i) {
238 switch(i) {
239 case CURL_SSLVERSION_TLSv1_0:
240 (*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT;
241 break;
242 case CURL_SSLVERSION_TLSv1_1:
243 (*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT;
244 break;
245 case CURL_SSLVERSION_TLSv1_2:
246 (*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT;
247 break;
248 case CURL_SSLVERSION_TLSv1_3:
249
250 /* Windows Server 2022 and newer */
251 if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
252 VERSION_GREATER_THAN_EQUAL)) {
253 (*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT;
254 break;
255 }
256 else { /* Windows 10 and older */
257 failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11");
258 return CURLE_SSL_CONNECT_ERROR;
259 }
260 }
261 }
262 return CURLE_OK;
263}
264
265/* longest is 26, buffer is slightly bigger */
266#define LONGEST_ALG_ID 32
267#define CIPHEROPTION(X) \
268 if(strcmp(#X, tmp) == 0) \
269 return X
270
271static int
272get_alg_id_by_name(char *name)
273{
274 char tmp[LONGEST_ALG_ID] = { 0 };
275 char *nameEnd = strchr(name, ':');
276 size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
277
278 /* reject too-long alg names */
279 if(n > (LONGEST_ALG_ID - 1))
280 return 0;
281
282 strncpy(tmp, name, n);
283 tmp[n] = 0;
284 CIPHEROPTION(CALG_MD2);
285 CIPHEROPTION(CALG_MD4);
286 CIPHEROPTION(CALG_MD5);
287 CIPHEROPTION(CALG_SHA);
288 CIPHEROPTION(CALG_SHA1);
289 CIPHEROPTION(CALG_MAC);
290 CIPHEROPTION(CALG_RSA_SIGN);
291 CIPHEROPTION(CALG_DSS_SIGN);
292/* ifdefs for the options that are defined conditionally in wincrypt.h */
293#ifdef CALG_NO_SIGN
294 CIPHEROPTION(CALG_NO_SIGN);
295#endif
296 CIPHEROPTION(CALG_RSA_KEYX);
297 CIPHEROPTION(CALG_DES);
298#ifdef CALG_3DES_112
299 CIPHEROPTION(CALG_3DES_112);
300#endif
301 CIPHEROPTION(CALG_3DES);
302 CIPHEROPTION(CALG_DESX);
303 CIPHEROPTION(CALG_RC2);
304 CIPHEROPTION(CALG_RC4);
305 CIPHEROPTION(CALG_SEAL);
306#ifdef CALG_DH_SF
307 CIPHEROPTION(CALG_DH_SF);
308#endif
309 CIPHEROPTION(CALG_DH_EPHEM);
310#ifdef CALG_AGREEDKEY_ANY
311 CIPHEROPTION(CALG_AGREEDKEY_ANY);
312#endif
313#ifdef CALG_HUGHES_MD5
314 CIPHEROPTION(CALG_HUGHES_MD5);
315#endif
316 CIPHEROPTION(CALG_SKIPJACK);
317#ifdef CALG_TEK
318 CIPHEROPTION(CALG_TEK);
319#endif
320 CIPHEROPTION(CALG_CYLINK_MEK);
321 CIPHEROPTION(CALG_SSL3_SHAMD5);
322#ifdef CALG_SSL3_MASTER
323 CIPHEROPTION(CALG_SSL3_MASTER);
324#endif
325#ifdef CALG_SCHANNEL_MASTER_HASH
326 CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
327#endif
328#ifdef CALG_SCHANNEL_MAC_KEY
329 CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
330#endif
331#ifdef CALG_SCHANNEL_ENC_KEY
332 CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
333#endif
334#ifdef CALG_PCT1_MASTER
335 CIPHEROPTION(CALG_PCT1_MASTER);
336#endif
337#ifdef CALG_SSL2_MASTER
338 CIPHEROPTION(CALG_SSL2_MASTER);
339#endif
340#ifdef CALG_TLS1_MASTER
341 CIPHEROPTION(CALG_TLS1_MASTER);
342#endif
343#ifdef CALG_RC5
344 CIPHEROPTION(CALG_RC5);
345#endif
346#ifdef CALG_HMAC
347 CIPHEROPTION(CALG_HMAC);
348#endif
349#ifdef CALG_TLS1PRF
350 CIPHEROPTION(CALG_TLS1PRF);
351#endif
352#ifdef CALG_HASH_REPLACE_OWF
353 CIPHEROPTION(CALG_HASH_REPLACE_OWF);
354#endif
355#ifdef CALG_AES_128
356 CIPHEROPTION(CALG_AES_128);
357#endif
358#ifdef CALG_AES_192
359 CIPHEROPTION(CALG_AES_192);
360#endif
361#ifdef CALG_AES_256
362 CIPHEROPTION(CALG_AES_256);
363#endif
364#ifdef CALG_AES
365 CIPHEROPTION(CALG_AES);
366#endif
367#ifdef CALG_SHA_256
368 CIPHEROPTION(CALG_SHA_256);
369#endif
370#ifdef CALG_SHA_384
371 CIPHEROPTION(CALG_SHA_384);
372#endif
373#ifdef CALG_SHA_512
374 CIPHEROPTION(CALG_SHA_512);
375#endif
376#ifdef CALG_ECDH
377 CIPHEROPTION(CALG_ECDH);
378#endif
379#ifdef CALG_ECMQV
380 CIPHEROPTION(CALG_ECMQV);
381#endif
382#ifdef CALG_ECDSA
383 CIPHEROPTION(CALG_ECDSA);
384#endif
385#ifdef CALG_ECDH_EPHEM
386 CIPHEROPTION(CALG_ECDH_EPHEM);
387#endif
388 return 0;
389}
390
391#define NUM_CIPHERS 47 /* There are 47 options listed above */
392
393static CURLcode
394set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
395 ALG_ID *algIds)
396{
397 char *startCur = ciphers;
398 int algCount = 0;
399 while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
400 long alg = strtol(startCur, 0, 0);
401 if(!alg)
402 alg = get_alg_id_by_name(startCur);
403 if(alg)
404 algIds[algCount++] = alg;
405 else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
406 sizeof("USE_STRONG_CRYPTO") - 1) ||
407 !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
408 sizeof("SCH_USE_STRONG_CRYPTO") - 1))
409 schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
410 else
411 return CURLE_SSL_CIPHER;
412 startCur = strchr(startCur, ':');
413 if(startCur)
414 startCur++;
415 }
416 schannel_cred->palgSupportedAlgs = algIds;
417 schannel_cred->cSupportedAlgs = algCount;
418 return CURLE_OK;
419}
420
421#ifdef HAS_CLIENT_CERT_PATH
422
423/* Function allocates memory for store_path only if CURLE_OK is returned */
424static CURLcode
425get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
426 TCHAR **thumbprint)
427{
428 TCHAR *sep;
429 TCHAR *store_path_start;
430 size_t store_name_len;
431
432 sep = _tcschr(path, TEXT('\\'));
433 if(!sep)
434 return CURLE_SSL_CERTPROBLEM;
435
436 store_name_len = sep - path;
437
438 if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
439 *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
440 else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
441 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
442 else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
443 *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
444 else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
445 *store_name = CERT_SYSTEM_STORE_SERVICES;
446 else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
447 *store_name = CERT_SYSTEM_STORE_USERS;
448 else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
449 store_name_len) == 0)
450 *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
451 else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
452 store_name_len) == 0)
453 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
454 else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
455 store_name_len) == 0)
456 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
457 else
458 return CURLE_SSL_CERTPROBLEM;
459
460 store_path_start = sep + 1;
461
462 sep = _tcschr(store_path_start, TEXT('\\'));
463 if(!sep)
464 return CURLE_SSL_CERTPROBLEM;
465
466 *thumbprint = sep + 1;
467 if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
468 return CURLE_SSL_CERTPROBLEM;
469
470 *sep = TEXT('\0');
471 *store_path = _tcsdup(store_path_start);
472 *sep = TEXT('\\');
473 if(!*store_path)
474 return CURLE_OUT_OF_MEMORY;
475
476 return CURLE_OK;
477}
478#endif
479static CURLcode
480schannel_acquire_credential_handle(struct Curl_cfilter *cf,
481 struct Curl_easy *data)
482{
483 struct ssl_connect_data *connssl = cf->ctx;
484 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
485 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
486
487#ifdef HAS_CLIENT_CERT_PATH
488 PCCERT_CONTEXT client_certs[1] = { NULL };
489 HCERTSTORE client_cert_store = NULL;
490#endif
491 SECURITY_STATUS sspi_status = SEC_E_OK;
492 CURLcode result;
493
494 /* setup Schannel API options */
495 DWORD flags = 0;
496 DWORD enabled_protocols = 0;
497
498 struct ssl_backend_data *backend = connssl->backend;
499
500 DEBUGASSERT(backend);
501
502 if(conn_config->verifypeer) {
503#ifdef HAS_MANUAL_VERIFY_API
504 if(backend->use_manual_cred_validation)
505 flags = SCH_CRED_MANUAL_CRED_VALIDATION;
506 else
507#endif
508 flags = SCH_CRED_AUTO_CRED_VALIDATION;
509
510 if(ssl_config->no_revoke) {
511 flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
512 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
513
514 DEBUGF(infof(data, "schannel: disabled server certificate revocation "
515 "checks"));
516 }
517 else if(ssl_config->revoke_best_effort) {
518 flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
519 SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
520
521 DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
522 }
523 else {
524 flags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
525
526 DEBUGF(infof(data,
527 "schannel: checking server certificate revocation"));
528 }
529 }
530 else {
531 flags = SCH_CRED_MANUAL_CRED_VALIDATION |
532 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
533 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
534 DEBUGF(infof(data,
535 "schannel: disabled server cert revocation checks"));
536 }
537
538 if(!conn_config->verifyhost) {
539 flags |= SCH_CRED_NO_SERVERNAME_CHECK;
540 DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
541 "comparing the supplied target name with the subject "
542 "names in server certificates."));
543 }
544
545 if(!ssl_config->auto_client_cert) {
546 flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
547 flags |= SCH_CRED_NO_DEFAULT_CREDS;
548 infof(data, "schannel: disabled automatic use of client certificate");
549 }
550 else
551 infof(data, "schannel: enabled automatic use of client certificate");
552
553 switch(conn_config->version) {
554 case CURL_SSLVERSION_DEFAULT:
555 case CURL_SSLVERSION_TLSv1:
556 case CURL_SSLVERSION_TLSv1_0:
557 case CURL_SSLVERSION_TLSv1_1:
558 case CURL_SSLVERSION_TLSv1_2:
559 case CURL_SSLVERSION_TLSv1_3:
560 {
561 result = set_ssl_version_min_max(&enabled_protocols, cf, data);
562 if(result != CURLE_OK)
563 return result;
564 break;
565 }
566 case CURL_SSLVERSION_SSLv3:
567 case CURL_SSLVERSION_SSLv2:
568 failf(data, "SSL versions not supported");
569 return CURLE_NOT_BUILT_IN;
570 default:
571 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
572 return CURLE_SSL_CONNECT_ERROR;
573 }
574
575#ifdef HAS_CLIENT_CERT_PATH
576 /* client certificate */
577 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
578 DWORD cert_store_name = 0;
579 TCHAR *cert_store_path = NULL;
580 TCHAR *cert_thumbprint_str = NULL;
581 CRYPT_HASH_BLOB cert_thumbprint;
582 BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
583 HCERTSTORE cert_store = NULL;
584 FILE *fInCert = NULL;
585 void *certdata = NULL;
586 size_t certsize = 0;
587 bool blob = data->set.ssl.primary.cert_blob != NULL;
588 TCHAR *cert_path = NULL;
589 if(blob) {
590 certdata = data->set.ssl.primary.cert_blob->data;
591 certsize = data->set.ssl.primary.cert_blob->len;
592 }
593 else {
594 cert_path = curlx_convert_UTF8_to_tchar(
595 data->set.ssl.primary.clientcert);
596 if(!cert_path)
597 return CURLE_OUT_OF_MEMORY;
598
599 result = get_cert_location(cert_path, &cert_store_name,
600 &cert_store_path, &cert_thumbprint_str);
601
602 if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
603 fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
604
605 if(result && !fInCert) {
606 failf(data, "schannel: Failed to get certificate location"
607 " or file for %s",
608 data->set.ssl.primary.clientcert);
609 curlx_unicodefree(cert_path);
610 return result;
611 }
612 }
613
614 if((fInCert || blob) && (data->set.ssl.cert_type) &&
615 (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
616 failf(data, "schannel: certificate format compatibility error "
617 " for %s",
618 blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
619 curlx_unicodefree(cert_path);
620 return CURLE_SSL_CERTPROBLEM;
621 }
622
623 if(fInCert || blob) {
624 /* Reading a .P12 or .pfx file, like the example at bottom of
625 https://social.msdn.microsoft.com/Forums/windowsdesktop/
626 en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
627 */
628 CRYPT_DATA_BLOB datablob;
629 WCHAR* pszPassword;
630 size_t pwd_len = 0;
631 int str_w_len = 0;
632 const char *cert_showfilename_error = blob ?
633 "(memory blob)" : data->set.ssl.primary.clientcert;
634 curlx_unicodefree(cert_path);
635 if(fInCert) {
636 long cert_tell = 0;
637 bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
638 if(continue_reading)
639 cert_tell = ftell(fInCert);
640 if(cert_tell < 0)
641 continue_reading = FALSE;
642 else
643 certsize = (size_t)cert_tell;
644 if(continue_reading)
645 continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
646 if(continue_reading)
647 certdata = malloc(certsize + 1);
648 if((!certdata) ||
649 ((int) fread(certdata, certsize, 1, fInCert) != 1))
650 continue_reading = FALSE;
651 fclose(fInCert);
652 if(!continue_reading) {
653 failf(data, "schannel: Failed to read cert file %s",
654 data->set.ssl.primary.clientcert);
655 free(certdata);
656 return CURLE_SSL_CERTPROBLEM;
657 }
658 }
659
660 /* Convert key-pair data to the in-memory certificate store */
661 datablob.pbData = (BYTE*)certdata;
662 datablob.cbData = (DWORD)certsize;
663
664 if(data->set.ssl.key_passwd)
665 pwd_len = strlen(data->set.ssl.key_passwd);
666 pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
667 if(pszPassword) {
668 if(pwd_len > 0)
669 str_w_len = MultiByteToWideChar(CP_UTF8,
670 MB_ERR_INVALID_CHARS,
671 data->set.ssl.key_passwd,
672 (int)pwd_len,
673 pszPassword, (int)(pwd_len + 1));
674
675 if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
676 pszPassword[str_w_len] = 0;
677 else
678 pszPassword[0] = 0;
679
680 if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
681 VERSION_GREATER_THAN_EQUAL))
682 cert_store = PFXImportCertStore(&datablob, pszPassword,
683 PKCS12_NO_PERSIST_KEY);
684 else
685 cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
686
687 free(pszPassword);
688 }
689 if(!blob)
690 free(certdata);
691 if(!cert_store) {
692 DWORD errorcode = GetLastError();
693 if(errorcode == ERROR_INVALID_PASSWORD)
694 failf(data, "schannel: Failed to import cert file %s, "
695 "password is bad",
696 cert_showfilename_error);
697 else
698 failf(data, "schannel: Failed to import cert file %s, "
699 "last error is 0x%x",
700 cert_showfilename_error, errorcode);
701 return CURLE_SSL_CERTPROBLEM;
702 }
703
704 client_certs[0] = CertFindCertificateInStore(
705 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
706 CERT_FIND_ANY, NULL, NULL);
707
708 if(!client_certs[0]) {
709 failf(data, "schannel: Failed to get certificate from file %s"
710 ", last error is 0x%x",
711 cert_showfilename_error, GetLastError());
712 CertCloseStore(cert_store, 0);
713 return CURLE_SSL_CERTPROBLEM;
714 }
715 }
716 else {
717 cert_store =
718 CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
719 (HCRYPTPROV)NULL,
720 CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
721 cert_store_path);
722 if(!cert_store) {
723 failf(data, "schannel: Failed to open cert store %x %s, "
724 "last error is 0x%x",
725 cert_store_name, cert_store_path, GetLastError());
726 free(cert_store_path);
727 curlx_unicodefree(cert_path);
728 return CURLE_SSL_CERTPROBLEM;
729 }
730 free(cert_store_path);
731
732 cert_thumbprint.pbData = cert_thumbprint_data;
733 cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
734
735 if(!CryptStringToBinary(cert_thumbprint_str,
736 CERT_THUMBPRINT_STR_LEN,
737 CRYPT_STRING_HEX,
738 cert_thumbprint_data,
739 &cert_thumbprint.cbData,
740 NULL, NULL)) {
741 curlx_unicodefree(cert_path);
742 CertCloseStore(cert_store, 0);
743 return CURLE_SSL_CERTPROBLEM;
744 }
745
746 client_certs[0] = CertFindCertificateInStore(
747 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
748 CERT_FIND_HASH, &cert_thumbprint, NULL);
749
750 curlx_unicodefree(cert_path);
751
752 if(!client_certs[0]) {
753 /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
754 CertCloseStore(cert_store, 0);
755 return CURLE_SSL_CERTPROBLEM;
756 }
757 }
758 client_cert_store = cert_store;
759 }
760#else
761 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
762 failf(data, "schannel: client cert support not built in");
763 return CURLE_NOT_BUILT_IN;
764 }
765#endif
766
767 /* allocate memory for the re-usable credential handle */
768 backend->cred = (struct Curl_schannel_cred *)
769 calloc(1, sizeof(struct Curl_schannel_cred));
770 if(!backend->cred) {
771 failf(data, "schannel: unable to allocate memory");
772
773#ifdef HAS_CLIENT_CERT_PATH
774 if(client_certs[0])
775 CertFreeCertificateContext(client_certs[0]);
776 if(client_cert_store)
777 CertCloseStore(client_cert_store, 0);
778#endif
779
780 return CURLE_OUT_OF_MEMORY;
781 }
782 backend->cred->refcount = 1;
783
784#ifdef HAS_CLIENT_CERT_PATH
785 /* Since we did not persist the key, we need to extend the store's
786 * lifetime until the end of the connection
787 */
788 backend->cred->client_cert_store = client_cert_store;
789#endif
790
791 /* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */
792 if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
793 VERSION_GREATER_THAN_EQUAL)) {
794
795 char *ciphers13 = 0;
796
797 bool disable_aes_gcm_sha384 = FALSE;
798 bool disable_aes_gcm_sha256 = FALSE;
799 bool disable_chacha_poly = FALSE;
800 bool disable_aes_ccm_8_sha256 = FALSE;
801 bool disable_aes_ccm_sha256 = FALSE;
802
803 SCH_CREDENTIALS credentials = { 0 };
804 TLS_PARAMETERS tls_parameters = { 0 };
805 CRYPTO_SETTINGS crypto_settings[4] = { 0 };
806 UNICODE_STRING blocked_ccm_modes[1] = { 0 };
807 UNICODE_STRING blocked_gcm_modes[1] = { 0 };
808
809 int crypto_settings_idx = 0;
810
811
812 /* If TLS 1.3 ciphers are explicitly listed, then
813 * disable all the ciphers and re-enable which
814 * ciphers the user has provided.
815 */
816 ciphers13 = conn_config->cipher_list13;
817 if(ciphers13) {
818 const int remaining_ciphers = 5;
819
820 /* detect which remaining ciphers to enable
821 and then disable everything else.
822 */
823
824 char *startCur = ciphers13;
825 int algCount = 0;
826 char tmp[LONGEST_ALG_ID] = { 0 };
827 char *nameEnd;
828 size_t n;
829
830 disable_aes_gcm_sha384 = TRUE;
831 disable_aes_gcm_sha256 = TRUE;
832 disable_chacha_poly = TRUE;
833 disable_aes_ccm_8_sha256 = TRUE;
834 disable_aes_ccm_sha256 = TRUE;
835
836 while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
837 nameEnd = strchr(startCur, ':');
838 n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
839
840 /* reject too-long cipher names */
841 if(n > (LONGEST_ALG_ID - 1)) {
842 failf(data, "Cipher name too long, not checked.");
843 return CURLE_SSL_CIPHER;
844 }
845
846 strncpy(tmp, startCur, n);
847 tmp[n] = 0;
848
849 if(disable_aes_gcm_sha384
850 && !strcmp("TLS_AES_256_GCM_SHA384", tmp)) {
851 disable_aes_gcm_sha384 = FALSE;
852 }
853 else if(disable_aes_gcm_sha256
854 && !strcmp("TLS_AES_128_GCM_SHA256", tmp)) {
855 disable_aes_gcm_sha256 = FALSE;
856 }
857 else if(disable_chacha_poly
858 && !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) {
859 disable_chacha_poly = FALSE;
860 }
861 else if(disable_aes_ccm_8_sha256
862 && !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) {
863 disable_aes_ccm_8_sha256 = FALSE;
864 }
865 else if(disable_aes_ccm_sha256
866 && !strcmp("TLS_AES_128_CCM_SHA256", tmp)) {
867 disable_aes_ccm_sha256 = FALSE;
868 }
869 else {
870 failf(data, "Passed in an unknown TLS 1.3 cipher.");
871 return CURLE_SSL_CIPHER;
872 }
873
874 startCur = nameEnd;
875 if(startCur)
876 startCur++;
877
878 algCount++;
879 }
880 }
881
882 if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
883 && disable_chacha_poly && disable_aes_ccm_8_sha256
884 && disable_aes_ccm_sha256) {
885 failf(data, "All available TLS 1.3 ciphers were disabled.");
886 return CURLE_SSL_CIPHER;
887 }
888
889 /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */
890 if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) {
891 /*
892 Disallow AES_CCM algorithm.
893 */
894 blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM);
895 blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM);
896 blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM;
897
898 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
899 TlsParametersCngAlgUsageCipher;
900 crypto_settings[crypto_settings_idx].rgstrChainingModes =
901 blocked_ccm_modes;
902 crypto_settings[crypto_settings_idx].cChainingModes =
903 ARRAYSIZE(blocked_ccm_modes);
904 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
905 sizeof(BCRYPT_AES_ALGORITHM);
906 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
907 sizeof(BCRYPT_AES_ALGORITHM);
908 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
909 (PWSTR)BCRYPT_AES_ALGORITHM;
910
911 /* only disabling one of the CCM modes */
912 if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) {
913 if(disable_aes_ccm_8_sha256)
914 crypto_settings[crypto_settings_idx].dwMinBitLength = 128;
915 else /* disable_aes_ccm_sha256 */
916 crypto_settings[crypto_settings_idx].dwMaxBitLength = 64;
917 }
918
919 crypto_settings_idx++;
920 }
921
922 /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */
923 if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) {
924
925 /*
926 Disallow AES_GCM algorithm
927 */
928 blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM);
929 blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM);
930 blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM;
931
932 /* if only one is disabled, then explicitly disable the
933 digest cipher suite (sha384 or sha256) */
934 if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) {
935 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
936 TlsParametersCngAlgUsageDigest;
937 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
938 sizeof(disable_aes_gcm_sha384 ?
939 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
940 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
941 sizeof(disable_aes_gcm_sha384 ?
942 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
943 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
944 (PWSTR)(disable_aes_gcm_sha384 ?
945 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
946 }
947 else { /* Disable both AES_GCM ciphers */
948 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
949 TlsParametersCngAlgUsageCipher;
950 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
951 sizeof(BCRYPT_AES_ALGORITHM);
952 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
953 sizeof(BCRYPT_AES_ALGORITHM);
954 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
955 (PWSTR)BCRYPT_AES_ALGORITHM;
956 }
957
958 crypto_settings[crypto_settings_idx].rgstrChainingModes =
959 blocked_gcm_modes;
960 crypto_settings[crypto_settings_idx].cChainingModes = 1;
961
962 crypto_settings_idx++;
963 }
964
965 /*
966 Disable ChaCha20-Poly1305.
967 */
968 if(disable_chacha_poly) {
969 crypto_settings[crypto_settings_idx].eAlgorithmUsage =
970 TlsParametersCngAlgUsageCipher;
971 crypto_settings[crypto_settings_idx].strCngAlgId.Length =
972 sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
973 crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
974 sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
975 crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
976 (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
977 crypto_settings_idx++;
978 }
979
980 tls_parameters.pDisabledCrypto = crypto_settings;
981
982 /* The number of blocked suites */
983 tls_parameters.cDisabledCrypto = crypto_settings_idx;
984 credentials.pTlsParameters = &tls_parameters;
985 credentials.cTlsParameters = 1;
986
987 credentials.dwVersion = SCH_CREDENTIALS_VERSION;
988 credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
989
990 credentials.pTlsParameters->grbitDisabledProtocols =
991 (DWORD)~enabled_protocols;
992
993#ifdef HAS_CLIENT_CERT_PATH
994 if(client_certs[0]) {
995 credentials.cCreds = 1;
996 credentials.paCred = client_certs;
997 }
998#endif
999
1000 sspi_status =
1001 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
1002 SECPKG_CRED_OUTBOUND, NULL,
1003 &credentials, NULL, NULL,
1004 &backend->cred->cred_handle,
1005 &backend->cred->time_stamp);
1006 }
1007 else {
1008 /* Pre-Windows 10 1809 */
1009 ALG_ID algIds[NUM_CIPHERS];
1010 char *ciphers = conn_config->cipher_list;
1011 SCHANNEL_CRED schannel_cred = { 0 };
1012 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
1013 schannel_cred.dwFlags = flags;
1014 schannel_cred.grbitEnabledProtocols = enabled_protocols;
1015
1016 if(ciphers) {
1017 result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
1018 if(CURLE_OK != result) {
1019 failf(data, "Unable to set ciphers to from connection ssl config");
1020 return result;
1021 }
1022 }
1023 else {
1024 schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
1025 }
1026
1027#ifdef HAS_CLIENT_CERT_PATH
1028 if(client_certs[0]) {
1029 schannel_cred.cCreds = 1;
1030 schannel_cred.paCred = client_certs;
1031 }
1032#endif
1033
1034 sspi_status =
1035 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
1036 SECPKG_CRED_OUTBOUND, NULL,
1037 &schannel_cred, NULL, NULL,
1038 &backend->cred->cred_handle,
1039 &backend->cred->time_stamp);
1040 }
1041
1042#ifdef HAS_CLIENT_CERT_PATH
1043 if(client_certs[0])
1044 CertFreeCertificateContext(client_certs[0]);
1045#endif
1046
1047 if(sspi_status != SEC_E_OK) {
1048 char buffer[STRERROR_LEN];
1049 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
1050 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1051 Curl_safefree(backend->cred);
1052 switch(sspi_status) {
1053 case SEC_E_INSUFFICIENT_MEMORY:
1054 return CURLE_OUT_OF_MEMORY;
1055 case SEC_E_NO_CREDENTIALS:
1056 case SEC_E_SECPKG_NOT_FOUND:
1057 case SEC_E_NOT_OWNER:
1058 case SEC_E_UNKNOWN_CREDENTIALS:
1059 case SEC_E_INTERNAL_ERROR:
1060 default:
1061 return CURLE_SSL_CONNECT_ERROR;
1062 }
1063 }
1064
1065 return CURLE_OK;
1066}
1067
1068static CURLcode
1069schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
1070{
1071 ssize_t written = -1;
1072 struct ssl_connect_data *connssl = cf->ctx;
1073 struct ssl_backend_data *backend = connssl->backend;
1074 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1075 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1076 SecBuffer outbuf;
1077 SecBufferDesc outbuf_desc;
1078 SecBuffer inbuf;
1079 SecBufferDesc inbuf_desc;
1080#ifdef HAS_ALPN
1081 unsigned char alpn_buffer[128];
1082#endif
1083 SECURITY_STATUS sspi_status = SEC_E_OK;
1084 struct Curl_schannel_cred *old_cred = NULL;
1085 struct in_addr addr;
1086#ifdef ENABLE_IPV6
1087 struct in6_addr addr6;
1088#endif
1089 CURLcode result;
1090 const char *hostname = connssl->hostname;
1091
1092 DEBUGASSERT(backend);
1093 DEBUGF(infof(data,
1094 "schannel: SSL/TLS connection with %s port %d (step 1/3)",
1095 hostname, connssl->port));
1096
1097 if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
1098 VERSION_LESS_THAN_EQUAL)) {
1099 /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
1100 algorithms that may not be supported by all servers. */
1101 infof(data, "schannel: Windows version is old and may not be able to "
1102 "connect to some servers due to lack of SNI, algorithms, etc.");
1103 }
1104
1105#ifdef HAS_ALPN
1106 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
1107 Also it doesn't seem to be supported for Wine, see curl bug #983. */
1108 backend->use_alpn = cf->conn->bits.tls_enable_alpn &&
1109 !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
1110 "wine_get_version") &&
1111 curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
1112 VERSION_GREATER_THAN_EQUAL);
1113#else
1114 backend->use_alpn = false;
1115#endif
1116
1117#ifdef _WIN32_WCE
1118#ifdef HAS_MANUAL_VERIFY_API
1119 /* certificate validation on CE doesn't seem to work right; we'll
1120 * do it following a more manual process. */
1121 backend->use_manual_cred_validation = true;
1122#else
1123#error "compiler too old to support requisite manual cert verify for Win CE"
1124#endif
1125#else
1126#ifdef HAS_MANUAL_VERIFY_API
1127 if(conn_config->CAfile || conn_config->ca_info_blob) {
1128 if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
1129 VERSION_GREATER_THAN_EQUAL)) {
1130 backend->use_manual_cred_validation = true;
1131 }
1132 else {
1133 failf(data, "schannel: this version of Windows is too old to support "
1134 "certificate verification via CA bundle file.");
1135 return CURLE_SSL_CACERT_BADFILE;
1136 }
1137 }
1138 else
1139 backend->use_manual_cred_validation = false;
1140#else
1141 if(conn_config->CAfile || conn_config->ca_info_blob) {
1142 failf(data, "schannel: CA cert support not built in");
1143 return CURLE_NOT_BUILT_IN;
1144 }
1145#endif
1146#endif
1147
1148 backend->cred = NULL;
1149
1150 /* check for an existing re-usable credential handle */
1151 if(ssl_config->primary.sessionid) {
1152 Curl_ssl_sessionid_lock(data);
1153 if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
1154 backend->cred = old_cred;
1155 DEBUGF(infof(data, "schannel: re-using existing credential handle"));
1156
1157 /* increment the reference counter of the credential/session handle */
1158 backend->cred->refcount++;
1159 DEBUGF(infof(data,
1160 "schannel: incremented credential handle refcount = %d",
1161 backend->cred->refcount));
1162 }
1163 Curl_ssl_sessionid_unlock(data);
1164 }
1165
1166 if(!backend->cred) {
1167 char *snihost;
1168 result = schannel_acquire_credential_handle(cf, data);
1169 if(result != CURLE_OK) {
1170 return result;
1171 }
1172 /* A hostname associated with the credential is needed by
1173 InitializeSecurityContext for SNI and other reasons. */
1174 snihost = Curl_ssl_snihost(data, hostname, NULL);
1175 if(!snihost) {
1176 failf(data, "Failed to set SNI");
1177 return CURLE_SSL_CONNECT_ERROR;
1178 }
1179 backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
1180 if(!backend->cred->sni_hostname)
1181 return CURLE_OUT_OF_MEMORY;
1182 }
1183
1184 /* Warn if SNI is disabled due to use of an IP address */
1185 if(Curl_inet_pton(AF_INET, hostname, &addr)
1186#ifdef ENABLE_IPV6
1187 || Curl_inet_pton(AF_INET6, hostname, &addr6)
1188#endif
1189 ) {
1190 infof(data, "schannel: using IP address, SNI is not supported by OS.");
1191 }
1192
1193#ifdef HAS_ALPN
1194 if(backend->use_alpn) {
1195 int cur = 0;
1196 int list_start_index = 0;
1197 unsigned int *extension_len = NULL;
1198 unsigned short* list_len = NULL;
1199
1200 /* The first four bytes will be an unsigned int indicating number
1201 of bytes of data in the rest of the buffer. */
1202 extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
1203 cur += sizeof(unsigned int);
1204
1205 /* The next four bytes are an indicator that this buffer will contain
1206 ALPN data, as opposed to NPN, for example. */
1207 *(unsigned int *)(void *)&alpn_buffer[cur] =
1208 SecApplicationProtocolNegotiationExt_ALPN;
1209 cur += sizeof(unsigned int);
1210
1211 /* The next two bytes will be an unsigned short indicating the number
1212 of bytes used to list the preferred protocols. */
1213 list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
1214 cur += sizeof(unsigned short);
1215
1216 list_start_index = cur;
1217
1218#ifdef USE_HTTP2
1219 if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
1220 alpn_buffer[cur++] = ALPN_H2_LENGTH;
1221 memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
1222 cur += ALPN_H2_LENGTH;
1223 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
1224 }
1225#endif
1226
1227 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
1228 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
1229 cur += ALPN_HTTP_1_1_LENGTH;
1230 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
1231
1232 *list_len = curlx_uitous(cur - list_start_index);
1233 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
1234
1235 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
1236 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1237 }
1238 else {
1239 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1240 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1241 }
1242#else /* HAS_ALPN */
1243 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1244 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1245#endif
1246
1247 /* setup output buffer */
1248 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1249 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1250
1251 /* security request flags */
1252 backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1253 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
1254 ISC_REQ_STREAM;
1255
1256 if(!ssl_config->auto_client_cert) {
1257 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1258 }
1259
1260 /* allocate memory for the security context handle */
1261 backend->ctxt = (struct Curl_schannel_ctxt *)
1262 calloc(1, sizeof(struct Curl_schannel_ctxt));
1263 if(!backend->ctxt) {
1264 failf(data, "schannel: unable to allocate memory");
1265 return CURLE_OUT_OF_MEMORY;
1266 }
1267
1268 /* Schannel InitializeSecurityContext:
1269 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
1270
1271 At the moment we don't pass inbuf unless we're using ALPN since we only
1272 use it for that, and Wine (for which we currently disable ALPN) is giving
1273 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
1274 */
1275 sspi_status = s_pSecFn->InitializeSecurityContext(
1276 &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
1277 backend->req_flags, 0, 0,
1278 (backend->use_alpn ? &inbuf_desc : NULL),
1279 0, &backend->ctxt->ctxt_handle,
1280 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1281
1282 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
1283 char buffer[STRERROR_LEN];
1284 Curl_safefree(backend->ctxt);
1285 switch(sspi_status) {
1286 case SEC_E_INSUFFICIENT_MEMORY:
1287 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1288 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1289 return CURLE_OUT_OF_MEMORY;
1290 case SEC_E_WRONG_PRINCIPAL:
1291 failf(data, "schannel: SNI or certificate check failed: %s",
1292 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1293 return CURLE_PEER_FAILED_VERIFICATION;
1294 /*
1295 case SEC_E_INVALID_HANDLE:
1296 case SEC_E_INVALID_TOKEN:
1297 case SEC_E_LOGON_DENIED:
1298 case SEC_E_TARGET_UNKNOWN:
1299 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1300 case SEC_E_INTERNAL_ERROR:
1301 case SEC_E_NO_CREDENTIALS:
1302 case SEC_E_UNSUPPORTED_FUNCTION:
1303 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1304 */
1305 default:
1306 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1307 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1308 return CURLE_SSL_CONNECT_ERROR;
1309 }
1310 }
1311
1312 DEBUGF(infof(data, "schannel: sending initial handshake data: "
1313 "sending %lu bytes.", outbuf.cbBuffer));
1314
1315 /* send initial handshake data which is now stored in output buffer */
1316 written = Curl_conn_cf_send(cf->next, data,
1317 outbuf.pvBuffer, outbuf.cbBuffer,
1318 &result);
1319 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1320 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1321 failf(data, "schannel: failed to send initial handshake data: "
1322 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
1323 return CURLE_SSL_CONNECT_ERROR;
1324 }
1325
1326 DEBUGF(infof(data, "schannel: sent initial handshake data: "
1327 "sent %zd bytes", written));
1328
1329 backend->recv_unrecoverable_err = CURLE_OK;
1330 backend->recv_sspi_close_notify = false;
1331 backend->recv_connection_closed = false;
1332 backend->recv_renegotiating = false;
1333 backend->encdata_is_incomplete = false;
1334
1335 /* continue to second handshake step */
1336 connssl->connecting_state = ssl_connect_2;
1337
1338 return CURLE_OK;
1339}
1340
1341static CURLcode
1342schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
1343{
1344 struct ssl_connect_data *connssl = cf->ctx;
1345 struct ssl_backend_data *backend = connssl->backend;
1346 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1347 int i;
1348 ssize_t nread = -1, written = -1;
1349 unsigned char *reallocated_buffer;
1350 SecBuffer outbuf[3];
1351 SecBufferDesc outbuf_desc;
1352 SecBuffer inbuf[2];
1353 SecBufferDesc inbuf_desc;
1354 SECURITY_STATUS sspi_status = SEC_E_OK;
1355 CURLcode result;
1356 bool doread;
1357 const char *pubkey_ptr;
1358
1359 DEBUGASSERT(backend);
1360
1361 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1362
1363 DEBUGF(infof(data,
1364 "schannel: SSL/TLS connection with %s port %d (step 2/3)",
1365 connssl->hostname, connssl->port));
1366
1367 if(!backend->cred || !backend->ctxt)
1368 return CURLE_SSL_CONNECT_ERROR;
1369
1370 /* buffer to store previously received and decrypted data */
1371 if(!backend->decdata_buffer) {
1372 backend->decdata_offset = 0;
1373 backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1374 backend->decdata_buffer = malloc(backend->decdata_length);
1375 if(!backend->decdata_buffer) {
1376 failf(data, "schannel: unable to allocate memory");
1377 return CURLE_OUT_OF_MEMORY;
1378 }
1379 }
1380
1381 /* buffer to store previously received and encrypted data */
1382 if(!backend->encdata_buffer) {
1383 backend->encdata_is_incomplete = false;
1384 backend->encdata_offset = 0;
1385 backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1386 backend->encdata_buffer = malloc(backend->encdata_length);
1387 if(!backend->encdata_buffer) {
1388 failf(data, "schannel: unable to allocate memory");
1389 return CURLE_OUT_OF_MEMORY;
1390 }
1391 }
1392
1393 /* if we need a bigger buffer to read a full message, increase buffer now */
1394 if(backend->encdata_length - backend->encdata_offset <
1395 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1396 /* increase internal encrypted data buffer */
1397 size_t reallocated_length = backend->encdata_offset +
1398 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1399 reallocated_buffer = realloc(backend->encdata_buffer,
1400 reallocated_length);
1401
1402 if(!reallocated_buffer) {
1403 failf(data, "schannel: unable to re-allocate memory");
1404 return CURLE_OUT_OF_MEMORY;
1405 }
1406 else {
1407 backend->encdata_buffer = reallocated_buffer;
1408 backend->encdata_length = reallocated_length;
1409 }
1410 }
1411
1412 for(;;) {
1413 if(doread) {
1414 /* read encrypted handshake data from socket */
1415 nread = Curl_conn_cf_recv(cf->next, data,
1416 (char *) (backend->encdata_buffer +
1417 backend->encdata_offset),
1418 backend->encdata_length -
1419 backend->encdata_offset,
1420 &result);
1421 if(result == CURLE_AGAIN) {
1422 if(connssl->connecting_state != ssl_connect_2_writing)
1423 connssl->connecting_state = ssl_connect_2_reading;
1424 DEBUGF(infof(data, "schannel: failed to receive handshake, "
1425 "need more data"));
1426 return CURLE_OK;
1427 }
1428 else if((result != CURLE_OK) || (nread == 0)) {
1429 failf(data, "schannel: failed to receive handshake, "
1430 "SSL/TLS connection failed");
1431 return CURLE_SSL_CONNECT_ERROR;
1432 }
1433
1434 /* increase encrypted data buffer offset */
1435 backend->encdata_offset += nread;
1436 backend->encdata_is_incomplete = false;
1437 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1438 }
1439
1440 DEBUGF(infof(data,
1441 "schannel: encrypted data buffer: offset %zu length %zu",
1442 backend->encdata_offset, backend->encdata_length));
1443
1444 /* setup input buffers */
1445 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
1446 curlx_uztoul(backend->encdata_offset));
1447 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1448 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1449
1450 /* setup output buffers */
1451 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1452 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1453 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1454 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1455
1456 if(!inbuf[0].pvBuffer) {
1457 failf(data, "schannel: unable to allocate memory");
1458 return CURLE_OUT_OF_MEMORY;
1459 }
1460
1461 /* copy received handshake data into input buffer */
1462 memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
1463 backend->encdata_offset);
1464
1465 sspi_status = s_pSecFn->InitializeSecurityContext(
1466 &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
1467 backend->cred->sni_hostname, backend->req_flags,
1468 0, 0, &inbuf_desc, 0, NULL,
1469 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1470
1471 /* free buffer for received handshake data */
1472 Curl_safefree(inbuf[0].pvBuffer);
1473
1474 /* check if the handshake was incomplete */
1475 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1476 backend->encdata_is_incomplete = true;
1477 connssl->connecting_state = ssl_connect_2_reading;
1478 DEBUGF(infof(data,
1479 "schannel: received incomplete message, need more data"));
1480 return CURLE_OK;
1481 }
1482
1483 /* If the server has requested a client certificate, attempt to continue
1484 the handshake without one. This will allow connections to servers which
1485 request a client certificate but do not require it. */
1486 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1487 !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1488 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1489 connssl->connecting_state = ssl_connect_2_writing;
1490 DEBUGF(infof(data,
1491 "schannel: a client certificate has been requested"));
1492 return CURLE_OK;
1493 }
1494
1495 /* check if the handshake needs to be continued */
1496 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1497 for(i = 0; i < 3; i++) {
1498 /* search for handshake tokens that need to be send */
1499 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1500 DEBUGF(infof(data, "schannel: sending next handshake data: "
1501 "sending %lu bytes.", outbuf[i].cbBuffer));
1502
1503 /* send handshake token to server */
1504 written = Curl_conn_cf_send(cf->next, data,
1505 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1506 &result);
1507 if((result != CURLE_OK) ||
1508 (outbuf[i].cbBuffer != (size_t) written)) {
1509 failf(data, "schannel: failed to send next handshake data: "
1510 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1511 return CURLE_SSL_CONNECT_ERROR;
1512 }
1513 }
1514
1515 /* free obsolete buffer */
1516 if(outbuf[i].pvBuffer) {
1517 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1518 }
1519 }
1520 }
1521 else {
1522 char buffer[STRERROR_LEN];
1523 switch(sspi_status) {
1524 case SEC_E_INSUFFICIENT_MEMORY:
1525 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1526 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1527 return CURLE_OUT_OF_MEMORY;
1528 case SEC_E_WRONG_PRINCIPAL:
1529 failf(data, "schannel: SNI or certificate check failed: %s",
1530 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1531 return CURLE_PEER_FAILED_VERIFICATION;
1532 case SEC_E_UNTRUSTED_ROOT:
1533 failf(data, "schannel: %s",
1534 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1535 return CURLE_PEER_FAILED_VERIFICATION;
1536 /*
1537 case SEC_E_INVALID_HANDLE:
1538 case SEC_E_INVALID_TOKEN:
1539 case SEC_E_LOGON_DENIED:
1540 case SEC_E_TARGET_UNKNOWN:
1541 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1542 case SEC_E_INTERNAL_ERROR:
1543 case SEC_E_NO_CREDENTIALS:
1544 case SEC_E_UNSUPPORTED_FUNCTION:
1545 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1546 */
1547 default:
1548 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1549 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1550 return CURLE_SSL_CONNECT_ERROR;
1551 }
1552 }
1553
1554 /* check if there was additional remaining encrypted data */
1555 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1556 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1557 inbuf[1].cbBuffer));
1558 /*
1559 There are two cases where we could be getting extra data here:
1560 1) If we're renegotiating a connection and the handshake is already
1561 complete (from the server perspective), it can encrypted app data
1562 (not handshake data) in an extra buffer at this point.
1563 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1564 connection and this extra data is part of the handshake.
1565 We should process the data immediately; waiting for the socket to
1566 be ready may fail since the server is done sending handshake data.
1567 */
1568 /* check if the remaining data is less than the total amount
1569 and therefore begins after the already processed data */
1570 if(backend->encdata_offset > inbuf[1].cbBuffer) {
1571 memmove(backend->encdata_buffer,
1572 (backend->encdata_buffer + backend->encdata_offset) -
1573 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1574 backend->encdata_offset = inbuf[1].cbBuffer;
1575 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1576 doread = FALSE;
1577 continue;
1578 }
1579 }
1580 }
1581 else {
1582 backend->encdata_offset = 0;
1583 }
1584 break;
1585 }
1586
1587 /* check if the handshake needs to be continued */
1588 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1589 connssl->connecting_state = ssl_connect_2_reading;
1590 return CURLE_OK;
1591 }
1592
1593 /* check if the handshake is complete */
1594 if(sspi_status == SEC_E_OK) {
1595 connssl->connecting_state = ssl_connect_3;
1596 DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1597 }
1598
1599 pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
1600 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
1601 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1602 if(pubkey_ptr) {
1603 result = pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
1604 if(result) {
1605 failf(data, "SSL: public key does not match pinned public key");
1606 return result;
1607 }
1608 }
1609
1610#ifdef HAS_MANUAL_VERIFY_API
1611 if(conn_config->verifypeer && backend->use_manual_cred_validation) {
1612 return Curl_verify_certificate(cf, data);
1613 }
1614#endif
1615
1616 return CURLE_OK;
1617}
1618
1619static bool
1620valid_cert_encoding(const CERT_CONTEXT *cert_context)
1621{
1622 return (cert_context != NULL) &&
1623 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1624 (cert_context->pbCertEncoded != NULL) &&
1625 (cert_context->cbCertEncoded > 0);
1626}
1627
1628typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1629
1630static void
1631traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1632 void *arg)
1633{
1634 const CERT_CONTEXT *current_context = NULL;
1635 bool should_continue = true;
1636 while(should_continue &&
1637 (current_context = CertEnumCertificatesInStore(
1638 context->hCertStore,
1639 current_context)) != NULL)
1640 should_continue = func(current_context, arg);
1641
1642 if(current_context)
1643 CertFreeCertificateContext(current_context);
1644}
1645
1646static bool
1647cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1648{
1649 if(valid_cert_encoding(ccert_context))
1650 (*(int *)certs_count)++;
1651 return true;
1652}
1653
1654struct Adder_args
1655{
1656 struct Curl_easy *data;
1657 CURLcode result;
1658 int idx;
1659 int certs_count;
1660};
1661
1662static bool
1663add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1664{
1665 struct Adder_args *args = (struct Adder_args*)raw_arg;
1666 args->result = CURLE_OK;
1667 if(valid_cert_encoding(ccert_context)) {
1668 const char *beg = (const char *) ccert_context->pbCertEncoded;
1669 const char *end = beg + ccert_context->cbCertEncoded;
1670 int insert_index = (args->certs_count - 1) - args->idx;
1671 args->result = Curl_extract_certinfo(args->data, insert_index,
1672 beg, end);
1673 args->idx++;
1674 }
1675 return args->result == CURLE_OK;
1676}
1677
1678static CURLcode
1679schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
1680{
1681 struct ssl_connect_data *connssl = cf->ctx;
1682 struct ssl_backend_data *backend = connssl->backend;
1683 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1684 CURLcode result = CURLE_OK;
1685 SECURITY_STATUS sspi_status = SEC_E_OK;
1686 CERT_CONTEXT *ccert_context = NULL;
1687#ifdef HAS_ALPN
1688 SecPkgContext_ApplicationProtocol alpn_result;
1689#endif
1690
1691 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1692 DEBUGASSERT(backend);
1693
1694 DEBUGF(infof(data,
1695 "schannel: SSL/TLS connection with %s port %d (step 3/3)",
1696 connssl->hostname, connssl->port));
1697
1698 if(!backend->cred)
1699 return CURLE_SSL_CONNECT_ERROR;
1700
1701 /* check if the required context attributes are met */
1702 if(backend->ret_flags != backend->req_flags) {
1703 if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
1704 failf(data, "schannel: failed to setup sequence detection");
1705 if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
1706 failf(data, "schannel: failed to setup replay detection");
1707 if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
1708 failf(data, "schannel: failed to setup confidentiality");
1709 if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1710 failf(data, "schannel: failed to setup memory allocation");
1711 if(!(backend->ret_flags & ISC_RET_STREAM))
1712 failf(data, "schannel: failed to setup stream orientation");
1713 return CURLE_SSL_CONNECT_ERROR;
1714 }
1715
1716#ifdef HAS_ALPN
1717 if(backend->use_alpn) {
1718 sspi_status =
1719 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1720 SECPKG_ATTR_APPLICATION_PROTOCOL,
1721 &alpn_result);
1722
1723 if(sspi_status != SEC_E_OK) {
1724 failf(data, "schannel: failed to retrieve ALPN result");
1725 return CURLE_SSL_CONNECT_ERROR;
1726 }
1727
1728 if(alpn_result.ProtoNegoStatus ==
1729 SecApplicationProtocolNegotiationStatus_Success) {
1730 unsigned char alpn = 0;
1731
1732 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR,
1733 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1734
1735#ifdef USE_HTTP2
1736 if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH &&
1737 !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) {
1738 alpn = CURL_HTTP_VERSION_2;
1739 }
1740 else
1741#endif
1742 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1743 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1744 ALPN_HTTP_1_1_LENGTH)) {
1745 alpn = CURL_HTTP_VERSION_1_1;
1746 }
1747 if(backend->recv_renegotiating) {
1748 if(alpn != cf->conn->alpn) {
1749 failf(data, "schannel: server selected an ALPN protocol too late");
1750 return CURLE_SSL_CONNECT_ERROR;
1751 }
1752 }
1753 else
1754 cf->conn->alpn = alpn;
1755 }
1756 else {
1757 if(!backend->recv_renegotiating)
1758 infof(data, VTLS_INFOF_NO_ALPN);
1759 }
1760
1761 if(!backend->recv_renegotiating) {
1762 Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
1763 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1764 }
1765 }
1766#endif
1767
1768 /* save the current session data for possible re-use */
1769 if(ssl_config->primary.sessionid) {
1770 bool incache;
1771 bool added = FALSE;
1772 struct Curl_schannel_cred *old_cred = NULL;
1773
1774 Curl_ssl_sessionid_lock(data);
1775 incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
1776 if(incache) {
1777 if(old_cred != backend->cred) {
1778 DEBUGF(infof(data,
1779 "schannel: old credential handle is stale, removing"));
1780 /* we're not taking old_cred ownership here, no refcount++ is needed */
1781 Curl_ssl_delsessionid(data, (void *)old_cred);
1782 incache = FALSE;
1783 }
1784 }
1785 if(!incache) {
1786 result = Curl_ssl_addsessionid(cf, data, backend->cred,
1787 sizeof(struct Curl_schannel_cred),
1788 &added);
1789 if(result) {
1790 Curl_ssl_sessionid_unlock(data);
1791 failf(data, "schannel: failed to store credential handle");
1792 return result;
1793 }
1794 else if(added) {
1795 /* this cred session is now also referenced by sessionid cache */
1796 backend->cred->refcount++;
1797 DEBUGF(infof(data,
1798 "schannel: stored credential handle in session cache"));
1799 }
1800 }
1801 Curl_ssl_sessionid_unlock(data);
1802 }
1803
1804 if(data->set.ssl.certinfo) {
1805 int certs_count = 0;
1806 sspi_status =
1807 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1808 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1809 &ccert_context);
1810
1811 if((sspi_status != SEC_E_OK) || !ccert_context) {
1812 failf(data, "schannel: failed to retrieve remote cert context");
1813 return CURLE_PEER_FAILED_VERIFICATION;
1814 }
1815
1816 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1817
1818 result = Curl_ssl_init_certinfo(data, certs_count);
1819 if(!result) {
1820 struct Adder_args args;
1821 args.data = data;
1822 args.idx = 0;
1823 args.certs_count = certs_count;
1824 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1825 result = args.result;
1826 }
1827 CertFreeCertificateContext(ccert_context);
1828 if(result)
1829 return result;
1830 }
1831
1832 connssl->connecting_state = ssl_connect_done;
1833
1834 return CURLE_OK;
1835}
1836
1837static CURLcode
1838schannel_connect_common(struct Curl_cfilter *cf,
1839 struct Curl_easy *data,
1840 bool nonblocking, bool *done)
1841{
1842 CURLcode result;
1843 struct ssl_connect_data *connssl = cf->ctx;
1844 curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
1845 timediff_t timeout_ms;
1846 int what;
1847
1848 /* check if the connection has already been established */
1849 if(ssl_connection_complete == connssl->state) {
1850 *done = TRUE;
1851 return CURLE_OK;
1852 }
1853
1854 if(ssl_connect_1 == connssl->connecting_state) {
1855 /* check out how much more time we're allowed */
1856 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1857
1858 if(timeout_ms < 0) {
1859 /* no need to continue if time already is up */
1860 failf(data, "SSL/TLS connection timeout");
1861 return CURLE_OPERATION_TIMEDOUT;
1862 }
1863
1864 result = schannel_connect_step1(cf, data);
1865 if(result)
1866 return result;
1867 }
1868
1869 while(ssl_connect_2 == connssl->connecting_state ||
1870 ssl_connect_2_reading == connssl->connecting_state ||
1871 ssl_connect_2_writing == connssl->connecting_state) {
1872
1873 /* check out how much more time we're allowed */
1874 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1875
1876 if(timeout_ms < 0) {
1877 /* no need to continue if time already is up */
1878 failf(data, "SSL/TLS connection timeout");
1879 return CURLE_OPERATION_TIMEDOUT;
1880 }
1881
1882 /* if ssl is expecting something, check if it's available. */
1883 if(connssl->connecting_state == ssl_connect_2_reading
1884 || connssl->connecting_state == ssl_connect_2_writing) {
1885
1886 curl_socket_t writefd = ssl_connect_2_writing ==
1887 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1888 curl_socket_t readfd = ssl_connect_2_reading ==
1889 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1890
1891 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1892 nonblocking ? 0 : timeout_ms);
1893 if(what < 0) {
1894 /* fatal error */
1895 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1896 return CURLE_SSL_CONNECT_ERROR;
1897 }
1898 else if(0 == what) {
1899 if(nonblocking) {
1900 *done = FALSE;
1901 return CURLE_OK;
1902 }
1903 else {
1904 /* timeout */
1905 failf(data, "SSL/TLS connection timeout");
1906 return CURLE_OPERATION_TIMEDOUT;
1907 }
1908 }
1909 /* socket is readable or writable */
1910 }
1911
1912 /* Run transaction, and return to the caller if it failed or if
1913 * this connection is part of a multi handle and this loop would
1914 * execute again. This permits the owner of a multi handle to
1915 * abort a connection attempt before step2 has completed while
1916 * ensuring that a client using select() or epoll() will always
1917 * have a valid fdset to wait on.
1918 */
1919 result = schannel_connect_step2(cf, data);
1920 if(result || (nonblocking &&
1921 (ssl_connect_2 == connssl->connecting_state ||
1922 ssl_connect_2_reading == connssl->connecting_state ||
1923 ssl_connect_2_writing == connssl->connecting_state)))
1924 return result;
1925
1926 } /* repeat step2 until all transactions are done. */
1927
1928 if(ssl_connect_3 == connssl->connecting_state) {
1929 result = schannel_connect_step3(cf, data);
1930 if(result)
1931 return result;
1932 }
1933
1934 if(ssl_connect_done == connssl->connecting_state) {
1935 connssl->state = ssl_connection_complete;
1936
1937#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1938 /* When SSPI is used in combination with Schannel
1939 * we need the Schannel context to create the Schannel
1940 * binding to pass the IIS extended protection checks.
1941 * Available on Windows 7 or later.
1942 */
1943 {
1944 struct ssl_backend_data *backend = connssl->backend;
1945 DEBUGASSERT(backend);
1946 cf->conn->sslContext = &backend->ctxt->ctxt_handle;
1947 }
1948#endif
1949
1950 *done = TRUE;
1951 }
1952 else
1953 *done = FALSE;
1954
1955 /* reset our connection state machine */
1956 connssl->connecting_state = ssl_connect_1;
1957
1958 return CURLE_OK;
1959}
1960
1961static ssize_t
1962schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1963 const void *buf, size_t len, CURLcode *err)
1964{
1965 ssize_t written = -1;
1966 size_t data_len = 0;
1967 unsigned char *ptr = NULL;
1968 struct ssl_connect_data *connssl = cf->ctx;
1969 SecBuffer outbuf[4];
1970 SecBufferDesc outbuf_desc;
1971 SECURITY_STATUS sspi_status = SEC_E_OK;
1972 CURLcode result;
1973 struct ssl_backend_data *backend = connssl->backend;
1974
1975 DEBUGASSERT(backend);
1976
1977 /* check if the maximum stream sizes were queried */
1978 if(backend->stream_sizes.cbMaximumMessage == 0) {
1979 sspi_status = s_pSecFn->QueryContextAttributes(
1980 &backend->ctxt->ctxt_handle,
1981 SECPKG_ATTR_STREAM_SIZES,
1982 &backend->stream_sizes);
1983 if(sspi_status != SEC_E_OK) {
1984 *err = CURLE_SEND_ERROR;
1985 return -1;
1986 }
1987 }
1988
1989 /* check if the buffer is longer than the maximum message length */
1990 if(len > backend->stream_sizes.cbMaximumMessage) {
1991 len = backend->stream_sizes.cbMaximumMessage;
1992 }
1993
1994 /* calculate the complete message length and allocate a buffer for it */
1995 data_len = backend->stream_sizes.cbHeader + len +
1996 backend->stream_sizes.cbTrailer;
1997 ptr = (unsigned char *) malloc(data_len);
1998 if(!ptr) {
1999 *err = CURLE_OUT_OF_MEMORY;
2000 return -1;
2001 }
2002
2003 /* setup output buffers (header, data, trailer, empty) */
2004 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
2005 ptr, backend->stream_sizes.cbHeader);
2006 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
2007 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
2008 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
2009 ptr + backend->stream_sizes.cbHeader + len,
2010 backend->stream_sizes.cbTrailer);
2011 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
2012 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
2013
2014 /* copy data into output buffer */
2015 memcpy(outbuf[1].pvBuffer, buf, len);
2016
2017 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
2018 sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
2019 &outbuf_desc, 0);
2020
2021 /* check if the message was encrypted */
2022 if(sspi_status == SEC_E_OK) {
2023 written = 0;
2024
2025 /* send the encrypted message including header, data and trailer */
2026 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
2027
2028 /*
2029 It's important to send the full message which includes the header,
2030 encrypted payload, and trailer. Until the client receives all the
2031 data a coherent message has not been delivered and the client
2032 can't read any of it.
2033
2034 If we wanted to buffer the unwritten encrypted bytes, we would
2035 tell the client that all data it has requested to be sent has been
2036 sent. The unwritten encrypted bytes would be the first bytes to
2037 send on the next invocation.
2038 Here's the catch with this - if we tell the client that all the
2039 bytes have been sent, will the client call this method again to
2040 send the buffered data? Looking at who calls this function, it
2041 seems the answer is NO.
2042 */
2043
2044 /* send entire message or fail */
2045 while(len > (size_t)written) {
2046 ssize_t this_write = 0;
2047 int what;
2048 timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
2049 if(timeout_ms < 0) {
2050 /* we already got the timeout */
2051 failf(data, "schannel: timed out sending data "
2052 "(bytes sent: %zd)", written);
2053 *err = CURLE_OPERATION_TIMEDOUT;
2054 written = -1;
2055 break;
2056 }
2057 else if(!timeout_ms)
2058 timeout_ms = TIMEDIFF_T_MAX;
2059 what = SOCKET_WRITABLE(cf->conn->sock[cf->sockindex], timeout_ms);
2060 if(what < 0) {
2061 /* fatal error */
2062 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2063 *err = CURLE_SEND_ERROR;
2064 written = -1;
2065 break;
2066 }
2067 else if(0 == what) {
2068 failf(data, "schannel: timed out sending data "
2069 "(bytes sent: %zd)", written);
2070 *err = CURLE_OPERATION_TIMEDOUT;
2071 written = -1;
2072 break;
2073 }
2074 /* socket is writable */
2075
2076 this_write = Curl_conn_cf_send(cf->next, data,
2077 ptr + written, len - written,
2078 &result);
2079 if(result == CURLE_AGAIN)
2080 continue;
2081 else if(result != CURLE_OK) {
2082 *err = result;
2083 written = -1;
2084 break;
2085 }
2086
2087 written += this_write;
2088 }
2089 }
2090 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
2091 *err = CURLE_OUT_OF_MEMORY;
2092 }
2093 else{
2094 *err = CURLE_SEND_ERROR;
2095 }
2096
2097 Curl_safefree(ptr);
2098
2099 if(len == (size_t)written)
2100 /* Encrypted message including header, data and trailer entirely sent.
2101 The return value is the number of unencrypted bytes that were sent. */
2102 written = outbuf[1].cbBuffer;
2103
2104 return written;
2105}
2106
2107static ssize_t
2108schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
2109 char *buf, size_t len, CURLcode *err)
2110{
2111 size_t size = 0;
2112 ssize_t nread = -1;
2113 struct ssl_connect_data *connssl = cf->ctx;
2114 unsigned char *reallocated_buffer;
2115 size_t reallocated_length;
2116 bool done = FALSE;
2117 SecBuffer inbuf[4];
2118 SecBufferDesc inbuf_desc;
2119 SECURITY_STATUS sspi_status = SEC_E_OK;
2120 /* we want the length of the encrypted buffer to be at least large enough
2121 that it can hold all the bytes requested and some TLS record overhead. */
2122 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
2123 struct ssl_backend_data *backend = connssl->backend;
2124
2125 DEBUGASSERT(backend);
2126
2127 /****************************************************************************
2128 * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
2129 * The pattern for return error is set *err, optional infof, goto cleanup.
2130 *
2131 * Our priority is to always return as much decrypted data to the caller as
2132 * possible, even if an error occurs. The state of the decrypted buffer must
2133 * always be valid. Transfer of decrypted data to the caller's buffer is
2134 * handled in the cleanup.
2135 */
2136
2137 DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
2138 *err = CURLE_OK;
2139
2140 if(len && len <= backend->decdata_offset) {
2141 infof(data, "schannel: enough decrypted data is already available");
2142 goto cleanup;
2143 }
2144 else if(backend->recv_unrecoverable_err) {
2145 *err = backend->recv_unrecoverable_err;
2146 infof(data, "schannel: an unrecoverable error occurred in a prior call");
2147 goto cleanup;
2148 }
2149 else if(backend->recv_sspi_close_notify) {
2150 /* once a server has indicated shutdown there is no more encrypted data */
2151 infof(data, "schannel: server indicated shutdown in a prior call");
2152 goto cleanup;
2153 }
2154
2155 /* It's debatable what to return when !len. Regardless we can't return
2156 immediately because there may be data to decrypt (in the case we want to
2157 decrypt all encrypted cached data) so handle !len later in cleanup.
2158 */
2159 else if(len && !backend->recv_connection_closed) {
2160 /* increase enc buffer in order to fit the requested amount of data */
2161 size = backend->encdata_length - backend->encdata_offset;
2162 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2163 backend->encdata_length < min_encdata_length) {
2164 reallocated_length = backend->encdata_offset +
2165 CURL_SCHANNEL_BUFFER_FREE_SIZE;
2166 if(reallocated_length < min_encdata_length) {
2167 reallocated_length = min_encdata_length;
2168 }
2169 reallocated_buffer = realloc(backend->encdata_buffer,
2170 reallocated_length);
2171 if(!reallocated_buffer) {
2172 *err = CURLE_OUT_OF_MEMORY;
2173 failf(data, "schannel: unable to re-allocate memory");
2174 goto cleanup;
2175 }
2176
2177 backend->encdata_buffer = reallocated_buffer;
2178 backend->encdata_length = reallocated_length;
2179 size = backend->encdata_length - backend->encdata_offset;
2180 DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
2181 backend->encdata_length));
2182 }
2183
2184 DEBUGF(infof(data,
2185 "schannel: encrypted data buffer: offset %zu length %zu",
2186 backend->encdata_offset, backend->encdata_length));
2187
2188 /* read encrypted data from socket */
2189 nread = Curl_conn_cf_recv(cf->next, data,
2190 (char *)(backend->encdata_buffer +
2191 backend->encdata_offset),
2192 size, err);
2193 if(*err) {
2194 nread = -1;
2195 if(*err == CURLE_AGAIN)
2196 DEBUGF(infof(data,
2197 "schannel: recv returned CURLE_AGAIN"));
2198 else if(*err == CURLE_RECV_ERROR)
2199 infof(data, "schannel: recv returned CURLE_RECV_ERROR");
2200 else
2201 infof(data, "schannel: recv returned error %d", *err);
2202 }
2203 else if(nread == 0) {
2204 backend->recv_connection_closed = true;
2205 DEBUGF(infof(data, "schannel: server closed the connection"));
2206 }
2207 else if(nread > 0) {
2208 backend->encdata_offset += (size_t)nread;
2209 backend->encdata_is_incomplete = false;
2210 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
2211 }
2212 }
2213
2214 DEBUGF(infof(data,
2215 "schannel: encrypted data buffer: offset %zu length %zu",
2216 backend->encdata_offset, backend->encdata_length));
2217
2218 /* decrypt loop */
2219 while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
2220 (!len || backend->decdata_offset < len ||
2221 backend->recv_connection_closed)) {
2222 /* prepare data buffer for DecryptMessage call */
2223 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
2224 curlx_uztoul(backend->encdata_offset));
2225
2226 /* we need 3 more empty input buffers for possible output */
2227 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
2228 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
2229 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
2230 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
2231
2232 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
2233 */
2234 sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
2235 &inbuf_desc, 0, NULL);
2236
2237 /* check if everything went fine (server may want to renegotiate
2238 or shutdown the connection context) */
2239 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
2240 sspi_status == SEC_I_CONTEXT_EXPIRED) {
2241 /* check for successfully decrypted data, even before actual
2242 renegotiation or shutdown of the connection context */
2243 if(inbuf[1].BufferType == SECBUFFER_DATA) {
2244 DEBUGF(infof(data, "schannel: decrypted data length: %lu",
2245 inbuf[1].cbBuffer));
2246
2247 /* increase buffer in order to fit the received amount of data */
2248 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
2249 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
2250 if(backend->decdata_length - backend->decdata_offset < size ||
2251 backend->decdata_length < len) {
2252 /* increase internal decrypted data buffer */
2253 reallocated_length = backend->decdata_offset + size;
2254 /* make sure that the requested amount of data fits */
2255 if(reallocated_length < len) {
2256 reallocated_length = len;
2257 }
2258 reallocated_buffer = realloc(backend->decdata_buffer,
2259 reallocated_length);
2260 if(!reallocated_buffer) {
2261 *err = CURLE_OUT_OF_MEMORY;
2262 failf(data, "schannel: unable to re-allocate memory");
2263 goto cleanup;
2264 }
2265 backend->decdata_buffer = reallocated_buffer;
2266 backend->decdata_length = reallocated_length;
2267 }
2268
2269 /* copy decrypted data to internal buffer */
2270 size = inbuf[1].cbBuffer;
2271 if(size) {
2272 memcpy(backend->decdata_buffer + backend->decdata_offset,
2273 inbuf[1].pvBuffer, size);
2274 backend->decdata_offset += size;
2275 }
2276
2277 DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
2278 DEBUGF(infof(data,
2279 "schannel: decrypted cached: offset %zu length %zu",
2280 backend->decdata_offset, backend->decdata_length));
2281 }
2282
2283 /* check for remaining encrypted data */
2284 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
2285 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
2286 inbuf[3].cbBuffer));
2287
2288 /* check if the remaining data is less than the total amount
2289 * and therefore begins after the already processed data
2290 */
2291 if(backend->encdata_offset > inbuf[3].cbBuffer) {
2292 /* move remaining encrypted data forward to the beginning of
2293 buffer */
2294 memmove(backend->encdata_buffer,
2295 (backend->encdata_buffer + backend->encdata_offset) -
2296 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
2297 backend->encdata_offset = inbuf[3].cbBuffer;
2298 }
2299
2300 DEBUGF(infof(data,
2301 "schannel: encrypted cached: offset %zu length %zu",
2302 backend->encdata_offset, backend->encdata_length));
2303 }
2304 else {
2305 /* reset encrypted buffer offset, because there is no data remaining */
2306 backend->encdata_offset = 0;
2307 }
2308
2309 /* check if server wants to renegotiate the connection context */
2310 if(sspi_status == SEC_I_RENEGOTIATE) {
2311 infof(data, "schannel: remote party requests renegotiation");
2312 if(*err && *err != CURLE_AGAIN) {
2313 infof(data, "schannel: can't renegotiate, an error is pending");
2314 goto cleanup;
2315 }
2316
2317 /* begin renegotiation */
2318 infof(data, "schannel: renegotiating SSL/TLS connection");
2319 connssl->state = ssl_connection_negotiating;
2320 connssl->connecting_state = ssl_connect_2_writing;
2321 backend->recv_renegotiating = true;
2322 *err = schannel_connect_common(cf, data, FALSE, &done);
2323 backend->recv_renegotiating = false;
2324 if(*err) {
2325 infof(data, "schannel: renegotiation failed");
2326 goto cleanup;
2327 }
2328 /* now retry receiving data */
2329 sspi_status = SEC_E_OK;
2330 infof(data, "schannel: SSL/TLS connection renegotiated");
2331 continue;
2332 }
2333 /* check if the server closed the connection */
2334 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2335 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2336 returned so we have to work around that in cleanup. */
2337 backend->recv_sspi_close_notify = true;
2338 if(!backend->recv_connection_closed) {
2339 backend->recv_connection_closed = true;
2340 infof(data, "schannel: server closed the connection");
2341 }
2342 goto cleanup;
2343 }
2344 }
2345 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2346 backend->encdata_is_incomplete = true;
2347 if(!*err)
2348 *err = CURLE_AGAIN;
2349 infof(data, "schannel: failed to decrypt data, need more data");
2350 goto cleanup;
2351 }
2352 else {
2353#ifndef CURL_DISABLE_VERBOSE_STRINGS
2354 char buffer[STRERROR_LEN];
2355#endif
2356 *err = CURLE_RECV_ERROR;
2357 infof(data, "schannel: failed to read data from server: %s",
2358 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2359 goto cleanup;
2360 }
2361 }
2362
2363 DEBUGF(infof(data,
2364 "schannel: encrypted data buffer: offset %zu length %zu",
2365 backend->encdata_offset, backend->encdata_length));
2366
2367 DEBUGF(infof(data,
2368 "schannel: decrypted data buffer: offset %zu length %zu",
2369 backend->decdata_offset, backend->decdata_length));
2370
2371 cleanup:
2372 /* Warning- there is no guarantee the encdata state is valid at this point */
2373 DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2374
2375 /* Error if the connection has closed without a close_notify.
2376
2377 The behavior here is a matter of debate. We don't want to be vulnerable
2378 to a truncation attack however there's some browser precedent for
2379 ignoring the close_notify for compatibility reasons.
2380
2381 Additionally, Windows 2000 (v5.0) is a special case since it seems it
2382 doesn't return close_notify. In that case if the connection was closed we
2383 assume it was graceful (close_notify) since there doesn't seem to be a
2384 way to tell.
2385 */
2386 if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2387 !backend->recv_sspi_close_notify) {
2388 bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2389 VERSION_EQUAL);
2390
2391 if(isWin2k && sspi_status == SEC_E_OK)
2392 backend->recv_sspi_close_notify = true;
2393 else {
2394 *err = CURLE_RECV_ERROR;
2395 infof(data, "schannel: server closed abruptly (missing close_notify)");
2396 }
2397 }
2398
2399 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2400 if(*err && *err != CURLE_AGAIN)
2401 backend->recv_unrecoverable_err = *err;
2402
2403 size = len < backend->decdata_offset ? len : backend->decdata_offset;
2404 if(size) {
2405 memcpy(buf, backend->decdata_buffer, size);
2406 memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2407 backend->decdata_offset - size);
2408 backend->decdata_offset -= size;
2409 DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2410 DEBUGF(infof(data,
2411 "schannel: decrypted data buffer: offset %zu length %zu",
2412 backend->decdata_offset, backend->decdata_length));
2413 *err = CURLE_OK;
2414 return (ssize_t)size;
2415 }
2416
2417 if(!*err && !backend->recv_connection_closed)
2418 *err = CURLE_AGAIN;
2419
2420 /* It's debatable what to return when !len. We could return whatever error
2421 we got from decryption but instead we override here so the return is
2422 consistent.
2423 */
2424 if(!len)
2425 *err = CURLE_OK;
2426
2427 return *err ? -1 : 0;
2428}
2429
2430static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
2431 struct Curl_easy *data,
2432 bool *done)
2433{
2434 return schannel_connect_common(cf, data, TRUE, done);
2435}
2436
2437static CURLcode schannel_connect(struct Curl_cfilter *cf,
2438 struct Curl_easy *data)
2439{
2440 CURLcode result;
2441 bool done = FALSE;
2442
2443 result = schannel_connect_common(cf, data, FALSE, &done);
2444 if(result)
2445 return result;
2446
2447 DEBUGASSERT(done);
2448
2449 return CURLE_OK;
2450}
2451
2452static bool schannel_data_pending(struct Curl_cfilter *cf,
2453 const struct Curl_easy *data)
2454{
2455 const struct ssl_connect_data *connssl = cf->ctx;
2456 struct ssl_backend_data *backend = connssl->backend;
2457
2458 (void)data;
2459 DEBUGASSERT(backend);
2460
2461 if(connssl->backend->ctxt) /* SSL/TLS is in use */
2462 return (backend->decdata_offset > 0 ||
2463 (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
2464 else
2465 return FALSE;
2466}
2467
2468static void schannel_session_free(void *ptr)
2469{
2470 /* this is expected to be called under sessionid lock */
2471 struct Curl_schannel_cred *cred = ptr;
2472
2473 if(cred) {
2474 cred->refcount--;
2475 if(cred->refcount == 0) {
2476 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
2477 curlx_unicodefree(cred->sni_hostname);
2478#ifdef HAS_CLIENT_CERT_PATH
2479 if(cred->client_cert_store) {
2480 CertCloseStore(cred->client_cert_store, 0);
2481 cred->client_cert_store = NULL;
2482 }
2483#endif
2484 Curl_safefree(cred);
2485 }
2486 }
2487}
2488
2489/* shut down the SSL connection and clean up related memory.
2490 this function can be called multiple times on the same connection including
2491 if the SSL connection failed (eg connection made but failed handshake). */
2492static int schannel_shutdown(struct Curl_cfilter *cf,
2493 struct Curl_easy *data)
2494{
2495 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2496 * Shutting Down an Schannel Connection
2497 */
2498 struct ssl_connect_data *connssl = cf->ctx;
2499 struct ssl_backend_data *backend = connssl->backend;
2500
2501 DEBUGASSERT(data);
2502 DEBUGASSERT(backend);
2503
2504 if(connssl->backend->ctxt) {
2505 infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
2506 connssl->hostname, connssl->port);
2507 }
2508
2509 if(backend->cred && backend->ctxt) {
2510 SecBufferDesc BuffDesc;
2511 SecBuffer Buffer;
2512 SECURITY_STATUS sspi_status;
2513 SecBuffer outbuf;
2514 SecBufferDesc outbuf_desc;
2515 CURLcode result;
2516 DWORD dwshut = SCHANNEL_SHUTDOWN;
2517
2518 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2519 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2520
2521 sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2522 &BuffDesc);
2523
2524 if(sspi_status != SEC_E_OK) {
2525 char buffer[STRERROR_LEN];
2526 failf(data, "schannel: ApplyControlToken failure: %s",
2527 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2528 }
2529
2530 /* setup output buffer */
2531 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2532 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2533
2534 sspi_status = s_pSecFn->InitializeSecurityContext(
2535 &backend->cred->cred_handle,
2536 &backend->ctxt->ctxt_handle,
2537 backend->cred->sni_hostname,
2538 backend->req_flags,
2539 0,
2540 0,
2541 NULL,
2542 0,
2543 &backend->ctxt->ctxt_handle,
2544 &outbuf_desc,
2545 &backend->ret_flags,
2546 &backend->ctxt->time_stamp);
2547
2548 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2549 /* send close message which is in output buffer */
2550 ssize_t written = Curl_conn_cf_send(cf->next, data,
2551 outbuf.pvBuffer, outbuf.cbBuffer,
2552 &result);
2553 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2554 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2555 infof(data, "schannel: failed to send close msg: %s"
2556 " (bytes written: %zd)", curl_easy_strerror(result), written);
2557 }
2558 }
2559 }
2560
2561 /* free SSPI Schannel API security context handle */
2562 if(backend->ctxt) {
2563 DEBUGF(infof(data, "schannel: clear security context handle"));
2564 s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2565 Curl_safefree(backend->ctxt);
2566 }
2567
2568 /* free SSPI Schannel API credential handle */
2569 if(backend->cred) {
2570 Curl_ssl_sessionid_lock(data);
2571 schannel_session_free(backend->cred);
2572 Curl_ssl_sessionid_unlock(data);
2573 backend->cred = NULL;
2574 }
2575
2576 /* free internal buffer for received encrypted data */
2577 if(backend->encdata_buffer) {
2578 Curl_safefree(backend->encdata_buffer);
2579 backend->encdata_length = 0;
2580 backend->encdata_offset = 0;
2581 backend->encdata_is_incomplete = false;
2582 }
2583
2584 /* free internal buffer for received decrypted data */
2585 if(backend->decdata_buffer) {
2586 Curl_safefree(backend->decdata_buffer);
2587 backend->decdata_length = 0;
2588 backend->decdata_offset = 0;
2589 }
2590
2591 return CURLE_OK;
2592}
2593
2594static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2595{
2596 schannel_shutdown(cf, data);
2597}
2598
2599static int schannel_init(void)
2600{
2601 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2602}
2603
2604static void schannel_cleanup(void)
2605{
2606 Curl_sspi_global_cleanup();
2607}
2608
2609static size_t schannel_version(char *buffer, size_t size)
2610{
2611 size = msnprintf(buffer, size, "Schannel");
2612
2613 return size;
2614}
2615
2616static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2617 unsigned char *entropy, size_t length)
2618{
2619 (void)data;
2620
2621 return Curl_win32_random(entropy, length);
2622}
2623
2624static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
2625 struct Curl_easy *data,
2626 const char *pinnedpubkey)
2627{
2628 struct ssl_connect_data *connssl = cf->ctx;
2629 struct ssl_backend_data *backend = connssl->backend;
2630 CERT_CONTEXT *pCertContextServer = NULL;
2631
2632 /* Result is returned to caller */
2633 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2634
2635 DEBUGASSERT(backend);
2636
2637 /* if a path wasn't specified, don't pin */
2638 if(!pinnedpubkey)
2639 return CURLE_OK;
2640
2641 do {
2642 SECURITY_STATUS sspi_status;
2643 const char *x509_der;
2644 DWORD x509_der_len;
2645 struct Curl_X509certificate x509_parsed;
2646 struct Curl_asn1Element *pubkey;
2647
2648 sspi_status =
2649 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2650 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2651 &pCertContextServer);
2652
2653 if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2654 char buffer[STRERROR_LEN];
2655 failf(data, "schannel: Failed to read remote certificate context: %s",
2656 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2657 break; /* failed */
2658 }
2659
2660
2661 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2662 (pCertContextServer->cbCertEncoded > 0)))
2663 break;
2664
2665 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2666 x509_der_len = pCertContextServer->cbCertEncoded;
2667 memset(&x509_parsed, 0, sizeof(x509_parsed));
2668 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2669 break;
2670
2671 pubkey = &x509_parsed.subjectPublicKeyInfo;
2672 if(!pubkey->header || pubkey->end <= pubkey->header) {
2673 failf(data, "SSL: failed retrieving public key from server certificate");
2674 break;
2675 }
2676
2677 result = Curl_pin_peer_pubkey(data,
2678 pinnedpubkey,
2679 (const unsigned char *)pubkey->header,
2680 (size_t)(pubkey->end - pubkey->header));
2681 if(result) {
2682 failf(data, "SSL: public key does not match pinned public key");
2683 }
2684 } while(0);
2685
2686 if(pCertContextServer)
2687 CertFreeCertificateContext(pCertContextServer);
2688
2689 return result;
2690}
2691
2692static void schannel_checksum(const unsigned char *input,
2693 size_t inputlen,
2694 unsigned char *checksum,
2695 size_t checksumlen,
2696 DWORD provType,
2697 const unsigned int algId)
2698{
2699 HCRYPTPROV hProv = 0;
2700 HCRYPTHASH hHash = 0;
2701 DWORD cbHashSize = 0;
2702 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2703 DWORD dwChecksumLen = (DWORD)checksumlen;
2704
2705 /* since this can fail in multiple ways, zero memory first so we never
2706 * return old data
2707 */
2708 memset(checksum, 0, checksumlen);
2709
2710 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2711 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2712 return; /* failed */
2713
2714 do {
2715 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2716 break; /* failed */
2717
2718 /* workaround for original MinGW, should be (const BYTE*) */
2719 if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2720 break; /* failed */
2721
2722 /* get hash size */
2723 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2724 &dwHashSizeLen, 0))
2725 break; /* failed */
2726
2727 /* check hash size */
2728 if(checksumlen < cbHashSize)
2729 break; /* failed */
2730
2731 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2732 break; /* failed */
2733 } while(0);
2734
2735 if(hHash)
2736 CryptDestroyHash(hHash);
2737
2738 if(hProv)
2739 CryptReleaseContext(hProv, 0);
2740}
2741
2742static CURLcode schannel_sha256sum(const unsigned char *input,
2743 size_t inputlen,
2744 unsigned char *sha256sum,
2745 size_t sha256len)
2746{
2747 schannel_checksum(input, inputlen, sha256sum, sha256len,
2748 PROV_RSA_AES, CALG_SHA_256);
2749 return CURLE_OK;
2750}
2751
2752static void *schannel_get_internals(struct ssl_connect_data *connssl,
2753 CURLINFO info UNUSED_PARAM)
2754{
2755 struct ssl_backend_data *backend = connssl->backend;
2756 (void)info;
2757 DEBUGASSERT(backend);
2758 return &backend->ctxt->ctxt_handle;
2759}
2760
2761const struct Curl_ssl Curl_ssl_schannel = {
2762 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2763
2764 SSLSUPP_CERTINFO |
2765#ifdef HAS_MANUAL_VERIFY_API
2766 SSLSUPP_CAINFO_BLOB |
2767#endif
2768 SSLSUPP_PINNEDPUBKEY |
2769 SSLSUPP_TLS13_CIPHERSUITES |
2770 SSLSUPP_HTTPS_PROXY,
2771
2772 sizeof(struct ssl_backend_data),
2773
2774 schannel_init, /* init */
2775 schannel_cleanup, /* cleanup */
2776 schannel_version, /* version */
2777 Curl_none_check_cxn, /* check_cxn */
2778 schannel_shutdown, /* shutdown */
2779 schannel_data_pending, /* data_pending */
2780 schannel_random, /* random */
2781 Curl_none_cert_status_request, /* cert_status_request */
2782 schannel_connect, /* connect */
2783 schannel_connect_nonblocking, /* connect_nonblocking */
2784 Curl_ssl_get_select_socks, /* getsock */
2785 schannel_get_internals, /* get_internals */
2786 schannel_close, /* close_one */
2787 Curl_none_close_all, /* close_all */
2788 schannel_session_free, /* session_free */
2789 Curl_none_set_engine, /* set_engine */
2790 Curl_none_set_engine_default, /* set_engine_default */
2791 Curl_none_engines_list, /* engines_list */
2792 Curl_none_false_start, /* false_start */
2793 schannel_sha256sum, /* sha256sum */
2794 NULL, /* associate_connection */
2795 NULL, /* disassociate_connection */
2796 NULL, /* free_multi_ssl_backend_data */
2797 schannel_recv, /* recv decrypted data */
2798 schannel_send, /* send data to encrypt */
2799};
2800
2801#endif /* USE_SCHANNEL */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette