feat: v0.2.4, add config subcommand

This commit is contained in:
2023-10-10 22:28:05 +08:00
parent fe226d9b75
commit a68f5e0e00
7 changed files with 204 additions and 18 deletions

66
src/cmd_config.rs Normal file
View File

@@ -0,0 +1,66 @@
use std::collections::HashMap;
use clap::Args;
use rust_util::XResult;
use tabled::{Table, Tabled};
use tabled::settings::Style;
use crate::config::TinyEncryptConfig;
use crate::util::TINY_ENC_CONFIG_FILE;
#[derive(Tabled)]
struct ConfigProfile {
profiles: String,
keys: String,
}
#[derive(Debug, Args)]
pub struct CmdConfig {}
pub fn config(_cmd_version: CmdConfig) -> XResult<()> {
let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE)?;
let mut reverse_map = HashMap::new();
for (p, v) in &config.profiles {
let p = p;
let mut v2 = v.clone();
v2.sort();
let vs = v2.join(",");
match reverse_map.get_mut(&vs) {
None => { reverse_map.insert(vs, vec![(p, v)]); }
Some(vec) => { vec.push((p, v)); }
}
}
let mut config_profiles = vec![];
for pvs in reverse_map.values() {
let mut ps: Vec<_> = pvs.iter().map(|pv| pv.0).collect();
ps.sort();
let pp = ps.iter().map(|s| s.to_string()).collect::<Vec<_>>().join(", ");
let kids = pvs[0].1;
let mut ks = Vec::with_capacity(kids.len());
for kid in kids {
match config.find_by_kid(kid) {
None => {
ks.push(format!("[ERROR] Key not found: {}", kid));
}
Some(envelop) => {
let desc = envelop.desc.as_ref()
.map(|desc| format!(", Desc: {}", desc))
.unwrap_or_else(|| "".to_string());
ks.push(format!("{}{}", envelop.kid, desc));
}
}
}
config_profiles.push(ConfigProfile {
profiles: pp,
keys: ks.join("\n"),
});
}
let mut table = Table::new(config_profiles);
table.with(Style::modern());
println!("{}", table.to_string());
Ok(())
}

View File

