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

28
Cargo.lock generated
View File

@@ -56,12 +56,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@@ -385,9 +379,9 @@ dependencies = [
[[package]] [[package]]
name = "fallible-iterator" name = "fallible-iterator"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]] [[package]]
name = "fallible-streaming-iterator" name = "fallible-streaming-iterator"
@@ -518,14 +512,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [ dependencies = [
"ahash", "ahash",
"allocator-api2",
] ]
[[package]] [[package]]
name = "hashlink" name = "hashlink"
version = "0.8.4" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
dependencies = [ dependencies = [
"hashbrown", "hashbrown",
] ]
@@ -715,9 +708,9 @@ dependencies = [
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.25.2" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"
dependencies = [ dependencies = [
"pkg-config", "pkg-config",
"vcpkg", "vcpkg",
@@ -749,7 +742,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]] [[package]]
name = "local-mini-kms" name = "local-mini-kms"
version = "0.3.4" version = "0.3.5"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"clap", "clap",
@@ -758,6 +751,7 @@ dependencies = [
"josekit", "josekit",
"lazy_static", "lazy_static",
"procfs", "procfs",
"rand",
"rpassword", "rpassword",
"rusqlite", "rusqlite",
"rust_util", "rust_util",
@@ -1131,11 +1125,11 @@ dependencies = [
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.28.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.6.0",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink", "hashlink",

View File

@@ -1,17 +1,17 @@
[package] [package]
name = "local-mini-kms" name = "local-mini-kms"
version = "0.3.4" version = "0.3.5"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
zeroize = "1.5" zeroize = "1.8"
clap = "2.33" clap = "2.34"
hex = "0.4" hex = "0.4"
base64 = "0.21" base64 = "0.21"
sha2 = "0.10" sha2 = "0.10"
lazy_static = "1.4" lazy_static = "1.5"
serde_derive = "1.0" serde_derive = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
@@ -19,11 +19,12 @@ josekit = "0.8"
secmem-proc = "0.3" secmem-proc = "0.3"
seckey = "0.12" seckey = "0.12"
rust_util = { version = "0.6", features = ["use_clap"] } rust_util = { version = "0.6", features = ["use_clap"] }
tokio = { version = "1.19", features = ["full"] } tokio = { version = "1.37", features = ["full"] }
hyper = { version = "0.14", features = ["client", "server", "tcp", "http1", "http2"] } hyper = { version = "0.14", features = ["client", "server", "tcp", "http1", "http2"] }
rusqlite = "0.28" rusqlite = "0.31"
yubico_manager = "0.9" yubico_manager = "0.9"
rpassword = "7.2" rpassword = "7.3"
rand = "0.8"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
procfs = "0.13" procfs = "0.13"

View File

@@ -2,8 +2,21 @@
Mini-KMS runs local written by Rust Mini-KMS runs local written by Rust
## Generate Yubikey encrypted master key
Generate encrypted master key with Yubikey:
```shell
local-mini-kms yubikey-init-master-key --generate-key [--yubikey-challenge *challenge*]
```
## Startup Server ## Startup Server
Startup without init:
```shell
local-mini-kms serve
```
Init with Yubikey:
```shell ```shell
local-mini-kms serve [--init-encrypted-master-key LKMS:*** [--yubikey-challenge *challenge*]] local-mini-kms serve [--init-encrypted-master-key LKMS:*** [--yubikey-challenge *challenge*]]
``` ```

View File

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