wire_e2e_identity/x509_check/
mod.rs1use certval::{ExtensionProcessing as _, PathValidationStatus};
2
3pub mod reexports {
4 pub use certval;
5}
6
7use crate::pki_env::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, Copy, PartialEq, Eq)]
54pub enum IdentityStatus {
55 Valid,
57 Expired,
59 Revoked,
61}
62
63impl IdentityStatus {
64 pub async fn from_cert(cert: &x509_cert::Certificate, env: &PkiEnvironment) -> Self {
65 match env.validate_cert(cert).await {
66 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 .get_extension(&const_oid::db::rfc5280::ID_CE_CRL_DISTRIBUTION_POINTS)?
88 .and_then(|ext| {
89 let PDVExtension::CrlDistributionPoints(crl_distribution_points) = ext else {
90 return None;
91 };
92
93 Some(crl_distribution_points.0.iter().fold(
94 Default::default(),
95 |mut set: std::collections::HashSet<String>, dp| {
96 if let Some(DistributionPointName::FullName(dp_full_names)) = dp.distribution_point.as_ref() {
97 for gn in dp_full_names.iter() {
98 if let GeneralName::UniformResourceIdentifier(uri) = gn {
99 set.insert(uri.to_string());
100 }
101 }
102 }
103
104 set
105 },
106 ))
107 }))
108}
109
110pub fn extract_expiration_from_crl(crl: &x509_cert::crl::CertificateList) -> Option<u64> {
112 crl.tbs_cert_list.next_update.map(|t| t.to_unix_duration().as_secs())
113}