ytls_record/record/handshake/
client_hello.rs1use ytls_traits::ClientHelloProcessor;
4
5use super::CipherSuites;
6use super::Extensions;
7use crate::error::{ClientHelloError, RecordError};
8
9use zerocopy::byteorder::network_endian::U16 as N16;
10use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes, Unaligned};
11
12#[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
13#[repr(C)]
14#[derive(Debug, PartialEq)]
15pub struct ClientHelloHdr {
16 pub(crate) legacy_version: [u8; 2],
17 pub(crate) client_random: [u8; 32],
18 pub(crate) ses_id_len: u8,
19}
20
21#[derive(Debug, PartialEq)]
22pub struct ClientHello<'r> {
23 pub(crate) hdr: &'r ClientHelloHdr,
24}
25
26impl<'r> ClientHello<'r> {
27 pub fn parse<P: ClientHelloProcessor>(
28 prc: &mut P,
29 bytes: &'r [u8],
30 ) -> Result<(Self, &'r [u8]), RecordError> {
31 let (hello_hdr, mut rest) = ClientHelloHdr::try_ref_from_prefix(bytes)
32 .map_err(|e| RecordError::from_zero_copy(e))?;
33
34 prc.handle_client_random(&hello_hdr.client_random);
35
36 let ses_id_len: usize = hello_hdr.ses_id_len.into();
37
38 if ses_id_len > 32 {
39 return Err(RecordError::ClientHello(ClientHelloError::OverflowSesId));
40 }
41
42 let ses_id = &rest[0..ses_id_len];
43 prc.handle_session_id(&ses_id);
44
45 rest = &rest[ses_id_len..];
46 let lenb: [u8; 2] = [rest[0], rest[1]];
47 let cipher_suite_len = N16::from_bytes(lenb);
48
49 if cipher_suite_len > 65534 {
50 return Err(RecordError::ClientHello(
51 ClientHelloError::OverflowCipherSuites,
52 ));
53 }
54
55 rest = &rest[2..];
56 let (cipher_suites, rest_next) = rest.split_at(cipher_suite_len.into());
57 rest = rest_next;
58
59 CipherSuites::parse_cipher_suites(prc, cipher_suites)
60 .map_err(|e| RecordError::ClientHello(ClientHelloError::CipherSuites(e)))?;
61
62 let compressors_len = rest[0];
65 rest = &rest[1..];
66 let (_compressors, rest_next) = rest.split_at(compressors_len.into());
67 rest = rest_next;
68
69 let extensions_len = N16::from_bytes([rest[0], rest[1]]);
70 rest = &rest[2..];
71 let (extensions, rest_next) = rest.split_at(extensions_len.into());
72 rest = rest_next;
73
74 Extensions::parse_client_extensions(prc, extensions)
75 .map_err(|e| RecordError::ClientHello(ClientHelloError::Extensions(e)))?;
76
77 Ok((ClientHello { hdr: hello_hdr }, rest))
78 }
79}