DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/Binary/Build/
CertificateManager.rs1use 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#[derive(Clone)]
86struct ServerCertData {
87 cert_pem:Vec<u8>,
89
90 key_pem:Vec<u8>,
92
93 server_config:Arc<ServerConfig>,
95
96 info:CertificateInfo,
98
99 valid_until:DateTime<Utc>,
101}
102
103pub struct CertificateManager {
108 app_id:String,
110
111 ca_cert:Option<Vec<u8>>,
113
114 ca_key:Option<Vec<u8>>,
116
117 server_certs:Arc<RwLock<HashMap<String, ServerCertData>>>,
119}
120
121impl CertificateManager {
122 const KEYRING_SERVICE:&'static str = "CodeEditorLand-TLS";
124
125 const KEYRING_CA_CERT:&'static str = "ca_certificate";
127
128 const KEYRING_CA_KEY:&'static str = "ca_private_key";
130
131 const CA_VALIDITY_DAYS:i64 = 365 * 10;
133
134 const SERVER_VALIDITY_DAYS:i64 = 365;
136
137 pub const RENEWAL_THRESHOLD_DAYS:i64 = 30;
139
140 pub async fn new(app_id:&str) -> Result<Self> {
156 Ok(Self {
157 app_id:app_id.to_string(),
158 ca_cert:None,
159 ca_key:None,
160 server_certs:Arc::new(RwLock::new(HashMap::new())),
161 })
162 }
163
164 pub async fn initialize_ca(&mut self) -> Result<()> {
180 if let Some((cert, key)) = self.load_ca_from_keyring()? {
181 dev_log!("security", "loading CA certificate from keyring");
182
183 self.ca_cert = Some(cert.clone());
184
185 self.ca_key = Some(key.clone());
186
187 dev_log!("security", "CA certificate loaded successfully");
188 } else {
189 dev_log!("security", "CA certificate not found in keyring, generating new CA");
190
191 let (cert, key) = self.generate_ca_cert()?;
192
193 self.save_ca_to_keyring(&cert, &key)?;
195
196 self.ca_cert = Some(cert.clone());
197
198 self.ca_key = Some(key);
199
200 dev_log!("security", "new CA certificate generated and stored");
201 }
202
203 Ok(())
204 }
205
206 fn generate_ca_cert(&self) -> Result<(Vec<u8>, Vec<u8>)> {
217 dev_log!("security", "generating new CA certificate");
218
219 let key_pair = rcgen::KeyPair::generate()?;
223
224 let mut params = rcgen::CertificateParams::default();
226
227 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
228
229 params.distinguished_name = rcgen::DistinguishedName::new();
230
231 let not_before = rcgen::date_time_ymd(2024, 1, 1);
233
234 params.not_before = not_before;
235
236 let expiry_year:i32 = (2024 + Self::CA_VALIDITY_DAYS / 365) as i32;
237
238 let not_after = rcgen::date_time_ymd(expiry_year, 1, 1);
239
240 params.not_after = not_after;
241
242 params.key_usages = vec![
243 rcgen::KeyUsagePurpose::DigitalSignature,
244 rcgen::KeyUsagePurpose::KeyCertSign,
245 rcgen::KeyUsagePurpose::CrlSign,
246 ];
247
248 let cert = params.self_signed(&key_pair)?;
250
251 let cert_pem = cert.pem();
253
254 let key_pem = key_pair.serialize_pem();
255
256 dev_log!("security", "CA certificate generated successfully");
257
258 Ok((cert_pem.into_bytes(), key_pem.into_bytes()))
259 }
260
261 pub async fn get_server_cert(&self, hostname:&str) -> Result<Arc<ServerConfig>> {
283 {
285 let certs = self.server_certs.read();
286
287 if let Some(cert_data) = certs.get(hostname) {
288 if !self.should_renew(&cert_data.cert_pem) {
290 dev_log!("security", "using cached server certificate for {}", hostname);
291
292 return Ok(cert_data.server_config.clone());
293 }
294
295 drop(certs);
297 }
298 }
299
300 dev_log!("security", "generating server certificate for {}", hostname);
302
303 let cert_data = self.generate_server_cert(hostname)?;
304
305 {
307 let mut certs = self.server_certs.write();
308
309 certs.insert(hostname.to_string(), cert_data.clone());
310 }
311
312 Ok(cert_data.server_config)
313 }
314
315 fn generate_server_cert(&self, hostname:&str) -> Result<ServerCertData> {
323 let mut params = rcgen::CertificateParams::default();
325
326 params.distinguished_name.push(rcgen::DnType::CommonName, hostname);
327
328 let now = chrono::Utc::now();
330
331 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 fn cert_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
632 let pem = pem::Pem::new("CERTIFICATE".to_string(), der.to_vec());
633
634 let pem_str = pem::encode(&pem);
635
636 Ok(pem_str.into_bytes())
637 }
638
639 fn private_key_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
641 let pem = pem::Pem::new("PRIVATE KEY".to_string(), der.to_vec());
642
643 let pem_str = pem::encode(&pem);
644
645 Ok(pem_str.into_bytes())
646 }
647
648 fn pem_to_der(pem:&[u8], label:&str) -> Result<Vec<u8>> {
650 let pem_str = String::from_utf8(pem.to_vec()).map_err(|e| anyhow::anyhow!("Invalid PEM UTF-8: {}", e))?;
651
652 let pem = pem::parse(&pem_str).map_err(|e| anyhow::anyhow!("Failed to parse PEM: {}", e))?;
653
654 if pem.tag() != label {
655 return Err(anyhow::anyhow!("Expected PEM label '{}', found '{}'", label, pem.tag()));
656 }
657
658 Ok(pem.contents().to_vec())
659 }
660
661 fn extract_cert_info(&self, cert_der:&[u8], hostname:&str, is_ca:bool) -> Result<CertificateInfo> {
663 let cert = x509_parser::parse_x509_certificate(cert_der)
665 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
666 .1;
667
668 let subject = cert.subject().to_string();
669
670 let issuer = cert.issuer().to_string();
671
672 let valid_from = cert.validity().not_before.to_string();
673
674 let valid_until = cert.validity().not_after.to_string();
675
676 let mut sans = vec![hostname.to_string(), "127.0.0.1".to_string(), "::1".to_string()];
678
679 if let Some(ext) = cert
680 .extensions()
681 .iter()
682 .find(|e| e.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)
683 {
684 if let x509_parser::extensions::ParsedExtension::SubjectAlternativeName(sans_list) = ext.parsed_extension()
685 {
686 sans = sans_list
687 .general_names
688 .iter()
689 .filter_map(|gn| {
690 match gn {
691 x509_parser::extensions::GeneralName::DNSName(dns) => Some(dns.to_string()),
692 x509_parser::extensions::GeneralName::IPAddress(ip) => {
693 let octets:&[u8] = ip.as_ref();
694 Some(match octets.len() {
695 4 => format!("{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]),
696 16 => {
697 format!(
698 "::{}:{}:{}:{}:{}",
699 octets[0], octets[1], octets[2], octets[3], octets[4]
700 )
701 },
702 _ => "?".to_string(),
703 })
704 },
705 _ => None,
706 }
707 })
708 .collect();
709 }
710 }
711
712 Ok(CertificateInfo { subject, issuer, valid_from, valid_until, is_self_signed:is_ca, sans })
713 }
714
715 fn check_cert_validity(&self, cert_pem:&[u8]) -> Result<CertValidityResult> {
717 let cert_der = Self::pem_to_der(cert_pem, "CERTIFICATE")?;
718
719 let cert = x509_parser::parse_x509_certificate(&cert_der)
720 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
721 .1;
722
723 let not_after_chrono = Self::parse_not_after(&cert.validity().not_after)?;
724
725 let now = chrono::Utc::now();
726
727 let is_valid = now <= not_after_chrono;
728
729 let days_until_expiry = (not_after_chrono - now).num_days();
730
731 let should_renew = days_until_expiry <= Self::RENEWAL_THRESHOLD_DAYS;
732
733 Ok(CertValidityResult { is_valid, days_until_expiry, should_renew, not_after:not_after_chrono })
734 }
735
736 fn parse_not_after(not_after:&x509_parser::time::ASN1Time) -> Result<DateTime<Utc>> {
738 let timestamp = Self::not_as_unix_timestamp(not_after)
740 .ok_or_else(|| anyhow::anyhow!("Failed to convert not_after to timestamp"))?;
741
742 DateTime::from_timestamp(timestamp, 0)
743 .ok_or_else(|| anyhow::anyhow!("Invalid timestamp"))
744 .map(|dt| dt.to_utc())
745 }
746
747 fn not_as_unix_timestamp(not_after:&x509_parser::time::ASN1Time) -> Option<i64> {
749 let time_str = not_after.to_string();
752
753 let dt = chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%SZ")
756 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%S"))
757 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&format!("{}000000", time_str), "%Y%m%d%H%M%S"))
758 .ok()?;
759
760 Some(dt.and_utc().timestamp())
761 }
762}
763
764#[derive(Debug, Clone)]
766struct CertValidityResult {
767 is_valid:bool,
769
770 days_until_expiry:i64,
772
773 should_renew:bool,
775
776 not_after:DateTime<Utc>,
778}
779
780#[cfg(test)]
781mod tests {
782
783 use super::*;
784
785 #[test]
786 fn test_pem_encoding() {
787 let test_data = b"test certificate data";
788
789 let pem = CertificateManager::cert_der_to_pem(test_data).unwrap();
790
791 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN CERTIFICATE-----"));
792
793 assert!(String::from_utf8_lossy(&pem).contains("-----END CERTIFICATE-----"));
794
795 let recovered = CertificateManager::pem_to_der(&pem, "CERTIFICATE").unwrap();
796
797 assert_eq!(recovered, test_data);
798 }
799
800 #[test]
801 fn test_private_key_pem_encoding() {
802 let test_data = b"test private key data";
803
804 let pem = CertificateManager::private_key_der_to_pem(test_data).unwrap();
805
806 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN PRIVATE KEY-----"));
807
808 assert!(String::from_utf8_lossy(&pem).contains("-----END PRIVATE KEY-----"));
809
810 let recovered = CertificateManager::pem_to_der(&pem, "PRIVATE KEY").unwrap();
811
812 assert_eq!(recovered, test_data);
813 }
814}