GHSA-pwjx-qhcg-rvj4
ADVISORY - githubSummary
There is a certificate revocation enforcement bug in rustls-webpki CRL processing. when both the certificate CRL distribution point and the CRL issuing distribution point contain multiple URI names, IssuingDistributionPoint::authoritative_for() reuses one-shot DER iterators across nested comparisons. If the only matching URI pair appears later in both sequences, the implementation misses the match, treats the CRL as non-authoritative, and under UnknownStatusPolicy::Allow accepts a revoked certificate.
affected versions
revocation support shipped in 0.104.0-alpha.4, and the same iterator-reuse logic is still present at commit e4590782afc1207c3e46ba1249e7c3fb9da95198 on 2026-03-20. i did not identify an upstream fix as of that date.
affected component
- component: CRL authority matching for certificate DP vs CRL IDP names
- repo pin:
https://github.com/rustls/webpki@e4590782afc1207c3e46ba1249e7c3fb9da95198 - callsite:
src/crl/types.rs:626,src/crl/types.rs:649,src/crl/types.rs:664 - pinned source: https://github.com/rustls/webpki/blob/e4590782afc1207c3e46ba1249e7c3fb9da95198/src/crl/types.rs#L626-L678
technical details
RFC 5280 section 5.2.5 and section 6.3.3(b)(2)(i) require the verifier to check whether one of the names in the IDP matches one of the names in the certificate DP. the current implementation contradicts that requirement in the later-match case because iterator state, not the actual set of URI names, determines whether later names are considered.
the attached PoC uses a single trust anchor and a single relevant CRL path. there is no alternate unconstrained root or duplicate trust path for the same key material, so the acceptance result is attributable to the DP/IDP matching bug rather than chain-builder fallback.
the vulnerable flow is:
authoritative_for()parsesidp_general_namesonce before iterating certificate distribution points.- each certificate DP fullName is parsed into another one-shot
DerIterator. uri_name_in_common()iterates the first IDP URI and drains the DP iterator while looking for a match.- if the matching URI pair is second in both lists, it is never compared.
- the CRL is treated as non-authoritative, and
UnknownStatusPolicy::Allowconverts that into a successful verification result for a revoked certificate.
the repository already has a single-URI happy-path revocation test, which demonstrates the expected rejection path when the first URI matches. the attached PoC shows that simply moving the valid match to second position flips the result from Err(CertRevoked) to Ok(()) under the permissive status policy.
steps to reproduce
the attached poc.zip contains a cargo-based integration harness. after extracting it, run make canonical to produce the vulnerable result and make control for the negative controls.
unzip poc.zip -d poc
cd poc
make canonical
make control
the canonical run emits:
[CALLSITE_HIT]: authoritative_for::uri_name_in_common later_uri_pair_skipped=true
[PROOF_MARKER]: vuln_case=Ok(()) first_uri_control=Err(CertRevoked) later_match_position=second allow_unknown=true
[IMPACT_MARKER]: revoked_cert_accepted=true policy=UnknownStatusPolicy::Allow
the control run emits:
[CALLSITE_HIT]: authoritative_for::uri_name_in_common control_path=true
[NC_MARKER]: first_uri_control=Err(CertRevoked) deny_policy=Err(UnknownRevocationStatus) vuln_blocked=true
recommended fix
avoid reusing exhausted DER iterators across nested DP/IDP comparisons. a minimal fix is to reparse or snapshot the URI name sets for each comparison so that every IDP URI can be compared against the full DP URI set. a regression test should cover the case where the only valid URI match is later in both sequences.
cheers, Oleh Konko
Common Weakness Enumeration (CWE)
Improper Check for Certificate Revocation
GitHub
0.7
CVSS SCORE
4.4mediumRustSec
-