Compare commits

..

No commits in common. "master" and "220905" have entirely different histories.

9 changed files with 599 additions and 1107 deletions

1602
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -5,28 +5,27 @@ edition = "2021"
description = "TCP-over-HTTP solution" description = "TCP-over-HTTP solution"
[dependencies] [dependencies]
clap = { version = "4.5.4", features = ["derive", "env"] } clap = { version = "3.2.18", features = ["derive", "env"] }
log = "0.4.21" log = "0.4.17"
env_logger = "0.11.3" env_logger = "0.9.0"
actix = "0.13.3" actix = "0.13.0"
actix-web = { version = "4.5.1", features = ["rustls-0_21"] } actix-web = { version = "4", features = ["rustls"] }
actix-web-actors = "4.3.0" actix-web-actors = "4.1.0"
actix-tls = "3.3.0" actix-tls = "3.0.3"
serde = { version = "1.0.200", features = ["derive"] } serde = { version = "1.0.144", features = ["derive"] }
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "1", features = ["full"] }
futures = "0.3.30" futures = "0.3.24"
webpki = "0.22.4" webpki = "0.22.0"
x509-parser = "0.16.0" x509-parser = "0.14.0"
pem = "3.0.4" pem = "1.1.0"
reqwest = { version = "0.12.4", features = ["json", "rustls-tls"], default-features = false } reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features = false }
tokio-tungstenite = { version = "0.20.0", features = ["__rustls-tls", "rustls-tls-native-roots"] } tokio-tungstenite = { version = "0.17.2", features = ["__rustls-tls", "rustls-tls-native-roots"] }
urlencoding = "2.1.3" urlencoding = "2.1.0"
hyper-rustls = { version = "0.23.2", features = ["rustls-native-certs"] } hyper-rustls = { version = "0.23.0", features = ["rustls-native-certs"] }
bytes = "1.6.0" bytes = "1.2.1"
rustls-pemfile = "2.0.0" rustls-pemfile = "1.0.1"
rustls = { version = "0.21.0", features = ["dangerous_configuration"] } rustls = "0.20.6"
rustls-native-certs = "0.6.3"
[dev-dependencies] [dev-dependencies]
rand = "0.8.5" rand = "0.8.5"
mktemp = "0.5.1" mktemp = "0.4.1"

View File

@ -1,9 +1,3 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json"
"packageRules": [
{
"matchUpdateTypes": ["major", "minor", "patch"],
"automerge": true
}
]
} }

View File

