big changes
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
|
||||
use crate::{
|
||||
crypto::hmac::generate_auth_tag,
|
||||
tlseng::{
|
||||
consts::HANDSHAKE_TYPE_CLIENT_HELLO,
|
||||
extension::ExtensionBuilder,
|
||||
profile::profile::BrowserProfile,
|
||||
tls_record::TlsRecord,
|
||||
types::{ContentType, ProtocolVersion},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ClientHello {
|
||||
/// The maximum version supported (legacy field in TLS 1.3)
|
||||
pub version: ProtocolVersion,
|
||||
/// 32 bytes of client-generated entropy
|
||||
pub random: [u8; 32],
|
||||
/// Legacy session ID (used in TLS 1.3 for middlebox compatibility)
|
||||
pub session_id: Bytes,
|
||||
/// List of cryptographic ciphers the client supports
|
||||
pub cipher_suites: Vec<u16>,
|
||||
/// Opaque block of extensions generated by ExtensionBuilder
|
||||
pub extensions: Bytes,
|
||||
}
|
||||
|
||||
impl ClientHello {
|
||||
/// Serializes the ClientHello message into its wire format.
|
||||
/// Includes the 4-byte Handshake header (Type + Length).
|
||||
pub fn serialize(&self) -> Bytes {
|
||||
let mut buf = BytesMut::with_capacity(512 + self.extensions.len());
|
||||
|
||||
// Handshake Type: 0x01 (ClientHello)
|
||||
buf.put_u8(HANDSHAKE_TYPE_CLIENT_HELLO);
|
||||
|
||||
// Handshake Length Placeholder:
|
||||
// Handshake messages use a 24-bit (3 byte) length field.
|
||||
let length_pos = buf.len();
|
||||
buf.put_bytes(0, 3);
|
||||
|
||||
// Protocol Version:
|
||||
// For TLS 1.3, this is traditionally pinned to 0x0303 (TLS 1.2)
|
||||
// to prevent middleboxes from dropping the packet.
|
||||
buf.put_u16(0x0303);
|
||||
buf.put_slice(&self.random);
|
||||
|
||||
// Legacy Session ID:
|
||||
// Formatted as Length (1 byte) + ID bytes.
|
||||
buf.put_u8(self.session_id.len() as u8);
|
||||
buf.put_slice(&self.session_id);
|
||||
|
||||
// Cipher Suites:
|
||||
// Formatted as Total Length (2 bytes) + Suite IDs (2 bytes each).
|
||||
buf.put_u16((self.cipher_suites.len() * 2) as u16);
|
||||
for &suite in &self.cipher_suites {
|
||||
buf.put_u16(suite);
|
||||
}
|
||||
|
||||
// Legacy Compression Methods:
|
||||
// Always 1 byte of length (1) followed by the 'Null' method (0x00).
|
||||
buf.put_u8(1);
|
||||
buf.put_u8(0x00);
|
||||
|
||||
// Extensions Block:
|
||||
// Formatted as Total Length (2 bytes) + Extension Data.
|
||||
buf.put_u16(self.extensions.len() as u16);
|
||||
buf.put_slice(&self.extensions);
|
||||
|
||||
// Patch the Handshake Length:
|
||||
// We calculate the length of everything after the 3-byte placeholder.
|
||||
let total_len = (buf.len() - length_pos - 3) as u32;
|
||||
let len_bytes = total_len.to_be_bytes();
|
||||
// Copy the last 3 bytes of the big-endian u32 into the placeholder.
|
||||
buf[length_pos..length_pos + 3].copy_from_slice(&len_bytes[1..4]);
|
||||
|
||||
buf.freeze()
|
||||
}
|
||||
|
||||
pub fn make_client_hello(profile: &BrowserProfile, host: &str) -> Bytes {
|
||||
// 1. Key Exchange: Generate ECDH pair and get public key
|
||||
|
||||
// 2. Authentication: Generate 32 bytes for TLS Random
|
||||
// [16 bytes entropy] + [16 bytes HMAC(timestamp)]
|
||||
let mut tls_random = [0; 32];
|
||||
|
||||
let auth_token = generate_auth_tag(&[]);
|
||||
tls_random[16..32].copy_from_slice(&auth_token);
|
||||
|
||||
// 3. Extensions: Build the extensions block using the profile
|
||||
let mut ext_builder = ExtensionBuilder::new();
|
||||
// Pass the public key into the KeyShare extension via apply_profile
|
||||
ext_builder.apply_profile(profile, host, &[0; 32]);
|
||||
let extensions_bytes = ext_builder.build();
|
||||
|
||||
let mut session_id = BytesMut::with_capacity(32);
|
||||
session_id.put_slice(&[0u8; 32]);
|
||||
|
||||
// 4. Assemble ClientHello Handshake message
|
||||
let client_hello = ClientHello {
|
||||
version: ProtocolVersion::Tls12, // Legacy version for compatibility
|
||||
random: tls_random,
|
||||
session_id: session_id.freeze(), // Standard 32-byte session ID
|
||||
cipher_suites: vec![0x1301, 0x1302, 0x1303], // TLS 1.3 suites
|
||||
extensions: extensions_bytes,
|
||||
};
|
||||
|
||||
// 5. Wrap ClientHello into a TLS Record
|
||||
let record = TlsRecord::new(
|
||||
ContentType::Handshake,
|
||||
ProtocolVersion::Tls10,
|
||||
client_hello.serialize(),
|
||||
);
|
||||
|
||||
// Final result: Byte buffer ready for the wire
|
||||
record.serialize()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user