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
21fn 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 async fn load_server_config(cert_file: &str, key_file: &str) -> ProxyResult<Arc<ServerConfig>> {
62 let cert_pem = tokio::fs::read(cert_file)
63 .await
64 .map_err(|e| ProxyError::Tls(format!("could not read {}: {}", cert_file, e)))?;
65 let key_pem = tokio::fs::read(key_file)
66 .await
67 .map_err(|e| ProxyError::Tls(format!("could not read {}: {}", key_file, e)))?;
68 build_server_config(&cert_pem, &key_pem)
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_alpn_offers_h2_first() {
77 assert_eq!(ALPN_PROTOCOLS[0], b"h2");
81 assert_eq!(ALPN_PROTOCOLS[1], b"http/1.1");
82 }
83
84 #[test]
85 fn test_rejects_pem_without_certificate() {
86 let err = build_server_config(b"not a certificate", b"not a key").unwrap_err();
87 assert!(
88 err.to_string().contains("no certificates"),
89 "unexpected error: {err}"
90 );
91 }
92
93 #[test]
94 fn test_rejects_certificate_without_key() {
95 let cert = b"-----BEGIN CERTIFICATE-----\nMA==\n-----END CERTIFICATE-----\n";
97 let err = build_server_config(cert, b"").unwrap_err();
98 assert!(
99 err.to_string().contains("no private key"),
100 "unexpected error: {err}"
101 );
102 }
103}