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
//! ECH acceptance signal (draft-ietf-tls-esni-22 §7).
//!
//! The server tells the client whether ECH was accepted (the inner
//! CH won) or rejected (the outer CH won) by writing 8 bytes into
//! `ServerHello.random[24..32]` (or into `HelloRetryRequest.random[24..32]`
//! in the HRR case). The 8 bytes are computed deterministically
//! from the handshake transcript.
//!
//! Concretely, draft §7.2 specifies:
//!
//! ```text
//! accept_confirmation =
//! HKDF-Expand-Label(
//! Derive-Secret(handshake_secret, "ech accept confirmation",
//! transcript_hash(ClientHelloInner..ServerHelloEchAcceptConfirmation)),
//! "ech accept confirmation",
//! "",
//! 8)
//! ```
//!
//! where `ServerHelloEchAcceptConfirmation` is the in-progress SH with
//! its last 8 random bytes zeroed.
//!
//! In our codebase the equivalent is computed below by piggy-backing
//! on the existing `derive_secret` / `expand_label_dyn` helpers.
use crate;
use Vec;
/// `accept_confirmation` for `ServerHello` (the 8 bytes patched into
/// `sh.random[24..32]`). `handshake_secret` is the TLS-1.3 handshake
/// secret on the **inner** transcript; `transcript_hash` is the hash
/// of `(inner CH || zero-tail SH)` taken over the chosen `alg`.
///
/// The caller is responsible for zeroing the last 8 bytes of the SH's
/// random field before hashing — that's the "zero placeholder" form
/// the draft prescribes.
/// `accept_confirmation` for `HelloRetryRequest` (draft §7.2.1). Same
/// shape, different label so the two confirmations can't be confused.
///
/// The HRR's last 8 random bytes are zeroed before hashing as for SH.
/// Constant-time equality check on the 8-byte accept signal —
/// avoids a sequence-of-bytes timing side channel against an
/// adversary that can repeatedly stuff CHs.
/// Helper: rebuild a wire `ServerHello.random` with the last 8 bytes
/// replaced with `signal`. Used by both the server (to patch the SH
/// it emits) and the client (to recompute what the SH *would* look
/// like if ECH had been accepted, before comparing to what arrived).
/// Helper: extract the last 8 bytes of a 32-byte random.
/// Helper: zero the last 8 bytes of a 32-byte random in-place, returning
/// the modified copy. Used to build the "zero-placeholder" SH the draft
/// hashes for the accept-confirmation computation.
/// Re-export — for callers that want to inspect the per-CH bytes used
/// to seed [`patch_random_tail`].
pub