F-11212: fail closed when PREFER_CRLS with NO_FALLBACK has no CRL source
parent
ec8d69466c
commit
a3da1774cc
|
|
@ -888,6 +888,10 @@ revoked, validation will fail. The difference only affects behavior when one
|
|||
method succeeds and the other would have failed (e.g., OCSP unreachable but
|
||||
CRL available).
|
||||
|
||||
A `PKIXRevocationChecker` added with `addCertPathChecker()` applies
|
||||
irregardless of if `setRevocationEnabled()` is set, so `PREFER_CRLS` with CRLs
|
||||
in the `CertStore` list performs CRL checking even when revocation is disabled.
|
||||
|
||||
#### Indirect CRL Not Supported
|
||||
|
||||
Native wolfSSL does not support indirect CRLs. An indirect CRL is a CRL signed
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ import java.security.cert.CertificateException;
|
|||
* validation will not return PolicyNode in CertPathValidatorResult
|
||||
*
|
||||
* Revocation checking is supported via:
|
||||
* - CRL: If PKIXParameters.isRevocationEnabled() is true and appropriate
|
||||
* - CRL: If PKIXParameters.isRevocationEnabled() is true, or a
|
||||
* PKIXRevocationChecker with PREFER_CRLS is registered, and appropriate
|
||||
* CRLs have been loaded into CertStore Set
|
||||
* - OCSP: via getRevocationChecker() which returns a
|
||||
* WolfCryptPKIXRevocationChecker supporting OCSP and options
|
||||
|
|
@ -839,25 +840,71 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
CertPath certPath, List<X509Certificate> certs)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
/* Report index of last cert in path (closest to trust anchor)
|
||||
* to match SunJCE behavior. */
|
||||
int failIndex = 0;
|
||||
if (certs != null && certs.size() > 1) {
|
||||
failIndex = certs.size() - 1;
|
||||
}
|
||||
throw new CertPathValidatorException(message, null, certPath,
|
||||
failIndex, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||
lastCertIndex(certs), BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if revocation has been enabled in PKIXParameters, and if so
|
||||
* find and load any CRLs in params.getCertStores().
|
||||
* Index of cert closest to the trust anchor.
|
||||
*
|
||||
* When a PKIXRevocationChecker is registered via addCertPathChecker(),
|
||||
* that checker handles revocation checking. CRL checking in the native
|
||||
* CertManager is only enabled if:
|
||||
* - No PKIXRevocationChecker is present (default CRL behavior), or
|
||||
* - PKIXRevocationChecker has PREFER_CRLS option set
|
||||
* @param certs certificate list from the CertPath
|
||||
*
|
||||
* @return index of the last cert, or 0 for a single-cert path
|
||||
*/
|
||||
private static int lastCertIndex(List<X509Certificate> certs) {
|
||||
|
||||
if (certs != null && certs.size() > 1) {
|
||||
return certs.size() - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable native CRL checking after a PREFER_CRLS checker found no CRL
|
||||
* to load, so wolfSSL doesn't fail chain validation on a missing CRL. With
|
||||
* NO_FALLBACK set, revocation is undetermined, which fails validation
|
||||
* unless SOFT_FAIL is set. Without NO_FALLBACK, the OCSP result the
|
||||
* checker already produced in check() propogates.
|
||||
*
|
||||
* @param revChecker the registered PREFER_CRLS checker
|
||||
* @param noFallback true if the checker has NO_FALLBACK set
|
||||
* @param cm WolfSSLCertManager with CRL checking enabled
|
||||
* @param certPath the CertPath being validated, for exception reporting
|
||||
* @param failIndex index of the cert to report
|
||||
*
|
||||
* @throws CertPathValidatorException if revocation is undetermined and
|
||||
* SOFT_FAIL is not set, or native CRL checking cannot be disabled
|
||||
*/
|
||||
private void handleMissingCrl(WolfCryptPKIXRevocationChecker revChecker,
|
||||
boolean noFallback, WolfSSLCertManager cm, CertPath certPath,
|
||||
int failIndex) throws CertPathValidatorException {
|
||||
|
||||
if (noFallback) {
|
||||
revChecker.handleMissingCrlRevocation(certPath, failIndex);
|
||||
}
|
||||
else {
|
||||
log("no CRL loaded, PREFER_CRLS checker falls back to OCSP");
|
||||
}
|
||||
|
||||
try {
|
||||
cm.CertManagerDisableCRL();
|
||||
}
|
||||
catch (WolfCryptException e) {
|
||||
throw new CertPathValidatorException("Failed to disable CRL " +
|
||||
"checking in native WolfSSLCertManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if CRL checking is wanted and, if so, find and load any CRLs in
|
||||
* params.getCertStores().
|
||||
*
|
||||
* CRL checking in the native CertManager is enabled when
|
||||
* PKIXParameters.isRevocationEnabled() is true, or when a
|
||||
* PKIXRevocationChecker with PREFER_CRLS is registered, which applies
|
||||
* irregardless of the revocation flag. A registered checker without
|
||||
* PREFER_CRLS handles revocation itself via OCSP.
|
||||
*
|
||||
* @param params parameters used to check if revocation is enabled and,
|
||||
* if so load any CRLs available
|
||||
|
|
@ -877,10 +924,13 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
int i = 0;
|
||||
int loadedCount = 0;
|
||||
int certCount = 0;
|
||||
int failIndex = lastCertIndex(certs);
|
||||
List<CertStore> stores = null;
|
||||
Collection<? extends CRL> crls = null;
|
||||
boolean hasRevocationChecker = false;
|
||||
boolean preferCrls = false;
|
||||
boolean noFallback = false;
|
||||
WolfCryptPKIXRevocationChecker revChecker = null;
|
||||
|
||||
if (params == null || cm == null) {
|
||||
throw new CertPathValidatorException(
|
||||
|
|
@ -894,13 +944,14 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
for (PKIXCertPathChecker checker : pathCheckers) {
|
||||
if (checker instanceof WolfCryptPKIXRevocationChecker) {
|
||||
hasRevocationChecker = true;
|
||||
WolfCryptPKIXRevocationChecker revChecker =
|
||||
(WolfCryptPKIXRevocationChecker)checker;
|
||||
revChecker = (WolfCryptPKIXRevocationChecker)checker;
|
||||
Set<PKIXRevocationChecker.Option> options =
|
||||
revChecker.getOptions();
|
||||
if (options != null && options.contains(
|
||||
PKIXRevocationChecker.Option.PREFER_CRLS)) {
|
||||
preferCrls = true;
|
||||
if (options != null) {
|
||||
preferCrls = options.contains(
|
||||
PKIXRevocationChecker.Option.PREFER_CRLS);
|
||||
noFallback = options.contains(
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -913,18 +964,24 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
return;
|
||||
}
|
||||
|
||||
if (params.isRevocationEnabled()) {
|
||||
log("revocation enabled in PKIXParameters, checking for CRLs " +
|
||||
"to load");
|
||||
if (params.isRevocationEnabled() || preferCrls) {
|
||||
log("revocation enabled or PREFER_CRLS checker registered, " +
|
||||
"checking for CRLs to load");
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
throw new CertPathValidatorException(
|
||||
"Revocation enabled in PKIXParameters but native " +
|
||||
"wolfCrypt CRL not compiled in");
|
||||
"CRL checking requested but native wolfCrypt CRL not " +
|
||||
"compiled in");
|
||||
}
|
||||
|
||||
/* Enable CRL in native WolfSSLCertManager */
|
||||
cm.CertManagerEnableCRL(WolfCrypt.WOLFSSL_CRL_CHECK);
|
||||
try {
|
||||
cm.CertManagerEnableCRL(WolfCrypt.WOLFSSL_CRL_CHECK);
|
||||
}
|
||||
catch (WolfCryptException e) {
|
||||
throw new CertPathValidatorException("Failed to enable CRL " +
|
||||
"checking in native WolfSSLCertManager", e);
|
||||
}
|
||||
log("CRL support enabled in native WolfSSLCertManager");
|
||||
|
||||
stores = params.getCertStores();
|
||||
|
|
@ -940,6 +997,10 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
"and no PKIXRevocationChecker configured for OCSP",
|
||||
certPath, certs);
|
||||
}
|
||||
else {
|
||||
handleMissingCrl(revChecker, noFallback, cm, certPath,
|
||||
failIndex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -990,22 +1051,32 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
}
|
||||
} catch (CertStoreException e) {
|
||||
throw new CertPathValidatorException(e);
|
||||
} catch (WolfCryptException e) {
|
||||
throw new CertPathValidatorException(
|
||||
"Failed to load CRL into native WolfSSLCertManager", e);
|
||||
}
|
||||
|
||||
log("loaded " + loadedCount + " CRLs into WolfSSLCertManager");
|
||||
|
||||
/* If no CRLs were loaded and no PKIXRevocationChecker is handling
|
||||
* OCSP, we cannot determine revocation status. */
|
||||
if (loadedCount == 0 && !hasRevocationChecker) {
|
||||
throwUndeterminedRevocationStatus(
|
||||
"Revocation checking enabled but no CRLs found in " +
|
||||
"CertStores and no PKIXRevocationChecker configured " +
|
||||
"for OCSP",
|
||||
certPath, certs);
|
||||
if (loadedCount == 0) {
|
||||
if (!hasRevocationChecker) {
|
||||
throwUndeterminedRevocationStatus(
|
||||
"Revocation checking enabled but no CRLs found in " +
|
||||
"CertStores and no PKIXRevocationChecker configured " +
|
||||
"for OCSP",
|
||||
certPath, certs);
|
||||
}
|
||||
else {
|
||||
handleMissingCrl(revChecker, noFallback, cm, certPath,
|
||||
failIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log("revocation not enabled in PKIXParameters");
|
||||
log("revocation not enabled in PKIXParameters and no PREFER_CRLS" +
|
||||
"checker registered");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ package com.wolfssl.provider.jce;
|
|||
import java.net.URI;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.Extension;
|
||||
|
|
@ -543,6 +544,27 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail closed when a PREFER_CRLS/NO_FALLBACK checker has no CRL source.
|
||||
*
|
||||
* check() runs before CRLs are loaded and cannot see whether a CRL source
|
||||
* is configured, so the validator calls this after CRL setup. With OCSP
|
||||
* suppressed by NO_FALLBACK and no CRL to check, revocation status is
|
||||
* undetermined. Honors SOFT_FAIL via handleException().
|
||||
*
|
||||
* @param certPath the CertPath being validated, for exception reporting
|
||||
* @param index index of the cert whose revocation status is undetermined
|
||||
*
|
||||
* @throws CertPathValidatorException if SOFT_FAIL is not set
|
||||
*/
|
||||
void handleMissingCrlRevocation(CertPath certPath, int index)
|
||||
throws CertPathValidatorException {
|
||||
handleException(new CertPathValidatorException(
|
||||
"PREFER_CRLS with NO_FALLBACK selected but no CRL source is " +
|
||||
"available, revocation status cannot be determined", null,
|
||||
certPath, index, BasicReason.UNDETERMINED_REVOCATION_STATUS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set OCSP responder URI override.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.junit.BeforeClass;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -41,6 +42,10 @@ import java.io.File;
|
|||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Arrays;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.security.Security;
|
||||
import java.security.Provider;
|
||||
|
|
@ -57,6 +62,7 @@ import java.security.cert.CertPath;
|
|||
import java.security.cert.CertPathValidator;
|
||||
import java.security.cert.CertPathValidatorResult;
|
||||
import java.security.cert.PKIXParameters;
|
||||
import java.security.cert.PKIXRevocationChecker;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.PKIXCertPathValidatorResult;
|
||||
import java.security.cert.CertificateException;
|
||||
|
|
@ -97,6 +103,7 @@ public class WolfCryptPKIXCertPathValidatorTest {
|
|||
protected static String caCertDer = null; /* ca-cert.der */
|
||||
protected static String caEccCertDer = null; /* ca-ecc-cert.der */
|
||||
protected static String crlDer = null; /* crl.der */
|
||||
protected static String crlRevoked = null; /* crl.revoked */
|
||||
|
||||
/* RSA-based cert chain with intermediates:
|
||||
* server/peer: server-int-cert.pem/der
|
||||
|
|
@ -208,6 +215,8 @@ public class WolfCryptPKIXCertPathValidatorTest {
|
|||
|
||||
crlDer =
|
||||
certPre.concat("examples/certs/crl/crl.der");
|
||||
crlRevoked =
|
||||
certPre.concat("examples/certs/crl/crl.revoked");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -314,6 +323,312 @@ public class WolfCryptPKIXCertPathValidatorTest {
|
|||
checkPKIXCertPathValidatorResult(result, caCert, certPubKey);
|
||||
}
|
||||
|
||||
/* Build a single server-cert path validated against the RSA CA anchor. */
|
||||
private CertPath singleServerCertPath(CertificateFactory certFactory)
|
||||
throws Exception {
|
||||
|
||||
List<Certificate> certList = new ArrayList<>();
|
||||
InputStream fis = new FileInputStream(serverCertDer);
|
||||
certList.add(certFactory.generateCertificate(fis));
|
||||
fis.close();
|
||||
return certFactory.generateCertPath(certList);
|
||||
}
|
||||
|
||||
/**
|
||||
* PREFER_CRLS with NO_FALLBACK and no CRL source must fail closed with
|
||||
* UNDETERMINED_REVOCATION_STATUS.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackWithoutCrlFailsClosed()
|
||||
throws Exception {
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(false);
|
||||
params.addCertPathChecker(rc);
|
||||
|
||||
try {
|
||||
cpv.validate(path, params);
|
||||
fail("Validation should fail closed with no CRL source");
|
||||
} catch (CertPathValidatorException e) {
|
||||
assertEquals(BasicReason.UNDETERMINED_REVOCATION_STATUS,
|
||||
e.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With SOFT_FAIL, the missing-CRL determination is soft, so validation
|
||||
* completes instead of failing closed. The soft-fail exception is not
|
||||
* asserted here because addCertPathChecker() clones rc, so it lands on
|
||||
* the clone rather than rc.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackWithoutCrlSoftFailPasses()
|
||||
throws Exception {
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv =
|
||||
CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK,
|
||||
PKIXRevocationChecker.Option.SOFT_FAIL));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(false);
|
||||
params.addCertPathChecker(rc);
|
||||
|
||||
cpv.validate(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* SOFT_FAIL with revocation enabled but no CRL source must also complete.
|
||||
* Revocation turns on the native CRL check, so the missing-CRL path must
|
||||
* disable it under SOFT_FAIL to avoid a hard CRL_MISSING failure.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackRevocationEnabledSoftFailPasses()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println("CertPathValidator revocation status test " +
|
||||
"skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK,
|
||||
PKIXRevocationChecker.Option.SOFT_FAIL));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(true);
|
||||
params.addCertPathChecker(rc);
|
||||
|
||||
cpv.validate(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a CRL from a file. Some CRL files carry a PEM text dump ahead
|
||||
* of the PEM block, which not every CertificateFactory skips, so start
|
||||
* at the PEM header when one is present.
|
||||
*/
|
||||
private CRL crlFromFile(CertificateFactory certFactory, String path)
|
||||
throws Exception {
|
||||
|
||||
byte[] data = Files.readAllBytes(Paths.get(path));
|
||||
int begin = new String(data, StandardCharsets.US_ASCII)
|
||||
.indexOf("-----BEGIN X509 CRL-----");
|
||||
|
||||
if (begin > 0) {
|
||||
data = Arrays.copyOfRange(data, begin, data.length);
|
||||
}
|
||||
return certFactory.generateCRL(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the single server cert with a PREFER_CRLS/NO_FALLBACK checker
|
||||
* and the given CRL supplied through a CertStore.
|
||||
*/
|
||||
private void validatePreferCrlsNoFallbackWithCrl(String crlPath,
|
||||
boolean revocationEnabled) throws Exception {
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK));
|
||||
|
||||
/* CRL files are issued by ca-cert.der, the root for server-cert */
|
||||
Collection<CRL> crls = new HashSet<>();
|
||||
crls.add(crlFromFile(certFactory, crlPath));
|
||||
List<CertStore> certStores = new ArrayList<>();
|
||||
certStores.add(CertStore.getInstance("Collection",
|
||||
new CollectionCertStoreParameters(crls)));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setCertStores(certStores);
|
||||
params.setRevocationEnabled(revocationEnabled);
|
||||
params.addCertPathChecker(rc);
|
||||
|
||||
cpv.validate(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a server cert with a PREFER_CRLS checker that allows OCSP
|
||||
* fallback, SOFT_FAIL set, and no CRL source.
|
||||
*/
|
||||
private void validatePreferCrlsFallbackSoftFailWithoutCrl(
|
||||
boolean revocationEnabled) throws Exception {
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.SOFT_FAIL));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(revocationEnabled);
|
||||
params.addCertPathChecker(rc);
|
||||
|
||||
cpv.validate(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* PREFER_CRLS with fallback allowed and no CRL source must not fail on
|
||||
* a missing CRL, revocation is then determined by OCSP alone. With
|
||||
* SOFT_FAIL an unreachable OCSP responder is not fatal, so validation
|
||||
* should complete successfully.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsFallbackWithoutCrlSoftFailPasses()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println(
|
||||
"PREFER_CRLS fallback test skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
validatePreferCrlsFallbackSoftFailWithoutCrl(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* PREFER_CRLS with fallback allowed, SOFT_FAIL, no CRL source, and
|
||||
* revocation enabled must not fail on the missing CRL, revocation is
|
||||
* then determined only by OCSP.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsFallbackEnabledWithoutCrlSoftFailPasses()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println(
|
||||
"PREFER_CRLS fallback test skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
validatePreferCrlsFallbackSoftFailWithoutCrl(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A PREFER_CRLS/NO_FALLBACK checker with CRLs actually loaded must still
|
||||
* validate a non-revoked cert. The missing-CRL fail-closed path must not
|
||||
* fire when a CRL source is present.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackWithCrlValidates()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println(
|
||||
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
validatePreferCrlsNoFallbackWithCrl(crlDer, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A checker added with addCertPathChecker() applies irrespective of
|
||||
* setRevocationEnabled(), so PREFER_CRLS with a CRL in the CertStores is
|
||||
* a supported CRL-only setup even with revocation disabled.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackRevocationDisabledWithCrlValidates()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println(
|
||||
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
validatePreferCrlsNoFallbackWithCrl(crlDer, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* PREFER_CRLS with NO_FALLBACK, revocation disabled, and a CRL in the
|
||||
* CertStores that revokes the server cert must fail validation, proving
|
||||
* the supplied CRL is checked and not just ignored.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackRevocationDisabledRevokedFails()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println(
|
||||
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
validatePreferCrlsNoFallbackWithCrl(crlRevoked, false);
|
||||
fail("Revoked cert should fail with revocation disabled and " +
|
||||
"PREFER_CRLS");
|
||||
|
||||
} catch (CertPathValidatorException e) {
|
||||
/* expected */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that setting the target cert constraints with
|
||||
* PKIXParameters.setTargetCertConstraints() passes with correct cert
|
||||
|
|
@ -2049,6 +2364,96 @@ public class WolfCryptPKIXCertPathValidatorTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PREFER_CRLS/NO_FALLBACK with revocation enabled and a CertStore that
|
||||
* loads no matching CRL (loadedCount == 0) must fail closed.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackEmptyCertStoreFailsClosed()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println("CertPathValidator revocation status test " +
|
||||
"skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(true);
|
||||
params.addCertPathChecker(rc);
|
||||
/* Non-empty store list holding no matching CRL drives loadedCount 0 */
|
||||
List<CertStore> certStores = new ArrayList<>();
|
||||
certStores.add(CertStore.getInstance("Collection",
|
||||
new CollectionCertStoreParameters(new HashSet<CRL>())));
|
||||
params.setCertStores(certStores);
|
||||
|
||||
try {
|
||||
cpv.validate(path, params);
|
||||
fail("Expected UNDETERMINED_REVOCATION_STATUS");
|
||||
} catch (CertPathValidatorException e) {
|
||||
assertEquals(BasicReason.UNDETERMINED_REVOCATION_STATUS,
|
||||
e.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above with SOFT_FAIL, validation must complete because the
|
||||
* missing-CRL path disables the native CRL check.
|
||||
*/
|
||||
@Test
|
||||
public void testPreferCrlsNoFallbackEmptyCertStoreSoftFailPasses()
|
||||
throws Exception {
|
||||
|
||||
if (!WolfCrypt.CrlEnabled()) {
|
||||
System.out.println("CertPathValidator revocation status test " +
|
||||
"skipped, CRL not compiled in");
|
||||
return;
|
||||
}
|
||||
|
||||
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
|
||||
keyStorePass);
|
||||
if (store == null || store.size() != 1) {
|
||||
throw new Exception("Error creating KeyStore");
|
||||
}
|
||||
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
CertPath path = singleServerCertPath(certFactory);
|
||||
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
||||
|
||||
PKIXRevocationChecker rc =
|
||||
(PKIXRevocationChecker) cpv.getRevocationChecker();
|
||||
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK,
|
||||
PKIXRevocationChecker.Option.SOFT_FAIL));
|
||||
|
||||
PKIXParameters params = new PKIXParameters(store);
|
||||
params.setRevocationEnabled(true);
|
||||
params.addCertPathChecker(rc);
|
||||
List<CertStore> certStores = new ArrayList<>();
|
||||
certStores.add(CertStore.getInstance("Collection",
|
||||
new CollectionCertStoreParameters(new HashSet<CRL>())));
|
||||
params.setCertStores(certStores);
|
||||
|
||||
cpv.validate(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that zero-length cert paths are valid per RFC 5280. This occurs
|
||||
* when CertPathBuilder determines the trust anchor itself is the target.
|
||||
|
|
|
|||
Loading…
Reference in New Issue