feat: add pgp card admin

This commit is contained in:
2022-03-27 15:11:11 +08:00
parent 03dfbe40d8
commit 4804f30b69
7 changed files with 83 additions and 53 deletions

25
src/cmd_pgpcardadmin.rs Normal file
View File

@@ -0,0 +1,25 @@
use clap::{App, Arg, ArgMatches, SubCommand};
use rust_util::util_clap::{Command, CommandError};
pub struct CommandImpl;
impl Command for CommandImpl {
fn name(&self) -> &str { "pgp-card-admin" }
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("OpenPGP Card Admin subcommand")
.arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("12345678").help("OpenPGP card admin pin"))
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let pin = opt_value_result!(sub_arg_matches.value_of("pin"), "Pass must be assigned");
if pin.len() < 8 { return simple_error!("Admin pin length:{}, must >= 8!", pin.len()); }
let _card_admin = crate::pgpcardutil::get_card_admin(pin)?;
information!("Admin pin verify success!");
// card_admin.get_aid()
Ok(None)
}
}

View File

@@ -11,7 +11,7 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("OpenPGP Card Decrypt subcommand") SubCommand::with_name(self.name()).about("OpenPGP Card Decrypt subcommand")
.arg(Arg::with_name("pass").short("p").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password")) .arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
.arg(Arg::with_name("cipher").short("c").long("cipher").takes_value(true).help("Cipher text HEX")) .arg(Arg::with_name("cipher").short("c").long("cipher").takes_value(true).help("Cipher text HEX"))
.arg(Arg::with_name("cipher-base64").short("b").long("cipher-base64").takes_value(true).help("Cipher text base64")) .arg(Arg::with_name("cipher-base64").short("b").long("cipher-base64").takes_value(true).help("Cipher text base64"))
.arg(Arg::with_name("json").long("json").help("JSON output")) .arg(Arg::with_name("json").long("json").help("JSON output"))
@@ -19,12 +19,11 @@ impl Command for CommandImpl {
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let json_output = sub_arg_matches.is_present("json"); let json_output = sub_arg_matches.is_present("json");
if json_output { if json_output { rust_util::util_msg::set_logger_std_out(false); }
rust_util::util_msg::set_logger_std_out(false);
} let pin = opt_value_result!(sub_arg_matches.value_of("pin"), "User pin must be assigned");
let pass_opt = sub_arg_matches.value_of("pass"); if pin.len() < 6 { return simple_error!("User pin length:{}, must >= 6!", pin.len()); }
let pass = opt_value_result!(pass_opt, "Pass must be assigned");
if pass.len() < 6 { return simple_error!("Pass length:{}, must >= 6!", pass.len()); }
let cipher = sub_arg_matches.value_of("cipher"); let cipher = sub_arg_matches.value_of("cipher");
let cipher_base64 = sub_arg_matches.value_of("cipher-base64"); let cipher_base64 = sub_arg_matches.value_of("cipher-base64");
@@ -36,7 +35,7 @@ impl Command for CommandImpl {
return simple_error!("cipher or cipher-base64 must assign one"); return simple_error!("cipher or cipher-base64 must assign one");
}; };
let user = crate::pgpcardutil::get_card_user_sw1_82(pass)?; let user = crate::pgpcardutil::get_card_user_sw1_82(pin)?;
let text = user.decrypt(DecryptMe::RSA(&cipher_bytes))?; let text = user.decrypt(DecryptMe::RSA(&cipher_bytes))?;
success!("Clear text HEX: {}", hex::encode(&text)); success!("Clear text HEX: {}", hex::encode(&text));
success!("Clear text base64: {}", base64::encode(&text)); success!("Clear text base64: {}", base64::encode(&text));

View File

@@ -71,12 +71,12 @@ impl Command for CommandImpl {
println!("{}", serde_json::to_string_pretty(&json).unwrap()); println!("{}", serde_json::to_string_pretty(&json).unwrap());
} }
if let Ok(pass) = std::env::var("PASS") { if let Ok(pin) = std::env::var("PASS") {
if let Ok(list) = OpenPGPCard::list_cards() { if let Ok(list) = OpenPGPCard::list_cards() {
// pw1_81 for signature // pw1_81 for signature
// openssl dgst -sha256 -verify aa -signature sig LICENSE // openssl dgst -sha256 -verify aa -signature sig LICENSE
for card in list { for card in list {
match card.verify_pw1_81(&pass) { match card.verify_pw1_81(&pin) {
Result::Ok(user) => { Result::Ok(user) => {
let h = hex::decode("8f25018489d6fe0dec34a352314c38dc146247b7de65735790f4398a92afa84b").unwrap(); let h = hex::decode("8f25018489d6fe0dec34a352314c38dc146247b7de65735790f4398a92afa84b").unwrap();
let mut hh = [0_u8; 0x20]; let mut hh = [0_u8; 0x20];
@@ -95,7 +95,7 @@ impl Command for CommandImpl {
// pw1_82 for encryption // pw1_82 for encryption
// PKCSv1.5 // PKCSv1.5
for card in list { for card in list {
match card.verify_pw1_82(&pass) { match card.verify_pw1_82(&pin) {
Result::Ok(user) => { Result::Ok(user) => {
let e = hex::decode("705d2af390174706c42de8361c4cb7a4684e06216305d6da70cab9248fa1abb9fac2b4c004187a53b9ed2b7f8ab75b20a54a12e6be672a742504b38d07b192f1f815285b6605b06a1a86d97f14ffcf41a9b3463ff3d8b2afe63e53aeb43048fef358639e5589fab8000d0805fe9145b5457cb5f7f91243b25181d1c7853b384a3bba45143a5ceeb2612463e51fbce52154e20726e6cf58f0317ebdf92613a10aec2b34224b0ffd1333c475cab473cf66aa895700e6681d20d12ddc897e0731226d4dc6bc9bd2e4aca02dba49175a35e45f9f3b56973a0381c777dac73a7eb8a04bfde45d3c19f44f740a193439da6829bf4beba90529c3017bddbd64aacbad92d3632260d5b6a7b5565fd852f17cff031fbdc2700d6acc2dedaaad307aaf7bb2de8f2b02faf84d94fa046e4ce487480918a54ca4672e1388deae8881436f454e65263a4984003495031126b4488ab27c6f4555f16bdd0fe2b9132443bbf49aa9c19864c4b1b917914e9c070a0327e52cf3b536e218a56ec97e12979e5981977e008eb9180d02da322c1a019fa535d77b67912039bc699b291d950714367d1c4a4a41edc86b1ab99d101da75a61c762fee28f8a004fb7656800623ac95d88c1978f18a1d286916cdab9c9f0f91d500cffdc8cb2853011a352bfa5f1fcd4a59720004153fb644afef083909c6a537ebc24255c1284ecf665a8cb7212672051e8b4").unwrap(); let e = hex::decode("705d2af390174706c42de8361c4cb7a4684e06216305d6da70cab9248fa1abb9fac2b4c004187a53b9ed2b7f8ab75b20a54a12e6be672a742504b38d07b192f1f815285b6605b06a1a86d97f14ffcf41a9b3463ff3d8b2afe63e53aeb43048fef358639e5589fab8000d0805fe9145b5457cb5f7f91243b25181d1c7853b384a3bba45143a5ceeb2612463e51fbce52154e20726e6cf58f0317ebdf92613a10aec2b34224b0ffd1333c475cab473cf66aa895700e6681d20d12ddc897e0731226d4dc6bc9bd2e4aca02dba49175a35e45f9f3b56973a0381c777dac73a7eb8a04bfde45d3c19f44f740a193439da6829bf4beba90529c3017bddbd64aacbad92d3632260d5b6a7b5565fd852f17cff031fbdc2700d6acc2dedaaad307aaf7bb2de8f2b02faf84d94fa046e4ce487480918a54ca4672e1388deae8881436f454e65263a4984003495031126b4488ab27c6f4555f16bdd0fe2b9132443bbf49aa9c19864c4b1b917914e9c070a0327e52cf3b536e218a56ec97e12979e5981977e008eb9180d02da322c1a019fa535d77b67912039bc699b291d950714367d1c4a4a41edc86b1ab99d101da75a61c762fee28f8a004fb7656800623ac95d88c1978f18a1d286916cdab9c9f0f91d500cffdc8cb2853011a352bfa5f1fcd4a59720004153fb644afef083909c6a537ebc24255c1284ecf665a8cb7212672051e8b4").unwrap();
println!(":::: {}", e.len()); println!(":::: {}", e.len());

View File

@@ -12,7 +12,7 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("OpenPGP Card Sign subcommand") SubCommand::with_name(self.name()).about("OpenPGP Card Sign subcommand")
.arg(Arg::with_name("pass").short("p").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password")) .arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
.arg(Arg::with_name("sha256").short("2").long("sha256").takes_value(true).help("Digest SHA256 HEX")) .arg(Arg::with_name("sha256").short("2").long("sha256").takes_value(true).help("Digest SHA256 HEX"))
.arg(Arg::with_name("sha384").short("3").long("sha384").takes_value(true).help("Digest SHA384 HEX")) .arg(Arg::with_name("sha384").short("3").long("sha384").takes_value(true).help("Digest SHA384 HEX"))
.arg(Arg::with_name("sha512").short("5").long("sha512").takes_value(true).help("Digest SHA512 HEX")) .arg(Arg::with_name("sha512").short("5").long("sha512").takes_value(true).help("Digest SHA512 HEX"))
@@ -24,11 +24,10 @@ impl Command for CommandImpl {
if json_output { if json_output {
rust_util::util_msg::set_logger_std_out(false); rust_util::util_msg::set_logger_std_out(false);
} }
let pass = sub_arg_matches.value_of("pass"); let pin_opt = sub_arg_matches.value_of("pin");
let pass = match pass { let pin = opt_value_result!(pin_opt, "User pin must be assigned");
Some(p) => p, if pin.len() < 6 { return simple_error!("User pin length:{}, must >= 6!", pin.len()); }
None => return simple_error!("Pass must be assigned"),
};
let sha256 = sub_arg_matches.value_of("sha256"); let sha256 = sub_arg_matches.value_of("sha256");
let sha384 = sub_arg_matches.value_of("sha384"); let sha384 = sub_arg_matches.value_of("sha384");
let sha512 = sub_arg_matches.value_of("sha512"); let sha512 = sub_arg_matches.value_of("sha512");
@@ -39,7 +38,7 @@ impl Command for CommandImpl {
let mut json = BTreeMap::new(); let mut json = BTreeMap::new();
if let Some(sha256) = sha256 { if let Some(sha256) = sha256 {
let user = crate::pgpcardutil::get_card_user_sw1_81(pass)?; let user = crate::pgpcardutil::get_card_user_sw1_81(pin)?;
let sha256_hex = opt_result!(hex::decode(sha256.trim()), "Decode sha256 failed: {}"); let sha256_hex = opt_result!(hex::decode(sha256.trim()), "Decode sha256 failed: {}");
let sha256_hex = copy_sha256(&sha256_hex)?; let sha256_hex = copy_sha256(&sha256_hex)?;
let sig = user.signature_for_hash(Hash::SHA256(sha256_hex))?; let sig = user.signature_for_hash(Hash::SHA256(sha256_hex))?;
@@ -53,7 +52,7 @@ impl Command for CommandImpl {
} }
} }
if let Some(sha384) = sha384 { if let Some(sha384) = sha384 {
let user = crate::pgpcardutil::get_card_user_sw1_81(pass)?; let user = crate::pgpcardutil::get_card_user_sw1_81(pin)?;
let sha384_hex = opt_result!(hex::decode(sha384.trim()), "Decode sha384 failed: {}"); let sha384_hex = opt_result!(hex::decode(sha384.trim()), "Decode sha384 failed: {}");
let sha384_hex = copy_sha384(&sha384_hex)?; let sha384_hex = copy_sha384(&sha384_hex)?;
let sig = user.signature_for_hash(Hash::SHA384(sha384_hex))?; let sig = user.signature_for_hash(Hash::SHA384(sha384_hex))?;
@@ -67,7 +66,7 @@ impl Command for CommandImpl {
} }
} }
if let Some(sha512) = sha512 { if let Some(sha512) = sha512 {
let user = crate::pgpcardutil::get_card_user_sw1_81(pass)?; let user = crate::pgpcardutil::get_card_user_sw1_81(pin)?;
let sha512_hex = opt_result!(hex::decode(sha512.trim()), "Decode sha512 failed: {}"); let sha512_hex = opt_result!(hex::decode(sha512.trim()), "Decode sha512 failed: {}");
let sha512_hex = copy_sha512(&sha512_hex)?; let sha512_hex = copy_sha512(&sha512_hex)?;
let sig = user.signature_for_hash(Hash::SHA512(sha512_hex))?; let sig = user.signature_for_hash(Hash::SHA512(sha512_hex))?;

View File

@@ -12,7 +12,7 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("PIV Sign subcommand") SubCommand::with_name(self.name()).about("PIV Sign subcommand")
.arg(Arg::with_name("pass").short("p").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password")) .arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
.arg(Arg::with_name("json").long("json").help("JSON output")) .arg(Arg::with_name("json").long("json").help("JSON output"))
} }
@@ -22,11 +22,10 @@ impl Command for CommandImpl {
rust_util::util_msg::set_logger_std_out(false); rust_util::util_msg::set_logger_std_out(false);
} }
warning!("This feature is not complete"); warning!("This feature is not complete");
let pass_opt = sub_arg_matches.value_of("pass"); let pin = opt_value_result!(sub_arg_matches.value_of("pin"), "User pin must be assigned");
let pass = opt_value_result!(pass_opt, "Pass must be assigned");
let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}"); let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}");
opt_result!(yk.verify_pin(pass.as_bytes()), "YubiKey verify pin failed: {}"); opt_result!(yk.verify_pin(pin.as_bytes()), "YubiKey verify pin failed: {}");
let raw_in = [1_u8; 256]; let raw_in = [1_u8; 256];
let sign_result = yubikey::piv::sign_data(&mut yk, &raw_in, AlgorithmId::Rsa2048, SlotId::Signature); let sign_result = yubikey::piv::sign_data(&mut yk, &raw_in, AlgorithmId::Rsa2048, SlotId::Signature);
let sign = opt_result!(sign_result, "Sign data failed: {}"); let sign = opt_result!(sign_result, "Sign data failed: {}");

View File

@@ -10,6 +10,7 @@ mod cmd_u2fregister;
mod cmd_u2fsign; mod cmd_u2fsign;
mod cmd_pgp; mod cmd_pgp;
mod pgpcardutil; mod pgpcardutil;
mod cmd_pgpcardadmin;
mod cmd_pgpcardlist; mod cmd_pgpcardlist;
mod cmd_pgpcardsign; mod cmd_pgpcardsign;
mod cmd_pgpcarddecrypt; mod cmd_pgpcarddecrypt;
@@ -41,6 +42,7 @@ fn inner_main() -> CommandError {
Box::new(cmd_chall::CommandImpl), Box::new(cmd_chall::CommandImpl),
Box::new(cmd_challconfig::CommandImpl), Box::new(cmd_challconfig::CommandImpl),
Box::new(cmd_pgp::CommandImpl), Box::new(cmd_pgp::CommandImpl),
Box::new(cmd_pgpcardadmin::CommandImpl),
Box::new(cmd_pgpcardlist::CommandImpl), Box::new(cmd_pgpcardlist::CommandImpl),
Box::new(cmd_pgpcardsign::CommandImpl), Box::new(cmd_pgpcardsign::CommandImpl),
Box::new(cmd_pgpcarddecrypt::CommandImpl), Box::new(cmd_pgpcarddecrypt::CommandImpl),

View File

@@ -1,37 +1,43 @@
use openpgp_card::{OpenPGPCard, OpenPGPCardUser}; use openpgp_card::{OpenPGPCard, OpenPGPCardAdmin, OpenPGPCardUser};
use rust_util::XResult; use rust_util::XResult;
pub fn get_card_user_sw1_81(pass: &str) -> XResult<OpenPGPCardUser> { pub fn get_card_user_sw1_81(pin: &str) -> XResult<OpenPGPCardUser> {
match OpenPGPCard::list_cards() { // pw1_81 for signature
Ok(list) => { // openssl dgst -sha256 -verify aa -signature sig LICENSE
// pw1_81 for signature get_card_user(|open_pgp_card: OpenPGPCard| open_pgp_card.verify_pw1_81(pin), "pw1_81")
// openssl dgst -sha256 -verify aa -signature sig LICENSE }
if list.is_empty() {
return simple_error!("Cannot find any card"); pub fn get_card_user_sw1_82(pin: &str) -> XResult<OpenPGPCardUser> {
} // pw1_82 for decrypt
match list.into_iter().next().unwrap().verify_pw1_81(pass) { // PKCSv1.5
Result::Ok(user) => Ok(user), get_card_user(|open_pgp_card: OpenPGPCard| open_pgp_card.verify_pw1_82(pin), "pw1_82")
Result::Err(_) => simple_error!("Verify pw1_81 OpenPGP card failed"), }
}
} pub fn get_card_admin(pin: &str) -> XResult<OpenPGPCardAdmin> {
Err(e) => simple_error!("Read OpenPGP card failed: {}", e), let card = get_card()?;
match card.verify_pw3(pin) {
Result::Ok(admin) => Ok(admin),
Result::Err(_) => simple_error!("Verify pw3 OpenPGP card failed"),
} }
} }
pub fn get_card_user_sw1_82(pass: &str) -> XResult<OpenPGPCardUser> { fn get_card_user(process_fn: impl Fn(OpenPGPCard) -> Result<OpenPGPCardUser, OpenPGPCard>, tag: &str) -> XResult<OpenPGPCardUser> {
match OpenPGPCard::list_cards() { let card = get_card()?;
Ok(list) => { match process_fn(card) {
// pw1_82 for decrypt Result::Ok(user) => Ok(user),
// PKCSv1.5 Result::Err(_) => simple_error!("Verify {} OpenPGP card failed", tag),
if list.is_empty() {
return simple_error!("Cannot find any card");
}
match list.into_iter().next().unwrap().verify_pw1_82(pass) {
Result::Ok(user) => Ok(user),
Result::Err(_) => simple_error!("Verify pw1_82 OpenPGP card failed"),
}
}
Err(e) => simple_error!("Read OpenPGP card failed: {}", e),
} }
} }
fn get_card() -> XResult<OpenPGPCard> {
let card_list = opt_result!(OpenPGPCard::list_cards(),
"Read OpenPGP card list failed: {}");
if card_list.is_empty() {
return simple_error!("Cannot find any card");
}
if card_list.len() > 0 {
warning!("Find {} OpenPGP cards, will use first card", card_list.len());
}
Ok(opt_value_result!(card_list.into_iter().next(), "Get first card failed"))
}