Skip to content

Commit

Permalink
feat(transport): Add server side peer cert support (#228)
Browse files Browse the repository at this point in the history
* feat(transport): Add server side peer cert support
  • Loading branch information
LucioFranco committed Jan 11, 2020
1 parent 3be8bc1 commit af807c3
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 13 deletions.
4 changes: 4 additions & 0 deletions examples/src/tls_client_auth/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub struct EchoServer;
#[tonic::async_trait]
impl pb::echo_server::Echo for EchoServer {
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
if let Some(certs) = request.peer_certs() {
println!("Got {} peer certs!", certs.len());
}

let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}
Expand Down
4 changes: 2 additions & 2 deletions tonic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ transport = [
"tower-load",
"tracing-futures",
]
tls = ["tokio-rustls"]
tls-roots = ["rustls-native-certs"]
tls = ["transport", "tokio-rustls"]
tls-roots = ["tls", "rustls-native-certs"]

# [[bench]]
# name = "bench_main"
Expand Down
18 changes: 18 additions & 0 deletions tonic/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use crate::metadata::MetadataMap;
#[cfg(feature = "transport")]
use crate::transport::Certificate;
use futures_core::Stream;
use http::Extensions;
use std::net::SocketAddr;
#[cfg(feature = "transport")]
use std::sync::Arc;

/// A gRPC request and metadata from an RPC call.
#[derive(Debug)]
Expand All @@ -14,6 +18,8 @@ pub struct Request<T> {
#[derive(Clone)]
pub(crate) struct ConnectionInfo {
pub(crate) remote_addr: Option<SocketAddr>,
#[cfg(feature = "transport")]
pub(crate) peer_certs: Option<Arc<Vec<Certificate>>>,
}

/// Trait implemented by RPC request types.
Expand Down Expand Up @@ -188,6 +194,18 @@ impl<T> Request<T> {
self.get::<ConnectionInfo>()?.remote_addr
}

/// Get the peer certificates of the connected client.
///
/// This is used to fetch the certificates from the TLS session
/// and is mostly used for mTLS. This currently only returns
/// `Some` on the server side of the `transport` server with
/// TLS enabled connections.
#[cfg(feature = "transport")]
#[cfg_attr(docsrs, doc(cfg(feature = "transport")))]
pub fn peer_certs(&self) -> Option<Arc<Vec<Certificate>>> {
self.get::<ConnectionInfo>()?.peer_certs.clone()
}

pub(crate) fn get<I: Send + Sync + 'static>(&self) -> Option<&I> {
self.extensions.get::<I>()
}
Expand Down
22 changes: 21 additions & 1 deletion tonic/src/transport/server/conn.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::transport::Certificate;
use hyper::server::conn::AddrStream;
use std::net::SocketAddr;
#[cfg(feature = "tls")]
use tokio_rustls::TlsStream;
use tokio_rustls::{rustls::Session, server::TlsStream};

/// Trait that connected IO resources implement.
///
Expand All @@ -13,6 +14,11 @@ pub trait Connected {
fn remote_addr(&self) -> Option<SocketAddr> {
None
}

/// Return the set of connected peer TLS certificates.
fn peer_certs(&self) -> Option<Vec<Certificate>> {
None
}
}

impl Connected for AddrStream {
Expand All @@ -27,4 +33,18 @@ impl<T: Connected> Connected for TlsStream<T> {
let (inner, _) = self.get_ref();
inner.remote_addr()
}

fn peer_certs(&self) -> Option<Vec<Certificate>> {
let (_, session) = self.get_ref();

if let Some(certs) = session.get_peer_certificates() {
let certs = certs
.into_iter()
.map(|c| Certificate::from_pem(c.0))
.collect();
Some(certs)
} else {
None
}
}
}
1 change: 1 addition & 0 deletions tonic/src/transport/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ where
fn call(&mut self, io: &ServerIo) -> Self::Future {
let conn_info = crate::request::ConnectionInfo {
remote_addr: io.remote_addr(),
peer_certs: io.peer_certs().map(Arc::new),
};

let interceptor = self.interceptor.clone();
Expand Down
9 changes: 6 additions & 3 deletions tonic/src/transport/service/io.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::transport::server::Connected;
use crate::transport::{server::Connected, Certificate};
use hyper::client::connect::{Connected as HyperConnected, Connection};
use std::io;
use std::net::SocketAddr;
Expand Down Expand Up @@ -71,8 +71,11 @@ impl ServerIo {

impl Connected for ServerIo {
fn remote_addr(&self) -> Option<SocketAddr> {
let io = &*self.0;
io.remote_addr()
(&*self.0).remote_addr()
}

fn peer_certs(&self) -> Option<Vec<Certificate>> {
(&self.0).peer_certs()
}
}

Expand Down
14 changes: 7 additions & 7 deletions tonic/src/transport/service/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,17 @@ impl TlsAcceptor {
})
}

pub(crate) async fn accept<IO>(&self, io: IO) -> Result<BoxedIo, crate::Error>
pub(crate) async fn accept<IO>(
&self,
io: IO,
) -> Result<tokio_rustls::server::TlsStream<IO>, crate::Error>
where
IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,
{
let io = {
let acceptor = RustlsAcceptor::from(self.inner.clone());
let tls = acceptor.accept(io).await?;
BoxedIo::new(tls)
};
let acceptor = RustlsAcceptor::from(self.inner.clone());
let tls = acceptor.accept(io).await?;

Ok(io)
Ok(tls)
}
}

Expand Down

0 comments on commit af807c3

Please sign in to comment.