Skip to content

Commit 27310ac

Browse files
committed
Add TestLargeClientHello and add a debug log in SecureNioChannel when BUFFER_UNDERFLOW occurs during handshake
1 parent b097411 commit 27310ac

3 files changed

Lines changed: 91 additions & 0 deletions

File tree

java/org/apache/tomcat/util/net/LocalStrings.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ channel.nio.ssl.unexpectedStatusDuringWrap=Unexpected status [{0}] during handsh
4444
channel.nio.ssl.unwrapFail=Unable to unwrap data, invalid status [{0}]
4545
channel.nio.ssl.unwrapFailResize=Unable to unwrap data because buffer is too small, invalid status [{0}]
4646
channel.nio.ssl.wrapFail=Unable to wrap data, invalid status [{0}]
47+
channel.nio.ssl.handshakeUnwrapBufferUnderflow=BUFFER_UNDERFLOW during handshake unwrap, more data needed from the network
4748

4849
endpoint.accept.fail=Socket accept failed
4950
endpoint.alpn.fail=Failed to configure endpoint for ALPN using [{0}]

java/org/apache/tomcat/util/net/SecureNioChannel.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,9 @@ protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
492492
// call unwrap
493493
getBufHandler().configureReadBufferForWrite();
494494
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
495+
if (log.isDebugEnabled() && result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
496+
log.debug(sm.getString("channel.nio.ssl.handshakeUnwrapBufferUnderflow"));
497+
}
495498
/*
496499
* ByteBuffer.compact() is an optional method but netInBuffer is created from either ByteBuffer.allocate()
497500
* or ByteBuffer.allocateDirect() and the ByteBuffers returned by those methods do implement compact(). The
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.tomcat.util.net;
19+
20+
import java.io.File;
21+
import java.util.logging.Level;
22+
23+
import javax.net.ssl.SSLContext;
24+
import javax.net.ssl.TrustManager;
25+
26+
import org.junit.Assert;
27+
import org.junit.Test;
28+
29+
import org.apache.catalina.Context;
30+
import org.apache.catalina.startup.Tomcat;
31+
import org.apache.catalina.startup.TomcatBaseTest;
32+
import org.apache.tomcat.util.res.StringManager;
33+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
34+
import org.bouncycastle.asn1.DERUTF8String;
35+
import org.bouncycastle.asn1.x509.BasicConstraints;
36+
import org.bouncycastle.asn1.x509.Extension;
37+
import org.bouncycastle.asn1.x509.KeyUsage;
38+
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
39+
40+
public class TestLargeClientHello extends TomcatBaseTest {
41+
42+
// https://bz.apache.org/bugzilla/show_bug.cgi?id=67938
43+
@Test
44+
public void testLargeClientHelloWithSessionResumption() throws Exception {
45+
File keystoreFile = TesterSupport.generateKeystore("localhost", "tomcat",
46+
new String[]{"localhost", "*.localhost"},
47+
(keyPair, certBuilder) -> {
48+
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
49+
certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
50+
extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
51+
certBuilder.addExtension(Extension.authorityKeyIdentifier, false,
52+
extUtils.createAuthorityKeyIdentifier(keyPair.getPublic()));
53+
certBuilder.addExtension(Extension.basicConstraints, true,
54+
new BasicConstraints(true));
55+
certBuilder.addExtension(Extension.keyUsage, false,
56+
new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
57+
certBuilder.addExtension(new ASN1ObjectIdentifier("2.999"), false,
58+
new DERUTF8String("x".repeat(16922)));
59+
});
60+
61+
Tomcat tomcat = getTomcatInstance();
62+
63+
Context ctx = getProgrammaticRootContext();
64+
Tomcat.addServlet(ctx, "hello", new HelloWorldServlet());
65+
ctx.addServletMappingDecoded("/", "hello");
66+
67+
TesterSupport.initSsl(tomcat, keystoreFile.getAbsolutePath(), false);
68+
69+
try (LogCapture logCapture = attachLogCapture(Level.FINE, "org.apache.tomcat.util.net.SecureNioChannel")) {
70+
71+
tomcat.start();
72+
73+
SSLContext sc = SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_3);
74+
sc.init(null, new TrustManager[]{new TesterSupport.TrustAllCerts()}, null);
75+
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
76+
77+
String url = "https://localhost:" + getPort() + "/";
78+
Assert.assertTrue(getUrl(url).toString().contains("Hello World"));
79+
Assert.assertTrue(getUrl(url).toString().contains("Hello World"));
80+
81+
Assert.assertTrue(logCapture.containsText(StringManager.getManager(SecureNioChannel.class)
82+
.getString("channel.nio.ssl.handshakeUnwrapBufferUnderflow")));
83+
84+
}
85+
86+
}
87+
}

0 commit comments

Comments
 (0)