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

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/master by this push:
     new e12589ecd Check CertificateStore for validity
e12589ecd is described below

commit e12589ecd3c7052b5b2d0d85066898015c73d863
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon Sep 21 14:05:51 2026 +0100

    Check CertificateStore for validity
---
 .../wss4j/common/crypto/CertificateStore.java      | 13 ++++++++
 .../components/crypto/CertificateStoreTest.java    | 38 +++++++++++++++++++++-
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
index 0ceba100f..b507fbe93 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
@@ -27,6 +27,8 @@ import java.security.PublicKey;
 import java.security.cert.CertPath;
 import java.security.cert.CertPathValidator;
 import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.PKIXParameters;
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
@@ -181,6 +183,17 @@ public class CertificateStore extends CryptoBase {
             // to ensure against phony DNs (compare encoded form including 
signature)
             //
             if (foundCerts != null && foundCerts.length > 0 && foundCerts[0] 
!= null && foundCerts[0].equals(certs[0])) {
+                // A directly trusted certificate still has to be within its 
validity period. The
+                // CertPathValidator enforces that on every other path through 
this method, so
+                // without this check an expired certificate would be accepted 
here and nowhere
+                // else.
+                try {
+                    certs[0].checkValidity();
+                } catch (CertificateExpiredException | 
CertificateNotYetValidException e) {
+                    throw new WSSecurityException(
+                        WSSecurityException.ErrorCode.FAILED_CHECK, e, 
"invalidCert"
+                    );
+                }
                 LOG.debug(
                     "Direct trust for certificate with {}", 
certs[0].getSubjectX500Principal().getName()
                 );
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/CertificateStoreTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/CertificateStoreTest.java
index 0231c8f79..2d2f2a35c 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/CertificateStoreTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/CertificateStoreTest.java
@@ -33,6 +33,7 @@ import org.apache.wss4j.common.crypto.CertificateStore;
 import org.apache.wss4j.common.crypto.Crypto;
 import org.apache.wss4j.common.crypto.CryptoFactory;
 import org.apache.wss4j.common.crypto.CryptoType;
+import org.apache.wss4j.common.crypto.Merlin;
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.util.XMLUtils;
 import org.apache.wss4j.dom.message.WSSecHeader;
@@ -44,9 +45,11 @@ import org.w3c.dom.Document;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 
 import javax.security.auth.callback.CallbackHandler;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -306,4 +309,37 @@ public class CertificateStoreTest {
     }
 
 
-}
\ No newline at end of file
+
+    /**
+     * A certificate that the CertificateStore holds directly is still only 
trusted while it is
+     * within its validity period. Every other path through verifyTrust runs 
the certificate
+     * through a CertPathValidator, which enforces that; the direct-trust 
shortcut has to enforce
+     * it itself.
+     */
+    @Test
+    public void testExpiredCertificateIsNotDirectlyTrusted() throws Exception {
+        Properties properties = new Properties();
+        properties.put("org.apache.wss4j.crypto.provider",
+                       "org.apache.wss4j.common.crypto.Merlin");
+        properties.put("org.apache.wss4j.crypto.merlin.keystore.type", "jks");
+        properties.put("org.apache.wss4j.crypto.merlin.keystore.password", 
"security");
+        properties.put("org.apache.wss4j.crypto.merlin.keystore.alias", 
"wss40exp");
+        properties.put("org.apache.wss4j.crypto.merlin.keystore.file", 
"keys/wss40exp.jks");
+        Crypto expiredCrypto = new Merlin(properties, 
this.getClass().getClassLoader(), null);
+
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
+        cryptoType.setAlias("wss40exp");
+        X509Certificate[] certChain = 
expiredCrypto.getX509Certificates(cryptoType);
+        assertNotNull(certChain);
+        // Only the leaf, so that the direct-trust shortcut in verifyTrust is 
the path taken
+        X509Certificate[] expiredCerts = new X509Certificate[] {certChain[0]};
+
+        Crypto certificateStore = new CertificateStore(expiredCerts);
+
+        WSSecurityException ex =
+            assertThrows(WSSecurityException.class,
+                () -> certificateStore.verifyTrust(expiredCerts, false, null, 
null));
+        assertEquals(WSSecurityException.ErrorCode.FAILED_CHECK, 
ex.getErrorCode());
+    }
+
+}

Reply via email to