#[non_exhaustive]pub struct RevocationPolicy {
pub known: Vec<KeyRevocation>,
pub discover: Option<RevocationDiscovery>,
}Expand description
Consumer-held key revocations to enforce during verification (ACDP 0.3, RFC-ACDP-0014 §7).
Self::known is pull-based: the pipeline does not go looking
for those revocations on its own — the caller supplies the
verified revocations it holds (from
find_revocations,
find_registry_attested_revocations,
an out-of-band channel, or its own indefinite cache — the statement
is permanent, cache accordingly). Self::discover (RFC-ACDP-0014
§8) is the opt-in complement: when set, verify_retrieved itself
runs those same two lookups and unions their result with known
(see RevocationDiscovery). When known is empty, discover is
None, AND no crate::RevocationCache is attached to the client,
the phase is inert and verification behaves exactly as before
RFC-ACDP-0014.
Issue #257 gives discover’s own caching a first-class home:
crate::RevocationCache, attached to the crate::RegistryClient
passed to verify_retrieved via
crate::RegistryClient::with_revocation_cache, persists exactly the
“own indefinite cache” a caller would otherwise have to hand-roll
around known — verified revocations discovered on one call are
unioned into every later call against the same client, unconditionally
and indefinitely, independent of RevocationDiscovery::freshness, and
regardless of whether that later call itself sets discover —
attaching a cache is itself the opt-in (MATERIAL-3, fresh-Opus review
of Phase 2): a call made with discover: None still seeds
producer-signed facts from the cache (never registry-attested ones —
see below), which is what extends this anti-rollback protection to
VerifiedContext::fetch/VerifiedContext::fetch_current (LIM-2),
the two entry points that can never set discover at all. A
registry-attested fact, by contrast, is additionally scoped to the
vantage that minted it (BLOCKER-1, RFC-ACDP-0014 §6): reading it back
through a client talking to a different authority never applies it,
even under RevocationDiscovery::include_registry_attested. See
that field’s doc and crate::revocation_cache for the full model,
including the separate, opt-in, TTL-bounded marker that can additionally
skip a repeat lookup.
When the body’s signing key matches a supplied revocation, §7
applies: a receipt-attested publish time strictly before the
(earliest, §4) compromised_since boundary verifies as
KeyAuthorization::HistoricallyAuthorizedPreCompromise; at/after
the boundary, or with no verified receipt to place the context at
all, verification fails closed with key_not_authorized —
regardless of DID-document state and regardless of the receipt’s
own validity. Note the interaction with ReceiptPolicy::Ignore:
an unverified receipt provides no publish time, so a revoked key’s
contexts all fail closed under it.
This applies uniformly to every entry point that accepts a
VerificationPolicy — VerifiedContext::fetch_with_policy,
VerifiedContext::fetch_current_with_policy, and the
fetch_report* family (five entry points in total) — since they all
reach this phase through the same internal pipeline. On
VerifiedContext::fetch_report_diagnose specifically, “fails
closed” means the returned VerifiedContext handle is withheld
and the cause is recorded in VerificationReport::policy_phase_error,
rather than the call returning Err — that method never
short-circuits on a policy-phase failure by design.
“Uniformly” has one remaining carve-out, structural rather than a
policy choice: VerifiedContext::fetch and
VerifiedContext::fetch_current hardcode
VerificationPolicy::default and so can never carry a non-empty
known or a discover; callers wanting either use the
_with_policy forms instead. This is recorded as a known limitation
(issue #248 LIM-2) rather than silently true. Phase 2’s cache still
extends anti-rollback protection to these two entry points — see
Self::discover’s doc — but they can never configure discovery
themselves.
Issue #260 closed the sibling limitation, LIM-1.
crate::CrossRegistryResolver::with_revocation_policy now injects a
RevocationPolicy into every node a cross-registry walk verifies,
and crate::CrossRegistryResolver::with_revocation_cache shares one
crate::RevocationCache across the walk (walk-scoped by default —
see that method’s doc). The resolver derives receipts itself, per
node, from that node’s advertised capabilities, so it takes a
RevocationPolicy, never a caller-supplied VerificationPolicy —
see CrossRegistryResolver::with_revocation_policy’s doc for why.
Only put revocations here that you have verified (strict body
pipeline + the §5 not-self-signed rule) and, per §6, that you have
decided to act on: producer-signed ones unconditionally;
registry-attested ones (RevocationTrustClass::RegistryAttested)
by default only for contexts served by or receipted by that same
registry, with corroboration before global application.
find_revocations itself
pre-filters its output to RevocationTrustClass::ProducerSigned
entries actually published by the queried producer, so §6
registry-attested attestations never arrive through it — obtain
those from
find_registry_attested_revocations
instead.
#[non_exhaustive]: this struct grew a second field
(Self::discover, RFC-ACDP-0014 §8 auto-discovery) after having
shipped with exactly one, and a caller constructing this with a
bare struct literal would otherwise break on every future field the
same way. Construct with Self::new (equivalent to today’s
RevocationPolicy { known }) and, when opting into discovery,
Self::with_discovery.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.known: Vec<KeyRevocation>Verified revocations to enforce, matched against the signing
key’s RFC-ACDP-0010 §6 fingerprint. The §4 earliest-
compromised_since rule is applied across entries naming the
same fingerprint, so include every revocation of a lineage,
superseded (and retracted) ones too — a later member can only
widen the compromise window, never narrow it, and dropping an
earlier one is exactly how that window gets quietly (and
wrongly) shrunk. This is no longer an unassisted obligation:
find_revocations and
find_registry_attested_revocations
each walk the full lineage of every candidate they find
(search-visible or not, including all-retracted lineages) and
already return the complete set for their respective trust
class; find_revocations_in_lineage
does the same directly from a known lineage_id, with no
producer/trust-class scope filter. Populate known from one of
these rather than hand-assembling a lineage.
discover: Option<RevocationDiscovery>RFC-ACDP-0014 §8 auto-discovery configuration. None (the
default) is exactly today’s behavior: the caller supplies
everything via Self::known and this phase does no network
I/O of its own. Some opts into running
find_revocations and,
depending on RevocationDiscovery::include_registry_attested,
find_registry_attested_revocations
as part of verification, merging their results with
Self::known.
Implementations§
Source§impl RevocationPolicy
impl RevocationPolicy
Sourcepub fn new(known: Vec<KeyRevocation>) -> Self
pub fn new(known: Vec<KeyRevocation>) -> Self
Construct a policy from a caller-supplied revocation set with
discovery left off (discover: None) — the same shape as the
bare RevocationPolicy { known } literal this struct’s
#[non_exhaustive] retires.
Sourcepub fn with_discovery(self, discovery: RevocationDiscovery) -> Self
pub fn with_discovery(self, discovery: RevocationDiscovery) -> Self
Opt into RFC-ACDP-0014 §8 auto-discovery on top of any
caller-supplied Self::known revocations. See
RevocationDiscovery for cost and the required explicit
trust-class choice.
Trait Implementations§
Source§impl Clone for RevocationPolicy
impl Clone for RevocationPolicy
Source§impl Debug for RevocationPolicy
impl Debug for RevocationPolicy
Source§impl Default for RevocationPolicy
impl Default for RevocationPolicy
impl Eq for RevocationPolicy
Source§impl PartialEq for RevocationPolicy
impl PartialEq for RevocationPolicy
impl StructuralPartialEq for RevocationPolicy
Auto Trait Implementations§
impl Freeze for RevocationPolicy
impl RefUnwindSafe for RevocationPolicy
impl Send for RevocationPolicy
impl Sync for RevocationPolicy
impl Unpin for RevocationPolicy
impl UnsafeUnpin for RevocationPolicy
impl UnwindSafe for RevocationPolicy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.