source: asp3_tinet_ecnl_arm/trunk/curl-7.57.0/lib/vtls/schannel.c@ 352

Last change on this file since 352 was 352, checked in by coas-nagasima, 6 years ago

arm向けASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 64.2 KB
Line 
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 */
133struct curl_schannel_cred {
134 CredHandle cred_handle;
135 TimeStamp time_stamp;
136 int refcount;
137};
138
139struct curl_schannel_ctxt {
140 CtxtHandle ctxt_handle;
141 TimeStamp time_stamp;
142};
143
144struct 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
165static Curl_recv schannel_recv;
166static Curl_send schannel_send;
167
168#ifdef _WIN32_WCE
169static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
170#endif
171
172static 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
180static 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
188static CURLcode
189set_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) {
197 case CURL_SSLVERSION_MAX_NONE:
198 ssl_version_max = ssl_version << 16;
199 break;
200 case CURL_SSLVERSION_MAX_DEFAULT:
201 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
202 break;
203 }
204 for(; i <= (ssl_version_max >> 16); ++i) {
205 switch(i) {
206 case CURL_SSLVERSION_TLSv1_0:
207 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
208 break;
209 case CURL_SSLVERSION_TLSv1_1:
210 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
211 break;
212 case CURL_SSLVERSION_TLSv1_2:
213 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
214 break;
215 case CURL_SSLVERSION_TLSv1_3:
216 failf(data, "Schannel: TLS 1.3 is not yet supported");
217 return CURLE_SSL_CONNECT_ERROR;
218 }
219 }
220 return CURLE_OK;
221}
222
223static CURLcode
224schannel_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;
244 CURLcode result;
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) {
330 case CURL_SSLVERSION_DEFAULT:
331 case CURL_SSLVERSION_TLSv1:
332 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
333 SP_PROT_TLS1_1_CLIENT |
334 SP_PROT_TLS1_2_CLIENT;
335 break;
336 case CURL_SSLVERSION_TLSv1_0:
337 case CURL_SSLVERSION_TLSv1_1:
338 case CURL_SSLVERSION_TLSv1_2:
339 case CURL_SSLVERSION_TLSv1_3:
340 {
341 result = set_ssl_version_min_max(&schannel_cred, conn);
342 if(result != CURLE_OK)
343 return result;
344 break;
345 }
346 case CURL_SSLVERSION_SSLv3:
347 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
348 break;
349 case CURL_SSLVERSION_SSLv2:
350 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
351 break;
352 default:
353 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
354 return CURLE_SSL_CONNECT_ERROR;
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);
384 return CURLE_SSL_CONNECT_ERROR;
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);
496 return CURLE_SSL_CONNECT_ERROR;
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);
509 return CURLE_SSL_CONNECT_ERROR;
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
526static CURLcode
527schannel_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;
541 CURLcode result;
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)
552 return CURLE_SSL_CONNECT_ERROR;
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) {
606 if(connssl->connecting_state != ssl_connect_2_writing)
607 connssl->connecting_state = ssl_connect_2_reading;
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");
615 return CURLE_SSL_CONNECT_ERROR;
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;
667 connssl->connecting_state = ssl_connect_2_reading;
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;
678 connssl->connecting_state = ssl_connect_2_writing;
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);
699 return CURLE_SSL_CONNECT_ERROR;
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 ?
717 CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR;
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) {
754 connssl->connecting_state = ssl_connect_2_reading;
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
774static CURLcode
775schannel_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
790 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
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)
796 return CURLE_SSL_CONNECT_ERROR;
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");
810 return CURLE_SSL_CONNECT_ERROR;
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");
820 return CURLE_SSL_CONNECT_ERROR;
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,
839 ALPN_HTTP_1_1_LENGTH)) {
840 conn->negnpn = CURL_HTTP_VERSION_1_1;
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");
888 return CURLE_SSL_CONNECT_ERROR;
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
906 connssl->connecting_state = ssl_connect_done;
907
908 return CURLE_OK;
909}
910
911static CURLcode
912schannel_connect_common(struct connectdata *conn, int sockindex,
913 bool nonblocking, bool *done)
914{
915 CURLcode result;
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");
935 return CURLE_OPERATION_TIMEDOUT;
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 ||
944 ssl_connect_2_reading == connssl->connecting_state ||
945 ssl_connect_2_writing == 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");
953 return CURLE_OPERATION_TIMEDOUT;
954 }
955
956 /* if ssl is expecting something, check if it's available. */
957 if(connssl->connecting_state == ssl_connect_2_reading
958 || connssl->connecting_state == ssl_connect_2_writing) {
959
960 curl_socket_t writefd = ssl_connect_2_writing ==
961 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
962 curl_socket_t readfd = ssl_connect_2_reading ==
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);
970 return CURLE_SSL_CONNECT_ERROR;
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");
980 return CURLE_OPERATION_TIMEDOUT;
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 ||
996 ssl_connect_2_reading == connssl->connecting_state ||
997 ssl_connect_2_writing == 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
1023static ssize_t
1024schannel_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
1168static ssize_t
1169schannel_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;
1381 connssl->connecting_state = ssl_connect_2_writing;
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
1425cleanup:
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
1480static 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
1486static 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
1500static 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
1512static 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
1519static 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
1531static 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
1635static int Curl_schannel_init(void)
1636{
1637 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
1638}
1639
1640static void Curl_schannel_cleanup(void)
1641{
1642 Curl_sspi_global_cleanup();
1643}
1644
1645static size_t Curl_schannel_version(char *buffer, size_t size)
1646{
1647 size = snprintf(buffer, size, "WinSSL");
1648
1649 return size;
1650}
1651
1652static 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
1673static 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));
1692 result = CURLE_PEER_FAILED_VERIFICATION;
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;
1712 result = CURLE_PEER_FAILED_VERIFICATION;
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);
1735 result = CURLE_PEER_FAILED_VERIFICATION;
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);
1788 result = CURLE_PEER_FAILED_VERIFICATION;
1789 }
1790 Curl_unicodefree(cert_hostname);
1791 }
1792 }
1793 else {
1794 failf(data,
1795 "schannel: CertGetNameString did not provide any "
1796 "certificate name information");
1797 result = CURLE_PEER_FAILED_VERIFICATION;
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
1812static 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
1819const 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_one */
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 */
Note: See TracBrowser for help on using the repository browser.