Skip to main content

Module revocation_cache

Module revocation_cache 

Source
Expand description

Issue #257: a cache for RFC-ACDP-0014 §7/§8 revocation discovery.

This is deliberately two objects sharing one lock, not one:

  • Facts — verified KeyRevocations. RFC-ACDP-0014 §7:114 licenses caching these indefinitely (“the statement is permanent”). They are always unioned into classification by crate::verified::VerifiedContext’s internal verify_retrieved — never used to replace or subset a discovery result. A revocation is monotone (more revocations ⇒ an earlier effective boundary ⇒ strictly more fail-closed verdicts), so seeding from the fact store can only tighten a verdict, never loosen one. That makes the fact store an anti-rollback security control: without it, a registry that serves a revocation on one call and hides it on the next causes the client to forget it ever saw it. See RevocationCache::facts_for (read) and RevocationCache::record_success (write) — both crate-private.

    Every stored fact carries the vantage that minted it (its origin, set from record_success’s authority parameter — see StoredFact). RFC-ACDP-0014 §6 draws a real distinction here: a producer-signed fact is self-contained and “verifies identically wherever it came from” (§8), so it is never filtered by origin — this is what makes it correct for it to cross vantages (see crate::verified’s anti-rollback tests). A registry-attested fact is one specific registry’s claim, and §6 licenses applying it only “for contexts served by or receipted by that same registry” — so a read filters registry-attested facts to origin == current vantage. Storing only trust_class (as an earlier revision of this cache did) answers a different question than “was this claim made by the registry now serving this context” — collapsing the two let a fact minted at a hostile or deceived registry A fail-close a producer’s contexts at every OTHER authority, for the cache’s lifetime: a targeted cross-registry DoS exactly bounded by §6’s scoping default.

  • Freshness markers — “vantage V was asked about producer/controller P for trust class C, and a full, untruncated discovery completed at time T.” This is a cached absence, which §7:114 does not license and which §8 explicitly warns about: “a malicious registry can hide a revocation … absence of search results is not evidence of absence.” So a marker is TTL-bounded (crate::verified::RevocationDiscovery::freshness, default std::time::Duration::ZERO — i.e. off), per-vantage, and read via RevocationCache::marker_fresh (crate-private) — the only method in this module that can cause a lookup to be skipped rather than merely supplemented.

Both objects live in the same per-producer CacheEntry (crate-private) so eviction is whole-entry: facts and markers for one producer always leave together, which makes “a fresh marker over an evicted (or fact-capped) set” — stale-absence-over-nothing — structurally unrepresentable rather than merely guarded against.

Never call anything here holding the lock across an .await — every method in this module is synchronous and returns before its caller does any network I/O.

Structs§

RevocationCache
A cache of RFC-ACDP-0014 revocation facts and discovery-freshness markers, injectable into a crate::RegistryClient via crate::RegistryClient::with_revocation_cache.