Skip to content

Commit

Permalink
feat: TLS session resumption
Browse files Browse the repository at this point in the history
  • Loading branch information
link2xt committed Nov 6, 2024
1 parent d2324a8 commit e682833
Show file tree
Hide file tree
Showing 7 changed files with 14 additions and 113 deletions.
72 changes: 0 additions & 72 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ anyhow = { workspace = true }
async-broadcast = "0.7.1"
async-channel = { workspace = true }
async-imap = { version = "0.10.2", default-features = false, features = ["runtime-tokio", "compress"] }
async-native-tls = { version = "0.5", default-features = false, features = ["runtime-tokio"] }
async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] }
async_zip = { version = "0.0.17", default-features = false, features = ["deflate", "tokio-fs"] }
base64 = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::pin::Pin;
use std::time::Duration;

use anyhow::{format_err, Context as _, Result};
use async_native_tls::TlsStream;
use tokio_rustls::client::TlsStream;
use tokio::net::TcpStream;
use tokio::task::JoinSet;
use tokio::time::timeout;
Expand Down
6 changes: 3 additions & 3 deletions src/net/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::Serialize;
use crate::context::Context;
use crate::net::proxy::ProxyConfig;
use crate::net::session::SessionStream;
use crate::net::tls::wrap_rustls;
use crate::net::tls::wrap_tls;

/// HTTP(S) GET response.
#[derive(Debug)]
Expand Down Expand Up @@ -72,11 +72,11 @@ where
let proxy_stream = proxy_config
.connect(context, host, port, load_cache)
.await?;
let tls_stream = wrap_rustls(host, &[], proxy_stream).await?;
let tls_stream = wrap_tls(true, host, &[], proxy_stream).await?;
Box::new(tls_stream)
} else {
let tcp_stream = crate::net::connect_tcp(context, host, port, load_cache).await?;
let tls_stream = wrap_rustls(host, &[], tcp_stream).await?;
let tls_stream = wrap_tls(true, host, &[], tcp_stream).await?;
Box::new(tls_stream)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/net/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::constants::NON_ALPHANUMERIC_WITHOUT_DOT;
use crate::context::Context;
use crate::net::connect_tcp;
use crate::net::session::SessionStream;
use crate::net::tls::wrap_rustls;
use crate::net::tls::wrap_tls;
use crate::sql::Sql;

/// Default SOCKS5 port according to [RFC 1928](https://tools.ietf.org/html/rfc1928).
Expand Down Expand Up @@ -425,7 +425,7 @@ impl ProxyConfig {
load_cache,
)
.await?;
let tls_stream = wrap_rustls(&https_config.host, &[], tcp_stream).await?;
let tls_stream = wrap_tls(true, &https_config.host, &[], tcp_stream).await?;
let auth = if let Some((username, password)) = &https_config.user_password {
Some((username.as_str(), password.as_str()))
} else {
Expand Down
5 changes: 0 additions & 5 deletions src/net/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ impl SessionStream for Box<dyn SessionStream> {
self.as_mut().set_read_timeout(timeout);
}
}
impl<T: SessionStream> SessionStream for async_native_tls::TlsStream<T> {
fn set_read_timeout(&mut self, timeout: Option<Duration>) {
self.get_mut().set_read_timeout(timeout);
}
}
impl<T: SessionStream> SessionStream for tokio_rustls::client::TlsStream<T> {
fn set_read_timeout(&mut self, timeout: Option<Duration>) {
self.get_mut().0.set_read_timeout(timeout);
Expand Down
37 changes: 8 additions & 29 deletions src/net/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,17 @@
use std::sync::Arc;

use anyhow::Result;
use async_native_tls::{Certificate, Protocol, TlsConnector, TlsStream};
use once_cell::sync::Lazy;
use tokio::io::{AsyncRead, AsyncWrite};
use rustls::client::ClientSessionStore;

// this certificate is missing on older android devices (eg. lg with android6 from 2017)
// certificate downloaded from https://letsencrypt.org/certificates/
static LETSENCRYPT_ROOT: Lazy<Certificate> = Lazy::new(|| {
Certificate::from_der(include_bytes!(
"../../assets/root-certificates/letsencrypt/isrgrootx1.der"
))
.unwrap()
// This is the default as of version 0.23.16, but make it shared between clients.
static RESUMPTION_STORE: Lazy<Arc<dyn ClientSessionStore>> = Lazy::new(|| {
Arc::new(rustls::client::ClientSessionMemoryCache::new(256))
});

pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>(
strict_tls: bool,
hostname: &str,
alpn: &[&str],
stream: T,
) -> Result<TlsStream<T>> {
let tls_builder = TlsConnector::new()
.min_protocol_version(Some(Protocol::Tlsv12))
.request_alpns(alpn)
.add_root_certificate(LETSENCRYPT_ROOT.clone());
let tls = if strict_tls {
tls_builder
} else {
tls_builder
.danger_accept_invalid_hostnames(true)
.danger_accept_invalid_certs(true)
};
let tls_stream = tls.connect(hostname, stream).await?;
Ok(tls_stream)
}

pub async fn wrap_rustls<T: AsyncRead + AsyncWrite + Unpin>(
_strict_tls: bool,
hostname: &str,
alpn: &[&str],
stream: T,
Expand All @@ -49,6 +25,9 @@ pub async fn wrap_rustls<T: AsyncRead + AsyncWrite + Unpin>(
.with_no_client_auth();
config.alpn_protocols = alpn.iter().map(|s| s.as_bytes().to_vec()).collect();

let resumption = rustls::client::Resumption::store(Arc::clone(&RESUMPTION_STORE));
config.resumption = resumption;

let tls = tokio_rustls::TlsConnector::from(Arc::new(config));
let name = rustls_pki_types::ServerName::try_from(hostname)?.to_owned();
let tls_stream = tls.connect(name, stream).await?;
Expand Down

0 comments on commit e682833

Please sign in to comment.