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

  1. Obtain a current CRL from the CA and replace the expired one.
  2. Fix server clock/NTP if skew caused all CRLs to appear expired.
  3. 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.
  4. 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

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


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)