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