Commit Graph

8408 Commits

Author SHA1 Message Date
Demi Marie Obenour
bd37faff72 HTTP: do not allow headers to end with a bare LF
This is consistent with Node.js.
2025-06-10 15:09:54 -04:00
Demi Marie Obenour
bb0a2b9de8 HTTP: Allow rejecting leading and trailing whitespace in HTTP2+ fields
All versions of HTTP forbid field (header and trailer) values from
having leading or trailing horizontal whitespace (0x20 and 0x09).  In
HTTP/1.0 and HTTP/1.1, leading and trailing whitespace must be stripped
from the field value before further processing.  In HTTP/2 and HTTP/3,
leading and trailing whitespace must cause the entire message to be
considered malformed.

Willy Tarreau (lead developer of HAProxy) has indicated that there are
clients that actually do send leading and/or trailing whitespace in
HTTP/2 and/or HTTP/3 cookie headers, which is why HAProxy accepts them.
Therefore, the fix is disabled by default and must be enabled with the
reject_leading_trailing_whitespace directive.
2025-06-10 15:09:29 -04:00
Demi Marie Obenour
436282ff74 HTTP: Remove redundant state from chunk parsing
The state machine never returns with state = sw_chunk_data and a size of
zero, nor did it return with state = sw_after_data.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
626b1d9bba HTTP: Reject trailers involved in framing
These are forbidden by the relevant standards.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
1c0426c8c0 Forbid malformed HTTP/1.1 trailers
HTTP/1.1 trailers must follow the same syntax as HTTP headers.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
1be6976866 Reject malformed chunk extensions
This forbids chunk extensions that violate RFC9112, and _only_ these
chunk extensions.  Bad whitespace is permitted, but a bare LF instead of
CRLF is not.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
0d2c8754ee HTTP: Do not allow request lines to end with bare CR
This is consistent with Node.js.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
e30ddb7a3b HTTP: Do not allow multiple CRs before LF
This is not permitted by RFC9112.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
dab8c0e762 HTTP: Do not allow header lines with no colon
RFC9112 does not permit them.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
98d266924f Proxy: Reject Transfer-Encoding or Content-Length trailers
These are forbidden by the standard, and if they were (invalidly) folded
into a header by downstream code, it would allow HTTP response
splitting.  This is a defense in depth measure.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
279ae488a4 HTTP: Reject hop-by-hop headers in HTTP/2 and HTTP/3 requests
RFC9113 and RFC9114 both require requests with connection-specific
headers to be treated as malformed, with the exception of "te: trailers".
Reject requests containing them.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
ae76c64300 HTTP: Reject invalid field values
RFC9110 is clear that the only CTRL character allowed in header values
is HTAB.  Conform to the standard, as Varnish, H2O, and (I suspect)
Hyper do.  This also makes the whitespace-stripping code simpler, as any
character that is less than 0x21 is either whitespace or rejected.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
b1c4b0757f HTTP: Reject invalid header names
HTTP headers must be an RFC9110 token, so only a subset of characters
are permitted.  RFC9113 and RFC9114 require rejecting invalid header
characters in HTTP/2 and HTTP/3 respectively, so reject them in HTTP/1.0
and HTTP/1.1 for consistency.  This also requires removing the ignore
hack for (presumably ancient) versions of IIS.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
1e30988516 HTTP: Reject HTTP/2 and HTTP/3 requests with Transfer-Encoding
RFC9113 and RFC9114 are clear that this header cannot be used in these
versions of HTTP, and in other proxies accepting Transfer-Encoding has
led to security vulnerabilities.  NGINX is safe from the vulnerability
because it ignores the header, but this is still wrong.

Fixes: #612
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
17ce4bcfa3 HTTP: Use common header code for v2 and v3
This makes the behavior of HTTP/2 and HTTP/3 much more similar.  In
particular, the HTTP/3 :authority pseudoheader is used to set the Host
header, instead of the virtual server.  This is arguably less correct,
but it is consistent with the existing HTTP/2 behavior and unbreaks
users of PHP-FPM and other FastCGI applications.  In the future, NGINX
could have a config option that caused :authority and Host to be treated
separately in both HTTP/2 and HTTP/3.

Fixes: #587
Fixes: #256
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
c7d26ccc9b HTTP/3: Do not allow invalid pseudo-header fields
RFC9114 requires invalid pseudo-header fields to be rejected, and this
is consistent with HTTP/2.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
3897c97cc3 Strip leading and trailing whitespace from HTTP field values
Per RFC9110, HTTP field values never contain leading or trailing
whitespace.  Strip all such whitespace from HTTP and HTTP field values.
The HTTP/1.x parser already stripped spaces but didn't strip tabs, so
change the parser to strip tabs as well.  In HTTP/2+, the stripping is
done during validation.  This requires modifying the value.

