VirtualBox

source: vbox/trunk/src/libs/curl-8.3.0/lib/vtls/schannel.c@ 101127

Last change on this file since 101127 was 101127, checked in by vboxsync, 19 months ago

curl-8.3.0: Applied and adjusted our curl changes to 8.0.1. bugref:10526

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

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