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
//! 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
//!
//! This module ships the ECH codec foundations (ECHConfig + extension
//! codecs, HPKE wrappers, accept signal, key types, GREASE producer), the
//! real-ECH inner/outer split, the server-side HPKE decap + inner-CH
//! dispatch, and the retry_configs flow. The one piece still staged for a
//! follow-up wave is the `ech_outer_extensions` compress/decompress
//! primitive (see [`inner`]); it is unit-tested but not yet wired into the
//! handshake, and carries its own scoped `#[allow(dead_code)]`.
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.