diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 716aa1785..6185f6828 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -32,8 +32,8 @@ transport = [ "tower-balance", "tower-load", ] -openssl = ["openssl1", "tokio-openssl", "tls"] -rustls = ["tokio-rustls", "tls"] +openssl = ["openssl1", "tokio-openssl", "openssl-probe", "tls"] +rustls = ["tokio-rustls", "tls", "webpki-roots"] tls = [] [[bench]] @@ -73,9 +73,11 @@ tower-load = { version = "=0.3.0-alpha.2", optional = true } # openssl tokio-openssl = { version = "=0.4.0-alpha.6", optional = true } openssl1 = { package = "openssl", version = "0.10", optional = true } +openssl-probe = { version = "0.1", optional = true } # rustls tokio-rustls = { version = "=0.12.0-alpha.5", optional = true } +webpki-roots = { version = "0.18", optional = true } [dev-dependencies] static_assertions = "1.0" diff --git a/tonic/src/transport/endpoint.rs b/tonic/src/transport/endpoint.rs index 8a5ed4b37..b5dffd108 100644 --- a/tonic/src/transport/endpoint.rs +++ b/tonic/src/transport/endpoint.rs @@ -213,6 +213,7 @@ pub struct ClientTlsConfig { domain: Option, cert: Option, identity: Option, + add_trust_anchors: bool, #[cfg(feature = "openssl")] openssl_raw: Option, #[cfg(feature = "rustls")] @@ -251,6 +252,7 @@ impl ClientTlsConfig { domain: None, cert: None, identity: None, + add_trust_anchors: false, #[cfg(feature = "openssl")] openssl_raw: None, #[cfg(feature = "rustls")] @@ -259,18 +261,40 @@ impl ClientTlsConfig { } /// Sets the domain name against which to verify the server's TLS certificate. + /// + /// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure + /// Rustls or OpenSSL respectively. pub fn domain_name(&mut self, domain_name: impl Into) -> &mut Self { self.domain = Some(domain_name.into()); self } + /// Specifies that trust anchors for server certificate validation should be added to the + /// TLS configuration. The actual behavior varies based on the selected TLS library: + /// + /// - OpenSSL: `openssl-probe` is used to locate the system root certificates. + /// - Rustls: `webpki_roots` are used to add the Mozilla trust anchors. + /// + /// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure + /// Rustls or OpenSSL respectively. + pub fn add_trust_anchors(&mut self) -> &mut Self { + self.add_trust_anchors = true; + self + } + /// Sets the CA Certificate against which to verify the server's TLS certificate. + /// + /// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure + /// Rustls or OpenSSL respectively. pub fn ca_certificate(&mut self, ca_certificate: Certificate) -> &mut Self { self.cert = Some(ca_certificate); self } /// Sets the client identity to present to the server. + /// + /// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure + /// Rustls or OpenSSL respectively. pub fn identity(&mut self, identity: Identity) -> &mut Self { self.identity = Some(identity); self @@ -309,6 +333,7 @@ impl ClientTlsConfig { self.cert.clone(), self.identity.clone(), domain, + self.add_trust_anchors, ), Some(r) => TlsConnector::new_with_openssl_raw(r.clone(), domain), }, @@ -318,6 +343,7 @@ impl ClientTlsConfig { self.cert.clone(), self.identity.clone(), domain, + self.add_trust_anchors, ), Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain), }, diff --git a/tonic/src/transport/service/tls.rs b/tonic/src/transport/service/tls.rs index 2c8532be3..4c65fdb60 100644 --- a/tonic/src/transport/service/tls.rs +++ b/tonic/src/transport/service/tls.rs @@ -6,6 +6,8 @@ use openssl1::{ ssl::{select_next_proto, AlpnError, SslAcceptor, SslConnector, SslMethod, SslVerifyMode}, x509::{store::X509StoreBuilder, X509}, }; +#[cfg(feature = "openssl")] +use openssl_probe; use std::{fmt, sync::Arc}; use tokio::net::TcpStream; #[cfg(feature = "rustls")] @@ -14,6 +16,8 @@ use tokio_rustls::{ webpki::DNSNameRef, TlsAcceptor as RustlsAcceptor, TlsConnector as RustlsConnector, }; +#[cfg(feature = "rustls")] +use webpki_roots; /// h2 alpn in wire format for openssl. #[cfg(feature = "openssl")] @@ -37,6 +41,8 @@ enum TlsError { CertificateParseError, #[cfg(feature = "rustls")] PrivateKeyParseError, + #[cfg(feature = "openssl")] + TrustAnchorsConfigurationError(openssl1::error::ErrorStack), } #[derive(Clone)] @@ -59,10 +65,19 @@ impl TlsConnector { cert: Option, identity: Option, domain: String, + add_trust_anchors: bool, ) -> Result { let mut config = SslConnector::builder(SslMethod::tls())?; config.set_alpn_protos(ALPN_H2_WIRE)?; + if add_trust_anchors { + openssl_probe::init_ssl_cert_env_vars(); + match config.cert_store_mut().set_default_paths() { + Ok(()) => (), + Err(e) => return Err(TlsError::TrustAnchorsConfigurationError(e)), + }; + } + if let Some(cert) = cert { let ca = X509::from_pem(&cert.pem[..])?; config.cert_store_mut().add_cert(ca)?; @@ -97,6 +112,7 @@ impl TlsConnector { ca_cert: Option, identity: Option, domain: String, + add_trust_anchors: bool, ) -> Result { let mut config = ClientConfig::new(); config.set_protocols(&[Vec::from(&ALPN_H2[..])]); @@ -106,6 +122,12 @@ impl TlsConnector { config.set_single_client_cert(client_cert, client_key); } + if add_trust_anchors { + config + .root_store + .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + } + if let Some(cert) = ca_cert { let mut buf = std::io::Cursor::new(&cert.pem[..]); config.root_store.add_pem_file(&mut buf).unwrap();