Skip to content

Commit ac0e333

Browse files
jen20LucioFranco
authored andcommitted
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.
1 parent b02b4b2 commit ac0e333

File tree

4 files changed

+43
-0
lines changed

4 files changed

+43
-0
lines changed

tonic/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ transport = [
3434
]
3535
openssl = ["openssl1", "tokio-openssl", "tls"]
3636
rustls = ["tokio-rustls", "tls"]
37+
openssl-roots = ["openssl-probe"]
38+
rustls-roots = ["rustls-native-certs"]
3739
tls = []
3840

3941
[[bench]]
@@ -73,9 +75,11 @@ tower-load = { version = "=0.3.0-alpha.2", optional = true }
7375
# openssl
7476
tokio-openssl = { version = "=0.4.0-alpha.6", optional = true }
7577
openssl1 = { package = "openssl", version = "0.10", optional = true }
78+
openssl-probe = { version = "0.1", optional = true }
7679

7780
# rustls
7881
tokio-rustls = { version = "=0.12.0-alpha.5", optional = true }
82+
rustls-native-certs = { version = "0.1", optional = true }
7983

8084
[dev-dependencies]
8185
static_assertions = "1.0"

tonic/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@
2222
//! for [`tonic-build`]. Enabled by default.
2323
//! - `openssl`: Enables the `openssl` based tls options for the `transport` feature`. Not
2424
//! enabled by default.
25+
//! - `openssl-roots`: Adds system trust roots to `openssl`-based gRPC clients using the
26+
//! `openssl-probe` crate. Not enabled by default. `openssl` must be enabled to use
27+
//! `openssl-roots`.
2528
//! - `rustls`: Enables the `ruslts` based tls options for the `transport` feature`. Not
2629
//! enabled by default.
30+
//! - `rustls-roots`: Adds system trust roots to `rustls`-based gRPC clients using the
31+
//! `rustls-native-certs` crate. Not enabled by default. `rustls` must be enabled to use
32+
//! `openssl-roots`.
2733
//! - `prost`: Enables the [`prost`] based gRPC [`Codec`] implementation.
2834
//!
2935
//! # Structure

tonic/src/transport/endpoint.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,27 @@ impl ClientTlsConfig {
259259
}
260260

261261
/// Sets the domain name against which to verify the server's TLS certificate.
262+
///
263+
/// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure
264+
/// Rustls or OpenSSL respectively.
262265
pub fn domain_name(&mut self, domain_name: impl Into<String>) -> &mut Self {
263266
self.domain = Some(domain_name.into());
264267
self
265268
}
266269

267270
/// Sets the CA Certificate against which to verify the server's TLS certificate.
271+
///
272+
/// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure
273+
/// Rustls or OpenSSL respectively.
268274
pub fn ca_certificate(&mut self, ca_certificate: Certificate) -> &mut Self {
269275
self.cert = Some(ca_certificate);
270276
self
271277
}
272278

273279
/// Sets the client identity to present to the server.
280+
///
281+
/// This has no effect if `rustls_client_config` or `openssl_connector` is used to configure
282+
/// Rustls or OpenSSL respectively.
274283
pub fn identity(&mut self, identity: Identity) -> &mut Self {
275284
self.identity = Some(identity);
276285
self

tonic/src/transport/service/tls.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ use openssl1::{
66
ssl::{select_next_proto, AlpnError, SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
77
x509::{store::X509StoreBuilder, X509},
88
};
9+
#[cfg(feature = "openssl-roots")]
10+
use openssl_probe;
11+
#[cfg(feature = "rustls-roots")]
12+
use rustls_native_certs;
913
use std::{fmt, sync::Arc};
1014
use tokio::net::TcpStream;
1115
#[cfg(feature = "rustls")]
@@ -37,6 +41,8 @@ enum TlsError {
3741
CertificateParseError,
3842
#[cfg(feature = "rustls")]
3943
PrivateKeyParseError,
44+
#[cfg(feature = "openssl-roots")]
45+
TrustAnchorsConfigurationError(openssl1::error::ErrorStack),
4046
}
4147

4248
#[derive(Clone)]
@@ -63,6 +69,15 @@ impl TlsConnector {
6369
let mut config = SslConnector::builder(SslMethod::tls())?;
6470
config.set_alpn_protos(ALPN_H2_WIRE)?;
6571

72+
#[cfg(feature = "openssl-roots")]
73+
{
74+
openssl_probe::init_ssl_cert_env_vars();
75+
match config.cert_store_mut().set_default_paths() {
76+
Ok(()) => (),
77+
Err(e) => return Err(Box::new(TlsError::TrustAnchorsConfigurationError(e))),
78+
};
79+
}
80+
6681
if let Some(cert) = cert {
6782
let ca = X509::from_pem(&cert.pem[..])?;
6883
config.cert_store_mut().add_cert(ca)?;
@@ -106,6 +121,11 @@ impl TlsConnector {
106121
config.set_single_client_cert(client_cert, client_key);
107122
}
108123

124+
#[cfg(feature = "rustls-roots")]
125+
{
126+
config.root_store = rustls_native_certs::load_native_certs()?;
127+
}
128+
109129
if let Some(cert) = ca_cert {
110130
let mut buf = std::io::Cursor::new(&cert.pem[..]);
111131
config.root_store.add_pem_file(&mut buf).unwrap();
@@ -336,6 +356,10 @@ impl fmt::Display for TlsError {
336356
f,
337357
"Error parsing TLS private key - no RSA or PKCS8-encoded keys found."
338358
),
359+
#[cfg(feature = "openssl-roots")]
360+
TlsError::TrustAnchorsConfigurationError(stack) => {
361+
f.write_fmt(format_args!("Error adding trust anchors - {}", stack))
362+
}
339363
}
340364
}
341365
}

0 commit comments

Comments
 (0)