authenticode/
signature.rs1use cms::content_info::CmsVersion;
10use cms::content_info::ContentInfo;
11use cms::signed_data::{SignedData, SignerInfo};
12use core::fmt::{self, Display, Formatter};
13use der::asn1::{ObjectIdentifier, OctetString};
14use der::Decode;
15use der::{Sequence, SliceReader};
16use x509_cert::Certificate;
17
18pub const SPC_INDIRECT_DATA_OBJID: ObjectIdentifier =
20 ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.1.4");
21
22#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
24pub struct SpcIndirectDataContent {
25 pub data: SpcAttributeTypeAndOptionalValue,
27
28 pub message_digest: DigestInfo,
30}
31
32#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
34pub struct SpcAttributeTypeAndOptionalValue {
35 pub value_type: ObjectIdentifier,
37
38 pub value: der::Any,
41}
42
43#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
45pub struct DigestInfo {
46 pub digest_algorithm: spki::AlgorithmIdentifierOwned,
48
49 pub digest: OctetString,
51}
52
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub enum AuthenticodeSignatureParseError {
56 Empty,
58
59 InvalidContentInfo(der::Error),
61
62 InvalidContentType(ObjectIdentifier),
64
65 InvalidSignedData(der::Error),
67
68 InvalidSignedDataVersion(CmsVersion),
70
71 InvalidNumDigestAlgorithms(usize),
73
74 InvalidEncapsulatedContentType(ObjectIdentifier),
76
77 EmptyEncapsulatedContent,
79
80 InvalidSpcIndirectDataContent(der::Error),
82
83 InvalidNumSignerInfo(usize),
85
86 InvalidSignerInfoVersion(CmsVersion),
88
89 AlgorithmMismatch,
91
92 EmptyAuthenticatedAttributes,
94
95 MissingContentTypeAuthenticatedAttribute,
97
98 MissingMessageDigestAuthenticatedAttribute,
100}
101
102impl Display for AuthenticodeSignatureParseError {
103 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104 write!(f, "authenticode signature parse error: {:?}", self)
106 }
107}
108
109#[cfg(feature = "std")]
110impl std::error::Error for AuthenticodeSignatureParseError {}
111
112#[derive(Clone, Debug, Eq, PartialEq)]
114pub struct AuthenticodeSignature {
115 signed_data: SignedData,
116 indirect_data: SpcIndirectDataContent,
117}
118
119impl AuthenticodeSignature {
120 pub fn from_bytes(
125 bytes: &[u8],
126 ) -> Result<Self, AuthenticodeSignatureParseError> {
127 let mut reader = SliceReader::new(bytes)
131 .map_err(|_| AuthenticodeSignatureParseError::Empty)?;
132 let content_info = ContentInfo::decode(&mut reader)
133 .map_err(AuthenticodeSignatureParseError::InvalidContentInfo)?;
134
135 if content_info.content_type != const_oid::db::rfc6268::ID_SIGNED_DATA {
136 return Err(AuthenticodeSignatureParseError::InvalidContentType(
137 content_info.content_type,
138 ));
139 }
140 let signed_data = content_info
141 .content
142 .decode_as::<SignedData>()
143 .map_err(AuthenticodeSignatureParseError::InvalidSignedData)?;
144
145 if signed_data.version != CmsVersion::V1 {
146 return Err(
147 AuthenticodeSignatureParseError::InvalidSignedDataVersion(
148 signed_data.version,
149 ),
150 );
151 }
152
153 if signed_data.digest_algorithms.len() != 1 {
155 return Err(
156 AuthenticodeSignatureParseError::InvalidNumDigestAlgorithms(
157 signed_data.digest_algorithms.len(),
158 ),
159 );
160 }
161
162 if signed_data.encap_content_info.econtent_type
163 != SPC_INDIRECT_DATA_OBJID
164 {
165 return Err(
166 AuthenticodeSignatureParseError::InvalidEncapsulatedContentType(
167 signed_data.encap_content_info.econtent_type,
168 ),
169 );
170 }
171 let indirect_data = signed_data
172 .clone()
173 .encap_content_info
174 .econtent
175 .ok_or(AuthenticodeSignatureParseError::EmptyEncapsulatedContent)?
176 .decode_as::<SpcIndirectDataContent>()
177 .map_err(
178 AuthenticodeSignatureParseError::InvalidSpcIndirectDataContent,
179 )?;
180
181 if signed_data.signer_infos.0.len() != 1 {
183 return Err(AuthenticodeSignatureParseError::InvalidNumSignerInfo(
184 signed_data.signer_infos.0.len(),
185 ));
186 }
187 let signer_info = &signed_data.signer_infos.0.as_slice()[0];
188
189 if signer_info.version != CmsVersion::V1 {
190 return Err(
191 AuthenticodeSignatureParseError::InvalidSignerInfoVersion(
192 signer_info.version,
193 ),
194 );
195 }
196
197 if signer_info.digest_alg != signed_data.digest_algorithms.as_slice()[0]
198 {
199 return Err(AuthenticodeSignatureParseError::AlgorithmMismatch);
200 }
201
202 let signed_attrs = if let Some(signed_attrs) = &signer_info.signed_attrs
203 {
204 signed_attrs
205 } else {
206 return Err(
207 AuthenticodeSignatureParseError::EmptyAuthenticatedAttributes,
208 );
209 };
210
211 if !signed_attrs
212 .iter()
213 .any(|a| a.oid == const_oid::db::rfc6268::ID_CONTENT_TYPE)
214 {
215 return Err(AuthenticodeSignatureParseError::MissingContentTypeAuthenticatedAttribute);
216 }
217
218 if !signed_attrs
219 .iter()
220 .any(|a| a.oid == const_oid::db::rfc6268::ID_MESSAGE_DIGEST)
221 {
222 return Err(AuthenticodeSignatureParseError::MissingMessageDigestAuthenticatedAttribute);
223 }
224
225 Ok(Self {
226 signed_data: signed_data.clone(),
227 indirect_data,
228 })
229 }
230
231 pub fn signer_info(&self) -> &SignerInfo {
233 &self.signed_data.signer_infos.0.as_slice()[0]
236 }
237
238 pub fn digest(&self) -> &[u8] {
243 self.indirect_data.message_digest.digest.as_bytes()
244 }
245
246 pub fn signature(&self) -> &[u8] {
251 self.signer_info().signature.as_bytes()
252 }
253
254 pub fn encapsulated_content(&self) -> Option<&[u8]> {
256 self.signed_data
257 .encap_content_info
258 .econtent
259 .as_ref()
260 .map(|c| c.value())
261 }
262
263 pub fn certificates(&self) -> impl Iterator<Item = &Certificate> {
265 self.signed_data
266 .certificates
267 .as_ref()
268 .unwrap()
269 .0
270 .iter()
271 .map(|cert| {
272 if let cms::cert::CertificateChoices::Certificate(cert) = cert {
273 cert
274 } else {
275 panic!()
276 }
277 })
278 }
279}