Skip to content

Commit

Permalink
upgrade quinn to 0.11.x
Browse files Browse the repository at this point in the history
  • Loading branch information
neevek committed Sep 8, 2024
1 parent b7c3cbe commit ed4e99e
Show file tree
Hide file tree
Showing 8 changed files with 774 additions and 605 deletions.
1,119 changes: 604 additions & 515 deletions Cargo.lock

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
[package]
name = "rstun"
version = "0.4.18"
version = "0.5.0"
edition = "2021"

[lib]
crate-type = ["lib"]

[dependencies]
rustls = { version = "0.21", features = ["dangerous_configuration", "quic"] }
rustls = { version = "0.23", default-features = false, features = ["ring"] }
clap = { version = "4.4", features = ["derive"] }
rcgen = "0.11"
tokio = { version = "1.32", features = ["full"] }
rcgen = "0.13"
tokio = { version = "1.40", features = ["full"] }
pretty_env_logger = "0.5.0"
ring = "0.17"
log = "0.4"
chrono = "0.4"
anyhow = "1.0"
quinn = "0.10"
quinn-proto = "0.10"
quinn = "0.11.5"
quinn-proto = "0.11.8"
futures-util = "0.3"
bincode = "1.3.3"
bincode = "1.3"
pin-utils = "0.1.0"
enum-as-inner = "0.6"
num_cpus = "1.13.1"
num_cpus = "1.16"
rs-utilities = "0.4.2"
# rs-utilities = { path = "../rs-utilities" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rustls-platform-verifier = "0.1.1"
rustls-platform-verifier = "0.3"
byte-pool = { git = "https://github.com/neevek/byte-pool" }
x509-parser = "0.15"
lazy_static = "1.4"
rustls-pemfile = "1.0"
x509-parser = "0.16"
lazy_static = "1.5"
rustls-pemfile = "2.1"

[dev-dependencies]
jni = "0.19"
Expand Down
4 changes: 2 additions & 2 deletions src/bin/rstunc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ struct RstuncArgs {
cert: String,

/// Preferred cipher suite
#[arg(short = 'e', long, default_value_t = String::from(SUPPORTED_CIPHER_SUITES[0]),
value_parser = PossibleValuesParser::new(SUPPORTED_CIPHER_SUITES).map(|v| v.to_string()))]
#[arg(short = 'e', long, default_value_t = String::from(SUPPORTED_CIPHER_SUITE_STRS[0]),
value_parser = PossibleValuesParser::new(SUPPORTED_CIPHER_SUITE_STRS).map(|v| v.to_string()))]
cipher: String,

/// Threads to run async tasks
Expand Down
147 changes: 106 additions & 41 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ use crate::{
};
use anyhow::{bail, Context, Result};
use log::{debug, error, info, warn};
use quinn::{congestion, TransportConfig};
use quinn::{congestion, crypto::rustls::QuicClientConfig, TransportConfig};
use quinn::{RecvStream, SendStream};
use quinn_proto::{IdleTimeout, VarInt};
use rs_utilities::{
dns::{self, DNSQueryOrdering, DNSResolverConfig, DNSResolverLookupIpStrategy},
log_and_bail,
};
use rustls::{client::ServerCertVerified, Certificate, RootCertStore, ServerName};
use rustls::{
client::danger::ServerCertVerified,
crypto::{ring::cipher_suite, CryptoProvider},
RootCertStore, SupportedCipherSuite,
};
use rustls_platform_verifier::{self, Verifier};
use serde::Serialize;
use std::{fmt::Display, str::FromStr};
use std::{
net::{IpAddr, SocketAddr},
time::SystemTime,
};
use std::{
sync::{Arc, Mutex},
sync::{Arc, Mutex, Once},
time::Duration,
{fmt::Display, str::FromStr},
};
#[cfg(not(target_os = "windows"))]
use tokio::signal::unix::{signal, SignalKind};
Expand All @@ -35,6 +36,7 @@ use x509_parser::prelude::{FromDer, X509Certificate};
const TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S.%3f";
const DEFAULT_SERVER_PORT: u16 = 3515;
const POST_TRAFFIC_DATA_INTERVAL_SECS: u64 = 10;
static INIT: Once = Once::new();

