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}