Skip to content

Commit 2f32181

Browse files
committed
DTLS fragments as DTLSMessageHandshakeBody::Fragment
1 parent 36a0022 commit 2f32181

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

src/dtls.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ pub enum DTLSMessageHandshakeBody<'a> {
113113
Finished(&'a [u8]),
114114
CertificateStatus(TlsCertificateStatusContents<'a>),
115115
NextProtocol(TlsNextProtocolContent<'a>),
116+
Fragment(&'a [u8]),
116117
}
117118

118119
/// DTLS plaintext message
@@ -127,6 +128,17 @@ pub enum DTLSMessage<'a> {
127128
Heartbeat(TlsMessageHeartbeat<'a>),
128129
}
129130

131+
impl<'a> DTLSMessage<'a> {
132+
/// Tell if this DTLSMessage is a (handshake) fragment that needs combining with other
133+
/// fragments to be a complete message.
134+
pub fn is_fragment(&self) -> bool {
135+
match self {
136+
DTLSMessage::Handshake(h) => matches!(h.body, DTLSMessageHandshakeBody::Fragment(_)),
137+
_ => false,
138+
}
139+
}
140+
}
141+
130142
// --------------------------- PARSERS ---------------------------
131143

132144
/// DTLS record header
@@ -148,6 +160,11 @@ pub fn parse_dtls_record_header(i: &[u8]) -> IResult<&[u8], DTLSRecordHeader> {
148160
Ok((i, record))
149161
}
150162

163+
/// Treat the entire input as an opaque fragment.
164+
fn parse_dtls_fragment(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> {
165+
Ok((&[], DTLSMessageHandshakeBody::Fragment(i)))
166+
}
167+
151168
/// DTLS Client Hello
152169
// Section 4.2 of RFC6347
153170
fn parse_dtls_client_hello(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> {
@@ -222,8 +239,16 @@ pub fn parse_dtls_message_handshake(i: &[u8]) -> IResult<&[u8], DTLSMessage> {
222239
let (i, message_seq) = be_u16(i)?;
223240
let (i, fragment_offset) = be_u24(i)?;
224241
let (i, fragment_length) = be_u24(i)?;
225-
let (i, raw_msg) = take(length)(i)?;
242+
// This packet contains fragment_length (which is less than length for fragmentation)
243+
let (i, raw_msg) = take(fragment_length)(i)?;
244+
245+
// Handshake messages can be fragmented over multiple packets. When fragmented, the user
246+
// needs the fragment_offset, fragment_length and length to determine whether they received
247+
// all the fragments. The DTLS spec allows for overlapping and duplicated fragments.
248+
let is_fragment = fragment_offset > 0 || fragment_length < length;
249+
226250
let (_, body) = match msg_type {
251+
_ if is_fragment => parse_dtls_fragment(raw_msg),
227252
TlsHandshakeType::ClientHello => parse_dtls_client_hello(raw_msg),
228253
TlsHandshakeType::HelloVerifyRequest => parse_dtls_hello_verify_request(raw_msg),
229254
TlsHandshakeType::ServerHello => parse_dtls_handshake_msg_server_hello_tlsv12(raw_msg),
@@ -281,18 +306,6 @@ pub fn parse_dtls_record_with_header<'i>(
281306
}
282307
}
283308

284-
/// Parse DTLS record, leaving `fragment` unparsed
285-
// Section 4.1 of RFC6347
286-
pub fn parse_dtls_raw_record(i: &[u8]) -> IResult<&[u8], DTLSRawRecord> {
287-
let (i, header) = parse_dtls_record_header(i)?;
288-
// As in TLS 1.2, the length should not exceed 2^14.
289-
if header.length > MAX_RECORD_LEN {
290-
return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
291-
}
292-
let (i, fragment) = take(header.length as usize)(i)?;
293-
Ok((i, DTLSRawRecord { header, fragment }))
294-
}
295-
296309
/// Parse one DTLS plaintext record
297310
// Section 4.1 of RFC6347
298311
pub fn parse_dtls_plaintext_record(i: &[u8]) -> IResult<&[u8], DTLSPlaintext> {

0 commit comments

Comments
 (0)