1use crate::core::MtopError;
2use rustls_pki_types::pem::PemObject;
3use rustls_pki_types::{CertificateDer, PrivateKeyDer, ServerName};
4use std::path::PathBuf;
5use tokio::fs;
6use tokio_rustls::rustls::{ClientConfig, RootCertStore};
7
8#[derive(Debug, Clone, Default)]
10pub struct TlsConfig {
11 pub ca_path: Option<PathBuf>,
14
15 pub cert_path: Option<PathBuf>,
18
19 pub key_path: Option<PathBuf>,
22
23 pub server_name: Option<ServerName<'static>>,
26}
27
28pub(crate) async fn tls_client_config(config: TlsConfig) -> Result<ClientConfig, MtopError> {
29 let client_cert = if let Some(p) = &config.cert_path {
30 Some(load_cert(p).await?)
31 } else {
32 None
33 };
34
35 let client_key = if let Some(p) = &config.key_path {
36 Some(load_key(p).await?)
37 } else {
38 None
39 };
40
41 let root = if let Some(p) = &config.ca_path {
42 custom_root_store(load_cert(p).await?)?
43 } else {
44 default_root_store()
45 };
46
47 let builder = ClientConfig::builder().with_root_certificates(root);
48 let client_config = match (client_cert, client_key, config.cert_path, config.key_path) {
49 (Some(cert), Some(key), Some(cert_path), Some(key_path)) => {
50 tracing::debug!(message = "using key and cert for client authentication", key = ?key_path, cert = ?cert_path);
51 builder
52 .with_client_auth_cert(cert, key)
53 .map_err(|e| MtopError::configuration_cause("unable to use client cert or key", e))?
54 }
55 _ => {
56 tracing::debug!(message = "not using any client authentication");
57 builder.with_no_client_auth()
58 }
59 };
60
61 Ok(client_config)
62}
63
64async fn load_cert(path: &PathBuf) -> Result<Vec<CertificateDer<'static>>, MtopError> {
65 let contents = fs::read(path)
66 .await
67 .map_err(|e| MtopError::configuration_cause(format!("unable to load cert {:?}", path), e))?;
68 let iter = CertificateDer::pem_slice_iter(&contents);
69
70 let mut out = Vec::new();
71 for res in iter {
72 out.push(res.map_err(|e| MtopError::configuration_cause(format!("unable to parse cert {:?}", path), e))?);
73 }
74
75 Ok(out)
76}
77
78async fn load_key(path: &PathBuf) -> Result<PrivateKeyDer<'static>, MtopError> {
79 let contents = fs::read(path)
80 .await
81 .map_err(|e| MtopError::configuration_cause(format!("unable to load key {:?}", path), e))?;
82
83 PrivateKeyDer::from_pem_slice(&contents)
84 .map_err(|e| MtopError::configuration_cause(format!("unable to parse key {:?}", path), e))
85}
86
87fn custom_root_store(ca: Vec<CertificateDer<'static>>) -> Result<RootCertStore, MtopError> {
88 let mut store = RootCertStore::empty();
89 for cert in ca {
90 store
91 .add(cert)
92 .map_err(|e| MtopError::configuration_cause("unable to parse CA cert", e))?;
93 }
94
95 Ok(store)
96}
97
98fn default_root_store() -> RootCertStore {
99 let mut store = RootCertStore::empty();
100 store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|c| c.to_owned()));
101 store
102}