Skip to content

Commit e09a4bc

Browse files
committed
Tweak DTLS13 Server auto sensing
1 parent 0b6103f commit e09a4bc

6 files changed

Lines changed: 158 additions & 157 deletions

File tree

File renamed without changes.

src/dtls13/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ impl Client {
170170
/// already sent on the wire by `ClientPending`, so no record is
171171
/// enqueued for output.
172172
pub(crate) fn new_from_hybrid(
173-
hybrid: crate::detect::HybridClientHello,
173+
hybrid: crate::auto::HybridClientHello,
174174
config: std::sync::Arc<crate::Config>,
175175
certificate: crate::DtlsCertificate,
176176
now: Instant,

src/dtls13/engine.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::dtls13::message::Sequence;
2727
use crate::timer::ExponentialBackoff;
2828
use crate::types::{HashAlgorithm, Random};
2929
use crate::window::ReplayWindow;
30-
use crate::{Config, Error, Output, SeededRng};
30+
use crate::{Config, DtlsCertificate, Error, Output, SeededRng};
3131

3232
const MAX_DEFRAGMENT_PACKETS: usize = 50;
3333

@@ -39,6 +39,9 @@ pub struct Engine {
3939
/// Configuration options.
4040
config: Arc<Config>,
4141

42+
/// Saved certificate
43+
certificate: DtlsCertificate,
44+
4245
/// Seedable random number generator for deterministic testing
4346
rng: SeededRng,
4447

@@ -93,9 +96,6 @@ pub struct Engine {
9396
/// Whether the remote peer has enabled encryption
9497
peer_encryption_enabled: bool,
9598

96-
/// Certificate in DER format
97-
certificate_der: Vec<u8>,
98-
9999
/// Signing key for CertificateVerify
100100
signing_key: Box<dyn SigningKey>,
101101

@@ -189,7 +189,7 @@ struct Entry {
189189
}
190190

191191
impl Engine {
192-
pub fn new(config: Arc<Config>, certificate: crate::DtlsCertificate) -> Self {
192+
pub fn new(config: Arc<Config>, certificate: DtlsCertificate) -> Self {
193193
let mut rng = SeededRng::new(config.rng_seed());
194194

195195
let flight_backoff =
@@ -206,6 +206,7 @@ impl Engine {
206206

207207
Self {
208208
config,
209+
certificate,
209210
rng,
210211
buffers_free: BufferPool::default(),
211212
sequence_epoch_0: Sequence::new(0),
@@ -224,7 +225,6 @@ impl Engine {
224225
prev_app_send_seq: 0,
225226
app_recv_keys: ArrayVec::new(),
226227
peer_encryption_enabled: false,
227-
certificate_der: certificate.certificate,
228228
signing_key,
229229
is_client: false,
230230
peer_handshake_seq_no: 0,
@@ -246,6 +246,10 @@ impl Engine {
246246
}
247247
}
248248

249+
pub fn into_fallback(self) -> (Arc<Config>, DtlsCertificate) {
250+
(self.config, self.certificate)
251+
}
252+
249253
pub fn set_client(&mut self, is_client: bool) {
250254
self.is_client = is_client;
251255
}
@@ -307,7 +311,7 @@ impl Engine {
307311
}
308312

309313
pub fn certificate_der(&self) -> &[u8] {
310-
&self.certificate_der
314+
&self.certificate.certificate
311315
}
312316

313317
pub fn signing_key(&mut self) -> &mut dyn SigningKey {

src/dtls13/server.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ const HRR_RANDOM: [u8; 32] = [
7474
0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
7575
];
7676

77+
const MAX_RETAINED_CLIENT_HELLO: usize = 64;
78+
7779
/// DTLS 1.3 server
7880
pub struct Server {
7981
/// Current server state.
@@ -143,7 +145,7 @@ pub struct Server {
143145

144146
/// Raw packets buffered during auto-sense so they can be replayed
145147
/// to a DTLS 1.2 server on fallback.
146-
auto_packets: Vec<Vec<u8>>,
148+
retained_hello: VecDeque<Buf>,
147149
}
148150

149151
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -179,7 +181,7 @@ impl Server {
179181
Self::new_with_engine(engine, now, true)
180182
}
181183

182-
pub(crate) fn new_with_engine(mut engine: Engine, now: Instant, auto_mode: bool) -> Server {
184+
pub fn new_with_engine(mut engine: Engine, now: Instant, auto_mode: bool) -> Server {
183185
let cookie_secret = engine.random_arr();
184186

185187
Server {
@@ -204,7 +206,7 @@ impl Server {
204206
cookie_secret,
205207
pending_key_update_response: false,
206208
auto_mode,
207-
auto_packets: Vec::new(),
209+
retained_hello: VecDeque::with_capacity(10),
208210
}
209211
}
210212

@@ -217,9 +219,15 @@ impl Server {
217219
self.auto_mode
218220
}
219221

220-
/// The last time instant seen by this server.
221-
pub fn last_now(&self) -> Instant {
222-
self.last_now
222+
/// Take all relevant config from this server instance.
223+
///
224+
/// This is used in two cases:
225+
///
226+
/// 1. Switching a server pending (auto-mode) to dtls12 server
227+
/// 2. set_active(true), turning a server pending (auto-mode) to a ClientPending
228+
pub fn into_parts(self) -> (Arc<Config>, DtlsCertificate, Instant, VecDeque<Buf>) {
229+
let (config, cert) = self.engine.into_fallback();
230+
(config, cert, self.last_now, self.retained_hello)
223231
}
224232

225233
pub(crate) fn state_name(&self) -> &'static str {
@@ -231,36 +239,24 @@ impl Server {
231239
// the ClientHello so they can be replayed to Server12 on fallback.
232240
if self.auto_mode && self.state == State::AwaitClientHello {
233241
// Cap buffered fragments to prevent unbounded growth from malicious traffic
234-
if self.auto_packets.len() >= 64 {
235-
return Err(Error::SecurityError(
236-
"too many fragmented packets during auto-sense".to_string(),
237-
));
242+
if self.retained_hello.len() >= MAX_RETAINED_CLIENT_HELLO {
243+
return Err(Error::TooManyClientHelloFragments);
238244
}
239-
self.auto_packets.push(packet.to_vec());
245+
self.retained_hello.push_back(packet.to_buf());
240246
}
241247

242248
self.engine.parse_packet(packet)?;
243249
self.make_progress()?;
244250

245251
// Once past AwaitClientHello, DTLS 1.3 is committed — free the buffer.
246252
if self.auto_mode && self.state != State::AwaitClientHello {
247-
self.auto_packets.clear();
253+
self.retained_hello.clear();
248254
self.auto_mode = false;
249255
}
250256

251257
Ok(())
252258
}
253259

254-
/// Take the buffered raw packets for DTLS 1.2 fallback replay.
255-
pub fn take_auto_packets(&mut self) -> Vec<Vec<u8>> {
256-
std::mem::take(&mut self.auto_packets)
257-
}
258-
259-
/// Number of buffered auto-sense packets.
260-
pub fn auto_packet_count(&self) -> usize {
261-
self.auto_packets.len()
262-
}
263-
264260
pub fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> Output<'a> {
265261
if let Some(event) = self.local_events.pop_front() {
266262
return event.into_output(buf, &self.client_certificates);

src/error.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,17 @@ pub enum Error {
3636
/// resolved. Callers should buffer the data and retry once the
3737
/// handshake advances.
3838
HandshakePending,
39+
/// If we are in auto-sense mode for a server and we received too
40+
/// many client hello fragments that haven't made a packet.
41+
TooManyClientHelloFragments,
3942
/// The DTLS 1.3 server received a ClientHello that does not offer
4043
/// DTLS 1.3 in `supported_versions`. In auto-sense mode the caller
4144
/// should fall back to a DTLS 1.2 server and replay the buffered
4245
/// packets.
46+
///
47+
/// This value should never be seen outside dimpl. It's an internal
48+
/// value to communicate from dtls13/server.rs to lib.rs
49+
#[doc(hidden)]
4350
Dtls12Fallback,
4451
}
4552

@@ -74,11 +81,9 @@ impl std::fmt::Display for Error {
7481
Error::HandshakePending => {
7582
write!(f, "handshake pending: cannot send application data yet")
7683
}
84+
Error::TooManyClientHelloFragments => write!(f, "too many client hello fragments"),
7785
Error::Dtls12Fallback => {
78-
write!(
79-
f,
80-
"dtls 1.2 fallback required: ClientHello does not offer DTLS 1.3"
81-
)
86+
write!(f, "dtls 1.2 fallback (internal)")
8287
}
8388
}
8489
}

0 commit comments

Comments
 (0)