Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ledger integration into KMS #172

Merged
merged 12 commits into from Feb 20, 2019

Refactoring and adjusting to new ledger-tm library

+ Adding a basic command line
  • Loading branch information...
jleni committed Feb 15, 2019
commit 99b5b271bce68e58ecbf02449eb131f66a789713
@@ -41,7 +41,7 @@ jobs:
command: |
rustc --version
cargo --version
cargo test --all --features "default softsign yubihsm yubihsm-mock"
cargo test --all --all-features
- run:
name: audit
command: |
@@ -4,3 +4,5 @@ tmkms.toml

# Ignore VIM swap files
*.swp

\.idea/

Some generated files are not rendered by default. Learn more.

@@ -51,10 +51,10 @@ rand = "0.6"

[features]
default = ["softsign"]
ledger = ["signatory-ledger-tm"]
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]
@@ -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");

This comment has been minimized.

Copy link
@Liamsi

Liamsi Feb 19, 2019

Member

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

}
}
@@ -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());
}
}
@@ -0,0 +1,35 @@
//! 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 {}
@@ -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,
};
@@ -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
@@ -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(),
}
}
}

This file was deleted.

@@ -0,0 +1,5 @@
//! Configuration for Ledger Tendermint signer

/// Ledger Tendermint signer configuration
#[derive(Clone, Deserialize, Debug)]
pub struct LedgerTendermintConfig {}
@@ -1,16 +1,16 @@
#[cfg(feature = "ledger")]
pub mod ledger;
#[cfg(feature = "softsign")]
pub mod softsign;
#[cfg(feature = "yubihsm")]
pub mod yubihsm;
#[cfg(feature = "ledgertm")]
pub mod ledgertm;

#[cfg(feature = "ledger")]
use self::ledger::LedgerConfig;
#[cfg(feature = "softsign")]
use self::softsign::SoftSignConfig;
#[cfg(feature = "yubihsm")]
use self::yubihsm::YubihsmConfig;
#[cfg(feature = "ledgertm")]
use self::ledgertm::LedgerTendermintConfig;

/// Provider configuration
#[derive(Clone, Deserialize, Debug)]
@@ -25,7 +25,8 @@ pub struct ProviderConfig {
#[serde(default)]
pub yubihsm: Vec<YubihsmConfig>,

#[cfg(feature = "ledger")]
/// Map of ledger-tm labels to their configurations
#[cfg(feature = "ledgertm")]
#[serde(default)]
pub ledger: Vec<LedgerConfig>,
pub ledgertm: Vec<LedgerTendermintConfig>,
}

This file was deleted.

@@ -0,0 +1,22 @@
//! Ledger Tendermint signer

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

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

pub const LEDGER_TM_PROVIDER_LABEL: &str = "ledgertm";
pub const LEDGER_TM_ID: &str = "ledgertm";

This comment has been minimized.

Copy link
@Liamsi

Liamsi Feb 19, 2019

Member

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(())
}
@@ -1,11 +1,11 @@
pub use signatory::ed25519::{PublicKey, Seed, PUBLIC_KEY_SIZE};

#[cfg(feature = "ledger")]
pub mod ledger;
mod signer;
#[cfg(feature = "softsign")]
pub mod softsign;
#[cfg(feature = "yubihsm")]
pub mod yubihsm;
#[cfg(feature = "ledgertm")]
pub mod ledgertm;

pub use self::signer::Signer;
@@ -12,11 +12,11 @@ use crate::{
error::{KmsError, KmsErrorKind::*},
};

#[cfg(feature = "ledger")]
use self::ed25519::ledger;
use self::ed25519::{softsign, Signer};
#[cfg(feature = "yubihsm")]
use self::ed25519::yubihsm;
use self::ed25519::{softsign, Signer};
#[cfg(feature = "ledgertm")]
use self::ed25519::ledgertm;

/// File encoding for software-backed secret keys
pub type SecretKeyEncoding = subtle_encoding::Base64;
@@ -44,8 +44,8 @@ impl KeyRing {
#[cfg(feature = "yubihsm")]
yubihsm::init(&mut keyring, &config.yubihsm)?;

#[cfg(feature = "ledger")]
ledger::init(&mut keyring, &config.ledger)?;
#[cfg(feature = "ledgertm")]
ledgertm::init(&mut keyring, &config.ledgertm)?;

if keyring.0.is_empty() {
fail!(ConfigError, "no signing keys configured!")
@@ -111,7 +111,6 @@ impl KeyRing {
}
}
};
debug!("Successfully got signer and now trying to sign message");