There are three ways to modify the value:

1. Modify the data in-place with memmove().
2. Move the data pointer to point to after the leading whitespace.
3. Allocate a new buffer and replace the data pointer.

Both HPACK and QPACK decompression make a copy of the data, but some
code might assume that the data pointer of a field value can safely be
passed to ngx_pfree().  Therefore, the first option is chosen.  Existing
code ensures that header values are NUL-terminated, so the stripping
code NUL-pads header values to ensure that the stripped strings have at
least as many terminating NUL bytes as they did before being stripped.

The stripping code has been tested in a standalone program to make sure
that it works correctly, and it correctly strips leading and trailing
whitespace from a variety of strings.  This code has also been tested
with real HTTP/3 requests from Cloudflare's h3i tool.

Fixes: #598
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
80b41e1002 HTTP: Use common header validation function for HTTP/2 and HTTP/3
The header validation required by HTTP/2 and HTTP/3 is identical, so use
a common function for both.  This will make it easier to add additional
validation in the future.  Move the function to ngx_http_parse.c so that
it can share code with the HTTP/1.x parser in the future.

No functional change intended.
2025-06-10 15:02:24 -04:00
Sergey Kandaurov
5b8a5c08ce Core: added support for TCP keepalive parameters on macOS.
Some checks failed
buildbot / buildbot (push) Has been cancelled
The support first appeared in OS X Mavericks 10.9 and documented since
OS X Yosemite 10.10.

It has a subtle implementation difference from other operating systems
in that the TCP_KEEPALIVE socket option (used in place of TCP_KEEPIDLE)
isn't inherited from a listening socket to an accepted socket.

An apparent reason for this behaviour is that it might be preserved for
the sake of backward compatibility.  The TCP_KEEPALIVE socket option is
not inherited since appearance in OS X Panther 10.3, which long predates
two other TCP_KEEPINTVL and TCP_KEEPCNT socket options.

Thanks to Andy Pan for initial work.
2025-05-27 01:59:02 +04:00
Aleksei Bavshin
3d5889a3ee SSL: disabled UI console prompts from worker processes.
Certain providers may attempt to reload the key on the first use after a
fork.  Such attempt would require re-prompting the pin, and this time we
are not able to pass the password callback.

While it is addressable with configuration for a specific provider, it would
be prudent to ensure that no such prompts could block worker processes by
setting the default UI method.

UI_null() first appeared in 1.1.1 along with the OSSL_STORE, so it is safe
to assume the same set of guards.
2025-05-26 06:56:18 -07:00
Aleksei Bavshin
0fdbfc1ff4 SSL: support loading keys via OSSL_STORE.
A new "store:..." prefix for the "ssl_certificate_key" directive allows
loading keys via the OSSL_STORE API.

The change is required to support hardware backed keys in OpenSSL 3.x using
the new "provider(7ossl)" modules, such as "pkcs11-provider".  While the
engine API is present in 3.x, some operating systems (notably, RHEL10)
have already disabled it in their builds of OpenSSL.

Related: https://trac.nginx.org/nginx/ticket/2449
2025-05-26 06:56:18 -07:00
Sergey Kandaurov
6a134dfd48 QUIC: using QUIC API introduced in OpenSSL 3.5.
Similarly to the QUIC API originated in BoringSSL, this API allows
to register custom TLS callbacks for an external QUIC implementation.
See the SSL_set_quic_tls_cbs manual page for details.

Due to a different approach used in OpenSSL 3.5, handling of CRYPTO
frames was streamlined to always write an incoming CRYPTO buffer to
the crypto context.  Using SSL_provide_quic_data(), this results in
transient allocation of chain links and buffers for CRYPTO frames
received in order.  Testing didn't reveal performance degradation of
QUIC handshakes, https://github.com/nginx/nginx/pull/646 provides
specific results.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
1d4d2f2c96 QUIC: better approach for premature handshake completion.
Using SSL_in_init() to inspect a handshake state was replaced with
SSL_is_init_finished().  This represents a more complete fix to the
BoringSSL issue addressed in 22671b37e.

This provides awareness of the early data handshake state when using
OpenSSL 3.5 TLS callbacks in 0-RTT enabled configurations, which, in
particular, is used to avoid premature completion of the initial TLS
handshake, before required client handshake messages are received.

This is a non-functional change when using BoringSSL.  It supersedes
testing non-positive SSL_do_handshake() results in all supported SSL
libraries, hence simplified.

In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
bcb9d3fd2c QUIC: ssl_encryption_level_t abstraction layer.
Encryption level values are decoupled from ssl_encryption_level_t,
which is now limited to BoringSSL QUIC callbacks, with mappings
provided.  Although the values match, this provides a technically
safe approach, in particular, to access protection level sized arrays.

