feat: v0.3.5, add subcommand yubikey-init-master-key
This commit is contained in:
@@ -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"))
|
||||
|
||||
60
src/yubikey_init_master_key.rs
Normal file
60
src/yubikey_init_master_key.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user