1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Single `eddsa-jcs-2022` Data-Integrity proof verifier for Trust Task
//! documents (P1.4).
//!
//! Every place that verifies a holder's DI proof on a Trust Task and recovers
//! the cryptographically-proven signer DID delegates here. In the **VTA**: the
//! canonical REST authenticate path (`routes/auth.rs::
//! verify_authenticate_proof`, signer unknown a priori) and the did-signed
//! step-up gate (`trust_tasks/step_up.rs::verify_did_signed_gate`, signer
//! checked against the document issuer). In the **VTC**: the same REST
//! authenticate path, and the join-request dispatcher's holder-binding check
//! (`trust_tasks/helpers.rs::verify_trust_task_proof`).
//!
//! It started as one implementation in the VTA that had already drifted into
//! two copies there, then a third when the VTC ported it. It lives in
//! `vti-common` because *both services verify the same holder proof over the
//! same wire shape* — a divergence between them is a divergence in what a
//! signature means, which is not a thing to let happen twice.
//!
//! # Which DIDs may sign
//!
//! Any DID that can name a key. A proof's `verificationMethod` is resolved by
//! [`TrustTaskVmResolver`](super::vm_resolver::TrustTaskVmResolver), which
//! handles `did:key` locally and every other method through the configured DID
//! cache — so `did:webvh:<scid>:example.com:glenn#key-0` signs a Trust Task
//! exactly as a `did:key` does.
//!
//! This used to be `did:key` only, on the reasoning that the mobile holder key
//! is always a `did:key` and it kept proof verification off the network on an
//! unauthenticated route. The first half was never true of the whole surface:
//! every DID this workspace provisions for an integration is a `did:webvh`, so
//! the restriction meant a provisioned integration could not sign a Trust Task
//! at all. The second half is a real cost and is bounded rather than dismissed
//! — see the resolver's own module docs, and
//! [`verify_trust_task_proof`], whose `did:key`-only behaviour is unchanged for
//! callers that want it.
use ;
use TrustTaskVmResolver;
use Value;
use TrustTask;
/// Why a Trust Task DI-proof verification failed. Callers map these onto their
/// own transport error types (`AppError::Authentication`, `GateError`, …).
/// Verify the proof on `doc` **against `did:key` only**, with no network I/O.
///
/// The narrow form, kept for callers whose signer is a `did:key` by
/// construction and who do not want an unauthenticated request to be able to
/// trigger DID resolution. Anything that must accept a provisioned
/// integration's `did:webvh` holder wants
/// [`verify_trust_task_proof_with`] and a configured resolver.
pub async
/// Verify the `eddsa-jcs-2022` Data-Integrity proof on `doc` and return the
/// proven signer DID — the base DID (before `#`) of the proof's
/// `verificationMethod`.
///
/// The signature is verified over the document with its `proof` block removed
/// (`eddsa-jcs-2022` canonicalises the proofless document via JCS). The
/// returned DID is *proven*, not merely claimed; binding it to an expected
/// identity (session DID, document issuer) is the caller's job — and remains so
/// however the verification method resolved. A proof by
/// `did:webvh:…:someone-else#key-0` verifies perfectly well; that it is not the
/// party you expected is a separate check, and not one this function makes.
pub async