In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
9857578f15 QUIC: factored out SSL_provide_quic_data() to the helper function.
It is now called from ngx_quic_handle_crypto_frame(), prior to proceeding
with the handshake.  With this logic removed, the handshake function is
renamed to ngx_quic_handshake() to better match ngx_ssl_handshake().
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
e561f7dbcf QUIC: defined SSL API macros in a single place.
All definitions now set in ngx_event_quic.h, this includes moving
NGX_QUIC_OPENSSL_COMPAT from autotests to compile time.  Further,
to improve code readability, a new NGX_QUIC_QUICTLS_API macro is
used for QuicTLS that provides old BoringSSL QUIC API.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
54e6b7cfee QUIC: logging missing mandatory TLS extensions only once.
Previously, they might be logged on every add_handshake_data
callback invocation when using OpenSSL compat layer and processing
coalesced handshake messages.

Further, the ALPN error message is adjusted to signal the missing
extension.  Possible reasons were previously narrowed down with
ebb6f7d65 changes in the ALPN callback that is invoked earlier in
the handshake.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
5d7fd4a7e3 QUIC: reset qc->error to zero again.
Following the previous change that removed posting a close event
in OpenSSL compat layer, now ngx_quic_close_connection() is always
called on error path with either NGX_ERROR or qc->error set.

This allows to remove a special value -1 served as a missing error,
which simplifies the code.  Partially reverts d3fb12d77.

Also, this improves handling of the draining connection state, which
consists of posting a close event with NGX_OK and no qc->error set,
where it was previously converted to NGX_QUIC_ERR_INTERNAL_ERROR.
Notably, this is rather a cosmetic fix, because drained connections
do not send any packets including CONNECTION_CLOSE, and qc->error
is not otherwise used.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
7468a10b62 QUIC: adjusted handling of callback errors.
Changed handshake callbacks to always return success.  This allows to avoid
logging SSL_do_handshake() errors with empty or cryptic "internal error"
OpenSSL error messages at the inappropriate "crit" log level.

Further, connections with failed callbacks are closed now right away when
using OpenSSL compat layer.  This change supersedes and reverts c37fdcdd1,
with the conditions to check callbacks invocation kept to slightly improve
code readability of control flow; they are optimized out in the resulting
assembly code.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
47f96993f6 QUIC: logging of SSL library errors.
Logging level for such errors, which should not normally happen,
is changed to NGX_LOG_ALERT, and ngx_log_error() is replaced with
ngx_ssl_error() for consistency with the rest of the code.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
ef9cd3214f QUIC: logging level of handshake errors.
Various errors reported by SSL_do_handshake() are now logged at the
"info" or "crit" level, akin to handshakes on regular TCP connections.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
aa43385ffa QUIC: removed ALPN feature test.
ALPN support is present in all libraries that have QUIC support,
it is safe to compile it unconditionally.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
39b1e3fe9d QUIC: removed excessive casts for ngx_ssl_get_connection().
They were blindly copied from ngx_ssl_info_callback(), where
the ngx_ssl_conn_t pointer is passed with const qualifier.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
335993154c QUIC: removed level field from ngx_quic_compat_record_t.
It was made unused in d15f8f2 after introducing reusable crypto contexts.
2025-05-23 15:00:47 +04:00
Sergey Kandaurov
f3542500b6 QUIC: do not block ACKs by congestion control.
Some checks failed
buildbot / buildbot (push) Has been cancelled
Previously, it was not possible to send acknowledgments if the
congestion window was limited or temporarily exceeded, such as
after sending a large response or MTU probe.  If ACKs were not
received from the peer for some reason to update the in-flight
bytes counter below the congestion window, this might result in
a stalled connection.

The fix is to send ACKs regardless of congestion control.  This
meets RFC 9002, Section 7:
: Similar to TCP, packets containing only ACK frames do not count
: toward bytes in flight and are not congestion controlled.

This is a simplified implementation to send ACK frames from the
head of the queue.  This was made possible after 6f5f17358.

Reported in trac ticket #2621 and subsequently by Vladimir Homutov:
https://mailman.nginx.org/pipermail/nginx-devel/2025-April/ZKBAWRJVQXSZ2ISG3YJAF3EWMDRDHCMO.html
2025-04-29 19:53:41 +04:00
Sergey Kandaurov
adda704158 SSL: fixed build with OPENSSL_NO_DH. 2025-04-25 14:56:31 +04:00
Sergey Kandaurov
4f8bc0b282 SSL: fixed build with OPENSSL_NO_DEPRECATED. 2025-04-25 14:56:31 +04:00
nandsky
9785db9bd5 QUIC: fixed a typo. 2025-04-23 11:53:51 +04:00
Aleksei Bavshin
020b1db7eb Win32: added detection of ARM64 target.
This extends the target selection implemented in dad6ec3aa6 to support
Windows ARM64 platforms.  OpenSSL support for VC-WIN64-ARM target first
appeared in 1.1.1 and is present in all currently supported (3.x)
branches.

