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