From 773e4e1749daf023222f2294816b1f09d9e916a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=C3=ADn=20Dufka?= Date: Thu, 16 Feb 2023 21:14:15 +0100 Subject: [PATCH] feat(tls): add an option for optional TLS client authentication (#1163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(tls): add an option for optional TLS client authentication Previously there were only two options for client authentication – either no authentication or mandatory authentication. With this change, a server can allow for optional authentication with a given root CA certificate and enforce client authentication on a per-request basis. Refs: #687 * Update tonic/src/transport/server/tls.rs --------- Co-authored-by: Lucio Franco --- tonic/src/transport/server/tls.rs | 21 ++++++++++++++++++++- tonic/src/transport/service/tls.rs | 14 +++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/tonic/src/transport/server/tls.rs b/tonic/src/transport/server/tls.rs index b6c7ec974..56b18b432 100644 --- a/tonic/src/transport/server/tls.rs +++ b/tonic/src/transport/server/tls.rs @@ -11,6 +11,7 @@ use std::fmt; pub struct ServerTlsConfig { identity: Option, client_ca_root: Option, + client_auth_optional: bool, } #[cfg(feature = "tls")] @@ -27,6 +28,7 @@ impl ServerTlsConfig { ServerTlsConfig { identity: None, client_ca_root: None, + client_auth_optional: false, } } @@ -46,7 +48,24 @@ impl ServerTlsConfig { } } + /// Sets whether client certificate verification is optional. + /// + /// This option has effect only if CA certificate is set. + /// + /// # Default + /// By default, this option is set to `false`. + pub fn client_auth_optional(self, optional: bool) -> Self { + ServerTlsConfig { + client_auth_optional: optional, + ..self + } + } + pub(crate) fn tls_acceptor(&self) -> Result { - TlsAcceptor::new(self.identity.clone().unwrap(), self.client_ca_root.clone()) + TlsAcceptor::new( + self.identity.clone().unwrap(), + self.client_ca_root.clone(), + self.client_auth_optional, + ) } } diff --git a/tonic/src/transport/service/tls.rs b/tonic/src/transport/service/tls.rs index bb9972c0a..19eaa8e55 100644 --- a/tonic/src/transport/service/tls.rs +++ b/tonic/src/transport/service/tls.rs @@ -118,12 +118,20 @@ impl TlsAcceptor { pub(crate) fn new( identity: Identity, client_ca_root: Option, + client_auth_optional: bool, ) -> Result { let builder = ServerConfig::builder().with_safe_defaults(); - let builder = match client_ca_root { - None => builder.with_no_client_auth(), - Some(cert) => { + let builder = match (client_ca_root, client_auth_optional) { + (None, _) => builder.with_no_client_auth(), + (Some(cert), true) => { + use tokio_rustls::rustls::server::AllowAnyAnonymousOrAuthenticatedClient; + let mut roots = RootCertStore::empty(); + rustls_keys::add_certs_from_pem(std::io::Cursor::new(&cert.pem[..]), &mut roots)?; + builder + .with_client_cert_verifier(AllowAnyAnonymousOrAuthenticatedClient::new(roots)) + } + (Some(cert), false) => { use tokio_rustls::rustls::server::AllowAnyAuthenticatedClient; let mut roots = RootCertStore::empty(); rustls_keys::add_certs_from_pem(std::io::Cursor::new(&cert.pem[..]), &mut roots)?;