Skip to main content

TrustStore

Struct TrustStore 

Source
pub struct TrustStore { /* private fields */ }
Expand description

The keys a host trusts, per provider — the local answer to “who may sign evidence I will treat as attested?” (ADR 0016).

Serde-able and persistable, mirroring ConsentStore, because it is the same kind of object: a record of a decision one person made about one provider on one machine. Nothing populates it implicitly — there is no discovery, no fetching, and no trust-on-first-use. An empty store is a host that verifies nothing and loses nothing, which is the default posture.

Implementations§

Source§

impl TrustStore

Source

pub fn new() -> Self

An empty store: no provider has a trusted key, so every attestation resolves to AttestationState::NoTrustedKey and every frame is still served (F9).

Source

pub fn trust(&mut self, provider_id: impl Into<String>, key: TrustedKey)

Trust key for provider_id, replacing any key already held under the same key_id.

Source

pub fn revoke(&mut self, provider_id: &str, key_id: &str) -> bool

Stop trusting one key. Returns whether a key was actually removed.

This is the whole of revocation, and it is local: nothing here learns that a key was compromised, so a host that is told so out of band calls this, and a host that is never told keeps trusting it (ADR 0016).

Source

pub fn key(&self, provider_id: &str, key_id: &str) -> Option<&TrustedKey>

The key held for (provider_id, key_id), if any.

Source

pub fn keys_for(&self, provider_id: &str) -> impl Iterator<Item = &TrustedKey>

Every key trusted for one provider, in key_id order.

Source

pub fn is_empty(&self) -> bool

Whether this store trusts no key at all.

Source

pub fn check( &self, provider_id: &str, frame: &ContextFrame, attestation: &ProvenanceAttestation, ) -> AttestationState

Check one attestation against this store and report what was found (SPEC.md §6.5.4).

Total: every input produces a state, and none of them is an error a caller could mistake for a reason to drop the frame (F9). The cheap structural checks run first so a hostile attestation cannot buy more than a constant amount of work before it is dismissed.

Source

pub fn check_signed_as( &self, local_id: &str, signing_id: &str, frame: &ContextFrame, attestation: &ProvenanceAttestation, ) -> AttestationState

check with the trust-lookup id and the signing id told apart. See check_result_signed_as for why a host needs both: local_id decides whose key may sign this, and signing_id — the handshake-declared provider.name — decides what bytes were signed (SPEC.md §6.5.2).

Source

pub fn check_result( &self, provider_id: &str, result: &ContextQueryResult, ) -> Vec<FrameAttestationOutcome>

Check the evidence a provider attached to one query result, and return one outcome per frame in it — including the frames no entry covered, which are AttestationState::Unattested.

The evidence is read off result itself (frame_attestations and result_attestation), not passed alongside it. That is deliberate and it is the whole of #161: an attestation has exactly one home (SPEC.md §6.5.5, ADR 0014), so a caller cannot hand this method a set of signatures that disagrees with the answer they cover, and no tie-breaking rule is needed because there is never a tie.

The result is a total account of the frames: a caller can read a state for every frame it is about to compose, and never has to guess whether an absent entry means unsigned or unchecked.

At most one entry is checked per frame, and at most result.frames.len() entries are examined at all. A conforming provider sends no more than one entry per frame, so the cap binds only a provider that already over-sent — and the consequence falls on that provider alone: its own later entries read as absent, and its frames are still served.

Source

pub fn check_result_signed_as( &self, local_id: &str, signing_id: &str, result: &ContextQueryResult, ) -> Vec<FrameAttestationOutcome>

check_result with the two provider identities told apart: local_id is the host’s own key for this provider, and signing_id is the name the provider signs under.

§Why there are two

SPEC.md §6.5.2 puts the provider id inside the signed preimage, and is explicit about which id: the handshake-declared provider.name, because a host’s local id “is not a string the provider ever sees — so it is not one a provider could sign against”. A host that recomputes the commitment with its own local id gets a different preimage and therefore a different digest, and reports AttestationVerdict::CommitmentMismatch — the verdict §6.5.4 reserves for a frame that changed after signing. An operator who merely named the provider something else in their config would be handed a tampering incident over honest evidence.

The two ids cannot be collapsed in the other direction either. Trust is keyed on local_id because that is the id the operator chose, in the same act as the consent grant; keying it on the declared name would let a provider claim another’s trusted key by declaring its name, which is the substitution the identity binding exists to prevent. So the local id answers “whose key may sign this?” and the declared name answers “what bytes were signed?” — different questions with different right answers.

§The same split decides matching, not only verifying

A provider has no notion of this host’s local routing id, so every FrameAttestation::frame it puts on the wire is built from the same name it signs under (the reference provider builds both from its one attestation_provider_id()). Matching offered against frame.identity(local_id) would therefore miss every entry whenever an operator’s config id differs from the provider’s declared name — the same false negative this split exists to close, one layer above the signature check itself. The lookup key is frame.identity(signing_id) for that reason.

The returned FrameIds are keyed by local_id, not signing_id: FrameId::provider_id is documented as “the same routing/consent key the host registered it under”, and it is the id the rest of the composition path (compose.rs, usage_report) already builds its own FrameIds from. Echoing signing_id here instead would desynchronize this ledger from every other identity the host emits for the same frame.

Trait Implementations§

Source§

impl Clone for TrustStore

Source§

fn clone(&self) -> TrustStore

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 Debug for TrustStore

Source§

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

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

impl Default for TrustStore

Source§

fn default() -> TrustStore

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for TrustStore

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for TrustStore

Source§

impl PartialEq for TrustStore

Source§

fn eq(&self, other: &TrustStore) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for TrustStore

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for TrustStore

Auto Trait Implementations§

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
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 = !

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

fn try_from(value: U) -> Result<T, !>

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<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more