Skip to main content

pdf_ast/crypto/
certificates.rs

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
33/// Certificate chain validator with support for multiple trust stores
34pub 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        // Load default system trust store if available
47        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    /// Add a trust store from a file path
57    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    /// Add system default trust store
64    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    /// Validate a certificate chain
71    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        // Parse all certificates in the chain
83        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        // Perform validation
103        self.validate_parsed_chain(&parsed_certs, cert_chain)
104    }
105
106    /// Validate a parsed certificate chain
107    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        // Check chain length
116        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        // Validate each certificate individually
125        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        // Validate chain structure
138        let chain_errors = self.validate_chain_structure(chain);
139        validation_errors.extend(chain_errors);
140
141        // Find trust anchor
142        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        // Perform revocation checking if enabled
148        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    /// Validate a certificate chain and return revocation events
168    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    /// Parse a single certificate
226    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        // Parse X.509 certificate using DER format
240        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        // Parse X.509 certificate using simple DER parser
261        if cert_data.len() < 100 {
262            return Err(CryptoError::CertificateError(
263                "Certificate data too short".to_string(),
264            ));
265        }
266
267        // Check for DER format
268        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        // Parse basic X.509 structure
275        let parser = SimpleDerParser::new(cert_data);
276        let cert_info = parser.parse_x509()?;
277
278        Ok(cert_info)
279    }
280
281    /// Validate a single certificate
282    fn validate_single_certificate(&self, cert: &CertificateInfo) -> Vec<String> {
283        let mut errors = Vec::new();
284        let now = super::chrono::Utc::now();
285
286        // Check validity period
287        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        // Check key usage for signing certificates
295        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        // Validate subject and issuer
300        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    /// Validate certificate chain structure
311    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        // Check that each certificate is signed by the next one in the chain
319        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            // Check that issuer certificate is a CA
334            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        // Check root certificate
344        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    /// Find trust anchor in the certificate chain
355    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    /// Check if a certificate is a trusted root
365    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    /// Check CRL (Certificate Revocation List) status
441    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    /// Check OCSP (Online Certificate Status Protocol) status
593    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/// Trust store containing trusted root certificates
975#[derive(Debug, Clone)]
976pub struct TrustStore {
977    certificates: Vec<CertificateInfo>,
978    name: String,
979}
980
981impl TrustStore {
982    /// Create a new empty trust store
983    pub fn new(name: String) -> Self {
984        Self {
985            certificates: Vec::new(),
986            name,
987        }
988    }
989
990    /// Load trust store from a file path
991    pub fn from_path(path: &str) -> CryptoResult<Self> {
992        let mut trust_store = Self::new(format!("File: {}", path));
993
994        // Read certificate file
995        let cert_data = std::fs::read(path).map_err(CryptoError::Io)?;
996
997        // Parse certificates from the file
998        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            // Try to auto-detect format
1004            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    /// Load system default trust store
1019    pub fn system_default() -> CryptoResult<Self> {
1020        let mut trust_store = Self::new("System Default".to_string());
1021
1022        // Load system certificates based on platform
1023        #[cfg(target_os = "linux")]
1024        {
1025            // Try common Linux certificate paths
1026            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            // Attempt to load common macOS trust store bundles
1045            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    /// Load PEM format certificates
1084    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        // Find all certificate blocks
1089        let cert_blocks = self.extract_pem_blocks(pem_str, "CERTIFICATE")?;
1090
1091        for cert_block in cert_blocks {
1092            // Decode base64
1093            let der_data = self.decode_base64(&cert_block)?;
1094            self.load_der_certificate(&der_data)?;
1095        }
1096
1097        Ok(())
1098    }
1099
1100    /// Load DER format certificate
1101    fn load_der_certificate(&mut self, der_data: &[u8]) -> CryptoResult<()> {
1102        #[cfg(feature = "crypto")]
1103        {
1104            // Parse with OpenSSL
1105            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    /// Extract PEM blocks of a specific type
1118    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    /// Decode base64 string
1140    fn decode_base64(&self, base64_str: &str) -> CryptoResult<Vec<u8>> {
1141        // Simple base64 decoder (for production, use a proper base64 library)
1142        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    /// Check if trust store contains a certificate
1193    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    /// Add a certificate to the trust store
1201    pub fn add_certificate(&mut self, cert: CertificateInfo) {
1202        if !self.contains_certificate(&cert) {
1203            self.certificates.push(cert);
1204        }
1205    }
1206
1207    /// Get all certificates in the trust store
1208    pub fn get_certificates(&self) -> &[CertificateInfo] {
1209        &self.certificates
1210    }
1211
1212    /// Get trust store name
1213    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        // Should succeed even if system trust store is not available
1229        assert!(result.is_ok() || result.is_err()); // Either way is acceptable for this test
1230    }
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            // System trust store may not be available on all platforms
1246            assert!(result.is_err());
1247        }
1248    }
1249
1250    #[test]
1251    fn test_certificate_validation() {
1252        let config = CryptoConfig::default();
1253
1254        // Create a mock certificate with expired date
1255        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), // Very old
1261            not_after: DateTime::from_timestamp(1),  // Expired
1262            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="; // "Hello World" in base64
1282        let result = trust_store.decode_base64(test_data).unwrap();
1283        assert_eq!(result, b"Hello World");
1284    }
1285}
1286
1287/// Simple X.509 certificate structure
1288#[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        // Compute SHA-256 of certificate
1359        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    // Field-like accessors for compatibility with direct field access
1367    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/// Simple DER parser for X.509
1519#[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        // Read SEQUENCE header
1535        let (tag, _length) = parser.read_tag_length()?;
1536        if tag != 0x30 {
1537            return Err(CryptoError::CertificateError("Not a SEQUENCE".to_string()));
1538        }
1539
1540        // Read TBSCertificate
1541        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        // Parse version
1549        let _version = parser.parse_version();
1550
1551        // Parse serial number
1552        let serial = parser.parse_integer()?;
1553
1554        // Parse signature algorithm
1555        let sig_algo = parser.parse_algorithm_identifier()?;
1556
1557        // Parse issuer
1558        let issuer = parser.parse_name()?;
1559
1560        // Parse validity
1561        let (not_before, not_after) = parser.parse_validity()?;
1562
1563        // Parse subject
1564        let subject = parser.parse_name()?;
1565
1566        // Parse public key
1567        let pub_key_algo = parser.parse_subject_public_key_info()?;
1568
1569        // Extensions
1570        let (key_usage, ext_key_usage, is_ca) = parser.parse_extensions();
1571
1572        // Compute fingerprint
1573        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; // v3
1636            }
1637        }
1638        0 // v1
1639    }
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; // NULL parameter
1690            }
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}