signer.sign(msg)
}
@@ -1,15 +1,11 @@
use std::sync::Mutex;

use signatory_ledger_tm::Ed25519LedgerTmAppSigner;
use std::sync::Mutex;

// This instance is only used by CLI commands or tests

This comment has been minimized.

Copy link
@Liamsi

Liamsi Feb 19, 2019

Member

Currently not used anywhere?

lazy_static! {
static ref HSM_CLIENT: Mutex<Ed25519LedgerTmAppSigner> = Mutex::new(create_hsm_client());
}

// pub fn get_hsm_client() -> MutexGuard<'static, Ed25519CosmosAppSigner> {
// HSM_CLIENT.lock().unwrap()
// }

fn create_hsm_client() -> Ed25519LedgerTmAppSigner {

This comment has been minimized.

Copy link
@Liamsi

Liamsi Feb 19, 2019

Member

It looks like this is not used anywhere?

Ed25519LedgerTmAppSigner::connect().unwrap()
}
@@ -27,14 +27,14 @@ extern crate serde_derive;
extern crate serde_json;
extern crate sha2;
extern crate signal_hook;
extern crate subtle_encoding;
extern crate tendermint;
extern crate signatory;
extern crate signatory_dalek;
#[cfg(feature = "ledger")]
extern crate signatory_ledger_tm;
#[cfg(feature = "yubihsm")]
extern crate signatory_yubihsm;
extern crate subtle_encoding;
extern crate tendermint;
#[cfg(feature = "ledgertm")]
extern crate signatory_ledger_tm;

#[macro_use]
mod error;
@@ -44,13 +44,13 @@ mod client;
mod commands;
mod config;
mod keyring;
#[cfg(feature = "ledger")]
mod ledger;
mod rpc;
mod session;
mod unix_connection;
#[cfg(feature = "yubihsm")]
mod yubihsm;
#[cfg(feature = "ledgertm")]
mod ledgertm;

pub use crate::application::KmsApplication;
pub use crate::unix_connection::UnixConnection;
@@ -95,23 +95,11 @@ where
}
debug!("started handling request ... ");
let response = match Request::read(&mut self.connection)? {
Request::SignProposal(req) => {
debug!("got sign proposal request");
self.sign(req)?
}
Request::SignVote(req) => {
debug!("got sign vote request");
self.sign(req)?
}
Request::SignProposal(req) => self.sign(req)?,
Request::SignVote(req) => self.sign(req)?,
// non-signable requests:
Request::ReplyPing(ref req) => {
debug!("got ping request");
self.reply_ping(req)
}
Request::ShowPublicKey(ref req) => {
debug!("got pubkey request");
self.get_public_key(req)?
}
Request::ReplyPing(ref req) => self.reply_ping(req),
Request::ShowPublicKey(ref req) => self.get_public_key(req)?,
};

let mut buf = vec![];
@@ -130,12 +118,10 @@ where

/// Perform a digital signature operation
fn sign<T: TendermintRequest + Debug>(&mut self, mut request: T) -> Result<Response, KmsError> {
debug!("got sign request");
request.validate()?;

let mut to_sign = vec![];
request.sign_bytes(self.chain_id, &mut to_sign)?;
debug!("sign_bytes for request: {:?}", to_sign);

// TODO(ismail): figure out which key to use here instead of taking the only key
// from keyring here:
@@ -154,7 +140,6 @@ where

/// Get the public key for (the only) public key in the keyring
fn get_public_key(&mut self, _request: &PubKeyRequest) -> Result<Response, KmsError> {
debug!("get_public_key request");
let pubkey = KeyRing::default_pubkey()?;
let pubkey_bytes = pubkey.as_bytes();

@@ -17,3 +17,5 @@ adapter = { type = "usb" }
auth = { key = 1, password = "password" } # Default YubiHSM admin credentials. Change ASAP!
keys = [{ id = "gaia-9000", key = 1 }]
#serial_number = "0123456789" # identify serial number of a specific YubiHSM to connect to

[[providers.ledgertm]]

This comment has been minimized.

Copy link
@Liamsi

Liamsi Feb 19, 2019

Member

Is this everything that is necessary to get the ledger up and running? If not providing (all) existing options with some exemplary defaults would be cool.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.