1use std::{collections::HashMap, sync::Arc};
52
53use parking_lot::RwLock;
54use anyhow::Result;
55use chrono::{DateTime, Utc};
56use rustls::ServerConfig;
57use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
58use keyring_core::{Entry, Error as KeyringError};
59
60use crate::dev_log;
61
62#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
64pub struct CertificateInfo {
65 pub subject:String,
67
68 pub issuer:String,
70
71 pub valid_from:String,
73
74 pub valid_until:String,
76
77 pub is_self_signed:bool,
79
80 pub sans:Vec<String>,
82}
83
84#[allow(dead_code)]
86#[derive(Clone)]
87struct ServerCertData {
88 cert_pem:Vec<u8>,
90
91 key_pem:Vec<u8>,
93
94 server_config:Arc<ServerConfig>,
96
97 info:CertificateInfo,
99
100 valid_until:DateTime<Utc>,
102}
103
104pub struct CertificateManager {
109 app_id:String,
111
112 ca_cert:Option<Vec<u8>>,
114
115 ca_key:Option<Vec<u8>>,
117
118 server_certs:Arc<RwLock<HashMap<String, ServerCertData>>>,
120}
121
122impl CertificateManager {
123 const KEYRING_SERVICE:&'static str = "CodeEditorLand-TLS";
125
126 const KEYRING_CA_CERT:&'static str = "ca_certificate";
128
129 const KEYRING_CA_KEY:&'static str = "ca_private_key";
131
132 const CA_VALIDITY_DAYS:i64 = 365 * 10;
134
135 const SERVER_VALIDITY_DAYS:i64 = 365;
137
138 pub const RENEWAL_THRESHOLD_DAYS:i64 = 30;
140
141 pub async fn new(app_id:&str) -> Result<Self> {
157 Ok(Self {
158 app_id:app_id.to_string(),
159 ca_cert:None,
160 ca_key:None,
161 server_certs:Arc::new(RwLock::new(HashMap::new())),
162 })
163 }
164
165 pub async fn initialize_ca(&mut self) -> Result<()> {
181 if let Some((cert, key)) = self.load_ca_from_keyring()? {
182 dev_log!("security", "loading CA certificate from keyring");
183
184 self.ca_cert = Some(cert.clone());
185
186 self.ca_key = Some(key.clone());
187
188 dev_log!("security", "CA certificate loaded successfully");
189 } else {
190 dev_log!("security", "CA certificate not found in keyring, generating new CA");
191
192 let (cert, key) = self.generate_ca_cert()?;
193
194 self.save_ca_to_keyring(&cert, &key)?;
196
197 self.ca_cert = Some(cert.clone());
198
199 self.ca_key = Some(key);
200
201 dev_log!("security", "new CA certificate generated and stored");
202 }
203
204 Ok(())
205 }
206
207 fn generate_ca_cert(&self) -> Result<(Vec<u8>, Vec<u8>)> {
218 dev_log!("security", "generating new CA certificate");
219
220 let key_pair = rcgen::KeyPair::generate()?;
224
225 let mut params = rcgen::CertificateParams::default();
227
228 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
229
230 params.distinguished_name = rcgen::DistinguishedName::new();
231
232 let not_before = rcgen::date_time_ymd(2024, 1, 1);
234
235 params.not_before = not_before;
236
237 let expiry_year:i32 = (2024 + Self::CA_VALIDITY_DAYS / 365) as i32;
238
239 let not_after = rcgen::date_time_ymd(expiry_year, 1, 1);
240
241 params.not_after = not_after;
242
243 params.key_usages = vec![
244 rcgen::KeyUsagePurpose::DigitalSignature,
245 rcgen::KeyUsagePurpose::KeyCertSign,
246 rcgen::KeyUsagePurpose::CrlSign,
247 ];
248
249 let cert = params.self_signed(&key_pair)?;
251
252 let cert_pem = cert.pem();
254
255 let key_pem = key_pair.serialize_pem();
256
257 dev_log!("security", "CA certificate generated successfully");
258
259 Ok((cert_pem.into_bytes(), key_pem.into_bytes()))
260 }
261
262 pub async fn get_server_cert(&self, hostname:&str) -> Result<Arc<ServerConfig>> {
284 {
286 let certs = self.server_certs.read();
287
288 if let Some(cert_data) = certs.get(hostname) {
289 if !self.should_renew(&cert_data.cert_pem) {
291 dev_log!("security", "using cached server certificate for {}", hostname);
292
293 return Ok(cert_data.server_config.clone());
294 }
295
296 drop(certs);
298 }
299 }
300
301 dev_log!("security", "generating server certificate for {}", hostname);
303
304 let cert_data = self.generate_server_cert(hostname)?;
305
306 {
308 let mut certs = self.server_certs.write();
309
310 certs.insert(hostname.to_string(), cert_data.clone());
311 }
312
313 Ok(cert_data.server_config)
314 }
315
316 fn generate_server_cert(&self, hostname:&str) -> Result<ServerCertData> {
324 let mut params = rcgen::CertificateParams::default();
326
327 params.distinguished_name.push(rcgen::DnType::CommonName, hostname);
328
329 let now = chrono::Utc::now();
331
332 let current_year = 2024; let current_month = 1;
334
335 let current_day = 1;
336
337 let not_before = rcgen::date_time_ymd(current_year, current_month, current_day);
338
339 params.not_before = not_before;
340
341 let not_after = rcgen::date_time_ymd(current_year + 1, current_month, current_day);
342
343 params.not_after = not_after;
344
345 params.key_usages = vec![
350 rcgen::KeyUsagePurpose::DigitalSignature,
351 rcgen::KeyUsagePurpose::KeyEncipherment,
352 ];
353
354 params.extended_key_usages = vec![
355 rcgen::ExtendedKeyUsagePurpose::ServerAuth,
356 rcgen::ExtendedKeyUsagePurpose::ClientAuth,
357 ];
358
359 let key_pair = rcgen::KeyPair::generate()?;
361
362 let cert = params.self_signed(&key_pair)?;
364
365 let server_cert_der = cert.der();
368
369 let server_key_der = key_pair.serialized_der();
370
371 let cert_der:Vec<u8> = server_cert_der.to_vec();
373
374 let key_der:Vec<u8> = server_key_der.to_vec();
375
376 let cert_der_for_info = cert_der.clone();
378
379 let cert_chain:Vec<CertificateDer<'static>> = vec![CertificateDer::from(cert_der)];
381
382 let private_key_der =
384 PrivatePkcs8KeyDer::try_from(key_der).map_err(|e| anyhow::anyhow!("Failed to parse private key: {}", e))?;
385
386 let private_key = PrivateKeyDer::Pkcs8(private_key_der);
387
388 let cert_pem:Vec<u8> = Vec::new();
390
391 let key_pem:Vec<u8> = Vec::new();
392
393 let mut server_config = ServerConfig::builder()
394 .with_no_client_auth()
395 .with_single_cert(cert_chain, private_key)
396 .map_err(|e| anyhow::anyhow!("Failed to create ServerConfig: {}", e))?;
397
398 server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
400
401 let info = self.extract_cert_info(&cert_der_for_info, hostname, true)?;
403
404 let valid_until = Utc::now() + chrono::Duration::days(Self::SERVER_VALIDITY_DAYS);
405
406 dev_log!(
407 "security",
408 "server certificate generated for {} (valid until {})",
409 hostname,
410 valid_until
411 );
412
413 Ok(ServerCertData { cert_pem, key_pem, server_config:Arc::new(server_config), info, valid_until })
414 }
415
416 fn load_ca_from_keyring(&self) -> Result<Option<(Vec<u8>, Vec<u8>)>> {
420 let keyring_entry_cert =
421 Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_CERT))
422 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
423
424 let keyring_entry_key = Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_KEY))
425 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
426
427 let cert = match keyring_entry_cert.get_password() {
428 Ok(s) => s.into_bytes(),
429
430 Err(KeyringError::NoEntry) => return Ok(None),
431
432 Err(e) => return Err(e.into()),
433 };
434
435 let key = keyring_entry_key
436 .get_password()
437 .map_err(|e| anyhow::anyhow!("Failed to load CA key from keyring: {}", e))?
438 .into_bytes();
439
440 dev_log!("security", "CA certificate loaded from keyring");
441
442 Ok(Some((cert, key)))
443 }
444
445 fn save_ca_to_keyring(&self, cert:&[u8], key:&[u8]) -> Result<()> {
447 let keyring_entry_cert =
448 Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_CERT))
449 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
450
451 let keyring_entry_key = Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_KEY))
452 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
453
454 let cert_str = String::from_utf8(cert.to_vec()).map_err(|e| anyhow::anyhow!("Invalid CA cert UTF-8: {}", e))?;
456
457 let key_str = String::from_utf8(key.to_vec()).map_err(|e| anyhow::anyhow!("Invalid CA key UTF-8: {}", e))?;
458
459 keyring_entry_cert
460 .set_password(&cert_str)
461 .map_err(|e| anyhow::anyhow!("Failed to save CA cert to keyring: {}", e))?;
462
463 keyring_entry_key
464 .set_password(&key_str)
465 .map_err(|e| anyhow::anyhow!("Failed to save CA key to keyring: {}", e))?;
466
467 dev_log!("security", "CA certificate saved to keyring");
468
469 Ok(())
470 }
471
472 pub fn should_renew(&self, cert_pem:&[u8]) -> bool {
477 if let Ok(result) = self.check_cert_validity(cert_pem) {
478 result.should_renew
479 } else {
480 dev_log!("security", "warn: could not parse certificate validity, forcing renewal");
482
483 true
484 }
485 }
486
487 pub async fn renew_certificate(&mut self, hostname:&str) -> Result<()> {
505 dev_log!("security", "forcing renewal of certificate for {}", hostname);
506
507 let mut certs = self.server_certs.write();
509
510 certs.remove(hostname);
511
512 drop(certs);
513
514 let cert_data = self.generate_server_cert(hostname)?;
516
517 let mut certs = self.server_certs.write();
519
520 certs.insert(hostname.to_string(), cert_data);
521
522 dev_log!("security", "certificate renewed for {}", hostname);
523
524 Ok(())
525 }
526
527 pub async fn build_server_config(&self, hostname:&str) -> Result<Arc<ServerConfig>> {
547 self.get_server_cert(hostname).await
548 }
549
550 pub fn get_ca_cert_pem(&self) -> Option<Vec<u8>> { self.ca_cert.clone() }
572
573 pub fn get_server_cert_info(&self, hostname:&str) -> Option<CertificateInfo> {
597 let certs = self.server_certs.read();
598
599 certs.get(hostname).map(|d| d.info.clone())
600 }
601
602 pub fn get_all_certs(&self) -> HashMap<String, CertificateInfo> {
625 let certs = self.server_certs.read();
626
627 certs.iter().map(|(k, v)| (k.clone(), v.info.clone())).collect()
628 }
629
630 #[allow(dead_code)]
632 fn cert_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
633 let pem = pem::Pem::new("CERTIFICATE".to_string(), der.to_vec());
634
635 let pem_str = pem::encode(&pem);
636
637 Ok(pem_str.into_bytes())
638 }
639
640 #[allow(dead_code)]
642 fn private_key_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
643 let pem = pem::Pem::new("PRIVATE KEY".to_string(), der.to_vec());
644
645 let pem_str = pem::encode(&pem);
646
647 Ok(pem_str.into_bytes())
648 }
649
650 fn pem_to_der(pem:&[u8], label:&str) -> Result<Vec<u8>> {
652 let pem_str = String::from_utf8(pem.to_vec()).map_err(|e| anyhow::anyhow!("Invalid PEM UTF-8: {}", e))?;
653
654 let pem = pem::parse(&pem_str).map_err(|e| anyhow::anyhow!("Failed to parse PEM: {}", e))?;
655
656 if pem.tag() != label {
657 return Err(anyhow::anyhow!("Expected PEM label '{}', found '{}'", label, pem.tag()));
658 }
659
660 Ok(pem.contents().to_vec())
661 }
662
663 fn extract_cert_info(&self, cert_der:&[u8], hostname:&str, is_ca:bool) -> Result<CertificateInfo> {
665 let cert = x509_parser::parse_x509_certificate(cert_der)
667 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
668 .1;
669
670 let subject = cert.subject().to_string();
671
672 let issuer = cert.issuer().to_string();
673
674 let valid_from = cert.validity().not_before.to_string();
675
676 let valid_until = cert.validity().not_after.to_string();
677
678 let mut sans = vec![hostname.to_string(), "127.0.0.1".to_string(), "::1".to_string()];
680
681 if let Some(ext) = cert
682 .extensions()
683 .iter()
684 .find(|e| e.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)
685 {
686 if let x509_parser::extensions::ParsedExtension::SubjectAlternativeName(sans_list) = ext.parsed_extension()
687 {
688 sans = sans_list
689 .general_names
690 .iter()
691 .filter_map(|gn| {
692 match gn {
693 x509_parser::extensions::GeneralName::DNSName(dns) => Some(dns.to_string()),
694 x509_parser::extensions::GeneralName::IPAddress(ip) => {
695 let octets:&[u8] = ip.as_ref();
696 Some(match octets.len() {
697 4 => format!("{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]),
698 16 => {
699 format!(
700 "::{}:{}:{}:{}:{}",
701 octets[0], octets[1], octets[2], octets[3], octets[4]
702 )
703 },
704 _ => "?".to_string(),
705 })
706 },
707 _ => None,
708 }
709 })
710 .collect();
711 }
712 }
713
714 Ok(CertificateInfo { subject, issuer, valid_from, valid_until, is_self_signed:is_ca, sans })
715 }
716
717 fn check_cert_validity(&self, cert_pem:&[u8]) -> Result<CertValidityResult> {
719 let cert_der = Self::pem_to_der(cert_pem, "CERTIFICATE")?;
720
721 let cert = x509_parser::parse_x509_certificate(&cert_der)
722 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
723 .1;
724
725 let not_after_chrono = Self::parse_not_after(&cert.validity().not_after)?;
726
727 let now = chrono::Utc::now();
728
729 let is_valid = now <= not_after_chrono;
730
731 let days_until_expiry = (not_after_chrono - now).num_days();
732
733 let should_renew = days_until_expiry <= Self::RENEWAL_THRESHOLD_DAYS;
734
735 Ok(CertValidityResult { is_valid, days_until_expiry, should_renew, not_after:not_after_chrono })
736 }
737
738 fn parse_not_after(not_after:&x509_parser::time::ASN1Time) -> Result<DateTime<Utc>> {
740 let timestamp = Self::not_as_unix_timestamp(not_after)
742 .ok_or_else(|| anyhow::anyhow!("Failed to convert not_after to timestamp"))?;
743
744 DateTime::from_timestamp(timestamp, 0)
745 .ok_or_else(|| anyhow::anyhow!("Invalid timestamp"))
746 .map(|dt| dt.to_utc())
747 }
748
749 fn not_as_unix_timestamp(not_after:&x509_parser::time::ASN1Time) -> Option<i64> {
751 let time_str = not_after.to_string();
754
755 let dt = chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%SZ")
758 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%S"))
759 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&format!("{}000000", time_str), "%Y%m%d%H%M%S"))
760 .ok()?;
761
762 Some(dt.and_utc().timestamp())
763 }
764}
765
766#[allow(dead_code)]
768#[derive(Debug, Clone)]
769struct CertValidityResult {
770 is_valid:bool,
772
773 days_until_expiry:i64,
775
776 should_renew:bool,
778
779 not_after:DateTime<Utc>,
781}
782
783#[cfg(test)]
784mod tests {
785
786 use super::*;
787
788 #[test]
789 fn test_pem_encoding() {
790 let test_data = b"test certificate data";
791
792 let pem = CertificateManager::cert_der_to_pem(test_data).unwrap();
793
794 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN CERTIFICATE-----"));
795
796 assert!(String::from_utf8_lossy(&pem).contains("-----END CERTIFICATE-----"));
797
798 let recovered = CertificateManager::pem_to_der(&pem, "CERTIFICATE").unwrap();
799
800 assert_eq!(recovered, test_data);
801 }
802
803 #[test]
804 fn test_private_key_pem_encoding() {
805 let test_data = b"test private key data";
806
807 let pem = CertificateManager::private_key_der_to_pem(test_data).unwrap();
808
809 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN PRIVATE KEY-----"));
810
811 assert!(String::from_utf8_lossy(&pem).contains("-----END PRIVATE KEY-----"));
812
813 let recovered = CertificateManager::pem_to_der(&pem, "PRIVATE KEY").unwrap();
814
815 assert_eq!(recovered, test_data);
816 }
817}