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