Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tls-parser-0.11.0/src/dtls.rs
Line
Count
Source
1
//! Datagram Transport Layer Security Version 1.2 (RFC 6347)
2
3
use crate::tls::*;
4
use crate::TlsMessageAlert;
5
use alloc::vec::Vec;
6
use nom::bytes::streaming::take;
7
use nom::combinator::{complete, cond, map, map_parser, opt, verify};
8
use nom::error::{make_error, ErrorKind};
9
use nom::multi::{length_data, many1};
10
use nom::number::streaming::{be_u16, be_u24, be_u64, be_u8};
11
use nom_derive::Parse;
12
13
/// DTLS Plaintext record header
14
#[derive(Debug, PartialEq)]
15
pub struct DTLSRecordHeader {
16
    pub content_type: TlsRecordType,
17
    pub version: TlsVersion,
18
    /// A counter value that is incremented on every cipher state change.
19
    pub epoch: u16,
20
    /// The sequence number for this record.
21
    pub sequence_number: u64, // really an u48
22
    pub length: u16,
23
}
24
25
/// DTLS Plaintext record
26
///
27
/// Each DTLS record MUST fit within a single datagram.
28
///
29
/// Multiple DTLS records may be placed in a single datagram.
30
#[derive(Debug, PartialEq)]
31
pub struct DTLSPlaintext<'a> {
32
    pub header: DTLSRecordHeader,
33
    pub messages: Vec<DTLSMessage<'a>>,
34
}
35
36
#[derive(Debug, PartialEq)]
37
pub struct DTLSRawRecord<'a> {
38
    pub header: DTLSRecordHeader,
39
    pub fragment: &'a [u8],
40
}
41
42
#[derive(Debug, PartialEq)]
43
pub struct DTLSClientHello<'a> {
44
    pub version: TlsVersion,
45
    pub random: &'a [u8],
46
    pub session_id: Option<&'a [u8]>,
47
    pub cookie: &'a [u8],
48
    /// A list of ciphers supported by client
49
    pub ciphers: Vec<TlsCipherSuiteID>,
50
    /// A list of compression methods supported by client
51
    pub comp: Vec<TlsCompressionID>,
52
    pub ext: Option<&'a [u8]>,
53
}
54
55
impl<'a> ClientHello<'a> for DTLSClientHello<'a> {
56
0
    fn version(&self) -> TlsVersion {
57
0
        self.version
58
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::version
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::version
59
60
0
    fn rand_data(&self) -> &'a [u8] {
61
0
        self.random
62
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::rand_data
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::rand_data
63
64
0
    fn session_id(&self) -> Option<&'a [u8]> {
65
0
        self.session_id
66
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::session_id
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::session_id
67
68
0
    fn ciphers(&self) -> &Vec<TlsCipherSuiteID> {
69
0
        &self.ciphers
70
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::ciphers
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::ciphers
71
72
0
    fn comp(&self) -> &Vec<TlsCompressionID> {
73
0
        &self.comp
74
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::comp
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::comp
75
76
0
    fn ext(&self) -> Option<&'a [u8]> {
77
0
        self.ext
78
0
    }
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::ext
Unexecuted instantiation: <tls_parser::dtls::DTLSClientHello as tls_parser::tls::ClientHello>::ext
79
}
80
81
#[derive(Debug, PartialEq)]
82
pub struct DTLSHelloVerifyRequest<'a> {
83
    pub server_version: TlsVersion,
84
    pub cookie: &'a [u8],
85
}
86
87
/// DTLS Generic handshake message
88
#[derive(Debug, PartialEq)]
89
pub struct DTLSMessageHandshake<'a> {
90
    pub msg_type: TlsHandshakeType,
91
    pub length: u32,
92
    pub message_seq: u16,
93
    pub fragment_offset: u32,
94
    pub fragment_length: u32,
95
    pub body: DTLSMessageHandshakeBody<'a>,
96
}
97
98
/// DTLS Generic handshake message
99
#[derive(Debug, PartialEq)]
100
pub enum DTLSMessageHandshakeBody<'a> {
101
    HelloRequest,
