Bug 1689358 - Generate minidumps for child process crashes using the minidump-writer...
[gecko.git] / third_party / rust / goblin / src / pe / authenticode.rs
blobe16b7997cddbf2882846674db07ae893a3efcf4c
1 // Reference:
2 //   https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode
3 //   https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
5 // Authenticode works by omiting sections of the PE binary from the digest
6 // those sections are:
7 //   - checksum
8 //   - data directory entry for certtable
9 //   - certtable
11 use core::ops::Range;
13 use super::PE;
15 impl PE<'_> {
16     /// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for
17     /// signature.
18     pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> {
19         ExcludedSectionsIter {
20             pe: self,
21             state: IterState::default(),
22         }
23     }
26 /// [`ExcludedSections`] holds the various ranges of the binary that are expected to be
27 /// excluded from the authenticode computation.
28 #[derive(Debug, Clone, Default)]
29 pub(super) struct ExcludedSections {
30     checksum: Range<usize>,
31     datadir_entry_certtable: Range<usize>,
32     certtable: Option<Range<usize>>,
35 impl ExcludedSections {
36     pub(super) fn new(
37         checksum: Range<usize>,
38         datadir_entry_certtable: Range<usize>,
39         certtable: Option<Range<usize>>,
40     ) -> Self {
41         Self {
42             checksum,
43             datadir_entry_certtable,
44             certtable,
45         }
46     }
49 pub struct ExcludedSectionsIter<'s> {
50     pe: &'s PE<'s>,
51     state: IterState,
54 #[derive(Debug, PartialEq)]
55 enum IterState {
56     Initial,
57     DatadirEntry(usize),
58     CertTable(usize),
59     Final(usize),
60     Done,
63 impl Default for IterState {
64     fn default() -> Self {
65         Self::Initial
66     }
69 impl<'s> Iterator for ExcludedSectionsIter<'s> {
70     type Item = &'s [u8];
72     fn next(&mut self) -> Option<Self::Item> {
73         let bytes = &self.pe.bytes;
75         if let Some(sections) = self.pe.authenticode_excluded_sections.as_ref() {
76             loop {
77                 match self.state {
78                     IterState::Initial => {
79                         self.state = IterState::DatadirEntry(sections.checksum.end);
80                         return Some(&bytes[..sections.checksum.start]);
81                     }
82                     IterState::DatadirEntry(start) => {
83                         self.state = IterState::CertTable(sections.datadir_entry_certtable.end);
84                         return Some(&bytes[start..sections.datadir_entry_certtable.start]);
85                     }
86                     IterState::CertTable(start) => {
87                         if let Some(certtable) = sections.certtable.as_ref() {
88                             self.state = IterState::Final(certtable.end);
89                             return Some(&bytes[start..certtable.start]);
90                         } else {
91                             self.state = IterState::Final(start)
92                         }
93                     }
94                     IterState::Final(start) => {
95                         self.state = IterState::Done;
96                         return Some(&bytes[start..]);
97                     }
98                     IterState::Done => return None,
99                 }
100             }
101         } else {
102             loop {
103                 match self.state {
104                     IterState::Initial => {
105                         self.state = IterState::Done;
106                         return Some(bytes);
107                     }
108                     IterState::Done => return None,
109                     _ => {
110                         self.state = IterState::Done;
111                     }
112                 }
113             }
114         }
115     }