1use alloc::vec::Vec;
2use nom::bytes::streaming::take;
3use nom::combinator::{complete, map_parser};
4use nom::error::{make_error, ErrorKind};
5use nom::multi::many1;
6use nom::{Err, IResult};
7use nom_derive::{NomBE, Parse};
8use rusticata_macros::newtype_enum;
9
10use crate::tls_handshake::*;
11use crate::tls_message::*;
12use crate::TlsVersion;
13
14pub const MAX_RECORD_LEN: u16 = (1 << 14) + 256;
16
17#[derive(Clone, Copy, PartialEq, Eq, NomBE)]
19pub struct TlsRecordType(pub u8);
20
21newtype_enum! {
22impl debug TlsRecordType {
23 ChangeCipherSpec = 0x14,
24 Alert = 0x15,
25 Handshake = 0x16,
26 ApplicationData = 0x17,
27 Heartbeat = 0x18,
28}
29}
30
31impl From<TlsRecordType> for u8 {
32 fn from(v: TlsRecordType) -> u8 {
33 v.0
34 }
35}
36
37#[derive(Clone, Copy, PartialEq, NomBE)]
39pub struct TlsRecordHeader {
40 pub record_type: TlsRecordType,
41 pub version: TlsVersion,
42 pub len: u16,
43}
44
45#[derive(Clone, Debug, PartialEq)]
50pub struct TlsPlaintext<'a> {
51 pub hdr: TlsRecordHeader,
52 pub msg: Vec<TlsMessage<'a>>,
53}
54
55#[derive(Clone, Debug, PartialEq)]
59pub struct TlsEncryptedContent<'a> {
60 pub blob: &'a [u8],
61}
62
63#[derive(Clone, Debug, PartialEq)]
65pub struct TlsEncrypted<'a> {
66 pub hdr: TlsRecordHeader,
67 pub msg: TlsEncryptedContent<'a>,
68}
69
70#[derive(Clone, Debug, PartialEq)]
74pub struct TlsRawRecord<'a> {
75 pub hdr: TlsRecordHeader,
76 pub data: &'a [u8],
77}
78
79#[inline]
85pub fn parse_tls_record_header(i: &[u8]) -> IResult<&[u8], TlsRecordHeader> {
86 TlsRecordHeader::parse(i)
87}
88
89#[rustfmt::skip]
96#[allow(clippy::trivially_copy_pass_by_ref)] pub fn parse_tls_record_with_header<'i>(i:&'i [u8], hdr:&TlsRecordHeader ) -> IResult<&'i [u8], Vec<TlsMessage<'i>>> {
98 match hdr.record_type {
99 TlsRecordType::ChangeCipherSpec => many1(complete(parse_tls_message_changecipherspec))(i),
100 TlsRecordType::Alert => many1(complete(parse_tls_message_alert))(i),
101 TlsRecordType::Handshake => many1(complete(parse_tls_message_handshake))(i),
102 TlsRecordType::ApplicationData => many1(complete(parse_tls_message_applicationdata))(i),
103 TlsRecordType::Heartbeat => parse_tls_message_heartbeat(i, hdr.len),
104 _ => Err(Err::Error(make_error(i, ErrorKind::Switch)))
105 }
106}
107
108pub fn parse_tls_plaintext(i: &[u8]) -> IResult<&[u8], TlsPlaintext> {
111 let (i, hdr) = parse_tls_record_header(i)?;
112 if hdr.len > MAX_RECORD_LEN {
113 return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
114 }
115 let (i, msg) = map_parser(take(hdr.len as usize), |i| {
116 parse_tls_record_with_header(i, &hdr)
117 })(i)?;
118 Ok((i, TlsPlaintext { hdr, msg }))
119}
120
121pub fn parse_tls_encrypted(i: &[u8]) -> IResult<&[u8], TlsEncrypted> {
123 let (i, hdr) = parse_tls_record_header(i)?;
124 if hdr.len > MAX_RECORD_LEN {
125 return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
126 }
127 let (i, blob) = take(hdr.len as usize)(i)?;
128 let msg = TlsEncryptedContent { blob };
129 Ok((i, TlsEncrypted { hdr, msg }))
130}
131
132pub fn parse_tls_raw_record(i: &[u8]) -> IResult<&[u8], TlsRawRecord> {
138 let (i, hdr) = parse_tls_record_header(i)?;
139 if hdr.len > MAX_RECORD_LEN {
140 return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
141 }
142 let (i, data) = take(hdr.len as usize)(i)?;
143 Ok((i, TlsRawRecord { hdr, data }))
144}
145
146#[deprecated(since = "0.5.0", note = "Use parse_tls_plaintext")]
153#[inline]
154pub fn tls_parser(i: &[u8]) -> IResult<&[u8], TlsPlaintext> {
155 parse_tls_plaintext(i)
156}
157
158pub fn tls_parser_many(i: &[u8]) -> IResult<&[u8], Vec<TlsPlaintext>> {
166 many1(complete(parse_tls_plaintext))(i)
167}