This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 852a742a89 Enable OCSP on the client side (to verify server certs)
852a742a89 is described below

commit 852a742a89ca26da7b9bf28e2c462ab7749ae122
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Dec 4 17:19:03 2025 +0000

    Enable OCSP on the client side (to verify server certs)
---
 test/org/apache/tomcat/util/net/TesterSupport.java |  66 +++++++--
 .../tomcat/util/net/ocsp/TestOcspEnabled.java      | 151 ++++++++++++++++++---
 2 files changed, 186 insertions(+), 31 deletions(-)

diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java 
b/test/org/apache/tomcat/util/net/TesterSupport.java
index 675b17cffe..548a5d8a75 100644
--- a/test/org/apache/tomcat/util/net/TesterSupport.java
+++ b/test/org/apache/tomcat/util/net/TesterSupport.java
@@ -24,12 +24,24 @@ import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.PrivateKey;
+import java.security.cert.CertPathValidator;
+import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
 import java.security.cert.X509Certificate;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
 
+import javax.net.ssl.CertPathTrustManagerParameters;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
@@ -214,33 +226,61 @@ public final class TesterSupport {
     }
 
     protected static TrustManager[] getTrustManagers() throws Exception {
-        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
-                TrustManagerFactory.getDefaultAlgorithm());
-        tmf.init(getKeyStore(CA_JKS));
+        return getTrustManagers(false);
+    }
+
+    protected static TrustManager[] getTrustManagers(boolean enableOcsp) 
throws Exception {
+        KeyStore trustStore = getKeyStore(CA_JKS);
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        if (enableOcsp) {
+            Set<TrustAnchor> trustAnchors = 
getTrustAnchorsFromKeystore(trustStore);
+            PKIXBuilderParameters pkix = new 
PKIXBuilderParameters(trustAnchors, new X509CertSelector());
+            PKIXRevocationChecker revocationChecker =
+                    (PKIXRevocationChecker) 
CertPathValidator.getInstance("PKIX").getRevocationChecker();
+            
revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));
+            pkix.addCertPathChecker(revocationChecker);
+            tmf.init(new CertPathTrustManagerParameters(pkix));
+        } else {
+            tmf.init(trustStore);
+        }
         return tmf.getTrustManagers();
     }
 
+    private static Set<TrustAnchor> getTrustAnchorsFromKeystore(KeyStore 
keyStore) throws KeyStoreException {
+        Set<TrustAnchor> trustAnchors = new HashSet<>();
+        Enumeration<String> aliases = keyStore.aliases();
+        while (aliases.hasMoreElements()) {
+            String alias = aliases.nextElement();
+            Certificate certificate = keyStore.getCertificate(alias);
+            if (certificate instanceof X509Certificate) {
+                trustAnchors.add(new TrustAnchor((X509Certificate) 
certificate, null));
+            }
+        }
+        return trustAnchors;
+    }
+
     public static ClientSSLSocketFactory configureClientSsl() {
-        return configureClientSsl(false, null, CLIENT_JKS);
+        return configureClientSsl(false, null, false, CLIENT_JKS);
     }
 
-    public static ClientSSLSocketFactory configureClientSsl(String keyStore) {
-        return configureClientSsl(false, null, keyStore);
+    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12) {
+        return configureClientSsl(forceTls12, null, false, CLIENT_JKS);
     }
 
     public static ClientSSLSocketFactory configureClientSsl(String[] ciphers) {
-        return configureClientSsl(false, ciphers, CLIENT_JKS);
+        return configureClientSsl(false, ciphers, false, CLIENT_JKS);
     }
 
-    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12) {
-        return configureClientSsl(forceTls12, null, CLIENT_JKS);
+    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12, String[] ciphers) {
+        return configureClientSsl(forceTls12, ciphers, false, CLIENT_JKS);
     }
 
