SecretStore: encrypt messages using private key from key store (#6146)
* do not cache ACL storage contract * when error comes before initialization * initial KeyServerSet commit * update_nodes_set in maintain * do not connect to self * fixed connection establishing * removed println * improved KeyServerSet tracing * moved parsing to KeyServerSet * re-read only when blockchain is changed * do not try to connect if not a part of cluster * improved logging * fixed tests * NodeKeyPAir trait * fixed parity to use new trait * continue integrating with parity * updated parity for NodeKeyPair * completed KeyStoreNodeKeyPair * removed comment * removed dependency && style
This commit is contained in:
		
							parent
							
								
									d209100a60
								
							
						
					
					
						commit
						33ba5b63f3
					
				| @ -519,6 +519,11 @@ impl AccountProvider { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/// Returns account public key.
 | ||||||
|  | 	pub fn account_public(&self, address: Address, password: &str) -> Result<Public, Error> { | ||||||
|  | 		self.sstore.public(&self.sstore.account_ref(&address)?, password) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/// Returns each account along with name and meta.
 | 	/// Returns each account along with name and meta.
 | ||||||
| 	pub fn set_account_name(&self, address: Address, name: String) -> Result<(), Error> { | 	pub fn set_account_name(&self, address: Address, name: String) -> Result<(), Error> { | ||||||
| 		self.sstore.set_name(&self.sstore.account_ref(&address)?, name)?; | 		self.sstore.set_name(&self.sstore.account_ref(&address)?, name)?; | ||||||
| @ -697,6 +702,13 @@ impl AccountProvider { | |||||||
| 		Ok(self.sstore.decrypt(&account, &password, shared_mac, message)?) | 		Ok(self.sstore.decrypt(&account, &password, shared_mac, message)?) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/// Agree on shared key.
 | ||||||
|  | 	pub fn agree(&self, address: Address, password: Option<String>, other_public: &Public) -> Result<Secret, SignError> { | ||||||
|  | 		let account = self.sstore.account_ref(&address)?; | ||||||
|  | 		let password = password.map(Ok).unwrap_or_else(|| self.password(&account))?; | ||||||
|  | 		Ok(self.sstore.agree(&account, &password, other_public)?) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/// Returns the underlying `SecretStore` reference if one exists.
 | 	/// Returns the underlying `SecretStore` reference if one exists.
 | ||||||
| 	pub fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> { | 	pub fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> { | ||||||
| 		self.sstore.list_geth_accounts(testnet).into_iter().map(|a| Address::from(a).into()).collect() | 		self.sstore.list_geth_accounts(testnet).into_iter().map(|a| Address::from(a).into()).collect() | ||||||
|  | |||||||
| @ -14,7 +14,8 @@ | |||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
| use ethkey::{KeyPair, sign, Address, Signature, Message, Public}; | use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret}; | ||||||
|  | use crypto::ecdh::agree; | ||||||
| use {json, Error, crypto}; | use {json, Error, crypto}; | ||||||
| use account::Version; | use account::Version; | ||||||
| use super::crypto::Crypto; | use super::crypto::Crypto; | ||||||
| @ -135,6 +136,12 @@ impl SafeAccount { | |||||||
| 		crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) | 		crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/// Agree on shared key.
 | ||||||
|  | 	pub fn agree(&self, password: &str, other: &Public) -> Result<Secret, Error> { | ||||||
|  | 		let secret = self.crypto.secret(password)?; | ||||||
|  | 		agree(&secret, other).map_err(From::from) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/// Derive public key.
 | 	/// Derive public key.
 | ||||||
| 	pub fn public(&self, password: &str) -> Result<Public, Error> { | 	pub fn public(&self, password: &str) -> Result<Public, Error> { | ||||||
| 		let secret = self.crypto.secret(password)?; | 		let secret = self.crypto.secret(password)?; | ||||||
|  | |||||||
| @ -97,6 +97,10 @@ impl SimpleSecretStore for EthStore { | |||||||
| 		self.store.sign_derived(account_ref, password, derivation, message) | 		self.store.sign_derived(account_ref, password, derivation, message) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error> { | ||||||
|  | 		self.store.agree(account, password, other) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> { | 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> { | ||||||
| 		let account = self.get(account)?; | 		let account = self.get(account)?; | ||||||
| 		account.decrypt(password, shared_mac, message) | 		account.decrypt(password, shared_mac, message) | ||||||
| @ -495,18 +499,26 @@ impl SimpleSecretStore for EthMultiStore { | |||||||
| 
 | 
 | ||||||
| 	fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result<Signature, Error> { | 	fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result<Signature, Error> { | ||||||
| 		let accounts = self.get_matching(account, password)?; | 		let accounts = self.get_matching(account, password)?; | ||||||
| 		for account in accounts { | 		match accounts.first() { | ||||||
| 			return account.sign(password, message); | 			Some(ref account) => account.sign(password, message), | ||||||
|  | 			None => Err(Error::InvalidPassword), | ||||||
| 		} | 		} | ||||||
| 		Err(Error::InvalidPassword) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> { | 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> { | ||||||
| 		let accounts = self.get_matching(account, password)?; | 		let accounts = self.get_matching(account, password)?; | ||||||
| 		for account in accounts { | 		match accounts.first() { | ||||||
| 			return account.decrypt(password, shared_mac, message); | 			Some(ref account) => account.decrypt(password, shared_mac, message), | ||||||
|  | 			None => Err(Error::InvalidPassword), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error> { | ||||||
|  | 		let accounts = self.get_matching(account, password)?; | ||||||
|  | 		match accounts.first() { | ||||||
|  | 			Some(ref account) => account.agree(password, other), | ||||||
|  | 			None => Err(Error::InvalidPassword), | ||||||
| 		} | 		} | ||||||
| 		Err(Error::InvalidPassword) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { | 	fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { | ||||||
|  | |||||||
| @ -60,6 +60,8 @@ pub trait SimpleSecretStore: Send + Sync { | |||||||
| 	fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) -> Result<Signature, Error>; | 	fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) -> Result<Signature, Error>; | ||||||
| 	/// Decrypt a messages with given account.
 | 	/// Decrypt a messages with given account.
 | ||||||
| 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error>; | 	fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error>; | ||||||
|  | 	/// Agree on shared key.
 | ||||||
|  | 	fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error>; | ||||||
| 
 | 
 | ||||||
| 	/// Returns all accounts in this secret store.
 | 	/// Returns all accounts in this secret store.
 | ||||||
| 	fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>; | 	fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>; | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ use ethcore_logger::Config as LogConfig; | |||||||
| use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; | use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; | ||||||
| use dapps::Configuration as DappsConfiguration; | use dapps::Configuration as DappsConfiguration; | ||||||
| use ipfs::Configuration as IpfsConfiguration; | use ipfs::Configuration as IpfsConfiguration; | ||||||
| use secretstore::Configuration as SecretStoreConfiguration; | use secretstore::{Configuration as SecretStoreConfiguration, NodeSecretKey}; | ||||||
| use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; | use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; | ||||||
| use run::RunCmd; | use run::RunCmd; | ||||||
| use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat}; | use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat}; | ||||||
| @ -993,10 +993,13 @@ impl Configuration { | |||||||
| 		self.interface(&self.args.flag_secretstore_http_interface) | 		self.interface(&self.args.flag_secretstore_http_interface) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn secretstore_self_secret(&self) -> Result<Option<Secret>, String> { | 	fn secretstore_self_secret(&self) -> Result<Option<NodeSecretKey>, String> { | ||||||
| 		match self.args.flag_secretstore_secret { | 		match self.args.flag_secretstore_secret { | ||||||
| 			Some(ref s) => Ok(Some(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))?)), | 				.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), | 			None => Ok(None), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -507,7 +507,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Attempt to sign in the engine signer.
 | 		// 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)); | 			return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -734,6 +734,8 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R | |||||||
| 	// secret store key server
 | 	// secret store key server
 | ||||||
| 	let secretstore_deps = secretstore::Dependencies { | 	let secretstore_deps = secretstore::Dependencies { | ||||||
| 		client: client.clone(), | 		client: client.clone(), | ||||||
|  | 		account_provider: account_provider, | ||||||
|  | 		accounts_passwords: &passwords, | ||||||
| 	}; | 	}; | ||||||
| 	let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps)?; | 	let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps)?; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,9 +17,20 @@ | |||||||
| use std::collections::BTreeMap; | use std::collections::BTreeMap; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use dir::default_data_path; | use dir::default_data_path; | ||||||
|  | use ethcore::account_provider::AccountProvider; | ||||||
| use ethcore::client::Client; | use ethcore::client::Client; | ||||||
| use ethkey::{Secret, Public}; | use ethkey::{Secret, Public}; | ||||||
| use helpers::replace_home; | 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)] | #[derive(Debug, PartialEq, Clone)] | ||||||
| /// Secret store configuration
 | /// Secret store configuration
 | ||||||
| @ -27,7 +38,7 @@ pub struct Configuration { | |||||||
| 	/// Is secret store functionality enabled?
 | 	/// Is secret store functionality enabled?
 | ||||||
| 	pub enabled: bool, | 	pub enabled: bool, | ||||||
| 	/// This node secret.
 | 	/// This node secret.
 | ||||||
| 	pub self_secret: Option<Secret>, | 	pub self_secret: Option<NodeSecretKey>, | ||||||
| 	/// Other nodes IDs + addresses.
 | 	/// Other nodes IDs + addresses.
 | ||||||
| 	pub nodes: BTreeMap<Public, (String, u16)>, | 	pub nodes: BTreeMap<Public, (String, u16)>, | ||||||
| 	/// Interface to listen to
 | 	/// Interface to listen to
 | ||||||
| @ -43,9 +54,13 @@ pub struct Configuration { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Secret store dependencies
 | /// Secret store dependencies
 | ||||||
| pub struct Dependencies { | pub struct Dependencies<'a> { | ||||||
| 	/// Blockchain client.
 | 	/// Blockchain client.
 | ||||||
| 	pub client: Arc<Client>, | 	pub client: Arc<Client>, | ||||||
|  | 	/// Account provider.
 | ||||||
|  | 	pub account_provider: Arc<AccountProvider>, | ||||||
|  | 	/// Passed accounts passwords.
 | ||||||
|  | 	pub accounts_passwords: &'a [String], | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(not(feature = "secretstore"))] | #[cfg(not(feature = "secretstore"))] | ||||||
| @ -65,9 +80,10 @@ mod server { | |||||||
| 
 | 
 | ||||||
| #[cfg(feature="secretstore")] | #[cfg(feature="secretstore")] | ||||||
| mod server { | mod server { | ||||||
|  | 	use std::sync::Arc; | ||||||
| 	use ethcore_secretstore; | 	use ethcore_secretstore; | ||||||
| 	use ethkey::KeyPair; | 	use ethkey::KeyPair; | ||||||
| 	use super::{Configuration, Dependencies}; | 	use super::{Configuration, Dependencies, NodeSecretKey}; | ||||||
| 
 | 
 | ||||||
| 	/// Key server
 | 	/// Key server
 | ||||||
| 	pub struct KeyServer { | 	pub struct KeyServer { | ||||||
| @ -76,8 +92,31 @@ mod server { | |||||||
| 
 | 
 | ||||||
| 	impl KeyServer { | 	impl KeyServer { | ||||||
| 		/// Create new key server
 | 		/// Create new key server
 | ||||||
| 		pub fn new(conf: Configuration, deps: Dependencies) -> Result<Self, String> { | 		pub fn new(mut conf: Configuration, deps: Dependencies) -> Result<Self, String> { | ||||||
| 			let self_secret = conf.self_secret.ok_or("self secret is required when using secretstore")?; | 			let self_secret: Arc<ethcore_secretstore::NodeKeyPair> = 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()), | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
| 			let mut conf = ethcore_secretstore::ServiceConfiguration { | 			let mut conf = ethcore_secretstore::ServiceConfiguration { | ||||||
| 				listener_address: ethcore_secretstore::NodeAddress { | 				listener_address: ethcore_secretstore::NodeAddress { | ||||||
| 					address: conf.http_interface.clone(), | 					address: conf.http_interface.clone(), | ||||||
| @ -86,7 +125,6 @@ mod server { | |||||||
| 				data_path: conf.data_path.clone(), | 				data_path: conf.data_path.clone(), | ||||||
| 				cluster_config: ethcore_secretstore::ClusterConfiguration { | 				cluster_config: ethcore_secretstore::ClusterConfiguration { | ||||||
| 					threads: 4, | 					threads: 4, | ||||||
| 					self_private: (**self_secret).into(), |  | ||||||
| 					listener_address: ethcore_secretstore::NodeAddress { | 					listener_address: ethcore_secretstore::NodeAddress { | ||||||
| 						address: conf.interface.clone(), | 						address: conf.interface.clone(), | ||||||
| 						port: conf.port, | 						port: conf.port, | ||||||
| @ -99,11 +137,9 @@ mod server { | |||||||
| 				}, | 				}, | ||||||
| 			}; | 			}; | ||||||
| 
 | 
 | ||||||
| 			let self_key_pair = KeyPair::from_secret(self_secret.clone()) | 			conf.cluster_config.nodes.insert(self_secret.public().clone(), conf.cluster_config.listener_address.clone()); | ||||||
| 				.map_err(|e| format!("valid secret is required when using secretstore. Error: {}", e))?; |  | ||||||
| 			conf.cluster_config.nodes.insert(self_key_pair.public().clone(), conf.cluster_config.listener_address.clone()); |  | ||||||
| 
 | 
 | ||||||
| 			let key_server = ethcore_secretstore::start(deps.client, conf) | 			let key_server = ethcore_secretstore::start(deps.client, self_secret, conf) | ||||||
| 				.map_err(Into::<String>::into)?; | 				.map_err(Into::<String>::into)?; | ||||||
| 
 | 
 | ||||||
| 			Ok(KeyServer { | 			Ok(KeyServer { | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ use super::acl_storage::AclStorage; | |||||||
| use super::key_storage::KeyStorage; | use super::key_storage::KeyStorage; | ||||||
| use super::key_server_set::KeyServerSet; | use super::key_server_set::KeyServerSet; | ||||||
| use key_server_cluster::{math, ClusterCore}; | use key_server_cluster::{math, ClusterCore}; | ||||||
| use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer}; | use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair}; | ||||||
| use types::all::{Error, Public, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, | use types::all::{Error, Public, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, | ||||||
| 	ClusterConfiguration, MessageHash, EncryptedMessageSignature}; | 	ClusterConfiguration, MessageHash, EncryptedMessageSignature}; | ||||||
| use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; | use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; | ||||||
| @ -45,9 +45,9 @@ pub struct KeyServerCore { | |||||||
| 
 | 
 | ||||||
| impl KeyServerImpl { | impl KeyServerImpl { | ||||||
| 	/// Create new key server instance
 | 	/// Create new key server instance
 | ||||||
| 	pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>) -> Result<Self, Error> { | 	pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, self_key_pair: Arc<NodeKeyPair>, acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>) -> Result<Self, Error> { | ||||||
| 		Ok(KeyServerImpl { | 		Ok(KeyServerImpl { | ||||||
| 			data: Arc::new(Mutex::new(KeyServerCore::new(config, key_server_set, acl_storage, key_storage)?)), | 			data: Arc::new(Mutex::new(KeyServerCore::new(config, key_server_set, self_key_pair, acl_storage, key_storage)?)), | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -144,10 +144,10 @@ impl MessageSigner for KeyServerImpl { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl KeyServerCore { | impl KeyServerCore { | ||||||
| 	pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>) -> Result<Self, Error> { | 	pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, self_key_pair: Arc<NodeKeyPair>, acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>) -> Result<Self, Error> { | ||||||
| 		let config = NetClusterConfiguration { | 		let config = NetClusterConfiguration { | ||||||
| 			threads: config.threads, | 			threads: config.threads, | ||||||
| 			self_key_pair: ethkey::KeyPair::from_secret_slice(&config.self_private)?, | 			self_key_pair: self_key_pair, | ||||||
| 			listen_address: (config.listener_address.address.clone(), config.listener_address.port), | 			listen_address: (config.listener_address.address.clone(), config.listener_address.port), | ||||||
| 			key_server_set: key_server_set, | 			key_server_set: key_server_set, | ||||||
| 			allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes, | 			allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes, | ||||||
| @ -198,6 +198,7 @@ pub mod tests { | |||||||
| 	use ethkey::{self, Secret, Random, Generator}; | 	use ethkey::{self, Secret, Random, Generator}; | ||||||
| 	use acl_storage::tests::DummyAclStorage; | 	use acl_storage::tests::DummyAclStorage; | ||||||
| 	use key_storage::tests::DummyKeyStorage; | 	use key_storage::tests::DummyKeyStorage; | ||||||
|  | 	use node_key_pair::PlainNodeKeyPair; | ||||||
| 	use key_server_set::tests::MapKeyServerSet; | 	use key_server_set::tests::MapKeyServerSet; | ||||||
| 	use key_server_cluster::math; | 	use key_server_cluster::math; | ||||||
| 	use util::H256; | 	use util::H256; | ||||||
| @ -244,7 +245,6 @@ pub mod tests { | |||||||
| 		let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect(); | 		let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect(); | ||||||
| 		let configs: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration { | 		let configs: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration { | ||||||
| 				threads: 1, | 				threads: 1, | ||||||
| 				self_private: (***key_pairs[i].secret()).into(), |  | ||||||
| 				listener_address: NodeAddress { | 				listener_address: NodeAddress { | ||||||
| 					address: "127.0.0.1".into(), | 					address: "127.0.0.1".into(), | ||||||
| 					port: start_port + (i as u16), | 					port: start_port + (i as u16), | ||||||
| @ -259,8 +259,11 @@ pub mod tests { | |||||||
| 		let key_servers_set: BTreeMap<Public, SocketAddr> = configs[0].nodes.iter() | 		let key_servers_set: BTreeMap<Public, SocketAddr> = configs[0].nodes.iter() | ||||||
| 			.map(|(k, a)| (k.clone(), format!("{}:{}", a.address, a.port).parse().unwrap())) | 			.map(|(k, a)| (k.clone(), format!("{}:{}", a.address, a.port).parse().unwrap())) | ||||||
| 			.collect(); | 			.collect(); | ||||||
| 		let key_servers: Vec<_> = configs.into_iter().map(|cfg| | 		let key_servers: Vec<_> = configs.into_iter().enumerate().map(|(i, cfg)| | ||||||
| 			KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(key_servers_set.clone())), Arc::new(DummyAclStorage::default()), Arc::new(DummyKeyStorage::default())).unwrap() | 			KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(key_servers_set.clone())), | ||||||
|  | 				Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())), | ||||||
|  | 				Arc::new(DummyAclStorage::default()), | ||||||
|  | 				Arc::new(DummyKeyStorage::default())).unwrap() | ||||||
| 		).collect(); | 		).collect(); | ||||||
| 
 | 
 | ||||||
| 		// wait until connections are established. It is fast => do not bother with events here
 | 		// wait until connections are established. It is fast => do not bother with events here
 | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ use tokio_core::reactor::{Handle, Remote, Interval}; | |||||||
| use tokio_core::net::{TcpListener, TcpStream}; | use tokio_core::net::{TcpListener, TcpStream}; | ||||||
| use ethkey::{Public, KeyPair, Signature, Random, Generator}; | use ethkey::{Public, KeyPair, Signature, Random, Generator}; | ||||||
| use util::H256; | use util::H256; | ||||||
| use key_server_cluster::{Error, NodeId, SessionId, AclStorage, KeyStorage, KeyServerSet}; | use key_server_cluster::{Error, NodeId, SessionId, AclStorage, KeyStorage, KeyServerSet, NodeKeyPair}; | ||||||
| use key_server_cluster::cluster_sessions::{ClusterSession, ClusterSessions, GenerationSessionWrapper, EncryptionSessionWrapper, | use key_server_cluster::cluster_sessions::{ClusterSession, ClusterSessions, GenerationSessionWrapper, EncryptionSessionWrapper, | ||||||
| 	DecryptionSessionWrapper, SigningSessionWrapper}; | 	DecryptionSessionWrapper, SigningSessionWrapper}; | ||||||
| use key_server_cluster::message::{self, Message, ClusterMessage, GenerationMessage, EncryptionMessage, DecryptionMessage, | use key_server_cluster::message::{self, Message, ClusterMessage, GenerationMessage, EncryptionMessage, DecryptionMessage, | ||||||
| @ -99,7 +99,7 @@ pub struct ClusterConfiguration { | |||||||
| 	/// Allow connecting to 'higher' nodes.
 | 	/// Allow connecting to 'higher' nodes.
 | ||||||
| 	pub allow_connecting_to_higher_nodes: bool, | 	pub allow_connecting_to_higher_nodes: bool, | ||||||
| 	/// KeyPair this node holds.
 | 	/// KeyPair this node holds.
 | ||||||
| 	pub self_key_pair: KeyPair, | 	pub self_key_pair: Arc<NodeKeyPair>, | ||||||
| 	/// Interface to listen to.
 | 	/// Interface to listen to.
 | ||||||
| 	pub listen_address: (String, u16), | 	pub listen_address: (String, u16), | ||||||
| 	/// Cluster nodes set.
 | 	/// Cluster nodes set.
 | ||||||
| @ -146,7 +146,7 @@ pub struct ClusterData { | |||||||
| 	/// Handle to the cpu thread pool.
 | 	/// Handle to the cpu thread pool.
 | ||||||
| 	pool: CpuPool, | 	pool: CpuPool, | ||||||
| 	/// KeyPair this node holds.
 | 	/// KeyPair this node holds.
 | ||||||
| 	self_key_pair: KeyPair, | 	self_key_pair: Arc<NodeKeyPair>, | ||||||
| 	/// Connections data.
 | 	/// Connections data.
 | ||||||
| 	connections: ClusterConnections, | 	connections: ClusterConnections, | ||||||
| 	/// Active sessions data.
 | 	/// Active sessions data.
 | ||||||
| @ -989,7 +989,7 @@ pub mod tests { | |||||||
| 	use parking_lot::Mutex; | 	use parking_lot::Mutex; | ||||||
| 	use tokio_core::reactor::Core; | 	use tokio_core::reactor::Core; | ||||||
| 	use ethkey::{Random, Generator, Public}; | 	use ethkey::{Random, Generator, Public}; | ||||||
| 	use key_server_cluster::{NodeId, SessionId, Error, DummyAclStorage, DummyKeyStorage, MapKeyServerSet}; | 	use key_server_cluster::{NodeId, SessionId, Error, DummyAclStorage, DummyKeyStorage, MapKeyServerSet, PlainNodeKeyPair}; | ||||||
| 	use key_server_cluster::message::Message; | 	use key_server_cluster::message::Message; | ||||||
| 	use key_server_cluster::cluster::{Cluster, ClusterCore, ClusterConfiguration}; | 	use key_server_cluster::cluster::{Cluster, ClusterCore, ClusterConfiguration}; | ||||||
| 	use key_server_cluster::generation_session::{Session as GenerationSession, SessionState as GenerationSessionState}; | 	use key_server_cluster::generation_session::{Session as GenerationSession, SessionState as GenerationSessionState}; | ||||||
| @ -1068,7 +1068,7 @@ pub mod tests { | |||||||
| 		let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect(); | 		let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect(); | ||||||
| 		let cluster_params: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration { | 		let cluster_params: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration { | ||||||
| 			threads: 1, | 			threads: 1, | ||||||
| 			self_key_pair: key_pairs[i].clone(), | 			self_key_pair: Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())), | ||||||
| 			listen_address: ("127.0.0.1".to_owned(), ports_begin + i as u16), | 			listen_address: ("127.0.0.1".to_owned(), ports_begin + i as u16), | ||||||
| 			key_server_set: Arc::new(MapKeyServerSet::new(key_pairs.iter().enumerate() | 			key_server_set: Arc::new(MapKeyServerSet::new(key_pairs.iter().enumerate() | ||||||
| 				.map(|(j, kp)| (kp.public().clone(), format!("127.0.0.1:{}", ports_begin + j as u16).parse().unwrap())) | 				.map(|(j, kp)| (kp.public().clone(), format!("127.0.0.1:{}", ports_begin + j as u16).parse().unwrap())) | ||||||
|  | |||||||
| @ -15,24 +15,25 @@ | |||||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
| use std::io; | use std::io; | ||||||
|  | use std::sync::Arc; | ||||||
| use std::collections::BTreeSet; | use std::collections::BTreeSet; | ||||||
| use futures::{Future, Poll, Async}; | use futures::{Future, Poll, Async}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| use ethkey::{Random, Generator, KeyPair, Secret, sign, verify_public}; | use ethkey::{Random, Generator, KeyPair, verify_public}; | ||||||
| use util::H256; | use util::H256; | ||||||
| use key_server_cluster::{NodeId, Error}; | use key_server_cluster::{NodeId, Error, NodeKeyPair}; | ||||||
| use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; | use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; | ||||||
| use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage, | use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage, | ||||||
| 	read_message, read_encrypted_message, compute_shared_key}; | 	read_message, read_encrypted_message, fix_shared_key}; | ||||||
| 
 | 
 | ||||||
| /// Start handshake procedure with another node from the cluster.
 | /// Start handshake procedure with another node from the cluster.
 | ||||||
| pub fn handshake<A>(a: A, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead { | pub fn handshake<A>(a: A, self_key_pair: Arc<NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead { | ||||||
| 	let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); | 	let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); | ||||||
| 	handshake_with_plain_confirmation(a, self_confirmation_plain, self_key_pair, trusted_nodes) | 	handshake_with_plain_confirmation(a, self_confirmation_plain, self_key_pair, trusted_nodes) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Start handshake procedure with another node from the cluster and given plain confirmation.
 | /// Start handshake procedure with another node from the cluster and given plain confirmation.
 | ||||||
| pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Result<H256, Error>, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead { | pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Result<H256, Error>, self_key_pair: Arc<NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead { | ||||||
| 	let (error, state) = match self_confirmation_plain.clone() | 	let (error, state) = match self_confirmation_plain.clone() | ||||||
| 		.and_then(|c| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), c)) { | 		.and_then(|c| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), c)) { | ||||||
| 		Ok(message) => (None, HandshakeState::SendPublicKey(write_message(a, message))), | 		Ok(message) => (None, HandshakeState::SendPublicKey(write_message(a, message))), | ||||||
| @ -53,7 +54,7 @@ pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Resul | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Wait for handshake procedure to be started by another node from the cluster.
 | /// Wait for handshake procedure to be started by another node from the cluster.
 | ||||||
| pub fn accept_handshake<A>(a: A, self_key_pair: KeyPair) -> Handshake<A> where A: AsyncWrite + AsyncRead { | pub fn accept_handshake<A>(a: A, self_key_pair: Arc<NodeKeyPair>) -> Handshake<A> where A: AsyncWrite + AsyncRead { | ||||||
| 	let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); | 	let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); | ||||||
| 	let (error, state) = match self_confirmation_plain.clone() { | 	let (error, state) = match self_confirmation_plain.clone() { | ||||||
| 		Ok(_) => (None, HandshakeState::ReceivePublicKey(read_message(a))), | 		Ok(_) => (None, HandshakeState::ReceivePublicKey(read_message(a))), | ||||||
| @ -87,7 +88,7 @@ pub struct Handshake<A> { | |||||||
| 	is_active: bool, | 	is_active: bool, | ||||||
| 	error: Option<(A, Result<HandshakeResult, Error>)>, | 	error: Option<(A, Result<HandshakeResult, Error>)>, | ||||||
| 	state: HandshakeState<A>, | 	state: HandshakeState<A>, | ||||||
| 	self_key_pair: KeyPair, | 	self_key_pair: Arc<NodeKeyPair>, | ||||||
| 	self_confirmation_plain: H256, | 	self_confirmation_plain: H256, | ||||||
| 	trusted_nodes: Option<BTreeSet<NodeId>>, | 	trusted_nodes: Option<BTreeSet<NodeId>>, | ||||||
| 	other_node_id: Option<NodeId>, | 	other_node_id: Option<NodeId>, | ||||||
| @ -117,9 +118,9 @@ impl<A> Handshake<A> where A: AsyncRead + AsyncWrite { | |||||||
| 		}))) | 		}))) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn make_private_key_signature_message(secret: &Secret, confirmation_plain: &H256) -> Result<Message, Error> { | 	fn make_private_key_signature_message(self_key_pair: &NodeKeyPair, confirmation_plain: &H256) -> Result<Message, Error> { | ||||||
| 		Ok(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature { | 		Ok(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature { | ||||||
| 			confirmation_signed: sign(secret, confirmation_plain)?.into(), | 			confirmation_signed: self_key_pair.sign(confirmation_plain)?.into(), | ||||||
| 		}))) | 		}))) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -142,15 +143,15 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite { | |||||||
| 						read_message(stream) | 						read_message(stream) | ||||||
| 					), Async::NotReady) | 					), Async::NotReady) | ||||||
| 				} else { | 				} else { | ||||||
| 					self.shared_key = match compute_shared_key(self.self_key_pair.secret(), | 					self.shared_key = match self.self_key_pair.compute_shared_key( | ||||||
| 						self.other_node_id.as_ref().expect("we are in passive mode; in passive mode SendPublicKey follows ReceivePublicKey; other_node_id is filled in ReceivePublicKey; qed") | 						self.other_node_id.as_ref().expect("we are in passive mode; in passive mode SendPublicKey follows ReceivePublicKey; other_node_id is filled in ReceivePublicKey; qed") | ||||||
| 					) { | 					).map_err(Into::into).and_then(|sk| fix_shared_key(sk.secret())) { | ||||||
| 						Ok(shared_key) => Some(shared_key), | 						Ok(shared_key) => Some(shared_key), | ||||||
| 						Err(err) => return Ok((stream, Err(err)).into()), | 						Err(err) => return Ok((stream, Err(err.into())).into()), | ||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
| 					let message = match Handshake::<A>::make_private_key_signature_message( | 					let message = match Handshake::<A>::make_private_key_signature_message( | ||||||
| 						self.self_key_pair.secret(), | 						&*self.self_key_pair, | ||||||
| 						self.other_confirmation_plain.as_ref().expect("we are in passive mode; in passive mode SendPublicKey follows ReceivePublicKey; other_confirmation_plain is filled in ReceivePublicKey; qed") | 						self.other_confirmation_plain.as_ref().expect("we are in passive mode; in passive mode SendPublicKey follows ReceivePublicKey; other_confirmation_plain is filled in ReceivePublicKey; qed") | ||||||
| 					) { | 					) { | ||||||
| 						Ok(message) => message, | 						Ok(message) => message, | ||||||
| @ -179,15 +180,15 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite { | |||||||
| 				self.other_node_id = Some(message.node_id.into()); | 				self.other_node_id = Some(message.node_id.into()); | ||||||
| 				self.other_confirmation_plain = Some(message.confirmation_plain.into()); | 				self.other_confirmation_plain = Some(message.confirmation_plain.into()); | ||||||
| 				if self.is_active { | 				if self.is_active { | ||||||
| 					self.shared_key = match compute_shared_key(self.self_key_pair.secret(), | 					self.shared_key = match self.self_key_pair.compute_shared_key( | ||||||
| 						self.other_node_id.as_ref().expect("filled couple of lines above; qed") | 						self.other_node_id.as_ref().expect("filled couple of lines above; qed") | ||||||
| 					) { | 					).map_err(Into::into).and_then(|sk| fix_shared_key(sk.secret())) { | ||||||
| 						Ok(shared_key) => Some(shared_key), | 						Ok(shared_key) => Some(shared_key), | ||||||
| 						Err(err) => return Ok((stream, Err(err)).into()), | 						Err(err) => return Ok((stream, Err(err.into())).into()), | ||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
| 					let message = match Handshake::<A>::make_private_key_signature_message( | 					let message = match Handshake::<A>::make_private_key_signature_message( | ||||||
| 						self.self_key_pair.secret(), | 						&*self.self_key_pair, | ||||||
| 						self.other_confirmation_plain.as_ref().expect("filled couple of lines above; qed") | 						self.other_confirmation_plain.as_ref().expect("filled couple of lines above; qed") | ||||||
| 					) { | 					) { | ||||||
| 						Ok(message) => message, | 						Ok(message) => message, | ||||||
| @ -248,11 +249,14 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|  | 	use std::sync::Arc; | ||||||
| 	use std::collections::BTreeSet; | 	use std::collections::BTreeSet; | ||||||
| 	use futures::Future; | 	use futures::Future; | ||||||
| 	use ethkey::{Random, Generator, sign}; | 	use ethkey::{Random, Generator, sign}; | ||||||
|  | 	use ethcrypto::ecdh::agree; | ||||||
| 	use util::H256; | 	use util::H256; | ||||||
| 	use key_server_cluster::io::message::compute_shared_key; | 	use key_server_cluster::PlainNodeKeyPair; | ||||||
|  | 	use key_server_cluster::io::message::fix_shared_key; | ||||||
| 	use key_server_cluster::io::message::tests::TestIo; | 	use key_server_cluster::io::message::tests::TestIo; | ||||||
| 	use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; | 	use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; | ||||||
| 	use super::{handshake_with_plain_confirmation, accept_handshake, HandshakeResult}; | 	use super::{handshake_with_plain_confirmation, accept_handshake, HandshakeResult}; | ||||||
| @ -283,9 +287,9 @@ mod tests { | |||||||
| 		let (self_confirmation_plain, io) = prepare_test_io(); | 		let (self_confirmation_plain, io) = prepare_test_io(); | ||||||
| 		let self_key_pair = io.self_key_pair().clone(); | 		let self_key_pair = io.self_key_pair().clone(); | ||||||
| 		let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); | 		let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); | ||||||
| 		let shared_key = compute_shared_key(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap(); | 		let shared_key = fix_shared_key(&agree(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap()).unwrap(); | ||||||
| 
 | 
 | ||||||
| 		let handshake = handshake_with_plain_confirmation(io, Ok(self_confirmation_plain), self_key_pair, trusted_nodes); | 		let handshake = handshake_with_plain_confirmation(io, Ok(self_confirmation_plain), Arc::new(PlainNodeKeyPair::new(self_key_pair)), trusted_nodes); | ||||||
| 		let handshake_result = handshake.wait().unwrap(); | 		let handshake_result = handshake.wait().unwrap(); | ||||||
| 		assert_eq!(handshake_result.1, Ok(HandshakeResult { | 		assert_eq!(handshake_result.1, Ok(HandshakeResult { | ||||||
| 			node_id: handshake_result.0.peer_public().clone(), | 			node_id: handshake_result.0.peer_public().clone(), | ||||||
| @ -298,9 +302,9 @@ mod tests { | |||||||
| 		let (self_confirmation_plain, io) = prepare_test_io(); | 		let (self_confirmation_plain, io) = prepare_test_io(); | ||||||
| 		let self_key_pair = io.self_key_pair().clone(); | 		let self_key_pair = io.self_key_pair().clone(); | ||||||
| 		let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); | 		let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); | ||||||
| 		let shared_key = compute_shared_key(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap(); | 		let shared_key = fix_shared_key(&agree(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap()).unwrap(); | ||||||
| 
 | 
 | ||||||
| 		let mut handshake = accept_handshake(io, self_key_pair); | 		let mut handshake = accept_handshake(io, Arc::new(PlainNodeKeyPair::new(self_key_pair))); | ||||||
| 		handshake.set_self_confirmation_plain(self_confirmation_plain); | 		handshake.set_self_confirmation_plain(self_confirmation_plain); | ||||||
| 
 | 
 | ||||||
| 		let handshake_result = handshake.wait().unwrap(); | 		let handshake_result = handshake.wait().unwrap(); | ||||||
|  | |||||||
| @ -19,9 +19,8 @@ use std::u16; | |||||||
| use std::ops::Deref; | use std::ops::Deref; | ||||||
| use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; | ||||||
| use serde_json; | use serde_json; | ||||||
| use ethcrypto::ecdh::agree; |  | ||||||
| use ethcrypto::ecies::{encrypt_single_message, decrypt_single_message}; | use ethcrypto::ecies::{encrypt_single_message, decrypt_single_message}; | ||||||
| use ethkey::{Public, Secret, KeyPair}; | use ethkey::{Secret, KeyPair}; | ||||||
| use ethkey::math::curve_order; | use ethkey::math::curve_order; | ||||||
| use util::{H256, U256}; | use util::{H256, U256}; | ||||||
| use key_server_cluster::Error; | use key_server_cluster::Error; | ||||||
| @ -154,12 +153,11 @@ pub fn decrypt_message(key: &KeyPair, payload: Vec<u8>) -> Result<Vec<u8>, Error | |||||||
| 	Ok(decrypt_single_message(key.secret(), &payload)?) | 	Ok(decrypt_single_message(key.secret(), &payload)?) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Compute shared encryption key.
 | /// Fix shared encryption key.
 | ||||||
| pub fn compute_shared_key(self_secret: &Secret, other_public: &Public) -> Result<KeyPair, Error> { | pub fn fix_shared_key(shared_secret: &Secret) -> Result<KeyPair, Error> { | ||||||
| 	// secret key created in agree function is invalid, as it is not calculated mod EC.field.n
 | 	// secret key created in agree function is invalid, as it is not calculated mod EC.field.n
 | ||||||
| 	// => let's do it manually
 | 	// => let's do it manually
 | ||||||
| 	let shared_secret = agree(self_secret, other_public)?; | 	let shared_secret: H256 = (**shared_secret).into(); | ||||||
| 	let shared_secret: H256 = (*shared_secret).into(); |  | ||||||
| 	let shared_secret: U256 = shared_secret.into(); | 	let shared_secret: U256 = shared_secret.into(); | ||||||
| 	let shared_secret: H256 = (shared_secret % curve_order()).into(); | 	let shared_secret: H256 = (shared_secret % curve_order()).into(); | ||||||
| 	let shared_key_pair = KeyPair::from_secret_slice(&*shared_secret)?; | 	let shared_key_pair = KeyPair::from_secret_slice(&*shared_secret)?; | ||||||
| @ -204,8 +202,9 @@ pub mod tests { | |||||||
| 	use futures::Poll; | 	use futures::Poll; | ||||||
| 	use tokio_io::{AsyncRead, AsyncWrite}; | 	use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| 	use ethkey::{KeyPair, Public}; | 	use ethkey::{KeyPair, Public}; | ||||||
|  | 	use ethcrypto::ecdh::agree; | ||||||
| 	use key_server_cluster::message::Message; | 	use key_server_cluster::message::Message; | ||||||
| 	use super::{MESSAGE_HEADER_SIZE, MessageHeader, compute_shared_key, encrypt_message, serialize_message, | 	use super::{MESSAGE_HEADER_SIZE, MessageHeader, fix_shared_key, encrypt_message, serialize_message, | ||||||
| 		serialize_header, deserialize_header}; | 		serialize_header, deserialize_header}; | ||||||
| 
 | 
 | ||||||
| 	pub struct TestIo { | 	pub struct TestIo { | ||||||
| @ -217,7 +216,7 @@ pub mod tests { | |||||||
| 
 | 
 | ||||||
| 	impl TestIo { | 	impl TestIo { | ||||||
| 		pub fn new(self_key_pair: KeyPair, peer_public: Public) -> Self { | 		pub fn new(self_key_pair: KeyPair, peer_public: Public) -> Self { | ||||||
| 			let shared_key_pair = compute_shared_key(self_key_pair.secret(), &peer_public).unwrap(); | 			let shared_key_pair = fix_shared_key(&agree(self_key_pair.secret(), &peer_public).unwrap()).unwrap(); | ||||||
| 			TestIo { | 			TestIo { | ||||||
| 				self_key_pair: self_key_pair, | 				self_key_pair: self_key_pair, | ||||||
| 				peer_public: peer_public, | 				peer_public: peer_public, | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ mod write_message; | |||||||
| pub use self::deadline::{deadline, Deadline, DeadlineStatus}; | pub use self::deadline::{deadline, Deadline, DeadlineStatus}; | ||||||
| pub use self::handshake::{handshake, accept_handshake, Handshake, HandshakeResult}; | pub use self::handshake::{handshake, accept_handshake, Handshake, HandshakeResult}; | ||||||
| pub use self::message::{MessageHeader, SerializedMessage, serialize_message, deserialize_message, | pub use self::message::{MessageHeader, SerializedMessage, serialize_message, deserialize_message, | ||||||
| 	encrypt_message, compute_shared_key}; | 	encrypt_message, fix_shared_key}; | ||||||
| pub use self::read_header::{read_header, ReadHeader}; | pub use self::read_header::{read_header, ReadHeader}; | ||||||
| pub use self::read_payload::{read_payload, read_encrypted_payload, ReadPayload}; | pub use self::read_payload::{read_payload, read_encrypted_payload, ReadPayload}; | ||||||
| pub use self::read_message::{read_message, read_encrypted_message, ReadMessage}; | pub use self::read_message::{read_message, read_encrypted_message, ReadMessage}; | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ use ethkey; | |||||||
| use ethcrypto; | use ethcrypto; | ||||||
| use super::types::all::ServerKeyId; | use super::types::all::ServerKeyId; | ||||||
| 
 | 
 | ||||||
|  | pub use super::traits::NodeKeyPair; | ||||||
| pub use super::types::all::{NodeId, EncryptedDocumentKeyShadow}; | pub use super::types::all::{NodeId, EncryptedDocumentKeyShadow}; | ||||||
| pub use super::acl_storage::AclStorage; | pub use super::acl_storage::AclStorage; | ||||||
| pub use super::key_storage::{KeyStorage, DocumentKeyShare}; | pub use super::key_storage::{KeyStorage, DocumentKeyShare}; | ||||||
| @ -30,6 +31,8 @@ pub use self::generation_session::Session as GenerationSession; | |||||||
| pub use self::encryption_session::Session as EncryptionSession; | pub use self::encryption_session::Session as EncryptionSession; | ||||||
| pub use self::decryption_session::Session as DecryptionSession; | pub use self::decryption_session::Session as DecryptionSession; | ||||||
| 
 | 
 | ||||||
|  | #[cfg(test)] | ||||||
|  | pub use super::node_key_pair::PlainNodeKeyPair; | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| pub use super::key_storage::tests::DummyKeyStorage; | pub use super::key_storage::tests::DummyKeyStorage; | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
|  | |||||||
| @ -15,18 +15,18 @@ | |||||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
| use std::io; | use std::io; | ||||||
|  | use std::sync::Arc; | ||||||
| use std::net::SocketAddr; | use std::net::SocketAddr; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| use futures::{Future, Poll}; | use futures::{Future, Poll}; | ||||||
| use tokio_core::reactor::Handle; | use tokio_core::reactor::Handle; | ||||||
| use tokio_core::net::TcpStream; | use tokio_core::net::TcpStream; | ||||||
| use ethkey::KeyPair; | use key_server_cluster::{Error, NodeKeyPair}; | ||||||
| use key_server_cluster::Error; |  | ||||||
| use key_server_cluster::io::{accept_handshake, Handshake, Deadline, deadline}; | use key_server_cluster::io::{accept_handshake, Handshake, Deadline, deadline}; | ||||||
| use key_server_cluster::net::Connection; | use key_server_cluster::net::Connection; | ||||||
| 
 | 
 | ||||||
| /// Create future for accepting incoming connection.
 | /// Create future for accepting incoming connection.
 | ||||||
| pub fn accept_connection(address: SocketAddr, stream: TcpStream, handle: &Handle, self_key_pair: KeyPair) -> Deadline<AcceptConnection> { | pub fn accept_connection(address: SocketAddr, stream: TcpStream, handle: &Handle, self_key_pair: Arc<NodeKeyPair>) -> Deadline<AcceptConnection> { | ||||||
| 	let accept = AcceptConnection { | 	let accept = AcceptConnection { | ||||||
| 		handshake: accept_handshake(stream, self_key_pair), | 		handshake: accept_handshake(stream, self_key_pair), | ||||||
| 		address: address, | 		address: address, | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
|  | use std::sync::Arc; | ||||||
| use std::collections::BTreeSet; | use std::collections::BTreeSet; | ||||||
| use std::io; | use std::io; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| @ -21,13 +22,12 @@ use std::net::SocketAddr; | |||||||
| use futures::{Future, Poll, Async}; | use futures::{Future, Poll, Async}; | ||||||
| use tokio_core::reactor::Handle; | use tokio_core::reactor::Handle; | ||||||
| use tokio_core::net::{TcpStream, TcpStreamNew}; | use tokio_core::net::{TcpStream, TcpStreamNew}; | ||||||
| use ethkey::KeyPair; | use key_server_cluster::{Error, NodeId, NodeKeyPair}; | ||||||
| use key_server_cluster::{Error, NodeId}; |  | ||||||
| use key_server_cluster::io::{handshake, Handshake, Deadline, deadline}; | use key_server_cluster::io::{handshake, Handshake, Deadline, deadline}; | ||||||
| use key_server_cluster::net::Connection; | use key_server_cluster::net::Connection; | ||||||
| 
 | 
 | ||||||
| /// Create future for connecting to other node.
 | /// Create future for connecting to other node.
 | ||||||
| pub fn connect(address: &SocketAddr, handle: &Handle, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Deadline<Connect> { | pub fn connect(address: &SocketAddr, handle: &Handle, self_key_pair: Arc<NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Deadline<Connect> { | ||||||
| 	let connect = Connect { | 	let connect = Connect { | ||||||
| 		state: ConnectState::TcpConnect(TcpStream::connect(address, handle)), | 		state: ConnectState::TcpConnect(TcpStream::connect(address, handle)), | ||||||
| 		address: address.clone(), | 		address: address.clone(), | ||||||
| @ -48,7 +48,7 @@ enum ConnectState { | |||||||
| pub struct Connect { | pub struct Connect { | ||||||
| 	state: ConnectState, | 	state: ConnectState, | ||||||
| 	address: SocketAddr, | 	address: SocketAddr, | ||||||
| 	self_key_pair: KeyPair, | 	self_key_pair: Arc<NodeKeyPair>, | ||||||
| 	trusted_nodes: BTreeSet<NodeId>, | 	trusted_nodes: BTreeSet<NodeId>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -241,7 +241,6 @@ pub mod tests { | |||||||
| 			data_path: path.as_str().to_owned(), | 			data_path: path.as_str().to_owned(), | ||||||
| 			cluster_config: ClusterConfiguration { | 			cluster_config: ClusterConfiguration { | ||||||
| 				threads: 1, | 				threads: 1, | ||||||
| 				self_private: (**Random.generate().unwrap().secret().clone()).into(), |  | ||||||
| 				listener_address: NodeAddress { | 				listener_address: NodeAddress { | ||||||
| 					address: "0.0.0.0".to_owned(), | 					address: "0.0.0.0".to_owned(), | ||||||
| 					port: 8083, | 					port: 8083, | ||||||
|  | |||||||
| @ -59,22 +59,24 @@ mod key_server; | |||||||
| mod key_storage; | mod key_storage; | ||||||
| mod serialization; | mod serialization; | ||||||
| mod key_server_set; | mod key_server_set; | ||||||
|  | mod node_key_pair; | ||||||
| 
 | 
 | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use ethcore::client::Client; | use ethcore::client::Client; | ||||||
| 
 | 
 | ||||||
| pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, | pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, | ||||||
| 	Error, NodeAddress, ServiceConfiguration, ClusterConfiguration}; | 	Error, NodeAddress, ServiceConfiguration, ClusterConfiguration}; | ||||||
| pub use traits::{KeyServer}; | pub use traits::{NodeKeyPair, KeyServer}; | ||||||
|  | pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; | ||||||
| 
 | 
 | ||||||
| /// Start new key server instance
 | /// Start new key server instance
 | ||||||
| pub fn start(client: Arc<Client>, config: ServiceConfiguration) -> Result<Box<KeyServer>, Error> { | pub fn start(client: Arc<Client>, self_key_pair: Arc<NodeKeyPair>, config: ServiceConfiguration) -> Result<Box<KeyServer>, Error> { | ||||||
| 	use std::sync::Arc; | 	use std::sync::Arc; | ||||||
| 
 | 
 | ||||||
| 	let acl_storage = acl_storage::OnChainAclStorage::new(&client); | 	let acl_storage = acl_storage::OnChainAclStorage::new(&client); | ||||||
| 	let key_server_set = key_server_set::OnChainKeyServerSet::new(&client, config.cluster_config.nodes.clone())?; | 	let key_server_set = key_server_set::OnChainKeyServerSet::new(&client, config.cluster_config.nodes.clone())?; | ||||||
| 	let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?); | 	let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?); | ||||||
| 	let key_server = key_server::KeyServerImpl::new(&config.cluster_config, key_server_set, acl_storage, key_storage)?; | 	let key_server = key_server::KeyServerImpl::new(&config.cluster_config, key_server_set, self_key_pair, acl_storage, key_storage)?; | ||||||
| 	let listener = http_listener::KeyServerHttpListener::start(&config.listener_address, key_server)?; | 	let listener = http_listener::KeyServerHttpListener::start(&config.listener_address, key_server)?; | ||||||
| 	Ok(Box::new(listener)) | 	Ok(Box::new(listener)) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										84
									
								
								secret_store/src/node_key_pair.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								secret_store/src/node_key_pair.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | // Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | use std::sync::Arc; | ||||||
|  | use ethcrypto::ecdh::agree; | ||||||
|  | use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign}; | ||||||
|  | use ethcore::account_provider::AccountProvider; | ||||||
|  | use util::{Address, H256}; | ||||||
|  | use traits::NodeKeyPair; | ||||||
|  | 
 | ||||||
|  | pub struct PlainNodeKeyPair { | ||||||
|  | 	key_pair: KeyPair, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct KeyStoreNodeKeyPair { | ||||||
|  | 	account_provider: Arc<AccountProvider>, | ||||||
|  | 	address: Address, | ||||||
|  | 	public: Public, | ||||||
|  | 	password: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl PlainNodeKeyPair { | ||||||
|  | 	pub fn new(key_pair: KeyPair) -> Self { | ||||||
|  | 		PlainNodeKeyPair { | ||||||
|  | 			key_pair: key_pair, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl NodeKeyPair for PlainNodeKeyPair { | ||||||
|  | 	fn public(&self) -> &Public { | ||||||
|  | 		self.key_pair.public() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> { | ||||||
|  | 		sign(self.key_pair.secret(), data) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError> { | ||||||
|  | 		agree(self.key_pair.secret(), peer_public).map_err(|e| EthKeyError::Custom(e.into())) | ||||||
|  | 			.and_then(KeyPair::from_secret) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl KeyStoreNodeKeyPair { | ||||||
|  | 	pub fn new(account_provider: Arc<AccountProvider>, address: Address, password: String) -> Result<Self, EthKeyError> { | ||||||
|  | 		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 { | ||||||
|  | 		&self.public | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> { | ||||||
|  | 		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<KeyPair, EthKeyError> { | ||||||
|  | 		KeyPair::from_secret(self.account_provider.agree(self.address.clone(), Some(self.password.clone()), peer_public) | ||||||
|  | 			.map_err(|e| EthKeyError::Custom(format!("{}", e)))?) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -14,9 +14,21 @@ | |||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
|  | use ethkey::{KeyPair, Signature, Error as EthKeyError}; | ||||||
|  | use util::H256; | ||||||
| use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey, | use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey, | ||||||
| 	EncryptedDocumentKeyShadow}; | 	EncryptedDocumentKeyShadow}; | ||||||
| 
 | 
 | ||||||
|  | /// Node key pair.
 | ||||||
|  | pub trait NodeKeyPair: Send + Sync { | ||||||
|  | 	/// Public portion of key.
 | ||||||
|  | 	fn public(&self) -> &Public; | ||||||
|  | 	/// Sign data with node key.
 | ||||||
|  | 	fn sign(&self, data: &H256) -> Result<Signature, EthKeyError>; | ||||||
|  | 	/// Compute shared key to encrypt channel between two nodes.
 | ||||||
|  | 	fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Server key (SK) generator.
 | /// Server key (SK) generator.
 | ||||||
| pub trait ServerKeyGenerator { | pub trait ServerKeyGenerator { | ||||||
| 	/// Generate new SK.
 | 	/// Generate new SK.
 | ||||||
|  | |||||||
| @ -83,8 +83,6 @@ pub struct ServiceConfiguration { | |||||||
| pub struct ClusterConfiguration { | pub struct ClusterConfiguration { | ||||||
| 	/// Number of threads reserved by cluster.
 | 	/// Number of threads reserved by cluster.
 | ||||||
| 	pub threads: usize, | 	pub threads: usize, | ||||||
| 	/// Private key this node holds.
 |  | ||||||
| 	pub self_private: Vec<u8>, // holds ethkey::Secret
 |  | ||||||
| 	/// This node address.
 | 	/// This node address.
 | ||||||
| 	pub listener_address: NodeAddress, | 	pub listener_address: NodeAddress, | ||||||
| 	/// All cluster nodes addresses.
 | 	/// All cluster nodes addresses.
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user