feat: supports yubikey init

This commit is contained in:
2023-08-13 21:26:16 +08:00
parent e16c28f2ab
commit b5e13dc13a
8 changed files with 393 additions and 48 deletions

259
Cargo.lock generated
View File

@@ -17,6 +17,18 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
"opaque-debug",
]
[[package]]
name = "ahash"
version = "0.8.3"
@@ -123,6 +135,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -132,6 +153,22 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-modes"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
dependencies = [
"block-padding",
"cipher",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "bumpalo"
version = "3.13.0"
@@ -180,6 +217,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array",
]
[[package]]
name = "clap"
version = "2.34.0"
@@ -229,19 +275,38 @@ dependencies = [
"typenum",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "deranged"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"block-buffer 0.10.4",
"crypto-common",
]
@@ -478,6 +543,16 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "http"
version = "0.2.9"
@@ -640,6 +715,18 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "libusb1-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22e89d08bbe6816c6c5d446203b859eba35b8fa94bf1b7edb2f6d25d43f023f"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
@@ -663,6 +750,7 @@ dependencies = [
"josekit",
"lazy_static",
"procfs",
"rpassword",
"rusqlite",
"rust_util",
"seckey",
@@ -672,6 +760,7 @@ dependencies = [
"serde_json",
"sha2",
"tokio",
"yubico_manager",
"zeroize",
]
@@ -762,6 +851,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.56"
@@ -784,7 +879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
]
@@ -841,6 +936,27 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-hack"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7f95648580798cc44ff8efb9bb0d7ee5205ea32e087b31b0732f3e8c2648ee2"
dependencies = [
"proc-macro-hack-impl",
]
[[package]]
name = "proc-macro-hack-impl"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be55bf0ae1635f4d7c7ddd6efc05c631e98a82104a73d35550bbc52db960027"
[[package]]
name = "proc-macro2"
version = "1.0.66"
@@ -865,6 +981,12 @@ dependencies = [
"rustix 0.35.14",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
[[package]]
name = "quote"
version = "1.0.32"
@@ -874,6 +996,36 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@@ -932,6 +1084,37 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "rpassword"
version = "7.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322"
dependencies = [
"libc",
"rtoolbox",
"winapi",
]
[[package]]
name = "rtoolbox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "rusb"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9a5084628cc5be77b1c750b3e5ee0cc519d2f2491b3f06b78b3aac3328b00ad"
dependencies = [
"libc",
"libusb1-sys",
]
[[package]]
name = "rusqlite"
version = "0.28.0"
@@ -1051,7 +1234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
]
@@ -1067,6 +1250,19 @@ dependencies = [
"serde",
]
[[package]]
name = "sha-1"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.7"
@@ -1075,7 +1271,7 @@ checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"digest 0.10.7",
]
[[package]]
@@ -1128,6 +1324,33 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structure"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8379aeb9cf8935b018b14d9191b15096e984ad8b77424b9bce075ea15d1fa59"
dependencies = [
"byteorder",
"proc-macro-hack",
"structure-macro-impl",
]
[[package]]
name = "structure-macro-impl"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c0529f2429c8bb5878688fffab7f700087f4bd47906e6acf03fd7361f77aca"
dependencies = [
"proc-macro-hack",
"quote 0.3.15",
]
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "2.0.28"
@@ -1135,7 +1358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"unicode-ident",
]
@@ -1185,7 +1408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
]
@@ -1243,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
]
@@ -1370,7 +1593,7 @@ dependencies = [
"log",
"once_cell",
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
"wasm-bindgen-shared",
]
@@ -1381,7 +1604,7 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"quote 1.0.32",
"wasm-bindgen-macro-support",
]
@@ -1392,7 +1615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.32",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
@@ -1582,6 +1805,22 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "yubico_manager"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff64094218f27836b8683bd93fa7f257475d217449eb7629746fa8eaee068eee"
dependencies = [
"aes",
"bitflags 1.3.2",
"block-modes",
"hmac",
"rand",
"rusb",
"sha-1",
"structure",
]
[[package]]
name = "zeroize"
version = "1.6.0"

View File

