mesquitte_core/server/
rustls.rs1use std::{fs::File, io::BufReader, sync::Arc};
2
3use rustls::{server::WebPkiClientVerifier, RootCertStore};
4use tokio_rustls::{
5 rustls::{Error as RustlsError, ServerConfig},
6 TlsAcceptor,
7};
8
9use super::config::TlsConfig;
10
11#[derive(Debug, thiserror::Error)]
12#[error("Acceptor error")]
13pub enum Error {
14 #[error("I/O {0}")]
15 Io(#[from] std::io::Error),
16 #[error("Rustls error {0}")]
17 Rustls(#[from] RustlsError),
18 #[error("Invalid CA cert file {0}")]
19 InvalidCACert(String),
20 #[error("Invalid server key file {0}")]
21 InvalidServerKey(String),
22}
23
24pub fn rustls_server_config(cfg: &TlsConfig) -> Result<ServerConfig, Error> {
25 let cert_file = &mut BufReader::new(File::open(cfg.cert_file.clone())?);
26 let key_file = &mut BufReader::new(File::open(cfg.key_file.clone())?);
27
28 let cert_chain = rustls_pemfile::certs(cert_file).collect::<Result<Vec<_>, _>>()?;
29 let key = rustls_pemfile::private_key(key_file)?
30 .ok_or(Error::InvalidServerKey("invalid server key".to_string()))?;
31
32 let client_auth = if cfg.fail_if_no_peer_cert {
33 match &cfg.ca_file {
34 Some(ca) => {
35 let ca_file = &mut BufReader::new(File::open(ca)?);
36 let cert_chain = rustls_pemfile::certs(ca_file).collect::<Result<Vec<_>, _>>()?;
37 let mut client_auth_roots = RootCertStore::empty();
38 for root in cert_chain {
39 client_auth_roots
40 .add(root)
41 .map_err(|e| Error::InvalidCACert(e.to_string()))?;
42 }
43 WebPkiClientVerifier::builder(client_auth_roots.into())
44 .build()
45 .map_err(|e| Error::InvalidCACert(e.to_string()))?
46 }
47 None => return Err(Error::InvalidCACert("empty ca".to_string())),
48 }
49 } else {
50 WebPkiClientVerifier::no_client_auth()
51 };
52
53 ServerConfig::builder()
54 .with_client_cert_verifier(client_auth)
55 .with_single_cert(cert_chain, key)
56 .map_err(|e| Error::InvalidCACert(e.to_string()))
57}
58
59pub fn rustls_acceptor(cfg: &TlsConfig) -> Result<TlsAcceptor, Error> {
60 Ok(TlsAcceptor::from(Arc::new(rustls_server_config(cfg)?)))
61}