feat(transport): Add system root anchors for TLS (#114)
As per #101, it is sometimes desirable to use standard web PKI roots for gRPC clients. This commit adds a method to ClientTlsConfig to add the trust roots from the system certificate store: - OpenSSL uses `openssl-probe` to search the system for roots. - Rustls uses `rustls-native-certs` to load the system roots. Enabling the `openssl-roots` or `rustls-roots` feature for `tonic` in `Cargo.toml` will add system roots by default when configuring a gRPC client.
This commit is contained in:
committed by
Lucio Franco
parent
b02b4b238b
commit
ac0e333b39
@@ -34,6 +34,8 @@ transport = [
|
|||||||
]
|
]
|
||||||
openssl = ["openssl1", "tokio-openssl", "tls"]
|
openssl = ["openssl1", "tokio-openssl", "tls"]
|
||||||
rustls = ["tokio-rustls", "tls"]
|
rustls = ["tokio-rustls", "tls"]
|
||||||
|
openssl-roots = ["openssl-probe"]
|
||||||
|
rustls-roots = ["rustls-native-certs"]
|
||||||
tls = []
|
tls = []
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
@@ -73,9 +75,11 @@ tower-load = { version = "=0.3.0-alpha.2", optional = true }
|
|||||||
# openssl
|
# openssl
|
||||||
tokio-openssl = { version = "=0.4.0-alpha.6", optional = true }
|
tokio-openssl = { version = "=0.4.0-alpha.6", optional = true }
|
||||||
openssl1 = { package = "openssl", version = "0.10", optional = true }
|
openssl1 = { package = "openssl", version = "0.10", optional = true }
|
||||||
|
openssl-probe = { version = "0.1", optional = true }
|
||||||
|
|
||||||
# rustls
|
# rustls
|
||||||
tokio-rustls = { version = "=0.12.0-alpha.5", optional = true }
|
tokio-rustls = { version = "=0.12.0-alpha.5", optional = true }
|
||||||
|
rustls-native-certs = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
static_assertions = "1.0"
|
static_assertions = "1.0"
|
||||||
|
|||||||
@@ -22,8 +22,14 @@
|
|||||||
//! for [`tonic-build`]. Enabled by default.
|
//! for [`tonic-build`]. Enabled by default.
|
||||||
//! - `openssl`: Enables the `openssl` based tls options for the `transport` feature`. Not
|
//! - `openssl`: Enables the `openssl` based tls options for the `transport` feature`. Not
|
||||||
//! enabled by default.
|
//! enabled by default.
|
||||||
|
//! - `openssl-roots`: Adds system trust roots to `openssl`-based gRPC clients using the
|
||||||
|
//! `openssl-probe` crate. Not enabled by default. `openssl` must be enabled to use
|
||||||
|
//! `openssl-roots`.
|
||||||
//! - `rustls`: Enables the `ruslts` based tls options for the `transport` feature`. Not
|
//! - `rustls`: Enables the `ruslts` based tls options for the `transport` feature`. Not
|
||||||
//! enabled by default.
|
//! enabled by default.
|
||||||
|
//! - `rustls-roots`: Adds system trust roots to `rustls`-based gRPC clients using the
|
||||||
|
//! `rustls-native-certs` crate. Not enabled by default. `rustls` must be enabled to use
|
||||||
|
//! `openssl-roots`.
|
||||||
//! - `prost`: Enables the [`prost`] based gRPC [`Codec`] implementation.
|
//! - `prost`: Enables the [`prost`] based gRPC [`Codec`] implementation.
|
||||||
//!
|
//!
|
||||||
//! # Structure
|
//! # Structure
|
||||||
|
|||||||
@@ -259,18 +259,27 @@ impl ClientTlsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the domain name against which to verify the server's TLS certificate.
|
/// 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<String>) -> &mut Self {
|
pub fn domain_name(&mut self, domain_name: impl Into<String>) -> &mut Self {
|
||||||
self.domain = Some(domain_name.into());
|
self.domain = Some(domain_name.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the CA Certificate against which to verify the server's TLS certificate.
|
/// 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 {
|
pub fn ca_certificate(&mut self, ca_certificate: Certificate) -> &mut Self {
|
||||||
self.cert = Some(ca_certificate);
|
self.cert = Some(ca_certificate);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the client identity to present to the server.
|
/// 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 {
|
pub fn identity(&mut self, identity: Identity) -> &mut Self {
|
||||||
self.identity = Some(identity);
|
self.identity = Some(identity);
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ use openssl1::{
|
|||||||
ssl::{select_next_proto, AlpnError, SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
|
ssl::{select_next_proto, AlpnError, SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
|
||||||
x509::{store::X509StoreBuilder, X509},
|
x509::{store::X509StoreBuilder, X509},
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "openssl-roots")]
|
||||||
|
use openssl_probe;
|
||||||
|
#[cfg(feature = "rustls-roots")]
|
||||||
|
use rustls_native_certs;
|
||||||
use std::{fmt, sync::Arc};
|
use std::{fmt, sync::Arc};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
@@ -37,6 +41,8 @@ enum TlsError {
|
|||||||
CertificateParseError,
|
CertificateParseError,
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
PrivateKeyParseError,
|
PrivateKeyParseError,
|
||||||
|
#[cfg(feature = "openssl-roots")]
|
||||||
|
TrustAnchorsConfigurationError(openssl1::error::ErrorStack),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -63,6 +69,15 @@ impl TlsConnector {
|
|||||||
let mut config = SslConnector::builder(SslMethod::tls())?;
|
let mut config = SslConnector::builder(SslMethod::tls())?;
|
||||||
config.set_alpn_protos(ALPN_H2_WIRE)?;
|
config.set_alpn_protos(ALPN_H2_WIRE)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-roots")]
|
||||||
|
{
|
||||||
|
openssl_probe::init_ssl_cert_env_vars();
|
||||||
|
match config.cert_store_mut().set_default_paths() {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(e) => return Err(Box::new(TlsError::TrustAnchorsConfigurationError(e))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(cert) = cert {
|
if let Some(cert) = cert {
|
||||||
let ca = X509::from_pem(&cert.pem[..])?;
|
let ca = X509::from_pem(&cert.pem[..])?;
|
||||||
config.cert_store_mut().add_cert(ca)?;
|
config.cert_store_mut().add_cert(ca)?;
|
||||||
@@ -106,6 +121,11 @@ impl TlsConnector {
|
|||||||
config.set_single_client_cert(client_cert, client_key);
|
config.set_single_client_cert(client_cert, client_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rustls-roots")]
|
||||||
|
{
|
||||||
|
config.root_store = rustls_native_certs::load_native_certs()?;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(cert) = ca_cert {
|
if let Some(cert) = ca_cert {
|
||||||
let mut buf = std::io::Cursor::new(&cert.pem[..]);
|
let mut buf = std::io::Cursor::new(&cert.pem[..]);
|
||||||
config.root_store.add_pem_file(&mut buf).unwrap();
|
config.root_store.add_pem_file(&mut buf).unwrap();
|
||||||
@@ -336,6 +356,10 @@ impl fmt::Display for TlsError {
|
|||||||
f,
|
f,
|
||||||
"Error parsing TLS private key - no RSA or PKCS8-encoded keys found."
|
"Error parsing TLS private key - no RSA or PKCS8-encoded keys found."
|
||||||
),
|
),
|
||||||
|
#[cfg(feature = "openssl-roots")]
|
||||||
|
TlsError::TrustAnchorsConfigurationError(stack) => {
|
||||||
|
f.write_fmt(format_args!("Error adding trust anchors - {}", stack))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user