mirror of
https://github.com/telemt/telemt.git
synced 2026-06-19 01:11:09 +03:00
Rustfmt + Bump
This commit is contained in:
Generated
+1
-1
@@ -2938,7 +2938,7 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "telemt"
|
name = "telemt"
|
||||||
version = "3.4.15"
|
version = "3.4.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "telemt"
|
name = "telemt"
|
||||||
version = "3.4.15"
|
version = "3.4.16"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -1849,10 +1849,7 @@ fn select_server_hello_cipher_suite_ignores_profile_tls12_cipher() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn select_server_hello_cipher_suite_rejects_without_offered_tls13_suite() {
|
fn select_server_hello_cipher_suite_rejects_without_offered_tls13_suite() {
|
||||||
let ch = build_client_hello_with_ciphers_and_exts(&[[0xc0, 0x2f]], Vec::new(), "example.com");
|
let ch = build_client_hello_with_ciphers_and_exts(&[[0xc0, 0x2f]], Vec::new(), "example.com");
|
||||||
assert_eq!(
|
assert_eq!(select_server_hello_cipher_suite(&ch, [0x13, 0x01]), None);
|
||||||
select_server_hello_cipher_suite(&ch, [0x13, 0x01]),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1869,10 +1866,7 @@ fn select_server_hello_cipher_suite_rejects_malformed_clienthello() {
|
|||||||
let mut ch =
|
let mut ch =
|
||||||
build_client_hello_with_ciphers_and_exts(&[[0x13, 0x03]], Vec::new(), "example.com");
|
build_client_hello_with_ciphers_and_exts(&[[0x13, 0x03]], Vec::new(), "example.com");
|
||||||
ch.truncate(12);
|
ch.truncate(12);
|
||||||
assert_eq!(
|
assert_eq!(select_server_hello_cipher_suite(&ch, [0x13, 0x01]), None);
|
||||||
select_server_hello_cipher_suite(&ch, [0x13, 0x01]),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1974,9 +1968,8 @@ fn build_server_hello_key_share_prefers_profiled_x25519() {
|
|||||||
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
let rng = crate::crypto::SecureRandom::new();
|
let rng = crate::crypto::SecureRandom::new();
|
||||||
|
|
||||||
let server_key_share =
|
let server_key_share = build_server_hello_key_share(&ch, Some(TLS_NAMED_GROUP_X25519), &rng)
|
||||||
build_server_hello_key_share(&ch, Some(TLS_NAMED_GROUP_X25519), &rng)
|
.expect("profiled X25519 share must be selected when client offers it");
|
||||||
.expect("profiled X25519 share must be selected when client offers it");
|
|
||||||
|
|
||||||
assert_eq!(server_key_share.group(), TLS_NAMED_GROUP_X25519);
|
assert_eq!(server_key_share.group(), TLS_NAMED_GROUP_X25519);
|
||||||
assert_eq!(server_key_share.key_exchange().len(), X25519_KEY_SHARE_LEN);
|
assert_eq!(server_key_share.key_exchange().len(), X25519_KEY_SHARE_LEN);
|
||||||
@@ -1991,9 +1984,8 @@ fn build_server_hello_key_share_falls_back_from_bad_profiled_x25519_to_hybrid()
|
|||||||
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
let rng = crate::crypto::SecureRandom::new();
|
let rng = crate::crypto::SecureRandom::new();
|
||||||
|
|
||||||
let server_key_share =
|
let server_key_share = build_server_hello_key_share(&ch, Some(TLS_NAMED_GROUP_X25519), &rng)
|
||||||
build_server_hello_key_share(&ch, Some(TLS_NAMED_GROUP_X25519), &rng)
|
.expect("hybrid share must be selected when profiled X25519 is unavailable");
|
||||||
.expect("hybrid share must be selected when profiled X25519 is unavailable");
|
|
||||||
|
|
||||||
assert_eq!(server_key_share.group(), TLS_NAMED_GROUP_X25519MLKEM768);
|
assert_eq!(server_key_share.group(), TLS_NAMED_GROUP_X25519MLKEM768);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -2032,8 +2024,7 @@ fn build_x25519mlkem768_server_key_share_rejects_all_zero_x25519_share() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn select_server_hello_key_share_group_accepts_x25519_when_hybrid_is_absent() {
|
fn select_server_hello_key_share_group_accepts_x25519_when_hybrid_is_absent() {
|
||||||
let key_share =
|
let key_share = client_key_share_extension(&[(TLS_NAMED_GROUP_X25519, X25519_KEY_SHARE_LEN)]);
|
||||||
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");
|
let ch = build_client_hello_with_exts(vec![(0x0033, key_share)], "example.com");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
+7
-8
@@ -63,9 +63,9 @@
|
|||||||
|
|
||||||
use super::constants::*;
|
use super::constants::*;
|
||||||
use crate::crypto::{SecureRandom, sha256_hmac};
|
use crate::crypto::{SecureRandom, sha256_hmac};
|
||||||
use ml_kem::{B32, EncapsulationKey as MlKemEncapsulationKey, Key as MlKemKey, MlKem768};
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::error::ProxyError;
|
use crate::error::ProxyError;
|
||||||
|
use ml_kem::{B32, EncapsulationKey as MlKemEncapsulationKey, Key as MlKemKey, MlKem768};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
use x25519_dalek::{X25519_BASEPOINT_BYTES, x25519};
|
use x25519_dalek::{X25519_BASEPOINT_BYTES, x25519};
|
||||||
@@ -617,8 +617,11 @@ pub(crate) fn build_x25519_server_key_share(
|
|||||||
handshake: &[u8],
|
handshake: &[u8],
|
||||||
rng: &SecureRandom,
|
rng: &SecureRandom,
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
let client_key_exchange =
|
let client_key_exchange = client_hello_key_share_group_entry(
|
||||||
client_hello_key_share_group_entry(handshake, TLS_NAMED_GROUP_X25519, X25519_KEY_SHARE_LEN)?;
|
handshake,
|
||||||
|
TLS_NAMED_GROUP_X25519,
|
||||||
|
X25519_KEY_SHARE_LEN,
|
||||||
|
)?;
|
||||||
let mut client_x25519 = [0u8; X25519_KEY_SHARE_LEN];
|
let mut client_x25519 = [0u8; X25519_KEY_SHARE_LEN];
|
||||||
client_x25519.copy_from_slice(client_key_exchange);
|
client_x25519.copy_from_slice(client_key_exchange);
|
||||||
let (server_x25519_scalar, server_x25519_key) = gen_x25519_key_pair(rng);
|
let (server_x25519_scalar, server_x25519_key) = gen_x25519_key_pair(rng);
|
||||||
@@ -1271,11 +1274,7 @@ fn key_share_extension_group_entry<'a>(
|
|||||||
pos = key_exchange_end;
|
pos = key_exchange_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos == shares_end {
|
if pos == shares_end { found_group } else { None }
|
||||||
found_group
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_hello_key_share_group_entry<'a>(
|
fn client_hello_key_share_group_entry<'a>(
|
||||||
|
|||||||
@@ -1527,11 +1527,12 @@ where
|
|||||||
&& matches!(client_tls_version, tls::ClientHelloTlsVersion::Tls12)
|
&& matches!(client_tls_version, tls::ClientHelloTlsVersion::Tls12)
|
||||||
{
|
{
|
||||||
if let Some(cache) = tls_cache.as_ref() {
|
if let Some(cache) = tls_cache.as_ref() {
|
||||||
cache.take_full_cert_budget_for_ip(
|
cache
|
||||||
peer.ip(),
|
.take_full_cert_budget_for_ip(
|
||||||
Duration::from_secs(config.censorship.tls_full_cert_ttl_secs),
|
peer.ip(),
|
||||||
)
|
Duration::from_secs(config.censorship.tls_full_cert_ttl_secs),
|
||||||
.await
|
)
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ fn should_replay_profiled_server_hello_shape(cached: &CachedTlsData) -> bool {
|
|||||||
matches!(
|
matches!(
|
||||||
cached.behavior_profile.source,
|
cached.behavior_profile.source,
|
||||||
TlsProfileSource::Raw | TlsProfileSource::Merged
|
TlsProfileSource::Raw | TlsProfileSource::Merged
|
||||||
) && cached.server_hello_template.is_replay_safe_tls13_shape(
|
) && cached
|
||||||
effective_profiled_server_hello_record_len(cached),
|
.server_hello_template
|
||||||
)
|
.is_replay_safe_tls13_shape(effective_profiled_server_hello_record_len(cached))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the origin-profiled ServerHello key_share group when it is replay-safe.
|
/// Return the origin-profiled ServerHello key_share group when it is replay-safe.
|
||||||
|
|||||||
+17
-17
@@ -9,9 +9,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use ml_kem::{
|
use ml_kem::{DecapsulationKey as MlKemDecapsulationKey, KeyExport, MlKem768, Seed as MlKemSeed};
|
||||||
DecapsulationKey as MlKemDecapsulationKey, KeyExport, MlKem768, Seed as MlKemSeed,
|
|
||||||
};
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -514,13 +512,11 @@ fn gen_x25519mlkem768_client_key_share(
|
|||||||
deterministic: bool,
|
deterministic: bool,
|
||||||
seed: &str,
|
seed: &str,
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
let mlkem_key = gen_mlkem768_client_encapsulation_key(
|
let mlkem_key =
|
||||||
rng,
|
gen_mlkem768_client_encapsulation_key(rng, deterministic, &format!("{seed}:mlkem768"))?;
|
||||||
deterministic,
|
|
||||||
&format!("{seed}:mlkem768"),
|
|
||||||
)?;
|
|
||||||
let x25519_key = gen_key_share(rng, deterministic, &format!("{seed}:x25519"));
|
let x25519_key = gen_key_share(rng, deterministic, &format!("{seed}:x25519"));
|
||||||
let mut key_share = Vec::with_capacity(MLKEM768_CLIENT_ENCAPSULATION_KEY_LEN + x25519_key.len());
|
let mut key_share =
|
||||||
|
Vec::with_capacity(MLKEM768_CLIENT_ENCAPSULATION_KEY_LEN + x25519_key.len());
|
||||||
key_share.extend_from_slice(&mlkem_key);
|
key_share.extend_from_slice(&mlkem_key);
|
||||||
key_share.extend_from_slice(&x25519_key);
|
key_share.extend_from_slice(&x25519_key);
|
||||||
Some(key_share)
|
Some(key_share)
|
||||||
@@ -661,8 +657,7 @@ fn build_client_hello(
|
|||||||
profile,
|
profile,
|
||||||
TlsFetchProfile::ModernChromeLike | TlsFetchProfile::ModernFirefoxLike
|
TlsFetchProfile::ModernChromeLike | TlsFetchProfile::ModernFirefoxLike
|
||||||
) {
|
) {
|
||||||
if let Some(key) =
|
if let Some(key) = gen_x25519mlkem768_client_key_share(rng, deterministic, &key_share_seed)
|
||||||
gen_x25519mlkem768_client_key_share(rng, deterministic, &key_share_seed)
|
|
||||||
{
|
{
|
||||||
push_client_key_share_entry(&mut keyshare, TLS_NAMED_GROUP_X25519MLKEM768, &key);
|
push_client_key_share_entry(&mut keyshare, TLS_NAMED_GROUP_X25519MLKEM768, &key);
|
||||||
}
|
}
|
||||||
@@ -1531,10 +1526,9 @@ mod tests {
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
MLKEM768_CLIENT_ENCAPSULATION_KEY_LEN, ProfileCacheValue, TLS_NAMED_GROUP_X25519,
|
MLKEM768_CLIENT_ENCAPSULATION_KEY_LEN, ProfileCacheValue, TLS_NAMED_GROUP_X25519,
|
||||||
TLS_NAMED_GROUP_X25519MLKEM768, TlsFetchStrategy, X25519_KEY_SHARE_LEN,
|
TLS_NAMED_GROUP_X25519MLKEM768, TlsFetchStrategy, X25519_KEY_SHARE_LEN, build_client_hello,
|
||||||
build_client_hello, build_tls_fetch_proxy_header, derive_behavior_profile,
|
build_tls_fetch_proxy_header, derive_behavior_profile, encode_tls13_certificate_message,
|
||||||
encode_tls13_certificate_message, fetch_via_rustls_stream, order_profiles, profile_alpn,
|
fetch_via_rustls_stream, order_profiles, profile_alpn, profile_cache, profile_cache_key,
|
||||||
profile_cache, profile_cache_key,
|
|
||||||
};
|
};
|
||||||
use crate::config::TlsFetchProfile;
|
use crate::config::TlsFetchProfile;
|
||||||
use crate::crypto::SecureRandom;
|
use crate::crypto::SecureRandom;
|
||||||
@@ -1886,8 +1880,14 @@ mod tests {
|
|||||||
u16::from_be_bytes([key_share_data[pos + 2], key_share_data[pos + 3]]) as usize;
|
u16::from_be_bytes([key_share_data[pos + 2], key_share_data[pos + 3]]) as usize;
|
||||||
pos += 4;
|
pos += 4;
|
||||||
let key = &key_share_data[pos..pos + key_len];
|
let key = &key_share_data[pos..pos + key_len];
|
||||||
assert_eq!(group, TLS_NAMED_GROUP_X25519, "second key_share group must be x25519");
|
assert_eq!(
|
||||||
assert_eq!(key_len, X25519_KEY_SHARE_LEN, "x25519 key length must be 32");
|
group, TLS_NAMED_GROUP_X25519,
|
||||||
|
"second key_share group must be x25519"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
key_len, X25519_KEY_SHARE_LEN,
|
||||||
|
"x25519 key length must be 32"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
key.iter().any(|b| *b != 0),
|
key.iter().any(|b| *b != 0),
|
||||||
"x25519 key must not be all zero"
|
"x25519 key must not be all zero"
|
||||||
|
|||||||
@@ -217,7 +217,10 @@ impl TlsBehaviorProfile {
|
|||||||
/// Refresh cached visible ServerHello summary fields and quality.
|
/// Refresh cached visible ServerHello summary fields and quality.
|
||||||
pub(crate) fn refresh_server_hello_summary(&mut self, server_hello: &ParsedServerHello) {
|
pub(crate) fn refresh_server_hello_summary(&mut self, server_hello: &ParsedServerHello) {
|
||||||
let mut has_replay_safe_server_hello = false;
|
let mut has_replay_safe_server_hello = false;
|
||||||
if matches!(self.source, TlsProfileSource::Raw | TlsProfileSource::Merged) {
|
if matches!(
|
||||||
|
self.source,
|
||||||
|
TlsProfileSource::Raw | TlsProfileSource::Merged
|
||||||
|
) {
|
||||||
if self.server_hello_record_len == 0 {
|
if self.server_hello_record_len == 0 {
|
||||||
self.server_hello_record_len = server_hello.record_body_len();
|
self.server_hello_record_len = server_hello.record_body_len();
|
||||||
}
|
}
|
||||||
@@ -236,9 +239,10 @@ impl TlsBehaviorProfile {
|
|||||||
|
|
||||||
/// Recompute the profile quality from current source and record-size evidence.
|
/// Recompute the profile quality from current source and record-size evidence.
|
||||||
fn refresh_quality(&mut self, has_replay_safe_server_hello: bool) {
|
fn refresh_quality(&mut self, has_replay_safe_server_hello: bool) {
|
||||||
let has_raw_server_hello =
|
let has_raw_server_hello = matches!(
|
||||||
matches!(self.source, TlsProfileSource::Raw | TlsProfileSource::Merged)
|
self.source,
|
||||||
&& has_replay_safe_server_hello;
|
TlsProfileSource::Raw | TlsProfileSource::Merged
|
||||||
|
) && has_replay_safe_server_hello;
|
||||||
self.quality = if has_raw_server_hello && !self.app_data_record_sizes.is_empty() {
|
self.quality = if has_raw_server_hello && !self.app_data_record_sizes.is_empty() {
|
||||||
TlsProfileQuality::RawStrict
|
TlsProfileQuality::RawStrict
|
||||||
} else if has_raw_server_hello {
|
} else if has_raw_server_hello {
|
||||||
|
|||||||
Reference in New Issue
Block a user