fix(transport): Remove support for OpenSSL (#141)

BREAKING CHANGE: Remove support for OpenSSL within the transport.
This commit is contained in:
James Nugent
2019-11-15 14:30:42 +02:00
committed by Lucio Franco
parent c63c107560
commit 85060500f3
14 changed files with 82 additions and 465 deletions
+3 -30
View File
@@ -74,12 +74,12 @@ jobs:
- name: Run tests
run: cargo test --all --all-features
interop-unix:
name: Interop Tests (Rustls & OpenSSL)
interop:
name: Interop Tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
os: [ubuntu-latest, macOS-latest, windows-latest]
rust: [stable]
env:
@@ -98,30 +98,3 @@ jobs:
- name: Run interop tests with Rustls
run: ./tonic-interop/test.sh --use_tls tls_rustls
shell: bash
- name: Run interop tests with OpenSSL
run: ./tonic-interop/test.sh --use_tls tls_openssl
shell: bash
interop-windows:
name: Interop Tests (Rustls) (Windows)
runs-on: windows-latest
strategy:
matrix:
rust: [stable]
env:
RUSTFLAGS: "-D warnings"
steps:
- uses: hecrj/setup-rust-action@master
with:
rust-version: ${{ matrix.rust }}
- name: Install rustfmt
run: rustup component add rustfmt
- uses: actions/checkout@master
- name: Run interop tests
run: ./tonic-interop/test.sh
shell: bash
- name: Run interop tests with Rustls
run: ./tonic-interop/test.sh --use_tls tls_rustls
shell: bash
+1 -2
View File
@@ -25,7 +25,7 @@ contains the tools to build clients and servers from [`protobuf`] definitions.
- Bi-directional streaming
- High performance async io
- Interoperability
- TLS backed via either [`openssl`] or [`rustls`]
- TLS backed by [`rustls`]
- Load balancing
- Custom metadata
- Authentication
@@ -97,7 +97,6 @@ terms or conditions.
[`prost`]: https://github.com/danburkert/prost
[`protobuf`]: https://developers.google.com/protocol-buffers
[`rustls`]: https://github.com/ctz/rustls
[`openssl`]: https://www.openssl.org/
[`tonic-examples`]: https://github.com/hyperium/tonic/tree/master/tonic-examples
[`tonic-interop`]: https://github.com/hyperium/tonic/tree/master/tonic-interop
[Examples]: https://github.com/hyperium/tonic/tree/master/tonic-examples
+1 -1
View File
@@ -67,7 +67,7 @@ name = "gcp-client"
path = "src/gcp/client.rs"
[dependencies]
tonic = { path = "../tonic", features = ["rustls"] }
tonic = { path = "../tonic", features = ["tls"] }
bytes = "0.4"
prost = "0.5"
+1 -6
View File
@@ -6,11 +6,6 @@ edition = "2018"
publish = false
license = "MIT"
[features]
default = ["tonic"]
tls_openssl = ["tonic", "tonic/tls", "tonic/openssl"]
tls_rustls = ["tonic", "tonic/tls", "tonic/rustls"]
[[bin]]
name = "client"
path = "src/bin/client.rs"
@@ -21,7 +16,7 @@ path = "src/bin/server.rs"
[dependencies]
tokio = "=0.2.0-alpha.6"
tonic = { path = "../tonic", optional = true }
tonic = { path = "../tonic", features = ["tls"] }
prost = "0.5"
prost-derive = "0.5"
bytes = "0.4"
+7 -27
View File
@@ -1,7 +1,6 @@
use std::time::Duration;
use structopt::{clap::arg_enum, StructOpt};
use tonic::transport::Endpoint;
#[cfg(any(feature = "tls_rustls", feature = "tls_openssl"))]
use tonic::transport::{Certificate, ClientTlsConfig};
use tonic_interop::client;
@@ -33,32 +32,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.concurrency_limit(30);
if matches.use_tls {
#[cfg(not(any(feature = "tls_rustls", feature = "tls_openssl")))]
{
panic!("No TLS library feature selected");
}
#[cfg(feature = "tls_rustls")]
{
let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let ca = Certificate::from_pem(pem);
endpoint = endpoint.tls_config(
ClientTlsConfig::with_rustls()
.ca_certificate(ca)
.domain_name("foo.test.google.fr"),
);
}
#[cfg(feature = "tls_openssl")]
{
let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let ca = Certificate::from_pem(pem);
endpoint = endpoint.tls_config(
ClientTlsConfig::with_openssl()
.ca_certificate(ca)
.domain_name("foo.test.google.fr"),
);
}
let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let ca = Certificate::from_pem(pem);
endpoint = endpoint.tls_config(
ClientTlsConfig::with_rustls()
.ca_certificate(ca)
.domain_name("foo.test.google.fr"),
);
}
let channel = endpoint.connect().await?;
+4 -22
View File
@@ -3,7 +3,6 @@ use structopt::StructOpt;
use tonic::body::BoxBody;
use tonic::client::GrpcService;
use tonic::transport::Server;
#[cfg(any(feature = "tls_rustls", feature = "tls_openssl"))]
use tonic::transport::{Identity, ServerTlsConfig};
use tonic_interop::{server, MergeTrailers};
@@ -50,28 +49,11 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
});
if matches.use_tls {
#[cfg(not(any(feature = "tls_rustls", feature = "tls_openssl")))]
{
panic!("No TLS library feature selected");
}
let cert = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
let identity = Identity::from_pem(cert, key);
#[cfg(feature = "tls_rustls")]
{
let cert = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
let identity = Identity::from_pem(cert, key);
builder = builder.tls_config(ServerTlsConfig::with_rustls().identity(identity));
}
#[cfg(feature = "tls_openssl")]
{
let cert = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
let identity = Identity::from_pem(cert, key);
builder = builder.tls_config(ServerTlsConfig::with_openssl().identity(identity));
}
builder = builder.tls_config(ServerTlsConfig::with_rustls().identity(identity));
}
let test_service = server::TestServiceServer::new(server::TestService::default());
+1 -8
View File
@@ -15,15 +15,8 @@ case "$OSTYPE" in
esac
ARG="${1:-""}"
TLS_PROVIDER="${2:-""}"
if [[ -n "${TLS_PROVIDER}" ]] ; then
FEATURES="--features ${TLS_PROVIDER}"
else
FEATURES=
fi
(cd tonic-interop && cargo build --bins ${FEATURES})
(cd tonic-interop && cargo build --bins)
SERVER="tonic-interop/bin/server_${OS}_amd64${EXT}"
+2 -10
View File
@@ -32,11 +32,8 @@ transport = [
"tower-balance",
"tower-load",
]
openssl = ["openssl1", "tokio-openssl", "tls"]
rustls = ["tokio-rustls", "tls"]
openssl-roots = ["openssl-probe"]
rustls-roots = ["rustls-native-certs"]
tls = []
tls = ["tokio-rustls"]
tls-roots = ["rustls-native-certs"]
[[bench]]
name = "bench_main"
@@ -72,11 +69,6 @@ tower-make = "=0.3.0-alpha.2a"
tower-balance = { version = "=0.3.0-alpha.2", optional = true }
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 }
rustls-native-certs = { version = "0.1", optional = true }
+6 -12
View File
@@ -20,16 +20,11 @@
//! implementation based on [`hyper`], [`tower`] and [`tokio`]. Enabled by default.
//! - `codegen`: Enables all the required exports and optional dependencies required
//! for [`tonic-build`]. Enabled by default.
//! - `openssl`: Enables the `openssl` based tls options for the `transport` feature`. Not
//! - `tls`: Enables the `ruslts` based TLS options for the `transport` feature`. Not
//! 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
//! 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
//! `rustls-roots`.
//! - `tls-roots`: Adds system trust roots to `rustls`-based gRPC clients using the
//! `rustls-native-certs` crate. Not enabled by default. `tls` must be enabled to use
//! `tls-roots`.
//! - `prost`: Enables the [`prost`] based gRPC [`Codec`] implementation.
//!
//! # Structure
@@ -48,8 +43,8 @@
//! and [`Server`]. These implementations are built on top of [`tokio`], [`hyper`] and [`tower`].
//! It also provides many of the features that the core gRPC libraries provide such as load balancing,
//! tls, timeouts, and many more. This implementation can also be used as a reference implementation
//! to build even more feature rich clients and servers. This module also provides the ability to choose
//! between [`rustls`] and [`openssl`] for the tls backend.
//! to build even more feature rich clients and servers. This module also provides the ability to
//! enable TLS using [`rustls`], via the `tls` feature flag.
//!
//! [gRPC]: https://grpc.io
//! [`tonic`]: https://github.com/hyperium/tonic
@@ -63,7 +58,6 @@
//! [`Channel`]: transport/struct.Channel.html
//! [`Server`]: transport/struct.Server.html
//! [`rustls`]: https://docs.rs/rustls
//! [`openssl`]: https://www.openssl.org
//! [`client`]: client/index.html
//! [`transport`]: transport/index.html
+9 -58
View File
@@ -2,7 +2,7 @@ use super::channel::Channel;
#[cfg(feature = "tls")]
use super::{
service::TlsConnector,
tls::{Certificate, Identity, TlsProvider},
tls::{Certificate, Identity},
};
use bytes::Bytes;
use http::uri::{InvalidUriBytes, Uri};
@@ -223,13 +223,9 @@ impl fmt::Debug for Endpoint {
#[cfg(feature = "tls")]
#[derive(Clone)]
pub struct ClientTlsConfig {
provider: TlsProvider,
domain: Option<String>,
cert: Option<Certificate>,
identity: Option<Identity>,
#[cfg(feature = "openssl")]
openssl_raw: Option<openssl1::ssl::SslConnector>,
#[cfg(feature = "rustls")]
rustls_raw: Option<tokio_rustls::rustls::ClientConfig>,
}
@@ -237,7 +233,6 @@ pub struct ClientTlsConfig {
impl fmt::Debug for ClientTlsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ClientTlsConfig")
.field("provider", &self.provider)
.field("domain", &self.domain)
.field("cert", &self.cert)
.field("identity", &self.identity)
@@ -247,35 +242,19 @@ impl fmt::Debug for ClientTlsConfig {
#[cfg(feature = "tls")]
impl ClientTlsConfig {
/// Creates a new `ClientTlsConfig` using OpenSSL.
#[cfg(feature = "openssl")]
pub fn with_openssl() -> Self {
Self::new(TlsProvider::OpenSsl)
}
/// Creates a new `ClientTlsConfig` using Rustls.
#[cfg(feature = "rustls")]
pub fn with_rustls() -> Self {
Self::new(TlsProvider::Rustls)
}
fn new(provider: TlsProvider) -> Self {
ClientTlsConfig {
provider,
domain: None,
cert: None,
identity: None,
#[cfg(feature = "openssl")]
openssl_raw: None,
#[cfg(feature = "rustls")]
rustls_raw: None,
}
}
/// 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.
/// This has no effect if `rustls_client_config` is used to configure Rustls.
pub fn domain_name(self, domain_name: impl Into<String>) -> Self {
ClientTlsConfig {
domain: Some(domain_name.into()),
@@ -285,8 +264,7 @@ impl ClientTlsConfig {
/// 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.
/// This has no effect if `rustls_client_config` is used to configure Rustls.
pub fn ca_certificate(self, ca_certificate: Certificate) -> Self {
ClientTlsConfig {
cert: Some(ca_certificate),
@@ -296,8 +274,7 @@ impl ClientTlsConfig {
/// 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.
/// This has no effect if `rustls_client_config` is used to configure Rustls.
pub fn identity(self, identity: Identity) -> Self {
ClientTlsConfig {
identity: Some(identity),
@@ -305,21 +282,9 @@ impl ClientTlsConfig {
}
}
/// Use options specified by the given `SslConnector` to configure TLS.
///
/// This overrides all other TLS options set via other means.
#[cfg(feature = "openssl")]
pub fn openssl_connector(self, connector: openssl1::ssl::SslConnector) -> Self {
ClientTlsConfig {
openssl_raw: Some(connector),
..self
}
}
/// Use options specified by the given `ClientConfig` to configure TLS.
///
/// This overrides all other TLS options set via other means.
#[cfg(feature = "rustls")]
pub fn rustls_client_config(self, config: tokio_rustls::rustls::ClientConfig) -> Self {
ClientTlsConfig {
rustls_raw: Some(config),
@@ -332,25 +297,11 @@ impl ClientTlsConfig {
None => uri.to_string(),
Some(domain) => domain.clone(),
};
match self.provider {
#[cfg(feature = "openssl")]
TlsProvider::OpenSsl => match &self.openssl_raw {
None => TlsConnector::new_with_openssl_cert(
self.cert.clone(),
self.identity.clone(),
domain,
),
Some(r) => TlsConnector::new_with_openssl_raw(r.clone(), domain),
},
#[cfg(feature = "rustls")]
TlsProvider::Rustls => match &self.rustls_raw {
None => TlsConnector::new_with_rustls_cert(
self.cert.clone(),
self.identity.clone(),
domain,
),
Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain),
},
match &self.rustls_raw {
None => {
TlsConnector::new_with_rustls_cert(self.cert.clone(), self.identity.clone(), domain)
}
Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain),
}
}
}
+4 -5
View File
@@ -1,13 +1,13 @@
//! Batteries included server and client.
//!
//! This module provides a set of batteries included, fully featured and
//! fast set of HTTP/2 server and client's. These components each provide either an
//! `openssl` or `rustls` tls backend when the respective feature flags are enabled.
//!They also provide may configurable knobs that can be used to tune how they work.
//! fast set of HTTP/2 server and client's. These components each provide a or
//! `rustls` tls backend when the respective feature flag is enabled, and
//! provides builders to configure transport behavior.
//!
//! # Features
//!
//! - TLS support via either [OpenSSL] or [rustls].
//! - TLS support via [rustls].
//! - Load balancing
//! - Timeouts
//! - Concurrency Limits
@@ -89,7 +89,6 @@
//! # }
//! ```
//!
//! [OpenSSL]: https://www.openssl.org/
//! [rustls]: https://docs.rs/rustls/0.16.0/rustls/
pub mod channel;
+9 -59
View File
@@ -2,11 +2,7 @@
use super::service::{layer_fn, BoxedIo, Or, Routes, ServiceBuilderExt};
#[cfg(feature = "tls")]
use super::{
service::TlsAcceptor,
tls::{Identity, TlsProvider},
Certificate,
};
use super::{service::TlsAcceptor, tls::Identity, Certificate};
use crate::body::BoxBody;
use futures_core::Stream;
use futures_util::{future, ready, try_future::MapErr, TryFutureExt, TryStreamExt};
@@ -332,48 +328,25 @@ impl fmt::Debug for Server {
#[cfg(feature = "tls")]
#[derive(Clone)]
pub struct ServerTlsConfig {
provider: TlsProvider,
identity: Option<Identity>,
client_ca_root: Option<Certificate>,
#[cfg(feature = "openssl")]
openssl_raw: Option<openssl1::ssl::SslAcceptor>,
#[cfg(feature = "rustls")]
rustls_raw: Option<tokio_rustls::rustls::ServerConfig>,
}
#[cfg(feature = "tls")]
impl fmt::Debug for ServerTlsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ServerTlsConfig")
.field("provider", &self.provider)
.finish()
f.debug_struct("ServerTlsConfig").finish()
}
}
#[cfg(feature = "tls")]
impl ServerTlsConfig {
/// Creates a new `ServerTlsConfig` using OpenSSL.
#[cfg(feature = "openssl")]
pub fn with_openssl() -> Self {
Self::new(TlsProvider::OpenSsl)
}
/// Creates a new `ServerTlsConfig` using Rustls.
#[cfg(feature = "rustls")]
/// Creates a new `ServerTlsConfig`.
pub fn with_rustls() -> Self {
Self::new(TlsProvider::Rustls)
}
/// Creates a new `ServerTlsConfig` backed by the specified provider. Enable the `openssl` or
/// `rustls` features of the `tonic` crate to use OpenSSL or Rustls respectively.
fn new(provider: TlsProvider) -> Self {
ServerTlsConfig {
provider,
identity: None,
client_ca_root: None,
#[cfg(feature = "openssl")]
openssl_raw: None,
#[cfg(feature = "rustls")]
rustls_raw: None,
}
}
@@ -394,21 +367,9 @@ impl ServerTlsConfig {
}
}
/// Use options specified by the given `SslAcceptor` to configure TLS.
///
/// This overrides all other TLS options set via other means.
#[cfg(feature = "openssl")]
pub fn openssl_connector(self, acceptor: openssl1::ssl::SslAcceptor) -> Self {
ServerTlsConfig {
openssl_raw: Some(acceptor),
..self
}
}
/// Use options specified by the given `ServerConfig` to configure TLS.
///
/// This overrides all other TLS options set via other means.
#[cfg(feature = "rustls")]
pub fn rustls_server_config(
&mut self,
config: tokio_rustls::rustls::ServerConfig,
@@ -418,23 +379,12 @@ impl ServerTlsConfig {
}
fn tls_acceptor(&self) -> Result<TlsAcceptor, crate::Error> {
match self.provider {
#[cfg(feature = "openssl")]
TlsProvider::OpenSsl => match &self.openssl_raw {
None => TlsAcceptor::new_with_openssl_identity(
self.identity.clone().unwrap(),
self.client_ca_root.clone(),
),
Some(acceptor) => TlsAcceptor::new_with_openssl_raw(acceptor.clone()),
},
#[cfg(feature = "rustls")]
TlsProvider::Rustls => match &self.rustls_raw {
None => TlsAcceptor::new_with_rustls_identity(
self.identity.clone().unwrap(),
self.client_ca_root.clone(),
),
Some(config) => TlsAcceptor::new_with_rustls_raw(config.clone()),
},
match &self.rustls_raw {
None => TlsAcceptor::new_with_rustls_identity(
self.identity.clone().unwrap(),
self.client_ca_root.clone(),
),
Some(config) => TlsAcceptor::new_with_rustls_raw(config.clone()),
}
}
}
+34 -214
View File
@@ -1,29 +1,18 @@
use super::io::BoxedIo;
use crate::transport::{Certificate, Identity};
#[cfg(feature = "openssl")]
use openssl1::{
pkey::PKey,
ssl::{select_next_proto, AlpnError, SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
x509::{store::X509StoreBuilder, X509},
};
#[cfg(feature = "openssl-roots")]
use openssl_probe;
#[cfg(feature = "rustls-roots")]
#[cfg(feature = "tls-roots")]
use rustls_native_certs;
use std::{fmt, sync::Arc};
use tokio::net::TcpStream;
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
use tokio_rustls::{
rustls::{ClientConfig, NoClientAuth, ServerConfig, Session},
webpki::DNSNameRef,
TlsAcceptor as RustlsAcceptor, TlsConnector as RustlsConnector,
};
/// h2 alpn in wire format for openssl.
#[cfg(feature = "openssl")]
const ALPN_H2_WIRE: &[u8] = b"\x02h2";
/// h2 alpn in plain format for rustls.
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
const ALPN_H2: &str = "h2";
#[derive(Debug, Clone)]
@@ -37,77 +26,20 @@ pub(crate) struct Cert {
enum TlsError {
#[allow(dead_code)]
H2NotNegotiated,
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
CertificateParseError,
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
PrivateKeyParseError,
#[cfg(feature = "openssl-roots")]
TrustAnchorsConfigurationError(openssl1::error::ErrorStack),
}
#[derive(Clone)]
pub(crate) struct TlsConnector {
inner: Connector,
config: Arc<ClientConfig>,
domain: Arc<String>,
}
#[derive(Clone)]
enum Connector {
#[cfg(feature = "openssl")]
Openssl(SslConnector),
#[cfg(feature = "rustls")]
Rustls(Arc<ClientConfig>),
}
impl TlsConnector {
#[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl_cert(
cert: Option<Certificate>,
identity: Option<Identity>,
domain: String,
) -> Result<Self, crate::Error> {
let mut config = SslConnector::builder(SslMethod::tls())?;
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 {
let ca = X509::from_pem(&cert.pem[..])?;
config.cert_store_mut().add_cert(ca)?;
}
if let Some(identity) = identity {
let key = PKey::private_key_from_pem(&identity.key[..])?;
let cert = X509::from_pem(&identity.cert.pem[..])?;
config.set_certificate(&cert)?;
config.set_private_key(&key)?;
}
Ok(Self {
inner: Connector::Openssl(config.build()),
domain: Arc::new(domain),
})
}
#[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl_raw(
ssl_connector: openssl1::ssl::SslConnector,
domain: String,
) -> Result<Self, crate::Error> {
Ok(Self {
inner: Connector::Openssl(ssl_connector),
domain: Arc::new(domain),
})
}
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
pub(crate) fn new_with_rustls_cert(
ca_cert: Option<Certificate>,
identity: Option<Identity>,
@@ -121,7 +53,7 @@ impl TlsConnector {
config.set_single_client_cert(client_cert, client_key);
}
#[cfg(feature = "rustls-roots")]
#[cfg(feature = "tls-roots")]
{
config.root_store = rustls_native_certs::load_native_certs()?;
}
@@ -132,58 +64,38 @@ impl TlsConnector {
}
Ok(Self {
inner: Connector::Rustls(Arc::new(config)),
config: Arc::new(config),
domain: Arc::new(domain),
})
}
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
pub(crate) fn new_with_rustls_raw(
config: tokio_rustls::rustls::ClientConfig,
domain: String,
) -> Result<Self, crate::Error> {
Ok(Self {
inner: Connector::Rustls(Arc::new(config)),
config: Arc::new(config),
domain: Arc::new(domain),
})
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<BoxedIo, crate::Error> {
let tls_io = match &self.inner {
#[cfg(feature = "openssl")]
Connector::Openssl(connector) => {
let config = connector.configure()?;
let tls = tokio_openssl::connect(config, &self.domain, io).await?;
let tls_io = {
let dns = DNSNameRef::try_from_ascii_str(self.domain.as_str())?.to_owned();
match tls.ssl().selected_alpn_protocol() {
Some(b) if b == b"h2" => tracing::trace!("HTTP/2 succesfully negotiated."),
_ => return Err(TlsError::H2NotNegotiated.into()),
};
let io = RustlsConnector::from(self.config.clone())
.connect(dns.as_ref(), io)
.await?;
BoxedIo::new(tls)
}
#[cfg(feature = "rustls")]
Connector::Rustls(config) => {
let dns = DNSNameRef::try_from_ascii_str(self.domain.as_str())
.unwrap()
.to_owned();
let (_, session) = io.get_ref();
let io = RustlsConnector::from(config.clone())
.connect(dns.as_ref(), io)
.await?;
match session.get_alpn_protocol() {
Some(b) if b == b"h2" => (),
_ => return Err(TlsError::H2NotNegotiated.into()),
};
let (_, session) = io.get_ref();
match session.get_alpn_protocol() {
Some(b) if b == b"h2" => (),
_ => return Err(TlsError::H2NotNegotiated.into()),
};
BoxedIo::new(io)
}
#[allow(unreachable_patterns)]
_ => unreachable!("Reached a tls config point with neither feature enabled!"),
BoxedIo::new(io)
};
Ok(tls_io)
@@ -192,79 +104,17 @@ impl TlsConnector {
impl fmt::Debug for TlsConnector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TlsConnector")
.field(
"inner",
match &self.inner {
#[cfg(feature = "openssl")]
Connector::Openssl(_) => &"Openssl",
#[cfg(feature = "rustls")]
Connector::Rustls(_) => &"Rustls",
#[allow(unreachable_patterns)]
_ => &"None",
},
)
.finish()
f.debug_struct("TlsConnector").finish()
}
}
#[derive(Clone)]
pub(crate) struct TlsAcceptor {
inner: Acceptor,
}
#[derive(Clone)]
enum Acceptor {
#[cfg(feature = "openssl")]
Openssl(SslAcceptor),
#[cfg(feature = "rustls")]
Rustls(Arc<ServerConfig>),
inner: Arc<ServerConfig>,
}
impl TlsAcceptor {
#[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl_identity(
identity: Identity,
client_ca_root: Option<Certificate>,
) -> Result<Self, crate::Error> {
let key = PKey::private_key_from_pem(&identity.key[..])?;
let cert = X509::from_pem(&identity.cert.pem[..])?;
let mut config = SslAcceptor::mozilla_modern(SslMethod::tls())?;
config.set_private_key(&key)?;
config.set_certificate(&cert)?;
config.set_alpn_protos(ALPN_H2_WIRE)?;
config.set_alpn_select_callback(|_ssl, alpn| {
select_next_proto(ALPN_H2_WIRE, alpn).ok_or(AlpnError::NOACK)
});
if let Some(cert) = client_ca_root {
let ca_cert = X509::from_pem(&cert.pem[..])?;
let mut store = X509StoreBuilder::new()?;
store.add_cert(ca_cert.clone())?;
config.add_client_ca(&ca_cert)?;
config.set_verify_cert_store(store.build())?;
config.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT);
}
Ok(Self {
inner: Acceptor::Openssl(config.build()),
})
}
#[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl_raw(
acceptor: openssl1::ssl::SslAcceptor,
) -> Result<Self, crate::Error> {
Ok(Self {
inner: Acceptor::Openssl(acceptor),
})
}
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
pub(crate) fn new_with_rustls_identity(
identity: Identity,
client_ca_root: Option<Certificate>,
@@ -291,36 +141,24 @@ impl TlsAcceptor {
config.set_protocols(&[Vec::from(&ALPN_H2[..])]);
Ok(Self {
inner: Acceptor::Rustls(Arc::new(config)),
inner: Arc::new(config),
})
}
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
pub(crate) fn new_with_rustls_raw(
config: tokio_rustls::rustls::ServerConfig,
) -> Result<Self, crate::Error> {
Ok(Self {
inner: Acceptor::Rustls(Arc::new(config)),
inner: Arc::new(config),
})
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<BoxedIo, crate::Error> {
let io = match &self.inner {
#[cfg(feature = "openssl")]
Acceptor::Openssl(acceptor) => {
let tls = tokio_openssl::accept(&acceptor, io).await?;
BoxedIo::new(tls)
}
#[cfg(feature = "rustls")]
Acceptor::Rustls(config) => {
let acceptor = RustlsAcceptor::from(config.clone());
let tls = acceptor.accept(io).await?;
BoxedIo::new(tls)
}
#[allow(unreachable_patterns)]
_ => unreachable!("Reached a tls config point with neither feature enabled!"),
let io = {
let acceptor = RustlsAcceptor::from(self.inner.clone());
let tls = acceptor.accept(io).await?;
BoxedIo::new(tls)
};
Ok(io)
@@ -329,19 +167,7 @@ impl TlsAcceptor {
impl fmt::Debug for TlsAcceptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TlsAcceptor")
.field(
"inner",
match &self.inner {
#[cfg(feature = "openssl")]
Acceptor::Openssl(_) => &"Openssl",
#[cfg(feature = "rustls")]
Acceptor::Rustls(_) => &"Rustls",
#[allow(unreachable_patterns)]
_ => &"None",
},
)
.finish()
f.debug_struct("TlsAcceptor").finish()
}
}
@@ -349,24 +175,18 @@ impl fmt::Display for TlsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TlsError::H2NotNegotiated => write!(f, "HTTP/2 was not negotiated."),
#[cfg(feature = "rustls")]
TlsError::CertificateParseError => write!(f, "Error parsing TLS certificate."),
#[cfg(feature = "rustls")]
TlsError::PrivateKeyParseError => write!(
f,
"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))
}
}
}
}
impl std::error::Error for TlsError {}
#[cfg(feature = "rustls")]
#[cfg(feature = "tls")]
mod rustls_keys {
use tokio_rustls::rustls::{internal::pemfile, Certificate, PrivateKey};
-11
View File
@@ -1,14 +1,3 @@
/// Selects a library to provide TLS.
#[derive(Clone, Debug)]
pub(crate) enum TlsProvider {
/// Use OpenSSL for TLS.
#[cfg(feature = "openssl")]
OpenSsl,
/// Use OpenSSL for TLS.
#[cfg(feature = "rustls")]
Rustls,
}
/// Represents a X509 certificate.
#[derive(Debug, Clone)]
pub struct Certificate {