blob: cf719489c3da7cd098945e75718c3f717aa1261b [file] [log] [blame] [edit]
//! Certificate types
use crate::{name::Name, time::Validity};
use alloc::vec::Vec;
use core::cmp::Ordering;
use const_oid::AssociatedOid;
use der::asn1::{BitStringRef, UIntRef};
use der::{Decode, Enumerated, Error, ErrorKind, Sequence, ValueOrd};
use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
#[cfg(feature = "pem")]
use der::pem::PemLabel;
/// Certificate `Version` as defined in [RFC 5280 Section 4.1].
///
/// ```text
/// Version ::= INTEGER { v1(0), v2(1), v3(2) }
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
#[asn1(type = "INTEGER")]
#[repr(u8)]
pub enum Version {
/// Version 1 (default)
V1 = 0,
/// Version 2
V2 = 1,
/// Version 3
V3 = 2,
}
impl ValueOrd for Version {
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
(&(*self as u8)).value_cmp(&(*other as u8))
}
}
impl Default for Version {
fn default() -> Self {
Self::V1
}
}
/// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1]
///
/// ASN.1 structure containing the names of the subject and issuer, a public
/// key associated with the subject, a validity period, and other associated
/// information.
///
/// ```text
/// 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] Extensions OPTIONAL
/// -- If present, version MUST be v3 --
/// }
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct TbsCertificate<'a> {
/// The certificate version
///
/// Note that this value defaults to Version 1 per the RFC. However,
/// fields such as `issuer_unique_id`, `subject_unique_id` and `extensions`
/// require later versions. Care should be taken in order to ensure
/// standards compliance.
#[asn1(context_specific = "0", default = "Default::default")]
pub version: Version,
pub serial_number: UIntRef<'a>,
pub signature: AlgorithmIdentifier<'a>,
pub issuer: Name<'a>,
pub validity: Validity,
pub subject: Name<'a>,
pub subject_public_key_info: SubjectPublicKeyInfo<'a>,
#[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
pub issuer_unique_id: Option<BitStringRef<'a>>,
#[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
pub subject_unique_id: Option<BitStringRef<'a>>,
#[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")]
pub extensions: Option<crate::ext::Extensions<'a>>,
}
impl<'a> TbsCertificate<'a> {
/// Decodes a single extension
///
/// Returns an error if multiple of these extensions is present. Returns
/// `Ok(None)` if the extension is not present. Returns a decoding error
/// if decoding failed. Otherwise returns the extension.
pub fn get<'b: 'a, T: Decode<'a> + AssociatedOid>(
&'b self,
) -> Result<Option<(bool, T)>, Error> {
let mut iter = self.filter::<T>().peekable();
match iter.next() {
None => Ok(None),
Some(item) => match iter.peek() {
Some(..) => Err(ErrorKind::Failed.into()),
None => Ok(Some(item?)),
},
}
}
/// Filters extensions by an associated OID
///
/// Returns a filtered iterator over all the extensions with the OID.
pub fn filter<'b: 'a, T: Decode<'a> + AssociatedOid>(
&'b self,
) -> impl 'b + Iterator<Item = Result<(bool, T), Error>> {
self.extensions
.as_deref()
.unwrap_or(&[])
.iter()
.filter(|e| e.extn_id == T::OID)
.map(|e| Ok((e.critical, T::from_der(e.extn_value)?)))
}
}
/// X.509 certificates are defined in [RFC 5280 Section 4.1].
///
/// ```text
/// Certificate ::= SEQUENCE {
/// tbsCertificate TBSCertificate,
/// signatureAlgorithm AlgorithmIdentifier,
/// signature BIT STRING
/// }
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct Certificate<'a> {
pub tbs_certificate: TbsCertificate<'a>,
pub signature_algorithm: AlgorithmIdentifier<'a>,
pub signature: BitStringRef<'a>,
}
#[cfg(feature = "pem")]
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
impl PemLabel for Certificate<'_> {
const PEM_LABEL: &'static str = "CERTIFICATE";
}
/// `PkiPath` as defined by X.509 and referenced by [RFC 6066].
///
/// This contains a series of certificates in validation order from the
/// top-most certificate to the bottom-most certificate. This means that
/// the first certificate signs the second certificate and so on.
///
/// ```text
/// PkiPath ::= SEQUENCE OF Certificate
/// ```
///
/// [RFC 6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-10.1
pub type PkiPath<'a> = Vec<Certificate<'a>>;