x509_parser/visitor/crl_visitor.rs
1use asn1_rs::BitString;
2use der_parser::num_bigint::BigUint;
3use oid_registry::*;
4
5use crate::extensions::*;
6use crate::revocation_list::*;
7use crate::time::ASN1Time;
8use crate::x509::*;
9
10/// Visitor pattern for [`CertificateRevocationList`]
11///
12/// # Extensions
13///
14/// Visitor methods are provided for extensions, both in a generic way (receiving a [`X509Extension`]
15/// object) and in a specific way for standard extensions (for ex, `visit_extension_aki` receives a
16/// [`AuthorityKeyIdentifier`]).
17///
18/// For a specific method to be called, the extension OID must be correct and the extension must be
19/// successfully parsed as the specific type.
20///
21/// A specific method can be called multiple times, if the extension is present multiple times.
22///
23/// Extension parsing methods are redundant. This is not a problem because default methods do nothing,
24/// but if a trait implementation provides several `visit_extension...` methods it must be aware
25/// that it will visit the same extension multiple times.
26///
27/// # Example
28///
29/// ```rust
30/// use der_parser::num_bigint::BigUint;
31/// use x509_parser::prelude::*;
32/// use x509_parser::visitor::CertificateRevocationListVisitor;
33/// #[derive(Debug, Default)]
34/// struct RevokedCertsVisitor {
35/// certificates: Vec<BigUint>,
36/// }
37///
38/// impl CertificateRevocationListVisitor for RevokedCertsVisitor {
39/// fn visit_revoked_certificate(&mut self, certificate: &RevokedCertificate<'_>) {
40/// self.certificates.push(certificate.user_certificate.clone());
41/// }
42/// }
43/// ```
44pub trait CertificateRevocationListVisitor {
45 /// Run the provided visitor (`self`) over the Certificate Revocation List
46 fn walk(&mut self, crl: &CertificateRevocationList)
47 where
48 Self: Sized,
49 {
50 crl.walk(self);
51 }
52
53 /// Invoked for the "tbsCertList" field of the Certificate Revocation List, before visiting children
54 fn visit_tbs_cert_list(&mut self, _tbs: &TbsCertList) {}
55
56 /// Invoked for the "signatureAlgorithm" field of the Certificate Revocation List
57 ///
58 /// Note: this is the "signatureAlgorithm" in the "CertificateList" sequence. According to the
59 /// specifications, it should be equal to "signature" field from the "TBSCertificate" sequence.
60 fn visit_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
61
62 /// Invoked for the "signatureValue" field of the TBSCertList
63 fn visit_signature_value(&mut self, _signature: &BitString) {}
64
65 /// Invoked for the "version" field of the TBSCertList
66 fn visit_version(&mut self, _version: Option<&X509Version>) {}
67
68 /// Invoked for the "signature" field of the TBSCertList
69 ///
70 /// Note: this is the "signature" field from the "TBSCertList" sequence. According to the
71 /// specifications, it should be equal to "signatureAlgorithm" in the "CertificateList" sequence.
72 fn visit_tbs_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
73
74 /// Invoked for the "issuer" field of the TBSCertList
75 fn visit_issuer(&mut self, _name: &X509Name) {}
76
77 /// Invoked for the "thisUpdate" field of the TBSCertList
78 fn visit_this_update(&mut self, _time: &ASN1Time) {}
79
80 /// Invoked for the "nextUpdate" field of the TBSCertList
81 fn visit_next_update(&mut self, _time: Option<&ASN1Time>) {}
82
83 /// Invoked for revoked certificate that appear in the TBSCertList
84 fn visit_revoked_certificates(&mut self, _certificate: &[RevokedCertificate]) {}
85
86 /// Invoked for any revoked certificates that appear in the TBSCertList
87 ///
88 /// Note: this function is redundant with `visit_revoked_certificates`
89 fn visit_revoked_certificate(&mut self, _certificate: &RevokedCertificate) {}
90
91 /// Invoked for extensions, before visiting children
92 fn pre_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
93
94 /// Invoked for any extension that appear in the TBSCertList
95 ///
96 /// Note: this method may be redundant with any other extension visitor method
97 fn visit_extension(&mut self, _extension: &X509Extension) {}
98
99 /// Invoked for extensions, after visiting children
100 fn post_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
101
102 /// Invoked for the "Authority Key Identifier" (if present)
103 fn visit_extension_aki(&mut self, _aki: &AuthorityKeyIdentifier) {}
104
105 /// Invoked for the "Issuer Alternative Name" (if present)
106 fn visit_extension_issuer_alternative_name(&mut self, _ian: &IssuerAlternativeName) {}
107
108 /// Invoked for the "CRL Number" (if present)
109 fn visit_extension_crl_number(&mut self, _number: &BigUint) {}
110
111 /// Invoked for the "Issuing Distribution Point" (if present)
112 fn visit_extension_issuing_distribution_point(&mut self, _dp: &IssuingDistributionPoint) {}
113
114 /// Invoked for the "Authority Information Access" (if present)
115 fn visit_extension_authority_information_access(&mut self, _info: &AuthorityInfoAccess) {}
116
117 /// Invoked for the "Reason Code" (if present)
118 fn visit_extension_reason_code(&mut self, _code: &ReasonCode) {}
119
120 /// Invoked for the "Invalidity Date" (if present)
121 fn visit_extension_invalidity_date(&mut self, _time: &ASN1Time) {}
122
123 /// Invoked for the "Signed Certificate Timestamp" (SCT) (if present)
124 fn visit_extension_sct(&mut self, _sct: &[SignedCertificateTimestamp]) {}
125
126 /// Invoked for any other extension than the specific (recognized) types
127 ///
128 /// This can happen for several reasons:
129 /// - the parser did not recognize the extension content
130 /// - the parser was explicitly asked to not parse extension content
131 /// - the extension could be correct (for ex in a CRL), but is not supposed to be part of a Certificate
132 fn visit_extension_unknown(&mut self, _ext: &X509Extension) {}
133
134 /// Invoked for any extension than caused a parse error
135 ///
136 /// Normally, this should not match anything except for invalid data.
137 /// This could match any known extension malformed or wrongly encoded.
138 fn visit_extension_parse_error(
139 &mut self,
140 _extension: &X509Extension,
141 _error: &asn1_rs::Err<asn1_rs::Error>,
142 ) {
143 }
144}
145
146impl CertificateRevocationList<'_> {
147 /// Run the provided [`CertificateRevocationListVisitor`] over the Certificate Revocation List (`self`)
148 pub fn walk<V: CertificateRevocationListVisitor>(&self, visitor: &mut V) {
149 visitor.visit_tbs_cert_list(&self.tbs_cert_list);
150 self.tbs_cert_list.walk(visitor);
151 visitor.visit_signature_algorithm(&self.signature_algorithm);
152 visitor.visit_signature_value(&self.signature_value);
153 }
154}
155
156impl TbsCertList<'_> {
157 /// Run the provided `visitor` over the [`TbsCertList`] object
158 pub fn walk<V: CertificateRevocationListVisitor>(&self, visitor: &mut V) {
159 // shorten name to reduce line length
160 let v = visitor;
161 v.visit_version(self.version.as_ref());
162 v.visit_tbs_signature_algorithm(&self.signature);
163 v.visit_issuer(&self.issuer);
164 v.visit_this_update(&self.this_update);
165 v.visit_next_update(self.next_update.as_ref());
166 v.visit_revoked_certificates(&self.revoked_certificates);
167 for certificate in &self.revoked_certificates {
168 v.visit_revoked_certificate(certificate);
169 }
170 v.pre_visit_extensions(self.extensions());
171 for extension in self.extensions() {
172 v.visit_extension(extension);
173
174 match extension.parsed_extension() {
175 ParsedExtension::AuthorityInfoAccess(info) => {
176 v.visit_extension_authority_information_access(info)
177 }
178 ParsedExtension::AuthorityKeyIdentifier(aki) => v.visit_extension_aki(aki),
179 ParsedExtension::CRLNumber(number) => v.visit_extension_crl_number(number),
180 ParsedExtension::InvalidityDate(time) => v.visit_extension_invalidity_date(time),
181 ParsedExtension::IssuerAlternativeName(ian) => {
182 v.visit_extension_issuer_alternative_name(ian)
183 }
184 ParsedExtension::IssuingDistributionPoint(dp) => {
185 v.visit_extension_issuing_distribution_point(dp)
186 }
187 ParsedExtension::ReasonCode(code) => v.visit_extension_reason_code(code),
188 ParsedExtension::SCT(sct) => v.visit_extension_sct(sct),
189 ParsedExtension::ParseError { error } => {
190 v.visit_extension_parse_error(extension, error)
191 }
192 _ => v.visit_extension_unknown(extension),
193 }
194 }
195 v.post_visit_extensions(self.extensions());
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::FromDer;
203
204 static CRL: &[u8] = include_bytes!("../../assets/example.crl");
205
206 #[test]
207 fn visitor_crl() {
208 #[derive(Debug, Default)]
209 struct RevokedCertsVisitor {
210 certificates: Vec<BigUint>,
211 }
212
213 impl CertificateRevocationListVisitor for RevokedCertsVisitor {
214 fn visit_revoked_certificate(&mut self, certificate: &RevokedCertificate) {
215 self.certificates.push(certificate.user_certificate.clone());
216 }
217 }
218
219 let mut visitor = RevokedCertsVisitor::default();
220 let (_, crl) = CertificateRevocationList::from_der(CRL).unwrap();
221
222 crl.walk(&mut visitor);
223 assert_eq!(visitor.certificates.len(), 5);
224 }
225}