postrust_proxy/tls/
server.rs1use std::io::BufReader;
8use std::sync::Arc;
9
10use tokio_rustls::rustls::ServerConfig;
11
12use crate::error::{ProxyError, ProxyResult};
13
14pub const ALPN_PROTOCOLS: [&[u8]; 2] = [b"h2", b"http/1.1"];
20
21pub(crate) fn install_crypto_provider() {
28 static ONCE: std::sync::Once = std::sync::Once::new();
29 ONCE.call_once(|| {
30 let _ = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider().install_default();
31 });
32}
33
34pub fn build_server_config(cert_pem: &[u8], key_pem: &[u8]) -> ProxyResult<Arc<ServerConfig>> {
36 install_crypto_provider();
37
38 let certs: Vec<_> = rustls_pemfile::certs(&mut BufReader::new(cert_pem))
39 .filter_map(|r| r.ok())
40 .collect();
41
42 if certs.is_empty() {
43 return Err(ProxyError::Tls("no certificates found in PEM".into()));
44 }
45
46 let key = rustls_pemfile::private_key(&mut BufReader::new(key_pem))
47 .map_err(|e| ProxyError::Tls(format!("could not parse private key: {}", e)))?
48 .ok_or_else(|| ProxyError::Tls("no private key found in PEM".into()))?;
49
50 let mut config = ServerConfig::builder()
51 .with_no_client_auth()
52 .with_single_cert(certs, key)
53 .map_err(|e| ProxyError::Tls(format!("could not build TLS config: {}", e)))?;
54
55 config.alpn_protocols = ALPN_PROTOCOLS.iter().map(|p| p.to_vec()).collect();
56
57 Ok(Arc::new(config))
58}
59
60pub fn build_server_config_with_resolver(
66 resolver: Arc<dyn tokio_rustls::rustls::server::ResolvesServerCert>,
67) -> Arc<ServerConfig> {
68 install_crypto_provider();
69
70 let mut config = ServerConfig::builder()
71 .with_no_client_auth()
72 .with_cert_resolver(resolver);
73
74 config.alpn_protocols = ALPN_PROTOCOLS.iter().map(|p| p.to_vec()).collect();
75
76 Arc::new(config)
77}
78
79pub async fn load_server_config(cert_file: &str, key_file: &str) -> ProxyResult<Arc<ServerConfig>> {
81 let cert_pem = tokio::fs::read(cert_file)
82 .await
83 .map_err(|e| ProxyError::Tls(format!("could not read {}: {}", cert_file, e)))?;
84 let key_pem = tokio::fs::read(key_file)
85 .await
86 .map_err(|e| ProxyError::Tls(format!("could not read {}: {}", key_file, e)))?;
87 build_server_config(&cert_pem, &key_pem)
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_alpn_offers_h2_first() {
96 assert_eq!(ALPN_PROTOCOLS[0], b"h2");
100 assert_eq!(ALPN_PROTOCOLS[1], b"http/1.1");
101 }
102
103 #[test]
104 fn test_rejects_pem_without_certificate() {
105 let err = build_server_config(b"not a certificate", b"not a key").unwrap_err();
106 assert!(
107 err.to_string().contains("no certificates"),
108 "unexpected error: {err}"
109 );
110 }
111
112 #[test]
113 fn test_rejects_certificate_without_key() {
114 let cert = b"-----BEGIN CERTIFICATE-----\nMA==\n-----END CERTIFICATE-----\n";
116 let err = build_server_config(cert, b"").unwrap_err();
117 assert!(
118 err.to_string().contains("no private key"),
119 "unexpected error: {err}"
120 );
121 }
122}