use ytls_traits::ClientHelloProcessor;
use super::CipherSuites;
use super::Extensions;
use crate::error::{ClientHelloError, RecordError};
use zerocopy::byteorder::network_endian::U16 as N16;
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes, Unaligned};
#[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct ClientHelloHdr {
pub(crate) legacy_version: [u8; 2],
pub(crate) client_random: [u8; 32],
pub(crate) ses_id_len: u8,
}
#[derive(Debug, PartialEq)]
pub struct ClientHello<'r> {
pub(crate) hdr: &'r ClientHelloHdr,
}
impl<'r> ClientHello<'r> {
pub fn parse<P: ClientHelloProcessor>(
prc: &mut P,
bytes: &'r [u8],
) -> Result<(Self, &'r [u8]), RecordError> {
let (hello_hdr, mut rest) = ClientHelloHdr::try_ref_from_prefix(bytes)
.map_err(|e| RecordError::from_zero_copy(e))?;
prc.handle_client_random(&hello_hdr.client_random);
let ses_id_len: usize = hello_hdr.ses_id_len.into();
if ses_id_len > 32 {
return Err(RecordError::ClientHello(ClientHelloError::OverflowSesId));
}
let ses_id = &rest[0..ses_id_len];
prc.handle_session_id(&ses_id);
rest = &rest[ses_id_len..];
let lenb: [u8; 2] = [rest[0], rest[1]];
let cipher_suite_len = N16::from_bytes(lenb);
if cipher_suite_len > 65534 {
return Err(RecordError::ClientHello(
ClientHelloError::OverflowCipherSuites,
));
}
rest = &rest[2..];
let (cipher_suites, rest_next) = rest.split_at(cipher_suite_len.into());
rest = rest_next;
CipherSuites::parse_cipher_suites(prc, cipher_suites)
.map_err(|e| RecordError::ClientHello(ClientHelloError::CipherSuites(e)))?;
let compressors_len = rest[0];
rest = &rest[1..];
let (_compressors, rest_next) = rest.split_at(compressors_len.into());
rest = rest_next;
let extensions_len = N16::from_bytes([rest[0], rest[1]]);
rest = &rest[2..];
let (extensions, rest_next) = rest.split_at(extensions_len.into());
rest = rest_next;
Extensions::parse_client_extensions(prc, extensions)
.map_err(|e| RecordError::ClientHello(ClientHelloError::Extensions(e)))?;
Ok((ClientHello { hdr: hello_hdr }, rest))
}
}