1use super::{
4 error::TlsParseError,
5 extensions::extension::TlsExtensions,
6 types::{TlsCipherSuite, TlsCompressionMethod, TlsExtensionType, TlsProtocolVersion},
7};
8
9pub const HELLO_RETRY_REQUEST_RANDOM: [u8; 32] = [
11 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91,
12 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
13];
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct ClientHello<'a> {
18 bytes: &'a [u8],
19 session_id: &'a [u8],
20 cipher_suites: &'a [u8],
21 compression_methods: &'a [u8],
22 extensions: &'a [u8],
23}
24
25impl<'a> ClientHello<'a> {
26 pub fn parse(bytes: &'a [u8]) -> Result<Self, TlsParseError> {
28 need(bytes, 34)?;
29 let mut offset = 34;
30
31 let session_id = take_u8_vector(bytes, &mut offset)?;
32 if session_id.len() > 32 {
33 return Err(TlsParseError::InvalidValue);
34 }
35
36 let cipher_suites = take_u16_vector(bytes, &mut offset)?;
37 if cipher_suites.is_empty() || !cipher_suites.len().is_multiple_of(2) {
38 return Err(TlsParseError::InvalidValue);
39 }
40
41 let compression_methods = take_u8_vector(bytes, &mut offset)?;
42 if compression_methods.is_empty() {
43 return Err(TlsParseError::InvalidValue);
44 }
45
46 let extensions = if offset == bytes.len() {
47 &[]
48 } else {
49 take_u16_vector(bytes, &mut offset)?
50 };
51 if offset != bytes.len() {
52 return Err(TlsParseError::TrailingBytes);
53 }
54
55 Ok(Self {
56 bytes,
57 session_id,
58 cipher_suites,
59 compression_methods,
60 extensions,
61 })
62 }
63
64 pub fn legacy_version(&self) -> TlsProtocolVersion {
66 TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[0], self.bytes[1]]))
67 }
68
69 pub fn random(&self) -> &'a [u8; 32] {
71 self.bytes[2..34]
72 .try_into()
73 .expect("validated ClientHello random")
74 }
75
76 pub fn session_id(&self) -> &'a [u8] {
78 self.session_id
79 }
80
81 pub fn cipher_suites(&self) -> impl Iterator<Item = TlsCipherSuite> + 'a {
83 self.cipher_suites
84 .chunks_exact(2)
85 .map(|bytes| TlsCipherSuite::new(u16::from_be_bytes([bytes[0], bytes[1]])))
86 }
87
88 pub fn compression_methods(&self) -> impl Iterator<Item = TlsCompressionMethod> + 'a {
90 self.compression_methods
91 .iter()
92 .copied()
93 .map(TlsCompressionMethod::new)
94 }
95
96 pub fn extensions(&self) -> TlsExtensions<'a> {
98 TlsExtensions::new(self.extensions)
99 }
100
101 pub fn offers_tls13(&self) -> bool {
103 self.extensions()
104 .filter_map(Result::ok)
105 .filter(|extension| extension.extension_type() == TlsExtensionType::SUPPORTED_VERSIONS)
106 .filter_map(|extension| extension.client_supported_versions().ok())
107 .any(|versions| {
108 versions
109 .iter()
110 .any(|version| version == TlsProtocolVersion::TLS13)
111 })
112 }
113
114 pub fn as_bytes(&self) -> &'a [u8] {
116 self.bytes
117 }
118}
119
120#[derive(Clone, Copy, Debug, Eq, PartialEq)]
122pub struct ServerHello<'a> {
123 bytes: &'a [u8],
124 session_id: &'a [u8],
125 cipher_suite: TlsCipherSuite,
126 compression_method: TlsCompressionMethod,
127 extensions: &'a [u8],
128}
129
130impl<'a> ServerHello<'a> {
131 pub fn parse(bytes: &'a [u8]) -> Result<Self, TlsParseError> {
133 need(bytes, 38)?;
134 let mut offset = 34;
135
136 let session_id = take_u8_vector(bytes, &mut offset)?;
137 if session_id.len() > 32 {
138 return Err(TlsParseError::InvalidValue);
139 }
140
141 need(&bytes[offset..], 3)?;
142 let cipher_suite =
143 TlsCipherSuite::new(u16::from_be_bytes([bytes[offset], bytes[offset + 1]]));
144 let compression_method = TlsCompressionMethod::new(bytes[offset + 2]);
145 offset += 3;
146
147 let extensions = if offset == bytes.len() {
148 &[]
149 } else {
150 take_u16_vector(bytes, &mut offset)?
151 };
152 if offset != bytes.len() {
153 return Err(TlsParseError::TrailingBytes);
154 }
155
156 Ok(Self {
157 bytes,
158 session_id,
159 cipher_suite,
160 compression_method,
161 extensions,
162 })
163 }
164
165 pub fn legacy_version(&self) -> TlsProtocolVersion {
167 TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[0], self.bytes[1]]))
168 }
169
170 pub fn random(&self) -> &'a [u8; 32] {
172 self.bytes[2..34]
173 .try_into()
174 .expect("validated ServerHello random")
175 }
176
177 pub fn session_id(&self) -> &'a [u8] {
179 self.session_id
180 }
181
182 pub fn cipher_suite(&self) -> TlsCipherSuite {
184 self.cipher_suite
185 }
186
187 pub fn compression_method(&self) -> TlsCompressionMethod {
189 self.compression_method
190 }
191
192 pub fn is_hello_retry_request(&self) -> bool {
194 self.random() == &HELLO_RETRY_REQUEST_RANDOM
195 }
196
197 pub fn extensions(&self) -> TlsExtensions<'a> {
199 TlsExtensions::new(self.extensions)
200 }
201
202 pub fn selected_version(&self) -> Result<Option<TlsProtocolVersion>, TlsParseError> {
204 for extension in self.extensions() {
205 let extension = extension?;
206 if extension.extension_type() == TlsExtensionType::SUPPORTED_VERSIONS {
207 return extension.server_supported_version().map(Some);
208 }
209 }
210 Ok(None)
211 }
212
213 pub fn as_bytes(&self) -> &'a [u8] {
215 self.bytes
216 }
217}
218
219fn need(bytes: &[u8], required: usize) -> Result<(), TlsParseError> {
220 if bytes.len() < required {
221 Err(TlsParseError::Incomplete {
222 required,
223 available: bytes.len(),
224 })
225 } else {
226 Ok(())
227 }
228}
229
230fn take_u8_vector<'a>(bytes: &'a [u8], offset: &mut usize) -> Result<&'a [u8], TlsParseError> {
231 need(&bytes[*offset..], 1)?;
232 let length = usize::from(bytes[*offset]);
233 *offset += 1;
234 take(bytes, offset, length)
235}
236
237fn take_u16_vector<'a>(bytes: &'a [u8], offset: &mut usize) -> Result<&'a [u8], TlsParseError> {
238 need(&bytes[*offset..], 2)?;
239 let length = usize::from(u16::from_be_bytes([bytes[*offset], bytes[*offset + 1]]));
240 *offset += 2;
241 take(bytes, offset, length)
242}
243
244fn take<'a>(bytes: &'a [u8], offset: &mut usize, length: usize) -> Result<&'a [u8], TlsParseError> {
245 let end = offset
246 .checked_add(length)
247 .ok_or(TlsParseError::InvalidValue)?;
248 need(&bytes[*offset..], length)?;
249 let result = &bytes[*offset..end];
250 *offset = end;
251 Ok(result)
252}