1#[cfg(not(test))]
2use std::fs;
3use std::path::Path;
4
5use serde::Deserialize;
6use serde::Serialize;
7
8use crate::Error;
9use crate::Result;
10
11#[derive(Debug, Serialize, Deserialize, Clone, Default)]
12#[allow(unused)]
13pub struct TlsConfig {
14 #[serde(default = "default_enable_tls")]
17 pub enable_tls: bool,
18
19 #[serde(default = "default_generate_self_signed")]
22 pub generate_self_signed_certificates: bool,
23
24 #[serde(default = "default_ca_path")]
27 pub certificate_authority_root_path: String,
28
29 #[serde(default = "default_server_cert_path")]
32 pub server_certificate_path: String,
33
34 #[serde(default = "default_server_key_path")]
37 pub server_private_key_path: String,
38
39 #[serde(default = "default_client_ca_path")]
42 pub client_certificate_authority_root_path: String,
43
44 #[serde(default = "default_enable_mtls")]
47 pub enable_mtls: bool,
48}
49impl TlsConfig {
50 pub fn validate(&self) -> Result<()> {
58 if !self.enable_tls {
59 return Ok(());
61 }
62
63 if self.enable_mtls && !self.enable_tls {
65 return Err(Error::InvalidConfig("mTLS requires enable_tls to be true".into()));
66 }
67
68 if self.generate_self_signed_certificates {
70 if !self.server_certificate_path.is_empty() || !self.server_private_key_path.is_empty() {
71 return Err(Error::InvalidConfig(
72 "Cannot specify certificate paths with generate_self_signed_certificates=true".into(),
73 ));
74 }
75 return Ok(());
76 }
77
78 self.validate_cert_file(&self.server_certificate_path, "server certificate")?;
80 self.validate_key_file(&self.server_private_key_path, "server private key")?;
81 self.validate_cert_file(&self.certificate_authority_root_path, "CA certificate")?;
82
83 if self.enable_mtls {
85 self.validate_cert_file(&self.client_certificate_authority_root_path, "client CA certificate")?;
86 }
87
88 Ok(())
89 }
90
91 fn validate_cert_file(
93 &self,
94 path: &str,
95 name: &str,
96 ) -> Result<()> {
97 let path = Path::new(path);
98
99 if path.exists() {
100 #[cfg(not(test))]
101 {
102 fs::File::open(path).map_err(|e| {
104 Error::InvalidConfig(format!("{} file {} is unreadable: {}", name, path.display(), e))
105 })?;
106 }
107 Ok(())
108 } else {
109 Err(Error::InvalidConfig(format!(
110 "{} file {} not found",
111 name,
112 path.display()
113 )))
114 }
115 }
116
117 fn validate_key_file(
119 &self,
120 path: &str,
121 name: &str,
122 ) -> Result<()> {
123 let path = Path::new(path);
124
125 if path.exists() {
126 #[cfg(not(test))]
127 {
128 let metadata = fs::metadata(path).map_err(|e| {
130 Error::InvalidConfig(format!("Cannot access {} permissions: {}", path.display(), e))
131 })?;
132
133 #[cfg(unix)]
134 {
135 use std::os::unix::fs::PermissionsExt;
136 let mode = metadata.permissions().mode();
137 if mode & 0o777 != 0o600 {
138 return Err(Error::InvalidConfig(format!(
139 "Insecure permissions {:o} for {} (should be 600)",
140 mode & 0o777,
141 path.display()
142 )));
143 }
144 }
145 }
146 Ok(())
147 } else {
148 Err(Error::InvalidConfig(format!(
149 "{} file {} not found",
150 name,
151 path.display()
152 )))
153 }
154 }
155}
156fn default_enable_tls() -> bool {
158 false
159}
160fn default_generate_self_signed() -> bool {
161 false
162}
163fn default_ca_path() -> String {
164 "/etc/ssl/certs/ca.pem".into()
165}
166fn default_server_cert_path() -> String {
167 "./certs/server.pem".into()
168}
169fn default_server_key_path() -> String {
170 "./certs/server.key".into()
171}
172fn default_client_ca_path() -> String {
173 "/etc/ssl/certs/ca.pem".into()
174}
175fn default_enable_mtls() -> bool {
176 false
177}