ytls_record/record/handshake/
client_hello.rs

1//! ClientHello
2
3use 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        // skip compressors parsing - add them in if someone needs them
63        // Note: Compressors have security related issues and was removed in TLS 1.3
64        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}