oxigdal_security/encryption/
in_transit.rs1use crate::error::{Result, SecurityError};
4use rustls::{ClientConfig, ServerConfig};
5use std::io::BufReader;
6use std::sync::Arc;
7
8pub struct TlsConfigBuilder {
10 server_name: Option<String>,
11 ca_cert: Option<Vec<u8>>,
12 client_cert: Option<Vec<u8>>,
13 client_key: Option<Vec<u8>>,
14 server_cert: Option<Vec<u8>>,
15 server_key: Option<Vec<u8>>,
16 verify_peer: bool,
17}
18
19impl Default for TlsConfigBuilder {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl TlsConfigBuilder {
26 pub fn new() -> Self {
28 Self {
29 server_name: None,
30 ca_cert: None,
31 client_cert: None,
32 client_key: None,
33 server_cert: None,
34 server_key: None,
35 verify_peer: true,
36 }
37 }
38
39 pub fn server_name(mut self, name: String) -> Self {
41 self.server_name = Some(name);
42 self
43 }
44
45 pub fn ca_cert(mut self, cert: Vec<u8>) -> Self {
47 self.ca_cert = Some(cert);
48 self
49 }
50
51 pub fn client_cert_and_key(mut self, cert: Vec<u8>, key: Vec<u8>) -> Self {
53 self.client_cert = Some(cert);
54 self.client_key = Some(key);
55 self
56 }
57
58 pub fn server_cert_and_key(mut self, cert: Vec<u8>, key: Vec<u8>) -> Self {
60 self.server_cert = Some(cert);
61 self.server_key = Some(key);
62 self
63 }
64
65 pub fn verify_peer(mut self, verify: bool) -> Self {
67 self.verify_peer = verify;
68 self
69 }
70
71 pub fn build_client(self) -> Result<Arc<ClientConfig>> {
73 let mut root_store = rustls::RootCertStore::empty();
74
75 if let Some(ca_cert) = self.ca_cert {
76 let mut reader = BufReader::new(ca_cert.as_slice());
77 let certs = rustls_pemfile::certs(&mut reader)
78 .collect::<std::result::Result<Vec<_>, _>>()
79 .map_err(|e| {
80 SecurityError::certificate(format!("Failed to parse CA cert: {}", e))
81 })?;
82
83 for cert in certs {
84 root_store.add(cert).map_err(|e| {
85 SecurityError::certificate(format!("Failed to add CA cert: {}", e))
86 })?;
87 }
88 } else {
89 root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
91 }
92
93 let config = if let (Some(cert), Some(key)) = (self.client_cert, self.client_key) {
95 let mut cert_reader = BufReader::new(cert.as_slice());
96 let certs = rustls_pemfile::certs(&mut cert_reader)
97 .collect::<std::result::Result<Vec<_>, _>>()
98 .map_err(|e| {
99 SecurityError::certificate(format!("Failed to parse client cert: {}", e))
100 })?;
101
102 let mut key_reader = BufReader::new(key.as_slice());
103 let key = rustls_pemfile::private_key(&mut key_reader)
104 .map_err(|e| {
105 SecurityError::certificate(format!("Failed to parse private key: {}", e))
106 })?
107 .ok_or_else(|| SecurityError::certificate("No private key found"))?;
108
109 ClientConfig::builder()
110 .with_root_certificates(root_store)
111 .with_client_auth_cert(certs, key)
112 .map_err(|e| {
113 SecurityError::certificate(format!("Failed to set client auth: {}", e))
114 })?
115 } else {
116 ClientConfig::builder()
117 .with_root_certificates(root_store)
118 .with_no_client_auth()
119 };
120
121 Ok(Arc::new(config))
122 }
123
124 pub fn build_server(self) -> Result<Arc<ServerConfig>> {
126 let cert = self
127 .server_cert
128 .ok_or_else(|| SecurityError::certificate("Server certificate required"))?;
129 let key = self
130 .server_key
131 .ok_or_else(|| SecurityError::certificate("Server private key required"))?;
132
133 let mut cert_reader = BufReader::new(cert.as_slice());
134 let certs = rustls_pemfile::certs(&mut cert_reader)
135 .collect::<std::result::Result<Vec<_>, _>>()
136 .map_err(|e| {
137 SecurityError::certificate(format!("Failed to parse server cert: {}", e))
138 })?;
139
140 let mut key_reader = BufReader::new(key.as_slice());
141 let private_key = rustls_pemfile::private_key(&mut key_reader)
142 .map_err(|e| SecurityError::certificate(format!("Failed to parse private key: {}", e)))?
143 .ok_or_else(|| SecurityError::certificate("No private key found"))?;
144
145 let config = if self.verify_peer {
146 if let Some(ca_cert) = self.ca_cert {
148 let mut root_store = rustls::RootCertStore::empty();
149 let mut reader = BufReader::new(ca_cert.as_slice());
150 let ca_certs = rustls_pemfile::certs(&mut reader)
151 .collect::<std::result::Result<Vec<_>, _>>()
152 .map_err(|e| {
153 SecurityError::certificate(format!("Failed to parse CA cert: {}", e))
154 })?;
155
156 for cert in ca_certs {
157 root_store.add(cert).map_err(|e| {
158 SecurityError::certificate(format!("Failed to add CA cert: {}", e))
159 })?;
160 }
161
162 let verifier = rustls::server::WebPkiClientVerifier::builder(Arc::new(root_store))
163 .build()
164 .map_err(|e| {
165 SecurityError::certificate(format!("Failed to build verifier: {}", e))
166 })?;
167
168 ServerConfig::builder()
169 .with_client_cert_verifier(verifier)
170 .with_single_cert(certs, private_key)
171 .map_err(|e| {
172 SecurityError::certificate(format!("Failed to build server config: {}", e))
173 })?
174 } else {
175 return Err(SecurityError::certificate(
176 "CA certificate required for client verification",
177 ));
178 }
179 } else {
180 ServerConfig::builder()
182 .with_no_client_auth()
183 .with_single_cert(certs, private_key)
184 .map_err(|e| {
185 SecurityError::certificate(format!("Failed to build server config: {}", e))
186 })?
187 };
188
189 Ok(Arc::new(config))
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
195pub enum TlsVersion {
196 Tls12,
198 Tls13,
200}
201
202#[derive(Debug, Clone)]
204pub struct CertificateValidation {
205 pub valid: bool,
207 pub errors: Vec<String>,
209 pub subject: Option<String>,
211 pub issuer: Option<String>,
213 pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
215}
216
217impl CertificateValidation {
218 pub fn valid() -> Self {
220 Self {
221 valid: true,
222 errors: Vec::new(),
223 subject: None,
224 issuer: None,
225 expires_at: None,
226 }
227 }
228
229 pub fn invalid(errors: Vec<String>) -> Self {
231 Self {
232 valid: false,
233 errors,
234 subject: None,
235 issuer: None,
236 expires_at: None,
237 }
238 }
239
240 pub fn add_error(&mut self, error: String) {
242 self.valid = false;
243 self.errors.push(error);
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_tls_config_builder() {
253 let builder = TlsConfigBuilder::new()
254 .server_name("example.com".to_string())
255 .verify_peer(true);
256
257 assert_eq!(builder.server_name, Some("example.com".to_string()));
259 assert!(builder.verify_peer);
260 }
261
262 #[test]
263 fn test_certificate_validation() {
264 let valid = CertificateValidation::valid();
265 assert!(valid.valid);
266 assert!(valid.errors.is_empty());
267
268 let invalid = CertificateValidation::invalid(vec!["expired".to_string()]);
269 assert!(!invalid.valid);
270 assert_eq!(invalid.errors.len(), 1);
271 }
272}