@@ -2,25 +2,30 @@ use std::{fs, io};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Instant;
use clap::Args;
use openpgp_card::{OpenPgp, OpenPgpTransaction};
use openpgp_card::crypto_data::Cryptogram;
use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_msg, util_term, warning, XResult};
use rust_util::{
debugging, failure, iff, information, opt_result, simple_error, success,
util_msg, util_term, warning, XResult,
};
use x509_parser::prelude::FromDer;
use x509_parser::x509::SubjectPublicKeyInfo;
use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId};
use yubikey::piv::{AlgorithmId, decrypt_data};
use yubikey::YubiKey;
use zeroize::Zeroize;
use crate::{card, file, util};
use crate::{card, file, util, util_piv};
use crate::compress::GzStreamDecoder;
use crate::config::TinyEncryptConfig;
use crate::crypto_aes::aes_gcm_decrypt;
use crate::spec::{TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta};
use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT};
use crate::util::{
ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
};
use crate::wrap_key::WrapKey;
#[derive(Debug, Args)]
@@ -194,10 +199,11 @@ fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
let epk_bytes = subject_public_key_info.subject_public_key.as_ref();
let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}");
let retired_slot_id = opt_result!(RetiredSlotId::from_str(&slot), "Slot not found: {}");
let slot_id = SlotId::Retired(retired_slot_id);
let slot_id = util_piv::get_slot_id(&slot)?;
opt_result!(yk.verify_pin(pin.as_bytes()), "YubiKey verify pin failed: {}");
let algo_id = iff!(expected_enc_type == ENC_AES256_GCM_P256, AlgorithmId::EccP256, AlgorithmId::EccP384);
let algo_id = iff!(
expected_enc_type == ENC_AES256_GCM_P256, AlgorithmId::EccP256, AlgorithmId::EccP384
);
let shared_secret = opt_result!(decrypt_data(
&mut yk,
&epk_bytes,
@@ -322,7 +328,9 @@ fn select_envelop(meta: &TinyEncryptMeta) -> XResult<&TinyEncryptEnvelop> {
envelops.iter().enumerate().for_each(|(i, envelop)| {
let kid = iff!(envelop.kid.is_empty(), "".into(), format!(", Kid: {}", envelop.kid));
let desc = envelop.desc.as_ref().map(|desc| format!(", Desc: {}", desc)).unwrap_or_else(|| "".to_string());
let desc = envelop.desc.as_ref()
.map(|desc| format!(", Desc: {}", desc))
.unwrap_or_else(|| "".to_string());
println!("#{} {}{}{}", i + 1,
envelop.r#type.get_upper_name(),
kid,

View File

@@ -2,6 +2,7 @@ extern crate core;
use clap::{Parser, Subcommand};
use rust_util::XResult;
use crate::cmd_config::CmdConfig;
use crate::cmd_decrypt::CmdDecrypt;
use crate::cmd_encrypt::CmdEncrypt;
@@ -9,6 +10,7 @@ use crate::cmd_info::CmdInfo;
use crate::cmd_version::CmdVersion;
mod util;
mod util_piv;
mod util_ecdh;
mod util_p384;
mod util_x25519;
@@ -21,6 +23,7 @@ mod wrap_key;
mod file;
mod card;
mod cmd_version;
mod cmd_config;
mod cmd_info;
mod cmd_decrypt;
mod cmd_encrypt;
@@ -47,6 +50,9 @@ enum Commands {
/// Show version
#[command(short_flag = 'v')]
Version(CmdVersion),
/// Show Config
#[command(short_flag = 'c')]
Config(CmdConfig),
}
fn main() -> XResult<()> {
@@ -56,5 +62,6 @@ fn main() -> XResult<()> {
Commands::Decrypt(cmd_decrypt) => cmd_decrypt::decrypt(cmd_decrypt),
Commands::Info(cmd_info) => cmd_info::info(cmd_info),
Commands::Version(cmd_version) => cmd_version::version(cmd_version),
Commands::Config(cmd_config) => cmd_config::config(cmd_config),
}
}

33
src/util_piv.rs Normal file
View File

@@ -0,0 +1,33 @@
use rust_util::{simple_error, XResult};
use yubikey::piv::{RetiredSlotId, SlotId};
pub fn get_slot_id(slot: &str) -> XResult<SlotId> {
let slot_lower = slot.to_lowercase();
Ok(match slot_lower.as_str() {
"9a" | "auth" | "authentication" => SlotId::Authentication,
"9c" | "sign" | "signature" => SlotId::Signature,
"9d" | "keym" | "keymanagement" => SlotId::KeyManagement,
"9e" | "card" | "cardauthentication" => SlotId::CardAuthentication,
"r1" | "82" => SlotId::Retired(RetiredSlotId::R1),
"r2" | "83" => SlotId::Retired(RetiredSlotId::R2),
"r3" | "84" => SlotId::Retired(RetiredSlotId::R3),
"r4" | "85" => SlotId::Retired(RetiredSlotId::R4),
"r5" | "86" => SlotId::Retired(RetiredSlotId::R5),
"r6" | "87" => SlotId::Retired(RetiredSlotId::R6),
"r7" | "88" => SlotId::Retired(RetiredSlotId::R7),
"r8" | "89" => SlotId::Retired(RetiredSlotId::R8),
"r9" | "8a" => SlotId::Retired(RetiredSlotId::R9),
"r10" | "8b" => SlotId::Retired(RetiredSlotId::R10),
"r11" | "8c" => SlotId::Retired(RetiredSlotId::R11),
"r12" | "8d" => SlotId::Retired(RetiredSlotId::R12),
"r13" | "8e" => SlotId::Retired(RetiredSlotId::R13),
"r14" | "8f" => SlotId::Retired(RetiredSlotId::R14),
"r15" | "90" => SlotId::Retired(RetiredSlotId::R15),
"r16" | "91" => SlotId::Retired(RetiredSlotId::R16),
"r17" | "92" => SlotId::Retired(RetiredSlotId::R17),
"r18" | "93" => SlotId::Retired(RetiredSlotId::R18),
"r19" | "94" => SlotId::Retired(RetiredSlotId::R19),
"r20" | "95" => SlotId::Retired(RetiredSlotId::R20),
_ => return simple_error!("Unknown slot: {}", slot),
})
}