schannel.c
Go to the documentation of this file.
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 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
11  *
12  * This software is licensed as described in the file COPYING, which
13  * you should have received as part of this distribution. The terms
14  * are also available at https://curl.haxx.se/docs/copyright.html.
15  *
16  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17  * copies of the Software, and permit persons to whom the Software is
18  * furnished to do so, under the terms of the COPYING file.
19  *
20  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21  * KIND, either express or implied.
22  *
23  ***************************************************************************/
24 
25 /*
26  * Source file for all SChannel-specific code for the TLS/SSL layer. No code
27  * but vtls.c should ever call or use these functions.
28  *
29  */
30 
31 /*
32  * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
33  * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
34  *
35  * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
36  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
37  *
38  * Thanks for code and inspiration!
39  */
40 
41 #include "curl_setup.h"
42 
43 #ifdef USE_SCHANNEL
44 
45 #ifndef USE_WINDOWS_SSPI
46 # error "Can't compile SCHANNEL support without SSPI."
47 #endif
48 
49 #include <schnlsp.h>
50 #include <schannel.h>
51 #include "curl_sspi.h"
52 #include "schannel.h"
53 #include "vtls.h"
54 #include "sendf.h"
55 #include "connect.h" /* for the connect timeout */
56 #include "strerror.h"
57 #include "select.h" /* for the socket readyness */
58 #include "inet_pton.h" /* for IP addr SNI check */
59 #include "curl_multibyte.h"
60 #include "warnless.h"
61 #include "x509asn1.h"
62 #include "curl_printf.h"
63 #include "system_win32.h"
64 #include "hostcheck.h"
65 
66  /* The last #include file should be: */
67 #include "curl_memory.h"
68 #include "memdebug.h"
69 
70 /* ALPN requires version 8.1 of the Windows SDK, which was
71  shipped with Visual Studio 2013, aka _MSC_VER 1800:
72 
73  https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
74 */
75 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
76 # define HAS_ALPN 1
77 #endif
78 
79 #ifndef UNISP_NAME_A
80 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
81 #endif
82 
83 #ifndef UNISP_NAME_W
84 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
85 #endif
86 
87 #ifndef UNISP_NAME
88 #ifdef UNICODE
89 #define UNISP_NAME UNISP_NAME_W
90 #else
91 #define UNISP_NAME UNISP_NAME_A
92 #endif
93 #endif
94 
95 #ifndef SP_PROT_SSL2_CLIENT
96 #define SP_PROT_SSL2_CLIENT 0x00000008
97 #endif
98 
99 #ifndef SP_PROT_SSL3_CLIENT
100 #define SP_PROT_SSL3_CLIENT 0x00000008
101 #endif
102 
103 #ifndef SP_PROT_TLS1_CLIENT
104 #define SP_PROT_TLS1_CLIENT 0x00000080
105 #endif
106 
107 #ifndef SP_PROT_TLS1_0_CLIENT
108 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
109 #endif
110 
111 #ifndef SP_PROT_TLS1_1_CLIENT
112 #define SP_PROT_TLS1_1_CLIENT 0x00000200
113 #endif
114 
115 #ifndef SP_PROT_TLS1_2_CLIENT
116 #define SP_PROT_TLS1_2_CLIENT 0x00000800
117 #endif
118 
119 #ifndef SECBUFFER_ALERT
120 #define SECBUFFER_ALERT 17
121 #endif
122 
123 /* Both schannel buffer sizes must be > 0 */
124 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
125 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
126 
127 /* Uncomment to force verbose output
128  * #define infof(x, y, ...) printf(y, __VA_ARGS__)
129  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
130  */
131 
132 /* Structs to store Schannel handles */
133 struct curl_schannel_cred {
134  CredHandle cred_handle;
135  TimeStamp time_stamp;
136  int refcount;
137 };
138 
139 struct curl_schannel_ctxt {
140  CtxtHandle ctxt_handle;
141  TimeStamp time_stamp;
142 };
143 
144 struct ssl_backend_data {
145  struct curl_schannel_cred *cred;
146  struct curl_schannel_ctxt *ctxt;
147  SecPkgContext_StreamSizes stream_sizes;
148  size_t encdata_length, decdata_length;
149  size_t encdata_offset, decdata_offset;
150  unsigned char *encdata_buffer, *decdata_buffer;
151  /* encdata_is_incomplete: if encdata contains only a partial record that
152  can't be decrypted without another Curl_read_plain (that is, status is
153  SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
154  more bytes into encdata then set this back to false. */
155  bool encdata_is_incomplete;
156  unsigned long req_flags, ret_flags;
157  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
158  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
159  bool recv_connection_closed; /* true if connection closed, regardless how */
160  bool use_alpn; /* true if ALPN is used for this connection */
161 };
162 
163 #define BACKEND connssl->backend
164 
165 static Curl_recv schannel_recv;
166 static Curl_send schannel_send;
167 
168 #ifdef _WIN32_WCE
169 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
170 #endif
171 
172 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
173  void *BufDataPtr, unsigned long BufByteSize)
174 {
175  buffer->cbBuffer = BufByteSize;
176  buffer->BufferType = BufType;
177  buffer->pvBuffer = BufDataPtr;
178 }
179 
180 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
181  unsigned long NumArrElem)
182 {
183  desc->ulVersion = SECBUFFER_VERSION;
184  desc->pBuffers = BufArr;
185  desc->cBuffers = NumArrElem;
186 }
187 
188 static CURLcode
189 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
190 {
191  struct Curl_easy *data = conn->data;
192  long ssl_version = SSL_CONN_CONFIG(version);
193  long ssl_version_max = SSL_CONN_CONFIG(version_max);
194  long i = ssl_version;
195 
196  switch(ssl_version_max) {
198  ssl_version_max = ssl_version << 16;
199  break;
201  ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
202  break;
203  }
204  for(; i <= (ssl_version_max >> 16); ++i) {
205  switch(i) {
207  schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
208  break;
210  schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
211  break;
213  schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
214  break;
216  failf(data, "Schannel: TLS 1.3 is not yet supported");
218  }
219  }
220  return CURLE_OK;
221 }
222 
223 static CURLcode
224 schannel_connect_step1(struct connectdata *conn, int sockindex)
225 {
226  ssize_t written = -1;
227  struct Curl_easy *data = conn->data;
228  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
229  SecBuffer outbuf;
230  SecBufferDesc outbuf_desc;
231  SecBuffer inbuf;
232  SecBufferDesc inbuf_desc;
233 #ifdef HAS_ALPN
234  unsigned char alpn_buffer[128];
235 #endif
236  SCHANNEL_CRED schannel_cred;
237  SECURITY_STATUS sspi_status = SEC_E_OK;
238  struct curl_schannel_cred *old_cred = NULL;
239  struct in_addr addr;
240 #ifdef ENABLE_IPV6
241  struct in6_addr addr6;
242 #endif
243  TCHAR *host_name;
245  char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
246  conn->host.name;
247 
248  infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
249  hostname, conn->remote_port);
250 
251  if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
252  VERSION_LESS_THAN_EQUAL)) {
253  /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
254  algorithms that may not be supported by all servers. */
255  infof(data, "schannel: WinSSL version is old and may not be able to "
256  "connect to some servers due to lack of SNI, algorithms, etc.\n");
257  }
258 
259 #ifdef HAS_ALPN
260  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
261  Also it doesn't seem to be supported for Wine, see curl bug #983. */
262  BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
263  !GetProcAddress(GetModuleHandleA("ntdll"),
264  "wine_get_version") &&
265  Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
266  VERSION_GREATER_THAN_EQUAL);
267 #else
268  BACKEND->use_alpn = false;
269 #endif
270 
271  BACKEND->cred = NULL;
272 
273  /* check for an existing re-usable credential handle */
274  if(SSL_SET_OPTION(primary.sessionid)) {
275  Curl_ssl_sessionid_lock(conn);
276  if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
277  BACKEND->cred = old_cred;
278  infof(data, "schannel: re-using existing credential handle\n");
279 
280  /* increment the reference counter of the credential/session handle */
281  BACKEND->cred->refcount++;
282  infof(data, "schannel: incremented credential handle refcount = %d\n",
283  BACKEND->cred->refcount);
284  }
285  Curl_ssl_sessionid_unlock(conn);
286  }
287 
288  if(!BACKEND->cred) {
289  /* setup Schannel API options */
290  memset(&schannel_cred, 0, sizeof(schannel_cred));
291  schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
292 
293  if(conn->ssl_config.verifypeer) {
294 #ifdef _WIN32_WCE
295  /* certificate validation on CE doesn't seem to work right; we'll
296  do it following a more manual process. */
297  schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
298  SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
299  SCH_CRED_IGNORE_REVOCATION_OFFLINE;
300 #else
301  schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
302  /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
303  if(data->set.ssl.no_revoke)
304  schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
305  SCH_CRED_IGNORE_REVOCATION_OFFLINE;
306  else
307  schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
308 #endif
309  if(data->set.ssl.no_revoke)
310  infof(data, "schannel: disabled server certificate revocation "
311  "checks\n");
312  else
313  infof(data, "schannel: checking server certificate revocation\n");
314  }
315  else {
316  schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
317  SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
318  SCH_CRED_IGNORE_REVOCATION_OFFLINE;
319  infof(data, "schannel: disabled server certificate revocation checks\n");
320  }
321 
322  if(!conn->ssl_config.verifyhost) {
323  schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
324  infof(data, "schannel: verifyhost setting prevents Schannel from "
325  "comparing the supplied target name with the subject "
326  "names in server certificates.\n");
327  }
328 
329  switch(conn->ssl_config.version) {
332  schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
333  SP_PROT_TLS1_1_CLIENT |
334  SP_PROT_TLS1_2_CLIENT;
335  break;
340  {
341  result = set_ssl_version_min_max(&schannel_cred, conn);
342  if(result != CURLE_OK)
343  return result;
344  break;
345  }
347  schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
348  break;
350  schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
351  break;
352  default:
353  failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
355  }
356 
357  /* allocate memory for the re-usable credential handle */
358  BACKEND->cred = (struct curl_schannel_cred *)
359  malloc(sizeof(struct curl_schannel_cred));
360  if(!BACKEND->cred) {
361  failf(data, "schannel: unable to allocate memory");
362  return CURLE_OUT_OF_MEMORY;
363  }
364  memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred));
365  BACKEND->cred->refcount = 1;
366 
367  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
368  */
369  sspi_status =
370  s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
371  SECPKG_CRED_OUTBOUND, NULL,
372  &schannel_cred, NULL, NULL,
373  &BACKEND->cred->cred_handle,
374  &BACKEND->cred->time_stamp);
375 
376  if(sspi_status != SEC_E_OK) {
377  if(sspi_status == SEC_E_WRONG_PRINCIPAL)
378  failf(data, "schannel: SNI or certificate check failed: %s",
379  Curl_sspi_strerror(conn, sspi_status));
380  else
381  failf(data, "schannel: AcquireCredentialsHandle failed: %s",
382  Curl_sspi_strerror(conn, sspi_status));
383  Curl_safefree(BACKEND->cred);
385  }
386  }
387 
388  /* Warn if SNI is disabled due to use of an IP address */
389  if(Curl_inet_pton(AF_INET, hostname, &addr)
390 #ifdef ENABLE_IPV6
391  || Curl_inet_pton(AF_INET6, hostname, &addr6)
392 #endif
393  ) {
394  infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
395  }
396 
397 #ifdef HAS_ALPN
398  if(BACKEND->use_alpn) {
399  int cur = 0;
400  int list_start_index = 0;
401  unsigned int *extension_len = NULL;
402  unsigned short* list_len = NULL;
403 
404  /* The first four bytes will be an unsigned int indicating number
405  of bytes of data in the rest of the the buffer. */
406  extension_len = (unsigned int *)(&alpn_buffer[cur]);
407  cur += sizeof(unsigned int);
408 
409  /* The next four bytes are an indicator that this buffer will contain
410  ALPN data, as opposed to NPN, for example. */
411  *(unsigned int *)&alpn_buffer[cur] =
412  SecApplicationProtocolNegotiationExt_ALPN;
413  cur += sizeof(unsigned int);
414 
415  /* The next two bytes will be an unsigned short indicating the number
416  of bytes used to list the preferred protocols. */
417  list_len = (unsigned short*)(&alpn_buffer[cur]);
418  cur += sizeof(unsigned short);
419 
420  list_start_index = cur;
421 
422 #ifdef USE_NGHTTP2
423  if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
424  memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
425  cur += NGHTTP2_PROTO_ALPN_LEN;
426  infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
427  }
428 #endif
429 
430  alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
431  memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
432  cur += ALPN_HTTP_1_1_LENGTH;
433  infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
434 
435  *list_len = curlx_uitous(cur - list_start_index);
436  *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
437 
438  InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
439  InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
440  }
441  else
442  {
443  InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
444  InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
445  }
446 #else /* HAS_ALPN */
447  InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
448  InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
449 #endif
450 
451  /* setup output buffer */
452  InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
453  InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
454 
455  /* setup request flags */
456  BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
457  ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
458  ISC_REQ_STREAM;
459 
460  /* allocate memory for the security context handle */
461  BACKEND->ctxt = (struct curl_schannel_ctxt *)
462  malloc(sizeof(struct curl_schannel_ctxt));
463  if(!BACKEND->ctxt) {
464  failf(data, "schannel: unable to allocate memory");
465  return CURLE_OUT_OF_MEMORY;
466  }
467  memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt));
468 
469  host_name = Curl_convert_UTF8_to_tchar(hostname);
470  if(!host_name)
471  return CURLE_OUT_OF_MEMORY;
472 
473  /* Schannel InitializeSecurityContext:
474  https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
475 
476  At the moment we don't pass inbuf unless we're using ALPN since we only
477  use it for that, and Wine (for which we currently disable ALPN) is giving
478  us problems with inbuf regardless. https://github.com/curl/curl/issues/983
479  */
480  sspi_status = s_pSecFn->InitializeSecurityContext(
481  &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
482  (BACKEND->use_alpn ? &inbuf_desc : NULL),
483  0, &BACKEND->ctxt->ctxt_handle,
484  &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
485 
486  Curl_unicodefree(host_name);
487 
488  if(sspi_status != SEC_I_CONTINUE_NEEDED) {
489  if(sspi_status == SEC_E_WRONG_PRINCIPAL)
490  failf(data, "schannel: SNI or certificate check failed: %s",
491  Curl_sspi_strerror(conn, sspi_status));
492  else
493  failf(data, "schannel: initial InitializeSecurityContext failed: %s",
494  Curl_sspi_strerror(conn, sspi_status));
495  Curl_safefree(BACKEND->ctxt);
497  }
498 
499  infof(data, "schannel: sending initial handshake data: "
500  "sending %lu bytes...\n", outbuf.cbBuffer);
501 
502  /* send initial handshake data which is now stored in output buffer */
503  result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
504  outbuf.cbBuffer, &written);
505  s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
506  if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
507  failf(data, "schannel: failed to send initial handshake data: "
508  "sent %zd of %lu bytes", written, outbuf.cbBuffer);
510  }
511 
512  infof(data, "schannel: sent initial handshake data: "
513  "sent %zd bytes\n", written);
514 
515  BACKEND->recv_unrecoverable_err = CURLE_OK;
516  BACKEND->recv_sspi_close_notify = false;
517  BACKEND->recv_connection_closed = false;
518  BACKEND->encdata_is_incomplete = false;
519 
520  /* continue to second handshake step */
521  connssl->connecting_state = ssl_connect_2;
522 
523  return CURLE_OK;
524 }
525 
526 static CURLcode
527 schannel_connect_step2(struct connectdata *conn, int sockindex)
528 {
529  int i;
530  ssize_t nread = -1, written = -1;
531  struct Curl_easy *data = conn->data;
532  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
533  unsigned char *reallocated_buffer;
534  size_t reallocated_length;
535  SecBuffer outbuf[3];
536  SecBufferDesc outbuf_desc;
537  SecBuffer inbuf[2];
538  SecBufferDesc inbuf_desc;
539  SECURITY_STATUS sspi_status = SEC_E_OK;
540  TCHAR *host_name;
542  bool doread;
543  char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
544  conn->host.name;
545 
546  doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
547 
548  infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
549  hostname, conn->remote_port);
550 
551  if(!BACKEND->cred || !BACKEND->ctxt)
553 
554  /* buffer to store previously received and decrypted data */
555  if(BACKEND->decdata_buffer == NULL) {
556  BACKEND->decdata_offset = 0;
557  BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
558  BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
559  if(BACKEND->decdata_buffer == NULL) {
560  failf(data, "schannel: unable to allocate memory");
561  return CURLE_OUT_OF_MEMORY;
562  }
563  }
564 
565  /* buffer to store previously received and encrypted data */
566  if(BACKEND->encdata_buffer == NULL) {
567  BACKEND->encdata_is_incomplete = false;
568  BACKEND->encdata_offset = 0;
569  BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
570  BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
571  if(BACKEND->encdata_buffer == NULL) {
572  failf(data, "schannel: unable to allocate memory");
573  return CURLE_OUT_OF_MEMORY;
574  }
575  }
576 
577  /* if we need a bigger buffer to read a full message, increase buffer now */
578  if(BACKEND->encdata_length - BACKEND->encdata_offset <
579  CURL_SCHANNEL_BUFFER_FREE_SIZE) {
580  /* increase internal encrypted data buffer */
581  reallocated_length = BACKEND->encdata_offset +
582  CURL_SCHANNEL_BUFFER_FREE_SIZE;
583  reallocated_buffer = realloc(BACKEND->encdata_buffer,
584  reallocated_length);
585 
586  if(reallocated_buffer == NULL) {
587  failf(data, "schannel: unable to re-allocate memory");
588  return CURLE_OUT_OF_MEMORY;
589  }
590  else {
591  BACKEND->encdata_buffer = reallocated_buffer;
592  BACKEND->encdata_length = reallocated_length;
593  }
594  }
595 
596  for(;;) {
597  if(doread) {
598  /* read encrypted handshake data from socket */
599  result = Curl_read_plain(conn->sock[sockindex],
600  (char *) (BACKEND->encdata_buffer +
601  BACKEND->encdata_offset),
602  BACKEND->encdata_length -
603  BACKEND->encdata_offset,
604  &nread);
605  if(result == CURLE_AGAIN) {
608  infof(data, "schannel: failed to receive handshake, "
609  "need more data\n");
610  return CURLE_OK;
611  }
612  else if((result != CURLE_OK) || (nread == 0)) {
613  failf(data, "schannel: failed to receive handshake, "
614  "SSL/TLS connection failed");
616  }
617 
618  /* increase encrypted data buffer offset */
619  BACKEND->encdata_offset += nread;
620  BACKEND->encdata_is_incomplete = false;
621  infof(data, "schannel: encrypted data got %zd\n", nread);
622  }
623 
624  infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
625  BACKEND->encdata_offset, BACKEND->encdata_length);
626 
627  /* setup input buffers */
628  InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
629  curlx_uztoul(BACKEND->encdata_offset));
630  InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
631  InitSecBufferDesc(&inbuf_desc, inbuf, 2);
632 
633  /* setup output buffers */
634  InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
635  InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
636  InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
637  InitSecBufferDesc(&outbuf_desc, outbuf, 3);
638 
639  if(inbuf[0].pvBuffer == NULL) {
640  failf(data, "schannel: unable to allocate memory");
641  return CURLE_OUT_OF_MEMORY;
642  }
643 
644  /* copy received handshake data into input buffer */
645  memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
646  BACKEND->encdata_offset);
647 
648  host_name = Curl_convert_UTF8_to_tchar(hostname);
649  if(!host_name)
650  return CURLE_OUT_OF_MEMORY;
651 
652  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
653  */
654  sspi_status = s_pSecFn->InitializeSecurityContext(
655  &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
656  host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
657  &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
658 
659  Curl_unicodefree(host_name);
660 
661  /* free buffer for received handshake data */
662  Curl_safefree(inbuf[0].pvBuffer);
663 
664  /* check if the handshake was incomplete */
665  if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
666  BACKEND->encdata_is_incomplete = true;
668  infof(data, "schannel: received incomplete message, need more data\n");
669  return CURLE_OK;
670  }
671 
672  /* If the server has requested a client certificate, attempt to continue
673  the handshake without one. This will allow connections to servers which
674  request a client certificate but do not require it. */
675  if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
676  !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
677  BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
679  infof(data, "schannel: a client certificate has been requested\n");
680  return CURLE_OK;
681  }
682 
683  /* check if the handshake needs to be continued */
684  if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
685  for(i = 0; i < 3; i++) {
686  /* search for handshake tokens that need to be send */
687  if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
688  infof(data, "schannel: sending next handshake data: "
689  "sending %lu bytes...\n", outbuf[i].cbBuffer);
690 
691  /* send handshake token to server */
692  result = Curl_write_plain(conn, conn->sock[sockindex],
693  outbuf[i].pvBuffer, outbuf[i].cbBuffer,
694  &written);
695  if((result != CURLE_OK) ||
696  (outbuf[i].cbBuffer != (size_t) written)) {
697  failf(data, "schannel: failed to send next handshake data: "
698  "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
700  }
701  }
702 
703  /* free obsolete buffer */
704  if(outbuf[i].pvBuffer != NULL) {
705  s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
706  }
707  }
708  }
709  else {
710  if(sspi_status == SEC_E_WRONG_PRINCIPAL)
711  failf(data, "schannel: SNI or certificate check failed: %s",
712  Curl_sspi_strerror(conn, sspi_status));
713  else
714  failf(data, "schannel: next InitializeSecurityContext failed: %s",
715  Curl_sspi_strerror(conn, sspi_status));
716  return sspi_status == SEC_E_UNTRUSTED_ROOT ?
718  }
719 
720  /* check if there was additional remaining encrypted data */
721  if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
722  infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
723  /*
724  There are two cases where we could be getting extra data here:
725  1) If we're renegotiating a connection and the handshake is already
726  complete (from the server perspective), it can encrypted app data
727  (not handshake data) in an extra buffer at this point.
728  2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
729  connection and this extra data is part of the handshake.
730  We should process the data immediately; waiting for the socket to
731  be ready may fail since the server is done sending handshake data.
732  */
733  /* check if the remaining data is less than the total amount
734  and therefore begins after the already processed data */
735  if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
736  memmove(BACKEND->encdata_buffer,
737  (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
738  inbuf[1].cbBuffer, inbuf[1].cbBuffer);
739  BACKEND->encdata_offset = inbuf[1].cbBuffer;
740  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
741  doread = FALSE;
742  continue;
743  }
744  }
745  }
746  else {
747  BACKEND->encdata_offset = 0;
748  }
749  break;
750  }
751 
752  /* check if the handshake needs to be continued */
753  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
755  return CURLE_OK;
756  }
757 
758  /* check if the handshake is complete */
759  if(sspi_status == SEC_E_OK) {
760  connssl->connecting_state = ssl_connect_3;
761  infof(data, "schannel: SSL/TLS handshake complete\n");
762  }
763 
764 #ifdef _WIN32_WCE
765  /* Windows CE doesn't do any server certificate validation.
766  We have to do it manually. */
767  if(conn->ssl_config.verifypeer)
768  return verify_certificate(conn, sockindex);
769 #endif
770 
771  return CURLE_OK;
772 }
773 
774 static CURLcode
775 schannel_connect_step3(struct connectdata *conn, int sockindex)
776 {
777  CURLcode result = CURLE_OK;
778  struct Curl_easy *data = conn->data;
779  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
780  SECURITY_STATUS sspi_status = SEC_E_OK;
781  CERT_CONTEXT *ccert_context = NULL;
782 #ifndef CURL_DISABLE_VERBOSE_STRINGS
783  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
784  conn->host.name;
785 #endif
786 #ifdef HAS_ALPN
787  SecPkgContext_ApplicationProtocol alpn_result;
788 #endif
789 
791 
792  infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
793  hostname, conn->remote_port);
794 
795  if(!BACKEND->cred)
797 
798  /* check if the required context attributes are met */
799  if(BACKEND->ret_flags != BACKEND->req_flags) {
800  if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
801  failf(data, "schannel: failed to setup sequence detection");
802  if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
803  failf(data, "schannel: failed to setup replay detection");
804  if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
805  failf(data, "schannel: failed to setup confidentiality");
806  if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
807  failf(data, "schannel: failed to setup memory allocation");
808  if(!(BACKEND->ret_flags & ISC_RET_STREAM))
809  failf(data, "schannel: failed to setup stream orientation");
811  }
812 
813 #ifdef HAS_ALPN
814  if(BACKEND->use_alpn) {
815  sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
816  SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
817 
818  if(sspi_status != SEC_E_OK) {
819  failf(data, "schannel: failed to retrieve ALPN result");
821  }
822 
823  if(alpn_result.ProtoNegoStatus ==
824  SecApplicationProtocolNegotiationStatus_Success) {
825 
826  infof(data, "schannel: ALPN, server accepted to use %.*s\n",
827  alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
828 
829 #ifdef USE_NGHTTP2
830  if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
831  !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
832  NGHTTP2_PROTO_VERSION_ID_LEN)) {
833  conn->negnpn = CURL_HTTP_VERSION_2;
834  }
835  else
836 #endif
837  if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
838  !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
841  }
842  }
843  else
844  infof(data, "ALPN, server did not agree to a protocol\n");
845  }
846 #endif
847 
848  /* save the current session data for possible re-use */
849  if(SSL_SET_OPTION(primary.sessionid)) {
850  bool incache;
851  struct curl_schannel_cred *old_cred = NULL;
852 
853  Curl_ssl_sessionid_lock(conn);
854  incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
855  sockindex));
856  if(incache) {
857  if(old_cred != BACKEND->cred) {
858  infof(data, "schannel: old credential handle is stale, removing\n");
859  /* we're not taking old_cred ownership here, no refcount++ is needed */
860  Curl_ssl_delsessionid(conn, (void *)old_cred);
861  incache = FALSE;
862  }
863  }
864  if(!incache) {
865  result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
866  sizeof(struct curl_schannel_cred),
867  sockindex);
868  if(result) {
869  Curl_ssl_sessionid_unlock(conn);
870  failf(data, "schannel: failed to store credential handle");
871  return result;
872  }
873  else {
874  /* this cred session is now also referenced by sessionid cache */
875  BACKEND->cred->refcount++;
876  infof(data, "schannel: stored credential handle in session cache\n");
877  }
878  }
879  Curl_ssl_sessionid_unlock(conn);
880  }
881 
882  if(data->set.ssl.certinfo) {
883  sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
884  SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
885 
886  if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
887  failf(data, "schannel: failed to retrieve remote cert context");
889  }
890 
891  result = Curl_ssl_init_certinfo(data, 1);
892  if(!result) {
893  if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
894  (ccert_context->cbCertEncoded > 0)) {
895 
896  const char *beg = (const char *) ccert_context->pbCertEncoded;
897  const char *end = beg + ccert_context->cbCertEncoded;
898  result = Curl_extract_certinfo(conn, 0, beg, end);
899  }
900  }
901  CertFreeCertificateContext(ccert_context);
902  if(result)
903  return result;
904  }
905 
907 
908  return CURLE_OK;
909 }
910 
911 static CURLcode
912 schannel_connect_common(struct connectdata *conn, int sockindex,
913  bool nonblocking, bool *done)
914 {
916  struct Curl_easy *data = conn->data;
917  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
918  curl_socket_t sockfd = conn->sock[sockindex];
919  time_t timeout_ms;
920  int what;
921 
922  /* check if the connection has already been established */
923  if(ssl_connection_complete == connssl->state) {
924  *done = TRUE;
925  return CURLE_OK;
926  }
927 
928  if(ssl_connect_1 == connssl->connecting_state) {
929  /* check out how much more time we're allowed */
930  timeout_ms = Curl_timeleft(data, NULL, TRUE);
931 
932  if(timeout_ms < 0) {
933  /* no need to continue if time already is up */
934  failf(data, "SSL/TLS connection timeout");
936  }
937 
938  result = schannel_connect_step1(conn, sockindex);
939  if(result)
940  return result;
941  }
942 
943  while(ssl_connect_2 == connssl->connecting_state ||
946 
947  /* check out how much more time we're allowed */
948  timeout_ms = Curl_timeleft(data, NULL, TRUE);
949 
950  if(timeout_ms < 0) {
951  /* no need to continue if time already is up */
952  failf(data, "SSL/TLS connection timeout");
954  }
955 
956  /* if ssl is expecting something, check if it's available. */
958  || connssl->connecting_state == ssl_connect_2_writing) {
959 
961  connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
963  connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
964 
965  what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
966  nonblocking ? 0 : timeout_ms);
967  if(what < 0) {
968  /* fatal error */
969  failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
971  }
972  else if(0 == what) {
973  if(nonblocking) {
974  *done = FALSE;
975  return CURLE_OK;
976  }
977  else {
978  /* timeout */
979  failf(data, "SSL/TLS connection timeout");
981  }
982  }
983  /* socket is readable or writable */
984  }
985 
986  /* Run transaction, and return to the caller if it failed or if
987  * this connection is part of a multi handle and this loop would
988  * execute again. This permits the owner of a multi handle to
989  * abort a connection attempt before step2 has completed while
990  * ensuring that a client using select() or epoll() will always
991  * have a valid fdset to wait on.
992  */
993  result = schannel_connect_step2(conn, sockindex);
994  if(result || (nonblocking &&
995  (ssl_connect_2 == connssl->connecting_state ||
998  return result;
999 
1000  } /* repeat step2 until all transactions are done. */
1001 
1002  if(ssl_connect_3 == connssl->connecting_state) {
1003  result = schannel_connect_step3(conn, sockindex);
1004  if(result)
1005  return result;
1006  }
1007 
1008  if(ssl_connect_done == connssl->connecting_state) {
1009  connssl->state = ssl_connection_complete;
1010  conn->recv[sockindex] = schannel_recv;
1011  conn->send[sockindex] = schannel_send;
1012  *done = TRUE;
1013  }
1014  else
1015  *done = FALSE;
1016 
1017  /* reset our connection state machine */
1018  connssl->connecting_state = ssl_connect_1;
1019 
1020  return CURLE_OK;
1021 }
1022 
1023 static ssize_t
1024 schannel_send(struct connectdata *conn, int sockindex,
1025  const void *buf, size_t len, CURLcode *err)
1026 {
1027  ssize_t written = -1;
1028  size_t data_len = 0;
1029  unsigned char *data = NULL;
1030  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1031  SecBuffer outbuf[4];
1032  SecBufferDesc outbuf_desc;
1033  SECURITY_STATUS sspi_status = SEC_E_OK;
1034  CURLcode result;
1035 
1036  /* check if the maximum stream sizes were queried */
1037  if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1038  sspi_status = s_pSecFn->QueryContextAttributes(
1039  &BACKEND->ctxt->ctxt_handle,
1040  SECPKG_ATTR_STREAM_SIZES,
1041  &BACKEND->stream_sizes);
1042  if(sspi_status != SEC_E_OK) {
1043  *err = CURLE_SEND_ERROR;
1044  return -1;
1045  }
1046  }
1047 
1048  /* check if the buffer is longer than the maximum message length */
1049  if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1050  len = BACKEND->stream_sizes.cbMaximumMessage;
1051  }
1052 
1053  /* calculate the complete message length and allocate a buffer for it */
1054  data_len = BACKEND->stream_sizes.cbHeader + len +
1055  BACKEND->stream_sizes.cbTrailer;
1056  data = (unsigned char *) malloc(data_len);
1057  if(data == NULL) {
1058  *err = CURLE_OUT_OF_MEMORY;
1059  return -1;
1060  }
1061 
1062  /* setup output buffers (header, data, trailer, empty) */
1063  InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1064  data, BACKEND->stream_sizes.cbHeader);
1065  InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1066  data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1067  InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1068  data + BACKEND->stream_sizes.cbHeader + len,
1069  BACKEND->stream_sizes.cbTrailer);
1070  InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1071  InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1072 
1073  /* copy data into output buffer */
1074  memcpy(outbuf[1].pvBuffer, buf, len);
1075 
1076  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1077  sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1078  &outbuf_desc, 0);
1079 
1080  /* check if the message was encrypted */
1081  if(sspi_status == SEC_E_OK) {
1082  written = 0;
1083 
1084  /* send the encrypted message including header, data and trailer */
1085  len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1086 
1087  /*
1088  It's important to send the full message which includes the header,
1089  encrypted payload, and trailer. Until the client receives all the
1090  data a coherent message has not been delivered and the client
1091  can't read any of it.
1092 
1093  If we wanted to buffer the unwritten encrypted bytes, we would
1094  tell the client that all data it has requested to be sent has been
1095  sent. The unwritten encrypted bytes would be the first bytes to
1096  send on the next invocation.
1097  Here's the catch with this - if we tell the client that all the
1098  bytes have been sent, will the client call this method again to
1099  send the buffered data? Looking at who calls this function, it
1100  seems the answer is NO.
1101  */
1102 
1103  /* send entire message or fail */
1104  while(len > (size_t)written) {
1105  ssize_t this_write;
1106  time_t timeleft;
1107  int what;
1108 
1109  this_write = 0;
1110 
1111  timeleft = Curl_timeleft(conn->data, NULL, FALSE);
1112  if(timeleft < 0) {
1113  /* we already got the timeout */
1114  failf(conn->data, "schannel: timed out sending data "
1115  "(bytes sent: %zd)", written);
1116  *err = CURLE_OPERATION_TIMEDOUT;
1117  written = -1;
1118  break;
1119  }
1120 
1121  what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
1122  if(what < 0) {
1123  /* fatal error */
1124  failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1125  *err = CURLE_SEND_ERROR;
1126  written = -1;
1127  break;
1128  }
1129  else if(0 == what) {
1130  failf(conn->data, "schannel: timed out sending data "
1131  "(bytes sent: %zd)", written);
1132  *err = CURLE_OPERATION_TIMEDOUT;
1133  written = -1;
1134  break;
1135  }
1136  /* socket is writable */
1137 
1138  result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1139  len - written, &this_write);
1140  if(result == CURLE_AGAIN)
1141  continue;
1142  else if(result != CURLE_OK) {
1143  *err = result;
1144  written = -1;
1145  break;
1146  }
1147 
1148  written += this_write;
1149  }
1150  }
1151  else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1152  *err = CURLE_OUT_OF_MEMORY;
1153  }
1154  else{
1155  *err = CURLE_SEND_ERROR;
1156  }
1157 
1158  Curl_safefree(data);
1159 
1160  if(len == (size_t)written)
1161  /* Encrypted message including header, data and trailer entirely sent.
1162  The return value is the number of unencrypted bytes that were sent. */
1163  written = outbuf[1].cbBuffer;
1164 
1165  return written;
1166 }
1167 
1168 static ssize_t
1169 schannel_recv(struct connectdata *conn, int sockindex,
1170  char *buf, size_t len, CURLcode *err)
1171 {
1172  size_t size = 0;
1173  ssize_t nread = -1;
1174  struct Curl_easy *data = conn->data;
1175  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1176  unsigned char *reallocated_buffer;
1177  size_t reallocated_length;
1178  bool done = FALSE;
1179  SecBuffer inbuf[4];
1180  SecBufferDesc inbuf_desc;
1181  SECURITY_STATUS sspi_status = SEC_E_OK;
1182  /* we want the length of the encrypted buffer to be at least large enough
1183  that it can hold all the bytes requested and some TLS record overhead. */
1184  size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1185 
1186  /****************************************************************************
1187  * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1188  * The pattern for return error is set *err, optional infof, goto cleanup.
1189  *
1190  * Our priority is to always return as much decrypted data to the caller as
1191  * possible, even if an error occurs. The state of the decrypted buffer must
1192  * always be valid. Transfer of decrypted data to the caller's buffer is
1193  * handled in the cleanup.
1194  */
1195 
1196  infof(data, "schannel: client wants to read %zu bytes\n", len);
1197  *err = CURLE_OK;
1198 
1199  if(len && len <= BACKEND->decdata_offset) {
1200  infof(data, "schannel: enough decrypted data is already available\n");
1201  goto cleanup;
1202  }
1203  else if(BACKEND->recv_unrecoverable_err) {
1204  *err = BACKEND->recv_unrecoverable_err;
1205  infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1206  goto cleanup;
1207  }
1208  else if(BACKEND->recv_sspi_close_notify) {
1209  /* once a server has indicated shutdown there is no more encrypted data */
1210  infof(data, "schannel: server indicated shutdown in a prior call\n");
1211  goto cleanup;
1212  }
1213  else if(!len) {
1214  /* It's debatable what to return when !len. Regardless we can't return
1215  immediately because there may be data to decrypt (in the case we want to
1216  decrypt all encrypted cached data) so handle !len later in cleanup.
1217  */
1218  ; /* do nothing */
1219  }
1220  else if(!BACKEND->recv_connection_closed) {
1221  /* increase enc buffer in order to fit the requested amount of data */
1222  size = BACKEND->encdata_length - BACKEND->encdata_offset;
1223  if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1224  BACKEND->encdata_length < min_encdata_length) {
1225  reallocated_length = BACKEND->encdata_offset +
1226  CURL_SCHANNEL_BUFFER_FREE_SIZE;
1227  if(reallocated_length < min_encdata_length) {
1228  reallocated_length = min_encdata_length;
1229  }
1230  reallocated_buffer = realloc(BACKEND->encdata_buffer,
1231  reallocated_length);
1232  if(reallocated_buffer == NULL) {
1233  *err = CURLE_OUT_OF_MEMORY;
1234  failf(data, "schannel: unable to re-allocate memory");
1235  goto cleanup;
1236  }
1237 
1238  BACKEND->encdata_buffer = reallocated_buffer;
1239  BACKEND->encdata_length = reallocated_length;
1240  size = BACKEND->encdata_length - BACKEND->encdata_offset;
1241  infof(data, "schannel: encdata_buffer resized %zu\n",
1242  BACKEND->encdata_length);
1243  }
1244 
1245  infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1246  BACKEND->encdata_offset, BACKEND->encdata_length);
1247 
1248  /* read encrypted data from socket */
1249  *err = Curl_read_plain(conn->sock[sockindex],
1250  (char *)(BACKEND->encdata_buffer +
1251  BACKEND->encdata_offset),
1252  size, &nread);
1253  if(*err) {
1254  nread = -1;
1255  if(*err == CURLE_AGAIN)
1256  infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
1257  else if(*err == CURLE_RECV_ERROR)
1258  infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1259  else
1260  infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1261  }
1262  else if(nread == 0) {
1263  BACKEND->recv_connection_closed = true;
1264  infof(data, "schannel: server closed the connection\n");
1265  }
1266  else if(nread > 0) {
1267  BACKEND->encdata_offset += (size_t)nread;
1268  BACKEND->encdata_is_incomplete = false;
1269  infof(data, "schannel: encrypted data got %zd\n", nread);
1270  }
1271  }
1272 
1273  infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1274  BACKEND->encdata_offset, BACKEND->encdata_length);
1275 
1276  /* decrypt loop */
1277  while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1278  (!len || BACKEND->decdata_offset < len ||
1279  BACKEND->recv_connection_closed)) {
1280  /* prepare data buffer for DecryptMessage call */
1281  InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1282  curlx_uztoul(BACKEND->encdata_offset));
1283 
1284  /* we need 3 more empty input buffers for possible output */
1285  InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1286  InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1287  InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1288  InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1289 
1290  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1291  */
1292  sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1293  &inbuf_desc, 0, NULL);
1294 
1295  /* check if everything went fine (server may want to renegotiate
1296  or shutdown the connection context) */
1297  if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1298  sspi_status == SEC_I_CONTEXT_EXPIRED) {
1299  /* check for successfully decrypted data, even before actual
1300  renegotiation or shutdown of the connection context */
1301  if(inbuf[1].BufferType == SECBUFFER_DATA) {
1302  infof(data, "schannel: decrypted data length: %lu\n",
1303  inbuf[1].cbBuffer);
1304 
1305  /* increase buffer in order to fit the received amount of data */
1306  size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1307  inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1308  if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1309  BACKEND->decdata_length < len) {
1310  /* increase internal decrypted data buffer */
1311  reallocated_length = BACKEND->decdata_offset + size;
1312  /* make sure that the requested amount of data fits */
1313  if(reallocated_length < len) {
1314  reallocated_length = len;
1315  }
1316  reallocated_buffer = realloc(BACKEND->decdata_buffer,
1317  reallocated_length);
1318  if(reallocated_buffer == NULL) {
1319  *err = CURLE_OUT_OF_MEMORY;
1320  failf(data, "schannel: unable to re-allocate memory");
1321  goto cleanup;
1322  }
1323  BACKEND->decdata_buffer = reallocated_buffer;
1324  BACKEND->decdata_length = reallocated_length;
1325  }
1326 
1327  /* copy decrypted data to internal buffer */
1328  size = inbuf[1].cbBuffer;
1329  if(size) {
1330  memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1331  inbuf[1].pvBuffer, size);
1332  BACKEND->decdata_offset += size;
1333  }
1334 
1335  infof(data, "schannel: decrypted data added: %zu\n", size);
1336  infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
1337  BACKEND->decdata_offset, BACKEND->decdata_length);
1338  }
1339 
1340  /* check for remaining encrypted data */
1341  if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1342  infof(data, "schannel: encrypted data length: %lu\n",
1343  inbuf[3].cbBuffer);
1344 
1345  /* check if the remaining data is less than the total amount
1346  * and therefore begins after the already processed data
1347  */
1348  if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1349  /* move remaining encrypted data forward to the beginning of
1350  buffer */
1351  memmove(BACKEND->encdata_buffer,
1352  (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1353  inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1354  BACKEND->encdata_offset = inbuf[3].cbBuffer;
1355  }
1356 
1357  infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
1358  BACKEND->encdata_offset, BACKEND->encdata_length);
1359  }
1360  else {
1361  /* reset encrypted buffer offset, because there is no data remaining */
1362  BACKEND->encdata_offset = 0;
1363  }
1364 
1365  /* check if server wants to renegotiate the connection context */
1366  if(sspi_status == SEC_I_RENEGOTIATE) {
1367  infof(data, "schannel: remote party requests renegotiation\n");
1368  if(*err && *err != CURLE_AGAIN) {
1369  infof(data, "schannel: can't renogotiate, an error is pending\n");
1370  goto cleanup;
1371  }
1372  if(BACKEND->encdata_offset) {
1373  *err = CURLE_RECV_ERROR;
1374  infof(data, "schannel: can't renogotiate, "
1375  "encrypted data available\n");
1376  goto cleanup;
1377  }
1378  /* begin renegotiation */
1379  infof(data, "schannel: renegotiating SSL/TLS connection\n");
1380  connssl->state = ssl_connection_negotiating;
1382  *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1383  if(*err) {
1384  infof(data, "schannel: renegotiation failed\n");
1385  goto cleanup;
1386  }
1387  /* now retry receiving data */
1388  sspi_status = SEC_E_OK;
1389  infof(data, "schannel: SSL/TLS connection renegotiated\n");
1390  continue;
1391  }
1392  /* check if the server closed the connection */
1393  else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1394  /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1395  returned so we have to work around that in cleanup. */
1396  BACKEND->recv_sspi_close_notify = true;
1397  if(!BACKEND->recv_connection_closed) {
1398  BACKEND->recv_connection_closed = true;
1399  infof(data, "schannel: server closed the connection\n");
1400  }
1401  goto cleanup;
1402  }
1403  }
1404  else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1405  BACKEND->encdata_is_incomplete = true;
1406  if(!*err)
1407  *err = CURLE_AGAIN;
1408  infof(data, "schannel: failed to decrypt data, need more data\n");
1409  goto cleanup;
1410  }
1411  else {
1412  *err = CURLE_RECV_ERROR;
1413  infof(data, "schannel: failed to read data from server: %s\n",
1414  Curl_sspi_strerror(conn, sspi_status));
1415  goto cleanup;
1416  }
1417  }
1418 
1419  infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1420  BACKEND->encdata_offset, BACKEND->encdata_length);
1421 
1422  infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1423  BACKEND->decdata_offset, BACKEND->decdata_length);
1424 
1425 cleanup:
1426  /* Warning- there is no guarantee the encdata state is valid at this point */
1427  infof(data, "schannel: schannel_recv cleanup\n");
1428 
1429  /* Error if the connection has closed without a close_notify.
1430  Behavior here is a matter of debate. We don't want to be vulnerable to a
1431  truncation attack however there's some browser precedent for ignoring the
1432  close_notify for compatibility reasons.
1433  Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1434  return close_notify. In that case if the connection was closed we assume it
1435  was graceful (close_notify) since there doesn't seem to be a way to tell.
1436  */
1437  if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1438  !BACKEND->recv_sspi_close_notify) {
1439  bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1440  VERSION_EQUAL);
1441 
1442  if(isWin2k && sspi_status == SEC_E_OK)
1443  BACKEND->recv_sspi_close_notify = true;
1444  else {
1445  *err = CURLE_RECV_ERROR;
1446  infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1447  }
1448  }
1449 
1450  /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1451  if(*err && *err != CURLE_AGAIN)
1452  BACKEND->recv_unrecoverable_err = *err;
1453 
1454  size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1455  if(size) {
1456  memcpy(buf, BACKEND->decdata_buffer, size);
1457  memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1458  BACKEND->decdata_offset - size);
1459  BACKEND->decdata_offset -= size;
1460 
1461  infof(data, "schannel: decrypted data returned %zu\n", size);
1462  infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1463  BACKEND->decdata_offset, BACKEND->decdata_length);
1464  *err = CURLE_OK;
1465  return (ssize_t)size;
1466  }
1467 
1468  if(!*err && !BACKEND->recv_connection_closed)
1469  *err = CURLE_AGAIN;
1470 
1471  /* It's debatable what to return when !len. We could return whatever error we
1472  got from decryption but instead we override here so the return is consistent.
1473  */
1474  if(!len)
1475  *err = CURLE_OK;
1476 
1477  return *err ? -1 : 0;
1478 }
1479 
1480 static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
1481  int sockindex, bool *done)
1482 {
1483  return schannel_connect_common(conn, sockindex, TRUE, done);
1484 }
1485 
1486 static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
1487 {
1488  CURLcode result;
1489  bool done = FALSE;
1490 
1491  result = schannel_connect_common(conn, sockindex, FALSE, &done);
1492  if(result)
1493  return result;
1494 
1495  DEBUGASSERT(done);
1496 
1497  return CURLE_OK;
1498 }
1499 
1500 static bool Curl_schannel_data_pending(const struct connectdata *conn,
1501  int sockindex)
1502 {
1503  const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1504 
1505  if(connssl->use) /* SSL/TLS is in use */
1506  return (BACKEND->decdata_offset > 0 ||
1507  (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1508  else
1509  return FALSE;
1510 }
1511 
1512 static void Curl_schannel_close(struct connectdata *conn, int sockindex)
1513 {
1514  if(conn->ssl[sockindex].use)
1515  /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1516  Curl_ssl_shutdown(conn, sockindex);
1517 }
1518 
1519 static void Curl_schannel_session_free(void *ptr)
1520 {
1521  /* this is expected to be called under sessionid lock */
1522  struct curl_schannel_cred *cred = ptr;
1523 
1524  cred->refcount--;
1525  if(cred->refcount == 0) {
1526  s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1527  Curl_safefree(cred);
1528  }
1529 }
1530 
1531 static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1532 {
1533  /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1534  * Shutting Down an Schannel Connection
1535  */
1536  struct Curl_easy *data = conn->data;
1537  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1538  char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1539  conn->host.name;
1540 
1541  infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1542  hostname, conn->remote_port);
1543 
1544  if(BACKEND->cred && BACKEND->ctxt) {
1545  SecBufferDesc BuffDesc;
1546  SecBuffer Buffer;
1547  SECURITY_STATUS sspi_status;
1548  SecBuffer outbuf;
1549  SecBufferDesc outbuf_desc;
1550  CURLcode result;
1551  TCHAR *host_name;
1552  DWORD dwshut = SCHANNEL_SHUTDOWN;
1553 
1554  InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
1555  InitSecBufferDesc(&BuffDesc, &Buffer, 1);
1556 
1557  sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
1558  &BuffDesc);
1559 
1560  if(sspi_status != SEC_E_OK)
1561  failf(data, "schannel: ApplyControlToken failure: %s",
1562  Curl_sspi_strerror(conn, sspi_status));
1563 
1564  host_name = Curl_convert_UTF8_to_tchar(hostname);
1565  if(!host_name)
1566  return CURLE_OUT_OF_MEMORY;
1567 
1568  /* setup output buffer */
1569  InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1570  InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1571 
1572  sspi_status = s_pSecFn->InitializeSecurityContext(
1573  &BACKEND->cred->cred_handle,
1574  &BACKEND->ctxt->ctxt_handle,
1575  host_name,
1576  BACKEND->req_flags,
1577  0,
1578  0,
1579  NULL,
1580  0,
1581  &BACKEND->ctxt->ctxt_handle,
1582  &outbuf_desc,
1583  &BACKEND->ret_flags,
1584  &BACKEND->ctxt->time_stamp);
1585 
1586  Curl_unicodefree(host_name);
1587 
1588  if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
1589  /* send close message which is in output buffer */
1590  ssize_t written;
1591  result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
1592  outbuf.cbBuffer, &written);
1593 
1594  s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1595  if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1596  infof(data, "schannel: failed to send close msg: %s"
1597  " (bytes written: %zd)\n", curl_easy_strerror(result), written);
1598  }
1599  }
1600  }
1601 
1602  /* free SSPI Schannel API security context handle */
1603  if(BACKEND->ctxt) {
1604  infof(data, "schannel: clear security context handle\n");
1605  s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
1606  Curl_safefree(BACKEND->ctxt);
1607  }
1608 
1609  /* free SSPI Schannel API credential handle */
1610  if(BACKEND->cred) {
1611  Curl_ssl_sessionid_lock(conn);
1612  Curl_schannel_session_free(BACKEND->cred);
1613  Curl_ssl_sessionid_unlock(conn);
1614  BACKEND->cred = NULL;
1615  }
1616 
1617  /* free internal buffer for received encrypted data */
1618  if(BACKEND->encdata_buffer != NULL) {
1619  Curl_safefree(BACKEND->encdata_buffer);
1620  BACKEND->encdata_length = 0;
1621  BACKEND->encdata_offset = 0;
1622  BACKEND->encdata_is_incomplete = false;
1623  }
1624 
1625  /* free internal buffer for received decrypted data */
1626  if(BACKEND->decdata_buffer != NULL) {
1627  Curl_safefree(BACKEND->decdata_buffer);
1628  BACKEND->decdata_length = 0;
1629  BACKEND->decdata_offset = 0;
1630  }
1631 
1632  return CURLE_OK;
1633 }
1634 
1635 static int Curl_schannel_init(void)
1636 {
1637  return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
1638 }
1639 
1640 static void Curl_schannel_cleanup(void)
1641 {
1642  Curl_sspi_global_cleanup();
1643 }
1644 
1645 static size_t Curl_schannel_version(char *buffer, size_t size)
1646 {
1647  size = snprintf(buffer, size, "WinSSL");
1648 
1649  return size;
1650 }
1651 
1652 static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
1653  unsigned char *entropy, size_t length)
1654 {
1655  HCRYPTPROV hCryptProv = 0;
1656 
1657  (void)data;
1658 
1659  if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
1660  CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
1661  return CURLE_FAILED_INIT;
1662 
1663  if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
1664  CryptReleaseContext(hCryptProv, 0UL);
1665  return CURLE_FAILED_INIT;
1666  }
1667 
1668  CryptReleaseContext(hCryptProv, 0UL);
1669  return CURLE_OK;
1670 }
1671 
1672 #ifdef _WIN32_WCE
1673 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
1674 {
1675  SECURITY_STATUS status;
1676  struct Curl_easy *data = conn->data;
1677  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1678  CURLcode result = CURLE_OK;
1679  CERT_CONTEXT *pCertContextServer = NULL;
1680  const CERT_CHAIN_CONTEXT *pChainContext = NULL;
1681  const char * const conn_hostname = SSL_IS_PROXY() ?
1682  conn->http_proxy.host.name :
1683  conn->host.name;
1684 
1685  status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1686  SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1687  &pCertContextServer);
1688 
1689  if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
1690  failf(data, "schannel: Failed to read remote certificate context: %s",
1691  Curl_sspi_strerror(conn, status));
1693  }
1694 
1695  if(result == CURLE_OK) {
1696  CERT_CHAIN_PARA ChainPara;
1697  memset(&ChainPara, 0, sizeof(ChainPara));
1698  ChainPara.cbSize = sizeof(ChainPara);
1699 
1700  if(!CertGetCertificateChain(NULL,
1701  pCertContextServer,
1702  NULL,
1703  pCertContextServer->hCertStore,
1704  &ChainPara,
1705  (data->set.ssl.no_revoke ? 0 :
1706  CERT_CHAIN_REVOCATION_CHECK_CHAIN),
1707  NULL,
1708  &pChainContext)) {
1709  failf(data, "schannel: CertGetCertificateChain failed: %s",
1710  Curl_sspi_strerror(conn, GetLastError()));
1711  pChainContext = NULL;
1713  }
1714 
1715  if(result == CURLE_OK) {
1716  CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
1717  DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
1718  dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
1719  if(dwTrustErrorMask) {
1720  if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
1721  failf(data, "schannel: CertGetCertificateChain trust error"
1722  " CERT_TRUST_IS_REVOKED");
1723  else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
1724  failf(data, "schannel: CertGetCertificateChain trust error"
1725  " CERT_TRUST_IS_PARTIAL_CHAIN");
1726  else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
1727  failf(data, "schannel: CertGetCertificateChain trust error"
1728  " CERT_TRUST_IS_UNTRUSTED_ROOT");
1729  else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
1730  failf(data, "schannel: CertGetCertificateChain trust error"
1731  " CERT_TRUST_IS_NOT_TIME_VALID");
1732  else
1733  failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
1734  dwTrustErrorMask);
1736  }
1737  }
1738  }
1739 
1740  if(result == CURLE_OK) {
1741  if(conn->ssl_config.verifyhost) {
1742  TCHAR cert_hostname_buff[256];
1743  DWORD len;
1744 
1745  /* TODO: Fix this for certificates with multiple alternative names.
1746  Right now we're only asking for the first preferred alternative name.
1747  Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
1748  (if WinCE supports that?) and run this section in a loop for each.
1749  https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
1750  curl: (51) schannel: CertGetNameString() certificate hostname
1751  (.google.com) did not match connection (google.com)
1752  */
1753  len = CertGetNameString(pCertContextServer,
1754  CERT_NAME_DNS_TYPE,
1755  CERT_NAME_DISABLE_IE4_UTF8_FLAG,
1756  NULL,
1757  cert_hostname_buff,
1758  256);
1759  if(len > 0) {
1760  const char *cert_hostname;
1761 
1762  /* Comparing the cert name and the connection hostname encoded as UTF-8
1763  * is acceptable since both values are assumed to use ASCII
1764  * (or some equivalent) encoding
1765  */
1766  cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
1767  if(!cert_hostname) {
1768  result = CURLE_OUT_OF_MEMORY;
1769  }
1770  else{
1771  int match_result;
1772 
1773  match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
1774  if(match_result == CURL_HOST_MATCH) {
1775  infof(data,
1776  "schannel: connection hostname (%s) validated "
1777  "against certificate name (%s)\n",
1778  conn->host.name,
1779  cert_hostname);
1780  result = CURLE_OK;
1781  }
1782  else{
1783  failf(data,
1784  "schannel: connection hostname (%s) "
1785  "does not match certificate name (%s)",
1786  conn->host.name,
1787  cert_hostname);
1789  }
1790  Curl_unicodefree(cert_hostname);
1791  }
1792  }
1793  else {
1794  failf(data,
1795  "schannel: CertGetNameString did not provide any "
1796  "certificate name information");
1798  }
1799  }
1800  }
1801 
1802  if(pChainContext)
1803  CertFreeCertificateChain(pChainContext);
1804 
1805  if(pCertContextServer)
1806  CertFreeCertificateContext(pCertContextServer);
1807 
1808  return result;
1809 }
1810 #endif /* _WIN32_WCE */
1811 
1812 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
1813  CURLINFO info UNUSED_PARAM)
1814 {
1815  (void)info;
1816  return &BACKEND->ctxt->ctxt_handle;
1817 }
1818 
1819 const struct Curl_ssl Curl_ssl_schannel = {
1820  { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
1821 
1822  0, /* have_ca_path */
1823  1, /* have_certinfo */
1824  0, /* have_pinnedpubkey */
1825  0, /* have_ssl_ctx */
1826  0, /* support_https_proxy */
1827 
1828  sizeof(struct ssl_backend_data),
1829 
1830  Curl_schannel_init, /* init */
1831  Curl_schannel_cleanup, /* cleanup */
1832  Curl_schannel_version, /* version */
1833  Curl_none_check_cxn, /* check_cxn */
1834  Curl_schannel_shutdown, /* shutdown */
1835  Curl_schannel_data_pending, /* data_pending */
1836  Curl_schannel_random, /* random */
1837  Curl_none_cert_status_request, /* cert_status_request */
1838  Curl_schannel_connect, /* connect */
1839  Curl_schannel_connect_nonblocking, /* connect_nonblocking */
1840  Curl_schannel_get_internals, /* get_internals */
1841  Curl_schannel_close, /* close */
1842  Curl_none_close_all, /* close_all */
1843  Curl_schannel_session_free, /* session_free */
1844  Curl_none_set_engine, /* set_engine */
1845  Curl_none_set_engine_default, /* set_engine_default */
1846  Curl_none_engines_list, /* engines_list */
1847  Curl_none_false_start, /* false_start */
1848  Curl_none_md5sum, /* md5sum */
1849  NULL /* sha256sum */
1850 };
1851 
1852 #endif /* USE_SCHANNEL */
struct ssl_connect_data ssl[2]
Definition: urldata.h:887
#define UNUSED_PARAM
Definition: curl_setup.h:660
ssize_t( Curl_recv)(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err)
Definition: urldata.h:737
struct ConnectBits bits
Definition: urldata.h:893
struct UserDefined set
Definition: urldata.h:1762
Curl_recv * recv[2]
Definition: urldata.h:881
#define SSL_CONN_CONFIG(var)
Definition: vtls.h:135
int negnpn
Definition: urldata.h:1027
struct hostname host
Definition: urldata.h:758
CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written)
Definition: sendf.c:408
#define ALPN_HTTP_1_1
Definition: vtls.h:125
#define CURL_SOCKET_BAD
Definition: curl.h:131
Definition: vtls.h:29
#define failf
Definition: sendf.h:48
#define SSL_SET_OPTION(var)
Definition: vtls.h:133
ssl_connect_state connecting_state
Definition: urldata.h:201
#define SOCKERRNO
#define DEBUGASSERT(x)
UNITTEST_START char * ptr
Definition: unit1330.c:38
CURLcode
Definition: curl.h:454
CURLINFO
Definition: curl.h:2439
#define ENABLE_IPV6
Definition: config-os400.h:71
struct hostname host
Definition: urldata.h:833
#define realloc(ptr, size)
Definition: curl_memory.h:128
#define malloc(size)
Definition: curl_memory.h:124
char * name
Definition: urldata.h:444
UNITTEST_START int result
Definition: unit1304.c:49
char buffer[]
Definition: unit1308.c:48
struct ssl_config_data ssl
Definition: urldata.h:1586
unsigned int i
Definition: unit1303.c:79
bool no_revoke
Definition: urldata.h:226
size_t len
Definition: curl_sasl.c:55
struct proxy_info http_proxy
Definition: urldata.h:839
CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n)
Definition: sendf.c:655
ssl_connection_state state
Definition: urldata.h:200
long httpversion
Definition: urldata.h:1583
memcpy(filename, filename1, strlen(filename1))
#define Curl_ssl_shutdown(x, y)
Definition: vtls.h:256
unsigned long curlx_uztoul(size_t uznum)
Definition: warnless.c:222
int Curl_none_check_cxn(struct connectdata *conn)
#define ALPN_HTTP_1_1_LENGTH
Definition: vtls.h:124
#define FALSE
time_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect)
Definition: connect.c:182
curl_easy_setopt expects a curl_off_t argument for this option curl_easy_setopt expects a curl_write_callback argument for this option curl_easy_setopt expects a curl_ioctl_callback argument for this option curl_easy_setopt expects a curl_opensocket_callback argument for this option curl_easy_setopt expects a curl_debug_callback argument for this option curl_easy_setopt expects a curl_conv_callback argument for this option curl_easy_setopt expects a private data pointer as argument for this option curl_easy_setopt expects a FILE *argument for this option curl_easy_setopt expects a struct curl_httppost *argument for this option curl_easy_setopt expects a struct curl_slist *argument for this option curl_easy_getinfo expects a pointer to char *for this info curl_easy_getinfo expects a pointer to double for this info curl_easy_getinfo expects a pointer to struct curl_tlssessioninfo *for this info curl_easy_getinfo expects a pointer to curl_socket_t for this info size_t
bool tls_enable_alpn
Definition: urldata.h:435
bool Curl_none_false_start(void)
bool Curl_none_cert_status_request(void)
#define SOCKET_WRITABLE(x, z)
Definition: select.h:81
Curl_send * send[2]
Definition: urldata.h:882
Definition: curl.h:455
ssize_t( Curl_send)(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err)
Definition: urldata.h:730
int Curl_inet_pton(int af, const char *src, void *dst)
Definition: inet_pton.c:66
CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len)
#define Curl_safefree(ptr)
Definition: memdebug.h:170
int Curl_socket_check(curl_socket_t readfd0, curl_socket_t readfd1, curl_socket_t writefd, time_t timeout_ms)
Definition: select.c:145
unsigned short curlx_uitous(unsigned int uinum)
Definition: warnless.c:388
CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine)
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
#define ssize_t
Definition: config-win32.h:382
curl_socket_t sock[2]
Definition: urldata.h:876
struct ssl_primary_config ssl_config
Definition: urldata.h:889
struct curl_slist * Curl_none_engines_list(struct Curl_easy *data)
char buf[3]
Definition: unit1398.c:32
#define infof
Definition: sendf.h:44
#define CURL_HTTP_VERSION_2
Definition: curl.h:1879
size_t size
Definition: unit1302.c:52
#define snprintf
Definition: curl_printf.h:42
#define TRUE
int curl_socket_t
Definition: curl.h:130
CURL_EXTERN const char * curl_easy_strerror(CURLcode)
Definition: strerror.c:57
CURLcode Curl_none_set_engine_default(struct Curl_easy *data)
Definition: debug.c:29
int remote_port
Definition: urldata.h:842
void Curl_none_close_all(struct Curl_easy *data)
#define CURL_HOST_MATCH
Definition: hostcheck.h:28
#define SSL_IS_PROXY()
Definition: vtls.h:130
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16