From 97e0dd72d91b79e1859ae2d982820404c4a607f4 Mon Sep 17 00:00:00 2001 From: Ronen Ulanovsky Date: Wed, 27 May 2026 16:29:33 +0300 Subject: [PATCH] dtls13: reject malformed ClientHello extensions --- CHANGELOG.md | 1 + src/dtls13/message/client_hello.rs | 34 ++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 482f77ca..c7d93a8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased + * Reject malformed DTLS 1.3 ClientHello extension vectors #133 * Parse DTLS 1.2-only ClientHellos for auto-sense fallback #129 * Reject malformed DTLS 1.3 Cookie extension bodies #128 * Reject oversized DTLS 1.2 CertificateRequest certificate authorities #127 diff --git a/src/dtls13/message/client_hello.rs b/src/dtls13/message/client_hello.rs index 49029065..b6ceedad 100644 --- a/src/dtls13/message/client_hello.rs +++ b/src/dtls13/message/client_hello.rs @@ -114,11 +114,10 @@ impl ClientHello { let original_input = input; let (remaining, extensions_len) = be_u16(input)?; - if extensions_len == 0 { - return Ok((remaining, extensions)); - } - let (remaining, extensions_data) = take(extensions_len)(remaining)?; + if !remaining.is_empty() { + return Err(Err::Failure(Error::new(remaining, ErrorKind::LengthValue))); + } let consumed = extensions_data.as_ptr() as usize - original_input.as_ptr() as usize; let data_base_offset = base_offset + consumed; @@ -356,4 +355,31 @@ mod tests { ); } } + + #[test] + fn zero_length_extension_vector_rejects_trailing_bytes() { + let mut message = MESSAGE.to_vec(); + message.extend_from_slice(&0u16.to_be_bytes()); + message.extend_from_slice(&ExtensionType::Cookie.as_u16().to_be_bytes()); + message.extend_from_slice(&0u16.to_be_bytes()); + + assert!( + ClientHello::parse(&message, 0).is_err(), + "extension vector length 0 must consume the remaining ClientHello body" + ); + } + + #[test] + fn underdeclared_extension_vector_rejects_trailing_bytes() { + let mut message = MESSAGE.to_vec(); + message.extend_from_slice(&4u16.to_be_bytes()); + message.extend_from_slice(&ExtensionType::Cookie.as_u16().to_be_bytes()); + message.extend_from_slice(&0u16.to_be_bytes()); + message.push(0); + + assert!( + ClientHello::parse(&message, 0).is_err(), + "declared extension vector length must consume the remaining ClientHello body" + ); + } }