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