diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 249ca40af..769db692c 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -519,6 +519,11 @@ impl AccountProvider { } } + /// Returns account public key. + pub fn account_public(&self, address: Address, password: &str) -> Result { + self.sstore.public(&self.sstore.account_ref(&address)?, password) + } + /// Returns each account along with name and meta. pub fn set_account_name(&self, address: Address, name: String) -> Result<(), Error> { self.sstore.set_name(&self.sstore.account_ref(&address)?, name)?; diff --git a/parity/configuration.rs b/parity/configuration.rs index e037defa2..09dbfeedf 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -997,8 +997,11 @@ impl Configuration { fn secretstore_self_secret(&self) -> Result, String> { match self.args.flag_secretstore_secret { - Some(ref s) => Ok(Some(NodeSecretKey::Plain(s.parse() + Some(ref s) if s.len() == 64 => Ok(Some(NodeSecretKey::Plain(s.parse() .map_err(|e| format!("Invalid secret store secret: {}. Error: {:?}", s, e))?))), + Some(ref s) if s.len() == 40 => Ok(Some(NodeSecretKey::KeyStore(s.parse() + .map_err(|e| format!("Invalid secret store secret address: {}. Error: {:?}", s, e))?))), + Some(_) => Err(format!("Invalid secret store secret. Must be either existing account address, or hex-encoded private key")), None => Ok(None), } } diff --git a/parity/run.rs b/parity/run.rs index 30f4c8759..8fc5da405 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -489,7 +489,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R } // Attempt to sign in the engine signer. - if !passwords.into_iter().any(|p| miner.set_engine_signer(engine_signer, p).is_ok()) { + if !passwords.iter().any(|p| miner.set_engine_signer(engine_signer, (*p).clone()).is_ok()) { return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT)); } } @@ -705,6 +705,8 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R // secret store key server let secretstore_deps = secretstore::Dependencies { client: client.clone(), + account_provider: account_provider, + accounts_passwords: &passwords, }; let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps)?; diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 7cdd26377..def2cd1a6 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -17,15 +17,19 @@ use std::collections::BTreeMap; use std::sync::Arc; use dir::default_data_path; +use ethcore::account_provider::AccountProvider; use ethcore::client::Client; use ethkey::{Secret, Public}; use helpers::replace_home; +use util::Address; #[derive(Debug, PartialEq, Clone)] /// This node secret key. pub enum NodeSecretKey { /// Stored as plain text in configuration file. Plain(Secret), + /// Stored as account in key store. + KeyStore(Address), } #[derive(Debug, PartialEq, Clone)] @@ -50,9 +54,13 @@ pub struct Configuration { } /// Secret store dependencies -pub struct Dependencies { +pub struct Dependencies<'a> { /// Blockchain client. pub client: Arc, + /// Account provider. + pub account_provider: Arc, + /// Passed accounts passwords. + pub accounts_passwords: &'a [String], } #[cfg(not(feature = "secretstore"))] @@ -73,7 +81,7 @@ mod server { #[cfg(feature="secretstore")] mod server { use std::sync::Arc; - use ethcore_secretstore::{self, NodeKeyPair}; + use ethcore_secretstore; use ethkey::KeyPair; use super::{Configuration, Dependencies, NodeSecretKey}; @@ -85,9 +93,27 @@ mod server { impl KeyServer { /// Create new key server pub fn new(mut conf: Configuration, deps: Dependencies) -> Result { - let self_secret = match conf.self_secret.take() { + let self_secret: Arc = match conf.self_secret.take() { Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new( KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)), + Some(NodeSecretKey::KeyStore(account)) => { + // Check if account exists + if !deps.account_provider.has_account(account.clone()).unwrap_or(false) { + return Err(format!("Account {} passed as secret store node key is not found", account)); + } + + // Check if any passwords have been read from the password file(s) + if deps.accounts_passwords.is_empty() { + return Err(format!("No password found for the secret store node account {}", account)); + } + + // Attempt to sign in the engine signer. + let password = deps.accounts_passwords.iter() + .find(|p| deps.account_provider.sign(account.clone(), Some((*p).clone()), Default::default()).is_ok()) + .ok_or(format!("No valid password for the secret store node account {}", account))?; + Arc::new(ethcore_secretstore::KeyStoreNodeKeyPair::new(deps.account_provider, account, password.clone()) + .map_err(|e| format!("{}", e))?) + }, None => return Err("self secret is required when using secretstore".into()), }; diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 8676dd16d..556625079 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use ethcrypto::ecdh::agree; use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign}; use ethcore::account_provider::AccountProvider; -use util::H256; +use util::{Address, H256}; use traits::NodeKeyPair; pub struct PlainNodeKeyPair { @@ -26,7 +26,10 @@ pub struct PlainNodeKeyPair { } pub struct KeyStoreNodeKeyPair { - _account_provider: Arc, + account_provider: Arc, + address: Address, + public: Public, + password: String, } impl PlainNodeKeyPair { @@ -52,13 +55,26 @@ impl NodeKeyPair for PlainNodeKeyPair { } } +impl KeyStoreNodeKeyPair { + pub fn new(account_provider: Arc, address: Address, password: String) -> Result { + let public = account_provider.account_public(address.clone(), &password).map_err(|e| EthKeyError::Custom(format!("{}", e)))?; + Ok(KeyStoreNodeKeyPair { + account_provider: account_provider, + address: address, + public: public, + password: password, + }) + } +} + impl NodeKeyPair for KeyStoreNodeKeyPair { fn public(&self) -> &Public { - unimplemented!() + &self.public } - fn sign(&self, _data: &H256) -> Result { - unimplemented!() + fn sign(&self, data: &H256) -> Result { + self.account_provider.sign(self.address.clone(), Some(self.password.clone()), data.clone()) + .map_err(|e| EthKeyError::Custom(format!("{}", e))) } fn compute_shared_key(&self, _peer_public: &Public) -> Result {