This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new e1027f0c3b Validate HTTP2-Settings before accepting h2c upgrade (#1122)
e1027f0c3b is described below
commit e1027f0c3bded9696a0e7456f77dccca88379e21
Author: Arturo Bernal <[email protected]>
AuthorDate: Fri Nov 6 15:49:47 2026 +0100
Validate HTTP2-Settings before accepting h2c upgrade (#1122)
RFC 7540, section 3.2.1 requires a server to refuse the h2c upgrade if
the HTTP2-Settings header field value is not a valid BASE64URL-encoded
HTTP/2 SETTINGS payload. The server was deferring validation until after
the 101 response had been sent, which is a violation of the MUST NOT
constraint.
The fix validates the header in accept(): if the value cannot be decoded
as base64url, or if the decoded length is not a multiple of 6 octets
(each SETTINGS entry defined in section 6.5 is exactly 6 octets), the
upgrade is declined and the request continues as HTTP/1.1.
---
java/org/apache/coyote/http2/Http2Protocol.java | 16 ++++++++++++-
.../apache/coyote/http2/TestHttp2Section_3_2.java | 27 ++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/coyote/http2/Http2Protocol.java
b/java/org/apache/coyote/http2/Http2Protocol.java
index 58820d5bf5..4b90108523 100644
--- a/java/org/apache/coyote/http2/Http2Protocol.java
+++ b/java/org/apache/coyote/http2/Http2Protocol.java
@@ -17,6 +17,7 @@
package org.apache.coyote.http2;
import java.nio.charset.StandardCharsets;
+import java.util.Base64;
import java.util.Enumeration;
import javax.management.ObjectName;
@@ -177,14 +178,27 @@ public class Http2Protocol implements UpgradeProtocol {
// Should only be one HTTP2-Settings header
Enumeration<String> settings =
request.getMimeHeaders().values("HTTP2-Settings");
int count = 0;
+ String settingsValue = null;
while (settings.hasMoreElements()) {
count++;
- settings.nextElement();
+ settingsValue = settings.nextElement();
}
if (count != 1) {
return false;
}
+ // RFC 7540, section 3.2.1: the server MUST NOT upgrade if the value
is not a valid
+ // BASE64URL-encoded HTTP/2 SETTINGS payload (section 6.5). A valid
payload decodes
+ // without error and its length is a multiple of 6 octets (each entry
is 6 octets).
+ try {
+ byte[] decoded = Base64.getUrlDecoder().decode(settingsValue);
+ if (decoded.length % 6 != 0) {
+ return false;
+ }
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+
Enumeration<String> connection =
request.getMimeHeaders().values("Connection");
boolean found = false;
while (connection.hasMoreElements() && !found) {
diff --git a/test/org/apache/coyote/http2/TestHttp2Section_3_2.java
b/test/org/apache/coyote/http2/TestHttp2Section_3_2.java
index 5532f2e547..72a8bf13db 100644
--- a/test/org/apache/coyote/http2/TestHttp2Section_3_2.java
+++ b/test/org/apache/coyote/http2/TestHttp2Section_3_2.java
@@ -188,4 +188,31 @@ public class TestHttp2Section_3_2 extends Http2TestBase {
// No need to test how trailing '=' are handled here. HTTP2Settings
payloads
// are always a multiple of 6 long which means valid payloads never end in
// '='. Invalid payloads will be rejected anyway.
+
+ @Test
+ public void testInvalidBase64Http2Settings() throws Exception {
+ // RFC 7540, section 3.2.1: a server MUST NOT upgrade if the
HTTP2-Settings value is
+ // not a valid BASE64URL-encoded SETTINGS payload. A value containing
characters
+ // outside the base64url alphabet must be rejected before the 101 is
sent.
+ enableHttp2();
+ configureAndStartWebApplication();
+ openClientConnection();
+ doHttpUpgrade(DEFAULT_CONNECTION_HEADER_VALUE, "h2c", "HTTP2-Settings:
!!!invalid!!!\r\n", false);
+ parseHttp11Response();
+ }
+
+
+ @Test
+ public void testInvalidLengthHttp2Settings() throws Exception {
+ // RFC 7540, section 3.2.1: the HTTP2-Settings value must be a
BASE64URL encoding of
+ // an HTTP/2 SETTINGS payload (section 6.5). Each entry is exactly 6
octets, so the
+ // decoded length must be a multiple of 6. A valid base64url string
that decodes to a
+ // length that is not a multiple of 6 must also be rejected.
+ enableHttp2();
+ configureAndStartWebApplication();
+ openClientConnection();
+ // "AQID" is valid base64url and decodes to 3 bytes, which is not a
multiple of 6
+ doHttpUpgrade(DEFAULT_CONNECTION_HEADER_VALUE, "h2c", "HTTP2-Settings:
AQID\r\n", false);
+ parseHttp11Response();
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]