feat(transport): Expose more granular control of TLS configuration (#48)

This commit reworks TLS configuration of both servers and endpoints in
order to provide a more flexible API. We now add options to configure
the selected TLS library using the appropriate 'native' configuration
structures, as well as retaining the existing simplier interface which
is compatible with both.

The new API can also be easily extended to support simple interfaces for
configuring mTLS and a range of other options without creating sprawl
in the builders for `Server` and `Endpoint`.
This commit is contained in:
James Nugent
2019-10-08 11:49:05 -04:00
committed by Lucio Franco
parent 4628ff0258
commit 8db3961491
9 changed files with 311 additions and 132 deletions
+7 -3
View File
@@ -3,19 +3,23 @@ pub mod pb {
} }
use pb::{client::EchoClient, EchoRequest}; use pb::{client::EchoClient, EchoRequest};
use tonic::transport::{Certificate, Channel}; use tonic::transport::{Certificate, Channel, ClientTlsConfig};
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pem = tokio::fs::read("tonic-examples/data/tls/ca.pem").await?; let pem = tokio::fs::read("tonic-examples/data/tls/ca.pem").await?;
let ca = Certificate::from_pem(pem); let ca = Certificate::from_pem(pem);
let tls = ClientTlsConfig::with_rustls()
.ca_certificate(ca)
.domain_name("example.com")
.clone();
let channel = Channel::from_static("http://[::1]:50051") let channel = Channel::from_static("http://[::1]:50051")
.rustls_tls(ca, Some("example.com".into())) .tls_config(&tls)
.channel(); .channel();
let mut client = EchoClient::new(channel); let mut client = EchoClient::new(channel);
let request = tonic::Request::new(EchoRequest { let request = tonic::Request::new(EchoRequest {
message: "hello".into(), message: "hello".into(),
}); });
+2 -2
View File
@@ -5,7 +5,7 @@ pub mod pb {
use pb::{EchoRequest, EchoResponse}; use pb::{EchoRequest, EchoResponse};
use std::collections::VecDeque; use std::collections::VecDeque;
use tonic::{ use tonic::{
transport::{Identity, Server}, transport::{Identity, Server, ServerTlsConfig},
Request, Response, Status, Streaming, Request, Response, Status, Streaming,
}; };
@@ -59,7 +59,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = EchoServer::default(); let server = EchoServer::default();
Server::builder() Server::builder()
.rustls_tls(identity) .tls_config(ServerTlsConfig::with_rustls().identity(identity))
.clone() .clone()
.serve(addr, pb::server::EchoServer::new(server)) .serve(addr, pb::server::EchoServer::new(server))
.await?; .await?;
+7 -2
View File
@@ -1,6 +1,6 @@
use std::time::Duration; use std::time::Duration;
use structopt::{clap::arg_enum, StructOpt}; use structopt::{clap::arg_enum, StructOpt};
use tonic::transport::{Certificate, Endpoint}; use tonic::transport::{Certificate, ClientTlsConfig, Endpoint};
use tonic_interop::client; use tonic_interop::client;
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -33,7 +33,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
if matches.use_tls { if matches.use_tls {
let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?; let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let ca = Certificate::from_pem(pem); let ca = Certificate::from_pem(pem);
endpoint.openssl_tls(ca, Some("foo.test.google.fr".into()));
endpoint.tls_config(
ClientTlsConfig::with_openssl()
.ca_certificate(ca)
.domain_name("foo.test.google.fr"),
);
} }
let channel = endpoint.channel(); let channel = endpoint.channel();
+2 -2
View File
@@ -2,7 +2,7 @@ use http::header::HeaderName;
use structopt::StructOpt; use structopt::StructOpt;
use tonic::body::BoxBody; use tonic::body::BoxBody;
use tonic::client::GrpcService; use tonic::client::GrpcService;
use tonic::transport::{Identity, Server}; use tonic::transport::{Identity, Server, ServerTlsConfig};
use tonic_interop::{server, MergeTrailers}; use tonic_interop::{server, MergeTrailers};
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -26,7 +26,7 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let key = tokio::fs::read("tonic-interop/data/server1.key").await?; let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
let identity = Identity::from_pem(cert, key); let identity = Identity::from_pem(cert, key);
builder.openssl_tls(identity); builder.tls_config(ServerTlsConfig::with_openssl().identity(identity));
} }
builder.interceptor_fn(|svc, req| { builder.interceptor_fn(|svc, req| {
+112 -59
View File
@@ -1,6 +1,9 @@
use super::channel::Channel; use super::channel::Channel;
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
use super::{service::TlsConnector, tls::Certificate}; use super::{
service::TlsConnector,
tls::{Certificate, TlsProvider},
};
use bytes::Bytes; use bytes::Bytes;
use http::uri::{InvalidUriBytes, Uri}; use http::uri::{InvalidUriBytes, Uri};
use std::{ use std::{
@@ -122,64 +125,6 @@ impl Endpoint {
self self
} }
/// Enable TLS and apply the CA as the root certificate.
///
/// Providing an optional domain to override. If `None` is passed to this
/// the TLS implementation will use the `Uri` that was used to create the
/// `Endpoint` builder.
///
/// ```no_run
/// # use tonic::transport::{Certificate, Endpoint};
/// # fn dothing() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut builder = Endpoint::from_static("https://example.com");
/// let ca = std::fs::read_to_string("ca.pem")?;
///
/// let ca = Certificate::from_pem(ca);
///
/// builder.openssl_tls(ca, "example.com".to_string());
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "openssl")]
#[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
pub fn openssl_tls(&mut self, ca: Certificate, domain: impl Into<Option<String>>) -> &mut Self {
let domain = domain
.into()
.unwrap_or_else(|| self.uri.clone().to_string());
let tls = TlsConnector::new_with_openssl(ca, domain).unwrap();
self.tls = Some(tls);
self
}
/// Enable TLS and apply the CA as the root certificate.
///
/// Providing an optional domain to override. If `None` is passed to this
/// the TLS implementation will use the `Uri` that was used to create the
/// `Endpoint` builder.
///
/// ```no_run
/// # use tonic::transport::{Certificate, Endpoint};
/// # fn dothing() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut builder = Endpoint::from_static("https://example.com");
/// let ca = std::fs::read_to_string("ca.pem")?;
///
/// let ca = Certificate::from_pem(ca);
///
/// builder.rustls_tls(ca, "example.com".to_string());
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "rustls")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
pub fn rustls_tls(&mut self, ca: Certificate, domain: impl Into<Option<String>>) -> &mut Self {
let domain = domain
.into()
.unwrap_or_else(|| self.uri.clone().to_string());
let tls = TlsConnector::new_with_rustls(ca, domain).unwrap();
self.tls = Some(tls);
self
}
/// Intercept outbound HTTP Request headers; /// Intercept outbound HTTP Request headers;
pub fn intercept_headers<F>(&mut self, f: F) -> &mut Self pub fn intercept_headers<F>(&mut self, f: F) -> &mut Self
where where
@@ -189,6 +134,13 @@ impl Endpoint {
self self
} }
/// Configures TLS for the endpoint.
#[cfg(feature = "tls")]
pub fn tls_config(&mut self, tls_config: &ClientTlsConfig) -> &mut Self {
self.tls = Some(tls_config.tls_connector(self.uri.clone()).unwrap());
self
}
/// Create a channel from this config. /// Create a channel from this config.
pub fn channel(&self) -> Channel { pub fn channel(&self) -> Channel {
Channel::connect(self.clone()) Channel::connect(self.clone())
@@ -252,3 +204,104 @@ impl fmt::Debug for Endpoint {
f.debug_struct("Endpoint").finish() f.debug_struct("Endpoint").finish()
} }
} }
/// Configures TLS settings for endpoints.
#[cfg(feature = "tls")]
#[derive(Clone)]
pub struct ClientTlsConfig {
provider: TlsProvider,
domain: Option<String>,
cert: Option<Certificate>,
#[cfg(feature = "openssl")]
openssl_raw: Option<openssl1::ssl::SslConnector>,
#[cfg(feature = "rustls")]
rustls_raw: Option<tokio_rustls::rustls::ClientConfig>,
}
#[cfg(feature = "tls")]
impl fmt::Debug for ClientTlsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ClientTlsConfig")
.field("provider", &self.provider)
.finish()
}
}
#[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,
#[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.
pub fn domain_name(&mut self, domain_name: impl Into<String>) -> &mut Self {
self.domain = Some(domain_name.into());
self
}
/// Sets the CA Certificate against which to verify the server's TLS certificate.
pub fn ca_certificate(&mut self, ca_certificate: Certificate) -> &mut Self {
self.cert = Some(ca_certificate);
self
}
/// 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(&mut self, connector: openssl1::ssl::SslConnector) -> &mut Self {
self.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(
&mut self,
config: tokio_rustls::rustls::ClientConfig,
) -> &mut Self {
self.rustls_raw = Some(config);
self
}
fn tls_connector(&self, uri: Uri) -> Result<TlsConnector, crate::Error> {
let domain = match &self.domain {
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(), 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(), domain),
Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain),
},
}
}
}
+12 -4
View File
@@ -19,7 +19,7 @@
//! ## Client //! ## Client
//! //!
//! ```no_run //! ```no_run
//! # use tonic::transport::{Channel, Certificate}; //! # use tonic::transport::{Channel, Certificate, ClientTlsConfig};
//! # use std::time::Duration; //! # use std::time::Duration;
//! # use tonic::body::BoxBody; //! # use tonic::body::BoxBody;
//! # use tonic::client::GrpcService;; //! # use tonic::client::GrpcService;;
@@ -29,7 +29,9 @@
//! let cert = std::fs::read_to_string("ca.pem")?; //! let cert = std::fs::read_to_string("ca.pem")?;
//! //!
//! let mut channel = Channel::from_static("https://example.com") //! let mut channel = Channel::from_static("https://example.com")
//! .rustls_tls(Certificate::from_pem(&cert), "example.com".to_string()) //! .tls_config(ClientTlsConfig::with_rustls()
//! .ca_certificate(Certificate::from_pem(&cert))
//! .domain_name("example.com".to_string()))
//! .timeout(Duration::from_secs(5)) //! .timeout(Duration::from_secs(5))
//! .rate_limit(5, Duration::from_secs(1)) //! .rate_limit(5, Duration::from_secs(1))
//! .concurrency_limit(256) //! .concurrency_limit(256)
@@ -43,7 +45,7 @@
//! ## Server //! ## Server
//! //!
//! ```no_run //! ```no_run
//! # use tonic::transport::{Server, Identity}; //! # use tonic::transport::{Server, Identity, ServerTlsConfig};
//! # use tower::{Service, service_fn}; //! # use tower::{Service, service_fn};
//! # use futures_util::future::{err, ok}; //! # use futures_util::future::{err, ok};
//! # #[cfg(feature = "rustls")] //! # #[cfg(feature = "rustls")]
@@ -55,7 +57,8 @@
//! let addr = "[::1]:50051".parse()?; //! let addr = "[::1]:50051".parse()?;
//! //!
//! Server::builder() //! Server::builder()
//! .rustls_tls(Identity::from_pem(&cert, &key)) //! .tls_config(ServerTlsConfig::with_rustls()
//! .identity(Identity::from_pem(&cert, &key)))
//! .concurrency_limit_per_connection(256) //! .concurrency_limit_per_connection(256)
//! .interceptor_fn(|svc, req| { //! .interceptor_fn(|svc, req| {
//! println!("Request: {:?}", req); //! println!("Request: {:?}", req);
@@ -89,4 +92,9 @@ pub use self::server::Server;
pub use self::tls::{Certificate, Identity}; pub use self::tls::{Certificate, Identity};
pub use hyper::Body; pub use hyper::Body;
#[cfg(feature = "tls")]
pub use self::endpoint::ClientTlsConfig;
#[cfg(feature = "tls")]
pub use self::server::ServerTlsConfig;
pub(crate) use self::error::ErrorKind; pub(crate) use self::error::ErrorKind;
+99 -44
View File
@@ -2,7 +2,10 @@
use super::service::{layer_fn, BoxedIo, ServiceBuilderExt}; use super::service::{layer_fn, BoxedIo, ServiceBuilderExt};
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
use super::{service::TlsAcceptor, tls::Identity}; use super::{
service::TlsAcceptor,
tls::{Identity, TlsProvider},
};
use crate::body::BoxBody; use crate::body::BoxBody;
use futures_core::Stream; use futures_core::Stream;
use futures_util::{ready, try_future::MapErr, TryFutureExt, TryStreamExt}; use futures_util::{ready, try_future::MapErr, TryFutureExt, TryStreamExt};
@@ -62,49 +65,10 @@ impl Server {
} }
impl Server { impl Server {
/// Set the [`Identity`] of this server using `openssl`. /// Configure TLS for this server.
/// #[cfg(feature = "tls")]
/// ```no_run pub fn tls_config(&mut self, tls_config: &ServerTlsConfig) -> &mut Self {
/// # use tonic::transport::{Identity, Server}; self.tls = Some(tls_config.tls_acceptor().unwrap());
/// # fn dothing() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut builder = Server::builder();
/// let cert = std::fs::read_to_string("server.pem")?;
/// let key = std::fs::read_to_string("server.key")?;
///
/// let identity = Identity::from_pem(&cert, &key);
///
/// builder.openssl_tls(identity);
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "openssl")]
#[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
pub fn openssl_tls(&mut self, identity: Identity) -> &mut Self {
let acceptor = TlsAcceptor::new_with_openssl(identity).unwrap();
self.tls = Some(acceptor);
self
}
/// Set the [`Identity`] of this server using `rustls`.
///
/// ```no_run
/// # use tonic::transport::{Identity, Server};
/// # fn dothing() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut builder = Server::builder();
/// let cert = std::fs::read_to_string("server.pem")?;
/// let key = std::fs::read_to_string("server.key")?;
///
/// let identity = Identity::from_pem(&cert, &key);
///
/// builder.rustls_tls(identity);
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "rustls")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
pub fn rustls_tls(&mut self, identity: Identity) -> &mut Self {
let acceptor = TlsAcceptor::new_with_rustls(identity).unwrap();
self.tls = Some(acceptor);
self self
} }
@@ -255,6 +219,97 @@ impl fmt::Debug for Server {
} }
} }
/// Configures TLS settings for servers.
#[cfg(feature = "tls")]
#[derive(Clone)]
pub struct ServerTlsConfig {
provider: TlsProvider,
identity: Option<Identity>,
#[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()
}
}
#[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")]
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,
#[cfg(feature = "openssl")]
openssl_raw: None,
#[cfg(feature = "rustls")]
rustls_raw: None,
}
}
/// Sets the [`Identity`] of the server.
pub fn identity(&mut self, identity: Identity) -> &mut Self {
self.identity = Some(identity);
self
}
/// 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(&mut self, acceptor: openssl1::ssl::SslAcceptor) -> &mut Self {
self.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_client_config(
&mut self,
config: tokio_rustls::rustls::ServerConfig,
) -> &mut Self {
self.rustls_raw = Some(config);
self
}
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()),
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()),
Some(config) => TlsAcceptor::new_with_rustls_raw(config.clone()),
},
}
}
}
#[derive(Debug)] #[derive(Debug)]
struct TcpIncoming { struct TcpIncoming {
inner: conn::AddrIncoming, inner: conn::AddrIncoming,
+59 -16
View File
@@ -56,35 +56,60 @@ enum Connector {
impl TlsConnector { impl TlsConnector {
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl( pub(crate) fn new_with_openssl_cert(
cert: Certificate, cert: Option<Certificate>,
domain: String, domain: String,
) -> Result<Self, crate::Error> { ) -> Result<Self, crate::Error> {
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)?;
let ca = X509::from_pem(&cert.pem[..])?; if let Some(cert) = cert {
let ca = X509::from_pem(&cert.pem[..])?;
config.cert_store_mut().add_cert(ca)?; config.cert_store_mut().add_cert(ca)?;
}
let config = config.build();
Ok(Self { Ok(Self {
inner: Connector::Openssl(config), 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), domain: Arc::new(domain),
}) })
} }
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls(cert: Certificate, domain: String) -> Result<Self, crate::Error> { pub(crate) fn new_with_rustls_cert(
let mut buf = std::io::Cursor::new(&cert.pem[..]); cert: Option<Certificate>,
domain: String,
) -> Result<Self, crate::Error> {
let mut config = ClientConfig::new(); let mut config = ClientConfig::new();
config.root_store.add_pem_file(&mut buf).unwrap();
config.set_protocols(&[Vec::from(&ALPN_H2[..])]); config.set_protocols(&[Vec::from(&ALPN_H2[..])]);
if cert.is_some() {
let cert = cert.unwrap();
let mut buf = std::io::Cursor::new(&cert.pem[..]);
config.root_store.add_pem_file(&mut buf).unwrap();
}
Ok(Self {
inner: Connector::Rustls(Arc::new(config)),
domain: Arc::new(domain),
})
}
#[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls_raw(
config: tokio_rustls::rustls::ClientConfig,
domain: String,
) -> Result<Self, crate::Error> {
Ok(Self { Ok(Self {
inner: Connector::Rustls(Arc::new(config)), inner: Connector::Rustls(Arc::new(config)),
domain: Arc::new(domain), domain: Arc::new(domain),
@@ -167,7 +192,7 @@ enum Acceptor {
impl TlsAcceptor { impl TlsAcceptor {
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl(identity: Identity) -> Result<Self, crate::Error> { pub(crate) fn new_with_openssl_identity(identity: Identity) -> Result<Self, crate::Error> {
let key = PKey::private_key_from_pem(&identity.key[..])?; let key = PKey::private_key_from_pem(&identity.key[..])?;
let cert = X509::from_pem(&identity.cert.pem[..])?; let cert = X509::from_pem(&identity.cert.pem[..])?;
@@ -185,6 +210,15 @@ impl TlsAcceptor {
}) })
} }
#[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 = "rustls")]
fn load_rustls_private_key( fn load_rustls_private_key(
mut cursor: std::io::Cursor<&[u8]>, mut cursor: std::io::Cursor<&[u8]>,
@@ -209,7 +243,7 @@ impl TlsAcceptor {
} }
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls(identity: Identity) -> Result<Self, crate::Error> { pub(crate) fn new_with_rustls_identity(identity: Identity) -> Result<Self, crate::Error> {
let cert = { let cert = {
let mut cert = std::io::Cursor::new(&identity.cert.pem[..]); let mut cert = std::io::Cursor::new(&identity.cert.pem[..]);
match pemfile::certs(&mut cert) { match pemfile::certs(&mut cert) {
@@ -238,6 +272,15 @@ impl TlsAcceptor {
}) })
} }
#[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls_raw(
config: tokio_rustls::rustls::ServerConfig,
) -> Result<Self, crate::Error> {
Ok(Self {
inner: Acceptor::Rustls(Arc::new(config)),
})
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<BoxedIo, crate::Error> { pub(crate) async fn connect(&self, io: TcpStream) -> Result<BoxedIo, crate::Error> {
let io = match &self.inner { let io = match &self.inner {
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
+11
View File
@@ -1,3 +1,14 @@
/// 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. /// Represents a X509 certificate.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Certificate { pub struct Certificate {