VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/vtls/schannel.c@ 97623

Last change on this file since 97623 was 95312, checked in by vboxsync, 3 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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