x509_parser/extensions/
mod.rs

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