use chrono::{DateTime, Local}; use clap::{App, Arg, ArgMatches, SubCommand}; use openssl::bn::BigNum; use openssl::rsa::Rsa; use pem::Pem; use rust_util::util_clap::{Command, CommandError}; use sequoia_openpgp::crypto::mpi::PublicKey; use sequoia_openpgp::Packet; use sequoia_openpgp::packet::{Key, Signature}; use sequoia_openpgp::packet::signature::subpacket::SubpacketTag; use sequoia_openpgp::parse::{PacketParser, PacketParserResult}; use sequoia_openpgp::parse::Parse; pub struct CommandImpl; impl Command for CommandImpl { fn name(&self) -> &str { "pgp" } fn subcommand<'a>(&self) -> App<'a, 'a> { SubCommand::with_name(self.name()).about("OpenPGP subcommand") .arg(Arg::with_name("in").short("i").long("in").takes_value(true).help("File input, *.pgp or *.asc")) .arg(Arg::with_name("detail").long("detail").help("Detail output")) .arg(Arg::with_name("json").long("json").help("JSON output")) } fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { let in_file = sub_arg_matches.value_of("in"); let show_detail = sub_arg_matches.is_present("detail"); let in_file = opt_value_result!(in_file, "Input file must assined"); let in_file_bytes = opt_result!(std::fs::read(in_file), "Read file: {}, failed: {}", in_file); let p = PacketParser::from_bytes(&in_file_bytes); let mut ppr = opt_result!(p, "Parse file: {}, failed: {}", in_file); while let PacketParserResult::Some(pp) = ppr { match &pp.packet { Packet::Signature(signature) => { debugging!("Found signature: {:?}", signature); match signature { Signature::V4(sig) => { // information!("-----> {:?}", sig.hashed_area()); if let Some(sub_package) = sig.hashed_area().subpacket(SubpacketTag::KeyFlags) { information!("Found sub key flags: {:?}", sub_package); } } unknown => warning!("Unknown signature: {:?}", unknown), } information!("Found signature: {:?} - {:?} [{:?}]", signature.get_issuers(), signature.hash_algo(), signature.features()); } Packet::OnePassSig(one_pass_sig) => { information!("Found one pass sig: {:?}", one_pass_sig); } Packet::PublicKey(public_key) => { information!("{}", "-".repeat(88)); debugging!("Found public key: {:?}", public_key); match public_key { Key::V4(key4) => { let mut public_key4 = String::with_capacity(512); public_key4.push_str(&format!("\n\tKey ID: {:?}", key4.keyid())); public_key4.push_str(&format!("\n\tFinger print {:?}", key4.fingerprint())); public_key4.push_str(&format!("\n\tHash algo security: {:?}", key4.hash_algo_security())); // public_key4.push_str(&format!("\n\tKey handle {:?}", key4.key_handle())); let creation_time: DateTime = DateTime::from(key4.creation_time()); let creation_time_str = simpledateformat::fmt("yyyy-MM-dd HH:mm:ss").unwrap().format(&creation_time); public_key4.push_str(&format!("\n\tCreation time {}", creation_time_str)); public_key4.push_str(&format!("\n\tPublic algo: {:?}", key4.pk_algo())); if show_detail { if let Some(pubkey_pem) = public_key_pem(key4.mpis()) { public_key4.push_str(&format!("\n\tPublic key PEM: {}", pubkey_pem)); } } information!("Found public key: {}", public_key4); } unknown => warning!("Unknown key: {:?}", unknown), } } Packet::PublicSubkey(public_sub_key) => { information!("{}", "-".repeat(88)); debugging!("Found public sub key: {:?}", public_sub_key); match public_sub_key { Key::V4(key4) => { let mut public_key4 = String::with_capacity(512); public_key4.push_str(&format!("\n\tKey ID: {:?}", key4.keyid())); public_key4.push_str(&format!("\n\tFinger print {:?}", key4.fingerprint())); public_key4.push_str(&format!("\n\tHash algo security: {:?}", key4.hash_algo_security())); let creation_time: DateTime = DateTime::from(key4.creation_time()); let creation_time_str = simpledateformat::fmt("yyyy-MM-dd HH:mm:ss").unwrap().format(&creation_time); public_key4.push_str(&format!("\n\tCreation time {}", creation_time_str)); public_key4.push_str(&format!("\n\tPublic algo: {:?}", key4.pk_algo())); if show_detail { if let Some(pubkey_pem) = public_key_pem(key4.mpis()) { public_key4.push_str(&format!("\n\tPublic key PEM: {}", pubkey_pem)); } } information!("Found public sub key: {}", public_key4); } unknown => warning!("Unknown key: {:?}", unknown), } } Packet::SecretKey(secret_key) => { information!("Found secret key: {:?}", secret_key); } Packet::SecretSubkey(secret_sub_key) => { information!("Found secret sub key: {:?}", secret_sub_key); } Packet::Marker(marker) => { information!("Found marker: {:?}", marker); } Packet::Trust(trust) => { information!("Found trust: {:?}", trust); } Packet::UserID(user_id) => { information!("Found user ID: {}", String::from_utf8_lossy(user_id.value())); } Packet::UserAttribute(user_attribute) => { information!("Found user attribute: {:?}", user_attribute); } Packet::Literal(literal) => { information!("Found literal: {:?}", literal); } Packet::CompressedData(compressed_data) => { information!("Found compressed data: {:?}", compressed_data); } Packet::PKESK(pkesk) => { information!("Found PKESK: {:?}", pkesk); } Packet::SKESK(skesk) => { information!("Found SKESK: {:?}", skesk); } Packet::SEIP(seip) => { information!("Found SEIP: {:?}", seip); } Packet::MDC(mdc) => { information!("Found MDC: {:?}", mdc); } Packet::AED(aed) => { information!("Found AED: {:?}", aed); } Packet::Unknown(unknown) => { warning!("Found unknown: {:?}", unknown); } unknown => { warning!("Found UNKNOWN: {:?}", unknown); } } ppr = pp.recurse()?.1; } if let PacketParserResult::EOF(eof) = ppr { debugging!("{:?}", eof); if eof.is_message().is_ok() { information!("FILE IS MESSAGE"); } else if eof.is_cert().is_ok() { information!("FILE IS CERT"); } else if eof.is_keyring().is_ok() { information!("FILE IS KEYRING"); } else { information!("FILE IS OTHER"); } } Ok(None) } } fn public_key_pem(public_key: &PublicKey) -> Option { match public_key { PublicKey::RSA { e, n } => { let rsa_pub_key = Rsa::from_public_components( BigNum::from_slice(n.value()).unwrap(), BigNum::from_slice(e.value()).unwrap(), ); let pub_key_pem_obj = Pem { tag: String::from("PUBLIC KEY"), contents: rsa_pub_key.unwrap().public_key_to_der().unwrap(), }; Some(pem::encode(&pub_key_pem_obj)) } _ => { warning!("Not RSA public key: {:?}", public_key); None } } }