Merge pull request #244 from dnaka91/rustls-0.20

Upgrade to rustls 0.20
pull/250/head
Daniel Abramov 3 years ago committed by GitHub
commit 4729b0f000
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      Cargo.toml
  2. 10
      src/error.rs
  3. 15
      src/stream.rs
  4. 44
      src/tls.rs

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

@ -255,9 +255,13 @@ pub enum TlsError {
/// Rustls error. /// Rustls error.
#[cfg(feature = "__rustls-tls")] #[cfg(feature = "__rustls-tls")]
#[error("rustls error: {0}")] #[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. /// DNS name resolution error.
#[cfg(feature = "__rustls-tls")] #[cfg(feature = "__rustls-tls")]
#[error("Invalid DNS name: {0}")] #[error("Invalid DNS name")]
Dns(#[from] webpki::InvalidDNSNameError), InvalidDnsName,
} }

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

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

Loading…
Cancel
Save