From 97d3c760c0f30ab92cb94867806921a7e9cd2851 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Wed, 20 Oct 2021 14:37:16 +0200 Subject: [PATCH] Update rustls to 0.20 (#648) --- Cargo.toml | 14 +++--- src/transport/smtp/client/async_net.rs | 24 ++++++---- src/transport/smtp/client/net.rs | 17 +++---- src/transport/smtp/client/tls.rs | 64 +++++++++++++++++--------- 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 132b7eb..976bdd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,9 +41,9 @@ hostname = { version = "0.3", optional = true } # feature ## tls native-tls = { version = "0.2", optional = true } # feature -rustls = { version = "0.19", features = ["dangerous_configuration"], optional = true } -webpki = { version = "0.21", optional = true } -webpki-roots = { version = "0.21", optional = true } +rustls = { version = "0.20", features = ["dangerous_configuration"], optional = true } +rustls-pemfile = { version = "0.2.1", optional = true } +webpki-roots = { version = "0.22", optional = true } # async futures-io = { version = "0.3.7", optional = true } @@ -53,12 +53,12 @@ async-trait = { version = "0.1", optional = true } ## async-std async-std = { version = "1.8", optional = true, features = ["unstable"] } #async-native-tls = { version = "0.3.3", optional = true } -async-rustls = { version = "0.2", optional = true } +futures-rustls = { version = "0.22", optional = true } ## tokio tokio1_crate = { package = "tokio", version = "1", features = ["fs", "process", "time", "net", "io-util"], optional = true } tokio1_native_tls_crate = { package = "tokio-native-tls", version = "0.3", optional = true } -tokio1_rustls = { package = "tokio-rustls", version = "0.22", optional = true } +tokio1_rustls = { package = "tokio-rustls", version = "0.23", optional = true } [dev-dependencies] criterion = "0.3" @@ -87,12 +87,12 @@ smtp-transport = ["base64", "nom"] pool = ["futures-util"] -rustls-tls = ["webpki", "webpki-roots", "rustls"] +rustls-tls = ["webpki-roots", "rustls", "rustls-pemfile"] # async async-std1 = ["async-std", "async-trait", "futures-io", "futures-util"] #async-std1-native-tls = ["async-std1", "native-tls", "async-native-tls"] -async-std1-rustls-tls = ["async-std1", "rustls-tls", "async-rustls"] +async-std1-rustls-tls = ["async-std1", "rustls-tls", "futures-rustls"] tokio1 = ["tokio1_crate", "async-trait", "futures-io", "futures-util"] tokio1-native-tls = ["tokio1", "native-tls", "tokio1_native_tls_crate"] tokio1-rustls-tls = ["tokio1", "rustls-tls", "tokio1_rustls"] diff --git a/src/transport/smtp/client/async_net.rs b/src/transport/smtp/client/async_net.rs index a757eb4..6678233 100644 --- a/src/transport/smtp/client/async_net.rs +++ b/src/transport/smtp/client/async_net.rs @@ -24,7 +24,7 @@ use async_native_tls::TlsStream as AsyncStd1TlsStream; use tokio1_native_tls_crate::TlsStream as Tokio1TlsStream; #[cfg(feature = "async-std1-rustls-tls")] -use async_rustls::client::TlsStream as AsyncStd1RustlsTlsStream; +use futures_rustls::client::TlsStream as AsyncStd1RustlsTlsStream; #[cfg(feature = "tokio1-rustls-tls")] use tokio1_rustls::client::TlsStream as Tokio1RustlsTlsStream; @@ -261,9 +261,9 @@ impl AsyncNetworkStream { #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))] async fn upgrade_tokio1_tls( tcp_stream: Tokio1TcpStream, - mut tls_parameters: TlsParameters, + tls_parameters: TlsParameters, ) -> Result { - let domain = mem::take(&mut tls_parameters.domain); + let domain = tls_parameters.domain().to_string(); match tls_parameters.connector { #[cfg(feature = "native-tls")] @@ -290,10 +290,13 @@ impl AsyncNetworkStream { #[cfg(feature = "tokio1-rustls-tls")] return { - use tokio1_rustls::{webpki::DNSNameRef, TlsConnector}; + use std::convert::TryFrom; - let domain = - DNSNameRef::try_from_ascii_str(&domain).map_err(error::connection)?; + use rustls::ServerName; + use tokio1_rustls::TlsConnector; + + let domain = ServerName::try_from(domain.as_str()) + .map_err(|_| error::connection("domain isn't a valid DNS name"))?; let connector = TlsConnector::from(config); let stream = connector @@ -342,10 +345,13 @@ impl AsyncNetworkStream { #[cfg(feature = "async-std1-rustls-tls")] return { - use async_rustls::{webpki::DNSNameRef, TlsConnector}; + use std::convert::TryFrom; - let domain = - DNSNameRef::try_from_ascii_str(&domain).map_err(error::connection)?; + use futures_rustls::TlsConnector; + use rustls::ServerName; + + let domain = ServerName::try_from(domain.as_str()) + .map_err(|_| error::connection("domain isn't a valid DNS name"))?; let connector = TlsConnector::from(config); let stream = connector diff --git a/src/transport/smtp/client/net.rs b/src/transport/smtp/client/net.rs index 597d445..2fa1094 100644 --- a/src/transport/smtp/client/net.rs +++ b/src/transport/smtp/client/net.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "rustls-tls")] +use std::convert::TryFrom; use std::{ io::{self, Read, Write}, mem, @@ -9,7 +11,7 @@ use std::{ use native_tls::TlsStream; #[cfg(feature = "rustls-tls")] -use rustls::{ClientSession, StreamOwned}; +use rustls::{ClientConnection, ServerName, StreamOwned}; #[cfg(any(feature = "native-tls", feature = "rustls-tls"))] use super::InnerTlsParameters; @@ -33,7 +35,7 @@ enum InnerNetworkStream { NativeTls(TlsStream), /// Encrypted TCP stream #[cfg(feature = "rustls-tls")] - RustlsTls(StreamOwned), + RustlsTls(StreamOwned), /// Can't be built None, } @@ -157,12 +159,11 @@ impl NetworkStream { } #[cfg(feature = "rustls-tls")] InnerTlsParameters::RustlsTls(connector) => { - use webpki::DNSNameRef; - - let domain = DNSNameRef::try_from_ascii_str(tls_parameters.domain()) - .map_err(error::connection)?; - let stream = StreamOwned::new(ClientSession::new(connector, domain), tcp_stream); - + let domain = ServerName::try_from(tls_parameters.domain()) + .map_err(|_| error::connection("domain isn't a valid DNS name"))?; + let connection = + ClientConnection::new(connector.clone(), domain).map_err(error::connection)?; + let stream = StreamOwned::new(connection, tcp_stream); InnerNetworkStream::RustlsTls(stream) } }) diff --git a/src/transport/smtp/client/tls.rs b/src/transport/smtp/client/tls.rs index 531f893..4777808 100644 --- a/src/transport/smtp/client/tls.rs +++ b/src/transport/smtp/client/tls.rs @@ -3,12 +3,13 @@ use crate::transport::smtp::{error, Error}; #[cfg(feature = "native-tls")] use native_tls::{Protocol, TlsConnector}; #[cfg(feature = "rustls-tls")] -use rustls::{ClientConfig, RootCertStore, ServerCertVerified, ServerCertVerifier, TLSError}; +use rustls::{ + client::{ServerCertVerified, ServerCertVerifier, WebPkiVerifier}, + ClientConfig, Error as TlsError, OwnedTrustAnchor, RootCertStore, ServerName, +}; use std::fmt::{self, Debug}; #[cfg(feature = "rustls-tls")] -use std::sync::Arc; -#[cfg(feature = "rustls-tls")] -use webpki::DNSNameRef; +use std::{sync::Arc, time::SystemTime}; /// Accepted protocols by default. /// This removes TLS 1.0 and 1.1 compared to tls-native defaults. @@ -163,21 +164,35 @@ impl TlsParametersBuilder { #[cfg(feature = "rustls-tls")] #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] pub fn build_rustls(self) -> Result { - use webpki_roots::TLS_SERVER_ROOTS; + let tls = ClientConfig::builder(); + let tls = tls.with_safe_defaults(); - let mut tls = ClientConfig::new(); - - for cert in self.root_certs { - for rustls_cert in cert.rustls { - tls.root_store.add(&rustls_cert).map_err(error::tls)?; + let tls = if self.accept_invalid_certs { + tls.with_custom_certificate_verifier(Arc::new(InvalidCertsVerifier {})) + } else { + let mut root_cert_store = RootCertStore::empty(); + for cert in self.root_certs { + for rustls_cert in cert.rustls { + root_cert_store.add(&rustls_cert).map_err(error::tls)?; + } } - } - if self.accept_invalid_certs { - tls.dangerous() - .set_certificate_verifier(Arc::new(InvalidCertsVerifier {})); - } + root_cert_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map( + |ta| { + OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + }, + )); + + tls.with_custom_certificate_verifier(Arc::new(WebPkiVerifier::new( + root_cert_store, + None, + ))) + }; + let tls = tls.with_no_client_auth(); - tls.root_store.add_server_trust_anchors(&TLS_SERVER_ROOTS); Ok(TlsParameters { connector: InnerTlsParameters::RustlsTls(Arc::new(tls)), domain: self.domain, @@ -257,11 +272,14 @@ impl Certificate { #[cfg(feature = "rustls-tls")] let rustls_cert = { - use rustls::internal::pemfile; use std::io::Cursor; let mut pem = Cursor::new(pem); - pemfile::certs(&mut pem).map_err(|_| error::tls("invalid certificates"))? + rustls_pemfile::certs(&mut pem) + .map_err(|_| error::tls("invalid certificates"))? + .into_iter() + .map(rustls::Certificate) + .collect::>() }; Ok(Self { @@ -286,11 +304,13 @@ struct InvalidCertsVerifier; impl ServerCertVerifier for InvalidCertsVerifier { fn verify_server_cert( &self, - _roots: &RootCertStore, - _presented_certs: &[rustls::Certificate], - _dns_name: DNSNameRef<'_>, + _end_entity: &rustls::Certificate, + _intermediates: &[rustls::Certificate], + _server_name: &ServerName, + _scts: &mut dyn Iterator, _ocsp_response: &[u8], - ) -> Result { + _now: SystemTime, + ) -> Result { Ok(ServerCertVerified::assertion()) } }