• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   sspi_status =
720     s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
721                                        SECPKG_CRED_OUTBOUND, NULL,
722                                        &schannel_cred, NULL, NULL,
723                                        &BACKEND->cred->cred_handle,
724                                        &BACKEND->cred->time_stamp);
725 
726   if(client_certs[0])
727     CertFreeCertificateContext(client_certs[0]);
728 
729   if(sspi_status != SEC_E_OK) {
730     char buffer[STRERROR_LEN];
731     failf(data, "schannel: AcquireCredentialsHandle failed: %s",
732           Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
733     Curl_safefree(BACKEND->cred);
734     switch(sspi_status) {
735     case SEC_E_INSUFFICIENT_MEMORY:
736       return CURLE_OUT_OF_MEMORY;
737     case SEC_E_NO_CREDENTIALS:
738     case SEC_E_SECPKG_NOT_FOUND:
739     case SEC_E_NOT_OWNER:
740     case SEC_E_UNKNOWN_CREDENTIALS:
741     case SEC_E_INTERNAL_ERROR:
742     default:
743       return CURLE_SSL_CONNECT_ERROR;
744     }
745   }
746 
747   return CURLE_OK;
748 }
749 
750 static CURLcode
schannel_connect_step1(struct Curl_easy * data,struct connectdata * conn,int sockindex)751 schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
752                        int sockindex)
753 {
754   ssize_t written = -1;
755   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
756   SecBuffer outbuf;
757   SecBufferDesc outbuf_desc;
758   SecBuffer inbuf;
759   SecBufferDesc inbuf_desc;
760 #ifdef HAS_ALPN
761   unsigned char alpn_buffer[128];
762 #endif
763   SECURITY_STATUS sspi_status = SEC_E_OK;
764   struct Curl_schannel_cred *old_cred = NULL;
765   struct in_addr addr;
766 #ifdef ENABLE_IPV6
767   struct in6_addr addr6;
768 #endif
769   TCHAR *host_name;
770   CURLcode result;
771   char * const hostname = SSL_HOST_NAME();
772 
773   DEBUGF(infof(data,
774                "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
775                hostname, conn->remote_port));
776 
777   if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
778                                   VERSION_LESS_THAN_EQUAL)) {
779     /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
780        algorithms that may not be supported by all servers. */
781     infof(data, "schannel: Windows version is old and may not be able to "
782           "connect to some servers due to lack of SNI, algorithms, etc.");
783   }
784 
785 #ifdef HAS_ALPN
786   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
787      Also it doesn't seem to be supported for Wine, see curl bug #983. */
788   BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
789     !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
790                     "wine_get_version") &&
791     curlx_verify_windows_version(6, 3, PLATFORM_WINNT,
792                                  VERSION_GREATER_THAN_EQUAL);
793 #else
794   BACKEND->use_alpn = false;
795 #endif
796 
797 #ifdef _WIN32_WCE
798 #ifdef HAS_MANUAL_VERIFY_API
799   /* certificate validation on CE doesn't seem to work right; we'll
800    * do it following a more manual process. */
801   BACKEND->use_manual_cred_validation = true;
802 #else
803 #error "compiler too old to support requisite manual cert verify for Win CE"
804 #endif
805 #else
806 #ifdef HAS_MANUAL_VERIFY_API
807   if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
808     if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
809                                     VERSION_GREATER_THAN_EQUAL)) {
810       BACKEND->use_manual_cred_validation = true;
811     }
812     else {
813       failf(data, "schannel: this version of Windows is too old to support "
814             "certificate verification via CA bundle file.");
815       return CURLE_SSL_CACERT_BADFILE;
816     }
817   }
818   else
819     BACKEND->use_manual_cred_validation = false;
820 #else
821   if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
822     failf(data, "schannel: CA cert support not built in");
823     return CURLE_NOT_BUILT_IN;
824   }
825 #endif
826 #endif
827 
828   BACKEND->cred = NULL;
829 
830   /* check for an existing re-usable credential handle */
831   if(SSL_SET_OPTION(primary.sessionid)) {
832     Curl_ssl_sessionid_lock(data);
833     if(!Curl_ssl_getsessionid(data, conn,
834                               SSL_IS_PROXY() ? TRUE : FALSE,
835                               (void **)&old_cred, NULL, sockindex)) {
836       BACKEND->cred = old_cred;
837       DEBUGF(infof(data, "schannel: re-using existing credential handle"));
838 
839       /* increment the reference counter of the credential/session handle */
840       BACKEND->cred->refcount++;
841       DEBUGF(infof(data,
842                    "schannel: incremented credential handle refcount = %d",
843                    BACKEND->cred->refcount));
844     }
845     Curl_ssl_sessionid_unlock(data);
846   }
847 
848   if(!BACKEND->cred) {
849     result = schannel_acquire_credential_handle(data, conn, sockindex);
850     if(result != CURLE_OK) {
851       return result;
852     }
853   }
854 
855   /* Warn if SNI is disabled due to use of an IP address */
856   if(Curl_inet_pton(AF_INET, hostname, &addr)
857 #ifdef ENABLE_IPV6
858      || Curl_inet_pton(AF_INET6, hostname, &addr6)
859 #endif
860     ) {
861     infof(data, "schannel: using IP address, SNI is not supported by OS.");
862   }
863 
864 #ifdef HAS_ALPN
865   if(BACKEND->use_alpn) {
866     int cur = 0;
867     int list_start_index = 0;
868     unsigned int *extension_len = NULL;
869     unsigned short* list_len = NULL;
870 
871     /* The first four bytes will be an unsigned int indicating number
872        of bytes of data in the rest of the buffer. */
873     extension_len = (unsigned int *)(&alpn_buffer[cur]);
874     cur += sizeof(unsigned int);
875 
876     /* The next four bytes are an indicator that this buffer will contain
877        ALPN data, as opposed to NPN, for example. */
878     *(unsigned int *)&alpn_buffer[cur] =
879       SecApplicationProtocolNegotiationExt_ALPN;
880     cur += sizeof(unsigned int);
881 
882     /* The next two bytes will be an unsigned short indicating the number
883        of bytes used to list the preferred protocols. */
884     list_len = (unsigned short*)(&alpn_buffer[cur]);
885     cur += sizeof(unsigned short);
886 
887     list_start_index = cur;
888 
889 #ifdef USE_HTTP2
890     if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
891       alpn_buffer[cur++] = ALPN_H2_LENGTH;
892       memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
893       cur += ALPN_H2_LENGTH;
894       infof(data, "schannel: ALPN, offering %s", ALPN_H2);
895     }
896 #endif
897 
898     alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
899     memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
900     cur += ALPN_HTTP_1_1_LENGTH;
901     infof(data, "schannel: ALPN, offering %s", ALPN_HTTP_1_1);
902 
903     *list_len = curlx_uitous(cur - list_start_index);
904     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
905 
906     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
907     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
908   }
909   else {
910     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
911     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
912   }
913 #else /* HAS_ALPN */
914   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
915   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
916 #endif
917 
918   /* setup output buffer */
919   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
920   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
921 
922   /* security request flags */
923   BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
924     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
925     ISC_REQ_STREAM;
926 
927   if(!SSL_SET_OPTION(auto_client_cert)) {
928     BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
929   }
930 
931   /* allocate memory for the security context handle */
932   BACKEND->ctxt = (struct Curl_schannel_ctxt *)
933     calloc(1, sizeof(struct Curl_schannel_ctxt));
934   if(!BACKEND->ctxt) {
935     failf(data, "schannel: unable to allocate memory");
936     return CURLE_OUT_OF_MEMORY;
937   }
938 
939   host_name = curlx_convert_UTF8_to_tchar(hostname);
940   if(!host_name)
941     return CURLE_OUT_OF_MEMORY;
942 
943   /* Schannel InitializeSecurityContext:
944      https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
945 
946      At the moment we don't pass inbuf unless we're using ALPN since we only
947      use it for that, and Wine (for which we currently disable ALPN) is giving
948      us problems with inbuf regardless. https://github.com/curl/curl/issues/983
949   */
950   sspi_status = s_pSecFn->InitializeSecurityContext(
951     &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
952     (BACKEND->use_alpn ? &inbuf_desc : NULL),
953     0, &BACKEND->ctxt->ctxt_handle,
954     &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
955 
956   curlx_unicodefree(host_name);
957 
958   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
959     char buffer[STRERROR_LEN];
960     Curl_safefree(BACKEND->ctxt);
961     switch(sspi_status) {
962     case SEC_E_INSUFFICIENT_MEMORY:
963       failf(data, "schannel: initial InitializeSecurityContext failed: %s",
964             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
965       return CURLE_OUT_OF_MEMORY;
966     case SEC_E_WRONG_PRINCIPAL:
967       failf(data, "schannel: SNI or certificate check failed: %s",
968             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
969       return CURLE_PEER_FAILED_VERIFICATION;
970       /*
971         case SEC_E_INVALID_HANDLE:
972         case SEC_E_INVALID_TOKEN:
973         case SEC_E_LOGON_DENIED:
974         case SEC_E_TARGET_UNKNOWN:
975         case SEC_E_NO_AUTHENTICATING_AUTHORITY:
976         case SEC_E_INTERNAL_ERROR:
977         case SEC_E_NO_CREDENTIALS:
978         case SEC_E_UNSUPPORTED_FUNCTION:
979         case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
980       */
981     default:
982       failf(data, "schannel: initial InitializeSecurityContext failed: %s",
983             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
984       return CURLE_SSL_CONNECT_ERROR;
985     }
986   }
987 
988   DEBUGF(infof(data, "schannel: sending initial handshake data: "
989                "sending %lu bytes.", outbuf.cbBuffer));
990 
991   /* send initial handshake data which is now stored in output buffer */
992   result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
993                             outbuf.cbBuffer, &written);
994   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
995   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
996     failf(data, "schannel: failed to send initial handshake data: "
997           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
998     return CURLE_SSL_CONNECT_ERROR;
999   }
1000 
1001   DEBUGF(infof(data, "schannel: sent initial handshake data: "
1002                "sent %zd bytes", written));
1003 
1004   BACKEND->recv_unrecoverable_err = CURLE_OK;
1005   BACKEND->recv_sspi_close_notify = false;
1006   BACKEND->recv_connection_closed = false;
1007   BACKEND->encdata_is_incomplete = false;
1008 
1009   /* continue to second handshake step */
1010   connssl->connecting_state = ssl_connect_2;
1011 
1012   return CURLE_OK;
1013 }
1014 
1015 static CURLcode
schannel_connect_step2(struct Curl_easy * data,struct connectdata * conn,int sockindex)1016 schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
1017                        int sockindex)
1018 {
1019   int i;
1020   ssize_t nread = -1, written = -1;
1021   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1022   unsigned char *reallocated_buffer;
1023   SecBuffer outbuf[3];
1024   SecBufferDesc outbuf_desc;
1025   SecBuffer inbuf[2];
1026   SecBufferDesc inbuf_desc;
1027   SECURITY_STATUS sspi_status = SEC_E_OK;
1028   CURLcode result;
1029   bool doread;
1030   char * const hostname = SSL_HOST_NAME();
1031   const char *pubkey_ptr;
1032 
1033   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1034 
1035   DEBUGF(infof(data,
1036                "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
1037                hostname, conn->remote_port));
1038 
1039   if(!BACKEND->cred || !BACKEND->ctxt)
1040     return CURLE_SSL_CONNECT_ERROR;
1041 
1042   /* buffer to store previously received and decrypted data */
1043   if(!BACKEND->decdata_buffer) {
1044     BACKEND->decdata_offset = 0;
1045     BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1046     BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
1047     if(!BACKEND->decdata_buffer) {
1048       failf(data, "schannel: unable to allocate memory");
1049       return CURLE_OUT_OF_MEMORY;
1050     }
1051   }
1052 
1053   /* buffer to store previously received and encrypted data */
1054   if(!BACKEND->encdata_buffer) {
1055     BACKEND->encdata_is_incomplete = false;
1056     BACKEND->encdata_offset = 0;
1057     BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1058     BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
1059     if(!BACKEND->encdata_buffer) {
1060       failf(data, "schannel: unable to allocate memory");
1061       return CURLE_OUT_OF_MEMORY;
1062     }
1063   }
1064 
1065   /* if we need a bigger buffer to read a full message, increase buffer now */
1066   if(BACKEND->encdata_length - BACKEND->encdata_offset <
1067      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1068     /* increase internal encrypted data buffer */
1069     size_t reallocated_length = BACKEND->encdata_offset +
1070       CURL_SCHANNEL_BUFFER_FREE_SIZE;
1071     reallocated_buffer = realloc(BACKEND->encdata_buffer,
1072                                  reallocated_length);
1073 
1074     if(!reallocated_buffer) {
1075       failf(data, "schannel: unable to re-allocate memory");
1076       return CURLE_OUT_OF_MEMORY;
1077     }
1078     else {
1079       BACKEND->encdata_buffer = reallocated_buffer;
1080       BACKEND->encdata_length = reallocated_length;
1081     }
1082   }
1083 
1084   for(;;) {
1085     TCHAR *host_name;
1086     if(doread) {
1087       /* read encrypted handshake data from socket */
1088       result = Curl_read_plain(conn->sock[sockindex],
1089                                (char *) (BACKEND->encdata_buffer +
1090                                          BACKEND->encdata_offset),
1091                                BACKEND->encdata_length -
1092                                BACKEND->encdata_offset,
1093                                &nread);
1094       if(result == CURLE_AGAIN) {
1095         if(connssl->connecting_state != ssl_connect_2_writing)
1096           connssl->connecting_state = ssl_connect_2_reading;
1097         DEBUGF(infof(data, "schannel: failed to receive handshake, "
1098                      "need more data"));
1099         return CURLE_OK;
1100       }
1101       else if((result != CURLE_OK) || (nread == 0)) {
1102         failf(data, "schannel: failed to receive handshake, "
1103               "SSL/TLS connection failed");
1104         return CURLE_SSL_CONNECT_ERROR;
1105       }
1106 
1107       /* increase encrypted data buffer offset */
1108       BACKEND->encdata_offset += nread;
1109       BACKEND->encdata_is_incomplete = false;
1110       DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1111     }
1112 
1113     DEBUGF(infof(data,
1114                  "schannel: encrypted data buffer: offset %zu length %zu",
1115                  BACKEND->encdata_offset, BACKEND->encdata_length));
1116 
1117     /* setup input buffers */
1118     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
1119                   curlx_uztoul(BACKEND->encdata_offset));
1120     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1121     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1122 
1123     /* setup output buffers */
1124     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1125     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1126     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1127     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1128 
1129     if(!inbuf[0].pvBuffer) {
1130       failf(data, "schannel: unable to allocate memory");
1131       return CURLE_OUT_OF_MEMORY;
1132     }
1133 
1134     /* copy received handshake data into input buffer */
1135     memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
1136            BACKEND->encdata_offset);
1137 
1138     host_name = curlx_convert_UTF8_to_tchar(hostname);
1139     if(!host_name)
1140       return CURLE_OUT_OF_MEMORY;
1141 
1142     sspi_status = s_pSecFn->InitializeSecurityContext(
1143       &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
1144       host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
1145       &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
1146 
1147     curlx_unicodefree(host_name);
1148 
1149     /* free buffer for received handshake data */
1150     Curl_safefree(inbuf[0].pvBuffer);
1151 
1152     /* check if the handshake was incomplete */
1153     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1154       BACKEND->encdata_is_incomplete = true;
1155       connssl->connecting_state = ssl_connect_2_reading;
1156       DEBUGF(infof(data,
1157                    "schannel: received incomplete message, need more data"));
1158       return CURLE_OK;
1159     }
1160 
1161     /* If the server has requested a client certificate, attempt to continue
1162        the handshake without one. This will allow connections to servers which
1163        request a client certificate but do not require it. */
1164     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1165        !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1166       BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1167       connssl->connecting_state = ssl_connect_2_writing;
1168       DEBUGF(infof(data,
1169                    "schannel: a client certificate has been requested"));
1170       return CURLE_OK;
1171     }
1172 
1173     /* check if the handshake needs to be continued */
1174     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1175       for(i = 0; i < 3; i++) {
1176         /* search for handshake tokens that need to be send */
1177         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1178           DEBUGF(infof(data, "schannel: sending next handshake data: "
1179                        "sending %lu bytes.", outbuf[i].cbBuffer));
1180 
1181           /* send handshake token to server */
1182           result = Curl_write_plain(data, conn->sock[sockindex],
1183                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1184                                     &written);
1185           if((result != CURLE_OK) ||
1186              (outbuf[i].cbBuffer != (size_t) written)) {
1187             failf(data, "schannel: failed to send next handshake data: "
1188                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1189             return CURLE_SSL_CONNECT_ERROR;
1190           }
1191         }
1192 
1193         /* free obsolete buffer */
1194         if(outbuf[i].pvBuffer != NULL) {
1195           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1196         }
1197       }
1198     }
1199     else {
1200       char buffer[STRERROR_LEN];
1201       switch(sspi_status) {
1202       case SEC_E_INSUFFICIENT_MEMORY:
1203         failf(data, "schannel: next InitializeSecurityContext failed: %s",
1204               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1205         return CURLE_OUT_OF_MEMORY;
1206       case SEC_E_WRONG_PRINCIPAL:
1207         failf(data, "schannel: SNI or certificate check failed: %s",
1208               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1209         return CURLE_PEER_FAILED_VERIFICATION;
1210       case SEC_E_UNTRUSTED_ROOT:
1211         failf(data, "schannel: %s",
1212               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1213         return CURLE_PEER_FAILED_VERIFICATION;
1214         /*
1215           case SEC_E_INVALID_HANDLE:
1216           case SEC_E_INVALID_TOKEN:
1217           case SEC_E_LOGON_DENIED:
1218           case SEC_E_TARGET_UNKNOWN:
1219           case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1220           case SEC_E_INTERNAL_ERROR:
1221           case SEC_E_NO_CREDENTIALS:
1222           case SEC_E_UNSUPPORTED_FUNCTION:
1223           case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1224         */
1225       default:
1226         failf(data, "schannel: next InitializeSecurityContext failed: %s",
1227               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1228         return CURLE_SSL_CONNECT_ERROR;
1229       }
1230     }
1231 
1232     /* check if there was additional remaining encrypted data */
1233     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1234       DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1235                    inbuf[1].cbBuffer));
1236       /*
1237         There are two cases where we could be getting extra data here:
1238         1) If we're renegotiating a connection and the handshake is already
1239         complete (from the server perspective), it can encrypted app data
1240         (not handshake data) in an extra buffer at this point.
1241         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1242         connection and this extra data is part of the handshake.
1243         We should process the data immediately; waiting for the socket to
1244         be ready may fail since the server is done sending handshake data.
1245       */
1246       /* check if the remaining data is less than the total amount
1247          and therefore begins after the already processed data */
1248       if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
1249         memmove(BACKEND->encdata_buffer,
1250                 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1251                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1252         BACKEND->encdata_offset = inbuf[1].cbBuffer;
1253         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1254           doread = FALSE;
1255           continue;
1256         }
1257       }
1258     }
1259     else {
1260       BACKEND->encdata_offset = 0;
1261     }
1262     break;
1263   }
1264 
1265   /* check if the handshake needs to be continued */
1266   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1267     connssl->connecting_state = ssl_connect_2_reading;
1268     return CURLE_OK;
1269   }
1270 
1271   /* check if the handshake is complete */
1272   if(sspi_status == SEC_E_OK) {
1273     connssl->connecting_state = ssl_connect_3;
1274     DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1275   }
1276 
1277   pubkey_ptr = SSL_PINNED_PUB_KEY();
1278   if(pubkey_ptr) {
1279     result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
1280     if(result) {
1281       failf(data, "SSL: public key does not match pinned public key!");
1282       return result;
1283     }
1284   }
1285 
1286 #ifdef HAS_MANUAL_VERIFY_API
1287   if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
1288     return Curl_verify_certificate(data, conn, sockindex);
1289   }
1290 #endif
1291 
1292   return CURLE_OK;
1293 }
1294 
1295 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1296 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1297 {
1298   return (cert_context != NULL) &&
1299     ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1300     (cert_context->pbCertEncoded != NULL) &&
1301     (cert_context->cbCertEncoded > 0);
1302 }
1303 
1304 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1305 
1306 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1307 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1308                     void *arg)
1309 {
1310   const CERT_CONTEXT *current_context = NULL;
1311   bool should_continue = true;
1312   while(should_continue &&
1313         (current_context = CertEnumCertificatesInStore(
1314           context->hCertStore,
1315           current_context)) != NULL)
1316     should_continue = func(current_context, arg);
1317 
1318   if(current_context)
1319     CertFreeCertificateContext(current_context);
1320 }
1321 
1322 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,void * certs_count)1323 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1324 {
1325   if(valid_cert_encoding(ccert_context))
1326     (*(int *)certs_count)++;
1327   return true;
1328 }
1329 
1330 struct Adder_args
1331 {
1332   struct Curl_easy *data;
1333   CURLcode result;
1334   int idx;
1335   int certs_count;
1336 };
1337 
1338 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,void * raw_arg)1339 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1340 {
1341   struct Adder_args *args = (struct Adder_args*)raw_arg;
1342   args->result = CURLE_OK;
1343   if(valid_cert_encoding(ccert_context)) {
1344     const char *beg = (const char *) ccert_context->pbCertEncoded;
1345     const char *end = beg + ccert_context->cbCertEncoded;
1346     int insert_index = (args->certs_count - 1) - args->idx;
1347     args->result = Curl_extract_certinfo(args->data, insert_index,
1348                                          beg, end);
1349     args->idx++;
1350   }
1351   return args->result == CURLE_OK;
1352 }
1353 
1354 static CURLcode
schannel_connect_step3(struct Curl_easy * data,struct connectdata * conn,int sockindex)1355 schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
1356                        int sockindex)
1357 {
1358   CURLcode result = CURLE_OK;
1359   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1360   SECURITY_STATUS sspi_status = SEC_E_OK;
1361   CERT_CONTEXT *ccert_context = NULL;
1362   bool isproxy = SSL_IS_PROXY();
1363 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1364   const char * const hostname = SSL_HOST_NAME();
1365 #endif
1366 #ifdef HAS_ALPN
1367   SecPkgContext_ApplicationProtocol alpn_result;
1368 #endif
1369 
1370   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1371 
1372   DEBUGF(infof(data,
1373                "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
1374                hostname, conn->remote_port));
1375 
1376   if(!BACKEND->cred)
1377     return CURLE_SSL_CONNECT_ERROR;
1378 
1379   /* check if the required context attributes are met */
1380   if(BACKEND->ret_flags != BACKEND->req_flags) {
1381     if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
1382       failf(data, "schannel: failed to setup sequence detection");
1383     if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
1384       failf(data, "schannel: failed to setup replay detection");
1385     if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
1386       failf(data, "schannel: failed to setup confidentiality");
1387     if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1388       failf(data, "schannel: failed to setup memory allocation");
1389     if(!(BACKEND->ret_flags & ISC_RET_STREAM))
1390       failf(data, "schannel: failed to setup stream orientation");
1391     return CURLE_SSL_CONNECT_ERROR;
1392   }
1393 
1394 #ifdef HAS_ALPN
1395   if(BACKEND->use_alpn) {
1396     sspi_status =
1397       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1398                                        SECPKG_ATTR_APPLICATION_PROTOCOL,
1399                                        &alpn_result);
1400 
1401     if(sspi_status != SEC_E_OK) {
1402       failf(data, "schannel: failed to retrieve ALPN result");
1403       return CURLE_SSL_CONNECT_ERROR;
1404     }
1405 
1406     if(alpn_result.ProtoNegoStatus ==
1407        SecApplicationProtocolNegotiationStatus_Success) {
1408 
1409       infof(data, "schannel: ALPN, server accepted to use %.*s",
1410             alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1411 
1412 #ifdef USE_HTTP2
1413       if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH &&
1414          !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) {
1415         conn->negnpn = CURL_HTTP_VERSION_2;
1416       }
1417       else
1418 #endif
1419         if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1420            !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1421                    ALPN_HTTP_1_1_LENGTH)) {
1422           conn->negnpn = CURL_HTTP_VERSION_1_1;
1423         }
1424     }
1425     else
1426       infof(data, "ALPN, server did not agree to a protocol");
1427     Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
1428                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1429   }
1430 #endif
1431 
1432   /* save the current session data for possible re-use */
1433   if(SSL_SET_OPTION(primary.sessionid)) {
1434     bool incache;
1435     bool added = FALSE;
1436     struct Curl_schannel_cred *old_cred = NULL;
1437 
1438     Curl_ssl_sessionid_lock(data);
1439     incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
1440                                       NULL, sockindex));
1441     if(incache) {
1442       if(old_cred != BACKEND->cred) {
1443         DEBUGF(infof(data,
1444                      "schannel: old credential handle is stale, removing"));
1445         /* we're not taking old_cred ownership here, no refcount++ is needed */
1446         Curl_ssl_delsessionid(data, (void *)old_cred);
1447         incache = FALSE;
1448       }
1449     }
1450     if(!incache) {
1451       result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred,
1452                                      sizeof(struct Curl_schannel_cred),
1453                                      sockindex, &added);
1454       if(result) {
1455         Curl_ssl_sessionid_unlock(data);
1456         failf(data, "schannel: failed to store credential handle");
1457         return result;
1458       }
1459       else if(added) {
1460         /* this cred session is now also referenced by sessionid cache */
1461         BACKEND->cred->refcount++;
1462         DEBUGF(infof(data,
1463                      "schannel: stored credential handle in session cache"));
1464       }
1465     }
1466     Curl_ssl_sessionid_unlock(data);
1467   }
1468 
1469   if(data->set.ssl.certinfo) {
1470     int certs_count = 0;
1471     sspi_status =
1472       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1473                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1474                                        &ccert_context);
1475 
1476     if((sspi_status != SEC_E_OK) || !ccert_context) {
1477       failf(data, "schannel: failed to retrieve remote cert context");
1478       return CURLE_PEER_FAILED_VERIFICATION;
1479     }
1480 
1481     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1482 
1483     result = Curl_ssl_init_certinfo(data, certs_count);
1484     if(!result) {
1485       struct Adder_args args;
1486       args.data = data;
1487       args.idx = 0;
1488       args.certs_count = certs_count;
1489       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1490       result = args.result;
1491     }
1492     CertFreeCertificateContext(ccert_context);
1493     if(result)
1494       return result;
1495   }
1496 
1497   connssl->connecting_state = ssl_connect_done;
1498 
1499   return CURLE_OK;
1500 }
1501 
1502 static CURLcode
schannel_connect_common(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1503 schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
1504                         int sockindex, bool nonblocking, bool *done)
1505 {
1506   CURLcode result;
1507   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1508   curl_socket_t sockfd = conn->sock[sockindex];
1509   timediff_t timeout_ms;
1510   int what;
1511 
1512   /* check if the connection has already been established */
1513   if(ssl_connection_complete == connssl->state) {
1514     *done = TRUE;
1515     return CURLE_OK;
1516   }
1517 
1518   if(ssl_connect_1 == connssl->connecting_state) {
1519     /* check out how much more time we're allowed */
1520     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1521 
1522     if(timeout_ms < 0) {
1523       /* no need to continue if time already is up */
1524       failf(data, "SSL/TLS connection timeout");
1525       return CURLE_OPERATION_TIMEDOUT;
1526     }
1527 
1528     result = schannel_connect_step1(data, conn, sockindex);
1529     if(result)
1530       return result;
1531   }
1532 
1533   while(ssl_connect_2 == connssl->connecting_state ||
1534         ssl_connect_2_reading == connssl->connecting_state ||
1535         ssl_connect_2_writing == connssl->connecting_state) {
1536 
1537     /* check out how much more time we're allowed */
1538     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1539 
1540     if(timeout_ms < 0) {
1541       /* no need to continue if time already is up */
1542       failf(data, "SSL/TLS connection timeout");
1543       return CURLE_OPERATION_TIMEDOUT;
1544     }
1545 
1546     /* if ssl is expecting something, check if it's available. */
1547     if(connssl->connecting_state == ssl_connect_2_reading
1548        || connssl->connecting_state == ssl_connect_2_writing) {
1549 
1550       curl_socket_t writefd = ssl_connect_2_writing ==
1551         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1552       curl_socket_t readfd = ssl_connect_2_reading ==
1553         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1554 
1555       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1556                                nonblocking ? 0 : timeout_ms);
1557       if(what < 0) {
1558         /* fatal error */
1559         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1560         return CURLE_SSL_CONNECT_ERROR;
1561       }
1562       else if(0 == what) {
1563         if(nonblocking) {
1564           *done = FALSE;
1565           return CURLE_OK;
1566         }
1567         else {
1568           /* timeout */
1569           failf(data, "SSL/TLS connection timeout");
1570           return CURLE_OPERATION_TIMEDOUT;
1571         }
1572       }
1573       /* socket is readable or writable */
1574     }
1575 
1576     /* Run transaction, and return to the caller if it failed or if
1577      * this connection is part of a multi handle and this loop would
1578      * execute again. This permits the owner of a multi handle to
1579      * abort a connection attempt before step2 has completed while
1580      * ensuring that a client using select() or epoll() will always
1581      * have a valid fdset to wait on.
1582      */
1583     result = schannel_connect_step2(data, conn, sockindex);
1584     if(result || (nonblocking &&
1585                   (ssl_connect_2 == connssl->connecting_state ||
1586                    ssl_connect_2_reading == connssl->connecting_state ||
1587                    ssl_connect_2_writing == connssl->connecting_state)))
1588       return result;
1589 
1590   } /* repeat step2 until all transactions are done. */
1591 
1592   if(ssl_connect_3 == connssl->connecting_state) {
1593     result = schannel_connect_step3(data, conn, sockindex);
1594     if(result)
1595       return result;
1596   }
1597 
1598   if(ssl_connect_done == connssl->connecting_state) {
1599     connssl->state = ssl_connection_complete;
1600     conn->recv[sockindex] = schannel_recv;
1601     conn->send[sockindex] = schannel_send;
1602 
1603 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1604     /* When SSPI is used in combination with Schannel
1605      * we need the Schannel context to create the Schannel
1606      * binding to pass the IIS extended protection checks.
1607      * Available on Windows 7 or later.
1608      */
1609     conn->sslContext = &BACKEND->ctxt->ctxt_handle;
1610 #endif
1611 
1612     *done = TRUE;
1613   }
1614   else
1615     *done = FALSE;
1616 
1617   /* reset our connection state machine */
1618   connssl->connecting_state = ssl_connect_1;
1619 
1620   return CURLE_OK;
1621 }
1622 
1623 static ssize_t
schannel_send(struct Curl_easy * data,int sockindex,const void * buf,size_t len,CURLcode * err)1624 schannel_send(struct Curl_easy *data, int sockindex,
1625               const void *buf, size_t len, CURLcode *err)
1626 {
1627   ssize_t written = -1;
1628   size_t data_len = 0;
1629   unsigned char *ptr = NULL;
1630   struct connectdata *conn = data->conn;
1631   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1632   SecBuffer outbuf[4];
1633   SecBufferDesc outbuf_desc;
1634   SECURITY_STATUS sspi_status = SEC_E_OK;
1635   CURLcode result;
1636 
1637   /* check if the maximum stream sizes were queried */
1638   if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1639     sspi_status = s_pSecFn->QueryContextAttributes(
1640       &BACKEND->ctxt->ctxt_handle,
1641       SECPKG_ATTR_STREAM_SIZES,
1642       &BACKEND->stream_sizes);
1643     if(sspi_status != SEC_E_OK) {
1644       *err = CURLE_SEND_ERROR;
1645       return -1;
1646     }
1647   }
1648 
1649   /* check if the buffer is longer than the maximum message length */
1650   if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1651     len = BACKEND->stream_sizes.cbMaximumMessage;
1652   }
1653 
1654   /* calculate the complete message length and allocate a buffer for it */
1655   data_len = BACKEND->stream_sizes.cbHeader + len +
1656     BACKEND->stream_sizes.cbTrailer;
1657   ptr = (unsigned char *) malloc(data_len);
1658   if(!ptr) {
1659     *err = CURLE_OUT_OF_MEMORY;
1660     return -1;
1661   }
1662 
1663   /* setup output buffers (header, data, trailer, empty) */
1664   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1665                 ptr, BACKEND->stream_sizes.cbHeader);
1666   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1667                 ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1668   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1669                 ptr + BACKEND->stream_sizes.cbHeader + len,
1670                 BACKEND->stream_sizes.cbTrailer);
1671   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1672   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1673 
1674   /* copy data into output buffer */
1675   memcpy(outbuf[1].pvBuffer, buf, len);
1676 
1677   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1678   sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1679                                          &outbuf_desc, 0);
1680 
1681   /* check if the message was encrypted */
1682   if(sspi_status == SEC_E_OK) {
1683     written = 0;
1684 
1685     /* send the encrypted message including header, data and trailer */
1686     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1687 
1688     /*
1689       It's important to send the full message which includes the header,
1690       encrypted payload, and trailer.  Until the client receives all the
1691       data a coherent message has not been delivered and the client
1692       can't read any of it.
1693 
1694       If we wanted to buffer the unwritten encrypted bytes, we would
1695       tell the client that all data it has requested to be sent has been
1696       sent. The unwritten encrypted bytes would be the first bytes to
1697       send on the next invocation.
1698       Here's the catch with this - if we tell the client that all the
1699       bytes have been sent, will the client call this method again to
1700       send the buffered data?  Looking at who calls this function, it
1701       seems the answer is NO.
1702     */
1703 
1704     /* send entire message or fail */
1705     while(len > (size_t)written) {
1706       ssize_t this_write = 0;
1707       int what;
1708       timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
1709       if(timeout_ms < 0) {
1710         /* we already got the timeout */
1711         failf(data, "schannel: timed out sending data "
1712               "(bytes sent: %zd)", written);
1713         *err = CURLE_OPERATION_TIMEDOUT;
1714         written = -1;
1715         break;
1716       }
1717       else if(!timeout_ms)
1718         timeout_ms = TIMEDIFF_T_MAX;
1719       what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
1720       if(what < 0) {
1721         /* fatal error */
1722         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1723         *err = CURLE_SEND_ERROR;
1724         written = -1;
1725         break;
1726       }
1727       else if(0 == what) {
1728         failf(data, "schannel: timed out sending data "
1729               "(bytes sent: %zd)", written);
1730         *err = CURLE_OPERATION_TIMEDOUT;
1731         written = -1;
1732         break;
1733       }
1734       /* socket is writable */
1735 
1736       result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
1737                                 len - written, &this_write);
1738       if(result == CURLE_AGAIN)
1739         continue;
1740       else if(result != CURLE_OK) {
1741         *err = result;
1742         written = -1;
1743         break;
1744       }
1745 
1746       written += this_write;
1747     }
1748   }
1749   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1750     *err = CURLE_OUT_OF_MEMORY;
1751   }
1752   else{
1753     *err = CURLE_SEND_ERROR;
1754   }
1755 
1756   Curl_safefree(ptr);
1757 
1758   if(len == (size_t)written)
1759     /* Encrypted message including header, data and trailer entirely sent.
1760        The return value is the number of unencrypted bytes that were sent. */
1761     written = outbuf[1].cbBuffer;
1762 
1763   return written;
1764 }
1765 
1766 static ssize_t
schannel_recv(struct Curl_easy * data,int sockindex,char * buf,size_t len,CURLcode * err)1767 schannel_recv(struct Curl_easy *data, int sockindex,
1768               char *buf, size_t len, CURLcode *err)
1769 {
1770   size_t size = 0;
1771   ssize_t nread = -1;
1772   struct connectdata *conn = data->conn;
1773   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1774   unsigned char *reallocated_buffer;
1775   size_t reallocated_length;
1776   bool done = FALSE;
1777   SecBuffer inbuf[4];
1778   SecBufferDesc inbuf_desc;
1779   SECURITY_STATUS sspi_status = SEC_E_OK;
1780   /* we want the length of the encrypted buffer to be at least large enough
1781      that it can hold all the bytes requested and some TLS record overhead. */
1782   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1783 
1784   /****************************************************************************
1785    * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1786    * The pattern for return error is set *err, optional infof, goto cleanup.
1787    *
1788    * Our priority is to always return as much decrypted data to the caller as
1789    * possible, even if an error occurs. The state of the decrypted buffer must
1790    * always be valid. Transfer of decrypted data to the caller's buffer is
1791    * handled in the cleanup.
1792    */
1793 
1794   DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
1795   *err = CURLE_OK;
1796 
1797   if(len && len <= BACKEND->decdata_offset) {
1798     infof(data, "schannel: enough decrypted data is already available");
1799     goto cleanup;
1800   }
1801   else if(BACKEND->recv_unrecoverable_err) {
1802     *err = BACKEND->recv_unrecoverable_err;
1803     infof(data, "schannel: an unrecoverable error occurred in a prior call");
1804     goto cleanup;
1805   }
1806   else if(BACKEND->recv_sspi_close_notify) {
1807     /* once a server has indicated shutdown there is no more encrypted data */
1808     infof(data, "schannel: server indicated shutdown in a prior call");
1809     goto cleanup;
1810   }
1811 
1812   /* It's debatable what to return when !len. Regardless we can't return
1813      immediately because there may be data to decrypt (in the case we want to
1814      decrypt all encrypted cached data) so handle !len later in cleanup.
1815   */
1816   else if(len && !BACKEND->recv_connection_closed) {
1817     /* increase enc buffer in order to fit the requested amount of data */
1818     size = BACKEND->encdata_length - BACKEND->encdata_offset;
1819     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1820        BACKEND->encdata_length < min_encdata_length) {
1821       reallocated_length = BACKEND->encdata_offset +
1822         CURL_SCHANNEL_BUFFER_FREE_SIZE;
1823       if(reallocated_length < min_encdata_length) {
1824         reallocated_length = min_encdata_length;
1825       }
1826       reallocated_buffer = realloc(BACKEND->encdata_buffer,
1827                                    reallocated_length);
1828       if(!reallocated_buffer) {
1829         *err = CURLE_OUT_OF_MEMORY;
1830         failf(data, "schannel: unable to re-allocate memory");
1831         goto cleanup;
1832       }
1833 
1834       BACKEND->encdata_buffer = reallocated_buffer;
1835       BACKEND->encdata_length = reallocated_length;
1836       size = BACKEND->encdata_length - BACKEND->encdata_offset;
1837       DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
1838                    BACKEND->encdata_length));
1839     }
1840 
1841     DEBUGF(infof(data,
1842                  "schannel: encrypted data buffer: offset %zu length %zu",
1843                  BACKEND->encdata_offset, BACKEND->encdata_length));
1844 
1845     /* read encrypted data from socket */
1846     *err = Curl_read_plain(conn->sock[sockindex],
1847                            (char *)(BACKEND->encdata_buffer +
1848                                     BACKEND->encdata_offset),
1849                            size, &nread);
1850     if(*err) {
1851       nread = -1;
1852       if(*err == CURLE_AGAIN)
1853         DEBUGF(infof(data,
1854                      "schannel: Curl_read_plain returned CURLE_AGAIN"));
1855       else if(*err == CURLE_RECV_ERROR)
1856         infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
1857       else
1858         infof(data, "schannel: Curl_read_plain returned error %d", *err);
1859     }
1860     else if(nread == 0) {
1861       BACKEND->recv_connection_closed = true;
1862       DEBUGF(infof(data, "schannel: server closed the connection"));
1863     }
1864     else if(nread > 0) {
1865       BACKEND->encdata_offset += (size_t)nread;
1866       BACKEND->encdata_is_incomplete = false;
1867       DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
1868     }
1869   }
1870 
1871   DEBUGF(infof(data,
1872                "schannel: encrypted data buffer: offset %zu length %zu",
1873                BACKEND->encdata_offset, BACKEND->encdata_length));
1874 
1875   /* decrypt loop */
1876   while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1877         (!len || BACKEND->decdata_offset < len ||
1878          BACKEND->recv_connection_closed)) {
1879     /* prepare data buffer for DecryptMessage call */
1880     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1881                   curlx_uztoul(BACKEND->encdata_offset));
1882 
1883     /* we need 3 more empty input buffers for possible output */
1884     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1885     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1886     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1887     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1888 
1889     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1890      */
1891     sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1892                                            &inbuf_desc, 0, NULL);
1893 
1894     /* check if everything went fine (server may want to renegotiate
1895        or shutdown the connection context) */
1896     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1897        sspi_status == SEC_I_CONTEXT_EXPIRED) {
1898       /* check for successfully decrypted data, even before actual
1899          renegotiation or shutdown of the connection context */
1900       if(inbuf[1].BufferType == SECBUFFER_DATA) {
1901         DEBUGF(infof(data, "schannel: decrypted data length: %lu",
1902                      inbuf[1].cbBuffer));
1903 
1904         /* increase buffer in order to fit the received amount of data */
1905         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1906           inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1907         if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1908            BACKEND->decdata_length < len) {
1909           /* increase internal decrypted data buffer */
1910           reallocated_length = BACKEND->decdata_offset + size;
1911           /* make sure that the requested amount of data fits */
1912           if(reallocated_length < len) {
1913             reallocated_length = len;
1914           }
1915           reallocated_buffer = realloc(BACKEND->decdata_buffer,
1916                                        reallocated_length);
1917           if(!reallocated_buffer) {
1918             *err = CURLE_OUT_OF_MEMORY;
1919             failf(data, "schannel: unable to re-allocate memory");
1920             goto cleanup;
1921           }
1922           BACKEND->decdata_buffer = reallocated_buffer;
1923           BACKEND->decdata_length = reallocated_length;
1924         }
1925 
1926         /* copy decrypted data to internal buffer */
1927         size = inbuf[1].cbBuffer;
1928         if(size) {
1929           memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1930                  inbuf[1].pvBuffer, size);
1931           BACKEND->decdata_offset += size;
1932         }
1933 
1934         DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
1935         DEBUGF(infof(data,
1936                      "schannel: decrypted cached: offset %zu length %zu",
1937                      BACKEND->decdata_offset, BACKEND->decdata_length));
1938       }
1939 
1940       /* check for remaining encrypted data */
1941       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1942         DEBUGF(infof(data, "schannel: encrypted data length: %lu",
1943                      inbuf[3].cbBuffer));
1944 
1945         /* check if the remaining data is less than the total amount
1946          * and therefore begins after the already processed data
1947          */
1948         if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1949           /* move remaining encrypted data forward to the beginning of
1950              buffer */
1951           memmove(BACKEND->encdata_buffer,
1952                   (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1953                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1954           BACKEND->encdata_offset = inbuf[3].cbBuffer;
1955         }
1956 
1957         DEBUGF(infof(data,
1958                      "schannel: encrypted cached: offset %zu length %zu",
1959                      BACKEND->encdata_offset, BACKEND->encdata_length));
1960       }
1961       else {
1962         /* reset encrypted buffer offset, because there is no data remaining */
1963         BACKEND->encdata_offset = 0;
1964       }
1965 
1966       /* check if server wants to renegotiate the connection context */
1967       if(sspi_status == SEC_I_RENEGOTIATE) {
1968         infof(data, "schannel: remote party requests renegotiation");
1969         if(*err && *err != CURLE_AGAIN) {
1970           infof(data, "schannel: can't renegotiate, an error is pending");
1971           goto cleanup;
1972         }
1973         if(BACKEND->encdata_offset) {
1974           *err = CURLE_RECV_ERROR;
1975           infof(data, "schannel: can't renegotiate, "
1976                 "encrypted data available");
1977           goto cleanup;
1978         }
1979         /* begin renegotiation */
1980         infof(data, "schannel: renegotiating SSL/TLS connection");
1981         connssl->state = ssl_connection_negotiating;
1982         connssl->connecting_state = ssl_connect_2_writing;
1983         *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
1984         if(*err) {
1985           infof(data, "schannel: renegotiation failed");
1986           goto cleanup;
1987         }
1988         /* now retry receiving data */
1989         sspi_status = SEC_E_OK;
1990         infof(data, "schannel: SSL/TLS connection renegotiated");
1991         continue;
1992       }
1993       /* check if the server closed the connection */
1994       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1995         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1996            returned so we have to work around that in cleanup. */
1997         BACKEND->recv_sspi_close_notify = true;
1998         if(!BACKEND->recv_connection_closed) {
1999           BACKEND->recv_connection_closed = true;
2000           infof(data, "schannel: server closed the connection");
2001         }
2002         goto cleanup;
2003       }
2004     }
2005     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
2006       BACKEND->encdata_is_incomplete = true;
2007       if(!*err)
2008         *err = CURLE_AGAIN;
2009       infof(data, "schannel: failed to decrypt data, need more data");
2010       goto cleanup;
2011     }
2012     else {
2013 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2014       char buffer[STRERROR_LEN];
2015 #endif
2016       *err = CURLE_RECV_ERROR;
2017       infof(data, "schannel: failed to read data from server: %s",
2018             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2019       goto cleanup;
2020     }
2021   }
2022 
2023   DEBUGF(infof(data,
2024                "schannel: encrypted data buffer: offset %zu length %zu",
2025                BACKEND->encdata_offset, BACKEND->encdata_length));
2026 
2027   DEBUGF(infof(data,
2028                "schannel: decrypted data buffer: offset %zu length %zu",
2029                BACKEND->decdata_offset, BACKEND->decdata_length));
2030 
2031   cleanup:
2032   /* Warning- there is no guarantee the encdata state is valid at this point */
2033   DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
2034 
2035   /* Error if the connection has closed without a close_notify.
2036 
2037      The behavior here is a matter of debate. We don't want to be vulnerable
2038      to a truncation attack however there's some browser precedent for
2039      ignoring the close_notify for compatibility reasons.
2040 
2041      Additionally, Windows 2000 (v5.0) is a special case since it seems it
2042      doesn't return close_notify. In that case if the connection was closed we
2043      assume it was graceful (close_notify) since there doesn't seem to be a
2044      way to tell.
2045   */
2046   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
2047      !BACKEND->recv_sspi_close_notify) {
2048     bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT,
2049                                                 VERSION_EQUAL);
2050 
2051     if(isWin2k && sspi_status == SEC_E_OK)
2052       BACKEND->recv_sspi_close_notify = true;
2053     else {
2054       *err = CURLE_RECV_ERROR;
2055       infof(data, "schannel: server closed abruptly (missing close_notify)");
2056     }
2057   }
2058 
2059   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2060   if(*err && *err != CURLE_AGAIN)
2061     BACKEND->recv_unrecoverable_err = *err;
2062 
2063   size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
2064   if(size) {
2065     memcpy(buf, BACKEND->decdata_buffer, size);
2066     memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
2067             BACKEND->decdata_offset - size);
2068     BACKEND->decdata_offset -= size;
2069     DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
2070     DEBUGF(infof(data,
2071                  "schannel: decrypted data buffer: offset %zu length %zu",
2072                  BACKEND->decdata_offset, BACKEND->decdata_length));
2073     *err = CURLE_OK;
2074     return (ssize_t)size;
2075   }
2076 
2077   if(!*err && !BACKEND->recv_connection_closed)
2078     *err = CURLE_AGAIN;
2079 
2080   /* It's debatable what to return when !len. We could return whatever error
2081      we got from decryption but instead we override here so the return is
2082      consistent.
2083   */
2084   if(!len)
2085     *err = CURLE_OK;
2086 
2087   return *err ? -1 : 0;
2088 }
2089 
schannel_connect_nonblocking(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool * done)2090 static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
2091                                              struct connectdata *conn,
2092                                              int sockindex, bool *done)
2093 {
2094   return schannel_connect_common(data, conn, sockindex, TRUE, done);
2095 }
2096 
schannel_connect(struct Curl_easy * data,struct connectdata * conn,int sockindex)2097 static CURLcode schannel_connect(struct Curl_easy *data,
2098                                  struct connectdata *conn, int sockindex)
2099 {
2100   CURLcode result;
2101   bool done = FALSE;
2102 
2103   result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
2104   if(result)
2105     return result;
2106 
2107   DEBUGASSERT(done);
2108 
2109   return CURLE_OK;
2110 }
2111 
schannel_data_pending(const struct connectdata * conn,int sockindex)2112 static bool schannel_data_pending(const struct connectdata *conn,
2113                                   int sockindex)
2114 {
2115   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2116 
2117   if(connssl->use) /* SSL/TLS is in use */
2118     return (BACKEND->decdata_offset > 0 ||
2119             (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
2120   else
2121     return FALSE;
2122 }
2123 
schannel_session_free(void * ptr)2124 static void schannel_session_free(void *ptr)
2125 {
2126   /* this is expected to be called under sessionid lock */
2127   struct Curl_schannel_cred *cred = ptr;
2128 
2129   if(cred) {
2130     cred->refcount--;
2131     if(cred->refcount == 0) {
2132       s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
2133       Curl_safefree(cred);
2134     }
2135   }
2136 }
2137 
2138 /* shut down the SSL connection and clean up related memory.
2139    this function can be called multiple times on the same connection including
2140    if the SSL connection failed (eg connection made but failed handshake). */
schannel_shutdown(struct Curl_easy * data,struct connectdata * conn,int sockindex)2141 static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
2142                              int sockindex)
2143 {
2144   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2145    * Shutting Down an Schannel Connection
2146    */
2147   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2148   char * const hostname = SSL_HOST_NAME();
2149 
2150   DEBUGASSERT(data);
2151 
2152   if(connssl->use) {
2153     infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
2154           hostname, conn->remote_port);
2155   }
2156 
2157   if(connssl->use && BACKEND->cred && BACKEND->ctxt) {
2158     SecBufferDesc BuffDesc;
2159     SecBuffer Buffer;
2160     SECURITY_STATUS sspi_status;
2161     SecBuffer outbuf;
2162     SecBufferDesc outbuf_desc;
2163     CURLcode result;
2164     TCHAR *host_name;
2165     DWORD dwshut = SCHANNEL_SHUTDOWN;
2166 
2167     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2168     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2169 
2170     sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
2171                                               &BuffDesc);
2172 
2173     if(sspi_status != SEC_E_OK) {
2174       char buffer[STRERROR_LEN];
2175       failf(data, "schannel: ApplyControlToken failure: %s",
2176             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2177     }
2178 
2179     host_name = curlx_convert_UTF8_to_tchar(hostname);
2180     if(!host_name)
2181       return CURLE_OUT_OF_MEMORY;
2182 
2183     /* setup output buffer */
2184     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2185     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2186 
2187     sspi_status = s_pSecFn->InitializeSecurityContext(
2188       &BACKEND->cred->cred_handle,
2189       &BACKEND->ctxt->ctxt_handle,
2190       host_name,
2191       BACKEND->req_flags,
2192       0,
2193       0,
2194       NULL,
2195       0,
2196       &BACKEND->ctxt->ctxt_handle,
2197       &outbuf_desc,
2198       &BACKEND->ret_flags,
2199       &BACKEND->ctxt->time_stamp);
2200 
2201     curlx_unicodefree(host_name);
2202 
2203     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2204       /* send close message which is in output buffer */
2205       ssize_t written;
2206       result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
2207                                 outbuf.cbBuffer, &written);
2208 
2209       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2210       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2211         infof(data, "schannel: failed to send close msg: %s"
2212               " (bytes written: %zd)", curl_easy_strerror(result), written);
2213       }
2214     }
2215   }
2216 
2217   /* free SSPI Schannel API security context handle */
2218   if(BACKEND->ctxt) {
2219     DEBUGF(infof(data, "schannel: clear security context handle"));
2220     s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
2221     Curl_safefree(BACKEND->ctxt);
2222   }
2223 
2224   /* free SSPI Schannel API credential handle */
2225   if(BACKEND->cred) {
2226     Curl_ssl_sessionid_lock(data);
2227     schannel_session_free(BACKEND->cred);
2228     Curl_ssl_sessionid_unlock(data);
2229     BACKEND->cred = NULL;
2230   }
2231 
2232   /* free internal buffer for received encrypted data */
2233   if(BACKEND->encdata_buffer != NULL) {
2234     Curl_safefree(BACKEND->encdata_buffer);
2235     BACKEND->encdata_length = 0;
2236     BACKEND->encdata_offset = 0;
2237     BACKEND->encdata_is_incomplete = false;
2238   }
2239 
2240   /* free internal buffer for received decrypted data */
2241   if(BACKEND->decdata_buffer != NULL) {
2242     Curl_safefree(BACKEND->decdata_buffer);
2243     BACKEND->decdata_length = 0;
2244     BACKEND->decdata_offset = 0;
2245   }
2246 
2247   return CURLE_OK;
2248 }
2249 
schannel_close(struct Curl_easy * data,struct connectdata * conn,int sockindex)2250 static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
2251                            int sockindex)
2252 {
2253   if(conn->ssl[sockindex].use)
2254     /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
2255     Curl_ssl_shutdown(data, conn, sockindex);
2256   else
2257     schannel_shutdown(data, conn, sockindex);
2258 }
2259 
schannel_init(void)2260 static int schannel_init(void)
2261 {
2262   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2263 }
2264 
schannel_cleanup(void)2265 static void schannel_cleanup(void)
2266 {
2267   Curl_sspi_global_cleanup();
2268 }
2269 
schannel_version(char * buffer,size_t size)2270 static size_t schannel_version(char *buffer, size_t size)
2271 {
2272   size = msnprintf(buffer, size, "Schannel");
2273 
2274   return size;
2275 }
2276 
schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2277 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
2278                                 unsigned char *entropy, size_t length)
2279 {
2280   HCRYPTPROV hCryptProv = 0;
2281 
2282   (void)data;
2283 
2284   if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2285                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2286     return CURLE_FAILED_INIT;
2287 
2288   if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2289     CryptReleaseContext(hCryptProv, 0UL);
2290     return CURLE_FAILED_INIT;
2291   }
2292 
2293   CryptReleaseContext(hCryptProv, 0UL);
2294   return CURLE_OK;
2295 }
2296 
pkp_pin_peer_pubkey(struct Curl_easy * data,struct connectdata * conn,int sockindex,const char * pinnedpubkey)2297 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
2298                                     struct connectdata *conn, int sockindex,
2299                                     const char *pinnedpubkey)
2300 {
2301   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2302   CERT_CONTEXT *pCertContextServer = NULL;
2303 
2304   /* Result is returned to caller */
2305   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2306 
2307   /* if a path wasn't specified, don't pin */
2308   if(!pinnedpubkey)
2309     return CURLE_OK;
2310 
2311   do {
2312     SECURITY_STATUS sspi_status;
2313     const char *x509_der;
2314     DWORD x509_der_len;
2315     struct Curl_X509certificate x509_parsed;
2316     struct Curl_asn1Element *pubkey;
2317 
2318     sspi_status =
2319       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
2320                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2321                                        &pCertContextServer);
2322 
2323     if((sspi_status != SEC_E_OK) || !pCertContextServer) {
2324       char buffer[STRERROR_LEN];
2325       failf(data, "schannel: Failed to read remote certificate context: %s",
2326             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2327       break; /* failed */
2328     }
2329 
2330 
2331     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2332          (pCertContextServer->cbCertEncoded > 0)))
2333       break;
2334 
2335     x509_der = (const char *)pCertContextServer->pbCertEncoded;
2336     x509_der_len = pCertContextServer->cbCertEncoded;
2337     memset(&x509_parsed, 0, sizeof(x509_parsed));
2338     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2339       break;
2340 
2341     pubkey = &x509_parsed.subjectPublicKeyInfo;
2342     if(!pubkey->header || pubkey->end <= pubkey->header) {
2343       failf(data, "SSL: failed retrieving public key from server certificate");
2344       break;
2345     }
2346 
2347     result = Curl_pin_peer_pubkey(data,
2348                                   pinnedpubkey,
2349                                   (const unsigned char *)pubkey->header,
2350                                   (size_t)(pubkey->end - pubkey->header));
2351     if(result) {
2352       failf(data, "SSL: public key does not match pinned public key!");
2353     }
2354   } while(0);
2355 
2356   if(pCertContextServer)
2357     CertFreeCertificateContext(pCertContextServer);
2358 
2359   return result;
2360 }
2361 
schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2362 static void schannel_checksum(const unsigned char *input,
2363                               size_t inputlen,
2364                               unsigned char *checksum,
2365                               size_t checksumlen,
2366                               DWORD provType,
2367                               const unsigned int algId)
2368 {
2369   HCRYPTPROV hProv = 0;
2370   HCRYPTHASH hHash = 0;
2371   DWORD cbHashSize = 0;
2372   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2373   DWORD dwChecksumLen = (DWORD)checksumlen;
2374 
2375   /* since this can fail in multiple ways, zero memory first so we never
2376    * return old data
2377    */
2378   memset(checksum, 0, checksumlen);
2379 
2380   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2381                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2382     return; /* failed */
2383 
2384   do {
2385     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2386       break; /* failed */
2387 
2388     /* workaround for original MinGW, should be (const BYTE*) */
2389     if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2390       break; /* failed */
2391 
2392     /* get hash size */
2393     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2394                           &dwHashSizeLen, 0))
2395       break; /* failed */
2396 
2397     /* check hash size */
2398     if(checksumlen < cbHashSize)
2399       break; /* failed */
2400 
2401     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2402       break; /* failed */
2403   } while(0);
2404 
2405   if(hHash)
2406     CryptDestroyHash(hHash);
2407 
2408   if(hProv)
2409     CryptReleaseContext(hProv, 0);
2410 }
2411 
schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2412 static CURLcode schannel_sha256sum(const unsigned char *input,
2413                                    size_t inputlen,
2414                                    unsigned char *sha256sum,
2415                                    size_t sha256len)
2416 {
2417   schannel_checksum(input, inputlen, sha256sum, sha256len,
2418                     PROV_RSA_AES, CALG_SHA_256);
2419   return CURLE_OK;
2420 }
2421 
schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2422 static void *schannel_get_internals(struct ssl_connect_data *connssl,
2423                                     CURLINFO info UNUSED_PARAM)
2424 {
2425   (void)info;
2426   return &BACKEND->ctxt->ctxt_handle;
2427 }
2428 
2429 const struct Curl_ssl Curl_ssl_schannel = {
2430   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2431 
2432   SSLSUPP_CERTINFO |
2433 #ifdef HAS_MANUAL_VERIFY_API
2434   SSLSUPP_CAINFO_BLOB |
2435 #endif
2436   SSLSUPP_PINNEDPUBKEY,
2437 
2438   sizeof(struct ssl_backend_data),
2439 
2440   schannel_init,                     /* init */
2441   schannel_cleanup,                  /* cleanup */
2442   schannel_version,                  /* version */
2443   Curl_none_check_cxn,               /* check_cxn */
2444   schannel_shutdown,                 /* shutdown */
2445   schannel_data_pending,             /* data_pending */
2446   schannel_random,                   /* random */
2447   Curl_none_cert_status_request,     /* cert_status_request */
2448   schannel_connect,                  /* connect */
2449   schannel_connect_nonblocking,      /* connect_nonblocking */
2450   Curl_ssl_getsock,                  /* getsock */
2451   schannel_get_internals,            /* get_internals */
2452   schannel_close,                    /* close_one */
2453   Curl_none_close_all,               /* close_all */
2454   schannel_session_free,             /* session_free */
2455   Curl_none_set_engine,              /* set_engine */
2456   Curl_none_set_engine_default,      /* set_engine_default */
2457   Curl_none_engines_list,            /* engines_list */
2458   Curl_none_false_start,             /* false_start */
2459   schannel_sha256sum,                /* sha256sum */
2460   NULL,                              /* associate_connection */
2461   NULL                               /* disassociate_connection */
2462 };
2463 
2464 #endif /* USE_SCHANNEL */
2465