feat: use Rustls for connections with strict TLS (#6186)

This commit is contained in:
l
2024-11-07 19:07:11 +00:00
committed by GitHub
parent c9cf2b7f2e
commit 3b2f18f926
3 changed files with 24 additions and 30 deletions

View File

@@ -5,13 +5,13 @@ use std::pin::Pin;
use std::time::Duration; use std::time::Duration;
use anyhow::{format_err, Context as _, Result}; use anyhow::{format_err, Context as _, Result};
use async_native_tls::TlsStream;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::task::JoinSet; use tokio::task::JoinSet;
use tokio::time::timeout; use tokio::time::timeout;
use tokio_io_timeout::TimeoutStream; use tokio_io_timeout::TimeoutStream;
use crate::context::Context; use crate::context::Context;
use crate::net::session::SessionStream;
use crate::sql::Sql; use crate::sql::Sql;
use crate::tools::time; use crate::tools::time;
@@ -128,7 +128,7 @@ pub(crate) async fn connect_tls_inner(
host: &str, host: &str,
strict_tls: bool, strict_tls: bool,
alpn: &[&str], alpn: &[&str],
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> { ) -> Result<impl SessionStream> {
let tcp_stream = connect_tcp_inner(addr).await?; let tcp_stream = connect_tcp_inner(addr).await?;
let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?; let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?;
Ok(tls_stream) Ok(tls_stream)

View File

@@ -2,45 +2,39 @@
use std::sync::Arc; use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use async_native_tls::{Certificate, Protocol, TlsConnector, TlsStream};
use once_cell::sync::Lazy;
use tokio::io::{AsyncRead, AsyncWrite};
// this certificate is missing on older android devices (eg. lg with android6 from 2017) use crate::net::session::SessionStream;
// 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()
});
pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>( pub async fn wrap_tls(
strict_tls: bool, strict_tls: bool,
hostname: &str, hostname: &str,
alpn: &[&str], alpn: &[&str],
stream: T, stream: impl SessionStream + 'static,
) -> Result<TlsStream<T>> { ) -> Result<impl SessionStream> {
let tls_builder = TlsConnector::new() if strict_tls {
.min_protocol_version(Some(Protocol::Tlsv12)) let tls_stream = wrap_rustls(hostname, alpn, stream).await?;
.request_alpns(alpn) let boxed_stream: Box<dyn SessionStream> = Box::new(tls_stream);
.add_root_certificate(LETSENCRYPT_ROOT.clone()); Ok(boxed_stream)
let tls = if strict_tls {
tls_builder
} else { } else {
tls_builder // We use native_tls because it accepts 1024-bit RSA keys.
// Rustls does not support them even if
// certificate checks are disabled: <https://github.com/rustls/rustls/issues/234>.
let tls = async_native_tls::TlsConnector::new()
.min_protocol_version(Some(async_native_tls::Protocol::Tlsv12))
.request_alpns(alpn)
.danger_accept_invalid_hostnames(true) .danger_accept_invalid_hostnames(true)
.danger_accept_invalid_certs(true) .danger_accept_invalid_certs(true);
};
let tls_stream = tls.connect(hostname, stream).await?; let tls_stream = tls.connect(hostname, stream).await?;
Ok(tls_stream) let boxed_stream: Box<dyn SessionStream> = Box::new(tls_stream);
Ok(boxed_stream)
}
} }
pub async fn wrap_rustls<T: AsyncRead + AsyncWrite + Unpin>( pub async fn wrap_rustls(
hostname: &str, hostname: &str,
alpn: &[&str], alpn: &[&str],
stream: T, stream: impl SessionStream,
) -> Result<tokio_rustls::client::TlsStream<T>> { ) -> Result<impl SessionStream> {
let mut root_cert_store = rustls::RootCertStore::empty(); let mut root_cert_store = rustls::RootCertStore::empty();
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());