apereo/cas · warning
CRL data expired on [ ]
Error message
CRL data expired on [{}] What it means
Logged when one or more retrieved CRLs have passed their nextUpdate timestamp (CertUtils.isExpired). Each expired CRL is collected and reported with its nextUpdate date. Expiration itself is only a warning here; if ALL CRLs are expired, the expiredCRLPolicy is applied (see the next message).
Solutions
- Refresh the CRL: re-download from the CA's distribution point or update the local resource file.
- Check server clock/NTP sync ('timedatectl') to rule out skew.
- Configure CRL caching with a TTL shorter than the CA's CRL publish interval.
- Adjust the expired-CRL policy (allow/deny) if expired-but-usable CRLs should be tolerated, understanding the security tradeoff.
Example fix
// before cas.authn.x509.crl.resource.location=file:/etc/cas/crls/ca.crl // after # automate refresh (cron/systemd timer) so nextUpdate never lapses 0 * * * * curl -s https://crl.example.com/ca.crl -o /etc/cas/crls/ca.crl
Defensive patterns
Strategy: retry
Validate before calling
X509CRL crl = /* fetched */;
if (crl.getNextUpdate() != null && crl.getNextUpdate().toInstant().isBefore(java.time.Instant.now())) {
// refresh CRL before calling check()
} Type guard
boolean isStale = Optional.ofNullable(crl.getNextUpdate())
.map(d -> d.toInstant().isBefore(Instant.now()))
.orElse(true); Try / catch
try {
checker.check(cert);
} catch (GeneralSecurityException e) {
// expired-CRL policy (e.g. DENY) rejected the request
LOGGER.warn("CRL expired; attempt refresh and retry once", e);
} Prevention
- Schedule CRL refresh (cron/systemd timer) faster than the CA's publish interval.
- Use HTTP cache headers or a fetcher that honors nextUpdate.
- Keep server clocks synchronized via NTP.
- Alert when a cached CRL approaches its nextUpdate deadline.
When it happens
Trigger: AbstractCRLRevocationChecker.check() fetches CRLs whose thisUpdate/nextUpdate window has lapsed — i.e. the CA has not republished the CRL since nextUpdate passed.
Common situations: Stale CRL files cached on disk or in an HTTP cache past their validity window; an offline/broken CA that stopped publishing CRL updates; clock skew on the CAS server making valid CRLs appear expired.
Related errors
- Failed to establish a connection ldap and search.
- Unknown CRL reason code.
- CRL data is not available for
- All CRLs retrieved have expired. Applying CRL expiration…
- All CRL entries have been revoked. Rejecting the first entry
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/25630f16ac22415b.
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:72
this.checkAll = checkAll;
this.unavailableCRLPolicy = Objects.requireNonNullElseGet(unavailableCRLPolicy, DenyRevocationPolicy::new);
this.expiredCRLPolicy = Objects.requireNonNullElseGet(expiredCRLPolicy, () -> new ThresholdExpiredCRLRevocationPolicy(0));
}
@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);
}View on GitHub (pinned to e7288fc434)