1pub struct SignatureVerifier;
2
3impl SignatureVerifier {
4 pub fn verify_pkcs7_signature(
5 contents: &[u8],
6 signed_data: &[u8],
7 ) -> SignatureVerificationResult {
8 let handler = crate::crypto::pkcs7::Pkcs7Handler::new();
9 match handler.verify_pkcs7(contents, signed_data) {
10 Ok(result) => SignatureVerificationResult {
11 is_valid: result.is_valid,
12 error: result.error_message.clone(),
13 certificate_chain: result
14 .certificate_chain
15 .iter()
16 .map(|c| CertificateInfo {
17 subject: c.subject.clone(),
18 issuer: c.issuer.clone(),
19 serial_number: c.serial_number.clone(),
20 not_before: format!("{}", c.not_before),
21 not_after: format!("{}", c.not_after),
22 public_key_algorithm: c.public_key_algorithm.clone(),
23 signature_algorithm: c.signature_algorithm.clone(),
24 key_usage: c.key_usage.clone(),
25 extended_key_usage: c.extended_key_usage.clone(),
26 })
27 .collect(),
28 signing_time: result.signing_time.map(|t| format!("{}", t)),
29 timestamp_info: result.timestamp_info.as_ref().map(|t| TimestampInfo {
30 timestamp_authority: t.timestamp_authority.clone(),
31 timestamp: format!("{}", t.timestamp),
32 hash_algorithm: t.hash_algorithm.clone(),
33 is_valid: t.is_valid,
34 }),
35 },
36 Err(e) => SignatureVerificationResult {
37 is_valid: false,
38 error: Some(format!("PKCS#7 verification error: {}", e)),
39 certificate_chain: Vec::new(),
40 signing_time: None,
41 timestamp_info: None,
42 },
43 }
44 }
45
46 pub fn verify_x509_signature(
47 _contents: &[u8],
48 _signed_data: &[u8],
49 ) -> SignatureVerificationResult {
50 SignatureVerificationResult {
51 is_valid: false,
52 error: Some("X.509 verification requires certificate and data context".to_string()),
53 certificate_chain: Vec::new(),
54 signing_time: None,
55 timestamp_info: None,
56 }
57 }
58
59 pub fn extract_signature_info(contents: &[u8]) -> Result<SignatureInfo, String> {
60 if contents.len() < 10 {
64 return Err("Signature contents too short".to_string());
65 }
66
67 if contents.starts_with(&[0x30, 0x82]) || contents.starts_with(&[0x30, 0x80]) {
69 Ok(SignatureInfo {
70 format: SignatureFormat::PKCS7,
71 algorithm: "Unknown".to_string(),
72 signer_info: None,
73 certificates: Vec::new(),
74 timestamp: None,
75 })
76 } else {
77 Err("Unknown signature format".to_string())
78 }
79 }
80}
81
82#[derive(Debug, Clone)]
83pub struct SignatureVerificationResult {
84 pub is_valid: bool,
85 pub error: Option<String>,
86 pub certificate_chain: Vec<CertificateInfo>,
87 pub signing_time: Option<String>,
88 pub timestamp_info: Option<TimestampInfo>,
89}
90
91#[derive(Debug, Clone)]
92pub struct SignatureInfo {
93 pub format: SignatureFormat,
94 pub algorithm: String,
95 pub signer_info: Option<SignerInfo>,
96 pub certificates: Vec<CertificateInfo>,
97 pub timestamp: Option<TimestampInfo>,
98}
99
100#[derive(Debug, Clone)]
101pub enum SignatureFormat {
102 PKCS7,
103 X509,
104 CAdES,
105 PAdES,
106}
107
108#[derive(Debug, Clone)]
109pub struct SignerInfo {
110 pub issuer: String,
111 pub serial_number: String,
112 pub digest_algorithm: String,
113 pub signature_algorithm: String,
114}
115
116#[derive(Debug, Clone)]
117pub struct CertificateInfo {
118 pub subject: String,
119 pub issuer: String,
120 pub serial_number: String,
121 pub not_before: String,
122 pub not_after: String,
123 pub public_key_algorithm: String,
124 pub signature_algorithm: String,
125 pub key_usage: Vec<String>,
126 pub extended_key_usage: Vec<String>,
127}
128
129#[derive(Debug, Clone)]
130pub struct TimestampInfo {
131 pub timestamp_authority: String,
132 pub timestamp: String,
133 pub hash_algorithm: String,
134 pub is_valid: bool,
135}
136
137pub fn to_digital_signature(
138 info: &crate::crypto::signature_verification::SignatureInfo,
139) -> crate::security::DigitalSignature {
140 let signature_type = match info.sub_filter.as_str() {
141 "adbe.pkcs7.detached" => crate::security::SignatureType::AdbePkcs7Detached,
142 "adbe.pkcs7.sha1" => crate::security::SignatureType::AdbePkcs7Sha1,
143 "adbe.x509.rsa_sha1" => crate::security::SignatureType::AdbeX509RsaSha1,
144 "ETSI.CAdES.detached" => crate::security::SignatureType::EtsiCadEsDetached,
145 "ETSI.RFC3161" => crate::security::SignatureType::EtsiRfc3161,
146 _ => crate::security::SignatureType::AdbePkcs7Detached,
147 };
148
149 let signer = if info.signer.subject.is_empty() {
150 None
151 } else {
152 Some(info.signer.subject.clone())
153 };
154
155 let certificate_info = if info.signer.subject.is_empty() && info.signer.issuer.is_empty() {
156 None
157 } else {
158 Some(crate::security::CertificateInfo {
159 issuer: info.signer.issuer.clone(),
160 subject: info.signer.subject.clone(),
161 serial_number: bytes_to_hex(&info.signer.serial_number),
162 valid_from: info.signer.not_before.to_string(),
163 valid_to: info.signer.not_after.to_string(),
164 key_usage: info.signer.key_usage.clone(),
165 algorithm: info.filter.clone(),
166 })
167 };
168
169 let validity = match &info.validity {
170 crate::crypto::signature_verification::SignatureValidity::Valid => {
171 crate::security::SignatureValidity::Valid
172 }
173 crate::crypto::signature_verification::SignatureValidity::Unknown(msg) => {
174 crate::security::SignatureValidity::Unknown(msg.clone())
175 }
176 crate::crypto::signature_verification::SignatureValidity::Invalid(msg) => {
177 crate::security::SignatureValidity::Invalid(msg.clone())
178 }
179 other => crate::security::SignatureValidity::Unknown(format!("{:?}", other)),
180 };
181
182 let timestamp = info
183 .timestamp
184 .as_ref()
185 .map(|ts| crate::security::TimestampDetails {
186 time: Some(ts.time.to_string()),
187 policy_oid: ts.policy_oid.clone(),
188 hash_algorithm: ts.hash_algorithm.clone(),
189 signature_valid: ts.signature_valid,
190 tsa_chain_valid: ts.tsa_chain_valid,
191 tsa_pin_valid: ts.tsa_pin_valid,
192 tsa_revocation_events: ts.tsa_revocation_events.clone(),
193 });
194
195 crate::security::DigitalSignature {
196 field_name: info.field_name.clone(),
197 signature_type,
198 signer,
199 signing_time: info.signing_time.map(|t| t.to_string()),
200 certificate_info,
201 validity,
202 location: info.location.clone(),
203 reason: info.reason.clone(),
204 contact_info: info.contact_info.clone(),
205 timestamp,
206 }
207}
208
209fn bytes_to_hex(bytes: &[u8]) -> String {
210 let mut out = String::with_capacity(bytes.len() * 2);
211 for b in bytes {
212 out.push_str(&format!("{:02x}", b));
213 }
214 out
215}
216
217pub fn parse_pdf_date(date_str: &str) -> Result<String, String> {
218 if !date_str.starts_with("D:") {
220 return Err("Invalid PDF date format".to_string());
221 }
222
223 let date_part = &date_str[2..];
224 if date_part.len() < 14 {
225 return Err("PDF date too short".to_string());
226 }
227
228 let year = &date_part[0..4];
229 let month = &date_part[4..6];
230 let day = &date_part[6..8];
231 let hour = &date_part[8..10];
232 let minute = &date_part[10..12];
233 let second = &date_part[12..14];
234
235 Ok(format!(
236 "{}-{}-{} {}:{}:{}",
237 year, month, day, hour, minute, second
238 ))
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn test_parse_pdf_date() {
247 let date = "D:20231201120000+01'00";
248 let result = parse_pdf_date(date);
249 assert!(result.is_ok());
250 assert_eq!(result.unwrap(), "2023-12-01 12:00:00");
251 }
252
253 #[test]
254 fn test_invalid_pdf_date() {
255 let date = "InvalidDate";
256 let result = parse_pdf_date(date);
257 assert!(result.is_err());
258 }
259}