#[derive(Clone, Serialize)]
pub enum ClientState {
Expand Down Expand Up @@ -102,6 +104,12 @@ pub struct Client {

impl Client {
pub fn new(config: ClientConfig) -> Arc<Self> {
INIT.call_once(|| {
rustls::crypto::ring::default_provider()
.install_default()
.unwrap();
});

Arc::new(Client {
config,
inner_state: ThreadSafeState::new(),
Expand Down Expand Up @@ -241,15 +249,15 @@ impl Client {
}

let (tls_client_cfg, domain) = self.parse_client_config_and_domain()?;

let mut cfg = quinn::ClientConfig::new(Arc::new(tls_client_cfg));
cfg.transport_config(Arc::new(transport_cfg));
let quic_client_cfg = Arc::new(QuicClientConfig::try_from(tls_client_cfg)?);
let mut quinn_client_cfg = quinn::ClientConfig::new(quic_client_cfg);
quinn_client_cfg.transport_config(Arc::new(transport_cfg));

let remote_addr = Self::parse_server_addr(&self.config.server_addr).await?;
let local_addr: SocketAddr = socket_addr_with_unspecified_ip_port(remote_addr.is_ipv6());

let mut endpoint = quinn::Endpoint::client(local_addr)?;
endpoint.set_default_client_config(cfg);
endpoint.set_default_client_config(quinn_client_cfg);

self.post_tunnel_log(
format!(
Expand Down Expand Up @@ -415,35 +423,59 @@ impl Client {
Ok(())
}

fn get_crypto_provider(self: &Arc<Self>, cipher: &SupportedCipherSuite) -> Arc<CryptoProvider> {
let default_provider = rustls::crypto::ring::default_provider();
let mut cipher_suites = vec![*cipher];
// Quinn assumes that the cipher suites contain this one
cipher_suites.push(cipher_suite::TLS13_AES_128_GCM_SHA256);
Arc::new(rustls::crypto::CryptoProvider {
cipher_suites,
..default_provider
})
}

fn create_client_config_builder(
self: &Arc<Self>,
cipher: &SupportedCipherSuite,
) -> std::result::Result<
rustls::ConfigBuilder<rustls::ClientConfig, rustls::WantsVerifier>,
rustls::Error,
> {
let cfg_builder =
rustls::ClientConfig::builder_with_provider(self.get_crypto_provider(cipher))
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap();
Ok(cfg_builder)
}

fn parse_client_config_and_domain(self: &Arc<Self>) -> Result<(rustls::ClientConfig, String)> {
self.post_tunnel_log(format!("will use cipher: {}", self.config.cipher).as_str());
let cipher = *SelectedCipherSuite::from_str(&self.config.cipher).map_err(|_| {
rustls::Error::General(format!("invalid cipher: {}", self.config.cipher))
})?;

self.post_tunnel_log(format!("will use cipher: {}", self.config.cipher).as_str());

if self.config.cert_path.is_empty() {
if !Self::is_ip_addr(&self.config.server_addr) {
let domain = match self.config.server_addr.rfind(':') {
Some(colon_index) => self.config.server_addr[0..colon_index].to_string(),
None => self.config.server_addr.to_string(),
};

let client_config = rustls::ClientConfig::builder()
.with_cipher_suites(&[cipher])
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()?
let client_config = self
.create_client_config_builder(&cipher)?
.dangerous()
.with_custom_certificate_verifier(Arc::new(Verifier::new()))
.with_no_client_auth();

return Ok((client_config, domain));
}

let client_config = rustls::ClientConfig::builder()
.with_cipher_suites(&[cipher])
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()?
.with_custom_certificate_verifier(Arc::new(InsecureCertVerifier::new()))
let client_config = self
.create_client_config_builder(&cipher)?
.dangerous()
.with_custom_certificate_verifier(Arc::new(InsecureCertVerifier::new(
self.get_crypto_provider(&cipher),
)))
.with_no_client_auth();

warn!("No certificate is provided for verification, domain \"localhost\" is assumed");
Expand All @@ -452,18 +484,20 @@ impl Client {

let certs = pem_util::load_certificates_from_pem(self.config.cert_path.as_str())
.context("failed to read from cert file")?;
let cert = certs.first().context("certificate is not in PEM format")?;
let cert = certs
.first()
.context("certificate is not in PEM format")?
.clone();

let mut roots = RootCertStore::empty();
roots.add(cert).context(format!(
"failed to add certificate: {}",
self.config.cert_path
))?;

let (_rem, cert) = X509Certificate::from_der(cert.as_ref()).context(format!(
"not a valid X509Certificate: {}",
self.config.cert_path
))?;
let (_rem, cert) = X509Certificate::from_der(certs.first().unwrap().as_ref()).context(
format!("not a valid X509Certificate: {}", self.config.cert_path),
)?;

let common_name = cert
.subject()
Expand All @@ -476,10 +510,7 @@ impl Client {
))?;

Ok((
rustls::ClientConfig::builder()
.with_cipher_suites(&[cipher])
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()?
self.create_client_config_builder(&cipher)?
.with_root_certificates(roots)
.with_no_client_auth(),
common_name.to_string(),
Expand Down Expand Up @@ -633,24 +664,58 @@ impl Client {
}
}

struct InsecureCertVerifier {}
#[derive(Debug)]
struct InsecureCertVerifier(Arc<rustls::crypto::CryptoProvider>);

impl InsecureCertVerifier {
pub fn new() -> Self {
InsecureCertVerifier {}
pub fn new(crypto: Arc<CryptoProvider>) -> Self {
Self(crypto)
}
}

impl rustls::client::ServerCertVerifier for InsecureCertVerifier {
impl rustls::client::danger::ServerCertVerifier for InsecureCertVerifier {
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &rustls::pki_types::CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> std::prelude::v1::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error>
{
rustls::crypto::verify_tls12_signature(
message,
cert,
dss,
&self.0.signature_verification_algorithms,
)
}

fn verify_tls13_signature(
&self,
message: &[u8],
cert: &rustls::pki_types::CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> std::prelude::v1::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error>
{
rustls::crypto::verify_tls12_signature(
message,
cert,
dss,
&self.0.signature_verification_algorithms,
)
}

fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
self.0.signature_verification_algorithms.supported_schemes()
}

fn verify_server_cert(
&self,
_end_entity: &Certificate,
_intermediates: &[Certificate],
_server_name: &ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_end_entity: &rustls::pki_types::CertificateDer<'_>,
_intermediates: &[rustls::pki_types::CertificateDer<'_>],
_server_name: &rustls::pki_types::ServerName<'_>,
_ocsp_response: &[u8],
_now: SystemTime,
) -> Result<ServerCertVerified, rustls::Error> {
_now: rustls::pki_types::UnixTime,
) -> std::prelude::v1::Result<ServerCertVerified, rustls::Error> {
warn!("======================================= WARNING ======================================");
warn!("Connecting to a server without verifying its certificate is DANGEROUS!!!");
warn!("Provide the self-signed certificate for verification or connect with a domain name");
Expand Down
21 changes: 12 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use lazy_static::lazy_static;
use log::error;
use quinn::{RecvStream, SendStream};
use rs_utilities::log_and_bail;
use rustls::crypto::ring::cipher_suite;
pub use server::Server;
use std::net::IpAddr;
use std::net::Ipv4Addr;
Expand All @@ -33,7 +34,7 @@ lazy_static! {
static ref BUFFER_POOL: BytePool::<Vec<u8>> = BytePool::<Vec<u8>>::new();
}

pub const SUPPORTED_CIPHER_SUITES: &[&str] = &[
pub const SUPPORTED_CIPHER_SUITE_STRS: &[&str] = &[
"chacha20-poly1305",
"aes-256-gcm",
"aes-128-gcm",
Expand All @@ -46,6 +47,12 @@ pub const SUPPORTED_CIPHER_SUITES: &[&str] = &[
// "ecdhe-rsa-chacha20-poly1305",
];

pub static SUPPORTED_CIPHER_SUITES: &[rustls::SupportedCipherSuite] = &[
cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS13_AES_256_GCM_SHA384,
cipher_suite::TLS13_AES_128_GCM_SHA256,
];

pub(crate) struct SelectedCipherSuite(rustls::SupportedCipherSuite);

impl std::str::FromStr for SelectedCipherSuite {
Expand All @@ -54,14 +61,10 @@ impl std::str::FromStr for SelectedCipherSuite {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"chacha20-poly1305" => Ok(SelectedCipherSuite(
rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
)),
"aes-256-gcm" => Ok(SelectedCipherSuite(
rustls::cipher_suite::TLS13_AES_256_GCM_SHA384,
)),
"aes-128-gcm" => Ok(SelectedCipherSuite(
rustls::cipher_suite::TLS13_AES_128_GCM_SHA256,
cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
)),
"aes-256-gcm" => Ok(SelectedCipherSuite(cipher_suite::TLS13_AES_256_GCM_SHA384)),
"aes-128-gcm" => Ok(SelectedCipherSuite(cipher_suite::TLS13_AES_128_GCM_SHA256)),
// "ecdhe-ecdsa-aes256-gcm" => Ok(SelectedCipherSuite(
// rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// )),
Expand All @@ -81,7 +84,7 @@ impl std::str::FromStr for SelectedCipherSuite {
// rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// )),
_ => Ok(SelectedCipherSuite(
rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
)),
}
}
Expand Down
Loading

0 comments on commit ed4e99e

Please sign in to comment.