A Trust Chain of Entity Statements validates up to your configured Trust Anchor — what has that actually proved?
answer
- the party, not the person
- keys come from above, always
- resolved metadata, not self-declared
- iss must appear in authority_hints
- validity ends at the earliest exp
basics
~20 sThat the anchor, through Superiors it authorised, currently attests this Entity Identifier, these federation keys and this resolved metadata. It proves nothing about any user, any login, or how carefully the member runs its identity provider.
solid answer
~40 sA validated Trust Chain of Entity Statements establishes the **party**, not the person. Three things are attested: the **Entity Identifier** at the leaf, the federation keys that entity may sign with, and the `metadata` it is entitled to, once the chain's merged `metadata_policy` has been applied. The evidence runs downward — the **Trust Anchor**'s Entity Configuration is verified against the key you configured out of band, each **Subordinate Statement** with the keys attested one level above it, and the leaf's **Entity Configuration** with the keys its Superior attested. Four things are not proved: that any particular login happened, how strongly the user was authenticated, that the member behaves well, and that the result lasts — validity is bounded by the earliest `exp` in the chain.
code
pseudocode · 22 linesfunction validate_trust_chain(statements, configured_anchor_id, configured_anchor_keys):
anchor_config = statements.last // Entity Configuration, iss == sub
leaf_config = statements.first // Entity Configuration, iss == sub
verify signature of anchor_config using configured_anchor_keys
if anchor_config.sub != configured_anchor_id:
reject "not the anchor we were configured with"
keys = anchor_config.jwks
policies = empty list
for each subordinate_statement from anchor downward:
verify signature of subordinate_statement using keys
if subordinate_statement.iss not in authority_hints_of(subordinate_statement.sub):
reject "superior not named by the subject"
if now >= subordinate_statement.exp:
reject "statement expired"
append subordinate_statement.metadata_policy to policies
keys = subordinate_statement.jwks // the subject's attested keys
verify signature of leaf_config using keys
return apply(merge(policies), leaf_config.metadata)go deeper
Recall that validation establishes which organisation you are talking to and which keys it may use — it happens before any user is involved and says nothing about them.
Explain the direction of evidence: the anchor's configured key verifies the top, each statement's attested key set verifies the one below, and the leaf's self-description is verified with keys from its Superior.
Show the operational failures — acting on self-declared rather than resolved metadata, and caching a chain past the earliest expiry so that a rotation or a withdrawal never reaches you.
Decide what your service will require beyond a valid chain. Registration is a low bar, and the policy question is which accreditations or local rules you layer on top before a member's users can reach anything.
## What a Trust Chain is A **Trust Chain** in OpenID Federation 1.0 is an ordered set of Entity Statements running from a **Leaf Entity** up to a **Trust Anchor**: the leaf's own Entity Configuration, then a **Subordinate Statement** about the leaf signed by its Superior, then a Subordinate Statement about that Superior signed by *its* Superior, and so on, ending at the anchor's self-signed Entity Configuration. It is not an X.509 certification path, and its "anchor" is not a root certificate in a local trust store. ## How the evidence actually flows The only thing a verifier brings to the problem is the **Trust Anchor**'s Entity Identifier and keys, configured out of band. Everything else is bootstrapped from that: 1. Verify the anchor's Entity Configuration against the configured keys, and check its subject is the anchor you meant. 2. Walk downward. Each Subordinate Statement is verified with the key set attested in the statement above it, matched by `kid`. 3. At each step, check well-formedness: the `iss` of a Subordinate Statement must appear in the subject's own `authority_hints`. A Superior the subject never named is not a Superior, and a graph that claims otherwise is malformed. 4. Verify the leaf's own Entity Configuration with the keys its Superior attested — **not** with the keys the leaf publishes about itself. 5. Apply the merged `metadata_policy` collected down the chain to the leaf's `metadata` claim, producing the **resolved** metadata. Invert step 4 and the whole structure collapses into self-assertion: you would be trusting a stranger's claim about its own keys and calling it federation. ## What is proved - **Naming.** The anchor, through a path of Superiors it authorised, currently attests this **Entity Identifier**. - **Keys.** The federation keys the leaf may sign with are the ones attested from above, so a rogue key the leaf simply publishes for itself does not validate. - **Entitlement.** The leaf's resolved metadata — the endpoints, algorithms and capabilities you should act on — is the declared metadata after the federation's policy has narrowed it. ## What is not proved - **Nothing about a user.** Chain validation happens before, and independently of, any login. It says who the counterparty is, not who signed in or whether anyone did. - **Nothing about authentication strength.** If the federation grades that at all, it does so with a separate object — a trust mark asserting an accreditation — and what a given grade means belongs to an assurance framework, not to the chain. - **Nothing about behaviour.** The anchor attests registration, not conduct. A member that releases sloppy attributes or is slow to deprovision leavers still produces a perfectly valid chain. - **Nothing permanent.** Every statement carries `exp`; the chain is usable only until the earliest of them expires, which is why resolution is a repeated operation rather than a one-off import. ## Where this bites in production The classic incident is a relying party that validates a chain, then reads endpoints and algorithms out of the leaf's self-declared `metadata` claim rather than out of the resolved metadata. Everything works for months, because most members declare what policy would have allowed anyway. Then one member declares a signing algorithm the federation forbids, the relying party honours it, and the federation's rule silently never applied to that pair. The second classic is treating validation as an install-time step. Chains are cached and then never rebuilt; a member's key rotation, a policy tightening or a withdrawal takes effect for everyone except the one relying party still holding a stale chain past its `exp`. | Question an operator asks | Does the chain answer it? | |---|---| | Is this Entity Identifier a member right now? | Yes, until the earliest `exp` | | Is this the key it may sign with? | Yes, as attested one level up | | Which endpoints and algorithms may it use? | Yes, after policy resolution | | Did a real person just authenticate? | No | | How strongly were they authenticated? | No — that is a separate assertion | | Is the member complying with the federation's rules? | No, only that it is still registered |
- How long does a validated Trust Chain stay usable?Until the earliest `exp` among the statements in it. A chain is only as fresh as its shortest-lived link, and operators set short lifetimes on Subordinate Statements precisely so that withdrawal and rotation take effect without asking anyone to act. Treat resolution as a repeated operation with an expiry, not as configuration you import once.
- The leaf declares a metadata value the federation's policy forbids — which value applies?The resolved one. The declared `metadata` claim is input; the merged `metadata_policy` from the chain is applied to it, and the result is what a relying party acts on. If policy and declaration cannot be reconciled at all — a `value` operator against an incompatible declaration, say — that is a resolution failure, and the correct outcome is to reject the chain rather than fall back to the declaration.
- Does a valid chain say anything about how strongly the provider authenticated the user?No. Chain validation is about the counterparty's registration, keys and entitlements. Any claim about how a user was authenticated is asserted separately — by the login response itself, or, at the federation level, by an accreditation the member holds — and interpreting such a grade is a different subject from establishing the party.
- Why check that a Subordinate Statement's iss appears in the subject's authority_hints?Because it is the subject that declares who its Superiors are. Without that check, any entity holding a valid path to the anchor could issue statements about an entity that never named it, and attach itself to someone else's identity. The check makes the graph two-sided: the Superior claims the subordinate and the subordinate claims the Superior.
A validated chain is the league office's current registration slip for a club: it confirms the club's name, its officials and what competitions it may enter. It says nothing about who that club lets in through its own front door.
saying these in an interview costs you the question
- Treats a valid chain as proof the user was strongly authenticated
- Verifies every statement with keys the signer publishes about itself
- Thinks a chain validated once stays valid indefinitely
- Reads the leaf's declared metadata and ignores the chain's policy
- Calls the anchor a root certificate and the chain a certification path
- Assumes the anchor has audited how the member runs its login