x509_parser/visitor/
certificate_visitor.rs

1use asn1_rs::BitString;
2use oid_registry::*;
3
4use crate::certificate::*;
5use crate::extensions::*;
6use crate::x509::*;
7
8/// Visitor pattern for [`X509Certificate`]
9///
10/// # Extensions
11///
12/// Visitor methods are provided for extensions, both in a generic way (receiving a [`X509Extension`]
13/// object) and in a specific way for standard extensions (for ex, `visit_extension_aki` receives a
14/// [`AuthorityKeyIdentifier`]).
15///
16/// For a specific method to be called, the extension OID must be correct and the extension must be
17/// successfully parsed as the specific type.
18///
19/// A specific method can be called multiple times, if the extension is present multiple times.
20///
21/// Extension parsing methods are redundant. This is not a problem because default methods do nothing,
22/// but if a trait implementation provides several `visit_extension...` methods it must be aware
23/// that it will visit the same extension multiple times.
24///
25/// # Example
26///
27/// ```rust
28/// use x509_parser::prelude::*;
29/// use x509_parser::visitor::X509CertificateVisitor;
30/// #[derive(Debug, Default)]
31/// struct SubjectIssuerVisitor {
32///     issuer: String,
33///     subject: String,
34///     is_ca: bool,
35/// }
36///
37/// impl X509CertificateVisitor for SubjectIssuerVisitor {
38///     fn visit_issuer(&mut self, name: &X509Name<'_>) {
39///         self.issuer = name.to_string();
40///     }
41///
42///     fn visit_subject(&mut self, name: &X509Name<'_>) {
43///         self.subject = name.to_string();
44///     }
45///
46///     fn visit_extension_basic_constraints(&mut self, bc: &BasicConstraints) {
47///         self.is_ca = bc.ca;
48///     }
49/// }
50/// ```
51pub trait X509CertificateVisitor {
52    /// Run the provided visitor (`self`) over the [`X509Certificate`] object
53    fn walk(&mut self, x509: &X509Certificate)
54    where
55        Self: Sized,
56    {
57        x509.walk(self);
58    }
59
60    /// Invoked for the "TBSCertificate" field of the X.509 Certificate, before visiting children
61    fn visit_tbs_certificate(&mut self, _tbs: &TbsCertificate) {}
62
63    /// Invoked for the "signatureAlgorithm" field of the X.509 Certificate
64    ///
65    /// Note: this is the "signatureAlgorithm" in the "Certificate" sequence. According to the
66    /// specifications, it should be equal to "signature" field from the "TBSCertificate" sequence.
67    fn visit_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
68
69    /// Invoked for the "signatureValue" field of the TBSCertificate
70    fn visit_signature_value(&mut self, _signature: &BitString) {}
71
72    /// Invoked for the "version" field of the TBSCertificate
73    fn visit_version(&mut self, _version: &X509Version) {}
74
75    /// Invoked for the "serialNumber" field of the TBSCertificate
76    fn visit_serial_number(&mut self, _serial: &[u8]) {}
77
78    /// Invoked for the "signature" field of the TBSCertificate
79    ///
80    /// Note: this is the "signature" field from the "TBSCertificate" sequence. According to the
81    /// specifications, it should be equal to "signatureAlgorithm" in the "Certificate" sequence.
82    fn visit_tbs_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
83
84    /// Invoked for the "issuer" field of the TBSCertificate
85    fn visit_issuer(&mut self, _name: &X509Name) {}
86
87    /// Invoked for the "validity" field of the TBSCertificate
88    fn visit_validity(&mut self, _validity: &Validity) {}
89
90    /// Invoked for the "subject" field of the TBSCertificate
91    fn visit_subject(&mut self, _name: &X509Name) {}
92
93    /// Invoked for the "subjectPublicKeyInfo" field of the TBSCertificate
94    fn visit_subject_public_key_info(&mut self, _subject_pki: &SubjectPublicKeyInfo) {}
95
96    /// Invoked for the "issuerUniqueID" field of the TBSCertificate
97    fn visit_issuer_unique_id(&mut self, _id: Option<&UniqueIdentifier>) {}
98
99    /// Invoked for the "subjectUniqueID" field of the TBSCertificate
100    fn visit_subject_unique_id(&mut self, _id: Option<&UniqueIdentifier>) {}
101
102    /// Invoked for extensions, before visiting children
103    fn pre_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
104
105    /// Invoked for any extension that appear in the X.509 Certificate
106    ///
107    /// Note: this method may be redundant with any other extension visitor method
108    fn visit_extension(&mut self, _extension: &X509Extension) {}
109
110    /// Invoked for extensions, after visiting children
111    fn post_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
112
113    /// Invoked for the "Authority Key Identifier" (if present)
114    fn visit_extension_aki(&mut self, _aki: &AuthorityKeyIdentifier) {}
115
116    /// Invoked for the "Subject Key Identifier" (if present)
117    fn visit_extension_ski(&mut self, _id: &KeyIdentifier) {}
118
119    /// Invoked for the "Key Usage" (if present)
120    fn visit_extension_key_usage(&mut self, _usage: &KeyUsage) {}
121
122    /// Invoked for the "Certificate Policies" (if present)
123    fn visit_extension_certificate_policies(&mut self, _policies: &CertificatePolicies) {}
124
125    /// Invoked for the "Subject Alternative Name" (if present)
126    fn visit_extension_subject_alternative_name(&mut self, _san: &SubjectAlternativeName) {}
127
128    /// Invoked for the "Issuer Alternative Name" (if present)
129    fn visit_extension_issuer_alternative_name(&mut self, _ian: &IssuerAlternativeName) {}
130
131    /// Invoked for the "Basic Constraints" (if present)
132    fn visit_extension_basic_constraints(&mut self, _bc: &BasicConstraints) {}
133
134    /// Invoked for the "Name Constraints" (if present)
135    fn visit_extension_name_constraints(&mut self, _constraints: &NameConstraints) {}
136
137    /// Invoked for the "Policy Constraints" (if present)
138    fn visit_extension_policy_constraints(&mut self, _constraints: &PolicyConstraints) {}
139
140    /// Invoked for the "Extended Key Usage" (if present)
141    fn visit_extension_extended_key_usage(&mut self, _usage: &ExtendedKeyUsage) {}
142
143    /// Invoked for the "CRL Distribution Points" (if present)
144    fn visit_extension_crl_distribution_points(&mut self, _crl: &CRLDistributionPoints) {}
145
146    /// Invoked for the "Inhibit anyPolicy" (if present)
147    fn visit_extension_inhibit_anypolicy(&mut self, _policy: &InhibitAnyPolicy) {}
148
149    /// Invoked for the "Authority Information Access" (if present)
150    fn visit_extension_authority_information_access(&mut self, _info: &AuthorityInfoAccess) {}
151
152    /// Invoked for the "Signed Certificate Timestamp" (SCT) (if present)
153    fn visit_extension_sct(&mut self, _sct: &[SignedCertificateTimestamp]) {}
154}
155
156impl X509Certificate<'_> {
157    /// Run the provided [`X509CertificateVisitor`] over the X.509 Certificate (`self`)
158    pub fn walk<V: X509CertificateVisitor>(&self, visitor: &mut V) {
159        visitor.visit_tbs_certificate(&self.tbs_certificate);
160        self.tbs_certificate.walk(visitor);
161        visitor.visit_signature_algorithm(&self.signature_algorithm);
162        visitor.visit_signature_value(&self.signature_value);
163    }
164}
165
166impl TbsCertificate<'_> {
167    /// Run the provided `visitor` over the [`TbsCertificate`] object
168    pub fn walk<V: X509CertificateVisitor>(&self, visitor: &mut V) {
169        visitor.visit_version(&self.version);
170        visitor.visit_serial_number(self.raw_serial());
171        visitor.visit_tbs_signature_algorithm(&self.signature);
172        visitor.visit_issuer(&self.issuer);
173        visitor.visit_validity(&self.validity);
174        visitor.visit_subject(&self.subject);
175        visitor.visit_subject_public_key_info(&self.subject_pki);
176        visitor.visit_issuer_unique_id(self.issuer_uid.as_ref());
177        visitor.visit_subject_unique_id(self.subject_uid.as_ref());
178        visitor.pre_visit_extensions(self.extensions());
179        for extension in self.extensions() {
180            visitor.visit_extension(extension);
181
182            if extension.oid == OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER {
183                if let ParsedExtension::AuthorityKeyIdentifier(aki) = &extension.parsed_extension {
184                    visitor.visit_extension_aki(aki);
185                }
186            } else if extension.oid == OID_X509_EXT_SUBJECT_KEY_IDENTIFIER {
187                if let ParsedExtension::SubjectKeyIdentifier(id) = &extension.parsed_extension {
188                    visitor.visit_extension_ski(id);
189                }
190            } else if extension.oid == OID_X509_EXT_KEY_USAGE {
191                if let ParsedExtension::KeyUsage(usage) = &extension.parsed_extension {
192                    visitor.visit_extension_key_usage(usage);
193                }
194            } else if extension.oid == OID_X509_EXT_CERTIFICATE_POLICIES {
195                if let ParsedExtension::CertificatePolicies(policies) = &extension.parsed_extension
196                {
197                    visitor.visit_extension_certificate_policies(policies);
198                }
199            } else if extension.oid == OID_X509_EXT_SUBJECT_ALT_NAME {
200                if let ParsedExtension::SubjectAlternativeName(san) = &extension.parsed_extension {
201                    visitor.visit_extension_subject_alternative_name(san);
202                }
203            } else if extension.oid == OID_X509_EXT_ISSUER_ALT_NAME {
204                if let ParsedExtension::IssuerAlternativeName(ian) = &extension.parsed_extension {
205                    visitor.visit_extension_issuer_alternative_name(ian);
206                }
207            } else if extension.oid == OID_X509_EXT_BASIC_CONSTRAINTS {
208                if let ParsedExtension::BasicConstraints(bc) = &extension.parsed_extension {
209                    visitor.visit_extension_basic_constraints(bc);
210                }
211            } else if extension.oid == OID_X509_EXT_NAME_CONSTRAINTS {
212                if let ParsedExtension::NameConstraints(constraints) = &extension.parsed_extension {
213                    visitor.visit_extension_name_constraints(constraints);
214                }
215            } else if extension.oid == OID_X509_EXT_POLICY_CONSTRAINTS {
216                if let ParsedExtension::PolicyConstraints(constraints) = &extension.parsed_extension
217                {
218                    visitor.visit_extension_policy_constraints(constraints);
219                }
220            } else if extension.oid == OID_X509_EXT_EXTENDED_KEY_USAGE {
221                if let ParsedExtension::ExtendedKeyUsage(usage) = &extension.parsed_extension {
222                    visitor.visit_extension_extended_key_usage(usage);
223                }
224            } else if extension.oid == OID_X509_EXT_CRL_DISTRIBUTION_POINTS {
225                if let ParsedExtension::CRLDistributionPoints(crl) = &extension.parsed_extension {
226                    visitor.visit_extension_crl_distribution_points(crl);
227                }
228            } else if extension.oid == OID_X509_EXT_INHIBITANT_ANY_POLICY {
229                if let ParsedExtension::InhibitAnyPolicy(policy) = &extension.parsed_extension {
230                    visitor.visit_extension_inhibit_anypolicy(policy);
231                }
232            } else if extension.oid == OID_PKIX_AUTHORITY_INFO_ACCESS {
233                if let ParsedExtension::AuthorityInfoAccess(info) = &extension.parsed_extension {
234                    visitor.visit_extension_authority_information_access(info);
235                }
236            } else if extension.oid == OID_CT_LIST_SCT {
237                if let ParsedExtension::SCT(sct) = &extension.parsed_extension {
238                    visitor.visit_extension_sct(sct);
239                }
240            }
241        }
242        visitor.post_visit_extensions(self.extensions());
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249    use crate::FromDer;
250
251    static IGCA_DER: &[u8] = include_bytes!("../../assets/IGC_A.der");
252
253    #[test]
254    fn visitor_certificate() {
255        #[derive(Debug, Default)]
256        struct SubjectIssuerVisitor {
257            issuer: String,
258            subject: String,
259            is_ca: bool,
260        }
261
262        impl X509CertificateVisitor for SubjectIssuerVisitor {
263            fn visit_issuer(&mut self, name: &X509Name) {
264                self.issuer = name.to_string();
265            }
266
267            fn visit_subject(&mut self, name: &X509Name) {
268                self.subject = name.to_string();
269            }
270
271            fn visit_extension_basic_constraints(&mut self, bc: &BasicConstraints) {
272                self.is_ca = bc.ca;
273            }
274        }
275
276        let mut visitor = SubjectIssuerVisitor::default();
277        let (_, x509) = X509Certificate::from_der(IGCA_DER).unwrap();
278
279        x509.walk(&mut visitor);
280        assert!(!visitor.issuer.is_empty());
281        assert!(visitor.is_ca);
282        assert_eq!(&visitor.issuer, &visitor.subject);
283    }
284}