F-5888: hard-fail OCSP revoked status regardless of SOFT_FAIL

pull/237/head
Chris Conlon 2026-07-07 12:37:13 -06:00
parent 21cfcc0bae
commit ac82b660c4
2 changed files with 68 additions and 0 deletions

View File

@ -41,6 +41,7 @@ import java.util.Set;
import com.wolfssl.wolfcrypt.WolfCrypt;
import com.wolfssl.wolfcrypt.WolfSSLCertManager;
import com.wolfssl.wolfcrypt.WolfCryptException;
import com.wolfssl.wolfcrypt.WolfCryptError;
import java.security.cert.TrustAnchor;
import javax.security.auth.x500.X500Principal;
@ -329,6 +330,13 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker {
"Failed to encode certificate", e);
} catch (WolfCryptException e) {
/* A definitive OCSP "revoked" status must always be a hard fail,
* with BasicReason.REVOKED. Other codes SOFT_FAIL may suppress. */
if (e.getCode() == WolfCryptError.OCSP_CERT_REVOKED.getCode()) {
throw new CertPathValidatorException(
"Certificate revoked (OCSP): " + e.getMessage(), e,
null, -1, BasicReason.REVOKED);
}
throw new CertPathValidatorException(
"OCSP check failed: " + e.getMessage(), e,
null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
@ -510,6 +518,11 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker {
private void handleException(CertPathValidatorException e)
throws CertPathValidatorException {
/* A confirmed revoked status is always a hard failure */
if (e.getReason() == BasicReason.REVOKED) {
throw e;
}
if (options.contains(Option.SOFT_FAIL)) {
softFailExceptions.add(e);
} else {

View File

@ -37,6 +37,7 @@ import java.security.Security;
import java.security.Provider;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.PKIXRevocationChecker.Option;
@ -52,6 +53,7 @@ import java.util.Set;
import com.wolfssl.wolfcrypt.WolfCrypt;
import com.wolfssl.wolfcrypt.WolfSSLCertManager;
import com.wolfssl.wolfcrypt.WolfCryptException;
import com.wolfssl.wolfcrypt.WolfCryptError;
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
import com.wolfssl.provider.jce.WolfCryptProvider;
import com.wolfssl.provider.jce.WolfCryptPKIXRevocationChecker;
@ -818,6 +820,59 @@ public class WolfCryptPKIXRevocationCheckerTest {
cm.free();
}
/* CertManager that simulates a definitive OCSP "revoked" response by
* throwing WolfCryptException(OCSP_CERT_REVOKED) from CertManagerCheckOCSP,
* exactly as native wolfSSL does for a revoked certificate. */
private static class RevokedOcspCertManager extends WolfSSLCertManager {
@Override
public synchronized void CertManagerCheckOCSP(byte[] cert, int sz) {
throw new WolfCryptException(
WolfCryptError.OCSP_CERT_REVOKED.getCode());
}
}
@Test
public void testOcspRevokedNotSuppressedBySoftFail() throws Exception {
if (!WolfCrypt.OcspEnabled()) {
/* Skip test if OCSP not compiled in */
return;
}
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
WolfCryptPKIXRevocationChecker checker =
(WolfCryptPKIXRevocationChecker)cpv.getRevocationChecker();
FileInputStream fis = new FileInputStream(caCertDer);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate)cf.generateCertificate(fis);
fis.close();
fis = new FileInputStream(serverCertDer);
X509Certificate serverCert =
(X509Certificate)cf.generateCertificate(fis);
fis.close();
/* SOFT_FAIL must not suppress a definitive revoked status. */
checker.setOptions(EnumSet.of(Option.SOFT_FAIL));
WolfSSLCertManager cm = new RevokedOcspCertManager();
cm.CertManagerLoadCA(caCert);
checker.setCertManager(cm);
checker.init(false);
try {
checker.check(serverCert, null);
fail("A revoked certificate must hard-fail even under SOFT_FAIL");
} catch (CertPathValidatorException e) {
assertEquals("Revoked cert must fail with BasicReason.REVOKED",
BasicReason.REVOKED, e.getReason());
}
cm.free();
}
@Test
public void testRevocationCheckerCheckWithCertChain() throws Exception {