Skip to content

Commit 29493f0

Browse files
committed
Updates for released versions of rustls 0.20 and rustls-native-certs 0.6
Convenience functions for rustls client configuration are now in a ConfigBuilderExt trait extending rustls::ConfigBuilder. Disables sct validation with certificate transparency logs, which can't be enabled (in a way that would be as compatible as chromium) without a bunch of intrusive policies to deal with validity/expiration. Parts of ConfigBuilderExt::with_native_roots come from rustls::RootCertStore::add_parsable_certificates, which cannot be used directly due to a newtype in rustls-native-certs.
1 parent 946e0ac commit 29493f0

File tree

7 files changed

+89
-75
lines changed

7 files changed

+89
-75
lines changed

Cargo.toml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,32 @@ repository = "https://github.com/ctz/hyper-rustls"
1111

1212
[dependencies]
1313
log = "0.4.4"
14-
ct-logs = { version = "^0.9", optional = true }
1514
hyper = { version = "0.14", default-features = false, features = ["client", "http1"] }
16-
rustls = { git = "https://github.com/ctz/rustls" }
17-
rustls-native-certs = { git = "https://github.com/djc/rustls-native-certs", rev = "6116ef59f5825b0ec74a38807635a70433d68c27", optional = true }
18-
rustls-pemfile = { version = "0.2.1" }
15+
rustls = "0.20"
16+
rustls-native-certs = { version = "0.6", optional = true }
1917
tokio = "1.0"
20-
tokio-rustls = { version = "0.23", git = "https://github.com/tokio-rs/tls", rev = "b433932bf1025960e5b99f353cf8eee4ce2f08f3" }
21-
webpki = "0.22.0"
18+
tokio-rustls = "0.23"
2219
webpki-roots = { version = "0.22", optional = true }
2320

2421
[dev-dependencies]
2522
async-stream = "0.3.0"
2623
tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] }
2724
hyper = { version = "0.14", features = ["full"] }
2825
futures-util = { version = "0.3.1", default-features = false }
26+
rustls-pemfile = "0.2.1"
2927

3028
[features]
3129
default = ["native-tokio", "http1"]
3230
http1 = ["hyper/http1"]
3331
http2 = ["hyper/http2"]
3432
webpki-tokio = ["tokio-runtime", "webpki-roots"]
3533
native-tokio = ["tokio-runtime", "rustls-native-certs"]
36-
tokio-runtime = ["hyper/runtime", "ct-logs"]
34+
tokio-runtime = ["hyper/runtime"]
3735

3836
[[example]]
3937
name = "client"
4038
path = "examples/client.rs"
41-
required-features = ["native-tokio", "tokio-runtime"]
39+
required-features = ["native-tokio", "http1"]
4240

4341
[[example]]
4442
name = "server"
@@ -48,6 +46,3 @@ required-features = ["tokio-runtime"]
4846
[package.metadata.docs.rs]
4947
all-features = true
5048
rustdoc-args = ["--cfg", "docsrs"]
51-
52-
[patch."crates-io"]
53-
rustls = { git = "https://github.com/ctz/rustls" }

examples/client.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! First parameter is the mandatory URL to GET.
44
//! Second parameter is an optional path to CA store.
55
use hyper::{body::to_bytes, client, Body, Uri};
6+
use hyper_rustls::ConfigBuilderExt;
67
use rustls::RootCertStore;
78

89
use std::str::FromStr;
@@ -42,29 +43,32 @@ async fn run_client() -> io::Result<()> {
4243
None => None,
4344
};
4445

