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


The following commit(s) were added to refs/heads/11.0.x by this push:
     new 297f127377 Revert "Select a JSSE certificate valid for TLS server 
authentication"
297f127377 is described below

commit 297f1273776ae0d550e30d923a12d778496e31f7
Author: Dimitris Soumis <[email protected]>
AuthorDate: Wed Oct 21 23:26:14 2026 +0300

    Revert "Select a JSSE certificate valid for TLS server authentication"
    
    This reverts commit 6bd6ec5c11bc31f0379f0cea6f80c6ab737f0cf6.
---
 java/org/apache/tomcat/util/net/Constants.java     |   7 -
 .../apache/tomcat/util/net/LocalStrings.properties |   4 -
 java/org/apache/tomcat/util/net/SSLUtilBase.java   | 107 -------------
 .../util/net/TestSSLUtilBaseKeyUsageSelection.java | 178 ---------------------
 .../tomcat/util/net/TesterKeystoreGenerator.java   |  84 ++--------
 webapps/docs/changelog.xml                         |   7 -
 webapps/docs/config/http.xml                       |  16 +-
 webapps/docs/ssl-howto.xml                         |  94 -----------
 8 files changed, 15 insertions(+), 482 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/Constants.java 
b/java/org/apache/tomcat/util/net/Constants.java
index 80fcbca6a9..1669adbfb3 100644
--- a/java/org/apache/tomcat/util/net/Constants.java
+++ b/java/org/apache/tomcat/util/net/Constants.java
@@ -68,13 +68,6 @@ public class Constants {
      */
     public static final String SSL_PROTO_SSLv2Hello = "SSLv2Hello";
 
-    /**
-     * EKU OIDs.
-     */
-    public static final String SERVER_AUTH_EXTENDED_KEY_USAGE_OID = 
"1.3.6.1.5.5.7.3.1";
-    public static final String CLIENT_AUTH_EXTENDED_KEY_USAGE_OID = 
"1.3.6.1.5.5.7.3.2";
-    public static final String ANY_EXTENDED_KEY_USAGE_OID = "2.5.29.37.0";
-
     /**
      * Private constructor to prevent instantiation.
      */
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index 404193ea40..44c9810470 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -182,16 +182,12 @@ sslUtilBase.alias_no_key_entry=Alias name [{0}] does not 
identify a key entry
 sslUtilBase.fipsPemNotSupported=FIPS enabled so PEM format certificate files 
are not supported. Configure the certificate using a key store rather than the 
certificateFile attribute
 sslUtilBase.invalidTrustManagerClassName=The trustManagerClassName provided 
[{0}] does not implement javax.net.ssl.TrustManager
 sslUtilBase.keystore_load_failed=Failed to load keystore type [{0}] with path 
[{1}] due to [{2}]
-sslUtilBase.multipleServerAuthCerts=Starting from alias [{0}], multiple 
certificates valid for TLS server authentication were found: [{1}]. The first 
one will be used.
 sslUtilBase.noCertFile=SSLHostConfig attribute certificateFile must be defined 
when using an SSL connector
 sslUtilBase.noCrlSupport=The truststoreProvider [{0}] does not support the 
certificateRevocationFile configuration option
 sslUtilBase.noKeys=No aliases for private keys found in key store
-sslUtilBase.noServerAuthCert=No certificate valid for TLS server 
authentication was found for alias [{0}]. The configured alias will be used 
unchanged.
 sslUtilBase.noVerificationDepth=The truststoreProvider [{0}] does not support 
the certificateVerificationDepth configuration option
 sslUtilBase.noneSupported=None of the [{0}] specified are supported by the SSL 
engine : [{1}]
-sslUtilBase.selectedServerAuthCert=Selected the certificate with alias [{0}] 
for TLS server authentication in preference to the configured alias [{1}]
 sslUtilBase.skipped=Tomcat interprets the [{0}] attribute in a manner 
consistent with the latest OpenSSL development branch. Some of the specified 
[{0}] are not supported by the configured SSL engine for this connector (which 
may use JSSE or an older OpenSSL version) and have been skipped: [{1}]
-sslUtilBase.skippedKeyUsage=Skipping certificate with alias [{0}] as it is not 
valid for TLS server authentication
 sslUtilBase.ssl3=SSLv3 has been explicitly enabled. This protocol is known to 
be insecure.
 sslUtilBase.tls13.auth=The JSSE TLS 1.3 implementation does not support post 
handshake authentication (PHA) and is therefore incompatible with optional 
certificate authentication
 sslUtilBase.trustedCertNotChecked=The validity dates of the trusted 
certificate with alias [{0}] were not checked as the certificate was of an 
unknown type
diff --git a/java/org/apache/tomcat/util/net/SSLUtilBase.java 
b/java/org/apache/tomcat/util/net/SSLUtilBase.java
index f8ecd64192..7c40846786 100644
--- a/java/org/apache/tomcat/util/net/SSLUtilBase.java
+++ b/java/org/apache/tomcat/util/net/SSLUtilBase.java
@@ -25,7 +25,6 @@ import java.nio.charset.StandardCharsets;
 import java.security.DomainLoadStoreParameter;
 import java.security.Key;
 import java.security.KeyStore;
-import java.security.KeyStoreException;
 import java.security.cert.CRL;
 import java.security.cert.CRLException;
 import java.security.cert.CertPathParameters;
@@ -37,7 +36,6 @@ import java.security.cert.CertificateException;
 import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.CertificateParsingException;
 import java.security.cert.CollectionCertStoreParameters;
 import java.security.cert.PKIXBuilderParameters;
 import java.security.cert.PKIXRevocationChecker;
@@ -61,7 +59,6 @@ import javax.net.ssl.SSLSessionContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509KeyManager;
-import javax.security.auth.x500.X500Principal;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -414,8 +411,6 @@ public abstract class SSLUtilBase implements SSLUtil {
                 }
             }
 
