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