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