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