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