diff --git a/Cargo.toml b/Cargo.toml index b0b6557e..a2557324 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" edition = "2021" rust-version = "1.70" license = "Apache-2.0 OR ISC OR MIT" @@ -10,13 +10,25 @@ homepage = "https://github.com/rustls/hyper-rustls" repository = "https://github.com/rustls/hyper-rustls" documentation = "https://docs.rs/hyper-rustls/" +[features] +default = ["native-tokio", "http1", "tls12", "logging", "aws-lc-rs"] +aws-lc-rs = ["rustls/aws_lc_rs"] +fips = ["aws-lc-rs", "rustls/fips"] +http1 = ["hyper-util/http1"] +http2 = ["hyper-util/http2"] +logging = ["log", "tokio-rustls/logging", "rustls/logging"] +native-tokio = ["rustls-native-certs"] +ring = ["rustls/ring"] +tls12 = ["tokio-rustls/tls12", "rustls/tls12"] +webpki-tokio = ["webpki-roots"] + [dependencies] http = "1" hyper = { version = "1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["client-legacy", "tokio"] } log = { version = "0.4.4", optional = true } pki-types = { package = "rustls-pki-types", version = "1" } -rustls-native-certs = { version = "0.7", optional = true } +rustls-native-certs = { version = "0.8", optional = true } rustls-platform-verifier = { version = "0.3", optional = true } rustls = { version = "0.23", default-features = false } tokio = "1.0" @@ -32,18 +44,6 @@ rustls = { version = "0.23", default-features = false, features = ["tls12"] } rustls-pemfile = "2" tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] } -[features] -default = ["native-tokio", "http1", "tls12", "logging", "aws-lc-rs"] -aws-lc-rs = ["rustls/aws_lc_rs"] -http1 = ["hyper-util/http1"] -http2 = ["hyper-util/http2"] -webpki-tokio = ["webpki-roots"] -native-tokio = ["rustls-native-certs"] -ring = ["rustls/ring"] -tls12 = ["tokio-rustls/tls12", "rustls/tls12"] -logging = ["log", "tokio-rustls/logging", "rustls/logging"] -fips = ["aws-lc-rs", "rustls/fips"] - [[example]] name = "client" path = "examples/client.rs" diff --git a/src/config.rs b/src/config.rs index 2af49c76..13de77d9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "rustls-native-certs")] +use std::io; #[cfg(feature = "rustls-platform-verifier")] use std::sync::Arc; @@ -8,6 +10,8 @@ use std::sync::Arc; ))] use rustls::client::WantsClientCert; use rustls::{ClientConfig, ConfigBuilder, WantsVerifier}; +#[cfg(feature = "rustls-native-certs")] +use rustls_native_certs::CertificateResult; /// Methods for configuring roots /// @@ -28,7 +32,7 @@ pub trait ConfigBuilderExt { /// This will return an error if no valid certs were found. In that case, /// it's recommended to use `with_webpki_roots`. #[cfg(feature = "rustls-native-certs")] - fn with_native_roots(self) -> std::io::Result>; + fn with_native_roots(self) -> Result, io::Error>; /// This configures the webpki roots, which are Mozilla's set of /// trusted roots as packaged by webpki-roots. @@ -47,13 +51,24 @@ impl ConfigBuilderExt for ConfigBuilder { #[cfg(feature = "rustls-native-certs")] #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - fn with_native_roots(self) -> std::io::Result> { + fn with_native_roots(self) -> Result, io::Error> { let mut roots = rustls::RootCertStore::empty(); let mut valid_count = 0; let mut invalid_count = 0; - for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs") - { + let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs(); + if !errors.is_empty() { + crate::log::warn!("native root CA certificate loading errors: {errors:?}"); + } + + if certs.is_empty() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!("no native root CA certificates found (errors: {errors:?})"), + )); + } + + for cert in certs { match roots.add(cert) { Ok(_) => valid_count += 1, Err(err) => { @@ -62,6 +77,7 @@ impl ConfigBuilderExt for ConfigBuilder { } } } + crate::log::debug!( "with_native_roots processed {} valid and {} invalid certs", valid_count, @@ -69,8 +85,8 @@ impl ConfigBuilderExt for ConfigBuilder { ); if roots.is_empty() { crate::log::debug!("no valid native root CA certificates found"); - Err(std::io::Error::new( - std::io::ErrorKind::NotFound, + Err(io::Error::new( + io::ErrorKind::NotFound, format!("no valid native root CA certificates found ({invalid_count} invalid)"), ))? } diff --git a/src/lib.rs b/src/lib.rs index 1920e78f..89e355ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,8 @@ mod stream; mod log { #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))] pub(crate) use log::debug; + #[cfg(feature = "rustls-native-certs")] + pub(crate) use log::warn; } #[cfg(not(feature = "logging"))] @@ -51,6 +53,10 @@ mod log { macro_rules! debug ( ($($tt:tt)*) => {{}} ); #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))] pub(crate) use debug; + #[cfg(feature = "rustls-native-certs")] + macro_rules! warn_ ( ($($tt:tt)*) => {{}} ); + #[cfg(feature = "rustls-native-certs")] + pub(crate) use warn_ as warn; } pub use crate::config::ConfigBuilderExt;