1use crate::error::RecordError;
4use ytls_traits::ServerApRecordProcessor;
5use ytls_traits::ServerWrappedRecordProcessor;
6
7#[derive(Debug, PartialEq)]
8pub enum WrappedContentType {
9 ChangeCipherSpec,
11 Alert,
13 Handshake,
15 ApplicationData,
17 Unknown(u8),
19}
20
21impl From<WrappedContentType> for &'static str {
22 fn from(t: WrappedContentType) -> &'static str {
23 match t {
24 WrappedContentType::ChangeCipherSpec => "ChangeCipherSpec",
25 WrappedContentType::Alert => "Alert",
26 WrappedContentType::Handshake => "Handshake",
27 WrappedContentType::ApplicationData => "ApplicationData",
28 WrappedContentType::Unknown(_) => "Unknown",
29 }
30 }
31}
32
33impl From<u8> for WrappedContentType {
34 fn from(i: u8) -> Self {
35 match i {
36 20 => Self::ChangeCipherSpec,
37 21 => Self::Alert,
38 22 => Self::Handshake,
39 23 => Self::ApplicationData,
40 _ => Self::Unknown(i),
41 }
42 }
43}
44
45#[derive(Debug, PartialEq)]
46pub struct WrappedRecord<'r> {
47 raw_bytes: &'r [u8],
48 msg: WrappedMsgType<'r>,
49}
50
51#[derive(Debug, PartialEq)]
52pub enum WrappedMsgType<'r> {
53 ApplicationData,
54 Handshake(HandshakeMsg<'r>),
55 Alert(AlertMsg<'r>),
56}
57
58use crate::AlertMsg;
59use crate::HandshakeMsg;
60
61impl<'r> WrappedRecord<'r> {
62 #[inline]
63 pub fn msg(&self) -> &WrappedMsgType<'r> {
64 &self.msg
65 }
66 #[inline]
67 pub fn parse_server_ap<P: ServerApRecordProcessor>(
68 prc: &mut P,
69 wrapped_data: &'r [u8],
70 ) -> Result<WrappedRecord<'r>, RecordError> {
71 let w_len = wrapped_data.len();
72
73 let rec_type: WrappedContentType = wrapped_data[w_len - 1].into();
74 let raw_bytes = &wrapped_data[0..w_len - 1];
75
76 let msg: WrappedMsgType<'_> = match rec_type {
77 WrappedContentType::Handshake => {
78 let msg = HandshakeMsg::server_wrapped_ap_parse(prc, raw_bytes)?;
79 WrappedMsgType::Handshake(msg)
80 }
81 WrappedContentType::ApplicationData => WrappedMsgType::ApplicationData,
82 WrappedContentType::Alert => {
83 let (msg, _r_next) = AlertMsg::client_parse(raw_bytes)?;
84 WrappedMsgType::Alert(msg)
85 }
86 _ => {
87 return Err(RecordError::NotImplemented(
88 rec_type.into(),
89 "Wrapped::parse_server_ap",
90 ))
91 }
92 };
93 Ok(WrappedRecord { raw_bytes, msg })
94 }
95 #[inline]
96 pub fn parse_server<P: ServerWrappedRecordProcessor>(
97 prc: &mut P,
98 wrapped_data: &'r [u8],
99 ) -> Result<WrappedRecord<'r>, RecordError> {
100 let w_len = wrapped_data.len();
101
102 let rec_type: WrappedContentType = wrapped_data[w_len - 1].into();
103 let raw_bytes = &wrapped_data[0..w_len - 1];
104
105 let msg = match rec_type {
106 WrappedContentType::Handshake => {
107 let msg = HandshakeMsg::server_wrapped_hs_parse(prc, raw_bytes)?;
108 WrappedMsgType::Handshake(msg)
109 }
110 WrappedContentType::Alert => {
111 let (msg, _r_next) = AlertMsg::client_parse(raw_bytes)?;
112 WrappedMsgType::Alert(msg)
113 }
114 WrappedContentType::Unknown(_) => return Err(RecordError::Validity),
115 _ => {
116 return Err(RecordError::NotImplemented(
117 rec_type.into(),
118 "Wrapped::parse_server",
119 ))
120 }
121 };
122 Ok(WrappedRecord { raw_bytes, msg })
123 }
124 #[inline]
125 pub fn parse_client(wrapped_data: &'r [u8]) -> Result<WrappedRecord<'r>, RecordError> {
126 let w_len = wrapped_data.len();
127
128 let rec_type: WrappedContentType = wrapped_data[w_len - 1].into();
129 let raw_bytes = &wrapped_data[0..w_len - 1];
130
131 let msg = match rec_type {
132 WrappedContentType::Handshake => {
133 let msg = HandshakeMsg::client_wrapped_parse(raw_bytes)?;
134 WrappedMsgType::Handshake(msg)
135 }
136 WrappedContentType::Alert => {
137 let (msg, _r_next) = AlertMsg::client_parse(raw_bytes)?;
138 WrappedMsgType::Alert(msg)
139 }
140 WrappedContentType::Unknown(_) => return Err(RecordError::Validity),
141 _ => {
142 return Err(RecordError::NotImplemented(
143 rec_type.into(),
144 "Wrapped::parse_server_ap",
145 ))
146 }
147 };
148 Ok(WrappedRecord { raw_bytes, msg })
149 }
150}
151
152#[cfg(test)]
153mod test {
154 use super::*;
155 use hex_literal::hex;
156 use rstest::rstest;
157
158 use crate::ClientFinished;
159
160 #[rstest]
161 #[case(
162 &hex!("14000020a0210258e7c4402ab07807a1e61df4cf0ab58f828b26c6adf29654228ac0b66f16"),
163 )]
164 fn wrapped_ok(#[case] in_data: &[u8]) {
165 let r = WrappedRecord::parse_client(in_data);
166 insta::assert_debug_snapshot!(r);
167 }
168
169 #[rstest]
170 #[case(&hex!("7710"))]
171 #[case(&hex!("1410"))]
172 #[case(&hex!("140010"))]
173 #[case(&hex!("14000010"))]
174 fn wrapped_err(#[case] in_data: &[u8]) {
175 assert_eq!(
176 WrappedRecord::parse_client(in_data),
177 Err(RecordError::Validity)
178 );
179 }
180}