pub struct CrlChecker<V> { /* private fields */ }crl only.Expand description
Offline CRL-based revocation checker.
Parses a DER-encoded CertificateList,
verifies its signature against the issuer’s SPKI, checks the
thisUpdate/nextUpdate validity window, and reports whether the
certificate’s serial number appears in the revoked list.
To also apply a delta CRL (RFC 5280 §5.2.4), use CrlChecker::with_delta.
§Feature
Only available when the crl feature is enabled.
§Return value semantics
RevocationChecker::check_revocation returns Ok(()) when the CRL covers
the certificate type and the serial number was not found in the revoked list
(not revoked).
When the CRL’s IssuingDistributionPoint scope flags
(onlyContainsUserCerts, onlyContainsCACerts, onlyContainsAttributeCerts)
indicate the CRL does not apply to this certificate type, the checker returns
Err(Error::OutOfScope) with a variant describing the mismatch.
Callers enforcing a hard-fail revocation policy should treat OutOfScope
as a non-determination and require that at least one CRL or OCSP response
actually covers the certificate in question.
§Indirect CRLs (RFC 5280 §5.2.6)
When the CRL is signed by a separate cRLIssuer certificate (rather
than by the cert’s own issuer), construct the checker with
CrlChecker::new_with_crl_issuer / CrlChecker::with_delta_and_crl_issuer.
The CRL’s IssuingDistributionPoint.indirectCRL flag must be TRUE,
and per-entry certificateIssuer extensions (RFC 5280 §5.3.3) are
honored to identify the actual issuer of each revoked entry. The
caller is responsible for having pre-validated the cRLIssuer’s chain
back to a trusted anchor.
§Limitations
- CRL distribution-point name matching (CDP vs IDP
distributionPoint) is implemented for both forms (fullNameandnameRelativeToCRLIssuer), withnameRelativeToCRLIssuerresolved by appending the relative RDN to the appropriate base DN (the certificate’s issuer for the cert’s CDP, the CRL’s issuer for the CRL’s IDP). Same-form direct comparison and cross-form resolved comparison both work, so a cert whose CDP usesnameRelativeToCRLIssuermatches a CRL whose IDP usesfullName(and vice versa) when both resolve to the same DN.GeneralName::DirectoryNameentries compare viapkix_path::names_match(proper DN equivalence); other variants (URI, dNSName, rfc822Name, IP address, etc.) compare via byte-exact DER encoding equality. The per-DPcRLIssuerfield on aDistributionPointentry is not currently honored when resolving the cert’s CDP base DN; the certificate’s issuer is always used. This is correct for the common case (RFC 5280 §4.2.1.13: “If the certificate issuer is also the CRL issuer, then conforming CAs MUST omit the cRLIssuer field”). Indirect CRLs with a non-issuer cRLIssuer that also usenameRelativeToCRLIssueron the cert’s CDP would resolve against the wrong base; that scenario has no PKITS coverage and is deferred. - Reasons-subset check (
onlySomeReasonson the IDP must cover the reasons the cert’s CDP asks to be checked, RFC 5280 §6.3.3(b)(1)) is not implemented. PKITS §4.14 fixtures do not exercise this. Tracked as future work; a separateOutOfScopeReasonvariant will be added at that time. - The checker enforces
onlyContainsUserCerts,onlyContainsCACerts, andonlyContainsAttributeCertsscope flags directly; seeOutOfScopeReasonfor the surfaced variants. - The cRLIssuer’s chain is NOT validated by this crate — callers must
present an already-validated cRLIssuer cert. Composing this with
pkix-pathto validate the cRLIssuer chain in-process is the umbrella crate’s responsibility (pkix-chain). - Path-level CRL signer discovery (RFC 5280 §6.3.3(f)) IS supported via
CrlChecker::new_with_signer_discoveryand the freediscover_crl_signerhelper, both gated by thecrlfeature. Discovery usesAuthorityKeyIdentifier→SubjectKeyIdentifiermatching with issuer-DN fallback, and verifies the discovered signer hascRLSigninKeyUsageand reaches a self-signed cert in the supplied bundle. Full RFC 5280 §6.1 validation of the signer’s chain remains the responsibility of higher-layer composers; see that constructor’s “Limitations” section for the project’s documented stance on the lenient-vs-strict tradeoff. - The
certificateIssuerextension’sissuerAltNameform (a non-DN GeneralName) is not currently used for entry-issuer lookup; only thedirectoryNameform is. Real-world indirect CRLs use directoryName. RevocationChecker::check_revocation_against_anchoris overridden. For the certificate issued directly by a trust anchor, the CRL is verified using the anchor’s subject DN and SPKI in place of the missing issuerCertificate. ThecRLSignKeyUsagecheck is omitted for trust anchors (anchors are trusted by construction; they carry noKeyUsageto inspect). If the CRL’s issuer name does not match the anchor, the method returnsError::CrlIssuerMismatchrather thanOk(()).
Implementations§
Source§impl<V: SignatureVerifier> CrlChecker<V>
impl<V: SignatureVerifier> CrlChecker<V>
Sourcepub fn new(
crl_der: impl AsRef<[u8]>,
now_unix: u64,
verifier: V,
) -> Result<Self>
pub fn new( crl_der: impl AsRef<[u8]>, now_unix: u64, verifier: V, ) -> Result<Self>
Create a new CrlChecker.
crl_der— DER-encodedCertificateList(anyAsRef<[u8]>, e.g.Vec<u8>or&[u8])now_unix— current time as seconds since the Unix epochverifier— signature verifier used to authenticate the CRL
The DER is parsed once at construction time and the parsed
CertificateList is reused on every check, eliminating per-check
re-parse work.
§Errors
Returns Error::CrlParseError if crl_der cannot be DER-decoded.
§Security
Do not pass a delta CRL (a CertificateList containing a
deltaCRLIndicator extension) as the sole crl_der argument. Delta CRLs
contain only the changes since the last base CRL; using one alone silently
under-covers revocations. Pass it via CrlChecker::with_delta together
with the matching base CRL to get correct coverage.
Sourcepub fn new_with_crl_issuer(
crl_der: impl AsRef<[u8]>,
crl_issuer_cert: Certificate,
now_unix: u64,
verifier: V,
) -> Result<Self>
pub fn new_with_crl_issuer( crl_der: impl AsRef<[u8]>, crl_issuer_cert: Certificate, now_unix: u64, verifier: V, ) -> Result<Self>
Create a CrlChecker for an indirect CRL (RFC 5280 §5.2.6).
crl_issuer_cert is the certificate that signed the CRL. It MUST
have its chain pre-validated by the caller back to a trusted
anchor — this crate verifies only the cRLIssuer-cert-to-CRL
relationship, not the cRLIssuer-cert-to-anchor chain.
The supplied CRL must declare itself indirect via its
IssuingDistributionPoint.indirectCRL flag (RFC 5280 §5.2.5);
otherwise Error::IndirectCrlIssuerUnexpected is returned at
check_revocation time.
§Errors
Returns Error::CrlParseError if crl_der cannot be DER-decoded.
Sourcepub fn new_with_signer_discovery(
crl_der: impl AsRef<[u8]>,
bundle: &[Certificate],
_cert_to_check: &Certificate,
now_unix: u64,
verifier: V,
) -> Result<Self>
pub fn new_with_signer_discovery( crl_der: impl AsRef<[u8]>, bundle: &[Certificate], _cert_to_check: &Certificate, now_unix: u64, verifier: V, ) -> Result<Self>
Create a CrlChecker that performs path-level CRL signer discovery
(RFC 5280 §6.3.3(f)).
The caller supplies an unordered bundle of candidate certificates
(typically the certs already collected for the chain plus any local
CRL-signer candidates) and the certificate that will subsequently be
revocation-checked. The function:
- Parses the CRL DER.
- Calls
discover_crl_signerto locate the cert inbundlethat signed the CRL (AKI/SKI walk with issuer-DN fallback). - Verifies the discovered signer has
cRLSignin itsKeyUsageextension (RFC 5280 §6.3.3(f)). A signer with noKeyUsageextension passes this check (RFC 5280 leaves the extension optional andpkix-revocationfollows the same fail-open interpretation asCrlChecker::new/new_with_crl_issuer). - Verifies the discovered signer chains structurally back to a self-signed (anchor-like) certificate present in the same bundle (see “Limitations” below for what “chains structurally” means and why it differs from full RFC 5280 §6.1 validation).
- Stores the discovered signer for use as the effective CRL
signer when
RevocationChecker::check_revocationis later called oncert_to_check. The signer is used regardless of whether the CRL’sIssuingDistributionPoint.indirectCRLflag is set, which is required to support PKITS §4.5 (direct CRLs signed by self-issued key-rollover bridge certs).
cert_to_check is the certificate whose revocation status will be
queried via check_revocation. It is taken at construction time
only for ergonomic symmetry with the discovery flow; the actual
revocation lookup happens at check_revocation call time. Passing
a different cert argument to check_revocation later is well-
defined: the stored signer is the one whose SPKI is used to
authenticate the CRL, but the (issuer, serial) lookup is driven
by the cert argument at call time.
§Errors
Error::CrlParseErrorifcrl_dercannot be DER-decoded.Error::CrlSignerNotFoundif no cert inbundlecould be identified as the CRL’s signer via AKI/SKI or issuer-DN match.Error::CrlSignMissingif the discovered signer has aKeyUsageextension that does not includecRLSign.Error::CrlSignerNotTrustedif the discovered signer cannot reach a self-signed cert inbundleby repeated AKI/SKI or issuer-DN walks.
§Limitations
No signature verification is performed on the signer’s chain.
Step 4 above is a structural reachability check — it verifies the
bundle contains an anchor for the signer, not that any of the
signatures along the way actually verify. This intentional
limitation preserves the project’s one-way dependency direction
(pkix-chain → pkix-revocation → pkix-path): pulling
pkix-path::validate_path into this constructor would invert that
direction.
Higher-layer composers that need full RFC 5280 §6.1 validation of
the signer’s path (signature, validity, name constraints, …) MUST
do that separately and then pass the validated cert via
CrlChecker::new_with_crl_issuer. This constructor is the
right choice when:
- The bundle is already known to be path-valid (e.g.,
pkix-chainalready validated it), OR - The caller accepts the project’s documented stance that bundle pre-validation is the caller’s responsibility.
The bundle slice is not retained. Only the discovered signer
Certificate is cloned and stored.
Sourcepub fn with_delta(
base_der: impl AsRef<[u8]>,
delta_der: impl AsRef<[u8]>,
now_unix: u64,
verifier: V,
) -> Result<Self>
pub fn with_delta( base_der: impl AsRef<[u8]>, delta_der: impl AsRef<[u8]>, now_unix: u64, verifier: V, ) -> Result<Self>
Create a CrlChecker with a base CRL and a delta CRL.
The delta CRL is merged into the base CRL per RFC 5280 §5.2.4:
- Entries in the delta that are not in the base are added.
- Entries in the delta with reason
removeFromCRLare removed from the base. - The merged result is used for all subsequent
check_revocationcalls.
§Errors
Returns Err(Error::CrlParseError) if either the base or delta CRL DER
cannot be decoded.
Returns Err(Error::DeltaCrlBaseMismatch) if:
- The delta CRL’s
BaseCRLNumberis absent (not a delta CRL), or - The delta’s
BaseCRLNumberis greater than the base CRL’sCRLNumber(the delta was produced against a newer base than the one supplied).
Sourcepub fn with_delta_and_crl_issuer(
base_der: impl AsRef<[u8]>,
delta_der: impl AsRef<[u8]>,
crl_issuer_cert: Certificate,
now_unix: u64,
verifier: V,
) -> Result<Self>
pub fn with_delta_and_crl_issuer( base_der: impl AsRef<[u8]>, delta_der: impl AsRef<[u8]>, crl_issuer_cert: Certificate, now_unix: u64, verifier: V, ) -> Result<Self>
Same as CrlChecker::new_with_crl_issuer plus a delta CRL.
The delta CRL must be signed by the same cRLIssuer cert and be
declared indirect via its own IssuingDistributionPoint.indirectCRL
flag (verified at check_revocation time).
§Errors
Same as CrlChecker::with_delta, plus the indirect-CRL gates
described in CrlChecker::new_with_crl_issuer.
Trait Implementations§
Source§impl<V: Clone> Clone for CrlChecker<V>
impl<V: Clone> Clone for CrlChecker<V>
Source§fn clone(&self) -> CrlChecker<V>
fn clone(&self) -> CrlChecker<V>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<V: Debug> Debug for CrlChecker<V>
impl<V: Debug> Debug for CrlChecker<V>
Source§impl<V: SignatureVerifier> RevocationChecker for CrlChecker<V>
impl<V: SignatureVerifier> RevocationChecker for CrlChecker<V>
Source§fn check_revocation_against_anchor(
&self,
cert: &Certificate,
anchor: &TrustAnchor,
) -> Result<()>
fn check_revocation_against_anchor( &self, cert: &Certificate, anchor: &TrustAnchor, ) -> Result<()>
Check revocation for cert issued directly by a trust anchor.
Uses the anchor’s subject and subject_public_key_info in place of
an issuer Certificate to verify the CRL. The cRLSign KeyUsage bit
check is omitted because trust anchors do not carry a Certificate with
extensions to inspect.
§Limitations
CRL discovery via the cRLDistributionPoints extension is by
design not implemented in pkix-revocation itself — this crate
stays no_std for its core types and does not perform network
I/O. The CRL DER must be supplied at construction time; for
online fetching from CRL DPs, use pkix-revocation-http.
Path-level CRL signer discovery (RFC 5280 §6.3.3(f)) IS supported
via CrlChecker::new_with_signer_discovery on the
check_revocation flow, but is not wired into the
check_revocation_against_anchor path: trust anchors do not carry
a Certificate for the bundle walk to terminate at, so the
anchor flow continues to require an explicit cRLIssuer cert for
indirect CRLs. Direct CRLs at the anchor level are unaffected.
If the CRL’s issuer name does not match the anchor’s subject, this
method returns Error::CrlIssuerMismatch rather than Ok(()),
ensuring a mismatched CRL is surfaced rather than silently skipped.
Source§fn check_revocation(
&self,
cert: &Certificate,
issuer: &Certificate,
) -> Result<()>
fn check_revocation( &self, cert: &Certificate, issuer: &Certificate, ) -> Result<()>
cert has been revoked. Read more