feat!: a VAC is not a bearer credential; remove audience - #21
Merged
Merged
Conversation
`verify_chain` already took a `presenter` and used it for one thing: comparing it against the leaf's OPTIONAL `audience`. A leaf without an `audience` was therefore accepted from anybody, which made a captured presentation a bearer token — a chain names what may be done, not who is doing it. It now requires the leaf to grant to `presenter`, refusing otherwise with the new `AuthorityError::NotThePresenter`. That is the rule dtgwg-cred-spec PR #41 states normatively, and both known consumers had already written it by hand after hitting the gap independently — `vti-rooms-dtg`'s chain verifier and its nomination check each call `verify_chain` and then re-compare the subject, with a comment explaining why they must. With that rule in place `audience` can only name the subject (adding nothing) or somebody else (satisfiable by nobody), so it is removed rather than kept as a weaker second check: from `AuthorityGrant`, from `attenuate` and `attenuate_from_json`, and from the verifier with `WrongAudience`. The field was also being read two incompatible ways, which is what brought this forward. This library compared it to the presenter; the Trust Tasks registry described it as the party a presentation is FOR — "a host's identifier, normally" — so an implementation following the registry minted leaves the verifier refused every time. The destination question is real, and it is answered one layer up by the trust task document's `recipient`, which its `proof` covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-cred-spec#41 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
This was referenced Sep 9, 2026
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
🛡️ AI Agentic Security Code Review🔎 A manual security review is recommended before merging. Please contact the Security team for specifics and remediation guidance.
|
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 9, 2026
…ntials 0.6 → 0.9.1 (#1356) * fix(rooms): bind a presentation to its presenter, not to the host `pnm-cli rooms --host-did …` could never work. Every request it made was refused as `WrongAudience`, and omitting the flag "worked" only by skipping the check it exists to perform — so the flag's two states were broken and unprotected. `audience` is not who a presentation is addressed to. `dtg_credentials::authority::verify_chain` compares it to the PRESENTER — "the leaf must be presentable by whoever is presenting it" — so it is holder binding, and its whole job is to make a captured presentation worthless to whoever captured it. Filled with the host's DID it named a party no presenter can ever match. The value to bind to was already named a few lines away: `RoomSigner`'s doc says "a room request is signed by the party the presentation was minted for". This passes exactly that. There is no unbound case left, so the warning about one goes, and `--host-did` keeps its real job of naming the document's recipient. ## The spec says otherwise, and that is filed separately `rooms/keys/present/0.1` describes `audience` as "the party the presentation is for … a host's identifier, normally". The CLI implemented the spec faithfully; the spec and the credential library it runs on disagree, identically in dtg-credentials 0.6 and 0.7, so it is not version drift. This changes the CLI to match the verifier rather than the prose, because a presentation that cannot verify protects nobody while being wrong in the other direction. Which side should move is a working-group question — 0.7's own notes point at upstream PR #41, "a key-control demonstration at invocation, which removes `audience` as redundant" — and is raised there. * fix(rooms)!: stop sending `audience` and `nonce` on rooms/keys/present Completes the previous commit, which repointed `audience` at the presenter so it would at least verify. It should not be sent at all, and neither should `nonce`. Both are removed from `rooms/keys/present` by spec 0.2. `audience` named the party that had to PRESENT a credential, not the one it was addressed to — so a host DID named somebody no presenter can ever be, and the host refused every request. That is now moot: dtg-credentials 0.8.0 removed the property and made the real rule explicit, which the VTA was already satisfying. The leaf grants to the DID this VTA authenticated, and a host refuses a chain whose leaf grants to anyone else. Who may present is established, not declared. `nonce` was written into the presentation object, which is closed and has no member for it — so a caller supplying one got a presentation the host rejects as malformed. It could not have been made to work: every signature in a presentation is an ISSUER's, never the presenter's, so a challenge inside it is unauthenticated and a replay copies it along with everything else. Freshness is the request's, via `issuedAt` and the duplicate-execution rule keyed on document `id`. ## A second live instance, found while doing this `rooms/keys/backfill` passed the caller-named host as the audience in `vta-service`, exactly as that spec's normative MUST instructed. Every backfill this VTA attempted was refused for the same reason. What actually makes a caller-named host safe is that the leaf grants to the VTA: naming a host transfers no standing. It does hand that host sight of the principal's credentials, which is a disclosure rather than an escalation, and the comment now says so. ## Nothing binds a presentation to a host, deliberately A chain is scoped to the ROOM. One rooted in a room confers nothing anywhere else, and any host serving that room would honour it — a room may have more than one host, and moving between them without reissuing credentials is the point. Binding a request to its destination is `recipient` on the document that carries the presentation, per SPEC.md §4.8.2, which its proof covers. Refs: trustoverip/dtgwg-trust-tasks-tf#414 Refs: trustoverip/dtgwg-trust-tasks-tf#415 Refs: OpenVTC/dtg-credentials#21 Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * chore(rooms)!: dtg-credentials 0.6 → 0.9.1 Three breaking releases at once. The middle one is why this is worth doing now rather than eventually. ## 0.8 — a VAC is not a bearer credential `verify_chain` now REQUIRES the presenter to be the leaf's subject, refusing otherwise with `NotThePresenter`. Before, it used `presenter` for one thing — comparing it against the leaf's OPTIONAL `audience` — so a leaf without one was accepted from anybody and a captured presentation was a bearer token. **Both hand-written copies of that rule are deleted**, which is the payoff: `vti-rooms-dtg`'s chain verifier and its nomination check had each written it independently, after hitting the gap separately, each with a comment explaining why they had to. Two copies of a rule is one place for it to be forgotten, and the duplicate is the one nobody updates. The tests that pinned the property stay exactly where they were — a chain presented by the wrong party is still refused, and which layer refuses it is no longer this crate's business. Their assertions move to the library's wording, which names both parties rather than only the rule. `vti-rooms-wasm`'s equivalent test moves from expecting `WrongAudience` to expecting `NotThePresenter`: same property, no field to fill in. ## 0.7 — digests, and a required expiry `validUntil` became required on `new_vac`. `rooms/owner/issue-authority` now REFUSES a request without one rather than defaulting: nothing about a subject's standing is consulted when a chain is verified, so authority that does not expire is authority nobody can withdraw by waiting, and picking a lifetime here would put the room's most consequential number somewhere its owner never looks. The same rule made `Option` dead in two test fixtures — every caller already passed a value, and "a nomination that never expires" is a state no test can construct any more. ## 0.9.1 — no behaviour change here, and pinned deliberately 0.9.1 applies the same rule to the VDC (`delegation::verify_chain` gains a `presenter`). This workspace does not use delegation, so it is a drop-in. Pinned `0.9.1` rather than `0.9` on purpose: that release is API-breaking despite the patch version, and Cargo treats the two as compatible, so `"0.9"` picks it up on a routine `cargo update`. Naming the floor says which behaviour this workspace requires rather than tolerating either. 0.9.1 also adds an **Upgrading** section stating that verifiers move before issuers — closing OpenVTC/dtg-credentials#22, which this work raised after a browser member on 0.7 was refused by a host on 0.6 with an error that blamed the chain. ## `vti-rooms-wasm` comes along It takes the workspace pin, so #1347 landing put it in scope: its `present` loses the `audience` argument it was passing, and its doc block saying "there is no audience parameter, and that is deliberate" becomes "there is no longer a field either" — the binding it relied on is the library's rule now rather than a value it declined to expose. ## Verified vti-rooms 106+3, vti-rooms-dtg 19, room-host 23+13, vti-rooms-wasm 8 — green. `cargo clippy --workspace --all-targets -D warnings` clean, and `vti-rooms-wasm` still checks for `wasm32-unknown-unknown`. * fix(members): read both spellings of an acknowledgement's digest Working Draft 02 renamed `credentialSubject.digest` to `digestMultibase` and changed its encoding from `sha256:<hex>` to a base58btc multihash. `vtc-service` hand-rolled the old definition and did not follow, so a member using a current client acknowledged a grant and was told it acknowledged a different one. The tests caught it, being written for precisely that: Two implementations, one definition — this is the assertion that catches either side drifting. ## One definition, one implementation The new form delegates to `dtg_credentials::digest_multibase_json` instead of being copied here. This module already carries two digest functions differing in encoding *and* coverage, with a doc comment warning not to substitute one for the other; the acknowledgement binding was quietly a third. Only the party that publishes the specification should own the definition. Note the trap that made this worth stating: this file's existing `digest_multibase` is the same *encoding* over different *coverage* — it digests the document whole, `proof` included. Reaching for it here would compile and produce a plausible string matching nothing. ## Both forms are read, each checked its own way A member whose client predates WD02 still sends the old spelling and their acknowledgement must keep verifying. So whichever property arrives is compared against the expected value computed the same way — this widens what is *accepted*, never what counts as a *match*. `DigestForm` keeps that pairing in one place, because a check comparing a WD02 digest against a WD01 expectation refuses a correct acknowledgement while saying the member acknowledged a different grant. Multibase digests are compared as decoded bytes, never as strings: one multihash has more than one spelling. ## Two tests for the branch that had none The fixture builds acknowledgements with `dtg-credentials`, which emits only the current form, so the legacy path could not be reached from it. Both cases are hand-built: an old acknowledgement of the right grant binds, and an old acknowledgement of a different grant is still refused. The second is the failure a fallback invites — accepting the property and never comparing it. vtc-service lib: 960 passed. --------- Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the credential-library half of
dtgwg-trust-tasks-tf#414.
The hole
authority::verify_chaintook apresenterand used it for exactly one thing: comparingit against the leaf's OPTIONAL
audience. So a leaf with noaudiencewas acceptedfrom anybody. A chain names what may be done, not who is doing it, and without a
presenter rule a captured presentation is a bearer token — every verifier a distribution
point for the authority it was just shown.
Both known consumers had already found this and written the missing rule by hand, each with
a comment explaining why they had to:
vti-rooms-dtg/src/lib.rs— "verify_chaintakespresenterbut uses it for onething: the
audiencecheck… Which makes it ours, and it is not optional: without it apresentation is a bearer token, and anyone who observes one inherits everything it
confers."
vti-rooms-dtg/src/nomination.rs— the same paragraph again, for nominations.Two copies of a security check is one place for it to be forgotten. It moves here.
The rule
verify_chainnow requires the leaf to grant topresenter, refusing with the newAuthorityError::NotThePresenter. This isdtgwg-cred-spec#41 verbatim: a
verifier MUST NOT accept a party as holding the authority a VAC confers unless that party
demonstrates control of the verification method associated with the presented VAC's
credentialSubject.id.Only the leaf's subject demonstrates anything. The links above it are not present and
are asked for nothing — requiring otherwise would defeat attenuation, whose whole purpose
is that the party who attenuated is not in the loop when its agent acts.
presenteris a precondition, not an input. It must be an identifier whose key controlthe caller already established for that request — a DID the transport authenticated, or one
a signature over the request proved. Passing a value read out of the request body reduces
this to a string comparison an attacker picks both sides of. Said in the module docs and on
the parameter.
Removing
audienceOnce the presenter must be the subject, an
audiencecan only name that same subject(adding nothing) or name someone else (satisfiable by no presentation). PR #41 removes it
for exactly that reason; this removes it rather than keeping it as a weaker second check —
gone from
AuthorityGrant, fromattenuate/attenuate_from_json, and from the verifierwith
WrongAudience.The field was also being read two incompatible ways, which is what brought this forward
rather than waiting for #41 to merge. This library compared
audienceto the presenter;trusttasks.org/spec/rooms/keys/present/0.1described it as the party the presentation isfor — "a host's identifier, normally". An implementation following the registry minted
leaves this verifier refused every time; omitting it skipped the check entirely. Broken one
way, unprotected the other.
The destination question the registry was reaching for is real. It is answered one layer up,
by the trust task document's
recipientmember, which itsproofcovers and whichSPEC.md §4.8.2already requires whenever a proof is present. Naming an intended verifierinside the credential would restrict where a presentation may be made, which is the task's
question and not the credential's.
Migrating
attenuate/attenuate_from_json.subject.document now.
Deliberately not in this PR
delegation::verify_chaintakes nopresenterat all, so the VDC's Invocation Binding— normative in merged WD02, same rule, same reasoning — is unimplemented. It is the same
class of gap and deserves the same fix, but the VDC has no
audienceand so is not part ofthis issue. Filing separately.
Revocation (#39) and
maxAttenuation(#40) remain unimplemented, as before.Verified
cargo test— 117 passed, 0 failedcargo clippy --all-targets -- -D warnings— cleancargo fmt,cargo doc --no-deps— cleancargo run --example data_room— runs end to endNew tests: a chain presented by a non-subject is refused; a root presented by a
non-subject is refused (the no-attenuation case, where a bearer reading is easiest to reach
for); and the attenuating holder cannot present their own agent's chain.