As a side effect, ARM64 Windows builds will get 16-byte alignment along
with the rest of non-x86 platforms.  This is safe, as malloc on 64-bit
Windows guarantees the fundamental alignment of allocations, 16 bytes.
2025-04-18 12:57:26 -07:00
Aleksei Bavshin
b9d0ba6677 Core: improved NGX_ALIGNMENT detection on some x86_64 platforms.
Previously, the default pool alignment used sizeof(unsigned long), with
the expectation that this would match to a platform word size.  Certain
64-bit platforms prove this assumption wrong by keeping the 32-bit long
type, which is fully compliant with the C standard.

This introduces a possibility of suboptimal misaligned access to the
data allocated with ngx_palloc() on the affected platforms, which is
addressed here by changing the default NGX_ALIGNMENT to a pointer size.

As we override the detection in auto/os/conf for all the machine types
except x86, and Unix-like 64-bit systems prefer the 64-bit long, the
impact of the change should be limited to Win64 x64.
2025-04-18 12:57:26 -07:00
Roman Arutyunyan
0f9f43b79e HTTP/3: fixed NGX_HTTP_V3_VARLEN_INT_LEN value.
After fixing ngx_http_v3_encode_varlen_int() in 400eb1b628,
NGX_HTTP_V3_VARLEN_INT_LEN retained the old value of 4, which is
insufficient for the values over 1073741823 (1G - 1).

The NGX_HTTP_V3_VARLEN_INT_LEN macro is used in ngx_http_v3_uni.c to
format stream and frame types.  Old buffer size is enough for formatting
this data.  Also, the macro is used in ngx_http_v3_filter_module.c to
format output chunks and trailers.  Considering output_buffers and
proxy_buffer_size are below 1G in all realistic scenarios, the old buffer
size is enough here as well.
2025-04-18 15:28:00 +04:00
Roman Arutyunyan
444954abac Fixed -Wunterminated-string-initialization with gcc15. 2025-04-17 19:12:59 +04:00
Roman Arutyunyan
04813dac86 QUIC: lowered log level for unsupported transport parameters. 2025-04-17 12:51:17 +04:00
Roman Arutyunyan
0626e60a75 Version bump. 2025-04-16 18:55:19 +04:00
Sergey Kandaurov
6ac8b69f06 nginx-1.27.5-RELEASE 2025-04-16 16:01:11 +04:00
Roman Arutyunyan
aa49a416b8 QUIC: dynamic packet threshold.
RFC 9002, Section 6.1.1 defines packet reordering threshold as 3.  Testing
shows that such low value leads to spurious packet losses followed by
congestion window collapse.  The change implements dynamic packet threshold
detection based on in-flight packet range.  Packet threshold is defined
as half the number of in-flight packets, with mininum value of 3.

Also, renamed ngx_quic_lost_threshold() to ngx_quic_time_threshold()
for better compliance with RFC 9002 terms.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
2fb32ff24d QUIC: optimized connection frame threshold.
Previosly the threshold was hardcoded at 10000.  This value is too low for
high BDP networks.  For example, if all frames are STREAM frames, and MTU
is 1500, the upper limit for congestion window would be roughly 15M
(10000 * 1500).  With 100ms RTT it's just a 1.2Gbps network (15M * 10 * 8).
In reality, the limit is even lower because of other frame types.  Also,
the number of frames that could be used simultaneously depends on the total
amount of data buffered in all server streams, and client flow control.

The change sets frame threshold based on max concurrent streams and stream
buffer size, the product of which is the maximum number of in-flight stream
data in all server streams at any moment.  The value is divided by 2000 to
account for a typical MTU 1500 and the fact that not all frames are STREAM
frames.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
f9a7e7cc11 QUIC: CUBIC congestion control. 2025-04-15 19:01:36 +04:00
Roman Arutyunyan
a40cc70023 QUIC: ignore congestion control when sending MTU probes.
If connection is network-limited, MTU probes have little chance of being
sent since congestion window is almost always full.  As a result, PMTUD
may not be able to reach the real MTU and the connection may operate with
a reduced MTU.  The solution is to ignore the congestion window.  This may
lead to a temporary increase in in-flight count beyond congestion window.
2025-04-15 19:01:36 +04:00
Roman Arutyunyan
6bf13e9d57 QUIC: do not shrink congestion window after losing an MTU probe.
As per RFC 9000, Section 14.4:

    Loss of a QUIC packet that is carried in a PMTU probe is therefore
    not a reliable indication of congestion and SHOULD NOT trigger a
    congestion control reaction.
2025-04-15 19:01:36 +04:00