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]

Reply via email to