1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
9  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
10  * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
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.haxx.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  ***************************************************************************/
24 
25 /*
26  * Source file for all Schannel-specific code for the TLS/SSL layer. No code
27  * but vtls.c should ever call or use these functions.
28  */
29 
30 /*
31  * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
32  *   Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
33  *
34  * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
35  *   Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
36  *
37  * Thanks for code and inspiration!
38  */
39 
40 #include "curl_setup.h"
41 
42 #ifdef USE_SCHANNEL
43 
44 #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
45 
46 #ifndef USE_WINDOWS_SSPI
47 #  error "Can't compile SCHANNEL support without SSPI."
48 #endif
49 
50 #include "schannel.h"
51 #include "vtls.h"
52 #include "sendf.h"
53 #include "connect.h" /* for the connect timeout */
54 #include "strerror.h"
55 #include "select.h" /* for the socket readyness */
56 #include "inet_pton.h" /* for IP addr SNI check */
57 #include "curl_multibyte.h"
58 #include "warnless.h"
59 #include "x509asn1.h"
60 #include "curl_printf.h"
61 #include "multiif.h"
62 #include "system_win32.h"
63 
64  /* The last #include file should be: */
65 #include "curl_memory.h"
66 #include "memdebug.h"
67 
68 /* ALPN requires version 8.1 of the Windows SDK, which was
69    shipped with Visual Studio 2013, aka _MSC_VER 1800:
70 
71    https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
72 */
73 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
74 #  define HAS_ALPN 1
75 #endif
76 
77 #ifndef UNISP_NAME_A
78 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
79 #endif
80 
81 #ifndef UNISP_NAME_W
82 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
83 #endif
84 
85 #ifndef UNISP_NAME
86 #ifdef UNICODE
87 #define UNISP_NAME  UNISP_NAME_W
88 #else
89 #define UNISP_NAME  UNISP_NAME_A
90 #endif
91 #endif
92 
93 #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
94 #define HAS_CLIENT_CERT_PATH
95 #endif
96 
97 #ifdef HAS_CLIENT_CERT_PATH
98 #ifdef UNICODE
99 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
100 #else
101 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
102 #endif
103 #endif
104 
105 #ifndef SP_PROT_SSL2_CLIENT
106 #define SP_PROT_SSL2_CLIENT             0x00000008
107 #endif
108 
109 #ifndef SP_PROT_SSL3_CLIENT
110 #define SP_PROT_SSL3_CLIENT             0x00000008
111 #endif
112 
113 #ifndef SP_PROT_TLS1_CLIENT
114 #define SP_PROT_TLS1_CLIENT             0x00000080
115 #endif
116 
117 #ifndef SP_PROT_TLS1_0_CLIENT
118 #define SP_PROT_TLS1_0_CLIENT           SP_PROT_TLS1_CLIENT
119 #endif
120 
121 #ifndef SP_PROT_TLS1_1_CLIENT
122 #define SP_PROT_TLS1_1_CLIENT           0x00000200
123 #endif
124 
125 #ifndef SP_PROT_TLS1_2_CLIENT
126 #define SP_PROT_TLS1_2_CLIENT           0x00000800
127 #endif
128 
129 #ifndef SECBUFFER_ALERT
130 #define SECBUFFER_ALERT                 17
131 #endif
132 
133 /* Both schannel buffer sizes must be > 0 */
134 #define CURL_SCHANNEL_BUFFER_INIT_SIZE   4096
135 #define CURL_SCHANNEL_BUFFER_FREE_SIZE   1024
136 
137 #define CERT_THUMBPRINT_STR_LEN 40
138 #define CERT_THUMBPRINT_DATA_LEN 20
139 
140 /* Uncomment to force verbose output
141  * #define infof(x, y, ...) printf(y, __VA_ARGS__)
142  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
143  */
144 
145 #ifndef CALG_SHA_256
146 #  define CALG_SHA_256 0x0000800c
147 #endif
148 
149 #define BACKEND connssl->backend
150 
151 static Curl_recv schannel_recv;
152 static Curl_send schannel_send;
153 
154 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
155                                     const char *pinnedpubkey);
156 
InitSecBuffer(SecBuffer * buffer,unsigned long BufType,void * BufDataPtr,unsigned long BufByteSize)157 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
158                           void *BufDataPtr, unsigned long BufByteSize)
159 {
160   buffer->cbBuffer = BufByteSize;
161   buffer->BufferType = BufType;
162   buffer->pvBuffer = BufDataPtr;
163 }
164 
InitSecBufferDesc(SecBufferDesc * desc,SecBuffer * BufArr,unsigned long NumArrElem)165 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
166                               unsigned long NumArrElem)
167 {
168   desc->ulVersion = SECBUFFER_VERSION;
169   desc->pBuffers = BufArr;
170   desc->cBuffers = NumArrElem;
171 }
172 
173 static CURLcode
set_ssl_version_min_max(SCHANNEL_CRED * schannel_cred,struct connectdata * conn)174 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
175 {
176   struct Curl_easy *data = conn->data;
177   long ssl_version = SSL_CONN_CONFIG(version);
178   long ssl_version_max = SSL_CONN_CONFIG(version_max);
179   long i = ssl_version;
180 
181   switch(ssl_version_max) {
182     case CURL_SSLVERSION_MAX_NONE:
183     case CURL_SSLVERSION_MAX_DEFAULT:
184       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
185       break;
186   }
187   for(; i <= (ssl_version_max >> 16); ++i) {
188     switch(i) {
189       case CURL_SSLVERSION_TLSv1_0:
190         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
191         break;
192       case CURL_SSLVERSION_TLSv1_1:
193         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
194         break;
195       case CURL_SSLVERSION_TLSv1_2:
196         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
197         break;
198       case CURL_SSLVERSION_TLSv1_3:
199         failf(data, "schannel: TLS 1.3 is not yet supported");
200         return CURLE_SSL_CONNECT_ERROR;
201     }
202   }
203   return CURLE_OK;
204 }
205 
206 /*longest is 26, buffer is slightly bigger*/
207 #define LONGEST_ALG_ID 32
208 #define CIPHEROPTION(X) \
209 if(strcmp(#X, tmp) == 0) \
210   return X
211 
212 static int
get_alg_id_by_name(char * name)213 get_alg_id_by_name(char *name)
214 {
215   char tmp[LONGEST_ALG_ID] = { 0 };
216   char *nameEnd = strchr(name, ':');
217   size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
218     min(strlen(name), LONGEST_ALG_ID - 1);
219   strncpy(tmp, name, n);
220   tmp[n] = 0;
221   CIPHEROPTION(CALG_MD2);
222   CIPHEROPTION(CALG_MD4);
223   CIPHEROPTION(CALG_MD5);
224   CIPHEROPTION(CALG_SHA);
225   CIPHEROPTION(CALG_SHA1);
226   CIPHEROPTION(CALG_MAC);
227   CIPHEROPTION(CALG_RSA_SIGN);
228   CIPHEROPTION(CALG_DSS_SIGN);
229 /*ifdefs for the options that are defined conditionally in wincrypt.h*/
230 #ifdef CALG_NO_SIGN
231   CIPHEROPTION(CALG_NO_SIGN);
232 #endif
233   CIPHEROPTION(CALG_RSA_KEYX);
234   CIPHEROPTION(CALG_DES);
235 #ifdef CALG_3DES_112
236   CIPHEROPTION(CALG_3DES_112);
237 #endif
238   CIPHEROPTION(CALG_3DES);
239   CIPHEROPTION(CALG_DESX);
240   CIPHEROPTION(CALG_RC2);
241   CIPHEROPTION(CALG_RC4);
242   CIPHEROPTION(CALG_SEAL);
243 #ifdef CALG_DH_SF
244   CIPHEROPTION(CALG_DH_SF);
245 #endif
246   CIPHEROPTION(CALG_DH_EPHEM);
247 #ifdef CALG_AGREEDKEY_ANY
248   CIPHEROPTION(CALG_AGREEDKEY_ANY);
249 #endif
250 #ifdef CALG_HUGHES_MD5
251   CIPHEROPTION(CALG_HUGHES_MD5);
252 #endif
253   CIPHEROPTION(CALG_SKIPJACK);
254 #ifdef CALG_TEK
255   CIPHEROPTION(CALG_TEK);
256 #endif
257   CIPHEROPTION(CALG_CYLINK_MEK);
258   CIPHEROPTION(CALG_SSL3_SHAMD5);
259 #ifdef CALG_SSL3_MASTER
260   CIPHEROPTION(CALG_SSL3_MASTER);
261 #endif
262 #ifdef CALG_SCHANNEL_MASTER_HASH
263   CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
264 #endif
265 #ifdef CALG_SCHANNEL_MAC_KEY
266   CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
267 #endif
268 #ifdef CALG_SCHANNEL_ENC_KEY
269   CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
270 #endif
271 #ifdef CALG_PCT1_MASTER
272   CIPHEROPTION(CALG_PCT1_MASTER);
273 #endif
274 #ifdef CALG_SSL2_MASTER
275   CIPHEROPTION(CALG_SSL2_MASTER);
276 #endif
277 #ifdef CALG_TLS1_MASTER
278   CIPHEROPTION(CALG_TLS1_MASTER);
279 #endif
280 #ifdef CALG_RC5
281   CIPHEROPTION(CALG_RC5);
282 #endif
283 #ifdef CALG_HMAC
284   CIPHEROPTION(CALG_HMAC);
285 #endif
286 #if !defined(__W32API_MAJOR_VERSION) || \
287     !defined(__W32API_MINOR_VERSION) || \
288     defined(__MINGW64_VERSION_MAJOR) || \
289     (__W32API_MAJOR_VERSION > 5)     || \
290     ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
291   /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
292      see https://osdn.net/projects/mingw/ticket/38391 */
293   CIPHEROPTION(CALG_TLS1PRF);
294 #endif
295 #ifdef CALG_HASH_REPLACE_OWF
296   CIPHEROPTION(CALG_HASH_REPLACE_OWF);
297 #endif
298 #ifdef CALG_AES_128
299   CIPHEROPTION(CALG_AES_128);
300 #endif
301 #ifdef CALG_AES_192
302   CIPHEROPTION(CALG_AES_192);
303 #endif
304 #ifdef CALG_AES_256
305   CIPHEROPTION(CALG_AES_256);
306 #endif
307 #ifdef CALG_AES
308   CIPHEROPTION(CALG_AES);
309 #endif
310 #ifdef CALG_SHA_256
311   CIPHEROPTION(CALG_SHA_256);
312 #endif
313 #ifdef CALG_SHA_384
314   CIPHEROPTION(CALG_SHA_384);
315 #endif
316 #ifdef CALG_SHA_512
317   CIPHEROPTION(CALG_SHA_512);
318 #endif
319 #ifdef CALG_ECDH
320   CIPHEROPTION(CALG_ECDH);
321 #endif
322 #ifdef CALG_ECMQV
323   CIPHEROPTION(CALG_ECMQV);
324 #endif
325 #ifdef CALG_ECDSA
326   CIPHEROPTION(CALG_ECDSA);
327 #endif
328 #ifdef CALG_ECDH_EPHEM
329   CIPHEROPTION(CALG_ECDH_EPHEM);
330 #endif
331   return 0;
332 }
333 
334 static CURLcode
set_ssl_ciphers(SCHANNEL_CRED * schannel_cred,char * ciphers)335 set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
336 {
337   char *startCur = ciphers;
338   int algCount = 0;
339   static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
340   while(startCur && (0 != *startCur) && (algCount < 45)) {
341     long alg = strtol(startCur, 0, 0);
342     if(!alg)
343       alg = get_alg_id_by_name(startCur);
344     if(alg)
345       algIds[algCount++] = alg;
346     else
347       return CURLE_SSL_CIPHER;
348     startCur = strchr(startCur, ':');
349     if(startCur)
350       startCur++;
351   }
352     schannel_cred->palgSupportedAlgs = algIds;
353   schannel_cred->cSupportedAlgs = algCount;
354   return CURLE_OK;
355 }
356 
357 #ifdef HAS_CLIENT_CERT_PATH
358 static CURLcode
get_cert_location(TCHAR * path,DWORD * store_name,TCHAR ** store_path,TCHAR ** thumbprint)359 get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
360                   TCHAR **thumbprint)
361 {
362   TCHAR *sep;
363   TCHAR *store_path_start;
364   size_t store_name_len;
365 
366   sep = _tcschr(path, TEXT('\\'));
367   if(sep == NULL)
368     return CURLE_SSL_CERTPROBLEM;
369 
370   store_name_len = sep - path;
371 
372   if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
373     *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
374   else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
375     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
376   else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
377     *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
378   else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
379     *store_name = CERT_SYSTEM_STORE_SERVICES;
380   else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
381     *store_name = CERT_SYSTEM_STORE_USERS;
382   else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
383                     store_name_len) == 0)
384     *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
385   else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
386                     store_name_len) == 0)
387     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
388   else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
389                     store_name_len) == 0)
390     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
391   else
392     return CURLE_SSL_CERTPROBLEM;
393 
394   store_path_start = sep + 1;
395 
396   sep = _tcschr(store_path_start, TEXT('\\'));
397   if(sep == NULL)
398     return CURLE_SSL_CERTPROBLEM;
399 
400   *sep = TEXT('\0');
401   *store_path = _tcsdup(store_path_start);
402   *sep = TEXT('\\');
403   if(*store_path == NULL)
404     return CURLE_OUT_OF_MEMORY;
405 
406   *thumbprint = sep + 1;
407   if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
408     return CURLE_SSL_CERTPROBLEM;
409 
410   return CURLE_OK;
411 }
412 #endif
413 
414 static CURLcode
schannel_connect_step1(struct connectdata * conn,int sockindex)415 schannel_connect_step1(struct connectdata *conn, int sockindex)
416 {
417   ssize_t written = -1;
418   struct Curl_easy *data = conn->data;
419   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
420   SecBuffer outbuf;
421   SecBufferDesc outbuf_desc;
422   SecBuffer inbuf;
423   SecBufferDesc inbuf_desc;
424 #ifdef HAS_ALPN
425   unsigned char alpn_buffer[128];
426 #endif
427   SCHANNEL_CRED schannel_cred;
428   PCCERT_CONTEXT client_certs[1] = { NULL };
429   SECURITY_STATUS sspi_status = SEC_E_OK;
430   struct curl_schannel_cred *old_cred = NULL;
431   struct in_addr addr;
432 #ifdef ENABLE_IPV6
433   struct in6_addr addr6;
434 #endif
435   TCHAR *host_name;
436   CURLcode result;
437   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
438     conn->host.name;
439 
440   DEBUGF(infof(data,
441                "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
442                hostname, conn->remote_port));
443 
444   if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
445                                  VERSION_LESS_THAN_EQUAL)) {
446      /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
447         algorithms that may not be supported by all servers. */
448      infof(data, "schannel: Windows version is old and may not be able to "
449            "connect to some servers due to lack of SNI, algorithms, etc.\n");
450   }
451 
452 #ifdef HAS_ALPN
453   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
454      Also it doesn't seem to be supported for Wine, see curl bug #983. */
455   BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
456                       !GetProcAddress(GetModuleHandleA("ntdll"),
457                                       "wine_get_version") &&
458                       Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
459                                                   VERSION_GREATER_THAN_EQUAL);
460 #else
461   BACKEND->use_alpn = false;
462 #endif
463 
464 #ifdef _WIN32_WCE
465 #ifdef HAS_MANUAL_VERIFY_API
466   /* certificate validation on CE doesn't seem to work right; we'll
467    * do it following a more manual process. */
468   BACKEND->use_manual_cred_validation = true;
469 #else
470 #error "compiler too old to support requisite manual cert verify for Win CE"
471 #endif
472 #else
473 #ifdef HAS_MANUAL_VERIFY_API
474   if(SSL_CONN_CONFIG(CAfile)) {
475     if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
476                                    VERSION_GREATER_THAN_EQUAL)) {
477       BACKEND->use_manual_cred_validation = true;
478     }
479     else {
480       failf(data, "schannel: this version of Windows is too old to support "
481             "certificate verification via CA bundle file.");
482       return CURLE_SSL_CACERT_BADFILE;
483     }
484   }
485   else
486     BACKEND->use_manual_cred_validation = false;
487 #else
488   if(SSL_CONN_CONFIG(CAfile)) {
489     failf(data, "schannel: CA cert support not built in");
490     return CURLE_NOT_BUILT_IN;
491   }
492 #endif
493 #endif
494 
495   BACKEND->cred = NULL;
496 
497   /* check for an existing re-usable credential handle */
498   if(SSL_SET_OPTION(primary.sessionid)) {
499     Curl_ssl_sessionid_lock(conn);
500     if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
501       BACKEND->cred = old_cred;
502       DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
503 
504       /* increment the reference counter of the credential/session handle */
505       BACKEND->cred->refcount++;
506       DEBUGF(infof(data,
507                    "schannel: incremented credential handle refcount = %d\n",
508                    BACKEND->cred->refcount));
509     }
510     Curl_ssl_sessionid_unlock(conn);
511   }
512 
513   if(!BACKEND->cred) {
514     /* setup Schannel API options */
515     memset(&schannel_cred, 0, sizeof(schannel_cred));
516     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
517 
518     if(conn->ssl_config.verifypeer) {
519 #ifdef HAS_MANUAL_VERIFY_API
520       if(BACKEND->use_manual_cred_validation)
521         schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
522       else
523 #endif
524         schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
525 
526       if(data->set.ssl.no_revoke) {
527         schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
528           SCH_CRED_IGNORE_REVOCATION_OFFLINE;
529 
530         DEBUGF(infof(data, "schannel: disabled server certificate revocation "
531                      "checks\n"));
532       }
533       else {
534         schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
535         DEBUGF(infof(data,
536                      "schannel: checking server certificate revocation\n"));
537       }
538     }
539     else {
540       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
541         SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
542         SCH_CRED_IGNORE_REVOCATION_OFFLINE;
543       DEBUGF(infof(data,
544                    "schannel: disabled server cert revocation checks\n"));
545     }
546 
547     if(!conn->ssl_config.verifyhost) {
548       schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
549       DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
550                    "comparing the supplied target name with the subject "
551                    "names in server certificates.\n"));
552     }
553 
554     switch(conn->ssl_config.version) {
555     case CURL_SSLVERSION_DEFAULT:
556     case CURL_SSLVERSION_TLSv1:
557       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
558         SP_PROT_TLS1_1_CLIENT |
559         SP_PROT_TLS1_2_CLIENT;
560       break;
561     case CURL_SSLVERSION_TLSv1_0:
562     case CURL_SSLVERSION_TLSv1_1:
563     case CURL_SSLVERSION_TLSv1_2:
564     case CURL_SSLVERSION_TLSv1_3:
565       {
566         result = set_ssl_version_min_max(&schannel_cred, conn);
567         if(result != CURLE_OK)
568           return result;
569         break;
570       }
571     case CURL_SSLVERSION_SSLv3:
572       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
573       break;
574     case CURL_SSLVERSION_SSLv2:
575       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
576       break;
577     default:
578       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
579       return CURLE_SSL_CONNECT_ERROR;
580     }
581 
582     if(SSL_CONN_CONFIG(cipher_list)) {
583       result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
584       if(CURLE_OK != result) {
585         failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
586         return result;
587       }
588     }
589 
590 
591 #ifdef HAS_CLIENT_CERT_PATH
592     /* client certificate */
593     if(data->set.ssl.cert) {
594       DWORD cert_store_name;
595       TCHAR *cert_store_path;
596       TCHAR *cert_thumbprint_str;
597       CRYPT_HASH_BLOB cert_thumbprint;
598       BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
599       HCERTSTORE cert_store;
600 
601       TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
602       if(!cert_path)
603         return CURLE_OUT_OF_MEMORY;
604 
605       result = get_cert_location(cert_path, &cert_store_name,
606                                  &cert_store_path, &cert_thumbprint_str);
607       if(result != CURLE_OK) {
608         failf(data, "schannel: Failed to get certificate location for %s",
609               cert_path);
610         Curl_unicodefree(cert_path);
611         return result;
612       }
613 
614       cert_store =
615         CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
616                       (HCRYPTPROV)NULL,
617                       CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
618                       cert_store_path);
619       if(!cert_store) {
620         failf(data, "schannel: Failed to open cert store %x %s, "
621               "last error is %x",
622               cert_store_name, cert_store_path, GetLastError());
623         free(cert_store_path);
624         Curl_unicodefree(cert_path);
625         return CURLE_SSL_CERTPROBLEM;
626       }
627       free(cert_store_path);
628 
629       cert_thumbprint.pbData = cert_thumbprint_data;
630       cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
631 
632       if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
633                               CRYPT_STRING_HEX,
634                               cert_thumbprint_data, &cert_thumbprint.cbData,
635                               NULL, NULL)) {
636         Curl_unicodefree(cert_path);
637         return CURLE_SSL_CERTPROBLEM;
638       }
639 
640       client_certs[0] = CertFindCertificateInStore(
641         cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
642         CERT_FIND_HASH, &cert_thumbprint, NULL);
643 
644       Curl_unicodefree(cert_path);
645 
646       if(client_certs[0]) {
647         schannel_cred.cCreds = 1;
648         schannel_cred.paCred = client_certs;
649       }
650       else {
651         /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
652         return CURLE_SSL_CERTPROBLEM;
653       }
654 
655       CertCloseStore(cert_store, 0);
656     }
657 #else
658     if(data->set.ssl.cert) {
659       failf(data, "schannel: client cert support not built in");
660       return CURLE_NOT_BUILT_IN;
661     }
662 #endif
663 
664     /* allocate memory for the re-usable credential handle */
665     BACKEND->cred = (struct curl_schannel_cred *)
666       calloc(1, sizeof(struct curl_schannel_cred));
667     if(!BACKEND->cred) {
668       failf(data, "schannel: unable to allocate memory");
669 
670       if(client_certs[0])
671         CertFreeCertificateContext(client_certs[0]);
672 
673       return CURLE_OUT_OF_MEMORY;
674     }
675     BACKEND->cred->refcount = 1;
676 
677     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
678        */
679     sspi_status =
680       s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
681                                          SECPKG_CRED_OUTBOUND, NULL,
682                                          &schannel_cred, NULL, NULL,
683                                          &BACKEND->cred->cred_handle,
684                                          &BACKEND->cred->time_stamp);
685 
686     if(client_certs[0])
687       CertFreeCertificateContext(client_certs[0]);
688 
689     if(sspi_status != SEC_E_OK) {
690       char buffer[STRERROR_LEN];
691       failf(data, "schannel: AcquireCredentialsHandle failed: %s",
692             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
693       Curl_safefree(BACKEND->cred);
694       switch(sspi_status) {
695         case SEC_E_INSUFFICIENT_MEMORY:
696           return CURLE_OUT_OF_MEMORY;
697         case SEC_E_NO_CREDENTIALS:
698         case SEC_E_SECPKG_NOT_FOUND:
699         case SEC_E_NOT_OWNER:
700         case SEC_E_UNKNOWN_CREDENTIALS:
701         case SEC_E_INTERNAL_ERROR:
702         default:
703           return CURLE_SSL_CONNECT_ERROR;
704       }
705     }
706   }
707 
708   /* Warn if SNI is disabled due to use of an IP address */
709   if(Curl_inet_pton(AF_INET, hostname, &addr)
710 #ifdef ENABLE_IPV6
711      || Curl_inet_pton(AF_INET6, hostname, &addr6)
712 #endif
713     ) {
714     infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
715   }
716 
717 #ifdef HAS_ALPN
718   if(BACKEND->use_alpn) {
719     int cur = 0;
720     int list_start_index = 0;
721     unsigned int *extension_len = NULL;
722     unsigned short* list_len = NULL;
723 
724     /* The first four bytes will be an unsigned int indicating number
725        of bytes of data in the rest of the the buffer. */
726     extension_len = (unsigned int *)(&alpn_buffer[cur]);
727     cur += sizeof(unsigned int);
728 
729     /* The next four bytes are an indicator that this buffer will contain
730        ALPN data, as opposed to NPN, for example. */
731     *(unsigned int *)&alpn_buffer[cur] =
732       SecApplicationProtocolNegotiationExt_ALPN;
733     cur += sizeof(unsigned int);
734 
735     /* The next two bytes will be an unsigned short indicating the number
736        of bytes used to list the preferred protocols. */
737     list_len = (unsigned short*)(&alpn_buffer[cur]);
738     cur += sizeof(unsigned short);
739 
740     list_start_index = cur;
741 
742 #ifdef USE_NGHTTP2
743     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
744       memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
745       cur += NGHTTP2_PROTO_ALPN_LEN;
746       infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
747     }
748 #endif
749 
750     alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
751     memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
752     cur += ALPN_HTTP_1_1_LENGTH;
753     infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
754 
755     *list_len = curlx_uitous(cur - list_start_index);
756     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
757 
758     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
759     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
760   }
761   else {
762     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
763     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
764   }
765 #else /* HAS_ALPN */
766   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
767   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
768 #endif
769 
770   /* setup output buffer */
771   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
772   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
773 
774   /* setup request flags */
775   BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
776     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
777     ISC_REQ_STREAM;
778 
779   /* allocate memory for the security context handle */
780   BACKEND->ctxt = (struct curl_schannel_ctxt *)
781     calloc(1, sizeof(struct curl_schannel_ctxt));
782   if(!BACKEND->ctxt) {
783     failf(data, "schannel: unable to allocate memory");
784     return CURLE_OUT_OF_MEMORY;
785   }
786 
787   host_name = Curl_convert_UTF8_to_tchar(hostname);
788   if(!host_name)
789     return CURLE_OUT_OF_MEMORY;
790 
791   /* Schannel InitializeSecurityContext:
792      https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
793 
794      At the moment we don't pass inbuf unless we're using ALPN since we only
795      use it for that, and Wine (for which we currently disable ALPN) is giving
796      us problems with inbuf regardless. https://github.com/curl/curl/issues/983
797   */
798   sspi_status = s_pSecFn->InitializeSecurityContext(
799     &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
800     (BACKEND->use_alpn ? &inbuf_desc : NULL),
801     0, &BACKEND->ctxt->ctxt_handle,
802     &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
803 
804   Curl_unicodefree(host_name);
805 
806   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
807     char buffer[STRERROR_LEN];
808     Curl_safefree(BACKEND->ctxt);
809     switch(sspi_status) {
810       case SEC_E_INSUFFICIENT_MEMORY:
811         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
812               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
813         return CURLE_OUT_OF_MEMORY;
814       case SEC_E_WRONG_PRINCIPAL:
815         failf(data, "schannel: SNI or certificate check failed: %s",
816               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
817         return CURLE_PEER_FAILED_VERIFICATION;
818         /*
819       case SEC_E_INVALID_HANDLE:
820       case SEC_E_INVALID_TOKEN:
821       case SEC_E_LOGON_DENIED:
822       case SEC_E_TARGET_UNKNOWN:
823       case SEC_E_NO_AUTHENTICATING_AUTHORITY:
824       case SEC_E_INTERNAL_ERROR:
825       case SEC_E_NO_CREDENTIALS:
826       case SEC_E_UNSUPPORTED_FUNCTION:
827       case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
828         */
829       default:
830         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
831               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
832         return CURLE_SSL_CONNECT_ERROR;
833     }
834   }
835 
836   DEBUGF(infof(data, "schannel: sending initial handshake data: "
837                "sending %lu bytes...\n", outbuf.cbBuffer));
838 
839   /* send initial handshake data which is now stored in output buffer */
840   result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
841                             outbuf.cbBuffer, &written);
842   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
843   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
844     failf(data, "schannel: failed to send initial handshake data: "
845           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
846     return CURLE_SSL_CONNECT_ERROR;
847   }
848 
849   DEBUGF(infof(data, "schannel: sent initial handshake data: "
850                "sent %zd bytes\n", written));
851 
852   BACKEND->recv_unrecoverable_err = CURLE_OK;
853   BACKEND->recv_sspi_close_notify = false;
854   BACKEND->recv_connection_closed = false;
855   BACKEND->encdata_is_incomplete = false;
856 
857   /* continue to second handshake step */
858   connssl->connecting_state = ssl_connect_2;
859 
860   return CURLE_OK;
861 }
862 
863 static CURLcode
schannel_connect_step2(struct connectdata * conn,int sockindex)864 schannel_connect_step2(struct connectdata *conn, int sockindex)
865 {
866   int i;
867   ssize_t nread = -1, written = -1;
868   struct Curl_easy *data = conn->data;
869   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
870   unsigned char *reallocated_buffer;
871   SecBuffer outbuf[3];
872   SecBufferDesc outbuf_desc;
873   SecBuffer inbuf[2];
874   SecBufferDesc inbuf_desc;
875   SECURITY_STATUS sspi_status = SEC_E_OK;
876   CURLcode result;
877   bool doread;
878   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
879     conn->host.name;
880   const char *pubkey_ptr;
881 
882   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
883 
884   DEBUGF(infof(data,
885                "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
886                hostname, conn->remote_port));
887 
888   if(!BACKEND->cred || !BACKEND->ctxt)
889     return CURLE_SSL_CONNECT_ERROR;
890 
891   /* buffer to store previously received and decrypted data */
892   if(BACKEND->decdata_buffer == NULL) {
893     BACKEND->decdata_offset = 0;
894     BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
895     BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
896     if(BACKEND->decdata_buffer == NULL) {
897       failf(data, "schannel: unable to allocate memory");
898       return CURLE_OUT_OF_MEMORY;
899     }
900   }
901 
902   /* buffer to store previously received and encrypted data */
903   if(BACKEND->encdata_buffer == NULL) {
904     BACKEND->encdata_is_incomplete = false;
905     BACKEND->encdata_offset = 0;
906     BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
907     BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
908     if(BACKEND->encdata_buffer == NULL) {
909       failf(data, "schannel: unable to allocate memory");
910       return CURLE_OUT_OF_MEMORY;
911     }
912   }
913 
914   /* if we need a bigger buffer to read a full message, increase buffer now */
915   if(BACKEND->encdata_length - BACKEND->encdata_offset <
916      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
917     /* increase internal encrypted data buffer */
918     size_t reallocated_length = BACKEND->encdata_offset +
919       CURL_SCHANNEL_BUFFER_FREE_SIZE;
920     reallocated_buffer = realloc(BACKEND->encdata_buffer,
921                                  reallocated_length);
922 
923     if(reallocated_buffer == NULL) {
924       failf(data, "schannel: unable to re-allocate memory");
925       return CURLE_OUT_OF_MEMORY;
926     }
927     else {
928       BACKEND->encdata_buffer = reallocated_buffer;
929       BACKEND->encdata_length = reallocated_length;
930     }
931   }
932 
933   for(;;) {
934     TCHAR *host_name;
935     if(doread) {
936       /* read encrypted handshake data from socket */
937       result = Curl_read_plain(conn->sock[sockindex],
938                                (char *) (BACKEND->encdata_buffer +
939                                          BACKEND->encdata_offset),
940                                BACKEND->encdata_length -
941                                BACKEND->encdata_offset,
942                                &nread);
943       if(result == CURLE_AGAIN) {
944         if(connssl->connecting_state != ssl_connect_2_writing)
945           connssl->connecting_state = ssl_connect_2_reading;
946         DEBUGF(infof(data, "schannel: failed to receive handshake, "
947                      "need more data\n"));
948         return CURLE_OK;
949       }
950       else if((result != CURLE_OK) || (nread == 0)) {
951         failf(data, "schannel: failed to receive handshake, "
952               "SSL/TLS connection failed");
953         return CURLE_SSL_CONNECT_ERROR;
954       }
955 
956       /* increase encrypted data buffer offset */
957       BACKEND->encdata_offset += nread;
958       BACKEND->encdata_is_incomplete = false;
959       DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
960     }
961 
962     DEBUGF(infof(data,
963                  "schannel: encrypted data buffer: offset %zu length %zu\n",
964                  BACKEND->encdata_offset, BACKEND->encdata_length));
965 
966     /* setup input buffers */
967     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
968                   curlx_uztoul(BACKEND->encdata_offset));
969     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
970     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
971 
972     /* setup output buffers */
973     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
974     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
975     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
976     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
977 
978     if(inbuf[0].pvBuffer == NULL) {
979       failf(data, "schannel: unable to allocate memory");
980       return CURLE_OUT_OF_MEMORY;
981     }
982 
983     /* copy received handshake data into input buffer */
984     memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
985            BACKEND->encdata_offset);
986 
987     host_name = Curl_convert_UTF8_to_tchar(hostname);
988     if(!host_name)
989       return CURLE_OUT_OF_MEMORY;
990 
991     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
992        */
993     sspi_status = s_pSecFn->InitializeSecurityContext(
994       &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
995       host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
996       &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
997 
998     Curl_unicodefree(host_name);
999 
1000     /* free buffer for received handshake data */
1001     Curl_safefree(inbuf[0].pvBuffer);
1002 
1003     /* check if the handshake was incomplete */
1004     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1005       BACKEND->encdata_is_incomplete = true;
1006       connssl->connecting_state = ssl_connect_2_reading;
1007       DEBUGF(infof(data,
1008                    "schannel: received incomplete message, need more data\n"));
1009       return CURLE_OK;
1010     }
1011 
1012     /* If the server has requested a client certificate, attempt to continue
1013        the handshake without one. This will allow connections to servers which
1014        request a client certificate but do not require it. */
1015     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1016        !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1017       BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1018       connssl->connecting_state = ssl_connect_2_writing;
1019       DEBUGF(infof(data,
1020                    "schannel: a client certificate has been requested\n"));
1021       return CURLE_OK;
1022     }
1023 
1024     /* check if the handshake needs to be continued */
1025     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1026       for(i = 0; i < 3; i++) {
1027         /* search for handshake tokens that need to be send */
1028         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1029           DEBUGF(infof(data, "schannel: sending next handshake data: "
1030                        "sending %lu bytes...\n", outbuf[i].cbBuffer));
1031 
1032           /* send handshake token to server */
1033           result = Curl_write_plain(conn, conn->sock[sockindex],
1034                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1035                                     &written);
1036           if((result != CURLE_OK) ||
1037              (outbuf[i].cbBuffer != (size_t) written)) {
1038             failf(data, "schannel: failed to send next handshake data: "
1039                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1040             return CURLE_SSL_CONNECT_ERROR;
1041           }
1042         }
1043 
1044         /* free obsolete buffer */
1045         if(outbuf[i].pvBuffer != NULL) {
1046           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1047         }
1048       }
1049     }
1050     else {
1051       char buffer[STRERROR_LEN];
1052       switch(sspi_status) {
1053         case SEC_E_INSUFFICIENT_MEMORY:
1054           failf(data, "schannel: next InitializeSecurityContext failed: %s",
1055                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1056           return CURLE_OUT_OF_MEMORY;
1057         case SEC_E_WRONG_PRINCIPAL:
1058           failf(data, "schannel: SNI or certificate check failed: %s",
1059                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1060           return CURLE_PEER_FAILED_VERIFICATION;
1061           /*
1062         case SEC_E_INVALID_HANDLE:
1063         case SEC_E_INVALID_TOKEN:
1064         case SEC_E_LOGON_DENIED:
1065         case SEC_E_TARGET_UNKNOWN:
1066         case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1067         case SEC_E_INTERNAL_ERROR:
1068         case SEC_E_NO_CREDENTIALS:
1069         case SEC_E_UNSUPPORTED_FUNCTION:
1070         case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1071           */
1072         default:
1073           failf(data, "schannel: next InitializeSecurityContext failed: %s",
1074                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1075           return CURLE_SSL_CONNECT_ERROR;
1076       }
1077     }
1078 
1079     /* check if there was additional remaining encrypted data */
1080     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1081       DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
1082                    inbuf[1].cbBuffer));
1083       /*
1084         There are two cases where we could be getting extra data here:
1085         1) If we're renegotiating a connection and the handshake is already
1086         complete (from the server perspective), it can encrypted app data
1087         (not handshake data) in an extra buffer at this point.
1088         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1089         connection and this extra data is part of the handshake.
1090         We should process the data immediately; waiting for the socket to
1091         be ready may fail since the server is done sending handshake data.
1092       */
1093       /* check if the remaining data is less than the total amount
1094          and therefore begins after the already processed data */
1095       if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
1096         memmove(BACKEND->encdata_buffer,
1097                 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1098                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1099         BACKEND->encdata_offset = inbuf[1].cbBuffer;
1100         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1101           doread = FALSE;
1102           continue;
1103         }
1104       }
1105     }
1106     else {
1107       BACKEND->encdata_offset = 0;
1108     }
1109     break;
1110   }
1111 
1112   /* check if the handshake needs to be continued */
1113   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1114     connssl->connecting_state = ssl_connect_2_reading;
1115     return CURLE_OK;
1116   }
1117 
1118   /* check if the handshake is complete */
1119   if(sspi_status == SEC_E_OK) {
1120     connssl->connecting_state = ssl_connect_3;
1121     DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
1122   }
1123 
1124   pubkey_ptr = SSL_IS_PROXY() ?
1125     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1126     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1127   if(pubkey_ptr) {
1128     result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
1129     if(result) {
1130       failf(data, "SSL: public key does not match pinned public key!");
1131       return result;
1132     }
1133   }
1134 
1135 #ifdef HAS_MANUAL_VERIFY_API
1136   if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
1137     return Curl_verify_certificate(conn, sockindex);
1138   }
1139 #endif
1140 
1141   return CURLE_OK;
1142 }
1143 
1144 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1145 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1146 {
1147   return (cert_context != NULL) &&
1148     ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1149     (cert_context->pbCertEncoded != NULL) &&
1150     (cert_context->cbCertEncoded > 0);
1151 }
1152 
1153 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1154 
1155 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1156 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1157                     void *arg)
1158 {
1159   const CERT_CONTEXT *current_context = NULL;
1160   bool should_continue = true;
1161   while(should_continue &&
1162         (current_context = CertEnumCertificatesInStore(
1163           context->hCertStore,
1164           current_context)) != NULL)
1165     should_continue = func(current_context, arg);
1166 
1167   if(current_context)
1168     CertFreeCertificateContext(current_context);
1169 }
1170 
1171 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,void * certs_count)1172 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1173 {
1174   if(valid_cert_encoding(ccert_context))
1175     (*(int *)certs_count)++;
1176   return true;
1177 }
1178 
1179 struct Adder_args
1180 {
1181   struct connectdata *conn;
1182   CURLcode result;
1183   int idx;
1184 };
1185 
1186 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,void * raw_arg)1187 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1188 {
1189   struct Adder_args *args = (struct Adder_args*)raw_arg;
1190   args->result = CURLE_OK;
1191   if(valid_cert_encoding(ccert_context)) {
1192     const char *beg = (const char *) ccert_context->pbCertEncoded;
1193     const char *end = beg + ccert_context->cbCertEncoded;
1194     args->result = Curl_extract_certinfo(args->conn, (args->idx)++, beg, end);
1195   }
1196   return args->result == CURLE_OK;
1197 }
1198 
1199 static CURLcode
schannel_connect_step3(struct connectdata * conn,int sockindex)1200 schannel_connect_step3(struct connectdata *conn, int sockindex)
1201 {
1202   CURLcode result = CURLE_OK;
1203   struct Curl_easy *data = conn->data;
1204   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1205   SECURITY_STATUS sspi_status = SEC_E_OK;
1206   CERT_CONTEXT *ccert_context = NULL;
1207 #ifdef DEBUGBUILD
1208   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1209     conn->host.name;
1210 #endif
1211 #ifdef HAS_ALPN
1212   SecPkgContext_ApplicationProtocol alpn_result;
1213 #endif
1214 
1215   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1216 
1217   DEBUGF(infof(data,
1218                "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
1219                hostname, conn->remote_port));
1220 
1221   if(!BACKEND->cred)
1222     return CURLE_SSL_CONNECT_ERROR;
1223 
1224   /* check if the required context attributes are met */
1225   if(BACKEND->ret_flags != BACKEND->req_flags) {
1226     if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
1227       failf(data, "schannel: failed to setup sequence detection");
1228     if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
1229       failf(data, "schannel: failed to setup replay detection");
1230     if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
1231       failf(data, "schannel: failed to setup confidentiality");
1232     if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1233       failf(data, "schannel: failed to setup memory allocation");
1234     if(!(BACKEND->ret_flags & ISC_RET_STREAM))
1235       failf(data, "schannel: failed to setup stream orientation");
1236     return CURLE_SSL_CONNECT_ERROR;
1237   }
1238 
1239 #ifdef HAS_ALPN
1240   if(BACKEND->use_alpn) {
1241     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1242       SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
1243 
1244     if(sspi_status != SEC_E_OK) {
1245       failf(data, "schannel: failed to retrieve ALPN result");
1246       return CURLE_SSL_CONNECT_ERROR;
1247     }
1248 
1249     if(alpn_result.ProtoNegoStatus ==
1250        SecApplicationProtocolNegotiationStatus_Success) {
1251 
1252       infof(data, "schannel: ALPN, server accepted to use %.*s\n",
1253         alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1254 
1255 #ifdef USE_NGHTTP2
1256       if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
1257          !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
1258           NGHTTP2_PROTO_VERSION_ID_LEN)) {
1259         conn->negnpn = CURL_HTTP_VERSION_2;
1260       }
1261       else
1262 #endif
1263       if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1264          !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1265            ALPN_HTTP_1_1_LENGTH)) {
1266         conn->negnpn = CURL_HTTP_VERSION_1_1;
1267       }
1268     }
1269     else
1270       infof(data, "ALPN, server did not agree to a protocol\n");
1271     Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
1272                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1273   }
1274 #endif
1275 
1276   /* save the current session data for possible re-use */
1277   if(SSL_SET_OPTION(primary.sessionid)) {
1278     bool incache;
1279     struct curl_schannel_cred *old_cred = NULL;
1280 
1281     Curl_ssl_sessionid_lock(conn);
1282     incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
1283                                       sockindex));
1284     if(incache) {
1285       if(old_cred != BACKEND->cred) {
1286         DEBUGF(infof(data,
1287                      "schannel: old credential handle is stale, removing\n"));
1288         /* we're not taking old_cred ownership here, no refcount++ is needed */
1289         Curl_ssl_delsessionid(conn, (void *)old_cred);
1290         incache = FALSE;
1291       }
1292     }
1293     if(!incache) {
1294       result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
1295                                      sizeof(struct curl_schannel_cred),
1296                                      sockindex);
1297       if(result) {
1298         Curl_ssl_sessionid_unlock(conn);
1299         failf(data, "schannel: failed to store credential handle");
1300         return result;
1301       }
1302       else {
1303         /* this cred session is now also referenced by sessionid cache */
1304         BACKEND->cred->refcount++;
1305         DEBUGF(infof(data,
1306                      "schannel: stored credential handle in session cache\n"));
1307       }
1308     }
1309     Curl_ssl_sessionid_unlock(conn);
1310   }
1311 
1312   if(data->set.ssl.certinfo) {
1313     int certs_count = 0;
1314     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1315       SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
1316 
1317     if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
1318       failf(data, "schannel: failed to retrieve remote cert context");
1319       return CURLE_PEER_FAILED_VERIFICATION;
1320     }
1321 
1322     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1323 
1324     result = Curl_ssl_init_certinfo(data, certs_count);
1325     if(!result) {
1326       struct Adder_args args;
1327       args.conn = conn;
1328       args.idx = 0;
1329       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1330       result = args.result;
1331     }
1332     CertFreeCertificateContext(ccert_context);
1333     if(result)
1334       return result;
1335   }
1336 
1337   connssl->connecting_state = ssl_connect_done;
1338 
1339   return CURLE_OK;
1340 }
1341 
1342 static CURLcode
schannel_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1343 schannel_connect_common(struct connectdata *conn, int sockindex,
1344                         bool nonblocking, bool *done)
1345 {
1346   CURLcode result;
1347   struct Curl_easy *data = conn->data;
1348   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1349   curl_socket_t sockfd = conn->sock[sockindex];
1350   time_t timeout_ms;
1351   int what;
1352 
1353   /* check if the connection has already been established */
1354   if(ssl_connection_complete == connssl->state) {
1355     *done = TRUE;
1356     return CURLE_OK;
1357   }
1358 
1359   if(ssl_connect_1 == connssl->connecting_state) {
1360     /* check out how much more time we're allowed */
1361     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1362 
1363     if(timeout_ms < 0) {
1364       /* no need to continue if time already is up */
1365       failf(data, "SSL/TLS connection timeout");
1366       return CURLE_OPERATION_TIMEDOUT;
1367     }
1368 
1369     result = schannel_connect_step1(conn, sockindex);
1370     if(result)
1371       return result;
1372   }
1373 
1374   while(ssl_connect_2 == connssl->connecting_state ||
1375         ssl_connect_2_reading == connssl->connecting_state ||
1376         ssl_connect_2_writing == connssl->connecting_state) {
1377 
1378     /* check out how much more time we're allowed */
1379     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1380 
1381     if(timeout_ms < 0) {
1382       /* no need to continue if time already is up */
1383       failf(data, "SSL/TLS connection timeout");
1384       return CURLE_OPERATION_TIMEDOUT;
1385     }
1386 
1387     /* if ssl is expecting something, check if it's available. */
1388     if(connssl->connecting_state == ssl_connect_2_reading
1389        || connssl->connecting_state == ssl_connect_2_writing) {
1390 
1391       curl_socket_t writefd = ssl_connect_2_writing ==
1392         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1393       curl_socket_t readfd = ssl_connect_2_reading ==
1394         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1395 
1396       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1397                                nonblocking ? 0 : timeout_ms);
1398       if(what < 0) {
1399         /* fatal error */
1400         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1401         return CURLE_SSL_CONNECT_ERROR;
1402       }
1403       else if(0 == what) {
1404         if(nonblocking) {
1405           *done = FALSE;
1406           return CURLE_OK;
1407         }
1408         else {
1409           /* timeout */
1410           failf(data, "SSL/TLS connection timeout");
1411           return CURLE_OPERATION_TIMEDOUT;
1412         }
1413       }
1414       /* socket is readable or writable */
1415     }
1416 
1417     /* Run transaction, and return to the caller if it failed or if
1418      * this connection is part of a multi handle and this loop would
1419      * execute again. This permits the owner of a multi handle to
1420      * abort a connection attempt before step2 has completed while
1421      * ensuring that a client using select() or epoll() will always
1422      * have a valid fdset to wait on.
1423      */
1424     result = schannel_connect_step2(conn, sockindex);
1425     if(result || (nonblocking &&
1426                   (ssl_connect_2 == connssl->connecting_state ||
1427                    ssl_connect_2_reading == connssl->connecting_state ||
1428                    ssl_connect_2_writing == connssl->connecting_state)))
1429       return result;
1430 
1431   } /* repeat step2 until all transactions are done. */
1432 
1433   if(ssl_connect_3 == connssl->connecting_state) {
1434     result = schannel_connect_step3(conn, sockindex);
1435     if(result)
1436       return result;
1437   }
1438 
1439   if(ssl_connect_done == connssl->connecting_state) {
1440     connssl->state = ssl_connection_complete;
1441     conn->recv[sockindex] = schannel_recv;
1442     conn->send[sockindex] = schannel_send;
1443 
1444 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1445     /* When SSPI is used in combination with Schannel
1446      * we need the Schannel context to create the Schannel
1447      * binding to pass the IIS extended protection checks.
1448      * Available on Windows 7 or later.
1449      */
1450     conn->sslContext = &BACKEND->ctxt->ctxt_handle;
1451 #endif
1452 
1453     *done = TRUE;
1454   }
1455   else
1456     *done = FALSE;
1457 
1458   /* reset our connection state machine */
1459   connssl->connecting_state = ssl_connect_1;
1460 
1461   return CURLE_OK;
1462 }
1463 
1464 static ssize_t
schannel_send(struct connectdata * conn,int sockindex,const void * buf,size_t len,CURLcode * err)1465 schannel_send(struct connectdata *conn, int sockindex,
1466               const void *buf, size_t len, CURLcode *err)
1467 {
1468   ssize_t written = -1;
1469   size_t data_len = 0;
1470   unsigned char *data = NULL;
1471   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1472   SecBuffer outbuf[4];
1473   SecBufferDesc outbuf_desc;
1474   SECURITY_STATUS sspi_status = SEC_E_OK;
1475   CURLcode result;
1476 
1477   /* check if the maximum stream sizes were queried */
1478   if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1479     sspi_status = s_pSecFn->QueryContextAttributes(
1480       &BACKEND->ctxt->ctxt_handle,
1481       SECPKG_ATTR_STREAM_SIZES,
1482       &BACKEND->stream_sizes);
1483     if(sspi_status != SEC_E_OK) {
1484       *err = CURLE_SEND_ERROR;
1485       return -1;
1486     }
1487   }
1488 
1489   /* check if the buffer is longer than the maximum message length */
1490   if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1491     len = BACKEND->stream_sizes.cbMaximumMessage;
1492   }
1493 
1494   /* calculate the complete message length and allocate a buffer for it */
1495   data_len = BACKEND->stream_sizes.cbHeader + len +
1496     BACKEND->stream_sizes.cbTrailer;
1497   data = (unsigned char *) malloc(data_len);
1498   if(data == NULL) {
1499     *err = CURLE_OUT_OF_MEMORY;
1500     return -1;
1501   }
1502 
1503   /* setup output buffers (header, data, trailer, empty) */
1504   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1505                 data, BACKEND->stream_sizes.cbHeader);
1506   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1507                 data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1508   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1509                 data + BACKEND->stream_sizes.cbHeader + len,
1510                 BACKEND->stream_sizes.cbTrailer);
1511   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1512   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1513 
1514   /* copy data into output buffer */
1515   memcpy(outbuf[1].pvBuffer, buf, len);
1516 
1517   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1518   sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1519                                          &outbuf_desc, 0);
1520 
1521   /* check if the message was encrypted */
1522   if(sspi_status == SEC_E_OK) {
1523     written = 0;
1524 
1525     /* send the encrypted message including header, data and trailer */
1526     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1527 
1528     /*
1529       It's important to send the full message which includes the header,
1530       encrypted payload, and trailer.  Until the client receives all the
1531       data a coherent message has not been delivered and the client
1532       can't read any of it.
1533 
1534       If we wanted to buffer the unwritten encrypted bytes, we would
1535       tell the client that all data it has requested to be sent has been
1536       sent. The unwritten encrypted bytes would be the first bytes to
1537       send on the next invocation.
1538       Here's the catch with this - if we tell the client that all the
1539       bytes have been sent, will the client call this method again to
1540       send the buffered data?  Looking at who calls this function, it
1541       seems the answer is NO.
1542     */
1543 
1544     /* send entire message or fail */
1545     while(len > (size_t)written) {
1546       ssize_t this_write;
1547       time_t timeleft;
1548       int what;
1549 
1550       this_write = 0;
1551 
1552       timeleft = Curl_timeleft(conn->data, NULL, FALSE);
1553       if(timeleft < 0) {
1554         /* we already got the timeout */
1555         failf(conn->data, "schannel: timed out sending data "
1556               "(bytes sent: %zd)", written);
1557         *err = CURLE_OPERATION_TIMEDOUT;
1558         written = -1;
1559         break;
1560       }
1561 
1562       what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
1563       if(what < 0) {
1564         /* fatal error */
1565         failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1566         *err = CURLE_SEND_ERROR;
1567         written = -1;
1568         break;
1569       }
1570       else if(0 == what) {
1571         failf(conn->data, "schannel: timed out sending data "
1572               "(bytes sent: %zd)", written);
1573         *err = CURLE_OPERATION_TIMEDOUT;
1574         written = -1;
1575         break;
1576       }
1577       /* socket is writable */
1578 
1579       result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1580                                 len - written, &this_write);
1581       if(result == CURLE_AGAIN)
1582         continue;
1583       else if(result != CURLE_OK) {
1584         *err = result;
1585         written = -1;
1586         break;
1587       }
1588 
1589       written += this_write;
1590     }
1591   }
1592   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1593     *err = CURLE_OUT_OF_MEMORY;
1594   }
1595   else{
1596     *err = CURLE_SEND_ERROR;
1597   }
1598 
1599   Curl_safefree(data);
1600 
1601   if(len == (size_t)written)
1602     /* Encrypted message including header, data and trailer entirely sent.
1603        The return value is the number of unencrypted bytes that were sent. */
1604     written = outbuf[1].cbBuffer;
1605 
1606   return written;
1607 }
1608 
1609 static ssize_t
schannel_recv(struct connectdata * conn,int sockindex,char * buf,size_t len,CURLcode * err)1610 schannel_recv(struct connectdata *conn, int sockindex,
1611               char *buf, size_t len, CURLcode *err)
1612 {
1613   size_t size = 0;
1614   ssize_t nread = -1;
1615   struct Curl_easy *data = conn->data;
1616   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1617   unsigned char *reallocated_buffer;
1618   size_t reallocated_length;
1619   bool done = FALSE;
1620   SecBuffer inbuf[4];
1621   SecBufferDesc inbuf_desc;
1622   SECURITY_STATUS sspi_status = SEC_E_OK;
1623   /* we want the length of the encrypted buffer to be at least large enough
1624      that it can hold all the bytes requested and some TLS record overhead. */
1625   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1626 
1627   /****************************************************************************
1628    * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1629    * The pattern for return error is set *err, optional infof, goto cleanup.
1630    *
1631    * Our priority is to always return as much decrypted data to the caller as
1632    * possible, even if an error occurs. The state of the decrypted buffer must
1633    * always be valid. Transfer of decrypted data to the caller's buffer is
1634    * handled in the cleanup.
1635    */
1636 
1637   DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
1638   *err = CURLE_OK;
1639 
1640   if(len && len <= BACKEND->decdata_offset) {
1641     infof(data, "schannel: enough decrypted data is already available\n");
1642     goto cleanup;
1643   }
1644   else if(BACKEND->recv_unrecoverable_err) {
1645     *err = BACKEND->recv_unrecoverable_err;
1646     infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1647     goto cleanup;
1648   }
1649   else if(BACKEND->recv_sspi_close_notify) {
1650     /* once a server has indicated shutdown there is no more encrypted data */
1651     infof(data, "schannel: server indicated shutdown in a prior call\n");
1652     goto cleanup;
1653   }
1654   else if(!len) {
1655     /* It's debatable what to return when !len. Regardless we can't return
1656     immediately because there may be data to decrypt (in the case we want to
1657     decrypt all encrypted cached data) so handle !len later in cleanup.
1658     */
1659     ; /* do nothing */
1660   }
1661   else if(!BACKEND->recv_connection_closed) {
1662     /* increase enc buffer in order to fit the requested amount of data */
1663     size = BACKEND->encdata_length - BACKEND->encdata_offset;
1664     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1665        BACKEND->encdata_length < min_encdata_length) {
1666       reallocated_length = BACKEND->encdata_offset +
1667                            CURL_SCHANNEL_BUFFER_FREE_SIZE;
1668       if(reallocated_length < min_encdata_length) {
1669         reallocated_length = min_encdata_length;
1670       }
1671       reallocated_buffer = realloc(BACKEND->encdata_buffer,
1672                                    reallocated_length);
1673       if(reallocated_buffer == NULL) {
1674         *err = CURLE_OUT_OF_MEMORY;
1675         failf(data, "schannel: unable to re-allocate memory");
1676         goto cleanup;
1677       }
1678 
1679       BACKEND->encdata_buffer = reallocated_buffer;
1680       BACKEND->encdata_length = reallocated_length;
1681       size = BACKEND->encdata_length - BACKEND->encdata_offset;
1682       DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
1683                    BACKEND->encdata_length));
1684     }
1685 
1686     DEBUGF(infof(data,
1687                  "schannel: encrypted data buffer: offset %zu length %zu\n",
1688                  BACKEND->encdata_offset, BACKEND->encdata_length));
1689 
1690     /* read encrypted data from socket */
1691     *err = Curl_read_plain(conn->sock[sockindex],
1692                            (char *)(BACKEND->encdata_buffer +
1693                                     BACKEND->encdata_offset),
1694                            size, &nread);
1695     if(*err) {
1696       nread = -1;
1697       if(*err == CURLE_AGAIN)
1698         DEBUGF(infof(data,
1699                      "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
1700       else if(*err == CURLE_RECV_ERROR)
1701         infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1702       else
1703         infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1704     }
1705     else if(nread == 0) {
1706       BACKEND->recv_connection_closed = true;
1707       DEBUGF(infof(data, "schannel: server closed the connection\n"));
1708     }
1709     else if(nread > 0) {
1710       BACKEND->encdata_offset += (size_t)nread;
1711       BACKEND->encdata_is_incomplete = false;
1712       DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
1713     }
1714   }
1715 
1716   DEBUGF(infof(data,
1717                "schannel: encrypted data buffer: offset %zu length %zu\n",
1718                BACKEND->encdata_offset, BACKEND->encdata_length));
1719 
1720   /* decrypt loop */
1721   while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1722         (!len || BACKEND->decdata_offset < len ||
1723          BACKEND->recv_connection_closed)) {
1724     /* prepare data buffer for DecryptMessage call */
1725     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1726                   curlx_uztoul(BACKEND->encdata_offset));
1727 
1728     /* we need 3 more empty input buffers for possible output */
1729     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1730     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1731     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1732     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1733 
1734     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1735        */
1736     sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1737                                            &inbuf_desc, 0, NULL);
1738 
1739     /* check if everything went fine (server may want to renegotiate
1740        or shutdown the connection context) */
1741     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1742        sspi_status == SEC_I_CONTEXT_EXPIRED) {
1743       /* check for successfully decrypted data, even before actual
1744          renegotiation or shutdown of the connection context */
1745       if(inbuf[1].BufferType == SECBUFFER_DATA) {
1746         DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
1747                      inbuf[1].cbBuffer));
1748 
1749         /* increase buffer in order to fit the received amount of data */
1750         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1751                inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1752         if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1753            BACKEND->decdata_length < len) {
1754           /* increase internal decrypted data buffer */
1755           reallocated_length = BACKEND->decdata_offset + size;
1756           /* make sure that the requested amount of data fits */
1757           if(reallocated_length < len) {
1758             reallocated_length = len;
1759           }
1760           reallocated_buffer = realloc(BACKEND->decdata_buffer,
1761                                        reallocated_length);
1762           if(reallocated_buffer == NULL) {
1763             *err = CURLE_OUT_OF_MEMORY;
1764             failf(data, "schannel: unable to re-allocate memory");
1765             goto cleanup;
1766           }
1767           BACKEND->decdata_buffer = reallocated_buffer;
1768           BACKEND->decdata_length = reallocated_length;
1769         }
1770 
1771         /* copy decrypted data to internal buffer */
1772         size = inbuf[1].cbBuffer;
1773         if(size) {
1774           memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1775                  inbuf[1].pvBuffer, size);
1776           BACKEND->decdata_offset += size;
1777         }
1778 
1779         DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
1780         DEBUGF(infof(data,
1781                      "schannel: decrypted cached: offset %zu length %zu\n",
1782                      BACKEND->decdata_offset, BACKEND->decdata_length));
1783       }
1784 
1785       /* check for remaining encrypted data */
1786       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1787         DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
1788                      inbuf[3].cbBuffer));
1789 
1790         /* check if the remaining data is less than the total amount
1791          * and therefore begins after the already processed data
1792          */
1793         if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1794           /* move remaining encrypted data forward to the beginning of
1795              buffer */
1796           memmove(BACKEND->encdata_buffer,
1797                   (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1798                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1799           BACKEND->encdata_offset = inbuf[3].cbBuffer;
1800         }
1801 
1802         DEBUGF(infof(data,
1803                      "schannel: encrypted cached: offset %zu length %zu\n",
1804                      BACKEND->encdata_offset, BACKEND->encdata_length));
1805       }
1806       else {
1807         /* reset encrypted buffer offset, because there is no data remaining */
1808         BACKEND->encdata_offset = 0;
1809       }
1810 
1811       /* check if server wants to renegotiate the connection context */
1812       if(sspi_status == SEC_I_RENEGOTIATE) {
1813         infof(data, "schannel: remote party requests renegotiation\n");
1814         if(*err && *err != CURLE_AGAIN) {
1815           infof(data, "schannel: can't renogotiate, an error is pending\n");
1816           goto cleanup;
1817         }
1818         if(BACKEND->encdata_offset) {
1819           *err = CURLE_RECV_ERROR;
1820           infof(data, "schannel: can't renogotiate, "
1821                       "encrypted data available\n");
1822           goto cleanup;
1823         }
1824         /* begin renegotiation */
1825         infof(data, "schannel: renegotiating SSL/TLS connection\n");
1826         connssl->state = ssl_connection_negotiating;
1827         connssl->connecting_state = ssl_connect_2_writing;
1828         *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1829         if(*err) {
1830           infof(data, "schannel: renegotiation failed\n");
1831           goto cleanup;
1832         }
1833         /* now retry receiving data */
1834         sspi_status = SEC_E_OK;
1835         infof(data, "schannel: SSL/TLS connection renegotiated\n");
1836         continue;
1837       }
1838       /* check if the server closed the connection */
1839       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1840         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1841            returned so we have to work around that in cleanup. */
1842         BACKEND->recv_sspi_close_notify = true;
1843         if(!BACKEND->recv_connection_closed) {
1844           BACKEND->recv_connection_closed = true;
1845           infof(data, "schannel: server closed the connection\n");
1846         }
1847         goto cleanup;
1848       }
1849     }
1850     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1851       BACKEND->encdata_is_incomplete = true;
1852       if(!*err)
1853         *err = CURLE_AGAIN;
1854       infof(data, "schannel: failed to decrypt data, need more data\n");
1855       goto cleanup;
1856     }
1857     else {
1858       char buffer[STRERROR_LEN];
1859       *err = CURLE_RECV_ERROR;
1860       infof(data, "schannel: failed to read data from server: %s\n",
1861             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1862       goto cleanup;
1863     }
1864   }
1865 
1866   DEBUGF(infof(data,
1867                "schannel: encrypted data buffer: offset %zu length %zu\n",
1868                BACKEND->encdata_offset, BACKEND->encdata_length));
1869 
1870   DEBUGF(infof(data,
1871                "schannel: decrypted data buffer: offset %zu length %zu\n",
1872                BACKEND->decdata_offset, BACKEND->decdata_length));
1873 
1874 cleanup:
1875   /* Warning- there is no guarantee the encdata state is valid at this point */
1876   DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
1877 
1878   /* Error if the connection has closed without a close_notify.
1879   Behavior here is a matter of debate. We don't want to be vulnerable to a
1880   truncation attack however there's some browser precedent for ignoring the
1881   close_notify for compatibility reasons.
1882   Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1883   return close_notify. In that case if the connection was closed we assume it
1884   was graceful (close_notify) since there doesn't seem to be a way to tell.
1885   */
1886   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1887      !BACKEND->recv_sspi_close_notify) {
1888     bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1889                                                VERSION_EQUAL);
1890 
1891     if(isWin2k && sspi_status == SEC_E_OK)
1892       BACKEND->recv_sspi_close_notify = true;
1893     else {
1894       *err = CURLE_RECV_ERROR;
1895       infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1896     }
1897   }
1898 
1899   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1900   if(*err && *err != CURLE_AGAIN)
1901       BACKEND->recv_unrecoverable_err = *err;
1902 
1903   size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1904   if(size) {
1905     memcpy(buf, BACKEND->decdata_buffer, size);
1906     memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1907             BACKEND->decdata_offset - size);
1908     BACKEND->decdata_offset -= size;
1909     DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
1910     DEBUGF(infof(data,
1911                  "schannel: decrypted data buffer: offset %zu length %zu\n",
1912                  BACKEND->decdata_offset, BACKEND->decdata_length));
1913     *err = CURLE_OK;
1914     return (ssize_t)size;
1915   }
1916 
1917   if(!*err && !BACKEND->recv_connection_closed)
1918       *err = CURLE_AGAIN;
1919 
1920   /* It's debatable what to return when !len. We could return whatever error we
1921   got from decryption but instead we override here so the return is consistent.
1922   */
1923   if(!len)
1924     *err = CURLE_OK;
1925 
1926   return *err ? -1 : 0;
1927 }
1928 
Curl_schannel_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)1929 static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
1930                                                   int sockindex, bool *done)
1931 {
1932   return schannel_connect_common(conn, sockindex, TRUE, done);
1933 }
1934 
Curl_schannel_connect(struct connectdata * conn,int sockindex)1935 static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
1936 {
1937   CURLcode result;
1938   bool done = FALSE;
1939 
1940   result = schannel_connect_common(conn, sockindex, FALSE, &done);
1941   if(result)
1942     return result;
1943 
1944   DEBUGASSERT(done);
1945 
1946   return CURLE_OK;
1947 }
1948 
Curl_schannel_data_pending(const struct connectdata * conn,int sockindex)1949 static bool Curl_schannel_data_pending(const struct connectdata *conn,
1950                                        int sockindex)
1951 {
1952   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1953 
1954   if(connssl->use) /* SSL/TLS is in use */
1955     return (BACKEND->decdata_offset > 0 ||
1956             (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1957   else
1958     return FALSE;
1959 }
1960 
Curl_schannel_close(struct connectdata * conn,int sockindex)1961 static void Curl_schannel_close(struct connectdata *conn, int sockindex)
1962 {
1963   if(conn->ssl[sockindex].use)
1964     /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1965     Curl_ssl_shutdown(conn, sockindex);
1966 }
1967 
Curl_schannel_session_free(void * ptr)1968 static void Curl_schannel_session_free(void *ptr)
1969 {
1970   /* this is expected to be called under sessionid lock */
1971   struct curl_schannel_cred *cred = ptr;
1972 
1973   cred->refcount--;
1974   if(cred->refcount == 0) {
1975     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1976     Curl_safefree(cred);
1977   }
1978 }
1979 
Curl_schannel_shutdown(struct connectdata * conn,int sockindex)1980 static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1981 {
1982   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1983    * Shutting Down an Schannel Connection
1984    */
1985   struct Curl_easy *data = conn->data;
1986   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1987   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1988     conn->host.name;
1989 
1990   DEBUGASSERT(data);
1991 
1992   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1993         hostname, conn->remote_port);
1994 
1995   if(BACKEND->cred && BACKEND->ctxt) {
1996     SecBufferDesc BuffDesc;
1997     SecBuffer Buffer;
1998     SECURITY_STATUS sspi_status;
1999     SecBuffer outbuf;
2000     SecBufferDesc outbuf_desc;
2001     CURLcode result;
2002     TCHAR *host_name;
2003     DWORD dwshut = SCHANNEL_SHUTDOWN;
2004 
2005     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2006     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2007 
2008     sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
2009                                               &BuffDesc);
2010 
2011     if(sspi_status != SEC_E_OK) {
2012       char buffer[STRERROR_LEN];
2013       failf(data, "schannel: ApplyControlToken failure: %s",
2014             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2015     }
2016 
2017     host_name = Curl_convert_UTF8_to_tchar(hostname);
2018     if(!host_name)
2019       return CURLE_OUT_OF_MEMORY;
2020 
2021     /* setup output buffer */
2022     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2023     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2024 
2025     sspi_status = s_pSecFn->InitializeSecurityContext(
2026       &BACKEND->cred->cred_handle,
2027       &BACKEND->ctxt->ctxt_handle,
2028       host_name,
2029       BACKEND->req_flags,
2030       0,
2031       0,
2032       NULL,
2033       0,
2034       &BACKEND->ctxt->ctxt_handle,
2035       &outbuf_desc,
2036       &BACKEND->ret_flags,
2037       &BACKEND->ctxt->time_stamp);
2038 
2039     Curl_unicodefree(host_name);
2040 
2041     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2042       /* send close message which is in output buffer */
2043       ssize_t written;
2044       result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
2045                                 outbuf.cbBuffer, &written);
2046 
2047       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2048       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2049         infof(data, "schannel: failed to send close msg: %s"
2050               " (bytes written: %zd)\n", curl_easy_strerror(result), written);
2051       }
2052     }
2053   }
2054 
2055   /* free SSPI Schannel API security context handle */
2056   if(BACKEND->ctxt) {
2057     DEBUGF(infof(data, "schannel: clear security context handle\n"));
2058     s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
2059     Curl_safefree(BACKEND->ctxt);
2060   }
2061 
2062   /* free SSPI Schannel API credential handle */
2063   if(BACKEND->cred) {
2064     /*
2065      * When this function is called from Curl_schannel_close() the connection
2066      * might not have an associated transfer so the check for conn->data is
2067      * necessary.
2068      */
2069     Curl_ssl_sessionid_lock(conn);
2070     Curl_schannel_session_free(BACKEND->cred);
2071     Curl_ssl_sessionid_unlock(conn);
2072     BACKEND->cred = NULL;
2073   }
2074 
2075   /* free internal buffer for received encrypted data */
2076   if(BACKEND->encdata_buffer != NULL) {
2077     Curl_safefree(BACKEND->encdata_buffer);
2078     BACKEND->encdata_length = 0;
2079     BACKEND->encdata_offset = 0;
2080     BACKEND->encdata_is_incomplete = false;
2081   }
2082 
2083   /* free internal buffer for received decrypted data */
2084   if(BACKEND->decdata_buffer != NULL) {
2085     Curl_safefree(BACKEND->decdata_buffer);
2086     BACKEND->decdata_length = 0;
2087     BACKEND->decdata_offset = 0;
2088   }
2089 
2090   return CURLE_OK;
2091 }
2092 
Curl_schannel_init(void)2093 static int Curl_schannel_init(void)
2094 {
2095   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2096 }
2097 
Curl_schannel_cleanup(void)2098 static void Curl_schannel_cleanup(void)
2099 {
2100   Curl_sspi_global_cleanup();
2101 }
2102 
Curl_schannel_version(char * buffer,size_t size)2103 static size_t Curl_schannel_version(char *buffer, size_t size)
2104 {
2105   size = msnprintf(buffer, size, "Schannel");
2106 
2107   return size;
2108 }
2109 
Curl_schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2110 static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
2111                                      unsigned char *entropy, size_t length)
2112 {
2113   HCRYPTPROV hCryptProv = 0;
2114 
2115   (void)data;
2116 
2117   if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2118                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2119     return CURLE_FAILED_INIT;
2120 
2121   if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2122     CryptReleaseContext(hCryptProv, 0UL);
2123     return CURLE_FAILED_INIT;
2124   }
2125 
2126   CryptReleaseContext(hCryptProv, 0UL);
2127   return CURLE_OK;
2128 }
2129 
pkp_pin_peer_pubkey(struct connectdata * conn,int sockindex,const char * pinnedpubkey)2130 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
2131                                     const char *pinnedpubkey)
2132 {
2133   struct Curl_easy *data = conn->data;
2134   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2135   CERT_CONTEXT *pCertContextServer = NULL;
2136 
2137   /* Result is returned to caller */
2138   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2139 
2140   /* if a path wasn't specified, don't pin */
2141   if(!pinnedpubkey)
2142     return CURLE_OK;
2143 
2144   do {
2145     SECURITY_STATUS sspi_status;
2146     const char *x509_der;
2147     DWORD x509_der_len;
2148     curl_X509certificate x509_parsed;
2149     curl_asn1Element *pubkey;
2150 
2151     sspi_status =
2152       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
2153                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2154                                        &pCertContextServer);
2155 
2156     if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
2157       char buffer[STRERROR_LEN];
2158       failf(data, "schannel: Failed to read remote certificate context: %s",
2159             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2160       break; /* failed */
2161     }
2162 
2163 
2164     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2165        (pCertContextServer->cbCertEncoded > 0)))
2166       break;
2167 
2168     x509_der = (const char *)pCertContextServer->pbCertEncoded;
2169     x509_der_len = pCertContextServer->cbCertEncoded;
2170     memset(&x509_parsed, 0, sizeof(x509_parsed));
2171     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2172       break;
2173 
2174     pubkey = &x509_parsed.subjectPublicKeyInfo;
2175     if(!pubkey->header || pubkey->end <= pubkey->header) {
2176       failf(data, "SSL: failed retrieving public key from server certificate");
2177       break;
2178     }
2179 
2180     result = Curl_pin_peer_pubkey(data,
2181                                   pinnedpubkey,
2182                                   (const unsigned char *)pubkey->header,
2183                                   (size_t)(pubkey->end - pubkey->header));
2184     if(result) {
2185       failf(data, "SSL: public key does not match pinned public key!");
2186     }
2187   } while(0);
2188 
2189   if(pCertContextServer)
2190     CertFreeCertificateContext(pCertContextServer);
2191 
2192   return result;
2193 }
2194 
Curl_schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2195 static void Curl_schannel_checksum(const unsigned char *input,
2196                                    size_t inputlen,
2197                                    unsigned char *checksum,
2198                                    size_t checksumlen,
2199                                    DWORD provType,
2200                                    const unsigned int algId)
2201 {
2202   HCRYPTPROV hProv = 0;
2203   HCRYPTHASH hHash = 0;
2204   DWORD cbHashSize = 0;
2205   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2206   DWORD dwChecksumLen = (DWORD)checksumlen;
2207 
2208   /* since this can fail in multiple ways, zero memory first so we never
2209    * return old data
2210    */
2211   memset(checksum, 0, checksumlen);
2212 
2213   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2214                           CRYPT_VERIFYCONTEXT))
2215     return; /* failed */
2216 
2217   do {
2218     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2219       break; /* failed */
2220 
2221     /* workaround for original MinGW, should be (const BYTE*) */
2222     if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2223       break; /* failed */
2224 
2225     /* get hash size */
2226     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2227                           &dwHashSizeLen, 0))
2228       break; /* failed */
2229 
2230     /* check hash size */
2231     if(checksumlen < cbHashSize)
2232       break; /* failed */
2233 
2234     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2235       break; /* failed */
2236   } while(0);
2237 
2238   if(hHash)
2239     CryptDestroyHash(hHash);
2240 
2241   if(hProv)
2242     CryptReleaseContext(hProv, 0);
2243 }
2244 
Curl_schannel_md5sum(unsigned char * input,size_t inputlen,unsigned char * md5sum,size_t md5len)2245 static CURLcode Curl_schannel_md5sum(unsigned char *input,
2246                                      size_t inputlen,
2247                                      unsigned char *md5sum,
2248                                      size_t md5len)
2249 {
2250   Curl_schannel_checksum(input, inputlen, md5sum, md5len,
2251                          PROV_RSA_FULL, CALG_MD5);
2252   return CURLE_OK;
2253 }
2254 
Curl_schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2255 static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
2256                                     size_t inputlen,
2257                                     unsigned char *sha256sum,
2258                                     size_t sha256len)
2259 {
2260   Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
2261                          PROV_RSA_AES, CALG_SHA_256);
2262   return CURLE_OK;
2263 }
2264 
Curl_schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2265 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
2266                                          CURLINFO info UNUSED_PARAM)
2267 {
2268   (void)info;
2269   return &BACKEND->ctxt->ctxt_handle;
2270 }
2271 
2272 const struct Curl_ssl Curl_ssl_schannel = {
2273   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2274 
2275   SSLSUPP_CERTINFO |
2276   SSLSUPP_PINNEDPUBKEY,
2277 
2278   sizeof(struct ssl_backend_data),
2279 
2280   Curl_schannel_init,                /* init */
2281   Curl_schannel_cleanup,             /* cleanup */
2282   Curl_schannel_version,             /* version */
2283   Curl_none_check_cxn,               /* check_cxn */
2284   Curl_schannel_shutdown,            /* shutdown */
2285   Curl_schannel_data_pending,        /* data_pending */
2286   Curl_schannel_random,              /* random */
2287   Curl_none_cert_status_request,     /* cert_status_request */
2288   Curl_schannel_connect,             /* connect */
2289   Curl_schannel_connect_nonblocking, /* connect_nonblocking */
2290   Curl_schannel_get_internals,       /* get_internals */
2291   Curl_schannel_close,               /* close_one */
2292   Curl_none_close_all,               /* close_all */
2293   Curl_schannel_session_free,        /* session_free */
2294   Curl_none_set_engine,              /* set_engine */
2295   Curl_none_set_engine_default,      /* set_engine_default */
2296   Curl_none_engines_list,            /* engines_list */
2297   Curl_none_false_start,             /* false_start */
2298   Curl_schannel_md5sum,              /* md5sum */
2299   Curl_schannel_sha256sum            /* sha256sum */
2300 };
2301 
2302 #endif /* USE_SCHANNEL */
2303