/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x509-parser-0.15.1/src/extensions/mod.rs
Line | Count | Source |
1 | | //! X.509 Extensions objects and types |
2 | | |
3 | | use crate::error::{X509Error, X509Result}; |
4 | | use crate::time::ASN1Time; |
5 | | use crate::utils::format_serial; |
6 | | use crate::x509::{ReasonCode, RelativeDistinguishedName}; |
7 | | |
8 | | use asn1_rs::FromDer; |
9 | | use der_parser::ber::parse_ber_bool; |
10 | | use der_parser::der::*; |
11 | | use der_parser::error::{BerError, BerResult}; |
12 | | use der_parser::num_bigint::BigUint; |
13 | | use der_parser::oid::Oid; |
14 | | use nom::combinator::{all_consuming, complete, cut, map, map_res, opt}; |
15 | | use nom::multi::{many0, many1}; |
16 | | use nom::{Err, IResult, Parser}; |
17 | | use oid_registry::*; |
18 | | use std::collections::HashMap; |
19 | | use std::fmt::{self, LowerHex}; |
20 | | |
21 | | mod generalname; |
22 | | mod keyusage; |
23 | | mod nameconstraints; |
24 | | mod policymappings; |
25 | | mod sct; |
26 | | |
27 | | pub use generalname::*; |
28 | | pub use keyusage::*; |
29 | | pub use nameconstraints::*; |
30 | | pub use policymappings::*; |
31 | | pub use sct::*; |
32 | | |
33 | | /// X.509 version 3 extension |
34 | | /// |
35 | | /// X.509 extensions allow adding attributes to objects like certificates or revocation lists. |
36 | | /// |
37 | | /// Each extension in a certificate is designated as either critical or non-critical. A |
38 | | /// certificate using system MUST reject the certificate if it encounters a critical extension it |
39 | | /// does not recognize; however, a non-critical extension MAY be ignored if it is not recognized. |
40 | | /// |
41 | | /// Each extension includes an OID and an ASN.1 structure. When an extension appears in a |
42 | | /// certificate, the OID appears as the field extnID and the corresponding ASN.1 encoded structure |
43 | | /// is the value of the octet string extnValue. A certificate MUST NOT include more than one |
44 | | /// instance of a particular extension. |
45 | | /// |
46 | | /// When parsing an extension, the global extension structure (described above) is parsed, |
47 | | /// and the object is returned if it succeeds. |
48 | | /// During this step, it also attempts to parse the content of the extension, if known. |
49 | | /// The returned object has a |
50 | | /// [`X509Extension::parsed_extension()`] method. The returned |
51 | | /// enum is either a known extension, or the special value `ParsedExtension::UnsupportedExtension`. |
52 | | /// |
53 | | /// # Example |
54 | | /// |
55 | | /// ```rust |
56 | | /// use x509_parser::prelude::FromDer; |
57 | | /// use x509_parser::extensions::{X509Extension, ParsedExtension}; |
58 | | /// |
59 | | /// static DER: &[u8] = &[ |
60 | | /// 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xA3, 0x05, 0x2F, 0x18, |
61 | | /// 0x60, 0x50, 0xC2, 0x89, 0x0A, 0xDD, 0x2B, 0x21, 0x4F, 0xFF, 0x8E, 0x4E, 0xA8, 0x30, 0x31, |
62 | | /// 0x36 ]; |
63 | | /// |
64 | | /// # fn main() { |
65 | | /// let res = X509Extension::from_der(DER); |
66 | | /// match res { |
67 | | /// Ok((_rem, ext)) => { |
68 | | /// println!("Extension OID: {}", ext.oid); |
69 | | /// println!(" Critical: {}", ext.critical); |
70 | | /// let parsed_ext = ext.parsed_extension(); |
71 | | /// assert!(!parsed_ext.unsupported()); |
72 | | /// assert!(parsed_ext.error().is_none()); |
73 | | /// if let ParsedExtension::SubjectKeyIdentifier(key_id) = parsed_ext { |
74 | | /// assert!(key_id.0.len() > 0); |
75 | | /// } else { |
76 | | /// panic!("Extension has wrong type"); |
77 | | /// } |
78 | | /// }, |
79 | | /// _ => panic!("x509 extension parsing failed: {:?}", res), |
80 | | /// } |
81 | | /// # } |
82 | | /// ``` |
83 | | #[derive(Clone, Debug, PartialEq)] |
84 | | pub struct X509Extension<'a> { |
85 | | /// OID describing the extension content |
86 | | pub oid: Oid<'a>, |
87 | | /// Boolean value describing the 'critical' attribute of the extension |
88 | | /// |
89 | | /// An extension includes the boolean critical, with a default value of FALSE. |
90 | | pub critical: bool, |
91 | | /// Raw content of the extension |
92 | | pub value: &'a [u8], |
93 | | pub(crate) parsed_extension: ParsedExtension<'a>, |
94 | | } |
95 | | |
96 | | impl<'a> X509Extension<'a> { |
97 | | /// Creates a new extension with the provided values. |
98 | | #[inline] |
99 | 0 | pub const fn new( |
100 | 0 | oid: Oid<'a>, |
101 | 0 | critical: bool, |
102 | 0 | value: &'a [u8], |
103 | 0 | parsed_extension: ParsedExtension<'a>, |
104 | 0 | ) -> X509Extension<'a> { |
105 | 0 | X509Extension { |
106 | 0 | oid, |
107 | 0 | critical, |
108 | 0 | value, |
109 | 0 | parsed_extension, |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | | /// Return the extension type or `UnsupportedExtension` if the extension is not implemented. |
114 | | #[inline] |
115 | 0 | pub fn parsed_extension(&self) -> &ParsedExtension<'a> { |
116 | 0 | &self.parsed_extension |
117 | 0 | } |
118 | | } |
119 | | |
120 | | /// <pre> |
121 | | /// Extension ::= SEQUENCE { |
122 | | /// extnID OBJECT IDENTIFIER, |
123 | | /// critical BOOLEAN DEFAULT FALSE, |
124 | | /// extnValue OCTET STRING } |
125 | | /// </pre> |
126 | | impl<'a> FromDer<'a, X509Error> for X509Extension<'a> { |
127 | 22.4k | fn from_der(i: &'a [u8]) -> X509Result<Self> { |
128 | 22.4k | X509ExtensionParser::new().parse(i) |
129 | 22.4k | } |
130 | | } |
131 | | |
132 | | /// `X509Extension` parser builder |
133 | | #[derive(Clone, Copy, Debug)] |
134 | | pub struct X509ExtensionParser { |
135 | | deep_parse_extensions: bool, |
136 | | } |
137 | | |
138 | | impl X509ExtensionParser { |
139 | | #[inline] |
140 | 22.4k | pub const fn new() -> Self { |
141 | 22.4k | X509ExtensionParser { |
142 | 22.4k | deep_parse_extensions: true, |
143 | 22.4k | } |
144 | 22.4k | } |
145 | | |
146 | | #[inline] |
147 | 0 | pub const fn with_deep_parse_extensions(self, deep_parse_extensions: bool) -> Self { |
148 | 0 | X509ExtensionParser { |
149 | 0 | deep_parse_extensions, |
150 | 0 | } |
151 | 0 | } |
152 | | } |
153 | | |
154 | | impl<'a> Parser<&'a [u8], X509Extension<'a>, X509Error> for X509ExtensionParser { |
155 | 22.4k | fn parse(&mut self, input: &'a [u8]) -> IResult<&'a [u8], X509Extension<'a>, X509Error> { |
156 | 22.4k | parse_der_sequence_defined_g(|i, _| { |
157 | 19.9k | let (i, oid) = Oid::from_der(i)?; |
158 | 19.8k | let (i, critical) = der_read_critical(i)?; |
159 | 19.8k | let (i, value) = <&[u8]>::from_der(i)?; |
160 | 19.7k | let (i, parsed_extension) = if self.deep_parse_extensions { |
161 | 19.7k | parser::parse_extension(i, value, &oid)? |
162 | | } else { |
163 | 0 | (&[] as &[_], ParsedExtension::Unparsed) |
164 | | }; |
165 | 19.7k | let ext = X509Extension { |
166 | 19.7k | oid, |
167 | 19.7k | critical, |
168 | 19.7k | value, |
169 | 19.7k | parsed_extension, |
170 | 19.7k | }; |
171 | 19.7k | Ok((i, ext)) |
172 | 22.4k | })(input) |
173 | 22.4k | .map_err(|_| X509Error::InvalidExtensions.into()) |
174 | 22.4k | } |
175 | | } |
176 | | |
177 | | #[derive(Clone, Debug, PartialEq)] |
178 | | pub enum ParsedExtension<'a> { |
179 | | /// Crate parser does not support this extension (yet) |
180 | | UnsupportedExtension { |
181 | | oid: Oid<'a>, |
182 | | }, |
183 | | ParseError { |
184 | | error: Err<BerError>, |
185 | | }, |
186 | | /// Section 4.2.1.1 of rfc 5280 |
187 | | AuthorityKeyIdentifier(AuthorityKeyIdentifier<'a>), |
188 | | /// Section 4.2.1.2 of rfc 5280 |
189 | | SubjectKeyIdentifier(KeyIdentifier<'a>), |
190 | | /// Section 4.2.1.3 of rfc 5280 |
191 | | KeyUsage(KeyUsage), |
192 | | /// Section 4.2.1.4 of rfc 5280 |
193 | | CertificatePolicies(CertificatePolicies<'a>), |
194 | | /// Section 4.2.1.5 of rfc 5280 |
195 | | PolicyMappings(PolicyMappings<'a>), |
196 | | /// Section 4.2.1.6 of rfc 5280 |
197 | | SubjectAlternativeName(SubjectAlternativeName<'a>), |
198 | | /// Section 4.2.1.7 of rfc 5280 |
199 | | IssuerAlternativeName(IssuerAlternativeName<'a>), |
200 | | /// Section 4.2.1.9 of rfc 5280 |
201 | | BasicConstraints(BasicConstraints), |
202 | | /// Section 4.2.1.10 of rfc 5280 |
203 | | NameConstraints(NameConstraints<'a>), |
204 | | /// Section 4.2.1.11 of rfc 5280 |
205 | | PolicyConstraints(PolicyConstraints), |
206 | | /// Section 4.2.1.12 of rfc 5280 |
207 | | ExtendedKeyUsage(ExtendedKeyUsage<'a>), |
208 | | /// Section 4.2.1.13 of rfc 5280 |
209 | | CRLDistributionPoints(CRLDistributionPoints<'a>), |
210 | | /// Section 4.2.1.14 of rfc 5280 |
211 | | InhibitAnyPolicy(InhibitAnyPolicy), |
212 | | /// Section 4.2.2.1 of rfc 5280 |
213 | | AuthorityInfoAccess(AuthorityInfoAccess<'a>), |
214 | | /// Netscape certificate type (subject is SSL client, an SSL server, or a CA) |
215 | | NSCertType(NSCertType), |
216 | | /// Netscape certificate comment |
217 | | NsCertComment(&'a str), |
218 | | /// Section 5.3.1 of rfc 5280 |
219 | | CRLNumber(BigUint), |
220 | | /// Section 5.3.1 of rfc 5280 |
221 | | ReasonCode(ReasonCode), |
222 | | /// Section 5.3.3 of rfc 5280 |
223 | | InvalidityDate(ASN1Time), |
224 | | /// rfc 6962 |
225 | | SCT(Vec<SignedCertificateTimestamp<'a>>), |
226 | | /// Unparsed extension (was not requested in parsing options) |
227 | | Unparsed, |
228 | | } |
229 | | |
230 | | impl<'a> ParsedExtension<'a> { |
231 | | /// Return `true` if the extension is unsupported |
232 | 0 | pub fn unsupported(&self) -> bool { |
233 | 0 | matches!(self, &ParsedExtension::UnsupportedExtension { .. }) |
234 | 0 | } |
235 | | |
236 | | /// Return a reference on the parsing error if the extension parsing failed |
237 | 0 | pub fn error(&self) -> Option<&Err<BerError>> { |
238 | 0 | match self { |
239 | 0 | ParsedExtension::ParseError { error } => Some(error), |
240 | 0 | _ => None, |
241 | | } |
242 | 0 | } |
243 | | } |
244 | | |
245 | | #[derive(Clone, Debug, PartialEq)] |
246 | | pub struct AuthorityKeyIdentifier<'a> { |
247 | | pub key_identifier: Option<KeyIdentifier<'a>>, |
248 | | pub authority_cert_issuer: Option<Vec<GeneralName<'a>>>, |
249 | | pub authority_cert_serial: Option<&'a [u8]>, |
250 | | } |
251 | | |
252 | | impl<'a> FromDer<'a, X509Error> for AuthorityKeyIdentifier<'a> { |
253 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
254 | 0 | parser::parse_authoritykeyidentifier(i).map_err(Err::convert) |
255 | 0 | } |
256 | | } |
257 | | |
258 | | pub type CertificatePolicies<'a> = Vec<PolicyInformation<'a>>; |
259 | | |
260 | | // impl<'a> FromDer<'a> for CertificatePolicies<'a> { |
261 | | // fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
262 | | // parser::parse_certificatepolicies(i).map_err(Err::convert) |
263 | | // } |
264 | | // } |
265 | | |
266 | | #[derive(Clone, Debug, PartialEq, Eq)] |
267 | | pub struct PolicyInformation<'a> { |
268 | | pub policy_id: Oid<'a>, |
269 | | pub policy_qualifiers: Option<Vec<PolicyQualifierInfo<'a>>>, |
270 | | } |
271 | | |
272 | | #[derive(Clone, Debug, PartialEq, Eq)] |
273 | | pub struct PolicyQualifierInfo<'a> { |
274 | | pub policy_qualifier_id: Oid<'a>, |
275 | | pub qualifier: &'a [u8], |
276 | | } |
277 | | |
278 | | /// Identifies whether the subject of the certificate is a CA, and the max validation depth. |
279 | | #[derive(Clone, Debug, PartialEq, Eq)] |
280 | | pub struct BasicConstraints { |
281 | | pub ca: bool, |
282 | | pub path_len_constraint: Option<u32>, |
283 | | } |
284 | | |
285 | | impl<'a> FromDer<'a, X509Error> for BasicConstraints { |
286 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
287 | 0 | parser::parse_basicconstraints(i).map_err(Err::convert) |
288 | 0 | } |
289 | | } |
290 | | |
291 | | #[derive(Clone, Debug, PartialEq, Eq)] |
292 | | pub struct KeyIdentifier<'a>(pub &'a [u8]); |
293 | | |
294 | | impl<'a> FromDer<'a, X509Error> for KeyIdentifier<'a> { |
295 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
296 | 0 | parser::parse_keyidentifier(i).map_err(Err::convert) |
297 | 0 | } |
298 | | } |
299 | | |
300 | | impl<'a> LowerHex for KeyIdentifier<'a> { |
301 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
302 | 0 | let s = format_serial(self.0); |
303 | 0 | f.write_str(&s) |
304 | 0 | } |
305 | | } |
306 | | |
307 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
308 | | pub struct NSCertType(u8); |
309 | | |
310 | | // The value is a bit-string, where the individual bit positions are defined as: |
311 | | // |
312 | | // bit-0 SSL client - this cert is certified for SSL client authentication use |
313 | | // bit-1 SSL server - this cert is certified for SSL server authentication use |
314 | | // bit-2 S/MIME - this cert is certified for use by clients (New in PR3) |
315 | | // bit-3 Object Signing - this cert is certified for signing objects such as Java applets and plugins(New in PR3) |
316 | | // bit-4 Reserved - this bit is reserved for future use |
317 | | // bit-5 SSL CA - this cert is certified for issuing certs for SSL use |
318 | | // bit-6 S/MIME CA - this cert is certified for issuing certs for S/MIME use (New in PR3) |
319 | | // bit-7 Object Signing CA - this cert is certified for issuing certs for Object Signing (New in PR3) |
320 | | impl NSCertType { |
321 | 0 | pub fn ssl_client(&self) -> bool { |
322 | 0 | self.0 & 0x1 == 1 |
323 | 0 | } |
324 | 0 | pub fn ssl_server(&self) -> bool { |
325 | 0 | (self.0 >> 1) & 1 == 1 |
326 | 0 | } |
327 | 0 | pub fn smime(&self) -> bool { |
328 | 0 | (self.0 >> 2) & 1 == 1 |
329 | 0 | } |
330 | 0 | pub fn object_signing(&self) -> bool { |
331 | 0 | (self.0 >> 3) & 1 == 1 |
332 | 0 | } |
333 | 0 | pub fn ssl_ca(&self) -> bool { |
334 | 0 | (self.0 >> 5) & 1 == 1 |
335 | 0 | } |
336 | 0 | pub fn smime_ca(&self) -> bool { |
337 | 0 | (self.0 >> 6) & 1 == 1 |
338 | 0 | } |
339 | 0 | pub fn object_signing_ca(&self) -> bool { |
340 | 0 | (self.0 >> 7) & 1 == 1 |
341 | 0 | } |
342 | | } |
343 | | |
344 | | const NS_CERT_TYPE_FLAGS: &[&str] = &[ |
345 | | "SSL CLient", |
346 | | "SSL Server", |
347 | | "S/MIME", |
348 | | "Object Signing", |
349 | | "Reserved", |
350 | | "SSL CA", |
351 | | "S/MIME CA", |
352 | | "Object Signing CA", |
353 | | ]; |
354 | | |
355 | | impl fmt::Display for NSCertType { |
356 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
357 | 0 | let mut s = String::new(); |
358 | 0 | let mut acc = self.0; |
359 | 0 | for flag_text in NS_CERT_TYPE_FLAGS { |
360 | 0 | if acc & 1 != 0 { |
361 | 0 | s = s + flag_text + ", "; |
362 | 0 | } |
363 | 0 | acc >>= 1; |
364 | | } |
365 | 0 | s.pop(); |
366 | 0 | s.pop(); |
367 | 0 | f.write_str(&s) |
368 | 0 | } |
369 | | } |
370 | | |
371 | | impl<'a> FromDer<'a, X509Error> for NSCertType { |
372 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
373 | 0 | parser::parse_nscerttype(i).map_err(Err::convert) |
374 | 0 | } |
375 | | } |
376 | | |
377 | | #[derive(Clone, Debug, PartialEq)] |
378 | | pub struct AuthorityInfoAccess<'a> { |
379 | | pub accessdescs: Vec<AccessDescription<'a>>, |
380 | | } |
381 | | |
382 | | impl<'a> AuthorityInfoAccess<'a> { |
383 | | /// Returns an iterator over the Access Descriptors |
384 | 0 | pub fn iter(&self) -> impl Iterator<Item = &AccessDescription<'a>> { |
385 | 0 | self.accessdescs.iter() |
386 | 0 | } |
387 | | |
388 | | /// Returns a `HashMap` mapping `Oid` to the list of references to `GeneralNames` |
389 | | /// |
390 | | /// If several names match the same `Oid`, they are merged in the same entry. |
391 | 0 | pub fn as_hashmap(&self) -> HashMap<Oid<'a>, Vec<&GeneralName<'a>>> { |
392 | | // create the hashmap and merge entries with same OID |
393 | 0 | let mut m: HashMap<Oid, Vec<&GeneralName>> = HashMap::new(); |
394 | 0 | for desc in &self.accessdescs { |
395 | | let AccessDescription { |
396 | 0 | access_method: oid, |
397 | 0 | access_location: gn, |
398 | 0 | } = desc; |
399 | 0 | if let Some(general_names) = m.get_mut(oid) { |
400 | 0 | general_names.push(gn); |
401 | 0 | } else { |
402 | 0 | m.insert(oid.clone(), vec![gn]); |
403 | 0 | } |
404 | | } |
405 | 0 | m |
406 | 0 | } |
407 | | |
408 | | /// Returns a `HashMap` mapping `Oid` to the list of `GeneralNames` (consuming the input) |
409 | | /// |
410 | | /// If several names match the same `Oid`, they are merged in the same entry. |
411 | 0 | pub fn into_hashmap(self) -> HashMap<Oid<'a>, Vec<GeneralName<'a>>> { |
412 | 0 | let mut aia_list = self.accessdescs; |
413 | | // create the hashmap and merge entries with same OID |
414 | 0 | let mut m: HashMap<Oid, Vec<GeneralName>> = HashMap::new(); |
415 | 0 | for desc in aia_list.drain(..) { |
416 | | let AccessDescription { |
417 | 0 | access_method: oid, |
418 | 0 | access_location: gn, |
419 | 0 | } = desc; |
420 | 0 | if let Some(general_names) = m.get_mut(&oid) { |
421 | 0 | general_names.push(gn); |
422 | 0 | } else { |
423 | 0 | m.insert(oid, vec![gn]); |
424 | 0 | } |
425 | | } |
426 | 0 | m |
427 | 0 | } |
428 | | } |
429 | | |
430 | | impl<'a> FromDer<'a, X509Error> for AuthorityInfoAccess<'a> { |
431 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
432 | 0 | parser::parse_authorityinfoaccess(i).map_err(Err::convert) |
433 | 0 | } |
434 | | } |
435 | | |
436 | | #[derive(Clone, Debug, PartialEq)] |
437 | | pub struct AccessDescription<'a> { |
438 | | pub access_method: Oid<'a>, |
439 | | pub access_location: GeneralName<'a>, |
440 | | } |
441 | | |
442 | | impl<'a> AccessDescription<'a> { |
443 | 3.94k | pub const fn new(access_method: Oid<'a>, access_location: GeneralName<'a>) -> Self { |
444 | 3.94k | AccessDescription { |
445 | 3.94k | access_method, |
446 | 3.94k | access_location, |
447 | 3.94k | } |
448 | 3.94k | } |
449 | | } |
450 | | |
451 | | #[derive(Clone, Debug, PartialEq, Eq)] |
452 | | pub struct InhibitAnyPolicy { |
453 | | pub skip_certs: u32, |
454 | | } |
455 | | |
456 | | impl<'a> FromDer<'a, X509Error> for InhibitAnyPolicy { |
457 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
458 | 0 | map(parse_der_u32, |skip_certs| InhibitAnyPolicy { skip_certs })(i).map_err(Err::convert) |
459 | 0 | } |
460 | | } |
461 | | |
462 | | #[derive(Clone, Debug, PartialEq, Eq)] |
463 | | pub struct PolicyConstraints { |
464 | | pub require_explicit_policy: Option<u32>, |
465 | | pub inhibit_policy_mapping: Option<u32>, |
466 | | } |
467 | | |
468 | | impl<'a> FromDer<'a, X509Error> for PolicyConstraints { |
469 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
470 | 0 | parser::parse_policyconstraints(i).map_err(Err::convert) |
471 | 0 | } |
472 | | } |
473 | | |
474 | | #[derive(Clone, Debug, PartialEq)] |
475 | | pub struct SubjectAlternativeName<'a> { |
476 | | pub general_names: Vec<GeneralName<'a>>, |
477 | | } |
478 | | |
479 | | impl<'a> FromDer<'a, X509Error> for SubjectAlternativeName<'a> { |
480 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
481 | 0 | parse_der_sequence_defined_g(|input, _| { |
482 | 0 | let (i, general_names) = |
483 | 0 | all_consuming(many0(complete(cut(GeneralName::from_der))))(input)?; |
484 | 0 | Ok((i, SubjectAlternativeName { general_names })) |
485 | 0 | })(i) |
486 | 0 | } |
487 | | } |
488 | | |
489 | | #[derive(Clone, Debug, PartialEq)] |
490 | | pub struct IssuerAlternativeName<'a> { |
491 | | pub general_names: Vec<GeneralName<'a>>, |
492 | | } |
493 | | |
494 | | impl<'a> FromDer<'a, X509Error> for IssuerAlternativeName<'a> { |
495 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
496 | 0 | parse_der_sequence_defined_g(|input, _| { |
497 | 0 | let (i, general_names) = |
498 | 0 | all_consuming(many0(complete(cut(GeneralName::from_der))))(input)?; |
499 | 0 | Ok((i, IssuerAlternativeName { general_names })) |
500 | 0 | })(i) |
501 | 0 | } |
502 | | } |
503 | | |
504 | | #[derive(Clone, Debug, PartialEq)] |
505 | | pub struct CRLDistributionPoints<'a> { |
506 | | pub points: Vec<CRLDistributionPoint<'a>>, |
507 | | } |
508 | | |
509 | | impl<'a> std::ops::Deref for CRLDistributionPoints<'a> { |
510 | | type Target = Vec<CRLDistributionPoint<'a>>; |
511 | | |
512 | 0 | fn deref(&self) -> &Self::Target { |
513 | 0 | &self.points |
514 | 0 | } |
515 | | } |
516 | | |
517 | | impl<'a> FromDer<'a, X509Error> for CRLDistributionPoints<'a> { |
518 | 0 | fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
519 | 0 | parser::parse_crldistributionpoints(i).map_err(Err::convert) |
520 | 0 | } |
521 | | } |
522 | | |
523 | | #[derive(Clone, Debug, PartialEq)] |
524 | | pub struct CRLDistributionPoint<'a> { |
525 | | pub distribution_point: Option<DistributionPointName<'a>>, |
526 | | pub reasons: Option<ReasonFlags>, |
527 | | pub crl_issuer: Option<Vec<GeneralName<'a>>>, |
528 | | } |
529 | | |
530 | | #[derive(Clone, Debug, PartialEq)] |
531 | | pub enum DistributionPointName<'a> { |
532 | | FullName(Vec<GeneralName<'a>>), |
533 | | NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>), |
534 | | } |
535 | | |
536 | | #[derive(Clone, Debug, PartialEq, Eq)] |
537 | | pub struct ReasonFlags { |
538 | | pub flags: u16, |
539 | | } |
540 | | |
541 | | impl ReasonFlags { |
542 | 0 | pub fn key_compromise(&self) -> bool { |
543 | 0 | (self.flags >> 1) & 1 == 1 |
544 | 0 | } |
545 | 0 | pub fn ca_compromise(&self) -> bool { |
546 | 0 | (self.flags >> 2) & 1 == 1 |
547 | 0 | } |
548 | 0 | pub fn affilation_changed(&self) -> bool { |
549 | 0 | (self.flags >> 3) & 1 == 1 |
550 | 0 | } |
551 | 0 | pub fn superseded(&self) -> bool { |
552 | 0 | (self.flags >> 4) & 1 == 1 |
553 | 0 | } |
554 | 0 | pub fn cessation_of_operation(&self) -> bool { |
555 | 0 | (self.flags >> 5) & 1 == 1 |
556 | 0 | } |
557 | 0 | pub fn certificate_hold(&self) -> bool { |
558 | 0 | (self.flags >> 6) & 1 == 1 |
559 | 0 | } |
560 | 0 | pub fn privelege_withdrawn(&self) -> bool { |
561 | 0 | (self.flags >> 7) & 1 == 1 |
562 | 0 | } |
563 | 0 | pub fn aa_compromise(&self) -> bool { |
564 | 0 | (self.flags >> 8) & 1 == 1 |
565 | 0 | } |
566 | | } |
567 | | |
568 | | const REASON_FLAGS: &[&str] = &[ |
569 | | "Unused", |
570 | | "Key Compromise", |
571 | | "CA Compromise", |
572 | | "Affiliation Changed", |
573 | | "Superseded", |
574 | | "Cessation Of Operation", |
575 | | "Certificate Hold", |
576 | | "Privilege Withdrawn", |
577 | | "AA Compromise", |
578 | | ]; |
579 | | |
580 | | impl fmt::Display for ReasonFlags { |
581 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
582 | 0 | let mut s = String::new(); |
583 | 0 | let mut acc = self.flags; |
584 | 0 | for flag_text in REASON_FLAGS { |
585 | 0 | if acc & 1 != 0 { |
586 | 0 | s = s + flag_text + ", "; |
587 | 0 | } |
588 | 0 | acc >>= 1; |
589 | | } |
590 | 0 | s.pop(); |
591 | 0 | s.pop(); |
592 | 0 | f.write_str(&s) |
593 | 0 | } |
594 | | } |
595 | | |
596 | | pub(crate) mod parser { |
597 | | use crate::extensions::*; |
598 | | use crate::time::ASN1Time; |
599 | | use asn1_rs::{GeneralizedTime, ParseResult}; |
600 | | use der_parser::error::BerError; |
601 | | use der_parser::{oid::Oid, *}; |
602 | | use lazy_static::lazy_static; |
603 | | use nom::combinator::{cut, map}; |
604 | | use nom::{Err, IResult}; |
605 | | |
606 | | type ExtParser = fn(&[u8]) -> IResult<&[u8], ParsedExtension, BerError>; |
607 | | |
608 | | lazy_static! { |
609 | | static ref EXTENSION_PARSERS: HashMap<Oid<'static>, ExtParser> = { |
610 | | macro_rules! add { |
611 | | ($m:ident, $oid:ident, $p:ident) => { |
612 | | $m.insert($oid, $p as ExtParser); |
613 | | }; |
614 | | } |
615 | | |
616 | | let mut m = HashMap::new(); |
617 | | add!( |
618 | | m, |
619 | | OID_X509_EXT_SUBJECT_KEY_IDENTIFIER, |
620 | | parse_keyidentifier_ext |
621 | | ); |
622 | | add!(m, OID_X509_EXT_KEY_USAGE, parse_keyusage_ext); |
623 | | add!( |
624 | | m, |
625 | | OID_X509_EXT_SUBJECT_ALT_NAME, |
626 | | parse_subjectalternativename_ext |
627 | | ); |
628 | | add!( |
629 | | m, |
630 | | OID_X509_EXT_ISSUER_ALT_NAME, |
631 | | parse_issueralternativename_ext |
632 | | ); |
633 | | add!( |
634 | | m, |
635 | | OID_X509_EXT_BASIC_CONSTRAINTS, |
636 | | parse_basicconstraints_ext |
637 | | ); |
638 | | add!(m, OID_X509_EXT_NAME_CONSTRAINTS, parse_nameconstraints_ext); |
639 | | add!( |
640 | | m, |
641 | | OID_X509_EXT_CERTIFICATE_POLICIES, |
642 | | parse_certificatepolicies_ext |
643 | | ); |
644 | | add!(m, OID_X509_EXT_POLICY_MAPPINGS, parse_policymappings_ext); |
645 | | add!( |
646 | | m, |
647 | | OID_X509_EXT_POLICY_CONSTRAINTS, |
648 | | parse_policyconstraints_ext |
649 | | ); |
650 | | add!( |
651 | | m, |
652 | | OID_X509_EXT_EXTENDED_KEY_USAGE, |
653 | | parse_extendedkeyusage_ext |
654 | | ); |
655 | | add!( |
656 | | m, |
657 | | OID_X509_EXT_CRL_DISTRIBUTION_POINTS, |
658 | | parse_crldistributionpoints_ext |
659 | | ); |
660 | | add!( |
661 | | m, |
662 | | OID_X509_EXT_INHIBITANT_ANY_POLICY, |
663 | | parse_inhibitanypolicy_ext |
664 | | ); |
665 | | add!( |
666 | | m, |
667 | | OID_PKIX_AUTHORITY_INFO_ACCESS, |
668 | | parse_authorityinfoaccess_ext |
669 | | ); |
670 | | add!( |
671 | | m, |
672 | | OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER, |
673 | | parse_authoritykeyidentifier_ext |
674 | | ); |
675 | | add!(m, OID_CT_LIST_SCT, parse_sct_ext); |
676 | | add!(m, OID_X509_EXT_CERT_TYPE, parse_nscerttype_ext); |
677 | | add!(m, OID_X509_EXT_CERT_COMMENT, parse_nscomment_ext); |
678 | | add!(m, OID_X509_EXT_CRL_NUMBER, parse_crl_number); |
679 | | add!(m, OID_X509_EXT_REASON_CODE, parse_reason_code); |
680 | | add!(m, OID_X509_EXT_INVALIDITY_DATE, parse_invalidity_date); |
681 | | m |
682 | | }; |
683 | | } |
684 | | |
685 | | // look into the parser map if the extension is known, and parse it |
686 | | // otherwise, leave it as UnsupportedExtension |
687 | 19.7k | fn parse_extension0<'a>( |
688 | 19.7k | orig_i: &'a [u8], |
689 | 19.7k | i: &'a [u8], |
690 | 19.7k | oid: &Oid, |
691 | 19.7k | ) -> IResult<&'a [u8], ParsedExtension<'a>, BerError> { |
692 | 19.7k | if let Some(parser) = EXTENSION_PARSERS.get(oid) { |
693 | 19.3k | match parser(i) { |
694 | 18.8k | Ok((_, ext)) => Ok((orig_i, ext)), |
695 | 458 | Err(error) => Ok((orig_i, ParsedExtension::ParseError { error })), |
696 | | } |
697 | | } else { |
698 | 435 | Ok(( |
699 | 435 | orig_i, |
700 | 435 | ParsedExtension::UnsupportedExtension { |
701 | 435 | oid: oid.to_owned(), |
702 | 435 | }, |
703 | 435 | )) |
704 | | } |
705 | 19.7k | } |
706 | | |
707 | 19.7k | pub(crate) fn parse_extension<'a>( |
708 | 19.7k | orig_i: &'a [u8], |
709 | 19.7k | i: &'a [u8], |
710 | 19.7k | oid: &Oid, |
711 | 19.7k | ) -> IResult<&'a [u8], ParsedExtension<'a>, BerError> { |
712 | 19.7k | parse_extension0(orig_i, i, oid) |
713 | 19.7k | } |
714 | | |
715 | | /// Parse a "Basic Constraints" extension |
716 | | /// |
717 | | /// <pre> |
718 | | /// id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } |
719 | | /// BasicConstraints ::= SEQUENCE { |
720 | | /// cA BOOLEAN DEFAULT FALSE, |
721 | | /// pathLenConstraint INTEGER (0..MAX) OPTIONAL } |
722 | | /// </pre> |
723 | | /// |
724 | | /// Note the maximum length of the `pathLenConstraint` field is limited to the size of a 32-bits |
725 | | /// unsigned integer, and parsing will fail if value if larger. |
726 | 2.20k | pub(super) fn parse_basicconstraints(i: &[u8]) -> IResult<&[u8], BasicConstraints, BerError> { |
727 | 2.20k | let (rem, obj) = parse_der_sequence(i)?; |
728 | 2.15k | if let Ok(seq) = obj.as_sequence() { |
729 | 2.15k | let (ca, path_len_constraint) = match seq.len() { |
730 | 1.75k | 0 => (false, None), |
731 | | 1 => { |
732 | 47 | if let Ok(b) = seq[0].as_bool() { |
733 | 46 | (b, None) |
734 | 1 | } else if let Ok(u) = seq[0].as_u32() { |
735 | 0 | (false, Some(u)) |
736 | | } else { |
737 | 1 | return Err(nom::Err::Error(BerError::InvalidTag)); |
738 | | } |
739 | | } |
740 | | 2 => { |
741 | 356 | let ca = seq[0] |
742 | 356 | .as_bool() |
743 | 356 | .or(Err(nom::Err::Error(BerError::InvalidLength)))?; |
744 | 356 | let pl = seq[1] |
745 | 356 | .as_u32() |
746 | 356 | .or(Err(nom::Err::Error(BerError::InvalidLength)))?; |
747 | 355 | (ca, Some(pl)) |
748 | | } |
749 | 1 | _ => return Err(nom::Err::Error(BerError::InvalidLength)), |
750 | | }; |
751 | 2.15k | Ok(( |
752 | 2.15k | rem, |
753 | 2.15k | BasicConstraints { |
754 | 2.15k | ca, |
755 | 2.15k | path_len_constraint, |
756 | 2.15k | }, |
757 | 2.15k | )) |
758 | | } else { |
759 | 0 | Err(nom::Err::Error(BerError::InvalidLength)) |
760 | | } |
761 | 2.20k | } |
762 | | |
763 | 2.20k | fn parse_basicconstraints_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
764 | 2.20k | map(parse_basicconstraints, ParsedExtension::BasicConstraints)(i) |
765 | 2.20k | } |
766 | | |
767 | 5 | fn parse_nameconstraints_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
768 | 5 | map(parse_nameconstraints, ParsedExtension::NameConstraints)(i) |
769 | 5 | } |
770 | | |
771 | 2.16k | pub(super) fn parse_subjectalternativename_ext( |
772 | 2.16k | i: &[u8], |
773 | 2.16k | ) -> IResult<&[u8], ParsedExtension, BerError> { |
774 | 2.16k | parse_der_sequence_defined_g(|input, _| { |
775 | 2.15k | let (i, general_names) = all_consuming(many0(complete(cut(parse_generalname))))(input)?; |
776 | 2.06k | Ok(( |
777 | 2.06k | i, |
778 | 2.06k | ParsedExtension::SubjectAlternativeName(SubjectAlternativeName { general_names }), |
779 | 2.06k | )) |
780 | 2.16k | })(i) |
781 | 2.16k | } |
782 | | |
783 | 4 | pub(super) fn parse_issueralternativename_ext( |
784 | 4 | i: &[u8], |
785 | 4 | ) -> IResult<&[u8], ParsedExtension, BerError> { |
786 | 4 | parse_der_sequence_defined_g(|input, _| { |
787 | 4 | let (i, general_names) = all_consuming(many0(complete(cut(parse_generalname))))(input)?; |
788 | 4 | Ok(( |
789 | 4 | i, |
790 | 4 | ParsedExtension::IssuerAlternativeName(IssuerAlternativeName { general_names }), |
791 | 4 | )) |
792 | 4 | })(i) |
793 | 4 | } |
794 | | |
795 | 9 | pub(super) fn parse_policyconstraints(i: &[u8]) -> IResult<&[u8], PolicyConstraints, BerError> { |
796 | 9 | parse_der_sequence_defined_g(|input, _| { |
797 | 7 | let (i, require_explicit_policy) = opt(complete(map_res( |
798 | 7 | parse_der_tagged_implicit(0, parse_der_content(Tag::Integer)), |
799 | 0 | |x| x.as_u32(), |
800 | 7 | )))(input)?; |
801 | 7 | let (i, inhibit_policy_mapping) = all_consuming(opt(complete(map_res( |
802 | 7 | parse_der_tagged_implicit(1, parse_der_content(Tag::Integer)), |
803 | 0 | |x| x.as_u32(), |
804 | 7 | ))))(i)?; |
805 | 0 | let policy_constraint = PolicyConstraints { |
806 | 0 | require_explicit_policy, |
807 | 0 | inhibit_policy_mapping, |
808 | 0 | }; |
809 | 0 | Ok((i, policy_constraint)) |
810 | 9 | })(i) |
811 | 9 | } |
812 | | |
813 | 9 | fn parse_policyconstraints_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
814 | 9 | map(parse_policyconstraints, ParsedExtension::PolicyConstraints)(i) |
815 | 9 | } |
816 | | |
817 | 0 | fn parse_policymappings_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
818 | 0 | map(parse_policymappings, ParsedExtension::PolicyMappings)(i) |
819 | 0 | } |
820 | | |
821 | 0 | fn parse_inhibitanypolicy_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
822 | 0 | let (ret, skip_certs) = parse_der_u32(i)?; |
823 | 0 | Ok(( |
824 | 0 | ret, |
825 | 0 | ParsedExtension::InhibitAnyPolicy(InhibitAnyPolicy { skip_certs }), |
826 | 0 | )) |
827 | 0 | } |
828 | | |
829 | 1.89k | fn parse_extendedkeyusage_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
830 | 1.89k | map(parse_extendedkeyusage, ParsedExtension::ExtendedKeyUsage)(i) |
831 | 1.89k | } |
832 | | |
833 | | // DistributionPointName ::= CHOICE { |
834 | | // fullName [0] GeneralNames, |
835 | | // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } |
836 | 2.99k | fn parse_distributionpointname(i: &[u8]) -> IResult<&[u8], DistributionPointName, BerError> { |
837 | 2.99k | let (rem, header) = der_read_element_header(i)?; |
838 | 2.98k | match header.tag().0 { |
839 | | 0 => { |
840 | 2.97k | let (rem, names) = many1(complete(parse_generalname))(rem)?; |
841 | 2.91k | Ok((rem, DistributionPointName::FullName(names))) |
842 | | } |
843 | | 1 => { |
844 | 4 | let (rem, rdn) = RelativeDistinguishedName::from_der(rem) |
845 | 4 | .map_err(|_| BerError::BerValueError)?; |
846 | 0 | Ok((rem, DistributionPointName::NameRelativeToCRLIssuer(rdn))) |
847 | | } |
848 | 7 | _ => Err(Err::Error(BerError::InvalidTag)), |
849 | | } |
850 | 2.99k | } |
851 | | |
852 | | // ReasonFlags ::= BIT STRING { |
853 | | // unused (0), |
854 | | // keyCompromise (1), |
855 | | // cACompromise (2), |
856 | | // affiliationChanged (3), |
857 | | // superseded (4), |
858 | | // cessationOfOperation (5), |
859 | | // certificateHold (6), |
860 | | // privilegeWithdrawn (7), |
861 | | // aACompromise (8) } |
862 | 3.01k | fn parse_tagged1_reasons(i: &[u8]) -> BerResult<ReasonFlags> { |
863 | 3.01k | let (rem, obj) = parse_der_tagged_implicit(1, parse_der_content(Tag::BitString))(i)?; |
864 | 0 | if let DerObjectContent::BitString(_, b) = obj.content { |
865 | 0 | let flags = b |
866 | 0 | .data |
867 | 0 | .iter() |
868 | 0 | .rev() |
869 | 0 | .fold(0, |acc, x| acc << 8 | (x.reverse_bits() as u16)); |
870 | 0 | Ok((rem, ReasonFlags { flags })) |
871 | | } else { |
872 | 0 | Err(nom::Err::Failure(BerError::InvalidTag)) |
873 | | } |
874 | 3.01k | } |
875 | | |
876 | 0 | fn parse_crlissuer_content(i: &[u8]) -> BerResult<Vec<GeneralName>> { |
877 | 0 | many1(complete(parse_generalname))(i) |
878 | 0 | } |
879 | | |
880 | | // DistributionPoint ::= SEQUENCE { |
881 | | // distributionPoint [0] DistributionPointName OPTIONAL, |
882 | | // reasons [1] ReasonFlags OPTIONAL, |
883 | | // cRLIssuer [2] GeneralNames OPTIONAL } |
884 | 5.48k | pub(super) fn parse_crldistributionpoint( |
885 | 5.48k | i: &[u8], |
886 | 5.48k | ) -> IResult<&[u8], CRLDistributionPoint, BerError> { |
887 | 5.48k | parse_der_sequence_defined_g(|content, _| { |
888 | 3.01k | let (rem, distribution_point) = |
889 | 3.01k | opt(complete(parse_der_tagged_explicit_g(0, |b, _| { |
890 | 2.99k | parse_distributionpointname(b) |
891 | 3.01k | })))(content)?; |
892 | 3.01k | let (rem, reasons) = opt(complete(parse_tagged1_reasons))(rem)?; |
893 | 3.01k | let (rem, crl_issuer) = opt(complete(parse_der_tagged_implicit_g(2, |i, _, _| { |
894 | 0 | parse_crlissuer_content(i) |
895 | 3.01k | })))(rem)?; |
896 | 3.01k | let crl_dp = CRLDistributionPoint { |
897 | 3.01k | distribution_point, |
898 | 3.01k | reasons, |
899 | 3.01k | crl_issuer, |
900 | 3.01k | }; |
901 | 3.01k | Ok((rem, crl_dp)) |
902 | 5.48k | })(i) |
903 | 5.48k | } |
904 | | |
905 | 2.48k | pub(super) fn parse_crldistributionpoints( |
906 | 2.48k | i: &[u8], |
907 | 2.48k | ) -> IResult<&[u8], CRLDistributionPoints, BerError> { |
908 | 2.48k | let (ret, crldps) = parse_der_sequence_of_v(parse_crldistributionpoint)(i)?; |
909 | 2.42k | Ok((ret, CRLDistributionPoints { points: crldps })) |
910 | 2.48k | } |
911 | | |
912 | 2.48k | fn parse_crldistributionpoints_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
913 | 2.48k | map( |
914 | 2.48k | parse_crldistributionpoints, |
915 | 2.48k | ParsedExtension::CRLDistributionPoints, |
916 | 2.48k | )(i) |
917 | 2.48k | } |
918 | | |
919 | | // AuthorityInfoAccessSyntax ::= |
920 | | // SEQUENCE SIZE (1..MAX) OF AccessDescription |
921 | | // |
922 | | // AccessDescription ::= SEQUENCE { |
923 | | // accessMethod OBJECT IDENTIFIER, |
924 | | // accessLocation GeneralName } |
925 | 2.34k | pub(super) fn parse_authorityinfoaccess( |
926 | 2.34k | i: &[u8], |
927 | 2.34k | ) -> IResult<&[u8], AuthorityInfoAccess, BerError> { |
928 | 6.29k | fn parse_aia(i: &[u8]) -> IResult<&[u8], AccessDescription, BerError> { |
929 | 6.29k | parse_der_sequence_defined_g(|content, _| { |
930 | | // Read first element, an oid. |
931 | 4.00k | let (gn, oid) = Oid::from_der(content)?; |
932 | | // Parse second element |
933 | 4.00k | let (rest, gn) = parse_generalname(gn)?; |
934 | 3.94k | Ok((rest, AccessDescription::new(oid, gn))) |
935 | 6.29k | })(i) |
936 | 6.29k | } |
937 | 2.34k | let (ret, accessdescs) = parse_der_sequence_of_v(parse_aia)(i)?; |
938 | 2.25k | Ok((ret, AuthorityInfoAccess { accessdescs })) |
939 | 2.34k | } |
940 | | |
941 | 2.34k | fn parse_authorityinfoaccess_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
942 | 2.34k | map( |
943 | 2.34k | parse_authorityinfoaccess, |
944 | 2.34k | ParsedExtension::AuthorityInfoAccess, |
945 | 2.34k | )(i) |
946 | 2.34k | } |
947 | | |
948 | 2.14k | fn parse_aki_content<'a>( |
949 | 2.14k | i: &'a [u8], |
950 | 2.14k | _hdr: Header<'_>, |
951 | 2.14k | ) -> IResult<&'a [u8], AuthorityKeyIdentifier<'a>, BerError> { |
952 | 2.14k | let (i, key_identifier) = opt(complete(parse_der_tagged_implicit_g(0, |d, _, _| { |
953 | 2.12k | Ok((&[], KeyIdentifier(d))) |
954 | 2.14k | })))(i)?; |
955 | 2.14k | let (i, authority_cert_issuer) = |
956 | 2.14k | opt(complete(parse_der_tagged_implicit_g(1, |d, _, _| { |
957 | 1 | many0(complete(parse_generalname))(d) |
958 | 2.14k | })))(i)?; |
959 | 2.14k | let (i, authority_cert_serial) = opt(complete(parse_der_tagged_implicit( |
960 | 2.14k | 2, |
961 | 2.14k | parse_der_content(Tag::Integer), |
962 | 2.14k | )))(i)?; |
963 | 2.14k | let authority_cert_serial = authority_cert_serial.and_then(|o| o.as_slice().ok()); |
964 | 2.14k | let aki = AuthorityKeyIdentifier { |
965 | 2.14k | key_identifier, |
966 | 2.14k | authority_cert_issuer, |
967 | 2.14k | authority_cert_serial, |
968 | 2.14k | }; |
969 | 2.14k | Ok((i, aki)) |
970 | 2.14k | } |
971 | | |
972 | | // RFC 5280 section 4.2.1.1: Authority Key Identifier |
973 | 2.15k | pub(super) fn parse_authoritykeyidentifier( |
974 | 2.15k | i: &[u8], |
975 | 2.15k | ) -> IResult<&[u8], AuthorityKeyIdentifier, BerError> { |
976 | 2.15k | let (rem, aki) = parse_der_sequence_defined_g(parse_aki_content)(i)?; |
977 | 2.14k | Ok((rem, aki)) |
978 | 2.15k | } |
979 | | |
980 | 2.15k | fn parse_authoritykeyidentifier_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
981 | 2.15k | map( |
982 | 2.15k | parse_authoritykeyidentifier, |
983 | 2.15k | ParsedExtension::AuthorityKeyIdentifier, |
984 | 2.15k | )(i) |
985 | 2.15k | } |
986 | | |
987 | 1.15k | pub(super) fn parse_keyidentifier(i: &[u8]) -> IResult<&[u8], KeyIdentifier, BerError> { |
988 | 1.15k | let (rest, id) = <&[u8]>::from_der(i)?; |
989 | 1.15k | let ki = KeyIdentifier(id); |
990 | 1.15k | Ok((rest, ki)) |
991 | 1.15k | } |
992 | | |
993 | 1.15k | fn parse_keyidentifier_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
994 | 1.15k | map(parse_keyidentifier, ParsedExtension::SubjectKeyIdentifier)(i) |
995 | 1.15k | } |
996 | | |
997 | 2.00k | fn parse_keyusage_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
998 | 2.00k | map(parse_keyusage, ParsedExtension::KeyUsage)(i) |
999 | 2.00k | } |
1000 | | |
1001 | 99 | pub(super) fn parse_nscerttype(i: &[u8]) -> IResult<&[u8], NSCertType, BerError> { |
1002 | 99 | let (rest, obj) = parse_der_bitstring(i)?; |
1003 | 86 | let bitstring = obj |
1004 | 86 | .content |
1005 | 86 | .as_bitstring() |
1006 | 86 | .or(Err(Err::Error(BerError::BerTypeError)))?; |
1007 | | // bitstring should be 1 byte long |
1008 | 86 | if bitstring.data.len() != 1 { |
1009 | 1 | return Err(Err::Error(BerError::BerValueError)); |
1010 | 85 | } |
1011 | 85 | let flags = bitstring.data[0].reverse_bits(); |
1012 | 85 | Ok((rest, NSCertType(flags))) |
1013 | 99 | } |
1014 | | |
1015 | 99 | fn parse_nscerttype_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1016 | 99 | map(parse_nscerttype, ParsedExtension::NSCertType)(i) |
1017 | 99 | } |
1018 | | |
1019 | 0 | fn parse_nscomment_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1020 | 0 | match parse_der_ia5string(i) { |
1021 | 0 | Ok((i, obj)) => { |
1022 | 0 | let s = obj.as_str()?; |
1023 | 0 | Ok((i, ParsedExtension::NsCertComment(s))) |
1024 | | } |
1025 | 0 | Err(e) => { |
1026 | | // Some implementations encode the comment directly, without |
1027 | | // wrapping it in an IA5String |
1028 | 0 | if let Ok(s) = std::str::from_utf8(i) { |
1029 | 0 | Ok((&[], ParsedExtension::NsCertComment(s))) |
1030 | | } else { |
1031 | 0 | Err(e) |
1032 | | } |
1033 | | } |
1034 | | } |
1035 | 0 | } |
1036 | | |
1037 | | // CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation |
1038 | | // |
1039 | | // PolicyInformation ::= SEQUENCE { |
1040 | | // policyIdentifier CertPolicyId, |
1041 | | // policyQualifiers SEQUENCE SIZE (1..MAX) OF |
1042 | | // PolicyQualifierInfo OPTIONAL } |
1043 | | // |
1044 | | // CertPolicyId ::= OBJECT IDENTIFIER |
1045 | | // |
1046 | | // PolicyQualifierInfo ::= SEQUENCE { |
1047 | | // policyQualifierId PolicyQualifierId, |
1048 | | // qualifier ANY DEFINED BY policyQualifierId } |
1049 | | // |
1050 | | // -- Implementations that recognize additional policy qualifiers MUST |
1051 | | // -- augment the following definition for PolicyQualifierId |
1052 | | // |
1053 | | // PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) |
1054 | 1.84k | pub(super) fn parse_certificatepolicies( |
1055 | 1.84k | i: &[u8], |
1056 | 1.84k | ) -> IResult<&[u8], Vec<PolicyInformation>, BerError> { |
1057 | 4.59k | fn parse_policy_qualifier_info(i: &[u8]) -> IResult<&[u8], PolicyQualifierInfo, BerError> { |
1058 | 4.59k | parse_der_sequence_defined_g(|content, _| { |
1059 | 2.82k | let (rem, policy_qualifier_id) = Oid::from_der(content)?; |
1060 | 2.82k | let info = PolicyQualifierInfo { |
1061 | 2.82k | policy_qualifier_id, |
1062 | 2.82k | qualifier: rem, |
1063 | 2.82k | }; |
1064 | 2.82k | Ok((&[], info)) |
1065 | 4.59k | })(i) |
1066 | 4.59k | } |
1067 | 4.11k | fn parse_policy_information(i: &[u8]) -> IResult<&[u8], PolicyInformation, BerError> { |
1068 | 4.11k | parse_der_sequence_defined_g(|content, _| { |
1069 | 2.29k | let (rem, policy_id) = Oid::from_der(content)?; |
1070 | 2.28k | let (rem, policy_qualifiers) = |
1071 | 2.28k | opt(complete(parse_der_sequence_defined_g(|content, _| { |
1072 | 1.77k | many1(complete(parse_policy_qualifier_info))(content) |
1073 | 2.28k | })))(rem)?; |
1074 | 2.28k | let info = PolicyInformation { |
1075 | 2.28k | policy_id, |
1076 | 2.28k | policy_qualifiers, |
1077 | 2.28k | }; |
1078 | 2.28k | Ok((rem, info)) |
1079 | 4.11k | })(i) |
1080 | 4.11k | } |
1081 | 1.84k | parse_der_sequence_of_v(parse_policy_information)(i) |
1082 | 1.84k | } |
1083 | | |
1084 | 1.84k | fn parse_certificatepolicies_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1085 | 1.84k | map( |
1086 | 1.84k | parse_certificatepolicies, |
1087 | 1.84k | ParsedExtension::CertificatePolicies, |
1088 | 1.84k | )(i) |
1089 | 1.84k | } |
1090 | | |
1091 | | // CRLReason ::= ENUMERATED { ... |
1092 | 0 | fn parse_reason_code(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1093 | 0 | let (rest, obj) = parse_der_enum(i)?; |
1094 | 0 | let code = obj |
1095 | 0 | .content |
1096 | 0 | .as_u32() |
1097 | 0 | .or(Err(Err::Error(BerError::BerValueError)))?; |
1098 | 0 | if code > 10 { |
1099 | 0 | return Err(Err::Error(BerError::BerValueError)); |
1100 | 0 | } |
1101 | 0 | let ret = ParsedExtension::ReasonCode(ReasonCode(code as u8)); |
1102 | 0 | Ok((rest, ret)) |
1103 | 0 | } |
1104 | | |
1105 | | // invalidityDate ::= GeneralizedTime |
1106 | 2 | fn parse_invalidity_date(i: &[u8]) -> ParseResult<ParsedExtension> { |
1107 | 2 | let (rest, t) = GeneralizedTime::from_der(i)?; |
1108 | 0 | let dt = t.utc_datetime()?; |
1109 | 0 | Ok((rest, ParsedExtension::InvalidityDate(ASN1Time::new(dt)))) |
1110 | 2 | } |
1111 | | |
1112 | | // CRLNumber ::= INTEGER (0..MAX) |
1113 | | // Note from RFC 3280: "CRL verifiers MUST be able to handle CRLNumber values up to 20 octets." |
1114 | 0 | fn parse_crl_number(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1115 | 0 | let (rest, num) = map_res(parse_der_integer, |obj| obj.as_biguint())(i)?; |
1116 | 0 | Ok((rest, ParsedExtension::CRLNumber(num))) |
1117 | 0 | } |
1118 | | |
1119 | 992 | fn parse_sct_ext(i: &[u8]) -> IResult<&[u8], ParsedExtension, BerError> { |
1120 | 992 | map( |
1121 | 992 | parse_ct_signed_certificate_timestamp_list, |
1122 | 992 | ParsedExtension::SCT, |
1123 | 992 | )(i) |
1124 | 992 | } |
1125 | | } |
1126 | | |
1127 | | /// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
1128 | 2.69k | pub(crate) fn parse_extension_sequence(i: &[u8]) -> X509Result<Vec<X509Extension>> { |
1129 | 2.69k | parse_der_sequence_defined_g(|a, _| all_consuming(many0(complete(X509Extension::from_der)))(a))( |
1130 | 2.69k | i, |
1131 | | ) |
1132 | 2.69k | } |
1133 | | |
1134 | 2.73k | pub(crate) fn parse_extensions(i: &[u8], explicit_tag: Tag) -> X509Result<Vec<X509Extension>> { |
1135 | 2.73k | if i.is_empty() { |
1136 | 2 | return Ok((i, Vec::new())); |
1137 | 2.73k | } |
1138 | | |
1139 | 2.73k | match der_read_element_header(i) { |
1140 | 2.73k | Ok((rem, hdr)) => { |
1141 | 2.73k | if hdr.tag() != explicit_tag { |
1142 | 42 | return Err(Err::Error(X509Error::InvalidExtensions)); |
1143 | 2.69k | } |
1144 | 2.69k | all_consuming(parse_extension_sequence)(rem) |
1145 | | } |
1146 | 0 | Err(_) => Err(X509Error::InvalidExtensions.into()), |
1147 | | } |
1148 | 2.73k | } |
1149 | | |
1150 | | /// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
1151 | 0 | pub(crate) fn parse_extension_envelope_sequence(i: &[u8]) -> X509Result<Vec<X509Extension>> { |
1152 | 0 | let parser = X509ExtensionParser::new().with_deep_parse_extensions(false); |
1153 | | |
1154 | 0 | parse_der_sequence_defined_g(move |a, _| all_consuming(many0(complete(parser)))(a))(i) |
1155 | 0 | } |
1156 | | |
1157 | 0 | pub(crate) fn parse_extensions_envelope( |
1158 | 0 | i: &[u8], |
1159 | 0 | explicit_tag: Tag, |
1160 | 0 | ) -> X509Result<Vec<X509Extension>> { |
1161 | 0 | if i.is_empty() { |
1162 | 0 | return Ok((i, Vec::new())); |
1163 | 0 | } |
1164 | | |
1165 | 0 | match der_read_element_header(i) { |
1166 | 0 | Ok((rem, hdr)) => { |
1167 | 0 | if hdr.tag() != explicit_tag { |
1168 | 0 | return Err(Err::Error(X509Error::InvalidExtensions)); |
1169 | 0 | } |
1170 | 0 | all_consuming(parse_extension_envelope_sequence)(rem) |
1171 | | } |
1172 | 0 | Err(_) => Err(X509Error::InvalidExtensions.into()), |
1173 | | } |
1174 | 0 | } |
1175 | | |
1176 | 19.8k | fn der_read_critical(i: &[u8]) -> BerResult<bool> { |
1177 | | // Some certificates do not respect the DER BOOLEAN constraint (true must be encoded as 0xff) |
1178 | | // so we attempt to parse as BER |
1179 | 19.8k | let (rem, obj) = opt(parse_ber_bool)(i)?; |
1180 | 19.8k | let value = obj |
1181 | 19.8k | .map(|o| o.as_bool().unwrap_or_default()) // unwrap cannot fail, we just read a bool |
1182 | 19.8k | .unwrap_or(false) // default critical value |
1183 | | ; |
1184 | 19.8k | Ok((rem, value)) |
1185 | 19.8k | } |
1186 | | |
1187 | | #[cfg(test)] |
1188 | | mod tests { |
1189 | | use super::*; |
1190 | | |
1191 | | #[test] |
1192 | | fn test_keyusage_flags() { |
1193 | | let ku = KeyUsage { flags: 98 }; |
1194 | | assert!(!ku.digital_signature()); |
1195 | | assert!(ku.non_repudiation()); |
1196 | | assert!(!ku.key_encipherment()); |
1197 | | assert!(!ku.data_encipherment()); |
1198 | | assert!(!ku.key_agreement()); |
1199 | | assert!(ku.key_cert_sign()); |
1200 | | assert!(ku.crl_sign()); |
1201 | | assert!(!ku.encipher_only()); |
1202 | | assert!(!ku.decipher_only()); |
1203 | | } |
1204 | | |
1205 | | #[test] |
1206 | | fn test_extensions1() { |
1207 | | use der_parser::oid; |
1208 | | let crt = crate::parse_x509_certificate(include_bytes!("../../assets/extension1.der")) |
1209 | | .unwrap() |
1210 | | .1; |
1211 | | let tbs = &crt.tbs_certificate; |
1212 | | let bc = crt |
1213 | | .basic_constraints() |
1214 | | .expect("could not get basic constraints") |
1215 | | .expect("no basic constraints found"); |
1216 | | assert_eq!( |
1217 | | bc.value, |
1218 | | &BasicConstraints { |
1219 | | ca: true, |
1220 | | path_len_constraint: Some(1) |
1221 | | } |
1222 | | ); |
1223 | | { |
1224 | | let ku = tbs |
1225 | | .key_usage() |
1226 | | .expect("could not get key usage") |
1227 | | .expect("no key usage found") |
1228 | | .value; |
1229 | | assert!(ku.digital_signature()); |
1230 | | assert!(!ku.non_repudiation()); |
1231 | | assert!(ku.key_encipherment()); |
1232 | | assert!(ku.data_encipherment()); |
1233 | | assert!(ku.key_agreement()); |
1234 | | assert!(!ku.key_cert_sign()); |
1235 | | assert!(!ku.crl_sign()); |
1236 | | assert!(ku.encipher_only()); |
1237 | | assert!(ku.decipher_only()); |
1238 | | } |
1239 | | { |
1240 | | let eku = tbs |
1241 | | .extended_key_usage() |
1242 | | .expect("could not get extended key usage") |
1243 | | .expect("no extended key usage found") |
1244 | | .value; |
1245 | | assert!(!eku.any); |
1246 | | assert!(eku.server_auth); |
1247 | | assert!(!eku.client_auth); |
1248 | | assert!(eku.code_signing); |
1249 | | assert!(!eku.email_protection); |
1250 | | assert!(eku.time_stamping); |
1251 | | assert!(!eku.ocsp_signing); |
1252 | | assert_eq!(eku.other, vec![oid!(1.2.3 .4 .0 .42)]); |
1253 | | } |
1254 | | assert_eq!( |
1255 | | tbs.policy_constraints() |
1256 | | .expect("could not get policy constraints") |
1257 | | .expect("no policy constraints found") |
1258 | | .value, |
1259 | | &PolicyConstraints { |
1260 | | require_explicit_policy: None, |
1261 | | inhibit_policy_mapping: Some(10) |
1262 | | } |
1263 | | ); |
1264 | | let val = tbs |
1265 | | .inhibit_anypolicy() |
1266 | | .expect("could not get inhibit_anypolicy") |
1267 | | .expect("no inhibit_anypolicy found") |
1268 | | .value; |
1269 | | assert_eq!(val, &InhibitAnyPolicy { skip_certs: 2 }); |
1270 | | { |
1271 | | let alt_names = &tbs |
1272 | | .subject_alternative_name() |
1273 | | .expect("could not get subject alt names") |
1274 | | .expect("no subject alt names found") |
1275 | | .value |
1276 | | .general_names; |
1277 | | assert_eq!(alt_names[0], GeneralName::RFC822Name("foo@example.com")); |
1278 | | assert_eq!(alt_names[1], GeneralName::URI("http://my.url.here/")); |
1279 | | assert_eq!( |
1280 | | alt_names[2], |
1281 | | GeneralName::IPAddress([192, 168, 7, 1].as_ref()) |
1282 | | ); |
1283 | | assert_eq!( |
1284 | | format!( |
1285 | | "{}", |
1286 | | match alt_names[3] { |
1287 | | GeneralName::DirectoryName(ref dn) => dn, |
1288 | | _ => unreachable!(), |
1289 | | } |
1290 | | ), |
1291 | | "C=UK, O=My Organization, OU=My Unit, CN=My Name" |
1292 | | ); |
1293 | | assert_eq!(alt_names[4], GeneralName::DNSName("localhost")); |
1294 | | assert_eq!(alt_names[5], GeneralName::RegisteredID(oid!(1.2.90 .0))); |
1295 | | assert_eq!( |
1296 | | alt_names[6], |
1297 | | GeneralName::OtherName(oid!(1.2.3 .4), b"\xA0\x17\x0C\x15some other identifier") |
1298 | | ); |
1299 | | } |
1300 | | |
1301 | | { |
1302 | | let name_constraints = &tbs |
1303 | | .name_constraints() |
1304 | | .expect("could not get name constraints") |
1305 | | .expect("no name constraints found") |
1306 | | .value; |
1307 | | assert_eq!(name_constraints.permitted_subtrees, None); |
1308 | | assert_eq!( |
1309 | | name_constraints.excluded_subtrees, |
1310 | | Some(vec![ |
1311 | | GeneralSubtree { |
1312 | | base: GeneralName::IPAddress([192, 168, 0, 0, 255, 255, 0, 0].as_ref()) |
1313 | | }, |
1314 | | GeneralSubtree { |
1315 | | base: GeneralName::RFC822Name("foo.com") |
1316 | | }, |
1317 | | ]) |
1318 | | ); |
1319 | | } |
1320 | | } |
1321 | | |
1322 | | #[test] |
1323 | | fn test_extensions2() { |
1324 | | use der_parser::oid; |
1325 | | let crt = crate::parse_x509_certificate(include_bytes!("../../assets/extension2.der")) |
1326 | | .unwrap() |
1327 | | .1; |
1328 | | let tbs = crt.tbs_certificate; |
1329 | | assert_eq!( |
1330 | | tbs.policy_constraints() |
1331 | | .expect("could not get policy constraints") |
1332 | | .expect("no policy constraints found") |
1333 | | .value, |
1334 | | &PolicyConstraints { |
1335 | | require_explicit_policy: Some(5000), |
1336 | | inhibit_policy_mapping: None |
1337 | | } |
1338 | | ); |
1339 | | { |
1340 | | let pm = tbs |
1341 | | .policy_mappings() |
1342 | | .expect("could not get policy_mappings") |
1343 | | .expect("no policy_mappings found") |
1344 | | .value |
1345 | | .clone() |
1346 | | .into_hashmap(); |
1347 | | let mut pm_ref = HashMap::new(); |
1348 | | pm_ref.insert(oid!(2.34.23), vec![oid!(2.2)]); |
1349 | | pm_ref.insert(oid!(1.1), vec![oid!(0.0.4)]); |
1350 | | pm_ref.insert(oid!(2.2), vec![oid!(2.2.1), oid!(2.2.3)]); |
1351 | | assert_eq!(pm, pm_ref); |
1352 | | } |
1353 | | } |
1354 | | |
1355 | | #[test] |
1356 | | fn test_extensions_crl_distribution_points() { |
1357 | | // Extension not present |
1358 | | { |
1359 | | let crt = crate::parse_x509_certificate(include_bytes!( |
1360 | | "../../assets/crl-ext/crl-no-crl.der" |
1361 | | )) |
1362 | | .unwrap() |
1363 | | .1; |
1364 | | assert!(crt |
1365 | | .tbs_certificate |
1366 | | .extensions_map() |
1367 | | .unwrap() |
1368 | | .get(&OID_X509_EXT_CRL_DISTRIBUTION_POINTS) |
1369 | | .is_none()); |
1370 | | } |
1371 | | // CRLDistributionPoints has 1 entry with 1 URI |
1372 | | { |
1373 | | let crt = crate::parse_x509_certificate(include_bytes!( |
1374 | | "../../assets/crl-ext/crl-simple.der" |
1375 | | )) |
1376 | | .unwrap() |
1377 | | .1; |
1378 | | let crl = crt |
1379 | | .tbs_certificate |
1380 | | .extensions_map() |
1381 | | .unwrap() |
1382 | | .get(&OID_X509_EXT_CRL_DISTRIBUTION_POINTS) |
1383 | | .unwrap() |
1384 | | .parsed_extension(); |
1385 | | assert!(matches!(crl, ParsedExtension::CRLDistributionPoints(_))); |
1386 | | if let ParsedExtension::CRLDistributionPoints(crl) = crl { |
1387 | | assert_eq!(crl.len(), 1); |
1388 | | assert!(crl[0].reasons.is_none()); |
1389 | | assert!(crl[0].crl_issuer.is_none()); |
1390 | | let distribution_point = crl[0].distribution_point.as_ref().unwrap(); |
1391 | | assert!(matches!( |
1392 | | distribution_point, |
1393 | | DistributionPointName::FullName(_) |
1394 | | )); |
1395 | | if let DistributionPointName::FullName(names) = distribution_point { |
1396 | | assert_eq!(names.len(), 1); |
1397 | | assert!(matches!(names[0], GeneralName::URI(_))); |
1398 | | if let GeneralName::URI(uri) = names[0] { |
1399 | | assert_eq!(uri, "http://example.com/myca.crl") |
1400 | | } |
1401 | | } |
1402 | | } |
1403 | | } |
1404 | | // CRLDistributionPoints has 2 entries |
1405 | | { |
1406 | | let crt = crate::parse_x509_certificate(include_bytes!( |
1407 | | "../../assets/crl-ext/crl-complex.der" |
1408 | | )) |
1409 | | .unwrap() |
1410 | | .1; |
1411 | | let crl = crt |
1412 | | .tbs_certificate |
1413 | | .extensions_map() |
1414 | | .unwrap() |
1415 | | .get(&OID_X509_EXT_CRL_DISTRIBUTION_POINTS) |
1416 | | .unwrap() |
1417 | | .parsed_extension(); |
1418 | | assert!(matches!(crl, ParsedExtension::CRLDistributionPoints(_))); |
1419 | | if let ParsedExtension::CRLDistributionPoints(crl) = crl { |
1420 | | assert_eq!(crl.len(), 2); |
1421 | | // First CRL Distribution point |
1422 | | let reasons = crl[0].reasons.as_ref().unwrap(); |
1423 | | assert!(reasons.key_compromise()); |
1424 | | assert!(reasons.ca_compromise()); |
1425 | | assert!(!reasons.affilation_changed()); |
1426 | | assert!(!reasons.superseded()); |
1427 | | assert!(!reasons.cessation_of_operation()); |
1428 | | assert!(!reasons.certificate_hold()); |
1429 | | assert!(!reasons.privelege_withdrawn()); |
1430 | | assert!(reasons.aa_compromise()); |
1431 | | assert_eq!( |
1432 | | format!("{}", reasons), |
1433 | | "Key Compromise, CA Compromise, AA Compromise" |
1434 | | ); |
1435 | | let issuers = crl[0].crl_issuer.as_ref().unwrap(); |
1436 | | assert_eq!(issuers.len(), 1); |
1437 | | assert!(matches!(issuers[0], GeneralName::DirectoryName(_))); |
1438 | | if let GeneralName::DirectoryName(name) = &issuers[0] { |
1439 | | assert_eq!(name.to_string(), "C=US, O=Organisation, CN=Some Name"); |
1440 | | } |
1441 | | let distribution_point = crl[0].distribution_point.as_ref().unwrap(); |
1442 | | assert!(matches!( |
1443 | | distribution_point, |
1444 | | DistributionPointName::FullName(_) |
1445 | | )); |
1446 | | if let DistributionPointName::FullName(names) = distribution_point { |
1447 | | assert_eq!(names.len(), 1); |
1448 | | assert!(matches!(names[0], GeneralName::URI(_))); |
1449 | | if let GeneralName::URI(uri) = names[0] { |
1450 | | assert_eq!(uri, "http://example.com/myca.crl") |
1451 | | } |
1452 | | } |
1453 | | // Second CRL Distribution point |
1454 | | let reasons = crl[1].reasons.as_ref().unwrap(); |
1455 | | assert!(reasons.key_compromise()); |
1456 | | assert!(reasons.ca_compromise()); |
1457 | | assert!(!reasons.affilation_changed()); |
1458 | | assert!(!reasons.superseded()); |
1459 | | assert!(!reasons.cessation_of_operation()); |
1460 | | assert!(!reasons.certificate_hold()); |
1461 | | assert!(!reasons.privelege_withdrawn()); |
1462 | | assert!(!reasons.aa_compromise()); |
1463 | | assert_eq!(format!("{}", reasons), "Key Compromise, CA Compromise"); |
1464 | | assert!(crl[1].crl_issuer.is_none()); |
1465 | | let distribution_point = crl[1].distribution_point.as_ref().unwrap(); |
1466 | | assert!(matches!( |
1467 | | distribution_point, |
1468 | | DistributionPointName::FullName(_) |
1469 | | )); |
1470 | | if let DistributionPointName::FullName(names) = distribution_point { |
1471 | | assert_eq!(names.len(), 1); |
1472 | | assert!(matches!(names[0], GeneralName::URI(_))); |
1473 | | if let GeneralName::URI(uri) = names[0] { |
1474 | | assert_eq!(uri, "http://example.com/myca2.crl") |
1475 | | } |
1476 | | } |
1477 | | } |
1478 | | } |
1479 | | } |
1480 | | |
1481 | | // Test cases for: |
1482 | | // - parsing SubjectAlternativeName |
1483 | | // - parsing NameConstraints |
1484 | | } |