Skip to main content

rustgate/
tls.rs

1use crate::cert::CertificateAuthority;
2use crate::error::{ProxyError, Result};
3use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer};
4use rustls::server::WebPkiClientVerifier;
5use rustls::ServerConfig;
6use std::sync::Arc;
7use tokio::net::TcpStream;
8use tokio_rustls::TlsAcceptor;
9
10/// Create a `TlsAcceptor` for the given domain using a dynamically generated certificate.
11pub async fn make_tls_acceptor(
12    ca: &CertificateAuthority,
13    domain: &str,
14) -> Result<TlsAcceptor> {
15    let ck = ca.get_or_create_cert(domain).await?;
16
17    let config = ServerConfig::builder()
18        .with_no_client_auth()
19        .with_single_cert(
20            vec![ck.cert_der.clone()],
21            rustls::pki_types::PrivateKeyDer::Pkcs8(ck.key_der.clone_key()),
22        )?;
23
24    Ok(TlsAcceptor::from(Arc::new(config)))
25}
26
27/// Connect to an upstream server over TLS and return the stream.
28pub async fn connect_tls_upstream(
29    host: &str,
30    addr: &str,
31) -> Result<tokio_rustls::client::TlsStream<TcpStream>> {
32    let tcp = TcpStream::connect(addr).await?;
33
34    let mut root_store = rustls::RootCertStore::empty();
35    root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
36
37    let config = rustls::ClientConfig::builder()
38        .with_root_certificates(root_store)
39        .with_no_client_auth();
40
41    let connector = tokio_rustls::TlsConnector::from(Arc::new(config));
42    let server_name = rustls::pki_types::ServerName::try_from(host.to_string())
43        .map_err(|e| crate::error::ProxyError::Other(e.to_string()))?;
44
45    let tls_stream = connector.connect(server_name, tcp).await?;
46    Ok(tls_stream)
47}
48
49/// Create a server TLS config that requires mTLS (client certificate verification).
50pub fn make_mtls_server_config(
51    server_cert_der: CertificateDer<'static>,
52    server_key_der: PrivatePkcs8KeyDer<'static>,
53    ca_cert_der: CertificateDer<'static>,
54) -> Result<Arc<ServerConfig>> {
55    let mut root_store = rustls::RootCertStore::empty();
56    root_store
57        .add(ca_cert_der)
58        .map_err(|e| ProxyError::Other(format!("Failed to add CA cert to root store: {e}")))?;
59
60    let client_verifier = WebPkiClientVerifier::builder(Arc::new(root_store))
61        .build()
62        .map_err(|e| ProxyError::Other(format!("Failed to build client verifier: {e}")))?;
63
64    let config = ServerConfig::builder()
65        .with_client_cert_verifier(client_verifier)
66        .with_single_cert(
67            vec![server_cert_der],
68            rustls::pki_types::PrivateKeyDer::Pkcs8(server_key_der),
69        )?;
70
71    Ok(Arc::new(config))
72}
73
74/// Create a client TLS config for mTLS (presents client cert, verifies server against CA).
75pub fn make_mtls_client_config(
76    client_cert_der: CertificateDer<'static>,
77    client_key_der: PrivatePkcs8KeyDer<'static>,
78    ca_cert_der: CertificateDer<'static>,
79) -> Result<Arc<rustls::ClientConfig>> {
80    let mut root_store = rustls::RootCertStore::empty();
81    root_store
82        .add(ca_cert_der)
83        .map_err(|e| ProxyError::Other(format!("Failed to add CA cert to root store: {e}")))?;
84
85    let config = rustls::ClientConfig::builder()
86        .with_root_certificates(root_store)
87        .with_client_auth_cert(
88            vec![client_cert_der],
89            rustls::pki_types::PrivateKeyDer::Pkcs8(client_key_der),
90        )
91        .map_err(ProxyError::Tls)?;
92
93    Ok(Arc::new(config))
94}