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