Skip to main content

cloudiful_server/core/
tls.rs

1use std::{fs::File, io::BufReader, sync::Arc};
2
3use crate::core::{
4    ValidatedServerConfig,
5    error::{ServerError, TlsConfigLoadError},
6};
7
8pub fn load_tls_config<U>(
9    config: &ValidatedServerConfig<U>,
10) -> Result<Option<rustls::ServerConfig>, ServerError> {
11    let Some(tls) = config.tls.as_ref() else {
12        return Ok(None);
13    };
14
15    let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
16
17    let mut cert_file = BufReader::new(File::open(&tls.cert_path).map_err(|source| {
18        ServerError::Tls(TlsConfigLoadError::OpenCertificate {
19            path: tls.cert_path.clone(),
20            source,
21        })
22    })?);
23
24    let mut key_file = BufReader::new(File::open(&tls.cert_key_path).map_err(|source| {
25        ServerError::Tls(TlsConfigLoadError::OpenPrivateKey {
26            path: tls.cert_key_path.clone(),
27            source,
28        })
29    })?);
30
31    let tls_certs = rustls_pemfile::certs(&mut cert_file)
32        .collect::<Result<Vec<_>, _>>()
33        .map_err(|source| {
34            ServerError::Tls(TlsConfigLoadError::ReadCertificates {
35                path: tls.cert_path.clone(),
36                source,
37            })
38        })?;
39
40    let tls_key = rustls_pemfile::private_key(&mut key_file)
41        .map_err(|source| {
42            ServerError::Tls(TlsConfigLoadError::ReadPrivateKey {
43                path: tls.cert_key_path.clone(),
44                source,
45            })
46        })?
47        .ok_or_else(|| {
48            ServerError::Tls(TlsConfigLoadError::MissingPrivateKey {
49                path: tls.cert_key_path.clone(),
50            })
51        })?;
52
53    let builder = rustls::ServerConfig::builder();
54    let builder = match tls.client_ca.as_ref() {
55        Some(client_ca_path) => {
56            let mut client_ca_file =
57                BufReader::new(File::open(client_ca_path).map_err(|source| {
58                    ServerError::Tls(TlsConfigLoadError::OpenClientCa {
59                        path: client_ca_path.clone(),
60                        source,
61                    })
62                })?);
63
64            let client_ca_certs = rustls_pemfile::certs(&mut client_ca_file)
65                .collect::<Result<Vec<_>, _>>()
66                .map_err(|source| {
67                    ServerError::Tls(TlsConfigLoadError::ReadClientCa {
68                        path: client_ca_path.clone(),
69                        source,
70                    })
71                })?;
72
73            let mut client_roots = rustls::RootCertStore::empty();
74            let (added, _ignored) = client_roots.add_parsable_certificates(client_ca_certs);
75            if added == 0 {
76                return Err(ServerError::Tls(TlsConfigLoadError::InvalidClientCa {
77                    path: client_ca_path.clone(),
78                    source: rustls::Error::General("no valid client CA certificates found".into()),
79                }));
80            }
81
82            let client_verifier =
83                rustls::server::WebPkiClientVerifier::builder(Arc::new(client_roots))
84                    .build()
85                    .map_err(|source| {
86                        ServerError::Tls(TlsConfigLoadError::InvalidClientCa {
87                            path: client_ca_path.clone(),
88                            source: rustls::Error::General(source.to_string().into()),
89                        })
90                    })?;
91
92            builder.with_client_cert_verifier(client_verifier)
93        }
94        None => builder.with_no_client_auth(),
95    };
96
97    builder
98        .with_single_cert(tls_certs, tls_key)
99        .map(Some)
100        .map_err(|source| ServerError::Tls(TlsConfigLoadError::InvalidConfig { source }))
101}