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