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 = (long)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_ID)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 = (DWORD)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 &= ~(DWORD)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 = (DWORD)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->peer.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, &connssl->peer,
1133 (void **)&old_cred, NULL)) {
1134 backend->cred = old_cred;
1135 DEBUGF(infof(data, "schannel: reusing existing credential handle"));
1136
1137 /* increment the reference counter of the credential/session handle */
1138 backend->cred->refcount++;
1139 DEBUGF(infof(data,
1140 "schannel: incremented credential handle refcount = %d",
1141 backend->cred->refcount));
1142 }
1143 Curl_ssl_sessionid_unlock(data);
1144 }
1145
1146 if(!backend->cred) {
1147 char *snihost;
1148 result = schannel_acquire_credential_handle(cf, data);
1149 if(result)
1150 return result;
1151 /* schannel_acquire_credential_handle() sets backend->cred accordingly or
1152 it returns error otherwise. */
1153
1154 /* A hostname associated with the credential is needed by
1155 InitializeSecurityContext for SNI and other reasons. */
1156 snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
1157 backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
1158 if(!backend->cred->sni_hostname)
1159 return CURLE_OUT_OF_MEMORY;
1160 }
1161
1162 /* Warn if SNI is disabled due to use of an IP address */
1163 if(connssl->peer.type != CURL_SSL_PEER_DNS) {
1164 infof(data, "schannel: using IP address, SNI is not supported by OS.");
1165 }
1166
1167 #ifdef HAS_ALPN
1168 if(backend->use_alpn) {
1169 int cur = 0;
1170 int list_start_index = 0;
1171 unsigned int *extension_len = NULL;
1172 unsigned short* list_len = NULL;
1173 struct alpn_proto_buf proto;
1174
1175 /* The first four bytes will be an unsigned int indicating number
1176 of bytes of data in the rest of the buffer. */
1177 extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
1178 cur += (int)sizeof(unsigned int);
1179
1180 /* The next four bytes are an indicator that this buffer will contain
1181 ALPN data, as opposed to NPN, for example. */
1182 *(unsigned int *)(void *)&alpn_buffer[cur] =
1183 SecApplicationProtocolNegotiationExt_ALPN;
1184 cur += (int)sizeof(unsigned int);
1185
1186 /* The next two bytes will be an unsigned short indicating the number
1187 of bytes used to list the preferred protocols. */
1188 list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
1189 cur += (int)sizeof(unsigned short);
1190
1191 list_start_index = cur;
1192
1193 result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
1194 if(result) {
1195 failf(data, "Error setting ALPN");
1196 return CURLE_SSL_CONNECT_ERROR;
1197 }
1198 memcpy(&alpn_buffer[cur], proto.data, proto.len);
1199 cur += proto.len;
1200
1201 *list_len = curlx_uitous(cur - list_start_index);
1202 *extension_len = (unsigned int)(*list_len +
1203 sizeof(unsigned int) + sizeof(unsigned short));
1204
1205 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
1206 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1207
1208 Curl_alpn_to_proto_str(&proto, connssl->alpn);
1209 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
1210 }
1211 else {
1212 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1213 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1214 }
1215 #else /* HAS_ALPN */
1216 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1217 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1218 #endif
1219
1220 /* setup output buffer */
1221 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1222 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1223
1224 /* security request flags */
1225 backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1226 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
1227 ISC_REQ_STREAM;
1228
1229 if(!ssl_config->auto_client_cert) {
1230 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1231 }
1232
1233 /* allocate memory for the security context handle */
1234 backend->ctxt = (struct Curl_schannel_ctxt *)
1235 calloc(1, sizeof(struct Curl_schannel_ctxt));
1236 if(!backend->ctxt) {
1237 failf(data, "schannel: unable to allocate memory");
1238 return CURLE_OUT_OF_MEMORY;
1239 }
1240
1241 /* Schannel InitializeSecurityContext:
1242 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
1243
1244 At the moment we don't pass inbuf unless we're using ALPN since we only
1245 use it for that, and Wine (for which we currently disable ALPN) is giving
1246 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
1247 */
1248 sspi_status = s_pSecFn->InitializeSecurityContext(
1249 &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
1250 backend->req_flags, 0, 0,
1251 (backend->use_alpn ? &inbuf_desc : NULL),
1252 0, &backend->ctxt->ctxt_handle,
1253 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1254
1255 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
1256 char buffer[STRERROR_LEN];
1257 Curl_safefree(backend->ctxt);
1258 switch(sspi_status) {
1259 case SEC_E_INSUFFICIENT_MEMORY:
1260 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1261 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1262 return CURLE_OUT_OF_MEMORY;
1263 case SEC_E_WRONG_PRINCIPAL:
1264 failf(data, "schannel: SNI or certificate check failed: %s",
1265 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1266 return CURLE_PEER_FAILED_VERIFICATION;
1267 /*
1268 case SEC_E_INVALID_HANDLE:
1269 case SEC_E_INVALID_TOKEN:
1270 case SEC_E_LOGON_DENIED:
1271 case SEC_E_TARGET_UNKNOWN:
1272 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1273 case SEC_E_INTERNAL_ERROR:
1274 case SEC_E_NO_CREDENTIALS:
1275 case SEC_E_UNSUPPORTED_FUNCTION:
1276 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1277 */
1278 default:
1279 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1280 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1281 return CURLE_SSL_CONNECT_ERROR;
1282 }
1283 }
1284
1285 DEBUGF(infof(data, "schannel: sending initial handshake data: "
1286 "sending %lu bytes.", outbuf.cbBuffer));
1287
1288 /* send initial handshake data which is now stored in output buffer */
1289 written = Curl_conn_cf_send(cf->next, data,
1290 outbuf.pvBuffer, outbuf.cbBuffer,
1291 &result);
1292 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1293 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1294 failf(data, "schannel: failed to send initial handshake data: "
1295 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
1296 return CURLE_SSL_CONNECT_ERROR;
1297 }
1298
1299 DEBUGF(infof(data, "schannel: sent initial handshake data: "
1300 "sent %zd bytes", written));
1301
1302 backend->recv_unrecoverable_err = CURLE_OK;
1303 backend->recv_sspi_close_notify = false;
1304 backend->recv_connection_closed = false;
1305 backend->recv_renegotiating = false;
1306 backend->encdata_is_incomplete = false;
1307
1308 /* continue to second handshake step */
1309 connssl->connecting_state = ssl_connect_2;
1310
1311 return CURLE_OK;
1312 }
1313
1314 static CURLcode
schannel_connect_step2(struct Curl_cfilter * cf,struct Curl_easy * data)1315 schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
1316 {
1317 struct ssl_connect_data *connssl = cf->ctx;
1318 struct schannel_ssl_backend_data *backend =
1319 (struct schannel_ssl_backend_data *)connssl->backend;
1320 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1321 int i;
1322 ssize_t nread = -1, written = -1;
1323 unsigned char *reallocated_buffer;
1324 SecBuffer outbuf[3];
1325 SecBufferDesc outbuf_desc;
1326 SecBuffer inbuf[2];
1327 SecBufferDesc inbuf_desc;
1328 SECURITY_STATUS sspi_status = SEC_E_OK;
1329 CURLcode result;
1330 bool doread;
1331 const char *pubkey_ptr;
1332
1333 DEBUGASSERT(backend);
1334
1335 doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
1336 connssl->io_need = CURL_SSL_IO_NEED_NONE;
1337
1338 DEBUGF(infof(data,
1339 "schannel: SSL/TLS connection with %s port %d (step 2/3)",
1340 connssl->peer.hostname, connssl->peer.port));
1341
1342 if(!backend->cred || !backend->ctxt)
1343 return CURLE_SSL_CONNECT_ERROR;
1344
1345 /* buffer to store previously received and decrypted data */
1346 if(!backend->decdata_buffer) {
1347 backend->decdata_offset = 0;
1348 backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1349 backend->decdata_buffer = malloc(backend->decdata_length);
1350 if(!backend->decdata_buffer) {
1351 failf(data, "schannel: unable to allocate memory");
1352 return CURLE_OUT_OF_MEMORY;
1353 }
1354 }
1355
1356 /* buffer to store previously received and encrypted data */
1357 if(!backend->encdata_buffer) {
1358 backend->encdata_is_incomplete = false;
1359 backend->encdata_offset = 0;
1360 backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1361 backend->encdata_buffer = malloc(backend->encdata_length);
1362 if(!backend->encdata_buffer) {
1363 failf(data, "schannel: unable to allocate memory");
1364 return CURLE_OUT_OF_MEMORY;
1365 }
1366 }
1367
1368 /* if we need a bigger buffer to read a full message, increase buffer now */
1369 if(backend->encdata_length - backend->encdata_offset <
1370 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1371 /* increase internal encrypted data buffer */
1372 size_t reallocated_length = backend->encdata_offset +
1373 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1374 reallocated_buffer = realloc(backend->encdata_buffer,
1375 reallocated_length);
1376
1377 if(!reallocated_buffer) {
1378 failf(data, "schannel: unable to re-allocate memory");
1379 return CURLE_OUT_OF_MEMORY;
1380 }
1381 else {
1382 backend->encdata_buffer = reallocated_buffer;
1383 backend->encdata_length = reallocated_length;
1384 }
1385 }
1386
1387 for(;;) {
1388 if(doread) {
1389 /* read encrypted handshake data from socket */
1390 nread = Curl_conn_cf_recv(cf->next, data,
1391 (char *) (backend->encdata_buffer +
1392 backend->encdata_offset),
1393 backend->encdata_length -
1394 backend->encdata_offset,
1395 &result);
1396 if(result == CURLE_AGAIN) {
1397 connssl->io_need = CURL_SSL_IO_NEED_RECV;
1398 DEBUGF(infof(data, "schannel: failed to receive handshake, "
1399 "need more data"));
1400 return CURLE_OK;
1401 }
1402 else if((result != CURLE_OK) || (nread == 0)) {
1403 failf(data, "schannel: failed to receive handshake, "
1404 "SSL/TLS connection failed");
1405 return CURLE_SSL_CONNECT_ERROR;
1406 }
1407
1408 /* increase encrypted data buffer offset */
1409 backend->encdata_offset += nread;
1410 backend->encdata_is_incomplete = false;
1411 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1412 }
1413
1414 DEBUGF(infof(data,
1415 "schannel: encrypted data buffer: offset %zu length %zu",
1416 backend->encdata_offset, backend->encdata_length));
1417
1418 /* setup input buffers */
1419 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
1420 curlx_uztoul(backend->encdata_offset));
1421 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1422 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1423
1424 /* setup output buffers */
1425 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1426 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1427 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1428 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1429
1430 if(!inbuf[0].pvBuffer) {
1431 failf(data, "schannel: unable to allocate memory");
1432 return CURLE_OUT_OF_MEMORY;
1433 }
1434
1435 /* copy received handshake data into input buffer */
1436 memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
1437 backend->encdata_offset);
1438
1439 sspi_status = s_pSecFn->InitializeSecurityContext(
1440 &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
1441 backend->cred->sni_hostname, backend->req_flags,
1442 0, 0, &inbuf_desc, 0, NULL,
1443 &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1444
1445 /* free buffer for received handshake data */
1446 Curl_safefree(inbuf[0].pvBuffer);
1447
1448 /* check if the handshake was incomplete */
1449 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1450 backend->encdata_is_incomplete = true;
1451 connssl->io_need = CURL_SSL_IO_NEED_RECV;
1452 DEBUGF(infof(data,
1453 "schannel: received incomplete message, need more data"));
1454 return CURLE_OK;
1455 }
1456
1457 /* If the server has requested a client certificate, attempt to continue
1458 the handshake without one. This will allow connections to servers which
1459 request a client certificate but do not require it. */
1460 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1461 !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1462 backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1463 connssl->io_need = CURL_SSL_IO_NEED_SEND;
1464 DEBUGF(infof(data,
1465 "schannel: a client certificate has been requested"));
1466 return CURLE_OK;
1467 }
1468
1469 /* check if the handshake needs to be continued */
1470 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1471 for(i = 0; i < 3; i++) {
1472 /* search for handshake tokens that need to be send */
1473 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1474 DEBUGF(infof(data, "schannel: sending next handshake data: "
1475 "sending %lu bytes.", outbuf[i].cbBuffer));
1476
1477 /* send handshake token to server */
1478 written = Curl_conn_cf_send(cf->next, data,
1479 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1480 &result);
1481 if((result != CURLE_OK) ||
1482 (outbuf[i].cbBuffer != (size_t) written)) {
1483 failf(data, "schannel: failed to send next handshake data: "
1484 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1485 return CURLE_SSL_CONNECT_ERROR;
1486 }
1487 }
1488
1489 /* free obsolete buffer */
1490 if(outbuf[i].pvBuffer) {
1491 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1492 }
1493 }
1494 }
1495 else {
1496 char buffer[STRERROR_LEN];
1497 switch(sspi_status) {
1498 case SEC_E_INSUFFICIENT_MEMORY:
1499 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1500 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1501 return CURLE_OUT_OF_MEMORY;
1502 case SEC_E_WRONG_PRINCIPAL:
1503 failf(data, "schannel: SNI or certificate check failed: %s",
1504 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1505 return CURLE_PEER_FAILED_VERIFICATION;
1506 case SEC_E_UNTRUSTED_ROOT:
1507 failf(data, "schannel: %s",
1508 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1509 return CURLE_PEER_FAILED_VERIFICATION;
1510 /*
1511 case SEC_E_INVALID_HANDLE:
1512 case SEC_E_INVALID_TOKEN:
1513 case SEC_E_LOGON_DENIED:
1514 case SEC_E_TARGET_UNKNOWN:
1515 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1516 case SEC_E_INTERNAL_ERROR:
1517 case SEC_E_NO_CREDENTIALS:
1518 case SEC_E_UNSUPPORTED_FUNCTION:
1519 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1520 */
1521 default:
1522 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1523 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1524 return CURLE_SSL_CONNECT_ERROR;
1525 }
1526 }
1527
1528 /* check if there was additional remaining encrypted data */
1529 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1530 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1531 inbuf[1].cbBuffer));
1532 /*
1533 There are two cases where we could be getting extra data here:
1534 1) If we're renegotiating a connection and the handshake is already
1535 complete (from the server perspective), it can encrypted app data
1536 (not handshake data) in an extra buffer at this point.
1537 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1538 connection and this extra data is part of the handshake.
1539 We should process the data immediately; waiting for the socket to
1540 be ready may fail since the server is done sending handshake data.
1541 */
1542 /* check if the remaining data is less than the total amount
1543 and therefore begins after the already processed data */
1544 if(backend->encdata_offset > inbuf[1].cbBuffer) {
1545 memmove(backend->encdata_buffer,
1546 (backend->encdata_buffer + backend->encdata_offset) -
1547 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1548 backend->encdata_offset = inbuf[1].cbBuffer;
1549 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1550 doread = FALSE;
1551 continue;
1552 }
1553 }
1554 }
1555 else {
1556 backend->encdata_offset = 0;
1557 }
1558 break;
1559 }
1560
1561 /* check if the handshake needs to be continued */
1562 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1563 connssl->io_need = CURL_SSL_IO_NEED_RECV;
1564 return CURLE_OK;
1565 }
1566
1567 /* check if the handshake is complete */
1568 if(sspi_status == SEC_E_OK) {
1569 connssl->connecting_state = ssl_connect_3;
1570 DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1571 }
1572
1573 #ifndef CURL_DISABLE_PROXY
1574 pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
1575 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
1576 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1577 #else
1578 pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1579 #endif
1580 if(pubkey_ptr) {
1581 result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
1582 if(result) {
1583 failf(data, "SSL: public key does not match pinned public key");
1584 return result;
1585 }
1586 }
1587
1588 #ifdef HAS_MANUAL_VERIFY_API
1589 if(conn_config->verifypeer && backend->use_manual_cred_validation) {
1590 /* Certificate verification also verifies the hostname if verifyhost */
1591 return Curl_verify_certificate(cf, data);
1592 }
1593 #endif
1594
1595 /* Verify the hostname manually when certificate verification is disabled,
1596 because in that case Schannel won't verify it. */
1597 if(!conn_config->verifypeer && conn_config->verifyhost)
1598 return Curl_verify_host(cf, data);
1599
1600 return CURLE_OK;
1601 }
1602
1603 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1604 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1605 {
1606 return (cert_context != NULL) &&
1607 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1608 (cert_context->pbCertEncoded != NULL) &&
1609 (cert_context->cbCertEncoded > 0);
1610 }
1611
1612 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context,
1613 bool reverse_order, void *arg);
1614
1615 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1616 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1617 void *arg)
1618 {
1619 const CERT_CONTEXT *current_context = NULL;
1620 bool should_continue = true;
1621 bool first = true;
1622 bool reverse_order = false;
1623 while(should_continue &&
1624 (current_context = CertEnumCertificatesInStore(
1625 context->hCertStore,
1626 current_context)) != NULL) {
1627 /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in
1628 leaf-to-root order while all previous versions of Windows enumerate
1629 certificates in root-to-leaf order. Determine the order of enumeration
1630 by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
1631 first certificate's pbCertContext. */
1632 if(first && context->pbCertEncoded != current_context->pbCertEncoded)
1633 reverse_order = true;
1634 should_continue = func(current_context, reverse_order, arg);
1635 first = false;
1636 }
1637
1638 if(current_context)
1639 CertFreeCertificateContext(current_context);
1640 }
1641
1642 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,bool reverse_order,void * certs_count)1643 cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
1644 void *certs_count)
1645 {
1646 (void)reverse_order; /* unused */
1647 if(valid_cert_encoding(ccert_context))
1648 (*(int *)certs_count)++;
1649 return true;
1650 }
1651
1652 struct Adder_args
1653 {
1654 struct Curl_easy *data;
1655 CURLcode result;
1656 int idx;
1657 int certs_count;
1658 };
1659
1660 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,bool reverse_order,void * raw_arg)1661 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
1662 void *raw_arg)
1663 {
1664 struct Adder_args *args = (struct Adder_args*)raw_arg;
1665 args->result = CURLE_OK;
1666 if(valid_cert_encoding(ccert_context)) {
1667 const char *beg = (const char *) ccert_context->pbCertEncoded;
1668 const char *end = beg + ccert_context->cbCertEncoded;
1669 int insert_index = reverse_order ? (args->certs_count - 1) - args->idx :
1670 args->idx;
1671 args->result = Curl_extract_certinfo(args->data, insert_index,
1672 beg, end);
1673 args->idx++;
1674 }
1675 return args->result == CURLE_OK;
1676 }
1677
schannel_session_free(void * sessionid,size_t idsize)1678 static void schannel_session_free(void *sessionid, size_t idsize)
1679 {
1680 /* this is expected to be called under sessionid lock */
1681 struct Curl_schannel_cred *cred = sessionid;
1682
1683 (void)idsize;
1684 if(cred) {
1685 cred->refcount--;
1686 if(cred->refcount == 0) {
1687 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1688 curlx_unicodefree(cred->sni_hostname);
1689 #ifdef HAS_CLIENT_CERT_PATH
1690 if(cred->client_cert_store) {
1691 CertCloseStore(cred->client_cert_store, 0);
1692 cred->client_cert_store = NULL;
1693 }
1694 #endif
1695 Curl_safefree(cred);
1696 }
1697 }
1698 }
1699
1700 static CURLcode
schannel_connect_step3(struct Curl_cfilter * cf,struct Curl_easy * data)1701 schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
1702 {
1703 struct ssl_connect_data *connssl = cf->ctx;
1704 struct schannel_ssl_backend_data *backend =
1705 (struct schannel_ssl_backend_data *)connssl->backend;
1706 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1707 CURLcode result = CURLE_OK;
1708 SECURITY_STATUS sspi_status = SEC_E_OK;
1709 CERT_CONTEXT *ccert_context = NULL;
1710 #ifdef HAS_ALPN
1711 SecPkgContext_ApplicationProtocol alpn_result;
1712 #endif
1713
1714 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1715 DEBUGASSERT(backend);
1716
1717 DEBUGF(infof(data,
1718 "schannel: SSL/TLS connection with %s port %d (step 3/3)",
1719 connssl->peer.hostname, connssl->peer.port));
1720
1721 if(!backend->cred)
1722 return CURLE_SSL_CONNECT_ERROR;
1723
1724 /* check if the required context attributes are met */
1725 if(backend->ret_flags != backend->req_flags) {
1726 if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
1727 failf(data, "schannel: failed to setup sequence detection");
1728 if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
1729 failf(data, "schannel: failed to setup replay detection");
1730 if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
1731 failf(data, "schannel: failed to setup confidentiality");
1732 if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1733 failf(data, "schannel: failed to setup memory allocation");
1734 if(!(backend->ret_flags & ISC_RET_STREAM))
1735 failf(data, "schannel: failed to setup stream orientation");
1736 return CURLE_SSL_CONNECT_ERROR;
1737 }
1738
1739 #ifdef HAS_ALPN
1740 if(backend->use_alpn) {
1741 sspi_status =
1742 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1743 SECPKG_ATTR_APPLICATION_PROTOCOL,
1744 &alpn_result);
1745
1746 if(sspi_status != SEC_E_OK) {
1747 failf(data, "schannel: failed to retrieve ALPN result");
1748 return CURLE_SSL_CONNECT_ERROR;
1749 }
1750
1751 if(alpn_result.ProtoNegoStatus ==
1752 SecApplicationProtocolNegotiationStatus_Success) {
1753 unsigned char prev_alpn = cf->conn->alpn;
1754
1755 Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId,
1756 alpn_result.ProtocolIdSize);
1757 if(backend->recv_renegotiating) {
1758 if(prev_alpn != cf->conn->alpn &&
1759 prev_alpn != CURL_HTTP_VERSION_NONE) {
1760 /* Renegotiation selected a different protocol now, we cannot
1761 * deal with this */
1762 failf(data, "schannel: server selected an ALPN protocol too late");
1763 return CURLE_SSL_CONNECT_ERROR;
1764 }
1765 }
1766 }
1767 else {
1768 if(!backend->recv_renegotiating)
1769 Curl_alpn_set_negotiated(cf, data, NULL, 0);
1770 }
1771 }
1772 #endif
1773
1774 /* save the current session data for possible reuse */
1775 if(ssl_config->primary.sessionid) {
1776 bool incache;
1777 struct Curl_schannel_cred *old_cred = NULL;
1778
1779 Curl_ssl_sessionid_lock(data);
1780 incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
1781 (void **)&old_cred, NULL));
1782 if(incache) {
1783 if(old_cred != backend->cred) {
1784 DEBUGF(infof(data,
1785 "schannel: old credential handle is stale, removing"));
1786 /* we're not taking old_cred ownership here, no refcount++ is needed */
1787 Curl_ssl_delsessionid(data, (void *)old_cred);
1788 incache = FALSE;
1789 }
1790 }
1791 if(!incache) {
1792 /* Up ref count since call takes ownership */
1793 backend->cred->refcount++;
1794 result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
1795 sizeof(struct Curl_schannel_cred),
1796 schannel_session_free);
1797 if(result) {
1798 Curl_ssl_sessionid_unlock(data);
1799 return result;
1800 }
1801 }
1802 Curl_ssl_sessionid_unlock(data);
1803 }
1804
1805 if(data->set.ssl.certinfo) {
1806 int certs_count = 0;
1807 sspi_status =
1808 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1809 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1810 &ccert_context);
1811
1812 if((sspi_status != SEC_E_OK) || !ccert_context) {
1813 failf(data, "schannel: failed to retrieve remote cert context");
1814 return CURLE_PEER_FAILED_VERIFICATION;
1815 }
1816
1817 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1818
1819 result = Curl_ssl_init_certinfo(data, certs_count);
1820 if(!result) {
1821 struct Adder_args args;
1822 args.data = data;
1823 args.idx = 0;
1824 args.certs_count = certs_count;
1825 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1826 result = args.result;
1827 }
1828 CertFreeCertificateContext(ccert_context);
1829 if(result)
1830 return result;
1831 }
1832
1833 connssl->connecting_state = ssl_connect_done;
1834
1835 return CURLE_OK;
1836 }
1837
1838 static CURLcode
schannel_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool nonblocking,bool * done)1839 schannel_connect_common(struct Curl_cfilter *cf,
1840 struct Curl_easy *data,
1841 bool nonblocking, bool *done)
1842 {
1843 CURLcode result;
1844 struct ssl_connect_data *connssl = cf->ctx;
1845 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1846 timediff_t timeout_ms;
1847 int what;
1848
1849 /* check if the connection has already been established */
1850 if(ssl_connection_complete == connssl->state) {
1851 *done = TRUE;
1852 return CURLE_OK;
1853 }
1854
1855 if(ssl_connect_1 == connssl->connecting_state) {
1856 /* check out how much more time we're allowed */
1857 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1858
1859 if(timeout_ms < 0) {
1860 /* no need to continue if time already is up */
1861 failf(data, "SSL/TLS connection timeout");
1862 return CURLE_OPERATION_TIMEDOUT;
1863 }
1864
1865 result = schannel_connect_step1(cf, data);
1866 if(result)
1867 return result;
1868 }
1869
1870 while(ssl_connect_2 == connssl->connecting_state) {
1871
1872 /* check out how much more time we're allowed */
1873 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1874
1875 if(timeout_ms < 0) {
1876 /* no need to continue if time already is up */
1877 failf(data, "SSL/TLS connection timeout");
1878 return CURLE_OPERATION_TIMEDOUT;
1879 }
1880
1881 /* if ssl is expecting something, check if it's available. */
1882 if(connssl->io_need) {
1883
1884 curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
1885 sockfd : CURL_SOCKET_BAD;
1886 curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
1887 sockfd : CURL_SOCKET_BAD;
1888
1889 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1890 nonblocking ? 0 : timeout_ms);
1891 if(what < 0) {
1892 /* fatal error */
1893 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1894 return CURLE_SSL_CONNECT_ERROR;
1895 }
1896 else if(0 == what) {
1897 if(nonblocking) {
1898 *done = FALSE;
1899 return CURLE_OK;
1900 }
1901 else {
1902 /* timeout */
1903 failf(data, "SSL/TLS connection timeout");
1904 return CURLE_OPERATION_TIMEDOUT;
1905 }
1906 }
1907 /* socket is readable or writable */
1908 }
1909
1910 /* Run transaction, and return to the caller if it failed or if
1911 * this connection is part of a multi handle and this loop would
1912 * execute again. This permits the owner of a multi handle to
1913 * abort a connection attempt before step2 has completed while
1914 * ensuring that a client using select() or epoll() will always
1915 * have a valid fdset to wait on.
1916 */
1917 result = schannel_connect_step2(cf, data);
1918 if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
1919 return result;
1920
1921 } /* repeat step2 until all transactions are done. */
1922
1923 if(ssl_connect_3 == connssl->connecting_state) {
1924 result = schannel_connect_step3(cf, data);
1925 if(result)
1926 return result;
1927 }
1928
1929 if(ssl_connect_done == connssl->connecting_state) {
1930 connssl->state = ssl_connection_complete;
1931
1932 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1933 /* When SSPI is used in combination with Schannel
1934 * we need the Schannel context to create the Schannel
1935 * binding to pass the IIS extended protection checks.
1936 * Available on Windows 7 or later.
1937 */
1938 {
1939 struct schannel_ssl_backend_data *backend =
1940 (struct schannel_ssl_backend_data *)connssl->backend;
1941 DEBUGASSERT(backend);
1942 cf->conn->sslContext = &backend->ctxt->ctxt_handle;
1943 }
1944 #endif
1945
1946 *done = TRUE;
1947 }
1948 else
1949 *done = FALSE;
1950
1951 /* reset our connection state machine */
1952 connssl->connecting_state = ssl_connect_1;
1953
1954 return CURLE_OK;
1955 }
1956
1957 static ssize_t
schannel_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1958 schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1959 const void *buf, size_t len, CURLcode *err)
1960 {
1961 ssize_t written = -1;
1962 size_t data_len = 0;
1963 unsigned char *ptr = NULL;
1964 struct ssl_connect_data *connssl = cf->ctx;
1965 SecBuffer outbuf[4];
1966 SecBufferDesc outbuf_desc;
1967 SECURITY_STATUS sspi_status = SEC_E_OK;
1968 CURLcode result;
1969 struct schannel_ssl_backend_data *backend =
1970 (struct schannel_ssl_backend_data *)connssl->backend;
1971
1972 DEBUGASSERT(backend);
1973
1974 /* check if the maximum stream sizes were queried */
1975 if(backend->stream_sizes.cbMaximumMessage == 0) {
1976 sspi_status = s_pSecFn->QueryContextAttributes(
1977 &backend->ctxt->ctxt_handle,
1978 SECPKG_ATTR_STREAM_SIZES,
1979 &backend->stream_sizes);
1980 if(sspi_status != SEC_E_OK) {
1981 *err = CURLE_SEND_ERROR;
1982 return -1;
1983 }
1984 }
1985
1986 /* check if the buffer is longer than the maximum message length */
1987 if(len > backend->stream_sizes.cbMaximumMessage) {
1988 len = backend->stream_sizes.cbMaximumMessage;
1989 }
1990
1991 /* calculate the complete message length and allocate a buffer for it */
1992 data_len = backend->stream_sizes.cbHeader + len +
1993 backend->stream_sizes.cbTrailer;
1994 ptr = (unsigned char *) malloc(data_len);
1995 if(!ptr) {
1996 *err = CURLE_OUT_OF_MEMORY;
1997 return -1;
1998 }
1999
2000 /* setup output buffers (header, data, trailer, empty) */
2001 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
2002 ptr, backend->stream_sizes.cbHeader);
2003 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
2004 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
2005 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
2006 ptr + backend->stream_sizes.cbHeader + len,
2007 backend->stream_sizes.cbTrailer);
2008 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
2009 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
2010
2011 /* copy data into output buffer */
2012 memcpy(outbuf[1].pvBuffer, buf, len);
2013
2014 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
2015 sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
2016 &outbuf_desc, 0);
2017
2018 /* check if the message was encrypted */
2019 if(sspi_status == SEC_E_OK) {
2020 written = 0;
2021
2022 /* send the encrypted message including header, data and trailer */
2023 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
2024
2025 /*
2026 It's important to send the full message which includes the header,
2027 encrypted payload, and trailer. Until the client receives all the
2028 data a coherent message has not been delivered and the client
2029 can't read any of it.
2030
2031 If we wanted to buffer the unwritten encrypted bytes, we would
2032 tell the client that all data it has requested to be sent has been
2033 sent. The unwritten encrypted bytes would be the first bytes to
2034 send on the next invocation.
2035 Here's the catch with this - if we tell the client that all the
2036 bytes have been sent, will the client call this method again to
2037 send the buffered data? Looking at who calls this function, it
2038 seems the answer is NO.
2039 */
2040
2041 /* send entire message or fail */
2042 while(len > (size_t)written) {
2043 ssize_t this_write = 0;
2044 int what;
2045 timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
2046 if(timeout_ms < 0) {
2047 /* we already got the timeout */
2048 failf(data, "schannel: timed out sending data "
2049 "(bytes sent: %zd)", written);
2050 *err = CURLE_OPERATION_TIMEDOUT;
2051 written = -1;
2052 break;
2053 }
2054 else if(!timeout_ms)
2055 timeout_ms = TIMEDIFF_T_MAX;
2056 what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms);
2057 if(what < 0) {
2058 /* fatal error */
2059 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2060 *err = CURLE_SEND_ERROR;
2061 written = -1;
2062 break;
2063 }
2064 else if(0 == what) {
2065 failf(data, "schannel: timed out sending data "
2066 "(bytes sent: %zd)", written);
2067 *err = CURLE_OPERATION_TIMEDOUT;
2068 written = -1;
2069 break;
2070 }
2071 /* socket is writable */
2072
2073 this_write = Curl_conn_cf_send(cf->next, data,
2074 ptr + written, len - written,
2075 &result);
2076 if(result == CURLE_AGAIN)
2077 continue;
2078 else if(result != CURLE_OK) {
2079 *err = result;
2080 written = -1;
2081 break;
2082 }
2083
2084 written += this_write;
2085 }
2086 }
2087 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
2088 *err = CURLE_OUT_OF_MEMORY;
2089 }
2090 else{
2091 *err = CURLE_SEND_ERROR;
2092 }
2093
2094 Curl_safefree(ptr);
2095
2096 if(len == (size_t)written)
2097 /* Encrypted message including header, data and trailer entirely sent.
2098 The return value is the number of unencrypted bytes that were sent. */
2099 written = outbuf[1].cbBuffer;
2100
2101 return written;
2102 }
2103
2104 static ssize_t
schannel_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)2105 schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
2106 char *buf, size_t len, CURLcode *err)
2107 {
2108 size_t size = 0;
2109 ssize_t nread = -1;
2110 struct ssl_connect_data *connssl = cf->ctx;
2111 unsigned char *reallocated_buffer;
2112 size_t reallocated_length;
2113 bool done = FALSE;
2114 SecBuffer inbuf[4];
2115 SecBufferDesc inbuf_desc;
2116 SECURITY_STATUS sspi_status = SEC_E_OK;
2117 /* we want the length of the encrypted buffer to be at least large enough
2118 that it can hold all the bytes requested and some TLS record overhead. */
2119 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
2120 struct schannel_ssl_backend_data *backend =
2121 (struct schannel_ssl_backend_data *)connssl->backend;
2122
2123 DEBUGASSERT(backend);
2124
2125 /****************************************************************************
2126 * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
2127 * The pattern for return error is set *err, optional infof, goto cleanup.
2128 *
2129 * Our priority is to always return as much decrypted data to the caller as
2130 * possible, even if an error occurs. The state of the decrypted buffer must
2131 * always be valid. Transfer of decrypted data to the caller's buffer is
2132 * handled in the cleanup.
2133 */
2134
2135 DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
2136 *err = CURLE_OK;
2137
2138 if(len && len <= backend->decdata_offset) {
2139 infof(data, "schannel: enough decrypted data is already available");
2140 goto cleanup;
2141 }
2142 else if(backend->recv_unrecoverable_err) {
2143 *err = backend->recv_unrecoverable_err;
2144 infof(data, "schannel: an unrecoverable error occurred in a prior call");
2145 goto cleanup;
2146 }
2147 else if(backend->recv_sspi_close_notify) {
2148 /* once a server has indicated shutdown there is no more encrypted data */
2149 infof(data, "schannel: server indicated shutdown in a prior call");
2150 goto cleanup;
2151 }
2152 /* It's debatable what to return when !len. Regardless we can't return
2153 immediately because there may be data to decrypt (in the case we want to
2154 decrypt all encrypted cached data) so handle !len later in cleanup.
2155 */
2156 else if(len && !backend->recv_connection_closed) {
2157 /* increase enc buffer in order to fit the requested amount of data */
2158 size = backend->encdata_length - backend->encdata_offset;
2159 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2160 backend->encdata_length < min_encdata_length) {
2161 reallocated_length = backend->encdata_offset +
2162 CURL_SCHANNEL_BUFFER_FREE_SIZE;
2163 if(reallocated_length < min_encdata_length) {
2164 reallocated_length = min_encdata_length;
2165 }
2166 reallocated_buffer = realloc(backend->encdata_buffer,
2167 reallocated_length);
2168 if(!reallocated_buffer) {
2169 *err = CURLE_OUT_OF_MEMORY;
2170 failf(data, "schannel: unable to re-allocate memory");
2171 goto cleanup;
2172 }
2173
2174 backend->encdata_buffer = reallocated_buffer;
2175 backend->encdata_length = reallocated_length;
2176 size = backend->encdata_length - backend->encdata_offset;
2177 DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
2178 backend->encdata_length));
2179 }
2180
2181 DEBUGF(infof(data,
2182 "schannel: encrypted data buffer: offset %zu length %zu",
2183 backend->encdata_offset, backend->encdata_length));
2184
2185 /* read encrypted data from socket */
2186 nread = Curl_conn_cf_recv(cf->next, data,
2187 (char *)(backend->encdata_buffer +
2188 backend->encdata_offset),
2189 size, err);
2190 if(*err) {
2191 nread = -1;
2192 if(*err == CURLE_AGAIN)
2193 DEBUGF(infof(data,
2194 "schannel: recv returned CURLE_AGAIN"));
2195 else if(*err == CURLE_RECV_ERROR)
2196 infof(data, "schannel: recv returned CURLE_RECV_ERROR");
2197 else
2198 infof(data, "schannel: recv returned error %d", *err);
2199 }
2200 else if(nread == 0) {
2201 backend->recv_connection_closed = true;
2202 DEBUGF(infof(data, "schannel: server closed the connection"));
2203 }
2204 else if(nread > 0) {
2205 backend->encdata_offset += (size_t)nread;
2206 backend->encdata_is_incomplete = false;
2207 DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
2208 }
2209 }
2210
2211 DEBUGF(infof(data,
2212 "schannel: encrypted data buffer: offset %zu length %zu",
2213 backend->encdata_offset, backend->encdata_length));
2214
2215 /* decrypt loop */
2216 while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
2217 (!len || backend->decdata_offset < len ||
2218 backend->recv_connection_closed)) {
2219 /* prepare data buffer for DecryptMessage call */
2220 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
2221 curlx_uztoul(backend->encdata_offset));
2222
2223 /* we need 3 more empty input buffers for possible output */
2224 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
2225 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
2226 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
2227 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
2228
2229 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
2230 */
2231 sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
2232 &inbuf_desc, 0, NULL);
2233
2234 /* check if everything went fine (server may want to renegotiate
2235 or shutdown the connection context) */
2236 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
2237 sspi_status == SEC_I_CONTEXT_EXPIRED) {
2238 /* check for successfully decrypted data, even before actual
2239 renegotiation or shutdown of the connection context */
2240 if(inbuf[1].BufferType == SECBUFFER_DATA) {
2241 DEBUGF(infof(data, "schannel: decrypted data length: %lu",
2242 inbuf[1].cbBuffer));
2243
2244 /* increase buffer in order to fit the received amount of data */
2245 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
2246 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
2247 if(backend->decdata_length - backend->decdata_offset < size ||
2248 backend->decdata_length < len) {
2249 /* increase internal decrypted data buffer */
2250 reallocated_length = backend->decdata_offset + size;
2251 /* make sure that the requested amount of data fits */
2252 if(reallocated_length < len) {
2253 reallocated_length = len;
2254 }
2255 reallocated_buffer = realloc(backend->decdata_buffer,
2256 reallocated_length);
2257 if(!reallocated_buffer) {
2258 *err = CURLE_OUT_OF_MEMORY;
2259 failf(data, "schannel: unable to re-allocate memory");
2260 goto cleanup;
2261 }
2262 backend->decdata_buffer = reallocated_buffer;
2263 backend->decdata_length = reallocated_length;
2264 }
2265
2266 /* copy decrypted data to internal buffer */
2267 size = inbuf[1].cbBuffer;
2268 if(size) {
2269 memcpy(backend->decdata_buffer + backend->decdata_offset,
2270 inbuf[1].pvBuffer, size);
2271 backend->decdata_offset += size;
2272 }
2273
2274 DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
2275 DEBUGF(infof(data,
2276 "schannel: decrypted cached: offset %zu length %zu",
2277 backend->decdata_offset, backend->decdata_length));
2278 }
2279
2280 /* check for remaining encrypted data */
2281 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
2282 DEBUGF(infof(data, "schannel: encrypted data length: %lu",
2283 inbuf[3].cbBuffer));
2284
2285 /* check if the remaining data is less than the total amount
2286 * and therefore begins after the already processed data
2287 */
2288 if(backend->encdata_offset > inbuf[3].cbBuffer) {
2289 /* move remaining encrypted data forward to the beginning of
2290 buffer */
2291 memmove(backend->encdata_buffer,
2292 (backend->encdata_buffer + backend->encdata_offset) -
2293 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
2294 backend->encdata_offset = inbuf[3].cbBuffer;
2295 }
2296
2297 DEBUGF(infof(data,
2298 "schannel: encrypted cached: offset %zu length %zu",
2299 backend->encdata_offset, backend->encdata_length));
2300 }
2301 else {
2302 /* reset encrypted buffer offset, because there is no data remaining */
2303 backend->encdata_offset = 0;
2304 }
2305
2306 /* check if server wants to renegotiate the connection context */
2307 if(sspi_status == SEC_I_RENEGOTIATE) {
2308 infof(data, "schannel: remote party requests renegotiation");
2309 if(*err && *err != CURLE_AGAIN) {
2310 infof(data, "schannel: can't renegotiate, an error is pending");
2311 goto cleanup;
2312 }
2313
2314 /* begin renegotiation */
2315 infof(data, "schannel: renegotiating SSL/TLS connection");
2316 connssl->state = ssl_connection_negotiating;
2317 connssl->connecting_state = ssl_connect_2;
2318 connssl->io_need = CURL_SSL_IO_NEED_SEND;
2319 backend->recv_renegotiating = true;
2320 *err = schannel_connect_common(cf, data, FALSE, &done);
2321 backend->recv_renegotiating = false;
2322 if(*err) {
2323 infof(data, "schannel: renegotiation failed");
2324 goto cleanup;
2325 }
2326 /* now retry receiving data */
2327 sspi_status = SEC_E_OK;
2328 infof(data, "schannel: SSL/TLS connection renegotiated");
2329 continue;
2330 }
2331 /* check if the server closed the connection */
2332 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2333 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2334 returned so we have to work around that in cleanup. */
2335 backend->recv_sspi_close_notify = true;
2336 if(!backend->recv_connection_closed)
2337 backend->recv_connection_closed = true;
2338 infof(data,
2339 "schannel: server close notification received (close_notify)");
2340 goto cleanup;
2341 }
2342 }
2343 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2344 backend->encdata_is_incomplete = true;
2345 if(!*err)
2346 *err = CURLE_AGAIN;
2347 infof(data, "schannel: failed to decrypt data, need more data");
2348 goto cleanup;
2349 }
2350 else {
2351 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2352 char buffer[STRERROR_LEN];
2353 infof(data, "schannel: failed to read data from server: %s",
2354 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2355 #endif
2356 *err = CURLE_RECV_ERROR;
2357 goto cleanup;
2358 }
2359 }
2360
2361 DEBUGF(infof(data,
2362 "schannel: encrypted data buffer: offset %zu length %zu",
2363 backend->encdata_offset, backend->encdata_length));
2364
2365 DEBUGF(infof(data,
2366 "schannel: decrypted data buffer: offset %zu length %zu",
2367 backend->decdata_offset, backend->decdata_length));
2368
2369 cleanup:
2370 /* Warning- there is no guarantee the encdata state is valid at this point */
2371 DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2372
2373 /* Error if the connection has closed without a close_notify.
2374
2375 The behavior here is a matter of debate. We don't want to be vulnerable
2376 to a truncation attack however there's some browser precedent for
2377 ignoring the close_notify for compatibility reasons.
2378
2379 Additionally, Windows 2000 (v5.0) is a special case since it seems it
2380 doesn't return close_notify. In that case if the connection was closed we
2381 assume it was graceful (close_notify) since there doesn't seem to be a
2382 way to tell.
2383 */
2384 if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2385 !backend->recv_sspi_close_notify) {
2386 bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2387 VERSION_EQUAL);
2388
2389 if(isWin2k && sspi_status == SEC_E_OK)
2390 backend->recv_sspi_close_notify = true;
2391 else {
2392 *err = CURLE_RECV_ERROR;
2393 infof(data, "schannel: server closed abruptly (missing close_notify)");
2394 }
2395 }
2396
2397 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2398 if(*err && *err != CURLE_AGAIN)
2399 backend->recv_unrecoverable_err = *err;
2400
2401 size = len < backend->decdata_offset ? len : backend->decdata_offset;
2402 if(size) {
2403 memcpy(buf, backend->decdata_buffer, size);
2404 memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2405 backend->decdata_offset - size);
2406 backend->decdata_offset -= size;
2407 DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2408 DEBUGF(infof(data,
2409 "schannel: decrypted data buffer: offset %zu length %zu",
2410 backend->decdata_offset, backend->decdata_length));
2411 *err = CURLE_OK;
2412 return (ssize_t)size;
2413 }
2414
2415 if(!*err && !backend->recv_connection_closed)
2416 *err = CURLE_AGAIN;
2417
2418 /* It's debatable what to return when !len. We could return whatever error
2419 we got from decryption but instead we override here so the return is
2420 consistent.
2421 */
2422 if(!len)
2423 *err = CURLE_OK;
2424
2425 return *err ? -1 : 0;
2426 }
2427
schannel_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)2428 static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
2429 struct Curl_easy *data,
2430 bool *done)
2431 {
2432 return schannel_connect_common(cf, data, TRUE, done);
2433 }
2434
schannel_connect(struct Curl_cfilter * cf,struct Curl_easy * data)2435 static CURLcode schannel_connect(struct Curl_cfilter *cf,
2436 struct Curl_easy *data)
2437 {
2438 CURLcode result;
2439 bool done = FALSE;
2440
2441 result = schannel_connect_common(cf, data, FALSE, &done);
2442 if(result)
2443 return result;
2444
2445 DEBUGASSERT(done);
2446
2447 return CURLE_OK;
2448 }
2449
schannel_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)2450 static bool schannel_data_pending(struct Curl_cfilter *cf,
2451 const struct Curl_easy *data)
2452 {
2453 const struct ssl_connect_data *connssl = cf->ctx;
2454 struct schannel_ssl_backend_data *backend =
2455 (struct schannel_ssl_backend_data *)connssl->backend;
2456
2457 (void)data;
2458 DEBUGASSERT(backend);
2459
2460 if(backend->ctxt) /* SSL/TLS is in use */
2461 return (backend->decdata_offset > 0 ||
2462 (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
2463 backend->recv_connection_closed ||
2464 backend->recv_sspi_close_notify ||
2465 backend->recv_unrecoverable_err);
2466 else
2467 return FALSE;
2468 }
2469
2470 /* shut down the SSL connection and clean up related memory.
2471 this function can be called multiple times on the same connection including
2472 if the SSL connection failed (eg connection made but failed handshake). */
schannel_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool send_shutdown,bool * done)2473 static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
2474 struct Curl_easy *data,
2475 bool send_shutdown, bool *done)
2476 {
2477 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2478 * Shutting Down an Schannel Connection
2479 */
2480 struct ssl_connect_data *connssl = cf->ctx;
2481 struct schannel_ssl_backend_data *backend =
2482 (struct schannel_ssl_backend_data *)connssl->backend;
2483 CURLcode result = CURLE_OK;
2484
2485 if(connssl->shutdown) {
2486 *done = TRUE;
2487 return CURLE_OK;
2488 }
2489
2490 DEBUGASSERT(data);
2491 DEBUGASSERT(backend);
2492
2493 /* Not supported in schannel */
2494 (void)send_shutdown;
2495
2496 *done = FALSE;
2497 if(backend->ctxt) {
2498 infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
2499 connssl->peer.hostname, connssl->peer.port);
2500 }
2501
2502 if(!backend->ctxt || connssl->shutdown) {
2503 *done = TRUE;
2504 goto out;
2505 }
2506
2507 if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
2508 SecBufferDesc BuffDesc;
2509 SecBuffer Buffer;
2510 SECURITY_STATUS sspi_status;
2511 SecBuffer outbuf;
2512 SecBufferDesc outbuf_desc;
2513 DWORD dwshut = SCHANNEL_SHUTDOWN;
2514
2515 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2516 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2517
2518 sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2519 &BuffDesc);
2520
2521 if(sspi_status != SEC_E_OK) {
2522 char buffer[STRERROR_LEN];
2523 failf(data, "schannel: ApplyControlToken failure: %s",
2524 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2525 result = CURLE_SEND_ERROR;
2526 goto out;
2527 }
2528
2529 /* setup output buffer */
2530 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2531 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2532
2533 sspi_status = s_pSecFn->InitializeSecurityContext(
2534 &backend->cred->cred_handle,
2535 &backend->ctxt->ctxt_handle,
2536 backend->cred->sni_hostname,
2537 backend->req_flags,
2538 0,
2539 0,
2540 NULL,
2541 0,
2542 &backend->ctxt->ctxt_handle,
2543 &outbuf_desc,
2544 &backend->ret_flags,
2545 &backend->ctxt->time_stamp);
2546
2547 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2548 /* send close message which is in output buffer */
2549 ssize_t written = Curl_conn_cf_send(cf->next, data,
2550 outbuf.pvBuffer, outbuf.cbBuffer,
2551 &result);
2552 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2553 if(!result) {
2554 if(written < (ssize_t)outbuf.cbBuffer) {
2555 /* TODO: handle partial sends */
2556 infof(data, "schannel: failed to send close msg: %s"
2557 " (bytes written: %zd)", curl_easy_strerror(result), written);
2558 result = CURLE_SEND_ERROR;
2559 goto out;
2560 }
2561 backend->sent_shutdown = TRUE;
2562 *done = TRUE;
2563 }
2564 else if(result == CURLE_AGAIN) {
2565 connssl->io_need = CURL_SSL_IO_NEED_SEND;
2566 result = CURLE_OK;
2567 goto out;
2568 }
2569 else {
2570 if(!backend->recv_connection_closed) {
2571 infof(data, "schannel: error sending close msg: %d", result);
2572 result = CURLE_SEND_ERROR;
2573 goto out;
2574 }
2575 /* Looks like server already closed the connection.
2576 * An error to send our close notify is not a failure. */
2577 *done = TRUE;
2578 result = CURLE_OK;
2579 }
2580 }
2581 }
2582
2583 /* If the connection seems open and we have not seen the close notify
2584 * from the server yet, try to receive it. */
2585 if(backend->cred && backend->ctxt &&
2586 !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
2587 char buffer[1024];
2588 ssize_t nread;
2589
2590 nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
2591 if(nread > 0) {
2592 /* still data coming in? */
2593 }
2594 else if(nread == 0) {
2595 /* We got the close notify alert and are done. */
2596 backend->recv_connection_closed = TRUE;
2597 *done = TRUE;
2598 }
2599 else if(nread < 0 && result == CURLE_AGAIN) {
2600 connssl->io_need = CURL_SSL_IO_NEED_RECV;
2601 }
2602 else {
2603 CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
2604 result = CURLE_RECV_ERROR;
2605 }
2606 }
2607
2608 out:
2609 connssl->shutdown = (result || *done);
2610 return result;
2611 }
2612
schannel_close(struct Curl_cfilter * cf,struct Curl_easy * data)2613 static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2614 {
2615 struct ssl_connect_data *connssl = cf->ctx;
2616 struct schannel_ssl_backend_data *backend =
2617 (struct schannel_ssl_backend_data *)connssl->backend;
2618
2619 DEBUGASSERT(data);
2620 DEBUGASSERT(backend);
2621
2622 if(backend->cred && backend->ctxt &&
2623 cf->connected && !connssl->shutdown &&
2624 cf->next && cf->next->connected && !connssl->peer_closed) {
2625 bool done;
2626 (void)schannel_shutdown(cf, data, TRUE, &done);
2627 }
2628
2629 /* free SSPI Schannel API security context handle */
2630 if(backend->ctxt) {
2631 DEBUGF(infof(data, "schannel: clear security context handle"));
2632 s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2633 Curl_safefree(backend->ctxt);
2634 }
2635
2636 /* free SSPI Schannel API credential handle */
2637 if(backend->cred) {
2638 Curl_ssl_sessionid_lock(data);
2639 schannel_session_free(backend->cred, 0);
2640 Curl_ssl_sessionid_unlock(data);
2641 backend->cred = NULL;
2642 }
2643
2644 /* free internal buffer for received encrypted data */
2645 if(backend->encdata_buffer) {
2646 Curl_safefree(backend->encdata_buffer);
2647 backend->encdata_length = 0;
2648 backend->encdata_offset = 0;
2649 backend->encdata_is_incomplete = false;
2650 }
2651
2652 /* free internal buffer for received decrypted data */
2653 if(backend->decdata_buffer) {
2654 Curl_safefree(backend->decdata_buffer);
2655 backend->decdata_length = 0;
2656 backend->decdata_offset = 0;
2657 }
2658 }
2659
schannel_init(void)2660 static int schannel_init(void)
2661 {
2662 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2663 }
2664
schannel_cleanup(void)2665 static void schannel_cleanup(void)
2666 {
2667 Curl_sspi_global_cleanup();
2668 }
2669
schannel_version(char * buffer,size_t size)2670 static size_t schannel_version(char *buffer, size_t size)
2671 {
2672 return msnprintf(buffer, size, "Schannel");
2673 }
2674
schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2675 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2676 unsigned char *entropy, size_t length)
2677 {
2678 (void)data;
2679
2680 return Curl_win32_random(entropy, length);
2681 }
2682
schannel_pkp_pin_peer_pubkey(struct Curl_cfilter * cf,struct Curl_easy * data,const char * pinnedpubkey)2683 static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
2684 struct Curl_easy *data,
2685 const char *pinnedpubkey)
2686 {
2687 struct ssl_connect_data *connssl = cf->ctx;
2688 struct schannel_ssl_backend_data *backend =
2689 (struct schannel_ssl_backend_data *)connssl->backend;
2690 CERT_CONTEXT *pCertContextServer = NULL;
2691
2692 /* Result is returned to caller */
2693 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2694
2695 DEBUGASSERT(backend);
2696
2697 /* if a path wasn't specified, don't pin */
2698 if(!pinnedpubkey)
2699 return CURLE_OK;
2700
2701 do {
2702 SECURITY_STATUS sspi_status;
2703 const char *x509_der;
2704 DWORD x509_der_len;
2705 struct Curl_X509certificate x509_parsed;
2706 struct Curl_asn1Element *pubkey;
2707
2708 sspi_status =
2709 s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2710 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2711 &pCertContextServer);
2712
2713 if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2714 char buffer[STRERROR_LEN];
2715 failf(data, "schannel: Failed to read remote certificate context: %s",
2716 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2717 break; /* failed */
2718 }
2719
2720
2721 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2722 (pCertContextServer->cbCertEncoded > 0)))
2723 break;
2724
2725 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2726 x509_der_len = pCertContextServer->cbCertEncoded;
2727 memset(&x509_parsed, 0, sizeof(x509_parsed));
2728 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2729 break;
2730
2731 pubkey = &x509_parsed.subjectPublicKeyInfo;
2732 if(!pubkey->header || pubkey->end <= pubkey->header) {
2733 failf(data, "SSL: failed retrieving public key from server certificate");
2734 break;
2735 }
2736
2737 result = Curl_pin_peer_pubkey(data,
2738 pinnedpubkey,
2739 (const unsigned char *)pubkey->header,
2740 (size_t)(pubkey->end - pubkey->header));
2741 if(result) {
2742 failf(data, "SSL: public key does not match pinned public key");
2743 }
2744 } while(0);
2745
2746 if(pCertContextServer)
2747 CertFreeCertificateContext(pCertContextServer);
2748
2749 return result;
2750 }
2751
schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2752 static void schannel_checksum(const unsigned char *input,
2753 size_t inputlen,
2754 unsigned char *checksum,
2755 size_t checksumlen,
2756 DWORD provType,
2757 const unsigned int algId)
2758 {
2759 #ifdef CURL_WINDOWS_APP
2760 (void)input;
2761 (void)inputlen;
2762 (void)provType;
2763 (void)algId;
2764 memset(checksum, 0, checksumlen);
2765 #else
2766 HCRYPTPROV hProv = 0;
2767 HCRYPTHASH hHash = 0;
2768 DWORD cbHashSize = 0;
2769 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2770 DWORD dwChecksumLen = (DWORD)checksumlen;
2771
2772 /* since this can fail in multiple ways, zero memory first so we never
2773 * return old data
2774 */
2775 memset(checksum, 0, checksumlen);
2776
2777 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2778 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2779 return; /* failed */
2780
2781 do {
2782 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2783 break; /* failed */
2784
2785 if(!CryptHashData(hHash, input, (DWORD)inputlen, 0))
2786 break; /* failed */
2787
2788 /* get hash size */
2789 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2790 &dwHashSizeLen, 0))
2791 break; /* failed */
2792
2793 /* check hash size */
2794 if(checksumlen < cbHashSize)
2795 break; /* failed */
2796
2797 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2798 break; /* failed */
2799 } while(0);
2800
2801 if(hHash)
2802 CryptDestroyHash(hHash);
2803
2804 if(hProv)
2805 CryptReleaseContext(hProv, 0);
2806 #endif
2807 }
2808
schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2809 static CURLcode schannel_sha256sum(const unsigned char *input,
2810 size_t inputlen,
2811 unsigned char *sha256sum,
2812 size_t sha256len)
2813 {
2814 schannel_checksum(input, inputlen, sha256sum, sha256len,
2815 PROV_RSA_AES, CALG_SHA_256);
2816 return CURLE_OK;
2817 }
2818
schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2819 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2820 CURLINFO info UNUSED_PARAM)
2821 {
2822 struct schannel_ssl_backend_data *backend =
2823 (struct schannel_ssl_backend_data *)connssl->backend;
2824 (void)info;
2825 DEBUGASSERT(backend);
2826 return &backend->ctxt->ctxt_handle;
2827 }
2828
Curl_schannel_get_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data)2829 HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
2830 const struct Curl_easy *data)
2831 {
2832 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2833 struct Curl_multi *multi = data->multi;
2834 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2835 struct schannel_cert_share *share;
2836 const struct ssl_general_config *cfg = &data->set.general_ssl;
2837 timediff_t timeout_ms;
2838 timediff_t elapsed_ms;
2839 struct curltime now;
2840 unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];
2841
2842 DEBUGASSERT(multi);
2843
2844 if(!multi) {
2845 return NULL;
2846 }
2847
2848 share = Curl_hash_pick(&multi->proto_hash,
2849 (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2850 sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
2851 if(!share || !share->cert_store) {
2852 return NULL;
2853 }
2854
2855 /* zero ca_cache_timeout completely disables caching */
2856 if(!cfg->ca_cache_timeout) {
2857 return NULL;
2858 }
2859
2860 /* check for cache timeout by using the cached_x509_store_expired timediff
2861 calculation pattern from openssl.c.
2862 negative timeout means retain forever. */
2863 timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
2864 if(timeout_ms >= 0) {
2865 now = Curl_now();
2866 elapsed_ms = Curl_timediff(now, share->time);
2867 if(elapsed_ms >= timeout_ms) {
2868 return NULL;
2869 }
2870 }
2871
2872 if(ca_info_blob) {
2873 if(!share->CAinfo_blob_digest) {
2874 return NULL;
2875 }
2876 if(share->CAinfo_blob_size != ca_info_blob->len) {
2877 return NULL;
2878 }
2879 schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2880 ca_info_blob->len,
2881 info_blob_digest,
2882 CURL_SHA256_DIGEST_LENGTH);
2883 if(memcmp(share->CAinfo_blob_digest,
2884 info_blob_digest,
2885 CURL_SHA256_DIGEST_LENGTH)) {
2886 return NULL;
2887 }
2888 }
2889 else {
2890 if(!conn_config->CAfile || !share->CAfile ||
2891 strcmp(share->CAfile, conn_config->CAfile)) {
2892 return NULL;
2893 }
2894 }
2895
2896 return share->cert_store;
2897 }
2898
schannel_cert_share_free(void * key,size_t key_len,void * p)2899 static void schannel_cert_share_free(void *key, size_t key_len, void *p)
2900 {
2901 struct schannel_cert_share *share = p;
2902 DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
2903 DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
2904 (void)key;
2905 (void)key_len;
2906 if(share->cert_store) {
2907 CertCloseStore(share->cert_store, 0);
2908 }
2909 free(share->CAinfo_blob_digest);
2910 free(share->CAfile);
2911 free(share);
2912 }
2913
Curl_schannel_set_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data,HCERTSTORE cert_store)2914 bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
2915 const struct Curl_easy *data,
2916 HCERTSTORE cert_store)
2917 {
2918 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2919 struct Curl_multi *multi = data->multi;
2920 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2921 struct schannel_cert_share *share;
2922 unsigned char *CAinfo_blob_digest = NULL;
2923 size_t CAinfo_blob_size = 0;
2924 char *CAfile = NULL;
2925
2926 DEBUGASSERT(multi);
2927
2928 if(!multi) {
2929 return false;
2930 }
2931
2932 share = Curl_hash_pick(&multi->proto_hash,
2933 (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2934 sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
2935 if(!share) {
2936 share = calloc(1, sizeof(*share));
2937 if(!share) {
2938 return false;
2939 }
2940 if(!Curl_hash_add2(&multi->proto_hash,
2941 (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2942 sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
2943 share, schannel_cert_share_free)) {
2944 free(share);
2945 return false;
2946 }
2947 }
2948
2949 if(ca_info_blob) {
2950 CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
2951 if(!CAinfo_blob_digest) {
2952 return false;
2953 }
2954 schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2955 ca_info_blob->len,
2956 CAinfo_blob_digest,
2957 CURL_SHA256_DIGEST_LENGTH);
2958 CAinfo_blob_size = ca_info_blob->len;
2959 }
2960 else {
2961 if(conn_config->CAfile) {
2962 CAfile = strdup(conn_config->CAfile);
2963 if(!CAfile) {
2964 return false;
2965 }
2966 }
2967 }
2968
2969 /* free old cache data */
2970 if(share->cert_store) {
2971 CertCloseStore(share->cert_store, 0);
2972 }
2973 free(share->CAinfo_blob_digest);
2974 free(share->CAfile);
2975
2976 share->time = Curl_now();
2977 share->cert_store = cert_store;
2978 share->CAinfo_blob_digest = CAinfo_blob_digest;
2979 share->CAinfo_blob_size = CAinfo_blob_size;
2980 share->CAfile = CAfile;
2981 return true;
2982 }
2983
2984 const struct Curl_ssl Curl_ssl_schannel = {
2985 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2986
2987 SSLSUPP_CERTINFO |
2988 #ifdef HAS_MANUAL_VERIFY_API
2989 SSLSUPP_CAINFO_BLOB |
2990 #endif
2991 #ifndef CURL_WINDOWS_APP
2992 SSLSUPP_PINNEDPUBKEY |
2993 #endif
2994 SSLSUPP_TLS13_CIPHERSUITES |
2995 SSLSUPP_CA_CACHE |
2996 SSLSUPP_HTTPS_PROXY,
2997
2998 sizeof(struct schannel_ssl_backend_data),
2999
3000 schannel_init, /* init */
3001 schannel_cleanup, /* cleanup */
3002 schannel_version, /* version */
3003 Curl_none_check_cxn, /* check_cxn */
3004 schannel_shutdown, /* shutdown */
3005 schannel_data_pending, /* data_pending */
3006 schannel_random, /* random */
3007 Curl_none_cert_status_request, /* cert_status_request */
3008 schannel_connect, /* connect */
3009 schannel_connect_nonblocking, /* connect_nonblocking */
3010 Curl_ssl_adjust_pollset, /* adjust_pollset */
3011 schannel_get_internals, /* get_internals */
3012 schannel_close, /* close_one */
3013 Curl_none_close_all, /* close_all */
3014 Curl_none_set_engine, /* set_engine */
3015 Curl_none_set_engine_default, /* set_engine_default */
3016 Curl_none_engines_list, /* engines_list */
3017 Curl_none_false_start, /* false_start */
3018 schannel_sha256sum, /* sha256sum */
3019 NULL, /* associate_connection */
3020 NULL, /* disassociate_connection */
3021 schannel_recv, /* recv decrypted data */
3022 schannel_send, /* send data to encrypt */
3023 };
3024
3025 #endif /* USE_SCHANNEL */
3026