mirror of
https://github.com/telemt/telemt.git
synced 2026-06-13 06:21:44 +03:00
Alles muss man selber machen
Co-Authored-By: Mikhail I. Izmestev <355023+izmmisha@users.noreply.github.com> Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com> Co-Authored-By: Dietmar Schreiber <376736+dginorg@users.noreply.github.com>
This commit is contained in:
@@ -1239,6 +1239,18 @@ fn test_gen_fake_x25519_key() {
|
|||||||
assert_ne!(key1, key2);
|
assert_ne!(key1, key2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gen_fake_x25519mlkem768_server_key_share_shape() {
|
||||||
|
let rng = crate::crypto::SecureRandom::new();
|
||||||
|
let key_share = gen_fake_x25519mlkem768_server_key_share(&rng);
|
||||||
|
|
||||||
|
assert_eq!(key_share.len(), X25519MLKEM768_SERVER_KEY_SHARE_LEN);
|
||||||
|
assert!(
|
||||||
|
key_share.iter().any(|byte| *byte != 0),
|
||||||
|
"hybrid ServerHello key_share must not collapse to all-zero bytes"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fake_x25519_key_is_nonzero_and_varies() {
|
fn test_fake_x25519_key_is_nonzero_and_varies() {
|
||||||
let rng = crate::crypto::SecureRandom::new();
|
let rng = crate::crypto::SecureRandom::new();
|
||||||
@@ -1325,6 +1337,65 @@ fn server_hello_extension_types(record: &[u8]) -> Vec<u16> {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn server_hello_key_share(record: &[u8]) -> Option<(u16, usize)> {
|
||||||
|
if record.len() < 9 || record[0] != TLS_RECORD_HANDSHAKE || record[5] != 0x02 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let record_len = u16::from_be_bytes([record[3], record[4]]) as usize;
|
||||||
|
if record.len() < 5 + record_len {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hs_len = u32::from_be_bytes([0, record[6], record[7], record[8]]) as usize;
|
||||||
|
let hs_start = 5;
|
||||||
|
let hs_end = hs_start + 4 + hs_len;
|
||||||
|
if hs_end > record.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pos = hs_start + 4 + 2 + 32;
|
||||||
|
if pos >= hs_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let sid_len = record[pos] as usize;
|
||||||
|
pos += 1 + sid_len;
|
||||||
|
if pos + 2 + 1 + 2 > hs_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += 2 + 1;
|
||||||
|
let ext_len = u16::from_be_bytes([record[pos], record[pos + 1]]) as usize;
|
||||||
|
pos += 2;
|
||||||
|
let ext_end = pos + ext_len;
|
||||||
|
if ext_end > hs_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
while pos + 4 <= ext_end {
|
||||||
|
let etype = u16::from_be_bytes([record[pos], record[pos + 1]]);
|
||||||
|
let elen = u16::from_be_bytes([record[pos + 2], record[pos + 3]]) as usize;
|
||||||
|
pos += 4;
|
||||||
|
if pos + elen > ext_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if etype == extension_type::KEY_SHARE {
|
||||||
|
if elen < 4 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let group = u16::from_be_bytes([record[pos], record[pos + 1]]);
|
||||||
|
let key_exchange_len = u16::from_be_bytes([record[pos + 2], record[pos + 3]]) as usize;
|
||||||
|
if 4 + key_exchange_len != elen {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some((group, key_exchange_len));
|
||||||
|
}
|
||||||
|
pos += elen;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_server_hello_never_places_alpn_in_server_hello_extensions() {
|
fn build_server_hello_never_places_alpn_in_server_hello_extensions() {
|
||||||
let secret = b"alpn_sh_forbidden";
|
let secret = b"alpn_sh_forbidden";
|
||||||
@@ -1386,6 +1457,7 @@ fn emulated_server_hello_never_places_alpn_in_server_hello_extensions() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(b"h2".to_vec()),
|
Some(b"h2".to_vec()),
|
||||||
0,
|
0,
|
||||||
@@ -1402,7 +1474,7 @@ fn test_tls_extension_builder() {
|
|||||||
let key = [0x42u8; 32];
|
let key = [0x42u8; 32];
|
||||||
|
|
||||||
let mut builder = TlsExtensionBuilder::new();
|
let mut builder = TlsExtensionBuilder::new();
|
||||||
builder.add_key_share(&key);
|
builder.add_key_share(TLS_NAMED_GROUP_X25519, &key);
|
||||||
builder.add_supported_versions(0x0304);
|
builder.add_supported_versions(0x0304);
|
||||||
|
|
||||||
let result = builder.build();
|
let result = builder.build();
|
||||||
@@ -1418,7 +1490,7 @@ fn test_server_hello_builder() {
|
|||||||
let key = [0x55u8; 32];
|
let key = [0x55u8; 32];
|
||||||
|
|
||||||
let builder = ServerHelloBuilder::new(session_id.clone())
|
let builder = ServerHelloBuilder::new(session_id.clone())
|
||||||
.with_x25519_key(&key)
|
.with_key_share(TLS_NAMED_GROUP_X25519, &key)
|
||||||
.with_tls13_version();
|
.with_tls13_version();
|
||||||
|
|
||||||
let record = builder.build_record();
|
let record = builder.build_record();
|
||||||
@@ -1452,6 +1524,39 @@ fn test_build_server_hello_structure() {
|
|||||||
let app_start = ccs_start + ccs_len;
|
let app_start = ccs_start + ccs_len;
|
||||||
assert!(response.len() > app_start + 5);
|
assert!(response.len() > app_start + 5);
|
||||||
assert_eq!(response[app_start], TLS_RECORD_APPLICATION);
|
assert_eq!(response[app_start], TLS_RECORD_APPLICATION);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
server_hello_key_share(&response),
|
||||||
|
Some((
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
|
X25519MLKEM768_SERVER_KEY_SHARE_LEN
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_server_hello_with_cipher_can_keep_x25519_key_share() {
|
||||||
|
let secret = b"test secret";
|
||||||
|
let client_digest = [0x42u8; 32];
|
||||||
|
let session_id = vec![0xAA; 32];
|
||||||
|
|
||||||
|
let rng = crate::crypto::SecureRandom::new();
|
||||||
|
let response = build_server_hello_with_cipher(
|
||||||
|
secret,
|
||||||
|
&client_digest,
|
||||||
|
&session_id,
|
||||||
|
2048,
|
||||||
|
&rng,
|
||||||
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
server_hello_key_share(&response),
|
||||||
|
Some((TLS_NAMED_GROUP_X25519, X25519_KEY_SHARE_LEN))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1477,7 +1582,7 @@ fn test_server_hello_extensions_length() {
|
|||||||
let key = [0x55u8; 32];
|
let key = [0x55u8; 32];
|
||||||
|
|
||||||
let builder = ServerHelloBuilder::new(session_id)
|
let builder = ServerHelloBuilder::new(session_id)
|
||||||
.with_x25519_key(&key)
|
.with_key_share(TLS_NAMED_GROUP_X25519, &key)
|
||||||
.with_tls13_version();
|
.with_tls13_version();
|
||||||
|
|
||||||
let record = builder.build_record();
|
let record = builder.build_record();
|
||||||
@@ -1513,6 +1618,23 @@ fn build_client_hello_with_exts(exts: Vec<(u16, Vec<u8>)>, host: &str) -> Vec<u8
|
|||||||
build_client_hello_with_ciphers_and_exts(&[[0x13, 0x01]], exts, host)
|
build_client_hello_with_ciphers_and_exts(&[[0x13, 0x01]], exts, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_key_share_extension(entries: &[(u16, usize)]) -> Vec<u8> {
|
||||||
|
let mut shares = Vec::new();
|
||||||
|
for (group, key_exchange_len) in entries {
|
||||||
|
assert!(*key_exchange_len <= u16::MAX as usize);
|
||||||
|
shares.extend_from_slice(&group.to_be_bytes());
|
||||||
|
shares.extend_from_slice(&(*key_exchange_len as u16).to_be_bytes());
|
||||||
|
let start = shares.len();
|
||||||
|
shares.resize(start + *key_exchange_len, 0x42);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(shares.len() <= u16::MAX as usize);
|
||||||
|
let mut extension = Vec::new();
|
||||||
|
extension.extend_from_slice(&(shares.len() as u16).to_be_bytes());
|
||||||
|
extension.extend_from_slice(&shares);
|
||||||
|
extension
|
||||||
|
}
|
||||||
|
|
||||||
fn build_client_hello_with_ciphers_and_exts(
|
fn build_client_hello_with_ciphers_and_exts(
|
||||||
cipher_suites: &[[u8; 2]],
|
cipher_suites: &[[u8; 2]],
|
||||||
exts: Vec<(u16, Vec<u8>)>,
|
exts: Vec<(u16, Vec<u8>)>,
|
||||||
@@ -1711,6 +1833,67 @@ fn select_server_hello_cipher_suite_keeps_preferred_for_malformed_clienthello()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_hello_key_share_group_prefers_hybrid_when_valid_share_is_offered() {
|
||||||
|
let key_share = client_key_share_extension(&[
|
||||||
|
(0x0a0a, 1),
|
||||||
|
(
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
|
X25519MLKEM768_CLIENT_KEY_SHARE_LEN,
|
||||||
|
),
|
||||||
|
(TLS_NAMED_GROUP_X25519, X25519_KEY_SHARE_LEN),
|
||||||
|
]);
|
||||||
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
select_server_hello_key_share_group(&ch),
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_hello_key_share_group_falls_back_without_hybrid_share() {
|
||||||
|
let key_share =
|
||||||
|
client_key_share_extension(&[(TLS_NAMED_GROUP_X25519, X25519_KEY_SHARE_LEN)]);
|
||||||
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
select_server_hello_key_share_group(&ch),
|
||||||
|
TLS_NAMED_GROUP_X25519
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_hello_key_share_group_falls_back_for_malformed_hybrid_len() {
|
||||||
|
let key_share = client_key_share_extension(&[(
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
|
X25519MLKEM768_CLIENT_KEY_SHARE_LEN - 1,
|
||||||
|
)]);
|
||||||
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
select_server_hello_key_share_group(&ch),
|
||||||
|
TLS_NAMED_GROUP_X25519
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_hello_key_share_group_falls_back_for_malformed_key_share_tail() {
|
||||||
|
let mut key_share = client_key_share_extension(&[(
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
|
X25519MLKEM768_CLIENT_KEY_SHARE_LEN,
|
||||||
|
)]);
|
||||||
|
let shares_len = u16::from_be_bytes([key_share[0], key_share[1]]) + 1;
|
||||||
|
key_share[0..2].copy_from_slice(&shares_len.to_be_bytes());
|
||||||
|
key_share.push(0);
|
||||||
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
select_server_hello_key_share_group(&ch),
|
||||||
|
TLS_NAMED_GROUP_X25519
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extract_sni_rejects_zero_length_host_name() {
|
fn extract_sni_rejects_zero_length_host_name() {
|
||||||
let mut sni_ext = Vec::new();
|
let mut sni_ext = Vec::new();
|
||||||
|
|||||||
@@ -109,11 +109,22 @@ mod cipher_suite {
|
|||||||
pub const TLS_CHACHA20_POLY1305_SHA256: [u8; 2] = [0x13, 0x03];
|
pub const TLS_CHACHA20_POLY1305_SHA256: [u8; 2] = [0x13, 0x03];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TLS Named Curves
|
/// TLS named groups used in KeyShare extensions.
|
||||||
mod named_curve {
|
mod named_curve {
|
||||||
pub const X25519: u16 = 0x001d;
|
pub const X25519: u16 = 0x001d;
|
||||||
|
pub const X25519MLKEM768: u16 = 0x11ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TLS X25519 named group.
|
||||||
|
pub(crate) const TLS_NAMED_GROUP_X25519: u16 = named_curve::X25519;
|
||||||
|
/// TLS X25519MLKEM768 named group.
|
||||||
|
pub(crate) const TLS_NAMED_GROUP_X25519MLKEM768: u16 = named_curve::X25519MLKEM768;
|
||||||
|
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
const X25519MLKEM768_CLIENT_KEY_SHARE_LEN: usize = 1216;
|
||||||
|
const X25519MLKEM768_SERVER_KEY_SHARE_LEN: usize = 1120;
|
||||||
|
const MLKEM768_SERVER_CIPHERTEXT_LEN: usize = 1088;
|
||||||
|
|
||||||
// ============= TLS Validation Result =============
|
// ============= TLS Validation Result =============
|
||||||
|
|
||||||
/// Result of validating TLS handshake
|
/// Result of validating TLS handshake
|
||||||
@@ -144,26 +155,28 @@ impl TlsExtensionBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add Key Share extension with X25519 key
|
/// Add KeyShare extension with the selected named group.
|
||||||
fn add_key_share(&mut self, public_key: &[u8; 32]) -> &mut Self {
|
fn add_key_share(&mut self, group: u16, key_exchange: &[u8]) -> &mut Self {
|
||||||
|
let Ok(key_exchange_len) = u16::try_from(key_exchange.len()) else {
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
let Some(entry_len) = key_exchange.len().checked_add(4) else {
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
let Ok(entry_len) = u16::try_from(entry_len) else {
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
// Extension type: key_share (0x0033)
|
// Extension type: key_share (0x0033)
|
||||||
self.extensions
|
self.extensions
|
||||||
.extend_from_slice(&extension_type::KEY_SHARE.to_be_bytes());
|
.extend_from_slice(&extension_type::KEY_SHARE.to_be_bytes());
|
||||||
|
|
||||||
// Key share entry: curve (2) + key_len (2) + key (32) = 36 bytes
|
// ServerHello key_share data is exactly one KeyShareEntry.
|
||||||
// Extension data length
|
|
||||||
let entry_len: u16 = 2 + 2 + 32; // curve + length + key
|
|
||||||
self.extensions.extend_from_slice(&entry_len.to_be_bytes());
|
self.extensions.extend_from_slice(&entry_len.to_be_bytes());
|
||||||
|
self.extensions.extend_from_slice(&group.to_be_bytes());
|
||||||
// Named curve: x25519
|
|
||||||
self.extensions
|
self.extensions
|
||||||
.extend_from_slice(&named_curve::X25519.to_be_bytes());
|
.extend_from_slice(&key_exchange_len.to_be_bytes());
|
||||||
|
self.extensions.extend_from_slice(key_exchange);
|
||||||
// Key length
|
|
||||||
self.extensions.extend_from_slice(&(32u16).to_be_bytes());
|
|
||||||
|
|
||||||
// Key data
|
|
||||||
self.extensions.extend_from_slice(public_key);
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -232,8 +245,8 @@ impl ServerHelloBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_x25519_key(mut self, key: &[u8; 32]) -> Self {
|
fn with_key_share(mut self, group: u16, key_exchange: &[u8]) -> Self {
|
||||||
self.extensions.add_key_share(key);
|
self.extensions.add_key_share(group, key_exchange);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,11 +521,22 @@ fn validate_tls_handshake_at_time_with_boot_cap(
|
|||||||
/// Uses RFC 7748 X25519 scalar multiplication over the canonical basepoint,
|
/// Uses RFC 7748 X25519 scalar multiplication over the canonical basepoint,
|
||||||
/// yielding distribution-consistent public keys for anti-fingerprinting.
|
/// yielding distribution-consistent public keys for anti-fingerprinting.
|
||||||
pub fn gen_fake_x25519_key(rng: &SecureRandom) -> [u8; 32] {
|
pub fn gen_fake_x25519_key(rng: &SecureRandom) -> [u8; 32] {
|
||||||
let mut scalar = [0u8; 32];
|
let mut scalar = [0u8; X25519_KEY_SHARE_LEN];
|
||||||
scalar.copy_from_slice(&rng.bytes(32));
|
scalar.copy_from_slice(&rng.bytes(X25519_KEY_SHARE_LEN));
|
||||||
x25519(scalar, X25519_BASEPOINT_BYTES)
|
x25519(scalar, X25519_BASEPOINT_BYTES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a fake X25519MLKEM768 ServerHello key_share payload.
|
||||||
|
pub(crate) fn gen_fake_x25519mlkem768_server_key_share(rng: &SecureRandom) -> Vec<u8> {
|
||||||
|
let mut key_share = vec![0u8; X25519MLKEM768_SERVER_KEY_SHARE_LEN];
|
||||||
|
// FakeTLS never derives TLS traffic secrets from this payload; only the
|
||||||
|
// externally visible named group and vector lengths are protocol-facing.
|
||||||
|
rng.fill(&mut key_share[..MLKEM768_SERVER_CIPHERTEXT_LEN]);
|
||||||
|
let x25519_key = gen_fake_x25519_key(rng);
|
||||||
|
key_share[MLKEM768_SERVER_CIPHERTEXT_LEN..].copy_from_slice(&x25519_key);
|
||||||
|
key_share
|
||||||
|
}
|
||||||
|
|
||||||
/// Build TLS ServerHello response
|
/// Build TLS ServerHello response
|
||||||
///
|
///
|
||||||
/// This builds a complete TLS 1.3-like response including:
|
/// This builds a complete TLS 1.3-like response including:
|
||||||
@@ -537,6 +561,7 @@ pub fn build_server_hello(
|
|||||||
fake_cert_len,
|
fake_cert_len,
|
||||||
rng,
|
rng,
|
||||||
cipher_suite::TLS_AES_128_GCM_SHA256,
|
cipher_suite::TLS_AES_128_GCM_SHA256,
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
alpn,
|
alpn,
|
||||||
new_session_tickets,
|
new_session_tickets,
|
||||||
)
|
)
|
||||||
@@ -554,20 +579,30 @@ pub(crate) fn build_server_hello_with_cipher(
|
|||||||
fake_cert_len: usize,
|
fake_cert_len: usize,
|
||||||
rng: &SecureRandom,
|
rng: &SecureRandom,
|
||||||
selected_cipher_suite: [u8; 2],
|
selected_cipher_suite: [u8; 2],
|
||||||
|
selected_key_share_group: u16,
|
||||||
alpn: Option<Vec<u8>>,
|
alpn: Option<Vec<u8>>,
|
||||||
new_session_tickets: u8,
|
new_session_tickets: u8,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
const MIN_APP_DATA: usize = 64;
|
const MIN_APP_DATA: usize = 64;
|
||||||
const MAX_APP_DATA: usize = MAX_TLS_CIPHERTEXT_SIZE;
|
const MAX_APP_DATA: usize = MAX_TLS_CIPHERTEXT_SIZE;
|
||||||
let fake_cert_len = fake_cert_len.clamp(MIN_APP_DATA, MAX_APP_DATA);
|
let fake_cert_len = fake_cert_len.clamp(MIN_APP_DATA, MAX_APP_DATA);
|
||||||
let x25519_key = gen_fake_x25519_key(rng);
|
|
||||||
|
|
||||||
// Build ServerHello
|
// Build ServerHello
|
||||||
let server_hello = ServerHelloBuilder::new(session_id.to_vec())
|
let server_hello = if selected_key_share_group == TLS_NAMED_GROUP_X25519MLKEM768 {
|
||||||
.with_cipher_suite(selected_cipher_suite)
|
let key_share = gen_fake_x25519mlkem768_server_key_share(rng);
|
||||||
.with_x25519_key(&x25519_key)
|
ServerHelloBuilder::new(session_id.to_vec())
|
||||||
.with_tls13_version()
|
.with_cipher_suite(selected_cipher_suite)
|
||||||
.build_record();
|
.with_key_share(TLS_NAMED_GROUP_X25519MLKEM768, &key_share)
|
||||||
|
.with_tls13_version()
|
||||||
|
.build_record()
|
||||||
|
} else {
|
||||||
|
let key_share = gen_fake_x25519_key(rng);
|
||||||
|
ServerHelloBuilder::new(session_id.to_vec())
|
||||||
|
.with_cipher_suite(selected_cipher_suite)
|
||||||
|
.with_key_share(TLS_NAMED_GROUP_X25519, &key_share)
|
||||||
|
.with_tls13_version()
|
||||||
|
.build_record()
|
||||||
|
};
|
||||||
|
|
||||||
// Build Change Cipher Spec record
|
// Build Change Cipher Spec record
|
||||||
let change_cipher_spec = [
|
let change_cipher_spec = [
|
||||||
@@ -1003,6 +1038,145 @@ fn client_hello_cipher_suites_range(handshake: &[u8]) -> Option<(usize, usize)>
|
|||||||
Some((pos, cipher_end))
|
Some((pos, cipher_end))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_hello_extensions_range(handshake: &[u8]) -> Option<(usize, usize)> {
|
||||||
|
if handshake.len() < 5 || handshake[0] != TLS_RECORD_HANDSHAKE {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let record_len = u16::from_be_bytes([handshake[3], handshake[4]]) as usize;
|
||||||
|
let record_end = 5usize.checked_add(record_len)?;
|
||||||
|
if record_end > handshake.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pos = 5;
|
||||||
|
if handshake.get(pos) != Some(&0x01) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
|
||||||
|
if pos + 3 > record_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let handshake_len = ((handshake[pos] as usize) << 16)
|
||||||
|
| ((handshake[pos + 1] as usize) << 8)
|
||||||
|
| handshake[pos + 2] as usize;
|
||||||
|
pos += 3;
|
||||||
|
let handshake_end = pos.checked_add(handshake_len)?;
|
||||||
|
if handshake_end > record_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos + 2 + 32 > handshake_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pos += 2 + 32;
|
||||||
|
|
||||||
|
let session_id_len = *handshake.get(pos)? as usize;
|
||||||
|
pos = pos.checked_add(1)?.checked_add(session_id_len)?;
|
||||||
|
if pos + 2 > handshake_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cipher_len = u16::from_be_bytes([handshake[pos], handshake[pos + 1]]) as usize;
|
||||||
|
if cipher_len == 0 || cipher_len % 2 != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pos += 2;
|
||||||
|
pos = pos.checked_add(cipher_len)?;
|
||||||
|
if pos + 1 > handshake_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let compression_len = *handshake.get(pos)? as usize;
|
||||||
|
pos = pos.checked_add(1)?.checked_add(compression_len)?;
|
||||||
|
if pos == handshake_end {
|
||||||
|
return Some((handshake_end, handshake_end));
|
||||||
|
}
|
||||||
|
if pos + 2 > handshake_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let extensions_len = u16::from_be_bytes([handshake[pos], handshake[pos + 1]]) as usize;
|
||||||
|
pos += 2;
|
||||||
|
let extensions_end = pos.checked_add(extensions_len)?;
|
||||||
|
if extensions_end > handshake_end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((pos, extensions_end))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_share_extension_has_group(
|
||||||
|
data: &[u8],
|
||||||
|
group: u16,
|
||||||
|
expected_key_exchange_len: usize,
|
||||||
|
) -> bool {
|
||||||
|
if data.len() < 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shares_len = u16::from_be_bytes([data[0], data[1]]) as usize;
|
||||||
|
if shares_len != data.len().saturating_sub(2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pos = 2usize;
|
||||||
|
let shares_end = 2 + shares_len;
|
||||||
|
let mut found_group = false;
|
||||||
|
while pos + 4 <= shares_end {
|
||||||
|
let entry_group = u16::from_be_bytes([data[pos], data[pos + 1]]);
|
||||||
|
let key_exchange_len = u16::from_be_bytes([data[pos + 2], data[pos + 3]]) as usize;
|
||||||
|
pos += 4;
|
||||||
|
let Some(key_exchange_end) = pos.checked_add(key_exchange_len) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if key_exchange_end > shares_end {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if entry_group == group && key_exchange_len == expected_key_exchange_len {
|
||||||
|
found_group = true;
|
||||||
|
}
|
||||||
|
pos = key_exchange_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
found_group && pos == shares_end
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_hello_offers_key_share_group(
|
||||||
|
handshake: &[u8],
|
||||||
|
group: u16,
|
||||||
|
expected_key_exchange_len: usize,
|
||||||
|
) -> bool {
|
||||||
|
let Some((mut pos, extensions_end)) = client_hello_extensions_range(handshake) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
while pos + 4 <= extensions_end {
|
||||||
|
let ext_type = u16::from_be_bytes([handshake[pos], handshake[pos + 1]]);
|
||||||
|
let ext_len = u16::from_be_bytes([handshake[pos + 2], handshake[pos + 3]]) as usize;
|
||||||
|
pos += 4;
|
||||||
|
let Some(ext_end) = pos.checked_add(ext_len) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if ext_end > extensions_end {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ext_type == extension_type::KEY_SHARE {
|
||||||
|
return key_share_extension_has_group(
|
||||||
|
&handshake[pos..ext_end],
|
||||||
|
group,
|
||||||
|
expected_key_exchange_len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = ext_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn client_hello_offers_cipher_suite(
|
fn client_hello_offers_cipher_suite(
|
||||||
handshake: &[u8],
|
handshake: &[u8],
|
||||||
range: (usize, usize),
|
range: (usize, usize),
|
||||||
@@ -1056,6 +1230,22 @@ pub(crate) fn select_server_hello_cipher_suite(handshake: &[u8], preferred: [u8;
|
|||||||
preferred
|
preferred
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Select the ServerHello key_share named group from the authenticated ClientHello.
|
||||||
|
///
|
||||||
|
/// Malformed key_share structures intentionally keep the legacy X25519 response
|
||||||
|
/// to avoid breaking older clients that do not advertise the hybrid group.
|
||||||
|
pub(crate) fn select_server_hello_key_share_group(handshake: &[u8]) -> u16 {
|
||||||
|
if client_hello_offers_key_share_group(
|
||||||
|
handshake,
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
|
X25519MLKEM768_CLIENT_KEY_SHARE_LEN,
|
||||||
|
) {
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768
|
||||||
|
} else {
|
||||||
|
TLS_NAMED_GROUP_X25519
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if bytes look like a TLS ClientHello
|
/// Check if bytes look like a TLS ClientHello
|
||||||
pub fn is_tls_handshake(first_bytes: &[u8]) -> bool {
|
pub fn is_tls_handshake(first_bytes: &[u8]) -> bool {
|
||||||
if first_bytes.len() < 3 {
|
if first_bytes.len() < 3 {
|
||||||
|
|||||||
@@ -1502,6 +1502,7 @@ where
|
|||||||
replay_checker.add_tls_digest(digest_half);
|
replay_checker.add_tls_digest(digest_half);
|
||||||
|
|
||||||
let validation_session_id_slice = &validation_session_id[..validation_session_id_len];
|
let validation_session_id_slice = &validation_session_id[..validation_session_id_len];
|
||||||
|
let selected_key_share_group = tls::select_server_hello_key_share_group(handshake);
|
||||||
|
|
||||||
let response = if let Some((cached_entry, use_full_cert_payload)) = cached {
|
let response = if let Some((cached_entry, use_full_cert_payload)) = cached {
|
||||||
let preferred_cipher_suite = if cached_entry.server_hello_template.cipher_suite == [0, 0] {
|
let preferred_cipher_suite = if cached_entry.server_hello_template.cipher_suite == [0, 0] {
|
||||||
@@ -1520,6 +1521,7 @@ where
|
|||||||
config.censorship.serverhello_compact,
|
config.censorship.serverhello_compact,
|
||||||
client_tls_version,
|
client_tls_version,
|
||||||
selected_cipher_suite,
|
selected_cipher_suite,
|
||||||
|
selected_key_share_group,
|
||||||
rng,
|
rng,
|
||||||
selected_alpn.clone(),
|
selected_alpn.clone(),
|
||||||
config.censorship.tls_new_session_tickets,
|
config.censorship.tls_new_session_tickets,
|
||||||
@@ -1533,6 +1535,7 @@ where
|
|||||||
config.censorship.fake_cert_len,
|
config.censorship.fake_cert_len,
|
||||||
rng,
|
rng,
|
||||||
selected_cipher_suite,
|
selected_cipher_suite,
|
||||||
|
selected_key_share_group,
|
||||||
selected_alpn.clone(),
|
selected_alpn.clone(),
|
||||||
config.censorship.tls_new_session_tickets,
|
config.censorship.tls_new_session_tickets,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ use crate::protocol::constants::{
|
|||||||
TLS_RECORD_HANDSHAKE, TLS_VERSION,
|
TLS_RECORD_HANDSHAKE, TLS_VERSION,
|
||||||
};
|
};
|
||||||
use crate::protocol::tls::{
|
use crate::protocol::tls::{
|
||||||
ClientHelloTlsVersion, TLS_DIGEST_LEN, TLS_DIGEST_POS, gen_fake_x25519_key,
|
ClientHelloTlsVersion, TLS_DIGEST_LEN, TLS_DIGEST_POS, TLS_NAMED_GROUP_X25519,
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768, gen_fake_x25519_key,
|
||||||
|
gen_fake_x25519mlkem768_server_key_share,
|
||||||
};
|
};
|
||||||
use crate::tls_front::types::{
|
use crate::tls_front::types::{
|
||||||
CachedTlsData, ParsedCertificateInfo, TlsExtension, TlsProfileSource,
|
CachedTlsData, ParsedCertificateInfo, TlsExtension, TlsProfileSource,
|
||||||
@@ -196,19 +198,43 @@ fn push_supported_versions_extension(extensions: &mut Vec<u8>) {
|
|||||||
extensions.extend_from_slice(&0x0304u16.to_be_bytes());
|
extensions.extend_from_slice(&0x0304u16.to_be_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_key_share_extension(extensions: &mut Vec<u8>, rng: &SecureRandom) {
|
fn push_key_share_entry(extensions: &mut Vec<u8>, group: u16, key_exchange: &[u8]) {
|
||||||
let key = gen_fake_x25519_key(rng);
|
let Ok(key_exchange_len) = u16::try_from(key_exchange.len()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(entry_len) = key_exchange.len().checked_add(4) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok(entry_len) = u16::try_from(entry_len) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
extensions.extend_from_slice(&EXT_KEY_SHARE.to_be_bytes());
|
extensions.extend_from_slice(&EXT_KEY_SHARE.to_be_bytes());
|
||||||
extensions.extend_from_slice(&(2 + 2 + 32u16).to_be_bytes());
|
extensions.extend_from_slice(&entry_len.to_be_bytes());
|
||||||
extensions.extend_from_slice(&0x001du16.to_be_bytes());
|
extensions.extend_from_slice(&group.to_be_bytes());
|
||||||
extensions.extend_from_slice(&(32u16).to_be_bytes());
|
extensions.extend_from_slice(&key_exchange_len.to_be_bytes());
|
||||||
extensions.extend_from_slice(&key);
|
extensions.extend_from_slice(key_exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_key_share_extension(
|
||||||
|
extensions: &mut Vec<u8>,
|
||||||
|
rng: &SecureRandom,
|
||||||
|
selected_key_share_group: u16,
|
||||||
|
) {
|
||||||
|
if selected_key_share_group == TLS_NAMED_GROUP_X25519MLKEM768 {
|
||||||
|
let key = gen_fake_x25519mlkem768_server_key_share(rng);
|
||||||
|
push_key_share_entry(extensions, TLS_NAMED_GROUP_X25519MLKEM768, &key);
|
||||||
|
} else {
|
||||||
|
let key = gen_fake_x25519_key(rng);
|
||||||
|
push_key_share_entry(extensions, TLS_NAMED_GROUP_X25519, &key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replay_profiled_server_hello_extension(
|
fn replay_profiled_server_hello_extension(
|
||||||
ext: &TlsExtension,
|
ext: &TlsExtension,
|
||||||
extensions: &mut Vec<u8>,
|
extensions: &mut Vec<u8>,
|
||||||
rng: &SecureRandom,
|
rng: &SecureRandom,
|
||||||
|
selected_key_share_group: u16,
|
||||||
saw_supported_versions: &mut bool,
|
saw_supported_versions: &mut bool,
|
||||||
saw_key_share: &mut bool,
|
saw_key_share: &mut bool,
|
||||||
) {
|
) {
|
||||||
@@ -218,7 +244,7 @@ fn replay_profiled_server_hello_extension(
|
|||||||
*saw_supported_versions = true;
|
*saw_supported_versions = true;
|
||||||
}
|
}
|
||||||
EXT_KEY_SHARE if !*saw_key_share => {
|
EXT_KEY_SHARE if !*saw_key_share => {
|
||||||
push_key_share_extension(extensions, rng);
|
push_key_share_extension(extensions, rng, selected_key_share_group);
|
||||||
*saw_key_share = true;
|
*saw_key_share = true;
|
||||||
}
|
}
|
||||||
EXT_ALPN => {}
|
EXT_ALPN => {}
|
||||||
@@ -226,7 +252,11 @@ fn replay_profiled_server_hello_extension(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_profiled_server_hello_extensions(cached: &CachedTlsData, rng: &SecureRandom) -> Vec<u8> {
|
fn build_profiled_server_hello_extensions(
|
||||||
|
cached: &CachedTlsData,
|
||||||
|
rng: &SecureRandom,
|
||||||
|
selected_key_share_group: u16,
|
||||||
|
) -> Vec<u8> {
|
||||||
let capacity = cached
|
let capacity = cached
|
||||||
.server_hello_template
|
.server_hello_template
|
||||||
.extensions
|
.extensions
|
||||||
@@ -243,13 +273,14 @@ fn build_profiled_server_hello_extensions(cached: &CachedTlsData, rng: &SecureRa
|
|||||||
ext,
|
ext,
|
||||||
&mut extensions,
|
&mut extensions,
|
||||||
rng,
|
rng,
|
||||||
|
selected_key_share_group,
|
||||||
&mut saw_supported_versions,
|
&mut saw_supported_versions,
|
||||||
&mut saw_key_share,
|
&mut saw_key_share,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !saw_key_share {
|
if !saw_key_share {
|
||||||
push_key_share_extension(&mut extensions, rng);
|
push_key_share_extension(&mut extensions, rng, selected_key_share_group);
|
||||||
}
|
}
|
||||||
if !saw_supported_versions {
|
if !saw_supported_versions {
|
||||||
push_supported_versions_extension(&mut extensions);
|
push_supported_versions_extension(&mut extensions);
|
||||||
@@ -268,12 +299,13 @@ pub fn build_emulated_server_hello(
|
|||||||
serverhello_compact: bool,
|
serverhello_compact: bool,
|
||||||
client_tls_version: ClientHelloTlsVersion,
|
client_tls_version: ClientHelloTlsVersion,
|
||||||
selected_cipher_suite: [u8; 2],
|
selected_cipher_suite: [u8; 2],
|
||||||
|
selected_key_share_group: u16,
|
||||||
rng: &SecureRandom,
|
rng: &SecureRandom,
|
||||||
alpn: Option<Vec<u8>>,
|
alpn: Option<Vec<u8>>,
|
||||||
new_session_tickets: u8,
|
new_session_tickets: u8,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
// --- ServerHello ---
|
// --- ServerHello ---
|
||||||
let extensions = build_profiled_server_hello_extensions(cached, rng);
|
let extensions = build_profiled_server_hello_extensions(cached, rng, selected_key_share_group);
|
||||||
let extensions_len = extensions.len() as u16;
|
let extensions_len = extensions.len() as u16;
|
||||||
|
|
||||||
let body_len = 2 + 32 + 1 + session_id.len() + 2 + 1 + 2 + extensions.len();
|
let body_len = 2 + 32 + 1 + session_id.len() + 2 + 1 + 2 + extensions.len();
|
||||||
@@ -458,7 +490,7 @@ mod tests {
|
|||||||
use crate::protocol::constants::{
|
use crate::protocol::constants::{
|
||||||
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
||||||
};
|
};
|
||||||
use crate::protocol::tls::ClientHelloTlsVersion;
|
use crate::protocol::tls::{ClientHelloTlsVersion, TLS_NAMED_GROUP_X25519MLKEM768};
|
||||||
|
|
||||||
fn first_app_data_payload(response: &[u8]) -> &[u8] {
|
fn first_app_data_payload(response: &[u8]) -> &[u8] {
|
||||||
let hello_len = u16::from_be_bytes([response[3], response[4]]) as usize;
|
let hello_len = u16::from_be_bytes([response[3], response[4]]) as usize;
|
||||||
@@ -540,6 +572,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls12,
|
ClientHelloTlsVersion::Tls12,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -569,6 +602,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x03],
|
[0x13, 0x03],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -604,6 +638,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(b"h2".to_vec()),
|
Some(b"h2".to_vec()),
|
||||||
0,
|
0,
|
||||||
@@ -628,6 +663,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls12,
|
ClientHelloTlsVersion::Tls12,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -663,6 +699,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls12,
|
ClientHelloTlsVersion::Tls12,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -704,6 +741,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -737,6 +775,7 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
ClientHelloTlsVersion::Tls12,
|
ClientHelloTlsVersion::Tls12,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(b"h2".to_vec()),
|
Some(b"h2".to_vec()),
|
||||||
0,
|
0,
|
||||||
@@ -769,6 +808,7 @@ mod tests {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::crypto::SecureRandom;
|
|||||||
use crate::protocol::constants::{
|
use crate::protocol::constants::{
|
||||||
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
||||||
};
|
};
|
||||||
use crate::protocol::tls::ClientHelloTlsVersion;
|
use crate::protocol::tls::{ClientHelloTlsVersion, TLS_NAMED_GROUP_X25519MLKEM768};
|
||||||
use crate::tls_front::emulator::build_emulated_server_hello;
|
use crate::tls_front::emulator::build_emulated_server_hello;
|
||||||
use crate::tls_front::types::{
|
use crate::tls_front::types::{
|
||||||
CachedTlsData, ParsedServerHello, TlsBehaviorProfile, TlsProfileSource,
|
CachedTlsData, ParsedServerHello, TlsBehaviorProfile, TlsProfileSource,
|
||||||
@@ -66,6 +66,7 @@ fn emulated_server_hello_keeps_single_change_cipher_spec_for_client_compatibilit
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -91,6 +92,7 @@ fn emulated_server_hello_does_not_emit_profile_ticket_tail_when_disabled() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@@ -114,6 +116,7 @@ fn emulated_server_hello_uses_profile_ticket_lengths_when_enabled() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
None,
|
None,
|
||||||
2,
|
2,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::crypto::SecureRandom;
|
|||||||
use crate::protocol::constants::{
|
use crate::protocol::constants::{
|
||||||
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
|
||||||
};
|
};
|
||||||
use crate::protocol::tls::ClientHelloTlsVersion;
|
use crate::protocol::tls::{ClientHelloTlsVersion, TLS_NAMED_GROUP_X25519MLKEM768};
|
||||||
use crate::tls_front::emulator::build_emulated_server_hello;
|
use crate::tls_front::emulator::build_emulated_server_hello;
|
||||||
use crate::tls_front::types::{
|
use crate::tls_front::types::{
|
||||||
CachedTlsData, ParsedServerHello, TlsBehaviorProfile, TlsCertPayload, TlsProfileSource,
|
CachedTlsData, ParsedServerHello, TlsBehaviorProfile, TlsCertPayload, TlsProfileSource,
|
||||||
@@ -59,6 +59,7 @@ fn emulated_server_hello_ignores_oversized_alpn_when_marker_would_not_fit() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(oversized_alpn),
|
Some(oversized_alpn),
|
||||||
0,
|
0,
|
||||||
@@ -98,6 +99,7 @@ fn emulated_server_hello_keeps_alpn_marker_out_of_appdata() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls13,
|
ClientHelloTlsVersion::Tls13,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(b"h2".to_vec()),
|
Some(b"h2".to_vec()),
|
||||||
0,
|
0,
|
||||||
@@ -129,6 +131,7 @@ fn emulated_server_hello_prefers_cert_payload_over_alpn_marker() {
|
|||||||
true,
|
true,
|
||||||
ClientHelloTlsVersion::Tls12,
|
ClientHelloTlsVersion::Tls12,
|
||||||
[0x13, 0x01],
|
[0x13, 0x01],
|
||||||
|
TLS_NAMED_GROUP_X25519MLKEM768,
|
||||||
&rng,
|
&rng,
|
||||||
Some(b"h2".to_vec()),
|
Some(b"h2".to_vec()),
|
||||||
0,
|
0,
|
||||||
|
|||||||
Reference in New Issue
Block a user