modules encapsulate from each other
This commit is contained in:
@@ -11,7 +11,7 @@ use tokio::{
|
|||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
// Добавили trace для частых логов (попакетно) и debug для состояний
|
// Добавили trace для частых логов (попакетно) и debug для состояний
|
||||||
use netrunner_logger::{debug, error, info, trace, warn};
|
use netrunner_logger::{debug, info, trace, warn};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 1. БАЗОВАЯ СТРУКТУРА (ConnectionCore)
|
// 1. БАЗОВАЯ СТРУКТУРА (ConnectionCore)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use netrunner_core::nrxp::socks::TargetAddress;
|
use netrunner_core::nrxp::TargetAddress;
|
||||||
use netrunner_logger::{debug, error, info, trace, warn};
|
use netrunner_logger::{debug, error, info, trace, warn};
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
iface::{SocketHandle, SocketSet},
|
iface::{SocketHandle, SocketSet},
|
||||||
socket::{AnySocket, icmp, tcp, udp},
|
socket::{AnySocket, icmp, tcp, udp},
|
||||||
wire::{IpListenEndpoint, IpProtocol, Ipv4Packet, TcpPacket, UdpPacket},
|
wire::{IpListenEndpoint, IpProtocol, Ipv4Packet, TcpPacket, UdpPacket},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, time::Duration, time::Instant as StdInstant};
|
use std::{collections::HashMap, time::Instant as StdInstant};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::{TcpStream, UdpSocket};
|
use tokio::net::{TcpStream, UdpSocket};
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ impl EngineBuilder {
|
|||||||
|
|
||||||
// 4. Подключение к серверу
|
// 4. Подключение к серверу
|
||||||
info!("Establishing secure tunnel to proxy server...");
|
info!("Establishing secure tunnel to proxy server...");
|
||||||
let muxer = ClientHandler::connect(&self.config.remote_address)
|
ClientHandler::connect(&self.config.remote_address)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to establish secure tunnel: {}", e))?;
|
.map_err(|e| format!("Failed to establish secure tunnel: {}", e))?;
|
||||||
info!("Secure tunnel established, Muxer is ready.");
|
info!("Secure tunnel established, Muxer is ready.");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
pub trait AeadPacker {
|
pub(crate) trait AeadPacker {
|
||||||
fn encrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error>;
|
fn encrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error>;
|
||||||
fn decrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error>;
|
fn decrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ use chacha20poly1305::aead::generic_array::GenericArray;
|
|||||||
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit, Nonce};
|
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit, Nonce};
|
||||||
|
|
||||||
use crate::crypto::aead::AeadPacker;
|
use crate::crypto::aead::AeadPacker;
|
||||||
|
struct NonceState {
|
||||||
pub struct NonceState {
|
|
||||||
counter: u64,
|
counter: u64,
|
||||||
base_iv: [u8; 12],
|
base_iv: [u8; 12],
|
||||||
}
|
}
|
||||||
@@ -32,10 +31,10 @@ impl NonceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChaChaCipher {
|
pub struct ChaChaCipher {
|
||||||
pub encrypt_cipher: ChaCha20Poly1305,
|
encrypt_cipher: ChaCha20Poly1305,
|
||||||
pub decrypt_cipher: ChaCha20Poly1305,
|
decrypt_cipher: ChaCha20Poly1305,
|
||||||
pub encrypt_state: NonceState,
|
encrypt_state: NonceState,
|
||||||
pub decrypt_state: NonceState,
|
decrypt_state: NonceState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChaChaCipher {
|
impl ChaChaCipher {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use aead::OsRng;
|
use aead::OsRng;
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
pub struct ECDH {
|
pub(crate) struct ECDH {
|
||||||
pub public_key: PublicKey,
|
pub public_key: PublicKey,
|
||||||
pub private_key: Option<EphemeralSecret>,
|
pub private_key: Option<EphemeralSecret>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ECDH {
|
impl ECDH {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
let secret = EphemeralSecret::random_from_rng(&mut OsRng);
|
let secret = EphemeralSecret::random_from_rng(&mut OsRng);
|
||||||
let public = PublicKey::from(&secret);
|
let public = PublicKey::from(&secret);
|
||||||
Self {
|
Self {
|
||||||
@@ -15,7 +15,7 @@ impl ECDH {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_shared(&mut self, public: &PublicKey) -> Option<[u8; 32]> {
|
pub(crate) fn get_shared(&mut self, public: &PublicKey) -> Option<[u8; 32]> {
|
||||||
let private_key = self.private_key.take()?;
|
let private_key = self.private_key.take()?;
|
||||||
let shared = private_key.diffie_hellman(&public);
|
let shared = private_key.diffie_hellman(&public);
|
||||||
Some(*shared.as_bytes())
|
Some(*shared.as_bytes())
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
|
|
||||||
pub struct HKDF;
|
pub(crate) struct HKDF;
|
||||||
|
|
||||||
impl HKDF {
|
impl HKDF {
|
||||||
pub fn extract_key(salt: &[u8], ikm: &[u8]) -> Hkdf<Sha256> {
|
pub(crate) fn extract_key(salt: &[u8], ikm: &[u8]) -> Hkdf<Sha256> {
|
||||||
let extracted_key = Hkdf::<Sha256>::new(Some(salt), ikm);
|
let extracted_key = Hkdf::<Sha256>::new(Some(salt), ikm);
|
||||||
extracted_key
|
extracted_key
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_key<const N: usize>(
|
pub(crate) fn expand_key<const N: usize>(
|
||||||
extracted_key: &Hkdf<Sha256>,
|
extracted_key: &Hkdf<Sha256>,
|
||||||
mark: &[u8],
|
mark: &[u8],
|
||||||
) -> Result<[u8; N], String> {
|
) -> Result<[u8; N], String> {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
pub mod aead;
|
mod aead;
|
||||||
pub mod chacha;
|
mod chacha;
|
||||||
mod ecdh;
|
mod ecdh;
|
||||||
mod hkdf;
|
mod hkdf;
|
||||||
pub mod session;
|
mod session;
|
||||||
|
|
||||||
|
pub(crate) use aead::AeadPacker;
|
||||||
|
pub(crate) use chacha::ChaChaCipher;
|
||||||
|
pub(crate) use session::SessionKeys;
|
||||||
|
|||||||
+27
-15
@@ -2,7 +2,7 @@ use x25519_dalek::PublicKey;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{ecdh::ECDH, hkdf::HKDF},
|
crypto::{ecdh::ECDH, hkdf::HKDF},
|
||||||
tlseng::extension::ExtensionStack,
|
tlseng::ExtensionStack,
|
||||||
};
|
};
|
||||||
|
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
@@ -12,14 +12,14 @@ type HmacSha256 = Hmac<Sha256>;
|
|||||||
|
|
||||||
use aead::{rand_core::RngCore, OsRng};
|
use aead::{rand_core::RngCore, OsRng};
|
||||||
|
|
||||||
pub struct SaltPair {
|
pub(crate) struct SaltPair {
|
||||||
local_salt: [u8; 32],
|
local_salt: [u8; 32],
|
||||||
remote_salt: [u8; 32],
|
remote_salt: [u8; 32],
|
||||||
is_initiator: bool,
|
is_initiator: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SaltPair {
|
impl SaltPair {
|
||||||
pub fn new(is_initiator: bool) -> Self {
|
pub(crate) fn new(is_initiator: bool) -> Self {
|
||||||
let mut local_salt = [0u8; 32];
|
let mut local_salt = [0u8; 32];
|
||||||
OsRng.fill_bytes(&mut local_salt);
|
OsRng.fill_bytes(&mut local_salt);
|
||||||
Self {
|
Self {
|
||||||
@@ -29,15 +29,15 @@ impl SaltPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_local(&self) -> [u8; 32] {
|
pub(crate) fn get_local(&self) -> [u8; 32] {
|
||||||
self.local_salt
|
self.local_salt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_remote_salt(&mut self, salt: [u8; 32]) {
|
pub(crate) fn set_remote_salt(&mut self, salt: [u8; 32]) {
|
||||||
self.remote_salt = salt
|
self.remote_salt = salt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_total(&self) -> [u8; 64] {
|
pub(crate) fn get_total(&self) -> [u8; 64] {
|
||||||
let mut salt = [0u8; 64];
|
let mut salt = [0u8; 64];
|
||||||
if self.is_initiator {
|
if self.is_initiator {
|
||||||
salt[..32].copy_from_slice(&self.local_salt);
|
salt[..32].copy_from_slice(&self.local_salt);
|
||||||
@@ -52,14 +52,14 @@ impl SaltPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SessionKeys {
|
pub struct SessionKeys {
|
||||||
pub salt: SaltPair,
|
salt: SaltPair,
|
||||||
pub ecdh: ECDH,
|
ecdh: ECDH,
|
||||||
pub auth_key: [u8; 32],
|
auth_key: [u8; 32],
|
||||||
pub current_aead: Option<([u8; 32], [u8; 12], [u8; 32], [u8; 12])>,
|
current_aead: Option<([u8; 32], [u8; 12], [u8; 32], [u8; 12])>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionKeys {
|
impl SessionKeys {
|
||||||
pub fn new(is_initiator: bool) -> Self {
|
pub(crate) fn new(is_initiator: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
salt: SaltPair::new(is_initiator),
|
salt: SaltPair::new(is_initiator),
|
||||||
ecdh: ECDH::new(),
|
ecdh: ECDH::new(),
|
||||||
@@ -68,12 +68,12 @@ impl SessionKeys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_aead_parameters(&self) -> ([u8; 32], [u8; 12], [u8; 32], [u8; 12]) {
|
pub(crate) fn get_aead_parameters(&self) -> ([u8; 32], [u8; 12], [u8; 32], [u8; 12]) {
|
||||||
self.current_aead
|
self.current_aead
|
||||||
.expect("Keys not generated yet. Call update_keys first.")
|
.expect("Keys not generated yet. Call update_keys first.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_keys(
|
pub(crate) fn update_keys(
|
||||||
&mut self,
|
&mut self,
|
||||||
salt: [u8; 32],
|
salt: [u8; 32],
|
||||||
extensions: &ExtensionStack,
|
extensions: &ExtensionStack,
|
||||||
@@ -176,7 +176,7 @@ impl SessionKeys {
|
|||||||
tag
|
tag
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_auth_tag(&self) -> [u8; 16] {
|
pub(crate) fn generate_auth_tag(&self) -> [u8; 16] {
|
||||||
let now = std::time::SystemTime::now()
|
let now = std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -185,7 +185,7 @@ impl SessionKeys {
|
|||||||
Self::compute_tag(&self.auth_key, now / 60)
|
Self::compute_tag(&self.auth_key, now / 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_auth_tag(&self, received_tag: &[u8; 16]) -> bool {
|
pub(crate) fn verify_auth_tag(&self, received_tag: &[u8; 16]) -> bool {
|
||||||
let now = std::time::SystemTime::now()
|
let now = std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
.expect("Time went backwards")
|
.expect("Time went backwards")
|
||||||
@@ -208,4 +208,16 @@ impl SessionKeys {
|
|||||||
);
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn local_salt(&self) -> [u8; 32] {
|
||||||
|
self.salt.get_local()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn public_key_bytes(&self) -> [u8; 32] {
|
||||||
|
self.ecdh.public_key.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn auth_key_fingerprint(&self) -> String {
|
||||||
|
hex::encode(&self.auth_key[..4])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::net::connection::muxer::{MuxMessage, Muxer};
|
use crate::net::connection::muxer::{MuxMessage, Muxer};
|
||||||
use crate::net::network::NetworkConfig;
|
use crate::net::network::NetworkConfig;
|
||||||
use crate::nrxp::frame::FrameType;
|
use crate::nrxp::FrameType;
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use netrunner_logger::{debug, error};
|
use netrunner_logger::{debug, error};
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
|||||||
@@ -6,13 +6,10 @@ use crate::{
|
|||||||
network::NetworkConfig,
|
network::NetworkConfig,
|
||||||
},
|
},
|
||||||
nrxp::{
|
nrxp::{
|
||||||
codec::Codec,
|
Codec, ErrorAction, FrameType, {SocksReply, SocksRequest},
|
||||||
errors::ErrorAction,
|
|
||||||
frame::FrameType,
|
|
||||||
socks::{SocksReply, SocksRequest},
|
|
||||||
},
|
},
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
tlseng::profile::BrowserProfile,
|
tlseng::BrowserProfile,
|
||||||
};
|
};
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use netrunner_logger::{info, warn};
|
use netrunner_logger::{info, warn};
|
||||||
@@ -93,8 +90,8 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientHandler {
|
pub struct ClientHandler {
|
||||||
pub conn: Connection,
|
pub(crate) conn: Connection,
|
||||||
pub muxer: Muxer,
|
pub(crate) muxer: Muxer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientHandler {
|
impl ClientHandler {
|
||||||
@@ -249,8 +246,7 @@ impl TunnelHandler for ClientHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerHandler {
|
pub struct ServerHandler {
|
||||||
pub conn: Connection,
|
pub(crate) conn: Connection,
|
||||||
pub token: CancellationToken,
|
|
||||||
}
|
}
|
||||||
impl ServerHandler {
|
impl ServerHandler {
|
||||||
async fn handle_stealth_fallback(
|
async fn handle_stealth_fallback(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use tokio_util::sync::CancellationToken;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net::connection::{handler::StreamHandler, muxer::MuxMessage},
|
net::connection::{handler::StreamHandler, muxer::MuxMessage},
|
||||||
nrxp::{codec::Codec, errors::ErrorAction, frame::FrameType},
|
nrxp::{Codec, ErrorAction, FrameType},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct TunnelEngine {
|
pub(crate) struct TunnelEngine {
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ use crate::{
|
|||||||
network::NetworkConfig,
|
network::NetworkConfig,
|
||||||
},
|
},
|
||||||
nrxp::{
|
nrxp::{
|
||||||
frame::{Frame, FrameType},
|
SocksReply, {Frame, FrameType},
|
||||||
socks::SocksReply,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::{error::SendError, Sender};
|
use tokio::sync::mpsc::{error::SendError, Sender};
|
||||||
|
|
||||||
use crate::nrxp::frame::FrameType;
|
use crate::nrxp::FrameType;
|
||||||
|
|
||||||
struct IdGenerator {
|
struct IdGenerator {
|
||||||
counter: AtomicU32,
|
counter: AtomicU32,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::sync::OnceLock;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net::connection::{ClientHandler, Connection, ConnectionRole, ServerHandler, TunnelHandler},
|
net::connection::{ClientHandler, Connection, ConnectionRole, ServerHandler, TunnelHandler},
|
||||||
nrxp::frame::{FRAME_HEADER_SIZE, MAX_PADDING_SIZE},
|
nrxp::{FRAME_HEADER_SIZE, MAX_PADDING_SIZE},
|
||||||
};
|
};
|
||||||
use netrunner_logger::{error, info};
|
use netrunner_logger::{error, info};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
@@ -75,7 +75,7 @@ impl Network {
|
|||||||
res = listener.accept() => {
|
res = listener.accept() => {
|
||||||
if let Ok((stream, client_addr)) = res {
|
if let Ok((stream, client_addr)) = res {
|
||||||
let conn = Connection::new(stream, true);
|
let conn = Connection::new(stream, true);
|
||||||
let handler = ServerHandler { conn, token: token.clone() };
|
let handler = ServerHandler { conn };
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = handler.run().await {
|
if let Err(e) = handler.run().await {
|
||||||
error!(client = %client_addr, error = %e, "Server handler error");
|
error!(client = %client_addr, error = %e, "Server handler error");
|
||||||
|
|||||||
+11
-11
@@ -1,14 +1,14 @@
|
|||||||
use crate::crypto::session::SessionKeys;
|
use crate::crypto::SessionKeys;
|
||||||
use crate::nrxp::errors::{ErrorAction, ErrorStage, TlsError};
|
use crate::nrxp::errors::{ErrorAction, ErrorStage, TlsError};
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
use crate::tlseng::extension::ExtensionStack;
|
use crate::tlseng::ExtensionStack;
|
||||||
use crate::tlseng::handshake::{ClientHello, HelloHeader, ServerHello};
|
use crate::tlseng::{ApplicationData, TlsRecord};
|
||||||
use crate::tlseng::profile::{BrowserProfile, ServerProfile};
|
use crate::tlseng::{BrowserProfile, ServerProfile};
|
||||||
use crate::tlseng::tls_record::{ApplicationData, TlsRecord};
|
use crate::tlseng::{ClientHello, HelloHeader, ServerHello};
|
||||||
use crate::tlseng::types::{ContentType, HelloType};
|
use crate::tlseng::{ContentType, HelloType};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
pub trait TlsInterceptor {
|
trait TlsInterceptor {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
fn start_process(buffer: &mut BytesMut) -> Result<Option<Self::Output>, TlsError> {
|
fn start_process(buffer: &mut BytesMut) -> Result<Option<Self::Output>, TlsError> {
|
||||||
@@ -22,7 +22,7 @@ pub trait TlsInterceptor {
|
|||||||
fn handle_record(record: TlsRecord) -> Result<Option<Self::Output>, TlsError>;
|
fn handle_record(record: TlsRecord) -> Result<Option<Self::Output>, TlsError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum HandshakeMessage {
|
pub(crate) enum HandshakeMessage {
|
||||||
Client {
|
Client {
|
||||||
base: ClientHello,
|
base: ClientHello,
|
||||||
extensions: ExtensionStack,
|
extensions: ExtensionStack,
|
||||||
@@ -122,7 +122,7 @@ impl TlsInterceptor for ApplicationData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TlsBridge;
|
pub(crate) struct TlsBridge;
|
||||||
|
|
||||||
impl TlsBridge {
|
impl TlsBridge {
|
||||||
pub fn unpack_handshake(buffer: &mut BytesMut) -> Result<Option<HandshakeMessage>, TlsError> {
|
pub fn unpack_handshake(buffer: &mut BytesMut) -> Result<Option<HandshakeMessage>, TlsError> {
|
||||||
@@ -173,12 +173,12 @@ impl TlsBridge {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let server_pub_key = keys.ecdh.public_key.to_bytes();
|
let server_pub_key = keys.public_key_bytes();
|
||||||
|
|
||||||
Ok(ServerHello::make_server_hello(
|
Ok(ServerHello::make_server_hello(
|
||||||
base,
|
base,
|
||||||
&server_pub_key,
|
&server_pub_key,
|
||||||
keys.salt.get_local(),
|
keys.local_salt(),
|
||||||
profile,
|
profile,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+16
-35
@@ -1,22 +1,22 @@
|
|||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::crypto::aead::AeadPacker;
|
use crate::crypto::AeadPacker;
|
||||||
use crate::crypto::chacha::ChaChaCipher;
|
use crate::crypto::ChaChaCipher;
|
||||||
use crate::crypto::session::SessionKeys;
|
use crate::crypto::SessionKeys;
|
||||||
use crate::nrxp::bridge::TlsBridge;
|
use crate::nrxp::bridge::TlsBridge;
|
||||||
use crate::nrxp::errors::{ErrorAction, ErrorStage, TlsError};
|
use crate::nrxp::errors::{ErrorAction, ErrorStage, TlsError};
|
||||||
use crate::nrxp::frame::{Frame, FrameHeader, FrameType, Padding};
|
use crate::nrxp::frame::{Frame, FrameType};
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
use crate::tlseng::profile::{BrowserProfile, ServerProfile};
|
use crate::tlseng::{BrowserProfile, ServerProfile};
|
||||||
|
|
||||||
pub struct Codec {
|
pub struct Codec {
|
||||||
crypto: ChaChaCipher,
|
crypto: ChaChaCipher,
|
||||||
pub session_keys: SessionKeys,
|
session_keys: SessionKeys,
|
||||||
staging: BytesMut,
|
staging: BytesMut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Codec {
|
impl Codec {
|
||||||
pub fn new(is_initiator: bool) -> Self {
|
pub(crate) fn new(is_initiator: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
crypto: ChaChaCipher::new(),
|
crypto: ChaChaCipher::new(),
|
||||||
session_keys: SessionKeys::new(is_initiator),
|
session_keys: SessionKeys::new(is_initiator),
|
||||||
@@ -24,7 +24,7 @@ impl Codec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_client_handshake(
|
pub(crate) fn make_client_handshake(
|
||||||
&mut self,
|
&mut self,
|
||||||
profile: &BrowserProfile,
|
profile: &BrowserProfile,
|
||||||
host: &str,
|
host: &str,
|
||||||
@@ -36,7 +36,10 @@ impl Codec {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_server_handshake(&mut self, buffer: &mut BytesMut) -> Result<Bytes, TlsError> {
|
pub(crate) fn make_server_handshake(
|
||||||
|
&mut self,
|
||||||
|
buffer: &mut BytesMut,
|
||||||
|
) -> Result<Bytes, TlsError> {
|
||||||
let client_msg = TlsBridge::unpack_handshake(buffer)?.ok_or_else(|| {
|
let client_msg = TlsBridge::unpack_handshake(buffer)?.ok_or_else(|| {
|
||||||
TlsError::new(
|
TlsError::new(
|
||||||
ErrorStage::Handshake("No CH"),
|
ErrorStage::Handshake("No CH"),
|
||||||
@@ -57,7 +60,7 @@ impl Codec {
|
|||||||
Ok(server_hello_record)
|
Ok(server_hello_record)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_handshake(&mut self, buffer: &mut BytesMut) -> Result<(), TlsError> {
|
pub(crate) fn process_handshake(&mut self, buffer: &mut BytesMut) -> Result<(), TlsError> {
|
||||||
let mes_opt = TlsBridge::unpack_handshake(buffer)?;
|
let mes_opt = TlsBridge::unpack_handshake(buffer)?;
|
||||||
let mes = mes_opt.ok_or_else(|| {
|
let mes = mes_opt.ok_or_else(|| {
|
||||||
TlsError::new(
|
TlsError::new(
|
||||||
@@ -83,43 +86,21 @@ impl Codec {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn try_handshake(&mut self, buffer: &mut BytesMut) -> Result<bool, TlsError> {
|
|
||||||
match self.process_handshake(buffer) {
|
|
||||||
Ok(_) => Ok(true),
|
|
||||||
Err(e) if e.action == ErrorAction::Wait => Ok(false),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn outbound(
|
fn outbound(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream_id: u32,
|
stream_id: u32,
|
||||||
frame_type: FrameType,
|
frame_type: FrameType,
|
||||||
payload: Bytes,
|
payload: Bytes,
|
||||||
) -> Result<Bytes, TlsError> {
|
) -> Result<Bytes, TlsError> {
|
||||||
let padding = Padding::generate_padding();
|
|
||||||
|
|
||||||
let tag = self.session_keys.generate_auth_tag();
|
let tag = self.session_keys.generate_auth_tag();
|
||||||
netrunner_logger::debug!(
|
netrunner_logger::debug!(
|
||||||
step = %(std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() / 60),
|
step = %(std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() / 60),
|
||||||
auth_key_hash = %hex::encode(&self.session_keys.auth_key[..4]),
|
auth_key_hash = %hex::encode(&self.session_keys.auth_key_fingerprint()),
|
||||||
generated_tag = %hex::encode(&tag[..4]),
|
generated_tag = %hex::encode(&tag[..4]),
|
||||||
"OUTBOUND: Generated auth tag"
|
"OUTBOUND: Generated auth tag"
|
||||||
);
|
);
|
||||||
|
|
||||||
let header = FrameHeader {
|
let frame = Frame::new(stream_id, frame_type, payload);
|
||||||
auth_tag: [0u8; 16],
|
|
||||||
stream_id,
|
|
||||||
frame_type,
|
|
||||||
payload_len: payload.len() as u16,
|
|
||||||
padding_len: padding.len as u16,
|
|
||||||
};
|
|
||||||
|
|
||||||
let frame = Frame {
|
|
||||||
header,
|
|
||||||
payload,
|
|
||||||
padding: padding.data,
|
|
||||||
};
|
|
||||||
let mut frame_bytes = frame.into_bytes(&tag);
|
let mut frame_bytes = frame.into_bytes(&tag);
|
||||||
|
|
||||||
let encrypted_payload = self.crypto.encrypt(&mut frame_bytes).map_err(|e| {
|
let encrypted_payload = self.crypto.encrypt(&mut frame_bytes).map_err(|e| {
|
||||||
@@ -179,7 +160,7 @@ impl Codec {
|
|||||||
|
|
||||||
if !self.session_keys.verify_auth_tag(&received_tag) {
|
if !self.session_keys.verify_auth_tag(&received_tag) {
|
||||||
netrunner_logger::error!(
|
netrunner_logger::error!(
|
||||||
expected_hash = %hex::encode(&self.session_keys.auth_key[..4]),
|
expected_hash = %hex::encode(&self.session_keys.auth_key_fingerprint()),
|
||||||
received = %hex::encode(&received_tag[..4]),
|
received = %hex::encode(&received_tag[..4]),
|
||||||
"AUTH MISMATCH: Potential replay or MITM attack. Dropping connection."
|
"AUTH MISMATCH: Potential replay or MITM attack. Dropping connection."
|
||||||
);
|
);
|
||||||
|
|||||||
+43
-24
@@ -4,7 +4,7 @@ use rand::Rng;
|
|||||||
|
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
|
|
||||||
pub struct Padding {
|
struct Padding {
|
||||||
pub len: u16,
|
pub len: u16,
|
||||||
pub data: Bytes,
|
pub data: Bytes,
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ impl Padding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum FrameType {
|
pub(crate) enum FrameType {
|
||||||
Connect = 0x00,
|
Connect = 0x00,
|
||||||
Data = 0x01,
|
Data = 0x01,
|
||||||
Close = 0x02,
|
Close = 0x02,
|
||||||
@@ -35,18 +35,18 @@ pub enum FrameType {
|
|||||||
UdpData = 0x05,
|
UdpData = 0x05,
|
||||||
}
|
}
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct FrameHeader {
|
pub(crate) struct FrameHeader {
|
||||||
pub auth_tag: [u8; 16],
|
pub(crate) _auth_tag: [u8; 16],
|
||||||
pub stream_id: u32,
|
pub(crate) stream_id: u32,
|
||||||
pub frame_type: FrameType,
|
pub(crate) frame_type: FrameType,
|
||||||
pub payload_len: u16,
|
pub(crate) payload_len: u16,
|
||||||
pub padding_len: u16,
|
pub(crate) padding_len: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Frame {
|
pub(crate) struct Frame {
|
||||||
pub header: FrameHeader,
|
pub(crate) header: FrameHeader,
|
||||||
pub payload: Bytes,
|
pub(crate) payload: Bytes,
|
||||||
pub padding: Bytes,
|
pub(crate) _padding: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
const AUTH_TAG_SIZE: u16 = 16;
|
const AUTH_TAG_SIZE: u16 = 16;
|
||||||
@@ -59,25 +59,44 @@ pub const FRAME_HEADER_SIZE: u16 =
|
|||||||
AUTH_TAG_SIZE + STREAM_ID_SIZE + FRAME_TYPE_SIZE + PAYLOAD_LEN_SIZE + PADDING_LEN_SIZE;
|
AUTH_TAG_SIZE + STREAM_ID_SIZE + FRAME_TYPE_SIZE + PAYLOAD_LEN_SIZE + PADDING_LEN_SIZE;
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn into_bytes(self, auth_key: &[u8; 16]) -> BytesMut {
|
pub(crate) fn new(stream_id: u32, frame_type: FrameType, payload: Bytes) -> Self {
|
||||||
let updated_padding = Padding::generate_padding();
|
Self {
|
||||||
let total_size = FRAME_HEADER_SIZE as usize + self.payload.len() + self.padding.len();
|
header: FrameHeader {
|
||||||
|
_auth_tag: [0u8; 16],
|
||||||
|
stream_id,
|
||||||
|
frame_type,
|
||||||
|
payload_len: payload.len() as u16,
|
||||||
|
padding_len: 0,
|
||||||
|
},
|
||||||
|
payload,
|
||||||
|
_padding: Bytes::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. БЕЗОПАСНАЯ СЕРИАЛИЗАЦИЯ С ИСПРАВЛЕННЫМ БАГОМ РАЗМЕРА
|
||||||
|
pub(crate) fn into_bytes(mut self, auth_key: &[u8; 16]) -> BytesMut {
|
||||||
|
let generated_padding = Padding::generate_padding();
|
||||||
|
|
||||||
|
// Обновляем заголовок реальной длиной сгенерированного паддинга
|
||||||
|
self.header.padding_len = generated_padding.len;
|
||||||
|
|
||||||
|
// Теперь размер считается правильно!
|
||||||
|
let total_size =
|
||||||
|
FRAME_HEADER_SIZE as usize + self.payload.len() + generated_padding.len as usize;
|
||||||
let mut buf = BytesMut::with_capacity(total_size);
|
let mut buf = BytesMut::with_capacity(total_size);
|
||||||
|
|
||||||
buf.put_slice(auth_key);
|
buf.put_slice(auth_key);
|
||||||
buf.put_u32(self.header.stream_id);
|
buf.put_u32(self.header.stream_id);
|
||||||
buf.put_u8(self.header.frame_type as u8);
|
buf.put_u8(self.header.frame_type as u8);
|
||||||
buf.put_u16(self.header.payload_len);
|
buf.put_u16(self.header.payload_len);
|
||||||
buf.put_u16(updated_padding.len);
|
buf.put_u16(self.header.padding_len);
|
||||||
|
|
||||||
buf.put(self.payload);
|
buf.put(self.payload);
|
||||||
|
buf.put(generated_padding.data);
|
||||||
buf.put(updated_padding.data);
|
|
||||||
|
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser for FrameHeader {
|
impl Parser for FrameHeader {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
@@ -92,8 +111,8 @@ impl Parser for FrameHeader {
|
|||||||
|
|
||||||
let mut header_chunk = bytes.split_to(FRAME_HEADER_SIZE as usize);
|
let mut header_chunk = bytes.split_to(FRAME_HEADER_SIZE as usize);
|
||||||
|
|
||||||
let mut auth_tag = [0u8; 16];
|
let mut _auth_tag = [0u8; 16];
|
||||||
header_chunk.copy_to_slice(&mut auth_tag);
|
header_chunk.copy_to_slice(&mut _auth_tag);
|
||||||
|
|
||||||
let stream_id = header_chunk.get_u32();
|
let stream_id = header_chunk.get_u32();
|
||||||
|
|
||||||
@@ -110,7 +129,7 @@ impl Parser for FrameHeader {
|
|||||||
let padding_len = header_chunk.get_u16();
|
let padding_len = header_chunk.get_u16();
|
||||||
|
|
||||||
Ok(Some(Self {
|
Ok(Some(Self {
|
||||||
auth_tag,
|
_auth_tag,
|
||||||
stream_id,
|
stream_id,
|
||||||
frame_type,
|
frame_type,
|
||||||
payload_len,
|
payload_len,
|
||||||
@@ -156,12 +175,12 @@ impl Parser for Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let payload = bytes.split_to(p_len).freeze();
|
let payload = bytes.split_to(p_len).freeze();
|
||||||
let padding = bytes.split_to(pad_len).freeze();
|
let _padding = bytes.split_to(pad_len).freeze();
|
||||||
|
|
||||||
Ok(Some(Self {
|
Ok(Some(Self {
|
||||||
header,
|
header,
|
||||||
payload,
|
payload,
|
||||||
padding,
|
_padding,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-4
@@ -1,5 +1,13 @@
|
|||||||
|
// Скрываем модули
|
||||||
mod bridge;
|
mod bridge;
|
||||||
pub mod codec;
|
mod codec;
|
||||||
pub mod errors;
|
mod errors;
|
||||||
pub mod frame;
|
mod frame;
|
||||||
pub mod socks;
|
mod socks;
|
||||||
|
|
||||||
|
// Экспортируем для остального ядра только необходимые типы
|
||||||
|
pub(crate) use codec::Codec;
|
||||||
|
pub(crate) use errors::{ErrorAction, ErrorStage, TlsError};
|
||||||
|
pub(crate) use frame::{Frame, FrameType, FRAME_HEADER_SIZE, MAX_PADDING_SIZE};
|
||||||
|
pub use socks::TargetAddress;
|
||||||
|
pub(crate) use socks::{SocksReply, SocksRequest};
|
||||||
|
|||||||
+13
-13
@@ -4,19 +4,19 @@ use bytes::{Buf, BufMut, BytesMut};
|
|||||||
|
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
|
|
||||||
pub const SOCKS5_VERSION: u8 = 0x05;
|
const SOCKS5_VERSION: u8 = 0x05;
|
||||||
pub const REPLY_SUCCESS: u8 = 0x00;
|
const REPLY_SUCCESS: u8 = 0x00;
|
||||||
pub const REPLY_AUTH_FAILURE: u8 = 0xFF;
|
const REPLY_AUTH_FAILURE: u8 = 0xFF;
|
||||||
pub const SOCKS5_MIN_HEADER: usize = 4;
|
const SOCKS5_MIN_HEADER: usize = 4;
|
||||||
pub const ATYP_IPV4: u8 = 0x01;
|
const ATYP_IPV4: u8 = 0x01;
|
||||||
pub const ATYP_DOMAIN: u8 = 0x03;
|
const ATYP_DOMAIN: u8 = 0x03;
|
||||||
pub const ATYP_IPV6: u8 = 0x04;
|
const ATYP_IPV6: u8 = 0x04;
|
||||||
pub const IPV4_SIZE: usize = 4;
|
const IPV4_SIZE: usize = 4;
|
||||||
pub const IPV6_SIZE: usize = 16;
|
const IPV6_SIZE: usize = 16;
|
||||||
pub const PORT_SIZE: usize = 2;
|
const PORT_SIZE: usize = 2;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SocksRequest {
|
pub(crate) enum SocksRequest {
|
||||||
Handshake { methods: Vec<u8> },
|
Handshake { methods: Vec<u8> },
|
||||||
Connect { command: u8, target: SocksTarget },
|
Connect { command: u8, target: SocksTarget },
|
||||||
Unknown,
|
Unknown,
|
||||||
@@ -151,7 +151,7 @@ impl SocksRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SocksReply {
|
pub(crate) enum SocksReply {
|
||||||
HandshakeSelect {
|
HandshakeSelect {
|
||||||
method: u8,
|
method: u8,
|
||||||
},
|
},
|
||||||
@@ -181,7 +181,7 @@ impl fmt::Display for TargetAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SocksTarget {
|
pub(crate) struct SocksTarget {
|
||||||
pub addr: TargetAddress,
|
pub addr: TargetAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
pub const HANDSHAKE_TYPE_CLIENT_HELLO: u8 = 0x01;
|
pub(crate) const HANDSHAKE_TYPE_CLIENT_HELLO: u8 = 0x01;
|
||||||
pub const HANDSHAKE_TYPE_SERVER_HELLO: u8 = 0x02;
|
pub(crate) const HANDSHAKE_TYPE_SERVER_HELLO: u8 = 0x02;
|
||||||
|
|
||||||
pub const TYPE_HOST_NAME: u8 = 0x00;
|
pub(crate) const TYPE_HOST_NAME: u8 = 0x00;
|
||||||
|
|
||||||
pub const PSK_DHE_KE_MODE: u8 = 0x01;
|
pub(crate) const PSK_DHE_KE_MODE: u8 = 0x01;
|
||||||
|
|
||||||
pub const CERT_COMPRESSION_BROTLI: u16 = 0x0002;
|
pub(crate) const CERT_COMPRESSION_BROTLI: u16 = 0x0002;
|
||||||
|
|
||||||
pub const OCSP_STATUS_TYPE: u8 = 0x01;
|
pub(crate) const OCSP_STATUS_TYPE: u8 = 0x01;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
nrxp::errors::{ErrorAction, ErrorStage, TlsError},
|
nrxp::{ErrorAction, ErrorStage, TlsError},
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
tlseng::{
|
tlseng::{
|
||||||
consts::{CERT_COMPRESSION_BROTLI, OCSP_STATUS_TYPE, PSK_DHE_KE_MODE, TYPE_HOST_NAME},
|
consts::{CERT_COMPRESSION_BROTLI, OCSP_STATUS_TYPE, PSK_DHE_KE_MODE, TYPE_HOST_NAME},
|
||||||
@@ -11,14 +11,14 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Extension {
|
pub(crate) struct Extension {
|
||||||
pub etype: u16,
|
pub etype: u16,
|
||||||
pub elen: u16,
|
pub _elen: u16,
|
||||||
pub data: Bytes,
|
pub data: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExtensionStack {
|
pub(crate) struct ExtensionStack {
|
||||||
pub extensions: Vec<Extension>,
|
pub extensions: Vec<Extension>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,13 +83,13 @@ impl Extension {
|
|||||||
pub fn new(etype: u16, data: Bytes) -> Self {
|
pub fn new(etype: u16, data: Bytes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
etype,
|
etype,
|
||||||
elen: data.len() as u16,
|
_elen: data.len() as u16,
|
||||||
data,
|
data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtensionBuilder {
|
pub(crate) struct ExtensionBuilder {
|
||||||
payload: BytesMut,
|
payload: BytesMut,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use aead::{rand_core::RngCore, OsRng};
|
|||||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::session::SessionKeys,
|
crypto::SessionKeys,
|
||||||
nrxp::errors::{ErrorAction, ErrorStage, TlsError},
|
nrxp::{ErrorAction, ErrorStage, TlsError},
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
tlseng::{
|
tlseng::{
|
||||||
consts::{HANDSHAKE_TYPE_CLIENT_HELLO, HANDSHAKE_TYPE_SERVER_HELLO},
|
consts::{HANDSHAKE_TYPE_CLIENT_HELLO, HANDSHAKE_TYPE_SERVER_HELLO},
|
||||||
@@ -15,7 +15,7 @@ use crate::{
|
|||||||
utils::u24::{BufExt, U24},
|
utils::u24::{BufExt, U24},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct HelloHeader {
|
pub(crate) struct HelloHeader {
|
||||||
pub header_type: HelloType,
|
pub header_type: HelloType,
|
||||||
pub _len: U24,
|
pub _len: U24,
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ impl Parser for HelloHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientHello {
|
pub(crate) struct ClientHello {
|
||||||
pub _version: ProtocolVersion,
|
pub _version: ProtocolVersion,
|
||||||
|
|
||||||
pub random: [u8; 32],
|
pub random: [u8; 32],
|
||||||
@@ -96,7 +96,7 @@ impl ClientHello {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_client_hello(profile: &BrowserProfile, host: &str, keys: &SessionKeys) -> Bytes {
|
pub fn make_client_hello(profile: &BrowserProfile, host: &str, keys: &SessionKeys) -> Bytes {
|
||||||
let tls_random = keys.salt.get_local();
|
let tls_random = keys.local_salt();
|
||||||
let mut session_id_bytes = [0u8; 32];
|
let mut session_id_bytes = [0u8; 32];
|
||||||
OsRng.fill_bytes(&mut session_id_bytes[..16]);
|
OsRng.fill_bytes(&mut session_id_bytes[..16]);
|
||||||
session_id_bytes[16..].copy_from_slice(&keys.generate_auth_tag());
|
session_id_bytes[16..].copy_from_slice(&keys.generate_auth_tag());
|
||||||
@@ -109,12 +109,7 @@ impl ClientHello {
|
|||||||
|
|
||||||
let mut ext_builder = ExtensionBuilder::new();
|
let mut ext_builder = ExtensionBuilder::new();
|
||||||
|
|
||||||
ext_builder.apply_profile(
|
ext_builder.apply_profile(profile, host, &keys.public_key_bytes(), total_overhead);
|
||||||
profile,
|
|
||||||
host,
|
|
||||||
&keys.ecdh.public_key.to_bytes(),
|
|
||||||
total_overhead,
|
|
||||||
);
|
|
||||||
|
|
||||||
let extensions_bytes = ext_builder.build();
|
let extensions_bytes = ext_builder.build();
|
||||||
|
|
||||||
@@ -220,7 +215,7 @@ impl Parser for ClientHello {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerHello {
|
pub(crate) struct ServerHello {
|
||||||
pub version: ProtocolVersion,
|
pub version: ProtocolVersion,
|
||||||
pub random: [u8; 32],
|
pub random: [u8; 32],
|
||||||
pub session_id: Bytes,
|
pub session_id: Bytes,
|
||||||
|
|||||||
+11
-5
@@ -1,6 +1,12 @@
|
|||||||
mod consts;
|
mod consts;
|
||||||
pub mod extension;
|
mod extension;
|
||||||
pub mod handshake;
|
mod handshake;
|
||||||
pub mod profile;
|
mod profile;
|
||||||
pub mod tls_record;
|
mod tls_record;
|
||||||
pub mod types;
|
mod types;
|
||||||
|
|
||||||
|
pub(crate) use extension::ExtensionStack;
|
||||||
|
pub(crate) use handshake::{ClientHello, HelloHeader, ServerHello};
|
||||||
|
pub(crate) use profile::{BrowserProfile, ServerProfile};
|
||||||
|
pub(crate) use tls_record::{ApplicationData, TlsRecord};
|
||||||
|
pub(crate) use types::{ContentType, HelloType};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::tlseng::types::{
|
use crate::tlseng::types::{
|
||||||
ExtensionOrder, ProtocolVersion, TlsGroups, TlsSignatures, TlsVersions,
|
ExtensionOrder, ProtocolVersion, TlsGroups, TlsSignatures, TlsVersions,
|
||||||
};
|
};
|
||||||
pub struct BrowserProfile {
|
pub(crate) struct BrowserProfile {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub groups: TlsGroups,
|
pub groups: TlsGroups,
|
||||||
pub signatures: TlsSignatures,
|
pub signatures: TlsSignatures,
|
||||||
@@ -63,7 +63,7 @@ impl BrowserProfile {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerProfile {
|
pub(crate) struct ServerProfile {
|
||||||
pub versions: TlsVersions,
|
pub versions: TlsVersions,
|
||||||
pub record_layer_version: ProtocolVersion,
|
pub record_layer_version: ProtocolVersion,
|
||||||
pub cipher_suites: &'static [u16],
|
pub cipher_suites: &'static [u16],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
nrxp::errors::{ErrorAction, ErrorStage, TlsError},
|
nrxp::{ErrorAction, ErrorStage, TlsError},
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
tlseng::types::{ContentType, ProtocolVersion},
|
tlseng::types::{ContentType, ProtocolVersion},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ContentType {
|
pub(crate) enum ContentType {
|
||||||
Handshake = 0x16,
|
Handshake = 0x16,
|
||||||
|
|
||||||
ApplicationData = 0x17,
|
ApplicationData = 0x17,
|
||||||
@@ -23,7 +23,7 @@ impl TryFrom<u8> for ContentType {
|
|||||||
|
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum ProtocolVersion {
|
pub(crate) enum ProtocolVersion {
|
||||||
Tls10 = 0x0301,
|
Tls10 = 0x0301,
|
||||||
Tls12 = 0x0303,
|
Tls12 = 0x0303,
|
||||||
Tls13 = 0x0304,
|
Tls13 = 0x0304,
|
||||||
@@ -45,7 +45,7 @@ impl TryFrom<u16> for ProtocolVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum HelloType {
|
pub(crate) enum HelloType {
|
||||||
Client = 0x01,
|
Client = 0x01,
|
||||||
|
|
||||||
Server = 0x02,
|
Server = 0x02,
|
||||||
@@ -64,7 +64,7 @@ impl TryFrom<u8> for HelloType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TlsGroups(pub &'static [u16]);
|
pub(crate) struct TlsGroups(pub &'static [u16]);
|
||||||
|
|
||||||
impl TlsGroups {
|
impl TlsGroups {
|
||||||
pub const X25519: u16 = 0x001d;
|
pub const X25519: u16 = 0x001d;
|
||||||
@@ -77,7 +77,7 @@ impl TlsGroups {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TlsSignatures(pub &'static [u16]);
|
pub(crate) struct TlsSignatures(pub &'static [u16]);
|
||||||
|
|
||||||
impl TlsSignatures {
|
impl TlsSignatures {
|
||||||
pub const ECDSA_SECP256R1_SHA256: u16 = 0x0403;
|
pub const ECDSA_SECP256R1_SHA256: u16 = 0x0403;
|
||||||
|
|||||||
Reference in New Issue
Block a user