VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/vtls/schannel.c@ 88444

Last change on this file since 88444 was 85671, checked in by vboxsync, 5 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

  • Property svn:eol-style set to native
File size: 74.7 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2012 - 2016, Marc Hoersken, <[email protected]>
9 * Copyright (C) 2012, Mark Salisbury, <[email protected]>
10 * Copyright (C) 2012 - 2019, Daniel Stenberg, <[email protected]>, et al.
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.haxx.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 ***************************************************************************/
24
25/*
26 * Source file for all Schannel-specific code for the TLS/SSL layer. No code
27 * but vtls.c should ever call or use these functions.
28 */
29
30/*
31 * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
32 * Copyright (C) 2010, 2011, Hoi-Ho Chan, <[email protected]>
33 *
34 * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
35 * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
36 *
37 * Thanks for code and inspiration!
38 */
39
40#include "curl_setup.h"
41
42#ifdef USE_SCHANNEL
43
44#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
45
46#ifndef USE_WINDOWS_SSPI
47# error "Can't compile SCHANNEL support without SSPI."
48#endif
49
50#include "schannel.h"
51#include "vtls.h"
52#include "sendf.h"
53#include "connect.h" /* for the connect timeout */
54#include "strerror.h"
55#include "select.h" /* for the socket readyness */
56#include "inet_pton.h" /* for IP addr SNI check */
57#include "curl_multibyte.h"
58#include "warnless.h"
59#include "x509asn1.h"
60#include "curl_printf.h"
61#include "system_win32.h"
62
63 /* The last #include file should be: */
64#include "curl_memory.h"
65#include "memdebug.h"
66
67/* ALPN requires version 8.1 of the Windows SDK, which was
68 shipped with Visual Studio 2013, aka _MSC_VER 1800:
69
70 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
71*/
72#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
73# define HAS_ALPN 1
74#endif
75
76#ifndef UNISP_NAME_A
77#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
78#endif
79
80#ifndef UNISP_NAME_W
81#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
82#endif
83
84#ifndef UNISP_NAME
85#ifdef UNICODE
86#define UNISP_NAME UNISP_NAME_W
87#else
88#define UNISP_NAME UNISP_NAME_A
89#endif
90#endif
91
92#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
93#define HAS_CLIENT_CERT_PATH
94#endif
95
96#ifdef HAS_CLIENT_CERT_PATH
97#ifdef UNICODE
98#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
99#else
100#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
101#endif
102#endif
103
104#ifndef SP_PROT_SSL2_CLIENT
105#define SP_PROT_SSL2_CLIENT 0x00000008
106#endif
107
108#ifndef SP_PROT_SSL3_CLIENT
109#define SP_PROT_SSL3_CLIENT 0x00000008
110#endif
111
112#ifndef SP_PROT_TLS1_CLIENT
113#define SP_PROT_TLS1_CLIENT 0x00000080
114#endif
115
116#ifndef SP_PROT_TLS1_0_CLIENT
117#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
118#endif
119
120#ifndef SP_PROT_TLS1_1_CLIENT
121#define SP_PROT_TLS1_1_CLIENT 0x00000200
122#endif
123
124#ifndef SP_PROT_TLS1_2_CLIENT
125#define SP_PROT_TLS1_2_CLIENT 0x00000800
126#endif
127
128#ifndef SECBUFFER_ALERT
129#define SECBUFFER_ALERT 17
130#endif
131
132/* Both schannel buffer sizes must be > 0 */
133#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
134#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
135
136#define CERT_THUMBPRINT_STR_LEN 40
137#define CERT_THUMBPRINT_DATA_LEN 20
138
139/* Uncomment to force verbose output
140 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
141 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
142 */
143
144#ifndef CALG_SHA_256
145# define CALG_SHA_256 0x0000800c
146#endif
147
148#define BACKEND connssl->backend
149
150static Curl_recv schannel_recv;
151static Curl_send schannel_send;
152
153static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
154 const char *pinnedpubkey);
155
156static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
157 void *BufDataPtr, unsigned long BufByteSize)
158{
159 buffer->cbBuffer = BufByteSize;
160 buffer->BufferType = BufType;
161 buffer->pvBuffer = BufDataPtr;
162}
163
164static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
165 unsigned long NumArrElem)
166{
167 desc->ulVersion = SECBUFFER_VERSION;
168 desc->pBuffers = BufArr;
169 desc->cBuffers = NumArrElem;
170}
171
172static CURLcode
173set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
174{
175 struct Curl_easy *data = conn->data;
176 long ssl_version = SSL_CONN_CONFIG(version);
177 long ssl_version_max = SSL_CONN_CONFIG(version_max);
178 long i = ssl_version;
179
180 switch(ssl_version_max) {
181 case CURL_SSLVERSION_MAX_NONE:
182 case CURL_SSLVERSION_MAX_DEFAULT:
183 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
184 break;
185 }
186 for(; i <= (ssl_version_max >> 16); ++i) {
187 switch(i) {
188 case CURL_SSLVERSION_TLSv1_0:
189 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
190 break;
191 case CURL_SSLVERSION_TLSv1_1:
192 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
193 break;
194 case CURL_SSLVERSION_TLSv1_2:
195 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
196 break;
197 case CURL_SSLVERSION_TLSv1_3:
198 failf(data, "schannel: TLS 1.3 is not yet supported");
199 return CURLE_SSL_CONNECT_ERROR;
200 }
201 }
202 return CURLE_OK;
203}
204
205/*longest is 26, buffer is slightly bigger*/
206#define LONGEST_ALG_ID 32
207#define CIPHEROPTION(X) \
208if(strcmp(#X, tmp) == 0) \
209 return X
210
211static int
212get_alg_id_by_name(char *name)
213{
214 char tmp[LONGEST_ALG_ID] = { 0 };
215 char *nameEnd = strchr(name, ':');
216 size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
217 min(strlen(name), LONGEST_ALG_ID - 1);
218 strncpy(tmp, name, n);
219 tmp[n] = 0;
220 CIPHEROPTION(CALG_MD2);
221 CIPHEROPTION(CALG_MD4);
222 CIPHEROPTION(CALG_MD5);
223 CIPHEROPTION(CALG_SHA);
224 CIPHEROPTION(CALG_SHA1);
225 CIPHEROPTION(CALG_MAC);
226 CIPHEROPTION(CALG_RSA_SIGN);
227 CIPHEROPTION(CALG_DSS_SIGN);
228/*ifdefs for the options that are defined conditionally in wincrypt.h*/
229#ifdef CALG_NO_SIGN
230 CIPHEROPTION(CALG_NO_SIGN);
231#endif
232 CIPHEROPTION(CALG_RSA_KEYX);
233 CIPHEROPTION(CALG_DES);
234#ifdef CALG_3DES_112
235 CIPHEROPTION(CALG_3DES_112);
236#endif
237 CIPHEROPTION(CALG_3DES);
238 CIPHEROPTION(CALG_DESX);
239 CIPHEROPTION(CALG_RC2);
240 CIPHEROPTION(CALG_RC4);
241 CIPHEROPTION(CALG_SEAL);
242#ifdef CALG_DH_SF
243 CIPHEROPTION(CALG_DH_SF);
244#endif
245 CIPHEROPTION(CALG_DH_EPHEM);
246#ifdef CALG_AGREEDKEY_ANY
247 CIPHEROPTION(CALG_AGREEDKEY_ANY);
248#endif
249#ifdef CALG_HUGHES_MD5
250 CIPHEROPTION(CALG_HUGHES_MD5);
251#endif
252 CIPHEROPTION(CALG_SKIPJACK);
253#ifdef CALG_TEK
254 CIPHEROPTION(CALG_TEK);
255#endif
256 CIPHEROPTION(CALG_CYLINK_MEK);
257 CIPHEROPTION(CALG_SSL3_SHAMD5);
258#ifdef CALG_SSL3_MASTER
259 CIPHEROPTION(CALG_SSL3_MASTER);
260#endif
261#ifdef CALG_SCHANNEL_MASTER_HASH
262 CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
263#endif
264#ifdef CALG_SCHANNEL_MAC_KEY
265 CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
266#endif
267#ifdef CALG_SCHANNEL_ENC_KEY
268 CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
269#endif
270#ifdef CALG_PCT1_MASTER
271 CIPHEROPTION(CALG_PCT1_MASTER);
272#endif
273#ifdef CALG_SSL2_MASTER
274 CIPHEROPTION(CALG_SSL2_MASTER);
275#endif
276#ifdef CALG_TLS1_MASTER
277 CIPHEROPTION(CALG_TLS1_MASTER);
278#endif
279#ifdef CALG_RC5
280 CIPHEROPTION(CALG_RC5);
281#endif
282#ifdef CALG_HMAC
283 CIPHEROPTION(CALG_HMAC);
284#endif
285#if !defined(__W32API_MAJOR_VERSION) || \
286 !defined(__W32API_MINOR_VERSION) || \
287 defined(__MINGW64_VERSION_MAJOR) || \
288 (__W32API_MAJOR_VERSION > 5) || \
289 ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
290 /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
291 see https://osdn.net/projects/mingw/ticket/38391 */
292 CIPHEROPTION(CALG_TLS1PRF);
293#endif
294#ifdef CALG_HASH_REPLACE_OWF
295 CIPHEROPTION(CALG_HASH_REPLACE_OWF);
296#endif
297#ifdef CALG_AES_128
298 CIPHEROPTION(CALG_AES_128);
299#endif
300#ifdef CALG_AES_192
301 CIPHEROPTION(CALG_AES_192);
302#endif
303#ifdef CALG_AES_256
304 CIPHEROPTION(CALG_AES_256);
305#endif
306#ifdef CALG_AES
307 CIPHEROPTION(CALG_AES);
308#endif
309#ifdef CALG_SHA_256
310 CIPHEROPTION(CALG_SHA_256);
311#endif
312#ifdef CALG_SHA_384
313 CIPHEROPTION(CALG_SHA_384);
314#endif
315#ifdef CALG_SHA_512
316 CIPHEROPTION(CALG_SHA_512);
317#endif
318#ifdef CALG_ECDH
319 CIPHEROPTION(CALG_ECDH);
320#endif
321#ifdef CALG_ECMQV
322 CIPHEROPTION(CALG_ECMQV);
323#endif
324#ifdef CALG_ECDSA
325 CIPHEROPTION(CALG_ECDSA);
326#endif
327 return 0;
328}
329
330static CURLcode
331set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
332{
333 char *startCur = ciphers;
334 int algCount = 0;
335 static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
336 while(startCur && (0 != *startCur) && (algCount < 45)) {
337 long alg = strtol(startCur, 0, 0);
338 if(!alg)
339 alg = get_alg_id_by_name(startCur);
340 if(alg)
341 algIds[algCount++] = alg;
342 else
343 return CURLE_SSL_CIPHER;
344 startCur = strchr(startCur, ':');
345 if(startCur)
346 startCur++;
347 }
348 schannel_cred->palgSupportedAlgs = algIds;
349 schannel_cred->cSupportedAlgs = algCount;
350 return CURLE_OK;
351}
352
353#ifdef HAS_CLIENT_CERT_PATH
354static CURLcode
355get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
356 TCHAR **thumbprint)
357{
358 TCHAR *sep;
359 TCHAR *store_path_start;
360 size_t store_name_len;
361
362 sep = _tcschr(path, TEXT('\\'));
363 if(sep == NULL)
364 return CURLE_SSL_CERTPROBLEM;
365
366 store_name_len = sep - path;
367
368 if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
369 *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
370 else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
371 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
372 else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
373 *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
374 else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
375 *store_name = CERT_SYSTEM_STORE_SERVICES;
376 else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
377 *store_name = CERT_SYSTEM_STORE_USERS;
378 else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
379 store_name_len) == 0)
380 *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
381 else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
382 store_name_len) == 0)
383 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
384 else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
385 store_name_len) == 0)
386 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
387 else
388 return CURLE_SSL_CERTPROBLEM;
389
390 store_path_start = sep + 1;
391
392 sep = _tcschr(store_path_start, TEXT('\\'));
393 if(sep == NULL)
394 return CURLE_SSL_CERTPROBLEM;
395
396 *sep = TEXT('\0');
397 *store_path = _tcsdup(store_path_start);
398 *sep = TEXT('\\');
399 if(*store_path == NULL)
400 return CURLE_OUT_OF_MEMORY;
401
402 *thumbprint = sep + 1;
403 if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
404 return CURLE_SSL_CERTPROBLEM;
405
406 return CURLE_OK;
407}
408#endif
409
410static CURLcode
411schannel_connect_step1(struct connectdata *conn, int sockindex)
412{
413 ssize_t written = -1;
414 struct Curl_easy *data = conn->data;
415 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
416 SecBuffer outbuf;
417 SecBufferDesc outbuf_desc;
418 SecBuffer inbuf;
419 SecBufferDesc inbuf_desc;
420#ifdef HAS_ALPN
421 unsigned char alpn_buffer[128];
422#endif
423 SCHANNEL_CRED schannel_cred;
424 PCCERT_CONTEXT client_certs[1] = { NULL };
425 SECURITY_STATUS sspi_status = SEC_E_OK;
426 struct curl_schannel_cred *old_cred = NULL;
427 struct in_addr addr;
428#ifdef ENABLE_IPV6
429 struct in6_addr addr6;
430#endif
431 TCHAR *host_name;
432 CURLcode result;
433 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
434 conn->host.name;
435
436 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
437 hostname, conn->remote_port);
438
439 if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
440 VERSION_LESS_THAN_EQUAL)) {
441 /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
442 algorithms that may not be supported by all servers. */
443 infof(data, "schannel: Windows version is old and may not be able to "
444 "connect to some servers due to lack of SNI, algorithms, etc.\n");
445 }
446
447#ifdef HAS_ALPN
448 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
449 Also it doesn't seem to be supported for Wine, see curl bug #983. */
450 BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
451 !GetProcAddress(GetModuleHandleA("ntdll"),
452 "wine_get_version") &&
453 Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
454 VERSION_GREATER_THAN_EQUAL);
455#else
456 BACKEND->use_alpn = false;
457#endif
458
459#ifdef _WIN32_WCE
460#ifdef HAS_MANUAL_VERIFY_API
461 /* certificate validation on CE doesn't seem to work right; we'll
462 * do it following a more manual process. */
463 BACKEND->use_manual_cred_validation = true;
464#else
465#error "compiler too old to support requisite manual cert verify for Win CE"
466#endif
467#else
468#ifdef HAS_MANUAL_VERIFY_API
469 if(SSL_CONN_CONFIG(CAfile)) {
470 if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
471 VERSION_GREATER_THAN_EQUAL)) {
472 BACKEND->use_manual_cred_validation = true;
473 }
474 else {
475 failf(data, "schannel: this version of Windows is too old to support "
476 "certificate verification via CA bundle file.");
477 return CURLE_SSL_CACERT_BADFILE;
478 }
479 }
480 else
481 BACKEND->use_manual_cred_validation = false;
482#else
483 if(SSL_CONN_CONFIG(CAfile)) {
484 failf(data, "schannel: CA cert support not built in");
485 return CURLE_NOT_BUILT_IN;
486 }
487#endif
488#endif
489
490 BACKEND->cred = NULL;
491
492 /* check for an existing re-usable credential handle */
493 if(SSL_SET_OPTION(primary.sessionid)) {
494 Curl_ssl_sessionid_lock(conn);
495 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
496 BACKEND->cred = old_cred;
497 infof(data, "schannel: re-using existing credential handle\n");
498
499 /* increment the reference counter of the credential/session handle */
500 BACKEND->cred->refcount++;
501 infof(data, "schannel: incremented credential handle refcount = %d\n",
502 BACKEND->cred->refcount);
503 }
504 Curl_ssl_sessionid_unlock(conn);
505 }
506
507 if(!BACKEND->cred) {
508 /* setup Schannel API options */
509 memset(&schannel_cred, 0, sizeof(schannel_cred));
510 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
511
512 if(conn->ssl_config.verifypeer) {
513#ifdef HAS_MANUAL_VERIFY_API
514 if(BACKEND->use_manual_cred_validation)
515 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
516 else
517#endif
518 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
519
520 /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
521 if(data->set.ssl.no_revoke) {
522 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
523 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
524
525 infof(data, "schannel: disabled server certificate revocation "
526 "checks\n");
527 }
528 else {
529 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
530 infof(data, "schannel: checking server certificate revocation\n");
531 }
532 }
533 else {
534 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
535 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
536 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
537 infof(data, "schannel: disabled server certificate revocation checks\n");
538 }
539
540 if(!conn->ssl_config.verifyhost) {
541 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
542 infof(data, "schannel: verifyhost setting prevents Schannel from "
543 "comparing the supplied target name with the subject "
544 "names in server certificates.\n");
545 }
546
547 switch(conn->ssl_config.version) {
548 case CURL_SSLVERSION_DEFAULT:
549 case CURL_SSLVERSION_TLSv1:
550 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
551 SP_PROT_TLS1_1_CLIENT |
552 SP_PROT_TLS1_2_CLIENT;
553 break;
554 case CURL_SSLVERSION_TLSv1_0:
555 case CURL_SSLVERSION_TLSv1_1:
556 case CURL_SSLVERSION_TLSv1_2:
557 case CURL_SSLVERSION_TLSv1_3:
558 {
559 result = set_ssl_version_min_max(&schannel_cred, conn);
560 if(result != CURLE_OK)
561 return result;
562 break;
563 }
564 case CURL_SSLVERSION_SSLv3:
565 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
566 break;
567 case CURL_SSLVERSION_SSLv2:
568 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
569 break;
570 default:
571 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
572 return CURLE_SSL_CONNECT_ERROR;
573 }
574
575 if(SSL_CONN_CONFIG(cipher_list)) {
576 result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
577 if(CURLE_OK != result) {
578 failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
579 return result;
580 }
581 }
582
583
584#ifdef HAS_CLIENT_CERT_PATH
585 /* client certificate */
586 if(data->set.ssl.cert) {
587 DWORD cert_store_name;
588 TCHAR *cert_store_path;
589 TCHAR *cert_thumbprint_str;
590 CRYPT_HASH_BLOB cert_thumbprint;
591 BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
592 HCERTSTORE cert_store;
593
594 TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
595 if(!cert_path)
596 return CURLE_OUT_OF_MEMORY;
597
598 result = get_cert_location(cert_path, &cert_store_name,
599 &cert_store_path, &cert_thumbprint_str);
600 if(result != CURLE_OK) {
601 failf(data, "schannel: Failed to get certificate location for %s",
602 cert_path);
603 Curl_unicodefree(cert_path);
604 return result;
605 }
606
607 cert_store =
608 CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
609 (HCRYPTPROV)NULL,
610 CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
611 cert_store_path);
612 if(!cert_store) {
613 failf(data, "schannel: Failed to open cert store %x %s, "
614 "last error is %x",
615 cert_store_name, cert_store_path, GetLastError());
616 free(cert_store_path);
617 Curl_unicodefree(cert_path);
618 return CURLE_SSL_CERTPROBLEM;
619 }
620 free(cert_store_path);
621
622 cert_thumbprint.pbData = cert_thumbprint_data;
623 cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
624
625 if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
626 CRYPT_STRING_HEX,
627 cert_thumbprint_data, &cert_thumbprint.cbData,
628 NULL, NULL)) {
629 Curl_unicodefree(cert_path);
630 return CURLE_SSL_CERTPROBLEM;
631 }
632
633 client_certs[0] = CertFindCertificateInStore(
634 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
635 CERT_FIND_HASH, &cert_thumbprint, NULL);
636
637 Curl_unicodefree(cert_path);
638
639 if(client_certs[0]) {
640 schannel_cred.cCreds = 1;
641 schannel_cred.paCred = client_certs;
642 }
643 else {
644 /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
645 return CURLE_SSL_CERTPROBLEM;
646 }
647
648 CertCloseStore(cert_store, 0);
649 }
650#else
651 if(data->set.ssl.cert) {
652 failf(data, "schannel: client cert support not built in");
653 return CURLE_NOT_BUILT_IN;
654 }
655#endif
656
657 /* allocate memory for the re-usable credential handle */
658 BACKEND->cred = (struct curl_schannel_cred *)
659 calloc(1, sizeof(struct curl_schannel_cred));
660 if(!BACKEND->cred) {
661 failf(data, "schannel: unable to allocate memory");
662
663 if(client_certs[0])
664 CertFreeCertificateContext(client_certs[0]);
665
666 return CURLE_OUT_OF_MEMORY;
667 }
668 BACKEND->cred->refcount = 1;
669
670 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
671 */
672 sspi_status =
673 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
674 SECPKG_CRED_OUTBOUND, NULL,
675 &schannel_cred, NULL, NULL,
676 &BACKEND->cred->cred_handle,
677 &BACKEND->cred->time_stamp);
678
679 if(client_certs[0])
680 CertFreeCertificateContext(client_certs[0]);
681
682 if(sspi_status != SEC_E_OK) {
683 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
684 Curl_sspi_strerror(conn, sspi_status));
685 Curl_safefree(BACKEND->cred);
686 switch(sspi_status) {
687 case SEC_E_INSUFFICIENT_MEMORY:
688 return CURLE_OUT_OF_MEMORY;
689 case SEC_E_NO_CREDENTIALS:
690 case SEC_E_SECPKG_NOT_FOUND:
691 case SEC_E_NOT_OWNER:
692 case SEC_E_UNKNOWN_CREDENTIALS:
693 case SEC_E_INTERNAL_ERROR:
694 default:
695 return CURLE_SSL_CONNECT_ERROR;
696 }
697 }
698 }
699
700 /* Warn if SNI is disabled due to use of an IP address */
701 if(Curl_inet_pton(AF_INET, hostname, &addr)
702#ifdef ENABLE_IPV6
703 || Curl_inet_pton(AF_INET6, hostname, &addr6)
704#endif
705 ) {
706 infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
707 }
708
709#ifdef HAS_ALPN
710 if(BACKEND->use_alpn) {
711 int cur = 0;
712 int list_start_index = 0;
713 unsigned int *extension_len = NULL;
714 unsigned short* list_len = NULL;
715
716 /* The first four bytes will be an unsigned int indicating number
717 of bytes of data in the rest of the the buffer. */
718 extension_len = (unsigned int *)(&alpn_buffer[cur]);
719 cur += sizeof(unsigned int);
720
721 /* The next four bytes are an indicator that this buffer will contain
722 ALPN data, as opposed to NPN, for example. */
723 *(unsigned int *)&alpn_buffer[cur] =
724 SecApplicationProtocolNegotiationExt_ALPN;
725 cur += sizeof(unsigned int);
726
727 /* The next two bytes will be an unsigned short indicating the number
728 of bytes used to list the preferred protocols. */
729 list_len = (unsigned short*)(&alpn_buffer[cur]);
730 cur += sizeof(unsigned short);
731
732 list_start_index = cur;
733
734#ifdef USE_NGHTTP2
735 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
736 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
737 cur += NGHTTP2_PROTO_ALPN_LEN;
738 infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
739 }
740#endif
741
742 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
743 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
744 cur += ALPN_HTTP_1_1_LENGTH;
745 infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
746
747 *list_len = curlx_uitous(cur - list_start_index);
748 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
749
750 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
751 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
752 }
753 else {
754 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
755 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
756 }
757#else /* HAS_ALPN */
758 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
759 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
760#endif
761
762 /* setup output buffer */
763 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
764 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
765
766 /* setup request flags */
767 BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
768 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
769 ISC_REQ_STREAM;
770
771 /* allocate memory for the security context handle */
772 BACKEND->ctxt = (struct curl_schannel_ctxt *)
773 calloc(1, sizeof(struct curl_schannel_ctxt));
774 if(!BACKEND->ctxt) {
775 failf(data, "schannel: unable to allocate memory");
776 return CURLE_OUT_OF_MEMORY;
777 }
778
779 host_name = Curl_convert_UTF8_to_tchar(hostname);
780 if(!host_name)
781 return CURLE_OUT_OF_MEMORY;
782
783 /* Schannel InitializeSecurityContext:
784 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
785
786 At the moment we don't pass inbuf unless we're using ALPN since we only
787 use it for that, and Wine (for which we currently disable ALPN) is giving
788 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
789 */
790 sspi_status = s_pSecFn->InitializeSecurityContext(
791 &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
792 (BACKEND->use_alpn ? &inbuf_desc : NULL),
793 0, &BACKEND->ctxt->ctxt_handle,
794 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
795
796 Curl_unicodefree(host_name);
797
798 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
799 Curl_safefree(BACKEND->ctxt);
800 switch(sspi_status) {
801 case SEC_E_INSUFFICIENT_MEMORY:
802 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
803 Curl_sspi_strerror(conn, sspi_status));
804 return CURLE_OUT_OF_MEMORY;
805 case SEC_E_WRONG_PRINCIPAL:
806 failf(data, "schannel: SNI or certificate check failed: %s",
807 Curl_sspi_strerror(conn, sspi_status));
808 return CURLE_PEER_FAILED_VERIFICATION;
809 /*
810 case SEC_E_INVALID_HANDLE:
811 case SEC_E_INVALID_TOKEN:
812 case SEC_E_LOGON_DENIED:
813 case SEC_E_TARGET_UNKNOWN:
814 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
815 case SEC_E_INTERNAL_ERROR:
816 case SEC_E_NO_CREDENTIALS:
817 case SEC_E_UNSUPPORTED_FUNCTION:
818 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
819 */
820 default:
821 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
822 Curl_sspi_strerror(conn, sspi_status));
823 return CURLE_SSL_CONNECT_ERROR;
824 }
825 }
826
827 infof(data, "schannel: sending initial handshake data: "
828 "sending %lu bytes...\n", outbuf.cbBuffer);
829
830 /* send initial handshake data which is now stored in output buffer */
831 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
832 outbuf.cbBuffer, &written);
833 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
834 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
835 failf(data, "schannel: failed to send initial handshake data: "
836 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
837 return CURLE_SSL_CONNECT_ERROR;
838 }
839
840 infof(data, "schannel: sent initial handshake data: "
841 "sent %zd bytes\n", written);
842
843 BACKEND->recv_unrecoverable_err = CURLE_OK;
844 BACKEND->recv_sspi_close_notify = false;
845 BACKEND->recv_connection_closed = false;
846 BACKEND->encdata_is_incomplete = false;
847
848 /* continue to second handshake step */
849 connssl->connecting_state = ssl_connect_2;
850
851 return CURLE_OK;
852}
853
854static CURLcode
855schannel_connect_step2(struct connectdata *conn, int sockindex)
856{
857 int i;
858 ssize_t nread = -1, written = -1;
859 struct Curl_easy *data = conn->data;
860 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
861 unsigned char *reallocated_buffer;
862 size_t reallocated_length;
863 SecBuffer outbuf[3];
864 SecBufferDesc outbuf_desc;
865 SecBuffer inbuf[2];
866 SecBufferDesc inbuf_desc;
867 SECURITY_STATUS sspi_status = SEC_E_OK;
868 TCHAR *host_name;
869 CURLcode result;
870 bool doread;
871 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
872 conn->host.name;
873 const char *pubkey_ptr;
874
875 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
876
877 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
878 hostname, conn->remote_port);
879
880 if(!BACKEND->cred || !BACKEND->ctxt)
881 return CURLE_SSL_CONNECT_ERROR;
882
883 /* buffer to store previously received and decrypted data */
884 if(BACKEND->decdata_buffer == NULL) {
885 BACKEND->decdata_offset = 0;
886 BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
887 BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
888 if(BACKEND->decdata_buffer == NULL) {
889 failf(data, "schannel: unable to allocate memory");
890 return CURLE_OUT_OF_MEMORY;
891 }
892 }
893
894 /* buffer to store previously received and encrypted data */
895 if(BACKEND->encdata_buffer == NULL) {
896 BACKEND->encdata_is_incomplete = false;
897 BACKEND->encdata_offset = 0;
898 BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
899 BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
900 if(BACKEND->encdata_buffer == NULL) {
901 failf(data, "schannel: unable to allocate memory");
902 return CURLE_OUT_OF_MEMORY;
903 }
904 }
905
906 /* if we need a bigger buffer to read a full message, increase buffer now */
907 if(BACKEND->encdata_length - BACKEND->encdata_offset <
908 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
909 /* increase internal encrypted data buffer */
910 reallocated_length = BACKEND->encdata_offset +
911 CURL_SCHANNEL_BUFFER_FREE_SIZE;
912 reallocated_buffer = realloc(BACKEND->encdata_buffer,
913 reallocated_length);
914
915 if(reallocated_buffer == NULL) {
916 failf(data, "schannel: unable to re-allocate memory");
917 return CURLE_OUT_OF_MEMORY;
918 }
919 else {
920 BACKEND->encdata_buffer = reallocated_buffer;
921 BACKEND->encdata_length = reallocated_length;
922 }
923 }
924
925 for(;;) {
926 if(doread) {
927 /* read encrypted handshake data from socket */
928 result = Curl_read_plain(conn->sock[sockindex],
929 (char *) (BACKEND->encdata_buffer +
930 BACKEND->encdata_offset),
931 BACKEND->encdata_length -
932 BACKEND->encdata_offset,
933 &nread);
934 if(result == CURLE_AGAIN) {
935 if(connssl->connecting_state != ssl_connect_2_writing)
936 connssl->connecting_state = ssl_connect_2_reading;
937 infof(data, "schannel: failed to receive handshake, "
938 "need more data\n");
939 return CURLE_OK;
940 }
941 else if((result != CURLE_OK) || (nread == 0)) {
942 failf(data, "schannel: failed to receive handshake, "
943 "SSL/TLS connection failed");
944 return CURLE_SSL_CONNECT_ERROR;
945 }
946
947 /* increase encrypted data buffer offset */
948 BACKEND->encdata_offset += nread;
949 BACKEND->encdata_is_incomplete = false;
950 infof(data, "schannel: encrypted data got %zd\n", nread);
951 }
952
953 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
954 BACKEND->encdata_offset, BACKEND->encdata_length);
955
956 /* setup input buffers */
957 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
958 curlx_uztoul(BACKEND->encdata_offset));
959 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
960 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
961
962 /* setup output buffers */
963 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
964 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
965 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
966 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
967
968 if(inbuf[0].pvBuffer == NULL) {
969 failf(data, "schannel: unable to allocate memory");
970 return CURLE_OUT_OF_MEMORY;
971 }
972
973 /* copy received handshake data into input buffer */
974 memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
975 BACKEND->encdata_offset);
976
977 host_name = Curl_convert_UTF8_to_tchar(hostname);
978 if(!host_name)
979 return CURLE_OUT_OF_MEMORY;
980
981 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
982 */
983 sspi_status = s_pSecFn->InitializeSecurityContext(
984 &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
985 host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
986 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
987
988 Curl_unicodefree(host_name);
989
990 /* free buffer for received handshake data */
991 Curl_safefree(inbuf[0].pvBuffer);
992
993 /* check if the handshake was incomplete */
994 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
995 BACKEND->encdata_is_incomplete = true;
996 connssl->connecting_state = ssl_connect_2_reading;
997 infof(data, "schannel: received incomplete message, need more data\n");
998 return CURLE_OK;
999 }
1000
1001 /* If the server has requested a client certificate, attempt to continue
1002 the handshake without one. This will allow connections to servers which
1003 request a client certificate but do not require it. */
1004 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1005 !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1006 BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1007 connssl->connecting_state = ssl_connect_2_writing;
1008 infof(data, "schannel: a client certificate has been requested\n");
1009 return CURLE_OK;
1010 }
1011
1012 /* check if the handshake needs to be continued */
1013 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1014 for(i = 0; i < 3; i++) {
1015 /* search for handshake tokens that need to be send */
1016 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1017 infof(data, "schannel: sending next handshake data: "
1018 "sending %lu bytes...\n", outbuf[i].cbBuffer);
1019
1020 /* send handshake token to server */
1021 result = Curl_write_plain(conn, conn->sock[sockindex],
1022 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1023 &written);
1024 if((result != CURLE_OK) ||
1025 (outbuf[i].cbBuffer != (size_t) written)) {
1026 failf(data, "schannel: failed to send next handshake data: "
1027 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1028 return CURLE_SSL_CONNECT_ERROR;
1029 }
1030 }
1031
1032 /* free obsolete buffer */
1033 if(outbuf[i].pvBuffer != NULL) {
1034 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1035 }
1036 }
1037 }
1038 else {
1039 switch(sspi_status) {
1040 case SEC_E_INSUFFICIENT_MEMORY:
1041 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1042 Curl_sspi_strerror(conn, sspi_status));
1043 return CURLE_OUT_OF_MEMORY;
1044 case SEC_E_WRONG_PRINCIPAL:
1045 failf(data, "schannel: SNI or certificate check failed: %s",
1046 Curl_sspi_strerror(conn, sspi_status));
1047 return CURLE_PEER_FAILED_VERIFICATION;
1048 /*
1049 case SEC_E_INVALID_HANDLE:
1050 case SEC_E_INVALID_TOKEN:
1051 case SEC_E_LOGON_DENIED:
1052 case SEC_E_TARGET_UNKNOWN:
1053 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1054 case SEC_E_INTERNAL_ERROR:
1055 case SEC_E_NO_CREDENTIALS:
1056 case SEC_E_UNSUPPORTED_FUNCTION:
1057 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1058 */
1059 default:
1060 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1061 Curl_sspi_strerror(conn, sspi_status));
1062 return CURLE_SSL_CONNECT_ERROR;
1063 }
1064 }
1065
1066 /* check if there was additional remaining encrypted data */
1067 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1068 infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
1069 /*
1070 There are two cases where we could be getting extra data here:
1071 1) If we're renegotiating a connection and the handshake is already
1072 complete (from the server perspective), it can encrypted app data
1073 (not handshake data) in an extra buffer at this point.
1074 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1075 connection and this extra data is part of the handshake.
1076 We should process the data immediately; waiting for the socket to
1077 be ready may fail since the server is done sending handshake data.
1078 */
1079 /* check if the remaining data is less than the total amount
1080 and therefore begins after the already processed data */
1081 if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
1082 memmove(BACKEND->encdata_buffer,
1083 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1084 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1085 BACKEND->encdata_offset = inbuf[1].cbBuffer;
1086 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1087 doread = FALSE;
1088 continue;
1089 }
1090 }
1091 }
1092 else {
1093 BACKEND->encdata_offset = 0;
1094 }
1095 break;
1096 }
1097
1098 /* check if the handshake needs to be continued */
1099 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1100 connssl->connecting_state = ssl_connect_2_reading;
1101 return CURLE_OK;
1102 }
1103
1104 /* check if the handshake is complete */
1105 if(sspi_status == SEC_E_OK) {
1106 connssl->connecting_state = ssl_connect_3;
1107 infof(data, "schannel: SSL/TLS handshake complete\n");
1108 }
1109
1110 pubkey_ptr = SSL_IS_PROXY() ?
1111 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1112 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1113 if(pubkey_ptr) {
1114 result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
1115 if(result) {
1116 failf(data, "SSL: public key does not match pinned public key!");
1117 return result;
1118 }
1119 }
1120
1121#ifdef HAS_MANUAL_VERIFY_API
1122 if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
1123 return Curl_verify_certificate(conn, sockindex);
1124 }
1125#endif
1126
1127 return CURLE_OK;
1128}
1129
1130static bool
1131valid_cert_encoding(const CERT_CONTEXT *cert_context)
1132{
1133 return (cert_context != NULL) &&
1134 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1135 (cert_context->pbCertEncoded != NULL) &&
1136 (cert_context->cbCertEncoded > 0);
1137}
1138
1139typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1140
1141static void
1142traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1143 void *arg)
1144{
1145 const CERT_CONTEXT *current_context = NULL;
1146 bool should_continue = true;
1147 while(should_continue &&
1148 (current_context = CertEnumCertificatesInStore(
1149 context->hCertStore,
1150 current_context)) != NULL)
1151 should_continue = func(current_context, arg);
1152
1153 if(current_context)
1154 CertFreeCertificateContext(current_context);
1155}
1156
1157static bool
1158cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1159{
1160 if(valid_cert_encoding(ccert_context))
1161 (*(int *)certs_count)++;
1162 return true;
1163}
1164
1165struct Adder_args
1166{
1167 struct connectdata *conn;
1168 CURLcode result;
1169 int idx;
1170};
1171
1172static bool
1173add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1174{
1175 struct Adder_args *args = (struct Adder_args*)raw_arg;
1176 args->result = CURLE_OK;
1177 if(valid_cert_encoding(ccert_context)) {
1178 const char *beg = (const char *) ccert_context->pbCertEncoded;
1179 const char *end = beg + ccert_context->cbCertEncoded;
1180 args->result = Curl_extract_certinfo(args->conn, (args->idx)++, beg, end);
1181 }
1182 return args->result == CURLE_OK;
1183}
1184
1185static CURLcode
1186schannel_connect_step3(struct connectdata *conn, int sockindex)
1187{
1188 CURLcode result = CURLE_OK;
1189 struct Curl_easy *data = conn->data;
1190 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1191 SECURITY_STATUS sspi_status = SEC_E_OK;
1192 CERT_CONTEXT *ccert_context = NULL;
1193#ifndef CURL_DISABLE_VERBOSE_STRINGS
1194 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1195 conn->host.name;
1196#endif
1197#ifdef HAS_ALPN
1198 SecPkgContext_ApplicationProtocol alpn_result;
1199#endif
1200
1201 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1202
1203 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
1204 hostname, conn->remote_port);
1205
1206 if(!BACKEND->cred)
1207 return CURLE_SSL_CONNECT_ERROR;
1208
1209 /* check if the required context attributes are met */
1210 if(BACKEND->ret_flags != BACKEND->req_flags) {
1211 if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
1212 failf(data, "schannel: failed to setup sequence detection");
1213 if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
1214 failf(data, "schannel: failed to setup replay detection");
1215 if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
1216 failf(data, "schannel: failed to setup confidentiality");
1217 if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1218 failf(data, "schannel: failed to setup memory allocation");
1219 if(!(BACKEND->ret_flags & ISC_RET_STREAM))
1220 failf(data, "schannel: failed to setup stream orientation");
1221 return CURLE_SSL_CONNECT_ERROR;
1222 }
1223
1224#ifdef HAS_ALPN
1225 if(BACKEND->use_alpn) {
1226 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1227 SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
1228
1229 if(sspi_status != SEC_E_OK) {
1230 failf(data, "schannel: failed to retrieve ALPN result");
1231 return CURLE_SSL_CONNECT_ERROR;
1232 }
1233
1234 if(alpn_result.ProtoNegoStatus ==
1235 SecApplicationProtocolNegotiationStatus_Success) {
1236
1237 infof(data, "schannel: ALPN, server accepted to use %.*s\n",
1238 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1239
1240#ifdef USE_NGHTTP2
1241 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
1242 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
1243 NGHTTP2_PROTO_VERSION_ID_LEN)) {
1244 conn->negnpn = CURL_HTTP_VERSION_2;
1245 }
1246 else
1247#endif
1248 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1249 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1250 ALPN_HTTP_1_1_LENGTH)) {
1251 conn->negnpn = CURL_HTTP_VERSION_1_1;
1252 }
1253 }
1254 else
1255 infof(data, "ALPN, server did not agree to a protocol\n");
1256 }
1257#endif
1258
1259 /* save the current session data for possible re-use */
1260 if(SSL_SET_OPTION(primary.sessionid)) {
1261 bool incache;
1262 struct curl_schannel_cred *old_cred = NULL;
1263
1264 Curl_ssl_sessionid_lock(conn);
1265 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
1266 sockindex));
1267 if(incache) {
1268 if(old_cred != BACKEND->cred) {
1269 infof(data, "schannel: old credential handle is stale, removing\n");
1270 /* we're not taking old_cred ownership here, no refcount++ is needed */
1271 Curl_ssl_delsessionid(conn, (void *)old_cred);
1272 incache = FALSE;
1273 }
1274 }
1275 if(!incache) {
1276 result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
1277 sizeof(struct curl_schannel_cred),
1278 sockindex);
1279 if(result) {
1280 Curl_ssl_sessionid_unlock(conn);
1281 failf(data, "schannel: failed to store credential handle");
1282 return result;
1283 }
1284 else {
1285 /* this cred session is now also referenced by sessionid cache */
1286 BACKEND->cred->refcount++;
1287 infof(data, "schannel: stored credential handle in session cache\n");
1288 }
1289 }
1290 Curl_ssl_sessionid_unlock(conn);
1291 }
1292
1293 if(data->set.ssl.certinfo) {
1294 int certs_count = 0;
1295 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1296 SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
1297
1298 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
1299 failf(data, "schannel: failed to retrieve remote cert context");
1300 return CURLE_PEER_FAILED_VERIFICATION;
1301 }
1302
1303 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1304
1305 result = Curl_ssl_init_certinfo(data, certs_count);
1306 if(!result) {
1307 struct Adder_args args;
1308 args.conn = conn;
1309 args.idx = 0;
1310 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1311 result = args.result;
1312 }
1313 CertFreeCertificateContext(ccert_context);
1314 if(result)
1315 return result;
1316 }
1317
1318 connssl->connecting_state = ssl_connect_done;
1319
1320 return CURLE_OK;
1321}
1322
1323static CURLcode
1324schannel_connect_common(struct connectdata *conn, int sockindex,
1325 bool nonblocking, bool *done)
1326{
1327 CURLcode result;
1328 struct Curl_easy *data = conn->data;
1329 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1330 curl_socket_t sockfd = conn->sock[sockindex];
1331 time_t timeout_ms;
1332 int what;
1333
1334 /* check if the connection has already been established */
1335 if(ssl_connection_complete == connssl->state) {
1336 *done = TRUE;
1337 return CURLE_OK;
1338 }
1339
1340 if(ssl_connect_1 == connssl->connecting_state) {
1341 /* check out how much more time we're allowed */
1342 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1343
1344 if(timeout_ms < 0) {
1345 /* no need to continue if time already is up */
1346 failf(data, "SSL/TLS connection timeout");
1347 return CURLE_OPERATION_TIMEDOUT;
1348 }
1349
1350 result = schannel_connect_step1(conn, sockindex);
1351 if(result)
1352 return result;
1353 }
1354
1355 while(ssl_connect_2 == connssl->connecting_state ||
1356 ssl_connect_2_reading == connssl->connecting_state ||
1357 ssl_connect_2_writing == connssl->connecting_state) {
1358
1359 /* check out how much more time we're allowed */
1360 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1361
1362 if(timeout_ms < 0) {
1363 /* no need to continue if time already is up */
1364 failf(data, "SSL/TLS connection timeout");
1365 return CURLE_OPERATION_TIMEDOUT;
1366 }
1367
1368 /* if ssl is expecting something, check if it's available. */
1369 if(connssl->connecting_state == ssl_connect_2_reading
1370 || connssl->connecting_state == ssl_connect_2_writing) {
1371
1372 curl_socket_t writefd = ssl_connect_2_writing ==
1373 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1374 curl_socket_t readfd = ssl_connect_2_reading ==
1375 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1376
1377 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1378 nonblocking ? 0 : timeout_ms);
1379 if(what < 0) {
1380 /* fatal error */
1381 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1382 return CURLE_SSL_CONNECT_ERROR;
1383 }
1384 else if(0 == what) {
1385 if(nonblocking) {
1386 *done = FALSE;
1387 return CURLE_OK;
1388 }
1389 else {
1390 /* timeout */
1391 failf(data, "SSL/TLS connection timeout");
1392 return CURLE_OPERATION_TIMEDOUT;
1393 }
1394 }
1395 /* socket is readable or writable */
1396 }
1397
1398 /* Run transaction, and return to the caller if it failed or if
1399 * this connection is part of a multi handle and this loop would
1400 * execute again. This permits the owner of a multi handle to
1401 * abort a connection attempt before step2 has completed while
1402 * ensuring that a client using select() or epoll() will always
1403 * have a valid fdset to wait on.
1404 */
1405 result = schannel_connect_step2(conn, sockindex);
1406 if(result || (nonblocking &&
1407 (ssl_connect_2 == connssl->connecting_state ||
1408 ssl_connect_2_reading == connssl->connecting_state ||
1409 ssl_connect_2_writing == connssl->connecting_state)))
1410 return result;
1411
1412 } /* repeat step2 until all transactions are done. */
1413
1414 if(ssl_connect_3 == connssl->connecting_state) {
1415 result = schannel_connect_step3(conn, sockindex);
1416 if(result)
1417 return result;
1418 }
1419
1420 if(ssl_connect_done == connssl->connecting_state) {
1421 connssl->state = ssl_connection_complete;
1422 conn->recv[sockindex] = schannel_recv;
1423 conn->send[sockindex] = schannel_send;
1424
1425#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1426 /* When SSPI is used in combination with Schannel
1427 * we need the Schannel context to create the Schannel
1428 * binding to pass the IIS extended protection checks.
1429 * Available on Windows 7 or later.
1430 */
1431 conn->sslContext = &BACKEND->ctxt->ctxt_handle;
1432#endif
1433
1434 *done = TRUE;
1435 }
1436 else
1437 *done = FALSE;
1438
1439 /* reset our connection state machine */
1440 connssl->connecting_state = ssl_connect_1;
1441
1442 return CURLE_OK;
1443}
1444
1445static ssize_t
1446schannel_send(struct connectdata *conn, int sockindex,
1447 const void *buf, size_t len, CURLcode *err)
1448{
1449 ssize_t written = -1;
1450 size_t data_len = 0;
1451 unsigned char *data = NULL;
1452 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1453 SecBuffer outbuf[4];
1454 SecBufferDesc outbuf_desc;
1455 SECURITY_STATUS sspi_status = SEC_E_OK;
1456 CURLcode result;
1457
1458 /* check if the maximum stream sizes were queried */
1459 if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1460 sspi_status = s_pSecFn->QueryContextAttributes(
1461 &BACKEND->ctxt->ctxt_handle,
1462 SECPKG_ATTR_STREAM_SIZES,
1463 &BACKEND->stream_sizes);
1464 if(sspi_status != SEC_E_OK) {
1465 *err = CURLE_SEND_ERROR;
1466 return -1;
1467 }
1468 }
1469
1470 /* check if the buffer is longer than the maximum message length */
1471 if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1472 len = BACKEND->stream_sizes.cbMaximumMessage;
1473 }
1474
1475 /* calculate the complete message length and allocate a buffer for it */
1476 data_len = BACKEND->stream_sizes.cbHeader + len +
1477 BACKEND->stream_sizes.cbTrailer;
1478 data = (unsigned char *) malloc(data_len);
1479 if(data == NULL) {
1480 *err = CURLE_OUT_OF_MEMORY;
1481 return -1;
1482 }
1483
1484 /* setup output buffers (header, data, trailer, empty) */
1485 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1486 data, BACKEND->stream_sizes.cbHeader);
1487 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1488 data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1489 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1490 data + BACKEND->stream_sizes.cbHeader + len,
1491 BACKEND->stream_sizes.cbTrailer);
1492 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1493 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1494
1495 /* copy data into output buffer */
1496 memcpy(outbuf[1].pvBuffer, buf, len);
1497
1498 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1499 sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1500 &outbuf_desc, 0);
1501
1502 /* check if the message was encrypted */
1503 if(sspi_status == SEC_E_OK) {
1504 written = 0;
1505
1506 /* send the encrypted message including header, data and trailer */
1507 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1508
1509 /*
1510 It's important to send the full message which includes the header,
1511 encrypted payload, and trailer. Until the client receives all the
1512 data a coherent message has not been delivered and the client
1513 can't read any of it.
1514
1515 If we wanted to buffer the unwritten encrypted bytes, we would
1516 tell the client that all data it has requested to be sent has been
1517 sent. The unwritten encrypted bytes would be the first bytes to
1518 send on the next invocation.
1519 Here's the catch with this - if we tell the client that all the
1520 bytes have been sent, will the client call this method again to
1521 send the buffered data? Looking at who calls this function, it
1522 seems the answer is NO.
1523 */
1524
1525 /* send entire message or fail */
1526 while(len > (size_t)written) {
1527 ssize_t this_write;
1528 time_t timeleft;
1529 int what;
1530
1531 this_write = 0;
1532
1533 timeleft = Curl_timeleft(conn->data, NULL, FALSE);
1534 if(timeleft < 0) {
1535 /* we already got the timeout */
1536 failf(conn->data, "schannel: timed out sending data "
1537 "(bytes sent: %zd)", written);
1538 *err = CURLE_OPERATION_TIMEDOUT;
1539 written = -1;
1540 break;
1541 }
1542
1543 what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
1544 if(what < 0) {
1545 /* fatal error */
1546 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1547 *err = CURLE_SEND_ERROR;
1548 written = -1;
1549 break;
1550 }
1551 else if(0 == what) {
1552 failf(conn->data, "schannel: timed out sending data "
1553 "(bytes sent: %zd)", written);
1554 *err = CURLE_OPERATION_TIMEDOUT;
1555 written = -1;
1556 break;
1557 }
1558 /* socket is writable */
1559
1560 result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1561 len - written, &this_write);
1562 if(result == CURLE_AGAIN)
1563 continue;
1564 else if(result != CURLE_OK) {
1565 *err = result;
1566 written = -1;
1567 break;
1568 }
1569
1570 written += this_write;
1571 }
1572 }
1573 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1574 *err = CURLE_OUT_OF_MEMORY;
1575 }
1576 else{
1577 *err = CURLE_SEND_ERROR;
1578 }
1579
1580 Curl_safefree(data);
1581
1582 if(len == (size_t)written)
1583 /* Encrypted message including header, data and trailer entirely sent.
1584 The return value is the number of unencrypted bytes that were sent. */
1585 written = outbuf[1].cbBuffer;
1586
1587 return written;
1588}
1589
1590static ssize_t
1591schannel_recv(struct connectdata *conn, int sockindex,
1592 char *buf, size_t len, CURLcode *err)
1593{
1594 size_t size = 0;
1595 ssize_t nread = -1;
1596 struct Curl_easy *data = conn->data;
1597 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1598 unsigned char *reallocated_buffer;
1599 size_t reallocated_length;
1600 bool done = FALSE;
1601 SecBuffer inbuf[4];
1602 SecBufferDesc inbuf_desc;
1603 SECURITY_STATUS sspi_status = SEC_E_OK;
1604 /* we want the length of the encrypted buffer to be at least large enough
1605 that it can hold all the bytes requested and some TLS record overhead. */
1606 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1607
1608 /****************************************************************************
1609 * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1610 * The pattern for return error is set *err, optional infof, goto cleanup.
1611 *
1612 * Our priority is to always return as much decrypted data to the caller as
1613 * possible, even if an error occurs. The state of the decrypted buffer must
1614 * always be valid. Transfer of decrypted data to the caller's buffer is
1615 * handled in the cleanup.
1616 */
1617
1618 infof(data, "schannel: client wants to read %zu bytes\n", len);
1619 *err = CURLE_OK;
1620
1621 if(len && len <= BACKEND->decdata_offset) {
1622 infof(data, "schannel: enough decrypted data is already available\n");
1623 goto cleanup;
1624 }
1625 else if(BACKEND->recv_unrecoverable_err) {
1626 *err = BACKEND->recv_unrecoverable_err;
1627 infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1628 goto cleanup;
1629 }
1630 else if(BACKEND->recv_sspi_close_notify) {
1631 /* once a server has indicated shutdown there is no more encrypted data */
1632 infof(data, "schannel: server indicated shutdown in a prior call\n");
1633 goto cleanup;
1634 }
1635 else if(!len) {
1636 /* It's debatable what to return when !len. Regardless we can't return
1637 immediately because there may be data to decrypt (in the case we want to
1638 decrypt all encrypted cached data) so handle !len later in cleanup.
1639 */
1640 ; /* do nothing */
1641 }
1642 else if(!BACKEND->recv_connection_closed) {
1643 /* increase enc buffer in order to fit the requested amount of data */
1644 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1645 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1646 BACKEND->encdata_length < min_encdata_length) {
1647 reallocated_length = BACKEND->encdata_offset +
1648 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1649 if(reallocated_length < min_encdata_length) {
1650 reallocated_length = min_encdata_length;
1651 }
1652 reallocated_buffer = realloc(BACKEND->encdata_buffer,
1653 reallocated_length);
1654 if(reallocated_buffer == NULL) {
1655 *err = CURLE_OUT_OF_MEMORY;
1656 failf(data, "schannel: unable to re-allocate memory");
1657 goto cleanup;
1658 }
1659
1660 BACKEND->encdata_buffer = reallocated_buffer;
1661 BACKEND->encdata_length = reallocated_length;
1662 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1663 infof(data, "schannel: encdata_buffer resized %zu\n",
1664 BACKEND->encdata_length);
1665 }
1666
1667 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1668 BACKEND->encdata_offset, BACKEND->encdata_length);
1669
1670 /* read encrypted data from socket */
1671 *err = Curl_read_plain(conn->sock[sockindex],
1672 (char *)(BACKEND->encdata_buffer +
1673 BACKEND->encdata_offset),
1674 size, &nread);
1675 if(*err) {
1676 nread = -1;
1677 if(*err == CURLE_AGAIN)
1678 infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
1679 else if(*err == CURLE_RECV_ERROR)
1680 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1681 else
1682 infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1683 }
1684 else if(nread == 0) {
1685 BACKEND->recv_connection_closed = true;
1686 infof(data, "schannel: server closed the connection\n");
1687 }
1688 else if(nread > 0) {
1689 BACKEND->encdata_offset += (size_t)nread;
1690 BACKEND->encdata_is_incomplete = false;
1691 infof(data, "schannel: encrypted data got %zd\n", nread);
1692 }
1693 }
1694
1695 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1696 BACKEND->encdata_offset, BACKEND->encdata_length);
1697
1698 /* decrypt loop */
1699 while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1700 (!len || BACKEND->decdata_offset < len ||
1701 BACKEND->recv_connection_closed)) {
1702 /* prepare data buffer for DecryptMessage call */
1703 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1704 curlx_uztoul(BACKEND->encdata_offset));
1705
1706 /* we need 3 more empty input buffers for possible output */
1707 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1708 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1709 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1710 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1711
1712 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1713 */
1714 sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1715 &inbuf_desc, 0, NULL);
1716
1717 /* check if everything went fine (server may want to renegotiate
1718 or shutdown the connection context) */
1719 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1720 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1721 /* check for successfully decrypted data, even before actual
1722 renegotiation or shutdown of the connection context */
1723 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1724 infof(data, "schannel: decrypted data length: %lu\n",
1725 inbuf[1].cbBuffer);
1726
1727 /* increase buffer in order to fit the received amount of data */
1728 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1729 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1730 if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1731 BACKEND->decdata_length < len) {
1732 /* increase internal decrypted data buffer */
1733 reallocated_length = BACKEND->decdata_offset + size;
1734 /* make sure that the requested amount of data fits */
1735 if(reallocated_length < len) {
1736 reallocated_length = len;
1737 }
1738 reallocated_buffer = realloc(BACKEND->decdata_buffer,
1739 reallocated_length);
1740 if(reallocated_buffer == NULL) {
1741 *err = CURLE_OUT_OF_MEMORY;
1742 failf(data, "schannel: unable to re-allocate memory");
1743 goto cleanup;
1744 }
1745 BACKEND->decdata_buffer = reallocated_buffer;
1746 BACKEND->decdata_length = reallocated_length;
1747 }
1748
1749 /* copy decrypted data to internal buffer */
1750 size = inbuf[1].cbBuffer;
1751 if(size) {
1752 memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1753 inbuf[1].pvBuffer, size);
1754 BACKEND->decdata_offset += size;
1755 }
1756
1757 infof(data, "schannel: decrypted data added: %zu\n", size);
1758 infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
1759 BACKEND->decdata_offset, BACKEND->decdata_length);
1760 }
1761
1762 /* check for remaining encrypted data */
1763 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1764 infof(data, "schannel: encrypted data length: %lu\n",
1765 inbuf[3].cbBuffer);
1766
1767 /* check if the remaining data is less than the total amount
1768 * and therefore begins after the already processed data
1769 */
1770 if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1771 /* move remaining encrypted data forward to the beginning of
1772 buffer */
1773 memmove(BACKEND->encdata_buffer,
1774 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1775 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1776 BACKEND->encdata_offset = inbuf[3].cbBuffer;
1777 }
1778
1779 infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
1780 BACKEND->encdata_offset, BACKEND->encdata_length);
1781 }
1782 else {
1783 /* reset encrypted buffer offset, because there is no data remaining */
1784 BACKEND->encdata_offset = 0;
1785 }
1786
1787 /* check if server wants to renegotiate the connection context */
1788 if(sspi_status == SEC_I_RENEGOTIATE) {
1789 infof(data, "schannel: remote party requests renegotiation\n");
1790 if(*err && *err != CURLE_AGAIN) {
1791 infof(data, "schannel: can't renogotiate, an error is pending\n");
1792 goto cleanup;
1793 }
1794 if(BACKEND->encdata_offset) {
1795 *err = CURLE_RECV_ERROR;
1796 infof(data, "schannel: can't renogotiate, "
1797 "encrypted data available\n");
1798 goto cleanup;
1799 }
1800 /* begin renegotiation */
1801 infof(data, "schannel: renegotiating SSL/TLS connection\n");
1802 connssl->state = ssl_connection_negotiating;
1803 connssl->connecting_state = ssl_connect_2_writing;
1804 *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1805 if(*err) {
1806 infof(data, "schannel: renegotiation failed\n");
1807 goto cleanup;
1808 }
1809 /* now retry receiving data */
1810 sspi_status = SEC_E_OK;
1811 infof(data, "schannel: SSL/TLS connection renegotiated\n");
1812 continue;
1813 }
1814 /* check if the server closed the connection */
1815 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1816 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1817 returned so we have to work around that in cleanup. */
1818 BACKEND->recv_sspi_close_notify = true;
1819 if(!BACKEND->recv_connection_closed) {
1820 BACKEND->recv_connection_closed = true;
1821 infof(data, "schannel: server closed the connection\n");
1822 }
1823 goto cleanup;
1824 }
1825 }
1826 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1827 BACKEND->encdata_is_incomplete = true;
1828 if(!*err)
1829 *err = CURLE_AGAIN;
1830 infof(data, "schannel: failed to decrypt data, need more data\n");
1831 goto cleanup;
1832 }
1833 else {
1834 *err = CURLE_RECV_ERROR;
1835 infof(data, "schannel: failed to read data from server: %s\n",
1836 Curl_sspi_strerror(conn, sspi_status));
1837 goto cleanup;
1838 }
1839 }
1840
1841 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1842 BACKEND->encdata_offset, BACKEND->encdata_length);
1843
1844 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1845 BACKEND->decdata_offset, BACKEND->decdata_length);
1846
1847cleanup:
1848 /* Warning- there is no guarantee the encdata state is valid at this point */
1849 infof(data, "schannel: schannel_recv cleanup\n");
1850
1851 /* Error if the connection has closed without a close_notify.
1852 Behavior here is a matter of debate. We don't want to be vulnerable to a
1853 truncation attack however there's some browser precedent for ignoring the
1854 close_notify for compatibility reasons.
1855 Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1856 return close_notify. In that case if the connection was closed we assume it
1857 was graceful (close_notify) since there doesn't seem to be a way to tell.
1858 */
1859 if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1860 !BACKEND->recv_sspi_close_notify) {
1861 bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1862 VERSION_EQUAL);
1863
1864 if(isWin2k && sspi_status == SEC_E_OK)
1865 BACKEND->recv_sspi_close_notify = true;
1866 else {
1867 *err = CURLE_RECV_ERROR;
1868 infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1869 }
1870 }
1871
1872 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1873 if(*err && *err != CURLE_AGAIN)
1874 BACKEND->recv_unrecoverable_err = *err;
1875
1876 size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1877 if(size) {
1878 memcpy(buf, BACKEND->decdata_buffer, size);
1879 memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1880 BACKEND->decdata_offset - size);
1881 BACKEND->decdata_offset -= size;
1882
1883 infof(data, "schannel: decrypted data returned %zu\n", size);
1884 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1885 BACKEND->decdata_offset, BACKEND->decdata_length);
1886 *err = CURLE_OK;
1887 return (ssize_t)size;
1888 }
1889
1890 if(!*err && !BACKEND->recv_connection_closed)
1891 *err = CURLE_AGAIN;
1892
1893 /* It's debatable what to return when !len. We could return whatever error we
1894 got from decryption but instead we override here so the return is consistent.
1895 */
1896 if(!len)
1897 *err = CURLE_OK;
1898
1899 return *err ? -1 : 0;
1900}
1901
1902static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
1903 int sockindex, bool *done)
1904{
1905 return schannel_connect_common(conn, sockindex, TRUE, done);
1906}
1907
1908static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
1909{
1910 CURLcode result;
1911 bool done = FALSE;
1912
1913 result = schannel_connect_common(conn, sockindex, FALSE, &done);
1914 if(result)
1915 return result;
1916
1917 DEBUGASSERT(done);
1918
1919 return CURLE_OK;
1920}
1921
1922static bool Curl_schannel_data_pending(const struct connectdata *conn,
1923 int sockindex)
1924{
1925 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1926
1927 if(connssl->use) /* SSL/TLS is in use */
1928 return (BACKEND->decdata_offset > 0 ||
1929 (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1930 else
1931 return FALSE;
1932}
1933
1934static void Curl_schannel_close(struct connectdata *conn, int sockindex)
1935{
1936 if(conn->ssl[sockindex].use)
1937 /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1938 Curl_ssl_shutdown(conn, sockindex);
1939}
1940
1941static void Curl_schannel_session_free(void *ptr)
1942{
1943 /* this is expected to be called under sessionid lock */
1944 struct curl_schannel_cred *cred = ptr;
1945
1946 cred->refcount--;
1947 if(cred->refcount == 0) {
1948 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1949 Curl_safefree(cred);
1950 }
1951}
1952
1953static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1954{
1955 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1956 * Shutting Down an Schannel Connection
1957 */
1958 struct Curl_easy *data = conn->data;
1959 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1960 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1961 conn->host.name;
1962
1963 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1964 hostname, conn->remote_port);
1965
1966 if(BACKEND->cred && BACKEND->ctxt) {
1967 SecBufferDesc BuffDesc;
1968 SecBuffer Buffer;
1969 SECURITY_STATUS sspi_status;
1970 SecBuffer outbuf;
1971 SecBufferDesc outbuf_desc;
1972 CURLcode result;
1973 TCHAR *host_name;
1974 DWORD dwshut = SCHANNEL_SHUTDOWN;
1975
1976 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
1977 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
1978
1979 sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
1980 &BuffDesc);
1981
1982 if(sspi_status != SEC_E_OK)
1983 failf(data, "schannel: ApplyControlToken failure: %s",
1984 Curl_sspi_strerror(conn, sspi_status));
1985
1986 host_name = Curl_convert_UTF8_to_tchar(hostname);
1987 if(!host_name)
1988 return CURLE_OUT_OF_MEMORY;
1989
1990 /* setup output buffer */
1991 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1992 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1993
1994 sspi_status = s_pSecFn->InitializeSecurityContext(
1995 &BACKEND->cred->cred_handle,
1996 &BACKEND->ctxt->ctxt_handle,
1997 host_name,
1998 BACKEND->req_flags,
1999 0,
2000 0,
2001 NULL,
2002 0,
2003 &BACKEND->ctxt->ctxt_handle,
2004 &outbuf_desc,
2005 &BACKEND->ret_flags,
2006 &BACKEND->ctxt->time_stamp);
2007
2008 Curl_unicodefree(host_name);
2009
2010 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2011 /* send close message which is in output buffer */
2012 ssize_t written;
2013 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
2014 outbuf.cbBuffer, &written);
2015
2016 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2017 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2018 infof(data, "schannel: failed to send close msg: %s"
2019 " (bytes written: %zd)\n", curl_easy_strerror(result), written);
2020 }
2021 }
2022 }
2023
2024 /* free SSPI Schannel API security context handle */
2025 if(BACKEND->ctxt) {
2026 infof(data, "schannel: clear security context handle\n");
2027 s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
2028 Curl_safefree(BACKEND->ctxt);
2029 }
2030
2031 /* free SSPI Schannel API credential handle */
2032 if(BACKEND->cred) {
2033 /*
2034 * When this function is called from Curl_schannel_close() the connection
2035 * might not have an associated transfer so the check for conn->data is
2036 * necessary.
2037 */
2038 if(conn->data)
2039 Curl_ssl_sessionid_lock(conn);
2040 Curl_schannel_session_free(BACKEND->cred);
2041 if(conn->data)
2042 Curl_ssl_sessionid_unlock(conn);
2043 BACKEND->cred = NULL;
2044 }
2045
2046 /* free internal buffer for received encrypted data */
2047 if(BACKEND->encdata_buffer != NULL) {
2048 Curl_safefree(BACKEND->encdata_buffer);
2049 BACKEND->encdata_length = 0;
2050 BACKEND->encdata_offset = 0;
2051 BACKEND->encdata_is_incomplete = false;
2052 }
2053
2054 /* free internal buffer for received decrypted data */
2055 if(BACKEND->decdata_buffer != NULL) {
2056 Curl_safefree(BACKEND->decdata_buffer);
2057 BACKEND->decdata_length = 0;
2058 BACKEND->decdata_offset = 0;
2059 }
2060
2061 return CURLE_OK;
2062}
2063
2064static int Curl_schannel_init(void)
2065{
2066 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2067}
2068
2069static void Curl_schannel_cleanup(void)
2070{
2071 Curl_sspi_global_cleanup();
2072}
2073
2074static size_t Curl_schannel_version(char *buffer, size_t size)
2075{
2076 size = msnprintf(buffer, size, "Schannel");
2077
2078 return size;
2079}
2080
2081static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
2082 unsigned char *entropy, size_t length)
2083{
2084 HCRYPTPROV hCryptProv = 0;
2085
2086 (void)data;
2087
2088 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2089 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2090 return CURLE_FAILED_INIT;
2091
2092 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2093 CryptReleaseContext(hCryptProv, 0UL);
2094 return CURLE_FAILED_INIT;
2095 }
2096
2097 CryptReleaseContext(hCryptProv, 0UL);
2098 return CURLE_OK;
2099}
2100
2101static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
2102 const char *pinnedpubkey)
2103{
2104 SECURITY_STATUS status;
2105 struct Curl_easy *data = conn->data;
2106 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2107 CERT_CONTEXT *pCertContextServer = NULL;
2108 const char *x509_der;
2109 DWORD x509_der_len;
2110 curl_X509certificate x509_parsed;
2111 curl_asn1Element *pubkey;
2112
2113 /* Result is returned to caller */
2114 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2115
2116 /* if a path wasn't specified, don't pin */
2117 if(!pinnedpubkey)
2118 return CURLE_OK;
2119
2120 do {
2121 status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
2122 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2123 &pCertContextServer);
2124
2125 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
2126 failf(data, "schannel: Failed to read remote certificate context: %s",
2127 Curl_sspi_strerror(conn, status));
2128 break; /* failed */
2129 }
2130
2131
2132 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2133 (pCertContextServer->cbCertEncoded > 0)))
2134 break;
2135
2136 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2137 x509_der_len = pCertContextServer->cbCertEncoded;
2138 memset(&x509_parsed, 0, sizeof(x509_parsed));
2139 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2140 break;
2141
2142 pubkey = &x509_parsed.subjectPublicKeyInfo;
2143 if(!pubkey->header || pubkey->end <= pubkey->header) {
2144 failf(data, "SSL: failed retrieving public key from server certificate");
2145 break;
2146 }
2147
2148 result = Curl_pin_peer_pubkey(data,
2149 pinnedpubkey,
2150 (const unsigned char *)pubkey->header,
2151 (size_t)(pubkey->end - pubkey->header));
2152 if(result) {
2153 failf(data, "SSL: public key does not match pinned public key!");
2154 }
2155 } while(0);
2156
2157 if(pCertContextServer)
2158 CertFreeCertificateContext(pCertContextServer);
2159
2160 return result;
2161}
2162
2163static void Curl_schannel_checksum(const unsigned char *input,
2164 size_t inputlen,
2165 unsigned char *checksum,
2166 size_t checksumlen,
2167 DWORD provType,
2168 const unsigned int algId)
2169{
2170 HCRYPTPROV hProv = 0;
2171 HCRYPTHASH hHash = 0;
2172 DWORD cbHashSize = 0;
2173 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2174 DWORD dwChecksumLen = (DWORD)checksumlen;
2175
2176 /* since this can fail in multiple ways, zero memory first so we never
2177 * return old data
2178 */
2179 memset(checksum, 0, checksumlen);
2180
2181 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2182 CRYPT_VERIFYCONTEXT))
2183 return; /* failed */
2184
2185 do {
2186 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2187 break; /* failed */
2188
2189 /* workaround for original MinGW, should be (const BYTE*) */
2190 if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2191 break; /* failed */
2192
2193 /* get hash size */
2194 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2195 &dwHashSizeLen, 0))
2196 break; /* failed */
2197
2198 /* check hash size */
2199 if(checksumlen < cbHashSize)
2200 break; /* failed */
2201
2202 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2203 break; /* failed */
2204 } while(0);
2205
2206 if(hHash)
2207 CryptDestroyHash(hHash);
2208
2209 if(hProv)
2210 CryptReleaseContext(hProv, 0);
2211}
2212
2213static CURLcode Curl_schannel_md5sum(unsigned char *input,
2214 size_t inputlen,
2215 unsigned char *md5sum,
2216 size_t md5len)
2217{
2218 Curl_schannel_checksum(input, inputlen, md5sum, md5len,
2219 PROV_RSA_FULL, CALG_MD5);
2220 return CURLE_OK;
2221}
2222
2223static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
2224 size_t inputlen,
2225 unsigned char *sha256sum,
2226 size_t sha256len)
2227{
2228 Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
2229 PROV_RSA_AES, CALG_SHA_256);
2230 return CURLE_OK;
2231}
2232
2233static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
2234 CURLINFO info UNUSED_PARAM)
2235{
2236 (void)info;
2237 return &BACKEND->ctxt->ctxt_handle;
2238}
2239
2240const struct Curl_ssl Curl_ssl_schannel = {
2241 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2242
2243 SSLSUPP_CERTINFO |
2244 SSLSUPP_PINNEDPUBKEY,
2245
2246 sizeof(struct ssl_backend_data),
2247
2248 Curl_schannel_init, /* init */
2249 Curl_schannel_cleanup, /* cleanup */
2250 Curl_schannel_version, /* version */
2251 Curl_none_check_cxn, /* check_cxn */
2252 Curl_schannel_shutdown, /* shutdown */
2253 Curl_schannel_data_pending, /* data_pending */
2254 Curl_schannel_random, /* random */
2255 Curl_none_cert_status_request, /* cert_status_request */
2256 Curl_schannel_connect, /* connect */
2257 Curl_schannel_connect_nonblocking, /* connect_nonblocking */
2258 Curl_schannel_get_internals, /* get_internals */
2259 Curl_schannel_close, /* close_one */
2260 Curl_none_close_all, /* close_all */
2261 Curl_schannel_session_free, /* session_free */
2262 Curl_none_set_engine, /* set_engine */
2263 Curl_none_set_engine_default, /* set_engine_default */
2264 Curl_none_engines_list, /* engines_list */
2265 Curl_none_false_start, /* false_start */
2266 Curl_schannel_md5sum, /* md5sum */
2267 Curl_schannel_sha256sum /* sha256sum */
2268};
2269
2270#endif /* USE_SCHANNEL */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette