feat: update local-mini-kms
This commit is contained in:
172
Cargo.lock
generated
172
Cargo.lock
generated
@@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@@ -13,6 +19,15 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -22,6 +37,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -39,6 +60,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@@ -51,6 +78,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -72,6 +105,15 @@ dependencies = [
|
|||||||
"vec_map",
|
"vec_map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-next"
|
name = "dirs-next"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -105,12 +147,37 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
@@ -287,6 +354,24 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "josekit"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dee6af62ad98bdf699ad2ecc8323479a1fdc7aa5faa6043d93119d83f6c5fca8"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"base64",
|
||||||
|
"flate2",
|
||||||
|
"once_cell",
|
||||||
|
"openssl",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -313,9 +398,11 @@ dependencies = [
|
|||||||
name = "local-mini-kms"
|
name = "local-mini-kms"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
"hex",
|
"hex",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"josekit",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rust_util",
|
"rust_util",
|
||||||
@@ -350,6 +437,15 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -372,12 +468,60 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.12.0"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -457,6 +601,23 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusqlite"
|
name = "rusqlite"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
@@ -528,6 +689,7 @@ version = "1.0.82"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -634,6 +796,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.19.2"
|
version = "1.19.2"
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
base64 = "0.13.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
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"
|
||||||
|
josekit = "0.8.1"
|
||||||
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.19", features = ["full"] }
|
||||||
hyper = { version = "0.14.20", features = ["client", "server", "tcp", "http1", "http2"] }
|
hyper = { version = "0.14.20", features = ["client", "server", "tcp", "http1", "http2"] }
|
||||||
|
|||||||
32
src/db.rs
32
src/db.rs
@@ -1,5 +1,12 @@
|
|||||||
use rusqlite::{Connection, params};
|
use rusqlite::{Connection, params};
|
||||||
use rust_util::{debugging, information, opt_result, success, XResult};
|
use rust_util::{debugging, information, opt_result, simple_error, success, XResult};
|
||||||
|
|
||||||
|
pub const DEFAULT_MASTER_KEY_VERIFICATION_KEY: &'static str = "__master_verification_key";
|
||||||
|
|
||||||
|
pub struct Key {
|
||||||
|
name: String,
|
||||||
|
encrypted_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open_db(db: &str) -> XResult<Connection> {
|
pub fn open_db(db: &str) -> XResult<Connection> {
|
||||||
let con = opt_result!(Connection::open(db), "Open sqlite db: {}, failed: {}", db);
|
let con = opt_result!(Connection::open(db), "Open sqlite db: {}, failed: {}", db);
|
||||||
@@ -25,3 +32,26 @@ pub fn init_db(conn: &Connection) -> XResult<bool> {
|
|||||||
success!("Table keys created");
|
success!("Table keys created");
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_key(conn: &Connection, key: &Key) -> XResult<()> {
|
||||||
|
let _ = conn.execute(
|
||||||
|
"INSERT INTO keys (name, value) VALUES (?1, ?2)",
|
||||||
|
(&key.name, &key.encrypted_key),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_key(conn: &Connection, name: &str) -> XResult<Option<Key>> {
|
||||||
|
let mut stmt = conn.prepare("SELECT id, name, value FROM keys WHERE name = ?1")?;
|
||||||
|
let mut key_iter = stmt.query_map(params![name], |row| {
|
||||||
|
Ok(Key {
|
||||||
|
name: row.get(1)?,
|
||||||
|
encrypted_key: row.get(2)?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
match key_iter.next() {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(Ok(r)) => Ok(Some(r)),
|
||||||
|
Some(Err(e)) => simple_error!("Find key failed: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/jose.rs
Normal file
57
src/jose.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use josekit::jwe;
|
||||||
|
use josekit::jwe::alg::aeskw::AeskwJweAlgorithm;
|
||||||
|
use josekit::jwe::alg::rsaes::RsaesJweAlgorithm;
|
||||||
|
use josekit::jwe::JweHeader;
|
||||||
|
use josekit::jwk::{Jwk, KeyPair};
|
||||||
|
use josekit::jwk::alg::rsa::RsaKeyPair;
|
||||||
|
use rust_util::XResult;
|
||||||
|
|
||||||
|
pub fn generate_rsa_key(bits: u32) -> XResult<RsaKeyPair> {
|
||||||
|
Ok(RsaKeyPair::generate(bits)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_jwe_rsa(payload: &[u8], jwk: &Jwk) -> XResult<String> {
|
||||||
|
let mut header = JweHeader::new();
|
||||||
|
header.set_content_encryption("A256GCM");
|
||||||
|
let encrypter = RsaesJweAlgorithm::RsaOaep.encrypter_from_jwk(&jwk)?;
|
||||||
|
Ok(jwe::serialize_compact(payload, &header, &encrypter)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_jwe_rsa(jwe: &str, jwk: &Jwk) -> XResult<(Vec<u8>, JweHeader)> {
|
||||||
|
let decrypter = RsaesJweAlgorithm::RsaOaep.decrypter_from_jwk(jwk)?;
|
||||||
|
Ok(jwe::deserialize_json(jwe, &decrypter)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult<String> {
|
||||||
|
let mut header = JweHeader::new();
|
||||||
|
header.set_content_encryption("A256GCM");
|
||||||
|
let encrypter = AeskwJweAlgorithm::A256kw.encrypter_from_bytes(key)?;
|
||||||
|
Ok(jwe::serialize_compact(payload, &header, &encrypter)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_jwe_aes(jwe: &str, key: &[u8]) -> XResult<(Vec<u8>, JweHeader)> {
|
||||||
|
let decrypter = AeskwJweAlgorithm::A192kw.decrypter_from_bytes(key)?;
|
||||||
|
Ok(jwe::deserialize_json(jwe, &decrypter)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a() {
|
||||||
|
let k = generate_rsa_key(4096).unwrap();
|
||||||
|
let k = k.to_jwk_key_pair();
|
||||||
|
let kk = k.to_public_key().unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", k);
|
||||||
|
println!("{:?}", kk);
|
||||||
|
|
||||||
|
let mut header = JweHeader::new();
|
||||||
|
header.set_content_encryption("A256GCM");
|
||||||
|
let encrypter = RsaesJweAlgorithm::RsaOaep.encrypter_from_jwk(&kk).unwrap();
|
||||||
|
let payload = "helloworld";
|
||||||
|
let r = jwe::serialize_compact(payload.as_bytes(), &header, &encrypter);
|
||||||
|
|
||||||
|
println!("{:?}", r);
|
||||||
|
|
||||||
|
let k = "abcdefghijklmnopqrstuvwxyz123456";
|
||||||
|
let t = serialize_jwe_aes(payload.as_bytes(), k.as_bytes());
|
||||||
|
println!("{:?}", t);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ use rust_util::{failure_and_exit, information};
|
|||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
|
mod jose;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod serve;
|
mod serve;
|
||||||
|
|
||||||
|
|||||||
134
src/serve.rs
134
src/serve.rs
@@ -1,11 +1,17 @@
|
|||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use hyper::{Body, Client, Method, Request, Response, Server, StatusCode};
|
use hyper::{Body, Client, header, Method, Request, Response, Server, StatusCode};
|
||||||
|
use hyper::body::Buf;
|
||||||
use hyper::client::HttpConnector;
|
use hyper::client::HttpConnector;
|
||||||
use hyper::service::{make_service_fn, service_fn};
|
use hyper::service::{make_service_fn, service_fn};
|
||||||
use rust_util::{failure_and_exit, iff, information, success};
|
use josekit::jwk::alg::rsa::RsaKeyPair;
|
||||||
|
use rust_util::{failure_and_exit, iff, information, success, XResult};
|
||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
use crate::db;
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
use crate::jose;
|
||||||
|
|
||||||
type GenericError = Box<dyn std::error::Error + Send + Sync>;
|
type GenericError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
type Result<T> = std::result::Result<T, GenericError>;
|
type Result<T> = std::result::Result<T, GenericError>;
|
||||||
@@ -23,6 +29,12 @@ impl Command for CommandImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||||
|
match init_instance() {
|
||||||
|
Ok(true) => success!("Init server success"),
|
||||||
|
Ok(false) => failure_and_exit!("SHOULD NOT HAPPEN, server already init"),
|
||||||
|
Err(e) => failure_and_exit!("Init server failed: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
let listen = sub_arg_matches.value_of("listen").expect("Get argument listen error");
|
let listen = sub_arg_matches.value_of("listen").expect("Get argument listen error");
|
||||||
let rt = tokio::runtime::Runtime::new().expect("Create tokio runtime error");
|
let rt = tokio::runtime::Runtime::new().expect("Create tokio runtime error");
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
@@ -48,41 +60,131 @@ impl Command for CommandImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ref: https://github.com/hyperium/hyper/blob/master/examples/web_api.rs
|
// ref: https://github.com/hyperium/hyper/blob/master/examples/web_api.rs
|
||||||
|
// ref: https://crates.io/crates/rusqlite
|
||||||
async fn response_requests(
|
async fn response_requests(
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
_client: Client<HttpConnector>,
|
_client: Client<HttpConnector>,
|
||||||
) -> Result<Response<Body>> {
|
) -> Result<Response<Body>> {
|
||||||
match (req.method(), req.uri().path()) {
|
match (req.method(), req.uri().path()) {
|
||||||
// (&Method::GET, "/") | (&Method::GET, "/index.html") => Ok(Response::new(INDEX.into())),
|
(&Method::POST, "/init") => init(req).await,
|
||||||
// (&Method::GET, "/test.html") => client_request_response(&client).await,
|
(&Method::POST, "/decrypt") => decrypt(req).await,
|
||||||
|
(&Method::POST, "/encrypt") => encrypt(req).await,
|
||||||
(&Method::GET, "/status") => status().await,
|
(&Method::GET, "/status") => status().await,
|
||||||
(&Method::GET, "/version") => get_version().await,
|
(&Method::GET, "/version") => get_version().await,
|
||||||
_ => {
|
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND).body(NOTFOUND.into())?),
|
||||||
Ok(Response::builder()
|
|
||||||
.status(StatusCode::NOT_FOUND).body(NOTFOUND.into())
|
|
||||||
.expect("Response not found error"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
struct MemoryKey {
|
struct MemoryKey {
|
||||||
master_key: Vec<u8>,
|
instance_rsa_key_pair: RsaKeyPair,
|
||||||
|
master_key: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref STATUS_RW_LOCK: RwLock<bool> = RwLock::new(false);
|
static ref STATUP_RW_LOCK: RwLock<Option<MemoryKey>> = RwLock::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_instance() -> XResult<bool> {
|
||||||
|
let mut startup_rw_lock = STATUP_RW_LOCK.write().expect("Lock write startup rw lock error");
|
||||||
|
match &*startup_rw_lock {
|
||||||
|
Some(_) => Ok(false),
|
||||||
|
None => {
|
||||||
|
let memory_key = MemoryKey {
|
||||||
|
instance_rsa_key_pair: jose::generate_rsa_key(4096)?,
|
||||||
|
master_key: None,
|
||||||
|
};
|
||||||
|
*startup_rw_lock = Some(memory_key);
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn decrypt(req: Request<Body>) -> Result<Response<Body>> {
|
||||||
|
let whole_body = hyper::body::aggregate(req).await?;
|
||||||
|
let data: serde_json::Value = serde_json::from_reader(whole_body.reader())?;
|
||||||
|
Ok(Response::builder().body(format!("{}", data).into())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn encrypt(req: Request<Body>) -> Result<Response<Body>> {
|
||||||
|
let whole_body = hyper::body::aggregate(req).await?;
|
||||||
|
let data: serde_json::Value = serde_json::from_reader(whole_body.reader())?;
|
||||||
|
Ok(Response::builder().body(format!("{}", data).into())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct InitRequest {
|
||||||
|
clear_master_key_hex: Option<String>,
|
||||||
|
clear_master_key_base64: Option<String>,
|
||||||
|
encrypted_master_key: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(req: Request<Body>) -> Result<Response<Body>> {
|
||||||
|
let whole_body = hyper::body::aggregate(req).await?;
|
||||||
|
let init_request: InitRequest = serde_json::from_reader(whole_body.reader())?;
|
||||||
|
|
||||||
|
let mut startup_rw_lock = STATUP_RW_LOCK.write().expect("Lock read startup rw lock error");
|
||||||
|
let (status_code, body) = match &*startup_rw_lock {
|
||||||
|
None => (StatusCode::INTERNAL_SERVER_ERROR, json!({ "error": "internal_error", "error_message": "not init " })),
|
||||||
|
Some(memory_key) => match memory_key.master_key {
|
||||||
|
Some(_) => (StatusCode::BAD_REQUEST, json!({ "error": "bad_request", "error_message": "already init " })),
|
||||||
|
None => (StatusCode::OK, Value::Null),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if status_code != StatusCode::OK {
|
||||||
|
return Ok(Response::builder().status(status_code).body(serde_json::to_string_pretty(&body)?.into())?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (status_code, body) = if let Some(clear_master_key_base64) = init_request.clear_master_key_base64 {
|
||||||
|
let clear_master_key = base64::decode(clear_master_key_base64)?;
|
||||||
|
if clear_master_key.len() != 32 {
|
||||||
|
(StatusCode::BAD_REQUEST, json!({ "error": "bad_request", "error_message": "bad clear_master_key_hex length" }))
|
||||||
|
} else {
|
||||||
|
if let Some(k) = &mut *startup_rw_lock {
|
||||||
|
k.master_key = Some(clear_master_key);
|
||||||
|
}
|
||||||
|
(StatusCode::OK, json!({}))
|
||||||
|
}
|
||||||
|
} else if let Some(clear_master_key_hex) = init_request.clear_master_key_hex {
|
||||||
|
let clear_master_key = hex::decode(clear_master_key_hex)?;
|
||||||
|
if clear_master_key.len() != 32 {
|
||||||
|
(StatusCode::BAD_REQUEST, json!({ "error": "bad_request", "error_message": "bad clear_master_key_hex length" }))
|
||||||
|
} else {
|
||||||
|
if let Some(k) = &mut *startup_rw_lock {
|
||||||
|
k.master_key = Some(clear_master_key);
|
||||||
|
}
|
||||||
|
(StatusCode::OK, json!({}))
|
||||||
|
}
|
||||||
|
} else if let Some(encrypted_master_key) = init_request.encrypted_master_key {
|
||||||
|
// TODO ...
|
||||||
|
(StatusCode::BAD_REQUEST, json!({ "error": "not_implement", "error_message": "not_implement" }))
|
||||||
|
} else {
|
||||||
|
(StatusCode::BAD_REQUEST, json!({ "error": "bad_request", "error_message": "master key is not provided" }))
|
||||||
|
};
|
||||||
|
Ok(Response::builder().status(status_code).body(serde_json::to_string_pretty(&body)?.into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status() -> Result<Response<Body>> {
|
async fn status() -> Result<Response<Body>> {
|
||||||
let status_rw_lock = STATUS_RW_LOCK.read().expect("Lock read status rw lock error");
|
let startup_rw_lock = STATUP_RW_LOCK.read().expect("Lock read startup rw lock error");
|
||||||
let status_rw_lock_value = *status_rw_lock;
|
let body = match &*startup_rw_lock {
|
||||||
Ok(Response::builder().body(format!("{}\n", iff!(status_rw_lock_value, "init", "uninit")).into()).expect("x"))
|
None => json!({ "status": "n/a" }),
|
||||||
|
Some(memory_key) => match memory_key.master_key {
|
||||||
|
None => json!({
|
||||||
|
"status": "not-ready",
|
||||||
|
"instance_public_key_jwk": memory_key.instance_rsa_key_pair.to_jwk_key_pair().to_public_key()?,
|
||||||
|
}),
|
||||||
|
Some(_) => json!({
|
||||||
|
"status": "ready",
|
||||||
|
"instance_public_key_jwk": memory_key.instance_rsa_key_pair.to_jwk_key_pair().to_public_key()?,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Response::builder().body(serde_json::to_string_pretty(&body)?.into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_version() -> Result<Response<Body>> {
|
async fn get_version() -> Result<Response<Body>> {
|
||||||
Ok(Response::builder().body(format!(
|
Ok(Response::builder().body(format!(
|
||||||
"{} - {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")
|
"{} - {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")
|
||||||
).into()).expect("Response get_version error"))
|
).into())?)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user