dep-curl/lib/vtls/rustls.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1469 lines
45 KiB
C
Raw Normal View History

/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Jacob Hoffman-Andrews, <github@hoffman-andrews.com>
* Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
2025-03-21 14:43:07 -04:00
* Copyright (C) Daniel McCarney, <daniel@binaryparadox.net>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
lib: use lib source directory as base include path Backtrack on previous change that aimed to solve the wrong `share.h` being included. It turns out it did not fix this issue. At the same time it introduced relative header filenames and the need to include the same headers differently depending on the source files' location, reducing readability and editability. Replace this method by re-adding curl's lib source directory to the header path and addressing headers by the their full, relative name to that base directory. Aligning with this method already used in src and tests. With these advantages: - makes includes easier to read, recognize, grep, sort, write, and copy between sources, - syncs the way these headers are included across curl components, - avoids the ambiguity between system `schannel.h`, `rustls.h` vs. local headers using the same names in `lib/vtls`, - silences clang-tidy `readability-duplicate-include` checker, which detects the above issue, Ref: https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html - possibly silences TIOBE coding standard warnings: `6.10.2.a: Don't use relative paths in #include statements.` - long shot: it works well with concatenated test sources, for clang-tidy-friendly custom unity builds. Ref: #20667 Slight downside: it's not enforced. If there happens to be a collision between a local `lib/*.h` header and a system one, the solution is to rename (possibly with its `.c` counterpart) into the `curl_` namespace. This is also the method used by curl in the past. Also: - curlx/inet_pton: reduce scope of an include. - toolx/tool_time: apply this to an include, and update VS project files accordingly. Also dropping unnecessary lib/curlx header path. - clang-tidy: enable `readability-duplicate-include`. Follow-up to 3887069c661b40e76b053a4867eb565d4761ab3e #19676 Follow-up to 625f2c1644da58b9617479775badea21f125ce6d #16991 #16949 Closes #20623
2026-02-19 00:44:43 +01:00
#include "curl_setup.h"
#ifdef USE_RUSTLS
#include <rustls.h>
lib: use lib source directory as base include path Backtrack on previous change that aimed to solve the wrong `share.h` being included. It turns out it did not fix this issue. At the same time it introduced relative header filenames and the need to include the same headers differently depending on the source files' location, reducing readability and editability. Replace this method by re-adding curl's lib source directory to the header path and addressing headers by the their full, relative name to that base directory. Aligning with this method already used in src and tests. With these advantages: - makes includes easier to read, recognize, grep, sort, write, and copy between sources, - syncs the way these headers are included across curl components, - avoids the ambiguity between system `schannel.h`, `rustls.h` vs. local headers using the same names in `lib/vtls`, - silences clang-tidy `readability-duplicate-include` checker, which detects the above issue, Ref: https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html - possibly silences TIOBE coding standard warnings: `6.10.2.a: Don't use relative paths in #include statements.` - long shot: it works well with concatenated test sources, for clang-tidy-friendly custom unity builds. Ref: #20667 Slight downside: it's not enforced. If there happens to be a collision between a local `lib/*.h` header and a system one, the solution is to rename (possibly with its `.c` counterpart) into the `curl_` namespace. This is also the method used by curl in the past. Also: - curlx/inet_pton: reduce scope of an include. - toolx/tool_time: apply this to an include, and update VS project files accordingly. Also dropping unnecessary lib/curlx header path. - clang-tidy: enable `readability-duplicate-include`. Follow-up to 3887069c661b40e76b053a4867eb565d4761ab3e #19676 Follow-up to 625f2c1644da58b9617479775badea21f125ce6d #16991 #16949 Closes #20623
2026-02-19 00:44:43 +01:00
#include "curlx/fopen.h"
#include "curlx/strerr.h"
#include "urldata.h"
#include "curl_trc.h"
#include "vdns/cf-dns.h"
#include "vdns/httpsrr.h"
lib: use lib source directory as base include path Backtrack on previous change that aimed to solve the wrong `share.h` being included. It turns out it did not fix this issue. At the same time it introduced relative header filenames and the need to include the same headers differently depending on the source files' location, reducing readability and editability. Replace this method by re-adding curl's lib source directory to the header path and addressing headers by the their full, relative name to that base directory. Aligning with this method already used in src and tests. With these advantages: - makes includes easier to read, recognize, grep, sort, write, and copy between sources, - syncs the way these headers are included across curl components, - avoids the ambiguity between system `schannel.h`, `rustls.h` vs. local headers using the same names in `lib/vtls`, - silences clang-tidy `readability-duplicate-include` checker, which detects the above issue, Ref: https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html - possibly silences TIOBE coding standard warnings: `6.10.2.a: Don't use relative paths in #include statements.` - long shot: it works well with concatenated test sources, for clang-tidy-friendly custom unity builds. Ref: #20667 Slight downside: it's not enforced. If there happens to be a collision between a local `lib/*.h` header and a system one, the solution is to rename (possibly with its `.c` counterpart) into the `curl_` namespace. This is also the method used by curl in the past. Also: - curlx/inet_pton: reduce scope of an include. - toolx/tool_time: apply this to an include, and update VS project files accordingly. Also dropping unnecessary lib/curlx header path. - clang-tidy: enable `readability-duplicate-include`. Follow-up to 3887069c661b40e76b053a4867eb565d4761ab3e #19676 Follow-up to 625f2c1644da58b9617479775badea21f125ce6d #16991 #16949 Closes #20623
2026-02-19 00:44:43 +01:00
#include "vtls/vtls.h"
#include "vtls/vtls_int.h"
#include "vtls/rustls.h"
#include "vtls/keylog.h"
#include "vtls/cipher_suite.h"
#include "vtls/x509asn1.h"
#ifdef USE_ECH
#include "curlx/base64.h"
#endif
#if EAGAIN != EWOULDBLOCK
#define RAW_EAGAIN(e) ((e) == EWOULDBLOCK || (e) == EAGAIN)
#else
#define RAW_EAGAIN(e) ((e) == EWOULDBLOCK)
#endif
struct rustls_ssl_backend_data {
const struct rustls_client_config *config;
struct rustls_connection *conn;
size_t plain_out_buffered;
BIT(data_in_pending);
BIT(sent_shutdown);
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
2025-03-21 14:43:07 -04:00
static CURLcode map_error(const rustls_result r)
{
if(rustls_result_is_cert_error(r)) {
return CURLE_PEER_FAILED_VERIFICATION;
}
switch(r) {
case RUSTLS_RESULT_OK:
return CURLE_OK;
case RUSTLS_RESULT_NULL_PARAMETER:
return CURLE_BAD_FUNCTION_ARGUMENT;
default:
return CURLE_RECV_ERROR;
}
}
static void rustls_failf(struct Curl_easy *data, const rustls_result rr,
const char *msg)
2025-03-21 14:43:07 -04:00
{
char errorbuf[STRERROR_LEN];
size_t errorlen;
rustls_error(rr, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "%s: %.*s", msg, (int)errorlen, errorbuf);
}
static bool cr_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
2025-03-21 14:43:07 -04:00
const struct ssl_connect_data *ctx = cf->ctx;
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
struct rustls_ssl_backend_data *backend;
(void)data;
DEBUGASSERT(ctx && ctx->backend);
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
backend = (struct rustls_ssl_backend_data *)ctx->backend;
return (bool)backend->data_in_pending;
}
struct io_ctx {
struct Curl_cfilter *cf;
struct Curl_easy *data;
};
static int read_cb(void *userdata, uint8_t *buf, uintptr_t len,
uintptr_t *out_n)
{
2025-03-21 14:43:07 -04:00
const struct io_ctx *io_ctx = userdata;
struct ssl_connect_data * const connssl = io_ctx->cf->ctx;
CURLcode result;
int ret = 0;
size_t nread;
result = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
(char *)buf, len, &nread);
if(result) {
nread = 0;
core: stop redefining `E*` macros on Windows, map `EACCES`, related fixes Before this patch, standard `E*` errno codes were redefined on Windows, onto matching winsock2 `WSA*` error codes, which have different values. This broke uses where using the `E*` value in non-socket context, or other places expecting a POSIX `errno`, e.g. file I/O, threads, IDN or interfacing with dependencies. Fix it by introducing a curl-specific `SOCKE*` set of macros that map to `WSA*` on Windows and standard POSIX codes on other platforms. Then verify and update the code to use `SOCKE*` or `E*` macro depending on context. - Add `SOCKE*` macros that map to either winsock2 or POSIX error codes. And use them with `SOCKERRNO` or in contexts requiring platform-dependent socket error codes. This fixes `E*` uses which were supposed be POSIX values, not `WSA*` socket errors, on Windows: - lib/curl_multibyte.c - lib/curl_threads.c - lib/idn.c - lib/vtls/gtls.c - lib/vtls/rustls.c - src/tool_cb_wrt.c - src/tool_dirhie.c - Ban `E*` codes having a `SOCKE*` mapping, via checksrc. Authored-by: Daniel Stenberg - Add exceptions for `E*` codes used in file I/O, or other contexts requiring POSIX error codes. Also: - ftp: fix missing `SOCKEACCES` mapping for Windows. - add `SOCKENOMEM` for `Curl_getaddrinfo()` via `asyn-thread.c`. - tests/server/sockfilt: fix to set `SOCKERRNO` in local `select()` override on Windows. - lib/inet_ntop: fix to return `WSAEINVAL` on Windows, where `ENOSPC` is used on other platforms. To simulate Windows' built-in `inet_ntop()`, as tested on a Win10 machine. Note: - WINE returns `STATUS_INVALID_PARAMETER` = `0xC000000D`. - Microsoft documentation says it returns `WSA_INVALID_PARAMETER` (= `ERROR_INVALID_PARAMETER`) 87: https://learn.microsoft.com/windows/win32/api/ws2tcpip/nf-ws2tcpip-inet_ntop#return-value - lib/inet_ntop: drop redundant `CURL_SETERRNO(ENOSPC)`. `inet_ntop4()` already sets it before returning `NULL`. - replace stray `WSAEWOULDBLOCK` with `USE_WINSOCK` macro to detect winsock2. - move existing `SOCKE*` mappings from `tests/server` to `curl_setup_once.h`. - add missing `EINTR`, `EINVAL` constants for WinCE. Follow-up to abf80aae384319ef9b19ffbd0d69a1fbe7421f1f #16612 Follow-up to d69425ed7d0918aceddd96048b146a9df85638ec #16615 Bug: https://github.com/curl/curl/pull/16553#issuecomment-2704679377 Closes #16621
2025-03-08 02:18:35 +01:00
/* !checksrc! disable ERRNOVAR 4 */
if(result == CURLE_AGAIN)
ret = EAGAIN;
else
ret = EINVAL;
}
else if(nread == 0)
connssl->peer_closed = TRUE;
*out_n = (uintptr_t)nread;
CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu",
(size_t)len, (int)result, nread);
return ret;
}
static int write_cb(void *userdata, const uint8_t *buf, uintptr_t len,
uintptr_t *out_n)
{
2025-03-21 14:43:07 -04:00
const struct io_ctx *io_ctx = userdata;
CURLcode result;
int ret = 0;
size_t nwritten;
result = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
buf, len, FALSE, &nwritten);
if(result) {
nwritten = 0;
if(result == CURLE_AGAIN)
ret = EAGAIN;
else
ret = EINVAL;
}
*out_n = (uintptr_t)nwritten;
CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %d, %zu",
len, (int)result, nwritten);
return ret;
}
static ssize_t tls_recv_more(struct Curl_cfilter *cf,
struct Curl_easy *data, CURLcode *err)
{
const struct ssl_connect_data * const connssl = cf->ctx;
struct rustls_ssl_backend_data * const backend =
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
(struct rustls_ssl_backend_data *)connssl->backend;
struct io_ctx io_ctx;
size_t tls_bytes_read = 0;
rustls_io_result io_error;
rustls_result rresult = 0;
io_ctx.cf = cf;
io_ctx.data = data;
io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx,
&tls_bytes_read);
if(RAW_EAGAIN(io_error)) {
*err = CURLE_AGAIN;
return -1;
}
else if(io_error) {
char buffer[STRERROR_LEN];
failf(data, "reading from socket: %s",
curlx_strerror(io_error, buffer, sizeof(buffer)));
*err = CURLE_RECV_ERROR;
return -1;
}
rresult = rustls_connection_process_new_packets(backend->conn);
if(rresult != RUSTLS_RESULT_OK) {
2025-03-21 14:43:07 -04:00
rustls_failf(data, rresult, "rustls_connection_process_new_packets");
*err = map_error(rresult);
return -1;
}
backend->data_in_pending = TRUE;
*err = CURLE_OK;
return (ssize_t)tls_bytes_read;
}
/*
* Filter receive method implementation. `plainbuf` and `plainlen`
* are always not NULL/0.
*/
static CURLcode cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *plainbuf, size_t plainlen, size_t *pnread)
{
const struct ssl_connect_data * const connssl = cf->ctx;
struct rustls_ssl_backend_data * const backend =
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
CURLcode result = CURLE_OK;
size_t n = 0;
rustls_result rresult = 0;
bool eof = FALSE;
DEBUGASSERT(backend);
*pnread = 0;
rconn = backend->conn;
while(*pnread < plainlen) {
if(!backend->data_in_pending) {
if(tls_recv_more(cf, data, &result) < 0) {
if(result != CURLE_AGAIN) {
goto out;
}
result = CURLE_OK;
break;
}
}
rresult = rustls_connection_read(rconn,
(uint8_t *)plainbuf + *pnread,
plainlen - *pnread,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
backend->data_in_pending = FALSE;
}
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
failf(data, "rustls: peer closed TCP connection "
"without first closing TLS connection");
result = CURLE_RECV_ERROR;
goto out;
}
else if(rresult != RUSTLS_RESULT_OK) {
/* n always equals 0 in this case, do not need to check it */
2025-03-21 14:43:07 -04:00
rustls_failf(data, rresult, "rustls_connection_read");
result = CURLE_RECV_ERROR;
goto out;
}
else if(n == 0) {
/* n == 0 indicates clean EOF, but we may have read some other
plaintext bytes before we reached this. Break out of the loop
so we can figure out whether to return success or EOF. */
eof = TRUE;
break;
}
else {
*pnread += n;
}
}
if(!eof && !*pnread) {
result = CURLE_AGAIN;
}
out:
CURL_TRC_CF(data, cf, "rustls_recv(len=%zu) -> %d, %zu",
plainlen, (int)result, *pnread);
return result;
}
static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
struct rustls_connection *rconn)
{
struct io_ctx io_ctx;
rustls_io_result io_error;
size_t tlswritten = 0;
size_t tlswritten_total = 0;
io_ctx.cf = cf;
io_ctx.data = data;
while(rustls_connection_wants_write(rconn)) {
io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
&tlswritten);
if(RAW_EAGAIN(io_error)) {
CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
tlswritten_total);
return CURLE_AGAIN;
}
else if(io_error) {
char buffer[STRERROR_LEN];
failf(data, "writing to socket: %s",
curlx_strerror(io_error, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
if(tlswritten == 0) {
failf(data, "EOF in swrite");
return CURLE_SEND_ERROR;
}
CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
tlswritten_total += tlswritten;
}
2025-03-21 14:43:07 -04:00
return CURLE_OK;
}
/*
* On each call:
* - Copy `plainlen` bytes into Rustls' plaintext input buffer (if > 0).
* - Fully drain Rustls' plaintext output buffer into the socket until
* we get either an error or EAGAIN/EWOULDBLOCK.
*
* it is okay to call this function with plainbuf == NULL and plainlen == 0.
* In that case, it does not read anything into Rustls' plaintext input buffer.
* It only drains Rustls' plaintext output buffer into the socket.
*/
static CURLcode cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *plainbuf, size_t plainlen,
size_t *pnwritten)
{
const struct ssl_connect_data * const connssl = cf->ctx;
struct rustls_ssl_backend_data * const backend =
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
size_t plainwritten = 0;
const unsigned char *buf = plainbuf;
CURLcode result = CURLE_OK;
size_t blen = plainlen;
DEBUGASSERT(backend);
*pnwritten = 0;
rconn = backend->conn;
DEBUGASSERT(rconn);
CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
/* If a previous send blocked, we already added its plain bytes
* to rustsls and must not do that again. Flush the TLS bytes and,
* if successful, deduct the previous plain bytes from the current
* send. */
if(backend->plain_out_buffered) {
result = cr_flush_out(cf, data, rconn);
CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
backend->plain_out_buffered, (int)result);
if(result)
return result;
if(blen > backend->plain_out_buffered) {
blen -= backend->plain_out_buffered;
buf += backend->plain_out_buffered;
}
else
blen = 0;
*pnwritten += backend->plain_out_buffered;
backend->plain_out_buffered = 0;
}
if(blen > 0) {
2025-03-21 14:43:07 -04:00
rustls_result rresult;
CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen);
rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
2025-03-21 14:43:07 -04:00
rustls_failf(data, rresult, "rustls_connection_write");
result = CURLE_WRITE_ERROR;
goto out;
}
else if(plainwritten == 0) {
failf(data, "rustls_connection_write: EOF");
result = CURLE_WRITE_ERROR;
goto out;
}
}
result = cr_flush_out(cf, data, rconn);
if(result) {
if(result == CURLE_AGAIN) {
/* The TLS bytes may have been partially written, but we fail the
* complete send() and remember how much we already added to Rustls. */
backend->plain_out_buffered = plainwritten;
if(*pnwritten) {
result = CURLE_OK;
}
}
goto out;
}
else
*pnwritten += plainwritten;
out:
CURL_TRC_CF(data, cf, "rustls_send(len=%zu) -> %d, %zu",
plainlen, (int)result, *pnwritten);
return result;
}
/* A server certificate verify callback for Rustls that always returns
RUSTLS_RESULT_OK, or in other words disable certificate verification. */
static uint32_t cr_verify_none(void *userdata,
const rustls_verify_server_cert_params *params)
{
(void)userdata;
(void)params;
return RUSTLS_RESULT_OK;
}
static int read_file_into(const char *filename, struct dynbuf *out)
{
FILE *f = curlx_fopen(filename, FOPEN_READTEXT);
if(!f) {
return 0;
}
for(;;) {
uint8_t buf[256];
2025-03-21 14:43:07 -04:00
const size_t rr = fread(buf, 1, sizeof(buf), f);
if((!rr && !feof(f)) ||
curlx_dyn_addn(out, buf, rr)) {
curlx_fclose(f);
return 0;
}
if(rr < sizeof(buf))
break;
}
return curlx_fclose(f) == 0;
}
static void
cr_get_selected_ciphers(struct Curl_easy *data,
const char *ciphers12,
const char *ciphers13,
const struct rustls_supported_ciphersuite **selected,
size_t *selected_size)
{
2025-03-21 14:43:07 -04:00
const size_t supported_len = *selected_size;
const size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
build: address some `-Weverything` warnings, update picky warnings `-Weverything` is not enabled by curl, and not recommended by LLVM, because it may enable experimental options, and will result in new fallouts after toolchain upgrades. This patch aims to fix/silence as much as possible as found with llvm/clang 21.1.0. It also permanently enables warnings that were fixed in source and deemed manageable in the future. `-Wformat` warnings are addressed separately via #18343. Fix/silence warnings in the source: - typecheck-gcc.h: fix `-Wreserved-identifier`. - lib: silence `-Wcast-function-type-strict`. For llvm 16+ or Apple clang 16+. - asyn-ares: limit `HAPPY_EYEBALLS_DNS_TIMEOUT` to old c-ares versions. - curl_trc: fix `-Wc++-hidden-decl`. - doh: fix `-Wc++-keyword`. - ftp: fix `-Wreserved-identifier`. - ldap: fix `-Wreserved-identifier`. - mqtt: comment unused macro to avoid warning. - multi_ev: drop unused macros to avoid warnings. - setopt: fix useless `break;` after `return;`. - gtls, mbedtls, rustls: silence `-Wconditional-uninitialized`. - socks_sspi, schannel, x509asn1: fix `-Wimplicit-int-enum-cast`. - x509asn1: fix `-Wc++-keyword`. - openssl: scope `OSSL_UI_METHOD_CAST` to avoid unused macro warning. - libssh2, wolfssl: drop unused macros. - curl_ngtcp2, curl_quiche, httpsrr, urlapi: drop/limit unused macros. - tool_getparam: fix useless `break;` after `return;` or `break;`. Not normally enabled because it doesn't work with unity. https://github.com/llvm/llvm-project/issues/71046 - tool_operate: fix `-Wc++-keyword`. - curlinfo: fix a `-Wunsafe-buffer-usage`. - tests: silence `-Wformat-non-iso`. - lib557: fix `-Wreserved-identifier`. - lib1565: silence `-Wconditional-uninitialized`. Enable the above clang warnings permanently in picky mode: - `-Wc++-hidden-decl` - `-Wc++-keyword` (except for Windows, where it collides with `wchar_t`) - `-Wcast-function-type-strict` - `-Wcast-function-type` - `-Wconditional-uninitialized` - `-Wformat-non-iso` (except for clang-cl) - `-Wreserved-identifier` - `-Wtentative-definition-compat` Silence problematic `-Weverything` warnings globally (in picky mode): - `-Wused-but-marked-unused` (88000+ hits) and `-Wdisabled-macro-expansion` (2600+ hits). Triggered by `typecheck-gcc.h` when building with clang 14+. Maybe there exists a way to fix within that header? Ref: https://discourse.llvm.org/t/removing-wused-but-marked-unused/55310 - `-Wunsafe-buffer-usage`. clang 16+. 7000+ hits. May be useful in theory, but such high volume of hits makes it impractical to review and possibly address. Meant for C++. Ref: https://clang.llvm.org/docs/SafeBuffers.html Ref: https://stackoverflow.com/questions/77017567/how-to-fix-code-to-avoid-warning-wunsafe-buffer-usage Ref: https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 Ref: https://github.com/llvm/llvm-project/pull/111624 - `-Wimplicit-void-ptr-cast`. clang 21+. 1700+ hits. C++ warning, deemed pure noise. Ref: https://github.com/curl/curl/issues/18470#issuecomment-3253506266 - `-Wswitch-default` (180+ hits), `-Wswitch-enum` (190+ hits), `-Wcovered-switch-default` (20+ hits). Next to impossible to fix cleanly, esp. when the covered `case` branches depend on compile-time options. - `-Wdocumentation-unknown-command` (8+ hits). Triggered in a few sources. Seems arbitrary and bogus. - `-Wpadded` (550+ hits). - `-Wc++-keyword` on Windows, where it collides with `wchar_t`. (100+ hits) Ref: https://github.com/llvm/llvm-project/issues/155988 - `-Wreserved-macro-identifier`. clang 13+. 5+ hits. Sometimes it's necessary to set external macros that use the reserved namespace. E.g. `_CRT_NONSTDC_NO_DEPRECATE`, `__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__`, `__NO_NET_API`, possibly `_REENTRANT`, and more. It's not worth trying to silence them individually. - `-Wnonportable-system-include-path` with `clang-cl`. It'd be broken by doing what the warning suggests. - `-Wformat-non-iso` for clang-cl. CMake `PICKY_COMPILER=ON` (the default) or `./configure` `--enable-warnings` (not the default) is required to enable these silencing rules. Also: - autotools, cmake: fix Apple clang and mainline llvm version translations. Ref: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - autotools, cmake: enable `-Warray-compare` for clang 20+. Follow-up to 4b7accda5ae3f2e663aa3f3853805241ef87c2fe #17196 - cmake: fix to enable `-Wmissing-variable-declarations` at an earlier clang version. - cmake: update internal logic to handle warning options with `+` in them. - cmake: fix internal logic to match the whole option when looking into `CMAKE_C_FLAGS` for custom-disabled warnings. Follow-up to b85cb8cb4e143d1615d4fcc1ce8f2f7b66453995 #18485 Closes #18477
2025-09-04 11:56:33 +02:00
const struct rustls_supported_ciphersuite *entry = NULL;
const char *ciphers = ciphers12;
size_t count = 0, default13_count = 0, i, j;
const char *ptr, *end;
DEBUGASSERT(default_len <= supported_len);
if(!ciphers13) {
/* Add default TLSv1.3 ciphers to selection */
for(j = 0; j < default_len; j++) {
entry = rustls_default_crypto_provider_ciphersuites_get(j);
if(rustls_supported_ciphersuite_protocol_version(entry) !=
RUSTLS_TLS_VERSION_TLSV1_3)
continue;
selected[count++] = entry;
}
default13_count = count;
if(!ciphers)
ciphers = "";
}
else
ciphers = ciphers13;
add_ciphers:
for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
/* Check if cipher is supported */
if(id) {
for(i = 0; i < supported_len; i++) {
entry = rustls_default_crypto_provider_ciphersuites_get(i);
if(rustls_supported_ciphersuite_get_suite(entry) == id)
break;
}
if(i == supported_len)
id = 0;
}
if(!id) {
if(ptr[0] != '\0')
infof(data, "rustls: unknown cipher in list: \"%.*s\"",
(int)(end - ptr), ptr);
continue;
}
/* No duplicates allowed (so selected cannot overflow) */
for(i = 0; i < count && selected[i] != entry; i++)
;
if(i < count) {
if(i >= default13_count)
infof(data, "rustls: duplicate cipher in list: \"%.*s\"",
(int)(end - ptr), ptr);
continue;
}
selected[count++] = entry;
}
if(ciphers == ciphers13 && ciphers12) {
ciphers = ciphers12;
goto add_ciphers;
}
if(!ciphers12) {
/* Add default TLSv1.2 ciphers to selection */
for(j = 0; j < default_len; j++) {
entry = rustls_default_crypto_provider_ciphersuites_get(j);
if(rustls_supported_ciphersuite_protocol_version(entry) ==
RUSTLS_TLS_VERSION_TLSV1_3)
continue;
/* No duplicates allowed (so selected cannot overflow) */
for(i = 0; i < count && selected[i] != entry; i++)
;
if(i < count)
continue;
selected[count++] = entry;
}
}
*selected_size = count;
}
static void cr_keylog_log_cb(struct rustls_str label,
const uint8_t *client_random,
size_t client_random_len, const uint8_t *secret,
size_t secret_len)
{
char clabel[KEYLOG_LABEL_MAXLEN];
DEBUGASSERT(client_random_len == CLIENT_RANDOM_SIZE);
/* Turning a "rustls_str" into a null delimited "c" string */
curl_msnprintf(clabel, sizeof(clabel), "%.*s", (int)label.len, label.data);
Curl_tls_keylog_write(clabel, client_random, client_random_len,
secret, secret_len);
}
static CURLcode
2025-03-21 14:43:07 -04:00
init_config_builder(struct Curl_easy *data,
const struct ssl_primary_config *conn_config,
struct rustls_client_config_builder **config_builder)
{
2025-03-21 14:43:07 -04:00
const struct rustls_supported_ciphersuite **cipher_suites = NULL;
struct rustls_crypto_provider_builder *custom_provider_builder = NULL;
const struct rustls_crypto_provider *custom_provider = NULL;
2025-03-21 14:43:07 -04:00
uint16_t tls_versions[2] = {
RUSTLS_TLS_VERSION_TLSV1_2,
RUSTLS_TLS_VERSION_TLSV1_3,
2025-03-21 14:43:07 -04:00
};
size_t tls_versions_len = 2;
size_t cipher_suites_len = rustls_default_crypto_provider_ciphersuites_len();
2025-03-21 14:43:07 -04:00
CURLcode result = CURLE_OK;
rustls_result rr;
DEBUGASSERT(conn_config->version != CURL_SSLVERSION_DEFAULT);
2025-03-21 14:43:07 -04:00
switch(conn_config->version) {
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
break;
case CURL_SSLVERSION_TLSv1_3:
tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
tls_versions_len = 1;
break;
default:
failf(data, "rustls: unsupported minimum TLS version value");
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto cleanup;
}
switch(conn_config->version_max) {
case CURL_SSLVERSION_MAX_DEFAULT:
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_TLSv1_3:
break;
case CURL_SSLVERSION_MAX_TLSv1_2:
if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
tls_versions_len = 1;
break;
}
2025-03-21 14:43:07 -04:00
FALLTHROUGH();
case CURL_SSLVERSION_MAX_TLSv1_1:
case CURL_SSLVERSION_MAX_TLSv1_0:
default:
failf(data, "rustls: unsupported maximum TLS version value");
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto cleanup;
}
#ifdef USE_ECH
if(CURLECH_ENABLED(data)) {
tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
tls_versions_len = 1;
infof(data, "rustls: ECH enabled, forcing TLSv1.3");
}
#endif /* USE_ECH */
cipher_suites = curlx_malloc(sizeof(*cipher_suites) * cipher_suites_len);
2025-03-21 14:43:07 -04:00
if(!cipher_suites) {
result = CURLE_OUT_OF_MEMORY;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
cr_get_selected_ciphers(data,
conn_config->cipher_list,
conn_config->cipher_list13,
cipher_suites, &cipher_suites_len);
if(cipher_suites_len == 0) {
failf(data, "rustls: no supported cipher in list");
result = CURLE_SSL_CIPHER;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
rr = rustls_crypto_provider_builder_new_from_default(
&custom_provider_builder);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr,
"failed to create crypto provider builder from default");
2025-03-21 14:43:07 -04:00
result = CURLE_SSL_CIPHER;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
rr =
rustls_crypto_provider_builder_set_cipher_suites(
custom_provider_builder,
cipher_suites,
cipher_suites_len);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr,
"failed to set ciphersuites for crypto provider builder");
2025-03-21 14:43:07 -04:00
result = CURLE_SSL_CIPHER;
goto cleanup;
}
rr = rustls_crypto_provider_builder_build(custom_provider_builder,
&custom_provider);
2025-03-21 14:43:07 -04:00
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to build custom crypto provider");
result = CURLE_SSL_CIPHER;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
rr = rustls_client_config_builder_new_custom(custom_provider,
tls_versions,
tls_versions_len,
config_builder);
2025-03-21 14:43:07 -04:00
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to create client config builder");
result = CURLE_SSL_CIPHER;
goto cleanup;
}
cleanup:
if(cipher_suites) {
build: stop overriding standard memory allocation functions Before this patch curl used the C preprocessor to override standard memory allocation symbols: malloc, calloc, strdup, realloc, free. The goal of these is to replace them with curl's debug wrappers in `CURLDEBUG` builds, another was to replace them with the wrappers calling user-defined allocators in libcurl. This solution needed a bunch of workarounds to avoid breaking external headers: it relied on include order to do the overriding last. For "unity" builds it needed to reset overrides before external includes. Also in test apps, which are always built as single source files. It also needed the `(symbol)` trick to avoid overrides in some places. This would still not fix cases where the standard symbols were macros. It was also fragile and difficult to figure out which was the actual function behind an alloc or free call in a specific piece of code. This in turn caused bugs where the wrong allocator was accidentally called. To avoid these problems, this patch replaces this solution with `curlx_`-prefixed allocator macros, and mapping them _once_ to either the libcurl wrappers, the debug wrappers or the standard ones, matching the rest of the code in libtests. This concludes the long journey to avoid redefining standard functions in the curl codebase. Note: I did not update `packages/OS400/*.c` sources. They did not `#include` `curl_setup.h`, `curl_memory.h` or `memdebug.h`, meaning the overrides were never applied to them. This may or may not have been correct. For now I suppressed the direct use of standard allocators via a local `.checksrc`. Probably they (except for `curlcl.c`) should be updated to include `curl_setup.h` and use the `curlx_` macros. This patch changes mappings in two places: - `lib/curl_threads.c` in libtests: Before this patch it mapped to libcurl allocators. After, it maps to standard allocators, like the rest of libtests code. - `units`: before this patch it mapped to standard allocators. After, it maps to libcurl allocators. Also: - drop all position-dependent `curl_memory.h` and `memdebug.h` includes, and delete the now unnecessary headers. - rename `Curl_tcsdup` macro to `curlx_tcsdup` and define like the other allocators. - map `curlx_strdup()` to `_strdup()` on Windows (was: `strdup()`). To fix warnings silenced via `_CRT_NONSTDC_NO_DEPRECATE`. - multibyte: map `curlx_convert_*()` to `_strdup()` on Windows (was: `strdup()`). - src: do not reuse the `strdup` name for the local replacement. - lib509: call `_strdup()` on Windows (was: `strdup()`). - test1132: delete test obsoleted by this patch. - CHECKSRC.md: update text for `SNPRINTF`. - checksrc: ban standard allocator symbols. Follow-up to b12da22db1f11da51082977dc21a7edee7858911 #18866 Follow-up to db98daab05aec251bcb6615d2d38dfebec291736 #18844 Follow-up to 4deea9396bc7dd25c6362fa746a57bf309c74ada #18814 Follow-up to 9678ff5b1bfea1c847aee4f9edf023e8f01c9293 #18776 Follow-up to 10bac43b873fe45869e15b36aac1c1e5bc89b6e0 #18774 Follow-up to 20142f5d06f7120ba94cbcc25c998e8d81aec85b #18634 Follow-up to bf7375ecc50e857760b0d0a668c436e208a400bd #18503 Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #19626
2025-10-08 02:33:19 +02:00
curlx_free(cipher_suites);
}
2025-03-21 14:43:07 -04:00
if(custom_provider_builder) {
rustls_crypto_provider_builder_free(custom_provider_builder);
}
if(custom_provider) {
rustls_crypto_provider_free(custom_provider);
}
return result;
}
2025-03-21 14:43:07 -04:00
static void
init_config_builder_alpn(struct Curl_easy *data,
const struct ssl_connect_data *connssl,
struct rustls_client_config_builder *config_builder)
{
2025-03-21 14:43:07 -04:00
struct alpn_proto_buf proto;
rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
size_t i;
2025-03-21 14:43:07 -04:00
for(i = 0; i < connssl->alpn->count; ++i) {
alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
alpn[i].len = strlen(connssl->alpn->entries[i]);
}
rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
connssl->alpn->count);
Curl_alpn_to_proto_str(&proto, connssl->alpn);
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
connections: introduce http/3 happy eyeballs New cfilter HTTP-CONNECT for h3/h2/http1.1 eyeballing. - filter is installed when `--http3` in the tool is used (or the equivalent CURLOPT_ done in the library) - starts a QUIC/HTTP/3 connect right away. Should that not succeed after 100ms (subject to change), a parallel attempt is started for HTTP/2 and HTTP/1.1 via TCP - both attempts are subject to IPv6/IPv4 eyeballing, same as happens for other connections - tie timeout to the ip-version HAPPY_EYEBALLS_TIMEOUT - use a `soft` timeout at half the value. When the soft timeout expires, the HTTPS-CONNECT filter checks if the QUIC filter has received any data from the server. If not, it will start the HTTP/2 attempt. HTTP/3(ngtcp2) improvements. - setting call_data in all cfilter calls similar to http/2 and vtls filters for use in callback where no stream data is available. - returning CURLE_PARTIAL_FILE for prematurely terminated transfers - enabling pytest test_05 for h3 - shifting functionality to "connect" UDP sockets from ngtcp2 implementation into the udp socket cfilter. Because unconnected UDP sockets are weird. For example they error when adding to a pollset. HTTP/3(quiche) improvements. - fixed upload bug in quiche implementation, now passes 251 and pytest - error codes on stream RESET - improved debug logs - handling of DRAIN during connect - limiting pending event queue HTTP/2 cfilter improvements. - use LOG_CF macros for dynamic logging in debug build - fix CURLcode on RST streams to be CURLE_PARTIAL_FILE - enable pytest test_05 for h2 - fix upload pytests and improve parallel transfer performance. GOAWAY handling for ngtcp2/quiche - during connect, when the remote server refuses to accept new connections and closes immediately (so the local conn goes into DRAIN phase), the connection is torn down and a another attempt is made after a short grace period. This is the behaviour observed with nghttpx when we tell it to shut down gracefully. Tested in pytest test_03_02. TLS improvements - ALPN selection for SSL/SSL-PROXY filters in one vtls set of functions, replaces copy of logic in all tls backends. - standardized the infof logging of offered ALPNs - ALPN negotiated: have common function for all backends that sets alpn proprty and connection related things based on the negotiated protocol (or lack thereof). - new tests/tests-httpd/scorecard.py for testing h3/h2 protocol implementation. Invoke: python3 tests/tests-httpd/scorecard.py --help for usage. Improvements on gathering connect statistics and socket access. - new CF_CTRL_CONN_REPORT_STATS cfilter control for having cfilters report connection statistics. This is triggered when the connection has completely connected. - new void Curl_pgrsTimeWas(..) method to report a timer update with a timestamp of when it happend. This allows for updating timers "later", e.g. a connect statistic after full connectivity has been reached. - in case of HTTP eyeballing, the previous changes will update statistics only from the filter chain that "won" the eyeballing. - new cfilter query CF_QUERY_SOCKET for retrieving the socket used by a filter chain. Added methods Curl_conn_cf_get_socket() and Curl_conn_get_socket() for convenient use of this query. - Change VTLS backend to query their sub-filters for the socket when checks during the handshake are made. HTTP/3 documentation on how https eyeballing works. TLS improvements - ALPN selection for SSL/SSL-PROXY filters in one vtls set of functions, replaces copy of logic in all tls backends. - standardized the infof logging of offered ALPNs - ALPN negotiated: have common function for all backends that sets alpn proprty and connection related things based on the negotiated protocol (or lack thereof). Scorecard with Caddy. - configure can be run with `--with-test-caddy=path` to specify which caddy to use for testing - tests/tests-httpd/scorecard.py now measures download speeds with caddy pytest improvements - adding Makfile to clean gen dir - adding nghttpx rundir creation on start - checking httpd version 2.4.55 for test_05 cases where it is needed. Skipping with message if too old. - catch exception when checking for caddy existance on system. Closes #10349
2023-02-01 17:13:12 +01:00
static CURLcode init_config_builder_verifier_crl(
2025-03-21 14:43:07 -04:00
struct Curl_easy *data,
const struct ssl_primary_config *conn_config,
struct rustls_web_pki_server_cert_verifier_builder *builder)
{
CURLcode result = CURLE_OK;
struct dynbuf crl_contents;
rustls_result rr;
curlx_dyn_init(&crl_contents, DYN_CRLFILE_SIZE);
2025-03-21 14:43:07 -04:00
if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
failf(data, "rustls: failed to read revocation list file");
result = CURLE_SSL_CRL_BADFILE;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
rr = rustls_web_pki_server_cert_verifier_builder_add_crl(
builder,
curlx_dyn_uptr(&crl_contents),
curlx_dyn_len(&crl_contents));
2025-03-21 14:43:07 -04:00
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to parse revocation list");
result = CURLE_SSL_CRL_BADFILE;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
cleanup:
curlx_dyn_free(&crl_contents);
2025-03-21 14:43:07 -04:00
return result;
}
static CURLcode
init_config_builder_verifier(struct Curl_easy *data,
struct rustls_client_config_builder *builder,
const struct ssl_primary_config *conn_config,
const struct curl_blob *ca_info_blob,
const char * const ssl_cafile)
{
2025-03-21 14:43:07 -04:00
const struct rustls_root_cert_store *roots = NULL;
struct rustls_root_cert_store_builder *roots_builder = NULL;
struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
struct rustls_server_cert_verifier *server_cert_verifier = NULL;
rustls_result rr = RUSTLS_RESULT_OK;
CURLcode result = CURLE_OK;
roots_builder = rustls_root_cert_store_builder_new();
if(ca_info_blob) {
rr = rustls_root_cert_store_builder_add_pem(roots_builder,
ca_info_blob->data,
ca_info_blob->len,
1);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to parse trusted certificates from blob");
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
}
else if(ssl_cafile) {
rr = rustls_root_cert_store_builder_load_roots_from_file(roots_builder,
ssl_cafile,
1);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to load trusted certificates");
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
}
2025-03-21 14:43:07 -04:00
rr = rustls_root_cert_store_builder_build(roots_builder, &roots);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to build trusted root certificate store");
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
2025-03-21 14:43:07 -04:00
}
verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
if(!verifier_builder) {
result = CURLE_OUT_OF_MEMORY;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
if(conn_config->CRLfile) {
result = init_config_builder_verifier_crl(data,
conn_config,
verifier_builder);
if(result) {
2025-03-21 14:43:07 -04:00
goto cleanup;
}
2025-03-21 14:43:07 -04:00
}
rr = rustls_web_pki_server_cert_verifier_builder_build(
verifier_builder, &server_cert_verifier);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to build certificate verifier");
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
2025-03-21 14:43:07 -04:00
rustls_client_config_builder_set_server_verifier(builder,
server_cert_verifier);
cleanup:
if(roots_builder) {
rustls_root_cert_store_builder_free(roots_builder);
}
if(roots) {
rustls_root_cert_store_free(roots);
2025-03-21 14:43:07 -04:00
}
if(verifier_builder) {
rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
}
if(server_cert_verifier) {
rustls_server_cert_verifier_free(server_cert_verifier);
}
2025-03-21 14:43:07 -04:00
return result;
}
static CURLcode init_config_builder_platform_verifier(
struct Curl_easy *data,
struct rustls_client_config_builder *builder)
{
struct rustls_server_cert_verifier *server_cert_verifier = NULL;
CURLcode result = CURLE_OK;
rustls_result rr;
rr = rustls_platform_server_cert_verifier(&server_cert_verifier);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to create platform certificate verifier");
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
rustls_client_config_builder_set_server_verifier(builder,
server_cert_verifier);
cleanup:
if(server_cert_verifier) {
rustls_server_cert_verifier_free(server_cert_verifier);
}
return result;
}
static CURLcode
init_config_builder_keylog(struct Curl_easy *data,
struct rustls_client_config_builder *builder)
{
rustls_result rr;
Curl_tls_keylog_open();
if(!Curl_tls_keylog_enabled()) {
return CURLE_OK;
}
rr = rustls_client_config_builder_set_key_log(builder,
cr_keylog_log_cb,
NULL);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls_client_config_builder_set_key_log");
Curl_tls_keylog_close();
return map_error(rr);
}
return CURLE_OK;
}
static CURLcode
init_config_builder_client_auth(struct Curl_easy *data,
const struct ssl_primary_config *conn_config,
const struct ssl_config_data *ssl_config,
struct rustls_client_config_builder *builder)
{
struct dynbuf cert_contents;
struct dynbuf key_contents;
rustls_result rr;
const struct rustls_certified_key *certified_key = NULL;
CURLcode result = CURLE_OK;
if(conn_config->clientcert && !ssl_config->primary.key) {
failf(data, "rustls: must provide key with certificate '%s'",
conn_config->clientcert);
return CURLE_SSL_CERTPROBLEM;
}
else if(!conn_config->clientcert && ssl_config->primary.key) {
failf(data, "rustls: must provide certificate with key '%s'",
ssl_config->primary.key);
return CURLE_SSL_CERTPROBLEM;
}
curlx_dyn_init(&cert_contents, DYN_CERTFILE_SIZE);
curlx_dyn_init(&key_contents, DYN_KEYFILE_SIZE);
if(!read_file_into(conn_config->clientcert, &cert_contents)) {
failf(data, "rustls: failed to read client certificate file: '%s'",
conn_config->clientcert);
result = CURLE_SSL_CERTPROBLEM;
goto cleanup;
}
if(!read_file_into(ssl_config->primary.key, &key_contents)) {
failf(data, "rustls: failed to read key file: '%s'",
ssl_config->primary.key);
result = CURLE_SSL_CERTPROBLEM;
goto cleanup;
}
rr = rustls_certified_key_build(curlx_dyn_uptr(&cert_contents),
curlx_dyn_len(&cert_contents),
curlx_dyn_uptr(&key_contents),
curlx_dyn_len(&key_contents),
&certified_key);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls: failed to build certified key");
result = CURLE_SSL_CERTPROBLEM;
goto cleanup;
}
rr = rustls_certified_key_keys_match(certified_key);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr,
"rustls: client certificate and keypair files do not match:");
result = CURLE_SSL_CERTPROBLEM;
goto cleanup;
}
rr = rustls_client_config_builder_set_certified_key(builder,
&certified_key,
1);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls: failed to set certified key");
result = CURLE_SSL_CERTPROBLEM;
goto cleanup;
}
cleanup:
curlx_dyn_free(&cert_contents);
curlx_dyn_free(&key_contents);
if(certified_key) {
rustls_certified_key_free(certified_key);
}
return result;
}
#ifdef USE_ECH
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
static bool cr_ech_need_httpsrr(struct Curl_easy *data)
{
if(!CURLECH_ENABLED(data))
return FALSE;
if((data->set.tls_ech == CURLECH_GREASE) ||
CURL_EASY_STR(data, STRING_ECH_CONFIG))
return FALSE;
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
return TRUE;
}
static CURLcode
init_config_builder_ech(struct Curl_easy *data,
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
struct Curl_cfilter *cf,
struct rustls_client_config_builder *builder)
{
const rustls_hpke *hpke = rustls_supported_hpke();
unsigned char *ech_config = NULL;
size_t ech_config_len = 0;
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
rustls_result rr;
if(!hpke) {
failf(data,
"rustls: ECH unavailable, rustls-ffi built without "
"HPKE compatible crypto provider");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
if(CURL_EASY_STR(data, STRING_ECH_PUBLIC)) {
failf(data, "rustls: ECH outername not supported");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
if(data->set.tls_ech == CURLECH_GREASE) {
rr = rustls_client_config_builder_enable_ech_grease(builder, hpke);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls: failed to configure ECH GREASE");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
return CURLE_OK;
}
if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) {
const char *b64 = CURL_EASY_STR(data, STRING_ECH_CONFIG);
size_t decode_result;
if(!b64) {
infof(data, "rustls: ECHConfig from command line empty");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
/* rustls-ffi expects the raw TLS encoded ECHConfigList bytes */
decode_result = curlx_base64_decode(b64, &ech_config, &ech_config_len);
if(decode_result || !ech_config) {
infof(data, "rustls: cannot base64 decode ECHConfig from command line");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
}
else {
const struct ssl_connect_data *connssl = cf->ctx;
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
const struct Curl_https_rrinfo *rinfo =
Curl_conn_dns_get_https(data, cf->sockindex, connssl->peer.origin);
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
if(!rinfo || !rinfo->echconfiglist) {
failf(data, "rustls: ECH requested but no ECHConfig available");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
ech_config = rinfo->echconfiglist;
ech_config_len = rinfo->echconfiglist_len;
}
rr = rustls_client_config_builder_enable_ech(builder,
ech_config,
ech_config_len,
hpke);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls: failed to configure ECH");
result = CURLE_SSL_CONNECT_ERROR;
goto cleanup;
}
cleanup:
/* if we base64 decoded, we can free now */
if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) {
build: stop overriding standard memory allocation functions Before this patch curl used the C preprocessor to override standard memory allocation symbols: malloc, calloc, strdup, realloc, free. The goal of these is to replace them with curl's debug wrappers in `CURLDEBUG` builds, another was to replace them with the wrappers calling user-defined allocators in libcurl. This solution needed a bunch of workarounds to avoid breaking external headers: it relied on include order to do the overriding last. For "unity" builds it needed to reset overrides before external includes. Also in test apps, which are always built as single source files. It also needed the `(symbol)` trick to avoid overrides in some places. This would still not fix cases where the standard symbols were macros. It was also fragile and difficult to figure out which was the actual function behind an alloc or free call in a specific piece of code. This in turn caused bugs where the wrong allocator was accidentally called. To avoid these problems, this patch replaces this solution with `curlx_`-prefixed allocator macros, and mapping them _once_ to either the libcurl wrappers, the debug wrappers or the standard ones, matching the rest of the code in libtests. This concludes the long journey to avoid redefining standard functions in the curl codebase. Note: I did not update `packages/OS400/*.c` sources. They did not `#include` `curl_setup.h`, `curl_memory.h` or `memdebug.h`, meaning the overrides were never applied to them. This may or may not have been correct. For now I suppressed the direct use of standard allocators via a local `.checksrc`. Probably they (except for `curlcl.c`) should be updated to include `curl_setup.h` and use the `curlx_` macros. This patch changes mappings in two places: - `lib/curl_threads.c` in libtests: Before this patch it mapped to libcurl allocators. After, it maps to standard allocators, like the rest of libtests code. - `units`: before this patch it mapped to standard allocators. After, it maps to libcurl allocators. Also: - drop all position-dependent `curl_memory.h` and `memdebug.h` includes, and delete the now unnecessary headers. - rename `Curl_tcsdup` macro to `curlx_tcsdup` and define like the other allocators. - map `curlx_strdup()` to `_strdup()` on Windows (was: `strdup()`). To fix warnings silenced via `_CRT_NONSTDC_NO_DEPRECATE`. - multibyte: map `curlx_convert_*()` to `_strdup()` on Windows (was: `strdup()`). - src: do not reuse the `strdup` name for the local replacement. - lib509: call `_strdup()` on Windows (was: `strdup()`). - test1132: delete test obsoleted by this patch. - CHECKSRC.md: update text for `SNPRINTF`. - checksrc: ban standard allocator symbols. Follow-up to b12da22db1f11da51082977dc21a7edee7858911 #18866 Follow-up to db98daab05aec251bcb6615d2d38dfebec291736 #18844 Follow-up to 4deea9396bc7dd25c6362fa746a57bf309c74ada #18814 Follow-up to 9678ff5b1bfea1c847aee4f9edf023e8f01c9293 #18776 Follow-up to 10bac43b873fe45869e15b36aac1c1e5bc89b6e0 #18774 Follow-up to 20142f5d06f7120ba94cbcc25c998e8d81aec85b #18634 Follow-up to bf7375ecc50e857760b0d0a668c436e208a400bd #18503 Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #19626
2025-10-08 02:33:19 +02:00
curlx_free(ech_config);
}
if(dns) {
Curl_dns_entry_unlink(data, &dns);
}
return result;
}
#endif /* USE_ECH */
static CURLcode cr_init_backend(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct rustls_ssl_backend_data * const backend)
2025-03-21 14:43:07 -04:00
{
const struct ssl_connect_data *connssl = cf->ctx;
const struct ssl_primary_config *conn_config =
Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
2025-03-21 14:43:07 -04:00
struct rustls_connection *rconn = NULL;
struct rustls_client_config_builder *config_builder = NULL;
2025-03-21 14:43:07 -04:00
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
(ca_info_blob ? NULL : conn_config->CAfile);
CURLcode result = CURLE_OK;
rustls_result rr;
DEBUGASSERT(backend);
rconn = backend->conn;
result = init_config_builder(data, conn_config, &config_builder);
if(result != CURLE_OK) {
return result;
}
if(connssl->alpn) {
init_config_builder_alpn(data, connssl, config_builder);
}
if(!conn_config->verifypeer) {
rustls_client_config_builder_dangerous_set_certificate_verifier(
config_builder, cr_verify_none);
}
else if(ssl_config->native_ca_store) {
if(conn_config->CRLfile) {
failf(data, "rustls: CRL file not supported with native CA store; "
"the platform verifier has no CRL attachment API");
rustls_client_config_builder_free(config_builder);
return CURLE_NOT_BUILT_IN;
}
result = init_config_builder_platform_verifier(data, config_builder);
if(result != CURLE_OK) {
rustls_client_config_builder_free(config_builder);
return result;
}
}
2025-03-21 14:43:07 -04:00
else if(ca_info_blob || ssl_cafile) {
result = init_config_builder_verifier(data,
config_builder,
conn_config,
ca_info_blob,
ssl_cafile);
if(result != CURLE_OK) {
rustls_client_config_builder_free(config_builder);
2025-03-21 14:43:07 -04:00
return result;
}
}
if(conn_config->clientcert || ssl_config->primary.key) {
result = init_config_builder_client_auth(data,
conn_config,
ssl_config,
config_builder);
if(result != CURLE_OK) {
rustls_client_config_builder_free(config_builder);
return result;
}
}
#ifdef USE_ECH
if(CURLECH_ENABLED(data)) {
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
result = init_config_builder_ech(data, cf, config_builder);
if((result != CURLE_OK) && (data->set.tls_ech == CURLECH_HARD)) {
rustls_client_config_builder_free(config_builder);
return result;
}
}
#endif /* USE_ECH */
result = init_config_builder_keylog(data, config_builder);
if(result != CURLE_OK) {
rustls_client_config_builder_free(config_builder);
return result;
}
rr = rustls_client_config_builder_build(config_builder, &backend->config);
2025-03-21 14:43:07 -04:00
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "failed to build client config");
return CURLE_SSL_CONNECT_ERROR;
}
DEBUGASSERT(!rconn);
2025-03-21 14:43:07 -04:00
rr = rustls_client_connection_new(backend->config,
connssl->peer.origin->hostname,
2025-03-21 14:43:07 -04:00
&rconn);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls_client_connection_new");
rustls_client_config_free(backend->config);
backend->config = NULL;
return CURLE_COULDNT_CONNECT;
}
DEBUGASSERT(rconn);
rustls_connection_set_userdata(rconn, backend);
backend->conn = rconn;
2025-03-21 14:43:07 -04:00
return result;
}
static void cr_set_negotiated_alpn(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct rustls_connection *rconn)
{
struct ssl_connect_data * const connssl = cf->ctx;
const uint8_t *protocol = NULL;
size_t len = 0;
rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
Curl_alpn_set_negotiated(cf, data, connssl, protocol, len);
}
/* Given an established network connection, do a TLS handshake.
*
* This function sets `*done` to true once the handshake is complete.
* This function never reads the value of `*done*`.
*/
static CURLcode cr_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
bool *done)
{
struct ssl_connect_data * const connssl = cf->ctx;
const struct rustls_ssl_backend_data * const backend =
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
(struct rustls_ssl_backend_data *)connssl->backend;
2025-03-21 14:43:07 -04:00
const struct rustls_connection *rconn = NULL;
CURLcode tmperr = CURLE_OK;
CURLcode result;
bool wants_read;
bool wants_write;
ssize_t nread;
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "cr_connect, state=%d", (int)connssl->state);
*done = FALSE;
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
#ifdef USE_ECH
/* if we do ECH and need the HTTPS-RR information for it,
* we delay the connect until it arrives or DNS resolve fails. */
if(cr_ech_need_httpsrr(data) &&
!Curl_conn_dns_resolved_https(data, cf->sockindex,
connssl->peer.peer)) {
lib: make resolving HTTPS DNS records reliable: - allow to specify when they are wanted on starting a resolve - match dns cache entries accordingly. An entry which never tried to get HTTPS-RRs is no answer for a resolve that wants it. - fix late arrivals of resolve answers to match the "async" records that started them - if it still exists. - provide for multiple "async" resolves in a transfer at the same time. We may need to resolve an IP interface while the main connection resolve has not finished yet. - allow lookup of HTTPS-RR information as soon as it is available, even if A/AAAA queries are still ongoing. For this, the "async" infrastructure is changed: - Defined bits for DNS queries `CURL_DNSQ_A`, `CURL_DNSQ_AAAA` and `CURL_DNSQ_HTTPS`. These replace `ip_version` which says nothing about HTTPS. Use them in dns cache entries for matching. - enhance the `async->id` to be a unique `uint32_t` for resolves inside one multi. This is weak, as the id may wrap around. However it is combined with the `mid` of the easy handle, making collisions highly unlikely. `data->state.async` is only accessed in few places where the mid/async-id match is performed. - vtls: for ECH supporting TLS backends (openssl, rustls, wolfssl), retrieve the HTTPS-RR information from the dns connection filter. Delay the connect if the HTTPS-RR is needed, but has not been resolved yet. The implementation of all this is complete for the threaded resolver. c-ares resolver and DoH do not take advantage of all new async features yet. To be done in separate PRs. Details: c-ares: cleanup settings and initialisation. Any ares channel is only being created on starting a resolve and propagating operations in setopt.c to the channel are not helpful. Changed threaded+ares pollset handling so that they do not overwrite each others `ASYNC_NAME` timeouts. Add trace name 'threads' for tracing thread queue and pool used by threaded resolver. Closes #21175
2026-03-31 11:45:21 +02:00
CURL_TRC_CF(data, cf, "need HTTPS-RR for ECH, delaying connect");
return CURLE_OK;
}
#endif /* USE_ECH */
if(!backend->conn) {
result =
cr_init_backend(cf, data,
(struct rustls_ssl_backend_data *)connssl->backend);
CURL_TRC_CF(data, cf, "cr_connect, init backend -> %d", (int)result);
if(result)
return result;
connssl->state = ssl_connection_negotiating;
}
rconn = backend->conn;
/* Read/write data until the handshake is done or the socket would block. */
for(;;) {
/*
* Connection has been established according to Rustls. Set send/recv
* handlers, and update the state machine.
*/
connssl->io_need = CURL_SSL_IO_NEED_NONE;
if(!rustls_connection_is_handshaking(rconn)) {
/* Rustls claims it is no longer handshaking *before* it has
* send its FINISHED message off. We attempt to let it write
* one more time. Oh my.
*/
size_t nwritten;
cr_set_negotiated_alpn(cf, data, rconn);
tmperr = cr_send(cf, data, NULL, 0, &nwritten);
if(tmperr == CURLE_AGAIN) {
connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
else if(tmperr != CURLE_OK) {
return tmperr;
}
/* REALLY Done with the handshake. */
{
#ifdef CURLVERBOSE
const uint16_t proto = rustls_connection_get_protocol_version(rconn);
const rustls_str ciphersuite_name =
rustls_connection_get_negotiated_ciphersuite_name(rconn);
const rustls_str kex_group_name =
rustls_connection_get_negotiated_key_exchange_group_name(rconn);
const char *ver = "TLS version unknown";
if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
ver = "TLSv1.3";
if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
ver = "TLSv1.2";
#endif
infof(data,
"rustls: handshake complete, %s, ciphersuite: %.*s, "
"key exchange group: %.*s",
ver,
(int) ciphersuite_name.len,
ciphersuite_name.data,
(int) kex_group_name.len,
kex_group_name.data);
}
if(data->set.ssl.certinfo) {
size_t num_certs = 0;
size_t i;
while(rustls_connection_get_peer_certificate(rconn, num_certs)) {
num_certs++;
if(num_certs > MAX_ALLOWED_CERT_AMOUNT) {
failf(data, "%zu certificates is more than allowed (%d)",
num_certs, MAX_ALLOWED_CERT_AMOUNT);
return CURLE_SSL_CONNECT_ERROR;
}
}
result = Curl_ssl_init_certinfo(data, (int)num_certs);
if(result)
return result;
for(i = 0; i < num_certs; i++) {
const rustls_certificate *cert;
const unsigned char *der_data;
size_t der_len;
rustls_result rresult = RUSTLS_RESULT_OK;
cert = rustls_connection_get_peer_certificate(rconn, i);
DEBUGASSERT(cert); /* Should exist since we counted already */
rresult = rustls_certificate_get_der(cert, &der_data, &der_len);
if(rresult != RUSTLS_RESULT_OK) {
char errorbuf[255];
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data,
"Failed getting DER of server certificate #%zu: %.*s", i,
(int)errorlen, errorbuf);
return map_error(rresult);
}
{
const char *beg;
const char *end;
beg = (const char *)der_data;
end = (const char *)(der_data + der_len);
result = Curl_extract_certinfo(data, (int)i, beg, end);
if(result)
return result;
}
}
}
connssl->state = ssl_connection_complete;
*done = TRUE;
return CURLE_OK;
}
connssl->connecting_state = ssl_connect_2;
wants_read = rustls_connection_wants_read(rconn);
wants_write = rustls_connection_wants_write(rconn) ||
backend->plain_out_buffered;
DEBUGASSERT(wants_read || wants_write);
if(wants_write) {
size_t nwritten;
CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
tmperr = cr_send(cf, data, NULL, 0, &nwritten);
if(tmperr == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "writing would block");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
}
else if(tmperr != CURLE_OK) {
return tmperr;
}
}
if(wants_read) {
CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
nread = tls_recv_more(cf, data, &tmperr);
if(nread == 0) {
connssl->peer_closed = TRUE;
failf(data, "TLS connect error: Connection closed abruptly");
return CURLE_SSL_CONNECT_ERROR;
}
if(nread < 0) {
if(tmperr == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "reading would block");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
}
else if(tmperr == CURLE_RECV_ERROR) {
return CURLE_SSL_CONNECT_ERROR;
}
else {
return tmperr;
}
}
}
}
/* We should never fall through the loop. We should return either because
the handshake is done or because we cannot read/write without blocking. */
DEBUGASSERT(FALSE);
}
static void *cr_get_internals(struct ssl_connect_data *connssl, CURLINFO info)
{
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
(void)info;
DEBUGASSERT(backend);
return backend->conn;
}
static CURLcode cr_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data,
const bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
CURLcode result = CURLE_OK;
build: address some `-Weverything` warnings, update picky warnings `-Weverything` is not enabled by curl, and not recommended by LLVM, because it may enable experimental options, and will result in new fallouts after toolchain upgrades. This patch aims to fix/silence as much as possible as found with llvm/clang 21.1.0. It also permanently enables warnings that were fixed in source and deemed manageable in the future. `-Wformat` warnings are addressed separately via #18343. Fix/silence warnings in the source: - typecheck-gcc.h: fix `-Wreserved-identifier`. - lib: silence `-Wcast-function-type-strict`. For llvm 16+ or Apple clang 16+. - asyn-ares: limit `HAPPY_EYEBALLS_DNS_TIMEOUT` to old c-ares versions. - curl_trc: fix `-Wc++-hidden-decl`. - doh: fix `-Wc++-keyword`. - ftp: fix `-Wreserved-identifier`. - ldap: fix `-Wreserved-identifier`. - mqtt: comment unused macro to avoid warning. - multi_ev: drop unused macros to avoid warnings. - setopt: fix useless `break;` after `return;`. - gtls, mbedtls, rustls: silence `-Wconditional-uninitialized`. - socks_sspi, schannel, x509asn1: fix `-Wimplicit-int-enum-cast`. - x509asn1: fix `-Wc++-keyword`. - openssl: scope `OSSL_UI_METHOD_CAST` to avoid unused macro warning. - libssh2, wolfssl: drop unused macros. - curl_ngtcp2, curl_quiche, httpsrr, urlapi: drop/limit unused macros. - tool_getparam: fix useless `break;` after `return;` or `break;`. Not normally enabled because it doesn't work with unity. https://github.com/llvm/llvm-project/issues/71046 - tool_operate: fix `-Wc++-keyword`. - curlinfo: fix a `-Wunsafe-buffer-usage`. - tests: silence `-Wformat-non-iso`. - lib557: fix `-Wreserved-identifier`. - lib1565: silence `-Wconditional-uninitialized`. Enable the above clang warnings permanently in picky mode: - `-Wc++-hidden-decl` - `-Wc++-keyword` (except for Windows, where it collides with `wchar_t`) - `-Wcast-function-type-strict` - `-Wcast-function-type` - `-Wconditional-uninitialized` - `-Wformat-non-iso` (except for clang-cl) - `-Wreserved-identifier` - `-Wtentative-definition-compat` Silence problematic `-Weverything` warnings globally (in picky mode): - `-Wused-but-marked-unused` (88000+ hits) and `-Wdisabled-macro-expansion` (2600+ hits). Triggered by `typecheck-gcc.h` when building with clang 14+. Maybe there exists a way to fix within that header? Ref: https://discourse.llvm.org/t/removing-wused-but-marked-unused/55310 - `-Wunsafe-buffer-usage`. clang 16+. 7000+ hits. May be useful in theory, but such high volume of hits makes it impractical to review and possibly address. Meant for C++. Ref: https://clang.llvm.org/docs/SafeBuffers.html Ref: https://stackoverflow.com/questions/77017567/how-to-fix-code-to-avoid-warning-wunsafe-buffer-usage Ref: https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 Ref: https://github.com/llvm/llvm-project/pull/111624 - `-Wimplicit-void-ptr-cast`. clang 21+. 1700+ hits. C++ warning, deemed pure noise. Ref: https://github.com/curl/curl/issues/18470#issuecomment-3253506266 - `-Wswitch-default` (180+ hits), `-Wswitch-enum` (190+ hits), `-Wcovered-switch-default` (20+ hits). Next to impossible to fix cleanly, esp. when the covered `case` branches depend on compile-time options. - `-Wdocumentation-unknown-command` (8+ hits). Triggered in a few sources. Seems arbitrary and bogus. - `-Wpadded` (550+ hits). - `-Wc++-keyword` on Windows, where it collides with `wchar_t`. (100+ hits) Ref: https://github.com/llvm/llvm-project/issues/155988 - `-Wreserved-macro-identifier`. clang 13+. 5+ hits. Sometimes it's necessary to set external macros that use the reserved namespace. E.g. `_CRT_NONSTDC_NO_DEPRECATE`, `__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__`, `__NO_NET_API`, possibly `_REENTRANT`, and more. It's not worth trying to silence them individually. - `-Wnonportable-system-include-path` with `clang-cl`. It'd be broken by doing what the warning suggests. - `-Wformat-non-iso` for clang-cl. CMake `PICKY_COMPILER=ON` (the default) or `./configure` `--enable-warnings` (not the default) is required to enable these silencing rules. Also: - autotools, cmake: fix Apple clang and mainline llvm version translations. Ref: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - autotools, cmake: enable `-Warray-compare` for clang 20+. Follow-up to 4b7accda5ae3f2e663aa3f3853805241ef87c2fe #17196 - cmake: fix to enable `-Wmissing-variable-declarations` at an earlier clang version. - cmake: update internal logic to handle warning options with `+` in them. - cmake: fix internal logic to match the whole option when looking into `CMAKE_C_FLAGS` for custom-disabled warnings. Follow-up to b85cb8cb4e143d1615d4fcc1ce8f2f7b66453995 #18485 Closes #18477
2025-09-04 11:56:33 +02:00
size_t i, nread = 0, nwritten;
DEBUGASSERT(backend);
lib: graceful connection shutdown When libcurl discards a connection there are two phases this may go through: "shutdown" and "closing". If a connection is aborted, the shutdown phase is skipped and it is closed right away. The connection filters attached to the connection implement the phases in their `do_shutdown()` and `do_close()` callbacks. Filters carry now a `shutdown` flags next to `connected` to keep track of the shutdown operation. Filters are shut down from top to bottom. If a filter is not connected, its shutdown is skipped. Notable filters that *do* something during shutdown are HTTP/2 and TLS. HTTP/2 sends the GOAWAY frame. TLS sends its close notify and expects to receive a close notify from the server. As sends and receives may EAGAIN on the network, a shutdown is often not successful right away and needs to poll the connection's socket(s). To facilitate this, such connections are placed on a new shutdown list inside the connection cache. Since managing this list requires the cooperation of a multi handle, only the connection cache belonging to a multi handle is used. If a connection was in another cache when being discarded, it is removed there and added to the multi's cache. If no multi handle is available at that time, the connection is shutdown and closed in a one-time, best-effort attempt. When a multi handle is destroyed, all connection still on the shutdown list are discarded with a final shutdown attempt and close. In curl debug builds, the environment variable `CURL_GRACEFUL_SHUTDOWN` can be set to make this graceful with a timeout in milliseconds given by the variable. The shutdown list is limited to the max number of connections configured for a multi cache. Set via CURLMOPT_MAX_TOTAL_CONNECTIONS. When the limit is reached, the oldest connection on the shutdown list is discarded. - In multi_wait() and multi_waitfds(), collect all connection caches involved (each transfer might carry its own) into a temporary list. Let each connection cache on the list contribute sockets and POLLIN/OUT events it's connections are waiting for. - in multi_perform() collect the connection caches the same way and let them peform their maintenance. This will make another non-blocking attempt to shutdown all connections on its shutdown list. - for event based multis (multi->socket_cb set), add the sockets and their poll events via the callback. When `multi_socket()` is invoked for a socket not known by an active transfer, forward this to the multi's cache for processing. On closing a connection, remove its socket(s) via the callback. TLS connection filters MUST NOT send close nofity messages in their `do_close()` implementation. The reason is that a TLS close notify signals a success. When a connection is aborted and skips its shutdown phase, the server needs to see a missing close notify to detect something has gone wrong. A graceful shutdown of FTP's data connection is performed implicitly before regarding the upload/download as complete and continuing on the control connection. For FTP without TLS, there is just the socket close happening. But with TLS, the sent/received close notify signals that the transfer is complete and healthy. Servers like `vsftpd` verify that and reject uploads without a TLS close notify. - added test_19_* for shutdown related tests - test_19_01 and test_19_02 test for TCP RST packets which happen without a graceful shutdown and should no longer appear otherwise. - add test_19_03 for handling shutdowns by the server - add test_19_04 for handling shutdowns by curl - add test_19_05 for event based shutdowny by server - add test_30_06/07 and test_31_06/07 for shutdown checks on FTP up- and downloads. Closes #13976
2024-06-19 12:40:06 +02:00
if(!backend->conn || cf->shutdown) {
*done = TRUE;
goto out;
}
connssl->io_need = CURL_SSL_IO_NEED_NONE;
*done = FALSE;
if(!backend->sent_shutdown) {
/* do this only once */
backend->sent_shutdown = TRUE;
if(send_shutdown) {
rustls_connection_send_close_notify(backend->conn);
}
}
result = cr_send(cf, data, NULL, 0, &nwritten);
if(result) {
if(result == CURLE_AGAIN) {
connssl->io_need = CURL_SSL_IO_NEED_SEND;
result = CURLE_OK;
goto out;
}
DEBUGASSERT(result);
CURL_TRC_CF(data, cf, "shutdown send failed: %d", (int)result);
goto out;
}
for(i = 0; i < 10; ++i) {
2025-03-21 14:43:07 -04:00
char buf[1024];
result = cr_recv(cf, data, buf, (int)sizeof(buf), &nread);
if(result)
break;
}
if(result == CURLE_AGAIN) {
connssl->io_need = CURL_SSL_IO_NEED_RECV;
result = CURLE_OK;
}
else if(result) {
DEBUGASSERT(result);
CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)result);
}
else if(nread == 0) {
/* We got the close notify alert and are done. */
*done = TRUE;
}
out:
lib: graceful connection shutdown When libcurl discards a connection there are two phases this may go through: "shutdown" and "closing". If a connection is aborted, the shutdown phase is skipped and it is closed right away. The connection filters attached to the connection implement the phases in their `do_shutdown()` and `do_close()` callbacks. Filters carry now a `shutdown` flags next to `connected` to keep track of the shutdown operation. Filters are shut down from top to bottom. If a filter is not connected, its shutdown is skipped. Notable filters that *do* something during shutdown are HTTP/2 and TLS. HTTP/2 sends the GOAWAY frame. TLS sends its close notify and expects to receive a close notify from the server. As sends and receives may EAGAIN on the network, a shutdown is often not successful right away and needs to poll the connection's socket(s). To facilitate this, such connections are placed on a new shutdown list inside the connection cache. Since managing this list requires the cooperation of a multi handle, only the connection cache belonging to a multi handle is used. If a connection was in another cache when being discarded, it is removed there and added to the multi's cache. If no multi handle is available at that time, the connection is shutdown and closed in a one-time, best-effort attempt. When a multi handle is destroyed, all connection still on the shutdown list are discarded with a final shutdown attempt and close. In curl debug builds, the environment variable `CURL_GRACEFUL_SHUTDOWN` can be set to make this graceful with a timeout in milliseconds given by the variable. The shutdown list is limited to the max number of connections configured for a multi cache. Set via CURLMOPT_MAX_TOTAL_CONNECTIONS. When the limit is reached, the oldest connection on the shutdown list is discarded. - In multi_wait() and multi_waitfds(), collect all connection caches involved (each transfer might carry its own) into a temporary list. Let each connection cache on the list contribute sockets and POLLIN/OUT events it's connections are waiting for. - in multi_perform() collect the connection caches the same way and let them peform their maintenance. This will make another non-blocking attempt to shutdown all connections on its shutdown list. - for event based multis (multi->socket_cb set), add the sockets and their poll events via the callback. When `multi_socket()` is invoked for a socket not known by an active transfer, forward this to the multi's cache for processing. On closing a connection, remove its socket(s) via the callback. TLS connection filters MUST NOT send close nofity messages in their `do_close()` implementation. The reason is that a TLS close notify signals a success. When a connection is aborted and skips its shutdown phase, the server needs to see a missing close notify to detect something has gone wrong. A graceful shutdown of FTP's data connection is performed implicitly before regarding the upload/download as complete and continuing on the control connection. For FTP without TLS, there is just the socket close happening. But with TLS, the sent/received close notify signals that the transfer is complete and healthy. Servers like `vsftpd` verify that and reject uploads without a TLS close notify. - added test_19_* for shutdown related tests - test_19_01 and test_19_02 test for TCP RST packets which happen without a graceful shutdown and should no longer appear otherwise. - add test_19_03 for handling shutdowns by the server - add test_19_04 for handling shutdowns by curl - add test_19_05 for event based shutdowny by server - add test_30_06/07 and test_31_06/07 for shutdown checks on FTP up- and downloads. Closes #13976
2024-06-19 12:40:06 +02:00
cf->shutdown = (result || *done);
return result;
}
static void cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
2025-03-21 14:43:07 -04:00
const struct ssl_connect_data *connssl = cf->ctx;
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
lib: graceful connection shutdown When libcurl discards a connection there are two phases this may go through: "shutdown" and "closing". If a connection is aborted, the shutdown phase is skipped and it is closed right away. The connection filters attached to the connection implement the phases in their `do_shutdown()` and `do_close()` callbacks. Filters carry now a `shutdown` flags next to `connected` to keep track of the shutdown operation. Filters are shut down from top to bottom. If a filter is not connected, its shutdown is skipped. Notable filters that *do* something during shutdown are HTTP/2 and TLS. HTTP/2 sends the GOAWAY frame. TLS sends its close notify and expects to receive a close notify from the server. As sends and receives may EAGAIN on the network, a shutdown is often not successful right away and needs to poll the connection's socket(s). To facilitate this, such connections are placed on a new shutdown list inside the connection cache. Since managing this list requires the cooperation of a multi handle, only the connection cache belonging to a multi handle is used. If a connection was in another cache when being discarded, it is removed there and added to the multi's cache. If no multi handle is available at that time, the connection is shutdown and closed in a one-time, best-effort attempt. When a multi handle is destroyed, all connection still on the shutdown list are discarded with a final shutdown attempt and close. In curl debug builds, the environment variable `CURL_GRACEFUL_SHUTDOWN` can be set to make this graceful with a timeout in milliseconds given by the variable. The shutdown list is limited to the max number of connections configured for a multi cache. Set via CURLMOPT_MAX_TOTAL_CONNECTIONS. When the limit is reached, the oldest connection on the shutdown list is discarded. - In multi_wait() and multi_waitfds(), collect all connection caches involved (each transfer might carry its own) into a temporary list. Let each connection cache on the list contribute sockets and POLLIN/OUT events it's connections are waiting for. - in multi_perform() collect the connection caches the same way and let them peform their maintenance. This will make another non-blocking attempt to shutdown all connections on its shutdown list. - for event based multis (multi->socket_cb set), add the sockets and their poll events via the callback. When `multi_socket()` is invoked for a socket not known by an active transfer, forward this to the multi's cache for processing. On closing a connection, remove its socket(s) via the callback. TLS connection filters MUST NOT send close nofity messages in their `do_close()` implementation. The reason is that a TLS close notify signals a success. When a connection is aborted and skips its shutdown phase, the server needs to see a missing close notify to detect something has gone wrong. A graceful shutdown of FTP's data connection is performed implicitly before regarding the upload/download as complete and continuing on the control connection. For FTP without TLS, there is just the socket close happening. But with TLS, the sent/received close notify signals that the transfer is complete and healthy. Servers like `vsftpd` verify that and reject uploads without a TLS close notify. - added test_19_* for shutdown related tests - test_19_01 and test_19_02 test for TCP RST packets which happen without a graceful shutdown and should no longer appear otherwise. - add test_19_03 for handling shutdowns by the server - add test_19_04 for handling shutdowns by curl - add test_19_05 for event based shutdowny by server - add test_30_06/07 and test_31_06/07 for shutdown checks on FTP up- and downloads. Closes #13976
2024-06-19 12:40:06 +02:00
(void)data;
DEBUGASSERT(backend);
if(backend->conn) {
rustls_connection_free(backend->conn);
backend->conn = NULL;
}
if(backend->config) {
rustls_client_config_free(backend->config);
backend->config = NULL;
}
}
static size_t cr_version(char *buffer, size_t size)
{
2025-03-21 14:43:07 -04:00
const struct rustls_str ver = rustls_version();
return curl_msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
}
static CURLcode cr_random(struct Curl_easy *data, unsigned char *entropy,
size_t length)
{
rustls_result rresult = 0;
(void)data;
rresult = rustls_default_crypto_provider_random(entropy, length);
return map_error(rresult);
}
static void cr_cleanup(void)
{
Curl_tls_keylog_close();
}
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
SSLSUPP_HTTPS_PROXY |
SSLSUPP_CIPHER_LIST |
SSLSUPP_TLS13_CIPHERSUITES |
SSLSUPP_CERTINFO |
SSLSUPP_ECH |
SSLSUPP_CRLFILE,
cmake: add support for "unity" builds Aka "jumbo" or "amalgamation" builds. It means to compile all sources per target as a single C source. This is experimental. You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. It requires CMake 3.16 or newer. It makes builds (much) faster, allows for better optimizations and tends to promote less ambiguous code. Also add a new AppVeyor CI job and convert an existing one to use "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. Fix related issues: - add missing include guard to `easy_lock.h`. - rename static variables and functions (and a macro) with names reused across sources, or shadowed by local variables. - add an `#undef` after use. - add a missing `#undef` before use. - move internal definitions from `ftp.h` to `ftp.c`. - `curl_memory.h` fixes to make it work when included repeatedly. - stop building/linking curlx bits twice for a static-mode curl tool. These caused doubly defined symbols in unity builds. - silence missing extern declarations compiler warning for ` _CRT_glob`. - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - fix colliding static symbols in debug mode: `debugtime()` and `statename`. - rename `ssl_backend_data` structure to unique names for each TLS-backend, along with the `ssl_connect_data` struct member referencing them. This required adding casts for each access. - add workaround for missing `[P]UNICODE_STRING` types in certain Windows builds when compiling `lib/ldap.c`. To support "unity" builds, we had to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows `schannel.h` option) _globally_. This caused an indirect inclusion of Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled as well. This requires `[P]UNICODE_STRING` types, which is apperantly not defined automatically (as seen with both MSVS and mingw-w64). This patch includes `<subauth.h>` to fix it. Ref: https://github.com/curl/curl/runs/13987772013 Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&view=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - tweak unity builds to compile `lib/memdebug.c` separately in memory trace builds to avoid PP confusion. - force-disable unity for test programs. - do not compile and link libcurl sources to libtests _twice_ when libcurl is built in static mode. KNOWN ISSUES: - running tests with unity builds may fail in cases. - some build configurations/env may not compile in unity mode. E.g.: https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfuauwl8q#L250 Ref: https://github.com/libssh2/libssh2/issues/1034 Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html Ref: https://en.wikipedia.org/wiki/Unity_build Closes #11095
2023-05-09 10:10:40 +00:00
sizeof(struct rustls_ssl_backend_data),
NULL, /* init */
cr_cleanup, /* cleanup */
cr_version, /* version */
cr_shutdown, /* shutdown */
cr_data_pending, /* data_pending */
cr_random, /* random */
NULL, /* cert_status_request */
cr_connect, /* connect */
Curl_ssl_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
NULL, /* close_all */
NULL, /* set_engine */
NULL, /* set_engine_default */
NULL, /* engines_list */
NULL, /* sha256sum */
cr_recv, /* recv decrypted data */
cr_send, /* send data to encrypt */
NULL, /* get_channel_binding */
};
#endif /* USE_RUSTLS */