102
    ClientHello(DTLSClientHello<'a>),
103
    HelloVerifyRequest(DTLSHelloVerifyRequest<'a>),
104
    ServerHello(TlsServerHelloContents<'a>),
105
    NewSessionTicket(TlsNewSessionTicketContent<'a>),
106
    HelloRetryRequest(TlsHelloRetryRequestContents<'a>),
107
    Certificate(TlsCertificateContents<'a>),
108
    ServerKeyExchange(TlsServerKeyExchangeContents<'a>),
109
    CertificateRequest(TlsCertificateRequestContents<'a>),
110
    ServerDone(&'a [u8]),
111
    CertificateVerify(&'a [u8]),
112
    ClientKeyExchange(TlsClientKeyExchangeContents<'a>),
113
    Finished(&'a [u8]),
114
    CertificateStatus(TlsCertificateStatusContents<'a>),
115
    NextProtocol(TlsNextProtocolContent<'a>),
116
}
117
118
/// DTLS plaintext message
119
///
120
/// Plaintext records can only be found during the handshake.
121
#[derive(Debug, PartialEq)]
122
pub enum DTLSMessage<'a> {
123
    Handshake(DTLSMessageHandshake<'a>),
124
    ChangeCipherSpec,
125
    Alert(TlsMessageAlert),
126
    ApplicationData(TlsMessageApplicationData<'a>),
127
    Heartbeat(TlsMessageHeartbeat<'a>),
128
}
129
130
// --------------------------- PARSERS ---------------------------
131
132
/// DTLS record header
133
// Section 4.1 of RFC6347
134
0
pub fn parse_dtls_record_header(i: &[u8]) -> IResult<&[u8], DTLSRecordHeader> {
135
0
    let (i, content_type) = TlsRecordType::parse(i)?;
136
0
    let (i, version) = TlsVersion::parse(i)?;
137
0
    let (i, int0) = be_u64(i)?;
138
0
    let epoch = (int0 >> 48) as u16;
139
0
    let sequence_number = int0 & 0xffff_ffff_ffff;
140
0
    let (i, length) = be_u16(i)?;
141
0
    let record = DTLSRecordHeader {
142
0
        content_type,
143
0
        version,
144
0
        epoch,
145
0
        sequence_number,
146
0
        length,
147
0
    };
148
0
    Ok((i, record))
149
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_record_header
Unexecuted instantiation: tls_parser::dtls::parse_dtls_record_header
150
151
/// DTLS Client Hello
152
// Section 4.2 of RFC6347
153
0
fn parse_dtls_client_hello(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> {
154
0
    let (i, version) = TlsVersion::parse(i)?;
155
0
    let (i, random) = take(32usize)(i)?;
156
0
    let (i, sidlen) = verify(be_u8, |&n| n <= 32)(i)?;
Unexecuted instantiation: tls_parser::dtls::parse_dtls_client_hello::{closure#0}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_client_hello::{closure#0}
157
0
    let (i, session_id) = cond(sidlen > 0, take(sidlen as usize))(i)?;
158
0
    let (i, cookie) = length_data(be_u8)(i)?;
159
0
    let (i, ciphers_len) = be_u16(i)?;
160
0
    let (i, ciphers) = parse_cipher_suites(i, ciphers_len as usize)?;
161
0
    let (i, comp_len) = be_u8(i)?;
162
0
    let (i, comp) = parse_compressions_algs(i, comp_len as usize)?;
163
0
    let (i, ext) = opt(complete(length_data(be_u16)))(i)?;
164
0
    let content = DTLSClientHello {
165
0
        version,
166
0
        random,
167
0
        session_id,
168
0
        cookie,
169
0
        ciphers,
170
0
        comp,
171
0
        ext,
172
0
    };
173
0
    Ok((i, DTLSMessageHandshakeBody::ClientHello(content)))
174
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_client_hello
Unexecuted instantiation: tls_parser::dtls::parse_dtls_client_hello
175
176
/// DTLS Client Hello
177
// Section 4.2 of RFC6347
178
0
fn parse_dtls_hello_verify_request(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> {
179
0
    let (i, server_version) = TlsVersion::parse(i)?;
180
0
    let (i, cookie) = length_data(be_u8)(i)?;
181
0
    let content = DTLSHelloVerifyRequest {
182
0
        server_version,
183
0
        cookie,
184
0
    };
185
0
    Ok((i, DTLSMessageHandshakeBody::HelloVerifyRequest(content)))
186
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_hello_verify_request
Unexecuted instantiation: tls_parser::dtls::parse_dtls_hello_verify_request
187
188
0
fn parse_dtls_handshake_msg_server_hello_tlsv12(
189
0
    i: &[u8],
190
0
) -> IResult<&[u8], DTLSMessageHandshakeBody> {
191
0
    map(
192
0
        parse_tls_server_hello_tlsv12,
193
0
        DTLSMessageHandshakeBody::ServerHello,
194
0
    )(i)
195
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_server_hello_tlsv12
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_server_hello_tlsv12
196
197
0
fn parse_dtls_handshake_msg_serverdone(
198
0
    i: &[u8],
199
0
    len: usize,
200
0
) -> IResult<&[u8], DTLSMessageHandshakeBody> {
201
0
    map(take(len), DTLSMessageHandshakeBody::ServerDone)(i)
202
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_serverdone
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_serverdone
203
204
0
fn parse_dtls_handshake_msg_clientkeyexchange(
205
0
    i: &[u8],
206
0
    len: usize,
207
0
) -> IResult<&[u8], DTLSMessageHandshakeBody> {
208
0
    map(
209
0
        parse_tls_clientkeyexchange(len),
210
0
        DTLSMessageHandshakeBody::ClientKeyExchange,
211
0
    )(i)
212
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_clientkeyexchange
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_clientkeyexchange
213
214
0
fn parse_dtls_handshake_msg_certificate(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> {
215
0
    map(parse_tls_certificate, DTLSMessageHandshakeBody::Certificate)(i)
216
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_certificate
Unexecuted instantiation: tls_parser::dtls::parse_dtls_handshake_msg_certificate
217
218
/// Parse a DTLS handshake message
219
0
pub fn parse_dtls_message_handshake(i: &[u8]) -> IResult<&[u8], DTLSMessage> {
220
0
    let (i, msg_type) = map(be_u8, TlsHandshakeType)(i)?;
221
0
    let (i, length) = be_u24(i)?;
222
0
    let (i, message_seq) = be_u16(i)?;
223
0
    let (i, fragment_offset) = be_u24(i)?;
224
0
    let (i, fragment_length) = be_u24(i)?;
225
0
    let (i, raw_msg) = take(length)(i)?;
226
0
    let (_, body) = match msg_type {
227
0
        TlsHandshakeType::ClientHello => parse_dtls_client_hello(raw_msg),
228
0
        TlsHandshakeType::HelloVerifyRequest => parse_dtls_hello_verify_request(raw_msg),
229
0
        TlsHandshakeType::ServerHello => parse_dtls_handshake_msg_server_hello_tlsv12(raw_msg),
230
        TlsHandshakeType::ServerDone => {
231
0
            parse_dtls_handshake_msg_serverdone(raw_msg, length as usize)
232
        }
233
        TlsHandshakeType::ClientKeyExchange => {
234
0
            parse_dtls_handshake_msg_clientkeyexchange(raw_msg, length as usize)
235
        }
236
0
        TlsHandshakeType::Certificate => parse_dtls_handshake_msg_certificate(raw_msg),
237
        _ => {
238
            // eprintln!("Unsupported message type {:?}", msg_type);
239
0
            Err(Err::Error(make_error(i, ErrorKind::Switch)))
240
        }
241
0
    }?;
242
0
    let msg = DTLSMessageHandshake {
243
0
        msg_type,
244
0
        length,
245
0
        message_seq,
246
0
        fragment_offset,
247
0
        fragment_length,
248
0
        body,
249
0
    };
250
0
    Ok((i, DTLSMessage::Handshake(msg)))
251
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_handshake
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_handshake
252
253
/// Parse a DTLS changecipherspec message
254
// XXX add extra verification hdr.len == 1
255
0
pub fn parse_dtls_message_changecipherspec(i: &[u8]) -> IResult<&[u8], DTLSMessage> {
256
0
    let (i, _) = verify(be_u8, |&tag| tag == 0x01)(i)?;
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_changecipherspec::{closure#0}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_changecipherspec::{closure#0}
257
0
    Ok((i, DTLSMessage::ChangeCipherSpec))
258
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_changecipherspec
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_changecipherspec
259
260
/// Parse a DTLS alert message
261
// XXX add extra verification hdr.len == 2
262
0
pub fn parse_dtls_message_alert(i: &[u8]) -> IResult<&[u8], DTLSMessage> {
263
0
    let (i, alert) = TlsMessageAlert::parse(i)?;
264
0
    Ok((i, DTLSMessage::Alert(alert)))
265
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_alert
Unexecuted instantiation: tls_parser::dtls::parse_dtls_message_alert
266
267
0
pub fn parse_dtls_record_with_header<'i, 'hdr>(
268
0
    i: &'i [u8],
269
0
    hdr: &'hdr DTLSRecordHeader,
270
0
) -> IResult<&'i [u8], Vec<DTLSMessage<'i>>> {
271
0
    match hdr.content_type {
272
0
        TlsRecordType::ChangeCipherSpec => many1(complete(parse_dtls_message_changecipherspec))(i),
273
0
        TlsRecordType::Alert => many1(complete(parse_dtls_message_alert))(i),
274
0
        TlsRecordType::Handshake => many1(complete(parse_dtls_message_handshake))(i),
275
        // TlsRecordType::ApplicationData  => many1(complete(parse_tls_message_applicationdata))(i),
276
        // TlsRecordType::Heartbeat        => parse_tls_message_heartbeat(i, hdr.length),
277
        _ => {
278
            // eprintln!("Unsupported record type {:?}", hdr.content_type);
279
0
            Err(Err::Error(make_error(i, ErrorKind::Switch)))
280
        }
281
    }
282
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_record_with_header
Unexecuted instantiation: tls_parser::dtls::parse_dtls_record_with_header
283
284
/// Parse DTLS record, leaving `fragment` unparsed
285
// Section 4.1 of RFC6347
286
0
pub fn parse_dtls_raw_record(i: &[u8]) -> IResult<&[u8], DTLSRawRecord> {
287
0
    let (i, header) = parse_dtls_record_header(i)?;
288
    // As in TLS 1.2, the length should not exceed 2^14.
289
0
    if header.length > MAX_RECORD_LEN {
290
0
        return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
291
0
    }
292
0
    let (i, fragment) = take(header.length as usize)(i)?;
293
0
    Ok((i, DTLSRawRecord { header, fragment }))
294
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_raw_record
Unexecuted instantiation: tls_parser::dtls::parse_dtls_raw_record
295
296
/// Parse one DTLS plaintext record
297
// Section 4.1 of RFC6347
298
0
pub fn parse_dtls_plaintext_record(i: &[u8]) -> IResult<&[u8], DTLSPlaintext> {
299
0
    let (i, header) = parse_dtls_record_header(i)?;
300
    // As in TLS 1.2, the length should not exceed 2^14.
301
0
    if header.length > MAX_RECORD_LEN {
302
0
        return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
303
0
    }
304
0
    let (i, messages) = map_parser(take(header.length as usize), |i| {
305
0
        parse_dtls_record_with_header(i, &header)
306
0
    })(i)?;
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_record::{closure#0}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_record::{closure#0}
307
0
    Ok((i, DTLSPlaintext { header, messages }))
308
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_record
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_record
309
310
/// Parse multiple DTLS plaintext record
311
// Section 4.1 of RFC6347
312
0
pub fn parse_dtls_plaintext_records(i: &[u8]) -> IResult<&[u8], Vec<DTLSPlaintext>> {
313
0
    many1(complete(parse_dtls_plaintext_record))(i)
314
0
}
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_records
Unexecuted instantiation: tls_parser::dtls::parse_dtls_plaintext_records