@@ -22,6 +22,8 @@ rust_util = { version = "0.6", features = ["use_clap"] }
tokio = { version = "1.19", features = ["full"] }
hyper = { version = "0.14", features = ["client", "server", "tcp", "http1", "http2"] }
rusqlite = "0.28"
yubico_manager = "0.9"
rpassword = "7.2"
[target.'cfg(target_os = "linux")'.dependencies]
procfs = "0.13"

View File

@@ -5,19 +5,33 @@ Mini-KMS runs local written by Rust
## Startup Server
```shell
./local-mini-kms serve
```
```shell
./local-mini-kms cli --init
local-mini-kms serve [--init-encrypted-master-key LKMS:*** [--yubikey-challenge *challenge*]]
```
## Local Client
```shell
./local-mini-kms cli --offline-init
local-mini-kms cli --init
```
```shell
local-mini-kms cli --offline-init
```
```shell
local-mini-kms cli --direct-init --value-base64 wNdr9sZN4**** [--yubikey-challenge *challenge*]
```
```shell
local-mini-kms cli --encrypt --value hello
```
```shell
local-mini-kms cli --decrypt --value LKMS:***
```
## cURL
Write value:
```shell
curl -X POST http://127.0.0.1:5567/write \

View File

@@ -8,7 +8,7 @@ use hyper::body::Buf;
use josekit::jwk::Jwk;
use rust_util::{debugging, opt_value_result, simple_error, success, XResult};
use rust_util::util_clap::{Command, CommandError};
use serde_json::{json, Value};
use serde_json::{json, Map, Value};
use crate::jose;
@@ -19,7 +19,7 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("Local mini KMS cli")
.arg(Arg::with_name("connect").long("connect").takes_value(true).default_value("127.0.0.1:5567").help("Connect server"))
.arg(Arg::with_name("connect").long("connect").short("C").takes_value(true).default_value("127.0.0.1:5567").help("Connect server"))
.arg(Arg::with_name("init").long("init").help("Init server"))
.arg(Arg::with_name("direct-init").long("direct-init").help("Direct init server"))
.arg(Arg::with_name("offline-init").long("offline-init").help("Offline init server"))
@@ -31,7 +31,8 @@ impl Command for CommandImpl {
.arg(Arg::with_name("key").long("key").takes_value(true).help("Read/Write key name"))
.arg(Arg::with_name("value-hex").long("value-hex").takes_value(true).help("Value(hex), for encrypt"))
.arg(Arg::with_name("value-base64").long("value-base64").takes_value(true).help("Value(base64), for encrypt"))
.arg(Arg::with_name("force-write").long("force-write").help("Force write value"))
.arg(Arg::with_name("yubikey-challenge").long("yubikey-challenge").short("c").takes_value(true).help("Yubikey challenge"))
.arg(Arg::with_name("force-write").long("force-write").short("F").help("Force write value"))
}
fn run(&self, arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
@@ -64,33 +65,22 @@ impl Command for CommandImpl {
}
async fn do_direct_init(_arg_matches: &ArgMatches<'_>, sub_arg_matches: &ArgMatches<'_>) -> CommandError {
let connect = sub_arg_matches.value_of("connect").expect("Get argument listen error");
let value_hex = sub_arg_matches.value_of("value-hex");
let value_base64 = sub_arg_matches.value_of("value-base64");
let yubikey_challenge = sub_arg_matches.value_of("yubikey-challenge");
let client = Client::new();
let uri = format!("http://{}/init", connect);
debugging!("Request uri: {}", &uri);
let body = if let Some(value_hex) = value_hex {
json!({
"clear_master_key_hex": value_hex,
})
let mut body_map = Map::new();
if let Some(value_hex) = value_hex {
body_map.insert("clear_master_key_hex".to_string(), value_hex.into());
} else if let Some(value_base64) = value_base64 {
json!({
"clear_master_key_base64": value_base64,
})
body_map.insert("clear_master_key_base64".to_string(), value_base64.into());
} else {
return simple_error!("Requires value hex or value base64");
};
let body = serde_json::to_string(&body)?;
let req = Request::builder().method(Method::POST).uri(uri).body(Body::from(body))?;
let req_response = client.request(req).await?;
if req_response.status() != StatusCode::OK {
let status = req_response.status().as_u16();
let data = response_to_value(req_response).await?;
return simple_error!("Server status is not success: {}, response: {}", status, data);
}
if let Some(yubikey_challenge) = yubikey_challenge {
body_map.insert("yubikey_challenge".to_string(), yubikey_challenge.into());
}
let _data = do_inner_request(sub_arg_matches, "init", &Value::Object(body_map)).await?;
success!("Init finished");
Ok(Some(0))
}

View File

@@ -6,6 +6,7 @@ mod db;
mod proc;
mod jose;
mod cli;
mod yubikey_hmac;
mod serve;
mod serve_common;
mod serve_status;

View File

@@ -5,17 +5,20 @@ use hyper::{Body, Client, Method, Request, Response, Server, StatusCode};
use hyper::client::HttpConnector;
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use rust_util::{failure_and_exit, information, success, XResult};
use rust_util::{failure_and_exit, information, success, warning, XResult};
use rust_util::util_clap::{Command, CommandError};
use serde_json::{json, Value};
use tokio::runtime::Runtime;
use crate::{db, jose, proc};
use crate::do_response;
use crate::serve_common::{self, GenericError, MemoryKey, Result};
use crate::serve_encrypt_decrypt;
use crate::serve_init;
use crate::serve_init::InitRequest;
use crate::serve_read_write;
use crate::serve_status;
use crate::yubikey_hmac;
pub struct CommandImpl;
@@ -24,8 +27,10 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("Local mini KMS serve")
.arg(Arg::with_name("listen").long("listen").takes_value(true).default_value("127.0.0.1:5567").help("Listen"))
.arg(Arg::with_name("local-db").long("local-db").takes_value(true).default_value("local-mini-kms.db").help("Local db file"))
.arg(Arg::with_name("listen").long("listen").short("L").takes_value(true).default_value("127.0.0.1:5567").help("Listen"))
.arg(Arg::with_name("local-db").long("local-db").short("d").takes_value(true).default_value("local-mini-kms.db").help("Local db file"))
.arg(Arg::with_name("yubikey-challenge").long("yubikey-challenge").short("c").takes_value(true).help("Yubikey challenge"))
.arg(Arg::with_name("init-encrypted-master-key").long("init-encrypted-master-key").short("k").takes_value(true).help("Init encrypted mater key"))
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
@@ -36,8 +41,10 @@ impl Command for CommandImpl {
Err(e) => failure_and_exit!("Init server failed: {}", e),
}
let rt = Runtime::new().expect("Create tokio runtime error");
init_with_yubikey_challenge(&rt, sub_arg_matches);
let listen = sub_arg_matches.value_of("listen").expect("Get argument listen error");
let rt = tokio::runtime::Runtime::new().expect("Create tokio runtime error");
rt.block_on(async {
let addr = listen.parse().expect(&format!("Parse listen error: {}", listen));
let client = Client::new();
@@ -156,3 +163,49 @@ Supports commands:
Ok(Response::builder().body("Root Not Found\n".into())?)
}
}
fn init_with_yubikey_challenge(rt: &Runtime, sub_arg_matches: &ArgMatches) {
let mut yubikey_challenge = sub_arg_matches.value_of("yubikey-challenge").map(ToString::to_string);
let init_encrypted_master_key = sub_arg_matches.value_of("init-encrypted-master-key");
if yubikey_challenge.is_none() {
yubikey_challenge = rpassword::prompt_password("Yubikey challenge: ").ok();
}
let (challenge_key, init_encrypted_master_key) = match (yubikey_challenge, init_encrypted_master_key) {
(Some(yubikey_challenge), Some(init_encrypted_master_key)) => {
match yubikey_hmac::yubikey_challenge_as_32_bytes(yubikey_challenge.as_bytes()) {
Err(e) => {
warning!("Yubikey challenge failed: {}", e);
return;
}
Ok(challenge_key) => (challenge_key, init_encrypted_master_key),
}
}
(Some(_), None) | (None, Some(_)) => {
warning!("Arguments yubikey-challenge and init-encrypted-master-key should both assigned.");
return;
}
_ => return,
};
match jose::deserialize_jwe_aes(&init_encrypted_master_key, &challenge_key) {
Err(e) => warning!("Yubikey seal master key failed: {}", e),
Ok((key, _)) => {
success!("Yubikey un-seal master key success");
let init_master_key_result = rt.block_on(async {
serve_init::inner_init_request(InitRequest {
yubikey_challenge: None,
clear_master_key_hex: Some(hex::encode(&key)),
clear_master_key_base64: None,
encrypted_master_key: None,
}).await
});
match init_master_key_result {
Err(e) => warning!("Init master key failed: {}", e),
Ok((StatusCode::OK, _)) => success!("Init master key success"),
Ok((_, response)) => warning!("Init master failed: {}", response),
}
}
}
}

View File

@@ -2,7 +2,7 @@ use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use hyper::{Body, Request, Response, StatusCode};
use hyper::body::Buf;
use rust_util::{debugging, information, opt_result, XResult};
use rust_util::{debugging, information, opt_result, success, warning, XResult};
use seckey::SecBytes;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
@@ -12,22 +12,28 @@ use crate::{db, jose};
use crate::db::Key;
use crate::do_response;
use crate::serve_common::{self, Result};
use crate::yubikey_hmac;
pub async fn init(req: Request<Body>) -> Result<Response<Body>> {
do_response!(inner_init(req).await)
}
#[derive(Serialize, Deserialize)]
struct InitRequest {
clear_master_key_hex: Option<String>,
clear_master_key_base64: Option<String>,
encrypted_master_key: Option<String>,
pub struct InitRequest {
pub yubikey_challenge: Option<String>,
pub clear_master_key_hex: Option<String>,
pub clear_master_key_base64: Option<String>,
pub encrypted_master_key: Option<String>,
}
async fn inner_init(req: Request<Body>) -> XResult<(StatusCode, Value)> {
let whole_body = hyper::body::aggregate(req).await?;
let init_request: InitRequest = serde_json::from_reader(whole_body.reader())?;
inner_init_request(init_request).await
}
pub async fn inner_init_request(init_request: InitRequest) -> XResult<(StatusCode, Value)> {
let mut startup_rw_lock = serve_common::STATUP_RW_LOCK.lock().expect("Lock read startup rw lock error");
match &*startup_rw_lock {
None => return Ok((StatusCode::INTERNAL_SERVER_ERROR, json!({ "error": "internal_error", "error_message": "not init " }))),
@@ -74,6 +80,17 @@ async fn inner_init(req: Request<Body>) -> XResult<(StatusCode, Value)> {
}
}
information!("Set master key success");
if let Some(yubikey_challenge) = &init_request.yubikey_challenge {
match yubikey_hmac::yubikey_challenge_as_32_bytes(yubikey_challenge.as_bytes()) {
Err(e) => warning!("Yubikey challenge failed: {}", e),
Ok(challenge_key) => match jose::serialize_jwe_aes(&clear_master_key, &challenge_key) {
Err(e) => warning!("Yubikey seal master key failed: {}", e),
Ok(jwe) => success!("Yubikey sealed master key: {}", jwe)
},
}
}
let sec_bytes = SecBytes::with(clear_master_key.len(), |buf| buf.copy_from_slice(&clear_master_key.as_slice()[..]));
let mut clear_master_key = clear_master_key;
clear_master_key.zeroize();

29
src/yubikey_hmac.rs Normal file
View File

@@ -0,0 +1,29 @@
use std::ops::Deref;
use rust_util::{opt_result, success, XResult};
use yubico_manager::config::{Config, Mode, Slot};
use yubico_manager::Yubico;
pub fn yubikey_challenge_as_32_bytes(challenge_bytes: &[u8]) -> XResult<Vec<u8>> {
let mut yubi = Yubico::new();
let device = opt_result!(yubi.find_yubikey(), "Find yubikey failed: {}");
success!("Found key, Vendor ID: {:?}, Product ID: {:?}", device.vendor_id, device.product_id);
let config = Config::default()
.set_vendor_id(device.vendor_id)
.set_product_id(device.product_id)
.set_variable_size(true)
.set_mode(Mode::Sha1)
.set_slot(Slot::Slot2);
// In HMAC Mode, the result will always be the SAME for the SAME provided challenge
let hmac_result = opt_result!(yubi.challenge_response_hmac(&challenge_bytes, config), "Challenge HMAC failed: {}");
// Just for debug, lets check the hex
let v: &[u8] = hmac_result.deref();
let mut r = vec![];
r.extend_from_slice(v);
r.extend_from_slice(&v[0..12]);
Ok(r)
}