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
//! The signature: preimage, algorithm, verifier, signer trait (`SPEC.md` §14.6). This crate never
//! holds a private key — [`StunSigner`] is implemented by the consumer over whatever key object it
//! already has (dig-node reuses `signer_from_node_cert`'s object, per the SPEC's citation).
use crateTransactionId;
use crateRequestKind;
use crate;
/// Domain-separates a `dig:stun:v1` signature from every other message the same TLS-leaf key
/// signs — a TLS `CertificateVerify`, a `dig:holdings:v1` record, or a future purpose — so a
/// signature produced for one is never valid for another, in either direction (`SPEC.md` §14.6,
/// §10 item 7).
pub const SIG_DOMAIN_TAG: & = b"dig:stun:v1";
/// Build the exact bytes a signed Binding's signature covers (`SPEC.md` §14.6):
/// `SIG_DOMAIN_TAG ‖ 0x01 ‖ transaction_id(12) ‖ nonce_len_be(2) ‖ nonce_attr_value ‖ spki_der(91)`.
///
/// `nonce_attr_value` MUST be the `NONCE` attribute value EXACTLY as carried on the wire (the
/// base64url text), never the decoded 20 raw bytes — the signer and the verifier must agree on
/// this or every signature fails. `spki_der` is the 91-byte SPKI (no version-byte prefix).
///
/// Binding the transaction id fixes which response the requester will accept; binding the nonce
/// fixes the issuing server, the source address, and the time bucket; binding the SPKI stops the
/// identity from being swapped under an otherwise-valid signature. Nothing else is signed — the
/// message type is fixed by the server (Binding only) and every other attribute is ignored
/// (`SPEC.md` §14.5).
/// A signature-verified requester identity (`SPEC.md` §14.6, §14.10). Carries only the SPKI: this
/// level-00 crate cannot compute a `peer_id` from it (that is `dig_tls::peer_id_from_tls_spki_der`,
/// a `dig-*` crate this one must never depend on) — callers that want the `peer_id` hash the SPKI
/// with that function themselves.
///
/// **What this does NOT prove**, stated once so nothing downstream over-reads it: network
/// membership, relay registration, on-chain standing, or that any later claim from the same
/// session is true (`SPEC.md` §14.1, §14.10, §7). It proves exactly key possession, freshness, and
/// return-routability.
///
/// `#[non_exhaustive]`: constructed only by [`verify_signed_request`], so an additive field is a
/// patch release for every consumer.
/// Verify a [`RequestKind::Signed`]'s signature against its own carried SPKI over
/// [`signing_message`] (`SPEC.md` §14.6): ECDSA, P-256, SHA-256, ASN.1 DER
/// (`ring::signature::ECDSA_P256_SHA256_ASN1`).
///
/// `kind` MUST be [`RequestKind::Signed`] — the caller has always already matched on `kind` to
/// decide whether verification even applies (`SPEC.md` §14.5 step 4: reached ONLY for `Signed` +
/// `Fresh`), so this is a precondition rather than adversary-reachable input. A `kind` of any
/// other variant returns [`CredentialError::Malformed`] rather than panicking — this function sits
/// on a path parsing untrusted datagrams, and failing closed costs nothing here.
///
/// `RequestKind`'s fields are public, so a `Signed` variant reaching this function is not
/// guaranteed to carry the 91-byte SPKI shape [`crate::credential::classify_request`] would have
/// enforced — only a value built from the wire via that parser gets that guarantee for free. This
/// function re-validates the shape itself (`is_valid_spki_der`) before it slices `spki`, so a
/// directly-constructed `Signed` carrying a too-short or otherwise malformed SPKI returns
/// [`CredentialError::Malformed`] rather than panicking on an out-of-bounds index.
///
/// # Errors
///
/// [`CredentialError::BadSignature`] when the signature does not verify (wrong key, wrong
/// preimage, or corrupt DER); [`CredentialError::Malformed`] when `kind` is not `Signed`, or when
/// its `spki` does not have the shape `is_valid_spki_der` requires.
/// Implemented by the consumer over the P-256 private key it already holds for its TLS leaf
/// (`SPEC.md` §14.6). This crate never constructs or stores a private key — no `from_pkcs8` site
/// lives here; dig-node's adapter wraps the SAME object `signer_from_node_cert` already builds for
/// `dig:holdings:v1` records, so no second key-loading site is written anywhere in the ecosystem.