1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
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.
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.
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.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ***************************************************************************/
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.
32 * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
33 * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
35 * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
36 * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
38 * Thanks for code and inspiration!
41 #include "curl_setup.h"
45 #ifndef USE_WINDOWS_SSPI
46 # error "Can't compile SCHANNEL support without SSPI."
49 #include "curl_sspi.h"
53 #include "connect.h" /* for the connect timeout */
55 #include "select.h" /* for the socket readyness */
56 #include "inet_pton.h" /* for IP addr SNI check */
57 #include "curl_multibyte.h"
60 #include "curl_printf.h"
61 #include "system_win32.h"
62 #include "hostcheck.h"
64 /* The last #include file should be: */
65 #include "curl_memory.h"
68 /* ALPN requires version 8.1 of the Windows SDK, which was
69 shipped with Visual Studio 2013, aka _MSC_VER 1800:
71 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
73 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
77 /* Uncomment to force verbose output
78 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
79 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
82 static Curl_recv schannel_recv;
83 static Curl_send schannel_send;
86 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
89 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
90 void *BufDataPtr, unsigned long BufByteSize)
92 buffer->cbBuffer = BufByteSize;
93 buffer->BufferType = BufType;
94 buffer->pvBuffer = BufDataPtr;
97 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
98 unsigned long NumArrElem)
100 desc->ulVersion = SECBUFFER_VERSION;
101 desc->pBuffers = BufArr;
102 desc->cBuffers = NumArrElem;
106 schannel_connect_step1(struct connectdata *conn, int sockindex)
108 ssize_t written = -1;
109 struct Curl_easy *data = conn->data;
110 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
112 SecBufferDesc outbuf_desc;
114 SecBufferDesc inbuf_desc;
116 unsigned char alpn_buffer[128];
118 SCHANNEL_CRED schannel_cred;
119 SECURITY_STATUS sspi_status = SEC_E_OK;
120 struct curl_schannel_cred *old_cred = NULL;
123 struct in6_addr addr6;
127 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
130 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
131 hostname, conn->remote_port);
133 if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
134 VERSION_LESS_THAN_EQUAL)) {
135 /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
136 algorithms that may not be supported by all servers. */
137 infof(data, "schannel: WinSSL version is old and may not be able to "
138 "connect to some servers due to lack of SNI, algorithms, etc.\n");
142 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
143 Also it doesn't seem to be supported for Wine, see curl bug #983. */
144 connssl->use_alpn = conn->bits.tls_enable_alpn &&
145 !GetProcAddress(GetModuleHandleA("ntdll"),
146 "wine_get_version") &&
147 Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
148 VERSION_GREATER_THAN_EQUAL);
150 connssl->use_alpn = false;
153 connssl->cred = NULL;
155 /* check for an existing re-usable credential handle */
156 if(data->set.general_ssl.sessionid) {
157 Curl_ssl_sessionid_lock(conn);
158 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
159 connssl->cred = old_cred;
160 infof(data, "schannel: re-using existing credential handle\n");
162 /* increment the reference counter of the credential/session handle */
163 connssl->cred->refcount++;
164 infof(data, "schannel: incremented credential handle refcount = %d\n",
165 connssl->cred->refcount);
167 Curl_ssl_sessionid_unlock(conn);
171 /* setup Schannel API options */
172 memset(&schannel_cred, 0, sizeof(schannel_cred));
173 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
175 if(conn->ssl_config.verifypeer) {
177 /* certificate validation on CE doesn't seem to work right; we'll
178 do it following a more manual process. */
179 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
180 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
181 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
183 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
184 /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
185 if(data->set.ssl.no_revoke)
186 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
187 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
189 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
191 if(data->set.ssl.no_revoke)
192 infof(data, "schannel: disabled server certificate revocation "
195 infof(data, "schannel: checking server certificate revocation\n");
198 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
199 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
200 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
201 infof(data, "schannel: disabled server certificate revocation checks\n");
204 if(!conn->ssl_config.verifyhost) {
205 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
206 infof(data, "schannel: verifyhost setting prevents Schannel from "
207 "comparing the supplied target name with the subject "
208 "names in server certificates.\n");
211 switch(conn->ssl_config.version) {
212 case CURL_SSLVERSION_DEFAULT:
213 case CURL_SSLVERSION_TLSv1:
214 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
215 SP_PROT_TLS1_1_CLIENT |
216 SP_PROT_TLS1_2_CLIENT;
218 case CURL_SSLVERSION_TLSv1_0:
219 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
221 case CURL_SSLVERSION_TLSv1_1:
222 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
224 case CURL_SSLVERSION_TLSv1_2:
225 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
227 case CURL_SSLVERSION_TLSv1_3:
228 failf(data, "Schannel: TLS 1.3 is not yet supported");
229 return CURLE_SSL_CONNECT_ERROR;
230 case CURL_SSLVERSION_SSLv3:
231 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
233 case CURL_SSLVERSION_SSLv2:
234 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
237 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
238 return CURLE_SSL_CONNECT_ERROR;
241 /* allocate memory for the re-usable credential handle */
242 connssl->cred = (struct curl_schannel_cred *)
243 malloc(sizeof(struct curl_schannel_cred));
245 failf(data, "schannel: unable to allocate memory");
246 return CURLE_OUT_OF_MEMORY;
248 memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
249 connssl->cred->refcount = 1;
251 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
254 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
255 SECPKG_CRED_OUTBOUND, NULL,
256 &schannel_cred, NULL, NULL,
257 &connssl->cred->cred_handle,
258 &connssl->cred->time_stamp);
260 if(sspi_status != SEC_E_OK) {
261 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
262 failf(data, "schannel: SNI or certificate check failed: %s",
263 Curl_sspi_strerror(conn, sspi_status));
265 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
266 Curl_sspi_strerror(conn, sspi_status));
267 Curl_safefree(connssl->cred);
268 return CURLE_SSL_CONNECT_ERROR;
272 /* Warn if SNI is disabled due to use of an IP address */
273 if(Curl_inet_pton(AF_INET, hostname, &addr)
275 || Curl_inet_pton(AF_INET6, hostname, &addr6)
278 infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
282 if(connssl->use_alpn) {
284 int list_start_index = 0;
285 unsigned int *extension_len = NULL;
286 unsigned short* list_len = NULL;
288 /* The first four bytes will be an unsigned int indicating number
289 of bytes of data in the rest of the the buffer. */
290 extension_len = (unsigned int *)(&alpn_buffer[cur]);
291 cur += sizeof(unsigned int);
293 /* The next four bytes are an indicator that this buffer will contain
294 ALPN data, as opposed to NPN, for example. */
295 *(unsigned int *)&alpn_buffer[cur] =
296 SecApplicationProtocolNegotiationExt_ALPN;
297 cur += sizeof(unsigned int);
299 /* The next two bytes will be an unsigned short indicating the number
300 of bytes used to list the preferred protocols. */
301 list_len = (unsigned short*)(&alpn_buffer[cur]);
302 cur += sizeof(unsigned short);
304 list_start_index = cur;
307 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
308 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
309 cur += NGHTTP2_PROTO_ALPN_LEN;
310 infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
314 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
315 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
316 cur += ALPN_HTTP_1_1_LENGTH;
317 infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
319 *list_len = curlx_uitous(cur - list_start_index);
320 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
322 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
323 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
327 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
328 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
331 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
332 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
335 /* setup output buffer */
336 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
337 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
339 /* setup request flags */
340 connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
341 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
344 /* allocate memory for the security context handle */
345 connssl->ctxt = (struct curl_schannel_ctxt *)
346 malloc(sizeof(struct curl_schannel_ctxt));
348 failf(data, "schannel: unable to allocate memory");
349 return CURLE_OUT_OF_MEMORY;
351 memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
353 host_name = Curl_convert_UTF8_to_tchar(hostname);
355 return CURLE_OUT_OF_MEMORY;
357 /* Schannel InitializeSecurityContext:
358 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
360 At the moment we don't pass inbuf unless we're using ALPN since we only
361 use it for that, and Wine (for which we currently disable ALPN) is giving
362 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
364 sspi_status = s_pSecFn->InitializeSecurityContext(
365 &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0,
366 (connssl->use_alpn ? &inbuf_desc : NULL),
367 0, &connssl->ctxt->ctxt_handle,
368 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
370 Curl_unicodefree(host_name);
372 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
373 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
374 failf(data, "schannel: SNI or certificate check failed: %s",
375 Curl_sspi_strerror(conn, sspi_status));
377 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
378 Curl_sspi_strerror(conn, sspi_status));
379 Curl_safefree(connssl->ctxt);
380 return CURLE_SSL_CONNECT_ERROR;
383 infof(data, "schannel: sending initial handshake data: "
384 "sending %lu bytes...\n", outbuf.cbBuffer);
386 /* send initial handshake data which is now stored in output buffer */
387 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
388 outbuf.cbBuffer, &written);
389 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
390 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
391 failf(data, "schannel: failed to send initial handshake data: "
392 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
393 return CURLE_SSL_CONNECT_ERROR;
396 infof(data, "schannel: sent initial handshake data: "
397 "sent %zd bytes\n", written);
399 connssl->recv_unrecoverable_err = CURLE_OK;
400 connssl->recv_sspi_close_notify = false;
401 connssl->recv_connection_closed = false;
403 /* continue to second handshake step */
404 connssl->connecting_state = ssl_connect_2;
410 schannel_connect_step2(struct connectdata *conn, int sockindex)
413 ssize_t nread = -1, written = -1;
414 struct Curl_easy *data = conn->data;
415 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
416 unsigned char *reallocated_buffer;
417 size_t reallocated_length;
419 SecBufferDesc outbuf_desc;
421 SecBufferDesc inbuf_desc;
422 SECURITY_STATUS sspi_status = SEC_E_OK;
426 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
429 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
431 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
432 hostname, conn->remote_port);
434 if(!connssl->cred || !connssl->ctxt)
435 return CURLE_SSL_CONNECT_ERROR;
437 /* buffer to store previously received and decrypted data */
438 if(connssl->decdata_buffer == NULL) {
439 connssl->decdata_offset = 0;
440 connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
441 connssl->decdata_buffer = malloc(connssl->decdata_length);
442 if(connssl->decdata_buffer == NULL) {
443 failf(data, "schannel: unable to allocate memory");
444 return CURLE_OUT_OF_MEMORY;
448 /* buffer to store previously received and encrypted data */
449 if(connssl->encdata_buffer == NULL) {
450 connssl->encdata_offset = 0;
451 connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
452 connssl->encdata_buffer = malloc(connssl->encdata_length);
453 if(connssl->encdata_buffer == NULL) {
454 failf(data, "schannel: unable to allocate memory");
455 return CURLE_OUT_OF_MEMORY;
459 /* if we need a bigger buffer to read a full message, increase buffer now */
460 if(connssl->encdata_length - connssl->encdata_offset <
461 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
462 /* increase internal encrypted data buffer */
463 reallocated_length = connssl->encdata_offset +
464 CURL_SCHANNEL_BUFFER_FREE_SIZE;
465 reallocated_buffer = realloc(connssl->encdata_buffer,
468 if(reallocated_buffer == NULL) {
469 failf(data, "schannel: unable to re-allocate memory");
470 return CURLE_OUT_OF_MEMORY;
473 connssl->encdata_buffer = reallocated_buffer;
474 connssl->encdata_length = reallocated_length;
480 /* read encrypted handshake data from socket */
481 result = Curl_read_plain(conn->sock[sockindex],
482 (char *) (connssl->encdata_buffer +
483 connssl->encdata_offset),
484 connssl->encdata_length -
485 connssl->encdata_offset,
487 if(result == CURLE_AGAIN) {
488 if(connssl->connecting_state != ssl_connect_2_writing)
489 connssl->connecting_state = ssl_connect_2_reading;
490 infof(data, "schannel: failed to receive handshake, "
494 else if((result != CURLE_OK) || (nread == 0)) {
495 failf(data, "schannel: failed to receive handshake, "
496 "SSL/TLS connection failed");
497 return CURLE_SSL_CONNECT_ERROR;
500 /* increase encrypted data buffer offset */
501 connssl->encdata_offset += nread;
504 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
505 connssl->encdata_offset, connssl->encdata_length);
507 /* setup input buffers */
508 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
509 curlx_uztoul(connssl->encdata_offset));
510 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
511 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
513 /* setup output buffers */
514 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
515 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
516 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
517 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
519 if(inbuf[0].pvBuffer == NULL) {
520 failf(data, "schannel: unable to allocate memory");
521 return CURLE_OUT_OF_MEMORY;
524 /* copy received handshake data into input buffer */
525 memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
526 connssl->encdata_offset);
528 host_name = Curl_convert_UTF8_to_tchar(hostname);
530 return CURLE_OUT_OF_MEMORY;
532 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
534 sspi_status = s_pSecFn->InitializeSecurityContext(
535 &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
536 host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
537 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
539 Curl_unicodefree(host_name);
541 /* free buffer for received handshake data */
542 Curl_safefree(inbuf[0].pvBuffer);
544 /* check if the handshake was incomplete */
545 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
546 connssl->connecting_state = ssl_connect_2_reading;
547 infof(data, "schannel: received incomplete message, need more data\n");
551 /* If the server has requested a client certificate, attempt to continue
552 the handshake without one. This will allow connections to servers which
553 request a client certificate but do not require it. */
554 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
555 !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
556 connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
557 connssl->connecting_state = ssl_connect_2_writing;
558 infof(data, "schannel: a client certificate has been requested\n");
562 /* check if the handshake needs to be continued */
563 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
564 for(i = 0; i < 3; i++) {
565 /* search for handshake tokens that need to be send */
566 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
567 infof(data, "schannel: sending next handshake data: "
568 "sending %lu bytes...\n", outbuf[i].cbBuffer);
570 /* send handshake token to server */
571 result = Curl_write_plain(conn, conn->sock[sockindex],
572 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
574 if((result != CURLE_OK) ||
575 (outbuf[i].cbBuffer != (size_t) written)) {
576 failf(data, "schannel: failed to send next handshake data: "
577 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
578 return CURLE_SSL_CONNECT_ERROR;
582 /* free obsolete buffer */
583 if(outbuf[i].pvBuffer != NULL) {
584 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
589 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
590 failf(data, "schannel: SNI or certificate check failed: %s",
591 Curl_sspi_strerror(conn, sspi_status));
593 failf(data, "schannel: next InitializeSecurityContext failed: %s",
594 Curl_sspi_strerror(conn, sspi_status));
595 return CURLE_SSL_CONNECT_ERROR;
598 /* check if there was additional remaining encrypted data */
599 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
600 infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
602 There are two cases where we could be getting extra data here:
603 1) If we're renegotiating a connection and the handshake is already
604 complete (from the server perspective), it can encrypted app data
605 (not handshake data) in an extra buffer at this point.
606 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
607 connection and this extra data is part of the handshake.
608 We should process the data immediately; waiting for the socket to
609 be ready may fail since the server is done sending handshake data.
611 /* check if the remaining data is less than the total amount
612 and therefore begins after the already processed data */
613 if(connssl->encdata_offset > inbuf[1].cbBuffer) {
614 memmove(connssl->encdata_buffer,
615 (connssl->encdata_buffer + connssl->encdata_offset) -
616 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
617 connssl->encdata_offset = inbuf[1].cbBuffer;
618 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
625 connssl->encdata_offset = 0;
630 /* check if the handshake needs to be continued */
631 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
632 connssl->connecting_state = ssl_connect_2_reading;
636 /* check if the handshake is complete */
637 if(sspi_status == SEC_E_OK) {
638 connssl->connecting_state = ssl_connect_3;
639 infof(data, "schannel: SSL/TLS handshake complete\n");
643 /* Windows CE doesn't do any server certificate validation.
644 We have to do it manually. */
645 if(conn->ssl_config.verifypeer)
646 return verify_certificate(conn, sockindex);
653 schannel_connect_step3(struct connectdata *conn, int sockindex)
655 CURLcode result = CURLE_OK;
656 struct Curl_easy *data = conn->data;
657 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
658 SECURITY_STATUS sspi_status = SEC_E_OK;
659 CERT_CONTEXT *ccert_context = NULL;
660 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
663 SecPkgContext_ApplicationProtocol alpn_result;
666 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
668 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
669 hostname, conn->remote_port);
672 return CURLE_SSL_CONNECT_ERROR;
674 /* check if the required context attributes are met */
675 if(connssl->ret_flags != connssl->req_flags) {
676 if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
677 failf(data, "schannel: failed to setup sequence detection");
678 if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
679 failf(data, "schannel: failed to setup replay detection");
680 if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
681 failf(data, "schannel: failed to setup confidentiality");
682 if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
683 failf(data, "schannel: failed to setup memory allocation");
684 if(!(connssl->ret_flags & ISC_RET_STREAM))
685 failf(data, "schannel: failed to setup stream orientation");
686 return CURLE_SSL_CONNECT_ERROR;
690 if(connssl->use_alpn) {
691 sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
692 SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
694 if(sspi_status != SEC_E_OK) {
695 failf(data, "schannel: failed to retrieve ALPN result");
696 return CURLE_SSL_CONNECT_ERROR;
699 if(alpn_result.ProtoNegoStatus ==
700 SecApplicationProtocolNegotiationStatus_Success) {
702 infof(data, "schannel: ALPN, server accepted to use %.*s\n",
703 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
706 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
707 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
708 NGHTTP2_PROTO_VERSION_ID_LEN)) {
709 conn->negnpn = CURL_HTTP_VERSION_2;
713 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
714 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
715 ALPN_HTTP_1_1_LENGTH)) {
716 conn->negnpn = CURL_HTTP_VERSION_1_1;
720 infof(data, "ALPN, server did not agree to a protocol\n");
724 /* save the current session data for possible re-use */
725 if(data->set.general_ssl.sessionid) {
727 struct curl_schannel_cred *old_cred = NULL;
729 Curl_ssl_sessionid_lock(conn);
730 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
733 if(old_cred != connssl->cred) {
734 infof(data, "schannel: old credential handle is stale, removing\n");
735 /* we're not taking old_cred ownership here, no refcount++ is needed */
736 Curl_ssl_delsessionid(conn, (void *)old_cred);
741 result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
742 sizeof(struct curl_schannel_cred),
745 Curl_ssl_sessionid_unlock(conn);
746 failf(data, "schannel: failed to store credential handle");
750 /* this cred session is now also referenced by sessionid cache */
751 connssl->cred->refcount++;
752 infof(data, "schannel: stored credential handle in session cache\n");
755 Curl_ssl_sessionid_unlock(conn);
758 if(data->set.ssl.certinfo) {
759 sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
760 SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
762 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
763 failf(data, "schannel: failed to retrieve remote cert context");
764 return CURLE_SSL_CONNECT_ERROR;
767 result = Curl_ssl_init_certinfo(data, 1);
769 if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
770 (ccert_context->cbCertEncoded > 0)) {
772 const char *beg = (const char *) ccert_context->pbCertEncoded;
773 const char *end = beg + ccert_context->cbCertEncoded;
774 result = Curl_extract_certinfo(conn, 0, beg, end);
777 CertFreeCertificateContext(ccert_context);
782 connssl->connecting_state = ssl_connect_done;
788 schannel_connect_common(struct connectdata *conn, int sockindex,
789 bool nonblocking, bool *done)
792 struct Curl_easy *data = conn->data;
793 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
794 curl_socket_t sockfd = conn->sock[sockindex];
798 /* check if the connection has already been established */
799 if(ssl_connection_complete == connssl->state) {
804 if(ssl_connect_1 == connssl->connecting_state) {
805 /* check out how much more time we're allowed */
806 timeout_ms = Curl_timeleft(data, NULL, TRUE);
809 /* no need to continue if time already is up */
810 failf(data, "SSL/TLS connection timeout");
811 return CURLE_OPERATION_TIMEDOUT;
814 result = schannel_connect_step1(conn, sockindex);
819 while(ssl_connect_2 == connssl->connecting_state ||
820 ssl_connect_2_reading == connssl->connecting_state ||
821 ssl_connect_2_writing == connssl->connecting_state) {
823 /* check out how much more time we're allowed */
824 timeout_ms = Curl_timeleft(data, NULL, TRUE);
827 /* no need to continue if time already is up */
828 failf(data, "SSL/TLS connection timeout");
829 return CURLE_OPERATION_TIMEDOUT;
832 /* if ssl is expecting something, check if it's available. */
833 if(connssl->connecting_state == ssl_connect_2_reading
834 || connssl->connecting_state == ssl_connect_2_writing) {
836 curl_socket_t writefd = ssl_connect_2_writing ==
837 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
838 curl_socket_t readfd = ssl_connect_2_reading ==
839 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
841 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
842 nonblocking ? 0 : timeout_ms);
845 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
846 return CURLE_SSL_CONNECT_ERROR;
855 failf(data, "SSL/TLS connection timeout");
856 return CURLE_OPERATION_TIMEDOUT;
859 /* socket is readable or writable */
862 /* Run transaction, and return to the caller if it failed or if
863 * this connection is part of a multi handle and this loop would
864 * execute again. This permits the owner of a multi handle to
865 * abort a connection attempt before step2 has completed while
866 * ensuring that a client using select() or epoll() will always
867 * have a valid fdset to wait on.
869 result = schannel_connect_step2(conn, sockindex);
870 if(result || (nonblocking &&
871 (ssl_connect_2 == connssl->connecting_state ||
872 ssl_connect_2_reading == connssl->connecting_state ||
873 ssl_connect_2_writing == connssl->connecting_state)))
876 } /* repeat step2 until all transactions are done. */
878 if(ssl_connect_3 == connssl->connecting_state) {
879 result = schannel_connect_step3(conn, sockindex);
884 if(ssl_connect_done == connssl->connecting_state) {
885 connssl->state = ssl_connection_complete;
886 conn->recv[sockindex] = schannel_recv;
887 conn->send[sockindex] = schannel_send;
893 /* reset our connection state machine */
894 connssl->connecting_state = ssl_connect_1;
900 schannel_send(struct connectdata *conn, int sockindex,
901 const void *buf, size_t len, CURLcode *err)
903 ssize_t written = -1;
905 unsigned char *data = NULL;
906 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
908 SecBufferDesc outbuf_desc;
909 SECURITY_STATUS sspi_status = SEC_E_OK;
912 /* check if the maximum stream sizes were queried */
913 if(connssl->stream_sizes.cbMaximumMessage == 0) {
914 sspi_status = s_pSecFn->QueryContextAttributes(
915 &connssl->ctxt->ctxt_handle,
916 SECPKG_ATTR_STREAM_SIZES,
917 &connssl->stream_sizes);
918 if(sspi_status != SEC_E_OK) {
919 *err = CURLE_SEND_ERROR;
924 /* check if the buffer is longer than the maximum message length */
925 if(len > connssl->stream_sizes.cbMaximumMessage) {
926 *err = CURLE_SEND_ERROR;
930 /* calculate the complete message length and allocate a buffer for it */
931 data_len = connssl->stream_sizes.cbHeader + len +
932 connssl->stream_sizes.cbTrailer;
933 data = (unsigned char *) malloc(data_len);
935 *err = CURLE_OUT_OF_MEMORY;
939 /* setup output buffers (header, data, trailer, empty) */
940 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
941 data, connssl->stream_sizes.cbHeader);
942 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
943 data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
944 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
945 data + connssl->stream_sizes.cbHeader + len,
946 connssl->stream_sizes.cbTrailer);
947 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
948 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
950 /* copy data into output buffer */
951 memcpy(outbuf[1].pvBuffer, buf, len);
953 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
954 sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
957 /* check if the message was encrypted */
958 if(sspi_status == SEC_E_OK) {
961 /* send the encrypted message including header, data and trailer */
962 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
965 It's important to send the full message which includes the header,
966 encrypted payload, and trailer. Until the client receives all the
967 data a coherent message has not been delivered and the client
968 can't read any of it.
970 If we wanted to buffer the unwritten encrypted bytes, we would
971 tell the client that all data it has requested to be sent has been
972 sent. The unwritten encrypted bytes would be the first bytes to
973 send on the next invocation.
974 Here's the catch with this - if we tell the client that all the
975 bytes have been sent, will the client call this method again to
976 send the buffered data? Looking at who calls this function, it
977 seems the answer is NO.
980 /* send entire message or fail */
981 while(len > (size_t)written) {
988 timeleft = Curl_timeleft(conn->data, NULL, FALSE);
990 /* we already got the timeout */
991 failf(conn->data, "schannel: timed out sending data "
992 "(bytes sent: %zd)", written);
993 *err = CURLE_OPERATION_TIMEDOUT;
998 what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
1001 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1002 *err = CURLE_SEND_ERROR;
1006 else if(0 == what) {
1007 failf(conn->data, "schannel: timed out sending data "
1008 "(bytes sent: %zd)", written);
1009 *err = CURLE_OPERATION_TIMEDOUT;
1013 /* socket is writable */
1015 result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1016 len - written, &this_write);
1017 if(result == CURLE_AGAIN)
1019 else if(result != CURLE_OK) {
1025 written += this_write;
1028 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1029 *err = CURLE_OUT_OF_MEMORY;
1032 *err = CURLE_SEND_ERROR;
1035 Curl_safefree(data);
1037 if(len == (size_t)written)
1038 /* Encrypted message including header, data and trailer entirely sent.
1039 The return value is the number of unencrypted bytes that were sent. */
1040 written = outbuf[1].cbBuffer;
1046 schannel_recv(struct connectdata *conn, int sockindex,
1047 char *buf, size_t len, CURLcode *err)
1051 struct Curl_easy *data = conn->data;
1052 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1053 unsigned char *reallocated_buffer;
1054 size_t reallocated_length;
1057 SecBufferDesc inbuf_desc;
1058 SECURITY_STATUS sspi_status = SEC_E_OK;
1059 /* we want the length of the encrypted buffer to be at least large enough
1060 that it can hold all the bytes requested and some TLS record overhead. */
1061 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1063 /****************************************************************************
1064 * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup.
1065 * The pattern for return error is set *err, optional infof, goto cleanup.
1067 * Our priority is to always return as much decrypted data to the caller as
1068 * possible, even if an error occurs. The state of the decrypted buffer must
1069 * always be valid. Transfer of decrypted data to the caller's buffer is
1070 * handled in the cleanup.
1073 infof(data, "schannel: client wants to read %zu bytes\n", len);
1076 if(len && len <= connssl->decdata_offset) {
1077 infof(data, "schannel: enough decrypted data is already available\n");
1080 else if(connssl->recv_unrecoverable_err) {
1081 *err = connssl->recv_unrecoverable_err;
1082 infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1085 else if(connssl->recv_sspi_close_notify) {
1086 /* once a server has indicated shutdown there is no more encrypted data */
1087 infof(data, "schannel: server indicated shutdown in a prior call\n");
1091 /* It's debatable what to return when !len. Regardless we can't return
1092 immediately because there may be data to decrypt (in the case we want to
1093 decrypt all encrypted cached data) so handle !len later in cleanup.
1097 else if(!connssl->recv_connection_closed) {
1098 /* increase enc buffer in order to fit the requested amount of data */
1099 size = connssl->encdata_length - connssl->encdata_offset;
1100 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1101 connssl->encdata_length < min_encdata_length) {
1102 reallocated_length = connssl->encdata_offset +
1103 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1104 if(reallocated_length < min_encdata_length) {
1105 reallocated_length = min_encdata_length;
1107 reallocated_buffer = realloc(connssl->encdata_buffer,
1108 reallocated_length);
1109 if(reallocated_buffer == NULL) {
1110 *err = CURLE_OUT_OF_MEMORY;
1111 failf(data, "schannel: unable to re-allocate memory");
1115 connssl->encdata_buffer = reallocated_buffer;
1116 connssl->encdata_length = reallocated_length;
1117 size = connssl->encdata_length - connssl->encdata_offset;
1118 infof(data, "schannel: encdata_buffer resized %zu\n",
1119 connssl->encdata_length);
1122 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1123 connssl->encdata_offset, connssl->encdata_length);
1125 /* read encrypted data from socket */
1126 *err = Curl_read_plain(conn->sock[sockindex],
1127 (char *)(connssl->encdata_buffer +
1128 connssl->encdata_offset),
1132 if(*err == CURLE_AGAIN)
1133 infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
1134 else if(*err == CURLE_RECV_ERROR)
1135 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1137 infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1139 else if(nread == 0) {
1140 connssl->recv_connection_closed = true;
1141 infof(data, "schannel: server closed the connection\n");
1143 else if(nread > 0) {
1144 connssl->encdata_offset += (size_t)nread;
1145 infof(data, "schannel: encrypted data got %zd\n", nread);
1149 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1150 connssl->encdata_offset, connssl->encdata_length);
1153 while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1154 (!len || connssl->decdata_offset < len ||
1155 connssl->recv_connection_closed)) {
1156 /* prepare data buffer for DecryptMessage call */
1157 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
1158 curlx_uztoul(connssl->encdata_offset));
1160 /* we need 3 more empty input buffers for possible output */
1161 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1162 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1163 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1164 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1166 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1168 sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
1169 &inbuf_desc, 0, NULL);
1171 /* check if everything went fine (server may want to renegotiate
1172 or shutdown the connection context) */
1173 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1174 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1175 /* check for successfully decrypted data, even before actual
1176 renegotiation or shutdown of the connection context */
1177 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1178 infof(data, "schannel: decrypted data length: %lu\n",
1181 /* increase buffer in order to fit the received amount of data */
1182 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1183 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1184 if(connssl->decdata_length - connssl->decdata_offset < size ||
1185 connssl->decdata_length < len) {
1186 /* increase internal decrypted data buffer */
1187 reallocated_length = connssl->decdata_offset + size;
1188 /* make sure that the requested amount of data fits */
1189 if(reallocated_length < len) {
1190 reallocated_length = len;
1192 reallocated_buffer = realloc(connssl->decdata_buffer,
1193 reallocated_length);
1194 if(reallocated_buffer == NULL) {
1195 *err = CURLE_OUT_OF_MEMORY;
1196 failf(data, "schannel: unable to re-allocate memory");
1199 connssl->decdata_buffer = reallocated_buffer;
1200 connssl->decdata_length = reallocated_length;
1203 /* copy decrypted data to internal buffer */
1204 size = inbuf[1].cbBuffer;
1206 memcpy(connssl->decdata_buffer + connssl->decdata_offset,
1207 inbuf[1].pvBuffer, size);
1208 connssl->decdata_offset += size;
1211 infof(data, "schannel: decrypted data added: %zu\n", size);
1212 infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
1213 connssl->decdata_offset, connssl->decdata_length);
1216 /* check for remaining encrypted data */
1217 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1218 infof(data, "schannel: encrypted data length: %lu\n",
1221 /* check if the remaining data is less than the total amount
1222 * and therefore begins after the already processed data
1224 if(connssl->encdata_offset > inbuf[3].cbBuffer) {
1225 /* move remaining encrypted data forward to the beginning of
1227 memmove(connssl->encdata_buffer,
1228 (connssl->encdata_buffer + connssl->encdata_offset) -
1229 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1230 connssl->encdata_offset = inbuf[3].cbBuffer;
1233 infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
1234 connssl->encdata_offset, connssl->encdata_length);
1237 /* reset encrypted buffer offset, because there is no data remaining */
1238 connssl->encdata_offset = 0;
1241 /* check if server wants to renegotiate the connection context */
1242 if(sspi_status == SEC_I_RENEGOTIATE) {
1243 infof(data, "schannel: remote party requests renegotiation\n");
1244 if(*err && *err != CURLE_AGAIN) {
1245 infof(data, "schannel: can't renogotiate, an error is pending\n");
1248 if(connssl->encdata_offset) {
1249 *err = CURLE_RECV_ERROR;
1250 infof(data, "schannel: can't renogotiate, "
1251 "encrypted data available\n");
1254 /* begin renegotiation */
1255 infof(data, "schannel: renegotiating SSL/TLS connection\n");
1256 connssl->state = ssl_connection_negotiating;
1257 connssl->connecting_state = ssl_connect_2_writing;
1258 *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1260 infof(data, "schannel: renegotiation failed\n");
1263 /* now retry receiving data */
1264 sspi_status = SEC_E_OK;
1265 infof(data, "schannel: SSL/TLS connection renegotiated\n");
1268 /* check if the server closed the connection */
1269 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1270 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1271 returned so we have to work around that in cleanup. */
1272 connssl->recv_sspi_close_notify = true;
1273 if(!connssl->recv_connection_closed) {
1274 connssl->recv_connection_closed = true;
1275 infof(data, "schannel: server closed the connection\n");
1280 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1283 infof(data, "schannel: failed to decrypt data, need more data\n");
1287 *err = CURLE_RECV_ERROR;
1288 infof(data, "schannel: failed to read data from server: %s\n",
1289 Curl_sspi_strerror(conn, sspi_status));
1294 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1295 connssl->encdata_offset, connssl->encdata_length);
1297 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1298 connssl->decdata_offset, connssl->decdata_length);
1301 /* Warning- there is no guarantee the encdata state is valid at this point */
1302 infof(data, "schannel: schannel_recv cleanup\n");
1304 /* Error if the connection has closed without a close_notify.
1305 Behavior here is a matter of debate. We don't want to be vulnerable to a
1306 truncation attack however there's some browser precedent for ignoring the
1307 close_notify for compatibility reasons.
1308 Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1309 return close_notify. In that case if the connection was closed we assume it
1310 was graceful (close_notify) since there doesn't seem to be a way to tell.
1312 if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
1313 !connssl->recv_sspi_close_notify) {
1314 bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1317 if(isWin2k && sspi_status == SEC_E_OK)
1318 connssl->recv_sspi_close_notify = true;
1320 *err = CURLE_RECV_ERROR;
1321 infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1325 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1326 if(*err && *err != CURLE_AGAIN)
1327 connssl->recv_unrecoverable_err = *err;
1329 size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
1331 memcpy(buf, connssl->decdata_buffer, size);
1332 memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
1333 connssl->decdata_offset - size);
1334 connssl->decdata_offset -= size;
1336 infof(data, "schannel: decrypted data returned %zu\n", size);
1337 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1338 connssl->decdata_offset, connssl->decdata_length);
1340 return (ssize_t)size;
1343 if(!*err && !connssl->recv_connection_closed)
1346 /* It's debatable what to return when !len. We could return whatever error we
1347 got from decryption but instead we override here so the return is consistent.
1352 return *err ? -1 : 0;
1356 Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
1359 return schannel_connect_common(conn, sockindex, TRUE, done);
1363 Curl_schannel_connect(struct connectdata *conn, int sockindex)
1368 result = schannel_connect_common(conn, sockindex, FALSE, &done);
1377 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
1379 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1381 if(connssl->use) /* SSL/TLS is in use */
1382 return (connssl->encdata_offset > 0 ||
1383 connssl->decdata_offset > 0) ? TRUE : FALSE;
1388 void Curl_schannel_close(struct connectdata *conn, int sockindex)
1390 if(conn->ssl[sockindex].use)
1391 /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1392 Curl_ssl_shutdown(conn, sockindex);
1395 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1397 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1398 * Shutting Down an Schannel Connection
1400 struct Curl_easy *data = conn->data;
1401 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1402 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1405 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1406 hostname, conn->remote_port);
1408 if(connssl->cred && connssl->ctxt) {
1409 SecBufferDesc BuffDesc;
1411 SECURITY_STATUS sspi_status;
1413 SecBufferDesc outbuf_desc;
1416 DWORD dwshut = SCHANNEL_SHUTDOWN;
1418 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
1419 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
1421 sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
1424 if(sspi_status != SEC_E_OK)
1425 failf(data, "schannel: ApplyControlToken failure: %s",
1426 Curl_sspi_strerror(conn, sspi_status));
1428 host_name = Curl_convert_UTF8_to_tchar(hostname);
1430 return CURLE_OUT_OF_MEMORY;
1432 /* setup output buffer */
1433 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1434 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1436 sspi_status = s_pSecFn->InitializeSecurityContext(
1437 &connssl->cred->cred_handle,
1438 &connssl->ctxt->ctxt_handle,
1445 &connssl->ctxt->ctxt_handle,
1447 &connssl->ret_flags,
1448 &connssl->ctxt->time_stamp);
1450 Curl_unicodefree(host_name);
1452 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
1453 /* send close message which is in output buffer */
1455 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
1456 outbuf.cbBuffer, &written);
1458 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1459 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1460 infof(data, "schannel: failed to send close msg: %s"
1461 " (bytes written: %zd)\n", curl_easy_strerror(result), written);
1466 /* free SSPI Schannel API security context handle */
1468 infof(data, "schannel: clear security context handle\n");
1469 s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
1470 Curl_safefree(connssl->ctxt);
1473 /* free SSPI Schannel API credential handle */
1475 Curl_ssl_sessionid_lock(conn);
1476 Curl_schannel_session_free(connssl->cred);
1477 Curl_ssl_sessionid_unlock(conn);
1478 connssl->cred = NULL;
1481 /* free internal buffer for received encrypted data */
1482 if(connssl->encdata_buffer != NULL) {
1483 Curl_safefree(connssl->encdata_buffer);
1484 connssl->encdata_length = 0;
1485 connssl->encdata_offset = 0;
1488 /* free internal buffer for received decrypted data */
1489 if(connssl->decdata_buffer != NULL) {
1490 Curl_safefree(connssl->decdata_buffer);
1491 connssl->decdata_length = 0;
1492 connssl->decdata_offset = 0;
1498 void Curl_schannel_session_free(void *ptr)
1500 /* this is expected to be called under sessionid lock */
1501 struct curl_schannel_cred *cred = ptr;
1504 if(cred->refcount == 0) {
1505 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1506 Curl_safefree(cred);
1510 int Curl_schannel_init(void)
1512 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
1515 void Curl_schannel_cleanup(void)
1517 Curl_sspi_global_cleanup();
1520 size_t Curl_schannel_version(char *buffer, size_t size)
1522 size = snprintf(buffer, size, "WinSSL");
1527 CURLcode Curl_schannel_random(unsigned char *entropy, size_t length)
1529 HCRYPTPROV hCryptProv = 0;
1531 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
1532 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
1533 return CURLE_FAILED_INIT;
1535 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
1536 CryptReleaseContext(hCryptProv, 0UL);
1537 return CURLE_FAILED_INIT;
1540 CryptReleaseContext(hCryptProv, 0UL);
1545 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
1547 SECURITY_STATUS status;
1548 struct Curl_easy *data = conn->data;
1549 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1550 CURLcode result = CURLE_OK;
1551 CERT_CONTEXT *pCertContextServer = NULL;
1552 const CERT_CHAIN_CONTEXT *pChainContext = NULL;
1553 const char * const conn_hostname = SSL_IS_PROXY() ?
1554 conn->http_proxy.host.name :
1557 status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
1558 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1559 &pCertContextServer);
1561 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
1562 failf(data, "schannel: Failed to read remote certificate context: %s",
1563 Curl_sspi_strerror(conn, status));
1564 result = CURLE_PEER_FAILED_VERIFICATION;
1567 if(result == CURLE_OK) {
1568 CERT_CHAIN_PARA ChainPara;
1569 memset(&ChainPara, 0, sizeof(ChainPara));
1570 ChainPara.cbSize = sizeof(ChainPara);
1572 if(!CertGetCertificateChain(NULL,
1575 pCertContextServer->hCertStore,
1577 (data->set.ssl.no_revoke ? 0 :
1578 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
1581 failf(data, "schannel: CertGetCertificateChain failed: %s",
1582 Curl_sspi_strerror(conn, GetLastError()));
1583 pChainContext = NULL;
1584 result = CURLE_PEER_FAILED_VERIFICATION;
1587 if(result == CURLE_OK) {
1588 CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
1589 DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
1590 dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
1591 if(dwTrustErrorMask) {
1592 if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
1593 failf(data, "schannel: CertGetCertificateChain trust error"
1594 " CERT_TRUST_IS_REVOKED");
1595 else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
1596 failf(data, "schannel: CertGetCertificateChain trust error"
1597 " CERT_TRUST_IS_PARTIAL_CHAIN");
1598 else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
1599 failf(data, "schannel: CertGetCertificateChain trust error"
1600 " CERT_TRUST_IS_UNTRUSTED_ROOT");
1601 else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
1602 failf(data, "schannel: CertGetCertificateChain trust error"
1603 " CERT_TRUST_IS_NOT_TIME_VALID");
1605 failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
1607 result = CURLE_PEER_FAILED_VERIFICATION;
1612 if(result == CURLE_OK) {
1613 if(conn->ssl_config.verifyhost) {
1614 TCHAR cert_hostname_buff[256];
1617 /* TODO: Fix this for certificates with multiple alternative names.
1618 Right now we're only asking for the first preferred alternative name.
1619 Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
1620 (if WinCE supports that?) and run this section in a loop for each.
1621 https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
1622 curl: (51) schannel: CertGetNameString() certificate hostname
1623 (.google.com) did not match connection (google.com)
1625 len = CertGetNameString(pCertContextServer,
1627 CERT_NAME_DISABLE_IE4_UTF8_FLAG,
1632 const char *cert_hostname;
1634 /* Comparing the cert name and the connection hostname encoded as UTF-8
1635 * is acceptable since both values are assumed to use ASCII
1636 * (or some equivalent) encoding
1638 cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
1639 if(!cert_hostname) {
1640 result = CURLE_OUT_OF_MEMORY;
1645 match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
1646 if(match_result == CURL_HOST_MATCH) {
1648 "schannel: connection hostname (%s) validated "
1649 "against certificate name (%s)\n",
1656 "schannel: connection hostname (%s) "
1657 "does not match certificate name (%s)",
1660 result = CURLE_PEER_FAILED_VERIFICATION;
1662 Curl_unicodefree(cert_hostname);
1667 "schannel: CertGetNameString did not provide any "
1668 "certificate name information");
1669 result = CURLE_PEER_FAILED_VERIFICATION;
1675 CertFreeCertificateChain(pChainContext);
1677 if(pCertContextServer)
1678 CertFreeCertificateContext(pCertContextServer);
1682 #endif /* _WIN32_WCE */
1684 #endif /* USE_SCHANNEL */