-    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12, String[] ciphers) {
-        return configureClientSsl(forceTls12, ciphers, CLIENT_JKS);
+    public static ClientSSLSocketFactory configureClientSsl(boolean 
enableOcsp, String keyStore) {
+        return configureClientSsl(false, null, enableOcsp, keyStore);
     }
 
-    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12, String[] ciphers, String keyStore) {
+    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12, String[] ciphers, boolean enableOcsp,
+            String keyStore) {
         ClientSSLSocketFactory clientSSLSocketFactory = null;
         try {
             SSLContext sc;
@@ -249,7 +289,7 @@ public final class TesterSupport {
             } else {
                 sc = SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_2);
             }
-            sc.init(getUserKeyManagers(keyStore), getTrustManagers(), null);
+            sc.init(getUserKeyManagers(keyStore), 
getTrustManagers(enableOcsp), null);
             clientSSLSocketFactory = new 
ClientSSLSocketFactory(sc.getSocketFactory());
             if (ciphers != null) {
                 clientSSLSocketFactory.setCipher(ciphers);
diff --git a/test/org/apache/tomcat/util/net/ocsp/TestOcspEnabled.java 
b/test/org/apache/tomcat/util/net/ocsp/TestOcspEnabled.java
index e67d934b2c..e346c283e5 100644
--- a/test/org/apache/tomcat/util/net/ocsp/TestOcspEnabled.java
+++ b/test/org/apache/tomcat/util/net/ocsp/TestOcspEnabled.java
@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.junit.AfterClass;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -120,39 +121,133 @@ public class TestOcspEnabled extends TomcatBaseTest {
 
 
     @Test
-    public void testValidClientValidServerVerifyNone() throws Exception {
-        doTest(true, true, false, false, HttpServletResponse.SC_OK);
+    public void testRevokedClientRevokedServerVerifyNone() throws Exception {
+        doTest(false, false, ClientCertificateVerification.DISABLED, false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testRevokedClientRevokedServerVerifyServer() throws Exception {
+        doTest(false, false, ClientCertificateVerification.DISABLED, true);
     }
 
     @Test
-    public void testValidClientRevokedServerVerifyNone() throws Exception {
-        doTest(true, false, false, false, HttpServletResponse.SC_OK);
+    public void testRevokedClientRevokedServerVerifyClientOptional() throws 
Exception {
+        doTest(false, false, ClientCertificateVerification.OPTIONAL_NO_CA, 
false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void 
testRevokedClientRevokedServerVerifyClientOpionalVerifyServer() throws 
Exception {
+        // Same as false, false, false, true since server certificate is 
verified before client certificate
+        doTest(false, false, ClientCertificateVerification.OPTIONAL_NO_CA, 
true);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testRevokedClientRevokedServerVerifyClient() throws Exception {
+        doTest(false, false, ClientCertificateVerification.ENABLED, false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testRevokedClientRevokedServerVerifyBoth() throws Exception {
+        // Same as false, false, false, true since server certificate is 
verified before client certificate
+        doTest(false, false, ClientCertificateVerification.ENABLED, true);
     }
 
     @Test
     public void testRevokedClientValidServerVerifyNone() throws Exception {
-        doTest(false, true, false, false, HttpServletResponse.SC_OK);
+        doTest(false, true, ClientCertificateVerification.DISABLED, false);
     }
 
     @Test
-    public void testRevokedClientRevokedServerVerifyNone() throws Exception {
-        doTest(false, false, false, false, HttpServletResponse.SC_OK);
+    public void testRevokedClientValidServerVerifyServer() throws Exception {
+        doTest(false, true, ClientCertificateVerification.DISABLED, true);
     }
 
+    @Test
+    public void testRevokedClientValidServerVerifyClientOptional() throws 
Exception {
+        doTest(false, true, ClientCertificateVerification.OPTIONAL_NO_CA, 
false);
+    }
 
     @Test
-    public void testValidClientValidServerVerifyClient() throws Exception {
-        doTest(true, true, true, false, HttpServletResponse.SC_OK);
+    public void testRevokedClientValidServerVerifyClientOptionalVerifyServer() 
throws Exception {
+        doTest(false, true, ClientCertificateVerification.OPTIONAL_NO_CA, 
true);
     }
 
     @Test(expected = SSLHandshakeException.class)
     public void testRevokedClientValidServerVerifyClient() throws Exception {
-        doTest(false, true, true, false, HttpServletResponse.SC_OK);
+        doTest(false, true, ClientCertificateVerification.ENABLED, false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testRevokedClientValidServerVerifyBoth() throws Exception {
+        doTest(false, true, ClientCertificateVerification.ENABLED, true);
+    }
+
+    @Test
+    public void testValidClientRevokedServerVerifyNone() throws Exception {
+        doTest(true, false, ClientCertificateVerification.DISABLED, false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testValidClientRevokedServerVerifyServer() throws Exception {
+        doTest(true, false, ClientCertificateVerification.DISABLED, true);
+    }
+
+    @Test
+    public void testValidClientRevokedServerVerifyClientOptional() throws 
Exception {
+        doTest(true, false, ClientCertificateVerification.OPTIONAL_NO_CA, 
false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testValidClientRevokedServerVerifyClientOptionalVerifyServer() 
throws Exception {
+        doTest(true, false, ClientCertificateVerification.OPTIONAL_NO_CA, 
true);
+    }
+
+    @Test
+    public void testValidClientRevokedServerVerifyClient() throws Exception {
+        doTest(true, false, ClientCertificateVerification.ENABLED, false);
+    }
+
+    @Test(expected = SSLHandshakeException.class)
+    public void testValidClientRevokedServerVerifyBoth() throws Exception {
+        doTest(true, false, ClientCertificateVerification.ENABLED, true);
+    }
+
+    @Test
+    public void testValidClientValidServerVerifyNone() throws Exception {
+        doTest(true, true, ClientCertificateVerification.DISABLED, false);
+    }
+
+    @Test
+    public void testValidClientValidServerVerifyServer() throws Exception {
+        doTest(true, true, ClientCertificateVerification.DISABLED, true);
+    }
+
+    @Test
+    public void testValidClientValidServerVerifyClientOptional() throws 
Exception {
+        doTest(true, true, ClientCertificateVerification.OPTIONAL_NO_CA, 
false);
     }
 
+    @Test
+    public void testValidClientValidServerVerifyClientOptionalVerifyServer() 
throws Exception {
+        doTest(true, true, ClientCertificateVerification.OPTIONAL_NO_CA, true);
+    }
+
+    @Test
+    public void testValidClientValidServerVerifyClient() throws Exception {
+        doTest(true, true, ClientCertificateVerification.ENABLED, false);
+    }
+
+    @Test
+    public void testValidClientValidServerVerifyBoth() throws Exception {
+        doTest(true, true, ClientCertificateVerification.ENABLED, true);
+    }
+
+
+    private void doTest(boolean clientCertValid, boolean serverCertValid, 
ClientCertificateVerification verifyClientCert,
+            boolean verifyServerCert) throws Exception {
+
+        Assume.assumeFalse(!useOpenSSLTrust && verifyClientCert == 
ClientCertificateVerification.OPTIONAL_NO_CA);
 
-    private void doTest(boolean clientCertValid, boolean serverCertValid, 
boolean verifyClientCert,
-            boolean verifyServerCert, int expectedStatusCode) throws Exception 
{
         Tomcat tomcat = getTomcatInstance();
 
         // No file system docBase required
@@ -167,20 +262,40 @@ public class TestOcspEnabled extends TomcatBaseTest {
             TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_CRL_RSA_JKS, 
useOpenSSLTrust);
         }
         SSLHostConfig sslHostConfig = 
tomcat.getConnector().findSslHostConfigs()[0];
-        sslHostConfig.setCertificateVerification("required");
-        sslHostConfig.setOcspEnabled(verifyClientCert);
+        switch (verifyClientCert) {
+            case DISABLED:
+                sslHostConfig.setOcspEnabled(false);
+                sslHostConfig.setCertificateVerification("required");
+                break;
+            case ENABLED:
+                sslHostConfig.setOcspEnabled(true);
+                sslHostConfig.setCertificateVerification("required");
+                break;
+            case OPTIONAL_NO_CA:
+                sslHostConfig.setOcspEnabled(true);
+                sslHostConfig.setCertificateVerification("optionalNoCA");
+                break;
+
+        }
 
         if (clientCertValid) {
-            TesterSupport.configureClientSsl(TesterSupport.CLIENT_JKS);
+            TesterSupport.configureClientSsl(verifyServerCert, 
TesterSupport.CLIENT_JKS);
         } else {
-            TesterSupport.configureClientSsl(TesterSupport.CLIENT_CRL_JKS);
+            TesterSupport.configureClientSsl(verifyServerCert, 
TesterSupport.CLIENT_CRL_JKS);
         }
-        // TODO enable client-side OCSP checks
 
         tomcat.start();
 
         int rc = getUrl("https://localhost:"; + getPort() + "/simple", new 
ByteChunk(), false);
 
-        Assert.assertEquals(expectedStatusCode, rc);
+        // If the TLS handshake fails, the test won't get this far.
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+    }
+
+
+    private enum ClientCertificateVerification {
+        ENABLED,
+        OPTIONAL_NO_CA,
+        DISABLED
     }
 }


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

Reply via email to