Skip to content

Commit 8b37ae4

Browse files
authored
Support to rustls 0.20 (#1388)
1 parent 8fe22c4 commit 8b37ae4

File tree

5 files changed

+136
-101
lines changed

5 files changed

+136
-101
lines changed

Cargo.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ rustls-tls-native-roots = ["rustls-native-certs", "__rustls"]
4444

4545
blocking = ["futures-util/io", "tokio/rt-multi-thread", "tokio/sync"]
4646

47-
cookies = ["cookie_crate", "cookie_store"]
47+
cookies = ["cookie_crate", "cookie_store", "proc-macro-hack"]
4848

4949
gzip = ["async-compression", "async-compression/gzip", "tokio-util"]
5050

@@ -70,7 +70,7 @@ __tls = []
7070

7171
# Enables common rustls code.
7272
# Equivalent to rustls-tls-manual-roots but shorter :)
73-
__rustls = ["hyper-rustls", "tokio-rustls", "rustls", "__tls"]
73+
__rustls = ["hyper-rustls", "tokio-rustls", "rustls", "__tls", "rustls-pemfile"]
7474

7575
# When enabled, disable using the cached SYS_PROXIES.
7676
__internal_proxy_sys_no_cache = []
@@ -112,15 +112,17 @@ native-tls-crate = { version = "0.2.8", optional = true, package = "native-tls"
112112
tokio-native-tls = { version = "0.3.0", optional = true }
113113

114114
# rustls-tls
115-
hyper-rustls = { version = "0.22.1", default-features = false, optional = true }
116-
rustls = { version = "0.19", features = ["dangerous_configuration"], optional = true }
117-
tokio-rustls = { version = "0.22", optional = true }
115+
hyper-rustls = { version = "0.23", default-features = false, optional = true }
116+
rustls = { version = "0.20", features = ["dangerous_configuration"], optional = true }
117+
tokio-rustls = { version = "0.23", optional = true }
118118
webpki-roots = { version = "0.21", optional = true }
119-
rustls-native-certs = { version = "0.5", optional = true }
119+
rustls-native-certs = { version = "0.6", optional = true }
120+
rustls-pemfile = { version = "0.2", optional = true }
120121

121122
## cookies
122123
cookie_crate = { version = "0.15", package = "cookie", optional = true }
123124
cookie_store = { version = "0.15", optional = true }
125+
proc-macro-hack = { version = "0.5.19", optional = true }
124126

125127
## compression
126128
async-compression = { version = "0.3.7", default-features = false, features = ["tokio"], optional = true }

src/async_impl/client.rs

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ use hyper::client::ResponseFuture;
1717
#[cfg(feature = "native-tls-crate")]
1818
use native_tls_crate::TlsConnector;
1919
use pin_project_lite::pin_project;
20-
#[cfg(feature = "rustls-tls-native-roots")]
21-
use rustls::RootCertStore;
2220
use std::future::Future;
2321
use std::pin::Pin;
2422
use std::task::{Context, Poll};
@@ -322,68 +320,94 @@ impl ClientBuilder {
322320
TlsBackend::Rustls => {
323321
use crate::tls::NoVerifier;
324322

325-
let mut tls = rustls::ClientConfig::new();
326-
match config.http_version_pref {
327-
HttpVersionPref::Http1 => {
328-
tls.set_protocols(&["http/1.1".into()]);
329-
}
330-
HttpVersionPref::Http2 => {
331-
tls.set_protocols(&["h2".into()]);
332-
}
333-
HttpVersionPref::All => {
334-
tls.set_protocols(&["h2".into(), "http/1.1".into()]);
335-
}
323+
// Set root certificates.
324+
let mut root_cert_store = rustls::RootCertStore::empty();
325+
for cert in config.root_certs {
326+
cert.add_to_rustls(&mut root_cert_store)?;
336327
}
328+
337329
#[cfg(feature = "rustls-tls-webpki-roots")]
338330
if config.tls_built_in_root_certs {
339-
tls.root_store
340-
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
341-
}
342-
#[cfg(feature = "rustls-tls-native-roots")]
343-
if config.tls_built_in_root_certs {
344-
let roots_slice = NATIVE_ROOTS.as_ref().unwrap().roots.as_slice();
345-
tls.root_store.roots.extend_from_slice(roots_slice);
346-
}
347-
348-
if !config.certs_verification {
349-
tls.dangerous()
350-
.set_certificate_verifier(Arc::new(NoVerifier));
351-
}
331+
use rustls::OwnedTrustAnchor;
332+
333+
let trust_anchors =
334+
webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|trust_anchor| {
335+
OwnedTrustAnchor::from_subject_spki_name_constraints(
336+
trust_anchor.subject,
337+
trust_anchor.spki,
338+
trust_anchor.name_constraints,
339+
)
340+
});
352341

353-
for cert in config.root_certs {
354-
cert.add_to_rustls(&mut tls)?;
342+
root_cert_store.add_server_trust_anchors(trust_anchors);
355343
}
356344

357-
if let Some(id) = config.identity {
358-
id.add_to_rustls(&mut tls)?;
345+
#[cfg(feature = "rustls-tls-native-roots")]
346+
if config.tls_built_in_root_certs {
347+
for cert in rustls_native_certs::load_native_certs()
348+
.map_err(crate::error::builder)?
349+
{
350+
root_cert_store
351+
.add(&rustls::Certificate(cert.0))
352+
.map_err(crate::error::builder)?
353+
}
359354
}
360355

361-
// rustls does not support TLS versions <1.2 and this is unlikely to change.
362-
// https://github.com/rustls/rustls/issues/33
363-
364-
// As of writing, TLS 1.2 and 1.3 are the only implemented versions and are both
365-
// enabled by default.
366-
// rustls 0.20 will add ALL_VERSIONS and DEFAULT_VERSIONS. That will enable a more
367-
// sophisticated approach.
368-
// For now we assume the default tls.versions matches the future ALL_VERSIONS and
369-
// act based on that.
356+
// Set TLS versions.
357+
let mut versions = rustls::ALL_VERSIONS.to_vec();
370358

371359
if let Some(min_tls_version) = config.min_tls_version {
372-
tls.versions
373-
.retain(|&version| match tls::Version::from_rustls(version) {
360+
versions.retain(|&supported_version| {
361+
match tls::Version::from_rustls(supported_version.version) {
374362
Some(version) => version >= min_tls_version,
375363
// Assume it's so new we don't know about it, allow it
376364
// (as of writing this is unreachable)
377365
None => true,
378-
});
366+
}
367+
});
379368
}
380369

381370
if let Some(max_tls_version) = config.max_tls_version {
382-
tls.versions
383-
.retain(|&version| match tls::Version::from_rustls(version) {
371+
versions.retain(|&supported_version| {
372+
match tls::Version::from_rustls(supported_version.version) {
384373
Some(version) => version <= max_tls_version,
385374
None => false,
386-
});
375+
}
376+
});
377+
}
378+
379+
// Build TLS config
380+
let config_builder = rustls::ClientConfig::builder()
381+
.with_safe_default_cipher_suites()
382+
.with_safe_default_kx_groups()
383+
.with_protocol_versions(&versions)
384+
.map_err(crate::error::builder)?
385+
.with_root_certificates(root_cert_store);
386+
387+
// Finalize TLS config
388+
let mut tls = if let Some(id) = config.identity {
389+
id.add_to_rustls(config_builder)?
390+
} else {
391+
config_builder.with_no_client_auth()
392+
};
393+
394+
// Certificate verifier
395+
if !config.certs_verification {
396+
tls.dangerous()
397+
.set_certificate_verifier(Arc::new(NoVerifier));
398+
}
399+
400+
// ALPN protocol
401+
match config.http_version_pref {
402+
HttpVersionPref::Http1 => {
403+
tls.alpn_protocols = vec!["http/1.1".into()];
404+
}
405+
HttpVersionPref::Http2 => {
406+
tls.alpn_protocols = vec!["h2".into()];
407+
}
408+
HttpVersionPref::All => {
409+
tls.alpn_protocols = vec!["h2".into(), "http/1.1".into()];
410+
}
387411
}
388412

389413
Connector::new_rustls_tls(
@@ -1848,12 +1872,6 @@ fn add_cookie_header(headers: &mut HeaderMap, cookie_store: &dyn cookie::CookieS
18481872
}
18491873
}
18501874

1851-
#[cfg(feature = "rustls-tls-native-roots")]
1852-
lazy_static! {
1853-
static ref NATIVE_ROOTS: std::io::Result<RootCertStore> =
1854-
rustls_native_certs::load_native_certs().map_err(|e| e.1);
1855-
}
1856-
18571875
#[cfg(test)]
18581876
mod tests {
18591877
#[tokio::test]

src/connect.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -325,17 +325,16 @@ impl Connector {
325325
#[cfg(feature = "__rustls")]
326326
Inner::RustlsTls { tls_proxy, .. } => {
327327
if dst.scheme() == Some(&Scheme::HTTPS) {
328-
use tokio_rustls::webpki::DNSNameRef;
328+
use std::convert::TryFrom;
329329
use tokio_rustls::TlsConnector as RustlsConnector;
330330

331331
let tls = tls_proxy.clone();
332332
let host = dst.host().ok_or("no host in url")?.to_string();
333333
let conn = socks::connect(proxy, dst, dns).await?;
334-
let dnsname = DNSNameRef::try_from_ascii_str(&host)
335-
.map(|dnsname| dnsname.to_owned())
336-
.map_err(|_| "Invalid DNS Name")?;
334+
let server_name = rustls::ServerName::try_from(host.as_str())
335+
.map_err(|_| "Invalid Server Name")?;
337336
let io = RustlsConnector::from(tls)
338-
.connect(dnsname.as_ref(), conn)
337+
.connect(server_name, conn)
339338
.await?;
340339
return Ok(Conn {
341340
inner: self.verbose.wrap(RustlsTlsConn { inner: io }),
@@ -479,7 +478,8 @@ impl Connector {
479478
tls_proxy,
480479
} => {
481480
if dst.scheme() == Some(&Scheme::HTTPS) {
482-
use tokio_rustls::webpki::DNSNameRef;
481+
use rustls::ServerName;
482+
use std::convert::TryFrom;
483483
use tokio_rustls::TlsConnector as RustlsConnector;
484484

485485
let host = dst.host().ok_or("no host in url")?.to_string();
@@ -489,13 +489,12 @@ impl Connector {
489489
let tls = tls.clone();
490490
let conn = http.call(proxy_dst).await?;
491491
log::trace!("tunneling HTTPS over proxy");
492-
let maybe_dnsname = DNSNameRef::try_from_ascii_str(&host)
493-
.map(|dnsname| dnsname.to_owned())
494-
.map_err(|_| "Invalid DNS Name");
492+
let maybe_server_name =
493+
ServerName::try_from(host.as_str()).map_err(|_| "Invalid Server Name");
495494
let tunneled = tunnel(conn, host, port, self.user_agent.clone(), auth).await?;
496-
let dnsname = maybe_dnsname?;
495+
let server_name = maybe_server_name?;
497496
let io = RustlsConnector::from(tls)
498-
.connect(dnsname.as_ref(), tunneled)
497+
.connect(server_name, tunneled)
499498
.await?;
500499

501500
return Ok(Conn {
@@ -820,7 +819,6 @@ mod native_tls_conn {
820819
mod rustls_tls_conn {
821820
use hyper::client::connect::{Connected, Connection};
822821
use pin_project_lite::pin_project;
823-
use rustls::Session;
824822
use std::{
825823
io::{self, IoSlice},
826824
pin::Pin,
@@ -837,7 +835,7 @@ mod rustls_tls_conn {
837835

838836
impl<T: Connection + AsyncRead + AsyncWrite + Unpin> Connection for RustlsTlsConn<T> {
839837
fn connected(&self) -> Connected {
840-
if self.inner.get_ref().1.get_alpn_protocol() == Some(b"h2") {
838+
if self.inner.get_ref().1.alpn_protocol() == Some(b"h2") {
841839
self.inner.get_ref().0.connected().negotiated_h2()
842840
} else {
843841
self.inner.get_ref().0.connected()

0 commit comments

Comments
 (0)