use asn1_rs::BitString;
use oid_registry::*;
use crate::certificate::*;
use crate::extensions::*;
use crate::x509::*;
pub trait X509CertificateVisitor {
fn walk(&mut self, x509: &X509Certificate)
where
Self: Sized,
{
x509.walk(self);
}
fn visit_tbs_certificate(&mut self, _tbs: &TbsCertificate) {}
fn visit_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
fn visit_signature_value(&mut self, _signature: &BitString) {}
fn visit_version(&mut self, _version: &X509Version) {}
fn visit_serial_number(&mut self, _serial: &[u8]) {}
fn visit_tbs_signature_algorithm(&mut self, _algorithm: &AlgorithmIdentifier) {}
fn visit_issuer(&mut self, _name: &X509Name) {}
fn visit_validity(&mut self, _validity: &Validity) {}
fn visit_subject(&mut self, _name: &X509Name) {}
fn visit_subject_public_key_info(&mut self, _subject_pki: &SubjectPublicKeyInfo) {}
fn visit_issuer_unique_id(&mut self, _id: Option<&UniqueIdentifier>) {}
fn visit_subject_unique_id(&mut self, _id: Option<&UniqueIdentifier>) {}
fn pre_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
fn visit_extension(&mut self, _extension: &X509Extension) {}
fn post_visit_extensions(&mut self, _extensions: &[X509Extension]) {}
fn visit_extension_aki(&mut self, _aki: &AuthorityKeyIdentifier) {}
fn visit_extension_ski(&mut self, _id: &KeyIdentifier) {}
fn visit_extension_key_usage(&mut self, _usage: &KeyUsage) {}
fn visit_extension_certificate_policies(&mut self, _policies: &CertificatePolicies) {}
fn visit_extension_subject_alternative_name(&mut self, _san: &SubjectAlternativeName) {}
fn visit_extension_issuer_alternative_name(&mut self, _ian: &IssuerAlternativeName) {}
fn visit_extension_basic_constraints(&mut self, _bc: &BasicConstraints) {}
fn visit_extension_name_constraints(&mut self, _constraints: &NameConstraints) {}
fn visit_extension_nscert_comment(&mut self, _nscert_comment: &str) {}
fn visit_extension_nscert_type(&mut self, _nscert_type: &NSCertType) {}
fn visit_extension_policy_constraints(&mut self, _constraints: &PolicyConstraints) {}
fn visit_extension_policy_mappings(&mut self, _mappings: &PolicyMappings) {}
fn visit_extension_extended_key_usage(&mut self, _usage: &ExtendedKeyUsage) {}
fn visit_extension_crl_distribution_points(&mut self, _crl: &CRLDistributionPoints) {}
fn visit_extension_inhibit_anypolicy(&mut self, _policy: &InhibitAnyPolicy) {}
fn visit_extension_authority_information_access(&mut self, _info: &AuthorityInfoAccess) {}
fn visit_extension_sct(&mut self, _sct: &[SignedCertificateTimestamp]) {}
fn visit_extension_unknown(&mut self, _ext: &X509Extension) {}
fn visit_extension_parse_error(
&mut self,
_extension: &X509Extension,
_error: &asn1_rs::Err<asn1_rs::Error>,
) {
}
}
impl X509Certificate<'_> {
pub fn walk<V: X509CertificateVisitor>(&self, visitor: &mut V) {
visitor.visit_tbs_certificate(&self.tbs_certificate);
self.tbs_certificate.walk(visitor);
visitor.visit_signature_algorithm(&self.signature_algorithm);
visitor.visit_signature_value(&self.signature_value);
}
}
impl TbsCertificate<'_> {
pub fn walk<V: X509CertificateVisitor>(&self, visitor: &mut V) {
let v = visitor;
v.visit_version(&self.version);
v.visit_serial_number(self.raw_serial());
v.visit_tbs_signature_algorithm(&self.signature);
v.visit_issuer(&self.issuer);
v.visit_validity(&self.validity);
v.visit_subject(&self.subject);
v.visit_subject_public_key_info(&self.subject_pki);
v.visit_issuer_unique_id(self.issuer_uid.as_ref());
v.visit_subject_unique_id(self.subject_uid.as_ref());
v.pre_visit_extensions(self.extensions());
for extension in self.extensions() {
v.visit_extension(extension);
match extension.parsed_extension() {
ParsedExtension::AuthorityInfoAccess(info) => {
v.visit_extension_authority_information_access(info)
}
ParsedExtension::AuthorityKeyIdentifier(aki) => v.visit_extension_aki(aki),
ParsedExtension::BasicConstraints(bc) => v.visit_extension_basic_constraints(bc),
ParsedExtension::CertificatePolicies(policies) => {
v.visit_extension_certificate_policies(policies)
}
ParsedExtension::CRLDistributionPoints(crl) => {
v.visit_extension_crl_distribution_points(crl)
}
ParsedExtension::ExtendedKeyUsage(usage) => {
v.visit_extension_extended_key_usage(usage)
}
ParsedExtension::InhibitAnyPolicy(policy) => {
v.visit_extension_inhibit_anypolicy(policy)
}
ParsedExtension::IssuerAlternativeName(ian) => {
v.visit_extension_issuer_alternative_name(ian)
}
ParsedExtension::KeyUsage(usage) => v.visit_extension_key_usage(usage),
ParsedExtension::NSCertType(nscert_type) => {
v.visit_extension_nscert_type(nscert_type)
}
ParsedExtension::NameConstraints(constraints) => {
v.visit_extension_name_constraints(constraints)
}
ParsedExtension::NsCertComment(comment) => {
v.visit_extension_nscert_comment(comment)
}
ParsedExtension::PolicyConstraints(constraints) => {
v.visit_extension_policy_constraints(constraints)
}
ParsedExtension::PolicyMappings(mappings) => {
v.visit_extension_policy_mappings(mappings)
}
ParsedExtension::SCT(sct) => v.visit_extension_sct(sct),
ParsedExtension::SubjectAlternativeName(san) => {
v.visit_extension_subject_alternative_name(san)
}
ParsedExtension::SubjectKeyIdentifier(id) => v.visit_extension_ski(id),
ParsedExtension::ParseError { error } => {
v.visit_extension_parse_error(extension, error)
}
_ => v.visit_extension_unknown(extension),
}
}
v.post_visit_extensions(self.extensions());
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::FromDer;
static IGCA_DER: &[u8] = include_bytes!("../../assets/IGC_A.der");
#[test]
fn visitor_certificate() {
#[derive(Debug, Default)]
struct SubjectIssuerVisitor {
issuer: String,
subject: String,
is_ca: bool,
}
impl X509CertificateVisitor for SubjectIssuerVisitor {
fn visit_issuer(&mut self, name: &X509Name) {
self.issuer = name.to_string();
}
fn visit_subject(&mut self, name: &X509Name) {
self.subject = name.to_string();
}
fn visit_extension_basic_constraints(&mut self, bc: &BasicConstraints) {
self.is_ca = bc.ca;
}
}
let mut visitor = SubjectIssuerVisitor::default();
let (_, x509) = X509Certificate::from_der(IGCA_DER).unwrap();
x509.walk(&mut visitor);
assert!(!visitor.issuer.is_empty());
assert!(visitor.is_ca);
assert_eq!(&visitor.issuer, &visitor.subject);
}
}