apereo/cas · warning
All CRLs retrieved have expired. Applying CRL expiration…
Error message
All CRLs retrieved have expired. Applying CRL expiration policy...
What it means
Logged when every CRL retrieved for the certificate has expired (expiredCrls.size() == crls.size()). CAS then applies the configured expiredCRLPolicy (e.g. ALLOW, DENY, or throw), so this message usually precedes either an authentication denial or a policy-driven exception.
Solutions
- Obtain a current CRL from the CA and replace the expired one.
- Fix server clock/NTP if skew caused all CRLs to appear expired.
- Set the expired-CRL policy to ALLOW only if the security posture accepts validating against expired revocation data; otherwise keep DENY and treat this as a CA operational incident.
- Switch to OCSP revocation checking if CRL freshness cannot be guaranteed.
Example fix
// before cas.authn.x509.crl.expired-crl-policy=ALLOW // after cas.authn.x509.crl.expired-crl-policy=DENY # plus scheduled CRL refresh to keep data current
Defensive patterns
Strategy: fallback
Validate before calling
boolean allExpired = crls.stream().allMatch(c -> c.getNextUpdate() == null
|| c.getNextUpdate().toInstant().isBefore(Instant.now()));
if (allExpired) { /* refresh CRLs or fail fast before check() */ } Try / catch
try {
checker.check(cert);
} catch (GeneralSecurityException e) {
// expiredCRLPolicy=DENY path: surface as auth failure with reason
throw new GeneralSecurityException("All CRLs expired for cert", e);
} Prevention
- Automate CRL renewal so all CRLs never lapse simultaneously.
- Verify CA operational health — all-expired usually means the CA stopped publishing.
- Fix NTP/time sync before blaming CRL freshness.
- Choose expired-CRL policy deliberately and document the security tradeoff.
When it happens
Trigger: AbstractCRLRevocationChecker.check() runs and CertUtils.isExpired(crl) is true for all fetched CRLs — none are within their nextUpdate window.
Common situations: CA stopped publishing CRL updates (CA shutdown, subscription lapsed); long-outdated cached CRL resource configured in CAS; server clock far in the future due to misconfigured NTP.
Related errors
- CRL data expired on [ ]
- Could not decode provided CRL file
- Failed to establish a connection ldap and search.
- Unknown CRL reason code.
- Unable to fetch [ ]
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/70f0dbed9be1dd6a.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-x509-core/src/main/java/org/apereo/cas/adaptors/x509/authentication/revocation/checker/AbstractCRLRevocationChecker.java:77
@Override
public void check(@NonNull final X509Certificate cert) throws GeneralSecurityException {
LOGGER.debug("Evaluating certificate revocation status for [{}]", CertUtils.toString(cert));
val crls = getCRLs(cert);
if (crls == null || crls.isEmpty()) {
LOGGER.warn("CRL data is not available for [{}]", CertUtils.toString(cert));
this.unavailableCRLPolicy.apply(null);
return;
}
val expiredCrls = new ArrayList<X509CRL>(crls.size());
crls.stream().filter(CertUtils::isExpired).forEach(crl -> {
LOGGER.warn("CRL data expired on [{}]", crl.getNextUpdate());
expiredCrls.add(crl);
});
if (crls.size() == expiredCrls.size()) {
LOGGER.warn("All CRLs retrieved have expired. Applying CRL expiration policy...");
for (val crl : expiredCrls) {
this.expiredCRLPolicy.apply(crl);
}
} else {
crls.removeAll(expiredCrls);
LOGGER.debug("Valid CRLs [{}] found that are not expired yet", crls);
val revokedCrls = crls.stream().map(crl -> crl.getRevokedCertificate(cert)).filter(Objects::nonNull).toList();
if (revokedCrls.size() == crls.size()) {
val entry = revokedCrls.getFirst();
LOGGER.warn("All CRL entries have been revoked. Rejecting the first entry [{}]", entry);
throw new RevokedCertificateException(entry);
}
}
}
/**
* Records the addition of a new CRL entry.View on GitHub (pinned to e7288fc434)