wire_e2e_identity/acme/x509_check/
revocation.rs1#![allow(dead_code)]
2
3use certval::{
4 CertSource, CertVector, CertificationPath, CertificationPathResults, CertificationPathSettings, DeferDecodeSigned,
5 EXTS_OF_INTEREST, ExtensionProcessing, PDVTrustAnchorChoice, TaSource, check_revocation, get_validation_status,
6 populate_5280_pki_environment, set_check_crls, set_forbid_self_signed_ee, set_require_ta_store,
7 set_time_of_interest, validate_path_rfc5280,
8 validator::{PDVCertificate, path_validator::check_validity},
9 verify_signatures,
10};
11use const_oid::AssociatedOid;
12use crl_store::CrlStore;
13use x509_cert::{
14 der::{Decode, DecodePem, Encode},
15 ext::pkix::AuthorityKeyIdentifier,
16};
17
18use crate::acme::x509_check::{RustyX509CheckError, RustyX509CheckResult, revocation::cache::RevocationCache};
19
20mod cache;
21mod crl_info;
22mod crl_store;
23mod misc;
24
25#[derive(Default)]
26pub struct PkiEnvironmentParams<'a> {
27 pub intermediates: &'a [x509_cert::Certificate],
29 pub trust_roots: &'a [x509_cert::anchor::TrustAnchorChoice],
31 pub crls: &'a [x509_cert::crl::CertificateList],
33 pub time_of_interest: Option<u64>,
35}
36
37pub struct PkiEnvironment {
38 pe: certval::environment::PkiEnvironment,
39 toi: u64,
40}
41
42impl std::ops::Deref for PkiEnvironment {
43 type Target = certval::environment::PkiEnvironment;
44
45 fn deref(&self) -> &Self::Target {
46 &self.pe
47 }
48}
49
50impl std::ops::DerefMut for PkiEnvironment {
51 fn deref_mut(&mut self) -> &mut Self::Target {
52 &mut self.pe
53 }
54}
55
56impl std::fmt::Debug for PkiEnvironment {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 f.debug_struct("PkiEnvironment")
59 .field("pe", &"[OPAQUE]")
60 .field("toi", &self.toi)
61 .finish()
62 }
63}
64
65fn check_cpr(cpr: CertificationPathResults) -> RustyX509CheckResult<()> {
66 if let Some(validation_status) = get_validation_status(&cpr) {
67 match validation_status {
68 certval::PathValidationStatus::Valid => Ok(()),
69 certval::PathValidationStatus::RevocationStatusNotDetermined
71 | certval::PathValidationStatus::RevocationStatusNotAvailable => Ok(()),
72 validation_status => Err(RustyX509CheckError::CertValError(certval::Error::PathValidation(
73 validation_status,
74 ))),
75 }
76 } else {
77 Err(RustyX509CheckError::CannotDetermineVerificationStatus)
78 }
79}
80
81impl PkiEnvironment {
82 pub fn decode_pem_cert(pem: String) -> RustyX509CheckResult<x509_cert::Certificate> {
83 Ok(x509_cert::Certificate::from_pem(pem)?)
84 }
85
86 pub fn decode_der_crl(crl_der: Vec<u8>) -> RustyX509CheckResult<x509_cert::crl::CertificateList> {
87 Ok(x509_cert::crl::CertificateList::from_der(&crl_der)?)
88 }
89
90 pub fn extract_ski_aki_from_cert(cert: &x509_cert::Certificate) -> RustyX509CheckResult<(String, Option<String>)> {
91 let cert = PDVCertificate::try_from(cert.clone())?;
92
93 let ski = cert
94 .get_extension(&const_oid::db::rfc5912::ID_CE_SUBJECT_KEY_IDENTIFIER)?
95 .ok_or(RustyX509CheckError::MissingSki)?;
96 let ski = match ski {
97 certval::PDVExtension::SubjectKeyIdentifier(ski) => hex::encode(ski.0.as_bytes()),
98 _ => return Err(RustyX509CheckError::ImplementationError),
99 };
100
101 let aki = cert
102 .get_extension(&const_oid::db::rfc5912::ID_CE_AUTHORITY_KEY_IDENTIFIER)?
103 .and_then(|ext| match ext {
104 certval::PDVExtension::AuthorityKeyIdentifier(AuthorityKeyIdentifier { key_identifier, .. }) => {
105 key_identifier.as_ref()
106 }
107 _ => None,
108 })
109 .map(|ki| hex::encode(ki.as_bytes()));
110
111 Ok((ski, aki))
112 }
113
114 pub fn encode_cert_to_der(cert: &x509_cert::Certificate) -> RustyX509CheckResult<Vec<u8>> {
115 Ok(cert.to_der()?)
116 }
117
118 pub fn encode_crl_to_der(crl: &x509_cert::crl::CertificateList) -> RustyX509CheckResult<Vec<u8>> {
119 Ok(crl.to_der()?)
120 }
121
122 pub fn init(params: PkiEnvironmentParams) -> RustyX509CheckResult<PkiEnvironment> {
124 let toi = if let Some(toi) = params.time_of_interest {
125 toi
126 } else {
127 web_time::SystemTime::now()
128 .duration_since(web_time::SystemTime::UNIX_EPOCH)
129 .map_err(|_| RustyX509CheckError::CannotDetermineCurrentTime)?
130 .as_secs()
131 };
132
133 let mut cps = CertificationPathSettings::new();
134 set_time_of_interest(&mut cps, toi);
135
136 let mut cert_source = CertSource::new();
138 for (i, cert) in params.intermediates.iter().enumerate() {
139 cert_source.push(certval::CertFile {
140 filename: format!("Intermediate CA #{i} [{}]", cert.tbs_certificate.subject),
141 bytes: cert.to_der()?,
142 });
143 }
144
145 cert_source.initialize(&cps)?;
146
147 let mut trust_anchors = TaSource::new();
149 for (i, root) in params.trust_roots.iter().enumerate() {
150 trust_anchors.push(certval::CertFile {
151 filename: format!("TrustAnchor #{i}"),
152 bytes: root.to_der()?,
153 });
154 }
155
156 trust_anchors.initialize()?;
157
158 let revocation_cache = RevocationCache::default();
159
160 let crl_source = CrlStore::from(params.crls);
162 crl_source.index_crls(toi)?;
163
164 let mut pe = certval::environment::PkiEnvironment::default();
165 populate_5280_pki_environment(&mut pe);
166 pe.add_trust_anchor_source(Box::new(trust_anchors));
167 pe.add_crl_source(Box::new(crl_source));
168 pe.add_revocation_cache(Box::new(revocation_cache));
169
170 cert_source.find_all_partial_paths(&pe, &cps);
171
172 pe.add_certificate_source(Box::new(cert_source));
173
174 Ok(Self { pe, toi })
175 }
176
177 pub fn set_time_of_interest(&mut self, toi: u64) {
179 self.toi = toi;
180 }
181
182 pub fn refresh_time_of_interest(&mut self) -> RustyX509CheckResult<()> {
184 self.set_time_of_interest(
185 web_time::SystemTime::now()
186 .duration_since(web_time::SystemTime::UNIX_EPOCH)
187 .map_err(|_| RustyX509CheckError::CannotDetermineCurrentTime)?
188 .as_secs(),
189 );
190
191 Ok(())
192 }
193
194 pub fn validate_trust_anchor_cert(&self, cert: &x509_cert::Certificate) -> RustyX509CheckResult<()> {
195 let mut cps = CertificationPathSettings::default();
196 set_time_of_interest(&mut cps, self.toi);
197
198 let mut cert = PDVCertificate::try_from(cert.clone())?;
199 cert.parse_extensions(EXTS_OF_INTEREST);
200
201 let ta = PDVTrustAnchorChoice::try_from(x509_cert::anchor::TrustAnchorChoice::Certificate(
202 cert.decoded_cert.clone(),
203 ))?;
204 let mut certification_path = CertificationPath::new(ta, vec![], cert);
205
206 check_validity(
207 &self.pe,
208 &cps,
209 &mut certification_path,
210 &mut CertificationPathResults::new(),
211 )?;
212
213 verify_signatures(
214 &self.pe,
215 &cps,
216 &mut certification_path,
217 &mut CertificationPathResults::new(),
218 )?;
219
220 Ok(())
221 }
222
223 #[inline]
224 #[deprecated = "This method is not to be used as it causes spurious verification failures because of re-encoding the DER repr of the CRL. Use `validate_crl_with_raw`"]
225 pub fn validate_crl(&self, crl: &x509_cert::crl::CertificateList) -> RustyX509CheckResult<()> {
226 let _ = self.validate_crl_with_raw(&crl.to_der()?)?;
227 Ok(())
228 }
229
230 pub fn validate_crl_with_raw(&self, crl_raw: &[u8]) -> RustyX509CheckResult<x509_cert::crl::CertificateList> {
231 let crl = x509_cert::crl::CertificateList::from_der(crl_raw)?;
232
233 let mut spki_list = vec![];
234 if let Some(aki) = crl.tbs_cert_list.crl_extensions.as_ref().and_then(|extensions| {
235 extensions
236 .iter()
237 .find(|ext| ext.extn_id == x509_cert::ext::pkix::AuthorityKeyIdentifier::OID)
238 }) {
239 let akid = aki.extn_value.as_bytes();
240 if let Ok(ta) = self.pe.get_trust_anchor(akid) {
241 spki_list
242 .push(certval::source::ta_source::get_subject_public_key_info_from_trust_anchor(&ta.decoded_ta));
243 } else if let Ok(intermediates) = self.pe.get_intermediates_by_skid(akid) {
244 spki_list.extend(
245 intermediates
246 .into_iter()
247 .map(|c| &c.decoded_cert.tbs_certificate.subject_public_key_info),
248 );
249 }
250 }
251
252 if let Ok(ta) = self.pe.get_trust_anchor_by_name(&crl.tbs_cert_list.issuer) {
253 let spki = certval::source::ta_source::get_subject_public_key_info_from_trust_anchor(&ta.decoded_ta);
254 if !spki_list.contains(&spki) {
255 spki_list.push(spki);
256 }
257 }
258
259 spki_list.extend(
260 self.pe
261 .get_cert_by_name(&crl.tbs_cert_list.issuer)
262 .into_iter()
263 .map(|c| &c.decoded_cert.tbs_certificate.subject_public_key_info),
264 );
265
266 spki_list.dedup();
267
268 let crl_defer = DeferDecodeSigned::from_der(crl_raw)?;
269
270 let any_spki_verifies = spki_list.into_iter().any(|spki| {
271 self.pe
272 .verify_signature_message(
273 &self.pe,
274 &crl_defer.tbs_field,
275 crl.signature.raw_bytes(),
276 &crl.signature_algorithm,
277 spki,
278 )
279 .is_ok()
280 });
281
282 if any_spki_verifies {
283 Ok(crl)
284 } else {
285 Err(RustyX509CheckError::CertValError(certval::Error::PathValidation(
286 certval::PathValidationStatus::SignatureVerificationFailure,
287 )))
288 }
289 }
290
291 fn validate_cert_internal(
292 &self,
293 end_identity_cert: &x509_cert::Certificate,
294 perform_revocation_check: bool,
295 ) -> RustyX509CheckResult<()> {
296 let mut cps = CertificationPathSettings::default();
297 set_time_of_interest(&mut cps, self.toi);
298 set_require_ta_store(&mut cps, true);
299 set_forbid_self_signed_ee(&mut cps, true);
300
301 let mut end_identity_cert = PDVCertificate::try_from(end_identity_cert.clone())?;
302 end_identity_cert.parse_extensions(EXTS_OF_INTEREST);
303
304 let mut paths = vec![];
305 self.pe
306 .get_paths_for_target(&self.pe, &end_identity_cert, &mut paths, 0, self.toi)?;
307
308 if paths.is_empty() {
309 return Err(RustyX509CheckError::CertValError(certval::Error::PathValidation(
310 certval::PathValidationStatus::NoPathsFound,
311 )));
312 }
313
314 let mut result = Ok(());
315
316 let any_path_validates = paths.into_iter().any(|mut path| {
317 let mut cpr = CertificationPathResults::new();
318 let _ = validate_path_rfc5280(&self.pe, &cps, &mut path, &mut cpr);
319 let r = check_cpr(cpr);
320 if r.is_err() {
321 result = r;
322 return false;
323 }
324
325 if perform_revocation_check {
326 set_check_crls(&mut cps, true);
327 let mut cpr = CertificationPathResults::new();
328 let _ = check_revocation(&self.pe, &cps, &mut path, &mut cpr);
329 let r = check_cpr(cpr);
330 if r.is_err() {
331 result = r;
332 return false;
333 }
334 }
335
336 true
337 });
338
339 if any_path_validates { Ok(()) } else { result }
340 }
341
342 #[inline]
343 pub fn validate_cert(&self, end_identity_cert: &x509_cert::Certificate) -> RustyX509CheckResult<()> {
344 self.validate_cert_internal(end_identity_cert, false)
345 }
346
347 #[inline]
348 pub fn validate_cert_and_revocation(&self, end_identity_cert: &x509_cert::Certificate) -> RustyX509CheckResult<()> {
349 self.validate_cert_internal(end_identity_cert, true)
350 }
351}