Files
card-cli/src/cmd_pgp.rs
2022-03-27 12:50:48 +08:00

185 lines
8.9 KiB
Rust

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<Local> = 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<Local> = 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<String> {
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
}
}
}