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