99 lines
3.2 KiB
Rust
99 lines
3.2 KiB
Rust
use der_parser::ber::*;
|
|
use der_parser::der::*;
|
|
use std::env;
|
|
use std::io;
|
|
|
|
use nom::HexDisplay;
|
|
|
|
struct BerPrinter {}
|
|
|
|
impl BerPrinter {
|
|
/// try to parse contents, constructed or not
|
|
///
|
|
/// Do not raise errors if object is not constructed
|
|
fn try_print_encapsulated(&mut self, data: &[u8], depth: usize, ber: &BerObject) {
|
|
let mut i = data;
|
|
let mut first_object = true;
|
|
while !i.is_empty() {
|
|
match parse_ber_any_r(i, MAX_RECURSION) {
|
|
Ok((rem, inner)) => {
|
|
if first_object {
|
|
println!("{:1$}encapsulates {{", " ", depth * 2);
|
|
first_object = false;
|
|
}
|
|
self.run_at(&inner, depth + 1);
|
|
i = rem;
|
|
}
|
|
Err(e) => {
|
|
if ber.is_constructed() {
|
|
// object was constructed, so should have been parsed correctly
|
|
eprintln!(
|
|
"Error while parsing constructed object at depth {}: {}",
|
|
depth, e
|
|
);
|
|
eprintln!("tried to parse\n{}", data.to_hex(16));
|
|
} else {
|
|
// does not look like encapsulated data
|
|
i = &[];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if !first_object {
|
|
println!("{:1$}}}", " ", depth * 2);
|
|
}
|
|
if !i.is_empty() {
|
|
println!("WARNING: {} remaining bytes at depth {}", i.len(), depth);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Visit<'a> for BerPrinter {
|
|
fn visit_ber(&mut self, ber: &'_ BerObject<'a>, depth: usize) {
|
|
// create a printer without the recursive flag, recursion is handled by the
|
|
// visitor pattern
|
|
let pp = PrettyBer::new(ber, vec![PrettyPrinterFlag::ShowHeader], depth * 2, 2);
|
|
println!("{:?}", pp);
|
|
match ber.content {
|
|
BerObjectContent::Unknown(ref any) => {
|
|
self.try_print_encapsulated(any.data, depth, ber);
|
|
}
|
|
// Bitstring and OctetString also can encapsulate objects
|
|
BerObjectContent::OctetString(data) => {
|
|
self.try_print_encapsulated(data, depth, ber);
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn main() -> io::Result<()> {
|
|
let mut parse_as_ber = false;
|
|
for file_name in env::args().skip(1) {
|
|
match file_name.as_ref() {
|
|
"--ber" => {
|
|
parse_as_ber = true;
|
|
continue;
|
|
}
|
|
"--der" => {
|
|
parse_as_ber = false;
|
|
continue;
|
|
}
|
|
_ => (),
|
|
}
|
|
let data = std::fs::read(file_name.clone()).expect("Unable to read file");
|
|
let (rem, obj) = if parse_as_ber {
|
|
parse_ber(&data).expect("could not parse BER data")
|
|
} else {
|
|
parse_der(&data).expect("could not parse DER data")
|
|
};
|
|
let mut printer = BerPrinter {};
|
|
printer.run_at(&obj, 1);
|
|
if !rem.is_empty() {
|
|
println!("WARNING: extra bytes after BER/DER object:\n{:x?}", rem);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|