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;
335
336 let current_day = 1;
337
338 let not_before = rcgen::date_time_ymd(current_year, current_month, current_day);
339
340 params.not_before = not_before;
341
342 let not_after = rcgen::date_time_ymd(current_year + 1, current_month, current_day);
343
344 params.not_after = not_after;
345
346 params.key_usages = vec![
351 rcgen::KeyUsagePurpose::DigitalSignature,
352 rcgen::KeyUsagePurpose::KeyEncipherment,
353 ];
354
355 params.extended_key_usages = vec![
356 rcgen::ExtendedKeyUsagePurpose::ServerAuth,
357 rcgen::ExtendedKeyUsagePurpose::ClientAuth,
358 ];
359
360 let key_pair = rcgen::KeyPair::generate()?;
362
363 let cert = params.self_signed(&key_pair)?;
365
366 let server_cert_der = cert.der();
369
370 let server_key_der = key_pair.serialized_der();
371
372 let cert_der:Vec<u8> = server_cert_der.to_vec();
374
375 let key_der:Vec<u8> = server_key_der.to_vec();
376
377 let cert_der_for_info = cert_der.clone();
379
380 let cert_chain:Vec<CertificateDer<'static>> = vec![CertificateDer::from(cert_der)];
382
383 let private_key_der =
385 PrivatePkcs8KeyDer::try_from(key_der).map_err(|e| anyhow::anyhow!("Failed to parse private key: {}", e))?;
386
387 let private_key = PrivateKeyDer::Pkcs8(private_key_der);
388
389 let cert_pem:Vec<u8> = Vec::new();
391
392 let key_pem:Vec<u8> = Vec::new();
393
394 let mut server_config = ServerConfig::builder()
395 .with_no_client_auth()
396 .with_single_cert(cert_chain, private_key)
397 .map_err(|e| anyhow::anyhow!("Failed to create ServerConfig: {}", e))?;
398
399 server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
401
402 let info = self.extract_cert_info(&cert_der_for_info, hostname, true)?;
404
405 let valid_until = Utc::now() + chrono::Duration::days(Self::SERVER_VALIDITY_DAYS);
406
407 dev_log!(
408 "security",
409 "server certificate generated for {} (valid until {})",
410 hostname,
411 valid_until
412 );
413
414 Ok(ServerCertData { cert_pem, key_pem, server_config:Arc::new(server_config), info, valid_until })
415 }
416
417 fn load_ca_from_keyring(&self) -> Result<Option<(Vec<u8>, Vec<u8>)>> {
421 let keyring_entry_cert =
422 Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_CERT))
423 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
424
425 let keyring_entry_key = Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_KEY))
426 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
427
428 let cert = match keyring_entry_cert.get_password() {
429 Ok(s) => s.into_bytes(),
430
431 Err(KeyringError::NoEntry) => return Ok(None),
432
433 Err(e) => return Err(e.into()),
434 };
435
436 let key = keyring_entry_key
437 .get_password()
438 .map_err(|e| anyhow::anyhow!("Failed to load CA key from keyring: {}", e))?
439 .into_bytes();
440
441 dev_log!("security", "CA certificate loaded from keyring");
442
443 Ok(Some((cert, key)))
444 }
445
446 fn save_ca_to_keyring(&self, cert:&[u8], key:&[u8]) -> Result<()> {
448 let keyring_entry_cert =
449 Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_CERT))
450 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
451
452 let keyring_entry_key = Entry::new(Self::KEYRING_SERVICE, &format!("{}:{}", self.app_id, Self::KEYRING_CA_KEY))
453 .map_err(|e| anyhow::anyhow!("Failed to create keyring entry: {}", e))?;
454
455 let cert_str = String::from_utf8(cert.to_vec()).map_err(|e| anyhow::anyhow!("Invalid CA cert UTF-8: {}", e))?;
457
458 let key_str = String::from_utf8(key.to_vec()).map_err(|e| anyhow::anyhow!("Invalid CA key UTF-8: {}", e))?;
459
460 keyring_entry_cert
461 .set_password(&cert_str)
462 .map_err(|e| anyhow::anyhow!("Failed to save CA cert to keyring: {}", e))?;
463
464 keyring_entry_key
465 .set_password(&key_str)
466 .map_err(|e| anyhow::anyhow!("Failed to save CA key to keyring: {}", e))?;
467
468 dev_log!("security", "CA certificate saved to keyring");
469
470 Ok(())
471 }
472
473 pub fn should_renew(&self, cert_pem:&[u8]) -> bool {
478 if let Ok(result) = self.check_cert_validity(cert_pem) {
479 result.should_renew
480 } else {
481 dev_log!("security", "warn: could not parse certificate validity, forcing renewal");
483
484 true
485 }
486 }
487
488 pub async fn renew_certificate(&mut self, hostname:&str) -> Result<()> {
506 dev_log!("security", "forcing renewal of certificate for {}", hostname);
507
508 let mut certs = self.server_certs.write();
510
511 certs.remove(hostname);
512
513 drop(certs);
514
515 let cert_data = self.generate_server_cert(hostname)?;
517
518 let mut certs = self.server_certs.write();
520
521 certs.insert(hostname.to_string(), cert_data);
522
523 dev_log!("security", "certificate renewed for {}", hostname);
524
525 Ok(())
526 }
527
528 pub async fn build_server_config(&self, hostname:&str) -> Result<Arc<ServerConfig>> {
548 self.get_server_cert(hostname).await
549 }
550
551 pub fn get_ca_cert_pem(&self) -> Option<Vec<u8>> { self.ca_cert.clone() }
573
574 pub fn get_server_cert_info(&self, hostname:&str) -> Option<CertificateInfo> {
598 let certs = self.server_certs.read();
599
600 certs.get(hostname).map(|d| d.info.clone())
601 }
602
603 pub fn get_all_certs(&self) -> HashMap<String, CertificateInfo> {
626 let certs = self.server_certs.read();
627
628 certs.iter().map(|(k, v)| (k.clone(), v.info.clone())).collect()
629 }
630
631 #[allow(dead_code)]
633 fn cert_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
634 let pem = pem::Pem::new("CERTIFICATE".to_string(), der.to_vec());
635
636 let pem_str = pem::encode(&pem);
637
638 Ok(pem_str.into_bytes())
639 }
640
641 #[allow(dead_code)]
643 fn private_key_der_to_pem(der:&[u8]) -> Result<Vec<u8>> {
644 let pem = pem::Pem::new("PRIVATE KEY".to_string(), der.to_vec());
645
646 let pem_str = pem::encode(&pem);
647
648 Ok(pem_str.into_bytes())
649 }
650
651 fn pem_to_der(pem:&[u8], label:&str) -> Result<Vec<u8>> {
653 let pem_str = String::from_utf8(pem.to_vec()).map_err(|e| anyhow::anyhow!("Invalid PEM UTF-8: {}", e))?;
654
655 let pem = pem::parse(&pem_str).map_err(|e| anyhow::anyhow!("Failed to parse PEM: {}", e))?;
656
657 if pem.tag() != label {
658 return Err(anyhow::anyhow!("Expected PEM label '{}', found '{}'", label, pem.tag()));
659 }
660
661 Ok(pem.contents().to_vec())
662 }
663
664 fn extract_cert_info(&self, cert_der:&[u8], hostname:&str, is_ca:bool) -> Result<CertificateInfo> {
666 let cert = x509_parser::parse_x509_certificate(cert_der)
668 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
669 .1;
670
671 let subject = cert.subject().to_string();
672
673 let issuer = cert.issuer().to_string();
674
675 let valid_from = cert.validity().not_before.to_string();
676
677 let valid_until = cert.validity().not_after.to_string();
678
679 let mut sans = vec![hostname.to_string(), "127.0.0.1".to_string(), "::1".to_string()];
681
682 if let Some(ext) = cert
683 .extensions()
684 .iter()
685 .find(|e| e.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)
686 {
687 if let x509_parser::extensions::ParsedExtension::SubjectAlternativeName(sans_list) = ext.parsed_extension()
688 {
689 sans = sans_list
690 .general_names
691 .iter()
692 .filter_map(|gn| {
693 match gn {
694 x509_parser::extensions::GeneralName::DNSName(dns) => Some(dns.to_string()),
695 x509_parser::extensions::GeneralName::IPAddress(ip) => {
696 let octets:&[u8] = ip.as_ref();
697 Some(match octets.len() {
698 4 => format!("{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]),
699 16 => {
700 format!(
701 "::{}:{}:{}:{}:{}",
702 octets[0], octets[1], octets[2], octets[3], octets[4]
703 )
704 },
705 _ => "?".to_string(),
706 })
707 },
708 _ => None,
709 }
710 })
711 .collect();
712 }
713 }
714
715 Ok(CertificateInfo { subject, issuer, valid_from, valid_until, is_self_signed:is_ca, sans })
716 }
717
718 fn check_cert_validity(&self, cert_pem:&[u8]) -> Result<CertValidityResult> {
720 let cert_der = Self::pem_to_der(cert_pem, "CERTIFICATE")?;
721
722 let cert = x509_parser::parse_x509_certificate(&cert_der)
723 .map_err(|e| anyhow::anyhow!("Failed to parse certificate: {}", e))?
724 .1;
725
726 let not_after_chrono = Self::parse_not_after(&cert.validity().not_after)?;
727
728 let now = chrono::Utc::now();
729
730 let is_valid = now <= not_after_chrono;
731
732 let days_until_expiry = (not_after_chrono - now).num_days();
733
734 let should_renew = days_until_expiry <= Self::RENEWAL_THRESHOLD_DAYS;
735
736 Ok(CertValidityResult { is_valid, days_until_expiry, should_renew, not_after:not_after_chrono })
737 }
738
739 fn parse_not_after(not_after:&x509_parser::time::ASN1Time) -> Result<DateTime<Utc>> {
741 let timestamp = Self::not_as_unix_timestamp(not_after)
743 .ok_or_else(|| anyhow::anyhow!("Failed to convert not_after to timestamp"))?;
744
745 DateTime::from_timestamp(timestamp, 0)
746 .ok_or_else(|| anyhow::anyhow!("Invalid timestamp"))
747 .map(|dt| dt.to_utc())
748 }
749
750 fn not_as_unix_timestamp(not_after:&x509_parser::time::ASN1Time) -> Option<i64> {
752 let time_str = not_after.to_string();
755
756 let dt = chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%SZ")
759 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&time_str, "%Y%m%d%H%M%S"))
760 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&format!("{}000000", time_str), "%Y%m%d%H%M%S"))
761 .ok()?;
762
763 Some(dt.and_utc().timestamp())
764 }
765}
766
767#[allow(dead_code)]
769#[derive(Debug, Clone)]
770struct CertValidityResult {
771 is_valid:bool,
773
774 days_until_expiry:i64,
776
777 should_renew:bool,
779
780 not_after:DateTime<Utc>,
782}
783
784#[cfg(test)]
785mod tests {
786
787 use super::*;
788
789 #[test]
790 fn test_pem_encoding() {
791 let test_data = b"test certificate data";
792
793 let pem = CertificateManager::cert_der_to_pem(test_data).unwrap();
794
795 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN CERTIFICATE-----"));
796
797 assert!(String::from_utf8_lossy(&pem).contains("-----END CERTIFICATE-----"));
798
799 let recovered = CertificateManager::pem_to_der(&pem, "CERTIFICATE").unwrap();
800
801 assert_eq!(recovered, test_data);
802 }
803
804 #[test]
805 fn test_private_key_pem_encoding() {
806 let test_data = b"test private key data";
807
808 let pem = CertificateManager::private_key_der_to_pem(test_data).unwrap();
809
810 assert!(String::from_utf8_lossy(&pem).contains("-----BEGIN PRIVATE KEY-----"));
811
812 assert!(String::from_utf8_lossy(&pem).contains("-----END PRIVATE KEY-----"));
813
814 let recovered = CertificateManager::pem_to_der(&pem, "PRIVATE KEY").unwrap();
815
816 assert_eq!(recovered, test_data);
817 }
818}