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 - 2018, 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."
51 #include "curl_sspi.h"
55 #include "connect.h" /* for the connect timeout */
57 #include "select.h" /* for the socket readyness */
58 #include "inet_pton.h" /* for IP addr SNI check */
59 #include "curl_multibyte.h"
62 #include "curl_printf.h"
63 #include "system_win32.h"
64 #include "hostcheck.h"
66 /* The last #include file should be: */
67 #include "curl_memory.h"
70 /* ALPN requires version 8.1 of the Windows SDK, which was
71 shipped with Visual Studio 2013, aka _MSC_VER 1800:
73 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
75 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
80 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
84 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
89 #define UNISP_NAME UNISP_NAME_W
91 #define UNISP_NAME UNISP_NAME_A
95 #ifndef SP_PROT_SSL2_CLIENT
96 #define SP_PROT_SSL2_CLIENT 0x00000008
99 #ifndef SP_PROT_SSL3_CLIENT
100 #define SP_PROT_SSL3_CLIENT 0x00000008
103 #ifndef SP_PROT_TLS1_CLIENT
104 #define SP_PROT_TLS1_CLIENT 0x00000080
107 #ifndef SP_PROT_TLS1_0_CLIENT
108 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
111 #ifndef SP_PROT_TLS1_1_CLIENT
112 #define SP_PROT_TLS1_1_CLIENT 0x00000200
115 #ifndef SP_PROT_TLS1_2_CLIENT
116 #define SP_PROT_TLS1_2_CLIENT 0x00000800
119 #ifndef SECBUFFER_ALERT
120 #define SECBUFFER_ALERT 17
123 /* Both schannel buffer sizes must be > 0 */
124 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
125 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
127 /* Uncomment to force verbose output
128 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
129 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
133 # define CALG_SHA_256 0x0000800c
136 /* Structs to store Schannel handles */
137 struct curl_schannel_cred {
138 CredHandle cred_handle;
139 TimeStamp time_stamp;
143 struct curl_schannel_ctxt {
144 CtxtHandle ctxt_handle;
145 TimeStamp time_stamp;
148 struct ssl_backend_data {
149 struct curl_schannel_cred *cred;
150 struct curl_schannel_ctxt *ctxt;
151 SecPkgContext_StreamSizes stream_sizes;
152 size_t encdata_length, decdata_length;
153 size_t encdata_offset, decdata_offset;
154 unsigned char *encdata_buffer, *decdata_buffer;
155 /* encdata_is_incomplete: if encdata contains only a partial record that
156 can't be decrypted without another Curl_read_plain (that is, status is
157 SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
158 more bytes into encdata then set this back to false. */
159 bool encdata_is_incomplete;
160 unsigned long req_flags, ret_flags;
161 CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
162 bool recv_sspi_close_notify; /* true if connection closed by close_notify */
163 bool recv_connection_closed; /* true if connection closed, regardless how */
164 bool use_alpn; /* true if ALPN is used for this connection */
167 #define BACKEND connssl->backend
169 static Curl_recv schannel_recv;
170 static Curl_send schannel_send;
172 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
173 const char *pinnedpubkey);
176 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
179 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
180 void *BufDataPtr, unsigned long BufByteSize)
182 buffer->cbBuffer = BufByteSize;
183 buffer->BufferType = BufType;
184 buffer->pvBuffer = BufDataPtr;
187 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
188 unsigned long NumArrElem)
190 desc->ulVersion = SECBUFFER_VERSION;
191 desc->pBuffers = BufArr;
192 desc->cBuffers = NumArrElem;
196 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
198 struct Curl_easy *data = conn->data;
199 long ssl_version = SSL_CONN_CONFIG(version);
200 long ssl_version_max = SSL_CONN_CONFIG(version_max);
201 long i = ssl_version;
203 switch(ssl_version_max) {
204 case CURL_SSLVERSION_MAX_NONE:
205 ssl_version_max = ssl_version << 16;
207 case CURL_SSLVERSION_MAX_DEFAULT:
208 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
211 for(; i <= (ssl_version_max >> 16); ++i) {
213 case CURL_SSLVERSION_TLSv1_0:
214 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
216 case CURL_SSLVERSION_TLSv1_1:
217 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
219 case CURL_SSLVERSION_TLSv1_2:
220 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
222 case CURL_SSLVERSION_TLSv1_3:
223 failf(data, "Schannel: TLS 1.3 is not yet supported");
224 return CURLE_SSL_CONNECT_ERROR;
231 schannel_connect_step1(struct connectdata *conn, int sockindex)
233 ssize_t written = -1;
234 struct Curl_easy *data = conn->data;
235 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
237 SecBufferDesc outbuf_desc;
239 SecBufferDesc inbuf_desc;
241 unsigned char alpn_buffer[128];
243 SCHANNEL_CRED schannel_cred;
244 SECURITY_STATUS sspi_status = SEC_E_OK;
245 struct curl_schannel_cred *old_cred = NULL;
248 struct in6_addr addr6;
252 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
255 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
256 hostname, conn->remote_port);
258 if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
259 VERSION_LESS_THAN_EQUAL)) {
260 /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
261 algorithms that may not be supported by all servers. */
262 infof(data, "schannel: WinSSL version is old and may not be able to "
263 "connect to some servers due to lack of SNI, algorithms, etc.\n");
267 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
268 Also it doesn't seem to be supported for Wine, see curl bug #983. */
269 BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
270 !GetProcAddress(GetModuleHandleA("ntdll"),
271 "wine_get_version") &&
272 Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
273 VERSION_GREATER_THAN_EQUAL);
275 BACKEND->use_alpn = false;
278 BACKEND->cred = NULL;
280 /* check for an existing re-usable credential handle */
281 if(SSL_SET_OPTION(primary.sessionid)) {
282 Curl_ssl_sessionid_lock(conn);
283 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
284 BACKEND->cred = old_cred;
285 infof(data, "schannel: re-using existing credential handle\n");
287 /* increment the reference counter of the credential/session handle */
288 BACKEND->cred->refcount++;
289 infof(data, "schannel: incremented credential handle refcount = %d\n",
290 BACKEND->cred->refcount);
292 Curl_ssl_sessionid_unlock(conn);
296 /* setup Schannel API options */
297 memset(&schannel_cred, 0, sizeof(schannel_cred));
298 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
300 if(conn->ssl_config.verifypeer) {
302 /* certificate validation on CE doesn't seem to work right; we'll
303 do it following a more manual process. */
304 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
305 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
306 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
308 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
309 /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
310 if(data->set.ssl.no_revoke)
311 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
312 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
314 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
316 if(data->set.ssl.no_revoke)
317 infof(data, "schannel: disabled server certificate revocation "
320 infof(data, "schannel: checking server certificate revocation\n");
323 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
324 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
325 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
326 infof(data, "schannel: disabled server certificate revocation checks\n");
329 if(!conn->ssl_config.verifyhost) {
330 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
331 infof(data, "schannel: verifyhost setting prevents Schannel from "
332 "comparing the supplied target name with the subject "
333 "names in server certificates.\n");
336 switch(conn->ssl_config.version) {
337 case CURL_SSLVERSION_DEFAULT:
338 case CURL_SSLVERSION_TLSv1:
339 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
340 SP_PROT_TLS1_1_CLIENT |
341 SP_PROT_TLS1_2_CLIENT;
343 case CURL_SSLVERSION_TLSv1_0:
344 case CURL_SSLVERSION_TLSv1_1:
345 case CURL_SSLVERSION_TLSv1_2:
346 case CURL_SSLVERSION_TLSv1_3:
348 result = set_ssl_version_min_max(&schannel_cred, conn);
349 if(result != CURLE_OK)
353 case CURL_SSLVERSION_SSLv3:
354 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
356 case CURL_SSLVERSION_SSLv2:
357 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
360 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
361 return CURLE_SSL_CONNECT_ERROR;
364 /* allocate memory for the re-usable credential handle */
365 BACKEND->cred = (struct curl_schannel_cred *)
366 malloc(sizeof(struct curl_schannel_cred));
368 failf(data, "schannel: unable to allocate memory");
369 return CURLE_OUT_OF_MEMORY;
371 memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred));
372 BACKEND->cred->refcount = 1;
374 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
377 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
378 SECPKG_CRED_OUTBOUND, NULL,
379 &schannel_cred, NULL, NULL,
380 &BACKEND->cred->cred_handle,
381 &BACKEND->cred->time_stamp);
383 if(sspi_status != SEC_E_OK) {
384 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
385 failf(data, "schannel: SNI or certificate check failed: %s",
386 Curl_sspi_strerror(conn, sspi_status));
388 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
389 Curl_sspi_strerror(conn, sspi_status));
390 Curl_safefree(BACKEND->cred);
391 return CURLE_SSL_CONNECT_ERROR;
395 /* Warn if SNI is disabled due to use of an IP address */
396 if(Curl_inet_pton(AF_INET, hostname, &addr)
398 || Curl_inet_pton(AF_INET6, hostname, &addr6)
401 infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
405 if(BACKEND->use_alpn) {
407 int list_start_index = 0;
408 unsigned int *extension_len = NULL;
409 unsigned short* list_len = NULL;
411 /* The first four bytes will be an unsigned int indicating number
412 of bytes of data in the rest of the the buffer. */
413 extension_len = (unsigned int *)(&alpn_buffer[cur]);
414 cur += sizeof(unsigned int);
416 /* The next four bytes are an indicator that this buffer will contain
417 ALPN data, as opposed to NPN, for example. */
418 *(unsigned int *)&alpn_buffer[cur] =
419 SecApplicationProtocolNegotiationExt_ALPN;
420 cur += sizeof(unsigned int);
422 /* The next two bytes will be an unsigned short indicating the number
423 of bytes used to list the preferred protocols. */
424 list_len = (unsigned short*)(&alpn_buffer[cur]);
425 cur += sizeof(unsigned short);
427 list_start_index = cur;
430 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
431 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
432 cur += NGHTTP2_PROTO_ALPN_LEN;
433 infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
437 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
438 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
439 cur += ALPN_HTTP_1_1_LENGTH;
440 infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
442 *list_len = curlx_uitous(cur - list_start_index);
443 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
445 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
446 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
450 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
451 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
454 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
455 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
458 /* setup output buffer */
459 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
460 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
462 /* setup request flags */
463 BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
464 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
467 /* allocate memory for the security context handle */
468 BACKEND->ctxt = (struct curl_schannel_ctxt *)
469 malloc(sizeof(struct curl_schannel_ctxt));
471 failf(data, "schannel: unable to allocate memory");
472 return CURLE_OUT_OF_MEMORY;
474 memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt));
476 host_name = Curl_convert_UTF8_to_tchar(hostname);
478 return CURLE_OUT_OF_MEMORY;
480 /* Schannel InitializeSecurityContext:
481 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
483 At the moment we don't pass inbuf unless we're using ALPN since we only
484 use it for that, and Wine (for which we currently disable ALPN) is giving
485 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
487 sspi_status = s_pSecFn->InitializeSecurityContext(
488 &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
489 (BACKEND->use_alpn ? &inbuf_desc : NULL),
490 0, &BACKEND->ctxt->ctxt_handle,
491 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
493 Curl_unicodefree(host_name);
495 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
496 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
497 failf(data, "schannel: SNI or certificate check failed: %s",
498 Curl_sspi_strerror(conn, sspi_status));
500 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
501 Curl_sspi_strerror(conn, sspi_status));
502 Curl_safefree(BACKEND->ctxt);
503 return CURLE_SSL_CONNECT_ERROR;
506 infof(data, "schannel: sending initial handshake data: "
507 "sending %lu bytes...\n", outbuf.cbBuffer);
509 /* send initial handshake data which is now stored in output buffer */
510 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
511 outbuf.cbBuffer, &written);
512 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
513 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
514 failf(data, "schannel: failed to send initial handshake data: "
515 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
516 return CURLE_SSL_CONNECT_ERROR;
519 infof(data, "schannel: sent initial handshake data: "
520 "sent %zd bytes\n", written);
522 BACKEND->recv_unrecoverable_err = CURLE_OK;
523 BACKEND->recv_sspi_close_notify = false;
524 BACKEND->recv_connection_closed = false;
525 BACKEND->encdata_is_incomplete = false;
527 /* continue to second handshake step */
528 connssl->connecting_state = ssl_connect_2;
534 schannel_connect_step2(struct connectdata *conn, int sockindex)
537 ssize_t nread = -1, written = -1;
538 struct Curl_easy *data = conn->data;
539 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
540 unsigned char *reallocated_buffer;
541 size_t reallocated_length;
543 SecBufferDesc outbuf_desc;
545 SecBufferDesc inbuf_desc;
546 SECURITY_STATUS sspi_status = SEC_E_OK;
550 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
552 const char *pubkey_ptr;
554 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
556 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
557 hostname, conn->remote_port);
559 if(!BACKEND->cred || !BACKEND->ctxt)
560 return CURLE_SSL_CONNECT_ERROR;
562 /* buffer to store previously received and decrypted data */
563 if(BACKEND->decdata_buffer == NULL) {
564 BACKEND->decdata_offset = 0;
565 BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
566 BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
567 if(BACKEND->decdata_buffer == NULL) {
568 failf(data, "schannel: unable to allocate memory");
569 return CURLE_OUT_OF_MEMORY;
573 /* buffer to store previously received and encrypted data */
574 if(BACKEND->encdata_buffer == NULL) {
575 BACKEND->encdata_is_incomplete = false;
576 BACKEND->encdata_offset = 0;
577 BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
578 BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
579 if(BACKEND->encdata_buffer == NULL) {
580 failf(data, "schannel: unable to allocate memory");
581 return CURLE_OUT_OF_MEMORY;
585 /* if we need a bigger buffer to read a full message, increase buffer now */
586 if(BACKEND->encdata_length - BACKEND->encdata_offset <
587 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
588 /* increase internal encrypted data buffer */
589 reallocated_length = BACKEND->encdata_offset +
590 CURL_SCHANNEL_BUFFER_FREE_SIZE;
591 reallocated_buffer = realloc(BACKEND->encdata_buffer,
594 if(reallocated_buffer == NULL) {
595 failf(data, "schannel: unable to re-allocate memory");
596 return CURLE_OUT_OF_MEMORY;
599 BACKEND->encdata_buffer = reallocated_buffer;
600 BACKEND->encdata_length = reallocated_length;
606 /* read encrypted handshake data from socket */
607 result = Curl_read_plain(conn->sock[sockindex],
608 (char *) (BACKEND->encdata_buffer +
609 BACKEND->encdata_offset),
610 BACKEND->encdata_length -
611 BACKEND->encdata_offset,
613 if(result == CURLE_AGAIN) {
614 if(connssl->connecting_state != ssl_connect_2_writing)
615 connssl->connecting_state = ssl_connect_2_reading;
616 infof(data, "schannel: failed to receive handshake, "
620 else if((result != CURLE_OK) || (nread == 0)) {
621 failf(data, "schannel: failed to receive handshake, "
622 "SSL/TLS connection failed");
623 return CURLE_SSL_CONNECT_ERROR;
626 /* increase encrypted data buffer offset */
627 BACKEND->encdata_offset += nread;
628 BACKEND->encdata_is_incomplete = false;
629 infof(data, "schannel: encrypted data got %zd\n", nread);
632 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
633 BACKEND->encdata_offset, BACKEND->encdata_length);
635 /* setup input buffers */
636 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
637 curlx_uztoul(BACKEND->encdata_offset));
638 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
639 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
641 /* setup output buffers */
642 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
643 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
644 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
645 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
647 if(inbuf[0].pvBuffer == NULL) {
648 failf(data, "schannel: unable to allocate memory");
649 return CURLE_OUT_OF_MEMORY;
652 /* copy received handshake data into input buffer */
653 memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
654 BACKEND->encdata_offset);
656 host_name = Curl_convert_UTF8_to_tchar(hostname);
658 return CURLE_OUT_OF_MEMORY;
660 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
662 sspi_status = s_pSecFn->InitializeSecurityContext(
663 &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
664 host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
665 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
667 Curl_unicodefree(host_name);
669 /* free buffer for received handshake data */
670 Curl_safefree(inbuf[0].pvBuffer);
672 /* check if the handshake was incomplete */
673 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
674 BACKEND->encdata_is_incomplete = true;
675 connssl->connecting_state = ssl_connect_2_reading;
676 infof(data, "schannel: received incomplete message, need more data\n");
680 /* If the server has requested a client certificate, attempt to continue
681 the handshake without one. This will allow connections to servers which
682 request a client certificate but do not require it. */
683 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
684 !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
685 BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
686 connssl->connecting_state = ssl_connect_2_writing;
687 infof(data, "schannel: a client certificate has been requested\n");
691 /* check if the handshake needs to be continued */
692 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
693 for(i = 0; i < 3; i++) {
694 /* search for handshake tokens that need to be send */
695 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
696 infof(data, "schannel: sending next handshake data: "
697 "sending %lu bytes...\n", outbuf[i].cbBuffer);
699 /* send handshake token to server */
700 result = Curl_write_plain(conn, conn->sock[sockindex],
701 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
703 if((result != CURLE_OK) ||
704 (outbuf[i].cbBuffer != (size_t) written)) {
705 failf(data, "schannel: failed to send next handshake data: "
706 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
707 return CURLE_SSL_CONNECT_ERROR;
711 /* free obsolete buffer */
712 if(outbuf[i].pvBuffer != NULL) {
713 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
718 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
719 failf(data, "schannel: SNI or certificate check failed: %s",
720 Curl_sspi_strerror(conn, sspi_status));
722 failf(data, "schannel: next InitializeSecurityContext failed: %s",
723 Curl_sspi_strerror(conn, sspi_status));
724 return sspi_status == SEC_E_UNTRUSTED_ROOT ?
725 CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR;
728 /* check if there was additional remaining encrypted data */
729 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
730 infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
732 There are two cases where we could be getting extra data here:
733 1) If we're renegotiating a connection and the handshake is already
734 complete (from the server perspective), it can encrypted app data
735 (not handshake data) in an extra buffer at this point.
736 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
737 connection and this extra data is part of the handshake.
738 We should process the data immediately; waiting for the socket to
739 be ready may fail since the server is done sending handshake data.
741 /* check if the remaining data is less than the total amount
742 and therefore begins after the already processed data */
743 if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
744 memmove(BACKEND->encdata_buffer,
745 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
746 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
747 BACKEND->encdata_offset = inbuf[1].cbBuffer;
748 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
755 BACKEND->encdata_offset = 0;
760 /* check if the handshake needs to be continued */
761 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
762 connssl->connecting_state = ssl_connect_2_reading;
766 /* check if the handshake is complete */
767 if(sspi_status == SEC_E_OK) {
768 connssl->connecting_state = ssl_connect_3;
769 infof(data, "schannel: SSL/TLS handshake complete\n");
772 pubkey_ptr = SSL_IS_PROXY() ?
773 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
774 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
776 result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
778 failf(data, "SSL: public key does not match pinned public key!");
784 /* Windows CE doesn't do any server certificate validation.
785 We have to do it manually. */
786 if(conn->ssl_config.verifypeer)
787 return verify_certificate(conn, sockindex);
794 schannel_connect_step3(struct connectdata *conn, int sockindex)
796 CURLcode result = CURLE_OK;
797 struct Curl_easy *data = conn->data;
798 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
799 SECURITY_STATUS sspi_status = SEC_E_OK;
800 CERT_CONTEXT *ccert_context = NULL;
801 #ifndef CURL_DISABLE_VERBOSE_STRINGS
802 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
806 SecPkgContext_ApplicationProtocol alpn_result;
809 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
811 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
812 hostname, conn->remote_port);
815 return CURLE_SSL_CONNECT_ERROR;
817 /* check if the required context attributes are met */
818 if(BACKEND->ret_flags != BACKEND->req_flags) {
819 if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
820 failf(data, "schannel: failed to setup sequence detection");
821 if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
822 failf(data, "schannel: failed to setup replay detection");
823 if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
824 failf(data, "schannel: failed to setup confidentiality");
825 if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
826 failf(data, "schannel: failed to setup memory allocation");
827 if(!(BACKEND->ret_flags & ISC_RET_STREAM))
828 failf(data, "schannel: failed to setup stream orientation");
829 return CURLE_SSL_CONNECT_ERROR;
833 if(BACKEND->use_alpn) {
834 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
835 SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
837 if(sspi_status != SEC_E_OK) {
838 failf(data, "schannel: failed to retrieve ALPN result");
839 return CURLE_SSL_CONNECT_ERROR;
842 if(alpn_result.ProtoNegoStatus ==
843 SecApplicationProtocolNegotiationStatus_Success) {
845 infof(data, "schannel: ALPN, server accepted to use %.*s\n",
846 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
849 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
850 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
851 NGHTTP2_PROTO_VERSION_ID_LEN)) {
852 conn->negnpn = CURL_HTTP_VERSION_2;
856 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
857 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
858 ALPN_HTTP_1_1_LENGTH)) {
859 conn->negnpn = CURL_HTTP_VERSION_1_1;
863 infof(data, "ALPN, server did not agree to a protocol\n");
867 /* save the current session data for possible re-use */
868 if(SSL_SET_OPTION(primary.sessionid)) {
870 struct curl_schannel_cred *old_cred = NULL;
872 Curl_ssl_sessionid_lock(conn);
873 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
876 if(old_cred != BACKEND->cred) {
877 infof(data, "schannel: old credential handle is stale, removing\n");
878 /* we're not taking old_cred ownership here, no refcount++ is needed */
879 Curl_ssl_delsessionid(conn, (void *)old_cred);
884 result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
885 sizeof(struct curl_schannel_cred),
888 Curl_ssl_sessionid_unlock(conn);
889 failf(data, "schannel: failed to store credential handle");
893 /* this cred session is now also referenced by sessionid cache */
894 BACKEND->cred->refcount++;
895 infof(data, "schannel: stored credential handle in session cache\n");
898 Curl_ssl_sessionid_unlock(conn);
901 if(data->set.ssl.certinfo) {
902 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
903 SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
905 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
906 failf(data, "schannel: failed to retrieve remote cert context");
907 return CURLE_SSL_CONNECT_ERROR;
910 result = Curl_ssl_init_certinfo(data, 1);
912 if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
913 (ccert_context->cbCertEncoded > 0)) {
915 const char *beg = (const char *) ccert_context->pbCertEncoded;
916 const char *end = beg + ccert_context->cbCertEncoded;
917 result = Curl_extract_certinfo(conn, 0, beg, end);
920 CertFreeCertificateContext(ccert_context);
925 connssl->connecting_state = ssl_connect_done;
931 schannel_connect_common(struct connectdata *conn, int sockindex,
932 bool nonblocking, bool *done)
935 struct Curl_easy *data = conn->data;
936 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
937 curl_socket_t sockfd = conn->sock[sockindex];
941 /* check if the connection has already been established */
942 if(ssl_connection_complete == connssl->state) {
947 if(ssl_connect_1 == connssl->connecting_state) {
948 /* check out how much more time we're allowed */
949 timeout_ms = Curl_timeleft(data, NULL, TRUE);
952 /* no need to continue if time already is up */
953 failf(data, "SSL/TLS connection timeout");
954 return CURLE_OPERATION_TIMEDOUT;
957 result = schannel_connect_step1(conn, sockindex);
962 while(ssl_connect_2 == connssl->connecting_state ||
963 ssl_connect_2_reading == connssl->connecting_state ||
964 ssl_connect_2_writing == connssl->connecting_state) {
966 /* check out how much more time we're allowed */
967 timeout_ms = Curl_timeleft(data, NULL, TRUE);
970 /* no need to continue if time already is up */
971 failf(data, "SSL/TLS connection timeout");
972 return CURLE_OPERATION_TIMEDOUT;
975 /* if ssl is expecting something, check if it's available. */
976 if(connssl->connecting_state == ssl_connect_2_reading
977 || connssl->connecting_state == ssl_connect_2_writing) {
979 curl_socket_t writefd = ssl_connect_2_writing ==
980 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
981 curl_socket_t readfd = ssl_connect_2_reading ==
982 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
984 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
985 nonblocking ? 0 : timeout_ms);
988 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
989 return CURLE_SSL_CONNECT_ERROR;
998 failf(data, "SSL/TLS connection timeout");
999 return CURLE_OPERATION_TIMEDOUT;
1002 /* socket is readable or writable */
1005 /* Run transaction, and return to the caller if it failed or if
1006 * this connection is part of a multi handle and this loop would
1007 * execute again. This permits the owner of a multi handle to
1008 * abort a connection attempt before step2 has completed while
1009 * ensuring that a client using select() or epoll() will always
1010 * have a valid fdset to wait on.
1012 result = schannel_connect_step2(conn, sockindex);
1013 if(result || (nonblocking &&
1014 (ssl_connect_2 == connssl->connecting_state ||
1015 ssl_connect_2_reading == connssl->connecting_state ||
1016 ssl_connect_2_writing == connssl->connecting_state)))
1019 } /* repeat step2 until all transactions are done. */
1021 if(ssl_connect_3 == connssl->connecting_state) {
1022 result = schannel_connect_step3(conn, sockindex);
1027 if(ssl_connect_done == connssl->connecting_state) {
1028 connssl->state = ssl_connection_complete;
1029 conn->recv[sockindex] = schannel_recv;
1030 conn->send[sockindex] = schannel_send;
1036 /* reset our connection state machine */
1037 connssl->connecting_state = ssl_connect_1;
1043 schannel_send(struct connectdata *conn, int sockindex,
1044 const void *buf, size_t len, CURLcode *err)
1046 ssize_t written = -1;
1047 size_t data_len = 0;
1048 unsigned char *data = NULL;
1049 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1050 SecBuffer outbuf[4];
1051 SecBufferDesc outbuf_desc;
1052 SECURITY_STATUS sspi_status = SEC_E_OK;
1055 /* check if the maximum stream sizes were queried */
1056 if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1057 sspi_status = s_pSecFn->QueryContextAttributes(
1058 &BACKEND->ctxt->ctxt_handle,
1059 SECPKG_ATTR_STREAM_SIZES,
1060 &BACKEND->stream_sizes);
1061 if(sspi_status != SEC_E_OK) {
1062 *err = CURLE_SEND_ERROR;
1067 /* check if the buffer is longer than the maximum message length */
1068 if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1069 len = BACKEND->stream_sizes.cbMaximumMessage;
1072 /* calculate the complete message length and allocate a buffer for it */
1073 data_len = BACKEND->stream_sizes.cbHeader + len +
1074 BACKEND->stream_sizes.cbTrailer;
1075 data = (unsigned char *) malloc(data_len);
1077 *err = CURLE_OUT_OF_MEMORY;
1081 /* setup output buffers (header, data, trailer, empty) */
1082 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1083 data, BACKEND->stream_sizes.cbHeader);
1084 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1085 data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1086 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1087 data + BACKEND->stream_sizes.cbHeader + len,
1088 BACKEND->stream_sizes.cbTrailer);
1089 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1090 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1092 /* copy data into output buffer */
1093 memcpy(outbuf[1].pvBuffer, buf, len);
1095 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1096 sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1099 /* check if the message was encrypted */
1100 if(sspi_status == SEC_E_OK) {
1103 /* send the encrypted message including header, data and trailer */
1104 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1107 It's important to send the full message which includes the header,
1108 encrypted payload, and trailer. Until the client receives all the
1109 data a coherent message has not been delivered and the client
1110 can't read any of it.
1112 If we wanted to buffer the unwritten encrypted bytes, we would
1113 tell the client that all data it has requested to be sent has been
1114 sent. The unwritten encrypted bytes would be the first bytes to
1115 send on the next invocation.
1116 Here's the catch with this - if we tell the client that all the
1117 bytes have been sent, will the client call this method again to
1118 send the buffered data? Looking at who calls this function, it
1119 seems the answer is NO.
1122 /* send entire message or fail */
1123 while(len > (size_t)written) {
1130 timeleft = Curl_timeleft(conn->data, NULL, FALSE);
1132 /* we already got the timeout */
1133 failf(conn->data, "schannel: timed out sending data "
1134 "(bytes sent: %zd)", written);
1135 *err = CURLE_OPERATION_TIMEDOUT;
1140 what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
1143 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1144 *err = CURLE_SEND_ERROR;
1148 else if(0 == what) {
1149 failf(conn->data, "schannel: timed out sending data "
1150 "(bytes sent: %zd)", written);
1151 *err = CURLE_OPERATION_TIMEDOUT;
1155 /* socket is writable */
1157 result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1158 len - written, &this_write);
1159 if(result == CURLE_AGAIN)
1161 else if(result != CURLE_OK) {
1167 written += this_write;
1170 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1171 *err = CURLE_OUT_OF_MEMORY;
1174 *err = CURLE_SEND_ERROR;
1177 Curl_safefree(data);
1179 if(len == (size_t)written)
1180 /* Encrypted message including header, data and trailer entirely sent.
1181 The return value is the number of unencrypted bytes that were sent. */
1182 written = outbuf[1].cbBuffer;
1188 schannel_recv(struct connectdata *conn, int sockindex,
1189 char *buf, size_t len, CURLcode *err)
1193 struct Curl_easy *data = conn->data;
1194 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1195 unsigned char *reallocated_buffer;
1196 size_t reallocated_length;
1199 SecBufferDesc inbuf_desc;
1200 SECURITY_STATUS sspi_status = SEC_E_OK;
1201 /* we want the length of the encrypted buffer to be at least large enough
1202 that it can hold all the bytes requested and some TLS record overhead. */
1203 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1205 /****************************************************************************
1206 * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1207 * The pattern for return error is set *err, optional infof, goto cleanup.
1209 * Our priority is to always return as much decrypted data to the caller as
1210 * possible, even if an error occurs. The state of the decrypted buffer must
1211 * always be valid. Transfer of decrypted data to the caller's buffer is
1212 * handled in the cleanup.
1215 infof(data, "schannel: client wants to read %zu bytes\n", len);
1218 if(len && len <= BACKEND->decdata_offset) {
1219 infof(data, "schannel: enough decrypted data is already available\n");
1222 else if(BACKEND->recv_unrecoverable_err) {
1223 *err = BACKEND->recv_unrecoverable_err;
1224 infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1227 else if(BACKEND->recv_sspi_close_notify) {
1228 /* once a server has indicated shutdown there is no more encrypted data */
1229 infof(data, "schannel: server indicated shutdown in a prior call\n");
1233 /* It's debatable what to return when !len. Regardless we can't return
1234 immediately because there may be data to decrypt (in the case we want to
1235 decrypt all encrypted cached data) so handle !len later in cleanup.
1239 else if(!BACKEND->recv_connection_closed) {
1240 /* increase enc buffer in order to fit the requested amount of data */
1241 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1242 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1243 BACKEND->encdata_length < min_encdata_length) {
1244 reallocated_length = BACKEND->encdata_offset +
1245 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1246 if(reallocated_length < min_encdata_length) {
1247 reallocated_length = min_encdata_length;
1249 reallocated_buffer = realloc(BACKEND->encdata_buffer,
1250 reallocated_length);
1251 if(reallocated_buffer == NULL) {
1252 *err = CURLE_OUT_OF_MEMORY;
1253 failf(data, "schannel: unable to re-allocate memory");
1257 BACKEND->encdata_buffer = reallocated_buffer;
1258 BACKEND->encdata_length = reallocated_length;
1259 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1260 infof(data, "schannel: encdata_buffer resized %zu\n",
1261 BACKEND->encdata_length);
1264 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1265 BACKEND->encdata_offset, BACKEND->encdata_length);
1267 /* read encrypted data from socket */
1268 *err = Curl_read_plain(conn->sock[sockindex],
1269 (char *)(BACKEND->encdata_buffer +
1270 BACKEND->encdata_offset),
1274 if(*err == CURLE_AGAIN)
1275 infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
1276 else if(*err == CURLE_RECV_ERROR)
1277 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1279 infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1281 else if(nread == 0) {
1282 BACKEND->recv_connection_closed = true;
1283 infof(data, "schannel: server closed the connection\n");
1285 else if(nread > 0) {
1286 BACKEND->encdata_offset += (size_t)nread;
1287 BACKEND->encdata_is_incomplete = false;
1288 infof(data, "schannel: encrypted data got %zd\n", nread);
1292 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1293 BACKEND->encdata_offset, BACKEND->encdata_length);
1296 while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1297 (!len || BACKEND->decdata_offset < len ||
1298 BACKEND->recv_connection_closed)) {
1299 /* prepare data buffer for DecryptMessage call */
1300 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1301 curlx_uztoul(BACKEND->encdata_offset));
1303 /* we need 3 more empty input buffers for possible output */
1304 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1305 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1306 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1307 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1309 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1311 sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1312 &inbuf_desc, 0, NULL);
1314 /* check if everything went fine (server may want to renegotiate
1315 or shutdown the connection context) */
1316 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1317 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1318 /* check for successfully decrypted data, even before actual
1319 renegotiation or shutdown of the connection context */
1320 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1321 infof(data, "schannel: decrypted data length: %lu\n",
1324 /* increase buffer in order to fit the received amount of data */
1325 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1326 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1327 if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1328 BACKEND->decdata_length < len) {
1329 /* increase internal decrypted data buffer */
1330 reallocated_length = BACKEND->decdata_offset + size;
1331 /* make sure that the requested amount of data fits */
1332 if(reallocated_length < len) {
1333 reallocated_length = len;
1335 reallocated_buffer = realloc(BACKEND->decdata_buffer,
1336 reallocated_length);
1337 if(reallocated_buffer == NULL) {
1338 *err = CURLE_OUT_OF_MEMORY;
1339 failf(data, "schannel: unable to re-allocate memory");
1342 BACKEND->decdata_buffer = reallocated_buffer;
1343 BACKEND->decdata_length = reallocated_length;
1346 /* copy decrypted data to internal buffer */
1347 size = inbuf[1].cbBuffer;
1349 memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1350 inbuf[1].pvBuffer, size);
1351 BACKEND->decdata_offset += size;
1354 infof(data, "schannel: decrypted data added: %zu\n", size);
1355 infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
1356 BACKEND->decdata_offset, BACKEND->decdata_length);
1359 /* check for remaining encrypted data */
1360 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1361 infof(data, "schannel: encrypted data length: %lu\n",
1364 /* check if the remaining data is less than the total amount
1365 * and therefore begins after the already processed data
1367 if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1368 /* move remaining encrypted data forward to the beginning of
1370 memmove(BACKEND->encdata_buffer,
1371 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1372 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1373 BACKEND->encdata_offset = inbuf[3].cbBuffer;
1376 infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
1377 BACKEND->encdata_offset, BACKEND->encdata_length);
1380 /* reset encrypted buffer offset, because there is no data remaining */
1381 BACKEND->encdata_offset = 0;
1384 /* check if server wants to renegotiate the connection context */
1385 if(sspi_status == SEC_I_RENEGOTIATE) {
1386 infof(data, "schannel: remote party requests renegotiation\n");
1387 if(*err && *err != CURLE_AGAIN) {
1388 infof(data, "schannel: can't renogotiate, an error is pending\n");
1391 if(BACKEND->encdata_offset) {
1392 *err = CURLE_RECV_ERROR;
1393 infof(data, "schannel: can't renogotiate, "
1394 "encrypted data available\n");
1397 /* begin renegotiation */
1398 infof(data, "schannel: renegotiating SSL/TLS connection\n");
1399 connssl->state = ssl_connection_negotiating;
1400 connssl->connecting_state = ssl_connect_2_writing;
1401 *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1403 infof(data, "schannel: renegotiation failed\n");
1406 /* now retry receiving data */
1407 sspi_status = SEC_E_OK;
1408 infof(data, "schannel: SSL/TLS connection renegotiated\n");
1411 /* check if the server closed the connection */
1412 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1413 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1414 returned so we have to work around that in cleanup. */
1415 BACKEND->recv_sspi_close_notify = true;
1416 if(!BACKEND->recv_connection_closed) {
1417 BACKEND->recv_connection_closed = true;
1418 infof(data, "schannel: server closed the connection\n");
1423 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1424 BACKEND->encdata_is_incomplete = true;
1427 infof(data, "schannel: failed to decrypt data, need more data\n");
1431 *err = CURLE_RECV_ERROR;
1432 infof(data, "schannel: failed to read data from server: %s\n",
1433 Curl_sspi_strerror(conn, sspi_status));
1438 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
1439 BACKEND->encdata_offset, BACKEND->encdata_length);
1441 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1442 BACKEND->decdata_offset, BACKEND->decdata_length);
1445 /* Warning- there is no guarantee the encdata state is valid at this point */
1446 infof(data, "schannel: schannel_recv cleanup\n");
1448 /* Error if the connection has closed without a close_notify.
1449 Behavior here is a matter of debate. We don't want to be vulnerable to a
1450 truncation attack however there's some browser precedent for ignoring the
1451 close_notify for compatibility reasons.
1452 Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
1453 return close_notify. In that case if the connection was closed we assume it
1454 was graceful (close_notify) since there doesn't seem to be a way to tell.
1456 if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1457 !BACKEND->recv_sspi_close_notify) {
1458 bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1461 if(isWin2k && sspi_status == SEC_E_OK)
1462 BACKEND->recv_sspi_close_notify = true;
1464 *err = CURLE_RECV_ERROR;
1465 infof(data, "schannel: server closed abruptly (missing close_notify)\n");
1469 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
1470 if(*err && *err != CURLE_AGAIN)
1471 BACKEND->recv_unrecoverable_err = *err;
1473 size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1475 memcpy(buf, BACKEND->decdata_buffer, size);
1476 memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1477 BACKEND->decdata_offset - size);
1478 BACKEND->decdata_offset -= size;
1480 infof(data, "schannel: decrypted data returned %zu\n", size);
1481 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
1482 BACKEND->decdata_offset, BACKEND->decdata_length);
1484 return (ssize_t)size;
1487 if(!*err && !BACKEND->recv_connection_closed)
1490 /* It's debatable what to return when !len. We could return whatever error we
1491 got from decryption but instead we override here so the return is consistent.
1496 return *err ? -1 : 0;
1499 static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
1500 int sockindex, bool *done)
1502 return schannel_connect_common(conn, sockindex, TRUE, done);
1505 static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
1510 result = schannel_connect_common(conn, sockindex, FALSE, &done);
1519 static bool Curl_schannel_data_pending(const struct connectdata *conn,
1522 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1524 if(connssl->use) /* SSL/TLS is in use */
1525 return (BACKEND->decdata_offset > 0 ||
1526 (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1531 static void Curl_schannel_close(struct connectdata *conn, int sockindex)
1533 if(conn->ssl[sockindex].use)
1534 /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
1535 Curl_ssl_shutdown(conn, sockindex);
1538 static void Curl_schannel_session_free(void *ptr)
1540 /* this is expected to be called under sessionid lock */
1541 struct curl_schannel_cred *cred = ptr;
1544 if(cred->refcount == 0) {
1545 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1546 Curl_safefree(cred);
1550 static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
1552 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
1553 * Shutting Down an Schannel Connection
1555 struct Curl_easy *data = conn->data;
1556 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1557 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1560 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
1561 hostname, conn->remote_port);
1563 if(BACKEND->cred && BACKEND->ctxt) {
1564 SecBufferDesc BuffDesc;
1566 SECURITY_STATUS sspi_status;
1568 SecBufferDesc outbuf_desc;
1571 DWORD dwshut = SCHANNEL_SHUTDOWN;
1573 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
1574 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
1576 sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
1579 if(sspi_status != SEC_E_OK)
1580 failf(data, "schannel: ApplyControlToken failure: %s",
1581 Curl_sspi_strerror(conn, sspi_status));
1583 host_name = Curl_convert_UTF8_to_tchar(hostname);
1585 return CURLE_OUT_OF_MEMORY;
1587 /* setup output buffer */
1588 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1589 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1591 sspi_status = s_pSecFn->InitializeSecurityContext(
1592 &BACKEND->cred->cred_handle,
1593 &BACKEND->ctxt->ctxt_handle,
1600 &BACKEND->ctxt->ctxt_handle,
1602 &BACKEND->ret_flags,
1603 &BACKEND->ctxt->time_stamp);
1605 Curl_unicodefree(host_name);
1607 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
1608 /* send close message which is in output buffer */
1610 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
1611 outbuf.cbBuffer, &written);
1613 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1614 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
1615 infof(data, "schannel: failed to send close msg: %s"
1616 " (bytes written: %zd)\n", curl_easy_strerror(result), written);
1621 /* free SSPI Schannel API security context handle */
1623 infof(data, "schannel: clear security context handle\n");
1624 s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
1625 Curl_safefree(BACKEND->ctxt);
1628 /* free SSPI Schannel API credential handle */
1630 Curl_ssl_sessionid_lock(conn);
1631 Curl_schannel_session_free(BACKEND->cred);
1632 Curl_ssl_sessionid_unlock(conn);
1633 BACKEND->cred = NULL;
1636 /* free internal buffer for received encrypted data */
1637 if(BACKEND->encdata_buffer != NULL) {
1638 Curl_safefree(BACKEND->encdata_buffer);
1639 BACKEND->encdata_length = 0;
1640 BACKEND->encdata_offset = 0;
1641 BACKEND->encdata_is_incomplete = false;
1644 /* free internal buffer for received decrypted data */
1645 if(BACKEND->decdata_buffer != NULL) {
1646 Curl_safefree(BACKEND->decdata_buffer);
1647 BACKEND->decdata_length = 0;
1648 BACKEND->decdata_offset = 0;
1654 static int Curl_schannel_init(void)
1656 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
1659 static void Curl_schannel_cleanup(void)
1661 Curl_sspi_global_cleanup();
1664 static size_t Curl_schannel_version(char *buffer, size_t size)
1666 size = snprintf(buffer, size, "WinSSL");
1671 static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
1672 unsigned char *entropy, size_t length)
1674 HCRYPTPROV hCryptProv = 0;
1678 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
1679 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
1680 return CURLE_FAILED_INIT;
1682 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
1683 CryptReleaseContext(hCryptProv, 0UL);
1684 return CURLE_FAILED_INIT;
1687 CryptReleaseContext(hCryptProv, 0UL);
1691 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
1692 const char *pinnedpubkey)
1694 SECURITY_STATUS status;
1695 struct Curl_easy *data = conn->data;
1696 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1697 CERT_CONTEXT *pCertContextServer = NULL;
1698 const char *x509_der;
1700 curl_X509certificate x509_parsed;
1701 curl_asn1Element *pubkey;
1703 /* Result is returned to caller */
1704 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1706 /* if a path wasn't specified, don't pin */
1711 status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1712 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1713 &pCertContextServer);
1715 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
1716 failf(data, "schannel: Failed to read remote certificate context: %s",
1717 Curl_sspi_strerror(conn, status));
1722 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1723 (pCertContextServer->cbCertEncoded > 0)))
1726 x509_der = (const char *)pCertContextServer->pbCertEncoded;
1727 x509_der_len = pCertContextServer->cbCertEncoded;
1728 memset(&x509_parsed, 0, sizeof x509_parsed);
1729 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
1732 pubkey = &x509_parsed.subjectPublicKeyInfo;
1733 if(!pubkey->header || pubkey->end <= pubkey->header) {
1734 failf(data, "SSL: failed retrieving public key from server certificate");
1738 result = Curl_pin_peer_pubkey(data,
1740 (const unsigned char *)pubkey->header,
1741 (size_t)(pubkey->end - pubkey->header));
1743 failf(data, "SSL: public key does not match pinned public key!");
1747 if(pCertContextServer)
1748 CertFreeCertificateContext(pCertContextServer);
1754 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
1756 SECURITY_STATUS status;
1757 struct Curl_easy *data = conn->data;
1758 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1759 CURLcode result = CURLE_OK;
1760 CERT_CONTEXT *pCertContextServer = NULL;
1761 const CERT_CHAIN_CONTEXT *pChainContext = NULL;
1762 const char * const conn_hostname = SSL_IS_PROXY() ?
1763 conn->http_proxy.host.name :
1766 status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1767 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1768 &pCertContextServer);
1770 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
1771 failf(data, "schannel: Failed to read remote certificate context: %s",
1772 Curl_sspi_strerror(conn, status));
1773 result = CURLE_PEER_FAILED_VERIFICATION;
1776 if(result == CURLE_OK) {
1777 CERT_CHAIN_PARA ChainPara;
1778 memset(&ChainPara, 0, sizeof(ChainPara));
1779 ChainPara.cbSize = sizeof(ChainPara);
1781 if(!CertGetCertificateChain(NULL,
1784 pCertContextServer->hCertStore,
1786 (data->set.ssl.no_revoke ? 0 :
1787 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
1790 failf(data, "schannel: CertGetCertificateChain failed: %s",
1791 Curl_sspi_strerror(conn, GetLastError()));
1792 pChainContext = NULL;
1793 result = CURLE_PEER_FAILED_VERIFICATION;
1796 if(result == CURLE_OK) {
1797 CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
1798 DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
1799 dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
1800 if(dwTrustErrorMask) {
1801 if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
1802 failf(data, "schannel: CertGetCertificateChain trust error"
1803 " CERT_TRUST_IS_REVOKED");
1804 else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
1805 failf(data, "schannel: CertGetCertificateChain trust error"
1806 " CERT_TRUST_IS_PARTIAL_CHAIN");
1807 else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
1808 failf(data, "schannel: CertGetCertificateChain trust error"
1809 " CERT_TRUST_IS_UNTRUSTED_ROOT");
1810 else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
1811 failf(data, "schannel: CertGetCertificateChain trust error"
1812 " CERT_TRUST_IS_NOT_TIME_VALID");
1814 failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
1816 result = CURLE_PEER_FAILED_VERIFICATION;
1821 if(result == CURLE_OK) {
1822 if(conn->ssl_config.verifyhost) {
1823 TCHAR cert_hostname_buff[256];
1826 /* TODO: Fix this for certificates with multiple alternative names.
1827 Right now we're only asking for the first preferred alternative name.
1828 Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
1829 (if WinCE supports that?) and run this section in a loop for each.
1830 https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
1831 curl: (51) schannel: CertGetNameString() certificate hostname
1832 (.google.com) did not match connection (google.com)
1834 len = CertGetNameString(pCertContextServer,
1836 CERT_NAME_DISABLE_IE4_UTF8_FLAG,
1841 const char *cert_hostname;
1843 /* Comparing the cert name and the connection hostname encoded as UTF-8
1844 * is acceptable since both values are assumed to use ASCII
1845 * (or some equivalent) encoding
1847 cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
1848 if(!cert_hostname) {
1849 result = CURLE_OUT_OF_MEMORY;
1854 match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
1855 if(match_result == CURL_HOST_MATCH) {
1857 "schannel: connection hostname (%s) validated "
1858 "against certificate name (%s)\n",
1865 "schannel: connection hostname (%s) "
1866 "does not match certificate name (%s)",
1869 result = CURLE_PEER_FAILED_VERIFICATION;
1871 Curl_unicodefree(cert_hostname);
1876 "schannel: CertGetNameString did not provide any "
1877 "certificate name information");
1878 result = CURLE_PEER_FAILED_VERIFICATION;
1884 CertFreeCertificateChain(pChainContext);
1886 if(pCertContextServer)
1887 CertFreeCertificateContext(pCertContextServer);
1891 #endif /* _WIN32_WCE */
1893 static void Curl_schannel_checksum(const unsigned char *input,
1895 unsigned char *checksum,
1898 const unsigned int algId)
1900 HCRYPTPROV hProv = 0;
1901 HCRYPTHASH hHash = 0;
1902 DWORD cbHashSize = 0;
1903 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
1904 DWORD dwChecksumLen = (DWORD)checksumlen;
1906 /* since this can fail in multiple ways, zero memory first so we never
1909 memset(checksum, 0, checksumlen);
1911 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
1912 CRYPT_VERIFYCONTEXT))
1913 return; /* failed */
1916 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
1919 if(!CryptHashData(hHash, (const BYTE*)input, (DWORD)inputlen, 0))
1923 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
1927 /* check hash size */
1928 if(checksumlen < cbHashSize)
1931 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
1936 CryptDestroyHash(hHash);
1939 CryptReleaseContext(hProv, 0);
1942 static CURLcode Curl_schannel_md5sum(unsigned char *input,
1944 unsigned char *md5sum,
1947 Curl_schannel_checksum(input, inputlen, md5sum, md5len,
1948 PROV_RSA_FULL, CALG_MD5);
1952 static void Curl_schannel_sha256sum(const unsigned char *input,
1954 unsigned char *sha256sum,
1957 Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
1958 PROV_RSA_AES, CALG_SHA_256);
1961 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
1962 CURLINFO info UNUSED_PARAM)
1965 return &BACKEND->ctxt->ctxt_handle;
1968 const struct Curl_ssl Curl_ssl_schannel = {
1969 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
1971 0, /* have_ca_path */
1972 1, /* have_certinfo */
1973 1, /* have_pinnedpubkey */
1974 0, /* have_ssl_ctx */
1975 0, /* support_https_proxy */
1977 sizeof(struct ssl_backend_data),
1979 Curl_schannel_init, /* init */
1980 Curl_schannel_cleanup, /* cleanup */
1981 Curl_schannel_version, /* version */
1982 Curl_none_check_cxn, /* check_cxn */
1983 Curl_schannel_shutdown, /* shutdown */
1984 Curl_schannel_data_pending, /* data_pending */
1985 Curl_schannel_random, /* random */
1986 Curl_none_cert_status_request, /* cert_status_request */
1987 Curl_schannel_connect, /* connect */
1988 Curl_schannel_connect_nonblocking, /* connect_nonblocking */
1989 Curl_schannel_get_internals, /* get_internals */
1990 Curl_schannel_close, /* close_one */
1991 Curl_none_close_all, /* close_all */
1992 Curl_schannel_session_free, /* session_free */
1993 Curl_none_set_engine, /* set_engine */
1994 Curl_none_set_engine_default, /* set_engine_default */
1995 Curl_none_engines_list, /* engines_list */
1996 Curl_none_false_start, /* false_start */
1997 Curl_schannel_md5sum, /* md5sum */
1998 Curl_schannel_sha256sum /* sha256sum */
2001 #endif /* USE_SCHANNEL */