45-
// Prepare the HTTPS connector.
46-
let https = match ca {
46+
// Prepare the TLS client config
47+
let tls = match ca {
4748
Some(ref mut rd) => {
48-
// Build an HTTP connector which supports HTTPS too.
49-
let mut http = client::HttpConnector::new();
50-
http.enforce_http(false);
5149
// Read trust roots
5250
let certs = rustls_pemfile::certs(rd)
5351
.map_err(|_| error("failed to load custom CA store".into()))?;
5452
let mut roots = RootCertStore::empty();
5553
roots.add_parsable_certificates(&certs);
5654
// Build a TLS client, using the custom CA store for lookups.
57-
let tls = rustls::ClientConfig::builder()
55+
rustls::ClientConfig::builder()
5856
.with_safe_defaults()
59-
.with_root_certificates(roots, &ct_logs::LOGS)
60-
.with_no_client_auth();
61-
// Join the above part into an HTTPS connector.
62-
hyper_rustls::HttpsConnector::from((http, tls))
57+
.with_root_certificates(roots)
58+
.with_no_client_auth()
6359
}
64-
// Default HTTPS connector.
65-
None => hyper_rustls::HttpsConnector::with_native_roots(),
60+
None => rustls::ClientConfig::builder()
61+
.with_safe_defaults()
62+
.with_native_roots(),
6663
};
6764

65+
// Build an HTTP connector which supports HTTPS too.
66+
let mut http = client::HttpConnector::new();
67+
http.enforce_http(false);
68+
69+
// Join the above parts into an HTTPS connector.
70+
let https = hyper_rustls::HttpsConnector::from((http, tls));
71+
6872
// Build the hyper client from the HTTPS connector.
6973
let client: client::Client<_, hyper::Body> = client::Client::builder().build(https);
7074

examples/server.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//! Certificate and private key are hardcoded to sample files.
55
//! hyper will automatically use HTTP/2 if a client starts talking HTTP/2,
66
//! otherwise HTTP/1.1 will be used.
7-
use std::pin::Pin;
87
use std::{env, fs, io, sync};
98

109
use async_stream::stream;

src/config.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use rustls::{ClientConfig, ConfigBuilder, WantsVerifier};
2+
3+
/// Methods for configuring roots
4+
///
5+
/// This adds methods (gated by crate features) for easily configuring
6+
/// TLS server roots a rustls ClientConfig will trust.
7+
pub trait ConfigBuilderExt {
8+
/// This configures the platform's trusted certs, as implemented by
9+
/// rustls-native-certs
10+
#[cfg(feature = "rustls-native-certs")]
11+
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
12+
fn with_native_roots(self) -> ClientConfig;
13+
14+
/// This configures the webpki roots, which are Mozilla's set of
15+
/// trusted roots as packaged by webpki-roots.
16+
#[cfg(feature = "webpki-roots")]
17+
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
18+
fn with_webpki_roots(self) -> ClientConfig;
19+
}
20+
21+
impl ConfigBuilderExt for ConfigBuilder<ClientConfig, WantsVerifier> {
22+
#[cfg(feature = "rustls-native-certs")]
23+
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
24+
fn with_native_roots(self) -> ClientConfig {
25+
let mut roots = rustls::RootCertStore::empty();
26+
let mut valid_count = 0;
27+
let mut invalid_count = 0;
28+
29+
for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs")
30+
{
31+
let cert = rustls::Certificate(cert.0);
32+
match roots.add(&cert) {
33+
Ok(_) => valid_count += 1,
34+
Err(err) => {
35+
log::trace!("invalid cert der {:?}", cert.0);
36+
log::debug!("certificate parsing failed: {:?}", err);
37+
invalid_count += 1
38+
}
39+
}
40+
}
41+
log::debug!(
42+
"with_native_roots processed {} valid and {} invalid certs",
43+
valid_count, invalid_count
44+
);
45+
assert!(!roots.is_empty(), "no CA certificates found");
46+
47+
self.with_root_certificates(roots).with_no_client_auth()
48+
}
49+
50+
#[cfg(feature = "webpki-roots")]
51+
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
52+
fn with_webpki_roots(self) -> ClientConfig {
53+
let mut roots = rustls::RootCertStore::empty();
54+
roots.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
55+
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
56+
ta.subject,
57+
ta.spki,
58+
ta.name_constraints,
59+
)
60+
}));
61+
self.with_root_certificates(roots).with_no_client_auth()
62+
}
63+
}

src/connector.rs

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
use std::convert::TryFrom;
12
use std::future::Future;
23
use std::pin::Pin;
34
use std::sync::Arc;
45
use std::task::{Context, Poll};
56
use std::{fmt, io};
6-
use std::convert::TryFrom;
77

88
#[cfg(feature = "tokio-runtime")]
99
use hyper::client::connect::HttpConnector;
1010
use hyper::{client::connect::Connection, service::Service, Uri};
11-
use rustls::{ClientConfig, RootCertStore};
11+
use rustls::ClientConfig;
1212
use tokio::io::{AsyncRead, AsyncWrite};
1313
use tokio_rustls::TlsConnector;
1414

@@ -29,60 +29,12 @@ pub struct HttpsConnector<T> {
2929
feature = "tokio-runtime"
3030
))]
3131
impl HttpsConnector<HttpConnector> {
32-
/// Construct a new `HttpsConnector` using the OS root store
33-
#[cfg(feature = "rustls-native-certs")]
34-
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
35-
pub fn with_native_roots() -> Self {
36-
let certs = match rustls_native_certs::load_native_certs() {
37-
Ok(certs) => certs,
38-
Err(err) => Err(err).expect("cannot access native cert store"),
39-
};
40-
41-
if certs.is_empty() {
42-
panic!("no CA certificates found");
43-
}
44-
45-
let mut roots = RootCertStore::empty();
46-
for cert in certs {
47-
roots.add_parsable_certificates(&[cert.0]);
48-
}
49-
50-
Self::build(roots)
51-
}
52-
53-
/// Construct a new `HttpsConnector` using the `webpki_roots`
54-
#[cfg(feature = "webpki-roots")]
55-
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
56-
pub fn with_webpki_roots() -> Self {
57-
let mut roots = rustls::RootCertStore::empty();
58-
roots.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0);
59-
Self::build(roots)
60-
}
61-
6232
/// Force the use of HTTPS when connecting.
6333
///
6434
/// If a URL is not `https` when connecting, an error is returned. Disabled by default.
6535
pub fn https_only(&mut self, enable: bool) {
6636
self.force_https = enable;
6737
}
68-
69-
fn build(mut config: ClientConfig) -> Self {
70-
let mut http = HttpConnector::new();
71-
http.enforce_http(false);
72-
73-
config.alpn_protocols.clear();
74-
#[cfg(feature = "http2")]
75-
{
76-
config.alpn_protocols.push(b"h2".to_vec());
77-
}
78-
79-
#[cfg(feature = "http1")]
80-
{
81-
config.alpn_protocols.push(b"http/1.1".to_vec());
82-
}
83-
84-
(http, config).into()
85-
}
8638
}
8739

8840
impl<T> fmt::Debug for HttpsConnector<T> {

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
2525
#![cfg_attr(docsrs, feature(doc_cfg))]
2626

27+
mod config;
2728
mod connector;
2829
mod stream;
2930

31+
pub use crate::config::ConfigBuilderExt;
3032
pub use crate::connector::HttpsConnector;
3133
pub use crate::stream::MaybeHttpsStream;

src/stream.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use hyper::client::connect::{Connected, Connection};
88

99
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
1010
use tokio_rustls::client::TlsStream;
11-
use tokio_rustls::rustls::{Connection as _};
1211

1312
/// A stream that might be protected with TLS.
1413
pub enum MaybeHttpsStream<T> {

0 commit comments

Comments
 (0)