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