use crate::error::{X509Error, X509Result};
use crate::extensions::*;
use crate::time::ASN1Time;
use crate::utils::format_serial;
#[cfg(feature = "validate")]
use crate::validate::*;
use crate::x509::{
parse_serial, parse_signature_value, AlgorithmIdentifier, SubjectPublicKeyInfo, X509Name,
X509Version,
};
#[cfg(any(feature = "verify", feature = "verify-aws"))]
use crate::verify::verify_signature;
use asn1_rs::{BitString, FromDer, OptTaggedImplicit};
use core::ops::Deref;
use der_parser::der::*;
use der_parser::error::*;
use der_parser::num_bigint::BigUint;
use der_parser::*;
use nom::{Offset, Parser};
use oid_registry::*;
use std::collections::HashMap;
use time::Duration;
#[derive(Clone, Debug, PartialEq)]
pub struct X509Certificate<'a> {
pub tbs_certificate: TbsCertificate<'a>,
pub signature_algorithm: AlgorithmIdentifier<'a>,
pub signature_value: BitString<'a>,
pub(crate) raw: &'a [u8],
}
impl<'a> X509Certificate<'a> {
pub fn as_raw(&self) -> &'a [u8] {
self.raw
}
#[cfg(any(feature = "verify", feature = "verify-aws"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))]
pub fn verify_signature(
&self,
public_key: Option<&SubjectPublicKeyInfo>,
) -> Result<(), X509Error> {
let spki = public_key.unwrap_or_else(|| self.public_key());
verify_signature(
spki,
&self.signature_algorithm,
&self.signature_value,
self.tbs_certificate.raw,
)
}
}
impl<'a> AsRef<[u8]> for X509Certificate<'a> {
fn as_ref(&self) -> &[u8] {
self.as_raw()
}
}
impl<'a> Deref for X509Certificate<'a> {
type Target = TbsCertificate<'a>;
fn deref(&self) -> &Self::Target {
&self.tbs_certificate
}
}
impl<'a> FromDer<'a, X509Error> for X509Certificate<'a> {
fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
X509CertificateParser::new().parse(i)
}
}
#[derive(Clone, Copy, Debug)]
pub struct X509CertificateParser {
deep_parse_extensions: 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 Default for X509CertificateParser {
fn default() -> Self {
X509CertificateParser::new()
}
}
impl<'a> Parser<&'a [u8], X509Certificate<'a>, X509Error> for X509CertificateParser {
fn parse(&mut self, input: &'a [u8]) -> IResult<&'a [u8], X509Certificate<'a>, X509Error> {
let start_i = input;
let (rem, mut cert) = parse_der_sequence_defined_g(|i, _| {
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,
raw: &[],
};
Ok((i, cert))
})(input)?;
let len = start_i.offset(rem);
cert.raw = &start_i[..len];
Ok((rem, cert))
}
}
#[allow(deprecated)]
#[cfg(feature = "validate")]
#[cfg_attr(docsrs, doc(cfg(feature = "validate")))]
impl Validate for X509Certificate<'_> {
fn validate<W, E>(&self, warn: W, err: E) -> bool
where
W: FnMut(&str),
E: FnMut(&str),
{
X509StructureValidator.validate(self, &mut CallbackLogger::new(warn, err))
}
}
#[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<UniqueIdentifier<'a>>,
pub subject_uid: Option<UniqueIdentifier<'a>>,
extensions: Vec<X509Extension<'a>>,
pub(crate) raw: &'a [u8],
pub(crate) raw_serial: &'a [u8],
}
impl<'a> TbsCertificate<'a> {
pub fn version(&self) -> X509Version {
self.version
}
#[inline]
pub fn subject(&self) -> &X509Name<'_> {
&self.subject
}
#[inline]
pub fn issuer(&self) -> &X509Name<'_> {
&self.issuer
}
#[inline]
pub fn validity(&self) -> &Validity {
&self.validity
}
#[inline]
pub fn public_key(&self) -> &SubjectPublicKeyInfo<'_> {
&self.subject_pki
}
#[inline]
pub fn extensions(&self) -> &[X509Extension<'a>] {
&self.extensions
}
#[inline]
pub fn iter_extensions(&self) -> impl Iterator<Item = &X509Extension<'a>> {
self.extensions.iter()
}
#[inline]
pub fn get_extension_unique(&self, oid: &Oid) -> Result<Option<&X509Extension<'a>>, X509Error> {
get_extension_unique(&self.extensions, oid)
}
#[deprecated(
since = "0.13.0",
note = "Do not use this function (duplicate extensions are not checked), use `get_extension_unique`"
)]
pub fn find_extension(&self, oid: &Oid) -> Option<&X509Extension<'a>> {
self.extensions.iter().find(|&ext| ext.oid == *oid)
}
pub fn extensions_map(&self) -> Result<HashMap<Oid<'_>, &X509Extension<'a>>, 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,
) -> Result<Option<BasicExtension<&BasicConstraints>>, X509Error> {
let r = self
.get_extension_unique(&OID_X509_EXT_BASIC_CONSTRAINTS)?
.and_then(|ext| match ext.parsed_extension {
ParsedExtension::BasicConstraints(ref bc) => {
Some(BasicExtension::new(ext.critical, bc))
}
_ => None,
});
Ok(r)
}
pub fn key_usage(&self) -> Result<Option<BasicExtension<&KeyUsage>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_KEY_USAGE)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::KeyUsage(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn extended_key_usage(
&self,
) -> Result<Option<BasicExtension<&ExtendedKeyUsage<'_>>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_EXTENDED_KEY_USAGE)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::ExtendedKeyUsage(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn policy_constraints(
&self,
) -> Result<Option<BasicExtension<&PolicyConstraints>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_POLICY_CONSTRAINTS)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::PolicyConstraints(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn inhibit_anypolicy(
&self,
) -> Result<Option<BasicExtension<&InhibitAnyPolicy>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_INHIBIT_ANY_POLICY)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::InhibitAnyPolicy(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn policy_mappings(
&self,
) -> Result<Option<BasicExtension<&PolicyMappings<'_>>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_POLICY_MAPPINGS)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::PolicyMappings(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn subject_alternative_name(
&self,
) -> Result<Option<BasicExtension<&SubjectAlternativeName<'a>>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_SUBJECT_ALT_NAME)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::SubjectAlternativeName(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn name_constraints(
&self,
) -> Result<Option<BasicExtension<&NameConstraints<'_>>>, X509Error> {
self.get_extension_unique(&OID_X509_EXT_NAME_CONSTRAINTS)?
.map_or(Ok(None), |ext| match ext.parsed_extension {
ParsedExtension::NameConstraints(ref value) => {
Ok(Some(BasicExtension::new(ext.critical, value)))
}
_ => Err(X509Error::InvalidExtensions),
})
}
pub fn is_ca(&self) -> bool {
self.basic_constraints()
.unwrap_or(None)
.map(|ext| ext.value.ca)
.unwrap_or(false)
}
pub fn raw_serial(&self) -> &'a [u8] {
self.raw_serial
}
pub fn raw_serial_as_string(&self) -> String {
format_serial(self.raw_serial)
}
}
fn get_extension_unique<'a, 'b>(
extensions: &'a [X509Extension<'b>],
oid: &Oid,
) -> Result<Option<&'a X509Extension<'b>>, X509Error> {
let mut res = None;
for ext in extensions {
if ext.oid == *oid {
if res.is_some() {
return Err(X509Error::DuplicateExtensions);
}
res = Some(ext);
}
}
Ok(res)
}
impl AsRef<[u8]> for TbsCertificate<'_> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.raw
}
}
impl<'a> FromDer<'a, X509Error> for TbsCertificate<'a> {
fn from_der(i: &'a [u8]) -> X509Result<'a, TbsCertificate<'a>> {
let start_i = i;
parse_der_sequence_defined_g(move |i, _| {
let (i, version) = X509Version::from_der_tagged_0(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, Tag(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)
}
}
#[derive(Clone, Copy, Debug)]
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 Default for TbsCertificateParser {
fn default() -> Self {
TbsCertificateParser::new()
}
}
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_tagged_0(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, Tag(3))?
} else {
parse_extensions_envelope(i, Tag(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)
}
}
#[allow(deprecated)]
#[cfg(feature = "validate")]
#[cfg_attr(docsrs, doc(cfg(feature = "validate")))]
impl Validate for TbsCertificate<'_> {
fn validate<W, E>(&self, warn: W, err: E) -> bool
where
W: FnMut(&str),
E: FnMut(&str),
{
TbsCertificateStructureValidator.validate(self, &mut CallbackLogger::new(warn, err))
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct BasicExtension<T> {
pub critical: bool,
pub value: T,
}
impl<T> BasicExtension<T> {
pub const fn new(critical: bool, value: T) -> Self {
Self { critical, value }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Validity {
pub not_before: ASN1Time,
pub not_after: ASN1Time,
}
impl Validity {
pub fn time_to_expiration(&self) -> Option<Duration> {
let now = ASN1Time::now();
if !self.is_valid_at(now) {
return None;
}
self.not_after - now
}
#[inline]
pub fn is_valid_at(&self, time: ASN1Time) -> bool {
time >= self.not_before && time <= self.not_after
}
#[inline]
pub fn is_valid(&self) -> bool {
self.is_valid_at(ASN1Time::now())
}
}
impl FromDer<'_, X509Error> for Validity {
fn from_der(i: &[u8]) -> X509Result<'_, Self> {
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, Eq)]
pub struct UniqueIdentifier<'a>(pub BitString<'a>);
impl<'a> UniqueIdentifier<'a> {
fn from_der_issuer(i: &'a [u8]) -> X509Result<'a, Option<Self>> {
Self::parse::<1>(i).map_err(|_| X509Error::InvalidIssuerUID.into())
}
fn from_der_subject(i: &[u8]) -> X509Result<'_, Option<UniqueIdentifier<'_>>> {
Self::parse::<2>(i).map_err(|_| X509Error::InvalidSubjectUID.into())
}
fn parse<const TAG: u32>(i: &[u8]) -> BerResult<'_, Option<UniqueIdentifier<'_>>> {
let (rem, unique_id) = OptTaggedImplicit::<BitString, Error, TAG>::from_der(i)?;
let unique_id = unique_id.map(|u| UniqueIdentifier(u.into_inner()));
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 + Duration::new(60, 0)).unwrap();
assert!(v.time_to_expiration().is_some());
assert!(v.time_to_expiration().unwrap() <= Duration::new(60, 0));
assert!(v.time_to_expiration().unwrap() > Duration::new(50, 0));
}
#[test]
fn extension_duplication() {
let extensions = vec![
X509Extension::new(oid! {1.2}, true, &[], ParsedExtension::Unparsed),
X509Extension::new(oid! {1.3}, true, &[], ParsedExtension::Unparsed),
X509Extension::new(oid! {1.2}, true, &[], ParsedExtension::Unparsed),
X509Extension::new(oid! {1.4}, true, &[], ParsedExtension::Unparsed),
X509Extension::new(oid! {1.4}, true, &[], ParsedExtension::Unparsed),
];
let r2 = get_extension_unique(&extensions, &oid! {1.2});
assert!(r2.is_err());
let r3 = get_extension_unique(&extensions, &oid! {1.3});
assert!(r3.is_ok());
let r4 = get_extension_unique(&extensions, &oid! {1.4});
assert!(r4.is_err());
}
}