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
//! JWT VC Issuer Metadata — the document that replaces `did:web` for this
//! credential type.
use ;
use ;
use ;
/// The well-known path a verifier fetches, from
/// draft-ietf-oauth-sd-jwt-vc-19 clause 4: inserted between the host and path
/// components of the `iss` value.
pub const WELL_KNOWN_PATH: &str = "/.well-known/jwt-vc-issuer";
/// Build the JWT VC Issuer Metadata configuration for this node.
///
/// # Why this exists alongside the DID document
///
/// This crate already publishes a `did:web` document, and that stays: the W3C
/// credential path and the UNTP door both resolve keys through it. SD-JWT VC
/// does not. Clause 2.5 of the profile defines exactly two key-discovery
/// mechanisms — this document, and an inline `x5c` certificate chain — and
/// **names no DID method at all**. A verifier built to the profile will not
/// resolve `did:web`, so a credential that offered only a DID would be
/// unverifiable by a conformant consumer.
///
/// The `x5c` route is the other half of clause 2.5 and is not implemented here:
/// it makes the issuer *the subject of an end-entity certificate*, which is a
/// procurement fact rather than a code one, and the credential would then be
/// making a claim about a certificate holder that nothing in this crate can
/// substantiate.
///
/// # Shape
///
/// Clause 4.2 requires `issuer`, identical to the credential's `iss` claim, plus
/// **exactly one** of `jwks` or `jwks_uri` — "but not both". Keys are embedded
/// by value: a `jwks_uri` would be a second document to serve, a second URL to
/// keep resolving for the life of a passport, and a second thing to get wrong,
/// for no benefit at this key count.
///
/// Archived keys are included and revoked keys are excluded — **including the
/// current one** — exactly as the DID document does it: a credential signed
/// before a rotation must keep verifying, and one signed with a revoked key must
/// stop. Returns `None` when nothing usable is left, rather than an empty key
/// set, which would assert that this issuer signs nothing.
/// The metadata document for a current key and its archived predecessors.
///
/// Separate from [`build_issuer_metadata`] so both revocation branches can be
/// tested. A store's public API never leaves its *current* key revoked —
/// `revoke_and_rotate` archives the revoked key and issues a fresh one — so the
/// branch below that guards against it is unreachable through the store, and a
/// guard nothing can reach is a guard nothing checks.
pub
/// One JWK, carrying the `kid` the Issuer-signed JWT's header names.
///
/// Clause 4.2: *"It is RECOMMENDED that the Issuer-signed JWT contains a `kid`
/// JWT header parameter that can be used to look up the public key in the JWK
/// Set."* The signer emits the key's fingerprint as `kid`, so the same value has
/// to appear here or the recommendation is met in name only — a verifier holding
/// two keys would have no way to pick.