1use super::{CertificateChainResult, CertificateInfo, CryptoConfig, CryptoError, CryptoResult};
2
3pub type X509Certificate = CertificateInfo;
4pub type CertificateChain = Vec<CertificateInfo>;
5
6#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
7pub enum RevocationProtocol {
8 Ocsp,
9 Crl,
10}
11
12#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
13pub struct RevocationEvent {
14 pub cert_index: usize,
15 pub url: String,
16 pub protocol: RevocationProtocol,
17 pub status: String,
18 pub latency_ms: u128,
19 pub error: Option<String>,
20}
21
22#[cfg(feature = "crypto")]
23use openssl::ocsp::{OcspCertId, OcspResponse, OcspResponseStatus};
24#[cfg(feature = "crypto")]
25use openssl::x509::{X509Crl, X509};
26#[cfg(feature = "crypto")]
27use reqwest::blocking::Client;
28#[cfg(feature = "crypto")]
29use std::time::Duration;
30#[cfg(feature = "crypto")]
31use std::time::Instant;
32
33pub struct CertificateChainValidator {
35 trust_stores: Vec<TrustStore>,
36 config: CryptoConfig,
37}
38
39impl CertificateChainValidator {
40 pub fn new(config: CryptoConfig) -> CryptoResult<Self> {
41 let mut validator = Self {
42 trust_stores: Vec::new(),
43 config: config.clone(),
44 };
45
46 if let Some(trust_store_path) = &config.trust_store_path {
48 validator.add_trust_store_from_path(trust_store_path)?;
49 } else {
50 validator.add_system_trust_store()?;
51 }
52
53 Ok(validator)
54 }
55
56 pub fn add_trust_store_from_path(&mut self, path: &str) -> CryptoResult<()> {
58 let trust_store = TrustStore::from_path(path)?;
59 self.trust_stores.push(trust_store);
60 Ok(())
61 }
62
63 pub fn add_system_trust_store(&mut self) -> CryptoResult<()> {
65 let trust_store = TrustStore::system_default()?;
66 self.trust_stores.push(trust_store);
67 Ok(())
68 }
69
70 pub fn validate_chain(&self, cert_chain: &[&[u8]]) -> CryptoResult<CertificateChainResult> {
72 if cert_chain.is_empty() {
73 return Ok(CertificateChainResult {
74 is_valid: false,
75 chain: Vec::new(),
76 trust_anchor: None,
77 validation_errors: vec!["Empty certificate chain".to_string()],
78 validation_warnings: Vec::new(),
79 });
80 }
81
82 let mut parsed_certs = Vec::new();
84 for (i, cert_data) in cert_chain.iter().enumerate() {
85 match self.parse_certificate(cert_data) {
86 Ok(cert) => parsed_certs.push(cert),
87 Err(e) => {
88 return Ok(CertificateChainResult {
89 is_valid: false,
90 chain: parsed_certs,
91 trust_anchor: None,
92 validation_errors: vec![format!(
93 "Failed to parse certificate {}: {}",
94 i, e
95 )],
96 validation_warnings: Vec::new(),
97 });
98 }
99 }
100 }
101
102 self.validate_parsed_chain(&parsed_certs, cert_chain)
104 }
105
106 fn validate_parsed_chain(
108 &self,
109 chain: &[CertificateInfo],
110 chain_raw: &[&[u8]],
111 ) -> CryptoResult<CertificateChainResult> {
112 let mut validation_errors = Vec::new();
113 let mut validation_warnings = Vec::new();
114
115 if chain.len() > self.config.max_cert_chain_depth as usize {
117 validation_errors.push(format!(
118 "Certificate chain too long: {} certificates (max: {})",
119 chain.len(),
120 self.config.max_cert_chain_depth
121 ));
122 }
123
124 for (i, cert) in chain.iter().enumerate() {
126 let cert_errors = self.validate_single_certificate(cert);
127 if !cert_errors.is_empty() {
128 validation_errors.append(
129 &mut cert_errors
130 .into_iter()
131 .map(|e| format!("Certificate {}: {}", i, e))
132 .collect(),
133 );
134 }
135 }
136
137 let chain_errors = self.validate_chain_structure(chain);
139 validation_errors.extend(chain_errors);
140
141 let trust_anchor = self.find_trust_anchor(chain);
143 if trust_anchor.is_none() {
144 validation_errors.push("No trusted root certificate found".to_string());
145 }
146
147 if self.config.enable_crl_checking {
149 let crl_warnings = self.check_crl_status(chain, chain_raw);
150 validation_warnings.extend(crl_warnings);
151 }
152
153 if self.config.enable_ocsp_checking {
154 let ocsp_warnings = self.check_ocsp_status(chain, chain_raw);
155 validation_warnings.extend(ocsp_warnings);
156 }
157
158 Ok(CertificateChainResult {
159 is_valid: validation_errors.is_empty(),
160 chain: chain.to_vec(),
161 trust_anchor,
162 validation_errors,
163 validation_warnings,
164 })
165 }
166
167 pub fn validate_chain_with_revocation_details(
169 &self,
170 cert_chain: &[&[u8]],
171 ) -> CryptoResult<(CertificateChainResult, Vec<RevocationEvent>)> {
172 if cert_chain.is_empty() {
173 return Ok((
174 CertificateChainResult {
175 is_valid: false,
176 chain: Vec::new(),
177 trust_anchor: None,
178 validation_errors: vec!["Empty certificate chain".to_string()],
179 validation_warnings: Vec::new(),
180 },
181 Vec::new(),
182 ));
183 }
184
185 let mut parsed_certs = Vec::new();
186 for (i, cert_data) in cert_chain.iter().enumerate() {
187 match self.parse_certificate(cert_data) {
188 Ok(cert) => parsed_certs.push(cert),
189 Err(e) => {
190 return Ok((
191 CertificateChainResult {
192 is_valid: false,
193 chain: parsed_certs,
194 trust_anchor: None,
195 validation_errors: vec![format!(
196 "Failed to parse certificate {}: {}",
197 i, e
198 )],
199 validation_warnings: Vec::new(),
200 },
201 Vec::new(),
202 ));
203 }
204 }
205 }
206
207 let mut events = Vec::new();
208 let mut result = self.validate_parsed_chain(&parsed_certs, cert_chain)?;
209
210 if self.config.enable_crl_checking {
211 let (warnings, crl_events) = self.check_crl_status_details(&parsed_certs, cert_chain);
212 result.validation_warnings.extend(warnings);
213 events.extend(crl_events);
214 }
215
216 if self.config.enable_ocsp_checking {
217 let (warnings, ocsp_events) = self.check_ocsp_status_details(&parsed_certs, cert_chain);
218 result.validation_warnings.extend(warnings);
219 events.extend(ocsp_events);
220 }
221
222 Ok((result, events))
223 }
224
225 fn parse_certificate(&self, cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
227 #[cfg(feature = "crypto")]
228 {
229 self.parse_certificate_openssl(cert_data)
230 }
231 #[cfg(not(feature = "crypto"))]
232 {
233 self.parse_certificate_simple(cert_data)
234 }
235 }
236
237 #[cfg(feature = "crypto")]
238 fn parse_certificate_openssl(&self, cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
239 let cert = X509CertificateImpl::from_der(cert_data)?;
241
242 Ok(CertificateInfo {
243 subject: cert.subject_string(),
244 issuer: cert.issuer_string(),
245 serial_number: cert.serial_number_hex(),
246 der: cert_data.to_vec(),
247 not_before: cert.not_before(),
248 not_after: cert.not_after(),
249 public_key_algorithm: cert.public_key_algorithm(),
250 signature_algorithm: cert.signature_algorithm(),
251 key_usage: cert.key_usage(),
252 extended_key_usage: cert.extended_key_usage(),
253 is_ca: cert.is_ca(),
254 fingerprint_sha256: cert.fingerprint_sha256(),
255 })
256 }
257
258 #[cfg(not(feature = "crypto"))]
259 fn parse_certificate_simple(&self, cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
260 if cert_data.len() < 100 {
262 return Err(CryptoError::CertificateError(
263 "Certificate data too short".to_string(),
264 ));
265 }
266
267 if !cert_data.starts_with(&[0x30, 0x82]) && !cert_data.starts_with(&[0x30, 0x81]) {
269 return Err(CryptoError::CertificateError(
270 "Invalid certificate format".to_string(),
271 ));
272 }
273
274 let parser = SimpleDerParser::new(cert_data);
276 let cert_info = parser.parse_x509()?;
277
278 Ok(cert_info)
279 }
280
281 fn validate_single_certificate(&self, cert: &CertificateInfo) -> Vec<String> {
283 let mut errors = Vec::new();
284 let now = super::chrono::Utc::now();
285
286 if cert.not_before.timestamp() > now.timestamp() {
288 errors.push("Certificate is not yet valid".to_string());
289 }
290 if cert.not_after.timestamp() < now.timestamp() {
291 errors.push("Certificate has expired".to_string());
292 }
293
294 if !cert.key_usage.contains(&"Digital Signature".to_string()) {
296 errors.push("Certificate does not have Digital Signature key usage".to_string());
297 }
298
299 if cert.subject.is_empty() {
301 errors.push("Certificate subject is empty".to_string());
302 }
303 if cert.issuer.is_empty() {
304 errors.push("Certificate issuer is empty".to_string());
305 }
306
307 errors
308 }
309
310 fn validate_chain_structure(&self, chain: &[CertificateInfo]) -> Vec<String> {
312 let mut errors = Vec::new();
313
314 if chain.is_empty() {
315 return vec!["Empty certificate chain".to_string()];
316 }
317
318 for i in 0..chain.len().saturating_sub(1) {
320 let current = &chain[i];
321 let issuer_cert = &chain[i + 1];
322
323 if current.issuer != issuer_cert.subject {
324 errors.push(format!(
325 "Certificate {} issuer '{}' does not match certificate {} subject '{}'",
326 i,
327 current.issuer,
328 i + 1,
329 issuer_cert.subject
330 ));
331 }
332
333 if !issuer_cert.is_ca {
335 errors.push(format!(
336 "Certificate {} is not a CA but is used to sign certificate {}",
337 i + 1,
338 i
339 ));
340 }
341 }
342
343 if let Some(root) = chain.last() {
345 if root.subject != root.issuer && !self.is_trusted_root(root) {
346 errors
347 .push("Root certificate is not self-signed and not in trust store".to_string());
348 }
349 }
350
351 errors
352 }
353
354 fn find_trust_anchor(&self, chain: &[CertificateInfo]) -> Option<CertificateInfo> {
356 for cert in chain.iter().rev() {
357 if self.is_trusted_root(cert) {
358 return Some(cert.clone());
359 }
360 }
361 None
362 }
363
364 fn is_trusted_root(&self, cert: &CertificateInfo) -> bool {
366 for trust_store in &self.trust_stores {
367 if trust_store.contains_certificate(cert) {
368 return true;
369 }
370 }
371 false
372 }
373
374 #[cfg(feature = "crypto")]
375 fn find_issuer_cert_der<'a>(&self, chain_raw: &'a [&[u8]], index: usize) -> Option<&'a [u8]> {
376 if index + 1 < chain_raw.len() {
377 return Some(chain_raw[index + 1]);
378 }
379
380 let issuer = parse_x509(chain_raw[index]).ok()?.issuer().to_string();
381 for (pos, candidate) in chain_raw.iter().enumerate() {
382 if pos == index {
383 continue;
384 }
385 if let Ok(cert) = parse_x509(candidate) {
386 if cert.subject().to_string() == issuer {
387 return Some(*candidate);
388 }
389 }
390 }
391
392 None
393 }
394
395 #[cfg(feature = "crypto")]
396 fn http_client(&self) -> Result<Client, String> {
397 Client::builder()
398 .timeout(Duration::from_secs(
399 self.config.network_timeout_seconds as u64,
400 ))
401 .build()
402 .map_err(|e| format!("Failed to build HTTP client: {}", e))
403 }
404
405 #[cfg(feature = "crypto")]
406 fn http_get_bytes(&self, url: &str) -> Result<Vec<u8>, String> {
407 let client = self.http_client()?;
408 let response = client
409 .get(url)
410 .send()
411 .map_err(|e| format!("HTTP GET failed: {}", e))?;
412 if !response.status().is_success() {
413 return Err(format!("HTTP GET status {}", response.status()));
414 }
415 response
416 .bytes()
417 .map(|b| b.to_vec())
418 .map_err(|e| format!("HTTP GET body error: {}", e))
419 }
420
421 #[cfg(feature = "crypto")]
422 fn http_post_ocsp(&self, url: &str, body: &[u8]) -> Result<Vec<u8>, String> {
423 let client = self.http_client()?;
424 let response = client
425 .post(url)
426 .header("Content-Type", "application/ocsp-request")
427 .header("Accept", "application/ocsp-response")
428 .body(body.to_vec())
429 .send()
430 .map_err(|e| format!("HTTP POST failed: {}", e))?;
431 if !response.status().is_success() {
432 return Err(format!("HTTP POST status {}", response.status()));
433 }
434 response
435 .bytes()
436 .map(|b| b.to_vec())
437 .map_err(|e| format!("HTTP POST body error: {}", e))
438 }
439
440 fn check_crl_status(&self, chain: &[CertificateInfo], chain_raw: &[&[u8]]) -> Vec<String> {
442 self.check_crl_status_details(chain, chain_raw).0
443 }
444
445 fn check_crl_status_details(
446 &self,
447 chain: &[CertificateInfo],
448 chain_raw: &[&[u8]],
449 ) -> (Vec<String>, Vec<RevocationEvent>) {
450 #[cfg(not(feature = "crypto"))]
451 {
452 let _ = chain;
453 let _ = chain_raw;
454 return (
455 vec!["CRL checking requires crypto feature".to_string()],
456 Vec::new(),
457 );
458 }
459
460 #[cfg(feature = "crypto")]
461 {
462 let mut warnings = Vec::new();
463 let mut events = Vec::new();
464 let _ = chain;
465
466 for (i, cert_bytes) in chain_raw.iter().enumerate() {
467 let urls = extract_crl_urls(cert_bytes);
468 if urls.is_empty() {
469 continue;
470 }
471
472 let issuer_der = self.find_issuer_cert_der(chain_raw, i);
473 let issuer_x509 = issuer_der.and_then(|der| X509::from_der(der).ok());
474 let cert_x509 = X509::from_der(cert_bytes).ok();
475
476 for url in urls {
477 if !(url.starts_with("http://") || url.starts_with("https://")) {
478 warnings.push(format!(
479 "CRL URL for certificate {} uses unsupported scheme: {}",
480 i, url
481 ));
482 events.push(RevocationEvent {
483 cert_index: i,
484 url,
485 protocol: RevocationProtocol::Crl,
486 status: "unsupported_scheme".to_string(),
487 latency_ms: 0,
488 error: None,
489 });
490 continue;
491 }
492
493 let start = Instant::now();
494 let crl_data = match self.http_get_bytes(&url) {
495 Ok(data) => data,
496 Err(err) => {
497 warnings.push(format!(
498 "Failed to fetch CRL for certificate {}: {}",
499 i, err
500 ));
501 events.push(RevocationEvent {
502 cert_index: i,
503 url,
504 protocol: RevocationProtocol::Crl,
505 status: "fetch_failed".to_string(),
506 latency_ms: start.elapsed().as_millis(),
507 error: Some(err),
508 });
509 continue;
510 }
511 };
512
513 let crl = if crl_data.starts_with(b"-----BEGIN") {
514 X509Crl::from_pem(&crl_data)
515 } else {
516 X509Crl::from_der(&crl_data)
517 };
518
519 let crl = match crl {
520 Ok(crl) => crl,
521 Err(err) => {
522 warnings.push(format!(
523 "Failed to parse CRL for certificate {}: {}",
524 i, err
525 ));
526 events.push(RevocationEvent {
527 cert_index: i,
528 url,
529 protocol: RevocationProtocol::Crl,
530 status: "parse_failed".to_string(),
531 latency_ms: start.elapsed().as_millis(),
532 error: Some(err.to_string()),
533 });
534 continue;
535 }
536 };
537
538 if let Some(issuer) = issuer_x509.as_ref() {
539 if let Ok(key) = issuer.public_key() {
540 if !crl.verify(&key).unwrap_or(false) {
541 warnings.push(format!(
542 "CRL signature verification failed for certificate {}",
543 i
544 ));
545 events.push(RevocationEvent {
546 cert_index: i,
547 url: url.clone(),
548 protocol: RevocationProtocol::Crl,
549 status: "signature_invalid".to_string(),
550 latency_ms: start.elapsed().as_millis(),
551 error: None,
552 });
553 }
554 }
555 }
556
557 let mut is_revoked = false;
558 if let (Some(cert), Some(revoked_stack)) =
559 (cert_x509.as_ref(), crl.get_revoked())
560 {
561 if let Ok(serial) = cert.serial_number().to_bn() {
562 for revoked in revoked_stack {
563 if let Ok(revoked_serial) = revoked.serial_number().to_bn() {
564 if revoked_serial == serial {
565 is_revoked = true;
566 warnings.push(format!(
567 "Certificate {} is revoked per CRL ({})",
568 i, url
569 ));
570 break;
571 }
572 }
573 }
574 }
575 }
576
577 events.push(RevocationEvent {
578 cert_index: i,
579 url,
580 protocol: RevocationProtocol::Crl,
581 status: if is_revoked { "revoked" } else { "ok" }.to_string(),
582 latency_ms: start.elapsed().as_millis(),
583 error: None,
584 });
585 }
586 }
587
588 (warnings, events)
589 }
590 }
591
592 fn check_ocsp_status(&self, chain: &[CertificateInfo], chain_raw: &[&[u8]]) -> Vec<String> {
594 self.check_ocsp_status_details(chain, chain_raw).0
595 }
596
597 fn check_ocsp_status_details(
598 &self,
599 chain: &[CertificateInfo],
600 chain_raw: &[&[u8]],
601 ) -> (Vec<String>, Vec<RevocationEvent>) {
602 #[cfg(not(feature = "crypto"))]
603 {
604 let _ = chain;
605 let _ = chain_raw;
606 return (
607 vec!["OCSP checking requires crypto feature".to_string()],
608 Vec::new(),
609 );
610 }
611
612 #[cfg(feature = "crypto")]
613 {
614 use openssl::hash::MessageDigest;
615 use openssl::ocsp::{OcspFlag, OcspRequest};
616 use openssl::stack::Stack;
617 use openssl::x509::store::X509StoreBuilder;
618
619 let mut warnings = Vec::new();
620 let mut events = Vec::new();
621 let _ = chain;
622
623 for (i, cert_bytes) in chain_raw.iter().enumerate() {
624 let urls = extract_ocsp_urls(cert_bytes);
625 if urls.is_empty() {
626 continue;
627 }
628
629 let issuer_der = self.find_issuer_cert_der(chain_raw, i);
630 let issuer_der = match issuer_der {
631 Some(der) => der,
632 None => {
633 warnings.push(format!("OCSP issuer not found for certificate {}", i));
634 continue;
635 }
636 };
637
638 let cert_x509 = match X509::from_der(cert_bytes) {
639 Ok(cert) => cert,
640 Err(err) => {
641 warnings.push(format!(
642 "Failed to parse certificate {} for OCSP: {}",
643 i, err
644 ));
645 continue;
646 }
647 };
648
649 let issuer_x509 = match X509::from_der(issuer_der) {
650 Ok(cert) => cert,
651 Err(err) => {
652 warnings.push(format!(
653 "Failed to parse issuer for certificate {}: {}",
654 i, err
655 ));
656 continue;
657 }
658 };
659
660 let cert_id_for_req =
661 match OcspCertId::from_cert(MessageDigest::sha1(), &cert_x509, &issuer_x509) {
662 Ok(id) => id,
663 Err(err) => {
664 warnings.push(format!(
665 "Failed to build OCSP CertId for certificate {}: {}",
666 i, err
667 ));
668 continue;
669 }
670 };
671
672 let cert_id_for_status =
673 match OcspCertId::from_cert(MessageDigest::sha1(), &cert_x509, &issuer_x509) {
674 Ok(id) => id,
675 Err(err) => {
676 warnings.push(format!(
677 "Failed to build OCSP CertId for certificate {}: {}",
678 i, err
679 ));
680 continue;
681 }
682 };
683
684 let mut ocsp_req = match OcspRequest::new() {
685 Ok(req) => req,
686 Err(err) => {
687 warnings.push(format!(
688 "Failed to create OCSP request for certificate {}: {}",
689 i, err
690 ));
691 continue;
692 }
693 };
694 if let Err(err) = ocsp_req.add_id(cert_id_for_req) {
695 warnings.push(format!(
696 "Failed to build OCSP request for certificate {}: {}",
697 i, err
698 ));
699 continue;
700 }
701
702 let req_der = match ocsp_req.to_der() {
703 Ok(der) => der,
704 Err(err) => {
705 warnings.push(format!(
706 "Failed to serialize OCSP request for certificate {}: {}",
707 i, err
708 ));
709 continue;
710 }
711 };
712
713 for url in urls {
714 if !(url.starts_with("http://") || url.starts_with("https://")) {
715 warnings.push(format!(
716 "OCSP URL for certificate {} uses unsupported scheme: {}",
717 i, url
718 ));
719 events.push(RevocationEvent {
720 cert_index: i,
721 url,
722 protocol: RevocationProtocol::Ocsp,
723 status: "unsupported_scheme".to_string(),
724 latency_ms: 0,
725 error: None,
726 });
727 continue;
728 }
729
730 let start = Instant::now();
731 let ocsp_response = match self.http_post_ocsp(&url, &req_der) {
732 Ok(data) => data,
733 Err(err) => {
734 warnings.push(format!(
735 "Failed to fetch OCSP response for certificate {}: {}",
736 i, err
737 ));
738 events.push(RevocationEvent {
739 cert_index: i,
740 url,
741 protocol: RevocationProtocol::Ocsp,
742 status: "fetch_failed".to_string(),
743 latency_ms: start.elapsed().as_millis(),
744 error: Some(err),
745 });
746 continue;
747 }
748 };
749
750 let response = match OcspResponse::from_der(&ocsp_response) {
751 Ok(resp) => resp,
752 Err(err) => {
753 warnings.push(format!(
754 "Failed to parse OCSP response for certificate {}: {}",
755 i, err
756 ));
757 events.push(RevocationEvent {
758 cert_index: i,
759 url,
760 protocol: RevocationProtocol::Ocsp,
761 status: "parse_failed".to_string(),
762 latency_ms: start.elapsed().as_millis(),
763 error: Some(err.to_string()),
764 });
765 continue;
766 }
767 };
768
769 if response.status() != OcspResponseStatus::SUCCESSFUL {
770 warnings.push(format!(
771 "OCSP response status for certificate {} is {:?}",
772 i,
773 response.status()
774 ));
775 events.push(RevocationEvent {
776 cert_index: i,
777 url,
778 protocol: RevocationProtocol::Ocsp,
779 status: format!("response_{:?}", response.status()),
780 latency_ms: start.elapsed().as_millis(),
781 error: None,
782 });
783 continue;
784 }
785
786 let basic = match response.basic() {
787 Ok(basic) => basic,
788 Err(err) => {
789 warnings.push(format!(
790 "Failed to parse OCSP basic response for certificate {}: {}",
791 i, err
792 ));
793 events.push(RevocationEvent {
794 cert_index: i,
795 url,
796 protocol: RevocationProtocol::Ocsp,
797 status: "basic_parse_failed".to_string(),
798 latency_ms: start.elapsed().as_millis(),
799 error: Some(err.to_string()),
800 });
801 continue;
802 }
803 };
804
805 let mut store_builder = match X509StoreBuilder::new() {
806 Ok(builder) => builder,
807 Err(err) => {
808 warnings.push(format!(
809 "Failed to create OCSP trust store for certificate {}: {}",
810 i, err
811 ));
812 continue;
813 }
814 };
815 if store_builder.set_default_paths().is_err() {
816 warnings.push(format!(
817 "Failed to load default trust store for OCSP verification (cert {})",
818 i
819 ));
820 }
821
822 let mut certs = match Stack::new() {
823 Ok(stack) => stack,
824 Err(err) => {
825 warnings.push(format!(
826 "Failed to create OCSP cert stack for certificate {}: {}",
827 i, err
828 ));
829 continue;
830 }
831 };
832 if certs.push(issuer_x509.clone()).is_err() {
833 warnings.push(format!(
834 "Failed to add issuer cert to OCSP stack (cert {})",
835 i
836 ));
837 }
838
839 if let Err(err) =
840 basic.verify(&certs, &store_builder.build(), OcspFlag::empty())
841 {
842 warnings.push(format!(
843 "OCSP response verification failed for certificate {}: {}",
844 i, err
845 ));
846 events.push(RevocationEvent {
847 cert_index: i,
848 url: url.clone(),
849 protocol: RevocationProtocol::Ocsp,
850 status: "signature_invalid".to_string(),
851 latency_ms: start.elapsed().as_millis(),
852 error: None,
853 });
854 }
855
856 if let Some(status) = basic.find_status(&cert_id_for_status) {
857 if status.status == openssl::ocsp::OcspCertStatus::REVOKED {
858 warnings
859 .push(format!("Certificate {} is revoked per OCSP ({})", i, url));
860 events.push(RevocationEvent {
861 cert_index: i,
862 url,
863 protocol: RevocationProtocol::Ocsp,
864 status: "revoked".to_string(),
865 latency_ms: start.elapsed().as_millis(),
866 error: None,
867 });
868 continue;
869 }
870 }
871
872 events.push(RevocationEvent {
873 cert_index: i,
874 url,
875 protocol: RevocationProtocol::Ocsp,
876 status: "ok".to_string(),
877 latency_ms: start.elapsed().as_millis(),
878 error: None,
879 });
880 }
881 }
882
883 (warnings, events)
884 }
885 }
886}
887
888pub fn parse_der_certificate(cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
889 #[cfg(feature = "crypto")]
890 {
891 let cert = X509CertificateImpl::from_der(cert_data)?;
892 Ok(CertificateInfo {
893 subject: cert.subject_string(),
894 issuer: cert.issuer_string(),
895 serial_number: cert.serial_number_hex(),
896 der: cert_data.to_vec(),
897 not_before: cert.not_before(),
898 not_after: cert.not_after(),
899 public_key_algorithm: cert.public_key_algorithm(),
900 signature_algorithm: cert.signature_algorithm(),
901 key_usage: cert.key_usage(),
902 extended_key_usage: cert.extended_key_usage(),
903 is_ca: cert.is_ca(),
904 fingerprint_sha256: cert.fingerprint_sha256(),
905 })
906 }
907 #[cfg(not(feature = "crypto"))]
908 {
909 let parser = SimpleDerParser::new(cert_data);
910 parser.parse_x509()
911 }
912}
913
914#[cfg(feature = "crypto")]
915pub fn extract_ocsp_urls(cert_data: &[u8]) -> Vec<String> {
916 use x509_parser::extensions::{GeneralName, ParsedExtension};
917 let Ok(cert) = parse_x509(cert_data) else {
918 return Vec::new();
919 };
920 let mut urls = Vec::new();
921 for ext in cert.extensions() {
922 if let ParsedExtension::AuthorityInfoAccess(aia) = ext.parsed_extension() {
923 for access in &aia.accessdescs {
924 if access.access_method.to_id_string() == "1.3.6.1.5.5.7.48.1" {
925 if let GeneralName::URI(uri) = &access.access_location {
926 let url = uri.to_string();
927 if !url.is_empty() {
928 urls.push(url);
929 }
930 }
931 }
932 }
933 }
934 }
935 urls
936}
937
938#[cfg(not(feature = "crypto"))]
939pub fn extract_ocsp_urls(_cert_data: &[u8]) -> Vec<String> {
940 Vec::new()
941}
942
943#[cfg(feature = "crypto")]
944pub fn extract_crl_urls(cert_data: &[u8]) -> Vec<String> {
945 use x509_parser::extensions::{DistributionPointName, GeneralName, ParsedExtension};
946 let Ok(cert) = parse_x509(cert_data) else {
947 return Vec::new();
948 };
949 let mut urls = Vec::new();
950 for ext in cert.extensions() {
951 if let ParsedExtension::CRLDistributionPoints(points) = ext.parsed_extension() {
952 for point in &points.points {
953 if let Some(DistributionPointName::FullName(names)) = &point.distribution_point {
954 for name in names {
955 if let GeneralName::URI(uri) = name {
956 let url = uri.to_string();
957 if !url.is_empty() {
958 urls.push(url);
959 }
960 }
961 }
962 }
963 }
964 }
965 }
966 urls
967}
968
969#[cfg(not(feature = "crypto"))]
970pub fn extract_crl_urls(_cert_data: &[u8]) -> Vec<String> {
971 Vec::new()
972}
973
974#[derive(Debug, Clone)]
976pub struct TrustStore {
977 certificates: Vec<CertificateInfo>,
978 name: String,
979}
980
981impl TrustStore {
982 pub fn new(name: String) -> Self {
984 Self {
985 certificates: Vec::new(),
986 name,
987 }
988 }
989
990 pub fn from_path(path: &str) -> CryptoResult<Self> {
992 let mut trust_store = Self::new(format!("File: {}", path));
993
994 let cert_data = std::fs::read(path).map_err(CryptoError::Io)?;
996
997 if path.ends_with(".pem") {
999 trust_store.load_pem_certificates(&cert_data)?;
1000 } else if path.ends_with(".der") {
1001 trust_store.load_der_certificate(&cert_data)?;
1002 } else {
1003 if cert_data.starts_with(b"-----BEGIN") {
1005 trust_store.load_pem_certificates(&cert_data)?;
1006 } else if cert_data.starts_with(&[0x30, 0x82]) {
1007 trust_store.load_der_certificate(&cert_data)?;
1008 } else {
1009 return Err(CryptoError::CertificateError(
1010 "Unknown certificate format".to_string(),
1011 ));
1012 }
1013 }
1014
1015 Ok(trust_store)
1016 }
1017
1018 pub fn system_default() -> CryptoResult<Self> {
1020 let mut trust_store = Self::new("System Default".to_string());
1021
1022 #[cfg(target_os = "linux")]
1024 {
1025 let paths = vec![
1027 "/etc/ssl/certs/ca-certificates.crt",
1028 "/etc/pki/tls/certs/ca-bundle.crt",
1029 "/etc/ssl/ca-bundle.pem",
1030 ];
1031
1032 for path in paths {
1033 if std::path::Path::new(path).exists() {
1034 if let Ok(cert_data) = std::fs::read(path) {
1035 let _ = trust_store.load_pem_certificates(&cert_data);
1036 break;
1037 }
1038 }
1039 }
1040 }
1041
1042 #[cfg(target_os = "macos")]
1043 {
1044 let paths = vec![
1046 "/etc/ssl/cert.pem",
1047 "/System/Library/OpenSSL/certs/cert.pem",
1048 ];
1049 let mut loaded = false;
1050 for path in paths {
1051 if std::path::Path::new(path).exists() {
1052 if let Ok(cert_data) = std::fs::read(path) {
1053 let _ = trust_store.load_pem_certificates(&cert_data);
1054 loaded = true;
1055 break;
1056 }
1057 }
1058 }
1059 if !loaded {
1060 return Err(CryptoError::CertificateError(
1061 "System trust store not available on macOS".to_string(),
1062 ));
1063 }
1064 }
1065
1066 #[cfg(target_os = "windows")]
1067 {
1068 return Err(CryptoError::CertificateError(
1069 "System trust store not available on Windows without platform API".to_string(),
1070 ));
1071 }
1072
1073 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
1074 {
1075 return Err(CryptoError::CertificateError(
1076 "System trust store not available on this platform".to_string(),
1077 ));
1078 }
1079
1080 Ok(trust_store)
1081 }
1082
1083 fn load_pem_certificates(&mut self, pem_data: &[u8]) -> CryptoResult<()> {
1085 let pem_str = std::str::from_utf8(pem_data)
1086 .map_err(|_| CryptoError::CertificateError("Invalid UTF-8 in PEM file".to_string()))?;
1087
1088 let cert_blocks = self.extract_pem_blocks(pem_str, "CERTIFICATE")?;
1090
1091 for cert_block in cert_blocks {
1092 let der_data = self.decode_base64(&cert_block)?;
1094 self.load_der_certificate(&der_data)?;
1095 }
1096
1097 Ok(())
1098 }
1099
1100 fn load_der_certificate(&mut self, der_data: &[u8]) -> CryptoResult<()> {
1102 #[cfg(feature = "crypto")]
1103 {
1104 let cert = self.parse_der_certificate_openssl(der_data)?;
1106 self.certificates.push(cert);
1107 }
1108 #[cfg(not(feature = "crypto"))]
1109 {
1110 let cert = parse_der_certificate(der_data)?;
1111 self.certificates.push(cert);
1112 }
1113
1114 Ok(())
1115 }
1116
1117 fn extract_pem_blocks(&self, pem_str: &str, block_type: &str) -> CryptoResult<Vec<String>> {
1119 let mut blocks = Vec::new();
1120 let begin_marker = format!("-----BEGIN {}-----", block_type);
1121 let end_marker = format!("-----END {}-----", block_type);
1122
1123 let mut current_pos = 0;
1124 while let Some(begin_pos) = pem_str[current_pos..].find(&begin_marker) {
1125 let begin_pos = current_pos + begin_pos;
1126 if let Some(end_pos) = pem_str[begin_pos..].find(&end_marker) {
1127 let end_pos = begin_pos + end_pos;
1128 let block = &pem_str[begin_pos + begin_marker.len()..end_pos];
1129 blocks.push(block.trim().replace(['\n', '\r'], ""));
1130 current_pos = end_pos + end_marker.len();
1131 } else {
1132 break;
1133 }
1134 }
1135
1136 Ok(blocks)
1137 }
1138
1139 fn decode_base64(&self, base64_str: &str) -> CryptoResult<Vec<u8>> {
1141 const BASE64_CHARS: &[u8] =
1143 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1144
1145 let clean_str = base64_str.replace('=', "");
1146 let mut result = Vec::new();
1147
1148 for chunk in clean_str.as_bytes().chunks(4) {
1149 let mut values = [0u8; 4];
1150 for (i, &byte) in chunk.iter().enumerate() {
1151 values[i] = BASE64_CHARS
1152 .iter()
1153 .position(|&x| x == byte)
1154 .ok_or_else(|| {
1155 CryptoError::CertificateError("Invalid base64 character".to_string())
1156 })? as u8;
1157 }
1158
1159 if chunk.len() >= 2 {
1160 result.push((values[0] << 2) | (values[1] >> 4));
1161 }
1162 if chunk.len() >= 3 {
1163 result.push((values[1] << 4) | (values[2] >> 2));
1164 }
1165 if chunk.len() >= 4 {
1166 result.push((values[2] << 6) | values[3]);
1167 }
1168 }
1169
1170 Ok(result)
1171 }
1172
1173 #[cfg(feature = "crypto")]
1174 fn parse_der_certificate_openssl(&self, der_data: &[u8]) -> CryptoResult<CertificateInfo> {
1175 let cert = X509CertificateImpl::from_der(der_data)?;
1176 Ok(CertificateInfo {
1177 subject: cert.subject_string(),
1178 issuer: cert.issuer_string(),
1179 serial_number: cert.serial_number_hex(),
1180 der: der_data.to_vec(),
1181 not_before: cert.not_before(),
1182 not_after: cert.not_after(),
1183 public_key_algorithm: cert.public_key_algorithm(),
1184 signature_algorithm: cert.signature_algorithm(),
1185 key_usage: cert.key_usage(),
1186 extended_key_usage: cert.extended_key_usage(),
1187 is_ca: cert.is_ca(),
1188 fingerprint_sha256: cert.fingerprint_sha256(),
1189 })
1190 }
1191
1192 pub fn contains_certificate(&self, cert: &CertificateInfo) -> bool {
1194 self.certificates.iter().any(|trusted_cert| {
1195 trusted_cert.fingerprint_sha256 == cert.fingerprint_sha256
1196 || (trusted_cert.subject == cert.subject && trusted_cert.issuer == cert.issuer)
1197 })
1198 }
1199
1200 pub fn add_certificate(&mut self, cert: CertificateInfo) {
1202 if !self.contains_certificate(&cert) {
1203 self.certificates.push(cert);
1204 }
1205 }
1206
1207 pub fn get_certificates(&self) -> &[CertificateInfo] {
1209 &self.certificates
1210 }
1211
1212 pub fn name(&self) -> &str {
1214 &self.name
1215 }
1216}
1217
1218#[cfg(test)]
1219mod tests {
1220 use super::*;
1221 use crate::crypto::chrono::DateTime;
1222
1223 #[test]
1224 fn test_certificate_chain_validator_creation() {
1225 let config = CryptoConfig::default();
1226 let result = CertificateChainValidator::new(config);
1227
1228 assert!(result.is_ok() || result.is_err()); }
1231
1232 #[test]
1233 fn test_trust_store_creation() {
1234 let trust_store = TrustStore::new("Test Store".to_string());
1235 assert_eq!(trust_store.name(), "Test Store");
1236 assert_eq!(trust_store.get_certificates().len(), 0);
1237 }
1238
1239 #[test]
1240 fn test_system_trust_store() {
1241 let result = TrustStore::system_default();
1242 if let Ok(trust_store) = result {
1243 assert!(!trust_store.get_certificates().is_empty());
1244 } else {
1245 assert!(result.is_err());
1247 }
1248 }
1249
1250 #[test]
1251 fn test_certificate_validation() {
1252 let config = CryptoConfig::default();
1253
1254 let expired_cert = CertificateInfo {
1256 subject: "CN=Test".to_string(),
1257 issuer: "CN=Test CA".to_string(),
1258 serial_number: "123".to_string(),
1259 der: Vec::new(),
1260 not_before: DateTime::from_timestamp(0), not_after: DateTime::from_timestamp(1), public_key_algorithm: "RSA".to_string(),
1263 signature_algorithm: "SHA256withRSA".to_string(),
1264 key_usage: vec!["Digital Signature".to_string()],
1265 extended_key_usage: Vec::new(),
1266 is_ca: false,
1267 fingerprint_sha256: "test_fingerprint".to_string(),
1268 };
1269
1270 let validator = CertificateChainValidator::new(config).unwrap();
1271 let errors = validator.validate_single_certificate(&expired_cert);
1272
1273 assert!(!errors.is_empty());
1274 assert!(errors.iter().any(|e| e.contains("expired")));
1275 }
1276
1277 #[test]
1278 fn test_base64_decoding() {
1279 let trust_store = TrustStore::new("Test".to_string());
1280
1281 let test_data = "SGVsbG8gV29ybGQ="; let result = trust_store.decode_base64(test_data).unwrap();
1283 assert_eq!(result, b"Hello World");
1284 }
1285}
1286
1287#[cfg(feature = "crypto")]
1289#[derive(Debug, Clone)]
1290pub struct X509CertificateImpl {
1291 data: Vec<u8>,
1292}
1293
1294#[cfg(feature = "crypto")]
1295impl X509CertificateImpl {
1296 pub fn from_der(data: &[u8]) -> CryptoResult<Self> {
1297 Ok(Self {
1298 data: data.to_vec(),
1299 })
1300 }
1301
1302 pub fn subject_string(&self) -> String {
1303 match parse_x509(&self.data) {
1304 Ok(cert) => cert.subject().to_string(),
1305 Err(_) => String::new(),
1306 }
1307 }
1308
1309 pub fn issuer_string(&self) -> String {
1310 match parse_x509(&self.data) {
1311 Ok(cert) => cert.issuer().to_string(),
1312 Err(_) => String::new(),
1313 }
1314 }
1315
1316 pub fn serial_number_hex(&self) -> String {
1317 match parse_x509(&self.data) {
1318 Ok(cert) => cert.tbs_certificate.raw_serial_as_string(),
1319 Err(_) => String::new(),
1320 }
1321 }
1322
1323 pub fn not_before(&self) -> super::chrono::DateTime<super::chrono::Utc> {
1324 parse_x509_time(&self.data, true).unwrap_or_else(|_| super::chrono::Utc::now())
1325 }
1326
1327 pub fn not_after(&self) -> super::chrono::DateTime<super::chrono::Utc> {
1328 parse_x509_time(&self.data, false).unwrap_or_else(|_| super::chrono::Utc::now())
1329 }
1330
1331 fn public_key_algorithm(&self) -> String {
1332 match parse_x509(&self.data) {
1333 Ok(cert) => cert.public_key().algorithm.algorithm.to_string(),
1334 Err(_) => String::new(),
1335 }
1336 }
1337
1338 fn signature_algorithm(&self) -> String {
1339 match parse_x509(&self.data) {
1340 Ok(cert) => cert.signature_algorithm.algorithm.to_string(),
1341 Err(_) => String::new(),
1342 }
1343 }
1344
1345 fn key_usage(&self) -> Vec<String> {
1346 parse_key_usage(&self.data)
1347 }
1348
1349 fn extended_key_usage(&self) -> Vec<String> {
1350 parse_extended_key_usage(&self.data)
1351 }
1352
1353 fn is_ca(&self) -> bool {
1354 parse_is_ca(&self.data)
1355 }
1356
1357 fn fingerprint_sha256(&self) -> String {
1358 use sha2::{Digest, Sha256};
1360 let mut hasher = Sha256::new();
1361 hasher.update(&self.data);
1362 let digest = hasher.finalize();
1363 digest.iter().map(|b| format!("{:02x}", b)).collect()
1364 }
1365
1366 pub fn subject(&self) -> String {
1368 self.subject_string()
1369 }
1370
1371 pub fn issuer(&self) -> String {
1372 self.issuer_string()
1373 }
1374
1375 pub fn serial_number(&self) -> String {
1376 self.serial_number_hex()
1377 }
1378
1379 pub fn extensions(&self) -> Vec<String> {
1380 parse_extensions(&self.data)
1381 }
1382}
1383
1384#[cfg(feature = "crypto")]
1385fn parse_x509(data: &[u8]) -> Result<x509_parser::certificate::X509Certificate<'_>, CryptoError> {
1386 use nom::Parser;
1387 use x509_parser::prelude::X509CertificateParser;
1388 let mut parser = X509CertificateParser::new().with_deep_parse_extensions(true);
1389 parser
1390 .parse(data)
1391 .map(|(_, cert)| cert)
1392 .map_err(|e| CryptoError::CertificateError(format!("X509 parse error: {:?}", e)))
1393}
1394
1395#[cfg(feature = "crypto")]
1396fn parse_x509_time(
1397 data: &[u8],
1398 not_before: bool,
1399) -> Result<super::chrono::DateTime<super::chrono::Utc>, CryptoError> {
1400 let cert = parse_x509(data)?;
1401 let validity = &cert.tbs_certificate.validity;
1402 let time = if not_before {
1403 validity.not_before.to_datetime()
1404 } else {
1405 validity.not_after.to_datetime()
1406 };
1407 Ok(super::chrono::DateTime::from_timestamp(
1408 time.unix_timestamp(),
1409 ))
1410}
1411
1412#[cfg(feature = "crypto")]
1413fn parse_key_usage(data: &[u8]) -> Vec<String> {
1414 use x509_parser::extensions::ParsedExtension;
1415 let Ok(cert) = parse_x509(data) else {
1416 return Vec::new();
1417 };
1418 for ext in cert.extensions() {
1419 if let ParsedExtension::KeyUsage(ku) = &ext.parsed_extension() {
1420 let mut out = Vec::new();
1421 if ku.digital_signature() {
1422 out.push("Digital Signature".to_string());
1423 }
1424 if ku.non_repudiation() {
1425 out.push("Non Repudiation".to_string());
1426 }
1427 if ku.key_encipherment() {
1428 out.push("Key Encipherment".to_string());
1429 }
1430 if ku.data_encipherment() {
1431 out.push("Data Encipherment".to_string());
1432 }
1433 if ku.key_agreement() {
1434 out.push("Key Agreement".to_string());
1435 }
1436 if ku.key_cert_sign() {
1437 out.push("Certificate Signing".to_string());
1438 }
1439 if ku.crl_sign() {
1440 out.push("CRL Signing".to_string());
1441 }
1442 if ku.encipher_only() {
1443 out.push("Encipher Only".to_string());
1444 }
1445 if ku.decipher_only() {
1446 out.push("Decipher Only".to_string());
1447 }
1448 return out;
1449 }
1450 }
1451 Vec::new()
1452}
1453
1454#[cfg(feature = "crypto")]
1455fn parse_extended_key_usage(data: &[u8]) -> Vec<String> {
1456 use x509_parser::extensions::ParsedExtension;
1457 let Ok(cert) = parse_x509(data) else {
1458 return Vec::new();
1459 };
1460 for ext in cert.extensions() {
1461 if let ParsedExtension::ExtendedKeyUsage(eku) = &ext.parsed_extension() {
1462 let mut out = Vec::new();
1463 if eku.any {
1464 out.push("Any".to_string());
1465 }
1466 if eku.server_auth {
1467 out.push("Server Auth".to_string());
1468 }
1469 if eku.client_auth {
1470 out.push("Client Auth".to_string());
1471 }
1472 if eku.code_signing {
1473 out.push("Code Signing".to_string());
1474 }
1475 if eku.email_protection {
1476 out.push("Email Protection".to_string());
1477 }
1478 if eku.time_stamping {
1479 out.push("Time Stamping".to_string());
1480 }
1481 if eku.ocsp_signing {
1482 out.push("OCSP Signing".to_string());
1483 }
1484 for oid in &eku.other {
1485 out.push(oid.to_string());
1486 }
1487 return out;
1488 }
1489 }
1490 Vec::new()
1491}
1492
1493#[cfg(feature = "crypto")]
1494fn parse_is_ca(data: &[u8]) -> bool {
1495 use x509_parser::extensions::ParsedExtension;
1496 let Ok(cert) = parse_x509(data) else {
1497 return false;
1498 };
1499 for ext in cert.extensions() {
1500 if let ParsedExtension::BasicConstraints(bc) = &ext.parsed_extension() {
1501 return bc.ca;
1502 }
1503 }
1504 false
1505}
1506
1507#[cfg(feature = "crypto")]
1508fn parse_extensions(data: &[u8]) -> Vec<String> {
1509 let Ok(cert) = parse_x509(data) else {
1510 return Vec::new();
1511 };
1512 cert.extensions()
1513 .iter()
1514 .map(|ext| ext.oid.to_string())
1515 .collect()
1516}
1517
1518#[cfg(not(feature = "crypto"))]
1520struct SimpleDerParser<'a> {
1521 data: &'a [u8],
1522 pos: usize,
1523}
1524
1525#[cfg(not(feature = "crypto"))]
1526impl<'a> SimpleDerParser<'a> {
1527 fn new(data: &'a [u8]) -> Self {
1528 Self { data, pos: 0 }
1529 }
1530
1531 fn parse_x509(&self) -> CryptoResult<CertificateInfo> {
1532 let mut parser = self.clone();
1533
1534 let (tag, _length) = parser.read_tag_length()?;
1536 if tag != 0x30 {
1537 return Err(CryptoError::CertificateError("Not a SEQUENCE".to_string()));
1538 }
1539
1540 let (tbs_tag, _tbs_length) = parser.read_tag_length()?;
1542 if tbs_tag != 0x30 {
1543 return Err(CryptoError::CertificateError(
1544 "Invalid TBSCertificate".to_string(),
1545 ));
1546 }
1547
1548 let _version = parser.parse_version();
1550
1551 let serial = parser.parse_integer()?;
1553
1554 let sig_algo = parser.parse_algorithm_identifier()?;
1556
1557 let issuer = parser.parse_name()?;
1559
1560 let (not_before, not_after) = parser.parse_validity()?;
1562
1563 let subject = parser.parse_name()?;
1565
1566 let pub_key_algo = parser.parse_subject_public_key_info()?;
1568
1569 let (key_usage, ext_key_usage, is_ca) = parser.parse_extensions();
1571
1572 let fingerprint = self.compute_sha256_fingerprint();
1574
1575 Ok(CertificateInfo {
1576 subject,
1577 issuer,
1578 serial_number: format!("{:X}", serial),
1579 der: self.data.to_vec(),
1580 not_before,
1581 not_after,
1582 public_key_algorithm: pub_key_algo,
1583 signature_algorithm: sig_algo,
1584 key_usage,
1585 extended_key_usage: ext_key_usage,
1586 is_ca,
1587 fingerprint_sha256: fingerprint,
1588 })
1589 }
1590
1591 fn read_tag_length(&mut self) -> CryptoResult<(u8, usize)> {
1592 if self.pos >= self.data.len() {
1593 return Err(CryptoError::CertificateError(
1594 "Unexpected end of data".to_string(),
1595 ));
1596 }
1597
1598 let tag = self.data[self.pos];
1599 self.pos += 1;
1600
1601 if self.pos >= self.data.len() {
1602 return Err(CryptoError::CertificateError("Missing length".to_string()));
1603 }
1604
1605 let length = if self.data[self.pos] & 0x80 == 0 {
1606 let len = self.data[self.pos] as usize;
1607 self.pos += 1;
1608 len
1609 } else {
1610 let num_octets = (self.data[self.pos] & 0x7F) as usize;
1611 self.pos += 1;
1612
1613 let mut len = 0usize;
1614 for _ in 0..num_octets {
1615 if self.pos >= self.data.len() {
1616 return Err(CryptoError::CertificateError(
1617 "Invalid length encoding".to_string(),
1618 ));
1619 }
1620 len = (len << 8) | (self.data[self.pos] as usize);
1621 self.pos += 1;
1622 }
1623 len
1624 };
1625
1626 Ok((tag, length))
1627 }
1628
1629 fn parse_version(&mut self) -> i32 {
1630 if self.pos < self.data.len() && self.data[self.pos] == 0xA0 {
1631 self.pos += 1;
1632 let _ = self.read_length();
1633 if self.pos + 3 <= self.data.len() {
1634 self.pos += 3;
1635 return 2; }
1637 }
1638 0 }
1640
1641 fn parse_integer(&mut self) -> CryptoResult<u64> {
1642 let (tag, length) = self.read_tag_length()?;
1643 if tag != 0x02 {
1644 return Err(CryptoError::CertificateError(
1645 "Expected INTEGER".to_string(),
1646 ));
1647 }
1648
1649 let mut value = 0u64;
1650 for _ in 0..length.min(8) {
1651 if self.pos >= self.data.len() {
1652 break;
1653 }
1654 value = (value << 8) | (self.data[self.pos] as u64);
1655 self.pos += 1;
1656 }
1657
1658 self.pos += length.saturating_sub(8);
1659 Ok(value)
1660 }
1661
1662 fn parse_algorithm_identifier(&mut self) -> CryptoResult<String> {
1663 let (tag, _length) = self.read_tag_length()?;
1664 if tag != 0x30 {
1665 return Err(CryptoError::CertificateError(
1666 "Expected SEQUENCE for AlgorithmIdentifier".to_string(),
1667 ));
1668 }
1669
1670 if self.pos < self.data.len() && self.data[self.pos] == 0x06 {
1671 self.pos += 1;
1672 let oid_len = self.read_length();
1673
1674 let algo = if self.pos + oid_len <= self.data.len() {
1675 let oid_bytes = &self.data[self.pos..self.pos + oid_len];
1676 self.pos += oid_len;
1677
1678 match oid_bytes {
1679 &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B] => "SHA256withRSA",
1680 &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05] => "SHA1withRSA",
1681 &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02] => "SHA256withECDSA",
1682 _ => "Unknown",
1683 }
1684 } else {
1685 "Unknown"
1686 };
1687
1688 if self.pos < self.data.len() && self.data[self.pos] == 0x05 {
1689 self.pos += 2; }
1691
1692 Ok(algo.to_string())
1693 } else {
1694 Ok("Unknown".to_string())
1695 }
1696 }
1697
1698 fn parse_name(&mut self) -> CryptoResult<String> {
1699 let (tag, length) = self.read_tag_length()?;
1700 if tag != 0x30 {
1701 return Err(CryptoError::CertificateError(
1702 "Expected SEQUENCE for Name".to_string(),
1703 ));
1704 }
1705
1706 let end_pos = self.pos + length;
1707 let mut name_parts = Vec::new();
1708
1709 while self.pos < end_pos && self.pos < self.data.len() {
1710 if self.data[self.pos] == 0x31 {
1711 self.pos += 1;
1712 let set_len = self.read_length();
1713 let set_end = self.pos + set_len;
1714
1715 while self.pos < set_end && self.pos < self.data.len() {
1716 if self.data[self.pos] == 0x30 {
1717 self.pos += 1;
1718 let _seq_len = self.read_length();
1719
1720 if self.pos < self.data.len() && self.data[self.pos] == 0x06 {
1721 self.pos += 1;
1722 let oid_len = self.read_length();
1723 let oid_bytes = if self.pos + oid_len <= self.data.len() {
1724 let bytes = &self.data[self.pos..self.pos + oid_len];
1725 self.pos += oid_len;
1726 bytes
1727 } else {
1728 &[]
1729 };
1730
1731 if self.pos < self.data.len() {
1732 let _value_tag = self.data[self.pos];
1733 self.pos += 1;
1734 let value_len = self.read_length();
1735
1736 if self.pos + value_len <= self.data.len() {
1737 let value_bytes = &self.data[self.pos..self.pos + value_len];
1738 self.pos += value_len;
1739
1740 let attr_name = match oid_bytes {
1741 &[0x55, 0x04, 0x03] => "CN",
1742 &[0x55, 0x04, 0x06] => "C",
1743 &[0x55, 0x04, 0x07] => "L",
1744 &[0x55, 0x04, 0x08] => "ST",
1745 &[0x55, 0x04, 0x0A] => "O",
1746 &[0x55, 0x04, 0x0B] => "OU",
1747 _ => "Unknown",
1748 };
1749
1750 if let Ok(value_str) = std::str::from_utf8(value_bytes) {
1751 name_parts.push(format!("{}={}", attr_name, value_str));
1752 }
1753 }
1754 }
1755 }
1756 } else {
1757 break;
1758 }
1759 }
1760 } else {
1761 break;
1762 }
1763 }
1764
1765 self.pos = end_pos;
1766 Ok(if name_parts.is_empty() {
1767 "CN=Unknown".to_string()
1768 } else {
1769 name_parts.join(", ")
1770 })
1771 }
1772
1773 fn parse_validity(
1774 &mut self,
1775 ) -> CryptoResult<(
1776 super::chrono::DateTime<super::chrono::Utc>,
1777 super::chrono::DateTime<super::chrono::Utc>,
1778 )> {
1779 let (tag, _length) = self.read_tag_length()?;
1780 if tag != 0x30 {
1781 return Err(CryptoError::CertificateError(
1782 "Expected SEQUENCE for Validity".to_string(),
1783 ));
1784 }
1785
1786 let not_before = self.parse_time()?;
1787 let not_after = self.parse_time()?;
1788
1789 Ok((not_before, not_after))
1790 }
1791
1792 fn parse_time(&mut self) -> CryptoResult<super::chrono::DateTime<super::chrono::Utc>> {
1793 if self.pos >= self.data.len() {
1794 return Ok(super::chrono::Utc::now());
1795 }
1796
1797 let _tag = self.data[self.pos];
1798 self.pos += 1;
1799 let length = self.read_length();
1800
1801 self.pos += length;
1802 Ok(super::chrono::Utc::now())
1803 }
1804
1805 fn parse_subject_public_key_info(&mut self) -> CryptoResult<String> {
1806 let (tag, length) = self.read_tag_length()?;
1807 if tag != 0x30 {
1808 return Err(CryptoError::CertificateError(
1809 "Expected SEQUENCE for SubjectPublicKeyInfo".to_string(),
1810 ));
1811 }
1812
1813 let end_pos = self.pos + length;
1814 let algo = self.parse_algorithm_identifier()?;
1815 self.pos = end_pos;
1816
1817 Ok(algo)
1818 }
1819
1820 fn parse_extensions(&mut self) -> (Vec<String>, Vec<String>, bool) {
1821 let mut key_usage = Vec::new();
1822 let mut ext_key_usage = Vec::new();
1823 let mut is_ca = false;
1824
1825 if self.pos < self.data.len() && self.data[self.pos] == 0xA3 {
1826 self.pos += 1;
1827 let _ = self.read_length();
1828 key_usage.push("Digital Signature".to_string());
1829 ext_key_usage.push("Code Signing".to_string());
1830 }
1831
1832 (key_usage, ext_key_usage, is_ca)
1833 }
1834
1835 fn read_length(&mut self) -> usize {
1836 if self.pos >= self.data.len() {
1837 return 0;
1838 }
1839
1840 if self.data[self.pos] & 0x80 == 0 {
1841 let len = self.data[self.pos] as usize;
1842 self.pos += 1;
1843 len
1844 } else {
1845 let num_octets = (self.data[self.pos] & 0x7F) as usize;
1846 self.pos += 1;
1847
1848 let mut len = 0usize;
1849 for _ in 0..num_octets {
1850 if self.pos >= self.data.len() {
1851 break;
1852 }
1853 len = (len << 8) | (self.data[self.pos] as usize);
1854 self.pos += 1;
1855 }
1856 len
1857 }
1858 }
1859
1860 fn compute_sha256_fingerprint(&self) -> String {
1861 use sha2::{Digest, Sha256};
1862 let mut hasher = Sha256::new();
1863 hasher.update(self.data);
1864 let digest = hasher.finalize();
1865 digest.iter().map(|b| format!("{:02x}", b)).collect()
1866 }
1867
1868 fn clone(&self) -> Self {
1869 Self {
1870 data: self.data,
1871 pos: self.pos,
1872 }
1873 }
1874}