//! X.509 Certificate object definitions and operations use crate::error::{X509Error, X509Result}; use crate::extensions::*; use crate::time::ASN1Time; use crate::traits::FromDer; #[cfg(feature = "validate")] use crate::validate::Validate; use crate::x509::{ parse_serial, parse_signature_value, AlgorithmIdentifier, SubjectPublicKeyInfo, X509Name, X509Version, }; use der_parser::ber::{parse_ber_optional, BerTag, BitStringObject}; use der_parser::der::*; use der_parser::error::*; use der_parser::num_bigint::BigUint; use der_parser::oid::Oid; use der_parser::*; use nom::{Offset, Parser}; use oid_registry::*; use std::collections::HashMap; #[cfg(feature = "validate")] use std::collections::HashSet; /// An X.509 v3 Certificate. /// /// X.509 v3 certificates are defined in [RFC5280](https://tools.ietf.org/html/rfc5280), section /// 4.1. This object uses the same structure for content, so for ex the subject can be accessed /// using the path `x509.tbs_certificate.subject`. /// /// `X509Certificate` also contains convenience methods to access the most common fields (subject, /// issuer, etc.). /// /// A `X509Certificate` is a zero-copy view over a buffer, so the lifetime is the same as the /// buffer containing the binary representation. /// /// ```rust /// # use x509_parser::certificate::X509Certificate; /// # use x509_parser::traits::FromDer; /// # /// # static DER: &'static [u8] = include_bytes!("../assets/IGC_A.der"); /// # /// fn display_x509_info(x509: &X509Certificate<'_>) { /// let subject = x509.subject(); /// let issuer = x509.issuer(); /// println!("X.509 Subject: {}", subject); /// println!("X.509 Issuer: {}", issuer); /// println!("X.509 serial: {}", x509.tbs_certificate.raw_serial_as_string()); /// } /// # /// # fn main() { /// # let res = X509Certificate::from_der(DER); /// # match res { /// # Ok((_rem, x509)) => { /// # display_x509_info(&x509); /// # }, /// # _ => panic!("x509 parsing failed: {:?}", res), /// # } /// # } /// ``` #[derive(Clone, Debug, PartialEq)] pub struct X509Certificate<'a> { pub tbs_certificate: TbsCertificate<'a>, pub signature_algorithm: AlgorithmIdentifier<'a>, pub signature_value: BitStringObject<'a>, } impl<'a> X509Certificate<'a> { /// Get the version of the encoded certificate pub fn version(&self) -> X509Version { self.tbs_certificate.version } /// Get the certificate subject. #[inline] pub fn subject(&self) -> &X509Name { &self.tbs_certificate.subject } /// Get the certificate issuer. #[inline] pub fn issuer(&self) -> &X509Name { &self.tbs_certificate.issuer } /// Get the certificate validity. #[inline] pub fn validity(&self) -> &Validity { &self.tbs_certificate.validity } /// Get the certificate public key information. #[inline] pub fn public_key(&self) -> &SubjectPublicKeyInfo { &self.tbs_certificate.subject_pki } /// Get the certificate extensions. #[inline] pub fn extensions(&self) -> &[X509Extension] { &self.tbs_certificate.extensions } /// Verify the cryptographic signature of this certificate /// /// `public_key` is the public key of the **signer**. For a self-signed certificate, /// (for ex. a public root certificate authority), this is the key from the certificate, /// so you can use `None`. /// /// For a leaf certificate, this is the public key of the certificate that signed it. /// It is usually an intermediate authority. #[cfg(feature = "verify")] #[cfg_attr(docsrs, doc(cfg(feature = "verify")))] pub fn verify_signature( &self, public_key: Option<&SubjectPublicKeyInfo>, ) -> Result<(), X509Error> { use ring::signature; let spki = public_key.unwrap_or_else(|| self.public_key()); let signature_alg = &self.signature_algorithm.algorithm; // identify verification algorithm let verification_alg: &dyn signature::VerificationAlgorithm = if *signature_alg == OID_PKCS1_SHA1WITHRSA { &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY } else if *signature_alg == OID_PKCS1_SHA256WITHRSA { &signature::RSA_PKCS1_2048_8192_SHA256 } else if *signature_alg == OID_PKCS1_SHA384WITHRSA { &signature::RSA_PKCS1_2048_8192_SHA384 } else if *signature_alg == OID_PKCS1_SHA512WITHRSA { &signature::RSA_PKCS1_2048_8192_SHA512 } else if *signature_alg == OID_SIG_ECDSA_WITH_SHA256 { &signature::ECDSA_P256_SHA256_ASN1 } else if *signature_alg == OID_SIG_ECDSA_WITH_SHA384 { &signature::ECDSA_P384_SHA384_ASN1 } else if *signature_alg == OID_SIG_ED25519 { &signature::ED25519 } else { return Err(X509Error::SignatureUnsupportedAlgorithm); }; // get public key let key = signature::UnparsedPublicKey::new(verification_alg, spki.subject_public_key.data); // verify signature let sig = self.signature_value.data; key.verify(self.tbs_certificate.raw, sig) .or(Err(X509Error::SignatureVerificationError)) } } impl<'a> FromDer<'a> for X509Certificate<'a> { /// Parse a DER-encoded X.509 Certificate, and return the remaining of the input and the built /// object. /// /// The returned object uses zero-copy, and so has the same lifetime as the input. /// /// Note that only parsing is done, not validation. /// ///
    /// Certificate  ::=  SEQUENCE  {
    ///         tbsCertificate       TBSCertificate,
    ///         signatureAlgorithm   AlgorithmIdentifier,
    ///         signatureValue       BIT STRING  }
    /// 
