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