use crate::error::BuilderError;
use ytls_traits::ClientHelloBuilder;
#[derive(Debug, PartialEq)]
pub struct BufStaticClientHello<const N: usize> {
bytes_buf: [u8; N],
bytes_len: usize,
}
use super::formatter::EncoderU16;
impl<const N: usize> BufStaticClientHello<N> {
pub(crate) fn as_hashing_context(&self) -> &[u8] {
&self.bytes_buf[5..self.bytes_len]
}
pub(crate) fn as_encoded_bytes(&self) -> &[u8] {
&self.bytes_buf[0..self.bytes_len]
}
#[inline]
pub(crate) fn static_from_untyped<S: ClientHelloBuilder>(s: &S) -> Result<Self, BuilderError> {
let mut cursor = EncoderU16::<N>::new();
let mut buffer: [u8; N] = [0; N];
cursor.try_skip_only(5)?;
buffer[0] = 0x16; let version_b = s.legacy_version();
buffer[1] = version_b[0];
buffer[2] = version_b[1];
let pos_rec_len_start = 3;
cursor.try_skip_only(4)?;
buffer[5] = 0x01;
let pos_client_hello_len_start = 7;
cursor.try_fill_with(&mut buffer, s.legacy_client_version())?;
cursor.try_fill_with(&mut buffer, s.client_random())?;
let session_id = s.legacy_session_id();
if session_id.len() > 255 {
return Err(BuilderError::SessionIdOverflow);
}
let cur = cursor.cur_as_usize();
cursor.try_skip_only(1)?;
buffer[cur] = session_id.len() as u8;
cursor.try_fill_with(&mut buffer, session_id)?;
let cipher_suites = s.cipher_suites();
let cipher_suites_len_b16 = ((cipher_suites.len() * 2) as u16).to_be_bytes();
cursor.try_fill_with(&mut buffer, &cipher_suites_len_b16)?;
for cipher_suite in cipher_suites {
cursor.try_fill_with(&mut buffer, cipher_suite)?;
}
let cur = cursor.cur_as_usize();
cursor.try_skip_only(1)?;
let compression_methods = s.supported_legacy_insecure_compression_methods();
if compression_methods.len() > 255 {
return Err(BuilderError::Overflow);
}
cursor.try_fill_with(&mut buffer, compression_methods)?;
buffer[cur] = compression_methods.len() as u8;
let pos_extension_len_start = cursor.cur_as_usize();
cursor.try_skip_only(2)?;
let mut extensions_total_len = 0_u16;
let extensions = s.extensions_list();
for ext in extensions {
cursor.try_fill_with(&mut buffer, &ext.to_be_bytes())?;
let ext_data = s.extension_data(*ext);
if ext_data.len() > u16::MAX as usize {
return Err(BuilderError::Overflow);
}
let ext_u16_b = (ext_data.len() as u16).to_be_bytes();
cursor.try_fill_with(&mut buffer, &ext_u16_b)?;
cursor.try_fill_with(&mut buffer, ext_data)?;
extensions_total_len += 4_u16 + ext_data.len() as u16;
}
buffer[pos_extension_len_start..pos_extension_len_start + 2]
.copy_from_slice(&extensions_total_len.to_be_bytes());
let record_len = cursor.cur_as_u16() - 5;
buffer[pos_rec_len_start..pos_rec_len_start + 2]
.copy_from_slice(&(record_len.to_be_bytes()));
let hello_len = record_len - 4;
buffer[pos_client_hello_len_start..pos_client_hello_len_start + 2]
.copy_from_slice(&hello_len.to_be_bytes());
Ok(Self {
bytes_buf: buffer,
bytes_len: cursor.cur_as_usize(),
})
}
}
#[cfg(test)]
mod test_ok_no_extensions {
use super::*;
use hex_literal::hex;
use ytls_traits::ClientHelloBuilder;
use ytls_traits::HandshakeBuilder;
struct Tester;
impl ClientHelloBuilder for Tester {
fn legacy_version(&self) -> &[u8; 2] {
&[3, 1]
}
fn legacy_client_version(&self) -> &[u8; 2] {
&[3, 3]
}
fn client_random(&self) -> &[u8; 32] {
&[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
]
}
fn legacy_session_id(&self) -> &[u8] {
&[
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
]
}
fn cipher_suites(&self) -> &[[u8; 2]] {
&[[0x13, 0x03]]
}
fn supported_legacy_insecure_compression_methods(&self) -> &[u8] {
&[00]
}
fn extensions_list(&self) -> &[u16] {
&[]
}
fn extension_data(&self, _id: u16) -> &[u8] {
unreachable!()
}
}
#[test]
fn static_8192_basic() {
let tester = Tester;
let b = BufStaticClientHello::<8192>::static_from_untyped(&tester)
.expect("Test: Builder: StaticClientHello failure");
let h = hex::encode(b.as_encoded_bytes());
let expected = hex!(
"16
03 01
00 4F
01
00 00 4b
03 03
01 02 03 04 05 06 07 08 09 0a
0b 0c 0d 0e 0f 10 11 12 13 14
15 16 17 18 19 1a 1b 1c 1d 1e
1f 20
20
32 33 34 35 36 37 38 39 3a 3b
3c 3d 3e 3f 40 41 42 43 44 45
46 47 48 49 4a 4b 4c 4d 4e 4f
50 51
00 02 13 03
01 00
00 00
"
);
assert_eq!(hex::encode(expected), h);
}
}