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