@ -2,15 +2,16 @@ use std::error::Error;
use std::io::{Cursor, ErrorKind}; use std::io::{Cursor, ErrorKind};
use rustls::{Certificate, PrivateKey}; use rustls::{Certificate, PrivateKey};
use rustls_pemfile::Item; use rustls_pemfile::{read_one, Item};
/// Parse PEM certificates bytes into a [`rustls::Certificate`] structure /// Parse PEM certificates bytes into a [`rustls::Certificate`] structure
/// ///
/// An error is returned if not any certificate could be found /// An error is returned if not any certificate could be found
pub fn parse_pem_certificates(certs: &[u8]) -> Result<Vec<Certificate>, Box<dyn Error>> { pub fn parse_pem_certificates(certs: &[u8]) -> Result<Vec<Certificate>, Box<dyn Error>> {
let certs = rustls_pemfile::certs(&mut Cursor::new(certs)) let certs = rustls_pemfile::certs(&mut Cursor::new(certs))?
.map(|c| c.map(|c| Certificate(c.to_vec()))) .into_iter()
.collect::<Result<Vec<_>, _>>()?; .map(Certificate)
.collect::<Vec<_>>();
if certs.is_empty() { if certs.is_empty() {
Err(std::io::Error::new( Err(std::io::Error::new(
@ -25,7 +26,7 @@ pub fn parse_pem_certificates(certs: &[u8]) -> Result<Vec<Certificate>, Box<dyn
/// Parse PEM private key bytes into a [`rustls::PrivateKey`] structure /// Parse PEM private key bytes into a [`rustls::PrivateKey`] structure
pub fn parse_pem_private_key(privkey: &[u8]) -> Result<PrivateKey, Box<dyn Error>> { pub fn parse_pem_private_key(privkey: &[u8]) -> Result<PrivateKey, Box<dyn Error>> {
let key = match rustls_pemfile::read_one(&mut Cursor::new(privkey))? { let key = match read_one(&mut Cursor::new(privkey))? {
None => { None => {
Err(std::io::Error::new( Err(std::io::Error::new(
ErrorKind::Other, ErrorKind::Other,
@ -33,8 +34,8 @@ pub fn parse_pem_private_key(privkey: &[u8]) -> Result<PrivateKey, Box<dyn Error
))?; ))?;
unreachable!() unreachable!()
} }
Some(Item::Pkcs8Key(key)) => key.secret_pkcs8_der().to_vec(), Some(Item::PKCS8Key(key)) => key,
Some(Item::Pkcs1Key(key)) => key.secret_pkcs1_der().to_vec(), Some(Item::RSAKey(key)) => key,
_ => { _ => {
Err(std::io::Error::new( Err(std::io::Error::new(
ErrorKind::Other, ErrorKind::Other,

View File

@ -93,7 +93,7 @@ fn load_pem_file(path: &Option<String>, name: &str) -> std::io::Result<Option<Ve
None => None, None => None,
Some(p) => Some( Some(p) => Some(
std::fs::read(p) std::fs::read(p)
.map_err(|e| encpasulate_error(e, format!("Failed to load {name}!")))?, .map_err(|e| encpasulate_error(e, format!("Failed to load {}!", name)))?,
), ),
}) })
} }

View File

@ -76,7 +76,7 @@ pub async fn run_app(mut args: ClientConfig) -> std::io::Result<()> {
Err(e) => { Err(e) => {
Err(std::io::Error::new( Err(std::io::Error::new(
ErrorKind::Other, ErrorKind::Other,
format!("Failed to fetch relay configuration from server! {e}"), format!("Failed to fetch relay configuration from server! {}", e),
))?; ))?;
unreachable!(); unreachable!();
} }

View File

@ -1,6 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use hyper_rustls::ConfigBuilderExt;
use rustls::RootCertStore; use rustls::RootCertStore;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
@ -41,17 +42,7 @@ async fn relay_connection(ws_url: String, socket: TcpStream, conf: Arc<ClientCon
let config = rustls::ClientConfig::builder().with_safe_defaults(); let config = rustls::ClientConfig::builder().with_safe_defaults();
let config = match conf.get_root_certificate() { let config = match conf.get_root_certificate() {
None => { None => config.with_native_roots(),
// Perform a connection over TLS
let mut roots = RootCertStore::empty();
for cert in rustls_native_certs::load_native_certs()
.expect("Failed to load native certificates")
{
roots.add(&rustls::Certificate(cert.0)).unwrap();
}
config.with_root_certificates(roots)
}
Some(cert) => { Some(cert) => {
log::debug!("Using custom root certificates"); log::debug!("Using custom root certificates");
let mut store = RootCertStore::empty(); let mut store = RootCertStore::empty();
@ -74,14 +65,14 @@ async fn relay_connection(ws_url: String, socket: TcpStream, conf: Arc<ClientCon
.expect("Failed to parse client auth private key!"); .expect("Failed to parse client auth private key!");
config config
.with_client_auth_cert(certs, key) .with_single_cert(certs, key)
.expect("Failed to set client certificate!") .expect("Failed to set client certificate!")
} }
}; };
let connector = tokio_tungstenite::Connector::Rustls(Arc::new(config)); let connector = tokio_tungstenite::Connector::Rustls(Arc::new(config));
let (ws_stream, _) = let (ws_stream, _) =
tokio_tungstenite::connect_async_tls_with_config(ws_url, None, false, Some(connector)) tokio_tungstenite::connect_async_tls_with_config(ws_url, None, Some(connector))
.await .await
.expect("Failed to connect to server relay!"); .expect("Failed to connect to server relay!");

View File

@ -121,7 +121,7 @@ pub async fn run_app(mut config: ServerConfig) -> std::io::Result<()> {
}); });
if let Some(tls_conf) = tls_config { if let Some(tls_conf) = tls_config {
server.bind_rustls_021(&args.listen_address, tls_conf)? server.bind_rustls(&args.listen_address, tls_conf)?
} else { } else {
server.bind(&args.listen_address)? server.bind(&args.listen_address)?
} }

View File

@ -1,8 +1,9 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
use rustls::internal::msgs::enums::AlertDescription;
use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier}; use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
use rustls::{AlertDescription, Certificate, DistinguishedName, Error, RootCertStore}; use rustls::{Certificate, DistinguishedNames, Error, RootCertStore};
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate}; use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
use crate::base::cert_utils::parse_pem_certificates; use crate::base::cert_utils::parse_pem_certificates;
@ -54,13 +55,13 @@ impl CustomCertClientVerifier {
let parsed_crl = pem::parse(crl_file) let parsed_crl = pem::parse(crl_file)
.map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?; .map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?;
Some(parsed_crl.into_contents()) Some(parsed_crl.contents)
} else { } else {
None None
}; };
Ok(Self { Ok(Self {
upstream_cert_verifier: Box::new(Arc::new(AllowAnyAuthenticatedClient::new(store))), upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
crl, crl,
}) })
} }
@ -71,12 +72,12 @@ impl ClientCertVerifier for CustomCertClientVerifier {
true true
} }
fn client_auth_mandatory(&self) -> bool { fn client_auth_mandatory(&self) -> Option<bool> {
true Some(true)
} }
fn client_auth_root_subjects(&self) -> &[DistinguishedName] { fn client_auth_root_subjects(&self) -> Option<DistinguishedNames> {
&[] Some(vec![])
} }
fn verify_client_cert( fn verify_client_cert(