Skip to main content

CrlChecker

Struct CrlChecker 

Source
pub struct CrlChecker<V> { /* private fields */ }
Available on crate feature 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 (fullName and nameRelativeToCRLIssuer), with nameRelativeToCRLIssuer resolved 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 uses nameRelativeToCRLIssuer matches a CRL whose IDP uses fullName (and vice versa) when both resolve to the same DN. GeneralName::DirectoryName entries compare via pkix_path::names_match (proper DN equivalence); other variants (URI, dNSName, rfc822Name, IP address, etc.) compare via byte-exact DER encoding equality. The per-DP cRLIssuer field on a DistributionPoint entry 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 use nameRelativeToCRLIssuer on the cert’s CDP would resolve against the wrong base; that scenario has no PKITS coverage and is deferred.
  • Reasons-subset check (onlySomeReasons on 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 separate OutOfScopeReason variant will be added at that time.
  • The checker enforces onlyContainsUserCerts, onlyContainsCACerts, and onlyContainsAttributeCerts scope flags directly; see OutOfScopeReason for 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-path to 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_discovery and the free discover_crl_signer helper, both gated by the crl feature. Discovery uses AuthorityKeyIdentifierSubjectKeyIdentifier matching with issuer-DN fallback, and verifies the discovered signer has cRLSign in KeyUsage and 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 certificateIssuer extension’s issuerAltName form (a non-DN GeneralName) is not currently used for entry-issuer lookup; only the directoryName form is. Real-world indirect CRLs use directoryName.
  • RevocationChecker::check_revocation_against_anchor is 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 issuer Certificate. The cRLSign KeyUsage check is omitted for trust anchors (anchors are trusted by construction; they carry no KeyUsage to inspect). If the CRL’s issuer name does not match the anchor, the method returns Error::CrlIssuerMismatch rather than Ok(()).

Implementations§

Source§

impl<V: SignatureVerifier> CrlChecker<V>

Source

pub fn new( crl_der: impl AsRef<[u8]>, now_unix: u64, verifier: V, ) -> Result<Self>

Create a new CrlChecker.

  • crl_der — DER-encoded CertificateList (any AsRef<[u8]>, e.g. Vec<u8> or &[u8])
  • now_unix — current time as seconds since the Unix epoch
  • verifier — 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.

Source

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.

Source

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:

  1. Parses the CRL DER.
  2. Calls discover_crl_signer to locate the cert in bundle that signed the CRL (AKI/SKI walk with issuer-DN fallback).
  3. Verifies the discovered signer has cRLSign in its KeyUsage extension (RFC 5280 §6.3.3(f)). A signer with no KeyUsage extension passes this check (RFC 5280 leaves the extension optional and pkix-revocation follows the same fail-open interpretation as CrlChecker::new / new_with_crl_issuer).
  4. 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).
  5. Stores the discovered signer for use as the effective CRL signer when RevocationChecker::check_revocation is later called on cert_to_check. The signer is used regardless of whether the CRL’s IssuingDistributionPoint.indirectCRL flag 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
§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-chainpkix-revocationpkix-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-chain already 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.

Source

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 removeFromCRL are removed from the base.
  • The merged result is used for all subsequent check_revocation calls.
§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 BaseCRLNumber is absent (not a delta CRL), or
  • The delta’s BaseCRLNumber is greater than the base CRL’s CRLNumber (the delta was produced against a newer base than the one supplied).
Source

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>

Source§

fn clone(&self) -> CrlChecker<V>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<V: Debug> Debug for CrlChecker<V>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<V: SignatureVerifier> RevocationChecker for CrlChecker<V>

Source§

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<()>

Check whether cert has been revoked. Read more

Auto Trait Implementations§

§

impl<V> Freeze for CrlChecker<V>
where V: Freeze,

§

impl<V> RefUnwindSafe for CrlChecker<V>
where V: RefUnwindSafe,

§

impl<V> Send for CrlChecker<V>
where V: Send,

§

impl<V> Sync for CrlChecker<V>
where V: Sync,

§

impl<V> Unpin for CrlChecker<V>
where V: Unpin,

§

impl<V> UnsafeUnpin for CrlChecker<V>
where V: UnsafeUnpin,

§

impl<V> UnwindSafe for CrlChecker<V>
where V: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V