use super::common::{
HANDSHAKE_TYPE_CERTIFICATE, HANDSHAKE_TYPE_CERTIFICATE_VERIFY,
HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS, HANDSHAKE_TYPE_FINISHED, HANDSHAKE_TYPE_SERVER_HELLO,
VERSION_TLS_1_2_MAJOR, VERSION_TLS_1_2_MINOR,
};
use aws_lc_rs::signature::Ed25519KeyPair;
use std::io::Result;
pub fn construct_server_hello(
server_random: &[u8; 32],
session_id: &[u8],
cipher_suite: u16,
key_share_data: &[u8],
) -> Result<Vec<u8>> {
let mut server_hello = Vec::new();
let mut payload = Vec::new();
payload.extend_from_slice(&[VERSION_TLS_1_2_MAJOR, VERSION_TLS_1_2_MINOR]);
payload.extend_from_slice(server_random);
payload.push(session_id.len() as u8);
payload.extend_from_slice(session_id);
payload.extend_from_slice(&cipher_suite.to_be_bytes());
payload.push(0x00);
let mut extensions = Vec::new();
extensions.extend_from_slice(&[0x00, 0x2b]); extensions.extend_from_slice(&[0x00, 0x02]); extensions.extend_from_slice(&[0x03, 0x04]);
let key_share_length = 2 + 2 + key_share_data.len(); extensions.extend_from_slice(&[0x00, 0x33]); extensions.extend_from_slice(&(key_share_length as u16).to_be_bytes());
extensions.extend_from_slice(&[0x00, 0x1d]); extensions.extend_from_slice(&(key_share_data.len() as u16).to_be_bytes());
extensions.extend_from_slice(key_share_data);
payload.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
payload.extend_from_slice(&extensions);
server_hello.push(HANDSHAKE_TYPE_SERVER_HELLO);
let length_bytes = [
((payload.len() >> 16) & 0xff) as u8,
((payload.len() >> 8) & 0xff) as u8,
(payload.len() & 0xff) as u8,
];
server_hello.extend_from_slice(&length_bytes);
server_hello.extend_from_slice(&payload);
Ok(server_hello)
}
pub fn construct_encrypted_extensions() -> Result<Vec<u8>> {
let mut encrypted_extensions = Vec::new();
encrypted_extensions.push(HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS);
let extensions_length: u16 = 0;
let payload_length = 2;
encrypted_extensions.extend_from_slice(&[0x00, 0x00, payload_length as u8]);
encrypted_extensions.extend_from_slice(&extensions_length.to_be_bytes());
Ok(encrypted_extensions)
}
pub fn construct_certificate(cert: rcgen::Certificate) -> Result<Vec<u8>> {
let cert_der = cert.der();
let cert_list_len = 3 + cert_der.len() + 2;
let payload_len = 1 + 3 + cert_list_len;
let total_len = 1 + 3 + payload_len;
let mut certificate = Vec::with_capacity(total_len);
certificate.push(HANDSHAKE_TYPE_CERTIFICATE);
certificate.extend_from_slice(&[
((payload_len >> 16) & 0xff) as u8,
((payload_len >> 8) & 0xff) as u8,
(payload_len & 0xff) as u8,
]);
certificate.push(0x00);
certificate.extend_from_slice(&[
((cert_list_len >> 16) & 0xff) as u8,
((cert_list_len >> 8) & 0xff) as u8,
(cert_list_len & 0xff) as u8,
]);
certificate.extend_from_slice(&[
((cert_der.len() >> 16) & 0xff) as u8,
((cert_der.len() >> 8) & 0xff) as u8,
(cert_der.len() & 0xff) as u8,
]);
certificate.extend_from_slice(cert_der);
certificate.extend_from_slice(&[0x00, 0x00]);
Ok(certificate)
}
pub fn construct_certificate_verify(
signing_key: &Ed25519KeyPair,
handshake_hash: &[u8],
) -> Result<Vec<u8>> {
let mut certificate_verify = Vec::new();
let mut signed_content = Vec::new();
signed_content.extend_from_slice(&[0x20u8; 64]); signed_content.extend_from_slice(b"TLS 1.3, server CertificateVerify");
signed_content.push(0x00);
signed_content.extend_from_slice(handshake_hash);
let signature = signing_key.sign(&signed_content);
let signature_bytes = signature.as_ref();
let mut payload = Vec::new();
payload.extend_from_slice(&[0x08, 0x07]);
payload.extend_from_slice(&(signature_bytes.len() as u16).to_be_bytes());
payload.extend_from_slice(signature_bytes);
certificate_verify.push(HANDSHAKE_TYPE_CERTIFICATE_VERIFY);
certificate_verify.extend_from_slice(&[
((payload.len() >> 16) & 0xff) as u8,
((payload.len() >> 8) & 0xff) as u8,
(payload.len() & 0xff) as u8,
]);
certificate_verify.extend_from_slice(&payload);
Ok(certificate_verify)
}
pub fn construct_finished(verify_data: &[u8]) -> Result<Vec<u8>> {
let mut finished = Vec::new();
finished.push(HANDSHAKE_TYPE_FINISHED);
finished.extend_from_slice(&[
((verify_data.len() >> 16) & 0xff) as u8,
((verify_data.len() >> 8) & 0xff) as u8,
(verify_data.len() & 0xff) as u8,
]);
finished.extend_from_slice(verify_data);
Ok(finished)
}
pub const DEFAULT_ALPN_PROTOCOLS: &[&str] = &["h2", "http/1.1"];
pub fn construct_client_hello(
client_random: &[u8; 32],
session_id: &[u8; 32],
client_public_key: &[u8],
server_name: &str,
cipher_suites: &[u16],
alpn_protocols: &[&str],
) -> Result<Vec<u8>> {
let mut hello = Vec::with_capacity(512);
hello.push(0x01);
let length_offset = hello.len();
hello.extend_from_slice(&[0u8; 3]);
hello.extend_from_slice(&[VERSION_TLS_1_2_MAJOR, VERSION_TLS_1_2_MINOR]);
hello.extend_from_slice(client_random);
hello.push(32);
hello.extend_from_slice(session_id);
let cipher_suites_len = (cipher_suites.len() * 2) as u16;
hello.extend_from_slice(&cipher_suites_len.to_be_bytes());
for &suite in cipher_suites {
hello.extend_from_slice(&suite.to_be_bytes());
}
hello.extend_from_slice(&[0x01, 0x00]);
let extensions_offset = hello.len();
hello.extend_from_slice(&[0u8; 2]);
let mut extensions = Vec::new();
{
let server_name_bytes = server_name.as_bytes();
let server_name_len = server_name_bytes.len();
extensions.extend_from_slice(&[0x00, 0x00]); let ext_len = 5 + server_name_len;
extensions.extend_from_slice(&(ext_len as u16).to_be_bytes()); extensions.extend_from_slice(&((server_name_len + 3) as u16).to_be_bytes()); extensions.push(0x00); extensions.extend_from_slice(&(server_name_len as u16).to_be_bytes()); extensions.extend_from_slice(server_name_bytes); }
{
extensions.extend_from_slice(&[0x00, 0x2b]); extensions.extend_from_slice(&[0x00, 0x03]); extensions.push(0x02); extensions.extend_from_slice(&[0x03, 0x04]); }
{
extensions.extend_from_slice(&[0x00, 0x0a]); extensions.extend_from_slice(&[0x00, 0x04]); extensions.extend_from_slice(&[0x00, 0x02]); extensions.extend_from_slice(&[0x00, 0x1d]); }
{
extensions.extend_from_slice(&[0x00, 0x33]); let key_share_len = 2 + 4 + client_public_key.len();
extensions.extend_from_slice(&(key_share_len as u16).to_be_bytes()); let key_share_list_len = 4 + client_public_key.len();
extensions.extend_from_slice(&(key_share_list_len as u16).to_be_bytes()); extensions.extend_from_slice(&[0x00, 0x1d]); extensions.extend_from_slice(&(client_public_key.len() as u16).to_be_bytes()); extensions.extend_from_slice(client_public_key); }
{
extensions.extend_from_slice(&[0x00, 0x0d]); extensions.extend_from_slice(&[0x00, 0x12]); extensions.extend_from_slice(&[0x00, 0x10]); extensions.extend_from_slice(&[0x04, 0x03]); extensions.extend_from_slice(&[0x08, 0x04]); extensions.extend_from_slice(&[0x04, 0x01]); extensions.extend_from_slice(&[0x05, 0x03]); extensions.extend_from_slice(&[0x08, 0x05]); extensions.extend_from_slice(&[0x05, 0x01]); extensions.extend_from_slice(&[0x08, 0x06]); extensions.extend_from_slice(&[0x06, 0x01]); }
if !alpn_protocols.is_empty() {
extensions.extend_from_slice(&[0x00, 0x10]);
let protocols_list_len: usize = alpn_protocols
.iter()
.map(|p| 1 + p.len()) .sum();
let ext_len = 2 + protocols_list_len;
extensions.extend_from_slice(&(ext_len as u16).to_be_bytes());
extensions.extend_from_slice(&(protocols_list_len as u16).to_be_bytes());
for protocol in alpn_protocols {
extensions.push(protocol.len() as u8);
extensions.extend_from_slice(protocol.as_bytes());
}
}
let extensions_length = extensions.len();
hello[extensions_offset..extensions_offset + 2]
.copy_from_slice(&(extensions_length as u16).to_be_bytes());
hello.extend_from_slice(&extensions);
let message_length = hello.len() - 4; hello[length_offset..length_offset + 3]
.copy_from_slice(&(message_length as u32).to_be_bytes()[1..]);
Ok(hello)
}
pub fn write_record_header(record_type: u8, length: u16) -> Vec<u8> {
let mut header = Vec::new();
header.push(record_type);
header.extend_from_slice(&[VERSION_TLS_1_2_MAJOR, VERSION_TLS_1_2_MINOR]); header.extend_from_slice(&length.to_be_bytes());
header
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reality::common::CONTENT_TYPE_HANDSHAKE;
#[test]
fn test_construct_server_hello() {
let server_random = [0x42u8; 32];
let session_id = vec![0x99u8; 32];
let cipher_suite = 0x1301; let key_share = vec![0xAAu8; 32];
let result = construct_server_hello(&server_random, &session_id, cipher_suite, &key_share);
assert!(result.is_ok());
let msg = result.unwrap();
assert_eq!(msg[0], HANDSHAKE_TYPE_SERVER_HELLO);
}
#[test]
fn test_construct_encrypted_extensions() {
let result = construct_encrypted_extensions();
assert!(result.is_ok());
let msg = result.unwrap();
assert_eq!(msg[0], HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS);
}
#[test]
fn test_construct_certificate() {
use crate::reality::reality_certificate::generate_hmac_certificate;
let auth_key = [0x42u8; 32];
let (cert, _) = generate_hmac_certificate(&auth_key, "test.example.com").unwrap();
let result = construct_certificate(cert);
assert!(result.is_ok());
let msg = result.unwrap();
assert_eq!(msg[0], HANDSHAKE_TYPE_CERTIFICATE);
}
#[test]
fn test_construct_finished() {
let verify_data = vec![0xCCu8; 32];
let result = construct_finished(&verify_data);
assert!(result.is_ok());
let msg = result.unwrap();
assert_eq!(msg[0], HANDSHAKE_TYPE_FINISHED);
assert_eq!(msg.len(), 1 + 3 + 32); }
#[test]
fn test_write_record_header() {
let header = write_record_header(CONTENT_TYPE_HANDSHAKE, 100);
assert_eq!(header.len(), 5);
assert_eq!(header[0], 0x16); assert_eq!(header[1], 0x03); assert_eq!(header[2], 0x03);
assert_eq!(u16::from_be_bytes([header[3], header[4]]), 100);
}
#[test]
fn test_client_hello_signature_algorithms_match_chrome_utls() {
let client_random = [0u8; 32];
let session_id = [0u8; 32];
let client_public_key = [0u8; 32];
let hello = construct_client_hello(
&client_random,
&session_id,
&client_public_key,
"example.com",
&[0x1301],
&["h2"],
)
.unwrap();
let mut offset = 1 + 3 + 2 + 32;
let session_id_len = hello[offset] as usize;
offset += 1 + session_id_len;
let cipher_suites_len = u16::from_be_bytes([hello[offset], hello[offset + 1]]) as usize;
offset += 2 + cipher_suites_len;
let compression_methods_len = hello[offset] as usize;
offset += 1 + compression_methods_len;
let extensions_len = u16::from_be_bytes([hello[offset], hello[offset + 1]]) as usize;
offset += 2;
let extensions_end = offset + extensions_len;
let mut signature_algorithms = None;
while offset < extensions_end {
let extension_type = u16::from_be_bytes([hello[offset], hello[offset + 1]]);
let extension_len = u16::from_be_bytes([hello[offset + 2], hello[offset + 3]]) as usize;
offset += 4;
if extension_type == 0x000d {
signature_algorithms = Some(&hello[offset..offset + extension_len]);
break;
}
offset += extension_len;
}
let extension = signature_algorithms.expect("missing signature_algorithms extension");
assert_eq!(u16::from_be_bytes([extension[0], extension[1]]), 16);
assert_eq!(
&extension[2..],
&[
0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, ]
);
}
}