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 - 2020, 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     case CURL_SSLVERSION_TLSv1_0:
558     case CURL_SSLVERSION_TLSv1_1:
559     case CURL_SSLVERSION_TLSv1_2:
560     case CURL_SSLVERSION_TLSv1_3:
561       {
562         result = set_ssl_version_min_max(&schannel_cred, conn);
563         if(result != CURLE_OK)
564           return result;
565         break;
566       }
567     case CURL_SSLVERSION_SSLv3:
568       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
569       break;
570     case CURL_SSLVERSION_SSLv2:
571       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
572       break;
573     default:
574       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
575       return CURLE_SSL_CONNECT_ERROR;
576     }
577 
578     if(SSL_CONN_CONFIG(cipher_list)) {
579       result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
580       if(CURLE_OK != result) {
581         failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
582         return result;
583       }
584     }
585 
586 
587 #ifdef HAS_CLIENT_CERT_PATH
588     /* client certificate */
589     if(data->set.ssl.cert) {
590       DWORD cert_store_name;
591       TCHAR *cert_store_path;
592       TCHAR *cert_thumbprint_str;
593       CRYPT_HASH_BLOB cert_thumbprint;
594       BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
595       HCERTSTORE cert_store;
596 
597       TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
598       if(!cert_path)
599         return CURLE_OUT_OF_MEMORY;
600 
601       result = get_cert_location(cert_path, &cert_store_name,
602                                  &cert_store_path, &cert_thumbprint_str);
603       if(result != CURLE_OK) {
604         failf(data, "schannel: Failed to get certificate location for %s",
605               cert_path);
606         Curl_unicodefree(cert_path);
607         return result;
608       }
609 
610       cert_store =
611         CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
612                       (HCRYPTPROV)NULL,
613                       CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
614                       cert_store_path);
615       if(!cert_store) {
616         failf(data, "schannel: Failed to open cert store %x %s, "
617               "last error is %x",
618               cert_store_name, cert_store_path, GetLastError());
619         free(cert_store_path);
620         Curl_unicodefree(cert_path);
621         return CURLE_SSL_CERTPROBLEM;
622       }
623       free(cert_store_path);
624 
625       cert_thumbprint.pbData = cert_thumbprint_data;
626       cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
627 
628       if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
629                               CRYPT_STRING_HEX,
630                               cert_thumbprint_data, &cert_thumbprint.cbData,
631                               NULL, NULL)) {
632         Curl_unicodefree(cert_path);
633         return CURLE_SSL_CERTPROBLEM;
634       }
635 
636       client_certs[0] = CertFindCertificateInStore(
637         cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
638         CERT_FIND_HASH, &cert_thumbprint, NULL);
639 
640       Curl_unicodefree(cert_path);
641 
642       if(client_certs[0]) {
643         schannel_cred.cCreds = 1;
644         schannel_cred.paCred = client_certs;
645       }
646       else {
647         /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
648         return CURLE_SSL_CERTPROBLEM;
649       }
650 
651       CertCloseStore(cert_store, 0);
652     }
653 #else
654     if(data->set.ssl.cert) {
655       failf(data, "schannel: client cert support not built in");
656       return CURLE_NOT_BUILT_IN;
657     }
658 #endif
659 
660     /* allocate memory for the re-usable credential handle */
661     BACKEND->cred = (struct curl_schannel_cred *)
662       calloc(1, sizeof(struct curl_schannel_cred));
663     if(!BACKEND->cred) {
664       failf(data, "schannel: unable to allocate memory");
665 
666       if(client_certs[0])
667         CertFreeCertificateContext(client_certs[0]);
668 
669       return CURLE_OUT_OF_MEMORY;
670     }
671     BACKEND->cred->refcount = 1;
672 
673     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
674        */
675     sspi_status =
676       s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
677                                          SECPKG_CRED_OUTBOUND, NULL,
678                                          &schannel_cred, NULL, NULL,
679                                          &BACKEND->cred->cred_handle,
680                                          &BACKEND->cred->time_stamp);
681 
682     if(client_certs[0])
683       CertFreeCertificateContext(client_certs[0]);
684 
685     if(sspi_status != SEC_E_OK) {
686       char buffer[STRERROR_LEN];
687       failf(data, "schannel: AcquireCredentialsHandle failed: %s",
688             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
689       Curl_safefree(BACKEND->cred);
690       switch(sspi_status) {
691         case SEC_E_INSUFFICIENT_MEMORY:
692           return CURLE_OUT_OF_MEMORY;
693         case SEC_E_NO_CREDENTIALS:
694         case SEC_E_SECPKG_NOT_FOUND:
695         case SEC_E_NOT_OWNER:
696         case SEC_E_UNKNOWN_CREDENTIALS:
697         case SEC_E_INTERNAL_ERROR:
698         default:
699           return CURLE_SSL_CONNECT_ERROR;
700       }
701     }
702   }
703 
704   /* Warn if SNI is disabled due to use of an IP address */
705   if(Curl_inet_pton(AF_INET, hostname, &addr)
706 #ifdef ENABLE_IPV6
707      || Curl_inet_pton(AF_INET6, hostname, &addr6)
708 #endif
709     ) {
710     infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
711   }
712 
713 #ifdef HAS_ALPN
714   if(BACKEND->use_alpn) {
715     int cur = 0;
716     int list_start_index = 0;
717     unsigned int *extension_len = NULL;
718     unsigned short* list_len = NULL;
719 
720     /* The first four bytes will be an unsigned int indicating number
721        of bytes of data in the rest of the the buffer. */
722     extension_len = (unsigned int *)(&alpn_buffer[cur]);
723     cur += sizeof(unsigned int);
724 
725     /* The next four bytes are an indicator that this buffer will contain
726        ALPN data, as opposed to NPN, for example. */
727     *(unsigned int *)&alpn_buffer[cur] =
728       SecApplicationProtocolNegotiationExt_ALPN;
729     cur += sizeof(unsigned int);
730 
731     /* The next two bytes will be an unsigned short indicating the number
732        of bytes used to list the preferred protocols. */
733     list_len = (unsigned short*)(&alpn_buffer[cur]);
734     cur += sizeof(unsigned short);
735 
736     list_start_index = cur;
737 
738 #ifdef USE_NGHTTP2
739     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
740       memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
741       cur += NGHTTP2_PROTO_ALPN_LEN;
742       infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
743     }
744 #endif
745 
746     alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
747     memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
748     cur += ALPN_HTTP_1_1_LENGTH;
749     infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
750 
751     *list_len = curlx_uitous(cur - list_start_index);
752     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
753 
754     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
755     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
756   }
757   else {
758     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
759     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
760   }
761 #else /* HAS_ALPN */
762   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
763   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
764 #endif
765 
766   /* setup output buffer */
767   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
768   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
769 
770   /* setup request flags */
771   BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
772     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
773     ISC_REQ_STREAM;
774 
775   /* allocate memory for the security context handle */
776   BACKEND->ctxt = (struct curl_schannel_ctxt *)
777     calloc(1, sizeof(struct curl_schannel_ctxt));
778   if(!BACKEND->ctxt) {
779     failf(data, "schannel: unable to allocate memory");
780     return CURLE_OUT_OF_MEMORY;
781   }
782 
783   host_name = Curl_convert_UTF8_to_tchar(hostname);
784   if(!host_name)
785     return CURLE_OUT_OF_MEMORY;
786 
787   /* Schannel InitializeSecurityContext:
788      https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
789 
790      At the moment we don't pass inbuf unless we're using ALPN since we only
791      use it for that, and Wine (for which we currently disable ALPN) is giving
792      us problems with inbuf regardless. https://github.com/curl/curl/issues/983
793   */
794   sspi_status = s_pSecFn->InitializeSecurityContext(
795     &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
796     (BACKEND->use_alpn ? &inbuf_desc : NULL),
797     0, &BACKEND->ctxt->ctxt_handle,
798     &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
799 
800   Curl_unicodefree(host_name);
801 
802   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
803     char buffer[STRERROR_LEN];
804     Curl_safefree(BACKEND->ctxt);
805     switch(sspi_status) {
806       case SEC_E_INSUFFICIENT_MEMORY:
807         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
808               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
809         return CURLE_OUT_OF_MEMORY;
810       case SEC_E_WRONG_PRINCIPAL:
811         failf(data, "schannel: SNI or certificate check failed: %s",
812               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
813         return CURLE_PEER_FAILED_VERIFICATION;
814         /*
815       case SEC_E_INVALID_HANDLE:
816       case SEC_E_INVALID_TOKEN:
817       case SEC_E_LOGON_DENIED:
818       case SEC_E_TARGET_UNKNOWN:
819       case SEC_E_NO_AUTHENTICATING_AUTHORITY:
820       case SEC_E_INTERNAL_ERROR:
821       case SEC_E_NO_CREDENTIALS:
822       case SEC_E_UNSUPPORTED_FUNCTION:
823       case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
824         */
825       default:
826         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
827               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
828         return CURLE_SSL_CONNECT_ERROR;
829     }
830   }
831 
832   DEBUGF(infof(data, "schannel: sending initial handshake data: "
833                "sending %lu bytes...\n", outbuf.cbBuffer));
834 
835   /* send initial handshake data which is now stored in output buffer */
836   result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
837                             outbuf.cbBuffer, &written);
838   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
839   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
840     failf(data, "schannel: failed to send initial handshake data: "
841           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
842     return CURLE_SSL_CONNECT_ERROR;
843   }
844 
845   DEBUGF(infof(data, "schannel: sent initial handshake data: "
846                "sent %zd bytes\n", written));
847 
848   BACKEND->recv_unrecoverable_err = CURLE_OK;
849   BACKEND->recv_sspi_close_notify = false;
850   BACKEND->recv_connection_closed = false;
851   BACKEND->encdata_is_incomplete = false;
852 
853   /* continue to second handshake step */
854   connssl->connecting_state = ssl_connect_2;
855 
856   return CURLE_OK;
857 }
858 
859 static CURLcode
schannel_connect_step2(struct connectdata * conn,int sockindex)860 schannel_connect_step2(struct connectdata *conn, int sockindex)
861 {
862   int i;
863   ssize_t nread = -1, written = -1;
864   struct Curl_easy *data = conn->data;
865   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
866   unsigned char *reallocated_buffer;
867   SecBuffer outbuf[3];
868   SecBufferDesc outbuf_desc;
869   SecBuffer inbuf[2];
870   SecBufferDesc inbuf_desc;
871   SECURITY_STATUS sspi_status = SEC_E_OK;
872   CURLcode result;
873   bool doread;
874   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
875     conn->host.name;
876   const char *pubkey_ptr;
877 
878   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
879 
880   DEBUGF(infof(data,
881                "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
882                hostname, conn->remote_port));
883 
884   if(!BACKEND->cred || !BACKEND->ctxt)
885     return CURLE_SSL_CONNECT_ERROR;
886 
887   /* buffer to store previously received and decrypted data */
888   if(BACKEND->decdata_buffer == NULL) {
889     BACKEND->decdata_offset = 0;
890     BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
891     BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
892     if(BACKEND->decdata_buffer == NULL) {
893       failf(data, "schannel: unable to allocate memory");
894       return CURLE_OUT_OF_MEMORY;
895     }
896   }
897 
898   /* buffer to store previously received and encrypted data */
899   if(BACKEND->encdata_buffer == NULL) {
900     BACKEND->encdata_is_incomplete = false;
901     BACKEND->encdata_offset = 0;
902     BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
903     BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
904     if(BACKEND->encdata_buffer == NULL) {
905       failf(data, "schannel: unable to allocate memory");
906       return CURLE_OUT_OF_MEMORY;
907     }
908   }
909 
910   /* if we need a bigger buffer to read a full message, increase buffer now */
911   if(BACKEND->encdata_length - BACKEND->encdata_offset <
912      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
913     /* increase internal encrypted data buffer */
914     size_t reallocated_length = BACKEND->encdata_offset +
915       CURL_SCHANNEL_BUFFER_FREE_SIZE;
916     reallocated_buffer = realloc(BACKEND->encdata_buffer,
917                                  reallocated_length);
918 
919     if(reallocated_buffer == NULL) {
920       failf(data, "schannel: unable to re-allocate memory");
921       return CURLE_OUT_OF_MEMORY;
922     }
923     else {
924       BACKEND->encdata_buffer = reallocated_buffer;
925       BACKEND->encdata_length = reallocated_length;
926     }
927   }
928 
929   for(;;) {
930     TCHAR *host_name;
931     if(doread) {
932       /* read encrypted handshake data from socket */
933       result = Curl_read_plain(conn->sock[sockindex],
934                                (char *) (BACKEND->encdata_buffer +
935                                          BACKEND->encdata_offset),
936                                BACKEND->encdata_length -
937                                BACKEND->encdata_offset,
938                                &nread);
939       if(result == CURLE_AGAIN) {
940         if(connssl->connecting_state != ssl_connect_2_writing)
941           connssl->connecting_state = ssl_connect_2_reading;
942         DEBUGF(infof(data, "schannel: failed to receive handshake, "
943                      "need more data\n"));
944         return CURLE_OK;
945       }
946       else if((result != CURLE_OK) || (nread == 0)) {
947         failf(data, "schannel: failed to receive handshake, "
948               "SSL/TLS connection failed");
949         return CURLE_SSL_CONNECT_ERROR;
950       }
951 
952       /* increase encrypted data buffer offset */
953       BACKEND->encdata_offset += nread;
954       BACKEND->encdata_is_incomplete = false;
955       DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
956     }
957 
958     DEBUGF(infof(data,
959                  "schannel: encrypted data buffer: offset %zu length %zu\n",
960                  BACKEND->encdata_offset, BACKEND->encdata_length));
961 
962     /* setup input buffers */
963     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
964                   curlx_uztoul(BACKEND->encdata_offset));
965     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
966     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
967 
968     /* setup output buffers */
969     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
970     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
971     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
972     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
973 
974     if(inbuf[0].pvBuffer == NULL) {
975       failf(data, "schannel: unable to allocate memory");
976       return CURLE_OUT_OF_MEMORY;
977     }
978 
979     /* copy received handshake data into input buffer */
980     memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
981            BACKEND->encdata_offset);
982 
983     host_name = Curl_convert_UTF8_to_tchar(hostname);
984     if(!host_name)
985       return CURLE_OUT_OF_MEMORY;
986 
987     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
988        */
989     sspi_status = s_pSecFn->InitializeSecurityContext(
990       &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
991       host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
992       &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
993 
994     Curl_unicodefree(host_name);
995 
996     /* free buffer for received handshake data */
997     Curl_safefree(inbuf[0].pvBuffer);
998 
999     /* check if the handshake was incomplete */
1000     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1001       BACKEND->encdata_is_incomplete = true;
1002       connssl->connecting_state = ssl_connect_2_reading;
1003       DEBUGF(infof(data,
1004                    "schannel: received incomplete message, need more data\n"));
1005       return CURLE_OK;
1006     }
1007 
1008     /* If the server has requested a client certificate, attempt to continue
1009        the handshake without one. This will allow connections to servers which
1010        request a client certificate but do not require it. */
1011     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1012        !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1013       BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1014       connssl->connecting_state = ssl_connect_2_writing;
1015       DEBUGF(infof(data,
1016                    "schannel: a client certificate has been requested\n"));
1017       return CURLE_OK;
1018     }
1019 
1020     /* check if the handshake needs to be continued */
1021     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1022       for(i = 0; i < 3; i++) {
1023         /* search for handshake tokens that need to be send */
1024         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1025           DEBUGF(infof(data, "schannel: sending next handshake data: "
1026                        "sending %lu bytes...\n", outbuf[i].cbBuffer));
1027 
1028           /* send handshake token to server */
1029           result = Curl_write_plain(conn, conn->sock[sockindex],
1030                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1031                                     &written);
1032           if((result != CURLE_OK) ||
1033              (outbuf[i].cbBuffer != (size_t) written)) {
1034             failf(data, "schannel: failed to send next handshake data: "
1035                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1036             return CURLE_SSL_CONNECT_ERROR;
1037           }
1038         }
1039 
1040         /* free obsolete buffer */
1041         if(outbuf[i].pvBuffer != NULL) {
1042           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1043         }
1044       }
1045     }
1046     else {
1047       char buffer[STRERROR_LEN];
1048       switch(sspi_status) {
1049         case SEC_E_INSUFFICIENT_MEMORY:
1050           failf(data, "schannel: next InitializeSecurityContext failed: %s",
1051                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1052           return CURLE_OUT_OF_MEMORY;
1053         case SEC_E_WRONG_PRINCIPAL:
1054           failf(data, "schannel: SNI or certificate check failed: %s",
1055                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1056           return CURLE_PEER_FAILED_VERIFICATION;
1057           /*
1058         case SEC_E_INVALID_HANDLE:
1059         case SEC_E_INVALID_TOKEN:
1060         case SEC_E_LOGON_DENIED:
1061         case SEC_E_TARGET_UNKNOWN:
1062         case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1063         case SEC_E_INTERNAL_ERROR:
1064         case SEC_E_NO_CREDENTIALS:
1065         case SEC_E_UNSUPPORTED_FUNCTION:
1066         case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1067           */
1068         default:
1069           failf(data, "schannel: next InitializeSecurityContext failed: %s",
1070                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1071           return CURLE_SSL_CONNECT_ERROR;
1072       }
1073     }
1074 
1075     /* check if there was additional remaining encrypted data */
1076     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1077       DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
1078                    inbuf[1].cbBuffer));
1079       /*
1080         There are two cases where we could be getting extra data here:
1081         1) If we're renegotiating a connection and the handshake is already
1082         complete (from the server perspective), it can encrypted app data
1083         (not handshake data) in an extra buffer at this point.
1084         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1085         connection and this extra data is part of the handshake.
1086         We should process the data immediately; waiting for the socket to
1087         be ready may fail since the server is done sending handshake data.
1088       */
1089       /* check if the remaining data is less than the total amount
1090          and therefore begins after the already processed data */
1091       if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
1092         memmove(BACKEND->encdata_buffer,
1093                 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1094                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1095         BACKEND->encdata_offset = inbuf[1].cbBuffer;
1096         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1097           doread = FALSE;
1098           continue;
1099         }
1100       }
1101     }
1102     else {
1103       BACKEND->encdata_offset = 0;
1104     }
1105     break;
1106   }
1107 
1108   /* check if the handshake needs to be continued */
1109   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1110     connssl->connecting_state = ssl_connect_2_reading;
1111     return CURLE_OK;
1112   }
1113 
1114   /* check if the handshake is complete */
1115   if(sspi_status == SEC_E_OK) {
1116     connssl->connecting_state = ssl_connect_3;
1117     DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
1118   }
1119 
1120   pubkey_ptr = SSL_IS_PROXY() ?
1121     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1122     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1123   if(pubkey_ptr) {
1124     result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
1125     if(result) {
1126       failf(data, "SSL: public key does not match pinned public key!");
1127       return result;
1128     }
1129   }
1130 
1131 #ifdef HAS_MANUAL_VERIFY_API
1132   if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
1133     return Curl_verify_certificate(conn, sockindex);
1134   }
1135 #endif
1136 
1137   return CURLE_OK;
1138 }
1139 
1140 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1141 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1142 {
1143   return (cert_context != NULL) &&
1144     ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1145     (cert_context->pbCertEncoded != NULL) &&
1146     (cert_context->cbCertEncoded > 0);
1147 }
1148 
1149 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1150 
1151 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1152 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1153                     void *arg)
1154 {
1155   const CERT_CONTEXT *current_context = NULL;
1156   bool should_continue = true;
1157   while(should_continue &&
1158         (current_context = CertEnumCertificatesInStore(
1159           context->hCertStore,
1160           current_context)) != NULL)
1161     should_continue = func(current_context, arg);
1162 
1163   if(current_context)
1164     CertFreeCertificateContext(current_context);
1165 }
1166 
1167 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,void * certs_count)1168 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1169 {
1170   if(valid_cert_encoding(ccert_context))
1171     (*(int *)certs_count)++;
1172   return true;
1173 }
1174 
1175 struct Adder_args
1176 {
1177   struct connectdata *conn;
1178   CURLcode result;
1179   int idx;
1180   int certs_count;
1181 };
1182 
1183 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,void * raw_arg)1184 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1185 {
1186   struct Adder_args *args = (struct Adder_args*)raw_arg;
1187   args->result = CURLE_OK;
1188   if(valid_cert_encoding(ccert_context)) {
1189     const char *beg = (const char *) ccert_context->pbCertEncoded;
1190     const char *end = beg + ccert_context->cbCertEncoded;
1191     int insert_index = (args->certs_count - 1) - args->idx;
1192     args->result = Curl_extract_certinfo(args->conn, insert_index, beg, end);
1193     args->idx++;
1194   }
1195   return args->result == CURLE_OK;
1196 }
1197 
1198 static CURLcode
schannel_connect_step3(struct connectdata * conn,int sockindex)1199 schannel_connect_step3(struct connectdata *conn, int sockindex)
1200 {
1201   CURLcode result = CURLE_OK;
1202   struct Curl_easy *data = conn->data;
1203   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1204   SECURITY_STATUS sspi_status = SEC_E_OK;
1205   CERT_CONTEXT *ccert_context = NULL;
1206 #ifdef DEBUGBUILD
1207   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1208     conn->host.name;
1209 #endif
1210 #ifdef HAS_ALPN
1211   SecPkgContext_ApplicationProtocol alpn_result;
1212 #endif
1213 
1214   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1215 
1216   DEBUGF(infof(data,
1217                "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
1218                hostname, conn->remote_port));
1219 
1220   if(!BACKEND->cred)
1221     return CURLE_SSL_CONNECT_ERROR;
1222 
1223   /* check if the required context attributes are met */
1224   if(BACKEND->ret_flags != BACKEND->req_flags) {
1225     if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
1226       failf(data, "schannel: failed to setup sequence detection");
1227     if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
1228       failf(data, "schannel: failed to setup replay detection");
1229     if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
1230       failf(data, "schannel: failed to setup confidentiality");
1231     if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1232       failf(data, "schannel: failed to setup memory allocation");
1233     if(!(BACKEND->ret_flags & ISC_RET_STREAM))
1234       failf(data, "schannel: failed to setup stream orientation");
1235     return CURLE_SSL_CONNECT_ERROR;
1236   }
1237 
1238 #ifdef HAS_ALPN
1239   if(BACKEND->use_alpn) {
1240     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1241       SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
1242 
1243     if(sspi_status != SEC_E_OK) {
1244       failf(data, "schannel: failed to retrieve ALPN result");
1245       return CURLE_SSL_CONNECT_ERROR;
1246     }
1247 
1248     if(alpn_result.ProtoNegoStatus ==
1249        SecApplicationProtocolNegotiationStatus_Success) {
1250 
1251       infof(data, "schannel: ALPN, server accepted to use %.*s\n",
1252         alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1253 
1254 #ifdef USE_NGHTTP2
1255       if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
1256          !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
1257           NGHTTP2_PROTO_VERSION_ID_LEN)) {
1258         conn->negnpn = CURL_HTTP_VERSION_2;
1259       }
1260       else
1261 #endif
1262       if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1263          !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1264            ALPN_HTTP_1_1_LENGTH)) {
1265         conn->negnpn = CURL_HTTP_VERSION_1_1;
1266       }
1267     }
1268     else
1269       infof(data, "ALPN, server did not agree to a protocol\n");
1270     Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
1271                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1272   }
1273 #endif
1274 
1275   /* save the current session data for possible re-use */
1276   if(SSL_SET_OPTION(primary.sessionid)) {
1277     bool incache;
1278     struct curl_schannel_cred *old_cred = NULL;
1279 
1280     Curl_ssl_sessionid_lock(conn);
1281     incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
1282                                       sockindex));
1283     if(incache) {
1284       if(old_cred != BACKEND->cred) {
1285         DEBUGF(infof(data,
1286                      "schannel: old credential handle is stale, removing\n"));
1287         /* we're not taking old_cred ownership here, no refcount++ is needed */
1288         Curl_ssl_delsessionid(conn, (void *)old_cred);
1289         incache = FALSE;
1290       }
1291     }
1292     if(!incache) {
1293       result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
1294                                      sizeof(struct curl_schannel_cred),
1295                                      sockindex);
1296       if(result) {
1297         Curl_ssl_sessionid_unlock(conn);
1298         failf(data, "schannel: failed to store credential handle");
1299         return result;
1300       }
1301       else {
1302         /* this cred session is now also referenced by sessionid cache */
1303         BACKEND->cred->refcount++;
1304         DEBUGF(infof(data,
1305                      "schannel: stored credential handle in session cache\n"));
1306       }
1307     }
1308     Curl_ssl_sessionid_unlock(conn);
1309   }
1310 
1311   if(data->set.ssl.certinfo) {
1312     int certs_count = 0;
1313     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1314       SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
1315 
1316     if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
1317       failf(data, "schannel: failed to retrieve remote cert context");
1318       return CURLE_PEER_FAILED_VERIFICATION;
1319     }
1320 
1321     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1322 
1323     result = Curl_ssl_init_certinfo(data, certs_count);
1324     if(!result) {
1325       struct Adder_args args;
1326       args.conn = conn;
1327       args.idx = 0;
1328       args.certs_count = certs_count;
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   timediff_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 : (time_t)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       timediff_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 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1859       char buffer[STRERROR_LEN];
1860 #endif
1861       *err = CURLE_RECV_ERROR;
1862       infof(data, "schannel: failed to read data from server: %s\n",
1863             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1864       goto cleanup;
1865     }
1866   }
1867 
1868   DEBUGF(infof(data,
1869                "schannel: encrypted data buffer: offset %zu length %zu\n",
1870                BACKEND->encdata_offset, BACKEND->encdata_length));
1871 
1872   DEBUGF(infof(data,
1873                "schannel: decrypted data buffer: offset %zu length %zu\n",
1874                BACKEND->decdata_offset, BACKEND->decdata_length));
1875 
1876 cleanup:
1877   /* Warning- there is no guarantee the encdata state is valid at this point */
1878   DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
1879 
1880   /* Error if the connection has closed without a close_notify.
1881   Behavior here is a matter of debate. We don't want to be vulnerable to a
1882   truncation attack however there's some browser precedent for ignoring the
1883   close_notify for compatibility reasons.
1884   Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1885   return close_notify. In that case if the connection was closed we assume it
1886   was graceful (close_notify) since there doesn't seem to be a way to tell.
1887   */
1888   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1889      !BACKEND->recv_sspi_close_notify) {
1890     bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1891                                                VERSION_EQUAL);
1892 
1893     if(isWin2k && sspi_status == SEC_E_OK)
1894       BACKEND->recv_sspi_close_notify = true;
1895     else {
1896       *err = CURLE_RECV_ERROR;
1897       infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1898     }
1899   }
1900 
1901   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1902   if(*err && *err != CURLE_AGAIN)
1903       BACKEND->recv_unrecoverable_err = *err;
1904 
1905   size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1906   if(size) {
1907     memcpy(buf, BACKEND->decdata_buffer, size);
1908     memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1909             BACKEND->decdata_offset - size);
1910     BACKEND->decdata_offset -= size;
1911     DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
1912     DEBUGF(infof(data,
1913                  "schannel: decrypted data buffer: offset %zu length %zu\n",
1914                  BACKEND->decdata_offset, BACKEND->decdata_length));
1915     *err = CURLE_OK;
1916     return (ssize_t)size;
1917   }
1918 
1919   if(!*err && !BACKEND->recv_connection_closed)
1920       *err = CURLE_AGAIN;
1921 
1922   /* It's debatable what to return when !len. We could return whatever error we
1923   got from decryption but instead we override here so the return is consistent.
1924   */
1925   if(!len)
1926     *err = CURLE_OK;
1927 
1928   return *err ? -1 : 0;
1929 }
1930 
Curl_schannel_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)1931 static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
1932                                                   int sockindex, bool *done)
1933 {
1934   return schannel_connect_common(conn, sockindex, TRUE, done);
1935 }
1936 
Curl_schannel_connect(struct connectdata * conn,int sockindex)1937 static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
1938 {
1939   CURLcode result;
1940   bool done = FALSE;
1941 
1942   result = schannel_connect_common(conn, sockindex, FALSE, &done);
1943   if(result)
1944     return result;
1945 
1946   DEBUGASSERT(done);
1947 
1948   return CURLE_OK;
1949 }
1950 
Curl_schannel_data_pending(const struct connectdata * conn,int sockindex)1951 static bool Curl_schannel_data_pending(const struct connectdata *conn,
1952                                        int sockindex)
1953 {
1954   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1955 
1956   if(connssl->use) /* SSL/TLS is in use */
1957     return (BACKEND->decdata_offset > 0 ||
1958             (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1959   else
1960     return FALSE;
1961 }
1962 
Curl_schannel_close(struct connectdata * conn,int sockindex)1963 static void Curl_schannel_close(struct connectdata *conn, int sockindex)
1964 {
1965   if(conn->ssl[sockindex].use)
1966     /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1967     Curl_ssl_shutdown(conn, sockindex);
1968 }
1969 
Curl_schannel_session_free(void * ptr)1970 static void Curl_schannel_session_free(void *ptr)
1971 {
1972   /* this is expected to be called under sessionid lock */
1973   struct curl_schannel_cred *cred = ptr;
1974 
1975   cred->refcount--;
1976   if(cred->refcount == 0) {
1977     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1978     Curl_safefree(cred);
1979   }
1980 }
1981 
Curl_schannel_shutdown(struct connectdata * conn,int sockindex)1982 static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1983 {
1984   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1985    * Shutting Down an Schannel Connection
1986    */
1987   struct Curl_easy *data = conn->data;
1988   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1989   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1990     conn->host.name;
1991 
1992   DEBUGASSERT(data);
1993 
1994   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1995         hostname, conn->remote_port);
1996 
1997   if(BACKEND->cred && BACKEND->ctxt) {
1998     SecBufferDesc BuffDesc;
1999     SecBuffer Buffer;
2000     SECURITY_STATUS sspi_status;
2001     SecBuffer outbuf;
2002     SecBufferDesc outbuf_desc;
2003     CURLcode result;
2004     TCHAR *host_name;
2005     DWORD dwshut = SCHANNEL_SHUTDOWN;
2006 
2007     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2008     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2009 
2010     sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
2011                                               &BuffDesc);
2012 
2013     if(sspi_status != SEC_E_OK) {
2014       char buffer[STRERROR_LEN];
2015       failf(data, "schannel: ApplyControlToken failure: %s",
2016             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2017     }
2018 
2019     host_name = Curl_convert_UTF8_to_tchar(hostname);
2020     if(!host_name)
2021       return CURLE_OUT_OF_MEMORY;
2022 
2023     /* setup output buffer */
2024     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2025     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2026 
2027     sspi_status = s_pSecFn->InitializeSecurityContext(
2028       &BACKEND->cred->cred_handle,
2029       &BACKEND->ctxt->ctxt_handle,
2030       host_name,
2031       BACKEND->req_flags,
2032       0,
2033       0,
2034       NULL,
2035       0,
2036       &BACKEND->ctxt->ctxt_handle,
2037       &outbuf_desc,
2038       &BACKEND->ret_flags,
2039       &BACKEND->ctxt->time_stamp);
2040 
2041     Curl_unicodefree(host_name);
2042 
2043     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2044       /* send close message which is in output buffer */
2045       ssize_t written;
2046       result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
2047                                 outbuf.cbBuffer, &written);
2048 
2049       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2050       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2051         infof(data, "schannel: failed to send close msg: %s"
2052               " (bytes written: %zd)\n", curl_easy_strerror(result), written);
2053       }
2054     }
2055   }
2056 
2057   /* free SSPI Schannel API security context handle */
2058   if(BACKEND->ctxt) {
2059     DEBUGF(infof(data, "schannel: clear security context handle\n"));
2060     s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
2061     Curl_safefree(BACKEND->ctxt);
2062   }
2063 
2064   /* free SSPI Schannel API credential handle */
2065   if(BACKEND->cred) {
2066     /*
2067      * When this function is called from Curl_schannel_close() the connection
2068      * might not have an associated transfer so the check for conn->data is
2069      * necessary.
2070      */
2071     Curl_ssl_sessionid_lock(conn);
2072     Curl_schannel_session_free(BACKEND->cred);
2073     Curl_ssl_sessionid_unlock(conn);
2074     BACKEND->cred = NULL;
2075   }
2076 
2077   /* free internal buffer for received encrypted data */
2078   if(BACKEND->encdata_buffer != NULL) {
2079     Curl_safefree(BACKEND->encdata_buffer);
2080     BACKEND->encdata_length = 0;
2081     BACKEND->encdata_offset = 0;
2082     BACKEND->encdata_is_incomplete = false;
2083   }
2084 
2085   /* free internal buffer for received decrypted data */
2086   if(BACKEND->decdata_buffer != NULL) {
2087     Curl_safefree(BACKEND->decdata_buffer);
2088     BACKEND->decdata_length = 0;
2089     BACKEND->decdata_offset = 0;
2090   }
2091 
2092   return CURLE_OK;
2093 }
2094 
Curl_schannel_init(void)2095 static int Curl_schannel_init(void)
2096 {
2097   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2098 }
2099 
Curl_schannel_cleanup(void)2100 static void Curl_schannel_cleanup(void)
2101 {
2102   Curl_sspi_global_cleanup();
2103 }
2104 
Curl_schannel_version(char * buffer,size_t size)2105 static size_t Curl_schannel_version(char *buffer, size_t size)
2106 {
2107   size = msnprintf(buffer, size, "Schannel");
2108 
2109   return size;
2110 }
2111 
Curl_schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2112 static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
2113                                      unsigned char *entropy, size_t length)
2114 {
2115   HCRYPTPROV hCryptProv = 0;
2116 
2117   (void)data;
2118 
2119   if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2120                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2121     return CURLE_FAILED_INIT;
2122 
2123   if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2124     CryptReleaseContext(hCryptProv, 0UL);
2125     return CURLE_FAILED_INIT;
2126   }
2127 
2128   CryptReleaseContext(hCryptProv, 0UL);
2129   return CURLE_OK;
2130 }
2131 
pkp_pin_peer_pubkey(struct connectdata * conn,int sockindex,const char * pinnedpubkey)2132 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
2133                                     const char *pinnedpubkey)
2134 {
2135   struct Curl_easy *data = conn->data;
2136   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2137   CERT_CONTEXT *pCertContextServer = NULL;
2138 
2139   /* Result is returned to caller */
2140   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2141 
2142   /* if a path wasn't specified, don't pin */
2143   if(!pinnedpubkey)
2144     return CURLE_OK;
2145 
2146   do {
2147     SECURITY_STATUS sspi_status;
2148     const char *x509_der;
2149     DWORD x509_der_len;
2150     curl_X509certificate x509_parsed;
2151     curl_asn1Element *pubkey;
2152 
2153     sspi_status =
2154       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
2155                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2156                                        &pCertContextServer);
2157 
2158     if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
2159       char buffer[STRERROR_LEN];
2160       failf(data, "schannel: Failed to read remote certificate context: %s",
2161             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2162       break; /* failed */
2163     }
2164 
2165 
2166     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2167        (pCertContextServer->cbCertEncoded > 0)))
2168       break;
2169 
2170     x509_der = (const char *)pCertContextServer->pbCertEncoded;
2171     x509_der_len = pCertContextServer->cbCertEncoded;
2172     memset(&x509_parsed, 0, sizeof(x509_parsed));
2173     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2174       break;
2175 
2176     pubkey = &x509_parsed.subjectPublicKeyInfo;
2177     if(!pubkey->header || pubkey->end <= pubkey->header) {
2178       failf(data, "SSL: failed retrieving public key from server certificate");
2179       break;
2180     }
2181 
2182     result = Curl_pin_peer_pubkey(data,
2183                                   pinnedpubkey,
2184                                   (const unsigned char *)pubkey->header,
2185                                   (size_t)(pubkey->end - pubkey->header));
2186     if(result) {
2187       failf(data, "SSL: public key does not match pinned public key!");
2188     }
2189   } while(0);
2190 
2191   if(pCertContextServer)
2192     CertFreeCertificateContext(pCertContextServer);
2193 
2194   return result;
2195 }
2196 
Curl_schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2197 static void Curl_schannel_checksum(const unsigned char *input,
2198                                    size_t inputlen,
2199                                    unsigned char *checksum,
2200                                    size_t checksumlen,
2201                                    DWORD provType,
2202                                    const unsigned int algId)
2203 {
2204   HCRYPTPROV hProv = 0;
2205   HCRYPTHASH hHash = 0;
2206   DWORD cbHashSize = 0;
2207   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2208   DWORD dwChecksumLen = (DWORD)checksumlen;
2209 
2210   /* since this can fail in multiple ways, zero memory first so we never
2211    * return old data
2212    */
2213   memset(checksum, 0, checksumlen);
2214 
2215   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2216                           CRYPT_VERIFYCONTEXT))
2217     return; /* failed */
2218 
2219   do {
2220     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2221       break; /* failed */
2222 
2223     /* workaround for original MinGW, should be (const BYTE*) */
2224     if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2225       break; /* failed */
2226 
2227     /* get hash size */
2228     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2229                           &dwHashSizeLen, 0))
2230       break; /* failed */
2231 
2232     /* check hash size */
2233     if(checksumlen < cbHashSize)
2234       break; /* failed */
2235 
2236     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2237       break; /* failed */
2238   } while(0);
2239 
2240   if(hHash)
2241     CryptDestroyHash(hHash);
2242 
2243   if(hProv)
2244     CryptReleaseContext(hProv, 0);
2245 }
2246 
Curl_schannel_md5sum(unsigned char * input,size_t inputlen,unsigned char * md5sum,size_t md5len)2247 static CURLcode Curl_schannel_md5sum(unsigned char *input,
2248                                      size_t inputlen,
2249                                      unsigned char *md5sum,
2250                                      size_t md5len)
2251 {
2252   Curl_schannel_checksum(input, inputlen, md5sum, md5len,
2253                          PROV_RSA_FULL, CALG_MD5);
2254   return CURLE_OK;
2255 }
2256 
Curl_schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2257 static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
2258                                     size_t inputlen,
2259                                     unsigned char *sha256sum,
2260                                     size_t sha256len)
2261 {
2262   Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
2263                          PROV_RSA_AES, CALG_SHA_256);
2264   return CURLE_OK;
2265 }
2266 
Curl_schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2267 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
2268                                          CURLINFO info UNUSED_PARAM)
2269 {
2270   (void)info;
2271   return &BACKEND->ctxt->ctxt_handle;
2272 }
2273 
2274 const struct Curl_ssl Curl_ssl_schannel = {
2275   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2276 
2277   SSLSUPP_CERTINFO |
2278   SSLSUPP_PINNEDPUBKEY,
2279 
2280   sizeof(struct ssl_backend_data),
2281 
2282   Curl_schannel_init,                /* init */
2283   Curl_schannel_cleanup,             /* cleanup */
2284   Curl_schannel_version,             /* version */
2285   Curl_none_check_cxn,               /* check_cxn */
2286   Curl_schannel_shutdown,            /* shutdown */
2287   Curl_schannel_data_pending,        /* data_pending */
2288   Curl_schannel_random,              /* random */
2289   Curl_none_cert_status_request,     /* cert_status_request */
2290   Curl_schannel_connect,             /* connect */
2291   Curl_schannel_connect_nonblocking, /* connect_nonblocking */
2292   Curl_schannel_get_internals,       /* get_internals */
2293   Curl_schannel_close,               /* close_one */
2294   Curl_none_close_all,               /* close_all */
2295   Curl_schannel_session_free,        /* session_free */
2296   Curl_none_set_engine,              /* set_engine */
2297   Curl_none_set_engine_default,      /* set_engine_default */
2298   Curl_none_engines_list,            /* engines_list */
2299   Curl_none_false_start,             /* false_start */
2300   Curl_schannel_md5sum,              /* md5sum */
2301   Curl_schannel_sha256sum            /* sha256sum */
2302 };
2303 
2304 #endif /* USE_SCHANNEL */
2305