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());
+ }
+
+}