From 24a47ccd70d9ec09891f8cca12bdafce383fdd66 Mon Sep 17 00:00:00 2001 From: int 80h Date: Fri, 8 May 2020 16:12:09 -0400 Subject: [PATCH 1/2] Port checked from config --- src/config.rs | 4 ++-- src/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 346cf59..7ac20a5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ use std::path::Path; #[derive(Debug, Deserialize, Clone)] pub struct Config { - pub port: i32, + pub port: u16, pub host: String, pub server: Vec, } @@ -30,7 +30,7 @@ pub struct ServerCfg { pub cert: String, pub cgi: String, pub usrdir: bool, - pub port: i32, + pub port: u16, } impl Config { diff --git a/src/main.rs b/src/main.rs index 5faf846..d7d94dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,9 +128,9 @@ async fn handle_connection(mut con: conn::Connection, srv: &config::ServerCfg) - con.send_status(status::Status::ProxyRequestRefused, "Url doesn't match certificate!").await?; return Ok(()); } - // TODO get port from config + match url.port() { - Some(p) => { if p != 1965 { + Some(p) => { if p != srv.port { con.send_status(status::Status::ProxyRequestRefused, "Wrong Port!").await?; }}, None => {} From 5a90aaffc1230cfb6d72618bbd532957b9da1bc8 Mon Sep 17 00:00:00 2001 From: int 80h Date: Sat, 9 May 2020 18:49:04 -0400 Subject: [PATCH 2/2] Switched rustls for openssl --- Cargo.toml | 6 +-- src/cgi.rs | 2 +- src/conn.rs | 4 +- src/main.rs | 16 +++----- src/tls.rs | 111 ++++++++++++++++++++++++---------------------------- 5 files changed, 64 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd8bd09..e8d0c7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,9 @@ edition = "2018" [dependencies] tokio = { version = "0.2", features = [ "net", "io-util", "rt-threaded" ] } -tokio-rustls = "*" -rustls = "*" -futures-util = "*" +openssl = "0.10" +tokio-openssl = "0.4" +futures-util = "0.3" toml = "*" serde = "*" serde_derive = "*" diff --git a/src/cgi.rs b/src/cgi.rs index c27740a..304059c 100644 --- a/src/cgi.rs +++ b/src/cgi.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::os::unix::fs::PermissionsExt; use tokio::net::TcpStream; -use tokio_rustls::server::TlsStream; +use tokio_openssl::SslStream; use url::Url; use crate::config; diff --git a/src/conn.rs b/src/conn.rs index 9ae1853..8c2b232 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -2,12 +2,12 @@ use std::io; use std::net::SocketAddr; use tokio::net::TcpStream; use tokio::prelude::*; -use tokio_rustls::server::TlsStream; +use tokio_openssl::SslStream; use crate::status; pub struct Connection { - pub stream: TlsStream, + pub stream: SslStream, pub peer_addr: SocketAddr, } diff --git a/src/main.rs b/src/main.rs index d7d94dd..3afc309 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,10 +22,8 @@ use tokio::net::TcpListener; use tokio::net::TcpStream; use tokio::prelude::*; use tokio::runtime; -use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys}; -use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig}; -use tokio_rustls::server::TlsStream; -use tokio_rustls::TlsAcceptor; +use tokio_openssl::SslStream; +use openssl::ssl::NameType; use url::Url; use chrono::{DateTime, Utc}; use mime_guess; @@ -257,9 +255,8 @@ fn main() -> io::Result<()> { .build()?; let handle = runtime.handle().clone(); - let config = tls::get_tls_config(cfg.clone()); - let acceptor = TlsAcceptor::from(Arc::new(config)); + let acceptor = tls::acceptor_conf(cfg.clone())?; let fut = async { let mut listener = TcpListener::bind(&addr).await?; @@ -269,13 +266,12 @@ fn main() -> io::Result<()> { let cmap = cmap.clone(); let fut = async move { - let mut stream = acceptor.accept(stream).await?; - let (_, sni) = TlsStream::get_mut(&mut stream); - let sni = match sni.get_sni_hostname() { + let mut stream = tokio_openssl::accept(&acceptor, stream).await.expect("Couldn't accept"); + let sni = match stream.ssl().servername(NameType::HOST_NAME) { Some(s) => s, None => return Ok(()), }; - + let srv = match cmap.get(sni) { Some(h) => h, None => { diff --git a/src/tls.rs b/src/tls.rs index 9245799..a72f36e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,72 +1,65 @@ +extern crate openssl; +extern crate tokio_openssl; use std::collections::HashMap; use std::fs::File; use std::io::{self, BufReader}; use std::sync::Arc; -use rustls::sign::CertifiedKey; -use rustls::sign::{RSASigningKey, SigningKey}; -use rustls::ClientHello; -use rustls::ResolvesServerCert; -use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys}; -use tokio_rustls::rustls::{Certificate, PrivateKey}; +use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; +use openssl::ssl::SslAcceptorBuilder; +use openssl::ssl::SniError; +use openssl::error::ErrorStack; +use openssl::ssl::SslContextBuilder; +use openssl::ssl::SslVersion; +use openssl::ssl::NameType; +use tokio_openssl::SslStream; use crate::config; -pub fn get_tls_config(cfg: config::Config) -> rustls::ServerConfig { - let store = rustls::RootCertStore::empty(); - let verifier = rustls::AllowAnyAnonymousOrAuthenticatedClient::new(store); - let mut tls_config = rustls::ServerConfig::new(verifier); - tls_config.cert_resolver = Arc::new(CertResolver::from_config(cfg).unwrap()); - - tls_config -} - -pub fn load_certs(path: &String) -> io::Result> { - certs(&mut BufReader::new(File::open(path)?)) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert")) -} - -pub fn load_key(path: &String) -> PrivateKey { - let keyfile = File::open(path).expect("cannot open private key file"); - let mut reader = BufReader::new(keyfile); - let key = pkcs8_private_keys(&mut reader).expect("file contains invalid pkcs8 private key"); - return key[0].clone(); -} - -// Rustls won't let self signed certs be used with sni which gemini requires. -// At 1.4.2 in https://gemini.circumlunar.space/docs/spec-spec.txt -pub struct CertResolver { - map: HashMap>, -} - -impl CertResolver { - pub fn from_config(cfg: config::Config) -> Result { - let mut map = HashMap::new(); - - for server in cfg.server.iter() { - let key = load_key(&server.key); - let certs = load_certs(&server.cert).unwrap(); - let signing_key = RSASigningKey::new(&key).unwrap(); - - let signing_key_boxed: Arc> = Arc::new(Box::new(signing_key)); - map.insert( - server.hostname.clone(), - Box::new(rustls::sign::CertifiedKey::new(certs, signing_key_boxed)), - ); +pub fn acceptor_conf(cfg: config::Config) -> Result { + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?; + acceptor.set_min_proto_version(Some(SslVersion::TLS1_2))?; + let mut map = HashMap::new(); + let mut num = 1; + for server in cfg.server.iter() { + let mut ctx = SslContextBuilder::new(SslMethod::tls())?; + match ctx.set_private_key_file(&server.key, SslFiletype::PEM) { + Ok(c) => c, + Err(e) => { + eprintln!("Error: Can't load key file"); + return Err(e) + }, + }; + match ctx.set_certificate_chain_file(&server.cert) { + Ok(c) => c, + Err(e) => { + eprintln!("Error: Can't load cert file"); + return Err(e) + }, + }; + let ctx = ctx.build(); + map.insert(server.hostname.clone(), ctx.clone()); + if num == 1 { + map.insert("default".to_string(), ctx); + num += 1; } - - Ok(CertResolver { map }) } -} -impl ResolvesServerCert for CertResolver { - fn resolve(&self, client_hello: ClientHello) -> Option { - if let Some(hostname) = client_hello.server_name() { - if let Some(cert) = self.map.get(hostname.into()) { - return Some(*cert.clone()); + let ctx_builder = &mut *acceptor; + ctx_builder.set_servername_callback(move |ssl, _alert| -> Result<(), SniError> { + ssl.set_ssl_context({ + let hostname = ssl.servername(NameType::HOST_NAME); + if let Some(host) = hostname { + if let Some(ctx) = map.get(host) { + &ctx + } else { + &map.get(&"default".to_string()).expect("Can't get default") + } + } else { + &map.get(&"default".to_string()).expect("Can't get default") } - } - - None - } + }).expect("Can't get sni"); + Ok(()) + }); + Ok(acceptor.build()) }