1use std::{fmt::Display, path::Path};
32
33use asn1_types::SpcIndirectDataContent;
34use cert::Algorithm;
35use chrono::{DateTime, Local, Utc};
36use cms::{
37 attr::SigningTime,
38 cert::x509::der::{oid::db::rfc5911::ID_SIGNED_DATA, Decode, SliceReader},
39 content_info::ContentInfo,
40};
41use der::{asn1::SetOfVec, Encode, EncodePem};
42use errors::{PeSignError, PeSignErrorKind, PeSignResult};
43use signed_data::SignedData;
44use utils::{to_hex_str, DisplayBytes, IndentString, TryVecInto};
45
46mod pe;
47
48pub mod asn1_types;
49pub mod cert;
50pub mod errors;
51pub mod signed_data;
52pub mod utils;
53pub use der;
54pub use pe::*;
55
56#[derive(Clone, Debug, Eq, PartialEq)]
72pub struct PeSign {
73 pub signed_data: SignedData,
74 pub authenticode_digest: String,
75 pub authenticode_digest_algorithm: Algorithm,
76 __inner: cms::content_info::ContentInfo,
77}
78
79impl der::Encode for PeSign {
80 fn encoded_len(&self) -> der::Result<der::Length> {
81 self.__inner.encoded_len()
82 }
83
84 fn encode(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
85 self.__inner.encode(encoder)
86 }
87}
88
89impl<'a> der::Decode<'a> for PeSign {
90 fn decode<R: der::Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
91 Self::from_reader(decoder)
92 .map_err(|_| der::Error::new(der::ErrorKind::Failed, der::Length::ZERO))
93 }
94}
95
96impl der::pem::PemLabel for PeSign {
97 const PEM_LABEL: &'static str = "PKCS7";
98}
99
100impl<'a> PeSign {
101 pub fn from_reader<R: der::Reader<'a>>(decoder: &mut R) -> Result<Self, PeSignError> {
102 let ci = ContentInfo::decode(decoder).map_app_err(PeSignErrorKind::InvalidContentInfo)?;
103
104 let __inner = ci.clone();
105
106 match ci.content_type {
108 ID_SIGNED_DATA => {
109 let signed_data: SignedData = ci
110 .content
111 .decode_as::<crate::asn1_types::SignedData>()
112 .map_app_err(PeSignErrorKind::InvalidSignedData)?
113 .try_into()?;
114
115 match &signed_data.encap_content_info.econtent_type[..] {
116 "1.3.6.1.4.1.311.2.1.4" => {
117 let spc_indirect_data_content = SpcIndirectDataContent::from_der(
118 &signed_data.encap_content_info.econtent,
119 )
120 .map_app_err(PeSignErrorKind::InvalidSpcIndirectDataContent)?;
121 let authenticode =
122 to_hex_str(spc_indirect_data_content.message_digest.digest.as_bytes());
123 let authenticode_digest =
124 spc_indirect_data_content.message_digest.algorithm.into();
125 Ok(Self {
126 signed_data,
127 authenticode_digest: authenticode,
128 authenticode_digest_algorithm: authenticode_digest,
129 __inner,
130 })
131 }
132 _ => Err(PeSignError {
133 kind: PeSignErrorKind::InvalidEncapsulatedContentType,
134 message: signed_data.encap_content_info.econtent_type,
135 }),
136 }
137 }
138 ct => Err(PeSignError {
139 kind: PeSignErrorKind::InvalidContentType,
140 message: ct.to_string(),
141 }
142 .into()),
143 }
144 }
145
146 pub fn from_certificate_table_buf(bin: &[u8]) -> Result<Self, PeSignError> {
148 let mut reader = SliceReader::new(bin).map_unknown_err()?;
149 Self::from_reader(&mut reader)
150 }
151
152 pub fn from_pe_path<P: AsRef<Path>>(filename: P) -> Result<Option<Self>, PeSignError> {
154 let mut image = PE::from_path(filename)?;
155
156 Self::from_pe_image(&mut image)
157 }
158
159 pub fn from_pe_data(bin: &[u8]) -> Result<Option<Self>, PeSignError> {
161 let mut image = PE::from_bytes(bin)?;
162
163 Self::from_pe_image(&mut image)
164 }
165
166 pub fn from_pe_image(image: &mut PE) -> Result<Option<Self>, PeSignError> {
168 match image.get_security_data()? {
169 Some(pkcs7_bytes) => Ok(Some(Self::from_certificate_table_buf(&pkcs7_bytes)?)),
170 None => Ok(None),
171 }
172 }
173
174 pub fn verify(self: &Self, option: &VerifyOption) -> Result<PeSignStatus, PeSignError> {
176 self.signed_data.verify(option)
177 }
178
179 pub fn verify_pe_path<P: AsRef<Path>>(
181 self: &Self,
182 filename: P,
183 option: &VerifyOption,
184 ) -> Result<PeSignStatus, PeSignError> {
185 let mut image = PE::from_path(filename)?;
186
187 self.verify_pe_image(&mut image, option)
188 }
189
190 pub fn verify_pe_data(
192 self: &Self,
193 bin: &[u8],
194 option: &VerifyOption,
195 ) -> Result<PeSignStatus, PeSignError> {
196 let mut image = PE::from_bytes(bin)?;
197
198 self.verify_pe_image(&mut image, option)
199 }
200
201 pub fn verify_pe_image(
203 self: &Self,
204 image: &mut PE,
205 option: &VerifyOption,
206 ) -> Result<PeSignStatus, PeSignError> {
207 let authenticode = image.calc_authenticode(self.authenticode_digest_algorithm.clone())?;
208
209 if authenticode != self.authenticode_digest {
210 Ok(PeSignStatus::Invalid)
211 } else {
212 self.verify(option)
213 }
214 }
215
216 pub fn export_der(self: &Self) -> Result<Vec<u8>, PeSignError> {
218 self.to_der().map_app_err(PeSignErrorKind::ExportDerError)
219 }
220
221 pub fn export_pem(self: &Self) -> Result<String, PeSignError> {
223 self.to_pem(Default::default())
224 .map_app_err(PeSignErrorKind::ExportPemError)
225 }
226}
227
228#[derive(Clone, Copy, Debug, Eq, PartialEq)]
230pub enum PeSignStatus {
231 UntrustedCertificateChain,
233
234 Expired,
236
237 Invalid,
239
240 Valid,
242}
243
244const DEFAULT_TRUSTED_CA_PEM: &str = include_str!("./cacert.pem");
245
246#[derive(Clone, Debug, Eq, PartialEq)]
247pub struct VerifyOption {
248 pub check_time: bool,
249 pub trusted_ca_pem: Option<String>,
250}
251
252impl Default for VerifyOption {
253 fn default() -> Self {
254 Self {
255 check_time: true,
256 trusted_ca_pem: None,
257 }
258 }
259}
260
261#[derive(Clone, Debug, Eq, PartialEq)]
262pub struct Attributes(pub Vec<Attribute>);
263
264impl TryFrom<x509_cert::attr::Attributes> for Attributes {
265 type Error = PeSignError;
266
267 fn try_from(value: x509_cert::attr::Attributes) -> Result<Self, Self::Error> {
268 Ok(Self(value.into_vec().try_vec_into().map_err(|err| {
269 Self::Error {
270 kind: PeSignErrorKind::Unknown,
271 message: err.to_string(),
272 }
273 })?))
274 }
275}
276
277impl Display for Attributes {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 write!(
280 f,
281 "{}",
282 self.0
283 .iter()
284 .map(|v| v.to_string())
285 .collect::<Vec<String>>()
286 .join("\n")
287 )
288 }
289}
290
291impl Attributes {
292 pub fn to_der(self: &Self) -> Result<Vec<u8>, PeSignError> {
293 let mut result = SetOfVec::<x509_cert::attr::Attribute>::new();
294
295 for vv in &self.0 {
296 result.insert(vv.__inner.clone()).map_unknown_err()?;
297 }
298
299 Ok(result.to_der().map_unknown_err()?)
300 }
301}
302
303#[derive(Clone, Debug, Eq, PartialEq)]
304pub struct Attribute {
305 pub oid: String,
306 pub values: Vec<Vec<u8>>,
307 __inner: x509_cert::attr::Attribute,
308}
309
310impl TryFrom<x509_cert::attr::Attribute> for Attribute {
311 type Error = PeSignError;
312
313 fn try_from(attr: x509_cert::attr::Attribute) -> Result<Self, Self::Error> {
314 let mut values = vec![];
315
316 for vv in attr.values.iter() {
317 values.push(vv.to_der().map_unknown_err()?);
318 }
319
320 Ok(Self {
321 oid: attr.oid.to_string(),
322 values: values,
323 __inner: attr,
324 })
325 }
326}
327
328impl Display for Attribute {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330 let attr_value = self.values.concat();
331 match self.oid.as_str() {
332 "1.2.840.113549.1.9.5" => {
333 writeln!(f, "{}", "Signing Time (1.2.840.113549.1.9.5):")?;
335 match SigningTime::from_der(&attr_value).map_err(|_| std::fmt::Error)? {
336 x509_cert::time::Time::UtcTime(time) => {
337 write!(
338 f,
339 "{}",
340 DateTime::<Utc>::from(time.to_system_time())
341 .with_timezone(&Local)
342 .to_string()
343 .indent(4)
344 )
345 }
346 x509_cert::time::Time::GeneralTime(time) => {
347 write!(
348 f,
349 "{}",
350 DateTime::<Utc>::from(time.to_system_time())
351 .with_timezone(&Local)
352 .to_string()
353 .indent(4)
354 )
355 }
356 }
357 }
358 "1.2.840.113549.1.9.6" => {
359 writeln!(f, "{}", "Counter Signature (1.2.840.113549.1.9.6):")?;
361 write!(f, "{}", attr_value.to_bytes_string().indent(4))
362 }
363 _ => {
364 writeln!(f, "{}:", self.oid)?;
365 write!(f, "{}", attr_value.to_bytes_string().indent(4))
366 }
367 }
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use std::time::UNIX_EPOCH;
374
375 use cms::cert::x509::der::SliceReader;
376 use der::{DecodePem, EncodePem};
377
378 use super::*;
379
380 #[test]
381 fn test_parse_pkcs7_from_der() {
382 let bytes = include_bytes!("./examples/pkcs7.cer");
383 assert!(ContentInfo::from_der(bytes)
384 .unwrap_err()
385 .to_string()
386 .starts_with("trailing data"));
387 }
388
389 #[test]
390 fn test_parse_pkcs7_decode() {
391 let bytes = include_bytes!("./examples/pkcs7.cer");
392 let mut reader = SliceReader::new(bytes).unwrap();
393 assert!(ContentInfo::decode(&mut reader).is_ok());
394 }
395
396 #[test]
397 fn get_authenticode() {
398 let bytes = include_bytes!("./examples/pkcs7.cer");
399 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
400
401 assert_eq!(
402 pesign.authenticode_digest,
403 "9253a6f72ee0e3970d5457e0f061fdb40b484f18"
404 );
405 }
406
407 #[test]
408 fn get_nested_authenticode() {
409 let bytes = include_bytes!("./examples/pkcs7.cer");
410 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
411 let nested = pesign
412 .signed_data
413 .signer_info
414 .get_nested_signature()
415 .unwrap()
416 .unwrap();
417
418 assert_eq!(
419 nested.authenticode_digest,
420 "33a755311b428c2063f983058dbf9e1648d00d5fec4adf00e0a34ddee639f68b",
421 );
422 }
423
424 #[test]
425 fn get_signer_signature_data() {
426 let bytes = include_bytes!("./examples/dotnet.cer");
427 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
428
429 let signature_value = &pesign.signed_data.signer_info.signature[..];
430
431 let signature_bin = include_bytes!("./examples/signature.bin");
432
433 assert_eq!(signature_value, signature_bin);
434 }
435
436 #[test]
437 fn parse_signingtime_from_cs() {
438 let bytes = include_bytes!("./examples/pkcs7.cer");
439 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
440
441 assert_eq!(
442 pesign
443 .signed_data
444 .get_signing_time()
445 .unwrap()
446 .duration_since(UNIX_EPOCH)
447 .unwrap()
448 .as_secs(),
449 1459215302
450 );
451 }
452
453 #[test]
454 fn parse_signingtime_from_ms_tst_sign() {
455 let bytes = include_bytes!("./examples/pkcs7.cer");
456 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
457
458 assert_eq!(
459 pesign
460 .signed_data
461 .signer_info
462 .get_nested_signature()
463 .unwrap()
464 .unwrap()
465 .signed_data
466 .get_signing_time()
467 .unwrap()
468 .duration_since(UNIX_EPOCH)
469 .unwrap()
470 .as_secs(),
471 1459215303
472 );
473 }
474
475 #[test]
476 fn parse_signingtime_from_attr() {
477 let bytes = include_bytes!("./examples/pkcs7_with_signing_time.cer");
478 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
479
480 assert_eq!(
481 pesign
482 .signed_data
483 .get_signing_time()
484 .unwrap()
485 .duration_since(UNIX_EPOCH)
486 .unwrap()
487 .as_secs(),
488 1717347664
489 );
490 }
491
492 #[test]
493 fn export_pem() {
494 let bytes = include_bytes!("./examples/pkcs7.cer");
495 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
496
497 assert_eq!(
498 pesign.to_pem(Default::default()).unwrap(),
499 include_str!("./examples/pkcs7.pem")
500 );
501 }
502
503 #[test]
504 fn from_pem() {
505 let pem = include_str!("./examples/pkcs7.pem");
506 let result = PeSign::from_pem(pem);
507
508 assert!(result.is_ok());
509 }
510
511 #[test]
512 fn from_pe() {
513 let result = PeSign::from_pe_data(include_bytes!("./examples/ProcessHacker.exe"));
514
515 assert!(result.is_ok());
516 }
517
518 #[test]
519 fn verify_pe() {
520 let pedata = include_bytes!("./examples/ProcessHacker.exe");
521
522 let status = PeSign::from_pe_data(pedata)
523 .unwrap()
524 .unwrap()
525 .verify_pe_data(pedata, &Default::default())
526 .unwrap();
527
528 assert_eq!(status, PeSignStatus::Expired);
529 }
530
531 #[test]
532 fn test_cert_include_attr_cert_v1() {
533 let bytes = include_bytes!("./examples/dotnet.cer");
534 let pesign = PeSign::from_certificate_table_buf(bytes).unwrap();
535
536 let signing_time = pesign.signed_data.get_signing_time().unwrap();
537
538 assert_eq!(
539 signing_time.duration_since(UNIX_EPOCH).unwrap().as_secs(),
540 1715980852
541 );
542 }
543}