From d4b3e22f689e909b6a029035560ebf9f04ef3f06 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Thu, 8 Sep 2022 22:55:56 +0300 Subject: [PATCH 1/7] HashiCorp feature --- .gitignore | 4 + Cargo.lock | 769 ++++++++++++++-- Cargo.toml | 9 + README.hashicorp.md | 167 ++++ src/commands.rs | 13 + src/commands/hashicorp.rs | 37 + src/commands/hashicorp/test.rs | 78 ++ src/commands/hashicorp/upload.rs | 299 ++++++ src/commands/init/config_builder.rs | 10 + .../init/templates/keyring/hashicorp.toml | 9 + src/config/provider.rs | 9 + src/config/provider/hashicorp.rs | 21 + src/keyring.rs | 3 + src/keyring/providers.rs | 10 + src/keyring/providers/hashicorp.rs | 80 ++ src/keyring/providers/hashicorp/client.rs | 490 ++++++++++ src/keyring/providers/hashicorp/error.rs | 53 ++ src/keyring/providers/hashicorp/signer.rs | 28 + src/lib.rs | 5 +- tests/cli/init.rs | 82 +- tests/integration.rs | 870 +++++++++--------- tmkms-hashicorp.toml | 41 + 22 files changed, 2549 insertions(+), 538 deletions(-) create mode 100644 README.hashicorp.md create mode 100644 src/commands/hashicorp.rs create mode 100644 src/commands/hashicorp/test.rs create mode 100644 src/commands/hashicorp/upload.rs create mode 100644 src/commands/init/templates/keyring/hashicorp.toml create mode 100644 src/config/provider/hashicorp.rs create mode 100644 src/keyring/providers/hashicorp.rs create mode 100644 src/keyring/providers/hashicorp/client.rs create mode 100644 src/keyring/providers/hashicorp/error.rs create mode 100644 src/keyring/providers/hashicorp/signer.rs create mode 100644 tmkms-hashicorp.toml diff --git a/.gitignore b/.gitignore index e134f360..02a38871 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ tmkms.toml *.swp \.idea/ +/state +/secrets +/.vscode +**/*.bin diff --git a/Cargo.lock b/Cargo.lock index 30441709..b7792eb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32ce48eff491a0ab32c0e1cadd7ba5221a38dc53438992c5e857ab9b8a3f1a3e" dependencies = [ "abscissa_core", - "tokio", + "tokio 1.20.1", ] [[package]] @@ -96,6 +96,29 @@ dependencies = [ "cpufeatures 0.2.2", ] +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead 0.5.1", + "aes", + "cipher 0.4.3", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-kw" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" +dependencies = [ + "aes", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -120,7 +143,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -147,6 +170,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109" +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-trait" version = "0.1.57" @@ -166,7 +199,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -196,6 +229,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -374,7 +413,7 @@ dependencies = [ "num-traits", "time 0.1.44", "wasm-bindgen", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -465,6 +504,23 @@ dependencies = [ "owo-colors", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi 0.3.9", +] + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "const-oid" version = "0.9.0" @@ -536,6 +592,16 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "crypto-bigint" version = "0.4.8" @@ -609,13 +675,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid 0.7.1", + "crypto-bigint 0.3.2", + "pem-rfc7468", +] + [[package]] name = "der" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" dependencies = [ - "const-oid", + "const-oid 0.9.0", "zeroize", ] @@ -645,7 +722,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bd46e0c364655e5baf2f5e99b603e7a09905da9966d7928d7470af393b28670" dependencies = [ - "der", + "der 0.6.0", "elliptic-curve", "rfc6979", "signature", @@ -668,7 +745,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek", "ed25519", - "rand", + "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", @@ -687,19 +764,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ "base16ct", - "crypto-bigint", - "der", + "crypto-bigint 0.4.8", + "der 0.6.0", "digest 0.10.3", "ff", "generic-array", "group", - "pkcs8", + "pkcs8 0.9.0", "rand_core 0.6.3", "sec1", "subtle", "zeroize", ] +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "eyre" version = "0.6.8" @@ -807,6 +893,22 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd79fa345a495d3ae89fb7165fec01c0e72f41821d642dda363a1e97975652e" +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "futures" version = "0.3.23" @@ -891,7 +993,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.9", "pin-utils", "slab", ] @@ -930,6 +1032,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.26.2" @@ -947,6 +1059,26 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio 0.2.25", + "tokio-util 0.3.1", + "tracing", + "tracing-futures", +] + [[package]] name = "h2" version = "0.3.13" @@ -961,8 +1093,8 @@ dependencies = [ "http", "indexmap", "slab", - "tokio", - "tokio-util", + "tokio 1.20.1", + "tokio-util 0.7.3", "tracing", ] @@ -972,18 +1104,35 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashicorp_vault" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd636b56a3e214f65bc9fec3217c3add72a424740162643267892149e992eb2" +dependencies = [ + "base64 0.12.3", + "chrono", + "log", + "quick-error", + "reqwest", + "serde", + "serde_derive", + "serde_json", + "url 2.2.2", +] + [[package]] name = "headers" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ - "base64", + "base64 0.13.0", "bitflags", "bytes 1.2.1", "headers-core", "http", - "httpdate", + "httpdate 1.0.2", "mime", "sha-1", ] @@ -1090,7 +1239,17 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes 1.2.1", "fnv", - "itoa", + "itoa 1.0.3", +] + +[[package]] +name = "http-body" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +dependencies = [ + "bytes 0.5.6", + "http", ] [[package]] @@ -1101,7 +1260,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.2.1", "http", - "pin-project-lite", + "pin-project-lite 0.2.9", ] [[package]] @@ -1110,12 +1269,42 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + [[package]] name = "httpdate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "hyper" +version = "0.13.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" +dependencies = [ + "bytes 0.5.6", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.2.7", + "http", + "http-body 0.3.1", + "httparse", + "httpdate 0.3.2", + "itoa 0.4.8", + "pin-project", + "socket2 0.3.19", + "tokio 0.2.25", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "0.14.20" @@ -1126,15 +1315,15 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.13", "http", - "http-body", + "http-body 0.4.5", "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", + "httpdate 1.0.2", + "itoa 1.0.3", + "pin-project-lite 0.2.9", + "socket2 0.4.4", + "tokio 1.20.1", "tower-service", "tracing", "want", @@ -1150,10 +1339,10 @@ dependencies = [ "futures", "headers", "http", - "hyper", + "hyper 0.14.20", "hyper-rustls 0.22.1", "rustls-native-certs 0.5.0", - "tokio", + "tokio 1.20.1", "tokio-rustls 0.22.0", "tower-service", "webpki 0.21.4", @@ -1167,11 +1356,11 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ "ct-logs", "futures-util", - "hyper", + "hyper 0.14.20", "log", "rustls 0.19.1", "rustls-native-certs 0.5.0", - "tokio", + "tokio 1.20.1", "tokio-rustls 0.22.0", "webpki 0.21.4", "webpki-roots 0.21.1", @@ -1184,15 +1373,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ "http", - "hyper", + "hyper 0.14.20", "log", "rustls 0.20.6", "rustls-native-certs 0.6.2", - "tokio", + "tokio 1.20.1", "tokio-rustls 0.23.4", "webpki-roots 0.22.4", ] +[[package]] +name = "hyper-tls" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +dependencies = [ + "bytes 0.5.6", + "hyper 0.13.10", + "native-tls", + "tokio 0.2.25", + "tokio-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.44" @@ -1203,7 +1405,7 @@ dependencies = [ "core-foundation-sys", "js-sys", "wasm-bindgen", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1269,6 +1471,21 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + [[package]] name = "itertools" version = "0.7.11" @@ -1287,6 +1504,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.3" @@ -1321,11 +1544,24 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "ledger" @@ -1349,6 +1585,12 @@ version = "0.2.131" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40" +[[package]] +name = "libm" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" + [[package]] name = "libusb1-sys" version = "0.6.4" @@ -1419,6 +1661,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1428,6 +1680,25 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "0.8.4" @@ -1440,6 +1711,36 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "mockito" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401edc088069634afaa5f4a29617b36dba683c0c16fe4435a86debad23fa2f1a" +dependencies = [ + "assert-json-diff", + "colored", + "httparse", + "lazy_static", + "log", + "rand 0.8.5", + "regex", + "serde_json", + "serde_urlencoded", + "similar", +] + [[package]] name = "native-tls" version = "0.2.10" @@ -1458,6 +1759,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + [[package]] name = "nix" version = "0.13.1" @@ -1471,6 +1783,23 @@ dependencies = [ "void", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566d173b2f9406afbc5510a90925d5a2cd80cae4605631f1212303df265de011" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -1492,6 +1821,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1499,6 +1839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1662,6 +2003,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" +[[package]] +name = "pem-rfc7468" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "1.0.1" @@ -1694,6 +2044,12 @@ dependencies = [ "syn", ] +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1706,14 +2062,36 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" +dependencies = [ + "der 0.5.1", + "pkcs8 0.8.0", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der 0.5.1", + "spki 0.5.4", + "zeroize", +] + [[package]] name = "pkcs8" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.0", + "spki 0.6.0", ] [[package]] @@ -1730,7 +2108,19 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures 0.2.2", "opaque-debug", - "universal-hash", + "universal-hash 0.4.1", +] + +[[package]] +name = "polyval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures 0.2.2", + "opaque-debug", + "universal-hash 0.5.0", ] [[package]] @@ -1852,11 +2242,22 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha", + "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1867,6 +2268,16 @@ dependencies = [ "rand_core 0.5.1", ] +[[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 0.6.3", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -1935,7 +2346,42 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi", + "winapi 0.3.9", +] + +[[package]] +name = "reqwest" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" +dependencies = [ + "base64 0.13.0", + "bytes 0.5.6", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body 0.3.1", + "hyper 0.13.10", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding 2.1.0", + "pin-project-lite 0.2.9", + "serde", + "serde_urlencoded", + "tokio 0.2.25", + "tokio-tls", + "url 2.2.2", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", ] [[package]] @@ -1944,7 +2390,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.8", "hmac 0.12.1", "zeroize", ] @@ -1961,7 +2407,7 @@ dependencies = [ "spin 0.5.2", "untrusted", "web-sys", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1993,7 +2439,27 @@ dependencies = [ "libc", "serde", "serde_json", - "winapi", + "winapi 0.3.9", +] + +[[package]] +name = "rsa" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" +dependencies = [ + "byteorder", + "digest 0.10.3", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8 0.8.0", + "rand_core 0.6.3", + "smallvec", + "subtle", + "zeroize", ] [[package]] @@ -2029,7 +2495,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.0", "log", "ring", "sct 0.6.1", @@ -2078,7 +2544,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ - "base64", + "base64 0.13.0", ] [[package]] @@ -2138,7 +2604,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "474a033e7cb7c343a496026464a55bee3d98bc308d2f2ed53a9d8a21c68e1419" dependencies = [ - "base64", + "base64 0.13.0", "bitflags", "headers", "log", @@ -2158,9 +2624,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", - "der", + "der 0.6.0", "generic-array", - "pkcs8", + "pkcs8 0.9.0", "subtle", "zeroize", ] @@ -2242,7 +2708,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ - "itoa", + "itoa 1.0.3", "ryu", "serde", ] @@ -2258,6 +2724,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.3", + "ryu", + "serde", +] + [[package]] name = "sha-1" version = "0.10.0" @@ -2335,6 +2813,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "similar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803" + [[package]] name = "simple-hyper-client" version = "0.1.0" @@ -2344,8 +2828,8 @@ dependencies = [ "futures-executor", "headers", "http", - "hyper", - "tokio", + "hyper 0.14.20", + "tokio 1.20.1", "tokio-native-tls", "tokio-stream", ] @@ -2365,6 +2849,17 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] + [[package]] name = "socket2" version = "0.4.4" @@ -2372,7 +2867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2390,6 +2885,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der 0.5.1", +] + [[package]] name = "spki" version = "0.6.0" @@ -2397,7 +2902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.0", ] [[package]] @@ -2476,7 +2981,7 @@ dependencies = [ "libc", "redox_syscall", "remove_dir_all", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2581,7 +3086,7 @@ dependencies = [ "futures", "getrandom 0.2.7", "http", - "hyper", + "hyper 0.14.20", "hyper-proxy", "hyper-rustls 0.22.1", "peg", @@ -2595,7 +3100,7 @@ dependencies = [ "tendermint-proto", "thiserror", "time 0.3.11", - "tokio", + "tokio 1.20.1", "tracing", "url 2.2.2", "uuid 0.8.2", @@ -2660,7 +3165,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2669,7 +3174,7 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ - "itoa", + "itoa 1.0.3", "libc", "num_threads", "serde", @@ -2716,6 +3221,9 @@ version = "0.12.2" dependencies = [ "abscissa_core", "abscissa_tokio", + "aes-gcm", + "aes-kw", + "base64 0.13.0", "byteorder", "bytes 0.5.6", "bytes 1.2.1", @@ -2726,20 +3234,24 @@ dependencies = [ "elliptic-curve", "eyre", "getrandom 0.2.7", + "hashicorp_vault", "hkd32", "hkdf 0.12.3", - "hyper", + "hyper 0.14.20", "hyper-rustls 0.23.0", "k256", "ledger", + "mockito", "once_cell", "prost", "prost-amino", "prost-amino-derive", "prost-derive", - "rand", + "rand 0.7.3", + "rand 0.8.5", "rand_core 0.6.3", "rpassword", + "rsa", "sdkms", "serde", "serde_json", @@ -2762,6 +3274,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tokio" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "iovec", + "lazy_static", + "memchr", + "mio 0.6.23", + "num_cpus", + "pin-project-lite 0.1.12", + "slab", +] + [[package]] name = "tokio" version = "1.20.1" @@ -2772,13 +3302,13 @@ dependencies = [ "bytes 1.2.1", "libc", "memchr", - "mio", + "mio 0.8.4", "num_cpus", "once_cell", - "pin-project-lite", - "socket2", + "pin-project-lite 0.2.9", + "socket2 0.4.4", "tokio-macros", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2799,7 +3329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio", + "tokio 1.20.1", ] [[package]] @@ -2809,7 +3339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls 0.19.1", - "tokio", + "tokio 1.20.1", "webpki 0.21.4", ] @@ -2820,7 +3350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ "rustls 0.20.6", - "tokio", + "tokio 1.20.1", "webpki 0.22.0", ] @@ -2831,8 +3361,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" dependencies = [ "futures-core", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.9", + "tokio 1.20.1", +] + +[[package]] +name = "tokio-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +dependencies = [ + "native-tls", + "tokio 0.2.25", +] + +[[package]] +name = "tokio-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +dependencies = [ + "bytes 0.5.6", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.1.12", + "tokio 0.2.25", ] [[package]] @@ -2844,8 +3398,8 @@ dependencies = [ "bytes 1.2.1", "futures-core", "futures-sink", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.9", + "tokio 1.20.1", "tracing", ] @@ -2871,7 +3425,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", - "pin-project-lite", + "log", + "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", ] @@ -2897,6 +3452,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.3" @@ -2938,6 +3503,15 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -2975,6 +3549,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.7.1" @@ -3061,7 +3645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi", + "winapi 0.3.9", "winapi-util", ] @@ -3100,6 +3684,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if 1.0.0", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -3118,6 +3704,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.82" @@ -3195,6 +3793,12 @@ dependencies = [ "webpki 0.22.0", ] +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -3205,6 +3809,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -3217,7 +3827,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3269,6 +3879,25 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "x25519-dalek" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index 24aae865..3a6a1ef4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,10 +61,18 @@ wait-timeout = "0.2" yubihsm = { version = "0.41", features = ["secp256k1", "setup", "usb"], optional = true } zeroize = "1" +hashicorp_vault = { version = "2.1.0", optional = true } +base64 = { version = "0.13.0", optional = true} +aes-kw = { version = "0.2.1", features = ["std"], optional = true} +rsa = { version = "0.6.1", default = true, optional = true} +rand = { version = "0.8", optional = true} +aes-gcm = { version = "0.10.1", optional = true} + [dev-dependencies] abscissa_core = { version = "0.6", features = ["testing"] } byteorder = "1" rand = "0.7" +mockito = "0.31.0" [features] softsign = [] @@ -72,6 +80,7 @@ tx-signer = ["abscissa_tokio", "hyper", "hyper-rustls", "stdtx", "tendermint-rpc yubihsm-mock = ["yubihsm/mockhsm"] yubihsm-server = ["yubihsm/http-server", "rpassword"] fortanixdsm = ["elliptic-curve", "sdkms", "url", "uuid"] +hashicorp = ["hashicorp_vault", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] # Enable integer overflow checks in release builds for security reasons [profile.release] diff --git a/README.hashicorp.md b/README.hashicorp.md new file mode 100644 index 00000000..b4a212a2 --- /dev/null +++ b/README.hashicorp.md @@ -0,0 +1,167 @@ +# HashiCorp Vault + TMKMS + +HashiCorp Vault's `transit` engine mainly designed for data-in-transit encryption, it also provides additional features (sign and verify data, generate hashes and HMACs of data, and act as a source of random bytes). + +This implementation will use Vault as `signer as a service` where private key will not ever leave Vault + + +This document describes how to configure HashiCorp Vault for production use with Tendermint KMS. + +## Setting up Vault for `signer-as-service` +Start vault instance as per Hashicorp tutorial + +following script sets up Vault's configuration. Script designed for single chain signing... Extend it with additional keys+policies for additional chains. These are steps for `admin` +``` +#!/bin/bash +#login with root token +vault login + +echo "\nenabling transit engine..." +vault secrets enable transit +echo "\nenabling transit's engine sign path..." +vault secrets enable -path=sign transit + +echo "\ncreating cosmoshub signing key..." +vault write transit/keys/cosmoshub-sign-key type=ed25519 + +echo "\ncreating policy..." +cat < vault write transit/sign/<...sign key...> plaintext=$(base64 <<< "some-data") +``` + + +## Compiling `tmkms` with HashiCorp Vault support + +Refer the main README.md for compiling `tmkms` +from source code. You will need the prerequisities mentioned as indicated above. + +There are two ways to install `tmkms` with HashiCorp Vault, you need to pass the `--features=hashicorp` parameter to cargo. + +### Compiling from source code (via git) + +`tmkms` can be compiled directly from the git repository source code using the +following method. + +``` +$ git clone https://github.com/iqlusioninc/tmkms.git && cd tmkms +[...] +$ cargo build --release --features=hashicorp +``` + +If successful, this will produce a `tmkms` executable located at +`./target/release/tmkms` + +### Installing with the `cargo install` command + +With Rust (1.40+) installed, you can install tmkms with the following: + +``` +cargo install tmkms --features=hashicorp +``` + +Or to install a specific version (recommended): + +``` +cargo install tmkms --features=hashicorp --version=0.4.0 +``` + +This command installs `tmkms` directly from packages hosted on Rust's +[crates.io] service. Package authenticity is verified via the +[crates.io index] (itself a git repository) and by SHA-256 digests of +released artifacts. + +However, if newer dependencies are available, it may use newer versions +besides the ones which are "locked" in the source code repository. We +cannot verify those dependencies do not contain malicious code. If you would +like to ensure the dependencies in use are identical to the main repository, +please build from source code instead. + + +to run +``` +cargo run --features=hashicorp -- -c /path/to/tmkms.toml +``` + +## Production HashiCorp Vault setup + +`tmkms` contains support for HashiCorp Vault service, which enables tmkms to access the secure keys, stored in HashiCorp Vault's transit engine. This requires creation of the keys in Vault which can be done by referring to this [guide](https://www.vaultproject.io/docs/secrets/transit). Creating the key for signing and export should enable tmkms to use the keys on HashiCorp Vault. + +### Configuring `tmkms` for initial setup + +In order to perform setup, `tmkms` needs a configuration file which +contains the authentication details needed to authenticate to the HashiCorp Vault with an access token. + +This configuration should be placed in a file called: `tmkms.toml`. +You can specifty the path to the config with either `-c /path/to/tmkms.toml` or else tmkms will look in the current working directory for the same file. + +example: +```toml +[[providers.hashicorp]] +chain_id = "<...chain id...>" +api_endpoint= "https://<...host...>:8200" +access_token="<...token...>" +pk_key_name="<...ed25519 signing key...>" +``` + +You can [get](https://learn.hashicorp.com/tutorials/vault/tokens) the access token from the HashiCorp Vault. + +### Generating keys in HashiCorp Vault, transit engine +1. Enable transit engine +```bash +vault secrets enable transit +``` +2. Enable sign path on transit engine +```bash +vault secrets enable -path=sign transit +``` +3. Create a key +```bash +vault write transit/keys/<..key-name...> type=ed25519 +``` +4. Create a policy for the key + ```bash +vault policy write tmkms-transit-sign-policy - +path "transit/sign/<...key name...>" { + capabilities = [ "update"] +} +#used by HashiCorp API to verify connectivity on startup +path "auth/token/lookup-self" { + capabilities = [ "read" ] +} +``` +5. Create access token for the policy above +```bash +vault token create \ + -policy=tmkms-transit-sign-policy \ + -no-default-policy \ + -non-interactive \ + -renewable=false \ + -period=0 +``` +6. To import an existing tendermint key (this is TODO). +``` diff --git a/src/commands.rs b/src/commands.rs index cff0c176..4b60b474 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,5 +1,7 @@ //! Subcommands of the `tmkms` command-line application +#[cfg(feature = "hashicorp")] +pub mod hashicorp; pub mod init; #[cfg(feature = "ledger")] pub mod ledger; @@ -10,6 +12,8 @@ pub mod version; #[cfg(feature = "yubihsm")] pub mod yubihsm; +#[cfg(feature = "hashicorp")] +pub use self::hashicorp::HashicorpCommand; #[cfg(feature = "ledger")] pub use self::ledger::LedgerCommand; #[cfg(feature = "softsign")] @@ -50,6 +54,11 @@ pub enum KmsCommand { #[cfg(feature = "yubihsm")] #[clap(subcommand)] Yubihsm(YubihsmCommand), + + /// subcommands for HashiCorp + #[cfg(feature = "hashicorp")] + #[clap(subcommand)] + Hashicorp(HashicorpCommand), } impl KmsCommand { @@ -59,6 +68,8 @@ impl KmsCommand { KmsCommand::Start(run) => run.verbose, #[cfg(feature = "yubihsm")] KmsCommand::Yubihsm(yubihsm) => yubihsm.verbose(), + #[cfg(feature = "hashicorp")] + KmsCommand::Hashicorp(hashicorp) => hashicorp.verbose(), _ => false, } } @@ -74,6 +85,8 @@ impl Configurable for KmsCommand { KmsCommand::Yubihsm(yubihsm) => yubihsm.config_path(), #[cfg(feature = "ledger")] KmsCommand::Ledger(ledger) => ledger.config_path(), + #[cfg(feature = "hashicorp")] + KmsCommand::Hashicorp(hashicorp) => hashicorp.config_path(), _ => return None, }; diff --git a/src/commands/hashicorp.rs b/src/commands/hashicorp.rs new file mode 100644 index 00000000..2345decc --- /dev/null +++ b/src/commands/hashicorp.rs @@ -0,0 +1,37 @@ +//! `tmkms hashicorp` CLI (sub)commands + +mod test; +mod upload; + +pub use self::test::TestCommand; +pub use self::upload::UploadCommand; + +use abscissa_core::{Command, Runnable}; +use clap::Subcommand; +use std::path::PathBuf; + +/// `hashicorp` subcommand +#[derive(Command, Debug, Runnable, Subcommand)] +pub enum HashicorpCommand { + /// perform a signing test + Test(TestCommand), + + /// upload priv/pub key + Upload(UploadCommand), +} + +impl HashicorpCommand { + pub(super) fn config_path(&self) -> Option<&PathBuf> { + match self { + HashicorpCommand::Test(init) => init.config.as_ref(), + HashicorpCommand::Upload(init) => init.config.as_ref(), + } + } + + pub(super) fn verbose(&self) -> bool { + match self { + HashicorpCommand::Test(test) => test.verbose, + HashicorpCommand::Upload(test) => test.verbose, + } + } +} diff --git a/src/commands/hashicorp/test.rs b/src/commands/hashicorp/test.rs new file mode 100644 index 00000000..7895a1f3 --- /dev/null +++ b/src/commands/hashicorp/test.rs @@ -0,0 +1,78 @@ +//! Test the Hashicorp is working by performing signatures successively + +use crate::prelude::*; +use abscissa_core::{Command, Runnable}; +use clap::Parser; +use signature::SignerMut; +use std::{path::PathBuf, process, time::Instant}; + +/// The `hashicorp test` subcommand +#[derive(Command, Debug, Default, Parser)] +pub struct TestCommand { + /// path to tmkms.toml + #[clap( + short = 'c', + long = "config", + value_name = "CONFIG", + help = "/path/to/tmkms.toml" + )] + pub config: Option, + /// enable verbose debug logging + #[clap(short = 'v', long = "verbose")] + pub verbose: bool, + + /// Ed25519 signing key ID in Hashicorp Vault + #[clap(help = "Vault's transit secret engine signing key")] + pk_name: String, + + ///test message + #[clap(help = "message to sign")] + test_messsage: String, +} + +impl Runnable for TestCommand { + /// Perform a signing test using the current TMKMS configuration + fn run(&self) { + if self.pk_name.is_empty() { + status_err!("pk_name cannot be empty!"); + process::exit(1); + } + + let config = APP.config(); + + let config = if let Some(c) = config + .providers + .hashicorp + .iter() + .find(|c| c.pk_name == self.pk_name) + { + c + } else { + status_err!("pk_name is not configured in provided \"tmkms.toml\"!"); + process::exit(1); + }; + + let started_at = Instant::now(); + + let app = crate::keyring::providers::hashicorp::client::TendermintValidatorApp::connect( + &config.api_endpoint, + &config.access_token, + &self.pk_name, + ) + .expect(&format!( + "Unable to connect to Vault at {}", + config.api_endpoint + )); + + let mut app = + crate::keyring::providers::hashicorp::signer::Ed25519HashiCorpAppSigner::new(app); + + let signature = app.try_sign(self.test_messsage.as_bytes()).unwrap(); + + println!( + "Elapsed:{} ms. Result: {:?}", + started_at.elapsed().as_millis(), + signature + ); + } +} diff --git a/src/commands/hashicorp/upload.rs b/src/commands/hashicorp/upload.rs new file mode 100644 index 00000000..f073710b --- /dev/null +++ b/src/commands/hashicorp/upload.rs @@ -0,0 +1,299 @@ +//! Test the Hashicorp is working by performing signatures successively + +use crate::{config::provider::hashicorp::HashiCorpConfig, prelude::*}; +use abscissa_core::{Command, Runnable}; +use aes_kw; +use clap::Parser; +use serde::Serialize; +use std::{path::PathBuf, process}; + +use crate::keyring::providers::hashicorp::{client, error}; +use rsa::{pkcs8::DecodePublicKey, PaddingScheme, PublicKey, RsaPublicKey}; + +///AES256 key length +const KEY_SIZE_AES256: usize = 32; //256 bits +///PKCS8 header +const PKCS8_HEADER: &[u8; 16] = b"\x30\x2e\x02\x01\x00\x30\x05\x06\x03\x2b\x65\x70\x04\x22\x04\x20"; + +/// The `hashicorp test` subcommand +#[derive(Command, Debug, Default, Parser)] +pub struct UploadCommand { + /// path to tmkms.toml + #[clap( + short = 'c', + long = "config", + value_name = "CONFIG", + help = "/path/to/tmkms.toml" + )] + pub config: Option, + + /// enable verbose debug logging + #[clap(short = 'v', long = "verbose")] + pub verbose: bool, + + ///key ID in Hashicorp Vault + #[clap(help = "Key ID")] + pk_name: String, + + /// base64 encoded key to upload + #[clap(long = "payload")] + pub payload: String, +} +///Import Secret Key Request +#[derive(Debug, Serialize)] +struct ImportRequest { + #[serde(default = "ed25519")] + r#type: String, + + ciphertext: String, +} + +impl Runnable for UploadCommand { + /// Perform a import using the current TMKMS configuration + fn run(&self) { + if self.pk_name.is_empty() { + status_err!("pk_name cannot be empty!"); + process::exit(1); + } + + let config = APP.config(); + + //finding key in config will point to correct Vault's URL + let config = if let Some(c) = config + .providers + .hashicorp + .iter() + .find(|c| c.pk_name == self.pk_name) + { + c + } else { + let cfg_path = if let Some(path) = self.config.as_ref() { + path.clone() + } else { + PathBuf::from("./tmkms.toml") + }; + status_err!( + "pk_name is not configured in provided \"{}\"!", + cfg_path.as_path().to_str().unwrap() + ); + process::exit(1); + }; + + self.upload(&config); + } +} + +impl UploadCommand { + fn upload(&self, config: &HashiCorpConfig) { + //https://www.vaultproject.io/docs/secrets/transit#bring-your-own-key-byok + //https://learn.hashicorp.com/tutorials/vault/eaas-transit + + //root token or token with enough admin rights + let vault_token = std::env::var("VAULT_TOKEN") + .expect("root token \"VAULT_TOKEN\" is not set (confg token is NOT used)!"); + + let ed25519_input_key = input_key(&self.payload) + .expect("secret: error converting \"key-to-upload\"[ed25519] with PKCS8 wrapping"); + + //create app instance + let app = client::TendermintValidatorApp::connect( + &config.api_endpoint, + &vault_token, + &self.pk_name, + ) + .expect(&format!( + "Unable to connect to Vault at {}", + config.api_endpoint + )); + + use aes_gcm::KeyInit; + let v_aes_key = aes_gcm::Aes256Gcm::generate_key(&mut aes_gcm::aead::OsRng); + debug_assert_eq!( + KEY_SIZE_AES256, + v_aes_key.len(), + "expected aes key length {}, actual:{}", + KEY_SIZE_AES256, + v_aes_key.len() + ); + + let mut aes_key = [0u8; KEY_SIZE_AES256]; + aes_key.copy_from_slice(&v_aes_key[..KEY_SIZE_AES256]); + + let kek = aes_kw::KekAes256::from(aes_key.clone()); + let wrapped_input_key = kek + .wrap_with_padding_vec(&ed25519_input_key) + .expect("input key wrapping error!"); + + let wrapping_key_pem = app + .wrapping_key_pem() + .expect("wrapping key error: fetching error!"); + + let pub_key = RsaPublicKey::from_public_key_pem(&wrapping_key_pem).unwrap(); + + //wrap AES256 into RSA4096 + let wrapped_aes = pub_key + .encrypt( + &mut rand_core::OsRng, + PaddingScheme::new_oaep::(), + &aes_key, + ) + .expect("failed to encrypt"); + + debug_assert_eq!(wrapped_aes.len(), 512); + let wrapped_aes: Vec = [wrapped_aes.as_slice(), wrapped_input_key.as_slice()].concat(); + + app.import_key( + &self.pk_name, + client::CreateKeyType::Ed25519, + &base64::encode(wrapped_aes), + ) + .expect("import key error!"); + } +} + +//https://docs.rs/ed25519/latest/ed25519/pkcs8/index.html +fn input_key(input_key: &str) -> Result, error::Error> { + let bytes = base64::decode(input_key)?; + + let secret_key = if bytes.len() == 64 { + ed25519_dalek::Keypair::from_bytes(&bytes)?.secret + } else { + ed25519_dalek::SecretKey::from_bytes(&bytes)? + }; + + let mut secret_key: Vec = secret_key.to_bytes().into_iter().collect::>(); + + //HashiCorp Vault Transit engine expects PKCS8 + if secret_key.len() == ed25519_dalek::SECRET_KEY_LENGTH { + let mut pkcs8_key = Vec::from(*PKCS8_HEADER); + pkcs8_key.extend_from_slice(&secret_key); + secret_key = pkcs8_key; + } + + debug_assert!(secret_key.len() == ed25519_dalek::SECRET_KEY_LENGTH + PKCS8_HEADER.len()); + + Ok(secret_key) +} + +#[cfg(test)] +mod tests { + use std::convert::TryFrom; + + use super::*; + + #[test] + fn test_input_key_32bit_ok() { + let bytes = ed25519_dalek::SecretKey::generate(&mut rand::thread_rng()).to_bytes(); + assert_eq!(bytes.len(), ed25519_dalek::SECRET_KEY_LENGTH); + + let secret = base64::encode(bytes); + + //under test + let bytes = input_key(&secret).unwrap(); + + assert_eq!( + bytes.len(), + ed25519_dalek::SECRET_KEY_LENGTH + PKCS8_HEADER.len() + ); + } + + #[test] + fn test_input_key_48bit_ok() { + let mut secret = PKCS8_HEADER.into_iter().cloned().collect::>(); + + let bytes = ed25519_dalek::SecretKey::generate(&mut rand::thread_rng()).to_bytes(); + assert_eq!(bytes.len(), ed25519_dalek::SECRET_KEY_LENGTH); + + secret.extend_from_slice(&bytes); + + let secret = base64::encode(bytes); + //under test + let bytes = input_key(&secret).unwrap(); + + assert_eq!( + bytes.len(), + ed25519_dalek::SECRET_KEY_LENGTH + PKCS8_HEADER.len() + ); + } + #[test] + fn test_input_key_64bit_ok() { + let mut secret = PKCS8_HEADER.into_iter().cloned().collect::>(); + + let bytes = ed25519_dalek::SecretKey::generate(&mut rand::thread_rng()).to_bytes(); + assert_eq!(bytes.len(), ed25519_dalek::SECRET_KEY_LENGTH); + + secret.extend_from_slice(&bytes); + + let secret = base64::encode(bytes); + //under test + let bytes = input_key(&secret).unwrap(); + + assert_eq!( + bytes.len(), + ed25519_dalek::SECRET_KEY_LENGTH + PKCS8_HEADER.len() + ); + } + + const PK_NAME: &str = "upload-test"; + const VAULT_TOKEN: &str = "access-token"; + const CHAIN_ID: &str = "mock-chain-id"; + const ED25519: &str = + "4YZKJ/pfJj42tdcl40dXz/ugRgrBR0/Pp5C2kjHL6AZhBFozq5EspBwCb44zef0cLEO/WuLf3dI+BPCNOPwxRw=="; + + use mockito::{mock, server_address}; + + #[test] + fn test_upload() { + let cmd = UploadCommand { + verbose: false, + pk_name: PK_NAME.into(), + config: None, + payload: ED25519.into(), + }; + + let config = HashiCorpConfig { + access_token: "crazy-long-string".into(), + api_endpoint: format!("http://{}", server_address()), + pk_name: PK_NAME.into(), + chain_id: tendermint::chain::Id::try_from(CHAIN_ID).unwrap(), + }; + + std::env::set_var("VAULT_TOKEN", VAULT_TOKEN); + + //init + let lookup_self = mock("GET", "/v1/auth/token/lookup-self") + .match_header("X-Vault-Token", VAULT_TOKEN) + .with_body(TOKEN_DATA) + .create(); + + //upload + let wrapping_key = mock("GET", "/v1/transit/wrapping_key") + .match_header("X-Vault-Token", VAULT_TOKEN) + .with_body(WRAPPING_KEY_RESPONSE) + .create(); + + let end_point = format!("/v1/transit/keys/{}/import", PK_NAME); + + //upload + let export = mock("POST", end_point.as_str()) + .match_header("X-Vault-Token", VAULT_TOKEN) + //.match_body(req.as_str()) //sipher string will be always different + .create(); + + //test + cmd.upload(&config); + + lookup_self.assert(); + export.assert(); + wrapping_key.expect(1).assert(); + // } + } + + //curl --header "X-Vault-Token: hvs.<...valid.token...>>" http://127.0.0.1:8200/v1/auth/token/lookup-self + const TOKEN_DATA: &str = r#" + {"request_id":"119fcc9e-85e2-1fcf-c2a2-96cfb20f7446","lease_id":"","renewable":false,"lease_duration":0,"data":{"accessor":"k1g6PqNWVIlKK9NDCWLiTvrG","creation_time":1661247016,"creation_ttl":2764800,"display_name":"token","entity_id":"","expire_time":"2022-09-24T09:30:16.898359776Z","explicit_max_ttl":0,"id":"hvs.CAESIEzWRWLvyYLGlYsCRI_Vt653K26b-cx_lrxBlFo3_2GBGh4KHGh2cy5GVzZ5b25nMVFpSkwzM1B1eHM2Y0ZqbXA","issue_time":"2022-08-23T09:30:16.898363509Z","meta":null,"num_uses":0,"orphan":false,"path":"auth/token/create","policies":["tmkms-transit-sign-policy"],"renewable":false,"ttl":2758823,"type":"service"},"wrap_info":null,"warnings":null,"auth":null} + "#; + + const WRAPPING_KEY_RESPONSE: &str = r#"{"request_id":"1d739895-ea6d-2e18-3457-edbbf8dcd129","lease_id":"","renewable":false,"lease_duration":0,"data":{"public_key":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1hXp53II1GokeS6UyOvF\nbQnNgstRJ4IINjiQXL0iO+US3p5Zc/wwads6R3sTw6nwf+cXzPEkzyXXBIMgdLTH\nx/7kOuzT+mRJbKQgFXdHyEfm9T6jEKOSJFaQQxYQcMgUiMXiaXSonDnShwQ3BOxT\nzPo9TR8Z6+xMYIFTV9/kHJT2JHAX4xf5+EuRae4XsHW2yaWZzY//qVu/z0hXEeh3\nk0yK0kAULXMlzyJDpCNuWsdtB4ZpFv0eJ5ic84ZmA3B5Y/LQ0VSHLYnJOtt7hMe2\nsEEFHS7sfTbFxtBpSTySikoCLtHOAUXC0u3FQBJRta+uT82Iufdz7Qzw2xmR1WP2\nSTdqVINYci3/cql1xzEdKmieMwEwGbMOjFA7N4hBPgT9Tjod8vqCizk+Z1AH6ijd\nhfhDXlDi2owsngijdKJEoWCIC1IsqOTkZsKspw3a/9gdAkzXC8qkevCtOccC3Nwu\nAiA1Nh+FtFdvTDtwp7/G7lFLJT2E2PdtX8nZsI0TMmQg9Wh4wFP4pJfOGsYtMdNf\nN6cNVgYsTfkKIpXpxJdRf7YNKy1bvVNIPDAREuJTT8J5aSnnE/gjDiTbUDVnLulE\nYu7BaQqzE86k20MakAg1OLMftJJo0UhPxezanG43ZRW/K8OgBKnoD6UFFPzMiJ89\nQAzzkMa+CgjZr6zkIRy5FqkCAwEAAQ==\n-----END PUBLIC KEY-----\n"},"wrap_info":null,"warnings":null,"auth":null} + "#; +} diff --git a/src/commands/init/config_builder.rs b/src/commands/init/config_builder.rs index 5906afce..e0e07dd7 100644 --- a/src/commands/init/config_builder.rs +++ b/src/commands/init/config_builder.rs @@ -86,6 +86,9 @@ impl ConfigBuilder { #[cfg(feature = "fortanixdsm")] self.add_fortanixdsm_provider_config(); + + #[cfg(feature = "hashicorp")] + self.add_hashicorp_provider_config(); } /// Add `[[validator]]` configurations @@ -179,6 +182,13 @@ impl ConfigBuilder { self.add_template_with_chain_id(include_str!("templates/keyring/fortanixdsm.toml")); } + /// Add `[[provider.hashicorp]]` configuration + #[cfg(feature = "hashicorp")] + fn add_hashicorp_provider_config(&mut self) { + self.add_str("### HashiCorp Vault Signer Configuration\n\n"); + self.add_template_with_chain_id(include_str!("templates/keyring/hashicorp.toml")); + } + /// Append a template to the config file, substituting `$KMS_HOME` fn add_template(&mut self, template: &str) { self.add_str(&format_template( diff --git a/src/commands/init/templates/keyring/hashicorp.toml b/src/commands/init/templates/keyring/hashicorp.toml new file mode 100644 index 00000000..8e7cb6e0 --- /dev/null +++ b/src/commands/init/templates/keyring/hashicorp.toml @@ -0,0 +1,9 @@ +[[providers.hashicorp]] +#ChainId this provider is configured for +chain_id = "$CHAIN_ID" +#Vault's api url - VAULT_ADDR +api_endpoint= "http://127.0.0.1:8200" +#Vault's access token - vault token create -policy= +access_token="hvs.CAESINi91lCOFj-_dOGiUfpdZUPKk93LD8YyHz-qZcYLVwH_Gh4KHGh2cy5kdXV1T2tpcXliakFFblU1SUpqanczYjU" +#Vault's transit secret engine key - vault write transit/keys/ type=ed25519 +pk_name="cosmoshub-sign-key" diff --git a/src/config/provider.rs b/src/config/provider.rs index 07e5d5d4..8fb937f4 100644 --- a/src/config/provider.rs +++ b/src/config/provider.rs @@ -2,6 +2,8 @@ #[cfg(feature = "fortanixdsm")] pub mod fortanixdsm; +#[cfg(feature = "hashicorp")] +pub mod hashicorp; #[cfg(feature = "ledger")] pub mod ledgertm; #[cfg(feature = "softsign")] @@ -11,6 +13,8 @@ pub mod yubihsm; #[cfg(feature = "fortanixdsm")] use self::fortanixdsm::FortanixDsmConfig; +#[cfg(feature = "hashicorp")] +use self::hashicorp::HashiCorpConfig; #[cfg(feature = "ledger")] use self::ledgertm::LedgerTendermintConfig; #[cfg(feature = "softsign")] @@ -44,6 +48,11 @@ pub struct ProviderConfig { #[cfg(feature = "fortanixdsm")] #[serde(default)] pub fortanixdsm: Vec, + + /// HashiCorp Vault provider configurations + #[cfg(feature = "hashicorp")] + #[serde(default)] + pub hashicorp: Vec, } /// Types of cryptographic keys diff --git a/src/config/provider/hashicorp.rs b/src/config/provider/hashicorp.rs new file mode 100644 index 00000000..26866868 --- /dev/null +++ b/src/config/provider/hashicorp.rs @@ -0,0 +1,21 @@ +//! Configuration for HashiCorp Vault + +use crate::chain; +use serde::Deserialize; + +#[derive(Clone, Deserialize, Debug)] +#[serde(deny_unknown_fields)] +/// Hashicorp Vault signer configuration +pub struct HashiCorpConfig { + /// Chains this signing key is authorized to be used from + pub chain_id: chain::Id, + + /// HashiCorp Vault API endpoint, e.g. https://127.0.0.1:8200 + pub api_endpoint: String, + + /// Access token for authenticating to HashiCorp Vault + pub access_token: String, + + /// Vault's key name with ed25519 pub+priv key + pub pk_name: String, +} diff --git a/src/keyring.rs b/src/keyring.rs index bce3c865..3a9c4913 100644 --- a/src/keyring.rs +++ b/src/keyring.rs @@ -190,5 +190,8 @@ pub fn load_config(registry: &mut chain::Registry, config: &ProviderConfig) -> R #[cfg(feature = "fortanixdsm")] providers::fortanixdsm::init(registry, &config.fortanixdsm)?; + #[cfg(feature = "hashicorp")] + providers::hashicorp::init(registry, &config.hashicorp)?; + Ok(()) } diff --git a/src/keyring/providers.rs b/src/keyring/providers.rs index d58bca2d..eba47d52 100644 --- a/src/keyring/providers.rs +++ b/src/keyring/providers.rs @@ -12,6 +12,9 @@ pub mod yubihsm; #[cfg(feature = "fortanixdsm")] pub mod fortanixdsm; +#[cfg(feature = "hashicorp")] +pub mod hashicorp; + use std::fmt::{self, Display}; /// Enumeration of signing key providers @@ -32,6 +35,10 @@ pub enum SigningProvider { /// Fortanix DSM signer #[cfg(feature = "fortanixdsm")] FortanixDsm, + + /// HashiCorp Vault provider + #[cfg(feature = "hashicorp")] + HashiCorp, } impl Display for SigningProvider { @@ -48,6 +55,9 @@ impl Display for SigningProvider { #[cfg(feature = "fortanixdsm")] SigningProvider::FortanixDsm => write!(f, "fortanixdsm"), + + #[cfg(feature = "hashicorp")] + SigningProvider::HashiCorp => write!(f, "hashicorp"), } } } diff --git a/src/keyring/providers/hashicorp.rs b/src/keyring/providers/hashicorp.rs new file mode 100644 index 00000000..4363a447 --- /dev/null +++ b/src/keyring/providers/hashicorp.rs @@ -0,0 +1,80 @@ +//! HashiCorp Vault provider +pub(crate) mod client; +pub(crate) mod error; +pub(crate) mod signer; + +use crate::{ + chain, + config::provider::hashicorp::HashiCorpConfig, + error::{Error, ErrorKind::*}, + keyring::{ + ed25519::{self, Signer}, + SigningProvider, + }, + prelude::*, +}; + +use tendermint::TendermintKey; + +use self::signer::Ed25519HashiCorpAppSigner; + +/// Create HashiCorp Vault Ed25519 signer objects from the given configuration +pub fn init( + chain_registry: &mut chain::Registry, + configs: &[HashiCorpConfig], +) -> Result<(), Error> { + if configs.is_empty() { + fail!( + ConfigError, + "expected at least one [providers.hashicorp] in config, found none!" + ); + } + + let mut chains = Vec::::new(); + + for config in configs { + //misconfiguration check + if chains.contains(&config.chain_id.to_string()) { + fail!( + ConfigError, + format!("already configured! chain id:{}", config.chain_id) + ) + } else { + chains.push(config.chain_id.to_string()) + } + + let mut app = client::TendermintValidatorApp::connect( + &config.api_endpoint, + &config.access_token, + &config.pk_name, + ) + .expect(&format!( + "Failed to authenticate to Vault for chain id:{}", + config.chain_id + )); + + let public_key = app.public_key().expect(&format!( + "Failed to get public key for chain id:{}", + config.chain_id + )); + + let public_key = ed25519::PublicKey::from_bytes(&public_key).expect(&format!( + "invalid Ed25519 public key for chain id:{}", + config.chain_id + )); + + let provider = Ed25519HashiCorpAppSigner::new(app); + + chain_registry.add_consensus_key( + &config.chain_id, + //avoiding need for clone + Signer::new( + SigningProvider::HashiCorp, + TendermintKey::ConsensusKey(public_key.into()), + Box::new(provider), + ), + )?; + } + + Ok(()) +} diff --git a/src/keyring/providers/hashicorp/client.rs b/src/keyring/providers/hashicorp/client.rs new file mode 100644 index 00000000..505a9621 --- /dev/null +++ b/src/keyring/providers/hashicorp/client.rs @@ -0,0 +1,490 @@ +use abscissa_core::prelude::*; +use std::collections::{BTreeMap, HashMap}; + +use super::error::Error; +use hashicorp_vault::{ + client::{EndpointResponse, HttpVerb, TokenData, VaultResponse}, + Client, +}; + +use serde::{Deserialize, Serialize}; + +const VAULT_BACKEND_NAME: &str = "transit"; +pub const CONSENUS_KEY_TYPE: &str = "ed25519"; + +pub(crate) struct TendermintValidatorApp { + client: Client, + key_name: String, + public_key_value: Option<[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]>, +} + +// TODO(tarcieri): check this is actually sound?! :-) +#[allow(unsafe_code)] +unsafe impl Send for TendermintValidatorApp {} + +///Sign Request Struct +#[derive(Debug, Serialize)] +struct SignRequest { + input: String, //Base64 encoded +} + +///Sign Response Struct +#[derive(Debug, Deserialize)] +struct SignResponse { + signature: String, //Base64 encoded +} + +#[derive(Debug, Serialize)] +pub(crate) struct ImportRequest { + pub r#type: String, + pub ciphertext: String, + pub hash_function: String, +} + +#[allow(dead_code)] +#[derive(Debug)] +pub(crate) enum ExportKeyType { + EncryptionKey, + SigningKey, + HmacKey, +} +impl std::fmt::Display for ExportKeyType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ExportKeyType::EncryptionKey => write!(f, "encryption-key"), + ExportKeyType::SigningKey => write!(f, "signing-key"), + ExportKeyType::HmacKey => write!(f, "hmac-key"), + } + } +} +#[allow(dead_code)] +#[derive(Debug)] +pub(crate) enum CreateKeyType { + ///AES-128 wrapped with GCM using a 96-bit nonce size AEAD (symmetric, supports derivation and convergent encryption) + Aes128Gcm96, + ///AES-256 wrapped with GCM using a 96-bit nonce size AEAD (symmetric, supports derivation and convergent encryption, default) + Aes256Gcm96, + ///ChaCha20-Poly1305 AEAD (symmetric, supports derivation and convergent encryption) + Chacha20Poly1305, + ///ED25519 (asymmetric, supports derivation). When using derivation, a sign operation with the same context will derive the same key and signature; this is a signing analogue to convergent_encryption. + Ed25519, + ///ECDSA using the P-256 elliptic curve (asymmetric) + EcdsaP256, + ///ECDSA using the P-384 elliptic curve (asymmetric) + EcdsaP384, + ///ECDSA using the P-521 elliptic curve (asymmetric) + EcdsaP521, + ///RSA with bit size of 2048 (asymmetric) + Rsa2048, + ///RSA with bit size of 3072 (asymmetric) + Rsa3072, + ///RSA with bit size of 4096 (asymmetric) + Rsa4096, +} + +impl std::fmt::Display for CreateKeyType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CreateKeyType::Aes128Gcm96 => write!(f, "aes128-gcm96"), + CreateKeyType::Aes256Gcm96 => write!(f, "aes256-gcm96"), + CreateKeyType::Chacha20Poly1305 => write!(f, "chacha20-poly1305"), + CreateKeyType::Ed25519 => write!(f, "ed25519"), + CreateKeyType::EcdsaP256 => write!(f, "ecdsa-p256"), + CreateKeyType::EcdsaP384 => write!(f, "ecdsa-p384"), + CreateKeyType::EcdsaP521 => write!(f, "ecdsa-p521"), + CreateKeyType::Rsa2048 => write!(f, "rsa-2048"), + CreateKeyType::Rsa3072 => write!(f, "rsa-3072"), + CreateKeyType::Rsa4096 => write!(f, "rsa-4096"), + } + } +} + +impl TendermintValidatorApp { + pub fn connect(host: &str, token: &str, key_name: &str) -> Result { + //this call performs token self lookup, to fail fast + let mut client = Client::new(host, token)?; + client.secret_backend(VAULT_BACKEND_NAME); + + let app = TendermintValidatorApp { + client, + key_name: key_name.to_owned(), + public_key_value: None, + }; + + debug!("Initialized with Vault host at {}", host); + Ok(app) + } + + //vault read transit/keys/cosmoshub-sign-key + //GET http://0.0.0.0:8200/v1/transit/keys/cosmoshub-sign-key + /// Get public key + pub fn public_key(&mut self) -> Result<[u8; ed25519_dalek::PUBLIC_KEY_LENGTH], Error> { + if let Some(v) = self.public_key_value { + debug!("using cached public key {}...", self.key_name); + return Ok(v.clone()); + } + + debug!("fetching public key for {}...", self.key_name); + + ///Response struct + #[derive(Debug, Deserialize)] + struct PublicKeyResponse { + keys: BTreeMap>, + } + + let data = self.client.call_endpoint::( + HttpVerb::GET, + &format!("transit/keys/{}", self.key_name), + None, + None, + )?; + + //{ keys: {1: {"name": "ed25519", "public_key": "R5n8OFaknb/3sCTx/aegNzYukwVx0uNtzzK/2RclIOE=", "creation_time": "2022-08-18T12:44:02.136328217Z"}} } + let data = if let EndpointResponse::VaultResponse(VaultResponse { + data: Some(data), .. + }) = data + { + data + } else { + return Err(Error::InvalidPubKey( + "Public key: Vault response unavailable".into(), + )); + }; + + //latest key version + let key_data = data.keys.iter().last(); + + let pubk = if let Some((version, map)) = key_data { + debug!("public key vetion:{}", version); + if let Some(pubk) = map.get("public_key") { + if let Some(key_type) = map.get("name") { + if CONSENUS_KEY_TYPE != key_type { + return Err(Error::InvalidPubKey(format!( + "Public key \"{}\": expected key type:{}, received:{}", + self.key_name, CONSENUS_KEY_TYPE, key_type + ))); + } + } else { + return Err(Error::InvalidPubKey(format!( + "Public key \"{}\": expected key type:{}, unable to determine type", + self.key_name, CONSENUS_KEY_TYPE + ))); + } + pubk + } else { + return Err(Error::InvalidPubKey( + "Public key: unable to retrieve - \"public_key\" key is not found!".into(), + )); + } + } else { + return Err(Error::InvalidPubKey( + "Public key: unable to retrieve last version - not available!".into(), + )); + }; + + debug!("Public key: fetched {}={}...", self.key_name, pubk); + + let pubk = base64::decode(pubk)?; + + debug!( + "Public key: base64 decoded {}, size:{}", + self.key_name, + pubk.len() + ); + + let mut array = [0u8; ed25519_dalek::PUBLIC_KEY_LENGTH]; + array.copy_from_slice(&pubk[..ed25519_dalek::PUBLIC_KEY_LENGTH]); + + //cache it... + self.public_key_value = Some(array.clone()); + debug!("Public key: value cached {}", self.key_name,); + + Ok(array) + } + + //vault write transit/sign/cosmoshub-sign-key plaintext=$(base64 <<< "some-data") + //"https://127.0.0.1:8200/v1/transit/sign/cosmoshub-sign-key" + /// Sign message + pub fn sign(&self, message: &[u8]) -> Result<[u8; ed25519_dalek::SIGNATURE_LENGTH], Error> { + debug!("signing request: received"); + if message.is_empty() { + return Err(Error::InvalidEmptyMessage); + } + + let body = SignRequest { + input: base64::encode(message), + }; + + debug!("signing request: base64 encoded and about to submit for signing..."); + + let data = self.client.call_endpoint::( + HttpVerb::POST, + &format!("transit/sign/{}", self.key_name), + None, + Some(&serde_json::to_string(&body)?), + )?; + + debug!("signing request: about to submit for signing..."); + + let data = if let EndpointResponse::VaultResponse(VaultResponse { + data: Some(data), .. + }) = data + { + data + } else { + return Err(Error::NoSignature); + }; + + let parts = data.signature.split(":").collect::>(); + if parts.len() != 3 { + return Err(Error::InvalidSignature(format!( + "expected 3 parts, received:{} full:{}", + parts.len(), + data.signature + ))); + } + + //signature: "vault:v1:/bcnnk4p8Uvidrs1/IX9s66UCOmmfdJudcV1/yek9a2deMiNGsVRSjirz6u+ti2wqUZfG6UukaoSHIDSSRV5Cw==" + let base64_signature = if let Some(sign) = parts.last() { + sign.to_owned() + } else { + //this should never happen + return Err(Error::InvalidSignature("last part is not available".into())); + }; + + let signature = base64::decode(base64_signature)?; + if signature.len() != 64 { + return Err(Error::InvalidSignature(format!( + "invalid signature length! 64 == {}", + signature.len() + ))); + } + + let mut array = [0u8; ed25519_dalek::SIGNATURE_LENGTH]; + array.copy_from_slice(&signature[..ed25519_dalek::SIGNATURE_LENGTH]); + Ok(array) + } + + ///fetch RSA wraping key from Vault/Transit. Returned key will be a 4096-bit RSA public key. + pub fn wrapping_key_pem(&self) -> Result { + debug!("getting wraping key..."); + #[derive(Debug, Deserialize)] + struct PublicKeyResponse { + public_key: String, + } + + let data = self.client.call_endpoint::( + HttpVerb::GET, + "transit/wrapping_key", + None, + None, + )?; + + Ok( + if let EndpointResponse::VaultResponse(VaultResponse { data: Some(d), .. }) = data { + debug!("wrapping key:\n{}", d.public_key); + d.public_key.trim().to_owned() + } else { + return Err(Error::InvalidPubKey("Error getting wrapping key!".into())); + }, + ) + } + + pub fn import_key( + &self, + key_name: &str, + key_type: CreateKeyType, + ciphertext: &str, + ) -> Result<(), Error> { + let body = ImportRequest { + r#type: key_type.to_string(), + ciphertext: ciphertext.into(), + hash_function: "SHA256".into(), + }; + + let _ = self.client.call_endpoint::<()>( + HttpVerb::POST, + &format!("transit/keys/{}/import", key_name), + None, + Some(&serde_json::to_string(&body)?), + )?; + + Ok(()) + } +} + +#[cfg(feature = "hashicorp")] +#[cfg(test)] +mod tests { + use super::*; + use base64; + use mockito::{mock, server_address}; + + const TEST_TOKEN: &str = "test-token"; + const TEST_KEY_NAME: &str = "test-key-name"; + const TEST_PUB_KEY_VALUE: &str = "ng+ab41LawVupIXX3ocMn+AfV2W1DEMCfjAdtrwXND8="; //base64 + const TEST_PAYLOAD_TO_SIGN_BASE64: &str = "cXFxcXFxcXFxcXFxcXFxcXFxcXE="; //$(base64 <<< "qqqqqqqqqqqqqqqqqqqq") => "cXFxcXFxcXFxcXFxcXFxcXFxcXEK", 'K' vs "=" ???? + const TEST_PAYLOAD_TO_SIGN: &[u8] = b"qqqqqqqqqqqqqqqqqqqq"; + + const TEST_SIGNATURE:&str = /*vault:v1:*/ "pNcc/FAUu+Ta7itVegaMUMGqXYkzE777y3kOe8AtdRTgLbA8eFnrKbbX/m7zoiC+vArsIUJ1aMCEDRjDK3ZsBg=="; + + #[test] + fn hashicorp_connect_ok() { + //setup + let lookup_self = mock("GET", "/v1/auth/token/lookup-self") + .match_header("X-Vault-Token", TEST_TOKEN) + .with_body(TOKEN_DATA) + .create(); + + //test + let app = TendermintValidatorApp::connect( + &format!("http://{}", server_address()), + TEST_TOKEN, + TEST_KEY_NAME, + ); + + assert!(app.is_ok()); + lookup_self.assert(); + } + + #[test] + fn hashicorp_public_key_ok() { + //setup + let lookup_self = mock("GET", "/v1/auth/token/lookup-self") + .match_header("X-Vault-Token", TEST_TOKEN) + .with_body(TOKEN_DATA) + .create(); + + //app + let mut app = TendermintValidatorApp::connect( + &format!("http://{}", server_address()), + TEST_TOKEN, + TEST_KEY_NAME, + ) + .expect("Failed to connect"); + + //Vault call + let read_key = mock( + "GET", + format!("/v1/transit/keys/{}", TEST_KEY_NAME).as_str(), + ) + .match_header("X-Vault-Token", TEST_TOKEN) + .with_body(READ_KEY_RESP) + .expect_at_most(1) //one call only + .create(); + + //server call + let res = app.public_key(); + assert!(res.is_ok()); + assert_eq!( + res.unwrap(), + base64::decode(TEST_PUB_KEY_VALUE).unwrap().as_slice() + ); + + //cached vaule + let res = app.public_key(); + assert!(res.is_ok()); + assert_eq!( + res.unwrap(), + base64::decode(TEST_PUB_KEY_VALUE).unwrap().as_slice() + ); + + read_key.assert(); + lookup_self.assert(); + } + + #[test] + fn hashicorp_sign_ok() { + //setup + let lookup_self = mock("GET", "/v1/auth/token/lookup-self") + .match_header("X-Vault-Token", TEST_TOKEN) + .with_body(TOKEN_DATA) + .create(); + + //app + let app = TendermintValidatorApp::connect( + &format!("http://{}", server_address()), + TEST_TOKEN, + TEST_KEY_NAME, + ) + .expect("Failed to connect"); + + let body = serde_json::to_string(&SignRequest { + input: TEST_PAYLOAD_TO_SIGN_BASE64.into(), + }) + .unwrap(); + + let sign_mock = mock( + "POST", + format!("/v1/transit/sign/{}", TEST_KEY_NAME).as_str(), + ) + .match_header("X-Vault-Token", TEST_TOKEN) + .match_body(body.as_str()) + .with_body(SIGN_RESPONSE) + .create(); + + //server call + let res = app.sign(TEST_PAYLOAD_TO_SIGN); + assert!(res.is_ok()); + assert_eq!( + res.unwrap(), + base64::decode(TEST_SIGNATURE).unwrap().as_slice() + ); + + lookup_self.assert(); + sign_mock.assert(); + } + + #[test] + fn hashicorp_sign_empty_payload_should_fail() { + //setup + let lookup_self = mock("GET", "/v1/auth/token/lookup-self") + .match_header("X-Vault-Token", TEST_TOKEN) + .with_body(TOKEN_DATA) + .create(); + + //app + let app = TendermintValidatorApp::connect( + &format!("http://{}", server_address()), + TEST_TOKEN, + TEST_KEY_NAME, + ) + .expect("Failed to connect"); + + let body = serde_json::to_string(&SignRequest { + input: TEST_PAYLOAD_TO_SIGN_BASE64.into(), + }) + .unwrap(); + + let sign_mock = mock( + "POST", + format!("/v1/transit/sign/{}", TEST_KEY_NAME).as_str(), + ) + .match_header("X-Vault-Token", TEST_TOKEN) + .match_body(body.as_str()) + .with_body(SIGN_RESPONSE) + .create(); + + //server call + let res = app.sign(&[]); + assert!(res.is_err()); + + lookup_self.assert(); + sign_mock.expect(0); + } + + //curl --header "X-Vault-Token: hvs.<...valid.token...>>" http://127.0.0.1:8200/v1/auth/token/lookup-self + const TOKEN_DATA: &str = r#" + {"request_id":"119fcc9e-85e2-1fcf-c2a2-96cfb20f7446","lease_id":"","renewable":false,"lease_duration":0,"data":{"accessor":"k1g6PqNWVIlKK9NDCWLiTvrG","creation_time":1661247016,"creation_ttl":2764800,"display_name":"token","entity_id":"","expire_time":"2022-09-24T09:30:16.898359776Z","explicit_max_ttl":0,"id":"hvs.CAESIEzWRWLvyYLGlYsCRI_Vt653K26b-cx_lrxBlFo3_2GBGh4KHGh2cy5GVzZ5b25nMVFpSkwzM1B1eHM2Y0ZqbXA","issue_time":"2022-08-23T09:30:16.898363509Z","meta":null,"num_uses":0,"orphan":false,"path":"auth/token/create","policies":["tmkms-transit-sign-policy"],"renewable":false,"ttl":2758823,"type":"service"},"wrap_info":null,"warnings":null,"auth":null} + "#; + + //curl --header "X-Vault-Token: $VAULT_TOKEN" "${VAULT_ADDR}/v1/transit/keys/" + const READ_KEY_RESP: &str = r#" + {"request_id":"9cb10d0a-1877-6da5-284b-8ece4b131ae3","lease_id":"","renewable":false,"lease_duration":0,"data":{"allow_plaintext_backup":false,"auto_rotate_period":0,"deletion_allowed":false,"derived":false,"exportable":false,"imported_key":false,"keys":{"1":{"creation_time":"2022-08-23T09:30:16.676998915Z","name":"ed25519","public_key":"ng+ab41LawVupIXX3ocMn+AfV2W1DEMCfjAdtrwXND8="}},"latest_version":1,"min_available_version":0,"min_decryption_version":1,"min_encryption_version":0,"name":"cosmoshub-sign-key","supports_decryption":false,"supports_derivation":true,"supports_encryption":false,"supports_signing":true,"type":"ed25519"},"wrap_info":null,"warnings":null,"auth":null} + "#; + + //curl --request POST --header "X-Vault-Token: $VAULT_TOKEN" "${VAULT_ADDR}/v1/transit/sign/<..key_name...>" -d '{"input":"base64 encoded"}' + const SIGN_RESPONSE: &str = r#" + {"request_id":"13534911-8e98-9a0f-a701-e9a7736140e2","lease_id":"","renewable":false,"lease_duration":0,"data":{"key_version":1,"signature":"vault:v1:pNcc/FAUu+Ta7itVegaMUMGqXYkzE777y3kOe8AtdRTgLbA8eFnrKbbX/m7zoiC+vArsIUJ1aMCEDRjDK3ZsBg=="},"wrap_info":null,"warnings":null,"auth":null} + "#; +} diff --git a/src/keyring/providers/hashicorp/error.rs b/src/keyring/providers/hashicorp/error.rs new file mode 100644 index 00000000..5cd0c242 --- /dev/null +++ b/src/keyring/providers/hashicorp/error.rs @@ -0,0 +1,53 @@ +//! Ledger errors + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("message cannot be empty")] + InvalidEmptyMessage, + + #[error("Public Key Error:{0}")] + InvalidPubKey(String), + + #[error("received no signature back")] + NoSignature, + + #[error("received an invalid signature: {0}")] + InvalidSignature(String), + + #[error("ApiClient error:{0}")] + ApiClientError(String), + + #[error("Base64 decode error")] + DecodeError(base64::DecodeError), + + #[error("Serde error")] + SerDeError(serde_json::Error), + + #[error("Signature error")] + SignatureError(signature::Error), +} + +impl From for Error { + fn from(err: hashicorp_vault::Error) -> Error { + Error::ApiClientError(err.to_string()) + } +} + +impl From for Error { + fn from(err: base64::DecodeError) -> Error { + Error::DecodeError(err) + } +} + +impl From for Error { + fn from(err: serde_json::Error) -> Error { + Error::SerDeError(err) + } +} +impl From for Error { + fn from(err: signature::Error) -> Error { + Error::SignatureError(err) + } +} diff --git a/src/keyring/providers/hashicorp/signer.rs b/src/keyring/providers/hashicorp/signer.rs new file mode 100644 index 00000000..aacd91bb --- /dev/null +++ b/src/keyring/providers/hashicorp/signer.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; +use std::sync::Mutex; + +use crate::keyring::ed25519::Signature; +use crate::keyring::providers::hashicorp::client::TendermintValidatorApp; +use signature::{Error, Signer}; + +/// ed25519 signature provider for the Ledger Tendermint Validator app +pub(crate) struct Ed25519HashiCorpAppSigner { + app: Arc>, +} + +impl Ed25519HashiCorpAppSigner { + pub fn new(app: TendermintValidatorApp) -> Self { + Ed25519HashiCorpAppSigner { + app: Arc::new(Mutex::new(app)), + } + } +} + +impl Signer for Ed25519HashiCorpAppSigner { + /// c: Compute a compact, fixed-sized signature of the given amino/json vote + fn try_sign(&self, msg: &[u8]) -> Result { + let app = self.app.lock().unwrap(); + let sig = app.sign(msg).map_err(Error::from_source)?; + Ok(Signature::from(sig)) + } +} diff --git a/src/lib.rs b/src/lib.rs index d4abc5d5..152ec4ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,12 @@ feature = "softsign", feature = "yubihsm", feature = "ledger", - feature = "fortanixdsm" + feature = "fortanixdsm", + feature = "hashicorp" )))] compile_error!( "please enable one of the following backends with cargo's --features argument: \ - yubihsm, ledgertm, softsign, fortanixdsm (e.g. --features=yubihsm)" + yubihsm, ledgertm, softsign, fortanixdsm, hashicorp (e.g. --features=yubihsm)" ); pub mod amino_types; diff --git a/tests/cli/init.rs b/tests/cli/init.rs index e3599498..c7e60005 100644 --- a/tests/cli/init.rs +++ b/tests/cli/init.rs @@ -1,43 +1,47 @@ //! Integration tests for the `init` subcommand -use crate::cli; -use abscissa_core::Config; -use std::{ffi::OsStr, fs}; -use tmkms::{commands::init::networks::Network, config::KmsConfig}; - -#[test] -fn test_command() { - let parent_dir = tempfile::tempdir().unwrap(); - - let output_dir = parent_dir.path().join("tmkms"); - assert!(!output_dir.exists()); - - // Network names to test with - let networks = Network::all() - .iter() - .map(ToString::to_string) - .collect::>(); - - let result = cli::run(&[ - OsStr::new("init"), - OsStr::new("-n"), - OsStr::new(&networks.join(",")), - output_dir.as_os_str(), - ]); - - assert!(result.status.success()); - - // Ensure generated configuration file parses - let kms_config_path = output_dir.join("tmkms.toml"); - let kms_config = KmsConfig::load_toml(fs::read_to_string(&kms_config_path).unwrap()).unwrap(); - - // Ensure all expected chain IDs are present - assert_eq!( - &kms_config - .chain +#[cfg(feature = "softsign")] +mod softsign_init_test { + use crate::cli; + use abscissa_core::Config; + use std::{ffi::OsStr, fs}; + use tmkms::{commands::init::networks::Network, config::KmsConfig}; + + #[test] + fn test_command() { + let parent_dir = tempfile::tempdir().unwrap(); + + let output_dir = parent_dir.path().join("tmkms"); + assert!(!output_dir.exists()); + + // Network names to test with + let networks = Network::all() .iter() - .map(|c| c.id.as_str().split("-").next().unwrap().to_owned()) - .collect::>(), - &networks - ) + .map(ToString::to_string) + .collect::>(); + + let result = cli::run(&[ + OsStr::new("init"), + OsStr::new("-n"), + OsStr::new(&networks.join(",")), + output_dir.as_os_str(), + ]); + + assert!(result.status.success()); + + // Ensure generated configuration file parses + let kms_config_path = output_dir.join("tmkms.toml"); + let kms_config = + KmsConfig::load_toml(fs::read_to_string(&kms_config_path).unwrap()).unwrap(); + + // Ensure all expected chain IDs are present + assert_eq!( + &kms_config + .chain + .iter() + .map(|c| c.id.as_str().split("-").next().unwrap().to_owned()) + .collect::>(), + &networks + ) + } } diff --git a/tests/integration.rs b/tests/integration.rs index 9e5705ed..241f8b84 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,137 +1,149 @@ //! KMS integration test -use std::{ - fs, - io::{self, Cursor, Read, Write}, - net::{TcpListener, TcpStream}, - os::unix::net::{UnixListener, UnixStream}, - process::{Child, Command}, -}; - -use abscissa_core::prelude::warn; -use chrono::{DateTime, Utc}; -use ed25519_dalek::{self as ed25519, Verifier}; -use rand::Rng; -use tempfile::NamedTempFile; - -use prost_amino::Message; -use tendermint_p2p::secret_connection::{self, SecretConnection}; - -use tmkms::{ - amino_types::{self, *}, - config::validator::ProtocolVersion, - connection::unix::UnixConnection, -}; - -/// Integration tests for the KMS command-line interface mod cli; - /// Path to the KMS executable const KMS_EXE_PATH: &str = "target/debug/tmkms"; -/// Path to the example validator signing key -const SIGNING_KEY_PATH: &str = "tests/support/signing.key"; +#[cfg(feature = "softsign")] +mod softsign_integration_tests { + use std::{ + fs, + io::{self, Cursor, Read, Write}, + net::{TcpListener, TcpStream}, + os::unix::net::{UnixListener, UnixStream}, + process::{Child, Command}, + }; -enum KmsSocket { - /// TCP socket type - TCP(TcpStream), + use abscissa_core::prelude::warn; + use chrono::{DateTime, Utc}; + use ed25519_dalek::{self as ed25519, Verifier}; + use rand::Rng; + use tempfile::NamedTempFile; - /// UNIX socket type - UNIX(UnixStream), -} + use prost_amino::Message; + use tendermint_p2p::secret_connection::{self, SecretConnection}; -enum KmsConnection { - /// Secret connection type - Tcp(SecretConnection), + use tmkms::{ + amino_types::{self, *}, + config::validator::ProtocolVersion, + connection::unix::UnixConnection, + }; - /// UNIX connection type - Unix(UnixConnection), -} + // /// Integration tests for the KMS command-line interface + // use super::cli; -impl io::Write for KmsConnection { - fn write(&mut self, data: &[u8]) -> Result { - match *self { - KmsConnection::Tcp(ref mut conn) => conn.write(data), - KmsConnection::Unix(ref mut conn) => conn.write(data), - } - } + // /// Path to the KMS executable + // const KMS_EXE_PATH: &str = "target/debug/tmkms"; - fn flush(&mut self) -> Result<(), io::Error> { - match *self { - KmsConnection::Tcp(ref mut conn) => conn.flush(), - KmsConnection::Unix(ref mut conn) => conn.flush(), - } + /// Path to the example validator signing key + const SIGNING_KEY_PATH: &str = "tests/support/signing.key"; + + enum KmsSocket { + /// TCP socket type + TCP(TcpStream), + + /// UNIX socket type + UNIX(UnixStream), } -} -impl io::Read for KmsConnection { - fn read(&mut self, data: &mut [u8]) -> Result { - match *self { - KmsConnection::Tcp(ref mut conn) => conn.read(data), - KmsConnection::Unix(ref mut conn) => conn.read(data), - } + enum KmsConnection { + /// Secret connection type + Tcp(SecretConnection), + + /// UNIX connection type + Unix(UnixConnection), } -} -/// Receives incoming KMS connection then sends commands -struct KmsProcess { - /// KMS child process - process: Child, + impl io::Write for KmsConnection { + fn write(&mut self, data: &[u8]) -> Result { + match *self { + KmsConnection::Tcp(ref mut conn) => conn.write(data), + KmsConnection::Unix(ref mut conn) => conn.write(data), + } + } - /// A socket to KMS process - socket: KmsSocket, -} + fn flush(&mut self) -> Result<(), io::Error> { + match *self { + KmsConnection::Tcp(ref mut conn) => conn.flush(), + KmsConnection::Unix(ref mut conn) => conn.flush(), + } + } + } -impl KmsProcess { - /// Spawn the KMS process and wait for an incoming TCP connection - pub fn create_tcp() -> Self { - // Generate a random port and a config file - let port: u16 = rand::thread_rng().gen_range(60000, 65535); - let config = KmsProcess::create_tcp_config(port); + impl io::Read for KmsConnection { + fn read(&mut self, data: &mut [u8]) -> Result { + match *self { + KmsConnection::Tcp(ref mut conn) => conn.read(data), + KmsConnection::Unix(ref mut conn) => conn.read(data), + } + } + } - // Listen on a random port - let listener = TcpListener::bind(format!("{}:{}", "127.0.0.1", port)).unwrap(); + /// Receives incoming KMS connection then sends commands + struct KmsProcess { + /// KMS child process + process: Child, - let args = &["start", "-c", config.path().to_str().unwrap()]; - let process = Command::new(KMS_EXE_PATH).args(args).spawn().unwrap(); + /// A socket to KMS process + socket: KmsSocket, + } - let (socket, _) = listener.accept().unwrap(); - Self { - process: process, - socket: KmsSocket::TCP(socket), + impl KmsProcess { + /// Spawn the KMS process and wait for an incoming TCP connection + pub fn create_tcp() -> Self { + // Generate a random port and a config file + let port: u16 = rand::thread_rng().gen_range(60000, 65535); + let config = KmsProcess::create_tcp_config(port); + + // Listen on a random port + let listener = TcpListener::bind(format!("{}:{}", "127.0.0.1", port)).unwrap(); + + let args = &["start", "-c", config.path().to_str().unwrap()]; + let process = Command::new(super::KMS_EXE_PATH) + .args(args) + .spawn() + .unwrap(); + + let (socket, _) = listener.accept().unwrap(); + Self { + process: process, + socket: KmsSocket::TCP(socket), + } } - } - /// Spawn the KMS process and connect to the Unix listener - pub fn create_unix() -> Self { - // Create a random socket path and a config file - let mut rng = rand::thread_rng(); - let letter: char = rng.gen_range(b'a', b'z') as char; - let number: u32 = rng.gen_range(0, 999999); - let socket_path = format!("/tmp/tmkms-{}{:06}.sock", letter, number); - let config = KmsProcess::create_unix_config(&socket_path); - - // Start listening for connections via the Unix socket - let listener = UnixListener::bind(socket_path).unwrap(); - - // Fire up the KMS process and allow it to connect to our Unix socket - let args = &["start", "-c", config.path().to_str().unwrap()]; - let process = Command::new(KMS_EXE_PATH).args(args).spawn().unwrap(); - - let (socket, _) = listener.accept().unwrap(); - Self { - process: process, - socket: KmsSocket::UNIX(socket), + /// Spawn the KMS process and connect to the Unix listener + pub fn create_unix() -> Self { + // Create a random socket path and a config file + let mut rng = rand::thread_rng(); + let letter: char = rng.gen_range(b'a', b'z') as char; + let number: u32 = rng.gen_range(0, 999999); + let socket_path = format!("/tmp/tmkms-{}{:06}.sock", letter, number); + let config = KmsProcess::create_unix_config(&socket_path); + + // Start listening for connections via the Unix socket + let listener = UnixListener::bind(socket_path).unwrap(); + + // Fire up the KMS process and allow it to connect to our Unix socket + let args = &["start", "-c", config.path().to_str().unwrap()]; + let process = Command::new(super::KMS_EXE_PATH) + .args(args) + .spawn() + .unwrap(); + + let (socket, _) = listener.accept().unwrap(); + Self { + process: process, + socket: KmsSocket::UNIX(socket), + } } - } - /// Create a config file for a TCP KMS and return its path - fn create_tcp_config(port: u16) -> NamedTempFile { - let mut config_file = NamedTempFile::new().unwrap(); - let pub_key = test_ed25519_keypair().public; - let peer_id = secret_connection::PublicKey::from(pub_key).peer_id(); + /// Create a config file for a TCP KMS and return its path + fn create_tcp_config(port: u16) -> NamedTempFile { + let mut config_file = NamedTempFile::new().unwrap(); + let pub_key = test_ed25519_keypair().public; + let peer_id = secret_connection::PublicKey::from(pub_key).peer_id(); - writeln!( + writeln!( config_file, r#" [[chain]] @@ -155,13 +167,13 @@ impl KmsProcess { ) .unwrap(); - config_file - } + config_file + } - /// Create a config file for a UNIX KMS and return its path - fn create_unix_config(socket_path: &str) -> NamedTempFile { - let mut config_file = NamedTempFile::new().unwrap(); - writeln!( + /// Create a config file for a UNIX KMS and return its path + fn create_unix_config(socket_path: &str) -> NamedTempFile { + let mut config_file = NamedTempFile::new().unwrap(); + writeln!( config_file, r#" [[chain]] @@ -183,363 +195,367 @@ impl KmsProcess { ) .unwrap(); - config_file - } + config_file + } - /// Get a connection from the socket - pub fn create_connection(&self) -> KmsConnection { - match self.socket { - KmsSocket::TCP(ref sock) => { - // we use the same key for both sides: - let identity_keypair = test_ed25519_keypair(); - - // Here we reply to the kms with a "remote" ephermal key, auth signature etc: - let socket_cp = sock.try_clone().unwrap(); - - KmsConnection::Tcp( - SecretConnection::new( - socket_cp, - identity_keypair, - secret_connection::Version::Legacy, + /// Get a connection from the socket + pub fn create_connection(&self) -> KmsConnection { + match self.socket { + KmsSocket::TCP(ref sock) => { + // we use the same key for both sides: + let identity_keypair = test_ed25519_keypair(); + + // Here we reply to the kms with a "remote" ephermal key, auth signature etc: + let socket_cp = sock.try_clone().unwrap(); + + KmsConnection::Tcp( + SecretConnection::new( + socket_cp, + identity_keypair, + secret_connection::Version::Legacy, + ) + .unwrap(), ) - .unwrap(), - ) - } + } - KmsSocket::UNIX(ref sock) => { - let socket_cp = sock.try_clone().unwrap(); + KmsSocket::UNIX(ref sock) => { + let socket_cp = sock.try_clone().unwrap(); - KmsConnection::Unix(UnixConnection::new(socket_cp)) + KmsConnection::Unix(UnixConnection::new(socket_cp)) + } } } } -} -/// A struct to hold protocol integration tests contexts -struct ProtocolTester { - tcp_device: KmsProcess, - tcp_connection: KmsConnection, - unix_device: KmsProcess, - unix_connection: KmsConnection, -} + /// A struct to hold protocol integration tests contexts + struct ProtocolTester { + tcp_device: KmsProcess, + tcp_connection: KmsConnection, + unix_device: KmsProcess, + unix_connection: KmsConnection, + } -impl ProtocolTester { - pub fn apply(functor: F) - where - F: FnOnce(ProtocolTester), - { - let tcp_device = KmsProcess::create_tcp(); - let tcp_connection = tcp_device.create_connection(); - let unix_device = KmsProcess::create_unix(); - let unix_connection = unix_device.create_connection(); - - functor(Self { - tcp_device, - tcp_connection, - unix_device, - unix_connection, - }); + impl ProtocolTester { + pub fn apply(functor: F) + where + F: FnOnce(ProtocolTester), + { + let tcp_device = KmsProcess::create_tcp(); + let tcp_connection = tcp_device.create_connection(); + let unix_device = KmsProcess::create_unix(); + let unix_connection = unix_device.create_connection(); + + functor(Self { + tcp_device, + tcp_connection, + unix_device, + unix_connection, + }); + } } -} -impl Drop for ProtocolTester { - fn drop(&mut self) { - self.tcp_device.process.kill().unwrap(); - self.unix_device.process.kill().unwrap(); + impl Drop for ProtocolTester { + fn drop(&mut self) { + self.tcp_device.process.kill().unwrap(); + self.unix_device.process.kill().unwrap(); - match fs::remove_file("test_chain_id_priv_validator_state.json") { - Err(ref e) if e.kind() != io::ErrorKind::NotFound => { - panic!("{}", e); + match fs::remove_file("test_chain_id_priv_validator_state.json") { + Err(ref e) if e.kind() != io::ErrorKind::NotFound => { + panic!("{}", e); + } + _ => (), } - _ => (), } } -} -impl io::Write for ProtocolTester { - fn write(&mut self, data: &[u8]) -> Result { - let unix_sz = self.unix_connection.write(data)?; - let tcp_sz = self.tcp_connection.write(data)?; + impl io::Write for ProtocolTester { + fn write(&mut self, data: &[u8]) -> Result { + let unix_sz = self.unix_connection.write(data)?; + let tcp_sz = self.tcp_connection.write(data)?; - // Assert caller sanity - assert!(unix_sz == tcp_sz); - Ok(unix_sz) - } + // Assert caller sanity + assert!(unix_sz == tcp_sz); + Ok(unix_sz) + } - fn flush(&mut self) -> Result<(), io::Error> { - self.unix_connection.flush()?; - self.tcp_connection.flush()?; - Ok(()) + fn flush(&mut self) -> Result<(), io::Error> { + self.unix_connection.flush()?; + self.tcp_connection.flush()?; + Ok(()) + } } -} -impl io::Read for ProtocolTester { - fn read(&mut self, data: &mut [u8]) -> Result { - let mut unix_buf = vec![0u8; data.len()]; + impl io::Read for ProtocolTester { + fn read(&mut self, data: &mut [u8]) -> Result { + let mut unix_buf = vec![0u8; data.len()]; - self.tcp_connection.read(data)?; - let unix_sz = self.unix_connection.read(&mut unix_buf)?; + self.tcp_connection.read(data)?; + let unix_sz = self.unix_connection.read(&mut unix_buf)?; - // Assert handler sanity - if unix_buf != data { - warn!("binary protocol differs between TCP and UNIX sockets"); - } + // Assert handler sanity + if unix_buf != data { + warn!("binary protocol differs between TCP and UNIX sockets"); + } - Ok(unix_sz) + Ok(unix_sz) + } } -} - -/// Get the Ed25519 signing keypair used by the tests -fn test_ed25519_keypair() -> ed25519::Keypair { - tmkms::key_utils::load_base64_ed25519_key(SIGNING_KEY_PATH).unwrap() -} -/// Extract the actual length of an amino message -pub fn extract_actual_len(buf: &[u8]) -> Result { - let mut buff = Cursor::new(buf); - let actual_len = prost_amino::encoding::decode_varint(&mut buff)?; - if actual_len == 0 { - return Ok(1); + /// Get the Ed25519 signing keypair used by the tests + fn test_ed25519_keypair() -> ed25519::Keypair { + tmkms::key_utils::load_base64_ed25519_key(SIGNING_KEY_PATH).unwrap() } - Ok(actual_len + (prost_amino::encoding::encoded_len_varint(actual_len) as u64)) -} - -#[test] -fn test_handle_and_sign_proposal() { - let chain_id = "test_chain_id"; - let pub_key = test_ed25519_keypair().public; - let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); - let t = TimeMsg { - seconds: dt.timestamp(), - nanos: dt.timestamp_subsec_nanos() as i32, - }; + /// Extract the actual length of an amino message + pub fn extract_actual_len(buf: &[u8]) -> Result { + let mut buff = Cursor::new(buf); + let actual_len = prost_amino::encoding::decode_varint(&mut buff)?; + if actual_len == 0 { + return Ok(1); + } + Ok(actual_len + (prost_amino::encoding::encoded_len_varint(actual_len) as u64)) + } - ProtocolTester::apply(|mut pt| { - let proposal = amino_types::proposal::Proposal { - msg_type: amino_types::SignedMsgType::Proposal.to_u32(), - height: 12345, - round: 1, - timestamp: Some(t), - pol_round: -1, - block_id: None, - signature: vec![], - }; + #[test] + fn test_handle_and_sign_proposal() { + let chain_id = "test_chain_id"; + let pub_key = test_ed25519_keypair().public; - let spr = amino_types::proposal::SignProposalRequest { - proposal: Some(proposal), + let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); + let t = TimeMsg { + seconds: dt.timestamp(), + nanos: dt.timestamp_subsec_nanos() as i32, }; - let mut buf = vec![]; - spr.encode(&mut buf).unwrap(); - pt.write_all(&buf).unwrap(); - - // receive response: - let mut resp_buf = vec![0u8; 1024]; - pt.read(&mut resp_buf).unwrap(); - - let actual_len = extract_actual_len(&resp_buf).unwrap(); - let mut resp = vec![0u8; actual_len as usize]; - resp.copy_from_slice(&mut resp_buf[..(actual_len as usize)]); - - let p_req = proposal::SignedProposalResponse::decode(resp.as_ref()) - .expect("decoding proposal failed"); - let mut sign_bytes: Vec = vec![]; - spr.sign_bytes( - chain_id.parse().unwrap(), - ProtocolVersion::Legacy, - &mut sign_bytes, - ) - .unwrap(); - - let prop: amino_types::proposal::Proposal = p_req - .proposal - .expect("proposal should be embedded but none was found"); - - let signature = ed25519::Signature::try_from(prop.signature.as_slice()).unwrap(); - let msg: &[u8] = sign_bytes.as_slice(); - - assert!(pub_key.verify(msg, &signature).is_ok()); - }); -} - -#[test] -fn test_handle_and_sign_vote() { - let chain_id = "test_chain_id"; - let pub_key = test_ed25519_keypair().public; - - let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); - let t = TimeMsg { - seconds: dt.timestamp(), - nanos: dt.timestamp_subsec_nanos() as i32, - }; + ProtocolTester::apply(|mut pt| { + let proposal = amino_types::proposal::Proposal { + msg_type: amino_types::SignedMsgType::Proposal.to_u32(), + height: 12345, + round: 1, + timestamp: Some(t), + pol_round: -1, + block_id: None, + signature: vec![], + }; + + let spr = amino_types::proposal::SignProposalRequest { + proposal: Some(proposal), + }; + + let mut buf = vec![]; + spr.encode(&mut buf).unwrap(); + pt.write_all(&buf).unwrap(); + + // receive response: + let mut resp_buf = vec![0u8; 1024]; + pt.read(&mut resp_buf).unwrap(); + + let actual_len = extract_actual_len(&resp_buf).unwrap(); + let mut resp = vec![0u8; actual_len as usize]; + resp.copy_from_slice(&mut resp_buf[..(actual_len as usize)]); + + let p_req = proposal::SignedProposalResponse::decode(resp.as_ref()) + .expect("decoding proposal failed"); + let mut sign_bytes: Vec = vec![]; + spr.sign_bytes( + chain_id.parse().unwrap(), + ProtocolVersion::Legacy, + &mut sign_bytes, + ) + .unwrap(); + + let prop: amino_types::proposal::Proposal = p_req + .proposal + .expect("proposal should be embedded but none was found"); + + let signature = ed25519::Signature::try_from(prop.signature.as_slice()).unwrap(); + let msg: &[u8] = sign_bytes.as_slice(); + + assert!(pub_key.verify(msg, &signature).is_ok()); + }); + } - ProtocolTester::apply(|mut pt| { - let vote_msg = amino_types::vote::Vote { - vote_type: 0x01, - height: 12345, - round: 2, - timestamp: Some(t), - block_id: Some(BlockId { - hash: b"some hash00000000000000000000000".to_vec(), - parts_header: Some(PartsSetHeader { - total: 1000000, - hash: b"parts_hash0000000000000000000000".to_vec(), - }), - }), - validator_address: vec![ - 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, - 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, - ], - validator_index: 56789, - signature: vec![], - }; + #[test] + fn test_handle_and_sign_vote() { + let chain_id = "test_chain_id"; + let pub_key = test_ed25519_keypair().public; - let svr = amino_types::vote::SignVoteRequest { - vote: Some(vote_msg), + let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); + let t = TimeMsg { + seconds: dt.timestamp(), + nanos: dt.timestamp_subsec_nanos() as i32, }; - let mut buf = vec![]; - svr.encode(&mut buf).unwrap(); - pt.write_all(&buf).unwrap(); - - // receive response: - let mut resp_buf = vec![0u8; 1024]; - pt.read(&mut resp_buf).unwrap(); - - let actual_len = extract_actual_len(&resp_buf).unwrap(); - let mut resp = vec![0u8; actual_len as usize]; - resp.copy_from_slice(&resp_buf[..actual_len as usize]); - - let v_resp = vote::SignedVoteResponse::decode(resp.as_ref()).expect("decoding vote failed"); - let mut sign_bytes: Vec = vec![]; - svr.sign_bytes( - chain_id.parse().unwrap(), - ProtocolVersion::Legacy, - &mut sign_bytes, - ) - .unwrap(); - - let vote_msg: amino_types::vote::Vote = v_resp - .vote - .expect("vote should be embedded int the response but none was found"); - - let sig: Vec = vote_msg.signature; - assert_ne!(sig.len(), 0); - let signature = ed25519::Signature::try_from(sig.as_slice()).unwrap(); - let msg: &[u8] = sign_bytes.as_slice(); - - assert!(pub_key.verify(msg, &signature).is_ok()); - }); -} - -#[test] -#[should_panic] -fn test_exceed_max_height() { - let chain_id = "test_chain_id"; - let pub_key = test_ed25519_keypair().public; - - let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); - let t = TimeMsg { - seconds: dt.timestamp(), - nanos: dt.timestamp_subsec_nanos() as i32, - }; - - ProtocolTester::apply(|mut pt| { - let vote_msg = amino_types::vote::Vote { - vote_type: 0x01, - height: 500001, - round: 2, - timestamp: Some(t), - block_id: Some(BlockId { - hash: b"some hash00000000000000000000000".to_vec(), - parts_header: Some(PartsSetHeader { - total: 1000000, - hash: b"parts_hash0000000000000000000000".to_vec(), + ProtocolTester::apply(|mut pt| { + let vote_msg = amino_types::vote::Vote { + vote_type: 0x01, + height: 12345, + round: 2, + timestamp: Some(t), + block_id: Some(BlockId { + hash: b"some hash00000000000000000000000".to_vec(), + parts_header: Some(PartsSetHeader { + total: 1000000, + hash: b"parts_hash0000000000000000000000".to_vec(), + }), }), - }), - validator_address: vec![ - 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, - 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, - ], - validator_index: 56789, - signature: vec![], - }; - - let svr = amino_types::vote::SignVoteRequest { - vote: Some(vote_msg), - }; - let mut buf = vec![]; - svr.encode(&mut buf).unwrap(); - pt.write_all(&buf).unwrap(); - - // receive response: - let mut resp_buf = vec![0u8; 1024]; - pt.read(&mut resp_buf).unwrap(); - - let actual_len = extract_actual_len(&resp_buf).unwrap(); - let mut resp = vec![0u8; actual_len as usize]; - resp.copy_from_slice(&resp_buf[..actual_len as usize]); - - let v_resp = vote::SignedVoteResponse::decode(resp.as_ref()).expect("decoding vote failed"); - let mut sign_bytes: Vec = vec![]; - svr.sign_bytes( - chain_id.parse().unwrap(), - ProtocolVersion::Legacy, - &mut sign_bytes, - ) - .unwrap(); - - let vote_msg: amino_types::vote::Vote = v_resp - .vote - .expect("vote should be embedded int the response but none was found"); + validator_address: vec![ + 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, + 0xf4, 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, + ], + validator_index: 56789, + signature: vec![], + }; + + let svr = amino_types::vote::SignVoteRequest { + vote: Some(vote_msg), + }; + let mut buf = vec![]; + svr.encode(&mut buf).unwrap(); + pt.write_all(&buf).unwrap(); + + // receive response: + let mut resp_buf = vec![0u8; 1024]; + pt.read(&mut resp_buf).unwrap(); + + let actual_len = extract_actual_len(&resp_buf).unwrap(); + let mut resp = vec![0u8; actual_len as usize]; + resp.copy_from_slice(&resp_buf[..actual_len as usize]); + + let v_resp = + vote::SignedVoteResponse::decode(resp.as_ref()).expect("decoding vote failed"); + let mut sign_bytes: Vec = vec![]; + svr.sign_bytes( + chain_id.parse().unwrap(), + ProtocolVersion::Legacy, + &mut sign_bytes, + ) + .unwrap(); + + let vote_msg: amino_types::vote::Vote = v_resp + .vote + .expect("vote should be embedded int the response but none was found"); + + let sig: Vec = vote_msg.signature; + assert_ne!(sig.len(), 0); + + let signature = ed25519::Signature::try_from(sig.as_slice()).unwrap(); + let msg: &[u8] = sign_bytes.as_slice(); + + assert!(pub_key.verify(msg, &signature).is_ok()); + }); + } - let sig: Vec = vote_msg.signature; - assert_ne!(sig.len(), 0); + #[test] + #[should_panic] + fn test_exceed_max_height() { + let chain_id = "test_chain_id"; + let pub_key = test_ed25519_keypair().public; - let signature = ed25519::Signature::try_from(sig.as_slice()).unwrap(); - let msg: &[u8] = sign_bytes.as_slice(); + let dt = "2018-02-11T07:09:22.765Z".parse::>().unwrap(); + let t = TimeMsg { + seconds: dt.timestamp(), + nanos: dt.timestamp_subsec_nanos() as i32, + }; - assert!(pub_key.verify(msg, &signature).is_ok()); - }); -} + ProtocolTester::apply(|mut pt| { + let vote_msg = amino_types::vote::Vote { + vote_type: 0x01, + height: 500001, + round: 2, + timestamp: Some(t), + block_id: Some(BlockId { + hash: b"some hash00000000000000000000000".to_vec(), + parts_header: Some(PartsSetHeader { + total: 1000000, + hash: b"parts_hash0000000000000000000000".to_vec(), + }), + }), + validator_address: vec![ + 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, + 0xf4, 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, + ], + validator_index: 56789, + signature: vec![], + }; + + let svr = amino_types::vote::SignVoteRequest { + vote: Some(vote_msg), + }; + let mut buf = vec![]; + svr.encode(&mut buf).unwrap(); + pt.write_all(&buf).unwrap(); + + // receive response: + let mut resp_buf = vec![0u8; 1024]; + pt.read(&mut resp_buf).unwrap(); + + let actual_len = extract_actual_len(&resp_buf).unwrap(); + let mut resp = vec![0u8; actual_len as usize]; + resp.copy_from_slice(&resp_buf[..actual_len as usize]); + + let v_resp = + vote::SignedVoteResponse::decode(resp.as_ref()).expect("decoding vote failed"); + let mut sign_bytes: Vec = vec![]; + svr.sign_bytes( + chain_id.parse().unwrap(), + ProtocolVersion::Legacy, + &mut sign_bytes, + ) + .unwrap(); + + let vote_msg: amino_types::vote::Vote = v_resp + .vote + .expect("vote should be embedded int the response but none was found"); + + let sig: Vec = vote_msg.signature; + assert_ne!(sig.len(), 0); + + let signature = ed25519::Signature::try_from(sig.as_slice()).unwrap(); + let msg: &[u8] = sign_bytes.as_slice(); + + assert!(pub_key.verify(msg, &signature).is_ok()); + }); + } -#[test] -fn test_handle_and_sign_get_publickey() { - ProtocolTester::apply(|mut pt| { - let mut buf = vec![]; + #[test] + fn test_handle_and_sign_get_publickey() { + ProtocolTester::apply(|mut pt| { + let mut buf = vec![]; - PubKeyRequest {}.encode(&mut buf).unwrap(); + PubKeyRequest {}.encode(&mut buf).unwrap(); - pt.write_all(&buf).unwrap(); + pt.write_all(&buf).unwrap(); - // receive response: - let mut resp_buf = vec![0u8; 1024]; - pt.read(&mut resp_buf).unwrap(); + // receive response: + let mut resp_buf = vec![0u8; 1024]; + pt.read(&mut resp_buf).unwrap(); - let actual_len = extract_actual_len(&resp_buf).unwrap(); - let mut resp = vec![0u8; actual_len as usize]; - resp.copy_from_slice(&resp_buf[..actual_len as usize]); + let actual_len = extract_actual_len(&resp_buf).unwrap(); + let mut resp = vec![0u8; actual_len as usize]; + resp.copy_from_slice(&resp_buf[..actual_len as usize]); - let pk_resp = PubKeyResponse::decode(resp.as_ref()).expect("decoding public key failed"); - assert_ne!(pk_resp.pub_key_ed25519.len(), 0); - }); -} + let pk_resp = + PubKeyResponse::decode(resp.as_ref()).expect("decoding public key failed"); + assert_ne!(pk_resp.pub_key_ed25519.len(), 0); + }); + } -#[test] -fn test_handle_and_sign_ping_pong() { - ProtocolTester::apply(|mut pt| { - let mut buf = vec![]; - PingRequest {}.encode(&mut buf).unwrap(); - pt.write_all(&buf).unwrap(); - - // receive response: - let mut resp_buf = vec![0u8; 1024]; - pt.read(&mut resp_buf).unwrap(); - - let actual_len = extract_actual_len(&resp_buf).unwrap(); - let mut resp = vec![0u8; actual_len as usize]; - resp.copy_from_slice(&resp_buf[..actual_len as usize]); - PingResponse::decode(resp.as_ref()).expect("decoding ping response failed"); - }); + #[test] + fn test_handle_and_sign_ping_pong() { + ProtocolTester::apply(|mut pt| { + let mut buf = vec![]; + PingRequest {}.encode(&mut buf).unwrap(); + pt.write_all(&buf).unwrap(); + + // receive response: + let mut resp_buf = vec![0u8; 1024]; + pt.read(&mut resp_buf).unwrap(); + + let actual_len = extract_actual_len(&resp_buf).unwrap(); + let mut resp = vec![0u8; actual_len as usize]; + resp.copy_from_slice(&resp_buf[..actual_len as usize]); + PingResponse::decode(resp.as_ref()).expect("decoding ping response failed"); + }); + } } diff --git a/tmkms-hashicorp.toml b/tmkms-hashicorp.toml new file mode 100644 index 00000000..40ac8e2d --- /dev/null +++ b/tmkms-hashicorp.toml @@ -0,0 +1,41 @@ +# Tendermint KMS configuration file + +## Chain Configuration +### Cosmos Hub Network +[[chain]] +id = "cosmoshub-4" +key_format = { type = "bech32", account_key_prefix = "cosmospub", consensus_key_prefix = "cosmosvalconspub" } +state_file = "/home/soleinik/work/rust/tmkms/state/cosmoshub-4-consensus.json" + +[[chain]] +id = "cosmoshub-3" +key_format = { type = "bech32", account_key_prefix = "cosmospub", consensus_key_prefix = "cosmosvalconspub" } +state_file = "/home/soleinik/work/rust/tmkms/state/cosmoshub-3-consensus.json" + + + +## Signing Provider Configuration +[[providers.hashicorp]] +chain_id = "cosmoshub-4" +api_endpoint= "http://127.0.0.1:8200" +access_token="hvs.CAESIBwDAKQh2JKuxibeHOV-jmc2T68loAKLNWO2_QX1l7L3Gh4KHGh2cy5iYnRJRVVLdHBqTVMwUGdLZFNGWjNCZkc" +pk_name="cosmoshub-sign-key" + +[[providers.hashicorp]] +chain_id = "cosmoshub-4" +api_endpoint= "http://127.0.0.1:8200" +access_token="hvs.CAESIBwDAKQh2JKuxibeHOV-jmc2T68loAKLNWO2_QX1l7L3Gh4KHGh2cy5iYnRJRVVLdHBqTVMwUGdLZFNGWjNCZkc" +pk_name="cosmoshub-sign-key" + + +## Validator Configuration + +# [[validator]] +# chain_id = "cosmoshub-3" +# addr = "tcp://deadbeefdeadbeefdeadbeefdeadbeefdeadbeef@example1.example.com:26658" +# secret_key = "/home/soleinik/work/rust/tmkms/secrets/kms-identity.key" +# protocol_version = "legacy" +# reconnect = true + + + From 4765b6e8fa03237207a29f3145e9c806e1e46e6e Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Tue, 18 Oct 2022 15:01:22 -0500 Subject: [PATCH 2/7] tests+clippy fixes --- Cargo.toml | 1 + src/commands/hashicorp/test.rs | 5 +--- src/commands/hashicorp/upload.rs | 9 +++---- src/keyring/providers/hashicorp.rs | 32 +++++++++++------------ src/keyring/providers/hashicorp/client.rs | 18 ++++++------- src/keyring/providers/hashicorp/error.rs | 17 +++++------- 6 files changed, 37 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a6a1ef4..d9c56886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ yubihsm-server = ["yubihsm/http-server", "rpassword"] fortanixdsm = ["elliptic-curve", "sdkms", "url", "uuid"] hashicorp = ["hashicorp_vault", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] + # Enable integer overflow checks in release builds for security reasons [profile.release] overflow-checks = true diff --git a/src/commands/hashicorp/test.rs b/src/commands/hashicorp/test.rs index 7895a1f3..cba93f3f 100644 --- a/src/commands/hashicorp/test.rs +++ b/src/commands/hashicorp/test.rs @@ -59,10 +59,7 @@ impl Runnable for TestCommand { &config.access_token, &self.pk_name, ) - .expect(&format!( - "Unable to connect to Vault at {}", - config.api_endpoint - )); + .unwrap_or_else(|_| panic!("Unable to connect to Vault at {}", config.api_endpoint)); let mut app = crate::keyring::providers::hashicorp::signer::Ed25519HashiCorpAppSigner::new(app); diff --git a/src/commands/hashicorp/upload.rs b/src/commands/hashicorp/upload.rs index f073710b..3ae68817 100644 --- a/src/commands/hashicorp/upload.rs +++ b/src/commands/hashicorp/upload.rs @@ -79,7 +79,7 @@ impl Runnable for UploadCommand { process::exit(1); }; - self.upload(&config); + self.upload(config); } } @@ -101,10 +101,7 @@ impl UploadCommand { &vault_token, &self.pk_name, ) - .expect(&format!( - "Unable to connect to Vault at {}", - config.api_endpoint - )); + .unwrap_or_else(|_| panic!("Unable to connect to Vault at {}", config.api_endpoint)); use aes_gcm::KeyInit; let v_aes_key = aes_gcm::Aes256Gcm::generate_key(&mut aes_gcm::aead::OsRng); @@ -119,7 +116,7 @@ impl UploadCommand { let mut aes_key = [0u8; KEY_SIZE_AES256]; aes_key.copy_from_slice(&v_aes_key[..KEY_SIZE_AES256]); - let kek = aes_kw::KekAes256::from(aes_key.clone()); + let kek = aes_kw::KekAes256::from(aes_key); let wrapped_input_key = kek .wrap_with_padding_vec(&ed25519_input_key) .expect("input key wrapping error!"); diff --git a/src/keyring/providers/hashicorp.rs b/src/keyring/providers/hashicorp.rs index 4363a447..e750a270 100644 --- a/src/keyring/providers/hashicorp.rs +++ b/src/keyring/providers/hashicorp.rs @@ -24,10 +24,7 @@ pub fn init( configs: &[HashiCorpConfig], ) -> Result<(), Error> { if configs.is_empty() { - fail!( - ConfigError, - "expected at least one [providers.hashicorp] in config, found none!" - ); + return Ok(()); } let mut chains = Vec::::new(); @@ -48,20 +45,23 @@ pub fn init( &config.access_token, &config.pk_name, ) - .expect(&format!( - "Failed to authenticate to Vault for chain id:{}", - config.chain_id - )); + .unwrap_or_else(|_| { + panic!( + "Failed to authenticate to Vault for chain id:{}", + config.chain_id + ) + }); - let public_key = app.public_key().expect(&format!( - "Failed to get public key for chain id:{}", - config.chain_id - )); + let public_key = app.public_key().unwrap_or_else(|_| { + panic!("Failed to get public key for chain id:{}", config.chain_id,) + }); - let public_key = ed25519::PublicKey::from_bytes(&public_key).expect(&format!( - "invalid Ed25519 public key for chain id:{}", - config.chain_id - )); + let public_key = ed25519::PublicKey::from_bytes(&public_key).unwrap_or_else(|_| { + panic!( + "invalid Ed25519 public key for chain id:{}", + config.chain_id + ) + }); let provider = Ed25519HashiCorpAppSigner::new(app); diff --git a/src/keyring/providers/hashicorp/client.rs b/src/keyring/providers/hashicorp/client.rs index 505a9621..3854dae0 100644 --- a/src/keyring/providers/hashicorp/client.rs +++ b/src/keyring/providers/hashicorp/client.rs @@ -44,16 +44,16 @@ pub(crate) struct ImportRequest { #[allow(dead_code)] #[derive(Debug)] pub(crate) enum ExportKeyType { - EncryptionKey, - SigningKey, - HmacKey, + Encryption, + Signing, + Hmac, } impl std::fmt::Display for ExportKeyType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ExportKeyType::EncryptionKey => write!(f, "encryption-key"), - ExportKeyType::SigningKey => write!(f, "signing-key"), - ExportKeyType::HmacKey => write!(f, "hmac-key"), + ExportKeyType::Encryption => write!(f, "encryption-key"), + ExportKeyType::Signing => write!(f, "signing-key"), + ExportKeyType::Hmac => write!(f, "hmac-key"), } } } @@ -121,7 +121,7 @@ impl TendermintValidatorApp { pub fn public_key(&mut self) -> Result<[u8; ed25519_dalek::PUBLIC_KEY_LENGTH], Error> { if let Some(v) = self.public_key_value { debug!("using cached public key {}...", self.key_name); - return Ok(v.clone()); + return Ok(v); } debug!("fetching public key for {}...", self.key_name); @@ -196,7 +196,7 @@ impl TendermintValidatorApp { array.copy_from_slice(&pubk[..ed25519_dalek::PUBLIC_KEY_LENGTH]); //cache it... - self.public_key_value = Some(array.clone()); + self.public_key_value = Some(array); debug!("Public key: value cached {}", self.key_name,); Ok(array) @@ -235,7 +235,7 @@ impl TendermintValidatorApp { return Err(Error::NoSignature); }; - let parts = data.signature.split(":").collect::>(); + let parts = data.signature.split(':').collect::>(); if parts.len() != 3 { return Err(Error::InvalidSignature(format!( "expected 3 parts, received:{} full:{}", diff --git a/src/keyring/providers/hashicorp/error.rs b/src/keyring/providers/hashicorp/error.rs index 5cd0c242..a11d3a66 100644 --- a/src/keyring/providers/hashicorp/error.rs +++ b/src/keyring/providers/hashicorp/error.rs @@ -17,37 +17,34 @@ pub enum Error { InvalidSignature(String), #[error("ApiClient error:{0}")] - ApiClientError(String), + ApiClient(String), #[error("Base64 decode error")] - DecodeError(base64::DecodeError), + Decode(base64::DecodeError), #[error("Serde error")] - SerDeError(serde_json::Error), - - #[error("Signature error")] - SignatureError(signature::Error), + SerDe(serde_json::Error), } impl From for Error { fn from(err: hashicorp_vault::Error) -> Error { - Error::ApiClientError(err.to_string()) + Error::ApiClient(err.to_string()) } } impl From for Error { fn from(err: base64::DecodeError) -> Error { - Error::DecodeError(err) + Error::Decode(err) } } impl From for Error { fn from(err: serde_json::Error) -> Error { - Error::SerDeError(err) + Error::SerDe(err) } } impl From for Error { fn from(err: signature::Error) -> Error { - Error::SignatureError(err) + Error::InvalidSignature(err.to_string()) } } From 4c17928e8c503e279f8c829190fced3faef6de69 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Wed, 19 Oct 2022 15:57:25 -0500 Subject: [PATCH 3/7] vault_client dependency replaced with ureq --- Cargo.lock | 519 ++++-------------- Cargo.toml | 7 +- src/amino_types/block_id.rs | 8 +- src/amino_types/ed25519.rs | 4 +- src/amino_types/ping.rs | 4 +- src/amino_types/proposal.rs | 6 +- src/amino_types/remote_error.rs | 2 +- src/amino_types/time.rs | 2 +- src/amino_types/vote.rs | 8 +- src/commands/hashicorp/test.rs | 2 +- src/keyring/providers/hashicorp.rs | 1 + src/keyring/providers/hashicorp/client.rs | 145 +++-- src/keyring/providers/hashicorp/error.rs | 17 +- src/keyring/providers/hashicorp/vault_data.rs | 52 ++ 14 files changed, 276 insertions(+), 501 deletions(-) create mode 100644 src/keyring/providers/hashicorp/vault_data.rs diff --git a/Cargo.lock b/Cargo.lock index 2ab47a42..368c36ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32ce48eff491a0ab32c0e1cadd7ba5221a38dc53438992c5e857ab9b8a3f1a3e" dependencies = [ "abscissa_core", - "tokio 1.21.2", + "tokio", ] [[package]] @@ -143,7 +143,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -199,7 +199,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -229,12 +229,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -413,7 +407,7 @@ dependencies = [ "num-traits", "time 0.1.44", "wasm-bindgen", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -512,7 +506,7 @@ checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -592,6 +586,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crypto-bigint" version = "0.3.2" @@ -777,15 +780,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "eyre" version = "0.6.8" @@ -837,6 +831,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "flex-error" version = "0.4.4" @@ -892,22 +896,6 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures" version = "0.3.24" @@ -992,7 +980,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.9", + "pin-project-lite", "pin-utils", "slab", ] @@ -1058,26 +1046,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio 0.2.25", - "tokio-util 0.3.1", - "tracing", - "tracing-futures", -] - [[package]] name = "h2" version = "0.3.14" @@ -1092,8 +1060,8 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.21.2", - "tokio-util 0.7.4", + "tokio", + "tokio-util", "tracing", ] @@ -1103,35 +1071,18 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashicorp_vault" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd636b56a3e214f65bc9fec3217c3add72a424740162643267892149e992eb2" -dependencies = [ - "base64 0.12.3", - "chrono", - "log", - "quick-error", - "reqwest", - "serde", - "serde_derive", - "serde_json", - "url 2.3.1", -] - [[package]] name = "headers" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ - "base64 0.13.0", + "base64", "bitflags", "bytes 1.2.1", "headers-core", "http", - "httpdate 1.0.2", + "httpdate", "mime", "sha1", ] @@ -1238,17 +1189,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes 1.2.1", "fnv", - "itoa 1.0.3", -] - -[[package]] -name = "http-body" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" -dependencies = [ - "bytes 0.5.6", - "http", + "itoa", ] [[package]] @@ -1259,7 +1200,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.2.1", "http", - "pin-project-lite 0.2.9", + "pin-project-lite", ] [[package]] @@ -1268,42 +1209,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" - [[package]] name = "httpdate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "hyper" -version = "0.13.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" -dependencies = [ - "bytes 0.5.6", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.2.7", - "http", - "http-body 0.3.1", - "httparse", - "httpdate 0.3.2", - "itoa 0.4.8", - "pin-project", - "socket2 0.3.19", - "tokio 0.2.25", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "0.14.20" @@ -1314,15 +1225,15 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.14", + "h2", "http", - "http-body 0.4.5", + "http-body", "httparse", - "httpdate 1.0.2", - "itoa 1.0.3", - "pin-project-lite 0.2.9", - "socket2 0.4.7", - "tokio 1.21.2", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", "tower-service", "tracing", "want", @@ -1338,10 +1249,10 @@ dependencies = [ "futures", "headers", "http", - "hyper 0.14.20", + "hyper", "hyper-rustls 0.22.1", "rustls-native-certs 0.5.0", - "tokio 1.21.2", + "tokio", "tokio-rustls 0.22.0", "tower-service", "webpki 0.21.4", @@ -1355,11 +1266,11 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ "ct-logs", "futures-util", - "hyper 0.14.20", + "hyper", "log", "rustls 0.19.1", "rustls-native-certs 0.5.0", - "tokio 1.21.2", + "tokio", "tokio-rustls 0.22.0", "webpki 0.21.4", "webpki-roots 0.21.1", @@ -1372,28 +1283,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ "http", - "hyper 0.14.20", + "hyper", "log", "rustls 0.20.6", "rustls-native-certs 0.6.2", - "tokio 1.21.2", + "tokio", "tokio-rustls 0.23.4", "webpki-roots 0.22.5", ] -[[package]] -name = "hyper-tls" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" -dependencies = [ - "bytes 0.5.6", - "hyper 0.13.10", - "native-tls", - "tokio 0.2.25", - "tokio-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.50" @@ -1404,7 +1302,7 @@ dependencies = [ "core-foundation-sys", "js-sys", "wasm-bindgen", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1469,21 +1367,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "ipnet" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" - [[package]] name = "itertools" version = "0.7.11" @@ -1502,12 +1385,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.3" @@ -1542,16 +1419,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1659,16 +1526,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.5.4" @@ -1678,25 +1535,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - [[package]] name = "mio" version = "0.8.4" @@ -1709,18 +1547,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - [[package]] name = "mockito" version = "0.31.0" @@ -1757,17 +1583,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "nix" version = "0.13.1" @@ -2042,12 +1857,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -2344,42 +2153,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "reqwest" -version = "0.10.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" -dependencies = [ - "base64 0.13.0", - "bytes 0.5.6", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "http-body 0.3.1", - "hyper 0.13.10", - "hyper-tls", - "ipnet", - "js-sys", - "lazy_static", - "log", - "mime", - "mime_guess", - "native-tls", - "percent-encoding 2.2.0", - "pin-project-lite 0.2.9", - "serde", - "serde_urlencoded", - "tokio 0.2.25", - "tokio-tls", - "url 2.3.1", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", + "winapi", ] [[package]] @@ -2405,7 +2179,7 @@ dependencies = [ "spin 0.5.2", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2437,7 +2211,7 @@ dependencies = [ "libc", "serde", "serde_json", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2493,7 +2267,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64 0.13.0", + "base64", "log", "ring", "sct 0.6.1", @@ -2542,7 +2316,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ - "base64 0.13.0", + "base64", ] [[package]] @@ -2602,7 +2376,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "474a033e7cb7c343a496026464a55bee3d98bc308d2f2ed53a9d8a21c68e1419" dependencies = [ - "base64 0.13.0", + "base64", "bitflags", "headers", "log", @@ -2706,7 +2480,7 @@ version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ - "itoa 1.0.3", + "itoa", "ryu", "serde", ] @@ -2729,7 +2503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.3", + "itoa", "ryu", "serde", ] @@ -2825,8 +2599,8 @@ dependencies = [ "futures-executor", "headers", "http", - "hyper 0.14.20", - "tokio 1.21.2", + "hyper", + "tokio", "tokio-native-tls", "tokio-stream", ] @@ -2846,17 +2620,6 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi 0.3.9", -] - [[package]] name = "socket2" version = "0.4.7" @@ -2864,7 +2627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2978,7 +2741,7 @@ dependencies = [ "libc", "redox_syscall", "remove_dir_all", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3083,7 +2846,7 @@ dependencies = [ "futures", "getrandom 0.2.7", "http", - "hyper 0.14.20", + "hyper", "hyper-proxy", "hyper-rustls 0.22.1", "peg", @@ -3097,7 +2860,7 @@ dependencies = [ "tendermint-proto", "thiserror", "time 0.3.11", - "tokio 1.21.2", + "tokio", "tracing", "url 2.3.1", "uuid 0.8.2", @@ -3162,7 +2925,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3171,7 +2934,7 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ - "itoa 1.0.3", + "itoa", "libc", "num_threads", "serde", @@ -3220,7 +2983,7 @@ dependencies = [ "abscissa_tokio", "aes-gcm", "aes-kw", - "base64 0.13.0", + "base64", "byteorder", "bytes 0.5.6", "bytes 1.2.1", @@ -3231,10 +2994,9 @@ dependencies = [ "elliptic-curve", "eyre", "getrandom 0.2.7", - "hashicorp_vault", "hkd32", "hkdf 0.12.3", - "hyper 0.14.20", + "hyper", "hyper-rustls 0.23.0", "k256", "ledger", @@ -3264,6 +3026,7 @@ dependencies = [ "tendermint-proto", "tendermint-rpc", "thiserror", + "ureq", "url 2.3.1", "uuid 1.1.2", "wait-timeout", @@ -3271,24 +3034,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tokio" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "memchr", - "mio 0.6.23", - "num_cpus", - "pin-project-lite 0.1.12", - "slab", -] - [[package]] name = "tokio" version = "1.21.2" @@ -3299,12 +3044,12 @@ dependencies = [ "bytes 1.2.1", "libc", "memchr", - "mio 0.8.4", + "mio", "num_cpus", - "pin-project-lite 0.2.9", - "socket2 0.4.7", + "pin-project-lite", + "socket2", "tokio-macros", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3325,7 +3070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio 1.21.2", + "tokio", ] [[package]] @@ -3335,7 +3080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls 0.19.1", - "tokio 1.21.2", + "tokio", "webpki 0.21.4", ] @@ -3346,7 +3091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ "rustls 0.20.6", - "tokio 1.21.2", + "tokio", "webpki 0.22.0", ] @@ -3357,32 +3102,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" dependencies = [ "futures-core", - "pin-project-lite 0.2.9", - "tokio 1.21.2", -] - -[[package]] -name = "tokio-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" -dependencies = [ - "native-tls", - "tokio 0.2.25", -] - -[[package]] -name = "tokio-util" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", + "pin-project-lite", + "tokio", ] [[package]] @@ -3394,8 +3115,8 @@ dependencies = [ "bytes 1.2.1", "futures-core", "futures-sink", - "pin-project-lite 0.2.9", - "tokio 1.21.2", + "pin-project-lite", + "tokio", "tracing", ] @@ -3421,8 +3142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.9", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -3448,16 +3168,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.3" @@ -3499,15 +3209,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -3561,6 +3262,25 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "ureq" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls 0.20.6", + "serde", + "serde_json", + "url 2.3.1", + "webpki 0.22.0", + "webpki-roots 0.22.5", +] + [[package]] name = "url" version = "1.7.2" @@ -3640,7 +3360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi 0.3.9", + "winapi", "winapi-util", ] @@ -3679,8 +3399,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if 1.0.0", - "serde", - "serde_json", "wasm-bindgen-macro", ] @@ -3699,18 +3417,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -3788,12 +3494,6 @@ dependencies = [ "webpki 0.22.0", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -3804,12 +3504,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -3822,7 +3516,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3874,25 +3568,6 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" -[[package]] -name = "winreg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "x25519-dalek" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index d9c56886..28b69c8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,9 @@ wait-timeout = "0.2" yubihsm = { version = "0.41", features = ["secp256k1", "setup", "usb"], optional = true } zeroize = "1" -hashicorp_vault = { version = "2.1.0", optional = true } + + +ureq = { version = "~2.5", default-features=false, features = ["tls", "json", "gzip"], optional = true} base64 = { version = "0.13.0", optional = true} aes-kw = { version = "0.2.1", features = ["std"], optional = true} rsa = { version = "0.6.1", default = true, optional = true} @@ -80,8 +82,7 @@ tx-signer = ["abscissa_tokio", "hyper", "hyper-rustls", "stdtx", "tendermint-rpc yubihsm-mock = ["yubihsm/mockhsm"] yubihsm-server = ["yubihsm/http-server", "rpassword"] fortanixdsm = ["elliptic-curve", "sdkms", "url", "uuid"] -hashicorp = ["hashicorp_vault", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] - +hashicorp = ["ureq", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] # Enable integer overflow checks in release builds for security reasons [profile.release] diff --git a/src/amino_types/block_id.rs b/src/amino_types/block_id.rs index 2a4d43e9..392201a2 100644 --- a/src/amino_types/block_id.rs +++ b/src/amino_types/block_id.rs @@ -7,7 +7,7 @@ use tendermint::{ }; use tendermint_proto as proto; -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct BlockId { #[prost_amino(bytes, tag = "1")] pub hash: Vec, @@ -95,7 +95,7 @@ impl ConsensusMessage for BlockId { } } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct CanonicalBlockId { #[prost_amino(bytes, tag = "1")] pub hash: Vec, @@ -119,7 +119,7 @@ impl ParseId for CanonicalBlockId { } } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct PartsSetHeader { #[prost_amino(int64, tag = "1")] pub total: i64, @@ -170,7 +170,7 @@ impl From for PartsSetHeader { } } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct CanonicalPartSetHeader { #[prost_amino(bytes, tag = "1")] pub hash: Vec, diff --git a/src/amino_types/ed25519.rs b/src/amino_types/ed25519.rs index 69cef702..7be1df0c 100644 --- a/src/amino_types/ed25519.rs +++ b/src/amino_types/ed25519.rs @@ -12,14 +12,14 @@ use tendermint::public_key::{Ed25519, PublicKey}; pub const AMINO_NAME: &str = "tendermint/remotesigner/PubKeyRequest"; pub static AMINO_PREFIX: Lazy> = Lazy::new(|| compute_prefix(AMINO_NAME)); -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, Eq, PartialEq, Message)] #[amino_name = "tendermint/remotesigner/PubKeyResponse"] pub struct PubKeyResponse { #[prost_amino(bytes, tag = "1", amino_name = "tendermint/PubKeyEd25519")] pub pub_key_ed25519: Vec, } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, Eq, PartialEq, Message)] #[amino_name = "tendermint/remotesigner/PubKeyRequest"] pub struct PubKeyRequest {} diff --git a/src/amino_types/ping.rs b/src/amino_types/ping.rs index 983288b4..41f4afa7 100644 --- a/src/amino_types/ping.rs +++ b/src/amino_types/ping.rs @@ -5,10 +5,10 @@ use prost_amino_derive::Message; pub const AMINO_NAME: &str = "tendermint/remotesigner/PingRequest"; pub static AMINO_PREFIX: Lazy> = Lazy::new(|| compute_prefix(AMINO_NAME)); -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/PingRequest"] pub struct PingRequest {} -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/PingResponse"] pub struct PingResponse {} diff --git a/src/amino_types/proposal.rs b/src/amino_types/proposal.rs index f99121a4..0b23c639 100644 --- a/src/amino_types/proposal.rs +++ b/src/amino_types/proposal.rs @@ -18,7 +18,7 @@ use prost_amino_derive::Message; use tendermint::{block, chain, consensus, error}; use tendermint_proto::types as proto_types; -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct Proposal { #[prost_amino(uint32, tag = "1")] pub msg_type: u32, @@ -46,7 +46,7 @@ impl block::ParseHeight for Proposal { pub const AMINO_NAME: &str = "tendermint/remotesigner/SignProposalRequest"; pub static AMINO_PREFIX: Lazy> = Lazy::new(|| compute_prefix(AMINO_NAME)); -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/SignProposalRequest"] pub struct SignProposalRequest { #[prost_amino(message, tag = "1")] @@ -84,7 +84,7 @@ impl block::ParseHeight for CanonicalProposal { } } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/SignedProposalResponse"] pub struct SignedProposalResponse { #[prost_amino(message, tag = "1")] diff --git a/src/amino_types/remote_error.rs b/src/amino_types/remote_error.rs index 1561e9cf..277ceceb 100644 --- a/src/amino_types/remote_error.rs +++ b/src/amino_types/remote_error.rs @@ -1,6 +1,6 @@ use prost_amino_derive::Message; -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct RemoteError { #[prost_amino(sint32, tag = "1")] pub code: i32, diff --git a/src/amino_types/time.rs b/src/amino_types/time.rs index 968e4b54..0a94f14f 100644 --- a/src/amino_types/time.rs +++ b/src/amino_types/time.rs @@ -8,7 +8,7 @@ use tendermint::{ }; use tendermint_proto as proto; -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct TimeMsg { // TODO(ismail): switch to protobuf's well known type as soon as // https://github.com/tendermint/go-amino/pull/224 was merged diff --git a/src/amino_types/vote.rs b/src/amino_types/vote.rs index b4248568..6e623d2c 100644 --- a/src/amino_types/vote.rs +++ b/src/amino_types/vote.rs @@ -20,7 +20,7 @@ use tendermint_proto::types as proto_types; const VALIDATOR_ADDR_SIZE: usize = 20; -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct Vote { #[prost_amino(uint32, tag = "1")] pub vote_type: u32, @@ -83,14 +83,14 @@ impl block::ParseHeight for Vote { pub const AMINO_NAME: &str = "tendermint/remotesigner/SignVoteRequest"; pub static AMINO_PREFIX: Lazy> = Lazy::new(|| compute_prefix(AMINO_NAME)); -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/SignVoteRequest"] pub struct SignVoteRequest { #[prost_amino(message, tag = "1")] pub vote: Option, } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] #[amino_name = "tendermint/remotesigner/SignedVoteResponse"] pub struct SignedVoteResponse { #[prost_amino(message, tag = "1")] @@ -99,7 +99,7 @@ pub struct SignedVoteResponse { pub err: Option, } -#[derive(Clone, PartialEq, Message)] +#[derive(Clone, PartialEq, Eq, Message)] pub struct CanonicalVote { #[prost_amino(uint32, tag = "1")] pub vote_type: u32, diff --git a/src/commands/hashicorp/test.rs b/src/commands/hashicorp/test.rs index cba93f3f..f36e7d69 100644 --- a/src/commands/hashicorp/test.rs +++ b/src/commands/hashicorp/test.rs @@ -59,7 +59,7 @@ impl Runnable for TestCommand { &config.access_token, &self.pk_name, ) - .unwrap_or_else(|_| panic!("Unable to connect to Vault at {}", config.api_endpoint)); + .unwrap_or_else(|e| panic!("Unable to connect to Vault {} {}", config.api_endpoint, e)); let mut app = crate::keyring::providers::hashicorp::signer::Ed25519HashiCorpAppSigner::new(app); diff --git a/src/keyring/providers/hashicorp.rs b/src/keyring/providers/hashicorp.rs index e750a270..a0acece4 100644 --- a/src/keyring/providers/hashicorp.rs +++ b/src/keyring/providers/hashicorp.rs @@ -2,6 +2,7 @@ pub(crate) mod client; pub(crate) mod error; pub(crate) mod signer; +pub(crate) mod vault_data; use crate::{ chain, diff --git a/src/keyring/providers/hashicorp/client.rs b/src/keyring/providers/hashicorp/client.rs index 3854dae0..20f413f4 100644 --- a/src/keyring/providers/hashicorp/client.rs +++ b/src/keyring/providers/hashicorp/client.rs @@ -2,18 +2,21 @@ use abscissa_core::prelude::*; use std::collections::{BTreeMap, HashMap}; use super::error::Error; -use hashicorp_vault::{ - client::{EndpointResponse, HttpVerb, TokenData, VaultResponse}, - Client, -}; + +use super::vault_data; + +use std::time::Duration; +use ureq::Agent; use serde::{Deserialize, Serialize}; -const VAULT_BACKEND_NAME: &str = "transit"; pub const CONSENUS_KEY_TYPE: &str = "ed25519"; +const VAULT_TOKEN: &str = "X-Vault-Token"; pub(crate) struct TendermintValidatorApp { - client: Client, + agent: Agent, + api_endpoint: String, + token: String, key_name: String, public_key_value: Option<[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]>, } @@ -100,21 +103,52 @@ impl std::fmt::Display for CreateKeyType { } impl TendermintValidatorApp { - pub fn connect(host: &str, token: &str, key_name: &str) -> Result { + pub fn connect(api_endpoint: &str, token: &str, key_name: &str) -> Result { //this call performs token self lookup, to fail fast - let mut client = Client::new(host, token)?; - client.secret_backend(VAULT_BACKEND_NAME); + //let mut client = Client::new(host, token)?; + + //default conect timeout is 30s, this should be ok, since we block + let agent: Agent = ureq::AgentBuilder::new() + .timeout_read(Duration::from_secs(5)) + .timeout_write(Duration::from_secs(5)) + .user_agent(&format!( + "{}/{}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + )) + .build(); + + //client.secret_backend(VAULT_BACKEND_NAME); let app = TendermintValidatorApp { - client, + agent, + api_endpoint: api_endpoint.to_owned(), + token: token.to_owned(), key_name: key_name.to_owned(), public_key_value: None, }; - debug!("Initialized with Vault host at {}", host); + debug!("Initialized with Vault host at {}", api_endpoint); + app.hand_shake()?; + Ok(app) } + fn hand_shake(&self) -> Result, Error> { + self.agent + .get(&format!("{}/v1/auth/token/lookup-self", self.api_endpoint)) + .set(VAULT_TOKEN, &self.token) + .call() + .map_err(|e| { + super::error::Error::Combined( + "Is \"access_token\" value correct?".into(), + Box::new(e.into()), + ) + })? + .into_json::>() + .map_err(super::error::Error::Io) + } + //vault read transit/keys/cosmoshub-sign-key //GET http://0.0.0.0:8200/v1/transit/keys/cosmoshub-sign-key /// Get public key @@ -132,17 +166,17 @@ impl TendermintValidatorApp { keys: BTreeMap>, } - let data = self.client.call_endpoint::( - HttpVerb::GET, - &format!("transit/keys/{}", self.key_name), - None, - None, - )?; - - //{ keys: {1: {"name": "ed25519", "public_key": "R5n8OFaknb/3sCTx/aegNzYukwVx0uNtzzK/2RclIOE=", "creation_time": "2022-08-18T12:44:02.136328217Z"}} } - let data = if let EndpointResponse::VaultResponse(VaultResponse { - data: Some(data), .. - }) = data + //TODO - explore "latest" + let data = if let Some(data) = self + .agent + .get(&format!( + "{}/v1/transit/keys/{}", + self.api_endpoint, self.key_name + )) + .set(VAULT_TOKEN, &self.token) + .call()? + .into_json::>()? + .data { data } else { @@ -217,18 +251,16 @@ impl TendermintValidatorApp { debug!("signing request: base64 encoded and about to submit for signing..."); - let data = self.client.call_endpoint::( - HttpVerb::POST, - &format!("transit/sign/{}", self.key_name), - None, - Some(&serde_json::to_string(&body)?), - )?; - - debug!("signing request: about to submit for signing..."); - - let data = if let EndpointResponse::VaultResponse(VaultResponse { - data: Some(data), .. - }) = data + let data = if let Some(data) = self + .agent + .post(&format!( + "{}/v1/transit/sign/{}", + self.api_endpoint, self.key_name + )) + .set(VAULT_TOKEN, &self.token) + .send_json(body)? + .into_json::>()? + .data { data } else { @@ -273,21 +305,20 @@ impl TendermintValidatorApp { public_key: String, } - let data = self.client.call_endpoint::( - HttpVerb::GET, - "transit/wrapping_key", - None, - None, - )?; - - Ok( - if let EndpointResponse::VaultResponse(VaultResponse { data: Some(d), .. }) = data { - debug!("wrapping key:\n{}", d.public_key); - d.public_key.trim().to_owned() - } else { - return Err(Error::InvalidPubKey("Error getting wrapping key!".into())); - }, - ) + let data = if let Some(data) = self + .agent + .get(&format!("{}/v1/transit/wrapping_key", self.api_endpoint)) + .set(VAULT_TOKEN, &self.token) + .call()? + .into_json::>()? + .data + { + data + } else { + return Err(Error::InvalidPubKey("Error getting wrapping key!".into())); + }; + + Ok(data.public_key.trim().to_owned()) } pub fn import_key( @@ -302,12 +333,14 @@ impl TendermintValidatorApp { hash_function: "SHA256".into(), }; - let _ = self.client.call_endpoint::<()>( - HttpVerb::POST, - &format!("transit/keys/{}/import", key_name), - None, - Some(&serde_json::to_string(&body)?), - )?; + let _ = self + .agent + .post(&format!( + "{}/v1/transit/keys/{}/import", + self.api_endpoint, key_name + )) + .set(VAULT_TOKEN, &self.token) + .send_json(body)?; Ok(()) } @@ -332,7 +365,7 @@ mod tests { fn hashicorp_connect_ok() { //setup let lookup_self = mock("GET", "/v1/auth/token/lookup-self") - .match_header("X-Vault-Token", TEST_TOKEN) + .match_header(VAULT_TOKEN, TEST_TOKEN) .with_body(TOKEN_DATA) .create(); diff --git a/src/keyring/providers/hashicorp/error.rs b/src/keyring/providers/hashicorp/error.rs index a11d3a66..bf0ea6e9 100644 --- a/src/keyring/providers/hashicorp/error.rs +++ b/src/keyring/providers/hashicorp/error.rs @@ -24,10 +24,16 @@ pub enum Error { #[error("Serde error")] SerDe(serde_json::Error), + + #[error("IO error")] + Io(std::io::Error), + + #[error("Help:{0}, Error:{1} ")] + Combined(String, Box), } -impl From for Error { - fn from(err: hashicorp_vault::Error) -> Error { +impl From for Error { + fn from(err: ureq::Error) -> Error { Error::ApiClient(err.to_string()) } } @@ -43,6 +49,13 @@ impl From for Error { Error::SerDe(err) } } + +impl From for Error { + fn from(err: std::io::Error) -> Error { + Error::Io(err) + } +} + impl From for Error { fn from(err: signature::Error) -> Error { Error::InvalidSignature(err.to_string()) diff --git a/src/keyring/providers/hashicorp/vault_data.rs b/src/keyring/providers/hashicorp/vault_data.rs new file mode 100644 index 00000000..9a7010ea --- /dev/null +++ b/src/keyring/providers/hashicorp/vault_data.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +///Vault message envelop +#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Root { + #[serde(rename = "request_id")] + pub request_id: String, + #[serde(rename = "lease_id")] + pub lease_id: String, + pub renewable: bool, + #[serde(rename = "lease_duration")] + pub lease_duration: i64, + pub data: Option, + #[serde(rename = "wrap_info")] + pub wrap_info: Value, + pub warnings: Value, + pub auth: Value, +} + +///Vault's envelop payload for "data" field +#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SelfLookupData { + pub accessor: String, + #[serde(rename = "creation_time")] + pub creation_time: i64, + #[serde(rename = "creation_ttl")] + pub creation_ttl: i64, + #[serde(rename = "display_name")] + pub display_name: String, + #[serde(rename = "entity_id")] + pub entity_id: String, + #[serde(rename = "expire_time")] + pub expire_time: String, + #[serde(rename = "explicit_max_ttl")] + pub explicit_max_ttl: i64, + pub id: String, + #[serde(rename = "issue_time")] + pub issue_time: String, + pub meta: Value, + #[serde(rename = "num_uses")] + pub num_uses: i64, + pub orphan: bool, + pub path: String, + pub policies: Vec, + pub renewable: bool, + pub ttl: i64, + #[serde(rename = "type")] + pub type_field: String, +} From cd1ab866639bb811d341ade72e61d68c43e070e0 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Wed, 19 Oct 2022 16:59:18 -0500 Subject: [PATCH 4/7] vault_client dependency replaced with ureq --- src/keyring/providers/hashicorp/client.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/keyring/providers/hashicorp/client.rs b/src/keyring/providers/hashicorp/client.rs index 20f413f4..b0d5da7d 100644 --- a/src/keyring/providers/hashicorp/client.rs +++ b/src/keyring/providers/hashicorp/client.rs @@ -118,8 +118,6 @@ impl TendermintValidatorApp { )) .build(); - //client.secret_backend(VAULT_BACKEND_NAME); - let app = TendermintValidatorApp { agent, api_endpoint: api_endpoint.to_owned(), @@ -134,8 +132,9 @@ impl TendermintValidatorApp { Ok(app) } - fn hand_shake(&self) -> Result, Error> { - self.agent + fn hand_shake(&self) -> Result<(), Error> { + let _ = self + .agent .get(&format!("{}/v1/auth/token/lookup-self", self.api_endpoint)) .set(VAULT_TOKEN, &self.token) .call() @@ -144,9 +143,8 @@ impl TendermintValidatorApp { "Is \"access_token\" value correct?".into(), Box::new(e.into()), ) - })? - .into_json::>() - .map_err(super::error::Error::Io) + })?; + Ok(()) } //vault read transit/keys/cosmoshub-sign-key From ecc748bae8567c6a2427d29ae7edcb04a7999346 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Wed, 19 Oct 2022 21:31:25 -0500 Subject: [PATCH 5/7] vault_client dependency replaced with ureq --- Cargo.toml | 2 +- src/keyring/providers/hashicorp.rs | 1 - src/keyring/providers/hashicorp/client.rs | 27 ++++++++-- src/keyring/providers/hashicorp/vault_data.rs | 52 ------------------- 4 files changed, 23 insertions(+), 59 deletions(-) delete mode 100644 src/keyring/providers/hashicorp/vault_data.rs diff --git a/Cargo.toml b/Cargo.toml index 28b69c8e..d288e83c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ yubihsm = { version = "0.41", features = ["secp256k1", "setup", "usb"], optional zeroize = "1" - +# HashiCorp deps ureq = { version = "~2.5", default-features=false, features = ["tls", "json", "gzip"], optional = true} base64 = { version = "0.13.0", optional = true} aes-kw = { version = "0.2.1", features = ["std"], optional = true} diff --git a/src/keyring/providers/hashicorp.rs b/src/keyring/providers/hashicorp.rs index a0acece4..e750a270 100644 --- a/src/keyring/providers/hashicorp.rs +++ b/src/keyring/providers/hashicorp.rs @@ -2,7 +2,6 @@ pub(crate) mod client; pub(crate) mod error; pub(crate) mod signer; -pub(crate) mod vault_data; use crate::{ chain, diff --git a/src/keyring/providers/hashicorp/client.rs b/src/keyring/providers/hashicorp/client.rs index b0d5da7d..de21c8d8 100644 --- a/src/keyring/providers/hashicorp/client.rs +++ b/src/keyring/providers/hashicorp/client.rs @@ -3,12 +3,11 @@ use std::collections::{BTreeMap, HashMap}; use super::error::Error; -use super::vault_data; - use std::time::Duration; use ureq::Agent; use serde::{Deserialize, Serialize}; +use serde_json::Value; pub const CONSENUS_KEY_TYPE: &str = "ed25519"; const VAULT_TOKEN: &str = "X-Vault-Token"; @@ -25,6 +24,24 @@ pub(crate) struct TendermintValidatorApp { #[allow(unsafe_code)] unsafe impl Send for TendermintValidatorApp {} +///Vault message envelop +#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Root { + #[serde(rename = "request_id")] + pub request_id: String, + #[serde(rename = "lease_id")] + pub lease_id: String, + pub renewable: bool, + #[serde(rename = "lease_duration")] + pub lease_duration: i64, + pub data: Option, + #[serde(rename = "wrap_info")] + pub wrap_info: Value, + pub warnings: Value, + pub auth: Value, +} + ///Sign Request Struct #[derive(Debug, Serialize)] struct SignRequest { @@ -173,7 +190,7 @@ impl TendermintValidatorApp { )) .set(VAULT_TOKEN, &self.token) .call()? - .into_json::>()? + .into_json::>()? .data { data @@ -257,7 +274,7 @@ impl TendermintValidatorApp { )) .set(VAULT_TOKEN, &self.token) .send_json(body)? - .into_json::>()? + .into_json::>()? .data { data @@ -308,7 +325,7 @@ impl TendermintValidatorApp { .get(&format!("{}/v1/transit/wrapping_key", self.api_endpoint)) .set(VAULT_TOKEN, &self.token) .call()? - .into_json::>()? + .into_json::>()? .data { data diff --git a/src/keyring/providers/hashicorp/vault_data.rs b/src/keyring/providers/hashicorp/vault_data.rs deleted file mode 100644 index 9a7010ea..00000000 --- a/src/keyring/providers/hashicorp/vault_data.rs +++ /dev/null @@ -1,52 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::Value; - -///Vault message envelop -#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Root { - #[serde(rename = "request_id")] - pub request_id: String, - #[serde(rename = "lease_id")] - pub lease_id: String, - pub renewable: bool, - #[serde(rename = "lease_duration")] - pub lease_duration: i64, - pub data: Option, - #[serde(rename = "wrap_info")] - pub wrap_info: Value, - pub warnings: Value, - pub auth: Value, -} - -///Vault's envelop payload for "data" field -#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SelfLookupData { - pub accessor: String, - #[serde(rename = "creation_time")] - pub creation_time: i64, - #[serde(rename = "creation_ttl")] - pub creation_ttl: i64, - #[serde(rename = "display_name")] - pub display_name: String, - #[serde(rename = "entity_id")] - pub entity_id: String, - #[serde(rename = "expire_time")] - pub expire_time: String, - #[serde(rename = "explicit_max_ttl")] - pub explicit_max_ttl: i64, - pub id: String, - #[serde(rename = "issue_time")] - pub issue_time: String, - pub meta: Value, - #[serde(rename = "num_uses")] - pub num_uses: i64, - pub orphan: bool, - pub path: String, - pub policies: Vec, - pub renewable: bool, - pub ttl: i64, - #[serde(rename = "type")] - pub type_field: String, -} From 6f68879099e38194c642daf990000f61915231f2 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Mon, 24 Oct 2022 15:32:32 -0500 Subject: [PATCH 6/7] 1.57 build fix --- Cargo.lock | 1 - Cargo.toml | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 368c36ac..3d743a81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3007,7 +3007,6 @@ dependencies = [ "prost-amino-derive", "prost-derive", "rand 0.7.3", - "rand 0.8.5", "rand_core 0.6.4", "rpassword", "rsa", diff --git a/Cargo.toml b/Cargo.toml index d288e83c..625f0f46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ ureq = { version = "~2.5", default-features=false, features = ["tls", "json", "g base64 = { version = "0.13.0", optional = true} aes-kw = { version = "0.2.1", features = ["std"], optional = true} rsa = { version = "0.6.1", default = true, optional = true} -rand = { version = "0.8", optional = true} +rand = { version = "0.7", optional = true} aes-gcm = { version = "0.10.1", optional = true} [dev-dependencies] @@ -83,6 +83,8 @@ yubihsm-mock = ["yubihsm/mockhsm"] yubihsm-server = ["yubihsm/http-server", "rpassword"] fortanixdsm = ["elliptic-curve", "sdkms", "url", "uuid"] hashicorp = ["ureq", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] +default= ["hashicorp"] + # Enable integer overflow checks in release builds for security reasons [profile.release] From 5014f1fb8de4a73fdda710266803bdbf45713911 Mon Sep 17 00:00:00 2001 From: Serguei Oleinik Date: Mon, 24 Oct 2022 17:00:24 -0500 Subject: [PATCH 7/7] remove default feature --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 625f0f46..6361de8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,6 @@ yubihsm-mock = ["yubihsm/mockhsm"] yubihsm-server = ["yubihsm/http-server", "rpassword"] fortanixdsm = ["elliptic-curve", "sdkms", "url", "uuid"] hashicorp = ["ureq", "base64", "aes-kw", "rsa", "rand", "aes-gcm"] -default= ["hashicorp"] # Enable integer overflow checks in release builds for security reasons