1use std::io;
11
12use axum_server::{accept::Accept, tls_rustls::RustlsAcceptor};
13use futures::{FutureExt, future::Map};
14use rustls::pki_types::CertificateDer;
15use tokio::io::{AsyncRead, AsyncWrite};
16use tokio_rustls::server::TlsStream;
17use tower::Layer;
18use tower_http::add_extension::{AddExtension, AddExtensionLayer};
19
20#[derive(Clone, Debug)]
32pub struct VerifiedTlsClientCert(pub Option<CertificateDer<'static>>);
33
34#[derive(Clone, Debug)]
57pub struct CertInjectorAcceptor {
58 inner: RustlsAcceptor,
59}
60
61impl CertInjectorAcceptor {
62 pub fn new(inner: RustlsAcceptor) -> Self {
65 Self { inner }
66 }
67}
68
69impl<I, S> Accept<I, S> for CertInjectorAcceptor
70where
71 I: AsyncRead + AsyncWrite + Unpin + Send + 'static,
72 S: Send + 'static,
73{
74 type Stream = TlsStream<I>;
75 type Service = AddExtension<S, VerifiedTlsClientCert>;
76 type Future = Map<
77 <RustlsAcceptor as Accept<I, S>>::Future,
78 fn(
79 io::Result<(TlsStream<I>, S)>,
80 ) -> io::Result<(
81 TlsStream<I>,
82 AddExtension<S, VerifiedTlsClientCert>,
83 )>,
84 >;
85
86 fn accept(&self, stream: I, service: S) -> Self::Future {
87 self.inner
89 .accept(stream, service)
90 .map(|result| -> io::Result<_> {
91 let (tls_stream, service) = result?;
92
93 let (_, server_conn) = tls_stream.get_ref();
97 let client_cert = server_conn
98 .peer_certificates()
99 .and_then(|chain| chain.first())
100 .cloned();
101 let verified_cert = VerifiedTlsClientCert(client_cert);
102
103 let service =
105 AddExtensionLayer::new(verified_cert).layer(service);
106 Ok((tls_stream, service))
107 })
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use std::sync::Arc;
114
115 use axum::{Router, extract::Request, routing::post};
116 use lexe_api_core::error::BackendApiError;
117 use lexe_common::root_seed::RootSeed;
118 use lexe_crypto::rng::FastRng;
119 use lexe_tls::{
120 LEXE_ALPN_PROTOCOLS, LEXE_CRYPTO_PROVIDER, client_config_builder,
121 server_config_builder,
122 shared_seed::certs::{
123 EphemeralClientCert, EphemeralIssuingCaCert, EphemeralServerCert,
124 },
125 };
126 use rustls::{RootCertStore, server::WebPkiClientVerifier};
127
128 use super::VerifiedTlsClientCert;
129 use crate::{
130 rest::RestClient, server::LxJson, test_utils::with_test_server,
131 };
132
133 #[tokio::test]
137 async fn injects_client_cert_into_handler() {
138 const DNS: &str = "localhost";
139 let mut rng = FastRng::from_u64(20240514);
140
141 let ca_cert = EphemeralIssuingCaCert::from_root_seed(
143 &RootSeed::from_rng(&mut rng),
144 );
145 let ca_cert_der = ca_cert.serialize_der_self_signed().unwrap();
146 let mut roots = RootCertStore::empty();
147 roots.add(ca_cert_der.into()).unwrap();
148 let roots = Arc::new(roots);
149
150 let server_cert =
152 EphemeralServerCert::from_rng(&mut rng, &[DNS]).unwrap();
153 let server_cert_der =
154 server_cert.serialize_der_ca_signed(&ca_cert).unwrap();
155 let client_cert = EphemeralClientCert::generate_from_rng(&mut rng);
156 let client_cert_der =
157 client_cert.serialize_der_ca_signed(&ca_cert).unwrap();
158 let expected_cert_der = client_cert_der.0.clone();
160
161 let client_verifier = WebPkiClientVerifier::builder_with_provider(
163 roots.clone(),
164 LEXE_CRYPTO_PROVIDER.clone(),
165 )
166 .build()
167 .unwrap();
168 let mut server_config = server_config_builder()
169 .with_client_cert_verifier(client_verifier)
170 .with_single_cert(
171 vec![server_cert_der.into()],
172 server_cert.serialize_key_der().into(),
173 )
174 .unwrap();
175 server_config
176 .alpn_protocols
177 .clone_from(&LEXE_ALPN_PROTOCOLS);
178 let server_config = Arc::new(server_config);
179
180 let mut client_config = client_config_builder()
182 .with_root_certificates(roots)
183 .with_client_auth_cert(
184 vec![client_cert_der.into()],
185 client_cert.serialize_key_der().into(),
186 )
187 .unwrap();
188 client_config
189 .alpn_protocols
190 .clone_from(&LEXE_ALPN_PROTOCOLS);
191
192 async fn handler(req: Request) -> LxJson<Option<Vec<u8>>> {
195 let cert_der = req
196 .extensions()
197 .get::<VerifiedTlsClientCert>()
198 .and_then(|cert| cert.0.as_ref())
199 .map(|cert| cert.as_ref().to_vec());
200 LxJson(cert_der)
201 }
202
203 let router = Router::new().route("/client_cert", post(handler));
204 with_test_server(server_config, DNS, router, |server_url| async move {
205 let rest =
206 RestClient::new("test-client", "test-server", client_config);
207 let url = format!("{server_url}/client_cert");
208 let http_req = rest.post(url, &());
209 let recovered_cert_der: Option<Vec<u8>> = rest
210 .send::<_, BackendApiError>(http_req)
211 .await
212 .expect("Request failed");
213
214 assert_eq!(recovered_cert_der, Some(expected_cert_der));
216 })
217 .await;
218 }
219}