feat: v0.3.5, add subcommand yubikey-init-master-key

This commit is contained in:
2024-09-03 23:19:17 +08:00
parent d6c49a15ea
commit b188a2bc1e
5 changed files with 94 additions and 24 deletions

View File

@@ -13,6 +13,7 @@ mod serve_status;
mod serve_init;
mod serve_encrypt_decrypt;
mod serve_read_write;
mod yubikey_init_master_key;
pub struct DefaultCommandImpl;
@@ -46,6 +47,7 @@ fn inner_main() -> CommandError {
let commands: Vec<Box<dyn Command>> = vec![
Box::new(cli::CommandImpl),
Box::new(serve::CommandImpl),
Box::new(yubikey_init_master_key::CommandImpl),
];
let mut app = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))

View File

@@ -0,0 +1,60 @@
use crate::{jose, yubikey_hmac};
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use clap::{App, Arg, ArgMatches, SubCommand};
use rand::random;
use rust_util::util_clap::{Command, CommandError};
use rust_util::{failure_and_exit, opt_result, success};
pub struct CommandImpl;
impl Command for CommandImpl {
fn name(&self) -> &str { "yubikey-init-master-key" }
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("Local mini KMS init yubikey")
.arg(Arg::with_name("yubikey-challenge").long("yubikey-challenge").short("c").takes_value(true).help("Yubikey challenge"))
.arg(Arg::with_name("key-hex").long("key-hex").short("x").takes_value(true).help("Key(hex), for encrypt"))
.arg(Arg::with_name("key-base64").long("key-base64").short("b").takes_value(true).help("Key(base64), for encrypt"))
.arg(Arg::with_name("generate-key").long("generate-key").short("K").help("Generate key"))
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let yubikey_challenge_opt = sub_arg_matches.value_of("yubikey-challenge").map(ToString::to_string);
let hex_value_opt = sub_arg_matches.value_of("key-hex");
let base64_value_opt = sub_arg_matches.value_of("key-base64");
let generate_key_present = sub_arg_matches.is_present("generate-key");
if hex_value_opt.is_none() && base64_value_opt.is_none() && !generate_key_present {
failure_and_exit!("--key-hex, --key-base64 or --generate-key must assign one");
}
let clear_master_key = if let Some(hex_value) = hex_value_opt {
opt_result!( hex::decode(hex_value), "Decode key-hex failed: {}")
} else if let Some(base64_value) = base64_value_opt {
opt_result!(STANDARD.decode(base64_value), "Decode key-base64 failed: {}")
} else {
let clear_master_key: [u8; 32] = random();
success!("Clear master key generated: {}", hex::encode(&clear_master_key));
clear_master_key.to_vec()
};
if clear_master_key.len() != 32 {
failure_and_exit!("Master key must be 32 bytes");
}
let yubikey_challenge = yubikey_challenge_opt.unwrap_or_else(
|| match rpassword::prompt_password("Yubikey challenge: ") {
Ok(yubikey_challenge) => yubikey_challenge,
Err(e) => failure_and_exit!("Read yubikey challenge failed: {}", e),
}
);
let challenge_key = opt_result!(
yubikey_hmac::yubikey_challenge_as_32_bytes(yubikey_challenge.as_bytes()), "Yubikey challenge failed: {}");
let encrypted_master_key = opt_result!(jose::serialize_jwe_aes(&clear_master_key, &challenge_key), "Encrypt master key failed: {}");
success!("Encrypted master key: {}", encrypted_master_key);
Ok(Some(0))
}
}