xref: /curl/lib/vtls/schannel.c (revision fb22459d)
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->peer.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, &connssl->peer,
1133                               (void **)&old_cred, NULL)) {
1134       backend->cred = old_cred;
1135       DEBUGF(infof(data, "schannel: reusing existing credential handle"));
1136 
1137       /* increment the reference counter of the credential/session handle */
1138       backend->cred->refcount++;
1139       DEBUGF(infof(data,
1140                    "schannel: incremented credential handle refcount = %d",
1141                    backend->cred->refcount));
1142     }
1143     Curl_ssl_sessionid_unlock(data);
1144   }
1145 
1146   if(!backend->cred) {
1147     char *snihost;
1148     result = schannel_acquire_credential_handle(cf, data);
1149     if(result)
1150       return result;
1151     /* schannel_acquire_credential_handle() sets backend->cred accordingly or
1152        it returns error otherwise. */
1153 
1154     /* A hostname associated with the credential is needed by
1155        InitializeSecurityContext for SNI and other reasons. */
1156     snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
1157     backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
1158     if(!backend->cred->sni_hostname)
1159       return CURLE_OUT_OF_MEMORY;
1160   }
1161 
1162   /* Warn if SNI is disabled due to use of an IP address */
1163   if(connssl->peer.type != CURL_SSL_PEER_DNS) {
1164     infof(data, "schannel: using IP address, SNI is not supported by OS.");
1165   }
1166 
1167 #ifdef HAS_ALPN
1168   if(backend->use_alpn) {
1169     int cur = 0;
1170     int list_start_index = 0;
1171     unsigned int *extension_len = NULL;
1172     unsigned short* list_len = NULL;
1173     struct alpn_proto_buf proto;
1174 
1175     /* The first four bytes will be an unsigned int indicating number
1176        of bytes of data in the rest of the buffer. */
1177     extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
1178     cur += (int)sizeof(unsigned int);
1179 
1180     /* The next four bytes are an indicator that this buffer will contain
1181        ALPN data, as opposed to NPN, for example. */
1182     *(unsigned int *)(void *)&alpn_buffer[cur] =
1183       SecApplicationProtocolNegotiationExt_ALPN;
1184     cur += (int)sizeof(unsigned int);
1185 
1186     /* The next two bytes will be an unsigned short indicating the number
1187        of bytes used to list the preferred protocols. */
1188     list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
1189     cur += (int)sizeof(unsigned short);
1190 
1191     list_start_index = cur;
1192 
1193     result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
1194     if(result) {
1195       failf(data, "Error setting ALPN");
1196       return CURLE_SSL_CONNECT_ERROR;
1197     }
1198     memcpy(&alpn_buffer[cur], proto.data, proto.len);
1199     cur += proto.len;
1200 
1201     *list_len = curlx_uitous(cur - list_start_index);
1202     *extension_len = (unsigned int)(*list_len +
1203       sizeof(unsigned int) + sizeof(unsigned short));
1204 
1205     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
1206     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1207 
1208     Curl_alpn_to_proto_str(&proto, connssl->alpn);
1209     infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
1210   }
1211   else {
1212     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1213     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1214   }
1215 #else /* HAS_ALPN */
1216   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
1217   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
1218 #endif
1219 
1220   /* setup output buffer */
1221   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1222   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1223 
1224   /* security request flags */
1225   backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1226     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
1227     ISC_REQ_STREAM;
1228 
1229   if(!ssl_config->auto_client_cert) {
1230     backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1231   }
1232 
1233   /* allocate memory for the security context handle */
1234   backend->ctxt = (struct Curl_schannel_ctxt *)
1235     calloc(1, sizeof(struct Curl_schannel_ctxt));
1236   if(!backend->ctxt) {
1237     failf(data, "schannel: unable to allocate memory");
1238     return CURLE_OUT_OF_MEMORY;
1239   }
1240 
1241   /* Schannel InitializeSecurityContext:
1242      https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
1243 
1244      At the moment we don't pass inbuf unless we're using ALPN since we only
1245      use it for that, and Wine (for which we currently disable ALPN) is giving
1246      us problems with inbuf regardless. https://github.com/curl/curl/issues/983
1247   */
1248   sspi_status = s_pSecFn->InitializeSecurityContext(
1249     &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
1250     backend->req_flags, 0, 0,
1251     (backend->use_alpn ? &inbuf_desc : NULL),
1252     0, &backend->ctxt->ctxt_handle,
1253     &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1254 
1255   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
1256     char buffer[STRERROR_LEN];
1257     Curl_safefree(backend->ctxt);
1258     switch(sspi_status) {
1259     case SEC_E_INSUFFICIENT_MEMORY:
1260       failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1261             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1262       return CURLE_OUT_OF_MEMORY;
1263     case SEC_E_WRONG_PRINCIPAL:
1264       failf(data, "schannel: SNI or certificate check failed: %s",
1265             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1266       return CURLE_PEER_FAILED_VERIFICATION;
1267       /*
1268         case SEC_E_INVALID_HANDLE:
1269         case SEC_E_INVALID_TOKEN:
1270         case SEC_E_LOGON_DENIED:
1271         case SEC_E_TARGET_UNKNOWN:
1272         case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1273         case SEC_E_INTERNAL_ERROR:
1274         case SEC_E_NO_CREDENTIALS:
1275         case SEC_E_UNSUPPORTED_FUNCTION:
1276         case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1277       */
1278     default:
1279       failf(data, "schannel: initial InitializeSecurityContext failed: %s",
1280             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1281       return CURLE_SSL_CONNECT_ERROR;
1282     }
1283   }
1284 
1285   DEBUGF(infof(data, "schannel: sending initial handshake data: "
1286                "sending %lu bytes.", outbuf.cbBuffer));
1287 
1288   /* send initial handshake data which is now stored in output buffer */
1289   written = Curl_conn_cf_send(cf->next, data,
1290                               outbuf.pvBuffer, outbuf.cbBuffer,
1291                               &result);
1292   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1293   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1294     failf(data, "schannel: failed to send initial handshake data: "
1295           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
1296     return CURLE_SSL_CONNECT_ERROR;
1297   }
1298 
1299   DEBUGF(infof(data, "schannel: sent initial handshake data: "
1300                "sent %zd bytes", written));
1301 
1302   backend->recv_unrecoverable_err = CURLE_OK;
1303   backend->recv_sspi_close_notify = false;
1304   backend->recv_connection_closed = false;
1305   backend->recv_renegotiating = false;
1306   backend->encdata_is_incomplete = false;
1307 
1308   /* continue to second handshake step */
1309   connssl->connecting_state = ssl_connect_2;
1310 
1311   return CURLE_OK;
1312 }
1313 
1314 static CURLcode
schannel_connect_step2(struct Curl_cfilter * cf,struct Curl_easy * data)1315 schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
1316 {
1317   struct ssl_connect_data *connssl = cf->ctx;
1318   struct schannel_ssl_backend_data *backend =
1319     (struct schannel_ssl_backend_data *)connssl->backend;
1320   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1321   int i;
1322   ssize_t nread = -1, written = -1;
1323   unsigned char *reallocated_buffer;
1324   SecBuffer outbuf[3];
1325   SecBufferDesc outbuf_desc;
1326   SecBuffer inbuf[2];
1327   SecBufferDesc inbuf_desc;
1328   SECURITY_STATUS sspi_status = SEC_E_OK;
1329   CURLcode result;
1330   bool doread;
1331   const char *pubkey_ptr;
1332 
1333   DEBUGASSERT(backend);
1334 
1335   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1336 
1337   DEBUGF(infof(data,
1338                "schannel: SSL/TLS connection with %s port %d (step 2/3)",
1339                connssl->peer.hostname, connssl->peer.port));
1340 
1341   if(!backend->cred || !backend->ctxt)
1342     return CURLE_SSL_CONNECT_ERROR;
1343 
1344   /* buffer to store previously received and decrypted data */
1345   if(!backend->decdata_buffer) {
1346     backend->decdata_offset = 0;
1347     backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1348     backend->decdata_buffer = malloc(backend->decdata_length);
1349     if(!backend->decdata_buffer) {
1350       failf(data, "schannel: unable to allocate memory");
1351       return CURLE_OUT_OF_MEMORY;
1352     }
1353   }
1354 
1355   /* buffer to store previously received and encrypted data */
1356   if(!backend->encdata_buffer) {
1357     backend->encdata_is_incomplete = false;
1358     backend->encdata_offset = 0;
1359     backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1360     backend->encdata_buffer = malloc(backend->encdata_length);
1361     if(!backend->encdata_buffer) {
1362       failf(data, "schannel: unable to allocate memory");
1363       return CURLE_OUT_OF_MEMORY;
1364     }
1365   }
1366 
1367   /* if we need a bigger buffer to read a full message, increase buffer now */
1368   if(backend->encdata_length - backend->encdata_offset <
1369      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1370     /* increase internal encrypted data buffer */
1371     size_t reallocated_length = backend->encdata_offset +
1372       CURL_SCHANNEL_BUFFER_FREE_SIZE;
1373     reallocated_buffer = realloc(backend->encdata_buffer,
1374                                  reallocated_length);
1375 
1376     if(!reallocated_buffer) {
1377       failf(data, "schannel: unable to re-allocate memory");
1378       return CURLE_OUT_OF_MEMORY;
1379     }
1380     else {
1381       backend->encdata_buffer = reallocated_buffer;
1382       backend->encdata_length = reallocated_length;
1383     }
1384   }
1385 
1386   for(;;) {
1387     if(doread) {
1388       /* read encrypted handshake data from socket */
1389       nread = Curl_conn_cf_recv(cf->next, data,
1390                                (char *) (backend->encdata_buffer +
1391                                          backend->encdata_offset),
1392                                backend->encdata_length -
1393                                backend->encdata_offset,
1394                                &result);
1395       if(result == CURLE_AGAIN) {
1396         if(connssl->connecting_state != ssl_connect_2_writing)
1397           connssl->connecting_state = ssl_connect_2_reading;
1398         DEBUGF(infof(data, "schannel: failed to receive handshake, "
1399                      "need more data"));
1400         return CURLE_OK;
1401       }
1402       else if((result != CURLE_OK) || (nread == 0)) {
1403         failf(data, "schannel: failed to receive handshake, "
1404               "SSL/TLS connection failed");
1405         return CURLE_SSL_CONNECT_ERROR;
1406       }
1407 
1408       /* increase encrypted data buffer offset */
1409       backend->encdata_offset += nread;
1410       backend->encdata_is_incomplete = false;
1411       DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1412     }
1413 
1414     DEBUGF(infof(data,
1415                  "schannel: encrypted data buffer: offset %zu length %zu",
1416                  backend->encdata_offset, backend->encdata_length));
1417 
1418     /* setup input buffers */
1419     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
1420                   curlx_uztoul(backend->encdata_offset));
1421     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1422     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1423 
1424     /* setup output buffers */
1425     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1426     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1427     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1428     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1429 
1430     if(!inbuf[0].pvBuffer) {
1431       failf(data, "schannel: unable to allocate memory");
1432       return CURLE_OUT_OF_MEMORY;
1433     }
1434 
1435     /* copy received handshake data into input buffer */
1436     memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
1437            backend->encdata_offset);
1438 
1439     sspi_status = s_pSecFn->InitializeSecurityContext(
1440       &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
1441       backend->cred->sni_hostname, backend->req_flags,
1442       0, 0, &inbuf_desc, 0, NULL,
1443       &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
1444 
1445     /* free buffer for received handshake data */
1446     Curl_safefree(inbuf[0].pvBuffer);
1447 
1448     /* check if the handshake was incomplete */
1449     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1450       backend->encdata_is_incomplete = true;
1451       connssl->connecting_state = ssl_connect_2_reading;
1452       DEBUGF(infof(data,
1453                    "schannel: received incomplete message, need more data"));
1454       return CURLE_OK;
1455     }
1456 
1457     /* If the server has requested a client certificate, attempt to continue
1458        the handshake without one. This will allow connections to servers which
1459        request a client certificate but do not require it. */
1460     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1461        !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1462       backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1463       connssl->connecting_state = ssl_connect_2_writing;
1464       DEBUGF(infof(data,
1465                    "schannel: a client certificate has been requested"));
1466       return CURLE_OK;
1467     }
1468 
1469     /* check if the handshake needs to be continued */
1470     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1471       for(i = 0; i < 3; i++) {
1472         /* search for handshake tokens that need to be send */
1473         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1474           DEBUGF(infof(data, "schannel: sending next handshake data: "
1475                        "sending %lu bytes.", outbuf[i].cbBuffer));
1476 
1477           /* send handshake token to server */
1478           written = Curl_conn_cf_send(cf->next, data,
1479                                       outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1480                                       &result);
1481           if((result != CURLE_OK) ||
1482              (outbuf[i].cbBuffer != (size_t) written)) {
1483             failf(data, "schannel: failed to send next handshake data: "
1484                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1485             return CURLE_SSL_CONNECT_ERROR;
1486           }
1487         }
1488 
1489         /* free obsolete buffer */
1490         if(outbuf[i].pvBuffer) {
1491           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1492         }
1493       }
1494     }
1495     else {
1496       char buffer[STRERROR_LEN];
1497       switch(sspi_status) {
1498       case SEC_E_INSUFFICIENT_MEMORY:
1499         failf(data, "schannel: next InitializeSecurityContext failed: %s",
1500               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1501         return CURLE_OUT_OF_MEMORY;
1502       case SEC_E_WRONG_PRINCIPAL:
1503         failf(data, "schannel: SNI or certificate check failed: %s",
1504               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1505         return CURLE_PEER_FAILED_VERIFICATION;
1506       case SEC_E_UNTRUSTED_ROOT:
1507         failf(data, "schannel: %s",
1508               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1509         return CURLE_PEER_FAILED_VERIFICATION;
1510         /*
1511           case SEC_E_INVALID_HANDLE:
1512           case SEC_E_INVALID_TOKEN:
1513           case SEC_E_LOGON_DENIED:
1514           case SEC_E_TARGET_UNKNOWN:
1515           case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1516           case SEC_E_INTERNAL_ERROR:
1517           case SEC_E_NO_CREDENTIALS:
1518           case SEC_E_UNSUPPORTED_FUNCTION:
1519           case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1520         */
1521       default:
1522         failf(data, "schannel: next InitializeSecurityContext failed: %s",
1523               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1524         return CURLE_SSL_CONNECT_ERROR;
1525       }
1526     }
1527 
1528     /* check if there was additional remaining encrypted data */
1529     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1530       DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1531                    inbuf[1].cbBuffer));
1532       /*
1533         There are two cases where we could be getting extra data here:
1534         1) If we're renegotiating a connection and the handshake is already
1535         complete (from the server perspective), it can encrypted app data
1536         (not handshake data) in an extra buffer at this point.
1537         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1538         connection and this extra data is part of the handshake.
1539         We should process the data immediately; waiting for the socket to
1540         be ready may fail since the server is done sending handshake data.
1541       */
1542       /* check if the remaining data is less than the total amount
1543          and therefore begins after the already processed data */
1544       if(backend->encdata_offset > inbuf[1].cbBuffer) {
1545         memmove(backend->encdata_buffer,
1546                 (backend->encdata_buffer + backend->encdata_offset) -
1547                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1548         backend->encdata_offset = inbuf[1].cbBuffer;
1549         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1550           doread = FALSE;
1551           continue;
1552         }
1553       }
1554     }
1555     else {
1556       backend->encdata_offset = 0;
1557     }
1558     break;
1559   }
1560 
1561   /* check if the handshake needs to be continued */
1562   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1563     connssl->connecting_state = ssl_connect_2_reading;
1564     return CURLE_OK;
1565   }
1566 
1567   /* check if the handshake is complete */
1568   if(sspi_status == SEC_E_OK) {
1569     connssl->connecting_state = ssl_connect_3;
1570     DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1571   }
1572 
1573 #ifndef CURL_DISABLE_PROXY
1574   pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
1575     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
1576     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1577 #else
1578   pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1579 #endif
1580   if(pubkey_ptr) {
1581     result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
1582     if(result) {
1583       failf(data, "SSL: public key does not match pinned public key");
1584       return result;
1585     }
1586   }
1587 
1588 #ifdef HAS_MANUAL_VERIFY_API
1589   if(conn_config->verifypeer && backend->use_manual_cred_validation) {
1590     /* Certificate verification also verifies the hostname if verifyhost */
1591     return Curl_verify_certificate(cf, data);
1592   }
1593 #endif
1594 
1595   /* Verify the hostname manually when certificate verification is disabled,
1596      because in that case Schannel won't verify it. */
1597   if(!conn_config->verifypeer && conn_config->verifyhost)
1598     return Curl_verify_host(cf, data);
1599 
1600   return CURLE_OK;
1601 }
1602 
1603 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1604 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1605 {
1606   return (cert_context != NULL) &&
1607     ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1608     (cert_context->pbCertEncoded != NULL) &&
1609     (cert_context->cbCertEncoded > 0);
1610 }
1611 
1612 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context,
1613                              bool reverse_order, void *arg);
1614 
1615 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1616 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1617                     void *arg)
1618 {
1619   const CERT_CONTEXT *current_context = NULL;
1620   bool should_continue = true;
1621   bool first = true;
1622   bool reverse_order = false;
1623   while(should_continue &&
1624         (current_context = CertEnumCertificatesInStore(
1625           context->hCertStore,
1626           current_context)) != NULL) {
1627     /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in
1628        leaf-to-root order while all previous versions of Windows enumerate
1629        certificates in root-to-leaf order. Determine the order of enumeration
1630        by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
1631        first certificate's pbCertContext. */
1632     if(first && context->pbCertEncoded != current_context->pbCertEncoded)
1633       reverse_order = true;
1634     should_continue = func(current_context, reverse_order, arg);
1635     first = false;
1636   }
1637 
1638   if(current_context)
1639     CertFreeCertificateContext(current_context);
1640 }
1641 
1642 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,bool reverse_order,void * certs_count)1643 cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
1644                       void *certs_count)
1645 {
1646   (void)reverse_order; /* unused */
1647   if(valid_cert_encoding(ccert_context))
1648     (*(int *)certs_count)++;
1649   return true;
1650 }
1651 
1652 struct Adder_args
1653 {
1654   struct Curl_easy *data;
1655   CURLcode result;
1656   int idx;
1657   int certs_count;
1658 };
1659 
1660 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,bool reverse_order,void * raw_arg)1661 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
1662                      void *raw_arg)
1663 {
1664   struct Adder_args *args = (struct Adder_args*)raw_arg;
1665   args->result = CURLE_OK;
1666   if(valid_cert_encoding(ccert_context)) {
1667     const char *beg = (const char *) ccert_context->pbCertEncoded;
1668     const char *end = beg + ccert_context->cbCertEncoded;
1669     int insert_index = reverse_order ? (args->certs_count - 1) - args->idx :
1670                        args->idx;
1671     args->result = Curl_extract_certinfo(args->data, insert_index,
1672                                          beg, end);
1673     args->idx++;
1674   }
1675   return args->result == CURLE_OK;
1676 }
1677 
schannel_session_free(void * sessionid,size_t idsize)1678 static void schannel_session_free(void *sessionid, size_t idsize)
1679 {
1680   /* this is expected to be called under sessionid lock */
1681   struct Curl_schannel_cred *cred = sessionid;
1682 
1683   (void)idsize;
1684   if(cred) {
1685     cred->refcount--;
1686     if(cred->refcount == 0) {
1687       s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1688       curlx_unicodefree(cred->sni_hostname);
1689 #ifdef HAS_CLIENT_CERT_PATH
1690       if(cred->client_cert_store) {
1691         CertCloseStore(cred->client_cert_store, 0);
1692         cred->client_cert_store = NULL;
1693       }
1694 #endif
1695       Curl_safefree(cred);
1696     }
1697   }
1698 }
1699 
1700 static CURLcode
schannel_connect_step3(struct Curl_cfilter * cf,struct Curl_easy * data)1701 schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
1702 {
1703   struct ssl_connect_data *connssl = cf->ctx;
1704   struct schannel_ssl_backend_data *backend =
1705     (struct schannel_ssl_backend_data *)connssl->backend;
1706   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1707   CURLcode result = CURLE_OK;
1708   SECURITY_STATUS sspi_status = SEC_E_OK;
1709   CERT_CONTEXT *ccert_context = NULL;
1710 #ifdef HAS_ALPN
1711   SecPkgContext_ApplicationProtocol alpn_result;
1712 #endif
1713 
1714   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1715   DEBUGASSERT(backend);
1716 
1717   DEBUGF(infof(data,
1718                "schannel: SSL/TLS connection with %s port %d (step 3/3)",
1719                connssl->peer.hostname, connssl->peer.port));
1720 
1721   if(!backend->cred)
1722     return CURLE_SSL_CONNECT_ERROR;
1723 
1724   /* check if the required context attributes are met */
1725   if(backend->ret_flags != backend->req_flags) {
1726     if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
1727       failf(data, "schannel: failed to setup sequence detection");
1728     if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
1729       failf(data, "schannel: failed to setup replay detection");
1730     if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
1731       failf(data, "schannel: failed to setup confidentiality");
1732     if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1733       failf(data, "schannel: failed to setup memory allocation");
1734     if(!(backend->ret_flags & ISC_RET_STREAM))
1735       failf(data, "schannel: failed to setup stream orientation");
1736     return CURLE_SSL_CONNECT_ERROR;
1737   }
1738 
1739 #ifdef HAS_ALPN
1740   if(backend->use_alpn) {
1741     sspi_status =
1742       s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1743                                        SECPKG_ATTR_APPLICATION_PROTOCOL,
1744                                        &alpn_result);
1745 
1746     if(sspi_status != SEC_E_OK) {
1747       failf(data, "schannel: failed to retrieve ALPN result");
1748       return CURLE_SSL_CONNECT_ERROR;
1749     }
1750 
1751     if(alpn_result.ProtoNegoStatus ==
1752        SecApplicationProtocolNegotiationStatus_Success) {
1753       unsigned char prev_alpn = cf->conn->alpn;
1754 
1755       Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId,
1756                                alpn_result.ProtocolIdSize);
1757       if(backend->recv_renegotiating) {
1758         if(prev_alpn != cf->conn->alpn &&
1759            prev_alpn != CURL_HTTP_VERSION_NONE) {
1760           /* Renegotiation selected a different protocol now, we cannot
1761            * deal with this */
1762           failf(data, "schannel: server selected an ALPN protocol too late");
1763           return CURLE_SSL_CONNECT_ERROR;
1764         }
1765       }
1766     }
1767     else {
1768       if(!backend->recv_renegotiating)
1769         Curl_alpn_set_negotiated(cf, data, NULL, 0);
1770     }
1771   }
1772 #endif
1773 
1774   /* save the current session data for possible reuse */
1775   if(ssl_config->primary.sessionid) {
1776     bool incache;
1777     struct Curl_schannel_cred *old_cred = NULL;
1778 
1779     Curl_ssl_sessionid_lock(data);
1780     incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
1781                                       (void **)&old_cred, NULL));
1782     if(incache) {
1783       if(old_cred != backend->cred) {
1784         DEBUGF(infof(data,
1785                      "schannel: old credential handle is stale, removing"));
1786         /* we're not taking old_cred ownership here, no refcount++ is needed */
1787         Curl_ssl_delsessionid(data, (void *)old_cred);
1788         incache = FALSE;
1789       }
1790     }
1791     if(!incache) {
1792       /* Up ref count since call takes ownership */
1793       backend->cred->refcount++;
1794       result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
1795                                      sizeof(struct Curl_schannel_cred),
1796                                      schannel_session_free);
1797       if(result) {
1798         Curl_ssl_sessionid_unlock(data);
1799         return result;
1800       }
1801     }
1802     Curl_ssl_sessionid_unlock(data);
1803   }
1804 
1805   if(data->set.ssl.certinfo) {
1806     int certs_count = 0;
1807     sspi_status =
1808       s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1809                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1810                                        &ccert_context);
1811 
1812     if((sspi_status != SEC_E_OK) || !ccert_context) {
1813       failf(data, "schannel: failed to retrieve remote cert context");
1814       return CURLE_PEER_FAILED_VERIFICATION;
1815     }
1816 
1817     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1818 
1819     result = Curl_ssl_init_certinfo(data, certs_count);
1820     if(!result) {
1821       struct Adder_args args;
1822       args.data = data;
1823       args.idx = 0;
1824       args.certs_count = certs_count;
1825       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1826       result = args.result;
1827     }
1828     CertFreeCertificateContext(ccert_context);
1829     if(result)
1830       return result;
1831   }
1832 
1833   connssl->connecting_state = ssl_connect_done;
1834 
1835   return CURLE_OK;
1836 }
1837 
1838 static CURLcode
schannel_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool nonblocking,bool * done)1839 schannel_connect_common(struct Curl_cfilter *cf,
1840                         struct Curl_easy *data,
1841                         bool nonblocking, bool *done)
1842 {
1843   CURLcode result;
1844   struct ssl_connect_data *connssl = cf->ctx;
1845   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1846   timediff_t timeout_ms;
1847   int what;
1848 
1849   /* check if the connection has already been established */
1850   if(ssl_connection_complete == connssl->state) {
1851     *done = TRUE;
1852     return CURLE_OK;
1853   }
1854 
1855   if(ssl_connect_1 == connssl->connecting_state) {
1856     /* check out how much more time we're allowed */
1857     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1858 
1859     if(timeout_ms < 0) {
1860       /* no need to continue if time already is up */
1861       failf(data, "SSL/TLS connection timeout");
1862       return CURLE_OPERATION_TIMEDOUT;
1863     }
1864 
1865     result = schannel_connect_step1(cf, data);
1866     if(result)
1867       return result;
1868   }
1869 
1870   while(ssl_connect_2 == connssl->connecting_state ||
1871         ssl_connect_2_reading == connssl->connecting_state ||
1872         ssl_connect_2_writing == connssl->connecting_state) {
1873 
1874     /* check out how much more time we're allowed */
1875     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1876 
1877     if(timeout_ms < 0) {
1878       /* no need to continue if time already is up */
1879       failf(data, "SSL/TLS connection timeout");
1880       return CURLE_OPERATION_TIMEDOUT;
1881     }
1882 
1883     /* if ssl is expecting something, check if it's available. */
1884     if(connssl->connecting_state == ssl_connect_2_reading
1885        || connssl->connecting_state == ssl_connect_2_writing) {
1886 
1887       curl_socket_t writefd = ssl_connect_2_writing ==
1888         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1889       curl_socket_t readfd = ssl_connect_2_reading ==
1890         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1891 
1892       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1893                                nonblocking ? 0 : timeout_ms);
1894       if(what < 0) {
1895         /* fatal error */
1896         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1897         return CURLE_SSL_CONNECT_ERROR;
1898       }
1899       else if(0 == what) {
1900         if(nonblocking) {
1901           *done = FALSE;
1902           return CURLE_OK;
1903         }
1904         else {
1905           /* timeout */
1906           failf(data, "SSL/TLS connection timeout");
1907           return CURLE_OPERATION_TIMEDOUT;
1908         }
1909       }
1910       /* socket is readable or writable */
1911     }
1912 
1913     /* Run transaction, and return to the caller if it failed or if
1914      * this connection is part of a multi handle and this loop would
1915      * execute again. This permits the owner of a multi handle to
1916      * abort a connection attempt before step2 has completed while
1917      * ensuring that a client using select() or epoll() will always
1918      * have a valid fdset to wait on.
1919      */
1920     result = schannel_connect_step2(cf, data);
1921     if(result || (nonblocking &&
1922                   (ssl_connect_2 == connssl->connecting_state ||
1923                    ssl_connect_2_reading == connssl->connecting_state ||
1924                    ssl_connect_2_writing == connssl->connecting_state)))
1925       return result;
1926 
1927   } /* repeat step2 until all transactions are done. */
1928 
1929   if(ssl_connect_3 == connssl->connecting_state) {
1930     result = schannel_connect_step3(cf, data);
1931     if(result)
1932       return result;
1933   }
1934 
1935   if(ssl_connect_done == connssl->connecting_state) {
1936     connssl->state = ssl_connection_complete;
1937 
1938 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1939     /* When SSPI is used in combination with Schannel
1940      * we need the Schannel context to create the Schannel
1941      * binding to pass the IIS extended protection checks.
1942      * Available on Windows 7 or later.
1943      */
1944     {
1945       struct schannel_ssl_backend_data *backend =
1946         (struct schannel_ssl_backend_data *)connssl->backend;
1947       DEBUGASSERT(backend);
1948       cf->conn->sslContext = &backend->ctxt->ctxt_handle;
1949     }
1950 #endif
1951 
1952     *done = TRUE;
1953   }
1954   else
1955     *done = FALSE;
1956 
1957   /* reset our connection state machine */
1958   connssl->connecting_state = ssl_connect_1;
1959 
1960   return CURLE_OK;
1961 }
1962 
1963 static ssize_t
schannel_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1964 schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1965               const void *buf, size_t len, CURLcode *err)
1966 {
1967   ssize_t written = -1;
1968   size_t data_len = 0;
1969   unsigned char *ptr = NULL;
1970   struct ssl_connect_data *connssl = cf->ctx;
1971   SecBuffer outbuf[4];
1972   SecBufferDesc outbuf_desc;
1973   SECURITY_STATUS sspi_status = SEC_E_OK;
1974   CURLcode result;
1975   struct schannel_ssl_backend_data *backend =
1976     (struct schannel_ssl_backend_data *)connssl->backend;
1977 
1978   DEBUGASSERT(backend);
1979 
1980   /* check if the maximum stream sizes were queried */
1981   if(backend->stream_sizes.cbMaximumMessage == 0) {
1982     sspi_status = s_pSecFn->QueryContextAttributes(
1983       &backend->ctxt->ctxt_handle,
1984       SECPKG_ATTR_STREAM_SIZES,
1985       &backend->stream_sizes);
1986     if(sspi_status != SEC_E_OK) {
1987       *err = CURLE_SEND_ERROR;
1988       return -1;
1989     }
1990   }
1991 
1992   /* check if the buffer is longer than the maximum message length */
1993   if(len > backend->stream_sizes.cbMaximumMessage) {
1994     len = backend->stream_sizes.cbMaximumMessage;
1995   }
1996 
1997   /* calculate the complete message length and allocate a buffer for it */
1998   data_len = backend->stream_sizes.cbHeader + len +
1999     backend->stream_sizes.cbTrailer;
2000   ptr = (unsigned char *) malloc(data_len);
2001   if(!ptr) {
2002     *err = CURLE_OUT_OF_MEMORY;
2003     return -1;
2004   }
2005 
2006   /* setup output buffers (header, data, trailer, empty) */
2007   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
2008                 ptr, backend->stream_sizes.cbHeader);
2009   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
2010                 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
2011   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
2012                 ptr + backend->stream_sizes.cbHeader + len,
2013                 backend->stream_sizes.cbTrailer);
2014   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
2015   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
2016 
2017   /* copy data into output buffer */
2018   memcpy(outbuf[1].pvBuffer, buf, len);
2019 
2020   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
2021   sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
2022                                          &outbuf_desc, 0);
2023 
2024   /* check if the message was encrypted */
2025   if(sspi_status == SEC_E_OK) {
2026     written = 0;
2027 
2028     /* send the encrypted message including header, data and trailer */
2029     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
2030 
2031     /*
2032       It's important to send the full message which includes the header,
2033       encrypted payload, and trailer.  Until the client receives all the
2034       data a coherent message has not been delivered and the client
2035       can't read any of it.
2036 
2037       If we wanted to buffer the unwritten encrypted bytes, we would
2038       tell the client that all data it has requested to be sent has been
2039       sent. The unwritten encrypted bytes would be the first bytes to
2040       send on the next invocation.
2041       Here's the catch with this - if we tell the client that all the
2042       bytes have been sent, will the client call this method again to
2043       send the buffered data?  Looking at who calls this function, it
2044       seems the answer is NO.
2045     */
2046 
2047     /* send entire message or fail */
2048     while(len > (size_t)written) {
2049       ssize_t this_write = 0;
2050       int what;
2051       timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
2052       if(timeout_ms < 0) {
2053         /* we already got the timeout */
2054         failf(data, "schannel: timed out sending data "
2055               "(bytes sent: %zd)", written);
2056         *err = CURLE_OPERATION_TIMEDOUT;
2057         written = -1;
2058         break;
2059       }
2060       else if(!timeout_ms)
2061         timeout_ms = TIMEDIFF_T_MAX;
2062       what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms);
2063       if(what < 0) {
2064         /* fatal error */
2065         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2066         *err = CURLE_SEND_ERROR;
2067         written = -1;
2068         break;
2069       }
2070       else if(0 == what) {
2071         failf(data, "schannel: timed out sending data "
2072               "(bytes sent: %zd)", written);
2073         *err = CURLE_OPERATION_TIMEDOUT;
2074         written = -1;
2075         break;
2076       }
2077       /* socket is writable */
2078 
2079        this_write = Curl_conn_cf_send(cf->next, data,
2080                                       ptr + written, len - written,
2081                                       &result);
2082       if(result == CURLE_AGAIN)
2083         continue;
2084       else if(result != CURLE_OK) {
2085         *err = result;
2086         written = -1;
2087         break;
2088       }
2089 
2090       written += this_write;
2091     }
2092   }
2093   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
2094     *err = CURLE_OUT_OF_MEMORY;
2095   }
2096   else{
2097     *err = CURLE_SEND_ERROR;
2098   }
2099 
2100   Curl_safefree(ptr);
2101 
2102   if(len == (size_t)written)
2103     /* Encrypted message including header, data and trailer entirely sent.
2104        The return value is the number of unencrypted bytes that were sent. */
2105     written = outbuf[1].cbBuffer;
2106 
2107   return written;
2108 }
2109 
2110 static ssize_t
schannel_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)2111 schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
2112               char *buf, size_t len, CURLcode *err)
2113 {
2114   size_t size = 0;
2115   ssize_t nread = -1;
2116   struct ssl_connect_data *connssl = cf->ctx;
2117   unsigned char *reallocated_buffer;
2118   size_t reallocated_length;
2119   bool done = FALSE;
2120   SecBuffer inbuf[4];
2121   SecBufferDesc inbuf_desc;
2122   SECURITY_STATUS sspi_status = SEC_E_OK;
2123   /* we want the length of the encrypted buffer to be at least large enough
2124      that it can hold all the bytes requested and some TLS record overhead. */
2125   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
2126   struct schannel_ssl_backend_data *backend =
2127     (struct schannel_ssl_backend_data *)connssl->backend;
2128 
2129   DEBUGASSERT(backend);
2130 
2131   /****************************************************************************
2132    * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
2133    * The pattern for return error is set *err, optional infof, goto cleanup.
2134    *
2135    * Our priority is to always return as much decrypted data to the caller as
2136    * possible, even if an error occurs. The state of the decrypted buffer must
2137    * always be valid. Transfer of decrypted data to the caller's buffer is
2138    * handled in the cleanup.
2139    */
2140 
2141   DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
2142   *err = CURLE_OK;
2143 
2144   if(len && len <= backend->decdata_offset) {
2145     infof(data, "schannel: enough decrypted data is already available");
2146     goto cleanup;
2147   }
2148   else if(backend->recv_unrecoverable_err) {
2149     *err = backend->recv_unrecoverable_err;
2150     infof(data, "schannel: an unrecoverable error occurred in a prior call");
2151     goto cleanup;
2152   }
2153   else if(backend->recv_sspi_close_notify) {
2154     /* once a server has indicated shutdown there is no more encrypted data */
2155     infof(data, "schannel: server indicated shutdown in a prior call");
2156     goto cleanup;
2157   }
2158   /* It's debatable what to return when !len. Regardless we can't return
2159      immediately because there may be data to decrypt (in the case we want to
2160      decrypt all encrypted cached data) so handle !len later in cleanup.
2161   */
2162   else if(len && !backend->recv_connection_closed) {
2163     /* increase enc buffer in order to fit the requested amount of data */
2164     size = backend->encdata_length - backend->encdata_offset;
2165     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2166        backend->encdata_length < min_encdata_length) {
2167       reallocated_length = backend->encdata_offset +
2168         CURL_SCHANNEL_BUFFER_FREE_SIZE;
2169       if(reallocated_length < min_encdata_length) {
2170         reallocated_length = min_encdata_length;
2171       }
2172       reallocated_buffer = realloc(backend->encdata_buffer,
2173                                    reallocated_length);
2174       if(!reallocated_buffer) {
2175         *err = CURLE_OUT_OF_MEMORY;
2176         failf(data, "schannel: unable to re-allocate memory");
2177         goto cleanup;
2178       }
2179 
2180       backend->encdata_buffer = reallocated_buffer;
2181       backend->encdata_length = reallocated_length;
2182       size = backend->encdata_length - backend->encdata_offset;
2183       DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
2184                    backend->encdata_length));
2185     }
2186 
2187     DEBUGF(infof(data,
2188                  "schannel: encrypted data buffer: offset %zu length %zu",
2189                  backend->encdata_offset, backend->encdata_length));
2190 
2191     /* read encrypted data from socket */
2192     nread = Curl_conn_cf_recv(cf->next, data,
2193                               (char *)(backend->encdata_buffer +
2194                                     backend->encdata_offset),
2195                               size, err);
2196     if(*err) {
2197       nread = -1;
2198       if(*err == CURLE_AGAIN)
2199         DEBUGF(infof(data,
2200                      "schannel: recv returned CURLE_AGAIN"));
2201       else if(*err == CURLE_RECV_ERROR)
2202         infof(data, "schannel: recv returned CURLE_RECV_ERROR");
2203       else
2204         infof(data, "schannel: recv returned error %d", *err);
2205     }
2206     else if(nread == 0) {
2207       backend->recv_connection_closed = true;
2208       DEBUGF(infof(data, "schannel: server closed the connection"));
2209     }
2210     else if(nread > 0) {
2211       backend->encdata_offset += (size_t)nread;
2212       backend->encdata_is_incomplete = false;
2213       DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
2214     }
2215   }
2216 
2217   DEBUGF(infof(data,
2218                "schannel: encrypted data buffer: offset %zu length %zu",
2219                backend->encdata_offset, backend->encdata_length));
2220 
2221   /* decrypt loop */
2222   while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
2223         (!len || backend->decdata_offset < len ||
2224          backend->recv_connection_closed)) {
2225     /* prepare data buffer for DecryptMessage call */
2226     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
2227                   curlx_uztoul(backend->encdata_offset));
2228 
2229     /* we need 3 more empty input buffers for possible output */
2230     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
2231     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
2232     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
2233     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
2234 
2235     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
2236      */
2237     sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
2238                                            &inbuf_desc, 0, NULL);
2239 
2240     /* check if everything went fine (server may want to renegotiate
2241        or shutdown the connection context) */
2242     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
2243        sspi_status == SEC_I_CONTEXT_EXPIRED) {
2244       /* check for successfully decrypted data, even before actual
2245          renegotiation or shutdown of the connection context */
2246       if(inbuf[1].BufferType == SECBUFFER_DATA) {
2247         DEBUGF(infof(data, "schannel: decrypted data length: %lu",
2248                      inbuf[1].cbBuffer));
2249 
2250         /* increase buffer in order to fit the received amount of data */
2251         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
2252           inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
2253         if(backend->decdata_length - backend->decdata_offset < size ||
2254            backend->decdata_length < len) {
2255           /* increase internal decrypted data buffer */
2256           reallocated_length = backend->decdata_offset + size;
2257           /* make sure that the requested amount of data fits */
2258           if(reallocated_length < len) {
2259             reallocated_length = len;
2260           }
2261           reallocated_buffer = realloc(backend->decdata_buffer,
2262                                        reallocated_length);
2263           if(!reallocated_buffer) {
2264             *err = CURLE_OUT_OF_MEMORY;
2265             failf(data, "schannel: unable to re-allocate memory");
2266             goto cleanup;
2267           }
2268           backend->decdata_buffer = reallocated_buffer;
2269           backend->decdata_length = reallocated_length;
2270         }
2271 
2272         /* copy decrypted data to internal buffer */
2273         size = inbuf[1].cbBuffer;
2274         if(size) {
2275           memcpy(backend->decdata_buffer + backend->decdata_offset,
2276                  inbuf[1].pvBuffer, size);
2277           backend->decdata_offset += size;
2278         }
2279 
2280         DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
2281         DEBUGF(infof(data,
2282                      "schannel: decrypted cached: offset %zu length %zu",
2283                      backend->decdata_offset, backend->decdata_length));
2284       }
2285 
2286       /* check for remaining encrypted data */
2287       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
2288         DEBUGF(infof(data, "schannel: encrypted data length: %lu",
2289                      inbuf[3].cbBuffer));
2290 
2291         /* check if the remaining data is less than the total amount
2292          * and therefore begins after the already processed data
2293          */
2294         if(backend->encdata_offset > inbuf[3].cbBuffer) {
2295           /* move remaining encrypted data forward to the beginning of
2296              buffer */
2297           memmove(backend->encdata_buffer,
2298                   (backend->encdata_buffer + backend->encdata_offset) -
2299                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
2300           backend->encdata_offset = inbuf[3].cbBuffer;
2301         }
2302 
2303         DEBUGF(infof(data,
2304                      "schannel: encrypted cached: offset %zu length %zu",
2305                      backend->encdata_offset, backend->encdata_length));
2306       }
2307       else {
2308         /* reset encrypted buffer offset, because there is no data remaining */
2309         backend->encdata_offset = 0;
2310       }
2311 
2312       /* check if server wants to renegotiate the connection context */
2313       if(sspi_status == SEC_I_RENEGOTIATE) {
2314         infof(data, "schannel: remote party requests renegotiation");
2315         if(*err && *err != CURLE_AGAIN) {
2316           infof(data, "schannel: can't renegotiate, an error is pending");
2317           goto cleanup;
2318         }
2319 
2320         /* begin renegotiation */
2321         infof(data, "schannel: renegotiating SSL/TLS connection");
2322         connssl->state = ssl_connection_negotiating;
2323         connssl->connecting_state = ssl_connect_2_writing;
2324         backend->recv_renegotiating = true;
2325         *err = schannel_connect_common(cf, data, FALSE, &done);
2326         backend->recv_renegotiating = false;
2327         if(*err) {
2328           infof(data, "schannel: renegotiation failed");
2329           goto cleanup;
2330         }
2331         /* now retry receiving data */
2332         sspi_status = SEC_E_OK;
2333         infof(data, "schannel: SSL/TLS connection renegotiated");
2334         continue;
2335       }
2336       /* check if the server closed the connection */
2337       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2338         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2339            returned so we have to work around that in cleanup. */
2340         backend->recv_sspi_close_notify = true;
2341         if(!backend->recv_connection_closed)
2342           backend->recv_connection_closed = true;
2343         infof(data,
2344               "schannel: server close notification received (close_notify)");
2345         goto cleanup;
2346       }
2347     }
2348     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2349       backend->encdata_is_incomplete = true;
2350       if(!*err)
2351         *err = CURLE_AGAIN;
2352       infof(data, "schannel: failed to decrypt data, need more data");
2353       goto cleanup;
2354     }
2355     else {
2356 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2357       char buffer[STRERROR_LEN];
2358       infof(data, "schannel: failed to read data from server: %s",
2359             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2360 #endif
2361       *err = CURLE_RECV_ERROR;
2362       goto cleanup;
2363     }
2364   }
2365 
2366   DEBUGF(infof(data,
2367                "schannel: encrypted data buffer: offset %zu length %zu",
2368                backend->encdata_offset, backend->encdata_length));
2369 
2370   DEBUGF(infof(data,
2371                "schannel: decrypted data buffer: offset %zu length %zu",
2372                backend->decdata_offset, backend->decdata_length));
2373 
2374 cleanup:
2375   /* Warning- there is no guarantee the encdata state is valid at this point */
2376   DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2377 
2378   /* Error if the connection has closed without a close_notify.
2379 
2380      The behavior here is a matter of debate. We don't want to be vulnerable
2381      to a truncation attack however there's some browser precedent for
2382      ignoring the close_notify for compatibility reasons.
2383 
2384      Additionally, Windows 2000 (v5.0) is a special case since it seems it
2385      doesn't return close_notify. In that case if the connection was closed we
2386      assume it was graceful (close_notify) since there doesn't seem to be a
2387      way to tell.
2388   */
2389   if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2390      !backend->recv_sspi_close_notify) {
2391     bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2392                                                 VERSION_EQUAL);
2393 
2394     if(isWin2k && sspi_status == SEC_E_OK)
2395       backend->recv_sspi_close_notify = true;
2396     else {
2397       *err = CURLE_RECV_ERROR;
2398       infof(data, "schannel: server closed abruptly (missing close_notify)");
2399     }
2400   }
2401 
2402   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2403   if(*err && *err != CURLE_AGAIN)
2404     backend->recv_unrecoverable_err = *err;
2405 
2406   size = len < backend->decdata_offset ? len : backend->decdata_offset;
2407   if(size) {
2408     memcpy(buf, backend->decdata_buffer, size);
2409     memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2410             backend->decdata_offset - size);
2411     backend->decdata_offset -= size;
2412     DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2413     DEBUGF(infof(data,
2414                  "schannel: decrypted data buffer: offset %zu length %zu",
2415                  backend->decdata_offset, backend->decdata_length));
2416     *err = CURLE_OK;
2417     return (ssize_t)size;
2418   }
2419 
2420   if(!*err && !backend->recv_connection_closed)
2421     *err = CURLE_AGAIN;
2422 
2423   /* It's debatable what to return when !len. We could return whatever error
2424      we got from decryption but instead we override here so the return is
2425      consistent.
2426   */
2427   if(!len)
2428     *err = CURLE_OK;
2429 
2430   return *err ? -1 : 0;
2431 }
2432 
schannel_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)2433 static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
2434                                              struct Curl_easy *data,
2435                                              bool *done)
2436 {
2437   return schannel_connect_common(cf, data, TRUE, done);
2438 }
2439 
schannel_connect(struct Curl_cfilter * cf,struct Curl_easy * data)2440 static CURLcode schannel_connect(struct Curl_cfilter *cf,
2441                                  struct Curl_easy *data)
2442 {
2443   CURLcode result;
2444   bool done = FALSE;
2445 
2446   result = schannel_connect_common(cf, data, FALSE, &done);
2447   if(result)
2448     return result;
2449 
2450   DEBUGASSERT(done);
2451 
2452   return CURLE_OK;
2453 }
2454 
schannel_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)2455 static bool schannel_data_pending(struct Curl_cfilter *cf,
2456                                   const struct Curl_easy *data)
2457 {
2458   const struct ssl_connect_data *connssl = cf->ctx;
2459   struct schannel_ssl_backend_data *backend =
2460     (struct schannel_ssl_backend_data *)connssl->backend;
2461 
2462   (void)data;
2463   DEBUGASSERT(backend);
2464 
2465   if(backend->ctxt) /* SSL/TLS is in use */
2466     return (backend->decdata_offset > 0 ||
2467             (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
2468             backend->recv_connection_closed ||
2469             backend->recv_sspi_close_notify ||
2470             backend->recv_unrecoverable_err);
2471   else
2472     return FALSE;
2473 }
2474 
2475 /* shut down the SSL connection and clean up related memory.
2476    this function can be called multiple times on the same connection including
2477    if the SSL connection failed (eg connection made but failed handshake). */
schannel_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data)2478 static int schannel_shutdown(struct Curl_cfilter *cf,
2479                              struct Curl_easy *data)
2480 {
2481   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2482    * Shutting Down an Schannel Connection
2483    */
2484   struct ssl_connect_data *connssl = cf->ctx;
2485   struct schannel_ssl_backend_data *backend =
2486     (struct schannel_ssl_backend_data *)connssl->backend;
2487 
2488   DEBUGASSERT(data);
2489   DEBUGASSERT(backend);
2490 
2491   if(backend->ctxt) {
2492     infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
2493           connssl->peer.hostname, connssl->peer.port);
2494   }
2495 
2496   if(backend->cred && backend->ctxt) {
2497     SecBufferDesc BuffDesc;
2498     SecBuffer Buffer;
2499     SECURITY_STATUS sspi_status;
2500     SecBuffer outbuf;
2501     SecBufferDesc outbuf_desc;
2502     CURLcode result;
2503     DWORD dwshut = SCHANNEL_SHUTDOWN;
2504 
2505     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2506     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2507 
2508     sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2509                                               &BuffDesc);
2510 
2511     if(sspi_status != SEC_E_OK) {
2512       char buffer[STRERROR_LEN];
2513       failf(data, "schannel: ApplyControlToken failure: %s",
2514             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2515     }
2516 
2517     /* setup output buffer */
2518     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2519     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2520 
2521     sspi_status = s_pSecFn->InitializeSecurityContext(
2522       &backend->cred->cred_handle,
2523       &backend->ctxt->ctxt_handle,
2524       backend->cred->sni_hostname,
2525       backend->req_flags,
2526       0,
2527       0,
2528       NULL,
2529       0,
2530       &backend->ctxt->ctxt_handle,
2531       &outbuf_desc,
2532       &backend->ret_flags,
2533       &backend->ctxt->time_stamp);
2534 
2535     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2536       /* send close message which is in output buffer */
2537       ssize_t written = Curl_conn_cf_send(cf->next, data,
2538                                           outbuf.pvBuffer, outbuf.cbBuffer,
2539                                           &result);
2540       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2541       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2542         infof(data, "schannel: failed to send close msg: %s"
2543               " (bytes written: %zd)", curl_easy_strerror(result), written);
2544       }
2545     }
2546   }
2547 
2548   /* free SSPI Schannel API security context handle */
2549   if(backend->ctxt) {
2550     DEBUGF(infof(data, "schannel: clear security context handle"));
2551     s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2552     Curl_safefree(backend->ctxt);
2553   }
2554 
2555   /* free SSPI Schannel API credential handle */
2556   if(backend->cred) {
2557     Curl_ssl_sessionid_lock(data);
2558     schannel_session_free(backend->cred, 0);
2559     Curl_ssl_sessionid_unlock(data);
2560     backend->cred = NULL;
2561   }
2562 
2563   /* free internal buffer for received encrypted data */
2564   if(backend->encdata_buffer) {
2565     Curl_safefree(backend->encdata_buffer);
2566     backend->encdata_length = 0;
2567     backend->encdata_offset = 0;
2568     backend->encdata_is_incomplete = false;
2569   }
2570 
2571   /* free internal buffer for received decrypted data */
2572   if(backend->decdata_buffer) {
2573     Curl_safefree(backend->decdata_buffer);
2574     backend->decdata_length = 0;
2575     backend->decdata_offset = 0;
2576   }
2577 
2578   return CURLE_OK;
2579 }
2580 
schannel_close(struct Curl_cfilter * cf,struct Curl_easy * data)2581 static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2582 {
2583   schannel_shutdown(cf, data);
2584 }
2585 
schannel_init(void)2586 static int schannel_init(void)
2587 {
2588   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2589 }
2590 
schannel_cleanup(void)2591 static void schannel_cleanup(void)
2592 {
2593   Curl_sspi_global_cleanup();
2594 }
2595 
schannel_version(char * buffer,size_t size)2596 static size_t schannel_version(char *buffer, size_t size)
2597 {
2598   size = msnprintf(buffer, size, "Schannel");
2599 
2600   return size;
2601 }
2602 
schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2603 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2604                                 unsigned char *entropy, size_t length)
2605 {
2606   (void)data;
2607 
2608   return Curl_win32_random(entropy, length);
2609 }
2610 
schannel_pkp_pin_peer_pubkey(struct Curl_cfilter * cf,struct Curl_easy * data,const char * pinnedpubkey)2611 static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
2612                                              struct Curl_easy *data,
2613                                              const char *pinnedpubkey)
2614 {
2615   struct ssl_connect_data *connssl = cf->ctx;
2616   struct schannel_ssl_backend_data *backend =
2617     (struct schannel_ssl_backend_data *)connssl->backend;
2618   CERT_CONTEXT *pCertContextServer = NULL;
2619 
2620   /* Result is returned to caller */
2621   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2622 
2623   DEBUGASSERT(backend);
2624 
2625   /* if a path wasn't specified, don't pin */
2626   if(!pinnedpubkey)
2627     return CURLE_OK;
2628 
2629   do {
2630     SECURITY_STATUS sspi_status;
2631     const char *x509_der;
2632     DWORD x509_der_len;
2633     struct Curl_X509certificate x509_parsed;
2634     struct Curl_asn1Element *pubkey;
2635 
2636     sspi_status =
2637       s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2638                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2639                                        &pCertContextServer);
2640 
2641     if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2642       char buffer[STRERROR_LEN];
2643       failf(data, "schannel: Failed to read remote certificate context: %s",
2644             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2645       break; /* failed */
2646     }
2647 
2648 
2649     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2650          (pCertContextServer->cbCertEncoded > 0)))
2651       break;
2652 
2653     x509_der = (const char *)pCertContextServer->pbCertEncoded;
2654     x509_der_len = pCertContextServer->cbCertEncoded;
2655     memset(&x509_parsed, 0, sizeof(x509_parsed));
2656     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2657       break;
2658 
2659     pubkey = &x509_parsed.subjectPublicKeyInfo;
2660     if(!pubkey->header || pubkey->end <= pubkey->header) {
2661       failf(data, "SSL: failed retrieving public key from server certificate");
2662       break;
2663     }
2664 
2665     result = Curl_pin_peer_pubkey(data,
2666                                   pinnedpubkey,
2667                                   (const unsigned char *)pubkey->header,
2668                                   (size_t)(pubkey->end - pubkey->header));
2669     if(result) {
2670       failf(data, "SSL: public key does not match pinned public key");
2671     }
2672   } while(0);
2673 
2674   if(pCertContextServer)
2675     CertFreeCertificateContext(pCertContextServer);
2676 
2677   return result;
2678 }
2679 
schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2680 static void schannel_checksum(const unsigned char *input,
2681                               size_t inputlen,
2682                               unsigned char *checksum,
2683                               size_t checksumlen,
2684                               DWORD provType,
2685                               const unsigned int algId)
2686 {
2687   HCRYPTPROV hProv = 0;
2688   HCRYPTHASH hHash = 0;
2689   DWORD cbHashSize = 0;
2690   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2691   DWORD dwChecksumLen = (DWORD)checksumlen;
2692 
2693   /* since this can fail in multiple ways, zero memory first so we never
2694    * return old data
2695    */
2696   memset(checksum, 0, checksumlen);
2697 
2698   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2699                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2700     return; /* failed */
2701 
2702   do {
2703     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2704       break; /* failed */
2705 
2706     if(!CryptHashData(hHash, input, (DWORD)inputlen, 0))
2707       break; /* failed */
2708 
2709     /* get hash size */
2710     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2711                           &dwHashSizeLen, 0))
2712       break; /* failed */
2713 
2714     /* check hash size */
2715     if(checksumlen < cbHashSize)
2716       break; /* failed */
2717 
2718     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2719       break; /* failed */
2720   } while(0);
2721 
2722   if(hHash)
2723     CryptDestroyHash(hHash);
2724 
2725   if(hProv)
2726     CryptReleaseContext(hProv, 0);
2727 }
2728 
schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2729 static CURLcode schannel_sha256sum(const unsigned char *input,
2730                                    size_t inputlen,
2731                                    unsigned char *sha256sum,
2732                                    size_t sha256len)
2733 {
2734   schannel_checksum(input, inputlen, sha256sum, sha256len,
2735                     PROV_RSA_AES, CALG_SHA_256);
2736   return CURLE_OK;
2737 }
2738 
schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2739 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2740                                     CURLINFO info UNUSED_PARAM)
2741 {
2742   struct schannel_ssl_backend_data *backend =
2743     (struct schannel_ssl_backend_data *)connssl->backend;
2744   (void)info;
2745   DEBUGASSERT(backend);
2746   return &backend->ctxt->ctxt_handle;
2747 }
2748 
Curl_schannel_get_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data)2749 HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
2750                                                const struct Curl_easy *data)
2751 {
2752   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2753   struct Curl_multi *multi = data->multi;
2754   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2755   struct schannel_multi_ssl_backend_data *mbackend;
2756   const struct ssl_general_config *cfg = &data->set.general_ssl;
2757   timediff_t timeout_ms;
2758   timediff_t elapsed_ms;
2759   struct curltime now;
2760   unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];
2761 
2762   DEBUGASSERT(multi);
2763 
2764   if(!multi || !multi->ssl_backend_data) {
2765     return NULL;
2766   }
2767 
2768   mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
2769   if(!mbackend->cert_store) {
2770     return NULL;
2771   }
2772 
2773   /* zero ca_cache_timeout completely disables caching */
2774   if(!cfg->ca_cache_timeout) {
2775     return NULL;
2776   }
2777 
2778   /* check for cache timeout by using the cached_x509_store_expired timediff
2779      calculation pattern from openssl.c.
2780      negative timeout means retain forever. */
2781   timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
2782   if(timeout_ms >= 0) {
2783     now = Curl_now();
2784     elapsed_ms = Curl_timediff(now, mbackend->time);
2785     if(elapsed_ms >= timeout_ms) {
2786       return NULL;
2787     }
2788   }
2789 
2790   if(ca_info_blob) {
2791     if(!mbackend->CAinfo_blob_digest) {
2792       return NULL;
2793     }
2794     if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
2795       return NULL;
2796     }
2797     schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2798                        ca_info_blob->len,
2799                        info_blob_digest,
2800                        CURL_SHA256_DIGEST_LENGTH);
2801     if(memcmp(mbackend->CAinfo_blob_digest,
2802               info_blob_digest,
2803               CURL_SHA256_DIGEST_LENGTH)) {
2804         return NULL;
2805     }
2806   }
2807   else {
2808     if(!conn_config->CAfile || !mbackend->CAfile ||
2809        strcmp(mbackend->CAfile, conn_config->CAfile)) {
2810       return NULL;
2811     }
2812   }
2813 
2814   return mbackend->cert_store;
2815 }
2816 
Curl_schannel_set_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data,HCERTSTORE cert_store)2817 bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
2818                                          const struct Curl_easy *data,
2819                                          HCERTSTORE cert_store)
2820 {
2821   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2822   struct Curl_multi *multi = data->multi;
2823   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2824   struct schannel_multi_ssl_backend_data *mbackend;
2825   unsigned char *CAinfo_blob_digest = NULL;
2826   size_t CAinfo_blob_size = 0;
2827   char *CAfile = NULL;
2828 
2829   DEBUGASSERT(multi);
2830 
2831   if(!multi) {
2832     return false;
2833   }
2834 
2835   if(!multi->ssl_backend_data) {
2836     multi->ssl_backend_data =
2837       calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
2838     if(!multi->ssl_backend_data) {
2839       return false;
2840     }
2841   }
2842 
2843   mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
2844 
2845 
2846   if(ca_info_blob) {
2847     CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
2848     if(!CAinfo_blob_digest) {
2849       return false;
2850     }
2851     schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2852                        ca_info_blob->len,
2853                        CAinfo_blob_digest,
2854                        CURL_SHA256_DIGEST_LENGTH);
2855     CAinfo_blob_size = ca_info_blob->len;
2856   }
2857   else {
2858     if(conn_config->CAfile) {
2859       CAfile = strdup(conn_config->CAfile);
2860       if(!CAfile) {
2861         return false;
2862       }
2863     }
2864   }
2865 
2866   /* free old cache data */
2867   if(mbackend->cert_store) {
2868     CertCloseStore(mbackend->cert_store, 0);
2869   }
2870   free(mbackend->CAinfo_blob_digest);
2871   free(mbackend->CAfile);
2872 
2873   mbackend->time = Curl_now();
2874   mbackend->cert_store = cert_store;
2875   mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
2876   mbackend->CAinfo_blob_size = CAinfo_blob_size;
2877   mbackend->CAfile = CAfile;
2878   return true;
2879 }
2880 
schannel_free_multi_ssl_backend_data(struct multi_ssl_backend_data * msbd)2881 static void schannel_free_multi_ssl_backend_data(
2882   struct multi_ssl_backend_data *msbd)
2883 {
2884   struct schannel_multi_ssl_backend_data *mbackend =
2885     (struct schannel_multi_ssl_backend_data*)msbd;
2886   if(mbackend->cert_store) {
2887     CertCloseStore(mbackend->cert_store, 0);
2888   }
2889   free(mbackend->CAinfo_blob_digest);
2890   free(mbackend->CAfile);
2891   free(mbackend);
2892 }
2893 
2894 const struct Curl_ssl Curl_ssl_schannel = {
2895   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2896 
2897   SSLSUPP_CERTINFO |
2898 #ifdef HAS_MANUAL_VERIFY_API
2899   SSLSUPP_CAINFO_BLOB |
2900 #endif
2901   SSLSUPP_PINNEDPUBKEY |
2902   SSLSUPP_TLS13_CIPHERSUITES |
2903   SSLSUPP_HTTPS_PROXY,
2904 
2905   sizeof(struct schannel_ssl_backend_data),
2906 
2907   schannel_init,                     /* init */
2908   schannel_cleanup,                  /* cleanup */
2909   schannel_version,                  /* version */
2910   Curl_none_check_cxn,               /* check_cxn */
2911   schannel_shutdown,                 /* shutdown */
2912   schannel_data_pending,             /* data_pending */
2913   schannel_random,                   /* random */
2914   Curl_none_cert_status_request,     /* cert_status_request */
2915   schannel_connect,                  /* connect */
2916   schannel_connect_nonblocking,      /* connect_nonblocking */
2917   Curl_ssl_adjust_pollset,           /* adjust_pollset */
2918   schannel_get_internals,            /* get_internals */
2919   schannel_close,                    /* close_one */
2920   Curl_none_close_all,               /* close_all */
2921   Curl_none_set_engine,              /* set_engine */
2922   Curl_none_set_engine_default,      /* set_engine_default */
2923   Curl_none_engines_list,            /* engines_list */
2924   Curl_none_false_start,             /* false_start */
2925   schannel_sha256sum,                /* sha256sum */
2926   NULL,                              /* associate_connection */
2927   NULL,                              /* disassociate_connection */
2928   schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
2929   schannel_recv,                     /* recv decrypted data */
2930   schannel_send,                     /* send data to encrypt */
2931 };
2932 
2933 #endif /* USE_SCHANNEL */
2934