feat: pgp card make

This commit is contained in:
2022-04-05 23:08:55 +08:00
parent ce0351a721
commit 02a9e72a8a
3 changed files with 169 additions and 1 deletions

View File

@@ -20,7 +20,7 @@ impl Command for CommandImpl {
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let pin_opt = sub_arg_matches.value_of("pass").or_else(|| sub_arg_matches.value_of("pin"));
let pin = opt_value_result!(pin_opt, "Pass must be assigned");
let pin = opt_value_result!(pin_opt, "Pin must be assigned");
if pin.len() < 8 { return simple_error!("Admin pin length:{}, must >= 8!", pin.len()); }
let mut card = crate::pgpcardutil::get_card()?;

166
src/cmd_pgpcardmake.rs Normal file
View File

@@ -0,0 +1,166 @@
use clap::{App, Arg, ArgMatches, SubCommand};
use openpgp::crypto::mpi::ProtectedMPI;
use openpgp::crypto::mpi::PublicKey as MpiPublicKey;
use openpgp::crypto::Password;
use openpgp::Fingerprint;
use openpgp::KeyID;
use openpgp::Packet;
use openpgp::packet::Key;
use openpgp::packet::key::{SecretKeyMaterial, SecretParts};
use openpgp::packet::key::SubordinateRole;
use openpgp::packet::Signature;
use openpgp::packet::signature::subpacket::{SubpacketTag, SubpacketValue};
use openpgp::parse::{PacketParser, PacketParserResult, Parse};
use openpgp_card::OpenPgp;
use openssl::bn::BigNum;
use rust_util::util_clap::{Command, CommandError};
use rust_util::XResult;
use sequoia_openpgp as openpgp;
use crate::rsautil::RsaCrt;
#[derive(Debug)]
struct PgpRsaPrivateKeySet {
signing: Option<PgpRsaPrivateKey>,
encryption: Option<PgpRsaPrivateKey>,
authentication: Option<PgpRsaPrivateKey>,
}
impl PgpRsaPrivateKeySet {
fn new() -> Self {
PgpRsaPrivateKeySet {
signing: None,
encryption: None,
authentication: None,
}
}
}
#[derive(Debug)]
struct PgpRsaPrivateKey {
key_id: KeyID,
fingerprint: Fingerprint,
rsa_private_key: RsaCrt,
}
pub struct CommandImpl;
impl Command for CommandImpl {
fn name(&self) -> &str { "pgp-card-make" }
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("OpenPGP Card Make subcommand")
// .arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("12345678").help("OpenPGP card admin pin"))
.arg(Arg::with_name("pass").long("pass").takes_value(true).required(false).help("Password for PGP secret key"))
.arg(Arg::with_name("in").long("in").takes_value(true).required(false).help("PGP file in"))
.arg(Arg::with_name("force-make").long("force-make").help("Force make OpenPGP card"))
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let pin_opt = sub_arg_matches.value_of("pin");
let pin = opt_value_result!(pin_opt, "Pin must be assigned");
if pin.len() < 8 { return simple_error!("Admin pin length:{}, must >= 8!", pin.len()); }
let pass = opt_value_result!(sub_arg_matches.value_of("pass"), "Pass must assigned!");
let password = Password::from(pass);
let pgp_in_file = opt_value_result!(sub_arg_matches.value_of("in"), "PGP in file must assigned!");
let mut pgp_rsa_private_key_set = PgpRsaPrivateKeySet::new();
let mut ppr = PacketParser::from_file(pgp_in_file)?;
let mut last_pgp_rsa_private_key = None;
while let PacketParserResult::Some(pp) = ppr {
if let Packet::SecretKey(key) = &pp.packet {
let key = key.role_as_subordinate();
let pgp_rsa_private_key = parse_security_sub_key_to_pgp_rsa_private_key(key, &password)?;
if last_pgp_rsa_private_key.is_some() { return simple_error!("Last PGP RSA private key is not none"); }
last_pgp_rsa_private_key.replace(pgp_rsa_private_key);
} else if let Packet::SecretSubkey(key) = &pp.packet {
let pgp_rsa_private_key = parse_security_sub_key_to_pgp_rsa_private_key(key, &password)?;
if last_pgp_rsa_private_key.is_some() { return simple_error!("Last PGP RSA private key is not none"); }
last_pgp_rsa_private_key.replace(pgp_rsa_private_key);
} else if let Packet::Signature(signature) = &pp.packet {
if let Signature::V4(signature_v4) = signature {
if let Some(sub_package) = signature_v4.hashed_area().subpacket(SubpacketTag::KeyFlags) {
if let SubpacketValue::KeyFlags(key_flags) = sub_package.value() {
if last_pgp_rsa_private_key.is_none() {
return simple_error!("Last PGP RSA private key is none, for signature flag: {:?}", key_flags);
}
if key_flags.for_certification() || key_flags.for_signing() {
pgp_rsa_private_key_set.signing = last_pgp_rsa_private_key.take();
} else if key_flags.for_transport_encryption() || key_flags.for_storage_encryption() {
pgp_rsa_private_key_set.encryption = last_pgp_rsa_private_key.take();
} else if key_flags.for_authentication() {
pgp_rsa_private_key_set.authentication = last_pgp_rsa_private_key.take();
} else {
return simple_error!("Unknown signature flags: {:?}", key_flags);
}
}
}
}
}
// Start parsing the next packet, recursing.
ppr = pp.recurse()?.1;
}
debugging!("Found PGP RSA private key set: {:?}", pgp_rsa_private_key_set);
// TODO success logging
if pgp_rsa_private_key_set.signing.is_none() || pgp_rsa_private_key_set.encryption.is_none() || pgp_rsa_private_key_set.authentication.is_none() {
warning!("");// TODO ...
}
let force_make = sub_arg_matches.is_present("force-make");
if !force_make {
warning!("Force make is OFF, skip write private keys to card!");
return Ok(None);
}
warning!("Force make is ON, try to write private keys to card!");
let mut card = crate::pgpcardutil::get_card()?;
let mut pgp = OpenPgp::new(&mut card);
let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}");
opt_result!(trans.verify_pw3(pin.as_ref()), "Admin pin verify failed: {}");
success!("Admin pin verify success!");
// trans.key_import()
Ok(None)
}
}
fn parse_security_sub_key_to_pgp_rsa_private_key(key: &Key<SecretParts, SubordinateRole>, password: &Password) -> XResult<PgpRsaPrivateKey> {
information!("Public key, key id: {}, fingerprint: {}", key.keyid(), key.fingerprint());
let e = if let MpiPublicKey::RSA { e, n: _ } = key.mpis() {
e.clone()
} else {
return simple_error!("Not RSA public key");
};
// default PGP implementation SHOULD encrypt private keys
let private_key = opt_result!(key.clone().decrypt_secret(&password), "Decrypt private key failed: {}");
let (p, q) = if let Key::V4(private_key4) = private_key {
if let SecretKeyMaterial::Unencrypted(unencrypted) = private_key4.secret() {
unencrypted.map(|f| {
let p_and_q_result: XResult<(ProtectedMPI, ProtectedMPI)> = if let openpgp::crypto::mpi::SecretKeyMaterial::RSA { d: _, p, q, u: _ } = f {
Ok((p.clone(), q.clone()))
} else {
simple_error!("Not RSA private key")
};
p_and_q_result
})?
} else {
return simple_error!("Not unencrypted private key");
}
} else {
return simple_error!("Not Key::V4 private key");
};
let p = BigNum::from_slice(p.value()).unwrap();
let q = BigNum::from_slice(q.value()).unwrap();
let e = BigNum::from_slice(e.value()).unwrap();
let rsa_crt = opt_result!(RsaCrt::from(p, q, e), "Parse RSA crt failed: {}");
Ok(PgpRsaPrivateKey {
key_id: key.keyid(),
fingerprint: key.fingerprint(),
rsa_private_key: rsa_crt,
})
}

View File

@@ -17,6 +17,7 @@ mod cmd_pgpcardadmin;
mod cmd_pgpcardlist;
mod cmd_pgpcardsign;
mod cmd_pgpcarddecrypt;
mod cmd_pgpcardmake;
mod cmd_piv;
mod cmd_pivsign;
mod cmd_chall;
@@ -49,6 +50,7 @@ fn inner_main() -> CommandError {
Box::new(cmd_pgpcardlist::CommandImpl),
Box::new(cmd_pgpcardsign::CommandImpl),
Box::new(cmd_pgpcarddecrypt::CommandImpl),
Box::new(cmd_pgpcardmake::CommandImpl),
Box::new(cmd_piv::CommandImpl),
Box::new(cmd_pivsign::CommandImpl),
Box::new(cmd_u2fregister::CommandImpl),