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
127impl CertificateRevocationList<'_> {
128    /// Run the provided [`CertificateRevocationListVisitor`] over the Certificate Revocation List (`self`)
129    pub fn walk<V: CertificateRevocationListVisitor>(&self, visitor: &mut V) {
130        visitor.visit_tbs_cert_list(&self.tbs_cert_list);
131        self.tbs_cert_list.walk(visitor);
132        visitor.visit_signature_algorithm(&self.signature_algorithm);
133        visitor.visit_signature_value(&self.signature_value);
134    }
135}
136
137impl TbsCertList<'_> {
138    /// Run the provided `visitor` over the [`TbsCertList`] object
139    pub fn walk<V: CertificateRevocationListVisitor>(&self, visitor: &mut V) {
140        visitor.visit_version(self.version.as_ref());
141        visitor.visit_tbs_signature_algorithm(&self.signature);
142        visitor.visit_issuer(&self.issuer);
143        visitor.visit_this_update(&self.this_update);
144        visitor.visit_next_update(self.next_update.as_ref());
145        visitor.visit_revoked_certificates(&self.revoked_certificates);
146        for certificate in &self.revoked_certificates {
147            visitor.visit_revoked_certificate(certificate);
148        }
149        visitor.pre_visit_extensions(self.extensions());
150        for extension in self.extensions() {
151            visitor.visit_extension(extension);
152
153            if extension.oid == OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER {
154                if let ParsedExtension::AuthorityKeyIdentifier(aki) = &extension.parsed_extension {
155                    visitor.visit_extension_aki(aki);
156                }
157            } else if extension.oid == OID_X509_EXT_ISSUER_ALT_NAME {
158                if let ParsedExtension::IssuerAlternativeName(ian) = &extension.parsed_extension {
159                    visitor.visit_extension_issuer_alternative_name(ian);
160                }
161            } else if extension.oid == OID_X509_EXT_CRL_NUMBER {
162                if let ParsedExtension::CRLNumber(number) = &extension.parsed_extension {
163                    visitor.visit_extension_crl_number(number);
164                }
165            } else if extension.oid == OID_X509_EXT_ISSUER_DISTRIBUTION_POINT {
166                if let ParsedExtension::IssuingDistributionPoint(dp) = &extension.parsed_extension {
167                    visitor.visit_extension_issuing_distribution_point(dp);
168                }
169            } else if extension.oid == OID_PKIX_AUTHORITY_INFO_ACCESS {
170                if let ParsedExtension::AuthorityInfoAccess(info) = &extension.parsed_extension {
171                    visitor.visit_extension_authority_information_access(info);
172                }
173            } else if extension.oid == OID_X509_EXT_REASON_CODE {
174                if let ParsedExtension::ReasonCode(code) = &extension.parsed_extension {
175                    visitor.visit_extension_reason_code(code);
176                }
177            } else if extension.oid == OID_X509_EXT_INVALIDITY_DATE {
178                if let ParsedExtension::InvalidityDate(time) = &extension.parsed_extension {
179                    visitor.visit_extension_invalidity_date(time);
180                }
181            } else if extension.oid == OID_CT_LIST_SCT {
182                if let ParsedExtension::SCT(sct) = &extension.parsed_extension {
183                    visitor.visit_extension_sct(sct);
184                }
185            }
186        }
187        visitor.post_visit_extensions(self.extensions());
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::*;
194    use crate::FromDer;
195
196    static CRL: &[u8] = include_bytes!("../../assets/example.crl");
197
198    #[test]
199    fn visitor_crl() {
200        #[derive(Debug, Default)]
201        struct RevokedCertsVisitor {
202            certificates: Vec<BigUint>,
203        }
204
205        impl CertificateRevocationListVisitor for RevokedCertsVisitor {
206            fn visit_revoked_certificate(&mut self, certificate: &RevokedCertificate) {
207                self.certificates.push(certificate.user_certificate.clone());
208            }
209        }
210
211        let mut visitor = RevokedCertsVisitor::default();
212        let (_, crl) = CertificateRevocationList::from_der(CRL).unwrap();
213
214        crl.walk(&mut visitor);
215        assert_eq!(visitor.certificates.len(), 5);
216    }
217}