/// /// # Example /// /// To parse a certificate and print the subject and issuer: /// /// ```rust /// # use x509_parser::parse_x509_certificate; /// # /// # static DER: &'static [u8] = include_bytes!("../assets/IGC_A.der"); /// # /// # fn main() { /// let res = parse_x509_certificate(DER); /// match res { /// Ok((_rem, x509)) => { /// let subject = x509.subject(); /// let issuer = x509.issuer(); /// println!("X.509 Subject: {}", subject); /// println!("X.509 Issuer: {}", issuer); /// }, /// _ => panic!("x509 parsing failed: {:?}", res), /// } /// # } /// ``` fn from_der(i: &'a [u8]) -> X509Result { // run parser with default options X509CertificateParser::new().parse(i) } } /// X.509 Certificate parser /// /// This object is a parser builder, and allows specifying parsing options. /// Currently, the only option is to control deep parsing of X.509v3 extensions: /// a parser can decide to skip deep-parsing to be faster (the structure of extensions is still /// parsed, and the contents can be parsed later using the [`from_der`](FromDer::from_der) /// method from individual extension objects). /// /// This object uses the `nom::Parser` trait, which must be imported. /// /// # Example /// /// To parse a certificate without parsing extensions: /// /// ```rust /// use x509_parser::certificate::X509CertificateParser; /// use x509_parser::nom::Parser; /// /// # static DER: &'static [u8] = include_bytes!("../assets/IGC_A.der"); /// # /// # fn main() { /// // create a parser that will not parse extensions /// let mut parser = X509CertificateParser::new() /// .with_deep_parse_extensions(false); /// let res = parser.parse(DER); /// match res { /// Ok((_rem, x509)) => { /// let subject = x509.subject(); /// let issuer = x509.issuer(); /// println!("X.509 Subject: {}", subject); /// println!("X.509 Issuer: {}", issuer); /// }, /// _ => panic!("x509 parsing failed: {:?}", res), /// } /// # } /// ``` #[derive(Clone, Copy, Debug, PartialEq)] pub struct X509CertificateParser { deep_parse_extensions: bool, // strict: bool, } impl X509CertificateParser { #[inline] pub const fn new() -> Self { X509CertificateParser { deep_parse_extensions: true, } } #[inline] pub const fn with_deep_parse_extensions(self, deep_parse_extensions: bool) -> Self { X509CertificateParser { deep_parse_extensions, } } } impl<'a> Parser<&'a [u8], X509Certificate<'a>, X509Error> for X509CertificateParser { fn parse(&mut self, input: &'a [u8]) -> IResult<&'a [u8], X509Certificate<'a>, X509Error> { parse_der_sequence_defined_g(|i, _| { // pass options to TbsCertificate parser let mut tbs_parser = TbsCertificateParser::new().with_deep_parse_extensions(self.deep_parse_extensions); let (i, tbs_certificate) = tbs_parser.parse(i)?; let (i, signature_algorithm) = AlgorithmIdentifier::from_der(i)?; let (i, signature_value) = parse_signature_value(i)?; let cert = X509Certificate { tbs_certificate, signature_algorithm, signature_value, }; Ok((i, cert)) })(input) } } #[cfg(feature = "validate")] #[cfg_attr(docsrs, doc(cfg(feature = "validate")))] impl Validate for X509Certificate<'_> { fn validate(&self, warn: W, err: E) -> bool where W: FnMut(&str), E: FnMut(&str), { let mut res = true; res |= self.tbs_certificate.validate(warn, err); res } } /// The sequence `TBSCertificate` contains information associated with the /// subject of the certificate and the CA that issued it. /// /// RFC5280 definition: /// ///
///   TBSCertificate  ::=  SEQUENCE  {
///        version         [0]  EXPLICIT Version DEFAULT v1,
///        serialNumber         CertificateSerialNumber,
///        signature            AlgorithmIdentifier,
///        issuer               Name,
///        validity             Validity,
///        subject              Name,
///        subjectPublicKeyInfo SubjectPublicKeyInfo,
///        issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
///                             -- If present, version MUST be v2 or v3
///        subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
///                             -- If present, version MUST be v2 or v3
///        extensions      [3]  EXPLICIT Extensions OPTIONAL
///                             -- If present, version MUST be v3
///        }
/// 
#[derive(Clone, Debug, PartialEq)] pub struct TbsCertificate<'a> { pub version: X509Version, pub serial: BigUint, pub signature: AlgorithmIdentifier<'a>, pub issuer: X509Name<'a>, pub validity: Validity, pub subject: X509Name<'a>, pub subject_pki: SubjectPublicKeyInfo<'a>, pub issuer_uid: Option>, pub subject_uid: Option>, extensions: Vec>, pub(crate) raw: &'a [u8], pub(crate) raw_serial: &'a [u8], } impl<'a> TbsCertificate<'a> { /// Returns the certificate extensions #[inline] pub fn extensions(&self) -> &[X509Extension<'a>] { &self.extensions } /// Returns an iterator over the certificate extensions #[inline] pub fn iter_extensions(&self) -> impl Iterator> { self.extensions.iter() } /// Searches for an extension with the given `Oid`. /// /// Note: if there are several extensions with the same `Oid`, the first one is returned. pub fn find_extension(&self, oid: &Oid) -> Option<&X509Extension<'a>> { self.extensions.iter().find(|&ext| ext.oid == *oid) } /// Builds and returns a map of extensions. /// /// If an extension is present twice, this will fail and return `DuplicateExtensions`. pub fn extensions_map(&self) -> Result>, X509Error> { self.extensions .iter() .try_fold(HashMap::new(), |mut m, ext| { if m.contains_key(&ext.oid) { return Err(X509Error::DuplicateExtensions); } m.insert(ext.oid.clone(), ext); Ok(m) }) } pub fn basic_constraints(&self) -> Option<(bool, &BasicConstraints)> { self.find_extension(&OID_X509_EXT_BASIC_CONSTRAINTS) .and_then(|ext| match ext.parsed_extension { ParsedExtension::BasicConstraints(ref bc) => Some((ext.critical, bc)), _ => None, }) } pub fn key_usage(&self) -> Option<(bool, &KeyUsage)> { self.find_extension(&OID_X509_EXT_KEY_USAGE) .and_then(|ext| match ext.parsed_extension { ParsedExtension::KeyUsage(ref ku) => Some((ext.critical, ku)), _ => None, }) } pub fn extended_key_usage(&self) -> Option<(bool, &ExtendedKeyUsage<'a>)> { self.find_extension(&OID_X509_EXT_EXTENDED_KEY_USAGE) .and_then(|ext| match ext.parsed_extension { ParsedExtension::ExtendedKeyUsage(ref eku) => Some((ext.critical, eku)), _ => None, }) } pub fn policy_constraints(&self) -> Option<(bool, &PolicyConstraints)> { self.find_extension(&OID_X509_EXT_POLICY_CONSTRAINTS) .and_then(|ext| match ext.parsed_extension { ParsedExtension::PolicyConstraints(ref pc) => Some((ext.critical, pc)), _ => None, }) } pub fn inhibit_anypolicy(&self) -> Option<(bool, &InhibitAnyPolicy)> { self.find_extension(&OID_X509_EXT_INHIBITANT_ANY_POLICY) .and_then(|ext| match ext.parsed_extension { ParsedExtension::InhibitAnyPolicy(ref iap) => Some((ext.critical, iap)), _ => None, }) } pub fn policy_mappings(&self) -> Option<(bool, &PolicyMappings<'a>)> { self.find_extension(&OID_X509_EXT_POLICY_MAPPINGS) .and_then(|ext| match ext.parsed_extension { ParsedExtension::PolicyMappings(ref pm) => Some((ext.critical, pm)), _ => None, }) } pub fn subject_alternative_name(&self) -> Option<(bool, &SubjectAlternativeName<'a>)> { self.find_extension(&OID_X509_EXT_SUBJECT_ALT_NAME) .and_then(|ext| match ext.parsed_extension { ParsedExtension::SubjectAlternativeName(ref san) => Some((ext.critical, san)), _ => None, }) } pub fn name_constraints(&self) -> Option<(bool, &NameConstraints<'a>)> { self.find_extension(&OID_X509_EXT_NAME_CONSTRAINTS) .and_then(|ext| match ext.parsed_extension { ParsedExtension::NameConstraints(ref nc) => Some((ext.critical, nc)), _ => None, }) } /// Returns true if certificate has `basicConstraints CA:true` pub fn is_ca(&self) -> bool { self.basic_constraints() .map(|(_, bc)| bc.ca) .unwrap_or(false) } /// Get the raw bytes of the certificate serial number pub fn raw_serial(&self) -> &'a [u8] { self.raw_serial } /// Get a formatted string of the certificate serial number, separated by ':' pub fn raw_serial_as_string(&self) -> String { let mut s = self .raw_serial .iter() .fold(String::with_capacity(3 * self.raw_serial.len()), |a, b| { a + &format!("{:02x}:", b) }); s.pop(); s } } impl<'a> AsRef<[u8]> for TbsCertificate<'a> { #[inline] fn as_ref(&self) -> &[u8] { self.raw } } impl<'a> FromDer<'a> for TbsCertificate<'a> { /// Parse a DER-encoded TbsCertificate object /// ///
    /// TBSCertificate  ::=  SEQUENCE  {
    ///      version         [0]  Version DEFAULT v1,
    ///      serialNumber         CertificateSerialNumber,
    ///      signature            AlgorithmIdentifier,
    ///      issuer               Name,
    ///      validity             Validity,
    ///      subject              Name,
    ///      subjectPublicKeyInfo SubjectPublicKeyInfo,
    ///      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
    ///                           -- If present, version MUST be v2 or v3
    ///      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
    ///                           -- If present, version MUST be v2 or v3
    ///      extensions      [3]  Extensions OPTIONAL
    ///                           -- If present, version MUST be v3 --  }
    /// 
