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