1use crate::certs::{load_certs, load_private_key};
2use anyhow::{Context, Result};
3use rustls::{RootCertStore, ServerConfig, server::WebPkiClientVerifier};
4use std::{path::Path, sync::Arc};
5use tokio_rustls::TlsAcceptor;
6use tracing::info;
7
8pub fn build_mtls_acceptor<P: AsRef<Path>>(
15 server_cert_path: P,
16 server_key_path: P,
17 ca_cert_path: P,
18) -> Result<TlsAcceptor> {
19 info!(
20 "Building server mTLS acceptor: cert={}, key={}, ca={}",
21 server_cert_path.as_ref().display(),
22 server_key_path.as_ref().display(),
23 ca_cert_path.as_ref().display()
24 );
25
26 let certs = load_certs(&server_cert_path)?;
28 info!("Loaded {} server certificate(s)", certs.len());
29
30 let key = load_private_key(&server_key_path)?;
32 info!("Server private key loaded");
33
34 let ca_certs = load_certs(&ca_cert_path)?;
36
37 let mut root_store = RootCertStore::empty();
39 for cert in ca_certs {
40 root_store
41 .add(cert)
42 .context("Failed to add CA cert to root store")?;
43 }
44 info!(
45 "CA certificate loaded, {} root certs in store",
46 root_store.len()
47 );
48
49 let client_verifier = WebPkiClientVerifier::builder(Arc::new(root_store))
51 .build()
52 .context("Failed to build client verifier")?;
53
54 let mut config = ServerConfig::builder()
56 .with_client_cert_verifier(client_verifier)
57 .with_single_cert(certs, key)
58 .context("Failed to build TLS server config")?;
59
60 config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
62
63 info!("Server TLS configuration built successfully (HTTP/2 + HTTP/1.1 via ALPN)");
64 Ok(TlsAcceptor::from(Arc::new(config)))
65}