1use crate::usize_from_u32;
10use crate::PeTrait;
11use crate::{AuthenticodeSignature, AuthenticodeSignatureParseError};
12use core::fmt::{self, Display, Formatter};
13
14pub const WIN_CERT_REVISION_2_0: u16 = 0x0200;
16
17pub const WIN_CERT_TYPE_PKCS_SIGNED_DATA: u16 = 0x0002;
19
20fn align_up_to_8(val: usize) -> Option<usize> {
21 const ALIGN: usize = 8;
22 let r = val % ALIGN;
23 if r == 0 {
24 Some(val)
25 } else {
26 let sub = ALIGN.checked_sub(r).unwrap();
28 val.checked_add(sub)
29 }
30}
31
32fn check_total_size_valid(remaining_data: &[u8]) -> bool {
33 let mut iter = AttributeCertificateIterator { remaining_data };
34 while iter.next().is_some() {}
35 iter.remaining_data.is_empty()
36}
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum AttributeCertificateError {
41 OutOfBounds,
43
44 InvalidSize,
47
48 InvalidCertificateSize {
50 size: u32,
52 },
53}
54
55impl Display for AttributeCertificateError {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 match self {
58 Self::OutOfBounds => {
59 write!(f, "certificate table range is out of bounds")
60 }
61 Self::InvalidSize => {
62 write!(f, "certificate table size does not match the sum of the certificate entry's aligned sizes")
63 }
64 Self::InvalidCertificateSize { size } => {
65 write!(f, "certificate table contains an entry with an invalid size: {size}")
66 }
67 }
68 }
69}
70
71#[cfg(feature = "std")]
72impl std::error::Error for AttributeCertificateError {}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub enum AttributeCertificateAuthenticodeError {
77 InvalidCertificateRevision(u16),
79
80 InvalidCertificateType(u16),
82
83 InvalidSignature(AuthenticodeSignatureParseError),
85}
86
87impl Display for AttributeCertificateAuthenticodeError {
88 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
89 match self {
90 Self::InvalidCertificateRevision(rev) => {
91 write!(f, "invalid attribute certificate revision: {rev:02x}")
92 }
93 Self::InvalidCertificateType(ctype) => {
94 write!(f, "invalid attribute certificate type: {ctype:02x}")
95 }
96 Self::InvalidSignature(err) => {
97 write!(f, "invalid signature: {err}")
98 }
99 }
100 }
101}
102
103#[cfg(feature = "std")]
104impl std::error::Error for AttributeCertificateAuthenticodeError {}
105
106#[derive(Debug)]
111pub struct AttributeCertificate<'a> {
112 pub revision: u16,
114
115 pub certificate_type: u16,
117
118 pub data: &'a [u8],
120}
121
122impl<'a> AttributeCertificate<'a> {
123 pub fn get_authenticode_signature(
125 &self,
126 ) -> Result<AuthenticodeSignature, AttributeCertificateAuthenticodeError>
127 {
128 if self.revision != WIN_CERT_REVISION_2_0 {
129 return Err(AttributeCertificateAuthenticodeError::InvalidCertificateRevision(self.revision));
130 }
131 if self.certificate_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA {
132 return Err(
133 AttributeCertificateAuthenticodeError::InvalidCertificateType(
134 self.certificate_type,
135 ),
136 );
137 }
138
139 AuthenticodeSignature::from_bytes(self.data)
140 .map_err(AttributeCertificateAuthenticodeError::InvalidSignature)
141 }
142}
143
144#[derive(Debug)]
146pub struct AttributeCertificateIterator<'a> {
147 remaining_data: &'a [u8],
148}
149
150impl<'a> AttributeCertificateIterator<'a> {
151 pub fn new(
164 pe: &'a dyn PeTrait,
165 ) -> Result<Option<Self>, AttributeCertificateError> {
166 match pe.certificate_table_range() {
167 Ok(Some(certificate_table_range)) => {
168 let remaining_data = pe
169 .data()
170 .get(certificate_table_range)
171 .ok_or(AttributeCertificateError::OutOfBounds)?;
172
173 if !check_total_size_valid(remaining_data) {
175 return Err(AttributeCertificateError::InvalidSize);
176 }
177 Ok(Some(Self { remaining_data }))
178 }
179 Ok(None) => Ok(None),
180 Err(_) => Err(AttributeCertificateError::OutOfBounds),
181 }
182 }
183}
184
185impl<'a> Iterator for AttributeCertificateIterator<'a> {
186 type Item = Result<AttributeCertificate<'a>, AttributeCertificateError>;
187
188 fn next(&mut self) -> Option<Self::Item> {
189 let header_size = 8;
190 if self.remaining_data.len() < header_size {
191 return None;
192 }
193
194 let cert_bytes = self.remaining_data;
197 let cert_size =
198 u32::from_le_bytes(cert_bytes[0..4].try_into().unwrap());
199 let cert_size_err = AttributeCertificateError::InvalidCertificateSize {
200 size: cert_size,
201 };
202 let cert_size = usize_from_u32(cert_size);
203 let revision = u16::from_le_bytes(cert_bytes[4..6].try_into().unwrap());
204 let certificate_type =
205 u16::from_le_bytes(cert_bytes[6..8].try_into().unwrap());
206
207 let cert_data_size =
210 if let Some(cert_data_size) = cert_size.checked_sub(header_size) {
211 cert_data_size
212 } else {
213 self.remaining_data = &[];
215 return Some(Err(cert_size_err));
216 };
217
218 let cert_data_end = if let Some(cert_data_end) =
221 header_size.checked_add(cert_data_size)
222 {
223 cert_data_end
224 } else {
225 self.remaining_data = &[];
227 return Some(Err(cert_size_err));
228 };
229
230 let cert_data = if let Some(cert_data) =
233 cert_bytes.get(header_size..cert_data_end)
234 {
235 cert_data
236 } else {
237 self.remaining_data = &[];
239 return Some(Err(cert_size_err));
240 };
241
242 let size_rounded_up = align_up_to_8(cert_size)?;
244 self.remaining_data = cert_bytes.get(size_rounded_up..)?;
245
246 Some(Ok(AttributeCertificate {
247 revision,
248 certificate_type,
249 data: cert_data,
250 }))
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn test_align_up() {
260 assert_eq!(align_up_to_8(0).unwrap(), 0);
261 for i in 1..=8 {
262 assert_eq!(align_up_to_8(i).unwrap(), 8);
263 }
264 for i in 9..=16 {
265 assert_eq!(align_up_to_8(i).unwrap(), 16);
266 }
267 }
268}