fix(transport): Remove support for OpenSSL (#141)
BREAKING CHANGE: Remove support for OpenSSL within the transport.
This commit is contained in:
committed by
Lucio Franco
parent
c63c107560
commit
85060500f3
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user