fn from_der(i: &'a [u8]) -> X509Result> { let start_i = i; parse_der_sequence_defined_g(move |i, _| { let (i, version) = X509Version::from_der(i)?; let (i, serial) = parse_serial(i)?; let (i, signature) = AlgorithmIdentifier::from_der(i)?; let (i, issuer) = X509Name::from_der(i)?; let (i, validity) = Validity::from_der(i)?; let (i, subject) = X509Name::from_der(i)?; let (i, subject_pki) = SubjectPublicKeyInfo::from_der(i)?; let (i, issuer_uid) = UniqueIdentifier::from_der_issuer(i)?; let (i, subject_uid) = UniqueIdentifier::from_der_subject(i)?; let (i, extensions) = parse_extensions(i, BerTag(3))?; let len = start_i.offset(i); let tbs = TbsCertificate { version, serial: serial.1, signature, issuer, validity, subject, subject_pki, issuer_uid, subject_uid, extensions, raw: &start_i[..len], raw_serial: serial.0, }; Ok((i, tbs)) })(i) } } /// `TbsCertificate` parser builder #[derive(Clone, Copy, Debug, PartialEq)] pub struct TbsCertificateParser { deep_parse_extensions: bool, } impl TbsCertificateParser { #[inline] pub const fn new() -> Self { TbsCertificateParser { deep_parse_extensions: true, } } #[inline] pub const fn with_deep_parse_extensions(self, deep_parse_extensions: bool) -> Self { TbsCertificateParser { deep_parse_extensions, } } } impl<'a> Parser<&'a [u8], TbsCertificate<'a>, X509Error> for TbsCertificateParser { fn parse(&mut self, input: &'a [u8]) -> IResult<&'a [u8], TbsCertificate<'a>, X509Error> { let start_i = input; parse_der_sequence_defined_g(move |i, _| { let (i, version) = X509Version::from_der(i)?; let (i, serial) = parse_serial(i)?; let (i, signature) = AlgorithmIdentifier::from_der(i)?; let (i, issuer) = X509Name::from_der(i)?; let (i, validity) = Validity::from_der(i)?; let (i, subject) = X509Name::from_der(i)?; let (i, subject_pki) = SubjectPublicKeyInfo::from_der(i)?; let (i, issuer_uid) = UniqueIdentifier::from_der_issuer(i)?; let (i, subject_uid) = UniqueIdentifier::from_der_subject(i)?; let (i, extensions) = if self.deep_parse_extensions { parse_extensions(i, BerTag(3))? } else { parse_extensions_envelope(i, BerTag(3))? }; let len = start_i.offset(i); let tbs = TbsCertificate { version, serial: serial.1, signature, issuer, validity, subject, subject_pki, issuer_uid, subject_uid, extensions, raw: &start_i[..len], raw_serial: serial.0, }; Ok((i, tbs)) })(input) } } #[cfg(feature = "validate")] #[cfg_attr(docsrs, doc(cfg(feature = "validate")))] impl Validate for TbsCertificate<'_> { fn validate(&self, mut warn: W, mut err: E) -> bool where W: FnMut(&str), E: FnMut(&str), { let mut res = true; // version must be 0, 1 or 2 if self.version.0 >= 3 { err("Invalid version"); res = false; } // extensions require v3 if !self.extensions().is_empty() && self.version != X509Version::V3 { err("Extensions present but version is not 3"); res = false; } let b = self.raw_serial(); if b.is_empty() { err("Serial is empty"); res = false; } else { // check MSB of serial if b[0] & 0x80 != 0 { warn("Serial number is negative"); } // check leading zeroes in serial if b.len() > 1 && b[0] == 0 && b[1] & 0x80 == 0 { warn("Leading zeroes in serial number"); } } // subject/issuer: verify charsets // - wildcards in PrintableString // - non-IA5 in IA5String for attr in self.subject.iter_attributes() { match attr.attr_value().content { DerObjectContent::PrintableString(s) | DerObjectContent::IA5String(s) => { if !s.as_bytes().iter().all(u8::is_ascii) { warn(&format!( "Invalid charset in 'Subject', component {}", attr.attr_type() )); } } _ => (), } } // check for parse errors or unsupported extensions for ext in self.extensions() { if let ParsedExtension::UnsupportedExtension { .. } = &ext.parsed_extension { warn(&format!("Unsupported extension {}", ext.oid)); } if let ParsedExtension::ParseError { error } = &ext.parsed_extension { err(&format!("Parse error in extension {}: {}", ext.oid, error)); res = false; } } // check for duplicate extensions let mut m = HashSet::new(); for ext in self.extensions() { if m.contains(&ext.oid) { err(&format!("Duplicate extension {}", ext.oid)); res = false; } else { m.insert(ext.oid.clone()); } // specific extension checks // SAN if let ParsedExtension::SubjectAlternativeName(san) = ext.parsed_extension() { for name in &san.general_names { match name { GeneralName::DNSName(ref s) | GeneralName::RFC822Name(ref s) => { // should be an ia5string if !s.as_bytes().iter().all(u8::is_ascii) { warn(&format!("Invalid charset in 'SAN' entry '{}'", s)); } } _ => (), } } } } res } } #[derive(Clone, Debug, PartialEq)] pub struct Validity { pub not_before: ASN1Time, pub not_after: ASN1Time, } impl Validity { /// The time left before the certificate expires. /// /// If the certificate is not currently valid, then `None` is /// returned. Otherwise, the `Duration` until the certificate /// expires is returned. pub fn time_to_expiration(&self) -> Option { let now = ASN1Time::now(); if !self.is_valid_at(now) { return None; } // Note that the duration below is guaranteed to be positive, // since we just checked that now < na self.not_after - now } /// Check the certificate time validity for the provided date/time #[inline] pub fn is_valid_at(&self, time: ASN1Time) -> bool { time >= self.not_before && time <= self.not_after } /// Check the certificate time validity #[inline] pub fn is_valid(&self) -> bool { self.is_valid_at(ASN1Time::now()) } } impl<'a> FromDer<'a> for Validity { fn from_der(i: &[u8]) -> X509Result { parse_der_sequence_defined_g(|i, _| { let (i, not_before) = ASN1Time::from_der(i)?; let (i, not_after) = ASN1Time::from_der(i)?; let v = Validity { not_before, not_after, }; Ok((i, v)) })(i) } } #[derive(Clone, Debug, PartialEq)] pub struct UniqueIdentifier<'a>(pub BitStringObject<'a>); impl<'a> UniqueIdentifier<'a> { // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL fn from_der_issuer(i: &'a [u8]) -> X509Result> { Self::parse(i, 1).map_err(|_| X509Error::InvalidIssuerUID.into()) } // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL fn from_der_subject(i: &[u8]) -> X509Result> { Self::parse(i, 2).map_err(|_| X509Error::InvalidSubjectUID.into()) } // Parse a [tag] UniqueIdentifier OPTIONAL // // UniqueIdentifier ::= BIT STRING fn parse(i: &[u8], tag: u32) -> BerResult> { let (rem, obj) = parse_ber_optional(parse_der_tagged_implicit( tag, parse_der_content(DerTag::BitString), ))(i)?; let unique_id = match obj.content { DerObjectContent::Optional(None) => Ok(None), DerObjectContent::Optional(Some(o)) => match o.content { DerObjectContent::BitString(_, b) => Ok(Some(UniqueIdentifier(b.to_owned()))), _ => Err(BerError::BerTypeError), }, _ => Err(BerError::BerTypeError), }?; Ok((rem, unique_id)) } } #[cfg(test)] mod tests { use super::*; #[test] fn check_validity_expiration() { let mut v = Validity { not_before: ASN1Time::now(), not_after: ASN1Time::now(), }; assert_eq!(v.time_to_expiration(), None); v.not_after = (v.not_after + std::time::Duration::new(60, 0)).unwrap(); assert!(v.time_to_expiration().is_some()); assert!(v.time_to_expiration().unwrap() <= std::time::Duration::from_secs(60)); // The following assumes this timing won't take 10 seconds... I // think that is safe. assert!(v.time_to_expiration().unwrap() > std::time::Duration::from_secs(50)); } }