| extern crate clap; |
| extern crate data_encoding; |
| extern crate derp; |
| extern crate pem; |
| extern crate untrusted; |
| |
| use clap::{App, Arg, ArgMatches}; |
| use derp::{Error, Result, Tag}; |
| use std::fs::File; |
| use std::io::Read; |
| use untrusted::{Input, Reader}; |
| |
| fn main() { |
| let matches = parser().get_matches(); |
| match run_main(matches) { |
| Ok(s) => { |
| println!("{}", s.trim()); |
| std::process::exit(0) |
| } |
| Err(e) => { |
| println!("Error: {:?}", e); |
| std::process::exit(1); |
| } |
| } |
| } |
| |
| fn run_main(matches: ArgMatches) -> Result<String> { |
| let mut file = File::open(matches.value_of("path").unwrap())?; |
| let mut buf = Vec::new(); |
| file.read_to_end(&mut buf)?; |
| let buf = parse_to_bytes(&buf); |
| let input = Input::from(&buf); |
| Ok(input.read_all(Error::Read, make_printable_string)?) |
| } |
| |
| fn parser<'a, 'b>() -> App<'a, 'b> { |
| App::new("derp") |
| .version(env!("CARGO_PKG_VERSION")) |
| .about("CLI tool for parsing and displaying DER") |
| .arg( |
| Arg::with_name("path") |
| .takes_value(true) |
| .required(true) |
| .help("The path to the file"), |
| ) |
| } |
| |
| fn parse_to_bytes(bytes: &[u8]) -> Vec<u8> { |
| data_encoding::BASE64 |
| .decode(bytes) |
| .map_err(|_| ()) |
| .or_else(|_| data_encoding::HEXUPPER.decode(bytes).map_err(|_| ())) |
| .or_else(|_| data_encoding::HEXLOWER.decode(bytes).map_err(|_| ())) |
| .or_else(|_| pem::parse(bytes).map(|p| p.contents).map_err(|_| ())) |
| .unwrap_or_else(|_| bytes.to_vec()) |
| } |
| |
| fn make_printable_string<'a>(input: &mut Reader<'a>) -> Result<String> { |
| if input.at_end() { |
| return Ok("".into()); |
| } |
| |
| if input.peek(Tag::Sequence as u8) { |
| let out = derp::nested(input, Tag::Sequence, make_printable_string)? |
| .lines() |
| .map(|l| format!(" {}\n", l)) |
| .collect::<String>(); |
| return Ok(format!("{}\n{}", Tag::Sequence, out)); |
| } |
| |
| if input.peek(Tag::BitString as u8) { |
| let out = derp::nested(input, Tag::BitString, make_printable_string) |
| .map(|s| s.lines().map(|l| format!(" {}\n", l)).collect::<String>()) |
| .unwrap_or_else(|_| "".into()); |
| return Ok(format!("{}\n{}", Tag::BitString, out)); |
| } |
| |
| if input.peek(Tag::OctetString as u8) { |
| let out = derp::nested(input, Tag::OctetString, make_printable_string) |
| .map(|s| s.lines().map(|l| format!(" {}\n", l)).collect::<String>()) |
| .unwrap_or_else(|_| "".into()); |
| return Ok(format!("{}\n{}", Tag::OctetString, out)); |
| } |
| |
| let mut out = String::new(); |
| while let Ok((tag, _)) = derp::read_tag_and_get_value(input) { |
| out.push_str(&format!( |
| "{}\n", |
| Tag::from_byte(tag) |
| .map(|t| format!("{}", t)) |
| .unwrap_or_else(|_| format!("0x{:x}", tag)) |
| )) |
| } |
| Ok(out) |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| const ED25519_PK8: &[u8] = include_bytes!("../../tests/ed25519.pk8"); |
| |
| #[test] |
| fn parse_ed25519_pk8() { |
| let input = parse_to_bytes(ED25519_PK8); |
| let input = Input::from(&input); |
| input.read_all(Error::Read, make_printable_string).unwrap(); |
| } |
| } |