1 use der_parser::oid::Oid;
2 use nom::HexDisplay;
3 use std::cmp::min;
4 use std::env;
5 use std::io;
6 use x509_parser::prelude::*;
7
print_hex_dump(bytes: &[u8], max_len: usize)8 fn print_hex_dump(bytes: &[u8], max_len: usize) {
9 let m = min(bytes.len(), max_len);
10 print!("{}", &bytes[..m].to_hex(16));
11 if bytes.len() > max_len {
12 println!("... <continued>");
13 }
14 }
15
format_oid(oid: &Oid) -> String16 fn format_oid(oid: &Oid) -> String {
17 match oid2sn(oid, oid_registry()) {
18 Ok(s) => s.to_owned(),
19 _ => format!("{}", oid),
20 }
21 }
22
print_authority_key_identifier(aki: &AuthorityKeyIdentifier, level: usize)23 fn print_authority_key_identifier(aki: &AuthorityKeyIdentifier, level: usize) {
24 if let Some(id) = &aki.key_identifier {
25 let mut s =
26 id.0.iter()
27 .fold(String::with_capacity(3 * id.0.len()), |a, b| {
28 a + &format!("{:02x}:", b)
29 });
30 s.pop();
31 println!("{:indent$}keyid: {}", "", &s, indent = level);
32 }
33 if aki.authority_cert_issuer.is_some() {
34 unimplemented!();
35 }
36 if let Some(serial) = aki.authority_cert_serial {
37 let mut s = serial
38 .iter()
39 .fold(String::with_capacity(3 * serial.len()), |a, b| {
40 a + &format!("{:02x}:", b)
41 });
42 s.pop();
43 println!("{:indent$}serial: {}", "", &s, indent = level);
44 }
45 }
46
print_x509_extension(oid: &Oid, ext: &X509Extension, level: usize)47 fn print_x509_extension(oid: &Oid, ext: &X509Extension, level: usize) {
48 match ext.parsed_extension() {
49 ParsedExtension::CRLNumber(num) => {
50 println!("{:indent$}X509v3 CRL Number: {}", "", num, indent = level);
51 }
52 ParsedExtension::ReasonCode(code) => {
53 println!(
54 "{:indent$}X509v3 CRL Reason Code: {}",
55 "",
56 code,
57 indent = level
58 );
59 }
60 ParsedExtension::InvalidityDate(date) => {
61 println!(
62 "{:indent$}Invalidity Date: {}",
63 "",
64 date.to_rfc2822(),
65 indent = level
66 );
67 }
68 ParsedExtension::AuthorityKeyIdentifier(aki) => {
69 println!(
70 "{:indent$}X509v3 Authority Key Identifier:",
71 "",
72 indent = level
73 );
74 print_authority_key_identifier(aki, level + 2);
75 }
76 x => {
77 print!("{:indent$}{}:", "", format_oid(oid), indent = level);
78 print!(" Critical={}", ext.critical);
79 print!(" len={}", ext.value.len());
80 println!();
81 println!(" {:indent$}{:?}", "", x, indent = level);
82 }
83 }
84 }
85
print_x509_digest_algorithm(alg: &AlgorithmIdentifier, level: usize)86 fn print_x509_digest_algorithm(alg: &AlgorithmIdentifier, level: usize) {
87 println!(
88 "{:indent$}Oid: {}",
89 "",
90 format_oid(&alg.algorithm),
91 indent = level
92 );
93 if let Some(parameter) = &alg.parameters {
94 println!(
95 "{:indent$}Parameter: <PRESENT> {:?}",
96 "",
97 parameter.header.tag,
98 indent = level
99 );
100 if let Ok(bytes) = parameter.as_slice() {
101 print_hex_dump(bytes, 32);
102 }
103 } else {
104 println!("{:indent$}Parameter: <ABSENT>", "", indent = level);
105 }
106 }
107
print_revoked_certificate(revoked: &RevokedCertificate, level: usize)108 fn print_revoked_certificate(revoked: &RevokedCertificate, level: usize) {
109 println!(
110 "{:indent$}Serial number: {}",
111 "",
112 revoked.raw_serial_as_string(),
113 indent = level
114 );
115 println!(
116 "{:indent$}Revocation Date: {}",
117 "",
118 revoked.revocation_date.to_rfc2822(),
119 indent = level + 2
120 );
121 println!("{:indent$}CRL Extensions:", "", indent = level + 2);
122 for ext in revoked.extensions() {
123 print_x509_extension(&ext.oid, ext, level + 4);
124 }
125 }
126
print_crl_info(crl: &CertificateRevocationList)127 fn print_crl_info(crl: &CertificateRevocationList) {
128 println!(" Version: {}", crl.version().unwrap_or(X509Version(0)));
129 // println!(" Subject: {}", crl.subject());
130 println!(" Signature Algorithm:");
131 print_x509_digest_algorithm(&crl.signature_algorithm, 4);
132 println!(" Issuer: {}", crl.issuer());
133 // println!(" Serial: {}", crl.tbs_certificate.raw_serial_as_string());
134 println!(" Last Update: {}", crl.last_update().to_rfc2822());
135 println!(
136 " Next Update: {}",
137 crl.next_update()
138 .map_or("NONE".to_owned(), |d| d.to_rfc2822())
139 );
140 println!("{:indent$}CRL Extensions:", "", indent = 2);
141 for ext in crl.extensions() {
142 print_x509_extension(&ext.oid, ext, 4);
143 }
144 println!(" Revoked certificates:");
145 for revoked in crl.iter_revoked_certificates() {
146 print_revoked_certificate(revoked, 4);
147 }
148 println!();
149 }
150
main() -> io::Result<()>151 pub fn main() -> io::Result<()> {
152 for file_name in env::args().skip(1) {
153 // placeholder to store decoded PEM data, if needed
154 let tmpdata;
155
156 println!("File: {}", file_name);
157 let data = std::fs::read(file_name.clone()).expect("Unable to read file");
158 let der_data: &[u8] = if (data[0], data[1]) == (0x30, 0x82) {
159 // probably DER
160 &data
161 } else {
162 // try as PEM
163 let (_, data) = parse_x509_pem(&data).expect("Could not decode the PEM file");
164 tmpdata = data;
165 &tmpdata.contents
166 };
167 let (_, crl) = parse_x509_crl(der_data).expect("Could not decode DER data");
168 print_crl_info(&crl);
169 }
170 Ok(())
171 }
172