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