From cf13ac7e36bea2e07fd63b1ac1e59cc9584cbdf6 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 21 Sep 2018 11:56:10 -0700 Subject: [PATCH] Initial YubiHSM2 support Adds a `yubihsm` cargo feature with support for generating signatures using Ed25519 keys stored in YubiHSM2 devices (accessed via USB). Also adds a set of `yubihsm` subcommands: - `detect`: print a list of detected YubiHSM2 devices and their serials - `keys generate`: generate an Ed25519 key within the YubiHSM2 - `keys list`: list the keys within the YubiHSM2 --- .circleci/config.yml | 26 +- Cargo.lock | 382 ++++++++++++++++---------- Cargo.toml | 36 +-- kms.toml.example | 23 +- src/application.rs | 14 +- src/client.rs | 37 +-- src/commands/help.rs | 10 +- src/commands/keygen.rs | 5 +- src/commands/mod.rs | 51 ++-- src/commands/run.rs | 21 +- src/commands/version.rs | 12 +- src/commands/yubihsm/detect.rs | 43 +++ src/commands/yubihsm/help.rs | 17 ++ src/commands/yubihsm/keys/generate.rs | 88 ++++++ src/commands/yubihsm/keys/help.rs | 17 ++ src/commands/yubihsm/keys/list.rs | 74 +++++ src/commands/yubihsm/keys/mod.rs | 46 ++++ src/commands/yubihsm/mod.rs | 47 ++++ src/config/dalek.rs | 16 -- src/config/mod.rs | 46 +--- src/config/provider/mod.rs | 23 ++ src/config/provider/softsign.rs | 25 ++ src/config/provider/yubihsm.rs | 120 ++++++++ src/config/validator.rs | 35 +++ src/config/yubihsm.rs | 68 ----- src/ed25519/keyring.rs | 21 +- src/ed25519/mod.rs | 4 +- src/ed25519/public_key.rs | 20 +- src/ed25519/signer/dalek.rs | 43 --- src/ed25519/signer/mod.rs | 5 +- src/ed25519/signer/softsign.rs | 39 +++ src/ed25519/signer/yubihsm.rs | 40 ++- src/error.rs | 27 ++ src/main.rs | 18 +- src/secret_connection.rs | 2 +- src/types/ed25519msg.rs | 16 +- src/types/heartbeat.rs | 2 +- src/types/proposal.rs | 2 +- src/types/vote.rs | 2 +- src/yubihsm.rs | 66 +++++ tests/cli/mod.rs | 48 ++++ tests/cli/yubihsm/detect.rs | 9 + tests/cli/yubihsm/keys/generate.rs | 2 + tests/cli/yubihsm/keys/list.rs | 15 + tests/cli/yubihsm/keys/mod.rs | 12 + tests/cli/yubihsm/kms-mockhsm.toml | 17 ++ tests/cli/yubihsm/mod.rs | 6 + tests/integration.rs | 55 ++-- tests/{test.toml => kms-test.toml} | 13 +- 49 files changed, 1275 insertions(+), 491 deletions(-) create mode 100644 src/commands/yubihsm/detect.rs create mode 100644 src/commands/yubihsm/help.rs create mode 100644 src/commands/yubihsm/keys/generate.rs create mode 100644 src/commands/yubihsm/keys/help.rs create mode 100644 src/commands/yubihsm/keys/list.rs create mode 100644 src/commands/yubihsm/keys/mod.rs create mode 100644 src/commands/yubihsm/mod.rs delete mode 100644 src/config/dalek.rs create mode 100644 src/config/provider/mod.rs create mode 100644 src/config/provider/softsign.rs create mode 100644 src/config/provider/yubihsm.rs create mode 100644 src/config/validator.rs delete mode 100644 src/config/yubihsm.rs delete mode 100644 src/ed25519/signer/dalek.rs create mode 100644 src/ed25519/signer/softsign.rs create mode 100644 src/yubihsm.rs create mode 100644 tests/cli/mod.rs create mode 100644 tests/cli/yubihsm/detect.rs create mode 100644 tests/cli/yubihsm/keys/generate.rs create mode 100644 tests/cli/yubihsm/keys/list.rs create mode 100644 tests/cli/yubihsm/keys/mod.rs create mode 100644 tests/cli/yubihsm/kms-mockhsm.toml create mode 100644 tests/cli/yubihsm/mod.rs rename tests/{test.toml => kms-test.toml} (53%) diff --git a/.circleci/config.yml b/.circleci/config.yml index eb7f272..5253a00 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,27 +21,29 @@ jobs: - run: name: build (default features) command: | - rustc --version - cargo --version + rustc --version + cargo --version cargo build cargo build --release - run: - name: build (all features) + name: build --all-features (debug) command: | - rustc --version - cargo --version + rustc --version + cargo --version cargo build --all-features - run: - name: build (--features=yubihsm-provider --release) + # NOTE: we can't build --all-features --release because one of the + # features is `yubihsm-mock` which can't be used in release builds + name: build --features=yubihsm --release command: | - rustc --version - cargo --version - cargo build --features=yubihsm-provider --release + rustc --version + cargo --version + cargo build --features=yubihsm --release - run: - name: test (all features) + name: test --all-features command: | - rustc --version - cargo --version + rustc --version + cargo --version cargo test --all-features - run: name: audit diff --git a/Cargo.lock b/Cargo.lock index a2d702f..50abbe4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,9 +1,9 @@ [[package]] name = "abscissa" version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312#a90d3123208219a80579825fa80997c3d121e569" dependencies = [ - "abscissa_derive 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "abscissa_derive 0.0.2 (git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312)", "canonical-path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -14,9 +14,19 @@ dependencies = [ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "abscissa_derive" +version = "0.0.2" +source = "git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312#a90d3123208219a80579825fa80997c3d121e569" +dependencies = [ + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -24,38 +34,38 @@ name = "abscissa_derive" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aes" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aes-soft 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aesni 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aes-soft" -version = "0.1.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aesni" -version = "0.3.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -72,7 +82,7 @@ dependencies = [ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -129,33 +139,52 @@ dependencies = [ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-buffer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "block-cipher-trait" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-modes" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "block-padding 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-padding" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "byte-tools" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byte-tools" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.6" @@ -214,12 +243,12 @@ dependencies = [ [[package]] name = "cmac" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dbl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -231,16 +260,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "cosmos-kms" version = "0.0.0" dependencies = [ - "abscissa 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "abscissa 0.0.4 (git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312)", "abscissa_derive 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hkdf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "prost 0.4.0 (git+https://github.com/Liamsi/prost?branch=prost_amino_derive)", @@ -249,13 +276,14 @@ dependencies = [ "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "signatory 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)", - "signatory-dalek 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)", - "signatory-yubihsm 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)", + "signatory 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", + "signatory-dalek 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "signatory-yubihsm 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle-encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "x25519-dalek 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "yubihsm 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -269,11 +297,11 @@ dependencies = [ [[package]] name = "crypto-mac" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -283,36 +311,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "dbl" -version = "0.1.0" +name = "curve25519-dalek" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dbl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "digest" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "ed25519-dalek" +name = "digest" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ed25519-dalek" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,7 +387,7 @@ name = "failure_derive" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -372,16 +421,19 @@ dependencies = [ ] [[package]] -name = "hex" -version = "0.3.2" +name = "generic-array" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "hkdf" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -392,16 +444,16 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hmac" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -421,7 +473,7 @@ dependencies = [ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -442,7 +494,7 @@ name = "lazy_static" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -492,22 +544,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "opaque-debug" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pbkdf2" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -517,7 +568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -537,10 +588,10 @@ name = "prost-derive" version = "0.4.0" source = "git+https://github.com/Liamsi/prost?branch=prost_amino_derive#4954933a364016d50b65ec8316ce0ce73563e22b" dependencies = [ - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -551,7 +602,7 @@ name = "quote" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -562,13 +613,21 @@ dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -625,14 +684,14 @@ name = "serde_derive" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.27" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -647,46 +706,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "signatory" -version = "0.9.0-alpha3" -source = "git+https://github.com/tendermint/signatory.git#a09eaae7bea74ccd935ff2fbf45fc0bd98189502" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle-encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "signatory-dalek" -version = "0.9.0-alpha3" -source = "git+https://github.com/tendermint/signatory.git#a09eaae7bea74ccd935ff2fbf45fc0bd98189502" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "signatory 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)", + "signatory 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "signatory-yubihsm" -version = "0.9.0-alpha3" -source = "git+https://github.com/tendermint/signatory.git#a09eaae7bea74ccd935ff2fbf45fc0bd98189502" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "signatory 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)", - "yubihsm 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "signatory 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", + "yubihsm 0.18.1 (git+https://github.com/tendermint/yubihsm-rs.git?rev=9d8b749)", ] [[package]] name = "simplelog" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -699,22 +770,37 @@ name = "subtle" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "subtle-encoding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.4" +version = "0.15.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -724,7 +810,7 @@ name = "synstructure" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -736,7 +822,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -746,12 +832,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", @@ -774,15 +860,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uuid" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "version_check" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -792,7 +878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -815,43 +901,52 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curve25519-dalek 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "yubihsm" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.18.1" +source = "git+https://github.com/tendermint/yubihsm-rs.git?rev=9d8b749#9d8b7491f19268acafa9ac7461e8aea21ecf2905" dependencies = [ - "aes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aes 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "block-modes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-modes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cmac 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cmac 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "libusb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zeroize" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] -"checksum abscissa 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4234edaeacf13b609439a7fdef0e963d903e820a1172849076caf3d066a17eb6" +"checksum abscissa 0.0.4 (git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312)" = "" +"checksum abscissa_derive 0.0.2 (git+https://github.com/iqlusioninc/abscissa.git?rev=a90d312)" = "" "checksum abscissa_derive 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4cd3ff1140f337a6d49256197c1455e2fb97ed76b2f220606809974f128814" -"checksum aes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0275405eedf13afd19de588add12a3b0d481a50b194eeb826e9dece11e741331" -"checksum aes-soft 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91f401742d8c1b0a3d01f53563f98d8ef0beea460b8d37322faf9fb4c7977cfa" -"checksum aesni 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ca074691b47c3dc585e05e45f6d069c75d0209069ca09b1c49ea37720e7b5f" +"checksum aes 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "efc57804fcd4ac04dae62b2f6d7f33bbbb8fd400efed3e5ad6adef0dd667a9f0" +"checksum aes-soft 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "acdc19c789666840bb86d1df8ee1f458418f74a6b9c8f10538fb700de5829cb8" +"checksum aesni 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea93ee7c249d885b395fca6181fd6416f0249b1a0a7c7a2e8bfd6b74cebd2f82" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" @@ -861,10 +956,12 @@ dependencies = [ "checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" -"checksum block-modes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "862511b40f91a3305dc119fdfdc25b561779f78828495e41b71d360b8c9f56df" -"checksum block-padding 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75bc2cfa52dc218b47ea000b15e6e5d00ca2f831db31e41592383c14d8802907" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-cipher-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30668a4dc25ca695ad6f4c4734b96b0a4414a87158eefeec04155bcef580a3de" +"checksum block-modes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283fa06a14026feac8912bf35328fc074f5d68907fd4b9cccad5658a3fc62a30" +"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" "checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" "checksum canonical-path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9aa83b9f518bd3943b6757de8489c7756566df78026771955b90ecb87295a5dc" @@ -873,25 +970,27 @@ dependencies = [ "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmac 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f175b5f76aa82ebe4c7e85ef95b23e9293c5618db28461cb10ee929e0f6e2f" +"checksum cmac 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f4a435124bcc292eba031f1f725d7abacdaf13cbf9f935450e8c45aa9e96cad" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" -"checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" +"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum curve25519-dalek 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "15d6d81c070d8090389f752510ce22c7d571100a78fa4e7c06e6f6d95585bb49" -"checksum dbl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "920e117b69060a961c4164ccf83af573292cb167ccdd918950bcf0f5afc32c1c" -"checksum digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b29c278aa8fd30796bd977169e8004b4aa88cdcd2f32a6eb22bc2d5d38df94a" -"checksum ed25519-dalek 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4ffe2ac7f79a25e95c0521e6200635c352ea89080aa4f56fb3612e5f900157" +"checksum curve25519-dalek 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eacf6ff1b911e3170a8c400b402e10c86dc3cb166bd69034ebbc2b785fea4c2" +"checksum dbl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c40b13b561e11560d7b12785e74113a3163df617e2fbce60ce1764e0b270eaa" +"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum ed25519-dalek 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd66d8a16ef71c23cf5eeb2140d8d3cd293457c6c7fd6804b593397a933fcf1e" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9" "checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hkdf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc351e6b070a96006f9d98cf67f14a7f2dfe2e205b081da3fa50d05f6b5b9e01" "checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" -"checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a" +"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" @@ -903,15 +1002,16 @@ dependencies = [ "checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" -"checksum pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c09cddfbfc98de7f76931acf44460972edb4023eb14d0c6d4018800e552d8e0" +"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682" +"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901" +"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" "checksum prost 0.4.0 (git+https://github.com/Liamsi/prost?branch=prost_amino_derive)" = "" "checksum prost-derive 0.4.0 (git+https://github.com/Liamsi/prost?branch=prost_amino_derive)" = "" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" +"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" +"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe642b9dd1ba0038d78c4a3999d1ee56178b4d415c1e1fbaba83b06dce012f0" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" @@ -921,27 +1021,31 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9" "checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe" -"checksum serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "59790990c5115d16027f00913e2e66de23a51f70422e549d2ad68c8c5f268f1c" +"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" -"checksum signatory 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)" = "" -"checksum signatory-dalek 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)" = "" -"checksum signatory-yubihsm 0.9.0-alpha3 (git+https://github.com/tendermint/signatory.git)" = "" -"checksum simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9cc12b39fdf4c9a07f88bffac2d628f0118ed5ac077a4b0feece61fadf1429e5" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum signatory 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7024b42706d46a62cfff4676bc6114a1dacc29abd1f16ef20dfbc72d489707e5" +"checksum signatory-dalek 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47b5931ac17fb3407a183adfaff36e9dc6e38854fe4fcac2373bce197dd6217c" +"checksum signatory-yubihsm 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc455ff52f9190c651cb79d25ee3dc821f2e23fedd25888a91c9b892ff1d158d" +"checksum simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e95345f185d5adeb8ec93459d2dc99654e294cc6ccf5b75414d8ea262de9a13" "checksum subtle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5938f1b89f10d6356339f071eca74209deeae0b6891c2678d655feb78637e369" +"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +"checksum subtle-encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f62d746ce38bd9b442d6ebd4147766cd4d5e8e55cecc47575085772f359376ba" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9056ebe7f2d6a38bc63171816fd1d3430da5a43896de21676dc5c0a4b8274a11" +"checksum syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b10ee269228fb723234fce98e9aac0eaed2bd5f1ad2f6930e8d5b93f04445a1a" "checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" +"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" -"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" -"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum x25519-dalek 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "538296831e9794ec5b3ec9d4a1a8c3e3c86271e9635a0e776e3214fec9c727de" -"checksum yubihsm 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2590010dc43781626f02c34e6b73226e5a59dcd0110e11774c1f0a9d7e5b67" +"checksum yubihsm 0.18.1 (git+https://github.com/tendermint/yubihsm-rs.git?rev=9d8b749)" = "" +"checksum zeroize 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d578f76311059e419360b151137cfb495e17bbc732c3795bf2953f898ce1dd76" diff --git a/Cargo.toml b/Cargo.toml index 2592ac1..bc200d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,33 +17,33 @@ abscissa = "0.0.4" abscissa_derive = "0.0.2" bincode = "1" byteorder = "1.2" -clear_on_drop = "0.2" +bytes = "0.4" +chrono = "0.4.2" failure = "0.1" failure_derive = "0.1" +hkdf = "0.5" lazy_static = "1" +prost = { git = "https://github.com/Liamsi/prost", branch = "prost_amino_derive" } +prost-derive = { git = "https://github.com/Liamsi/prost", branch = "prost_amino_derive" } rand = "0.5" +ring = "0.13" serde = "1.0" serde_derive = "1.0" -sha2 = "0.7" -hkdf = "0.5" -ring = "0.13" -signatory = { version = "0.9.0-alpha3", features = ["ed25519"] } -signatory-dalek = "0.9.0-alpha3" -signatory-yubihsm = { version = "0.9.0-alpha3", optional = true } -yubihsm = { version = "0.16", optional = true } serde_json = "1.0" -hex = "0.3.2" -bytes = "0.4" -chrono = "0.4.2" +sha2 = "0.7" +signatory = { version = "0.9", features = ["ed25519"] } +signatory-dalek = "0.9" +signatory-yubihsm = { version = "0.9", optional = true } +subtle-encoding = "0.2" x25519-dalek = { version = "0.3", default-features = false, features = ["std", "u64_backend"] } -prost = { git = "https://github.com/Liamsi/prost", branch = "prost_amino_derive"} -prost-derive = {git = "https://github.com/Liamsi/prost", branch = "prost_amino_derive"} +zeroize = "0.1" [features] -yubihsm-provider = ["signatory-yubihsm/usb", "yubihsm/usb"] -yubihsm-mockhsm = ["yubihsm-provider", "signatory-yubihsm/mockhsm", "yubihsm/mockhsm"] +default = ["softsign"] +softsign = [] +yubihsm = ["signatory-yubihsm/usb"] # USB only for now +yubihsm-mock = ["yubihsm", "signatory-yubihsm/mockhsm"] [patch.crates-io] -signatory = { git = "https://github.com/tendermint/signatory.git" } -signatory-dalek = { git = "https://github.com/tendermint/signatory.git" } -signatory-yubihsm = { git = "https://github.com/tendermint/signatory.git" } +abscissa = { git = "https://github.com/iqlusioninc/abscissa.git", rev = "a90d312" } +yubihsm = { git = "https://github.com/tendermint/yubihsm-rs.git", rev = "9d8b749" } diff --git a/kms.toml.example b/kms.toml.example index 5bc7601..09be8b2 100644 --- a/kms.toml.example +++ b/kms.toml.example @@ -2,18 +2,21 @@ # # Copy this to 'kms.toml' and edit for your own purposes -[providers.dalek.keys] -validator-key-1 = { path = "path/to/validator.key" } +[[validator]] +addr = "example1.example.com" +port = 26657 -[providers.yubihsm.connector1] -http = { addr = "127.0.0.1", port = 12345 } -auth = { key-id = 1, password = "example" } # password-file = "path/to/password.file" -keys = { example-key-42 = { key-id = 42 }, example-key-42 = { key-id = 43 } } +[[providers.softsign]] +id = "gaia-8000" +path = "path/to/validator.key" + +[[providers.yubihsm]] +adapter = { type = "usb" } +auth = { key = 1, password = "example" } +serial-number = "0123456789" +keys = [{ id = "gaia-9000", key = 42 }, { id = "gaia-9001", key = 43 }] [secret-connection] secret-key-path = "path/to/kms-node.key" -[validators] -example1 = { addr = "example1.example.com", port = 26657 } -example2 = { addr = "example1.example.com", port = 26657 } -example3 = { addr = "example1.example.com", port = 26657 } + diff --git a/src/application.rs b/src/application.rs index b473b37..df49d18 100644 --- a/src/application.rs +++ b/src/application.rs @@ -2,17 +2,17 @@ use abscissa::{Application, LoggingConfig}; -use commands::KMSCommand; -use config::KMSConfig; +use commands::KmsCommand; +use config::KmsConfig; #[derive(Debug)] -pub struct KMSApplication; +pub struct KmsApplication; -impl Application for KMSApplication { - type Cmd = KMSCommand; - type Config = KMSConfig; +impl Application for KmsApplication { + type Cmd = KmsCommand; + type Config = KmsConfig; - fn logging_config(&self, command: &KMSCommand) -> LoggingConfig { + fn logging_config(&self, command: &KmsCommand) -> LoggingConfig { if command.verbose() { LoggingConfig::verbose() } else { diff --git a/src/client.rs b/src/client.rs index b63faaa..a49e5eb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -32,13 +32,9 @@ pub struct Client { impl Client { /// Spawn a new client, returning a handle so it can be joined - pub fn spawn( - label: String, - config: ValidatorConfig, - secret_connection_key: Ed25519Seed, - ) -> Self { + pub fn spawn(config: ValidatorConfig, secret_connection_key: Ed25519Seed) -> Self { Self { - handle: thread::spawn(move || client_loop(&label, config, &secret_connection_key)), + handle: thread::spawn(move || client_loop(&config, &secret_connection_key)), } } @@ -49,19 +45,12 @@ impl Client { } /// Main loop for all clients. Handles reconnecting in the event of an error -fn client_loop(label: &str, config: ValidatorConfig, secret_connection_key: &Ed25519Seed) { - let ValidatorConfig { - addr, - port, - reconnect, - } = config; - let peer_info = format!("{} ({}:{})", label, &addr, port); - - while let Err(e) = client_session(addr.clone(), port, secret_connection_key) { - error!("[{}] {}", &peer_info, e); +fn client_loop(config: &ValidatorConfig, secret_connection_key: &Ed25519Seed) { + while let Err(e) = client_session(&config.addr, config.port, secret_connection_key) { + error!("[{}] {}", config.uri(), e); // Break out of the loop if auto-reconnect is explicitly disabled - if reconnect { + if config.reconnect { // TODO: configurable respawn delay thread::sleep(Duration::from_secs(RESPAWN_DELAY)); } else { @@ -69,17 +58,17 @@ fn client_loop(label: &str, config: ValidatorConfig, secret_connection_key: &Ed2 } } - info!("[{}] session closed gracefully", &peer_info); + info!("[{}] session closed gracefully", config.uri()); } /// Establish a session with the validator and handle incoming requests -fn client_session( - addr: String, - port: u16, - secret_connection_key: &Ed25519Seed, -) -> Result<(), Error> { +fn client_session(addr: &str, port: u16, secret_connection_key: &Ed25519Seed) -> Result<(), Error> { panic::catch_unwind(move || { - let mut session = Session::new(&addr, port, &secret_connection_key)?; + let mut session = Session::new(addr, port, &secret_connection_key)?; + info!( + "[gaia-rpc://{}:{}] connected to validator successfully", + addr, port + ); while session.handle_request()? {} Ok(()) }).unwrap_or_else(|e| Err(Error::from_panic(&e))) diff --git a/src/commands/help.rs b/src/commands/help.rs index b57bd3b..876eec5 100644 --- a/src/commands/help.rs +++ b/src/commands/help.rs @@ -1,8 +1,8 @@ //! The `help` subcommand -use abscissa::Command; +use abscissa::{Callable, Command}; -use super::KMSCommand; +use super::KmsCommand; /// The `help` subcommand #[derive(Debug, Default, Options)] @@ -11,9 +11,9 @@ pub struct HelpCommand { pub args: Vec, } -impl HelpCommand { +impl Callable for HelpCommand { /// Print help message - pub fn call(&self) -> ! { - KMSCommand::print_usage(self.args.as_slice()) + fn call(&self) { + KmsCommand::print_usage(self.args.as_slice()); } } diff --git a/src/commands/keygen.rs b/src/commands/keygen.rs index 8c1a10c..1cc9f1d 100644 --- a/src/commands/keygen.rs +++ b/src/commands/keygen.rs @@ -1,3 +1,4 @@ +use abscissa::Callable; use signatory::{Ed25519Seed, Encode}; use std::{env, process}; @@ -10,9 +11,9 @@ pub struct KeygenCommand { output_paths: Vec, } -impl KeygenCommand { +impl Callable for KeygenCommand { /// Generate an Ed25519 secret key for use with a software provider (i.e. ed25519-dalek) - pub fn call(&self) { + fn call(&self) { if self.output_paths.len() != 1 { eprintln!("Usage: {} keygen [PATH]", env::args().next().unwrap()); process::exit(2); diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 8a64421..1386b2f 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,5 +1,7 @@ //! Subcommands of the `cosmos-kms` command-line application +#![allow(unknown_lints, renamed_and_removed_lints, never_loop)] + use abscissa::{Callable, LoadConfig}; use std::path::PathBuf; @@ -7,15 +9,19 @@ mod help; mod keygen; mod run; mod version; +#[cfg(feature = "yubihsm")] +mod yubihsm; +#[cfg(feature = "yubihsm")] +pub use self::yubihsm::YubihsmCommand; pub use self::{ help::HelpCommand, keygen::KeygenCommand, run::RunCommand, version::VersionCommand, }; -use config::{KMSConfig, CONFIG_FILE_NAME}; +use config::{KmsConfig, CONFIG_FILE_NAME}; /// Subcommands of the KMS command-line application #[derive(Debug, Options)] -pub enum KMSCommand { +pub enum KmsCommand { #[options(help = "show help for a command")] Help(HelpCommand), @@ -27,46 +33,51 @@ pub enum KMSCommand { #[options(help = "display version information")] Version(VersionCommand), + + #[cfg(feature = "yubihsm")] + #[options(help = "subcommands for YubiHSM2")] + Yubihsm(YubihsmCommand), } // TODO: refactor abscissa internally so this is all part of the proc macro -impl_command!(KMSCommand); +impl_command!(KmsCommand); -impl KMSCommand { +impl KmsCommand { /// Are we configured for verbose logging? pub fn verbose(&self) -> bool { match self { - KMSCommand::Run(run) => run.verbose, + KmsCommand::Run(run) => run.verbose, _ => false, } } } -impl LoadConfig for KMSCommand { +impl LoadConfig for KmsCommand { /// Get the path to the configuration file, either from selected subcommand /// or the default fn config_path(&self) -> Option { - match self { - KMSCommand::Run(run) => Some(PathBuf::from( - run.config - .as_ref() - .map(|s| s.as_ref()) - .unwrap_or(CONFIG_FILE_NAME), - )), - _ => None, - } + let config = match self { + KmsCommand::Run(run) => run.config.as_ref().map(|s| s.as_ref()), + #[cfg(feature = "yubihsm")] + KmsCommand::Yubihsm(yubihsm) => yubihsm.config_path(), + _ => return None, + }; + + Some(PathBuf::from(config.unwrap_or(CONFIG_FILE_NAME))) } } // TODO: refactor abscissa internally so this is all part of the proc macro -impl Callable for KMSCommand { +impl Callable for KmsCommand { /// Call the given command chosen via the CLI fn call(&self) { match self { - KMSCommand::Help(help) => help.call(), - KMSCommand::Keygen(keygen) => keygen.call(), - KMSCommand::Run(run) => run.call(), - KMSCommand::Version(version) => version.call(), + KmsCommand::Help(help) => help.call(), + KmsCommand::Keygen(keygen) => keygen.call(), + KmsCommand::Run(run) => run.call(), + KmsCommand::Version(version) => version.call(), + #[cfg(feature = "yubihsm")] + KmsCommand::Yubihsm(yubihsm) => yubihsm.call(), } } } diff --git a/src/commands/run.rs b/src/commands/run.rs index 3e8cac4..47bc604 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -1,10 +1,10 @@ use abscissa::{Callable, GlobalConfig}; use signatory::{self, Decode, Ed25519Seed, Encode}; use signatory_dalek::Ed25519Signer; -use std::{collections::BTreeMap, process}; +use std::process; use client::Client; -use config::{KMSConfig, SecretConnectionConfig, ValidatorConfig}; +use config::{KmsConfig, SecretConnectionConfig, ValidatorConfig}; use ed25519::{KeyRing, PublicKey, SECRET_KEY_ENCODING}; use error::Error; @@ -38,7 +38,7 @@ impl Callable for RunCommand { env!("CARGO_PKG_VERSION") ); - let config = KMSConfig::get_global(); + let config = KmsConfig::get_global(); let secret_connection_key = load_secret_connection_key(&config.secret_connection) .unwrap_or_else(|e| { @@ -54,7 +54,7 @@ impl Callable for RunCommand { }); // Spawn the validator client threads - let validator_clients = spawn_validator_clients(&config.validators, &secret_connection_key); + let validator_clients = spawn_validator_clients(&config.validator, &secret_connection_key); // Wait for the validator client threads to exit // TODO: Find something more useful for this thread to do @@ -81,22 +81,17 @@ fn load_secret_connection_key(config: &SecretConnectionConfig) -> Result, + config: &[ValidatorConfig], secret_connection_key: &Ed25519Seed, ) -> Vec { config .iter() - .map(|(label, validator_config)| { - Client::spawn( - label.clone(), - validator_config.clone(), - secret_connection_key.clone(), - ) - }).collect() + .map(|validator| Client::spawn(validator.clone(), secret_connection_key.clone())) + .collect() } diff --git a/src/commands/version.rs b/src/commands/version.rs index ee52e47..b469e98 100644 --- a/src/commands/version.rs +++ b/src/commands/version.rs @@ -1,18 +1,16 @@ //! The `version` subcommand -#![allow(unknown_lints, renamed_and_removed_lints, never_loop)] +use abscissa::{Callable, Command as CommandTrait}; -use abscissa::Command as CommandTrait; - -use super::KMSCommand; +use super::KmsCommand; /// The `version` subcommand #[derive(Debug, Default, Options)] pub struct VersionCommand {} -impl VersionCommand { +impl Callable for VersionCommand { /// Print version message - pub fn call(&self) { - KMSCommand::print_package_info(); + fn call(&self) { + KmsCommand::print_package_info(); } } diff --git a/src/commands/yubihsm/detect.rs b/src/commands/yubihsm/detect.rs new file mode 100644 index 0000000..090210e --- /dev/null +++ b/src/commands/yubihsm/detect.rs @@ -0,0 +1,43 @@ +use abscissa::Callable; +use std::process; + +use yubihsm::connector::usb::Devices; + +/// The `yubihsm detect` subcommand +#[derive(Debug, Default, Options)] +pub struct DetectCommand { + /// Path to configuration file + #[options(short = "c", long = "config")] + pub config: Option, + + /// Print debugging information + #[options(short = "v", long = "verbose")] + pub verbose: bool, +} + +impl Callable for DetectCommand { + /// Detect all YubiHSM2 devices connected via USB + fn call(&self) { + let devices = Devices::new(Default::default()).unwrap_or_else(|e| { + status_err!("couldn't detect USB devices: {}", e); + + // TODO: handle exits via abscissa + process::exit(1); + }); + + if devices.is_empty() { + status_err!("no YubiHSM2 devices detected!"); + process::exit(1); + } + + println!("Detected YubiHSM2 USB devices:"); + + for device in devices.iter() { + println!( + "- Serial #{} (bus {})", + device.serial_number.as_str(), + device.bus_number(), + ); + } + } +} diff --git a/src/commands/yubihsm/help.rs b/src/commands/yubihsm/help.rs new file mode 100644 index 0000000..3e3a508 --- /dev/null +++ b/src/commands/yubihsm/help.rs @@ -0,0 +1,17 @@ +use abscissa::{Callable, Command}; + +use super::YubihsmCommand; + +/// The `yubihsm help` subcommand +#[derive(Debug, Default, Options)] +pub struct HelpCommand { + #[options(free)] + pub args: Vec, +} + +impl Callable for HelpCommand { + /// Print help for the `yubihsm` subcommand + fn call(&self) { + YubihsmCommand::print_usage(self.args.as_slice()); + } +} diff --git a/src/commands/yubihsm/keys/generate.rs b/src/commands/yubihsm/keys/generate.rs new file mode 100644 index 0000000..e776320 --- /dev/null +++ b/src/commands/yubihsm/keys/generate.rs @@ -0,0 +1,88 @@ +use abscissa::Callable; +use std::process; + +use ed25519::PublicKey; +use yubihsm; + +/// Default key type to generate +pub const DEFAULT_KEY_TYPE: &str = "ed25519"; + +/// Default YubiHSM2 domain (internal partitioning) +pub const DEFAULT_DOMAINS: yubihsm::Domain = yubihsm::Domain::DOM1; + +/// Default YubiHSM2 permissions for generated keys +pub const DEFAULT_CAPABILITIES: yubihsm::Capability = yubihsm::Capability::ASYMMETRIC_SIGN_EDDSA; + +/// The `yubihsm keys generate` subcommand +#[derive(Debug, Default, Options)] +pub struct GenerateCommand { + /// Path to configuration file + #[options(short = "c", long = "config")] + pub config: Option, + + /// Label for generated key(s) + #[options(short = "l", long = "label")] + pub label: Option, + + /// Type of key to generate (default 'ed25519') + #[options(short = "t")] + pub key_type: Option, + + /// Key IDs to generate + #[options(free)] + key_ids: Vec, +} + +impl Callable for GenerateCommand { + /// Generate an Ed25519 signing key inside a YubiHSM2 device + fn call(&self) { + if self.key_ids.is_empty() { + status_err!("must provide at least one key ID to generate"); + process::exit(1); + } + + match &self.key_type { + Some(ref key_type) => if key_type != DEFAULT_KEY_TYPE { + status_err!( + "only supported key type is: ed25519 (given: \"{}\")", + key_type + ); + process::exit(1); + }, + None => (), + } + + let mut hsm = yubihsm::get_hsm_client(); + + for key_id_str in &self.key_ids { + let key_id = key_id_str.parse::().unwrap_or_else(|e| { + status_err!("bad key id: {} ({})", key_id_str, e); + process::exit(1); + }); + + let label = + yubihsm::ObjectLabel::from(self.label.as_ref().map(|l| l.as_ref()).unwrap_or("")); + + if let Err(e) = hsm.generate_asymmetric_key( + key_id, + label, + DEFAULT_DOMAINS, + DEFAULT_CAPABILITIES, + yubihsm::AsymmetricAlg::Ed25519, + ) { + status_err!("couldn't generate key #{}: {}", key_id, e); + process::exit(1); + } + + let public_key = PublicKey::from(hsm.get_pubkey(key_id).unwrap_or_else(|e| { + status_err!("couldn't get public key for key #{}: {}", key_id, e); + process::exit(1); + })); + + status_ok!("Generated", "key #{}: {}", key_id, public_key); + } + } +} + +// TODO: custom derive in abscissa +impl_command!(GenerateCommand); diff --git a/src/commands/yubihsm/keys/help.rs b/src/commands/yubihsm/keys/help.rs new file mode 100644 index 0000000..3419102 --- /dev/null +++ b/src/commands/yubihsm/keys/help.rs @@ -0,0 +1,17 @@ +use abscissa::{Callable, Command}; + +use super::KeysCommand; + +/// The `yubihsm keys help` subcommand +#[derive(Debug, Default, Options)] +pub struct HelpCommand { + #[options(free)] + pub args: Vec, +} + +impl Callable for HelpCommand { + /// Print help for the `yubihsm` subcommand + fn call(&self) { + KeysCommand::print_usage(self.args.as_slice()); + } +} diff --git a/src/commands/yubihsm/keys/list.rs b/src/commands/yubihsm/keys/list.rs new file mode 100644 index 0000000..e07a024 --- /dev/null +++ b/src/commands/yubihsm/keys/list.rs @@ -0,0 +1,74 @@ +use abscissa::Callable; +use std::process; + +use ed25519::PublicKey; +use yubihsm; + +/// The `yubihsm keys list` subcommand +#[derive(Debug, Default, Options)] +pub struct ListCommand { + /// Path to configuration file + #[options(short = "c", long = "config")] + pub config: Option, +} + +impl Callable for ListCommand { + /// List all suitable Ed25519 keys in the HSM + fn call(&self) { + let hsm_connector = yubihsm::create_hsm_connector(); + + let serial_number = hsm_connector.serial_number().unwrap_or_else(|e| { + status_err!("couldn't get YubiHSM serial number: {}", e); + process::exit(1); + }); + + let credentials = yubihsm::get_config().auth.credentials(); + + let mut hsm = yubihsm::Client::open(hsm_connector, credentials, true).unwrap_or_else(|e| { + status_err!("error connecting to YubiHSM2: {}", e); + process::exit(1); + }); + + let objects = hsm.list_objects().unwrap_or_else(|e| { + status_err!("couldn't list YubiHSM objects: {}", e); + process::exit(1); + }); + + let mut keys = objects + .iter() + .filter(|o| o.object_type == yubihsm::ObjectType::AsymmetricKey) + .collect::>(); + + keys.sort_by(|k1, k2| k1.object_id.cmp(&k2.object_id)); + + if keys.is_empty() { + status_err!("no keys in this YubiHSM (#{})", serial_number); + process::exit(0); + } + + println!("Listing keys in YubiHSM #{}:", serial_number); + + for key in &keys { + let public_key = hsm.get_pubkey(key.object_id).unwrap_or_else(|e| { + status_err!( + "couldn't get public key for asymmetric key #{}: {}", + key.object_id, + e + ); + process::exit(1); + }); + + let key_id = format!("- #{}", key.object_id); + + // TODO: support for non-Ed25519 keys + if public_key.algorithm == yubihsm::AsymmetricAlg::Ed25519 { + status_attr_ok!(key_id, PublicKey::from(public_key)); + } else { + status_attr_err!(key_id, "unsupported algorithm: {:?}", public_key.algorithm); + } + } + } +} + +// TODO: custom derive in abscissa +impl_command!(ListCommand); diff --git a/src/commands/yubihsm/keys/mod.rs b/src/commands/yubihsm/keys/mod.rs new file mode 100644 index 0000000..fd28173 --- /dev/null +++ b/src/commands/yubihsm/keys/mod.rs @@ -0,0 +1,46 @@ +mod generate; +mod help; +mod list; + +use abscissa::Callable; + +use self::{generate::GenerateCommand, help::HelpCommand, list::ListCommand}; + +/// The `yubihsm keys` subcommand +#[derive(Debug, Options)] +pub enum KeysCommand { + #[options(help = "generate an Ed25519 signing key inside the HSM device")] + Generate(GenerateCommand), + + #[options(help = "show help for the 'yubihsm keys' subcommand")] + Help(HelpCommand), + + #[options(help = "list all suitable Ed25519 keys in the HSM")] + List(ListCommand), +} + +impl KeysCommand { + /// Optional path to the configuration file + pub(super) fn config_path(&self) -> Option<&str> { + match self { + KeysCommand::Generate(generate) => generate.config.as_ref().map(|s| s.as_ref()), + KeysCommand::List(list) => list.config.as_ref().map(|s| s.as_ref()), + _ => None, + } + } +} + +// TODO: refactor abscissa internally so this is all part of the proc macro +impl Callable for KeysCommand { + /// Call the given command chosen via the CLI + fn call(&self) { + match self { + KeysCommand::Generate(generate) => generate.call(), + KeysCommand::Help(help) => help.call(), + KeysCommand::List(list) => list.call(), + } + } +} + +// TODO: custom derive in abscissa +impl_command!(KeysCommand); diff --git a/src/commands/yubihsm/mod.rs b/src/commands/yubihsm/mod.rs new file mode 100644 index 0000000..9f75284 --- /dev/null +++ b/src/commands/yubihsm/mod.rs @@ -0,0 +1,47 @@ +//! The KMS `yubihsm` subcommand + +use abscissa::Callable; + +mod detect; +mod help; +mod keys; + +pub use self::{detect::DetectCommand, help::HelpCommand, keys::KeysCommand}; + +/// The `yubihsm` subcommand +#[derive(Debug, Options)] +pub enum YubihsmCommand { + #[options(help = "detect all YubiHSM2 devices connected via USB")] + Detect(DetectCommand), + + #[options(help = "show help for the 'yubihsm' subcommand")] + Help(HelpCommand), + + #[options(help = "key management subcommands")] + Keys(KeysCommand), +} + +// TODO: custom derive in abscissa +impl_command!(YubihsmCommand); + +// TODO: refactor abscissa internally so this is all part of the proc macro +impl Callable for YubihsmCommand { + /// Call the given command chosen via the CLI + fn call(&self) { + match self { + YubihsmCommand::Detect(detect) => detect.call(), + YubihsmCommand::Help(help) => help.call(), + YubihsmCommand::Keys(keys) => keys.call(), + } + } +} + +impl YubihsmCommand { + pub(super) fn config_path(&self) -> Option<&str> { + match self { + YubihsmCommand::Detect(detect) => detect.config.as_ref().map(|s| s.as_ref()), + YubihsmCommand::Keys(keys) => keys.config_path(), + _ => None, + } + } +} diff --git a/src/config/dalek.rs b/src/config/dalek.rs deleted file mode 100644 index 8d7cfaa..0000000 --- a/src/config/dalek.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Configuration for the ed25519-dalek backend - -use std::collections::BTreeMap; -use std::path::PathBuf; - -#[derive(Clone, Deserialize, Debug)] -pub struct DalekConfig { - /// Ed25519 private key configurations - pub keys: BTreeMap, -} - -#[derive(Clone, Deserialize, Debug)] -pub struct DalekPrivateKey { - /// Path to a file containing a cryptographic key - pub path: PathBuf, -} diff --git a/src/config/mod.rs b/src/config/mod.rs index c4eee7a..f017dd2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,24 +1,22 @@ //! Configuration file structures (with serde-derived parser) -use std::collections::BTreeMap; use std::path::PathBuf; -mod dalek; -pub use self::dalek::DalekConfig; +pub mod provider; +mod validator; -#[cfg(feature = "yubihsm-provider")] -mod yubihsm; -#[cfg(feature = "yubihsm-provider")] -pub use self::yubihsm::YubihsmConfig; +use self::provider::ProviderConfig; +pub use self::validator::*; /// Name of the KMS configuration file pub const CONFIG_FILE_NAME: &str = "kms.toml"; /// KMS configuration (i.e. TOML file parsed with serde) #[derive(Clone, Deserialize, Debug)] -pub struct KMSConfig { +#[serde(deny_unknown_fields)] +pub struct KmsConfig { /// Addresses of validator nodes - pub validators: BTreeMap, + pub validator: Vec, /// Cryptographic signature provider configuration pub providers: ProviderConfig, @@ -30,30 +28,7 @@ pub struct KMSConfig { // Impl the `abscissa::GlobalConfig` trait, storing the configuration in the // `GLOBAL_CONFIG` static value -impl_global_config!(KMSConfig, GLOBAL_CONFIG); - -#[derive(Clone, Deserialize, Debug)] -pub struct ValidatorConfig { - /// Validator hostname or IP address - pub addr: String, - - /// Validator port - pub port: u16, - - /// Automatically reconnect on error? (default: true) - #[serde(default = "reconnect_default")] - pub reconnect: bool, -} - -#[derive(Clone, Deserialize, Debug)] -pub struct ProviderConfig { - /// ed25519-dalek configuration - pub dalek: Option, - - /// Map of yubihsm-connector labels to their configurations - #[cfg(feature = "yubihsm-provider")] - pub yubihsm: Option, -} +impl_global_config!(KmsConfig, GLOBAL_CONFIG); #[derive(Clone, Deserialize, Debug)] pub struct SecretConnectionConfig { @@ -61,8 +36,3 @@ pub struct SecretConnectionConfig { #[serde(rename = "secret-key-path")] pub secret_key_path: PathBuf, } - -/// Default value for the `ValidatorConfig` reconnect field -fn reconnect_default() -> bool { - true -} diff --git a/src/config/provider/mod.rs b/src/config/provider/mod.rs new file mode 100644 index 0000000..dbf577a --- /dev/null +++ b/src/config/provider/mod.rs @@ -0,0 +1,23 @@ +#[cfg(feature = "softsign")] +pub mod softsign; +#[cfg(feature = "yubihsm")] +pub mod yubihsm; + +#[cfg(feature = "softsign")] +use self::softsign::SoftSignConfig; +#[cfg(feature = "yubihsm")] +use self::yubihsm::YubihsmConfig; + +/// Provider configuration +#[derive(Clone, Deserialize, Debug)] +pub struct ProviderConfig { + /// Software-backed signer + #[cfg(feature = "softsign")] + #[serde(default)] + pub softsign: Vec, + + /// Map of yubihsm-connector labels to their configurations + #[cfg(feature = "yubihsm")] + #[serde(default)] + pub yubihsm: Vec, +} diff --git a/src/config/provider/softsign.rs b/src/config/provider/softsign.rs new file mode 100644 index 0000000..60a95a0 --- /dev/null +++ b/src/config/provider/softsign.rs @@ -0,0 +1,25 @@ +//! Configuration for software-backed signer (using ed25519-dalek) + +use std::path::{Path, PathBuf}; + +/// Software signer configuration +#[derive(Clone, Deserialize, Debug)] +pub struct SoftSignConfig { + /// Identifier for this key + pub id: String, + + /// Path to a file containing a cryptographic key + // TODO: use `abscissa::Secret` to wrap this `PathBuf` + pub path: SoftPrivateKey, +} + +/// Software-backed private key (stored in a file) +#[derive(Clone, Deserialize, Debug)] +pub struct SoftPrivateKey(PathBuf); + +impl SoftPrivateKey { + /// Borrow this private key as a path + pub fn as_path(&self) -> &Path { + self.0.as_ref() + } +} diff --git a/src/config/provider/yubihsm.rs b/src/config/provider/yubihsm.rs new file mode 100644 index 0000000..253fe87 --- /dev/null +++ b/src/config/provider/yubihsm.rs @@ -0,0 +1,120 @@ +//! Configuration for the `YubiHSM` backend + +use abscissa::secrets::{BorrowSecret, DebugSecret, Secret}; +use std::process; +use yubihsm::{Credentials, HttpConfig, SerialNumber, UsbConfig}; + +/// The (optional) `[providers.yubihsm]` config section +#[derive(Clone, Deserialize, Debug)] +pub struct YubihsmConfig { + /// Adapter configuration + pub adapter: AdapterConfig, + + /// Authentication configuration + pub auth: AuthConfig, + + /// List of signing keys in this YubiHSM + #[serde(default)] + pub keys: Vec, + + /// Serial number of the YubiHSM to connect to + #[serde(rename = "serial-number")] + pub serial_number: Option, +} + +impl YubihsmConfig { + /// Get the `yubihsm::HttpConfig` or exit if unconfigured + #[allow(dead_code)] + pub fn http_config(&self) -> HttpConfig { + match self.adapter { + AdapterConfig::Http { ref connector } => connector.clone(), + AdapterConfig::Usb { .. } => { + status_err!("YubiHSM2 HTTP adapter support required, sorry"); + process::exit(1); + } + } + } + + /// Get the `yubihsm::UsbConfig` or exit if unconfigured + pub fn usb_config(&self) -> UsbConfig { + match self.adapter { + AdapterConfig::Http { .. } => { + status_err!("YubiHSM2 USB adapter support required, sorry"); + process::exit(1); + } + AdapterConfig::Usb { timeout_ms } => UsbConfig { + serial: self.serial_number, + timeout_ms, + }, + } + } +} + +/// Configuration for an individual YubiHSM +#[derive(Clone, Deserialize, Debug)] +#[serde(tag = "type")] +pub enum AdapterConfig { + /// Connect to the YubiHSM2 directly via USB + #[serde(rename = "usb")] + Usb { + /// Timeout when communicating with YubiHSM2 + #[serde(default = "usb_timeout_ms_default")] + timeout_ms: u64, + }, + + /// Connect to the YubiHSM2 via `yubihsm-connector` + #[serde(rename = "http")] + Http { + /// `yubihsm-connector` configuration + connector: HttpConfig, + }, +} + +/// Configuration options for this connector +#[derive(Clone, Debug, Deserialize)] +pub struct AuthConfig { + /// Authentication key ID to use to authenticate to the YubiHSM + pub key: u16, + + /// Password to use to authenticate to the YubiHSM + // TODO: allow password to be read from an external password-file + pub password: Secret, +} + +impl AuthConfig { + /// Get the `yubihsm::Credentials` for this `AuthConfig` + pub fn credentials(&self) -> Credentials { + Credentials::from_password(self.key, self.password.borrow_secret().0.as_bytes()) + } +} + +/// Password to the YubiHSM +#[derive(Clone, Deserialize)] +pub struct Password(String); + +impl DebugSecret for Password { + fn debug_secret(&self) -> &'static str { + "REDACTED PASSWORD" + } +} + +// Needed by clear_on_drop +impl Default for Password { + fn default() -> Self { + Password("".to_owned()) + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct SigningKeyConfig { + /// Identifier for this key + pub id: String, + + /// Signing key ID + pub key: u16, +} + +/// Default value for `AdapterConfig::Usb { timeout_ms }` +fn usb_timeout_ms_default() -> u64 { + 1000 +} diff --git a/src/config/validator.rs b/src/config/validator.rs new file mode 100644 index 0000000..45711b4 --- /dev/null +++ b/src/config/validator.rs @@ -0,0 +1,35 @@ +/// Validator configuration +#[derive(Clone, Deserialize, Debug)] +pub struct ValidatorConfig { + /// Validator hostname or IP address + pub addr: String, + + /// Validator port + pub port: u16, + + /// Automatically reconnect on error? (default: true) + #[serde(default = "reconnect_default")] + pub reconnect: bool, +} + +impl ValidatorConfig { + /// Get the URI which represents this configuration + pub fn uri(&self) -> String { + format!("gaia-rpc://{}:{}", self.addr, self.port) + } +} + +impl Default for ValidatorConfig { + fn default() -> ValidatorConfig { + ValidatorConfig { + addr: "127.0.0.1".to_owned(), + port: 26657, + reconnect: true, + } + } +} + +/// Default value for the `ValidatorConfig` reconnect field +fn reconnect_default() -> bool { + ValidatorConfig::default().reconnect +} diff --git a/src/config/yubihsm.rs b/src/config/yubihsm.rs deleted file mode 100644 index 3471b50..0000000 --- a/src/config/yubihsm.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Configuration for the `YubiHSM` backend - -use abscissa::secrets::{DebugSecret, Secret}; -use std::collections::BTreeMap; - -/// The (optional) `[providers.yubihsm]` config section -pub type YubihsmConfig = BTreeMap; - -/// Configuration for a particular yubihsm-connector process -#[derive(Clone, Deserialize, Debug)] -pub struct ConnectorConfig { - /// Address of yubihsm-connector (IP or hostname) - pub http: HttpConfig, - - /// Authentication configuration - pub auth: AuthConfig, - - /// Map of labels to private key configurations - pub keys: BTreeMap, -} - -/// Configuration options for this connector -#[derive(Clone, Debug, Deserialize)] -pub struct HttpConfig { - /// Address of the connector (IP address or DNS name) - pub addr: String, - - /// Port the connector process is listening on - pub port: u16, - - /// Timeout for connecting, reading, and writing in milliseconds - pub timeout_ms: u64, -} - -/// Configuration options for this connector -#[derive(Clone, Debug, Deserialize)] -pub struct AuthConfig { - /// Authentication key ID to use to authenticate to the YubiHSM - #[serde(rename = "key-id")] - pub key_id: u16, - - /// Password to use to authenticate to the YubiHSM - // TODO: allow password to be read from an external password-file - pub password: Secret, -} - -/// Password to the YubiHSM -#[derive(Clone, Deserialize)] -pub struct Password(String); - -impl DebugSecret for Password { - fn debug_secret(&self) -> &'static str { - "[PASSWORD]" - } -} - -impl Default for Password { - fn default() -> Self { - Password("".to_owned()) - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct SigningKeyConfig { - /// Signing key ID - #[serde(rename = "key-id")] - pub key_id: u16, -} diff --git a/src/ed25519/keyring.rs b/src/ed25519/keyring.rs index 5930437..d678380 100644 --- a/src/ed25519/keyring.rs +++ b/src/ed25519/keyring.rs @@ -2,11 +2,11 @@ use signatory::Ed25519Signature; use std::{collections::BTreeMap, sync::RwLock}; use super::{PublicKey, Signer}; -use config::ProviderConfig; +use config::provider::ProviderConfig; use error::Error; -use super::signer::dalek; -#[cfg(feature = "yubihsm-provider")] +use super::signer::softsign; +#[cfg(feature = "yubihsm")] use super::signer::yubihsm; lazy_static! { @@ -22,16 +22,21 @@ impl KeyRing { // Clear the current global keyring if !keyring.0.is_empty() { - info!("Clearing keyring"); + info!("[keyring:*] Clearing keyring"); keyring.0.clear(); } - dalek::init(&mut keyring, config.dalek.as_ref())?; + #[cfg(feature = "softsign")] + softsign::init(&mut keyring, &config.softsign)?; - #[cfg(feature = "yubihsm-provider")] + #[cfg(feature = "yubihsm")] yubihsm::init(&mut keyring, &config.yubihsm)?; - Ok(()) + if keyring.0.is_empty() { + Err(err!(ConfigError, "no signing keys configured!")) + } else { + Ok(()) + } } /// Sign a message using the secret key associated with the given public key @@ -51,7 +56,7 @@ impl KeyRing { /// signer registered for the given public key pub(super) fn add(&mut self, public_key: PublicKey, signer: Signer) -> Result<(), Error> { info!( - "Adding {}:{} {}", + "[keyring:{}:{}] added validator key {}", signer.provider_name, signer.key_id, public_key ); diff --git a/src/ed25519/mod.rs b/src/ed25519/mod.rs index db92115..4da4af4 100644 --- a/src/ed25519/mod.rs +++ b/src/ed25519/mod.rs @@ -1,4 +1,4 @@ -use signatory; +use subtle_encoding; mod keyring; mod public_key; @@ -9,4 +9,4 @@ pub use self::public_key::{PublicKey, PUBLIC_KEY_SIZE}; pub use self::signer::Signer; /// Encoding for secret keys -pub const SECRET_KEY_ENCODING: signatory::Encoding = signatory::Encoding::Raw; +pub const SECRET_KEY_ENCODING: &subtle_encoding::Identity = subtle_encoding::IDENTITY; diff --git a/src/ed25519/public_key.rs b/src/ed25519/public_key.rs index deffed0..86a6ca3 100644 --- a/src/ed25519/public_key.rs +++ b/src/ed25519/public_key.rs @@ -1,18 +1,20 @@ -use signatory::ed25519::Ed25519PublicKey; +use signatory::ed25519; pub use signatory::ed25519::PUBLIC_KEY_SIZE; use std::fmt::{self, Display}; +#[cfg(feature = "yubihsm")] +use yubihsm; use error::Error; /// Ed25519 public keys #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] -pub struct PublicKey(Ed25519PublicKey); +pub struct PublicKey(ed25519::PublicKey); impl PublicKey { /// Convert a bytestring to a public key pub fn from_bytes(bytes: &[u8]) -> Result { Ok(PublicKey( - Ed25519PublicKey::from_bytes(bytes).map_err(|e| err!(InvalidKey, "{}", e))?, + ed25519::PublicKey::from_bytes(bytes).map_err(|e| err!(InvalidKey, "{}", e))?, )) } @@ -37,8 +39,16 @@ impl Display for PublicKey { } } -impl From for PublicKey { - fn from(key: Ed25519PublicKey) -> PublicKey { +impl From for PublicKey { + fn from(key: ed25519::PublicKey) -> PublicKey { PublicKey(key) } } + +#[cfg(feature = "yubihsm")] +impl From for PublicKey { + fn from(key: yubihsm::client::get_pubkey::PublicKey) -> PublicKey { + assert_eq!(key.algorithm, yubihsm::AsymmetricAlg::Ed25519); + Self::from_bytes(key.as_slice()).unwrap() + } +} diff --git a/src/ed25519/signer/dalek.rs b/src/ed25519/signer/dalek.rs deleted file mode 100644 index b674664..0000000 --- a/src/ed25519/signer/dalek.rs +++ /dev/null @@ -1,43 +0,0 @@ -// ed25519-dalek software-based signer -// -// This is mainly intended for testing/CI. Ideally real validators will use HSMs - -use signatory::{ - encoding::{Decode, Encoding}, - Ed25519Seed, PublicKeyed, -}; -use signatory_dalek::Ed25519Signer; - -use config::DalekConfig; -use ed25519::{KeyRing, PublicKey, Signer}; -use error::Error; - -/// Label for ed25519-dalek provider -pub const DALEK_PROVIDER_LABEL: &str = "dalek"; - -/// Create software-backed Ed25519 signer objects from the given configuration -pub fn init(keyring: &mut KeyRing, config_option: Option<&DalekConfig>) -> Result<(), Error> { - if let Some(ref config) = config_option { - for (key_id, key_config) in &config.keys { - let seed = - Ed25519Seed::decode_from_file(&key_config.path, Encoding::Raw).map_err(|e| { - err!( - ConfigError, - "can't open {}: {}", - key_config.path.display(), - e - ) - })?; - - let signer = Box::new(Ed25519Signer::from(&seed)); - let public_key = PublicKey::from_bytes(signer.public_key().unwrap().as_ref()).unwrap(); - - keyring.add( - public_key, - Signer::new(DALEK_PROVIDER_LABEL, key_id.to_owned(), signer), - )?; - } - } - - Ok(()) -} diff --git a/src/ed25519/signer/mod.rs b/src/ed25519/signer/mod.rs index fa4a27c..f7756ee 100644 --- a/src/ed25519/signer/mod.rs +++ b/src/ed25519/signer/mod.rs @@ -1,7 +1,8 @@ use signatory::{self, Ed25519Signature, Signer as SignerTrait}; -pub mod dalek; -#[cfg(feature = "yubihsm-provider")] +#[cfg(feature = "softsign")] +pub mod softsign; +#[cfg(feature = "yubihsm")] pub mod yubihsm; use error::Error; diff --git a/src/ed25519/signer/softsign.rs b/src/ed25519/signer/softsign.rs new file mode 100644 index 0000000..23e8124 --- /dev/null +++ b/src/ed25519/signer/softsign.rs @@ -0,0 +1,39 @@ +// ed25519-dalek software-based signer +// +// This is mainly intended for testing/CI. Ideally real validators will use HSMs + +use signatory::{encoding::Decode, Ed25519Seed, PublicKeyed}; +use signatory_dalek::Ed25519Signer; +use subtle_encoding::IDENTITY; + +use config::provider::softsign::SoftSignConfig; +use ed25519::{KeyRing, PublicKey, Signer}; +use error::Error; + +/// Label for ed25519-dalek provider +// TODO: use a non-string type for these, e.g. an enum +pub const DALEK_PROVIDER_LABEL: &str = "dalek"; + +/// Create software-backed Ed25519 signer objects from the given configuration +pub fn init(keyring: &mut KeyRing, configs: &[SoftSignConfig]) -> Result<(), Error> { + for config in configs { + let seed = Ed25519Seed::decode_from_file(config.path.as_path(), IDENTITY).map_err(|e| { + err!( + ConfigError, + "can't open {}: {}", + config.path.as_path().display(), + e + ) + })?; + + let signer = Box::new(Ed25519Signer::from(&seed)); + let public_key = PublicKey::from(signer.public_key()?); + + keyring.add( + public_key, + Signer::new(DALEK_PROVIDER_LABEL, config.id.clone(), signer), + )?; + } + + Ok(()) +} diff --git a/src/ed25519/signer/yubihsm.rs b/src/ed25519/signer/yubihsm.rs index def830c..e95687e 100644 --- a/src/ed25519/signer/yubihsm.rs +++ b/src/ed25519/signer/yubihsm.rs @@ -1,15 +1,43 @@ //! YubiHSM2-based signer -// TODO: finish implementing this! -use config::YubihsmConfig; -use ed25519::KeyRing; +use signatory::PublicKeyed; +use signatory_yubihsm::{self, KeyId}; + +use config::provider::yubihsm::YubihsmConfig; +use ed25519::{KeyRing, PublicKey, Signer}; use error::Error; +/// Label for ed25519-dalek provider +// TODO: use a non-string type for these, e.g. an enum +pub const YUBIHSM_PROVIDER_LABEL: &str = "yubihsm"; + /// Create hardware-backed YubiHSM signer objects from the given configuration -pub fn init(_keyring: &mut KeyRing, config: &Option) -> Result<(), Error> { - if config.is_none() { +pub fn init(keyring: &mut KeyRing, yubihsm_configs: &[YubihsmConfig]) -> Result<(), Error> { + if yubihsm_configs.is_empty() { return Ok(()); } - panic!("YubiHSM2 support unimplemented!"); + if yubihsm_configs.len() != 1 { + return Err(err!( + ConfigError, + "expected one [yubihsm.provider] in config, found: {}", + yubihsm_configs.len() + )); + } + + let yubihsm_config = &yubihsm_configs[0]; + let connector = signatory_yubihsm::yubihsm::UsbConnector::new(&yubihsm_config.usb_config())?; + let session = signatory_yubihsm::Session::create(connector, yubihsm_config.auth.credentials())?; + + for key_config in &yubihsm_config.keys { + let signer = Box::new(session.ed25519_signer(KeyId(key_config.key))?); + let public_key = PublicKey::from(signer.public_key()?); + + keyring.add( + public_key, + Signer::new(YUBIHSM_PROVIDER_LABEL, key_config.id.clone(), signer), + )?; + } + + Ok(()) } diff --git a/src/error.rs b/src/error.rs index 5ebb901..f5bed7a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,8 @@ use std::{ fmt::{self, Display}, io, }; +#[cfg(feature = "yubihsm")] +use yubihsm; /// Create a new error (of a given enum variant) with a formatted message macro_rules! err { @@ -109,6 +111,11 @@ impl Display for Error { /// Kinds of errors #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] pub enum ErrorKind { + /// Access denied + #[fail(display = "access denied")] + #[cfg(feature = "yubihsm")] + AccessError, + /// Error in configuration file #[fail(display = "config error")] ConfigError, @@ -183,3 +190,23 @@ impl From for Error { Error::with_description(kind, other.description().to_owned()) } } + +#[cfg(feature = "yubihsm")] +impl From for Error { + fn from(other: yubihsm::connector::ConnectionError) -> Self { + use yubihsm::connector::ConnectionErrorKind; + + let kind = match other.kind() { + ConnectionErrorKind::AddrInvalid => ErrorKind::ConfigError, + ConnectionErrorKind::AccessDenied => ErrorKind::AccessError, + ConnectionErrorKind::IoError + | ConnectionErrorKind::ConnectionFailed + | ConnectionErrorKind::DeviceBusyError + | ConnectionErrorKind::RequestError + | ConnectionErrorKind::ResponseError + | ConnectionErrorKind::UsbError => ErrorKind::IoError, + }; + + Error::with_description(kind, other.description().to_owned()) + } +} diff --git a/src/main.rs b/src/main.rs index 70fdc69..2fdc575 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,9 @@ extern crate abscissa_derive; extern crate byteorder; extern crate bytes; extern crate chrono; -extern crate clear_on_drop; extern crate failure; #[macro_use] extern crate failure_derive; -extern crate hex; extern crate hkdf; #[macro_use] extern crate lazy_static; @@ -22,16 +20,16 @@ extern crate rand; extern crate ring; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate serde_json; extern crate sha2; extern crate signatory; extern crate signatory_dalek; -#[cfg(feature = "yubihsm-provider")] +#[cfg(feature = "yubihsm")] extern crate signatory_yubihsm; -#[macro_use] -extern crate serde_json; +extern crate subtle_encoding; extern crate x25519_dalek; -#[cfg(feature = "yubihsm-provider")] -extern crate yubihsm; +extern crate zeroize; #[macro_use] mod error; @@ -45,10 +43,12 @@ mod rpc; mod secret_connection; mod session; mod types; +#[cfg(feature = "yubihsm")] +mod yubihsm; -use application::KMSApplication; +use application::KmsApplication; /// Main entry point fn main() { - abscissa::boot(KMSApplication); + abscissa::boot(KmsApplication); } diff --git a/src/secret_connection.rs b/src/secret_connection.rs index 2f25447..f6d2969 100644 --- a/src/secret_connection.rs +++ b/src/secret_connection.rs @@ -464,11 +464,11 @@ mod tests { #[test] fn test_derive_secrets_and_challenge_golden_test_vectors() { - extern crate hex; use std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::str::FromStr; + use subtle_encoding::hex; let f = File::open("src/TestDeriveSecretsAndChallenge.golden").unwrap(); let file = BufReader::new(&f); diff --git a/src/types/ed25519msg.rs b/src/types/ed25519msg.rs index c482b2f..98e20b3 100644 --- a/src/types/ed25519msg.rs +++ b/src/types/ed25519msg.rs @@ -1,4 +1,4 @@ -use signatory::ed25519::{Ed25519PublicKey, PUBLIC_KEY_SIZE}; +use signatory::ed25519::{PublicKey, PUBLIC_KEY_SIZE}; // Note:On the golang side this is generic in the sense that it could everything that implements // github.com/tendermint/tendermint/crypto.PubKey @@ -15,17 +15,17 @@ pub struct PubKeyMsg { pub_key_ed25519: Vec, } -impl Into for PubKeyMsg { +impl Into for PubKeyMsg { // This does not check if the underlying pub_key_ed25519 has the right size. // The caller needs to make sure that this is actually the case. - fn into(self) -> Ed25519PublicKey { + fn into(self) -> PublicKey { let mut public_key = [0u8; PUBLIC_KEY_SIZE]; public_key.copy_from_slice(self.pub_key_ed25519.as_ref()); - Ed25519PublicKey(public_key) + PublicKey(public_key) } } -impl Into for Ed25519PublicKey { +impl Into for PublicKey { fn into(self) -> PubKeyMsg { let pk = self.0.to_vec(); PubKeyMsg { @@ -131,7 +131,7 @@ mod tests { 0xe7, 0xc1, 0xd4, 0x69, 0xc3, 0x44, 0x26, 0xec, 0xef, 0xc0, 0x72, 0xa, 0x52, 0x4d, 0x37, 0x32, 0xef, 0xed, ]; - let want = Ed25519PublicKey(raw_pk); + let want = PublicKey(raw_pk); let pk = PubKeyMsg { pub_key_ed25519: vec![ 0x79, 0xce, 0xd, 0xe0, 0x43, 0x33, 0x4a, 0xec, 0xe0, 0x8b, 0x7b, 0xb5, 0x61, 0xbc, @@ -140,7 +140,7 @@ mod tests { ], }; let orig = pk.clone(); - let got: Ed25519PublicKey = pk.into(); + let got: PublicKey = pk.into(); assert_eq!(got, want); @@ -156,6 +156,6 @@ mod tests { pub_key_ed25519: vec![], }; // we expect this to panic: - let _got: Ed25519PublicKey = empty_msg.into(); + let _got: PublicKey = empty_msg.into(); } } diff --git a/src/types/heartbeat.rs b/src/types/heartbeat.rs index 507a04d..545fce9 100644 --- a/src/types/heartbeat.rs +++ b/src/types/heartbeat.rs @@ -1,5 +1,5 @@ use super::TendermintSign; -use hex::encode; +use subtle_encoding::hex::encode; #[derive(Clone, PartialEq, Message)] pub struct Heartbeat { diff --git a/src/types/proposal.rs b/src/types/proposal.rs index 57fa3ca..c74fbbb 100644 --- a/src/types/proposal.rs +++ b/src/types/proposal.rs @@ -1,7 +1,7 @@ use super::{BlockID, PartsSetHeader, TendermintSign, Time}; use chrono::{DateTime, Utc}; -use hex::encode_upper; use std::time::{SystemTime, UNIX_EPOCH}; +use subtle_encoding::hex::encode_upper; #[derive(Clone, PartialEq, Message)] pub struct Proposal { diff --git a/src/types/vote.rs b/src/types/vote.rs index d51bcf4..a54195f 100644 --- a/src/types/vote.rs +++ b/src/types/vote.rs @@ -1,7 +1,7 @@ use super::{BlockID, TendermintSign, Time}; use chrono::{DateTime, Utc}; -use hex::encode_upper; use std::time::{SystemTime, UNIX_EPOCH}; +use subtle_encoding::hex::encode_upper; // TODO(ismail): we might not want to use this error type here // see below: those aren't prost errors use prost::error::DecodeError; diff --git a/src/yubihsm.rs b/src/yubihsm.rs new file mode 100644 index 0000000..8cac5ec --- /dev/null +++ b/src/yubihsm.rs @@ -0,0 +1,66 @@ +use abscissa::GlobalConfig; +pub use signatory_yubihsm::yubihsm::*; +use std::{ + process, + sync::{Mutex, MutexGuard}, +}; + +use config::{provider::yubihsm::YubihsmConfig, KmsConfig}; + +lazy_static! { + static ref HSM_CLIENT: Mutex = Mutex::new(create_hsm_client()); +} + +/// Get a `Box` instantiated via the configuration file +pub fn get_hsm_client() -> MutexGuard<'static, Client> { + HSM_CLIENT.lock().unwrap() +} + +/// Get a `yubihsm::Client` configured from the global configuration +fn create_hsm_client() -> Client { + let connector = create_hsm_connector(); + let credentials = get_config().auth.credentials(); + + Client::open(connector, credentials, true).unwrap_or_else(|e| { + status_err!("error connecting to YubiHSM2: {}", e); + process::exit(1); + }) +} + +/// Get the YubiHSM-related configuration +pub fn get_config() -> YubihsmConfig { + let kms_config = KmsConfig::get_global(); + let yubihsm_configs = &kms_config.providers.yubihsm; + + if yubihsm_configs.len() != 1 { + status_err!( + "expected one [yubihsm.provider] in config, found: {}", + yubihsm_configs.len() + ); + process::exit(1); + } + + yubihsm_configs[0].clone() +} + +/// Open a session with the YubiHSM2 using settings from the global config +#[cfg(not(feature = "yubihsm-mock"))] +pub fn create_hsm_connector() -> Box { + // TODO: `HttpConnector` support + let connector = UsbConnector::new(&get_config().usb_config()).unwrap_or_else(|e| { + status_err!("error opening USB connection to YubiHSM2: {}", e); + process::exit(1); + }); + + connector.into() +} + +#[cfg(feature = "yubihsm-mock")] +pub fn create_hsm_connector() -> Box { + MOCK_HSM.clone().into() +} + +#[cfg(feature = "yubihsm-mock")] +lazy_static! { + static ref MOCK_HSM: MockHsm = MockHsm::default(); +} diff --git a/tests/cli/mod.rs b/tests/cli/mod.rs new file mode 100644 index 0000000..7a39169 --- /dev/null +++ b/tests/cli/mod.rs @@ -0,0 +1,48 @@ +//! Tests for the KMS command-line interface + +use std::{ + ffi::OsStr, + io::{self, Write}, + process::{Command, Output}, +}; + +/// Path to the KMS executable +pub const KMS_EXE_PATH: &str = "./target/debug/cosmos-kms"; + +#[cfg(feature = "yubihsm")] +mod yubihsm; + +/// Run the `cosmos-kms` CLI command with the given arguments +pub fn run(args: I) -> Output +where + I: IntoIterator, + S: AsRef, +{ + Command::new(KMS_EXE_PATH).args(args).output().unwrap() +} + +/// Run the `cosmos-kms` CLI command with the expectation that it will exit successfully, +/// panicking and printing stdout/stderr if it does not +pub fn run_successfully(args: I) -> Output +where + I: IntoIterator, + S: AsRef, +{ + let output = run(args); + let status_code = output.status.code().unwrap(); + + if status_code == 0 { + output + } else { + io::stdout().write(&output.stdout).unwrap(); + io::stderr().write(&output.stderr).unwrap(); + + panic!("{} exited with error status: {}", KMS_EXE_PATH, status_code); + } +} + +#[test] +fn test_usage() { + let status_code = run(&[] as &[&OsStr]).status.code().unwrap(); + assert_eq!(status_code, 2); +} diff --git a/tests/cli/yubihsm/detect.rs b/tests/cli/yubihsm/detect.rs new file mode 100644 index 0000000..c5ec90c --- /dev/null +++ b/tests/cli/yubihsm/detect.rs @@ -0,0 +1,9 @@ +//! Integration tests for the `yubihsm detect` subcommand + +use cli; + +#[test] +fn detect_command_test() { + // TODO: parse results + cli::run_successfully(&["yubihsm", "detect"]); +} diff --git a/tests/cli/yubihsm/keys/generate.rs b/tests/cli/yubihsm/keys/generate.rs new file mode 100644 index 0000000..df5c03a --- /dev/null +++ b/tests/cli/yubihsm/keys/generate.rs @@ -0,0 +1,2 @@ +//! Integration tests for the `yubihsm keys generate` subcommand +// TODO: `yubihsm keys generate` tests diff --git a/tests/cli/yubihsm/keys/list.rs b/tests/cli/yubihsm/keys/list.rs new file mode 100644 index 0000000..2673a5e --- /dev/null +++ b/tests/cli/yubihsm/keys/list.rs @@ -0,0 +1,15 @@ +//! Integration tests for the `yubihsm keys list` subcommand + +use cli; + +#[test] +fn keys_command_test() { + #[allow(unused_mut)] + let mut args = vec!["yubihsm", "keys", "list"]; + + #[cfg(feature = "yubihsm-mock")] + args.extend_from_slice(&["-c", "tests/cli/yubihsm/kms-mockhsm.toml"]); + + // TODO: parse results + cli::run_successfully(args.as_slice()); +} diff --git a/tests/cli/yubihsm/keys/mod.rs b/tests/cli/yubihsm/keys/mod.rs new file mode 100644 index 0000000..ee6888b --- /dev/null +++ b/tests/cli/yubihsm/keys/mod.rs @@ -0,0 +1,12 @@ +//! Integration tests for the `yubihsm keys` subcommand + +mod generate; +mod list; + +use cli; + +#[test] +fn test_usage() { + let status_code = cli::run(&["yubihsm", "keys"]).status.code().unwrap(); + assert_eq!(status_code, 2); +} diff --git a/tests/cli/yubihsm/kms-mockhsm.toml b/tests/cli/yubihsm/kms-mockhsm.toml new file mode 100644 index 0000000..26236a2 --- /dev/null +++ b/tests/cli/yubihsm/kms-mockhsm.toml @@ -0,0 +1,17 @@ +# KMS configuration for testing `yubihsm` subcommands +# +# This file is passed to the KMS executable during integration tests + +[[validator]] +addr = "127.0.0.1" +port = 23456 +reconnect = false + +[[providers.yubihsm]] +adapter = { type = "usb" } +auth = { key = 1, password = "password" } +serial-number = "0123456789" +keys = [{ id = "gaia-9000", key = 1 }] + +[secret-connection] +secret-key-path = "tests/seccon.key" diff --git a/tests/cli/yubihsm/mod.rs b/tests/cli/yubihsm/mod.rs new file mode 100644 index 0000000..0074786 --- /dev/null +++ b/tests/cli/yubihsm/mod.rs @@ -0,0 +1,6 @@ +//! Integration tests for the `yubihsm` subcommands + +// This test requires USB access to a YubiHSM2 +#[cfg(not(feature = "yubihsm-mock"))] +mod detect; +mod keys; diff --git a/tests/integration.rs b/tests/integration.rs index 6ba4d79..d76e67e 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -13,6 +13,9 @@ extern crate prost_derive; extern crate rand; extern crate signatory; extern crate signatory_dalek; +#[cfg(feature = "yubihsm")] +extern crate signatory_yubihsm; +extern crate subtle_encoding; /// Hacks for accessing the RPC types in tests #[macro_use] @@ -21,32 +24,40 @@ extern crate byteorder; extern crate bytes; extern crate chrono; extern crate failure; -extern crate hex; extern crate hkdf; extern crate ring; extern crate sha2; extern crate x25519_dalek; use prost::Message; -use signatory::{ - encoding::{Decode, Encoding}, - Ed25519PublicKey, Ed25519Seed, Ed25519Signature, Signer, -}; +use signatory::{ed25519, encoding::Decode, Signer}; use signatory_dalek::Ed25519Signer; -use std::ffi::OsStr; -use std::io::{Read, Write}; -use std::net::{TcpListener, TcpStream}; -use std::process::{Child, Command}; +#[cfg(feature = "yubihsm")] +use signatory_yubihsm::yubihsm; +use std::{ + ffi::OsStr, + io::{Read, Write}, + net::{TcpListener, TcpStream}, + path::Path, + process::{Child, Command}, +}; +use subtle_encoding::Encoding; use types::TendermintSign; +/// Integration tests for the KMS command-line interface +mod cli; + /// Address the mock validator listens on pub const MOCK_VALIDATOR_ADDR: &str = "127.0.0.1"; /// Port the mock validator listens on pub const MOCK_VALIDATOR_PORT: u16 = 23456; +/// Path to the KMS executable +pub const KMS_EXE_PATH: &str = "./target/debug/cosmos-kms"; + /// Arguments to pass when launching the KMS -pub const KMS_TEST_ARGS: &[&str] = &["run", "-c", "tests/test.toml"]; +pub const KMS_TEST_ARGS: &[&str] = &["run", "-c", "tests/kms-test.toml"]; mod types { include!("../src/types/mod.rs"); @@ -80,10 +91,7 @@ impl KmsConnection { let listener = TcpListener::bind(format!("{}:{}", MOCK_VALIDATOR_ADDR, MOCK_VALIDATOR_PORT)).unwrap(); - let process = Command::new("./target/debug/cosmos-kms") - .args(args) - .spawn() - .unwrap(); + let process = Command::new(KMS_EXE_PATH).args(args).spawn().unwrap(); let (socket, _) = listener.accept().unwrap(); Self { process, socket } @@ -92,10 +100,10 @@ impl KmsConnection { /// Sign the given message with the given public key using the KMS pub fn sign( &mut self, - public_key: &Ed25519PublicKey, - signer: &Signer, + public_key: &ed25519::PublicKey, + signer: &Signer, request: impl types::TendermintSign, - ) -> Ed25519Signature { + ) -> ed25519::Signature { // TODO(ismail) SignRequest -> now one of: // SignHeartbeat(SignHeartbeatMsg), SignProposal(SignProposalMsg), SignVote(SignVoteMsg), ShowPublicKey(PubKeyMsg), /*let req = Request::SignHeartbeat(types::heartbeat::SignHeartbeatMsg { @@ -113,9 +121,16 @@ impl KmsConnection { } } +impl Default for KmsConnection { + fn default() -> KmsConnection { + KmsConnection::create(KMS_TEST_ARGS) + } +} + /// Get the public key associated with the testing private key -fn test_key() -> (Ed25519PublicKey, Ed25519Signer) { - let seed = Ed25519Seed::decode_from_file("tests/signing.key", Encoding::Raw).unwrap(); +fn test_key() -> (ed25519::PublicKey, Ed25519Signer) { + let seed = + ed25519::Seed::decode_from_file("tests/signing.key", subtle_encoding::IDENTITY).unwrap(); let signer = Ed25519Signer::from(&seed); (signatory::public_key(&signer).unwrap(), signer) } @@ -124,7 +139,7 @@ fn test_key() -> (Ed25519PublicKey, Ed25519Signer) { fn test_handle_poisonpill() { use secret_connection::SecretConnection; // this spawns a process which wants to share ephermal keys and blocks until it reads a reply: - let mut kms = KmsConnection::create(KMS_TEST_ARGS); + let mut kms = KmsConnection::default(); // we use the same key for both sides: let (_, signer) = test_key(); diff --git a/tests/test.toml b/tests/kms-test.toml similarity index 53% rename from tests/test.toml rename to tests/kms-test.toml index 4688b52..54dd8df 100644 --- a/tests/test.toml +++ b/tests/kms-test.toml @@ -2,11 +2,14 @@ # # This file is passed to the KMS executable during integration tests -[providers.dalek.keys] -example-key-1 = { path = "tests/signing.key" } +[[validator]] +addr = "127.0.0.1" +port = 23456 +reconnect = false + +[[providers.softsign]] +id = "example-key-1" +path = "tests/signing.key" [secret-connection] secret-key-path = "tests/seccon.key" - -[validators] -example1 = { addr = "127.0.0.1", port = 23456, reconnect = false }