From 740f17a9fa0e738d4aea212960f99245cc23534b Mon Sep 17 00:00:00 2001 From: Joel Weinberger Date: Mon, 14 Oct 2024 20:58:57 -0700 Subject: [PATCH] Updating peer certificate logic to work with modern rustls --- .gitignore | 2 ++ Cargo.toml | 3 ++- src/filters/mtls.rs | 47 ++++++++++++++++++--------------------------- src/test.rs | 9 ++++++--- src/tls.rs | 6 ++++-- src/transport.rs | 5 ++++- tests/mtls.rs | 10 ++++------ 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 3e631c8af..0abf1a8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ Cargo.lock .idea/ warp.iml + +*.swp diff --git a/Cargo.toml b/Cargo.toml index 5d426c0d5..ada6c2fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ percent-encoding = "2.1" pin-project = "1.0" tokio-rustls = { version = "0.25", optional = true } rustls-pemfile = { version = "2.0", optional = true } +rustls-pki-types = { version = "1.9.0", optional = true } [dev-dependencies] pretty_env_logger = "0.5" @@ -56,7 +57,7 @@ listenfd = "1.0" default = ["multipart", "websocket"] multipart = ["multer"] websocket = ["tokio-tungstenite"] -tls = ["tokio-rustls", "rustls-pemfile"] +tls = ["tokio-rustls", "rustls-pemfile", "rustls-pki-types"] # Enable compression-related filters compression = ["compression-brotli", "compression-gzip"] diff --git a/src/filters/mtls.rs b/src/filters/mtls.rs index dca3215f1..7299c332b 100644 --- a/src/filters/mtls.rs +++ b/src/filters/mtls.rs @@ -2,13 +2,16 @@ use std::convert::Infallible; -use tokio_rustls::rustls::Certificate; +use rustls_pki_types::CertificateDer; use crate::{ filter::{filter_fn_one, Filter}, route::Route, }; +/// Certificates is a iterable container of Certificates. +pub type Certificates = Vec>; + /// Creates a `Filter` to get the peer certificates for the TLS connection. /// /// If the underlying transport doesn't have peer certificates, this will yield @@ -27,35 +30,23 @@ use crate::{ /// ``` pub fn peer_certificates( ) -> impl Filter,), Error = Infallible> + Copy { - filter_fn_one(|route| futures_util::future::ok(Certificates::from_route(route))) + filter_fn_one(|route| futures_util::future::ok(from_route(route))) } -/// Certificates is a iterable container of Certificates. -#[derive(Debug)] -pub struct Certificates(Vec); - -impl Certificates { - fn from_route(route: &Route) -> Option { - route - .peer_certificates() - .read() - .unwrap() - .as_ref() - .map(|certs| Self(certs.to_vec())) - } +/// Testing +pub fn peer_certs_into_owned(certs: &Vec>) -> Vec> { + certs + .to_vec() + .iter() + .map(|cert| cert.clone().into_owned()) + .collect() } -impl AsRef<[Certificate]> for Certificates { - fn as_ref(&self) -> &[Certificate] { - self.0.as_ref() - } -} - -impl<'a> IntoIterator for &'a Certificates { - type Item = &'a Certificate; - type IntoIter = std::slice::Iter<'a, Certificate>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } +fn from_route(route: &Route) -> Option { + route + .peer_certificates() + .read() + .unwrap() + .as_ref() + .map(peer_certs_into_owned) } diff --git a/src/test.rs b/src/test.rs index 17ae80130..c8e09c4e7 100644 --- a/src/test.rs +++ b/src/test.rs @@ -113,11 +113,14 @@ use crate::filters::ws::Message; use crate::reject::IsReject; use crate::reply::Reply; use crate::route::{self, Route}; -use crate::Request; use crate::transport::PeerInfo; +use crate::Request; #[cfg(feature = "websocket")] use crate::{Sink, Stream}; +#[cfg(feature = "tls")] +use crate::filters::mtls::Certificates; + use self::inner::OneOrTuple; /// Starts a new test `RequestBuilder`. @@ -256,10 +259,10 @@ impl RequestBuilder { /// # Example /// ``` /// let req = warp::test::request() - /// .peer_certificates([tokio_rustls::rustls::Certificate(b"FAKE CERT".to_vec())]); + /// .peer_certificates([rustls_pki_types::CertificateDer::from_slice(b"FAKE CERT")]); /// ``` #[cfg(feature = "tls")] - pub fn peer_certificates(self, certs: impl Into>) -> Self { + pub fn peer_certificates(self, certs: impl Into) -> Self { *self.peer_info.peer_certificates.write().unwrap() = Some(certs.into()); self } diff --git a/src/tls.rs b/src/tls.rs index 6391887be..df9cd87f5 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -15,6 +15,7 @@ use hyper::server::conn::{AddrIncoming, AddrStream}; use tokio_rustls::rustls::server::WebPkiClientVerifier; use tokio_rustls::rustls::{Error as TlsError, RootCertStore, ServerConfig}; +use crate::filters::mtls::peer_certs_into_owned; use crate::transport::{PeerCertificates, Transport}; /// Represents errors that can occur building the TlsConfig @@ -327,8 +328,9 @@ impl AsyncRead for TlsStream { State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) { Ok(mut stream) => { let (_, conn) = stream.get_ref(); - *pin.peer_certs.write().unwrap() = - conn.peer_certificates().map(|certs| certs.to_vec()); + *pin.peer_certs.write().unwrap() = conn + .peer_certificates() + .map(|certs| peer_certs_into_owned(&certs.to_vec())); let result = Pin::new(&mut stream).poll_read(cx, buf); pin.state = State::Streaming(stream); diff --git a/src/transport.rs b/src/transport.rs index 66fe9328d..22c785122 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -7,7 +7,10 @@ use hyper::server::conn::AddrStream; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; #[cfg(feature = "tls")] -pub(crate) type PeerCertificates = std::sync::Arc>>>; +use crate::filters::mtls::Certificates; + +#[cfg(feature = "tls")] +pub(crate) type PeerCertificates = std::sync::Arc>>; #[cfg(not(feature = "tls"))] pub(crate) type PeerCertificates = (); diff --git a/tests/mtls.rs b/tests/mtls.rs index 5f844a356..d8a51a2fe 100644 --- a/tests/mtls.rs +++ b/tests/mtls.rs @@ -1,7 +1,7 @@ #![deny(warnings)] #![cfg(feature = "tls")] -use tokio_rustls::rustls::Certificate; +use rustls_pki_types::CertificateDer; #[tokio::test] async fn peer_certificates_missing() { @@ -16,11 +16,9 @@ async fn peer_certificates_missing() { async fn peer_certificates_present() { let extract_peer_certs = warp::mtls::peer_certificates(); - let cert = Certificate(b"TEST CERT".to_vec()); + let cert = CertificateDer::<'_>::from_slice(b"TEST CERT"); + let req = warp::test::request().peer_certificates([cert.clone()]); let resp = req.filter(&extract_peer_certs).await.unwrap(); - assert_eq!( - resp.unwrap().as_ref(), - &[cert], - ) + assert_eq!(resp.unwrap(), &[cert],) }