-            keyAlias = selectServerAuthAlias(ks, keyAlias, 
certificate.getCertificateKeyAlias() != null);
-
             Key k = ks.getKey(keyAlias, keyPassArray);
             if (k != null && 
!"DKS".equalsIgnoreCase(certificate.getCertificateKeystoreType()) &&
                     "PKCS#8".equalsIgnoreCase(k.getFormat())) {
@@ -455,108 +450,6 @@ public abstract class SSLUtilBase implements SSLUtil {
     }
 
 
-    /*
-     * Prefer a key entry whose certificate is usable for TLS server 
authentication. This handles key stores that can
-     * expose several certificates sharing a Subject (and therefore colliding 
on similar aliases).
-     * The certificate currently identified by the alias provides the Subject 
to match.
-     * When no alias was configured every key entry is a candidate.
-     * When no usable certificate is found, the configured alias is returned 
unchanged.
-     */
-    private String selectServerAuthAlias(KeyStore ks, String currentAlias, 
boolean aliasConfigured)
-        throws KeyStoreException, CertificateParsingException {
-
-        Certificate current = ks.getCertificate(currentAlias);
-        X509Certificate currentX509 = current instanceof X509Certificate x509 
? x509 : null;
-
-        // If the current selection is already usable there is nothing to do.
-        if (currentX509 != null && isServerAuthCapable(currentX509)) {
-            return currentAlias;
-        }
-
-        X500Principal subject = currentX509 == null ? null : 
currentX509.getSubjectX500Principal();
-
-        List<String> matches = new ArrayList<>();
-        // Defense-in-depth so no misbehaving provider can ever hang a 
TLS-config path.
-        int remaining = ks.size();
-        Enumeration<String> aliases = ks.aliases();
-        while (aliases.hasMoreElements() && remaining-- > 0) {
-            String alias = aliases.nextElement();
-            if (!ks.isKeyEntry(alias)) {
-                continue;
-            }
-            Certificate candidate = ks.getCertificate(alias);
-            if (!(candidate instanceof X509Certificate x509Candidate)) {
-                continue;
-            }
-            // When the user named an alias, only consider certificates that 
share its Subject.
-            if (aliasConfigured && subject != null && 
!subject.equals(x509Candidate.getSubjectX500Principal())) {
-                continue;
-            }
-            if (isServerAuthCapable(x509Candidate)) {
-                matches.add(alias);
-            } else if (log.isDebugEnabled()) {
-                log.debug(sm.getString("sslUtilBase.skippedKeyUsage", alias));
-            }
-        }
-
-        if (matches.isEmpty()) {
-            if (log.isDebugEnabled()) {
-                log.debug(sm.getString("sslUtilBase.noServerAuthCert", 
currentAlias));
-            }
-            return currentAlias;
-        }
-        if (matches.size() > 1 && log.isDebugEnabled()) {
-            log.debug(sm.getString("sslUtilBase.multipleServerAuthCerts", 
currentAlias, matches));
-        }
-        String selected = matches.get(0);
-        if (!selected.equals(currentAlias) && log.isDebugEnabled()) {
-            log.debug(sm.getString("sslUtilBase.selectedServerAuthCert", 
selected, currentAlias));
-        }
-        return selected;
-    }
-
-
-    /**
-     * Determines whether the given certificate may be used for TLS server 
authentication, based on its Extended Key
-     * Usage (EKU) extension. Called by {@link #selectServerAuthAlias} to 
choose between certificates that share a
-     * Subject.
-     * <p>
-     * The policy is deliberately lenient about absent usage and strict about 
declared usage:
-     * <ul>
-     * <li>A certificate with <strong>no EKU extension</strong> ({@link 
X509Certificate#getExtendedKeyUsage()} returns
-     *     {@code null}) is treated as usable. An absent EKU places no 
restriction on the certificate's purpose - the
-     *     way TLS implementations generally interpret such certificates - so 
rejecting them would needlessly exclude
-     *     the many server certificates issued without an EKU.</li>
-     * <li>A certificate that <strong>does</strong> carry an EKU extension is 
usable only if that extension explicitly
-     *     lists the {@code id-kp-serverAuth} OID ({@value 
Constants#SERVER_AUTH_EXTENDED_KEY_USAGE_OID}) or the
-     *     {@code anyExtendedKeyUsage} OID ({@value 
Constants#ANY_EXTENDED_KEY_USAGE_OID}). Any other declared usage
-     *     - for example a certificate limited to client authentication, such 
as a Remote Desktop authentication
-     *     certificate - is rejected, which is what lets this feature skip the 
wrong certificate.</li>
-     * </ul>
-     *
-     * @param cert the certificate to test
-     *
-     * @return {@code true} if the certificate may be used for TLS server 
authentication
-     *
-     * @throws CertificateParsingException if the Extended Key Usage extension 
cannot be decoded
-     */
-    private static boolean isServerAuthCapable(X509Certificate cert) throws 
CertificateParsingException {
-        List<String> objectIdentifiers = cert.getExtendedKeyUsage();
-
-        if (objectIdentifiers == null) {
-            return true;
-        }
-
-        for (String objectIdentifier : objectIdentifiers) {
-            if 
(objectIdentifier.equals(Constants.SERVER_AUTH_EXTENDED_KEY_USAGE_OID) ||
-                    
objectIdentifier.equals(Constants.ANY_EXTENDED_KEY_USAGE_OID)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     @Override
     public String[] getEnabledProtocols() {
         return enabledProtocols;
diff --git 
a/test/org/apache/tomcat/util/net/TestSSLUtilBaseKeyUsageSelection.java 
b/test/org/apache/tomcat/util/net/TestSSLUtilBaseKeyUsageSelection.java
deleted file mode 100644
index a64224c80b..0000000000
--- a/test/org/apache/tomcat/util/net/TestSSLUtilBaseKeyUsageSelection.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.security.cert.X509Certificate;
-import java.util.List;
-
-import javax.net.ssl.X509KeyManager;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
-import 
org.apache.tomcat.util.net.TesterKeystoreGenerator.CertificateExtensionsCustomizer;
-import org.apache.tomcat.util.net.TesterKeystoreGenerator.KeystoreEntry;
-import org.apache.tomcat.util.net.jsse.JSSEUtil;
-import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.KeyPurposeId;
-
-/**
- * Tests selection of a TLS server authentication certificate when a key store 
holds several certificates that share a
- * Subject.
- */
-public class TestSSLUtilBaseKeyUsageSelection {
-
-    private static final String HOST = "localhost";
-
-    @SuppressWarnings("unused")
-    private static final CertificateExtensionsCustomizer SERVER_AUTH = 
(keyPair, builder) -> builder
-            .addExtension(Extension.extendedKeyUsage, true, new 
ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
-    @SuppressWarnings("unused")
-    private static final CertificateExtensionsCustomizer CLIENT_AUTH = 
(keyPair, builder) -> builder
-            .addExtension(Extension.extendedKeyUsage, true, new 
ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));
-    @SuppressWarnings("unused")
-    private static final CertificateExtensionsCustomizer ANY_AUTH = (keyPair, 
builder) -> builder
-            .addExtension(Extension.extendedKeyUsage, true, new 
ExtendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage));
-
-
-    private static KeystoreEntry key(String alias, 
CertificateExtensionsCustomizer eku) {
-        return KeystoreEntry.key(alias, HOST, eku);
-    }
-
-
-    /*
-     * Builds a key store from the given entries, configures a JSSE 
certificate pointed at alias (null for none), and
-     * returns the leaf certificate the key manager actually presents.
-     */
-    private static X509Certificate present(String alias, KeystoreEntry... 
entries) throws Exception {
-        File keystore = 
TesterKeystoreGenerator.generateKeystore(List.of(entries));
-
-        SSLHostConfig hostConfig = new SSLHostConfig();
-        SSLHostConfigCertificate certificate = new 
SSLHostConfigCertificate(hostConfig, Type.UNDEFINED);
-        certificate.setCertificateKeystoreFile(keystore.getAbsolutePath());
-        certificate.setCertificateKeystorePassword(TesterSupport.JKS_PASS);
-        if (alias != null) {
-            certificate.setCertificateKeyAlias(alias);
-        }
-
-        X509KeyManager keyManager = (X509KeyManager) new 
JSSEUtil(certificate).getKeyManagers()[0];
-        X509Certificate[] chain = 
keyManager.getCertificateChain(keyManager.chooseServerAlias("RSA", null, null));
-        Assert.assertNotNull("Key manager returned no certificate chain", 
chain);
-        return chain[0];
-    }
-
-
-    private static void assertEku(X509Certificate certificate, String oid) 
throws Exception {
-        List<String> extendedKeyUsage = certificate.getExtendedKeyUsage();
-        Assert.assertNotNull("Presented certificate has no Extended Key 
Usage", extendedKeyUsage);
-        Assert.assertTrue("Presented certificate must be valid for Extended 
Key Usage " + oid,
-                extendedKeyUsage.contains(oid));
-    }
-
-
-    @Test
-    public void 
testSelectsServerAuthCertificateOverConfiguredClientAuthAlias() throws 
Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                key("localhost-server", SERVER_AUTH));
-        assertEku(presented, Constants.SERVER_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testKeepsConfiguredAliasWhenItIsAlreadyServerAuth() throws 
Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, SERVER_AUTH),
-                key("localhost-client", CLIENT_AUTH));
-        assertEku(presented, Constants.SERVER_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testSelectsCertificateWithAnyExtendedKeyUsage() throws 
Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                key("localhost-any", ANY_AUTH));
-        assertEku(presented, Constants.ANY_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testSelectsCertificateWithoutExtendedKeyUsage() throws 
Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                key("localhost-none", null));
-        Assert.assertNull("A certificate with no Extended Key Usage is 
unrestricted and must be selectable",
-                presented.getExtendedKeyUsage());
-    }
-
-
-    @Test
-    public void testSelectsServerAuthCertificateWhenNoAliasConfigured() throws 
Exception {
-        X509Certificate presented = present(null,
-                key("first", CLIENT_AUTH),
-                key("second", SERVER_AUTH));
-        assertEku(presented, Constants.SERVER_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testSelectsServerAuthCertificateWhenMultipleMatch() throws 
Exception {
-        // Two server-auth certificates share the Subject. Which one wins 
depends on key-store enumeration order,
-        // which JKS does not guarantee, so this only asserts that the 
ambiguity resolves to a server-auth
-        // certificate rather than the client-auth one - not which of the two 
is chosen.
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                key("localhost-s1", SERVER_AUTH),
-                key("localhost-s2", SERVER_AUTH));
-        assertEku(presented, Constants.SERVER_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testFallsBackToConfiguredAliasWhenNoServerAuthCertificate() 
throws Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                key("localhost-2", CLIENT_AUTH));
-        assertEku(presented, Constants.CLIENT_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testIgnoresServerAuthCertificateWithDifferentSubject() throws 
Exception {
-        X509Certificate presented = present(HOST,
-                key(HOST, CLIENT_AUTH),
-                KeystoreEntry.key("other-server", "other.example", 
SERVER_AUTH));
-        assertEku(presented, Constants.CLIENT_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-
-
-    @Test
-    public void testIgnoresTrustedCertificateEntries() throws Exception {
-        // The only server-auth-capable certificate is a trusted (keyless) 
entry, so it cannot be used as a server key.
-        // Selection must skip it and fall back to the configured key entry. 
If trusted entries were NOT skipped, the
-        // keyless "ca" would be chosen and the resulting key manager would 
have no chain for it.
-        X509Certificate presented = present(HOST,
-                KeystoreEntry.trusted("ca", HOST, SERVER_AUTH),
-                key(HOST, CLIENT_AUTH));
-        assertEku(presented, Constants.CLIENT_AUTH_EXTENDED_KEY_USAGE_OID);
-    }
-}
diff --git a/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java 
b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
index 480ddf045b..00f1772fcc 100644
--- a/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
+++ b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
@@ -26,7 +26,6 @@ import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
 import java.util.Date;
-import java.util.List;
 
 import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.Extension;
@@ -51,84 +50,25 @@ public final class TesterKeystoreGenerator {
     }
 
     /**
-     * Generate a temporary JKS keystore containing a single self-signed RSA 
certificate.
+     * 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
+     * @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}
+     *  @return a temporary keystore file with password {@link  
TesterSupport#JKS_PASS}
      *
-     * @throws Exception if certificate generation or keystore creation fails
+     *  @throws Exception if certificate generation or keystore creation fails
      */
     public static File generateKeystore(String cn, String alias, String[] 
sanNames,
                                         CertificateExtensionsCustomizer 
customizer) throws Exception {
-        CertAndKey generated = generateSelfSignedCertificate(cn, sanNames, 
customizer);
-
-        KeyStore ks = KeyStore.getInstance("JKS");
-        ks.load(null, null);
-        ks.setKeyEntry(alias, generated.keyPair().getPrivate(), 
TesterSupport.JKS_PASS.toCharArray(),
-                new X509Certificate[] { generated.certificate() });
-
-        return storeToTempFile(ks);
-    }
-
-    /**
-     * Generate a temporary JKS keystore from an explicit list of entries. 
Each entry has its own Common Name and may be
-     * either a private key entry or a trusted certificate entry, which lets 
tests reproduce stores that mix certificates
-     * with different Subjects and certificate-only (keyless) entries.
-     *
-     * @param entries the entries to add, in order
-     *
-     * @return a temporary keystore file with password {@link 
TesterSupport#JKS_PASS}
-     *
-     * @throws Exception if certificate generation or keystore creation fails
-     */
-    public static File generateKeystore(List<KeystoreEntry> entries) throws 
Exception {
-        KeyStore ks = KeyStore.getInstance("JKS");
-        ks.load(null, null);
-
-        for (KeystoreEntry entry : entries) {
-            CertAndKey generated = generateSelfSignedCertificate(entry.cn(), 
null, entry.customizer());
-            if (entry.keyEntry()) {
-                ks.setKeyEntry(entry.alias(), 
generated.keyPair().getPrivate(), TesterSupport.JKS_PASS.toCharArray(),
-                        new X509Certificate[] { generated.certificate() });
-            } else {
-                ks.setCertificateEntry(entry.alias(), generated.certificate());
-            }
-        }
-
-        return storeToTempFile(ks);
-    }
-
-    /**
-     * A single entry for {@link #generateKeystore(List)}.
-     *
-     * @param alias      the keystore alias
-     * @param cn         the certificate Subject Common Name
-     * @param keyEntry   {@code true} for a private key entry, {@code false} 
for a trusted certificate entry
-     * @param customizer extensions to add to the certificate, or {@code null} 
for none
-     */
-    public record KeystoreEntry(String alias, String cn, boolean keyEntry, 
CertificateExtensionsCustomizer customizer) {
-
-        public static KeystoreEntry key(String alias, String cn, 
CertificateExtensionsCustomizer customizer) {
-            return new KeystoreEntry(alias, cn, true, customizer);
-        }
-
-        public static KeystoreEntry trusted(String alias, String cn, 
CertificateExtensionsCustomizer customizer) {
-            return new KeystoreEntry(alias, cn, false, customizer);
-        }
-    }
-
-    private static CertAndKey generateSelfSignedCertificate(String cn, 
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.nanoTime());
+        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
         long oneDay = 86400000L;
         Date notBefore = new Date(System.currentTimeMillis() - oneDay);
         Date notAfter = new Date(System.currentTimeMillis() + 365L * oneDay);
@@ -150,17 +90,17 @@ public final class TesterKeystoreGenerator {
 
         ContentSigner signer = new 
JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
         X509Certificate certificate = new 
JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
-        return new CertAndKey(keyPair, certificate);
-    }
 
-    private record CertAndKey(KeyPair keyPair, X509Certificate certificate) {}
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+        ks.setKeyEntry(alias, keyPair.getPrivate(), 
TesterSupport.JKS_PASS.toCharArray(), new X509Certificate[] { certificate });
 
-    private static File storeToTempFile(KeyStore ks) throws Exception {
         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/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index a6725128b4..afc7c04bf6 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -407,13 +407,6 @@
         directly via the configured trust store) is not subject to OCSP
         checking. (markt)
       </fix>
-      <update>
-        When configuring a JSSE <code>Certificate</code> from a key store that
-        exposes several certificates sharing a Subject, ignore certificates
-        that are not valid for TLS server authentication so that a usable
-        certificate is selected rather than relying on the key store to
-        return the correct one for the configured alias. (dsoumis)
-      </update>
     </changelog>
   </subsection>
   <subsection name="Jasper">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 55378cae6e..acffcc5d7a 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -1702,12 +1702,6 @@
       the same order as they were added. If more than one key is present in the
       keystore it is strongly recommended that a keyAlias is configured to
       ensure that the correct key is used.</p>
-      <p>When several certificates in the key store share a Subject, Tomcat 
automatically ignores any that are
-      not valid for TLS server authentication - i.e. whose Extended Key Usage
-      excludes both <code>serverAuth</code> and 
<code>anyExtendedKeyUsage</code> -
-      so a usable certificate is selected. Certificates with no Extended Key 
Usage
-      extension are unrestricted and remain eligible. If none qualify, the
-      configured alias is used unchanged.</p>
     </attribute>
 
     <attribute name="certificateKeyFile" required="false">
@@ -1898,13 +1892,9 @@
   <subsection name="Key store types">
 
     <p>In addition to the standard key store types (JKS and PKCS12), most Java
-    runtimes support additional key store types such as Windows-MY, 
Windows-ROOT,
-    DKS as well as hardware security modules. On Windows, Windows-MY and
-    Windows-ROOT access the current user's certificate store, while
-    Windows-MY-LOCALMACHINE and Windows-ROOT-LOCALMACHINE access the local 
machine
-    store (reading the local machine store from a non-elevated process requires
-    Java 17.0.17, 21.0.9, 24 or later). Generally, to use these additional key
-    store types with a TLS Connector in Tomcat:</p>
+    runtimes support additional key store types such as Windows-ROOT,
+    Windows-My, DKS as well as hardware security modules. Generally, to use
+    these additional keystore types with a TLS Connector in Tomcat:</p>
 
     <ul>
       <li>Set the certificateKeystoreType and/or truststoreType Connector
diff --git a/webapps/docs/ssl-howto.xml b/webapps/docs/ssl-howto.xml
index 968655fa57..8ac7e61dfe 100644
--- a/webapps/docs/ssl-howto.xml
+++ b/webapps/docs/ssl-howto.xml
@@ -451,100 +451,6 @@ mailing list</a>.</p>
 </subsection>
 </section>
 
-<section name="Automatic certificate selection and reloading">
-
-<p>When a key store contains more than one certificate, Tomcat must choose 
which
-one to present to clients, and certificates must be replaced before they 
expire.
-Two features help to automate this so that a single configuration can be 
deployed
-to many hosts without per-host customization: selection of a certificate by key
-usage, and automatic reloading of renewed certificates.</p>
-
-<subsection name="Selecting a certificate by key usage">
-
-<p>When a key store holds several certificates - for example one intended for 
TLS
-server authentication alongside one intended for another purpose, which may 
share
-the same Subject - Tomcat selects a certificate that is valid for TLS server
-authentication. A certificate qualifies if its Extended Key Usage includes
-<code>serverAuth</code> or <code>anyExtendedKeyUsage</code>, or if it has no
-Extended Key Usage extension at all. Certificates that declare a different 
purpose,
-such as client authentication, are ignored.</p>
-
-<p>Because of this, it is usually not necessary to set
-<strong>certificateKeyAlias</strong>: Tomcat picks a usable server certificate
-automatically. When <strong>certificateKeyAlias</strong> is set, only 
certificates
-that share the Subject of that alias are considered.</p>
-
-<p>If no certificate valid for server authentication is found, the configured
-alias (or, when none is configured, the first key in the store) is used 
unchanged,
-so existing configurations are not affected.</p>
-
-</subsection>
-
-<subsection name="Reloading certificates before they expire">
-
-<p>When certificates are renewed by an external process the
-TLS certificate reload listener can load the renewed certificate without
-restarting Tomcat. Add it to the <strong>Server</strong> element:</p>
-
-<source><![CDATA[<Server ...>
-    <Listener 
className="org.apache.catalina.security.TLSCertificateReloadListener" />
-    ...
-</Server>]]></source>
-
-<p>The listener periodically checks each certificate and, when one is within
-<code>daysBefore</code> days of expiry (14 by default), reloads the associated
-<code>SSLHostConfig</code> so that the renewed certificate is picked up. See 
the
-<a href="config/listeners.html">listener documentation</a> for the available
-attributes.</p>
-
-</subsection>
-
-<subsection name="Example: the Windows certificate store">
-
-<p>On Windows, Tomcat can read certificates directly from the Windows 
certificate
-store. Set <strong>certificateKeystoreType</strong> to
-<code>Windows-MY-LOCALMACHINE</code> for the local machine store, or to
-<code>Windows-MY</code> for the current user's store. Reading the local machine
-store from a Tomcat service that is not running with elevated privileges 
requires
-Java 17.0.17, 21.0.9, 24, or a later release; on earlier releases the service 
must
-run with elevated privileges. This works well with AD CS autoenrollment, which
-issues and renews the machine's certificates automatically.</p>
-
-<p>The local machine store usually contains several certificates issued for the
-machine's name, such as a TLS server certificate and a Remote Desktop
-authentication certificate. Because Tomcat selects the certificate that is 
valid
-for server authentication, the same configuration can be deployed to every host
-with no <strong>certificateKeyAlias</strong>:</p>
-
-<source><![CDATA[<Connector port="8443" protocol="HTTP/1.1"
-    SSLEnabled="true" scheme="https" secure="true">
-    <SSLHostConfig>
-        <Certificate certificateKeystoreType="Windows-MY-LOCALMACHINE"
-            certificateKeystoreFile=""
-            certificateKeystorePassword=""
-            protocols="TLSv1.2,TLSv1.3" />
-    </SSLHostConfig>
-</Connector>]]></source>
-
-<p>Combined with the reload listener described above this gives fully automated
-certificate handling: AD CS issues and renews the certificate, while Tomcat
-selects the correct one and reloads it before it expires.</p>
-
-<p>Two points to note:</p>
-
-<ul>
-  <li>The account running Tomcat must have read access to the certificate's 
private
-      key. A renewed certificate may use a new key that does not inherit this
-      access, so grant it as part of the enrollment or renewal process.</li>
-  <li>If a host holds more than one certificate valid for server 
authentication,
-      set a unique friendly name on the intended certificate and use it as the
-      <strong>certificateKeyAlias</strong>.</li>
-</ul>
-
-</subsection>
-
-</section>
-
 <section name="Using OCSP Certificates">
 <p>Tomcat supports the Online Certificate Status Protocol (OCSP) to verify the
 status of client provided certificates for a sub-set of connector


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

Reply via email to