You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ds...@apache.org on 2026/03/29 12:08:20 UTC
(tomcat) branch main updated (a5ce36f38e -> 722464b256)
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
from a5ce36f38e Reduce log verbosity for Kubernetes
new 766ea5e694 Fix naming convention of performance tests in BUILDING.txt
new 80bac5628f Add TestSSLAuthenticator
new 9ef7b4a94c Add TestValidateClientSessionId
new 4fd8f8e5a9 Add generateKeystore method in TesterSupport which utilizes BouncyCastle to generate a temporary JKS keystore containing a self-signed RSA certificate.
new 067341658d Add TestLargeClientHello and add a debug log in SecureNioChannel when BUFFER_UNDERFLOW occurs during handshake
new 722464b256 Move generateKeystore() from TesterSupport to independent TesterKeystoreGenerator class
The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
BUILDING.txt | 2 +-
.../apache/tomcat/util/net/LocalStrings.properties | 1 +
.../apache/tomcat/util/net/SecureNioChannel.java | 3 +
.../authenticator/TestSSLAuthenticator.java} | 21 +++--
.../connector/TestValidateClientSessionId.java | 89 ++++++++++++++++++
.../tomcat/util/net/TestLargeClientHello.java | 86 +++++++++++++++++
.../tomcat/util/net/TesterKeystoreGenerator.java | 103 +++++++++++++++++++++
7 files changed, 295 insertions(+), 10 deletions(-)
copy test/org/apache/{jasper/compiler/TestNodeIntegration.java => catalina/authenticator/TestSSLAuthenticator.java} (62%)
create mode 100644 test/org/apache/catalina/connector/TestValidateClientSessionId.java
create mode 100644 test/org/apache/tomcat/util/net/TestLargeClientHello.java
create mode 100644 test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 03/06: Add TestValidateClientSessionId
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 9ef7b4a94c733fe36c01a0d482073d043ea2d13b
Author: Dimitris Soumis <ji...@gmail.com>
AuthorDate: Tue Mar 24 14:53:23 2026 +0200
Add TestValidateClientSessionId
---
.../connector/TestValidateClientSessionId.java | 89 ++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/test/org/apache/catalina/connector/TestValidateClientSessionId.java b/test/org/apache/catalina/connector/TestValidateClientSessionId.java
new file mode 100644
index 0000000000..dc94fc3fc3
--- /dev/null
+++ b/test/org/apache/catalina/connector/TestValidateClientSessionId.java
@@ -0,0 +1,89 @@
+/*
+ * 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.catalina.connector;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.apache.tomcat.util.buf.ByteChunk;
+
+public class TestValidateClientSessionId extends TomcatBaseTest {
+
+ @Test
+ public void testMaliciousSessionIdRejected() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ Context ctx = getProgrammaticRootContext();
+ Tomcat.addServlet(ctx, "snoop", new SnoopServlet());
+ ctx.addServletMappingDecoded("/", "snoop");
+
+ tomcat.start();
+
+ Map<String, List<String>> reqHead = new HashMap<>();
+ reqHead.put("Cookie", List.of("JSESSIONID=DUMMY_SESSION_ID"));
+
+ ByteChunk res = new ByteChunk();
+ getUrl("http://localhost:" + getPort() + "/?createSession=true", res, reqHead, null);
+
+ RequestDescriptor requestDesc = SnoopResult.parse(res.toString());
+
+ String actualSessionId = requestDesc.getRequestInfo("SESSION-ID");
+ Assert.assertNotEquals("DUMMY_SESSION_ID", actualSessionId);
+ }
+
+ @Test
+ public void testValidSessionIdAcceptedAcrossContexts() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ Context ctx1 = tomcat.addContext("/app1", null);
+ ctx1.setSessionCookiePath("/");
+ Tomcat.addServlet(ctx1, "snoop", new SnoopServlet());
+ ctx1.addServletMappingDecoded("/", "snoop");
+
+ Context ctx2 = tomcat.addContext("/app2", null);
+ ctx2.setSessionCookiePath("/");
+ Tomcat.addServlet(ctx2, "snoop", new SnoopServlet());
+ ctx2.addServletMappingDecoded("/", "snoop");
+
+ tomcat.start();
+
+ ByteChunk res = new ByteChunk();
+ Map<String, List<String>> resHead = new HashMap<>();
+ getUrl("http://localhost:" + getPort() + "/app1/?createSession=true", res, null, resHead);
+
+ RequestDescriptor requestDesc = SnoopResult.parse(res.toString());
+ String sessionId1 = requestDesc.getRequestInfo("SESSION-ID");
+
+ Map<String, List<String>> reqHead = new HashMap<>();
+ reqHead.put("Cookie", List.of("JSESSIONID=" + sessionId1));
+
+ getUrl("http://localhost:" + getPort() + "/app2/?createSession=true", res, reqHead, null);
+
+ requestDesc = SnoopResult.parse(res.toString());
+ String sessionId2 = requestDesc.getRequestInfo("SESSION-ID");
+ Assert.assertEquals(sessionId1, sessionId2);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 05/06: Add TestLargeClientHello and add a debug log in SecureNioChannel when BUFFER_UNDERFLOW occurs during handshake
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 067341658d5856cebd699de02edb0512dc84ddb0
Author: Dimitris Soumis <ji...@gmail.com>
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 720f07bdcc..f433c46a81 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -44,6 +44,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: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 04/06: Add generateKeystore method in TesterSupport which utilizes BouncyCastle to generate a temporary JKS keystore containing a self-signed RSA certificate.
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 4fd8f8e5a94eb4cae6025e9dc031a4d5fc17ff0e
Author: Dimitris Soumis <ji...@gmail.com>
AuthorDate: Fri Mar 27 14:38:54 2026 +0200
Add generateKeystore method in TesterSupport which utilizes BouncyCastle to generate a temporary JKS keystore containing a self-signed RSA certificate.
---
test/org/apache/tomcat/util/net/TesterSupport.java | 76 ++++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java b/test/org/apache/tomcat/util/net/TesterSupport.java
index 9c3e0d2095..31a1c73240 100644
--- a/test/org/apache/tomcat/util/net/TesterSupport.java
+++ b/test/org/apache/tomcat/util/net/TesterSupport.java
@@ -18,11 +18,15 @@ package org.apache.tomcat.util.net;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.math.BigInteger;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -36,6 +40,7 @@ import java.security.cert.PKIXRevocationChecker;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
+import java.util.Date;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashSet;
@@ -79,6 +84,15 @@ import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.net.jsse.JSSEImplementation;
import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public final class TesterSupport {
@@ -412,6 +426,68 @@ public final class TesterSupport {
new X500Principal(lastRequestedIssuers[0].getName()));
}
+ @FunctionalInterface
+ public interface CertificateExtensionsCustomizer {
+ void customize(KeyPair keyPair, X509v3CertificateBuilder certBuilder)
+ throws Exception;
+ }
+
+ /**
+ * Generate a temporary JKS keystore containing a self-signed RSA certificate.
+ *
+ * @param cn the Common Name for the certificate subject
+ * @param alias the keystore alias for the key entry
+ * @param sanNames DNS Subject Alternative Names to include, or {@code null} for none
+ * @param customizer callback to add extensions to the certificate, or {@code null} for none.
+ *
+ * @return a temporary keystore file with password {@link #JKS_PASS}
+ *
+ * @throws Exception if certificate generation or keystore creation fails
+ */
+ public static File generateKeystore(String cn, String alias, String[] sanNames,
+ CertificateExtensionsCustomizer customizer) throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(4096);
+ KeyPair keyPair = kpg.generateKeyPair();
+
+ X500Name subject = new X500Name("CN=" + cn);
+ BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
+ long oneDay = 86400000L;
+ Date notBefore = new Date(System.currentTimeMillis() - oneDay);
+ Date notAfter = new Date(System.currentTimeMillis() + 365L * oneDay);
+
+ X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(subject, serial, notBefore, notAfter,
+ subject, keyPair.getPublic());
+
+ if (sanNames != null && sanNames.length > 0) {
+ GeneralName[] generalNames = new GeneralName[sanNames.length];
+ for (int i = 0; i < sanNames.length; i++) {
+ generalNames[i] = new GeneralName(GeneralName.dNSName, sanNames[i]);
+ }
+ certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(generalNames));
+ }
+
+ if (customizer != null) {
+ customizer.customize(keyPair, certBuilder);
+ }
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
+ X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+ ks.setKeyEntry(alias, keyPair.getPrivate(), JKS_PASS.toCharArray(), new X509Certificate[] { certificate });
+
+ File keystoreFile = File.createTempFile("test-cert-", ".jks");
+ keystoreFile.deleteOnExit();
+ try (FileOutputStream fos = new FileOutputStream(keystoreFile)) {
+ ks.store(fos, JKS_PASS.toCharArray());
+ }
+
+ return keystoreFile;
+ }
+
+
public static final byte DATA = (byte)33;
public static class SimpleServlet extends HttpServlet {
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 06/06: Move generateKeystore() from TesterSupport to independent TesterKeystoreGenerator class
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 722464b256cde6104fcf26e5efd707e9ae9e37fa
Author: Dimitris Soumis <ji...@gmail.com>
AuthorDate: Fri Mar 27 20:46:19 2026 +0200
Move generateKeystore() from TesterSupport to independent TesterKeystoreGenerator class
---
.../tomcat/util/net/TestLargeClientHello.java | 2 +-
.../tomcat/util/net/TesterKeystoreGenerator.java | 103 +++++++++++++++++++++
test/org/apache/tomcat/util/net/TesterSupport.java | 76 ---------------
3 files changed, 104 insertions(+), 77 deletions(-)
diff --git a/test/org/apache/tomcat/util/net/TestLargeClientHello.java b/test/org/apache/tomcat/util/net/TestLargeClientHello.java
index c476fe0a24..43370f9c54 100644
--- a/test/org/apache/tomcat/util/net/TestLargeClientHello.java
+++ b/test/org/apache/tomcat/util/net/TestLargeClientHello.java
@@ -41,7 +41,7 @@ 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",
+ File keystoreFile = TesterKeystoreGenerator.generateKeystore("localhost", "tomcat",
new String[]{"localhost", "*.localhost"},
(keyPair, certBuilder) -> {
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
diff --git a/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
new file mode 100644
index 0000000000..9fd4affde6
--- /dev/null
+++ b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
@@ -0,0 +1,103 @@
+/*
+ * 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.io.FileOutputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+
+public final class TesterKeystoreGenerator {
+
+ private TesterKeystoreGenerator() {}
+
+ @FunctionalInterface
+ public interface CertificateExtensionsCustomizer {
+ void customize(KeyPair keyPair, X509v3CertificateBuilder certBuilder)
+ throws Exception;
+ }
+
+ /**
+ * Generate a temporary JKS keystore containing a self-signed RSA certificate.
+ *
+ * @param cn the Common Name for the certificate subject
+ * @param alias the keystore alias for the key entry
+ * @param sanNames DNS Subject Alternative Names to include, or {@code null} for none
+ * @param customizer callback to add extensions to the certificate, or {@code null} for none.
+ *
+ * @return a temporary keystore file with password {@link TesterSupport#JKS_PASS}
+ *
+ * @throws Exception if certificate generation or keystore creation fails
+ */
+ public static File generateKeystore(String cn, String alias, String[] sanNames,
+ CertificateExtensionsCustomizer customizer) throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(4096);
+ KeyPair keyPair = kpg.generateKeyPair();
+
+ X500Name subject = new X500Name("CN=" + cn);
+ BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
+ long oneDay = 86400000L;
+ Date notBefore = new Date(System.currentTimeMillis() - oneDay);
+ Date notAfter = new Date(System.currentTimeMillis() + 365L * oneDay);
+
+ X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(subject, serial, notBefore, notAfter,
+ subject, keyPair.getPublic());
+
+ if (sanNames != null && sanNames.length > 0) {
+ GeneralName[] generalNames = new GeneralName[sanNames.length];
+ for (int i = 0; i < sanNames.length; i++) {
+ generalNames[i] = new GeneralName(GeneralName.dNSName, sanNames[i]);
+ }
+ certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(generalNames));
+ }
+
+ if (customizer != null) {
+ customizer.customize(keyPair, certBuilder);
+ }
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
+ X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+ ks.setKeyEntry(alias, keyPair.getPrivate(), TesterSupport.JKS_PASS.toCharArray(), new X509Certificate[] { certificate });
+
+ File keystoreFile = File.createTempFile("test-cert-", ".jks");
+ keystoreFile.deleteOnExit();
+ try (FileOutputStream fos = new FileOutputStream(keystoreFile)) {
+ ks.store(fos, TesterSupport.JKS_PASS.toCharArray());
+ }
+
+ return keystoreFile;
+ }
+}
diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java b/test/org/apache/tomcat/util/net/TesterSupport.java
index 31a1c73240..9c3e0d2095 100644
--- a/test/org/apache/tomcat/util/net/TesterSupport.java
+++ b/test/org/apache/tomcat/util/net/TesterSupport.java
@@ -18,15 +18,11 @@ package org.apache.tomcat.util.net;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.math.BigInteger;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -40,7 +36,6 @@ import java.security.cert.PKIXRevocationChecker;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
-import java.util.Date;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashSet;
@@ -84,15 +79,6 @@ import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.net.jsse.JSSEImplementation;
import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public final class TesterSupport {
@@ -426,68 +412,6 @@ public final class TesterSupport {
new X500Principal(lastRequestedIssuers[0].getName()));
}
- @FunctionalInterface
- public interface CertificateExtensionsCustomizer {
- void customize(KeyPair keyPair, X509v3CertificateBuilder certBuilder)
- throws Exception;
- }
-
- /**
- * Generate a temporary JKS keystore containing a self-signed RSA certificate.
- *
- * @param cn the Common Name for the certificate subject
- * @param alias the keystore alias for the key entry
- * @param sanNames DNS Subject Alternative Names to include, or {@code null} for none
- * @param customizer callback to add extensions to the certificate, or {@code null} for none.
- *
- * @return a temporary keystore file with password {@link #JKS_PASS}
- *
- * @throws Exception if certificate generation or keystore creation fails
- */
- public static File generateKeystore(String cn, String alias, String[] sanNames,
- CertificateExtensionsCustomizer customizer) throws Exception {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
- kpg.initialize(4096);
- KeyPair keyPair = kpg.generateKeyPair();
-
- X500Name subject = new X500Name("CN=" + cn);
- BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
- long oneDay = 86400000L;
- Date notBefore = new Date(System.currentTimeMillis() - oneDay);
- Date notAfter = new Date(System.currentTimeMillis() + 365L * oneDay);
-
- X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(subject, serial, notBefore, notAfter,
- subject, keyPair.getPublic());
-
- if (sanNames != null && sanNames.length > 0) {
- GeneralName[] generalNames = new GeneralName[sanNames.length];
- for (int i = 0; i < sanNames.length; i++) {
- generalNames[i] = new GeneralName(GeneralName.dNSName, sanNames[i]);
- }
- certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(generalNames));
- }
-
- if (customizer != null) {
- customizer.customize(keyPair, certBuilder);
- }
-
- ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
- X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
-
- KeyStore ks = KeyStore.getInstance("JKS");
- ks.load(null, null);
- ks.setKeyEntry(alias, keyPair.getPrivate(), JKS_PASS.toCharArray(), new X509Certificate[] { certificate });
-
- File keystoreFile = File.createTempFile("test-cert-", ".jks");
- keystoreFile.deleteOnExit();
- try (FileOutputStream fos = new FileOutputStream(keystoreFile)) {
- ks.store(fos, JKS_PASS.toCharArray());
- }
-
- return keystoreFile;
- }
-
-
public static final byte DATA = (byte)33;
public static class SimpleServlet extends HttpServlet {
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 02/06: Add TestSSLAuthenticator
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 80bac5628f89d17931e34b66467a0b895a675789
Author: Dimitris Soumis <ji...@gmail.com>
AuthorDate: Tue Mar 24 14:21:59 2026 +0200
Add TestSSLAuthenticator
---
.../authenticator/TestSSLAuthenticator.java | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/test/org/apache/catalina/authenticator/TestSSLAuthenticator.java b/test/org/apache/catalina/authenticator/TestSSLAuthenticator.java
new file mode 100644
index 0000000000..346d06add8
--- /dev/null
+++ b/test/org/apache/catalina/authenticator/TestSSLAuthenticator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.catalina.authenticator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.net.TesterSupport;
+
+public class TestSSLAuthenticator extends TomcatBaseTest {
+
+ // https://bz.apache.org/bugzilla/show_bug.cgi?id=65991
+ @Test
+ public void testBindOnInitFalseNoNPE() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ TesterSupport.configureClientCertContext(tomcat);
+ Assert.assertTrue(tomcat.getConnector().setProperty("bindOnInit", "false"));
+
+ tomcat.start();
+ tomcat.stop();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 01/06: Fix naming convention of performance tests in BUILDING.txt
Posted by ds...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dsoumis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 766ea5e69445c43a02c79005e2f8337937561486
Author: Dimitris Soumis <ji...@gmail.com>
AuthorDate: Tue Mar 24 13:26:29 2026 +0200
Fix naming convention of performance tests in BUILDING.txt
---
BUILDING.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BUILDING.txt b/BUILDING.txt
index 0159b6803a..c5a285533c 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -570,7 +570,7 @@ NOTE: Cobertura is licensed under GPL v2 with parts of it being under
Where there is no benefit in running an absolute performance test as part
of a standard test run, the test will be excluded by naming it
- Tester*Performance.java.
+ Test*Performance.java.
The relative tests are included as part of a standard test run however,
where the assumptions made about host capabilities are not true (e.g. on
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org