/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 |