pers/pe_file/
authenticode.rs1use alloc::vec::Vec;
4
5use x509_cert::Certificate;
6
7use super::PeFile;
8use crate::authenticode::{AuthenticodeInfo, CrlUrlList, HashAlgorithm};
9use crate::bytes::Bytes;
10use crate::error::{Result, malformed};
11use crate::lazy::cached;
12use crate::pe::{DataDirectoryType, field_offset};
13
14impl<'a> PeFile<'a> {
15 pub fn authenticode_info(&self) -> Result<Option<&AuthenticodeInfo<'a>>> {
18 cached(&self.cache.authenticode, || AuthenticodeInfo::parse(self)).map(Option::as_ref)
19 }
20
21 pub fn signing_certificate(&self) -> Result<Option<&Certificate>> {
23 Ok(self
24 .authenticode_info()?
25 .and_then(|i| i.signing_certificate.as_ref()))
26 }
27
28 pub fn is_signed(&self) -> bool {
30 self.signing_certificate().is_ok_and(|c| c.is_some())
31 }
32
33 pub fn has_valid_signature(&self) -> bool {
35 self.authenticode_info()
36 .is_ok_and(|i| i.is_some_and(|i| i.is_valid))
37 }
38
39 pub fn crl_url_list(&self) -> Result<Option<CrlUrlList>> {
41 self.signing_certificate()?
42 .map(CrlUrlList::from_certificate)
43 .transpose()
44 }
45
46 pub fn authenticode_hash(&self, algorithm: HashAlgorithm) -> Result<Vec<u8>> {
49 let nt_headers = &self.nt_headers;
50 let certificate_table_entry = nt_headers.data_directory_offset(DataDirectoryType::Security);
51 let size_of_headers = nt_headers.optional_header.size_of_headers() as usize;
52 let check_sum = nt_headers.optional_header_offset() + field_offset::CHECK_SUM;
53 let bytes = Bytes(self.data);
54 let range = |start: usize, end: usize| {
55 end.checked_sub(start)
56 .ok_or(malformed("Authenticode hash", "overlapping ranges"))
57 .and_then(|length| bytes.slice(start, length))
58 };
59
60 let mut hasher = algorithm.hasher();
61 hasher.update(range(0, check_sum)?);
62 hasher.update(range(check_sum + 4, certificate_table_entry)?);
63 hasher.update(range(certificate_table_entry + 8, size_of_headers)?);
64 let mut end_of_hashed_data = size_of_headers;
65 if let Some(certificate) = self.win_certificate()? {
66 hasher.update(range(size_of_headers, certificate.offset)?);
67 let size = self.data_directory(DataDirectoryType::Security).size() as usize;
68 end_of_hashed_data = certificate.offset + size;
69 }
70 if self.data.len() > end_of_hashed_data {
71 hasher.update(range(end_of_hashed_data, self.data.len())?);
72 }
73 Ok(hasher.finalize())
74 }
75}