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
//! Encrypted Client Hello (draft-ietf-tls-esni-22).
//!
//! ECH conceals the inner ClientHello — and therefore the SNI, ALPN,
//! and other rendezvous bits — by encrypting it under HPKE
//! ([`crate::hpke`]) to a public key the server has published in DNS
//! as an `ECHConfigList`. The wire CH the network sees is the *outer*
//! CH; its SNI is the `public_name` from the `ECHConfig`, and a single
//! `encrypted_client_hello` extension carries the HPKE-sealed inner CH.
//!
//! The server tries to decrypt; on success the inner CH supplants the
//! outer one and the handshake proceeds privately. On failure (no
//! matching `config_id`, AEAD reject, malformed payload, or server
//! deliberately not configured), the outer CH is completed under the
//! `public_name` certificate and `EncryptedExtensions` carries an
//! `ECHConfigList` of `retry_configs` for the client to retry against.
//!
//! Clients that don't have a fresh `ECHConfig` for a given host (or are
//! deliberately censorship-resistant) still emit a bit-shape-identical
//! "GREASE" `encrypted_client_hello` extension via
//! [`EchClient::grease`] so the wire image is constant.
//!
//! The acceptance signal — last 8 bytes of `ServerHello.random` — is
//! computed in [`accept_signal`] using `Derive-Secret(handshake_secret,
//! "ech accept confirmation", transcript_hash(CH..SH'))` per draft §7.
//!
//! ## Implementation status
//!
//! The ECH module lands in two waves. This wave ships the codec
//! foundations (ECHConfig + extension codecs, HPKE wrappers, accept
//! signal, key types, GREASE producer) and wires GREASE into the
//! ClientHello. The real-ECH inner/outer split, the server-side
//! HPKE decap + inner-CH dispatch, and the retry_configs flow land
//! in a follow-up commit under the same Phase 5 banner. Items that
//! will be referenced by that follow-up but are unused today are
//! marked with `#[allow(dead_code)]` at the module level here; the
//! in-module tests still exercise them so they don't bit-rot.
pub use ;
pub use GreaseParams;
pub use ;
use Vec;
/// Client-side ECH configuration attached to a [`crate::tls::Config`].
///
/// Either a real `ECHConfigList` to seal against, or a GREASE marker
/// that produces a bit-shape-identical `encrypted_client_hello` so the
/// wire image is constant across users.
pub
/// Server-side ECH configuration attached to a [`crate::tls::Config`].
///
/// Holds the active key ring (the keys the server will actually try
/// to decrypt with) and the `retry_configs` to publish to clients
/// when the inner CH cannot be decrypted.