From 60c96296309a75209d53271658c299064c3dca00 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Tue, 24 Sep 2019 14:32:16 -0400 Subject: [PATCH] Refactor all of the tls --- .github/workflows/test.yml | 14 +- tonic-build/Cargo.toml | 3 +- tonic-examples/src/helloworld/server.rs | 2 +- tonic-interop/Cargo.toml | 2 +- tonic-interop/src/bin/client.rs | 7 +- tonic-interop/src/bin/server.rs | 8 +- tonic/Cargo.toml | 8 +- tonic/src/lib.rs | 2 - tonic/src/transport/endpoint.rs | 29 ++- tonic/src/transport/mod.rs | 1 + tonic/src/transport/server.rs | 72 ++++--- tonic/src/transport/service/connection.rs | 10 +- tonic/src/transport/service/connector.rs | 55 +++--- tonic/src/transport/service/mod.rs | 6 +- tonic/src/transport/service/tls.rs | 228 ++++++++++++++++++++++ tonic/src/transport/tls.rs | 23 +++ tonic/src/transport/tls/mod.rs | 64 ------ tonic/src/transport/tls/openssl.rs | 72 ------- tonic/src/transport/tls/rustls.rs | 92 --------- 19 files changed, 376 insertions(+), 322 deletions(-) create mode 100644 tonic/src/transport/service/tls.rs create mode 100644 tonic/src/transport/tls.rs delete mode 100644 tonic/src/transport/tls/mod.rs delete mode 100644 tonic/src/transport/tls/openssl.rs delete mode 100644 tonic/src/transport/tls/rustls.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b003ce..7f19762 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 diff --git a/tonic-build/Cargo.toml b/tonic-build/Cargo.toml index 20c3292..623078f 100644 --- a/tonic-build/Cargo.toml +++ b/tonic-build/Cargo.toml @@ -14,5 +14,6 @@ proc-macro2 = "1.0" [features] default = ["transport"] -rustfmt = [] +# TODO: reenable this feature +# rustfmt = [] transport = [] diff --git a/tonic-examples/src/helloworld/server.rs b/tonic-examples/src/helloworld/server.rs index bc7f256..8099d78 100644 --- a/tonic-examples/src/helloworld/server.rs +++ b/tonic-examples/src/helloworld/server.rs @@ -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")); diff --git a/tonic-interop/Cargo.toml b/tonic-interop/Cargo.toml index a215408..ead37ed 100644 --- a/tonic-interop/Cargo.toml +++ b/tonic-interop/Cargo.toml @@ -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" diff --git a/tonic-interop/src/bin/client.rs b/tonic-interop/src/bin/client.rs index 5cac9f5..d175676 100644 --- a/tonic-interop/src/bin/client.rs +++ b/tonic-interop/src/bin/client.rs @@ -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> { .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()?; diff --git a/tonic-interop/src/bin/server.rs b/tonic-interop/src/bin/server.rs index 6dfe384..ce94a19 100644 --- a/tonic-interop/src/bin/server.rs +++ b/tonic-interop/src/bin/server.rs @@ -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> { 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| { diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 1ce94b7..0ded4e1 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -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 = [] diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index dd4951b..5124564 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -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; diff --git a/tonic/src/transport/endpoint.rs b/tonic/src/transport/endpoint.rs index ca60c48..c28abed 100644 --- a/tonic/src/transport/endpoint.rs +++ b/tonic/src/transport/endpoint.rs @@ -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, pub(super) concurrency_limit: Option, pub(super) rate_limit: Option<(u64, Duration)>, - pub(super) cert: Option, + #[cfg(feature = "tls")] + pub(super) tls: Option, } impl Endpoint { @@ -38,12 +41,19 @@ impl Endpoint { self } - pub fn tls_cert(&mut self, ca: Vec, domain: Option) -> &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) -> &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) -> &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 for Endpoint { concurrency_limit: None, rate_limit: None, timeout: None, - cert: None, + #[cfg(feature = "tls")] + tls: None, } } } diff --git a/tonic/src/transport/mod.rs b/tonic/src/transport/mod.rs index 35cff24..03a96a0 100644 --- a/tonic/src/transport/mod.rs +++ b/tonic/src/transport/mod.rs @@ -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; diff --git a/tonic/src/transport/server.rs b/tonic/src/transport/server.rs index 078406e..c587397 100644 --- a/tonic/src/transport/server.rs +++ b/tonic/src/transport/server.rs @@ -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, Vec)>, interceptor: Option, // concurrency_limit: Option, + #[cfg(feature = "tls")] + tls: Option, } impl Builder { @@ -59,8 +59,17 @@ impl Builder { } /// Add a tls cert. - pub fn tls(&mut self, pem: Vec, key: Vec) -> &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 + 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, -) -> impl futures_core::Stream> { - 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, diff --git a/tonic/src/transport/service/connection.rs b/tonic/src/transport/service/connection.rs index 1008a9c..1e0c81d 100644 --- a/tonic/src/transport/service/connection.rs +++ b/tonic/src/transport/service/connection.rs @@ -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 { - let connector = Connector::new(endpoint.cert.take())?; + pub fn new(endpoint: Endpoint) -> Result { + #[cfg(feature = "tls")] + let connector = connector(endpoint.tls.clone()); + + #[cfg(not(feature = "tls"))] + let connector = connector(); let settings = Builder::new().http2_only(true).clone(); diff --git a/tonic/src/transport/service/connector.rs b/tonic/src/transport/service/connector.rs index 57b5539..908c5b7 100644 --- a/tonic/src/transport/service/connector.rs +++ b/tonic/src/transport/service/connector.rs @@ -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 = >::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) -> Connector { + Connector::new(tls) +} pub(crate) struct Connector { http: HttpConnector, + #[cfg(feature = "tls")] tls: Option, } impl Connector { - pub(crate) fn new(cert: Option) -> Result { + #[cfg(feature = "tls")] + pub(crate) fn new(tls: Option) -> 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 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, -) -> Result { - 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)) + }) } } diff --git a/tonic/src/transport/service/mod.rs b/tonic/src/transport/service/mod.rs index 4a3c8b3..c252c0d 100644 --- a/tonic/src/transport/service/mod.rs +++ b/tonic/src/transport/service/mod.rs @@ -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}; diff --git a/tonic/src/transport/service/tls.rs b/tonic/src/transport/service/tls.rs new file mode 100644 index 0000000..f554566 --- /dev/null +++ b/tonic/src/transport/service/tls.rs @@ -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, + pub(crate) key: Option>, + pub(crate) domain: String, +} + +#[derive(Clone)] +pub(crate) struct TlsConnector { + inner: Connector, + domain: Arc, +} + +#[derive(Clone)] +enum Connector { + #[cfg(feature = "openssl")] + Openssl(SslConnector), + #[cfg(feature = "rustls")] + Rustls(Arc), +} + +impl TlsConnector { + #[cfg(feature = "openssl")] + pub(crate) fn new_with_openssl( + cert: Certificate, + domain: String, + ) -> Result { + 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 { + 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 { + 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), +} + +impl TlsAcceptor { + #[cfg(feature = "openssl")] + pub(crate) fn new_with_openssl(identity: Identity) -> Result { + 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 { + 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 { + 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() + } +} diff --git a/tonic/src/transport/tls.rs b/tonic/src/transport/tls.rs new file mode 100644 index 0000000..a08b156 --- /dev/null +++ b/tonic/src/transport/tls.rs @@ -0,0 +1,23 @@ +#[derive(Debug, Clone)] +pub struct Certificate { + pub(crate) pem: Vec, +} + +#[derive(Debug, Clone)] +pub struct Identity { + pub(crate) cert: Certificate, + pub(crate) key: Vec, +} + +impl Certificate { + pub fn from_pem(pem: Vec) -> Self { + Self { pem } + } +} + +impl Identity { + pub fn from_pem(cert: Vec, key: Vec) -> Self { + let cert = Certificate::from_pem(cert); + Self { cert, key } + } +} diff --git a/tonic/src/transport/tls/mod.rs b/tonic/src/transport/tls/mod.rs deleted file mode 100644 index 5904d15..0000000 --- a/tonic/src/transport/tls/mod.rs +++ /dev/null @@ -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, - pub(crate) key: Option>, - pub(crate) domain: String, -} - -#[derive(Clone)] -pub(crate) struct TlsConnector { - inner: imp::TlsConnector, -} - -impl TlsConnector { - pub(crate) fn new(cert: Cert) -> Result { - let inner = imp::TlsConnector::new(cert)?; - Ok(Self { inner }) - } - - pub(crate) async fn connect(&self, io: TcpStream) -> Result { - 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 { - let inner = imp::TlsAcceptor::new(cert)?; - Ok(Self { inner }) - } - - pub(crate) async fn connect(&self, io: TcpStream) -> Result { - self.inner.connect(io).await - } -} - -impl fmt::Debug for TlsAcceptor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TlsAcceptor").finish() - } -} diff --git a/tonic/src/transport/tls/openssl.rs b/tonic/src/transport/tls/openssl.rs deleted file mode 100644 index 449e72f..0000000 --- a/tonic/src/transport/tls/openssl.rs +++ /dev/null @@ -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; - -#[derive(Clone)] -pub(crate) struct TlsConnector { - config: SslConnector, - domain: Arc, -} - -impl TlsConnector { - pub(crate) fn new(cert: Cert) -> Result { - 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 { - 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 { - 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 { - let config = self.config.clone(); - let tls = tokio_openssl::accept(&config, io).await?; - Ok(tls) - } -} diff --git a/tonic/src/transport/tls/rustls.rs b/tonic/src/transport/tls/rustls.rs deleted file mode 100644 index 3353973..0000000 --- a/tonic/src/transport/tls/rustls.rs +++ /dev/null @@ -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, - domain: String, -} - -impl TlsConnector { - #[cfg_attr(feature = "openssl-1", allow(dead_code))] - pub fn new(ca: Vec, 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 for TlsConnector { - type Response = TlsStream; - type Error = super::Error; - - type Future = - Pin> + Send + 'static>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - 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) - } -}