Refactor all of the tls

This commit is contained in:
Lucio Franco
2019-09-24 14:32:16 -04:00
parent ffba9ef6d2
commit 60c9629630
19 changed files with 376 additions and 322 deletions
+10 -4
View File
@@ -15,11 +15,17 @@ jobs:
- uses: actions/checkout@master
- name: Install rustfmt
run: rustup component add rustfmt
- name: Run fmt
- name: Check fmt
run: cargo fmt -- --check
- name: Run check
- name: Check all
run: cargo check --all
- name: Run check with no default features
run: cargo check --all --no-default-features
- name: Check with no default features
run: cargo check -p tonic --no-default-features
- name: Check with transport no tls
run: cargo check -p tonic
- name: Check with transport w/ openssl
run: cargo check -p tonic --features openssl
- name: Check with transport w/ rustls
run: cargo check -p tonic --features rustls
- name: Run tests
run: cargo test --all
+2 -1
View File
@@ -14,5 +14,6 @@ proc-macro2 = "1.0"
[features]
default = ["transport"]
rustfmt = []
# TODO: reenable this feature
# rustfmt = []
transport = []
+1 -1
View File
@@ -1,4 +1,4 @@
use tonic::{Request, Response, Server, Status};
use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world {
include!(concat!(env!("OUT_DIR"), "/helloworld.rs"));
+1 -1
View File
@@ -14,7 +14,7 @@ path = "src/bin/server.rs"
[dependencies]
tokio = "=0.2.0-alpha.4"
tonic = { path = "../tonic" }
tonic = { path = "../tonic", features = ["openssl"] }
prost = "0.5"
prost-derive = "0.5"
bytes = "0.4"
+4 -3
View File
@@ -1,6 +1,6 @@
use std::time::Duration;
use structopt::{clap::arg_enum, StructOpt};
use tonic::transport::Endpoint;
use tonic::transport::{Certificate, Endpoint};
use tonic_interop::client;
#[derive(StructOpt)]
@@ -31,8 +31,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.clone();
if matches.use_tls {
let ca = tokio::fs::read("tonic-interop/data/ca.pem").await?;
endpoint.tls_cert(ca, Some("foo.test.google.fr".into()));
let pem = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let ca = Certificate::from_pem(pem);
endpoint.openssl_tls(ca, Some("foo.test.google.fr".into()));
}
let channel = endpoint.channel()?;
+5 -3
View File
@@ -1,5 +1,5 @@
use structopt::StructOpt;
use tonic::Server;
use tonic::transport::{Identity, Server};
use tonic_interop::{server, MergeTrailers};
// TODO: move GrpcService out of client since it can be used for the
// server too.
@@ -24,9 +24,11 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let mut builder = Server::builder();
if matches.use_tls {
let ca = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let cert = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
builder.tls(ca, key);
let identity = Identity::from_pem(cert, key);
builder.openssl_tls(identity);
}
builder.interceptor_fn(|svc, req| {
+4 -4
View File
@@ -32,7 +32,7 @@ tower-load = { version = "=0.3.0-alpha.1", optional = true }
# openssl
tokio-openssl = { version = "=0.4.0-alpha.4", optional = true }
openssl = { version = "0.10", optional = true }
openssl1 = { package = "openssl", version = "0.10", optional = true }
# rustls
tokio-rustls = { version = "0.12.0-alpha.2", optional = true }
@@ -43,7 +43,6 @@ transport = [
"hyper",
"tower-1",
"tokio",
"native-tls",
]
tower-1 = [
"tower",
@@ -51,5 +50,6 @@ tower-1 = [
"tower-balance",
"tower-load",
]
native-tls = ["openssl", "tokio-openssl"]
# rustls = ["tokio-rustls"]
openssl = ["openssl1", "tokio-openssl", "tls"]
rustls = ["tokio-rustls", "tls"]
tls = []
-2
View File
@@ -51,8 +51,6 @@ pub use codec::Streaming;
pub use request::Request;
pub use response::Response;
pub use status::{Code, Status};
#[doc(inline)]
pub use transport::{Channel, Server};
pub(crate) type Error = Box<dyn std::error::Error + Send + Sync>;
+20 -9
View File
@@ -1,4 +1,6 @@
use super::{channel::Channel, tls::Cert};
use super::channel::Channel;
#[cfg(feature = "tls")]
use super::{service::TlsConnector, tls::Certificate};
use bytes::Bytes;
use http::uri::{InvalidUriBytes, Uri};
use std::{convert::TryFrom, time::Duration};
@@ -9,7 +11,8 @@ pub struct Endpoint {
pub(super) timeout: Option<Duration>,
pub(super) concurrency_limit: Option<usize>,
pub(super) rate_limit: Option<(u64, Duration)>,
pub(super) cert: Option<Cert>,
#[cfg(feature = "tls")]
pub(super) tls: Option<TlsConnector>,
}
impl Endpoint {
@@ -38,12 +41,19 @@ impl Endpoint {
self
}
pub fn tls_cert(&mut self, ca: Vec<u8>, domain: Option<String>) -> &mut Self {
self.cert = Some(Cert {
ca,
domain: domain.unwrap_or_else(|| self.uri.clone().to_string()),
key: None,
});
#[cfg(feature = "openssl")]
pub fn openssl_tls(&mut self, ca: Certificate, domain: Option<String>) -> &mut Self {
let domain = domain.unwrap_or_else(|| self.uri.clone().to_string());
let tls = TlsConnector::new_with_openssl(ca, domain).unwrap();
self.tls = Some(tls);
self
}
#[cfg(feature = "rustls")]
pub fn rustls_tls(&mut self, ca: Certificate, domain: Option<String>) -> &mut Self {
let domain = domain.unwrap_or_else(|| self.uri.clone().to_string());
let tls = TlsConnector::new_with_rustls(ca, domain).unwrap();
self.tls = Some(tls);
self
}
@@ -61,7 +71,8 @@ impl From<Uri> for Endpoint {
concurrency_limit: None,
rate_limit: None,
timeout: None,
cert: None,
#[cfg(feature = "tls")]
tls: None,
}
}
}
+1
View File
@@ -14,6 +14,7 @@ pub use self::channel::Channel;
pub use self::endpoint::Endpoint;
pub use self::error::Error;
pub use self::server::Server;
pub use self::tls::{Certificate, Identity};
pub use hyper::Body;
pub(crate) use self::error::ErrorKind;
+34 -38
View File
@@ -1,19 +1,18 @@
use super::{
service::{layer_fn, BoxedIo},
tls::{Cert, TlsAcceptor},
};
use super::service::{layer_fn, BoxedIo};
#[cfg(feature = "tls")]
use super::{service::TlsAcceptor, tls::Identity};
use crate::body::BoxBody;
use futures_core::Stream;
use futures_util::{ready, try_future::MapErr, TryFutureExt, TryStreamExt};
use http::{Request, Response};
use hyper::server::{accept::Accept, conn};
use hyper::Body;
use std::sync::Arc;
use std::{
fmt,
future::Future,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use tower::layer::util::Stack;
@@ -48,9 +47,10 @@ impl Server {
///
#[derive(Default)]
pub struct Builder {
tls: Option<(Vec<u8>, Vec<u8>)>,
interceptor: Option<Interceptor>,
// concurrency_limit: Option<usize>,
#[cfg(feature = "tls")]
tls: Option<TlsAcceptor>,
}
impl Builder {
@@ -59,8 +59,17 @@ impl Builder {
}
/// Add a tls cert.
pub fn tls(&mut self, pem: Vec<u8>, key: Vec<u8>) -> &mut Self {
self.tls = Some((pem, key));
#[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
}
#[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
}
@@ -94,23 +103,28 @@ impl Builder {
S::Future: Send + 'static,
S::Error: Into<crate::Error> + Send,
{
let tls = if let Some(tls) = self.tls {
let cert = Cert {
ca: tls.0,
key: Some(tls.1),
domain: String::new(),
};
let interceptor = self.interceptor.clone();
Some(TlsAcceptor::new(cert).map_err(map_err)?)
} else {
None
};
let incoming = hyper::server::accept::from_stream(async_stream::try_stream! {
let mut tcp = TcpIncoming::bind(addr)?;
let incoming = hyper::server::accept::from_stream(incoming(addr, tls));
while let Some(stream) = tcp.try_next().await? {
#[cfg(feature = "tls")]
{
if let Some(tls) = &self.tls {
let io = tls.connect(stream.into_inner()).await?;
yield BoxedIo::new(io);
continue;
}
}
yield BoxedIo::new(stream);
}
});
let svc = MakeSvc {
inner: svc,
interceptor: self.interceptor.clone(),
interceptor,
};
hyper::Server::builder(incoming)
@@ -133,24 +147,6 @@ impl fmt::Debug for Builder {
}
}
fn incoming(
addr: SocketAddr,
tls: Option<TlsAcceptor>,
) -> impl futures_core::Stream<Item = Result<BoxedIo, crate::Error>> {
async_stream::try_stream! {
let mut tcp = TcpIncoming::bind(addr)?;
while let Some(stream) = tcp.try_next().await? {
if let Some(tls) = &tls {
let io = tls.connect(stream.into_inner()).await?;
yield BoxedIo::new(io);
} else {
yield BoxedIo::new(stream);
}
}
}
}
#[derive(Debug)]
struct TcpIncoming {
inner: conn::AddrIncoming,
+7 -3
View File
@@ -1,4 +1,4 @@
use super::{layer::ServiceBuilderExt, AddOrigin, Connector};
use super::{connector, layer::ServiceBuilderExt, AddOrigin};
use crate::{body::BoxBody, transport::Endpoint};
use hyper::client::conn::Builder;
use hyper::client::service::Connect as HyperConnect;
@@ -27,8 +27,12 @@ pub struct Connection {
}
impl Connection {
pub fn new(mut endpoint: Endpoint) -> Result<Self, crate::Error> {
let connector = Connector::new(endpoint.cert.take())?;
pub fn new(endpoint: Endpoint) -> Result<Self, crate::Error> {
#[cfg(feature = "tls")]
let connector = connector(endpoint.tls.clone());
#[cfg(not(feature = "tls"))]
let connector = connector();
let settings = Builder::new().http2_only(true).clone();
+31 -24
View File
@@ -1,5 +1,6 @@
use super::io::BoxedIo;
use crate::transport::tls::{Cert, TlsConnector};
#[cfg(feature = "tls")]
use super::tls::TlsConnector;
use http::Uri;
use hyper::client::connect::HttpConnector;
use std::future::Future;
@@ -8,25 +9,31 @@ use std::task::{Context, Poll};
use tower_make::MakeConnection;
use tower_service::Service;
type ConnectFuture = <HttpConnector as MakeConnection<Uri>>::Future;
#[cfg(not(feature = "tls"))]
pub(crate) fn connector() -> HttpConnector {
let mut http = HttpConnector::new();
http.enforce_http(false);
http
}
#[cfg(feature = "tls")]
pub(crate) fn connector(tls: Option<TlsConnector>) -> Connector {
Connector::new(tls)
}
pub(crate) struct Connector {
http: HttpConnector,
#[cfg(feature = "tls")]
tls: Option<TlsConnector>,
}
impl Connector {
pub(crate) fn new(cert: Option<Cert>) -> Result<Self, crate::Error> {
#[cfg(feature = "tls")]
pub(crate) fn new(tls: Option<TlsConnector>) -> Self {
let mut http = HttpConnector::new();
http.enforce_http(false);
let tls = if let Some(cert) = cert {
Some(TlsConnector::new(cert)?)
} else {
None
};
Ok(Self { http, tls })
Self { http, tls }
}
}
@@ -42,23 +49,23 @@ impl Service<Uri> for Connector {
}
fn call(&mut self, uri: Uri) -> Self::Future {
let io = MakeConnection::make_connection(&mut self.http, uri);
let connect = MakeConnection::make_connection(&mut self.http, uri);
#[cfg(feature = "tls")]
let tls = self.tls.clone();
Box::pin(connect(io, tls))
}
}
Box::pin(async move {
let io = connect.await?;
async fn connect(
connect: ConnectFuture,
tls: Option<TlsConnector>,
) -> Result<BoxedIo, crate::Error> {
let io = connect.await?;
#[cfg(feature = "tls")]
{
if let Some(tls) = tls {
let conn = tls.connect(io).await?;
return Ok(BoxedIo::new(conn));
}
}
if let Some(tls) = tls {
let conn = tls.connect(io).await?;
Ok(BoxedIo::new(conn))
} else {
Ok(BoxedIo::new(io))
Ok(BoxedIo::new(io))
})
}
}
+5 -1
View File
@@ -5,11 +5,15 @@ mod connector;
mod discover;
mod io;
mod layer;
#[cfg(feature = "tls")]
mod tls;
pub(crate) use self::add_origin::AddOrigin;
pub(crate) use self::boxed::BoxService;
pub(crate) use self::connection::Connection;
pub(crate) use self::connector::Connector;
pub(crate) use self::connector::connector;
pub(crate) use self::discover::ServiceList;
pub(crate) use self::io::BoxedIo;
pub(crate) use self::layer::layer_fn;
#[cfg(feature = "tls")]
pub(crate) use self::tls::{TlsAcceptor, TlsConnector};
+228
View File
@@ -0,0 +1,228 @@
use super::io::BoxedIo;
use crate::transport::{Certificate, Identity};
#[cfg(feature = "openssl")]
use openssl1::{
pkey::PKey,
ssl::{SslAcceptor, SslConnector, SslMethod},
x509::X509,
};
use std::{fmt, sync::Arc};
use tokio::net::TcpStream;
#[cfg(feature = "rustls")]
use tokio_rustls::{
rustls::{internal::pemfile, ClientConfig, NoClientAuth, ServerConfig},
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")]
const ALPN_H2: &str = "h2";
#[derive(Debug, Clone)]
pub(crate) struct Cert {
pub(crate) ca: Vec<u8>,
pub(crate) key: Option<Vec<u8>>,
pub(crate) domain: String,
}
#[derive(Clone)]
pub(crate) struct TlsConnector {
inner: Connector,
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: Certificate,
domain: String,
) -> Result<Self, crate::Error> {
let mut config = SslConnector::builder(SslMethod::tls())?;
config.set_alpn_protos(ALPN_H2_WIRE)?;
let ca = X509::from_pem(&cert.pem[..])?;
config.cert_store_mut().add_cert(ca)?;
let config = config.build();
Ok(Self {
inner: Connector::Openssl(config),
domain: Arc::new(domain),
})
}
#[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls(cert: Certificate, domain: String) -> Result<Self, crate::Error> {
let mut buf = std::io::Cursor::new(&cert.pem[..]);
let mut config = ClientConfig::new();
config.root_store.add_pem_file(&mut buf).unwrap();
config.set_protocols(&[Vec::from(&ALPN_H2[..])]);
Ok(Self {
inner: Connector::Rustls(Arc::new(config)),
domain: Arc::new(domain),
})
}
// TODO: Write an either tlsstream to avoid this box
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?;
// TODO: check that we actually got an h2 stream
BoxedIo::new(tls)
}
#[cfg(feature = "rustls")]
Connector::Rustls(config) => {
let dns = DNSNameRef::try_from_ascii_str(self.domain.as_str())
.unwrap()
.to_owned();
let io = RustlsConnector::from(config.clone())
.connect(dns.as_ref(), io)
.await?;
// TODO: check that we actually got an h2 stream
BoxedIo::new(io)
}
#[allow(unreachable_patterns)]
_ => unreachable!("Reached a tls config point with neither feature enabled!"),
};
Ok(tls_io)
}
}
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()
}
}
#[derive(Clone)]
pub(crate) struct TlsAcceptor {
inner: Acceptor,
}
#[derive(Clone)]
enum Acceptor {
#[cfg(feature = "openssl")]
Openssl(SslAcceptor),
#[cfg(feature = "rustls")]
Rustls(Arc<ServerConfig>),
}
impl TlsAcceptor {
#[cfg(feature = "openssl")]
pub(crate) fn new_with_openssl(identity: Identity) -> 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_alpn_protos(ALPN_H2_WIRE)?;
config.set_private_key(&key)?;
config.set_certificate(&cert)?;
Ok(Self {
inner: Acceptor::Openssl(config.build()),
})
}
#[cfg(feature = "rustls")]
pub(crate) fn new_with_rustls(identity: Identity) -> Result<Self, crate::Error> {
let cert = {
let mut cert = std::io::Cursor::new(&identity.cert.pem[..]);
pemfile::certs(&mut cert).unwrap()
};
let key = {
let mut key = std::io::Cursor::new(&identity.key[..]);
pemfile::pkcs8_private_keys(&mut key).unwrap().remove(0)
};
let mut config = ServerConfig::new(NoClientAuth::new());
config.set_single_cert(cert, key)?;
config.set_protocols(&[Vec::from(&ALPN_H2[..])]);
Ok(Self {
inner: Acceptor::Rustls(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!"),
};
Ok(io)
}
}
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()
}
}
+23
View File
@@ -0,0 +1,23 @@
#[derive(Debug, Clone)]
pub struct Certificate {
pub(crate) pem: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct Identity {
pub(crate) cert: Certificate,
pub(crate) key: Vec<u8>,
}
impl Certificate {
pub fn from_pem(pem: Vec<u8>) -> Self {
Self { pem }
}
}
impl Identity {
pub fn from_pem(cert: Vec<u8>, key: Vec<u8>) -> Self {
let cert = Certificate::from_pem(cert);
Self { cert, key }
}
}
-64
View File
@@ -1,64 +0,0 @@
// TODO: bring back rustls
// #[cfg(feature = "native-tls")]
// #[cfg(not(feature = "rustls"))]
// #[path = "rustls.rs"]
// mod imp;
#[cfg(feature = "native-tls")]
#[cfg(not(feature = "rustls"))]
#[path = "openssl.rs"]
mod imp;
use std::fmt;
use tokio::net::TcpStream;
#[derive(Debug, Clone)]
pub(crate) struct Cert {
pub(crate) ca: Vec<u8>,
pub(crate) key: Option<Vec<u8>>,
pub(crate) domain: String,
}
#[derive(Clone)]
pub(crate) struct TlsConnector {
inner: imp::TlsConnector,
}
impl TlsConnector {
pub(crate) fn new(cert: Cert) -> Result<Self, crate::Error> {
let inner = imp::TlsConnector::new(cert)?;
Ok(Self { inner })
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<imp::TlsStream, crate::Error> {
self.inner.connect(io).await
}
}
impl fmt::Debug for TlsConnector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TlsConnector").finish()
}
}
#[derive(Clone)]
pub(crate) struct TlsAcceptor {
inner: imp::TlsAcceptor,
}
impl TlsAcceptor {
pub(crate) fn new(cert: Cert) -> Result<Self, crate::Error> {
let inner = imp::TlsAcceptor::new(cert)?;
Ok(Self { inner })
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<imp::TlsStream, crate::Error> {
self.inner.connect(io).await
}
}
impl fmt::Debug for TlsAcceptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TlsAcceptor").finish()
}
}
-72
View File
@@ -1,72 +0,0 @@
use super::Cert;
use openssl::ssl::{SslAcceptor, SslConnector, SslMethod};
use openssl::{pkey::PKey, x509::X509};
use std::sync::Arc;
use tokio::net::TcpStream;
use tokio_openssl::SslStream;
const ALPN_H2: &[u8] = b"\x02h2";
pub(crate) type TlsStream = SslStream<TcpStream>;
#[derive(Clone)]
pub(crate) struct TlsConnector {
config: SslConnector,
domain: Arc<String>,
}
impl TlsConnector {
pub(crate) fn new(cert: Cert) -> Result<Self, crate::Error> {
let Cert { ca, domain, .. } = cert;
let mut config = SslConnector::builder(SslMethod::tls()).unwrap();
config.set_alpn_protos(ALPN_H2)?;
let ca = X509::from_pem(&ca[..])?;
config.cert_store_mut().add_cert(ca)?;
let config = config.build();
Ok(Self {
config,
domain: Arc::new(domain),
})
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<TlsStream, crate::Error> {
let config = self.config.configure()?;
let tls = tokio_openssl::connect(config, &self.domain, io).await?;
Ok(tls)
}
}
#[derive(Clone)]
pub(crate) struct TlsAcceptor {
config: SslAcceptor,
}
impl TlsAcceptor {
pub(crate) fn new(cert: Cert) -> Result<Self, crate::Error> {
let Cert { ca, key, .. } = cert;
let key = PKey::private_key_from_pem(&key.unwrap()[..])?;
let ca = X509::from_pem(&ca[..])?;
let mut config = SslAcceptor::mozilla_modern(SslMethod::tls())?;
config.set_alpn_protos(ALPN_H2)?;
config.set_private_key(&key)?;
config.set_certificate(&ca)?;
Ok(Self {
config: config.build(),
})
}
pub(crate) async fn connect(&self, io: TcpStream) -> Result<TlsStream, crate::Error> {
let config = self.config.clone();
let tls = tokio_openssl::accept(&config, io).await?;
Ok(tls)
}
}
-92
View File
@@ -1,92 +0,0 @@
use http::Uri;
use hyper::client::connect::HttpConnector;
use std::{
future::Future,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use tokio::net::TcpStream;
use tokio_rustls::{
client::TlsStream,
rustls::{ClientConfig, Session},
webpki::DNSNameRef,
TlsConnector as RustlsConnector,
};
use tower_make::MakeConnection;
use tower_service::Service;
const ALPN_H2: &str = "h2";
#[derive(Clone)]
pub struct TlsConnector {
http: HttpConnector,
config: Arc<ClientConfig>,
domain: String,
}
impl TlsConnector {
#[cfg_attr(feature = "openssl-1", allow(dead_code))]
pub fn new(ca: Vec<u8>, domain: String) -> Self {
let mut buf = std::io::Cursor::new(ca);
let mut config = ClientConfig::new();
config.root_store.add_pem_file(&mut buf).unwrap();
config.set_protocols(&[Vec::from(&ALPN_H2[..])]);
let mut http = HttpConnector::new();
http.enforce_http(false);
Self {
http,
config: Arc::new(config),
domain,
}
}
}
impl Service<Uri> for TlsConnector {
type Response = TlsStream<TcpStream>;
type Error = super::Error;
type Future =
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
MakeConnection::poll_ready(&mut self.http, cx)
.map_err(|e| super::Error::from((super::ErrorKind::Client, e.into())))
}
fn call(&mut self, uri: Uri) -> Self::Future {
let dns = DNSNameRef::try_from_ascii_str(self.domain.as_str())
.unwrap()
.to_owned();
let config = self.config.clone();
let connect = self.http.make_connection(uri.clone());
let fut = async move {
let io = match connect.await {
Ok(io) => io,
Err(e) => return Err(super::Error::from((super::ErrorKind::Client, e.into()))),
};
RustlsConnector::from(config)
.connect(dns.as_ref(), io)
.await
.map_err(|e| super::Error::from((super::ErrorKind::Client, e.into())))
.and_then(|conn| {
let (_, session) = conn.get_ref();
let negotiated_protocol = session.get_alpn_protocol();
if Some(ALPN_H2.as_bytes()) == negotiated_protocol.as_ref().map(|x| &**x) {
Ok(conn)
} else {
Err(super::Error::from(super::ErrorKind::Client).into())
}
})
};
Box::pin(fut)
}
}