Merge pull request #244 from dnaka91/rustls-0.20

Upgrade to rustls 0.20
This commit is contained in:
Daniel Abramov 2021-10-27 15:11:53 +02:00 committed by GitHub
commit 4729b0f000
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 21 deletions

View File

@ -48,11 +48,11 @@ version = "0.20.0"
[dependencies.rustls-native-certs]
optional = true
version = "0.5.0"
version = "0.6.0"
[dependencies.webpki]
optional = true
version = "0.21"
version = "0.22"
[dependencies.webpki-roots]
optional = true

View File

@ -255,9 +255,13 @@ pub enum TlsError {
/// Rustls error.
#[cfg(feature = "__rustls-tls")]
#[error("rustls error: {0}")]
Rustls(#[from] rustls::TLSError),
Rustls(#[from] rustls::Error),
/// Webpki error.
#[cfg(feature = "__rustls-tls")]
#[error("webpki error: {0}")]
Webpki(#[from] webpki::Error),
/// DNS name resolution error.
#[cfg(feature = "__rustls-tls")]
#[error("Invalid DNS name: {0}")]
Dns(#[from] webpki::InvalidDNSNameError),
#[error("Invalid DNS name")]
InvalidDnsName,
}

View File

@ -4,6 +4,8 @@
//! `native_tls` or `openssl` will work as long as there is a TLS stream supporting standard
//! `Read + Write` traits.
#[cfg(feature = "__rustls-tls")]
use std::ops::Deref;
use std::{
fmt::{self, Debug},
io::{Read, Result as IoResult, Write},
@ -45,7 +47,12 @@ impl<S: Read + Write + NoDelay> NoDelay for TlsStream<S> {
}
#[cfg(feature = "__rustls-tls")]
impl<S: rustls::Session, T: Read + Write + NoDelay> NoDelay for StreamOwned<S, T> {
impl<S, SD, T> NoDelay for StreamOwned<S, T>
where
S: Deref<Target = rustls::ConnectionCommon<SD>>,
SD: rustls::SideData,
T: Read + Write + NoDelay,
{
fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
self.sock.set_nodelay(nodelay)
}
@ -61,7 +68,7 @@ pub enum MaybeTlsStream<S: Read + Write> {
NativeTls(native_tls_crate::TlsStream<S>),
#[cfg(feature = "__rustls-tls")]
/// Encrypted socket stream using `rustls`.
Rustls(rustls::StreamOwned<rustls::ClientSession, S>),
Rustls(rustls::StreamOwned<rustls::ClientConnection, S>),
}
impl<S: Read + Write + Debug> Debug for MaybeTlsStream<S> {
@ -73,13 +80,13 @@ impl<S: Read + Write + Debug> Debug for MaybeTlsStream<S> {
#[cfg(feature = "__rustls-tls")]
Self::Rustls(s) => {
struct RustlsStreamDebug<'a, S: Read + Write>(
&'a rustls::StreamOwned<rustls::ClientSession, S>,
&'a rustls::StreamOwned<rustls::ClientConnection, S>,
);
impl<'a, S: Read + Write + Debug> Debug for RustlsStreamDebug<'a, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StreamOwned")
.field("sess", &self.0.sess)
.field("conn", &self.0.conn)
.field("sock", &self.0.sock)
.finish()
}

View File

@ -70,10 +70,10 @@ mod encryption {
#[cfg(feature = "__rustls-tls")]
pub mod rustls {
use rustls::{ClientConfig, ClientSession, StreamOwned};
use webpki::DNSNameRef;
use rustls::{ClientConfig, ClientConnection, RootCertStore, ServerName, StreamOwned};
use std::{
convert::TryFrom,
io::{Read, Write},
sync::Arc,
};
@ -100,24 +100,40 @@ mod encryption {
Some(config) => config,
None => {
#[allow(unused_mut)]
let mut config = ClientConfig::new();
let mut root_store = RootCertStore::empty();
#[cfg(feature = "rustls-tls-native-roots")]
{
config.root_store = rustls_native_certs::load_native_certs()
.map_err(|(_, err)| err)?;
for cert in rustls_native_certs::load_native_certs()? {
root_store
.add(&rustls::Certificate(cert.0))
.map_err(TlsError::Webpki)?;
}
}
#[cfg(feature = "rustls-tls-webpki-roots")]
{
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
root_store.add_server_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
})
);
}
Arc::new(config)
Arc::new(
ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth(),
)
}
};
let domain = DNSNameRef::try_from_ascii_str(domain).map_err(TlsError::Dns)?;
let client = ClientSession::new(&config, domain);
let domain =
ServerName::try_from(domain).map_err(|_| TlsError::InvalidDnsName)?;
let client = ClientConnection::new(config, domain).map_err(TlsError::Rustls)?;
let stream = StreamOwned::new(client, socket);
Ok(MaybeTlsStream::Rustls(stream))
@ -185,7 +201,7 @@ where
None => Err(Error::Url(UrlError::NoHostName)),
}?;
let mode = uri_mode(&request.uri())?;
let mode = uri_mode(request.uri())?;
let stream = match connector {
Some(conn) => match conn {