wire_e2e_identity/acme/x509_check/
mod.rs1use certval::PathValidationStatus;
2
3pub mod reexports {
4 pub use certval;
5}
6
7use revocation::PkiEnvironment;
8
9pub mod revocation;
10
11#[derive(Debug, thiserror::Error)]
12pub enum RustyX509CheckError {
13 #[error(transparent)]
15 DerError(#[from] x509_cert::der::Error),
16 #[error("PEM en/decoding error: {0}")]
18 PemError(x509_cert::der::pem::Error),
19 #[error("A lock has been poisoned and cannot be recovered from.")]
21 LockPoisonError,
22 #[error("Cannot determine current UNIX epoch")]
24 CannotDetermineCurrentTime,
25 #[error("Certificate validation error: {0}")]
27 CertValError(certval::Error),
28 #[error("Something went wrong, we cannot determine if this certificate is OK. You might want to ignore this")]
30 CannotDetermineVerificationStatus,
31 #[error("Required 'Subject Key Identifier' extension is missing")]
33 MissingSki,
34 #[error("Implementation error")]
36 ImplementationError,
37}
38
39impl From<x509_cert::der::pem::Error> for RustyX509CheckError {
40 fn from(value: x509_cert::der::pem::Error) -> Self {
41 RustyX509CheckError::PemError(value)
42 }
43}
44
45impl From<certval::Error> for RustyX509CheckError {
46 fn from(value: certval::Error) -> Self {
47 RustyX509CheckError::CertValError(value)
48 }
49}
50
51pub type RustyX509CheckResult<T> = Result<T, RustyX509CheckError>;
52
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub enum IdentityStatus {
55 Valid,
57 Expired,
59 Revoked,
61}
62
63impl IdentityStatus {
64 pub fn from_cert(cert: &x509_cert::Certificate, env: Option<&PkiEnvironment>) -> Self {
65 match env.map(|e| e.validate_cert_and_revocation(cert)) {
66 Some(Err(RustyX509CheckError::CertValError(certval::Error::PathValidation(e)))) => match e {
67 PathValidationStatus::InvalidNotAfterDate => IdentityStatus::Expired,
68 PathValidationStatus::CertificateRevoked
69 | PathValidationStatus::CertificateRevokedEndEntity
70 | PathValidationStatus::NoPathsFound
71 | PathValidationStatus::CertificateRevokedIntermediateCa => IdentityStatus::Revoked,
72 _ => IdentityStatus::Valid,
73 },
74 _ => IdentityStatus::Valid,
75 }
76 }
77}
78
79pub fn extract_crl_uris(
81 cert: &x509_cert::Certificate,
82) -> RustyX509CheckResult<Option<std::collections::HashSet<String>>> {
83 use certval::validator::{PDVCertificate, PDVExtension};
84 use x509_cert::ext::pkix::name::{DistributionPointName, GeneralName};
85
86 Ok(PDVCertificate::try_from(cert.clone())?
87 .parsed_extensions
88 .get(&const_oid::db::rfc5280::ID_CE_CRL_DISTRIBUTION_POINTS)
89 .and_then(|ext| {
90 let PDVExtension::CrlDistributionPoints(crl_distribution_points) = ext else {
91 return None;
92 };
93
94 Some(crl_distribution_points.0.iter().fold(
95 Default::default(),
96 |mut set: std::collections::HashSet<String>, dp| {
97 if let Some(DistributionPointName::FullName(dp_full_names)) = dp.distribution_point.as_ref() {
98 for gn in dp_full_names.iter() {
99 if let GeneralName::UniformResourceIdentifier(uri) = gn {
100 set.insert(uri.to_string());
101 }
102 }
103 }
104
105 set
106 },
107 ))
108 }))
109}
110
111pub fn extract_expiration_from_crl(crl: &x509_cert::crl::CertificateList) -> Option<u64> {
113 crl.tbs_cert_list.next_update.map(|t| t.to_unix_duration().as_secs())
114}