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]
