Stefan Eissing [Fri, 5 Jun 2026 06:34:46 +0000 (08:34 +0200)]
quic: count zero length packets against max
With a flood of zero lenght UDP packets to curl, the receive loop might
run longer than intended to. Count such packets against the max to
terminate the loop as intended.
URL: https://hackerone.com/reports/3783438 Reported-by: vectorqueue on hackerone
Closes #21869
Viktor Szakats [Tue, 2 Jun 2026 13:33:14 +0000 (15:33 +0200)]
gtls: minor fixes and improvements
- fix GnuTLS function name reference in `Curl_gtls_shared_creds_create()`
error message.
Spotted by GitHub Code Quality.
- unfold a line.
- in `Curl_gtls_verifyserver()`:
- report the failure of `gnutls_x509_crt_import()`.
Spotted by GitHub Code Quality.
- fix a minor inconsistency in error strings.
- drop redundant NULL checks for `config->issuercert`.
Joshua Rogers [Tue, 19 May 2026 13:54:30 +0000 (15:54 +0200)]
gtls: verify OCSP response signature in gtls_verify_ocsp_status
Since aeb1a281ca ("gtls: fix OCSP stapling management"), the function
parses the stapled OCSP response and reads the certificate status via
gnutls_ocsp_resp_get_single(), but never calls gnutls_ocsp_resp_verify()
or gnutls_ocsp_resp_verify_direct(). A response with a forged or
corrupted signature is accepted without question.
Fix by calling gnutls_ocsp_resp_verify() against the trust list obtained
from the session credentials immediately after gnutls_ocsp_resp_import().
This handles both directly-signed responses and delegated OCSP responders
without requiring the issuer certificate to be present in the peer chain.
The missing check only affects the CURLOPT_SSL_VERIFYSTATUS code path
when CURLOPT_SSL_VERIFYPEER is disabled. With peer verification enabled,
gnutls_certificate_verify_peers2() independently catches the invalid
response via GNUTLS_CERT_INVALID_OCSP_STATUS before
gtls_verify_ocsp_status() is reached. As a result, no attack is possible
that is not already trivially achievable without OCSP stapling when peer
verification is off. This is a correctness and consistency fix, not a
security vulnerability.
Joshua Rogers [Tue, 19 May 2026 22:37:27 +0000 (00:37 +0200)]
telnet: honor CURLOPT_TIMEOUT in send_telnet_data()
The poll-before-write loop used -1 (infinite) as the Curl_poll timeout,
so a peer that stops reading could stall the transfer indefinitely,
bypassing CURLOPT_TIMEOUT. Use Curl_timeleft_ms() instead and return
CURLE_OPERATION_TIMEDOUT when the deadline is reached or exceeded.
Viktor Szakats [Sun, 31 May 2026 23:29:14 +0000 (01:29 +0200)]
units: drop redundant pointer check and workaround
All users of the `verify_memory()` macro used a fixed-length buffer for
the test output, which then needed a workaround to silence GCC
`-Waddress` warnings.
```
tests/unit/unit1615.c: In function 'test_unit1615':
tests/libtest/unitcheck.h:51:8: error: the address of 'output_buf' will always evaluate as 'true' [-Werror=address]
51 | if((dynamic) && memcmp(dynamic, check, len)) { \
| ^
tests/unit/unit1615.c:114:3: note: in expansion of macro 'verify_memory'
114 | verify_memory(output_buf, precomp_hash1, CURL_SHA512_256_DIGEST_LENGTH);
| ^~~~~~~~~~~~~
```
Drop redundant address check and the workarounds with it.
Viktor Szakats [Thu, 28 May 2026 21:50:52 +0000 (23:50 +0200)]
tidy-up: miscellaneous
- drop more uses of the word "just". (not enforced here)
- drop some uses of the "will" word.
- "then" -> "than".
- tests/http/testenv/curl.py: fix copy-paste typo in error message.
- pytest: replace `shutdownh` with `shutdown` in test names.
Spotted by GitHub Code Quality.
- comment typos.
- whitespace and newlines fixes.
Stefan Eissing [Tue, 26 May 2026 13:01:09 +0000 (15:01 +0200)]
data creds: detect change
Reshuffle code a little to detect when the transfer's credentials
actually change. Otherwise, leave the existing creds in place.
This gives the precise location where we may want to reset other
states that become invalid with change credentials. Also, by
keeping a creds instance as long as it is valid, we can associate
meta data with it.
Viktor Szakats [Sun, 31 May 2026 18:44:57 +0000 (20:44 +0200)]
cmake: add basic way to select pytests to run
Not documented and experimental, example:
`-D_CURL_PYTEST=/test_60_h3_proxy.py`
Ideally, this should be an env like `TFLAGS` and it should allow
selecting any test ID or a group of them, but so far could not figure
out how even a basic env could work.
Viktor Szakats [Sat, 30 May 2026 08:53:21 +0000 (10:53 +0200)]
pytest: fixes and tidy-ups to h3-proxy tests
- merge tests into a single class.
For shorter names, to fix sort order by test number, and to align with
other tests.
- fix preconditions to make `test_60_04_guard_proxy_http3_unsupported`
actually run.
- replace local precondition with constant of the same effect.
- drop redundant non-`ngtcp2` requirement for
`test_60_04_guard_proxy_http3_unsupported`.
(seemed relevant for no longer supported openssl-quic builds.)
- drop unused `NGTCP2_ONLY_MSG` constant.
Follow-up to e4139a73c82d2035142f5ae36196adb4e9831dae #21798
- avoid creating unnecessary test data blobs, and minimize their scopes.
Stefan Eissing [Wed, 20 May 2026 11:25:49 +0000 (13:25 +0200)]
vtls_config: adjust to origin
When a transfer goes against another origin than the initial one, do not
add the following to the ssl configuration: client cert, client key, srp
user/pass, pinned key.
Stefan Eissing [Tue, 19 May 2026 08:57:53 +0000 (10:57 +0200)]
url: connection reuse fixes for starttls
Add test_31_13 to check connection reuse on mixed --ssl-reqd setting.
For that add debug env var CURL_DBG_NO_USE_SSL_ON_FIRST to disable
--ssl-reqd for the first url. Check that the connection without SSL
from the first url is not reused on the second URL that requires it.
Tweak special ftp: protocol check to fail a DEBUGASSERT on mismatched
`use_ssl` settings as that should have been caught before in the
connection reuse matching (imap/smtp etc. do not have this extra check
and rely on the general part doing its job).
Viktor Szakats [Thu, 28 May 2026 20:22:32 +0000 (22:22 +0200)]
h3-proxy: fix callback return values, and a typo in tests
- replace literal -1 with `NGHTTP3_ERR_CALLBACK_FAILURE` in nghttp3
callback.
- replace `NGHTTP3_ERR_CALLBACK_FAILURE` with
`NGTCP2_ERR_CALLBACK_FAILURE` in ngtcp2 callbacks.
- test_60_h3_proxy: fix non-critical typo in symbol.
Stefan Eissing [Wed, 27 May 2026 14:50:18 +0000 (16:50 +0200)]
h3-proxy: fixes around H3 proxy
code:
- less exception handling in existing code
- true ip happy eyeballing
- enable certificate verification
- cf-h2-proxy: abort connection when server closed connection
tests:
- remove all --insecure and --proxy-insecure args
- make session reuse test_60_12 a working one
- resolve port conflicts between h2o and nghttpx
- use proxy args better
- make test_60_06 run shorter
- kill h2o at the end of tests, normal stop takes too long
Viktor Szakats [Wed, 27 May 2026 21:56:50 +0000 (23:56 +0200)]
GHA: enable H3 proxy in CI, also enable h2o tests on Linux
Also:
- GHA/http3-linux: enable deprecated APIs in openssl-prev local
OpenSSL builds. Required by h2o and its vendored dependencies.
Tried OpenSSL 4, LibreSSL 4.x, BoringSSL: all failed at one point.
- GHA/http3-linux: build h2o from source.
libuv1-dev may not be stricly required.
Tried installing libwslay-dev, but it wasn't recognized.
Also disable building h2o libs for a much smaller dist directory and
slightly faster build.
Sadly, h2o is not versioned, so I pinned to the current latest commit
at the master branch. It advertises itself as 2.3.0-DEV in pytest.
- drop redundant `libnghttp3` installs. Remains of openssl-quic builds.
Follow-up to 6aaac9dd388a64d0f511544496608693e1105d13 #20226
Note GHA/macos pytests may or not not be stable with the H3 proxy tests.
Aritra Basu [Thu, 28 May 2026 00:35:44 +0000 (20:35 -0400)]
tests/http: fix HTTP/3 proxy pytest failures with h2o
Fix pytest failures in HTTP/3 proxy tests when h2o is not installed,
misconfigured, or fails to start at runtime.
This prevents:
- FileNotFoundError when h2o document root does not exist
- Fixture setup errors when h2o is configured but cannot start
- Unused test data file creation when h2o is absent or broken
- CI aborts on systems where h2o exists but is not runnable
ambikeesshh [Fri, 22 May 2026 18:57:18 +0000 (00:27 +0530)]
cf-socket: set scope_id for IPv6 link-local addresses
When connecting to an mDNS hostname that resolves to an IPv6 link-local
address, connect() fails with EINVAL because sin6_scope_id is 0. This is
a regression since 8.20.0 where the threaded resolver started splitting
A and AAAA queries into separate getaddrinfo calls. The AAAA-only call
with PF_INET6 may not set scope_id on systems where the same call with
PF_UNSPEC did.
When the resolver does not provide scope_id for a link-local address,
try to determine it from the system's network interfaces using
getifaddrs(). Also add scope_id to verbose connect output so the value
can be seen in curl -v logs.
Built and tested locally on Linux. checksrc passes.
Viktor Szakats [Wed, 27 May 2026 20:40:50 +0000 (22:40 +0200)]
pytest: re-enable test test_05_01 and test_05_02 for quiche 0.29.0+
The upstream issue seems to have been fixed or mitigated in quiche
v0.29.0. Though the original upstream report and patch remain open at
the time of writing this.
Viktor Szakats [Wed, 27 May 2026 16:06:51 +0000 (18:06 +0200)]
lib1560: fix to propagate failure from `get_nothing()`
Also:
- check `curl_url()` for NULL where missing.
- free memory `curl_url_get()` return pointer where missing.
- propagate `curl_url_set()` errors in `clear_url()`, where missing.
- add missing NULL-check before `strcmp()` in `clear_url()`.
Viktor Szakats [Wed, 27 May 2026 08:21:24 +0000 (10:21 +0200)]
curl_sha512_256: fix result code on error
Replace result code `CURLE_SSL_CIPHER` with
`CURLE_BAD_FUNCTION_ARGUMENT` in case of a low-level digest function
fails. Functionality is related to vauth, not SSL, and the operation is
a digest, not a cipher.
Viktor Szakats [Wed, 20 May 2026 10:20:10 +0000 (12:20 +0200)]
tidy-up: miscellaneous
- H3 proxy: re-sync code with original source `curl_ngtcp2.c` to reduce
differences, and to apply missed minor fixes. Also apply clang-format.
Drop redundant `#undef`s, casts, `#endif` comments, includes, drop
intermediate variables, sync include and macro order.
Follow-up to e78b1b3eccfa6a2e367a1225ea1b66dafcdac3c4 #21153
- INSTALL-CMAKE.md: move `CURL_ENABLE_SMB` to the enable section.
- tests/http/env: rename `tcpdmp` to `tcpdump` to match object variable.
- mbedtls: drop incorrect `mbedTLS 4+` comments.
(features are also supported by 3+, meaning it's always supported.)
- lib1648: rename a variable to match purpose.
- CIPHERS.md: alpha-sort link list.
- replace rare `X''` hex markup with `0x`.
- `IP v4/6` -> `IPv4/6`.
- 'version X.Y' -> 'vX.Y', where sensible.
- 'VX.Y' -> 'vX.Y', where sensible.
- fix indents, casing, newlines, typos.
Stefan Eissing [Tue, 26 May 2026 13:59:09 +0000 (15:59 +0200)]
content_encoding: timeout during slow decoding
Check during transfer/content decoding for every MB or so, if the
transfer has reached its overall time limit. Error out if so.
This is mainly a protectin against compression bombs using way more time
than the transfer is allowed to. Normal compression ratios are unlikely
to benefit as they need more upstream data where the timeout handling is
already in place.
Joshua Rogers [Tue, 19 May 2026 14:16:12 +0000 (16:16 +0200)]
gtls: fix ignored return and uninitialized status in OCSP check
gnutls_ocsp_resp_get_single() was called with (void) discarding its
return value, so a failure (e.g. an OCSP response with no
SingleResponse entries) went undetected. The following switch() then
read an uninitialized gnutls_ocsp_cert_status_t, which is undefined
behaviour and could yield GNUTLS_OCSP_CERT_GOOD (0) depending on
stack contents, causing gtls_verify_ocsp_status to return CURLE_OK for
a response that was never successfully parsed.
Fix by initializing status to GNUTLS_OCSP_CERT_UNKNOWN and treating a
negative return from gnutls_ocsp_resp_get_single as an error.
HTTP/3: add proxy CONNECT and MASQUE CONNECT-UDP support (ngtcp2 QUIC)
This patch adds two major proxy capabilities to curl (ngtcp2 QUIC):
- HTTP/3 Proxy CONNECT: Tunnel HTTP/1.1 or HTTP/2 traffic through an
HTTPS proxy that speaks HTTP/3 (QUIC) using the standard CONNECT
method over an HTTP/3 connection.
- MASQUE CONNECT-UDP: Tunnel HTTP/3 (QUIC) traffic through an HTTP
proxy (speaking HTTP/1.1, HTTP/2, or HTTP/3) using the extended
CONNECT method with the CONNECT-UDP protocol (RFC9297 & RFC9298).
Public API additions:
- `CURLPROXY_HTTPS3`: new proxy type constant for HTTP/3 proxy
- `--proxy-http3`: new CLI flag to negotiate HTTP/3 with HTTPS proxy
The implementation adds two new filters:
- `H3-PROXY` - enables negotiating HTTP/3 (QUIC) to the proxy and
running CONNECT/CONNECT-UDP through that proxy transport.
- `CAPSULE` - dedicated filter inserted between QUIC transport and
HTTP-PROXY to handle datagram capsule encapsulation/decapsulation.
Here is how the curl filter chaining looks in different scenarios:
- HTTP/3 Proxy CONNECT (tunneling TCP protocols over QUIC proxy):
conn -> HTTP/1.1 or HTTP/2 -> SSL -> HTTP-PROXY ->
H3-PROXY -> HAPPY-EYEBALLS -> UDP
- MASQUE CONNECT-UDP (tunneling QUIC over any proxy):
conn -> HTTP/3 -> CAPSULE -> HTTP-PROXY -> H3-PROXY ->
HAPPY-EYEBALLS -> UDP
conn -> HTTP/3 -> CAPSULE -> HTTP-PROXY -> H1-PROXY or H2-PROXY ->
SSL -> HAPPY-EYEBALLS -> TCP
- Both features currently require the ngtcp2 QUIC backend.
- Both features are experimental (disabled by default). Enable with
`--enable-proxy-http3`(autotools) or `-DUSE_PROXY_HTTP3=ON`(CMake).
Tests:
- tests/unit/unit3400.c: Unit tests for capsule protocol encode/decode
- tests/http/test_60_h3_proxy.py: Comprehensive pytest integration suite
- tests/http/testenv/h2o.py: Managing h2o instances with HTTP/1.1, HTTP/2,
and HTTP/3 (QUIC) listeners, proxy.connect and proxy.connect-udp enabled.
References:
RFC 9297 - HTTP Datagrams and the Capsule Protocol
RFC 9298 - Proxying UDP in HTTP
RFC 9000 §16 — Variable-Length Integer Encoding