Skip to content
This repository has been archived by the owner on Jun 3, 2020. It is now read-only.

Ledger integration into KMS #172

Merged
merged 12 commits into from
Feb 20, 2019
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
command: |
rustc --version
cargo --version
cargo test --all --all-features
cargo test --all --features "default softsign yubihsm yubihsm-mock"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test harness does not work with the Ledger since I haven't implemented a ledger-mock.

- run:
name: audit
command: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ tmkms.toml

# Ignore VIM swap files
*.swp

\.idea/
87 changes: 86 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ signal-hook = "0.1.7"
signatory = { version = "0.11", features = ["ed25519"] }
signatory-dalek = "0.11"
signatory-yubihsm = { version = "0.11", optional = true }
signatory-ledger-tm = { version = "0.11", optional = true }
subtle-encoding = "0.3"
tendermint = { version = "0.2", path = "tendermint-rs" }

Expand All @@ -43,10 +44,11 @@ tempfile = "3"
rand = "0.6"

[features]
default = ["softsign", "yubihsm"]
default = ["softsign"]
softsign = []
yubihsm = ["signatory-yubihsm/usb"] # USB only for now
yubihsm-mock = ["yubihsm", "signatory-yubihsm/mockhsm"]
ledgertm = ["signatory-ledger-tm"]

# Enable integer overflow checks in release builds for security reasons
[profile.release]
Expand Down
16 changes: 16 additions & 0 deletions src/commands/ledgertm/detect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use abscissa::Callable;

/// The `ledgertm detect` subcommand
#[derive(Debug, Default, Options)]
pub struct DetectCommand {
/// Print debugging information
#[options(short = "v", long = "verbose")]
pub verbose: bool,
}

impl Callable for DetectCommand {
/// Detect all Ledger devices running the Tendermint app
fn call(&self) {
println!("This feature will be soon available");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why include the detect command if it does not do anything yet?

}
}
17 changes: 17 additions & 0 deletions src/commands/ledgertm/help.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use abscissa::{Callable, Command};

use super::LedgertmCommand;

/// The `ledgertm help` subcommand
#[derive(Debug, Default, Options)]
pub struct HelpCommand {
#[options(free)]
pub args: Vec<String>,
}

impl Callable for HelpCommand {
/// Print help for the `ledgertm` subcommand
fn call(&self) {
LedgertmCommand::print_usage(self.args.as_slice());
}
}
32 changes: 32 additions & 0 deletions src/commands/ledgertm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! The KMS `ledgertm` subcommand

use abscissa::Callable;

mod detect;
mod help;

pub use self::{detect::DetectCommand, help::HelpCommand};

/// The `ledgertm` subcommand
#[derive(Debug, Options)]
pub enum LedgertmCommand {
#[options(help = "detect connected Ledger devices running the Tendermint app")]
Detect(DetectCommand),

#[options(help = "show help for the 'ledgertm' subcommand")]
Help(HelpCommand),
}

impl_command!(LedgertmCommand);

impl Callable for LedgertmCommand {
/// Call the given command chosen via the CLI
fn call(&self) {
match self {
LedgertmCommand::Detect(detect) => detect.call(),
LedgertmCommand::Help(help) => help.call(),
}
}
}

impl LedgertmCommand {}
13 changes: 12 additions & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ mod start;
mod version;
#[cfg(feature = "yubihsm")]
mod yubihsm;

#[cfg(feature = "yubihsm")]
pub use self::yubihsm::YubihsmCommand;

#[cfg(feature = "ledgertm")]
mod ledgertm;
#[cfg(feature = "ledgertm")]
pub use self::ledgertm::LedgertmCommand;

pub use self::{
help::HelpCommand, keygen::KeygenCommand, start::StartCommand, version::VersionCommand,
};
Expand All @@ -37,6 +42,10 @@ pub enum KmsCommand {
#[cfg(feature = "yubihsm")]
#[options(help = "subcommands for YubiHSM2")]
Yubihsm(YubihsmCommand),

#[cfg(feature = "ledgertm")]
#[options(help = "subcommands for Ledger Tendermint app")]
Ledgertm(LedgertmCommand),
}

// TODO: refactor abscissa internally so this is all part of the proc macro
Expand Down Expand Up @@ -80,6 +89,8 @@ impl Callable for KmsCommand {
KmsCommand::Version(version) => version.call(),
#[cfg(feature = "yubihsm")]
KmsCommand::Yubihsm(yubihsm) => yubihsm.call(),
#[cfg(feature = "ledgertm")]
KmsCommand::Ledgertm(ledgertm) => ledgertm.call(),
}
}
}
5 changes: 5 additions & 0 deletions src/config/provider/ledgertm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//! Configuration for Ledger Tendermint signer

/// Ledger Tendermint signer configuration
#[derive(Clone, Deserialize, Debug)]
pub struct LedgerTendermintConfig {}
9 changes: 9 additions & 0 deletions src/config/provider/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#[cfg(feature = "ledgertm")]
pub mod ledgertm;
#[cfg(feature = "softsign")]
pub mod softsign;
#[cfg(feature = "yubihsm")]
pub mod yubihsm;

#[cfg(feature = "ledgertm")]
use self::ledgertm::LedgerTendermintConfig;
#[cfg(feature = "softsign")]
use self::softsign::SoftSignConfig;
#[cfg(feature = "yubihsm")]
Expand All @@ -20,4 +24,9 @@ pub struct ProviderConfig {
#[cfg(feature = "yubihsm")]
#[serde(default)]
pub yubihsm: Vec<YubihsmConfig>,

/// Map of ledger-tm labels to their configurations
#[cfg(feature = "ledgertm")]
#[serde(default)]
pub ledgertm: Vec<LedgerTendermintConfig>,
}
22 changes: 22 additions & 0 deletions src/keyring/ed25519/ledgertm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Ledger Tendermint signer

use signatory::PublicKeyed;
use signatory_ledger_tm::{self, Ed25519LedgerTmAppSigner};

use crate::{
config::provider::ledgertm::LedgerTendermintConfig,
error::KmsError,
keyring::{ed25519::Signer, KeyRing},
};

pub const LEDGER_TM_PROVIDER_LABEL: &str = "ledgertm";
pub const LEDGER_TM_ID: &str = "ledgertm";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the ID come from the config? An ID that is always the same (and the same as the constant LEDGER_TM_PROVIDER_LABEL), feels wrong.


/// Create Ledger Tendermint signer object from the given configuration
pub fn init(keyring: &mut KeyRing, _config: &[LedgerTendermintConfig]) -> Result<(), KmsError> {
let provider = Box::new(Ed25519LedgerTmAppSigner::connect()?);
let pk = provider.public_key()?;
let signer = Signer::new(LEDGER_TM_PROVIDER_LABEL, LEDGER_TM_ID.to_string(), provider);
keyring.add(pk, signer)?;
Ok(())
}
2 changes: 2 additions & 0 deletions src/keyring/ed25519/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub use signatory::ed25519::{PublicKey, Seed, PUBLIC_KEY_SIZE};

#[cfg(feature = "ledgertm")]
pub mod ledgertm;
mod signer;
#[cfg(feature = "softsign")]
pub mod softsign;
Expand Down
Loading