172 lines
5.2 KiB
Rust
172 lines
5.2 KiB
Rust
use der_parser::oid::Oid;
|
|
use nom::HexDisplay;
|
|
use std::cmp::min;
|
|
use std::env;
|
|
use std::io;
|
|
use x509_parser::prelude::*;
|
|
|
|
fn print_hex_dump(bytes: &[u8], max_len: usize) {
|
|
let m = min(bytes.len(), max_len);
|
|
print!("{}", &bytes[..m].to_hex(16));
|
|
if bytes.len() > max_len {
|
|
println!("... <continued>");
|
|
}
|
|
}
|
|
|
|
fn format_oid(oid: &Oid) -> String {
|
|
match oid2sn(oid, oid_registry()) {
|
|
Ok(s) => s.to_owned(),
|
|
_ => format!("{}", oid),
|
|
}
|
|
}
|
|
|
|
fn print_authority_key_identifier(aki: &AuthorityKeyIdentifier, level: usize) {
|
|
if let Some(id) = &aki.key_identifier {
|
|
let mut s =
|
|
id.0.iter()
|
|
.fold(String::with_capacity(3 * id.0.len()), |a, b| {
|
|
a + &format!("{:02x}:", b)
|
|
});
|
|
s.pop();
|
|
println!("{:indent$}keyid: {}", "", &s, indent = level);
|
|
}
|
|
if aki.authority_cert_issuer.is_some() {
|
|
unimplemented!();
|
|
}
|
|
if let Some(serial) = aki.authority_cert_serial {
|
|
let mut s = serial
|
|
.iter()
|
|
.fold(String::with_capacity(3 * serial.len()), |a, b| {
|
|
a + &format!("{:02x}:", b)
|
|
});
|
|
s.pop();
|
|
println!("{:indent$}serial: {}", "", &s, indent = level);
|
|
}
|
|
}
|
|
|
|
fn print_x509_extension(oid: &Oid, ext: &X509Extension, level: usize) {
|
|
match ext.parsed_extension() {
|
|
ParsedExtension::CRLNumber(num) => {
|
|
println!("{:indent$}X509v3 CRL Number: {}", "", num, indent = level);
|
|
}
|
|
ParsedExtension::ReasonCode(code) => {
|
|
println!(
|
|
"{:indent$}X509v3 CRL Reason Code: {}",
|
|
"",
|
|
code,
|
|
indent = level
|
|
);
|
|
}
|
|
ParsedExtension::InvalidityDate(date) => {
|
|
println!(
|
|
"{:indent$}Invalidity Date: {}",
|
|
"",
|
|
date.to_rfc2822(),
|
|
indent = level
|
|
);
|
|
}
|
|
ParsedExtension::AuthorityKeyIdentifier(aki) => {
|
|
println!(
|
|
"{:indent$}X509v3 Authority Key Identifier:",
|
|
"",
|
|
indent = level
|
|
);
|
|
print_authority_key_identifier(aki, level + 2);
|
|
}
|
|
x => {
|
|
print!("{:indent$}{}:", "", format_oid(oid), indent = level);
|
|
print!(" Critical={}", ext.critical);
|
|
print!(" len={}", ext.value.len());
|
|
println!();
|
|
println!(" {:indent$}{:?}", "", x, indent = level);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn print_x509_digest_algorithm(alg: &AlgorithmIdentifier, level: usize) {
|
|
println!(
|
|
"{:indent$}Oid: {}",
|
|
"",
|
|
format_oid(&alg.algorithm),
|
|
indent = level
|
|
);
|
|
if let Some(parameter) = &alg.parameters {
|
|
println!(
|
|
"{:indent$}Parameter: <PRESENT> {:?}",
|
|
"",
|
|
parameter.header.tag,
|
|
indent = level
|
|
);
|
|
if let Ok(bytes) = parameter.as_slice() {
|
|
print_hex_dump(bytes, 32);
|
|
}
|
|
} else {
|
|
println!("{:indent$}Parameter: <ABSENT>", "", indent = level);
|
|
}
|
|
}
|
|
|
|
fn print_revoked_certificate(revoked: &RevokedCertificate, level: usize) {
|
|
println!(
|
|
"{:indent$}Serial number: {}",
|
|
"",
|
|
revoked.raw_serial_as_string(),
|
|
indent = level
|
|
);
|
|
println!(
|
|
"{:indent$}Revocation Date: {}",
|
|
"",
|
|
revoked.revocation_date.to_rfc2822(),
|
|
indent = level + 2
|
|
);
|
|
println!("{:indent$}CRL Extensions:", "", indent = level + 2);
|
|
for ext in revoked.extensions() {
|
|
print_x509_extension(&ext.oid, ext, level + 4);
|
|
}
|
|
}
|
|
|
|
fn print_crl_info(crl: &CertificateRevocationList) {
|
|
println!(" Version: {}", crl.version().unwrap_or(X509Version(0)));
|
|
// println!(" Subject: {}", crl.subject());
|
|
println!(" Signature Algorithm:");
|
|
print_x509_digest_algorithm(&crl.signature_algorithm, 4);
|
|
println!(" Issuer: {}", crl.issuer());
|
|
// println!(" Serial: {}", crl.tbs_certificate.raw_serial_as_string());
|
|
println!(" Last Update: {}", crl.last_update().to_rfc2822());
|
|
println!(
|
|
" Next Update: {}",
|
|
crl.next_update()
|
|
.map_or("NONE".to_owned(), |d| d.to_rfc2822())
|
|
);
|
|
println!("{:indent$}CRL Extensions:", "", indent = 2);
|
|
for ext in crl.extensions() {
|
|
print_x509_extension(&ext.oid, ext, 4);
|
|
}
|
|
println!(" Revoked certificates:");
|
|
for revoked in crl.iter_revoked_certificates() {
|
|
print_revoked_certificate(revoked, 4);
|
|
}
|
|
println!();
|
|
}
|
|
|
|
pub fn main() -> io::Result<()> {
|
|
for file_name in env::args().skip(1) {
|
|
// placeholder to store decoded PEM data, if needed
|
|
let tmpdata;
|
|
|
|
println!("File: {}", file_name);
|
|
let data = std::fs::read(file_name.clone()).expect("Unable to read file");
|
|
let der_data: &[u8] = if (data[0], data[1]) == (0x30, 0x82) {
|
|
// probably DER
|
|
&data
|
|
} else {
|
|
// try as PEM
|
|
let (_, data) = parse_x509_pem(&data).expect("Could not decode the PEM file");
|
|
tmpdata = data;
|
|
&tmpdata.contents
|
|
};
|
|
let (_, crl) = parse_x509_crl(der_data).expect("Could not decode DER data");
|
|
print_crl_info(&crl);
|
|
}
|
|
Ok(())
|
|
}
|