Switched rustls for openssl

This commit is contained in:
int 80h
2020-05-09 18:49:04 -04:00
parent 24a47ccd70
commit 5a90aaffc1
5 changed files with 64 additions and 75 deletions

View File

@@ -8,9 +8,9 @@ edition = "2018"
[dependencies] [dependencies]
tokio = { version = "0.2", features = [ "net", "io-util", "rt-threaded" ] } tokio = { version = "0.2", features = [ "net", "io-util", "rt-threaded" ] }
tokio-rustls = "*" openssl = "0.10"
rustls = "*" tokio-openssl = "0.4"
futures-util = "*" futures-util = "0.3"
toml = "*" toml = "*"
serde = "*" serde = "*"
serde_derive = "*" serde_derive = "*"

View File

@@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio_rustls::server::TlsStream; use tokio_openssl::SslStream;
use url::Url; use url::Url;
use crate::config; use crate::config;

View File

@@ -2,12 +2,12 @@ use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::prelude::*; use tokio::prelude::*;
use tokio_rustls::server::TlsStream; use tokio_openssl::SslStream;
use crate::status; use crate::status;
pub struct Connection { pub struct Connection {
pub stream: TlsStream<TcpStream>, pub stream: SslStream<TcpStream>,
pub peer_addr: SocketAddr, pub peer_addr: SocketAddr,
} }

View File

@@ -22,10 +22,8 @@ use tokio::net::TcpListener;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::prelude::*; use tokio::prelude::*;
use tokio::runtime; use tokio::runtime;
use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys}; use tokio_openssl::SslStream;
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig}; use openssl::ssl::NameType;
use tokio_rustls::server::TlsStream;
use tokio_rustls::TlsAcceptor;
use url::Url; use url::Url;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use mime_guess; use mime_guess;
@@ -257,9 +255,8 @@ fn main() -> io::Result<()> {
.build()?; .build()?;
let handle = runtime.handle().clone(); 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 fut = async {
let mut listener = TcpListener::bind(&addr).await?; let mut listener = TcpListener::bind(&addr).await?;
@@ -269,13 +266,12 @@ fn main() -> io::Result<()> {
let cmap = cmap.clone(); let cmap = cmap.clone();
let fut = async move { let fut = async move {
let mut stream = acceptor.accept(stream).await?; let mut stream = tokio_openssl::accept(&acceptor, stream).await.expect("Couldn't accept");
let (_, sni) = TlsStream::get_mut(&mut stream); let sni = match stream.ssl().servername(NameType::HOST_NAME) {
let sni = match sni.get_sni_hostname() {
Some(s) => s, Some(s) => s,
None => return Ok(()), None => return Ok(()),
}; };
let srv = match cmap.get(sni) { let srv = match cmap.get(sni) {
Some(h) => h, Some(h) => h,
None => { None => {

View File

@@ -1,72 +1,65 @@
extern crate openssl;
extern crate tokio_openssl;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::{self, BufReader}; use std::io::{self, BufReader};
use std::sync::Arc; use std::sync::Arc;
use rustls::sign::CertifiedKey; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use rustls::sign::{RSASigningKey, SigningKey}; use openssl::ssl::SslAcceptorBuilder;
use rustls::ClientHello; use openssl::ssl::SniError;
use rustls::ResolvesServerCert; use openssl::error::ErrorStack;
use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys}; use openssl::ssl::SslContextBuilder;
use tokio_rustls::rustls::{Certificate, PrivateKey}; use openssl::ssl::SslVersion;
use openssl::ssl::NameType;
use tokio_openssl::SslStream;
use crate::config; use crate::config;
pub fn get_tls_config(cfg: config::Config) -> rustls::ServerConfig { pub fn acceptor_conf(cfg: config::Config) -> Result<SslAcceptor, ErrorStack> {
let store = rustls::RootCertStore::empty(); let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
let verifier = rustls::AllowAnyAnonymousOrAuthenticatedClient::new(store); acceptor.set_min_proto_version(Some(SslVersion::TLS1_2))?;
let mut tls_config = rustls::ServerConfig::new(verifier); let mut map = HashMap::new();
tls_config.cert_resolver = Arc::new(CertResolver::from_config(cfg).unwrap()); let mut num = 1;
for server in cfg.server.iter() {
tls_config let mut ctx = SslContextBuilder::new(SslMethod::tls())?;
} match ctx.set_private_key_file(&server.key, SslFiletype::PEM) {
Ok(c) => c,
pub fn load_certs(path: &String) -> io::Result<Vec<Certificate>> { Err(e) => {
certs(&mut BufReader::new(File::open(path)?)) eprintln!("Error: Can't load key file");
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert")) return Err(e)
} },
};
pub fn load_key(path: &String) -> PrivateKey { match ctx.set_certificate_chain_file(&server.cert) {
let keyfile = File::open(path).expect("cannot open private key file"); Ok(c) => c,
let mut reader = BufReader::new(keyfile); Err(e) => {
let key = pkcs8_private_keys(&mut reader).expect("file contains invalid pkcs8 private key"); eprintln!("Error: Can't load cert file");
return key[0].clone(); return Err(e)
} },
};
// Rustls won't let self signed certs be used with sni which gemini requires. let ctx = ctx.build();
// At 1.4.2 in https://gemini.circumlunar.space/docs/spec-spec.txt map.insert(server.hostname.clone(), ctx.clone());
pub struct CertResolver { if num == 1 {
map: HashMap<String, Box<CertifiedKey>>, map.insert("default".to_string(), ctx);
} num += 1;
impl CertResolver {
pub fn from_config(cfg: config::Config) -> Result<Self, ()> {
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<Box<dyn SigningKey>> = Arc::new(Box::new(signing_key));
map.insert(
server.hostname.clone(),
Box::new(rustls::sign::CertifiedKey::new(certs, signing_key_boxed)),
);
} }
Ok(CertResolver { map })
} }
}
impl ResolvesServerCert for CertResolver { let ctx_builder = &mut *acceptor;
fn resolve(&self, client_hello: ClientHello) -> Option<CertifiedKey> { ctx_builder.set_servername_callback(move |ssl, _alert| -> Result<(), SniError> {
if let Some(hostname) = client_hello.server_name() { ssl.set_ssl_context({
if let Some(cert) = self.map.get(hostname.into()) { let hostname = ssl.servername(NameType::HOST_NAME);
return Some(*cert.clone()); 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")
} }
} }).expect("Can't get sni");
Ok(())
None });
} Ok(acceptor.build())
} }