From 3b2f18f9262d44470d128b4e3366e67544715d80 Mon Sep 17 00:00:00 2001 From: l <link2xt@testrun.org> Date: Thu, 7 Nov 2024 19:07:11 +0000 Subject: [PATCH] feat: use Rustls for connections with strict TLS (#6186) --- .../letsencrypt/isrgrootx1.der | Bin 1391 -> 0 bytes src/net.rs | 4 +- src/net/tls.rs | 50 ++++++++---------- 3 files changed, 24 insertions(+), 30 deletions(-) delete mode 100644 assets/root-certificates/letsencrypt/isrgrootx1.der diff --git a/assets/root-certificates/letsencrypt/isrgrootx1.der b/assets/root-certificates/letsencrypt/isrgrootx1.der deleted file mode 100644 index 9d2132e7f1e352fabac7eafb231488b5da91ffb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1391 zcmXqLV$C*aVh&!w%*4pVB*@StaDKxjhsTjF$q#lXH+3@@@Un4gwRyCC=VfH%W@Rw& zH{>?pWMd9xVH0Kw4K~y?PzQ0igcUsVN>YpRQcDzqQ<F=JGD|8If>Mi96N{2F6x@sQ zOA8D|4TM2TnT2^ggM-`^g7WiA6e0`_<ivRmO%2QpObiVTOpGm}#CeU8xzx9?iAf3B zQ;e((%uP)E3<gb1Tue<&j0|gEs1$z@G5<V!o_4r~O#8k&+wWUU=*hEr7QUe3d+DJ? z|GsABePi&~xP339Eyrc@wvEYuMTD~V%U^nBI9svqqOr{`kFR$t?{D7mU+AOaEboI| zZH1X$X=yqAbv6b2*J>)UeSUJ_S;M+V-u>HW)=goaf7yL{%}fvF;1?F_{JHX*^)7mb z_cWAjyQP1@qPLp4KvBB%lYz~z{&jb6C9i%h=6|S9(7WzD_ly5q%k{o&s`h%|Bc#ex z(95j3;9;=J8{wPpB=-w!_Uf_kT$~tqZ%sS<lrPDJZ}cAJN6%<{*coF|nN#-OdO}j= zv)fB%>8l;RAn=gy-c5l%vESRjulRoaDHHpQelw1#&mWmj<25Ut_nWV1qwMTG%s)L@ zZ#3Rz-J*5P@#PxEvZ-ABH|}5ED<p5KuOXguX~w}7oGImb?&iDBt%;1wm|I_Tt@9|G zqo!S?-Ceb>DklY(M=kbokat@+bL(=ez`Qo=d9_8$g;*;h-`WLMh;lRc_g>Iv-DFqo zCF5PpD)i^rs|NwXHO`YuHlHea-Y3t<alzn9bfMW6_FV@J3}QUCH(AeER-4eZXt8F~ znO%FES)>;=GdnK4#`;nE(6$dNYTB&bR(NQ2+$oz?wqHJLsjX!HYm3h*_fBZ@a%uek ze*2NA(-ox)>ah<i|4BSA=veFb>}I#svAgPldH?sMd^L9VXJTe#U|j5E;9$T9Os}&1 zjEw(TSb({M&43@o7Y6ZJ4VZzHfh<UXk420{q;gB-v+8Y6pD-3TaCDrIium?&b{=vn z17;myDq~~_m5*4tXVZ#+3p^WdNM$OhYjUhfERE^P`_c3?Q~&C>Fz=l^iUlGsD^9O_ z?o;@C)1`#9mMgeli7SS+ehlD?e0}ag<jY+rMc=p0?Qd!L_T=Tn33tS2CrP`0NSk`8 zCjZbY>-X~KPhVT7{&D4o6YKug*3J5*#Pa(8&H7gpwUsuC^Ywq~GKr43@rUtb$j%*V zXSzC!JAHIpY?|)Bn-<QxOK11@BioPrSvT!7JfT!vJn7=0h9#Dk0>;WsJ~s2)HigcR z-KW{sqcnToqipMNtEK|qJDkTmPjj*R=DdjQJNf?H>f^h&YWulf^SYpR=4sI>j;y6q zAB!&hzU1vmo%p4{|F6+t(%W~vdiUeP>Iq_(+2h=TYs}f5dM+QCHs|Whty&MJN;P<_ z^RZ+<cgB55&{XYRJASXdWE@=kRMt25>cWl3o${YKsGG(t*4WP8`@Gk9!gJ;MzXRq} z=D1zmBD#56Ufpb-X;wRebnUN2Km5&csO6u^ip8C`)?_`D(Av1dIWhXO{2lAwvQN4% zdQ0z%8|T;t|E@mm82|syq6>)@52x)|6WeWmz4WT_ftiBq<~klMDs9=v<meQiuHrG} z;%xPO?Dji%_&1gWKCIgQcCPZHeGjf`un5~2GS9nPmD7KWUE)~%J@-C)jd?6==a+_< hl<$4hIs2u!^Zn@C@&Eed!WW%&m|K^mbnBjkIsk}=Sg-&9 diff --git a/src/net.rs b/src/net.rs index 1ad85a3ea5..350967ddef 100644 --- a/src/net.rs +++ b/src/net.rs @@ -5,13 +5,13 @@ use std::pin::Pin; use std::time::Duration; use anyhow::{format_err, Context as _, Result}; -use async_native_tls::TlsStream; use tokio::net::TcpStream; use tokio::task::JoinSet; use tokio::time::timeout; use tokio_io_timeout::TimeoutStream; use crate::context::Context; +use crate::net::session::SessionStream; use crate::sql::Sql; use crate::tools::time; @@ -128,7 +128,7 @@ pub(crate) async fn connect_tls_inner( host: &str, strict_tls: bool, alpn: &[&str], -) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> { +) -> Result<impl SessionStream> { let tcp_stream = connect_tcp_inner(addr).await?; let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?; Ok(tls_stream) diff --git a/src/net/tls.rs b/src/net/tls.rs index f30ed5cfd8..183ad75319 100644 --- a/src/net/tls.rs +++ b/src/net/tls.rs @@ -2,45 +2,39 @@ 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}; -// 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() -}); +use crate::net::session::SessionStream; -pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>( +pub async fn wrap_tls( 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 + stream: impl SessionStream + 'static, +) -> Result<impl SessionStream> { + if strict_tls { + let tls_stream = wrap_rustls(hostname, alpn, stream).await?; + let boxed_stream: Box<dyn SessionStream> = Box::new(tls_stream); + Ok(boxed_stream) } 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_certs(true) - }; - let tls_stream = tls.connect(hostname, stream).await?; - Ok(tls_stream) + .danger_accept_invalid_certs(true); + let tls_stream = tls.connect(hostname, stream).await?; + 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, alpn: &[&str], - stream: T, -) -> Result<tokio_rustls::client::TlsStream<T>> { + stream: impl SessionStream, +) -> Result<impl SessionStream> { let mut root_cert_store = rustls::RootCertStore::empty(); root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());