mirror of
https://github.com/telemt/telemt.git
synced 2026-06-15 02:00:09 +07:00
Fix for TLS-F, ALPN и SNI/ALPN helpers
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -1719,6 +1719,9 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -1730,6 +1733,19 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
body.push(0);
|
body.push(0);
|
||||||
|
|
||||||
let mut ext_blob = Vec::new();
|
let mut ext_blob = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
|
|||||||
@@ -21,11 +21,52 @@ fn test_config_with_secret_hex(secret_hex: &str) -> ProxyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
||||||
|
const TLS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01];
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
let session_id_len: usize = 32;
|
let session_id_len: usize = 32;
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
let fill = 0x42u8;
|
||||||
let mut handshake = vec![0x42u8; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
let mut extensions = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
extensions.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
|
let body_len =
|
||||||
|
2 + 32 + 1 + session_id_len + 2 + TLS_AES_128_GCM_SHA256.len() + 1 + 1 + 2
|
||||||
|
+ extensions.len();
|
||||||
|
let mut body = Vec::with_capacity(body_len);
|
||||||
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.push(session_id_len as u8);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.extend_from_slice(&(TLS_AES_128_GCM_SHA256.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&TLS_AES_128_GCM_SHA256);
|
||||||
|
body.push(1);
|
||||||
|
body.push(0);
|
||||||
|
body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&extensions);
|
||||||
|
assert_eq!(body.len(), body_len);
|
||||||
|
|
||||||
|
let mut handshake = Vec::with_capacity(5 + 4 + body_len);
|
||||||
|
handshake.push(TLS_RECORD_HANDSHAKE);
|
||||||
|
handshake.extend_from_slice(&[0x03, 0x01]);
|
||||||
|
handshake.extend_from_slice(&((4 + body_len) as u16).to_be_bytes());
|
||||||
|
handshake.push(0x01);
|
||||||
|
let body_len_bytes = (body_len as u32).to_be_bytes();
|
||||||
|
handshake.extend_from_slice(&body_len_bytes[1..4]);
|
||||||
|
handshake.extend_from_slice(&body);
|
||||||
|
|
||||||
|
// The proxy authenticates TLS-fronted clients through the random field.
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
||||||
|
|
||||||
let computed = sha256_hmac(secret, &handshake);
|
let computed = sha256_hmac(secret, &handshake);
|
||||||
@@ -85,6 +126,9 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -96,6 +140,19 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
body.push(0);
|
body.push(0);
|
||||||
|
|
||||||
let mut ext_blob = Vec::new();
|
let mut ext_blob = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
@@ -150,13 +207,7 @@ async fn tls_minimum_viable_length_boundary() {
|
|||||||
let rng = SecureRandom::new();
|
let rng = SecureRandom::new();
|
||||||
let peer: SocketAddr = "192.0.2.1:12345".parse().unwrap();
|
let peer: SocketAddr = "192.0.2.1:12345".parse().unwrap();
|
||||||
|
|
||||||
let min_len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1;
|
let exact_min_handshake = make_valid_tls_handshake(&secret, 0);
|
||||||
let mut exact_min_handshake = vec![0x42u8; min_len];
|
|
||||||
exact_min_handshake[min_len - 1] = 0;
|
|
||||||
exact_min_handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
|
||||||
let digest = sha256_hmac(&secret, &exact_min_handshake);
|
|
||||||
exact_min_handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN]
|
|
||||||
.copy_from_slice(&digest);
|
|
||||||
|
|
||||||
let res = handle_tls_handshake(
|
let res = handle_tls_handshake(
|
||||||
&exact_min_handshake,
|
&exact_min_handshake,
|
||||||
@@ -171,12 +222,12 @@ async fn tls_minimum_viable_length_boundary() {
|
|||||||
.await;
|
.await;
|
||||||
assert!(
|
assert!(
|
||||||
matches!(res, HandshakeResult::Success(_)),
|
matches!(res, HandshakeResult::Success(_)),
|
||||||
"Exact minimum length TLS handshake must succeed"
|
"Minimum valid TLS ClientHello must succeed"
|
||||||
);
|
);
|
||||||
|
|
||||||
let short_handshake = vec![0x42u8; min_len - 1];
|
let short_handshake = &exact_min_handshake[..exact_min_handshake.len() - 1];
|
||||||
let res_short = handle_tls_handshake(
|
let res_short = handle_tls_handshake(
|
||||||
&short_handshake,
|
short_handshake,
|
||||||
tokio::io::empty(),
|
tokio::io::empty(),
|
||||||
tokio::io::sink(),
|
tokio::io::sink(),
|
||||||
peer,
|
peer,
|
||||||
@@ -188,7 +239,7 @@ async fn tls_minimum_viable_length_boundary() {
|
|||||||
.await;
|
.await;
|
||||||
assert!(
|
assert!(
|
||||||
matches!(res_short, HandshakeResult::BadClient { .. }),
|
matches!(res_short, HandshakeResult::BadClient { .. }),
|
||||||
"Handshake 1 byte shorter than minimum must fail closed"
|
"Handshake 1 byte shorter than minimum valid ClientHello must fail closed"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::crypto::sha256_hmac;
|
use crate::crypto::sha256_hmac;
|
||||||
|
use crate::protocol::constants::{TLS_RECORD_HANDSHAKE, TLS_VERSION};
|
||||||
use crate::stats::ReplayChecker;
|
use crate::stats::ReplayChecker;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
@@ -17,11 +18,52 @@ fn test_config_with_secret_hex(secret_hex: &str) -> ProxyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
||||||
|
const TLS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01];
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
let session_id_len: usize = 32;
|
let session_id_len: usize = 32;
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
let fill = 0x42u8;
|
||||||
let mut handshake = vec![0x42u8; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
let mut extensions = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
extensions.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
|
let body_len =
|
||||||
|
2 + 32 + 1 + session_id_len + 2 + TLS_AES_128_GCM_SHA256.len() + 1 + 1 + 2
|
||||||
|
+ extensions.len();
|
||||||
|
let mut body = Vec::with_capacity(body_len);
|
||||||
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.push(session_id_len as u8);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.extend_from_slice(&(TLS_AES_128_GCM_SHA256.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&TLS_AES_128_GCM_SHA256);
|
||||||
|
body.push(1);
|
||||||
|
body.push(0);
|
||||||
|
body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&extensions);
|
||||||
|
assert_eq!(body.len(), body_len);
|
||||||
|
|
||||||
|
let mut handshake = Vec::with_capacity(5 + 4 + body_len);
|
||||||
|
handshake.push(TLS_RECORD_HANDSHAKE);
|
||||||
|
handshake.extend_from_slice(&[0x03, 0x01]);
|
||||||
|
handshake.extend_from_slice(&((4 + body_len) as u16).to_be_bytes());
|
||||||
|
handshake.push(0x01);
|
||||||
|
let body_len_bytes = (body_len as u32).to_be_bytes();
|
||||||
|
handshake.extend_from_slice(&body_len_bytes[1..4]);
|
||||||
|
handshake.extend_from_slice(&body);
|
||||||
|
|
||||||
|
// The proxy authenticates TLS-fronted clients through the random field.
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
||||||
|
|
||||||
let computed = sha256_hmac(secret, &handshake);
|
let computed = sha256_hmac(secret, &handshake);
|
||||||
|
|||||||
@@ -25,11 +25,52 @@ fn test_config_with_secret_hex(secret_hex: &str) -> ProxyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
||||||
|
const TLS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01];
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
let session_id_len: usize = 32;
|
let session_id_len: usize = 32;
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
let fill = 0x42u8;
|
||||||
let mut handshake = vec![0x42u8; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
let mut extensions = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
extensions.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
|
let body_len =
|
||||||
|
2 + 32 + 1 + session_id_len + 2 + TLS_AES_128_GCM_SHA256.len() + 1 + 1 + 2
|
||||||
|
+ extensions.len();
|
||||||
|
let mut body = Vec::with_capacity(body_len);
|
||||||
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.push(session_id_len as u8);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.extend_from_slice(&(TLS_AES_128_GCM_SHA256.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&TLS_AES_128_GCM_SHA256);
|
||||||
|
body.push(1);
|
||||||
|
body.push(0);
|
||||||
|
body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&extensions);
|
||||||
|
assert_eq!(body.len(), body_len);
|
||||||
|
|
||||||
|
let mut handshake = Vec::with_capacity(5 + 4 + body_len);
|
||||||
|
handshake.push(TLS_RECORD_HANDSHAKE);
|
||||||
|
handshake.extend_from_slice(&[0x03, 0x01]);
|
||||||
|
handshake.extend_from_slice(&((4 + body_len) as u16).to_be_bytes());
|
||||||
|
handshake.push(0x01);
|
||||||
|
let body_len_bytes = (body_len as u32).to_be_bytes();
|
||||||
|
handshake.extend_from_slice(&body_len_bytes[1..4]);
|
||||||
|
handshake.extend_from_slice(&body);
|
||||||
|
|
||||||
|
// The proxy authenticates TLS-fronted clients through the random field.
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
||||||
|
|
||||||
let computed = sha256_hmac(secret, &handshake);
|
let computed = sha256_hmac(secret, &handshake);
|
||||||
@@ -90,6 +131,9 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
sni_host: &str,
|
sni_host: &str,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -112,6 +156,19 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
||||||
ext_blob.extend_from_slice(&sni_payload);
|
ext_blob.extend_from_slice(&sni_payload);
|
||||||
|
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -35,6 +38,19 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
body.push(0);
|
body.push(0);
|
||||||
|
|
||||||
let mut ext_blob = Vec::new();
|
let mut ext_blob = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
|
|||||||
@@ -10,11 +10,52 @@ use std::time::{Duration, Instant};
|
|||||||
use tokio::sync::Barrier;
|
use tokio::sync::Barrier;
|
||||||
|
|
||||||
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
||||||
|
const TLS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01];
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
let session_id_len: usize = 32;
|
let session_id_len: usize = 32;
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
let fill = 0x42u8;
|
||||||
let mut handshake = vec![0x42u8; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
let mut extensions = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
extensions.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
|
let body_len =
|
||||||
|
2 + 32 + 1 + session_id_len + 2 + TLS_AES_128_GCM_SHA256.len() + 1 + 1 + 2
|
||||||
|
+ extensions.len();
|
||||||
|
let mut body = Vec::with_capacity(body_len);
|
||||||
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.push(session_id_len as u8);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.extend_from_slice(&(TLS_AES_128_GCM_SHA256.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&TLS_AES_128_GCM_SHA256);
|
||||||
|
body.push(1);
|
||||||
|
body.push(0);
|
||||||
|
body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&extensions);
|
||||||
|
assert_eq!(body.len(), body_len);
|
||||||
|
|
||||||
|
let mut handshake = Vec::with_capacity(5 + 4 + body_len);
|
||||||
|
handshake.push(TLS_RECORD_HANDSHAKE);
|
||||||
|
handshake.extend_from_slice(&[0x03, 0x01]);
|
||||||
|
handshake.extend_from_slice(&((4 + body_len) as u16).to_be_bytes());
|
||||||
|
handshake.push(0x01);
|
||||||
|
let body_len_bytes = (body_len as u32).to_be_bytes();
|
||||||
|
handshake.extend_from_slice(&body_len_bytes[1..4]);
|
||||||
|
handshake.extend_from_slice(&body);
|
||||||
|
|
||||||
|
// The proxy authenticates TLS-fronted clients through the random field.
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
||||||
|
|
||||||
let computed = sha256_hmac(secret, &handshake);
|
let computed = sha256_hmac(secret, &handshake);
|
||||||
@@ -34,6 +75,9 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -45,6 +89,19 @@ fn make_valid_tls_client_hello_with_alpn(
|
|||||||
body.push(0);
|
body.push(0);
|
||||||
|
|
||||||
let mut ext_blob = Vec::new();
|
let mut ext_blob = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
@@ -92,6 +149,9 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
sni_host: &str,
|
sni_host: &str,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -114,6 +174,19 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
||||||
ext_blob.extend_from_slice(&sni_payload);
|
ext_blob.extend_from_slice(&sni_payload);
|
||||||
|
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
@@ -549,25 +622,6 @@ async fn adversarial_tls_replay_churn_allows_only_unique_digests() {
|
|||||||
let replay_checker = Arc::new(ReplayChecker::new(8192, Duration::from_secs(60)));
|
let replay_checker = Arc::new(ReplayChecker::new(8192, Duration::from_secs(60)));
|
||||||
let rng = Arc::new(SecureRandom::new());
|
let rng = Arc::new(SecureRandom::new());
|
||||||
|
|
||||||
let make_tagged_handshake = |timestamp: u32, tag: u8| {
|
|
||||||
let session_id_len: usize = 32;
|
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
|
||||||
let mut handshake = vec![tag; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
|
||||||
let computed = sha256_hmac(&secret, &handshake);
|
|
||||||
let mut digest = computed;
|
|
||||||
let ts = timestamp.to_le_bytes();
|
|
||||||
for i in 0..4 {
|
|
||||||
digest[28 + i] ^= ts[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN]
|
|
||||||
.copy_from_slice(&digest);
|
|
||||||
handshake
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
// 128 exact duplicates: only one should pass.
|
// 128 exact duplicates: only one should pass.
|
||||||
@@ -601,7 +655,7 @@ async fn adversarial_tls_replay_churn_allows_only_unique_digests() {
|
|||||||
let config = Arc::clone(&config);
|
let config = Arc::clone(&config);
|
||||||
let replay_checker = Arc::clone(&replay_checker);
|
let replay_checker = Arc::clone(&replay_checker);
|
||||||
let rng = Arc::clone(&rng);
|
let rng = Arc::clone(&rng);
|
||||||
let handshake = make_tagged_handshake(10_000 + i as u32, (i as u8).wrapping_add(0x80));
|
let handshake = make_valid_tls_handshake(&secret, 10_000 + i as u32);
|
||||||
tasks.push(tokio::spawn(async move {
|
tasks.push(tokio::spawn(async move {
|
||||||
let peer = SocketAddr::new(
|
let peer = SocketAddr::new(
|
||||||
IpAddr::V4(Ipv4Addr::new(198, 18, 0, ((i % 250) + 1) as u8)),
|
IpAddr::V4(Ipv4Addr::new(198, 18, 0, ((i % 250) + 1) as u8)),
|
||||||
|
|||||||
@@ -47,11 +47,52 @@ fn make_valid_mtproto_handshake(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
fn make_valid_tls_handshake(secret: &[u8], timestamp: u32) -> Vec<u8> {
|
||||||
|
const TLS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01];
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
let session_id_len: usize = 32;
|
let session_id_len: usize = 32;
|
||||||
let len = tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN + 1 + session_id_len;
|
let fill = 0x42u8;
|
||||||
let mut handshake = vec![0x42u8; len];
|
|
||||||
|
|
||||||
handshake[tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN] = session_id_len as u8;
|
let mut extensions = Vec::new();
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
extensions.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
extensions.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
|
let body_len =
|
||||||
|
2 + 32 + 1 + session_id_len + 2 + TLS_AES_128_GCM_SHA256.len() + 1 + 1 + 2
|
||||||
|
+ extensions.len();
|
||||||
|
let mut body = Vec::with_capacity(body_len);
|
||||||
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.push(session_id_len as u8);
|
||||||
|
body.extend_from_slice(&[fill; 32]);
|
||||||
|
body.extend_from_slice(&(TLS_AES_128_GCM_SHA256.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&TLS_AES_128_GCM_SHA256);
|
||||||
|
body.push(1);
|
||||||
|
body.push(0);
|
||||||
|
body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
|
||||||
|
body.extend_from_slice(&extensions);
|
||||||
|
assert_eq!(body.len(), body_len);
|
||||||
|
|
||||||
|
let mut handshake = Vec::with_capacity(5 + 4 + body_len);
|
||||||
|
handshake.push(TLS_RECORD_HANDSHAKE);
|
||||||
|
handshake.extend_from_slice(&[0x03, 0x01]);
|
||||||
|
handshake.extend_from_slice(&((4 + body_len) as u16).to_be_bytes());
|
||||||
|
handshake.push(0x01);
|
||||||
|
let body_len_bytes = (body_len as u32).to_be_bytes();
|
||||||
|
handshake.extend_from_slice(&body_len_bytes[1..4]);
|
||||||
|
handshake.extend_from_slice(&body);
|
||||||
|
|
||||||
|
// The proxy authenticates TLS-fronted clients through the random field.
|
||||||
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
handshake[tls::TLS_DIGEST_POS..tls::TLS_DIGEST_POS + tls::TLS_DIGEST_LEN].fill(0);
|
||||||
|
|
||||||
let computed = sha256_hmac(secret, &handshake);
|
let computed = sha256_hmac(secret, &handshake);
|
||||||
@@ -72,6 +113,9 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
sni_host: &str,
|
sni_host: &str,
|
||||||
alpn_protocols: &[&[u8]],
|
alpn_protocols: &[&[u8]],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
const TLS_EXTENSION_KEY_SHARE: u16 = 0x0033;
|
||||||
|
const X25519_KEY_SHARE_LEN: usize = 32;
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
body.extend_from_slice(&TLS_VERSION);
|
body.extend_from_slice(&TLS_VERSION);
|
||||||
body.extend_from_slice(&[0u8; 32]);
|
body.extend_from_slice(&[0u8; 32]);
|
||||||
@@ -93,6 +137,19 @@ fn make_valid_tls_client_hello_with_sni_and_alpn(
|
|||||||
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
ext_blob.extend_from_slice(&(sni_payload.len() as u16).to_be_bytes());
|
||||||
ext_blob.extend_from_slice(&sni_payload);
|
ext_blob.extend_from_slice(&sni_payload);
|
||||||
|
|
||||||
|
let mut key_share = Vec::new();
|
||||||
|
key_share.extend_from_slice(&tls::TLS_NAMED_GROUP_X25519.to_be_bytes());
|
||||||
|
key_share.extend_from_slice(&(X25519_KEY_SHARE_LEN as u16).to_be_bytes());
|
||||||
|
key_share.push(9);
|
||||||
|
key_share.resize(key_share.len() + X25519_KEY_SHARE_LEN - 1, 0);
|
||||||
|
|
||||||
|
let mut key_share_extension = Vec::new();
|
||||||
|
key_share_extension.extend_from_slice(&(key_share.len() as u16).to_be_bytes());
|
||||||
|
key_share_extension.extend_from_slice(&key_share);
|
||||||
|
ext_blob.extend_from_slice(&TLS_EXTENSION_KEY_SHARE.to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&(key_share_extension.len() as u16).to_be_bytes());
|
||||||
|
ext_blob.extend_from_slice(&key_share_extension);
|
||||||
|
|
||||||
if !alpn_protocols.is_empty() {
|
if !alpn_protocols.is_empty() {
|
||||||
let mut alpn_list = Vec::new();
|
let mut alpn_list = Vec::new();
|
||||||
for proto in alpn_protocols {
|
for proto in alpn_protocols {
|
||||||
|
|||||||
Reference in New Issue
Block a user