xref: /curl/lib/vtls/schannel.c (revision bc2f72b9)
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 "cannot 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 = (long)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_ID)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 = (DWORD)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 &= ~(DWORD)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 = (DWORD)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       Curl_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        does not 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       Curl_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 does not 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 does not seem to work right; we will
1099    * do it following a more manual process. */
1100   backend->use_manual_cred_validation = true;
1101 #else
1102 #error "compiler too old to support Windows CE requisite manual cert verify"
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.cache_session) {
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 do not pass inbuf unless we are 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 = Curl_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, FALSE,
1291                               &result);
1292   Curl_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->io_need & CURL_SSL_IO_NEED_SEND) ? FALSE : TRUE;
1336   connssl->io_need = CURL_SSL_IO_NEED_NONE;
1337 
1338   DEBUGF(infof(data,
1339                "schannel: SSL/TLS connection with %s port %d (step 2/3)",
1340                connssl->peer.hostname, connssl->peer.port));
1341 
1342   if(!backend->cred || !backend->ctxt)
1343     return CURLE_SSL_CONNECT_ERROR;
1344 
1345   /* buffer to store previously received and decrypted data */
1346   if(!backend->decdata_buffer) {
1347     backend->decdata_offset = 0;
1348     backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1349     backend->decdata_buffer = malloc(backend->decdata_length);
1350     if(!backend->decdata_buffer) {
1351       failf(data, "schannel: unable to allocate memory");
1352       return CURLE_OUT_OF_MEMORY;
1353     }
1354   }
1355 
1356   /* buffer to store previously received and encrypted data */
1357   if(!backend->encdata_buffer) {
1358     backend->encdata_is_incomplete = false;
1359     backend->encdata_offset = 0;
1360     backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1361     backend->encdata_buffer = malloc(backend->encdata_length);
1362     if(!backend->encdata_buffer) {
1363       failf(data, "schannel: unable to allocate memory");
1364       return CURLE_OUT_OF_MEMORY;
1365     }
1366   }
1367 
1368   /* if we need a bigger buffer to read a full message, increase buffer now */
1369   if(backend->encdata_length - backend->encdata_offset <
1370      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1371     /* increase internal encrypted data buffer */
1372     size_t reallocated_length = backend->encdata_offset +
1373       CURL_SCHANNEL_BUFFER_FREE_SIZE;
1374     reallocated_buffer = realloc(backend->encdata_buffer,
1375                                  reallocated_length);
1376 
1377     if(!reallocated_buffer) {
1378       failf(data, "schannel: unable to re-allocate memory");
1379       return CURLE_OUT_OF_MEMORY;
1380     }
1381     else {
1382       backend->encdata_buffer = reallocated_buffer;
1383       backend->encdata_length = reallocated_length;
1384     }
1385   }
1386 
1387   for(;;) {
1388     if(doread) {
1389       /* read encrypted handshake data from socket */
1390       nread = Curl_conn_cf_recv(cf->next, data,
1391                                (char *) (backend->encdata_buffer +
1392                                          backend->encdata_offset),
1393                                backend->encdata_length -
1394                                backend->encdata_offset,
1395                                &result);
1396       if(result == CURLE_AGAIN) {
1397         connssl->io_need = CURL_SSL_IO_NEED_RECV;
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 = Curl_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->io_need = CURL_SSL_IO_NEED_RECV;
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->io_need = CURL_SSL_IO_NEED_SEND;
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                                       FALSE, &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           Curl_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 are 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->io_need = CURL_SSL_IO_NEED_RECV;
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 will not 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       Curl_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       Curl_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.cache_session) {
1776     Curl_ssl_sessionid_lock(data);
1777     /* Up ref count since call takes ownership */
1778     backend->cred->refcount++;
1779     result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
1780                                     sizeof(struct Curl_schannel_cred),
1781                                     schannel_session_free);
1782     Curl_ssl_sessionid_unlock(data);
1783     if(result)
1784       return result;
1785   }
1786 
1787   if(data->set.ssl.certinfo) {
1788     int certs_count = 0;
1789     sspi_status =
1790       Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
1791                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1792                                        &ccert_context);
1793 
1794     if((sspi_status != SEC_E_OK) || !ccert_context) {
1795       failf(data, "schannel: failed to retrieve remote cert context");
1796       return CURLE_PEER_FAILED_VERIFICATION;
1797     }
1798 
1799     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1800 
1801     result = Curl_ssl_init_certinfo(data, certs_count);
1802     if(!result) {
1803       struct Adder_args args;
1804       args.data = data;
1805       args.idx = 0;
1806       args.certs_count = certs_count;
1807       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1808       result = args.result;
1809     }
1810     CertFreeCertificateContext(ccert_context);
1811     if(result)
1812       return result;
1813   }
1814 
1815   connssl->connecting_state = ssl_connect_done;
1816 
1817   return CURLE_OK;
1818 }
1819 
1820 static CURLcode
schannel_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool nonblocking,bool * done)1821 schannel_connect_common(struct Curl_cfilter *cf,
1822                         struct Curl_easy *data,
1823                         bool nonblocking, bool *done)
1824 {
1825   CURLcode result;
1826   struct ssl_connect_data *connssl = cf->ctx;
1827   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1828   timediff_t timeout_ms;
1829   int what;
1830 
1831   /* check if the connection has already been established */
1832   if(ssl_connection_complete == connssl->state) {
1833     *done = TRUE;
1834     return CURLE_OK;
1835   }
1836 
1837   if(ssl_connect_1 == connssl->connecting_state) {
1838     /* check out how much more time we are allowed */
1839     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1840 
1841     if(timeout_ms < 0) {
1842       /* no need to continue if time already is up */
1843       failf(data, "SSL/TLS connection timeout");
1844       return CURLE_OPERATION_TIMEDOUT;
1845     }
1846 
1847     result = schannel_connect_step1(cf, data);
1848     if(result)
1849       return result;
1850   }
1851 
1852   while(ssl_connect_2 == connssl->connecting_state) {
1853 
1854     /* check out how much more time we are allowed */
1855     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1856 
1857     if(timeout_ms < 0) {
1858       /* no need to continue if time already is up */
1859       failf(data, "SSL/TLS connection timeout");
1860       return CURLE_OPERATION_TIMEDOUT;
1861     }
1862 
1863     /* if ssl is expecting something, check if it is available. */
1864     if(connssl->io_need) {
1865 
1866       curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
1867         sockfd : CURL_SOCKET_BAD;
1868       curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
1869         sockfd : CURL_SOCKET_BAD;
1870 
1871       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1872                                nonblocking ? 0 : timeout_ms);
1873       if(what < 0) {
1874         /* fatal error */
1875         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1876         return CURLE_SSL_CONNECT_ERROR;
1877       }
1878       else if(0 == what) {
1879         if(nonblocking) {
1880           *done = FALSE;
1881           return CURLE_OK;
1882         }
1883         else {
1884           /* timeout */
1885           failf(data, "SSL/TLS connection timeout");
1886           return CURLE_OPERATION_TIMEDOUT;
1887         }
1888       }
1889       /* socket is readable or writable */
1890     }
1891 
1892     /* Run transaction, and return to the caller if it failed or if
1893      * this connection is part of a multi handle and this loop would
1894      * execute again. This permits the owner of a multi handle to
1895      * abort a connection attempt before step2 has completed while
1896      * ensuring that a client using select() or epoll() will always
1897      * have a valid fdset to wait on.
1898      */
1899     result = schannel_connect_step2(cf, data);
1900     if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
1901       return result;
1902 
1903   } /* repeat step2 until all transactions are done. */
1904 
1905   if(ssl_connect_3 == connssl->connecting_state) {
1906     result = schannel_connect_step3(cf, data);
1907     if(result)
1908       return result;
1909   }
1910 
1911   if(ssl_connect_done == connssl->connecting_state) {
1912     connssl->state = ssl_connection_complete;
1913 
1914 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1915     /* When SSPI is used in combination with Schannel
1916      * we need the Schannel context to create the Schannel
1917      * binding to pass the IIS extended protection checks.
1918      * Available on Windows 7 or later.
1919      */
1920     {
1921       struct schannel_ssl_backend_data *backend =
1922         (struct schannel_ssl_backend_data *)connssl->backend;
1923       DEBUGASSERT(backend);
1924       cf->conn->sslContext = &backend->ctxt->ctxt_handle;
1925     }
1926 #endif
1927 
1928     *done = TRUE;
1929   }
1930   else
1931     *done = FALSE;
1932 
1933   /* reset our connection state machine */
1934   connssl->connecting_state = ssl_connect_1;
1935 
1936   return CURLE_OK;
1937 }
1938 
1939 static ssize_t
schannel_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1940 schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1941               const void *buf, size_t len, CURLcode *err)
1942 {
1943   ssize_t written = -1;
1944   size_t data_len = 0;
1945   unsigned char *ptr = NULL;
1946   struct ssl_connect_data *connssl = cf->ctx;
1947   SecBuffer outbuf[4];
1948   SecBufferDesc outbuf_desc;
1949   SECURITY_STATUS sspi_status = SEC_E_OK;
1950   CURLcode result;
1951   struct schannel_ssl_backend_data *backend =
1952     (struct schannel_ssl_backend_data *)connssl->backend;
1953 
1954   DEBUGASSERT(backend);
1955 
1956   /* check if the maximum stream sizes were queried */
1957   if(backend->stream_sizes.cbMaximumMessage == 0) {
1958     sspi_status = Curl_pSecFn->QueryContextAttributes(
1959       &backend->ctxt->ctxt_handle,
1960       SECPKG_ATTR_STREAM_SIZES,
1961       &backend->stream_sizes);
1962     if(sspi_status != SEC_E_OK) {
1963       *err = CURLE_SEND_ERROR;
1964       return -1;
1965     }
1966   }
1967 
1968   /* check if the buffer is longer than the maximum message length */
1969   if(len > backend->stream_sizes.cbMaximumMessage) {
1970     len = backend->stream_sizes.cbMaximumMessage;
1971   }
1972 
1973   /* calculate the complete message length and allocate a buffer for it */
1974   data_len = backend->stream_sizes.cbHeader + len +
1975     backend->stream_sizes.cbTrailer;
1976   ptr = (unsigned char *) malloc(data_len);
1977   if(!ptr) {
1978     *err = CURLE_OUT_OF_MEMORY;
1979     return -1;
1980   }
1981 
1982   /* setup output buffers (header, data, trailer, empty) */
1983   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1984                 ptr, backend->stream_sizes.cbHeader);
1985   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1986                 ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
1987   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1988                 ptr + backend->stream_sizes.cbHeader + len,
1989                 backend->stream_sizes.cbTrailer);
1990   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1991   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1992 
1993   /* copy data into output buffer */
1994   memcpy(outbuf[1].pvBuffer, buf, len);
1995 
1996   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1997   sspi_status = Curl_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
1998                                          &outbuf_desc, 0);
1999 
2000   /* check if the message was encrypted */
2001   if(sspi_status == SEC_E_OK) {
2002     written = 0;
2003 
2004     /* send the encrypted message including header, data and trailer */
2005     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
2006 
2007     /*
2008       it is important to send the full message which includes the header,
2009       encrypted payload, and trailer. Until the client receives all the
2010       data a coherent message has not been delivered and the client
2011       cannot read any of it.
2012 
2013       If we wanted to buffer the unwritten encrypted bytes, we would
2014       tell the client that all data it has requested to be sent has been
2015       sent. The unwritten encrypted bytes would be the first bytes to
2016       send on the next invocation.
2017       Here's the catch with this - if we tell the client that all the
2018       bytes have been sent, will the client call this method again to
2019       send the buffered data?  Looking at who calls this function, it
2020       seems the answer is NO.
2021     */
2022 
2023     /* send entire message or fail */
2024     while(len > (size_t)written) {
2025       ssize_t this_write = 0;
2026       int what;
2027       timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
2028       if(timeout_ms < 0) {
2029         /* we already got the timeout */
2030         failf(data, "schannel: timed out sending data "
2031               "(bytes sent: %zd)", written);
2032         *err = CURLE_OPERATION_TIMEDOUT;
2033         written = -1;
2034         break;
2035       }
2036       else if(!timeout_ms)
2037         timeout_ms = TIMEDIFF_T_MAX;
2038       what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms);
2039       if(what < 0) {
2040         /* fatal error */
2041         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2042         *err = CURLE_SEND_ERROR;
2043         written = -1;
2044         break;
2045       }
2046       else if(0 == what) {
2047         failf(data, "schannel: timed out sending data "
2048               "(bytes sent: %zd)", written);
2049         *err = CURLE_OPERATION_TIMEDOUT;
2050         written = -1;
2051         break;
2052       }
2053       /* socket is writable */
2054 
2055        this_write = Curl_conn_cf_send(cf->next, data,
2056                                       ptr + written, len - written,
2057                                       FALSE, &result);
2058       if(result == CURLE_AGAIN)
2059         continue;
2060       else if(result != CURLE_OK) {
2061         *err = result;
2062         written = -1;
2063         break;
2064       }
2065 
2066       written += this_write;
2067     }
2068   }
2069   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
2070     *err = CURLE_OUT_OF_MEMORY;
2071   }
2072   else{
2073     *err = CURLE_SEND_ERROR;
2074   }
2075 
2076   Curl_safefree(ptr);
2077 
2078   if(len == (size_t)written)
2079     /* Encrypted message including header, data and trailer entirely sent.
2080        The return value is the number of unencrypted bytes that were sent. */
2081     written = outbuf[1].cbBuffer;
2082 
2083   return written;
2084 }
2085 
2086 static ssize_t
schannel_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)2087 schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
2088               char *buf, size_t len, CURLcode *err)
2089 {
2090   size_t size = 0;
2091   ssize_t nread = -1;
2092   struct ssl_connect_data *connssl = cf->ctx;
2093   unsigned char *reallocated_buffer;
2094   size_t reallocated_length;
2095   bool done = FALSE;
2096   SecBuffer inbuf[4];
2097   SecBufferDesc inbuf_desc;
2098   SECURITY_STATUS sspi_status = SEC_E_OK;
2099   /* we want the length of the encrypted buffer to be at least large enough
2100      that it can hold all the bytes requested and some TLS record overhead. */
2101   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
2102   struct schannel_ssl_backend_data *backend =
2103     (struct schannel_ssl_backend_data *)connssl->backend;
2104 
2105   DEBUGASSERT(backend);
2106 
2107   /****************************************************************************
2108    * Do not return or set backend->recv_unrecoverable_err unless in the
2109    * cleanup. The pattern for return error is set *err, optional infof, goto
2110    * cleanup.
2111    *
2112    * Our priority is to always return as much decrypted data to the caller as
2113    * possible, even if an error occurs. The state of the decrypted buffer must
2114    * always be valid. Transfer of decrypted data to the caller's buffer is
2115    * handled in the cleanup.
2116    */
2117 
2118   DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
2119   *err = CURLE_OK;
2120 
2121   if(len && len <= backend->decdata_offset) {
2122     infof(data, "schannel: enough decrypted data is already available");
2123     goto cleanup;
2124   }
2125   else if(backend->recv_unrecoverable_err) {
2126     *err = backend->recv_unrecoverable_err;
2127     infof(data, "schannel: an unrecoverable error occurred in a prior call");
2128     goto cleanup;
2129   }
2130   else if(backend->recv_sspi_close_notify) {
2131     /* once a server has indicated shutdown there is no more encrypted data */
2132     infof(data, "schannel: server indicated shutdown in a prior call");
2133     goto cleanup;
2134   }
2135   /* it is debatable what to return when !len. Regardless we cannot return
2136      immediately because there may be data to decrypt (in the case we want to
2137      decrypt all encrypted cached data) so handle !len later in cleanup.
2138   */
2139   else if(len && !backend->recv_connection_closed) {
2140     /* increase enc buffer in order to fit the requested amount of data */
2141     size = backend->encdata_length - backend->encdata_offset;
2142     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2143        backend->encdata_length < min_encdata_length) {
2144       reallocated_length = backend->encdata_offset +
2145         CURL_SCHANNEL_BUFFER_FREE_SIZE;
2146       if(reallocated_length < min_encdata_length) {
2147         reallocated_length = min_encdata_length;
2148       }
2149       reallocated_buffer = realloc(backend->encdata_buffer,
2150                                    reallocated_length);
2151       if(!reallocated_buffer) {
2152         *err = CURLE_OUT_OF_MEMORY;
2153         failf(data, "schannel: unable to re-allocate memory");
2154         goto cleanup;
2155       }
2156 
2157       backend->encdata_buffer = reallocated_buffer;
2158       backend->encdata_length = reallocated_length;
2159       size = backend->encdata_length - backend->encdata_offset;
2160       DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
2161                    backend->encdata_length));
2162     }
2163 
2164     DEBUGF(infof(data,
2165                  "schannel: encrypted data buffer: offset %zu length %zu",
2166                  backend->encdata_offset, backend->encdata_length));
2167 
2168     /* read encrypted data from socket */
2169     nread = Curl_conn_cf_recv(cf->next, data,
2170                               (char *)(backend->encdata_buffer +
2171                                     backend->encdata_offset),
2172                               size, err);
2173     if(*err) {
2174       nread = -1;
2175       if(*err == CURLE_AGAIN)
2176         DEBUGF(infof(data,
2177                      "schannel: recv returned CURLE_AGAIN"));
2178       else if(*err == CURLE_RECV_ERROR)
2179         infof(data, "schannel: recv returned CURLE_RECV_ERROR");
2180       else
2181         infof(data, "schannel: recv returned error %d", *err);
2182     }
2183     else if(nread == 0) {
2184       backend->recv_connection_closed = true;
2185       DEBUGF(infof(data, "schannel: server closed the connection"));
2186     }
2187     else if(nread > 0) {
2188       backend->encdata_offset += (size_t)nread;
2189       backend->encdata_is_incomplete = false;
2190       DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
2191     }
2192   }
2193 
2194   DEBUGF(infof(data,
2195                "schannel: encrypted data buffer: offset %zu length %zu",
2196                backend->encdata_offset, backend->encdata_length));
2197 
2198   /* decrypt loop */
2199   while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
2200         (!len || backend->decdata_offset < len ||
2201          backend->recv_connection_closed)) {
2202     /* prepare data buffer for DecryptMessage call */
2203     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
2204                   curlx_uztoul(backend->encdata_offset));
2205 
2206     /* we need 3 more empty input buffers for possible output */
2207     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
2208     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
2209     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
2210     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
2211 
2212     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
2213      */
2214     sspi_status = Curl_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
2215                                            &inbuf_desc, 0, NULL);
2216 
2217     /* check if everything went fine (server may want to renegotiate
2218        or shutdown the connection context) */
2219     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
2220        sspi_status == SEC_I_CONTEXT_EXPIRED) {
2221       /* check for successfully decrypted data, even before actual
2222          renegotiation or shutdown of the connection context */
2223       if(inbuf[1].BufferType == SECBUFFER_DATA) {
2224         DEBUGF(infof(data, "schannel: decrypted data length: %lu",
2225                      inbuf[1].cbBuffer));
2226 
2227         /* increase buffer in order to fit the received amount of data */
2228         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
2229           inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
2230         if(backend->decdata_length - backend->decdata_offset < size ||
2231            backend->decdata_length < len) {
2232           /* increase internal decrypted data buffer */
2233           reallocated_length = backend->decdata_offset + size;
2234           /* make sure that the requested amount of data fits */
2235           if(reallocated_length < len) {
2236             reallocated_length = len;
2237           }
2238           reallocated_buffer = realloc(backend->decdata_buffer,
2239                                        reallocated_length);
2240           if(!reallocated_buffer) {
2241             *err = CURLE_OUT_OF_MEMORY;
2242             failf(data, "schannel: unable to re-allocate memory");
2243             goto cleanup;
2244           }
2245           backend->decdata_buffer = reallocated_buffer;
2246           backend->decdata_length = reallocated_length;
2247         }
2248 
2249         /* copy decrypted data to internal buffer */
2250         size = inbuf[1].cbBuffer;
2251         if(size) {
2252           memcpy(backend->decdata_buffer + backend->decdata_offset,
2253                  inbuf[1].pvBuffer, size);
2254           backend->decdata_offset += size;
2255         }
2256 
2257         DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
2258         DEBUGF(infof(data,
2259                      "schannel: decrypted cached: offset %zu length %zu",
2260                      backend->decdata_offset, backend->decdata_length));
2261       }
2262 
2263       /* check for remaining encrypted data */
2264       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
2265         DEBUGF(infof(data, "schannel: encrypted data length: %lu",
2266                      inbuf[3].cbBuffer));
2267 
2268         /* check if the remaining data is less than the total amount
2269          * and therefore begins after the already processed data
2270          */
2271         if(backend->encdata_offset > inbuf[3].cbBuffer) {
2272           /* move remaining encrypted data forward to the beginning of
2273              buffer */
2274           memmove(backend->encdata_buffer,
2275                   (backend->encdata_buffer + backend->encdata_offset) -
2276                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
2277           backend->encdata_offset = inbuf[3].cbBuffer;
2278         }
2279 
2280         DEBUGF(infof(data,
2281                      "schannel: encrypted cached: offset %zu length %zu",
2282                      backend->encdata_offset, backend->encdata_length));
2283       }
2284       else {
2285         /* reset encrypted buffer offset, because there is no data remaining */
2286         backend->encdata_offset = 0;
2287       }
2288 
2289       /* check if server wants to renegotiate the connection context */
2290       if(sspi_status == SEC_I_RENEGOTIATE) {
2291         infof(data, "schannel: remote party requests renegotiation");
2292         if(*err && *err != CURLE_AGAIN) {
2293           infof(data, "schannel: cannot renegotiate, an error is pending");
2294           goto cleanup;
2295         }
2296 
2297         /* begin renegotiation */
2298         infof(data, "schannel: renegotiating SSL/TLS connection");
2299         connssl->state = ssl_connection_negotiating;
2300         connssl->connecting_state = ssl_connect_2;
2301         connssl->io_need = CURL_SSL_IO_NEED_SEND;
2302         backend->recv_renegotiating = true;
2303         *err = schannel_connect_common(cf, data, FALSE, &done);
2304         backend->recv_renegotiating = false;
2305         if(*err) {
2306           infof(data, "schannel: renegotiation failed");
2307           goto cleanup;
2308         }
2309         /* now retry receiving data */
2310         sspi_status = SEC_E_OK;
2311         infof(data, "schannel: SSL/TLS connection renegotiated");
2312         continue;
2313       }
2314       /* check if the server closed the connection */
2315       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
2316         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
2317            returned so we have to work around that in cleanup. */
2318         backend->recv_sspi_close_notify = true;
2319         if(!backend->recv_connection_closed)
2320           backend->recv_connection_closed = true;
2321         infof(data,
2322               "schannel: server close notification received (close_notify)");
2323         goto cleanup;
2324       }
2325     }
2326     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2327       backend->encdata_is_incomplete = true;
2328       if(!*err)
2329         *err = CURLE_AGAIN;
2330       infof(data, "schannel: failed to decrypt data, need more data");
2331       goto cleanup;
2332     }
2333     else {
2334 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2335       char buffer[STRERROR_LEN];
2336       infof(data, "schannel: failed to read data from server: %s",
2337             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2338 #endif
2339       *err = CURLE_RECV_ERROR;
2340       goto cleanup;
2341     }
2342   }
2343 
2344   DEBUGF(infof(data,
2345                "schannel: encrypted data buffer: offset %zu length %zu",
2346                backend->encdata_offset, backend->encdata_length));
2347 
2348   DEBUGF(infof(data,
2349                "schannel: decrypted data buffer: offset %zu length %zu",
2350                backend->decdata_offset, backend->decdata_length));
2351 
2352 cleanup:
2353   /* Warning- there is no guarantee the encdata state is valid at this point */
2354   DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2355 
2356   /* Error if the connection has closed without a close_notify.
2357 
2358      The behavior here is a matter of debate. We do not want to be vulnerable
2359      to a truncation attack however there is some browser precedent for
2360      ignoring the close_notify for compatibility reasons.
2361 
2362      Additionally, Windows 2000 (v5.0) is a special case since it seems it
2363      does not return close_notify. In that case if the connection was closed we
2364      assume it was graceful (close_notify) since there does not seem to be a
2365      way to tell.
2366   */
2367   if(len && !backend->decdata_offset && backend->recv_connection_closed &&
2368      !backend->recv_sspi_close_notify) {
2369     bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
2370                                                 VERSION_EQUAL);
2371 
2372     if(isWin2k && sspi_status == SEC_E_OK)
2373       backend->recv_sspi_close_notify = true;
2374     else {
2375       *err = CURLE_RECV_ERROR;
2376       infof(data, "schannel: server closed abruptly (missing close_notify)");
2377     }
2378   }
2379 
2380   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2381   if(*err && *err != CURLE_AGAIN)
2382     backend->recv_unrecoverable_err = *err;
2383 
2384   size = len < backend->decdata_offset ? len : backend->decdata_offset;
2385   if(size) {
2386     memcpy(buf, backend->decdata_buffer, size);
2387     memmove(backend->decdata_buffer, backend->decdata_buffer + size,
2388             backend->decdata_offset - size);
2389     backend->decdata_offset -= size;
2390     DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2391     DEBUGF(infof(data,
2392                  "schannel: decrypted data buffer: offset %zu length %zu",
2393                  backend->decdata_offset, backend->decdata_length));
2394     *err = CURLE_OK;
2395     return (ssize_t)size;
2396   }
2397 
2398   if(!*err && !backend->recv_connection_closed)
2399     *err = CURLE_AGAIN;
2400 
2401   /* it is debatable what to return when !len. We could return whatever error
2402      we got from decryption but instead we override here so the return is
2403      consistent.
2404   */
2405   if(!len)
2406     *err = CURLE_OK;
2407 
2408   return *err ? -1 : 0;
2409 }
2410 
schannel_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)2411 static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
2412                                              struct Curl_easy *data,
2413                                              bool *done)
2414 {
2415   return schannel_connect_common(cf, data, TRUE, done);
2416 }
2417 
schannel_connect(struct Curl_cfilter * cf,struct Curl_easy * data)2418 static CURLcode schannel_connect(struct Curl_cfilter *cf,
2419                                  struct Curl_easy *data)
2420 {
2421   CURLcode result;
2422   bool done = FALSE;
2423 
2424   result = schannel_connect_common(cf, data, FALSE, &done);
2425   if(result)
2426     return result;
2427 
2428   DEBUGASSERT(done);
2429 
2430   return CURLE_OK;
2431 }
2432 
schannel_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)2433 static bool schannel_data_pending(struct Curl_cfilter *cf,
2434                                   const struct Curl_easy *data)
2435 {
2436   const struct ssl_connect_data *connssl = cf->ctx;
2437   struct schannel_ssl_backend_data *backend =
2438     (struct schannel_ssl_backend_data *)connssl->backend;
2439 
2440   (void)data;
2441   DEBUGASSERT(backend);
2442 
2443   if(backend->ctxt) /* SSL/TLS is in use */
2444     return (backend->decdata_offset > 0 ||
2445             (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
2446             backend->recv_connection_closed ||
2447             backend->recv_sspi_close_notify ||
2448             backend->recv_unrecoverable_err);
2449   else
2450     return FALSE;
2451 }
2452 
2453 /* shut down the SSL connection and clean up related memory.
2454    this function can be called multiple times on the same connection including
2455    if the SSL connection failed (eg connection made but failed handshake). */
schannel_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool send_shutdown,bool * done)2456 static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
2457                                   struct Curl_easy *data,
2458                                   bool send_shutdown, bool *done)
2459 {
2460   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2461    * Shutting Down an Schannel Connection
2462    */
2463   struct ssl_connect_data *connssl = cf->ctx;
2464   struct schannel_ssl_backend_data *backend =
2465     (struct schannel_ssl_backend_data *)connssl->backend;
2466   CURLcode result = CURLE_OK;
2467 
2468   if(cf->shutdown) {
2469     *done = TRUE;
2470     return CURLE_OK;
2471   }
2472 
2473   DEBUGASSERT(data);
2474   DEBUGASSERT(backend);
2475 
2476   /* Not supported in schannel */
2477   (void)send_shutdown;
2478 
2479   *done = FALSE;
2480   if(backend->ctxt) {
2481     infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
2482           connssl->peer.hostname, connssl->peer.port);
2483   }
2484 
2485   if(!backend->ctxt || cf->shutdown) {
2486     *done = TRUE;
2487     goto out;
2488   }
2489 
2490   if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
2491     SecBufferDesc BuffDesc;
2492     SecBuffer Buffer;
2493     SECURITY_STATUS sspi_status;
2494     SecBuffer outbuf;
2495     SecBufferDesc outbuf_desc;
2496     DWORD dwshut = SCHANNEL_SHUTDOWN;
2497 
2498     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2499     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2500 
2501     sspi_status = Curl_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
2502                                               &BuffDesc);
2503 
2504     if(sspi_status != SEC_E_OK) {
2505       char buffer[STRERROR_LEN];
2506       failf(data, "schannel: ApplyControlToken failure: %s",
2507             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2508       result = CURLE_SEND_ERROR;
2509       goto out;
2510     }
2511 
2512     /* setup output buffer */
2513     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2514     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2515 
2516     sspi_status = Curl_pSecFn->InitializeSecurityContext(
2517       &backend->cred->cred_handle,
2518       &backend->ctxt->ctxt_handle,
2519       backend->cred->sni_hostname,
2520       backend->req_flags,
2521       0,
2522       0,
2523       NULL,
2524       0,
2525       &backend->ctxt->ctxt_handle,
2526       &outbuf_desc,
2527       &backend->ret_flags,
2528       &backend->ctxt->time_stamp);
2529 
2530     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2531       /* send close message which is in output buffer */
2532       ssize_t written = Curl_conn_cf_send(cf->next, data,
2533                                           outbuf.pvBuffer, outbuf.cbBuffer,
2534                                           FALSE, &result);
2535       Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2536       if(!result) {
2537         if(written < (ssize_t)outbuf.cbBuffer) {
2538           /* TODO: handle partial sends */
2539           infof(data, "schannel: failed to send close msg: %s"
2540                 " (bytes written: %zd)", curl_easy_strerror(result), written);
2541           result = CURLE_SEND_ERROR;
2542           goto out;
2543         }
2544         backend->sent_shutdown = TRUE;
2545         *done = TRUE;
2546       }
2547       else if(result == CURLE_AGAIN) {
2548         connssl->io_need = CURL_SSL_IO_NEED_SEND;
2549         result = CURLE_OK;
2550         goto out;
2551       }
2552       else {
2553         if(!backend->recv_connection_closed) {
2554           infof(data, "schannel: error sending close msg: %d", result);
2555           result = CURLE_SEND_ERROR;
2556           goto out;
2557         }
2558         /* Looks like server already closed the connection.
2559          * An error to send our close notify is not a failure. */
2560         *done = TRUE;
2561         result = CURLE_OK;
2562       }
2563     }
2564   }
2565 
2566   /* If the connection seems open and we have not seen the close notify
2567    * from the server yet, try to receive it. */
2568   if(backend->cred && backend->ctxt &&
2569      !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
2570     char buffer[1024];
2571     ssize_t nread;
2572 
2573     nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
2574     if(nread > 0) {
2575       /* still data coming in? */
2576     }
2577     else if(nread == 0) {
2578       /* We got the close notify alert and are done. */
2579       backend->recv_connection_closed = TRUE;
2580       *done = TRUE;
2581     }
2582     else if(nread < 0 && result == CURLE_AGAIN) {
2583       connssl->io_need = CURL_SSL_IO_NEED_RECV;
2584     }
2585     else {
2586       CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
2587       result = CURLE_RECV_ERROR;
2588     }
2589   }
2590 
2591 out:
2592   cf->shutdown = (result || *done);
2593   return result;
2594 }
2595 
schannel_close(struct Curl_cfilter * cf,struct Curl_easy * data)2596 static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2597 {
2598   struct ssl_connect_data *connssl = cf->ctx;
2599   struct schannel_ssl_backend_data *backend =
2600     (struct schannel_ssl_backend_data *)connssl->backend;
2601 
2602   DEBUGASSERT(data);
2603   DEBUGASSERT(backend);
2604 
2605   /* free SSPI Schannel API security context handle */
2606   if(backend->ctxt) {
2607     DEBUGF(infof(data, "schannel: clear security context handle"));
2608     Curl_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
2609     Curl_safefree(backend->ctxt);
2610   }
2611 
2612   /* free SSPI Schannel API credential handle */
2613   if(backend->cred) {
2614     Curl_ssl_sessionid_lock(data);
2615     schannel_session_free(backend->cred, 0);
2616     Curl_ssl_sessionid_unlock(data);
2617     backend->cred = NULL;
2618   }
2619 
2620   /* free internal buffer for received encrypted data */
2621   if(backend->encdata_buffer) {
2622     Curl_safefree(backend->encdata_buffer);
2623     backend->encdata_length = 0;
2624     backend->encdata_offset = 0;
2625     backend->encdata_is_incomplete = false;
2626   }
2627 
2628   /* free internal buffer for received decrypted data */
2629   if(backend->decdata_buffer) {
2630     Curl_safefree(backend->decdata_buffer);
2631     backend->decdata_length = 0;
2632     backend->decdata_offset = 0;
2633   }
2634 }
2635 
schannel_init(void)2636 static int schannel_init(void)
2637 {
2638   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2639 }
2640 
schannel_cleanup(void)2641 static void schannel_cleanup(void)
2642 {
2643   Curl_sspi_global_cleanup();
2644 }
2645 
schannel_version(char * buffer,size_t size)2646 static size_t schannel_version(char *buffer, size_t size)
2647 {
2648   return msnprintf(buffer, size, "Schannel");
2649 }
2650 
schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2651 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2652                                 unsigned char *entropy, size_t length)
2653 {
2654   (void)data;
2655 
2656   return Curl_win32_random(entropy, length);
2657 }
2658 
schannel_pkp_pin_peer_pubkey(struct Curl_cfilter * cf,struct Curl_easy * data,const char * pinnedpubkey)2659 static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
2660                                              struct Curl_easy *data,
2661                                              const char *pinnedpubkey)
2662 {
2663   struct ssl_connect_data *connssl = cf->ctx;
2664   struct schannel_ssl_backend_data *backend =
2665     (struct schannel_ssl_backend_data *)connssl->backend;
2666   CERT_CONTEXT *pCertContextServer = NULL;
2667 
2668   /* Result is returned to caller */
2669   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2670 
2671   DEBUGASSERT(backend);
2672 
2673   /* if a path was not specified, do not pin */
2674   if(!pinnedpubkey)
2675     return CURLE_OK;
2676 
2677   do {
2678     SECURITY_STATUS sspi_status;
2679     const char *x509_der;
2680     DWORD x509_der_len;
2681     struct Curl_X509certificate x509_parsed;
2682     struct Curl_asn1Element *pubkey;
2683 
2684     sspi_status =
2685       Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
2686                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2687                                        &pCertContextServer);
2688 
2689     if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2690       char buffer[STRERROR_LEN];
2691       failf(data, "schannel: Failed to read remote certificate context: %s",
2692             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2693       break; /* failed */
2694     }
2695 
2696 
2697     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2698          (pCertContextServer->cbCertEncoded > 0)))
2699       break;
2700 
2701     x509_der = (const char *)pCertContextServer->pbCertEncoded;
2702     x509_der_len = pCertContextServer->cbCertEncoded;
2703     memset(&x509_parsed, 0, sizeof(x509_parsed));
2704     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2705       break;
2706 
2707     pubkey = &x509_parsed.subjectPublicKeyInfo;
2708     if(!pubkey->header || pubkey->end <= pubkey->header) {
2709       failf(data, "SSL: failed retrieving public key from server certificate");
2710       break;
2711     }
2712 
2713     result = Curl_pin_peer_pubkey(data,
2714                                   pinnedpubkey,
2715                                   (const unsigned char *)pubkey->header,
2716                                   (size_t)(pubkey->end - pubkey->header));
2717     if(result) {
2718       failf(data, "SSL: public key does not match pinned public key");
2719     }
2720   } while(0);
2721 
2722   if(pCertContextServer)
2723     CertFreeCertificateContext(pCertContextServer);
2724 
2725   return result;
2726 }
2727 
schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2728 static void schannel_checksum(const unsigned char *input,
2729                               size_t inputlen,
2730                               unsigned char *checksum,
2731                               size_t checksumlen,
2732                               DWORD provType,
2733                               const unsigned int algId)
2734 {
2735 #ifdef CURL_WINDOWS_UWP
2736   (void)input;
2737   (void)inputlen;
2738   (void)provType;
2739   (void)algId;
2740   memset(checksum, 0, checksumlen);
2741 #else
2742   HCRYPTPROV hProv = 0;
2743   HCRYPTHASH hHash = 0;
2744   DWORD cbHashSize = 0;
2745   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2746   DWORD dwChecksumLen = (DWORD)checksumlen;
2747 
2748   /* since this can fail in multiple ways, zero memory first so we never
2749    * return old data
2750    */
2751   memset(checksum, 0, checksumlen);
2752 
2753   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2754                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2755     return; /* failed */
2756 
2757   do {
2758     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2759       break; /* failed */
2760 
2761     if(!CryptHashData(hHash, input, (DWORD)inputlen, 0))
2762       break; /* failed */
2763 
2764     /* get hash size */
2765     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2766                           &dwHashSizeLen, 0))
2767       break; /* failed */
2768 
2769     /* check hash size */
2770     if(checksumlen < cbHashSize)
2771       break; /* failed */
2772 
2773     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2774       break; /* failed */
2775   } while(0);
2776 
2777   if(hHash)
2778     CryptDestroyHash(hHash);
2779 
2780   if(hProv)
2781     CryptReleaseContext(hProv, 0);
2782 #endif
2783 }
2784 
schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2785 static CURLcode schannel_sha256sum(const unsigned char *input,
2786                                    size_t inputlen,
2787                                    unsigned char *sha256sum,
2788                                    size_t sha256len)
2789 {
2790   schannel_checksum(input, inputlen, sha256sum, sha256len,
2791                     PROV_RSA_AES, CALG_SHA_256);
2792   return CURLE_OK;
2793 }
2794 
schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2795 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2796                                     CURLINFO info UNUSED_PARAM)
2797 {
2798   struct schannel_ssl_backend_data *backend =
2799     (struct schannel_ssl_backend_data *)connssl->backend;
2800   (void)info;
2801   DEBUGASSERT(backend);
2802   return &backend->ctxt->ctxt_handle;
2803 }
2804 
Curl_schannel_get_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data)2805 HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
2806                                                const struct Curl_easy *data)
2807 {
2808   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2809   struct Curl_multi *multi = data->multi;
2810   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2811   struct schannel_cert_share *share;
2812   const struct ssl_general_config *cfg = &data->set.general_ssl;
2813   timediff_t timeout_ms;
2814   timediff_t elapsed_ms;
2815   struct curltime now;
2816   unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];
2817 
2818   DEBUGASSERT(multi);
2819 
2820   if(!multi) {
2821     return NULL;
2822   }
2823 
2824   share = Curl_hash_pick(&multi->proto_hash,
2825                          (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2826                          sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
2827   if(!share || !share->cert_store) {
2828     return NULL;
2829   }
2830 
2831   /* zero ca_cache_timeout completely disables caching */
2832   if(!cfg->ca_cache_timeout) {
2833     return NULL;
2834   }
2835 
2836   /* check for cache timeout by using the cached_x509_store_expired timediff
2837      calculation pattern from openssl.c.
2838      negative timeout means retain forever. */
2839   timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
2840   if(timeout_ms >= 0) {
2841     now = Curl_now();
2842     elapsed_ms = Curl_timediff(now, share->time);
2843     if(elapsed_ms >= timeout_ms) {
2844       return NULL;
2845     }
2846   }
2847 
2848   if(ca_info_blob) {
2849     if(share->CAinfo_blob_size != ca_info_blob->len) {
2850       return NULL;
2851     }
2852     schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2853                        ca_info_blob->len,
2854                        info_blob_digest,
2855                        CURL_SHA256_DIGEST_LENGTH);
2856     if(memcmp(share->CAinfo_blob_digest, info_blob_digest,
2857               CURL_SHA256_DIGEST_LENGTH)) {
2858       return NULL;
2859     }
2860   }
2861   else {
2862     if(!conn_config->CAfile || !share->CAfile ||
2863        strcmp(share->CAfile, conn_config->CAfile)) {
2864       return NULL;
2865     }
2866   }
2867 
2868   return share->cert_store;
2869 }
2870 
schannel_cert_share_free(void * key,size_t key_len,void * p)2871 static void schannel_cert_share_free(void *key, size_t key_len, void *p)
2872 {
2873   struct schannel_cert_share *share = p;
2874   DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
2875   DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
2876   (void)key;
2877   (void)key_len;
2878   if(share->cert_store) {
2879     CertCloseStore(share->cert_store, 0);
2880   }
2881   free(share->CAfile);
2882   free(share);
2883 }
2884 
Curl_schannel_set_cached_cert_store(struct Curl_cfilter * cf,const struct Curl_easy * data,HCERTSTORE cert_store)2885 bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
2886                                          const struct Curl_easy *data,
2887                                          HCERTSTORE cert_store)
2888 {
2889   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2890   struct Curl_multi *multi = data->multi;
2891   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
2892   struct schannel_cert_share *share;
2893   size_t CAinfo_blob_size = 0;
2894   char *CAfile = NULL;
2895 
2896   DEBUGASSERT(multi);
2897 
2898   if(!multi) {
2899     return false;
2900   }
2901 
2902   share = Curl_hash_pick(&multi->proto_hash,
2903                          (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2904                          sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
2905   if(!share) {
2906     share = calloc(1, sizeof(*share));
2907     if(!share) {
2908       return false;
2909     }
2910     if(!Curl_hash_add2(&multi->proto_hash,
2911                        (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
2912                        sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
2913                        share, schannel_cert_share_free)) {
2914       free(share);
2915       return false;
2916     }
2917   }
2918 
2919   if(ca_info_blob) {
2920     schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2921                        ca_info_blob->len,
2922                        share->CAinfo_blob_digest,
2923                        CURL_SHA256_DIGEST_LENGTH);
2924     CAinfo_blob_size = ca_info_blob->len;
2925   }
2926   else {
2927     if(conn_config->CAfile) {
2928       CAfile = strdup(conn_config->CAfile);
2929       if(!CAfile) {
2930         return false;
2931       }
2932     }
2933   }
2934 
2935   /* free old cache data */
2936   if(share->cert_store) {
2937     CertCloseStore(share->cert_store, 0);
2938   }
2939   free(share->CAfile);
2940 
2941   share->time = Curl_now();
2942   share->cert_store = cert_store;
2943   share->CAinfo_blob_size = CAinfo_blob_size;
2944   share->CAfile = CAfile;
2945   return true;
2946 }
2947 
2948 const struct Curl_ssl Curl_ssl_schannel = {
2949   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2950 
2951   SSLSUPP_CERTINFO |
2952 #ifdef HAS_MANUAL_VERIFY_API
2953   SSLSUPP_CAINFO_BLOB |
2954 #endif
2955 #ifndef CURL_WINDOWS_UWP
2956   SSLSUPP_PINNEDPUBKEY |
2957 #endif
2958   SSLSUPP_TLS13_CIPHERSUITES |
2959   SSLSUPP_CA_CACHE |
2960   SSLSUPP_HTTPS_PROXY |
2961   SSLSUPP_CIPHER_LIST,
2962 
2963   sizeof(struct schannel_ssl_backend_data),
2964 
2965   schannel_init,                     /* init */
2966   schannel_cleanup,                  /* cleanup */
2967   schannel_version,                  /* version */
2968   Curl_none_check_cxn,               /* check_cxn */
2969   schannel_shutdown,                 /* shutdown */
2970   schannel_data_pending,             /* data_pending */
2971   schannel_random,                   /* random */
2972   Curl_none_cert_status_request,     /* cert_status_request */
2973   schannel_connect,                  /* connect */
2974   schannel_connect_nonblocking,      /* connect_nonblocking */
2975   Curl_ssl_adjust_pollset,           /* adjust_pollset */
2976   schannel_get_internals,            /* get_internals */
2977   schannel_close,                    /* close_one */
2978   Curl_none_close_all,               /* close_all */
2979   Curl_none_set_engine,              /* set_engine */
2980   Curl_none_set_engine_default,      /* set_engine_default */
2981   Curl_none_engines_list,            /* engines_list */
2982   Curl_none_false_start,             /* false_start */
2983   schannel_sha256sum,                /* sha256sum */
2984   NULL,                              /* associate_connection */
2985   NULL,                              /* disassociate_connection */
2986   schannel_recv,                     /* recv decrypted data */
2987   schannel_send,                     /* send data to encrypt */
2988   NULL,                              /* get_channel_binding */
2989 };
2990 
2991 #endif /* USE_SCHANNEL */
2992