octoproxy_lib/
tls.rs

1use std::{io::BufReader, path::PathBuf};
2
3use anyhow::{bail, Context};
4use rustls::{
5    client::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
6    server::{AllowAnyAuthenticatedClient, NoClientAuth, ServerSessionMemoryCache},
7    ClientConfig, DigitallySignedStruct, OwnedTrustAnchor, RootCertStore, ServerConfig,
8};
9
10pub const DEFAULT_FORMARD_PORT: u16 = 8443;
11
12pub struct NoVerifier;
13
14pub static QUIC_ALPN: &[u8] = b"h3";
15
16impl ServerCertVerifier for NoVerifier {
17    fn verify_server_cert(
18        &self,
19        _end_entity: &rustls::Certificate,
20        _intermediates: &[rustls::Certificate],
21        _server_name: &rustls::ServerName,
22        _scts: &mut dyn Iterator<Item = &[u8]>,
23        _ocsp_response: &[u8],
24        _now: std::time::SystemTime,
25    ) -> Result<ServerCertVerified, rustls::Error> {
26        Ok(ServerCertVerified::assertion())
27    }
28
29    fn verify_tls12_signature(
30        &self,
31        _message: &[u8],
32        _cert: &rustls::Certificate,
33        _dss: &DigitallySignedStruct,
34    ) -> Result<HandshakeSignatureValid, rustls::Error> {
35        Ok(HandshakeSignatureValid::assertion())
36    }
37
38    fn verify_tls13_signature(
39        &self,
40        _message: &[u8],
41        _cert: &rustls::Certificate,
42        _dss: &DigitallySignedStruct,
43    ) -> Result<HandshakeSignatureValid, rustls::Error> {
44        Ok(HandshakeSignatureValid::assertion())
45    }
46}
47
48pub fn load_private_key(filename: &PathBuf) -> anyhow::Result<rustls::PrivateKey> {
49    let keyfile = std::fs::File::open(filename).context("cannot open private key file")?;
50    let mut reader = std::io::BufReader::new(keyfile);
51
52    loop {
53        match rustls_pemfile::read_one(&mut reader)? {
54            Some(rustls_pemfile::Item::RSAKey(key)) => return Ok(rustls::PrivateKey(key)),
55            Some(rustls_pemfile::Item::PKCS8Key(key)) => return Ok(rustls::PrivateKey(key)),
56            Some(rustls_pemfile::Item::ECKey(key)) => return Ok(rustls::PrivateKey(key)),
57            None => break,
58            _ => {}
59        }
60    }
61
62    bail!("no keys found (encrypted keys not supported)")
63}
64
65/// load cert
66/// TODO support many files?
67pub fn load_certs(filename: &PathBuf) -> anyhow::Result<Vec<rustls::Certificate>> {
68    let certfile = std::fs::File::open(filename).context("cannot open certificate file")?;
69    let mut reader = BufReader::new(certfile);
70    Ok(rustls_pemfile::certs(&mut reader)?
71        .iter()
72        .map(|v| rustls::Certificate(v.clone()))
73        .collect())
74}
75
76pub fn build_client_root_store(cafile: &Option<PathBuf>) -> anyhow::Result<RootCertStore> {
77    let mut root_store = RootCertStore::empty();
78    if let Some(cafile) = cafile {
79        let mut pem =
80            std::io::BufReader::new(std::fs::File::open(cafile).context("cannot open ca file")?);
81        let certs = rustls_pemfile::certs(&mut pem)?;
82        let (added, _skipped) = root_store.add_parsable_certificates(&certs);
83        if added == 0 {
84            bail!("cannot parse cert");
85        }
86    } else {
87        root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
88            OwnedTrustAnchor::from_subject_spki_name_constraints(
89                ta.subject,
90                ta.spki,
91                ta.name_constraints,
92            )
93        }));
94    }
95    Ok(root_store)
96}
97
98pub fn build_tls_server_config(
99    certs: PathBuf,
100    key: PathBuf,
101    client_ca: Option<PathBuf>,
102) -> anyhow::Result<ServerConfig> {
103    let certs = load_certs(&certs)?;
104    let keys = load_private_key(&key)?;
105
106    let tls_config = rustls::ServerConfig::builder().with_safe_defaults();
107
108    // add trusted client certs
109    let client_verifier = match client_ca {
110        Some(client_certs) => {
111            let client_certs = load_certs(&client_certs)?;
112            let mut client_auth_roots = RootCertStore::empty();
113            for cert in client_certs {
114                client_auth_roots.add(&cert)?;
115            }
116            AllowAnyAuthenticatedClient::new(client_auth_roots).boxed()
117        }
118        None => {
119            // dangerous
120            // TODO throw a warning if not given client ca or put this into `dangerous` feature
121            NoClientAuth::boxed()
122        }
123    };
124
125    let mut tls_config = tls_config
126        // .with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256])
127        .with_client_cert_verifier(client_verifier)
128        .with_single_cert(certs, keys)?;
129
130    // using ticket
131    tls_config.ticketer = rustls::Ticketer::new()?;
132    tls_config.session_storage = ServerSessionMemoryCache::new(256);
133    Ok(tls_config)
134}
135
136pub fn build_tls_client_config(
137    cacert: &Option<PathBuf>,
138    client_cert: &PathBuf,
139    client_key: &PathBuf,
140) -> anyhow::Result<ClientConfig> {
141    let root_store = build_client_root_store(cacert)?;
142
143    let tls_config = rustls::ClientConfig::builder()
144        .with_safe_defaults()
145        .with_root_certificates(root_store);
146
147    let certs = load_certs(client_cert)?;
148    let key = load_private_key(client_key)?;
149    let tls_config = tls_config.with_single_cert(certs, key)?;
150
151    Ok(tls_config)
152}
153
154pub struct NeverProducesTickets {}
155
156impl rustls::server::ProducesTickets for NeverProducesTickets {
157    fn enabled(&self) -> bool {
158        false
159    }
160    fn lifetime(&self) -> u32 {
161        0
162    }
163    fn encrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> {
164        None
165    }
166    fn decrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> {
167        None
168    }
169}