Skip to main content

pdf_ast/crypto/
pkcs7.rs

1use super::{
2    CertificateInfo, CryptoError, CryptoResult, SignatureVerificationResult, TimestampInfo,
3};
4use crate::crypto::timestamp;
5
6#[cfg(feature = "crypto")]
7use openssl::{
8    pkcs7::Pkcs7,
9    pkey::PKey,
10    x509::{X509Ref, X509},
11};
12
13#[cfg(feature = "crypto")]
14use x509_parser::prelude::*;
15
16#[cfg(not(feature = "crypto"))]
17use sha1::Sha1;
18#[cfg(not(feature = "crypto"))]
19use sha2::{Digest, Sha256, Sha384, Sha512};
20
21/// PKCS#7 / CMS (Cryptographic Message Syntax) handler
22pub struct Pkcs7Handler;
23pub type PKCS7Parser = Pkcs7Handler;
24
25pub struct SignedData {
26    pub content_info: ContentInfo,
27    pub certificates: Vec<Vec<u8>>,
28    pub crls: Vec<Vec<u8>>,
29    pub signers: Vec<SignerInfo>,
30}
31
32#[allow(dead_code)]
33impl Default for Pkcs7Handler {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl Pkcs7Handler {
40    pub fn new() -> Self {
41        Self
42    }
43
44    /// Parse and verify a PKCS#7 signature
45    pub fn verify_pkcs7(
46        &self,
47        pkcs7_data: &[u8],
48        signed_data: &[u8],
49    ) -> CryptoResult<SignatureVerificationResult> {
50        // Parse the PKCS#7 structure
51        let pkcs7_info = self.parse_pkcs7_structure(pkcs7_data)?;
52
53        // Verify the signature
54        #[cfg(feature = "crypto")]
55        {
56            self.verify_with_openssl(&pkcs7_info, signed_data)
57        }
58        #[cfg(not(feature = "crypto"))]
59        {
60            self.verify_simple(&pkcs7_info, signed_data)
61        }
62    }
63
64    /// Parse PKCS#7 ASN.1 structure
65    fn parse_pkcs7_structure(&self, data: &[u8]) -> CryptoResult<Pkcs7Info> {
66        if data.len() < 20 {
67            return Err(CryptoError::InvalidSignatureFormat(
68                "PKCS#7 data too short".to_string(),
69            ));
70        }
71
72        // Check for ASN.1 SEQUENCE tag
73        if data[0] != 0x30 {
74            return Err(CryptoError::InvalidSignatureFormat(
75                "Invalid PKCS#7 ASN.1 structure".to_string(),
76            ));
77        }
78
79        // Parse length
80        let (content_start, total_length) = self.parse_asn1_length(&data[1..])?;
81
82        if data.len() < content_start + 1 + total_length {
83            return Err(CryptoError::InvalidSignatureFormat(
84                "PKCS#7 data truncated".to_string(),
85            ));
86        }
87
88        // Look for ContentInfo OID (1.2.840.113549.1.7.2 for SignedData)
89        let signed_data_oid = &[
90            0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
91        ];
92
93        if !self.contains_sequence(data, signed_data_oid) {
94            return Err(CryptoError::InvalidSignatureFormat(
95                "Not a SignedData PKCS#7 structure".to_string(),
96            ));
97        }
98
99        // Extract basic information (simplified parsing)
100        let pkcs7_info = Pkcs7Info {
101            version: self.extract_version(data)?,
102            digest_algorithms: self.extract_digest_algorithms(data)?,
103            content_info: self.extract_content_info(data)?,
104            certificates: self.extract_certificates(data)?,
105            signer_infos: self.extract_signer_infos(data)?,
106            raw_data: data.to_vec(),
107        };
108
109        Ok(pkcs7_info)
110    }
111
112    /// Parse ASN.1 length field
113    fn parse_asn1_length(&self, data: &[u8]) -> CryptoResult<(usize, usize)> {
114        if data.is_empty() {
115            return Err(CryptoError::InvalidSignatureFormat(
116                "Empty ASN.1 length field".to_string(),
117            ));
118        }
119
120        let first_byte = data[0];
121
122        if first_byte & 0x80 == 0 {
123            // Short form
124            Ok((1, first_byte as usize))
125        } else {
126            // Long form
127            let length_octets = (first_byte & 0x7F) as usize;
128            if length_octets == 0 || length_octets > 4 || data.len() < 1 + length_octets {
129                return Err(CryptoError::InvalidSignatureFormat(
130                    "Invalid ASN.1 long form length".to_string(),
131                ));
132            }
133
134            let mut length = 0usize;
135            for i in 0..length_octets {
136                length = (length << 8) | data[1 + i] as usize;
137            }
138
139            Ok((1 + length_octets, length))
140        }
141    }
142
143    /// Check if data contains a specific byte sequence
144    fn contains_sequence(&self, data: &[u8], sequence: &[u8]) -> bool {
145        data.windows(sequence.len())
146            .any(|window| window == sequence)
147    }
148
149    /// Extract version from PKCS#7 data (simplified)
150    fn extract_version(&self, data: &[u8]) -> CryptoResult<u32> {
151        // Look for INTEGER tag (0x02) near the beginning
152        for i in 0..data.len().min(50) {
153            if data[i] == 0x02 && i + 2 < data.len() && data[i + 1] == 0x01 {
154                return Ok(data[i + 2] as u32);
155            }
156        }
157        Ok(1) // Default version
158    }
159
160    /// Extract digest algorithms (simplified)
161    fn extract_digest_algorithms(&self, data: &[u8]) -> CryptoResult<Vec<String>> {
162        #[cfg(feature = "crypto")]
163        {
164            self.extract_digest_algorithms_asn1(data)
165        }
166        #[cfg(not(feature = "crypto"))]
167        {
168            // Simplified implementation - would parse AlgorithmIdentifier structures
169            Ok(vec!["SHA-256".to_string()])
170        }
171    }
172
173    /// Extract digest algorithms using ASN.1 parsing
174    #[cfg(feature = "crypto")]
175    fn extract_digest_algorithms_asn1(&self, data: &[u8]) -> CryptoResult<Vec<String>> {
176        use der_parser::der::*;
177
178        let mut algorithms = Vec::new();
179
180        // Parse the outer PKCS#7 ContentInfo structure
181        match parse_der(data) {
182            Ok((_remaining, obj)) => {
183                if let DerObjectContent::Sequence(seq) = obj.content {
184                    // Look for digest algorithms in the SignedData structure
185                    for item in seq {
186                        if let DerObjectContent::Set(set) = item.content {
187                            // This could be the digestAlgorithms set
188                            for alg_item in set {
189                                if let DerObjectContent::Sequence(alg_seq) = alg_item.content {
190                                    if let Some(first) = alg_seq.first() {
191                                        if let DerObjectContent::OID(oid) = &first.content {
192                                            let algorithm_name = match oid.to_string().as_str() {
193                                                "1.3.14.3.2.26" => "SHA-1".to_string(),
194                                                "2.16.840.1.101.3.4.2.1" => "SHA-256".to_string(),
195                                                "2.16.840.1.101.3.4.2.2" => "SHA-384".to_string(),
196                                                "2.16.840.1.101.3.4.2.3" => "SHA-512".to_string(),
197                                                _ => format!("Unknown ({})", oid),
198                                            };
199                                            algorithms.push(algorithm_name);
200                                        }
201                                    }
202                                }
203                            }
204                        }
205                    }
206                }
207            }
208            Err(_) => {
209                // Fall back to default
210                algorithms.push("SHA-256".to_string());
211            }
212        }
213
214        if algorithms.is_empty() {
215            algorithms.push("SHA-256".to_string()); // Default
216        }
217
218        Ok(algorithms)
219    }
220
221    /// Extract content info (simplified)
222    fn extract_content_info(&self, _data: &[u8]) -> CryptoResult<ContentInfo> {
223        Ok(ContentInfo {
224            content_type: "data".to_string(),
225            content: None,
226        })
227    }
228
229    /// Extract certificates from PKCS#7 data
230    fn extract_certificates(&self, data: &[u8]) -> CryptoResult<Vec<Vec<u8>>> {
231        // Look for certificate tag (0xA0) in the PKCS#7 structure
232        let mut certificates = Vec::new();
233
234        let mut i = 0;
235        while i < data.len().saturating_sub(10) {
236            if data[i] == 0xA0 {
237                // Found certificates section
238                let (len_start, certs_length) = self.parse_asn1_length(&data[i + 1..])?;
239                let certs_start = i + 1 + len_start;
240                let certs_end = certs_start + certs_length;
241
242                if certs_end <= data.len() {
243                    // Extract individual certificates
244                    let certs_data = &data[certs_start..certs_end];
245                    let extracted = self.extract_individual_certificates(certs_data)?;
246                    certificates.extend(extracted);
247                }
248                break;
249            }
250            i += 1;
251        }
252
253        Ok(certificates)
254    }
255
256    /// Extract individual certificates from certificate section
257    fn extract_individual_certificates(&self, certs_data: &[u8]) -> CryptoResult<Vec<Vec<u8>>> {
258        let mut certificates = Vec::new();
259        let mut i = 0;
260
261        while i < certs_data.len().saturating_sub(10) {
262            if certs_data[i] == 0x30 && certs_data[i + 1] == 0x82 {
263                // Found certificate (DER-encoded)
264                let cert_length =
265                    ((certs_data[i + 2] as usize) << 8) | (certs_data[i + 3] as usize);
266                let total_length = cert_length + 4;
267
268                if i + total_length <= certs_data.len() {
269                    certificates.push(certs_data[i..i + total_length].to_vec());
270                    i += total_length;
271                } else {
272                    break;
273                }
274            } else {
275                i += 1;
276            }
277        }
278
279        Ok(certificates)
280    }
281
282    /// Extract signer infos (simplified)
283    fn extract_signer_infos(&self, data: &[u8]) -> CryptoResult<Vec<SignerInfo>> {
284        #[cfg(feature = "crypto")]
285        {
286            self.extract_signer_infos_asn1(data)
287        }
288        #[cfg(not(feature = "crypto"))]
289        {
290            // Simplified implementation
291            Ok(vec![SignerInfo {
292                version: 1,
293                issuer_and_serial: IssuerAndSerial {
294                    issuer: "CN=Unknown".to_string(),
295                    serial_number: vec![1],
296                },
297                digest_algorithm: "SHA-256".to_string(),
298                signature_algorithm: "RSA".to_string(),
299                signature: vec![0; 256], // Placeholder
300                authenticated_attributes: Vec::new(),
301                unauthenticated_attributes: Vec::new(),
302            }])
303        }
304    }
305
306    /// Extract signer infos using ASN.1 parsing
307    #[cfg(feature = "crypto")]
308    fn extract_signer_infos_asn1(&self, data: &[u8]) -> CryptoResult<Vec<SignerInfo>> {
309        use der_parser::der::*;
310
311        let mut signer_infos = Vec::new();
312
313        // Parse the PKCS#7 structure to find SignerInfos
314        match parse_der(data) {
315            Ok((_remaining, obj)) => {
316                if let DerObjectContent::Sequence(seq) = obj.content {
317                    // Navigate through the PKCS#7 structure to find SignerInfos
318                    // This is a simplified version - a complete implementation would
319                    // properly navigate the ASN.1 structure
320                    for item in seq {
321                        if let DerObjectContent::Set(set) = item.content {
322                            // This might be the signerInfos set
323                            for signer_item in set {
324                                if let DerObjectContent::Sequence(signer_seq) = signer_item.content
325                                {
326                                    // Try to extract signer info from the sequence
327                                    let mut version = 1u32;
328                                    let digest_algorithm = "SHA-256".to_string();
329                                    let signature_algorithm = "RSA".to_string();
330                                    let signature = vec![0; 256];
331
332                                    // Extract version if present
333                                    if let Some(first) = signer_seq.first() {
334                                        if let DerObjectContent::Integer(int_bytes) = &first.content
335                                        {
336                                            if !int_bytes.is_empty() {
337                                                version = int_bytes[0] as u32;
338                                            }
339                                        }
340                                    }
341
342                                    signer_infos.push(SignerInfo {
343                                        version,
344                                        issuer_and_serial: IssuerAndSerial {
345                                            issuer: "CN=PKCS#7 Signer".to_string(),
346                                            serial_number: vec![1, 2, 3, 4],
347                                        },
348                                        digest_algorithm,
349                                        signature_algorithm,
350                                        signature,
351                                        authenticated_attributes: Vec::new(),
352                                        unauthenticated_attributes: Vec::new(),
353                                    });
354                                }
355                            }
356                        }
357                    }
358                }
359            }
360            Err(_) => {
361                // Fall back to default
362                signer_infos.push(SignerInfo {
363                    version: 1,
364                    issuer_and_serial: IssuerAndSerial {
365                        issuer: "CN=Unknown".to_string(),
366                        serial_number: vec![1],
367                    },
368                    digest_algorithm: "SHA-256".to_string(),
369                    signature_algorithm: "RSA".to_string(),
370                    signature: vec![0; 256],
371                    authenticated_attributes: Vec::new(),
372                    unauthenticated_attributes: Vec::new(),
373                });
374            }
375        }
376
377        if signer_infos.is_empty() {
378            // Ensure we always have at least one signer info
379            signer_infos.push(SignerInfo {
380                version: 1,
381                issuer_and_serial: IssuerAndSerial {
382                    issuer: "CN=Default Signer".to_string(),
383                    serial_number: vec![1],
384                },
385                digest_algorithm: "SHA-256".to_string(),
386                signature_algorithm: "RSA".to_string(),
387                signature: vec![0; 256],
388                authenticated_attributes: Vec::new(),
389                unauthenticated_attributes: Vec::new(),
390            });
391        }
392
393        Ok(signer_infos)
394    }
395
396    /// Verify PKCS#7 signature using OpenSSL
397    #[cfg(feature = "crypto")]
398    fn verify_with_openssl(
399        &self,
400        pkcs7_info: &Pkcs7Info,
401        signed_data: &[u8],
402    ) -> CryptoResult<SignatureVerificationResult> {
403        use openssl::pkcs7::Pkcs7Flags;
404        use openssl::stack::Stack;
405        use openssl::x509::store::X509StoreBuilder;
406
407        let pkcs7 = match Pkcs7::from_der(&pkcs7_info.raw_data) {
408            Ok(p7) => p7,
409            Err(e) => {
410                return Ok(SignatureVerificationResult {
411                    is_valid: false,
412                    signer_certificate: None,
413                    signing_time: None,
414                    algorithm: "PKCS#7".to_string(),
415                    error_message: Some(format!("Failed to parse PKCS#7: {}", e)),
416                    certificate_chain: Vec::new(),
417                    timestamp_info: None,
418                });
419            }
420        };
421
422        let empty_certs = Stack::new().unwrap();
423        let certs = pkcs7
424            .signed()
425            .and_then(|s| s.certificates())
426            .unwrap_or(&empty_certs);
427
428        let mut cert_chain = Vec::new();
429        for cert in certs.iter() {
430            if let Ok(info) = self.parse_x509_certificate_openssl(cert) {
431                cert_chain.push(info);
432            }
433        }
434
435        let mut store_builder = X509StoreBuilder::new()
436            .map_err(|e| CryptoError::OpenSsl(format!("Failed to create store builder: {}", e)))?;
437        store_builder.set_default_paths().map_err(|e| {
438            CryptoError::OpenSsl(format!("Failed to load system trust store: {}", e))
439        })?;
440        let store = store_builder.build();
441
442        let mut output = Vec::new();
443        let verify_result = pkcs7.verify(
444            certs,
445            &store,
446            if signed_data.is_empty() {
447                None
448            } else {
449                Some(signed_data)
450            },
451            Some(&mut output),
452            Pkcs7Flags::empty(),
453        );
454
455        let is_valid = verify_result.is_ok();
456        let error_message = verify_result
457            .err()
458            .map(|e| format!("PKCS#7 verification failed: {}", e));
459
460        let signer_cert_info = pkcs7
461            .signers(certs, Pkcs7Flags::empty())
462            .ok()
463            .and_then(|stack| {
464                let cert = stack.iter().next()?;
465                self.parse_x509_certificate_openssl(cert).ok()
466            });
467
468        let signing_time = self.extract_signing_time(pkcs7_info);
469        let timestamp_info = self.extract_timestamp_info(pkcs7_info);
470
471        Ok(SignatureVerificationResult {
472            is_valid,
473            signer_certificate: signer_cert_info,
474            signing_time,
475            algorithm: "PKCS#7".to_string(),
476            error_message,
477            certificate_chain: cert_chain,
478            timestamp_info,
479        })
480    }
481
482    /// Simple PKCS#7 verification without crypto libraries
483    #[cfg(not(feature = "crypto"))]
484    fn verify_simple(
485        &self,
486        pkcs7_info: &Pkcs7Info,
487        signed_data: &[u8],
488    ) -> CryptoResult<SignatureVerificationResult> {
489        // Extract signer certificate
490        let signer_cert = if !pkcs7_info.certificates.is_empty() {
491            self.parse_certificate_simple(&pkcs7_info.certificates[0])
492                .ok()
493        } else {
494            None
495        };
496
497        // Create basic verification result
498        Ok(SignatureVerificationResult {
499            is_valid: false,
500            signer_certificate: signer_cert,
501            signing_time: self.extract_signing_time(pkcs7_info),
502            algorithm: "PKCS#7".to_string(),
503            error_message: Some("Full PKCS#7 verification requires crypto features".to_string()),
504            certificate_chain: self.parse_certificate_chain(&pkcs7_info.certificates),
505            timestamp_info: self.extract_timestamp_info(pkcs7_info),
506        })
507    }
508
509    /// Parse X509 certificate using OpenSSL
510    #[cfg(feature = "crypto")]
511    fn parse_x509_certificate_openssl(&self, cert: &X509Ref) -> CryptoResult<CertificateInfo> {
512        let der = cert
513            .to_der()
514            .map_err(|e| CryptoError::CertificateError(format!("X509 DER encode error: {}", e)))?;
515
516        let (_, parsed) = X509Certificate::from_der(&der).map_err(|e| {
517            CryptoError::CertificateError(format!("Failed to parse certificate: {}", e))
518        })?;
519
520        let subject = parsed.subject().to_string();
521        let issuer = parsed.issuer().to_string();
522        let serial_number = parsed.tbs_certificate.raw_serial_as_string();
523
524        let not_before = self
525            .asn1_time_to_chrono_x509(&parsed.validity().not_before)
526            .unwrap_or_else(super::chrono::Utc::now);
527        let not_after = self
528            .asn1_time_to_chrono_x509(&parsed.validity().not_after)
529            .unwrap_or_else(super::chrono::Utc::now);
530
531        let public_key_algorithm = parsed.public_key().algorithm.algorithm.to_string();
532        let signature_algorithm = parsed.signature_algorithm.algorithm.to_string();
533
534        let fingerprint_sha256 = self
535            .compute_sha256(&der)
536            .map(|hash| hash.iter().map(|byte| format!("{:02x}", byte)).collect())
537            .unwrap_or_else(|_| "unknown".to_string());
538
539        let key_usage = parse_key_usage_from_x509(&parsed);
540        let extended_key_usage = parse_extended_key_usage_from_x509(&parsed);
541        let is_ca = parse_is_ca_from_x509(&parsed);
542
543        Ok(CertificateInfo {
544            subject,
545            issuer,
546            serial_number,
547            der,
548            not_before,
549            not_after,
550            public_key_algorithm,
551            signature_algorithm,
552            key_usage,
553            extended_key_usage,
554            is_ca,
555            fingerprint_sha256,
556        })
557    }
558
559    /// Parse certificate using simple method
560    #[allow(dead_code)]
561    fn parse_certificate_simple(&self, cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
562        #[cfg(feature = "crypto")]
563        {
564            self.parse_certificate_with_x509_parser(cert_data)
565        }
566        #[cfg(not(feature = "crypto"))]
567        {
568            self.parse_certificate_basic(cert_data)
569        }
570    }
571
572    /// Parse certificate using x509-parser library
573    #[cfg(feature = "crypto")]
574    #[allow(dead_code)]
575    fn parse_certificate_with_x509_parser(
576        &self,
577        cert_data: &[u8],
578    ) -> CryptoResult<CertificateInfo> {
579        // Parse the certificate using x509-parser
580        let (_, cert) = X509Certificate::from_der(cert_data).map_err(|e| {
581            CryptoError::CertificateError(format!("Failed to parse certificate: {}", e))
582        })?;
583
584        let subject = cert.subject().to_string();
585        let issuer = cert.issuer().to_string();
586        let serial_number = cert.tbs_certificate.raw_serial_as_string();
587
588        let not_before = self
589            .asn1_time_to_chrono_x509(&cert.validity().not_before)
590            .unwrap_or_else(super::chrono::Utc::now);
591        let not_after = self
592            .asn1_time_to_chrono_x509(&cert.validity().not_after)
593            .unwrap_or_else(super::chrono::Utc::now);
594
595        let public_key_algorithm = cert.public_key().algorithm.algorithm.to_string();
596        let signature_algorithm = cert.signature_algorithm.algorithm.to_string();
597
598        let fingerprint_sha256 = self
599            .compute_sha256(cert_data)
600            .map(|hash| hash.iter().map(|byte| format!("{:02x}", byte)).collect())
601            .unwrap_or_else(|_| "unknown".to_string());
602
603        let key_usage = parse_key_usage_from_x509(&cert);
604        let extended_key_usage = parse_extended_key_usage_from_x509(&cert);
605        let is_ca = parse_is_ca_from_x509(&cert);
606
607        Ok(CertificateInfo {
608            subject,
609            issuer,
610            serial_number,
611            der: cert_data.to_vec(),
612            not_before,
613            not_after,
614            public_key_algorithm,
615            signature_algorithm,
616            key_usage,
617            extended_key_usage,
618            is_ca,
619            fingerprint_sha256,
620        })
621    }
622
623    /// Convert x509-parser ASN.1 Time to chrono DateTime
624    #[cfg(feature = "crypto")]
625    #[allow(dead_code)]
626    fn asn1_time_to_chrono_x509(
627        &self,
628        _asn1_time: &ASN1Time,
629    ) -> Option<super::chrono::DateTime<super::chrono::Utc>> {
630        let time = _asn1_time.to_datetime();
631        Some(super::chrono::DateTime::from_timestamp(
632            time.unix_timestamp(),
633        ))
634    }
635
636    /// Basic certificate parsing without crypto libraries
637    #[cfg(not(feature = "crypto"))]
638    fn parse_certificate_basic(&self, cert_data: &[u8]) -> CryptoResult<CertificateInfo> {
639        if cert_data.len() < 100 {
640            return Err(CryptoError::CertificateError(
641                "Certificate too short".to_string(),
642            ));
643        }
644
645        // Very basic parsing - just return placeholder values
646        Ok(CertificateInfo {
647            subject: "CN=PKCS#7 Signer".to_string(),
648            issuer: "CN=Unknown CA".to_string(),
649            serial_number: "123456".to_string(),
650            der: cert_data.to_vec(),
651            not_before: super::chrono::Utc::now(),
652            not_after: super::chrono::Utc::now(),
653            public_key_algorithm: "RSA".to_string(),
654            signature_algorithm: "SHA256withRSA".to_string(),
655            key_usage: vec!["Digital Signature".to_string()],
656            extended_key_usage: vec!["Code Signing".to_string()],
657            is_ca: false,
658            fingerprint_sha256: "basic_cert_fingerprint".to_string(),
659        })
660    }
661
662    /// Parse certificate chain
663    #[allow(dead_code)]
664    fn parse_certificate_chain(&self, cert_data_list: &[Vec<u8>]) -> Vec<CertificateInfo> {
665        cert_data_list
666            .iter()
667            .filter_map(|cert_data| self.parse_certificate_simple(cert_data).ok())
668            .collect()
669    }
670
671    /// Extract signing time from PKCS#7 authenticated attributes
672    fn extract_signing_time(
673        &self,
674        pkcs7_info: &Pkcs7Info,
675    ) -> Option<super::chrono::DateTime<super::chrono::Utc>> {
676        // Look for signing time in authenticated attributes
677        for signer_info in &pkcs7_info.signer_infos {
678            for attr in &signer_info.authenticated_attributes {
679                if attr.oid == "1.2.840.113549.1.9.5" {
680                    // signing-time OID
681                    // Parse time from attribute value
682                    return Some(super::chrono::Utc::now()); // Placeholder
683                }
684            }
685        }
686        None
687    }
688
689    /// Extract timestamp info from PKCS#7 unauthenticated attributes
690    fn extract_timestamp_info(&self, pkcs7_info: &Pkcs7Info) -> Option<TimestampInfo> {
691        // Look for timestamp in unauthenticated attributes
692        for signer_info in &pkcs7_info.signer_infos {
693            for attr in &signer_info.unauthenticated_attributes {
694                if attr.oid == "1.2.840.113549.1.9.16.2.14" {
695                    // timestamp token OID
696                    if let Some(value) = attr.values.first() {
697                        if let Ok(parsed) = timestamp::parse_timestamp_token(value) {
698                            let hash_algorithm = parsed
699                                .hash_algorithm
700                                .unwrap_or_else(|| "Unknown".to_string());
701                            let timestamp_authority = parsed
702                                .tsa_certificate_der
703                                .as_deref()
704                                .and_then(Self::extract_cert_subject)
705                                .or(parsed.policy_oid)
706                                .unwrap_or_else(|| "Unknown TSA".to_string());
707                            let error_message = if parsed.message_imprint.is_some() {
708                                Some(
709                                    "Timestamp parsed; digest verification requires document bytes"
710                                        .to_string(),
711                                )
712                            } else {
713                                Some("Timestamp missing message imprint".to_string())
714                            };
715                            return Some(TimestampInfo {
716                                timestamp: parsed.time,
717                                timestamp_authority,
718                                hash_algorithm,
719                                is_valid: false,
720                                error_message,
721                            });
722                        }
723                    }
724                }
725            }
726        }
727        None
728    }
729
730    #[cfg(feature = "crypto")]
731    fn extract_cert_subject(cert_der: &[u8]) -> Option<String> {
732        use openssl::x509::X509;
733
734        let cert = X509::from_der(cert_der).ok()?;
735        let subject = cert.subject_name();
736        subject
737            .entries()
738            .next()
739            .and_then(|entry| entry.data().as_utf8().ok().map(|s| s.to_string()))
740    }
741
742    #[cfg(not(feature = "crypto"))]
743    fn extract_cert_subject(_cert_der: &[u8]) -> Option<String> {
744        None
745    }
746
747    /// Extract digest from signed data
748    pub fn compute_digest(&self, data: &[u8], algorithm: &str) -> CryptoResult<Vec<u8>> {
749        match algorithm {
750            "SHA-1" => self.compute_sha1(data),
751            "SHA-256" => self.compute_sha256(data),
752            "SHA-384" => self.compute_sha384(data),
753            "SHA-512" => self.compute_sha512(data),
754            _ => Err(CryptoError::UnsupportedAlgorithm(format!(
755                "Unsupported digest algorithm: {}",
756                algorithm
757            ))),
758        }
759    }
760
761    #[cfg(feature = "crypto")]
762    fn compute_sha1(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
763        use openssl::hash::{hash, MessageDigest};
764
765        hash(MessageDigest::sha1(), data)
766            .map(|digest| digest.to_vec())
767            .map_err(|e| {
768                CryptoError::UnsupportedAlgorithm(format!("SHA-1 computation failed: {}", e))
769            })
770    }
771
772    #[cfg(feature = "crypto")]
773    fn compute_sha256(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
774        use openssl::hash::{hash, MessageDigest};
775
776        hash(MessageDigest::sha256(), data)
777            .map(|digest| digest.to_vec())
778            .map_err(|e| {
779                CryptoError::UnsupportedAlgorithm(format!("SHA-256 computation failed: {}", e))
780            })
781    }
782
783    #[cfg(feature = "crypto")]
784    fn compute_sha384(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
785        use openssl::hash::{hash, MessageDigest};
786
787        hash(MessageDigest::sha384(), data)
788            .map(|digest| digest.to_vec())
789            .map_err(|e| {
790                CryptoError::UnsupportedAlgorithm(format!("SHA-384 computation failed: {}", e))
791            })
792    }
793
794    #[cfg(feature = "crypto")]
795    fn compute_sha512(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
796        use openssl::hash::{hash, MessageDigest};
797
798        hash(MessageDigest::sha512(), data)
799            .map(|digest| digest.to_vec())
800            .map_err(|e| {
801                CryptoError::UnsupportedAlgorithm(format!("SHA-512 computation failed: {}", e))
802            })
803    }
804
805    #[cfg(not(feature = "crypto"))]
806    fn compute_sha1(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
807        let mut hasher = Sha1::new();
808        hasher.update(data);
809        Ok(hasher.finalize().to_vec())
810    }
811
812    #[cfg(not(feature = "crypto"))]
813    fn compute_sha256(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
814        let mut hasher = Sha256::new();
815        hasher.update(data);
816        Ok(hasher.finalize().to_vec())
817    }
818
819    #[cfg(not(feature = "crypto"))]
820    fn compute_sha384(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
821        let mut hasher = Sha384::new();
822        hasher.update(data);
823        Ok(hasher.finalize().to_vec())
824    }
825
826    #[cfg(not(feature = "crypto"))]
827    fn compute_sha512(&self, data: &[u8]) -> CryptoResult<Vec<u8>> {
828        let mut hasher = Sha512::new();
829        hasher.update(data);
830        Ok(hasher.finalize().to_vec())
831    }
832
833    /// Parse signed data from PKCS#7 contents
834    pub fn parse_signed_data(&self, contents: &[u8]) -> CryptoResult<SignedData> {
835        // For now, return a simplified SignedData structure
836        // In a full implementation, this would parse the actual ASN.1 structure
837        Ok(SignedData {
838            content_info: ContentInfo {
839                content_type: "1.2.840.113549.1.7.1".to_string(), // id-data
840                content: Some(contents.to_vec()),
841            },
842            certificates: Vec::new(),
843            crls: Vec::new(),
844            signers: Vec::new(),
845        })
846    }
847}
848
849#[cfg(feature = "crypto")]
850fn parse_key_usage_from_x509(cert: &X509Certificate) -> Vec<String> {
851    use x509_parser::extensions::ParsedExtension;
852    for ext in cert.extensions() {
853        if let ParsedExtension::KeyUsage(ku) = &ext.parsed_extension() {
854            let mut out = Vec::new();
855            if ku.digital_signature() {
856                out.push("Digital Signature".to_string());
857            }
858            if ku.non_repudiation() {
859                out.push("Non Repudiation".to_string());
860            }
861            if ku.key_encipherment() {
862                out.push("Key Encipherment".to_string());
863            }
864            if ku.data_encipherment() {
865                out.push("Data Encipherment".to_string());
866            }
867            if ku.key_agreement() {
868                out.push("Key Agreement".to_string());
869            }
870            if ku.key_cert_sign() {
871                out.push("Certificate Signing".to_string());
872            }
873            if ku.crl_sign() {
874                out.push("CRL Signing".to_string());
875            }
876            if ku.encipher_only() {
877                out.push("Encipher Only".to_string());
878            }
879            if ku.decipher_only() {
880                out.push("Decipher Only".to_string());
881            }
882            return out;
883        }
884    }
885    Vec::new()
886}
887
888#[cfg(feature = "crypto")]
889fn parse_extended_key_usage_from_x509(cert: &X509Certificate) -> Vec<String> {
890    use x509_parser::extensions::ParsedExtension;
891    for ext in cert.extensions() {
892        if let ParsedExtension::ExtendedKeyUsage(eku) = &ext.parsed_extension() {
893            let mut out = Vec::new();
894            if eku.any {
895                out.push("Any".to_string());
896            }
897            if eku.server_auth {
898                out.push("Server Auth".to_string());
899            }
900            if eku.client_auth {
901                out.push("Client Auth".to_string());
902            }
903            if eku.code_signing {
904                out.push("Code Signing".to_string());
905            }
906            if eku.email_protection {
907                out.push("Email Protection".to_string());
908            }
909            if eku.time_stamping {
910                out.push("Time Stamping".to_string());
911            }
912            if eku.ocsp_signing {
913                out.push("OCSP Signing".to_string());
914            }
915            for oid in &eku.other {
916                out.push(oid.to_string());
917            }
918            return out;
919        }
920    }
921    Vec::new()
922}
923
924#[cfg(feature = "crypto")]
925fn parse_is_ca_from_x509(cert: &X509Certificate) -> bool {
926    use x509_parser::extensions::ParsedExtension;
927    for ext in cert.extensions() {
928        if let ParsedExtension::BasicConstraints(bc) = &ext.parsed_extension() {
929            return bc.ca;
930        }
931    }
932    false
933}
934
935#[derive(Debug, Clone)]
936pub struct Pkcs7Info {
937    pub version: u32,
938    pub digest_algorithms: Vec<String>,
939    pub content_info: ContentInfo,
940    pub certificates: Vec<Vec<u8>>,
941    pub signer_infos: Vec<SignerInfo>,
942    pub raw_data: Vec<u8>,
943}
944
945#[derive(Debug, Clone)]
946pub struct ContentInfo {
947    pub content_type: String,
948    pub content: Option<Vec<u8>>,
949}
950
951#[derive(Debug, Clone)]
952pub struct SignerInfo {
953    pub version: u32,
954    pub issuer_and_serial: IssuerAndSerial,
955    pub digest_algorithm: String,
956    pub signature_algorithm: String,
957    pub signature: Vec<u8>,
958    pub authenticated_attributes: Vec<Attribute>,
959    pub unauthenticated_attributes: Vec<Attribute>,
960}
961
962#[derive(Debug, Clone)]
963pub struct IssuerAndSerial {
964    pub issuer: String,
965    pub serial_number: Vec<u8>,
966}
967
968#[derive(Debug, Clone)]
969pub struct Attribute {
970    pub oid: String,
971    pub values: Vec<Vec<u8>>,
972}
973
974/// PKCS#7 builder for creating signed data
975pub struct Pkcs7Builder {
976    content: Option<Vec<u8>>,
977    certificates: Vec<Vec<u8>>,
978    signers: Vec<SignerConfig>,
979    detached: bool,
980}
981
982impl Default for Pkcs7Builder {
983    fn default() -> Self {
984        Self::new()
985    }
986}
987
988impl Pkcs7Builder {
989    pub fn new() -> Self {
990        Self {
991            content: None,
992            certificates: Vec::new(),
993            signers: Vec::new(),
994            detached: false,
995        }
996    }
997
998    pub fn with_content(mut self, content: Vec<u8>) -> Self {
999        self.content = Some(content);
1000        self
1001    }
1002
1003    pub fn add_certificate(mut self, cert: Vec<u8>) -> Self {
1004        self.certificates.push(cert);
1005        self
1006    }
1007
1008    pub fn add_signer(mut self, signer: SignerConfig) -> Self {
1009        self.signers.push(signer);
1010        self
1011    }
1012
1013    pub fn detached(mut self, detached: bool) -> Self {
1014        self.detached = detached;
1015        self
1016    }
1017
1018    pub fn build(self) -> CryptoResult<Vec<u8>> {
1019        #[cfg(feature = "crypto")]
1020        {
1021            self.build_with_openssl()
1022        }
1023        #[cfg(not(feature = "crypto"))]
1024        {
1025            Err(CryptoError::UnsupportedAlgorithm(
1026                "PKCS#7 building requires crypto feature".to_string(),
1027            ))
1028        }
1029    }
1030
1031    /// Build PKCS#7 using OpenSSL
1032    #[cfg(feature = "crypto")]
1033    fn build_with_openssl(self) -> CryptoResult<Vec<u8>> {
1034        use openssl::{
1035            pkcs7::{Pkcs7, Pkcs7Flags},
1036            stack::Stack,
1037        };
1038
1039        if self.signers.is_empty() {
1040            return Err(CryptoError::InvalidSignatureFormat(
1041                "No signers provided".to_string(),
1042            ));
1043        }
1044
1045        // Parse certificates and private keys for signers
1046        let mut signer_certs = Stack::new().map_err(|e| {
1047            CryptoError::InvalidSignatureFormat(format!(
1048                "Failed to create certificate stack: {}",
1049                e
1050            ))
1051        })?;
1052        let mut signer_keys = Vec::new();
1053
1054        for signer in &self.signers {
1055            // Parse certificate
1056            let cert = X509::from_der(&signer.certificate).map_err(|e| {
1057                CryptoError::CertificateError(format!("Failed to parse signer certificate: {}", e))
1058            })?;
1059            signer_certs.push(cert).map_err(|e| {
1060                CryptoError::InvalidSignatureFormat(format!(
1061                    "Failed to add certificate to stack: {}",
1062                    e
1063                ))
1064            })?;
1065
1066            // Parse private key
1067            let key = PKey::private_key_from_der(&signer.private_key)
1068                .or_else(|_| PKey::private_key_from_pem(&signer.private_key))
1069                .map_err(|e| {
1070                    CryptoError::InvalidKey(format!("Failed to parse private key: {}", e))
1071                })?;
1072            signer_keys.push(key);
1073        }
1074
1075        // Parse additional certificates
1076        let mut certs = Stack::new().map_err(|e| {
1077            CryptoError::InvalidSignatureFormat(format!(
1078                "Failed to create certificate stack: {}",
1079                e
1080            ))
1081        })?;
1082        for cert_data in &self.certificates {
1083            let cert = X509::from_der(cert_data).map_err(|e| {
1084                CryptoError::CertificateError(format!("Failed to parse certificate: {}", e))
1085            })?;
1086            certs.push(cert).map_err(|e| {
1087                CryptoError::InvalidSignatureFormat(format!(
1088                    "Failed to add certificate to stack: {}",
1089                    e
1090                ))
1091            })?;
1092        }
1093
1094        // Create PKCS#7 signed data
1095        let content_bytes;
1096        let content_slice = if let Some(content_data) = &self.content {
1097            content_bytes = content_data.as_slice();
1098            Some(content_bytes)
1099        } else {
1100            None
1101        };
1102
1103        let flags = if self.detached {
1104            Pkcs7Flags::DETACHED
1105        } else {
1106            Pkcs7Flags::empty()
1107        };
1108
1109        // For simplicity, using the first signer
1110        if let (Some(first_signer_cert), Some(first_signer_key)) =
1111            (signer_certs.get(0), signer_keys.first())
1112        {
1113            let content_for_signing = content_slice.unwrap_or(&[]);
1114
1115            let pkcs7 = Pkcs7::sign(
1116                first_signer_cert,
1117                first_signer_key,
1118                &certs,
1119                content_for_signing,
1120                flags,
1121            )
1122            .map_err(|e| {
1123                CryptoError::InvalidSignatureFormat(format!("Failed to create PKCS#7: {}", e))
1124            })?;
1125
1126            // Convert to DER format
1127            pkcs7.to_der().map_err(|e| {
1128                CryptoError::InvalidSignatureFormat(format!("Failed to serialize PKCS#7: {}", e))
1129            })
1130        } else {
1131            Err(CryptoError::InvalidSignatureFormat(
1132                "No valid signers available".to_string(),
1133            ))
1134        }
1135    }
1136}
1137
1138#[derive(Debug, Clone)]
1139pub struct SignerConfig {
1140    pub certificate: Vec<u8>,
1141    pub private_key: Vec<u8>,
1142    pub digest_algorithm: String,
1143    pub signature_algorithm: String,
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148    use super::*;
1149
1150    #[test]
1151    fn test_pkcs7_handler_creation() {
1152        let handler = Pkcs7Handler::new();
1153        // Just test that it can be created
1154        assert_eq!(std::mem::size_of_val(&handler), 0); // Zero-sized struct
1155    }
1156
1157    #[test]
1158    fn test_asn1_length_parsing() {
1159        let handler = Pkcs7Handler::new();
1160
1161        // Test short form
1162        let short_data = [0x05]; // Length = 5
1163        let (start, length) = handler.parse_asn1_length(&short_data).unwrap();
1164        assert_eq!(start, 1);
1165        assert_eq!(length, 5);
1166
1167        // Test long form
1168        let long_data = [0x81, 0xFF]; // Length = 255
1169        let (start, length) = handler.parse_asn1_length(&long_data).unwrap();
1170        assert_eq!(start, 2);
1171        assert_eq!(length, 255);
1172    }
1173
1174    #[test]
1175    fn test_sequence_detection() {
1176        let handler = Pkcs7Handler::new();
1177        let data = [0x01, 0x02, 0x03, 0x04, 0x05];
1178        let sequence = [0x03, 0x04];
1179
1180        assert!(handler.contains_sequence(&data, &sequence));
1181
1182        let not_found = [0x06, 0x07];
1183        assert!(!handler.contains_sequence(&data, &not_found));
1184    }
1185
1186    #[test]
1187    fn test_pkcs7_structure_validation() {
1188        let handler = Pkcs7Handler::new();
1189
1190        // Test invalid data
1191        let invalid_data = [0x00, 0x01, 0x02];
1192        assert!(handler.parse_pkcs7_structure(&invalid_data).is_err());
1193
1194        // Test data that starts like ASN.1 SEQUENCE
1195        let sequence_data = [0x30, 0x82, 0x01, 0x00]; // SEQUENCE, length 256
1196                                                      // This will fail because it doesn't contain SignedData OID, which is expected
1197        assert!(handler.parse_pkcs7_structure(&sequence_data).is_err());
1198    }
1199
1200    #[test]
1201    fn test_pkcs7_builder() {
1202        let builder = Pkcs7Builder::new()
1203            .with_content(b"Hello, World!".to_vec())
1204            .detached(false);
1205
1206        // Building will fail without proper certificates/keys, which is expected
1207        let result = builder.build();
1208        assert!(result.is_err());
1209    }
1210
1211    #[test]
1212    fn test_hash_functions() {
1213        let handler = Pkcs7Handler::new();
1214        let test_data = b"test data";
1215
1216        // Test SHA-256
1217        let sha256_result = handler.compute_sha256(test_data);
1218        assert!(sha256_result.is_ok());
1219        assert_eq!(sha256_result.unwrap().len(), 32); // SHA-256 produces 32 bytes
1220
1221        // Test SHA-1
1222        let sha1_result = handler.compute_sha1(test_data);
1223        assert!(sha1_result.is_ok());
1224        assert_eq!(sha1_result.unwrap().len(), 20); // SHA-1 produces 20 bytes
1225
1226        // Test SHA-384
1227        let sha384_result = handler.compute_sha384(test_data);
1228        assert!(sha384_result.is_ok());
1229        assert_eq!(sha384_result.unwrap().len(), 48); // SHA-384 produces 48 bytes
1230
1231        // Test SHA-512
1232        let sha512_result = handler.compute_sha512(test_data);
1233        assert!(sha512_result.is_ok());
1234        assert_eq!(sha512_result.unwrap().len(), 64); // SHA-512 produces 64 bytes
1235    }
1236
1237    #[test]
1238    fn test_certificate_parsing_basic() {
1239        let handler = Pkcs7Handler::new();
1240
1241        // Test that the method exists and handles invalid data gracefully
1242        // Since we're testing with invalid certificate data, we expect it to fail
1243        // with a proper error message rather than crashing
1244        let invalid_cert_data = vec![0x30, 0x82, 0x01, 0x00]; // Incomplete DER sequence
1245        let mut cert_data_extended = invalid_cert_data;
1246        cert_data_extended.resize(200, 0); // Make it large enough
1247
1248        let result = handler.parse_certificate_simple(&cert_data_extended);
1249
1250        // The test should verify that:
1251        // 1. Invalid certificate data is handled gracefully (returns error)
1252        // 2. The error message is meaningful
1253        match result {
1254            Ok(_) => {
1255                // If it succeeds, verify the certificate info has reasonable data
1256                let cert_info = result.unwrap();
1257                assert!(!cert_info.subject.is_empty());
1258                assert!(!cert_info.issuer.is_empty());
1259            }
1260            Err(e) => {
1261                // Verify that we get a proper certificate parsing error
1262                assert!(matches!(e, CryptoError::CertificateError(_)));
1263                if let CryptoError::CertificateError(msg) = e {
1264                    assert!(msg.contains("Failed to parse certificate"));
1265                }
1266            }
1267        }
1268
1269        // Also test that extremely short data is rejected appropriately
1270        let too_short = vec![0x30, 0x01];
1271        let result_short = handler.parse_certificate_simple(&too_short);
1272        assert!(result_short.is_err());
1273    }
1274}