This is an automated email from the ASF dual-hosted git repository.

dsoumis pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c2bd7fa98d3d712d42dcc35759f311a28de92784
Author: Dimitris Soumis <[email protected]>
AuthorDate: Fri Mar 27 14:38:58 2026 +0200

    Add TestLargeClientHello and add a debug log in SecureNioChannel when 
BUFFER_UNDERFLOW occurs during handshake
---
 .../apache/tomcat/util/net/LocalStrings.properties |  1 +
 .../apache/tomcat/util/net/SecureNioChannel.java   |  3 +
 .../tomcat/util/net/TestLargeClientHello.java      | 86 ++++++++++++++++++++++
 3 files changed, 90 insertions(+)

diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index b023ad09a7..6a56e51816 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -47,6 +47,7 @@ channel.nio.ssl.unexpectedStatusDuringWrap=Unexpected status 
[{0}] during handsh
 channel.nio.ssl.unwrapFail=Unable to unwrap data, invalid status [{0}]
 channel.nio.ssl.unwrapFailResize=Unable to unwrap data because buffer is too 
small, invalid status [{0}]
 channel.nio.ssl.wrapFail=Unable to wrap data, invalid status [{0}]
+channel.nio.ssl.handshakeUnwrapBufferUnderflow=BUFFER_UNDERFLOW during 
handshake unwrap, more data needed from the network
 
 endpoint.accept.fail=Socket accept failed
 endpoint.alpn.fail=Failed to configure endpoint for ALPN using [{0}]
diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java 
b/java/org/apache/tomcat/util/net/SecureNioChannel.java
index bb43c5c098..28c090d5c8 100644
--- a/java/org/apache/tomcat/util/net/SecureNioChannel.java
+++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java
@@ -492,6 +492,9 @@ public class SecureNioChannel extends NioChannel {
             // call unwrap
             getBufHandler().configureReadBufferForWrite();
             result = sslEngine.unwrap(netInBuffer, 
getBufHandler().getReadBuffer());
+            if (log.isDebugEnabled() && result.getStatus() == 
SSLEngineResult.Status.BUFFER_UNDERFLOW) {
+                
log.debug(sm.getString("channel.nio.ssl.handshakeUnwrapBufferUnderflow"));
+            }
             /*
              * ByteBuffer.compact() is an optional method but netInBuffer is 
created from either ByteBuffer.allocate()
              * or ByteBuffer.allocateDirect() and the ByteBuffers returned by 
those methods do implement compact(). The
diff --git a/test/org/apache/tomcat/util/net/TestLargeClientHello.java 
b/test/org/apache/tomcat/util/net/TestLargeClientHello.java
new file mode 100644
index 0000000000..c476fe0a24
--- /dev/null
+++ b/test/org/apache/tomcat/util/net/TestLargeClientHello.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tomcat.util.net;
+
+import java.io.File;
+import java.util.logging.Level;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
+
+public class TestLargeClientHello extends TomcatBaseTest {
+
+    // https://bz.apache.org/bugzilla/show_bug.cgi?id=67938
+    @Test
+    public void testLargeClientHelloWithSessionResumption() throws Exception {
+        File keystoreFile = TesterSupport.generateKeystore("localhost", 
"tomcat",
+            new String[]{"localhost", "*.localhost"},
+                (keyPair, certBuilder) -> {
+                JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+                certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
+                        
extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
+                certBuilder.addExtension(Extension.authorityKeyIdentifier, 
false,
+                        
extUtils.createAuthorityKeyIdentifier(keyPair.getPublic()));
+                certBuilder.addExtension(Extension.basicConstraints, true,
+                    new BasicConstraints(true));
+                certBuilder.addExtension(Extension.keyUsage, false,
+                    new KeyUsage(KeyUsage.digitalSignature | 
KeyUsage.keyEncipherment));
+                certBuilder.addExtension(new ASN1ObjectIdentifier("2.999"), 
false,
+                    new DERUTF8String("x".repeat(16922)));
+            });
+
+        Tomcat tomcat = getTomcatInstance();
+
+        Context ctx = getProgrammaticRootContext();
+        Tomcat.addServlet(ctx, "hello", new HelloWorldServlet());
+        ctx.addServletMappingDecoded("/", "hello");
+
+        TesterSupport.initSsl(tomcat, keystoreFile.getAbsolutePath(), false);
+
+        try (LogCapture logCapture = attachLogCapture(Level.FINE, 
"org.apache.tomcat.util.net.SecureNioChannel")) {
+
+            tomcat.start();
+
+            SSLContext sc = 
SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_3);
+            sc.init(null, new TrustManager[]{new 
TesterSupport.TrustAllCerts()}, null);
+            
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+
+            String url = "https://localhost:"; + getPort() + "/";
+            Assert.assertTrue(getUrl(url).toString().contains("Hello World"));
+            Assert.assertTrue(getUrl(url).toString().contains("Hello World"));
+
+            Assert.assertTrue(logCapture.containsText(
+                    
TomcatBaseTest.getKeyFromPropertiesFile("org.apache.tomcat.util.net",
+                    "channel.nio.ssl.handshakeUnwrapBufferUnderflow")));
+        }
+
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to