irontide_engine/
ssl_manager.rs1use std::sync::Arc;
7
8use irontide_wire::ssl::{self, SslConfig};
9
10use irontide_settings::Settings;
11
12pub struct SslManager {
16 our_cert_pem: Vec<u8>,
18 our_key_pem: Vec<u8>,
20}
21
22impl SslManager {
23 pub fn new(settings: &Settings) -> crate::Result<Self> {
32 let (cert_pem, key_pem) = if let (Some(cert_path), Some(key_path)) =
33 (&settings.ssl_cert_path, &settings.ssl_key_path)
34 {
35 let cert = std::fs::read(cert_path).map_err(|e| {
36 crate::Error::Config(format!(
37 "failed to read SSL cert {}: {e}",
38 cert_path.display()
39 ))
40 })?;
41 let key = std::fs::read(key_path).map_err(|e| {
42 crate::Error::Config(format!(
43 "failed to read SSL key {}: {e}",
44 key_path.display()
45 ))
46 })?;
47 (cert, key)
48 } else {
49 let (cert, key) = ssl::generate_self_signed_cert()
51 .map_err(|e| crate::Error::Config(format!("SSL cert generation: {e}")))?;
52
53 if let Some(ref dir) = settings.resume_data_dir {
55 let cert_path = dir.join("ssl_cert.pem");
56 let key_path = dir.join("ssl_key.pem");
57 let _ = std::fs::create_dir_all(dir);
59 let _ = std::fs::write(&cert_path, &cert);
60 let _ = std::fs::write(&key_path, &key);
61 }
62
63 (cert, key)
64 };
65
66 Ok(Self {
67 our_cert_pem: cert_pem,
68 our_key_pem: key_pem,
69 })
70 }
71
72 #[must_use]
74 pub fn from_pem(cert_pem: Vec<u8>, key_pem: Vec<u8>) -> Self {
75 Self {
76 our_cert_pem: cert_pem,
77 our_key_pem: key_pem,
78 }
79 }
80
81 #[must_use]
83 pub fn config_for_torrent(&self, ca_cert_pem: &[u8]) -> SslConfig {
84 SslConfig {
85 ca_cert_pem: ca_cert_pem.to_vec(),
86 our_cert_pem: self.our_cert_pem.clone(),
87 our_key_pem: self.our_key_pem.clone(),
88 }
89 }
90
91 pub fn client_config(
96 &self,
97 ca_cert_pem: &[u8],
98 ) -> Result<Arc<rustls::ClientConfig>, irontide_wire::Error> {
99 let config = self.config_for_torrent(ca_cert_pem);
100 ssl::build_client_config(&config)
101 }
102
103 pub fn server_config(
108 &self,
109 ca_cert_pem: &[u8],
110 ) -> Result<Arc<rustls::ServerConfig>, irontide_wire::Error> {
111 let config = self.config_for_torrent(ca_cert_pem);
112 ssl::build_server_config(&config)
113 }
114
115 #[must_use]
117 pub fn cert_pem(&self) -> &[u8] {
118 &self.our_cert_pem
119 }
120
121 #[must_use]
123 pub fn key_pem(&self) -> &[u8] {
124 &self.our_key_pem
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn ssl_manager_generates_cert() {
134 let settings = Settings::default();
135 let mgr = SslManager::new(&settings).unwrap();
136
137 assert!(!mgr.cert_pem().is_empty());
139 assert!(!mgr.key_pem().is_empty());
140 assert!(mgr.cert_pem().starts_with(b"-----BEGIN CERTIFICATE-----"));
141 assert!(
142 mgr.key_pem().starts_with(b"-----BEGIN PRIVATE KEY-----")
143 || mgr
144 .key_pem()
145 .starts_with(b"-----BEGIN RSA PRIVATE KEY-----")
146 || mgr.key_pem().starts_with(b"-----BEGIN EC PRIVATE KEY-----")
147 );
148 }
149
150 #[test]
151 fn ssl_manager_builds_config() {
152 let settings = Settings::default();
153 let mgr = SslManager::new(&settings).unwrap();
154
155 let ca_cert = mgr.cert_pem().to_vec();
157
158 let client_cfg = mgr.client_config(&ca_cert).unwrap();
160 assert!(Arc::strong_count(&client_cfg) >= 1);
161
162 let server_cfg = mgr.server_config(&ca_cert).unwrap();
163 assert!(Arc::strong_count(&server_cfg) >= 1);
164
165 let ssl_config = mgr.config_for_torrent(&ca_cert);
167 assert_eq!(ssl_config.ca_cert_pem, ca_cert);
168 assert_eq!(ssl_config.our_cert_pem, mgr.cert_pem());
169 assert_eq!(ssl_config.our_key_pem, mgr.key_pem());
170 }
171
172 #[test]
173 fn ssl_manager_from_pem_round_trip() {
174 let settings = Settings::default();
176 let original = SslManager::new(&settings).unwrap();
177
178 let restored =
179 SslManager::from_pem(original.cert_pem().to_vec(), original.key_pem().to_vec());
180
181 assert_eq!(restored.cert_pem(), original.cert_pem());
182 assert_eq!(restored.key_pem(), original.key_pem());
183
184 let ca_cert = restored.cert_pem().to_vec();
186 restored.client_config(&ca_cert).unwrap();
187 restored.server_config(&ca_cert).unwrap();
188 }
189}