2019-01-07 11:33:07 +01:00
|
|
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of Parity Ethereum.
|
2017-02-20 16:13:21 +01:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2017-02-20 16:13:21 +01:00
|
|
|
// 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.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2017-02-20 16:13:21 +01:00
|
|
|
// 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
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2017-02-20 16:13:21 +01:00
|
|
|
|
2017-11-16 17:34:23 +01:00
|
|
|
use std::collections::BTreeSet;
|
2017-04-03 11:13:51 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
use parking_lot::Mutex;
|
2018-05-05 11:02:33 +02:00
|
|
|
use crypto::DEFAULT_MAC;
|
|
|
|
use ethkey::crypto;
|
2018-11-25 18:36:43 +01:00
|
|
|
use parity_runtime::Executor;
|
2017-02-20 16:13:21 +01:00
|
|
|
use super::acl_storage::AclStorage;
|
|
|
|
use super::key_storage::KeyStorage;
|
2017-07-19 10:35:17 +02:00
|
|
|
use super::key_server_set::KeyServerSet;
|
2019-02-18 13:38:19 +01:00
|
|
|
use key_server_cluster::{math, new_network_cluster};
|
2017-11-16 17:34:23 +01:00
|
|
|
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair};
|
2018-05-01 15:02:14 +02:00
|
|
|
use types::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow,
|
2017-11-16 17:34:23 +01:00
|
|
|
ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId};
|
2019-02-18 13:38:19 +01:00
|
|
|
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration, NetConnectionsManagerConfig};
|
2017-02-20 16:13:21 +01:00
|
|
|
|
|
|
|
/// Secret store key server implementation
|
2017-04-03 11:13:51 +02:00
|
|
|
pub struct KeyServerImpl {
|
|
|
|
data: Arc<Mutex<KeyServerCore>>,
|
2017-02-20 16:13:21 +01:00
|
|
|
}
|
|
|
|
|
2017-04-03 11:13:51 +02:00
|
|
|
/// Secret store key server data.
|
|
|
|
pub struct KeyServerCore {
|
2017-04-08 11:26:16 +02:00
|
|
|
cluster: Arc<ClusterClient>,
|
2017-04-03 11:13:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl KeyServerImpl {
|
2017-02-20 16:13:21 +01:00
|
|
|
/// Create new key server instance
|
2018-11-25 18:36:43 +01:00
|
|
|
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, self_key_pair: Arc<NodeKeyPair>,
|
|
|
|
acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>, executor: Executor) -> Result<Self, Error>
|
|
|
|
{
|
2017-04-03 11:13:51 +02:00
|
|
|
Ok(KeyServerImpl {
|
2018-11-25 18:36:43 +01:00
|
|
|
data: Arc::new(Mutex::new(KeyServerCore::new(config, key_server_set, self_key_pair, acl_storage, key_storage, executor)?)),
|
2017-04-03 11:13:51 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get cluster client reference.
|
|
|
|
pub fn cluster(&self) -> Arc<ClusterClient> {
|
|
|
|
self.data.lock().cluster.clone()
|
2017-02-20 16:13:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
impl KeyServer for KeyServerImpl {}
|
|
|
|
|
2017-11-16 17:34:23 +01:00
|
|
|
impl AdminSessionsServer for KeyServerImpl {
|
|
|
|
fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet<NodeId>) -> Result<(), Error> {
|
|
|
|
let servers_set_change_session = self.data.lock().cluster
|
2018-01-10 11:33:45 +01:00
|
|
|
.new_servers_set_change_session(None, None, new_servers_set, old_set_signature, new_set_signature)?;
|
2017-11-22 08:21:14 +01:00
|
|
|
servers_set_change_session.as_servers_set_change()
|
|
|
|
.expect("new_servers_set_change_session creates servers_set_change_session; qed")
|
|
|
|
.wait().map_err(Into::into)
|
2017-11-16 17:34:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
impl ServerKeyGenerator for KeyServerImpl {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<Public, Error> {
|
2017-04-03 11:13:51 +02:00
|
|
|
// recover requestor' public key from signature
|
2018-04-03 16:54:34 +02:00
|
|
|
let address = author.address(key_id).map_err(Error::InsufficientRequesterData)?;
|
2017-04-03 11:13:51 +02:00
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
// generate server key
|
2018-04-03 16:54:34 +02:00
|
|
|
let generation_session = self.data.lock().cluster.new_generation_session(key_id.clone(), None, address, threshold)?;
|
|
|
|
generation_session.wait(None)
|
|
|
|
.expect("when wait is called without timeout it always returns Some; qed")
|
|
|
|
.map_err(Into::into)
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DocumentKeyServer for KeyServerImpl {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn store_document_key(&self, key_id: &ServerKeyId, author: &Requester, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> {
|
2017-07-06 14:02:10 +02:00
|
|
|
// store encrypted key
|
2018-03-19 06:42:40 +01:00
|
|
|
let encryption_session = self.data.lock().cluster.new_encryption_session(key_id.clone(),
|
2018-04-03 16:54:34 +02:00
|
|
|
author.clone(), common_point, encrypted_document_key)?;
|
2017-07-06 14:02:10 +02:00
|
|
|
encryption_session.wait(None).map_err(Into::into)
|
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn generate_document_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<EncryptedDocumentKey, Error> {
|
2017-07-06 14:02:10 +02:00
|
|
|
// recover requestor' public key from signature
|
2018-04-03 16:54:34 +02:00
|
|
|
let public = author.public(key_id).map_err(Error::InsufficientRequesterData)?;
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// generate server key
|
2018-04-03 16:54:34 +02:00
|
|
|
let server_key = self.generate_key(key_id, author, threshold)?;
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// generate random document key
|
|
|
|
let document_key = math::generate_random_point()?;
|
|
|
|
let encrypted_document_key = math::encrypt_secret(&document_key, &server_key)?;
|
|
|
|
|
|
|
|
// store document key in the storage
|
2018-04-03 16:54:34 +02:00
|
|
|
self.store_document_key(key_id, author, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?;
|
2017-04-03 11:13:51 +02:00
|
|
|
|
|
|
|
// encrypt document key with requestor public key
|
2018-05-05 11:02:33 +02:00
|
|
|
let document_key = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &document_key)
|
2017-04-03 11:13:51 +02:00
|
|
|
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
|
|
|
Ok(document_key)
|
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn restore_document_key(&self, key_id: &ServerKeyId, requester: &Requester) -> Result<EncryptedDocumentKey, Error> {
|
2017-02-20 16:13:21 +01:00
|
|
|
// recover requestor' public key from signature
|
2018-04-03 16:54:34 +02:00
|
|
|
let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?;
|
2017-02-20 16:13:21 +01:00
|
|
|
|
2017-04-03 11:13:51 +02:00
|
|
|
// decrypt document key
|
2018-03-19 06:42:40 +01:00
|
|
|
let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(),
|
2018-04-03 16:54:34 +02:00
|
|
|
None, requester.clone(), None, false, false)?;
|
|
|
|
let document_key = decryption_session.wait(None)
|
|
|
|
.expect("when wait is called without timeout it always returns Some; qed")?
|
|
|
|
.decrypted_secret;
|
2017-02-20 16:13:21 +01:00
|
|
|
|
|
|
|
// encrypt document key with requestor public key
|
2018-05-05 11:02:33 +02:00
|
|
|
let document_key = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &document_key)
|
2017-02-20 16:13:21 +01:00
|
|
|
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
|
|
|
Ok(document_key)
|
|
|
|
}
|
2017-04-08 11:26:16 +02:00
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn restore_document_key_shadow(&self, key_id: &ServerKeyId, requester: &Requester) -> Result<EncryptedDocumentKeyShadow, Error> {
|
2018-03-19 06:42:40 +01:00
|
|
|
let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(),
|
2018-04-03 16:54:34 +02:00
|
|
|
None, requester.clone(), None, true, false)?;
|
|
|
|
decryption_session.wait(None)
|
|
|
|
.expect("when wait is called without timeout it always returns Some; qed")
|
|
|
|
.map_err(Into::into)
|
2017-04-08 11:26:16 +02:00
|
|
|
}
|
2017-02-20 16:13:21 +01:00
|
|
|
}
|
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
impl MessageSigner for KeyServerImpl {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn sign_message_schnorr(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
2017-07-06 14:02:10 +02:00
|
|
|
// recover requestor' public key from signature
|
2018-04-03 16:54:34 +02:00
|
|
|
let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?;
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// sign message
|
2018-03-19 06:42:40 +01:00
|
|
|
let signing_session = self.data.lock().cluster.new_schnorr_signing_session(key_id.clone(),
|
2018-04-03 16:54:34 +02:00
|
|
|
requester.clone().into(), None, message)?;
|
2017-07-06 14:02:10 +02:00
|
|
|
let message_signature = signing_session.wait()?;
|
|
|
|
|
|
|
|
// compose two message signature components into single one
|
|
|
|
let mut combined_signature = [0; 64];
|
|
|
|
combined_signature[..32].clone_from_slice(&**message_signature.0);
|
|
|
|
combined_signature[32..].clone_from_slice(&**message_signature.1);
|
|
|
|
|
|
|
|
// encrypt combined signature with requestor public key
|
2018-05-05 11:02:33 +02:00
|
|
|
let message_signature = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &combined_signature)
|
2017-07-06 14:02:10 +02:00
|
|
|
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
|
|
|
Ok(message_signature)
|
|
|
|
}
|
2018-03-01 09:59:21 +01:00
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn sign_message_ecdsa(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
2018-03-01 09:59:21 +01:00
|
|
|
// recover requestor' public key from signature
|
2018-04-03 16:54:34 +02:00
|
|
|
let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?;
|
2018-03-01 09:59:21 +01:00
|
|
|
|
|
|
|
// sign message
|
2018-03-19 06:42:40 +01:00
|
|
|
let signing_session = self.data.lock().cluster.new_ecdsa_signing_session(key_id.clone(),
|
2018-04-03 16:54:34 +02:00
|
|
|
requester.clone().into(), None, message)?;
|
2018-03-01 09:59:21 +01:00
|
|
|
let message_signature = signing_session.wait()?;
|
|
|
|
|
|
|
|
// encrypt combined signature with requestor public key
|
2018-05-05 11:02:33 +02:00
|
|
|
let message_signature = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &*message_signature)
|
2018-03-01 09:59:21 +01:00
|
|
|
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
|
|
|
Ok(message_signature)
|
|
|
|
}
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
|
2017-04-03 11:13:51 +02:00
|
|
|
impl KeyServerCore {
|
2018-11-25 18:36:43 +01:00
|
|
|
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<KeyServerSet>, self_key_pair: Arc<NodeKeyPair>,
|
|
|
|
acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>, executor: Executor) -> Result<Self, Error>
|
|
|
|
{
|
2019-02-18 13:38:19 +01:00
|
|
|
let cconfig = NetClusterConfiguration {
|
2018-04-03 16:54:34 +02:00
|
|
|
self_key_pair: self_key_pair.clone(),
|
2017-07-19 10:35:17 +02:00
|
|
|
key_server_set: key_server_set,
|
2017-04-03 11:13:51 +02:00
|
|
|
acl_storage: acl_storage,
|
|
|
|
key_storage: key_storage,
|
2019-02-18 13:38:19 +01:00
|
|
|
admin_public: config.admin_public,
|
|
|
|
preserve_sessions: false,
|
|
|
|
};
|
|
|
|
let net_config = NetConnectionsManagerConfig {
|
|
|
|
listen_address: (config.listener_address.address.clone(), config.listener_address.port),
|
|
|
|
allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes,
|
2018-01-10 11:33:45 +01:00
|
|
|
auto_migrate_enabled: config.auto_migrate_enabled,
|
2017-04-03 11:13:51 +02:00
|
|
|
};
|
|
|
|
|
2019-02-18 13:38:19 +01:00
|
|
|
let core = new_network_cluster(executor, cconfig, net_config)?;
|
|
|
|
let cluster = core.client();
|
|
|
|
core.run()?;
|
2017-04-03 11:13:51 +02:00
|
|
|
|
|
|
|
Ok(KeyServerCore {
|
2018-11-25 18:36:43 +01:00
|
|
|
cluster,
|
2017-04-03 11:13:51 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-20 16:13:21 +01:00
|
|
|
#[cfg(test)]
|
2017-04-25 21:34:03 +02:00
|
|
|
pub mod tests {
|
2017-11-16 17:34:23 +01:00
|
|
|
use std::collections::BTreeSet;
|
2017-04-03 11:13:51 +02:00
|
|
|
use std::time;
|
|
|
|
use std::sync::Arc;
|
2017-07-24 11:36:31 +02:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
use std::collections::BTreeMap;
|
2018-05-05 11:02:33 +02:00
|
|
|
use crypto::DEFAULT_MAC;
|
|
|
|
use ethkey::{self, crypto, Secret, Random, Generator, verify_public};
|
2017-07-27 14:48:07 +02:00
|
|
|
use acl_storage::DummyAclStorage;
|
2018-04-03 16:54:34 +02:00
|
|
|
use key_storage::KeyStorage;
|
2017-02-20 16:13:21 +01:00
|
|
|
use key_storage::tests::DummyKeyStorage;
|
2017-07-25 08:24:54 +02:00
|
|
|
use node_key_pair::PlainNodeKeyPair;
|
2017-07-24 11:36:31 +02:00
|
|
|
use key_server_set::tests::MapKeyServerSet;
|
2017-07-06 14:02:10 +02:00
|
|
|
use key_server_cluster::math;
|
2018-03-01 09:59:21 +01:00
|
|
|
use ethereum_types::{H256, H520};
|
2018-11-25 18:36:43 +01:00
|
|
|
use parity_runtime::Runtime;
|
2018-05-01 15:02:14 +02:00
|
|
|
use types::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
|
2018-04-03 16:54:34 +02:00
|
|
|
EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature,
|
|
|
|
Requester, NodeId};
|
2017-11-16 17:34:23 +01:00
|
|
|
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
2017-07-06 14:02:10 +02:00
|
|
|
use super::KeyServerImpl;
|
2017-02-20 16:13:21 +01:00
|
|
|
|
2017-11-22 15:31:34 +01:00
|
|
|
#[derive(Default)]
|
2018-04-03 16:54:34 +02:00
|
|
|
pub struct DummyKeyServer;
|
2017-04-25 21:34:03 +02:00
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
impl KeyServer for DummyKeyServer {}
|
|
|
|
|
2017-11-16 17:34:23 +01:00
|
|
|
impl AdminSessionsServer for DummyKeyServer {
|
|
|
|
fn change_servers_set(&self, _old_set_signature: RequestSignature, _new_set_signature: RequestSignature, _new_servers_set: BTreeSet<NodeId>) -> Result<(), Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-11-16 17:34:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:02:10 +02:00
|
|
|
impl ServerKeyGenerator for DummyKeyServer {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn generate_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result<Public, Error> {
|
|
|
|
unimplemented!("test-only")
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DocumentKeyServer for DummyKeyServer {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn store_document_key(&self, _key_id: &ServerKeyId, _author: &Requester, _common_point: Public, _encrypted_document_key: Public) -> Result<(), Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn generate_document_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result<EncryptedDocumentKey, Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-04-25 21:34:03 +02:00
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn restore_document_key(&self, _key_id: &ServerKeyId, _requester: &Requester) -> Result<EncryptedDocumentKey, Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-04-25 21:34:03 +02:00
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn restore_document_key_shadow(&self, _key_id: &ServerKeyId, _requester: &Requester) -> Result<EncryptedDocumentKeyShadow, Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MessageSigner for DummyKeyServer {
|
2018-04-03 16:54:34 +02:00
|
|
|
fn sign_message_schnorr(&self, _key_id: &ServerKeyId, _requester: &Requester, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
2018-03-01 09:59:21 +01:00
|
|
|
unimplemented!("test-only")
|
|
|
|
}
|
|
|
|
|
2018-04-03 16:54:34 +02:00
|
|
|
fn sign_message_ecdsa(&self, _key_id: &ServerKeyId, _requester: &Requester, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
2018-01-10 11:33:45 +01:00
|
|
|
unimplemented!("test-only")
|
2017-04-25 21:34:03 +02:00
|
|
|
}
|
|
|
|
}
|
2017-04-03 11:13:51 +02:00
|
|
|
|
2018-11-25 18:36:43 +01:00
|
|
|
fn make_key_servers(start_port: u16, num_nodes: usize) -> (Vec<KeyServerImpl>, Vec<Arc<DummyKeyStorage>>, Runtime) {
|
2017-04-03 11:13:51 +02:00
|
|
|
let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect();
|
|
|
|
let configs: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration {
|
|
|
|
listener_address: NodeAddress {
|
|
|
|
address: "127.0.0.1".into(),
|
2017-04-25 21:34:03 +02:00
|
|
|
port: start_port + (i as u16),
|
2017-04-03 11:13:51 +02:00
|
|
|
},
|
|
|
|
nodes: key_pairs.iter().enumerate().map(|(j, kp)| (kp.public().clone(),
|
|
|
|
NodeAddress {
|
|
|
|
address: "127.0.0.1".into(),
|
2017-04-25 21:34:03 +02:00
|
|
|
port: start_port + (j as u16),
|
2017-04-03 11:13:51 +02:00
|
|
|
})).collect(),
|
2018-06-14 09:01:52 +02:00
|
|
|
key_server_set_contract_address: None,
|
2017-04-03 11:13:51 +02:00
|
|
|
allow_connecting_to_higher_nodes: false,
|
2017-10-02 15:27:31 +02:00
|
|
|
admin_public: None,
|
2018-01-10 11:33:45 +01:00
|
|
|
auto_migrate_enabled: false,
|
2017-04-03 11:13:51 +02:00
|
|
|
}).collect();
|
2017-07-24 11:36:31 +02:00
|
|
|
let key_servers_set: BTreeMap<Public, SocketAddr> = configs[0].nodes.iter()
|
|
|
|
.map(|(k, a)| (k.clone(), format!("{}:{}", a.address, a.port).parse().unwrap()))
|
|
|
|
.collect();
|
2018-04-03 16:54:34 +02:00
|
|
|
let key_storages = (0..num_nodes).map(|_| Arc::new(DummyKeyStorage::default())).collect::<Vec<_>>();
|
2018-11-25 18:36:43 +01:00
|
|
|
let runtime = Runtime::with_thread_count(4);
|
2017-07-25 08:24:54 +02:00
|
|
|
let key_servers: Vec<_> = configs.into_iter().enumerate().map(|(i, cfg)|
|
2018-06-14 09:01:52 +02:00
|
|
|
KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(false, key_servers_set.clone())),
|
2017-07-25 08:24:54 +02:00
|
|
|
Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())),
|
|
|
|
Arc::new(DummyAclStorage::default()),
|
2018-11-25 18:36:43 +01:00
|
|
|
key_storages[i].clone(), runtime.executor()).unwrap()
|
2017-04-03 11:13:51 +02:00
|
|
|
).collect();
|
|
|
|
|
2017-04-25 21:34:03 +02:00
|
|
|
// wait until connections are established. It is fast => do not bother with events here
|
2017-04-03 11:13:51 +02:00
|
|
|
let start = time::Instant::now();
|
2017-04-25 21:34:03 +02:00
|
|
|
let mut tried_reconnections = false;
|
2017-04-03 11:13:51 +02:00
|
|
|
loop {
|
2019-02-18 13:38:19 +01:00
|
|
|
if key_servers.iter().all(|ks| ks.cluster().is_fully_connected()) {
|
2017-04-03 11:13:51 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-04-25 21:34:03 +02:00
|
|
|
|
|
|
|
let old_tried_reconnections = tried_reconnections;
|
|
|
|
let mut fully_connected = true;
|
|
|
|
for key_server in &key_servers {
|
2019-02-18 13:38:19 +01:00
|
|
|
if !key_server.cluster().is_fully_connected() {
|
2017-04-25 21:34:03 +02:00
|
|
|
fully_connected = false;
|
|
|
|
if !old_tried_reconnections {
|
|
|
|
tried_reconnections = true;
|
|
|
|
key_server.cluster().connect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if fully_connected {
|
|
|
|
break;
|
|
|
|
}
|
2018-10-31 11:50:38 +01:00
|
|
|
if time::Instant::now() - start > time::Duration::from_millis(3000) {
|
|
|
|
panic!("connections are not established in 3000ms");
|
2017-04-03 11:13:51 +02:00
|
|
|
}
|
|
|
|
}
|
2017-02-20 16:13:21 +01:00
|
|
|
|
2018-11-25 18:36:43 +01:00
|
|
|
(key_servers, key_storages, runtime)
|
2017-04-25 21:34:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn document_key_generation_and_retrievement_works_over_network_with_single_node() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2018-11-25 18:36:43 +01:00
|
|
|
let (key_servers, _, runtime) = make_key_servers(6070, 1);
|
2017-04-25 21:34:03 +02:00
|
|
|
|
|
|
|
// generate document key
|
|
|
|
let threshold = 0;
|
|
|
|
let document = Random.generate().unwrap().secret().clone();
|
|
|
|
let secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
2017-04-25 21:34:03 +02:00
|
|
|
|
|
|
|
// now let's try to retrieve key back
|
|
|
|
for key_server in key_servers.iter() {
|
2018-04-03 16:54:34 +02:00
|
|
|
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
2017-04-25 21:34:03 +02:00
|
|
|
assert_eq!(retrieved_key, generated_key);
|
|
|
|
}
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-04-25 21:34:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn document_key_generation_and_retrievement_works_over_network_with_3_nodes() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2018-11-25 18:36:43 +01:00
|
|
|
let (key_servers, key_storages, runtime) = make_key_servers(6080, 3);
|
2017-04-25 21:34:03 +02:00
|
|
|
|
2017-04-03 11:13:51 +02:00
|
|
|
let test_cases = [0, 1, 2];
|
|
|
|
for threshold in &test_cases {
|
|
|
|
// generate document key
|
2017-04-08 11:26:16 +02:00
|
|
|
let document = Random.generate().unwrap().secret().clone();
|
|
|
|
let secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), *threshold).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
2017-04-03 11:13:51 +02:00
|
|
|
|
|
|
|
// now let's try to retrieve key back
|
2018-04-03 16:54:34 +02:00
|
|
|
for (i, key_server) in key_servers.iter().enumerate() {
|
|
|
|
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
2017-04-03 11:13:51 +02:00
|
|
|
assert_eq!(retrieved_key, generated_key);
|
2018-04-03 16:54:34 +02:00
|
|
|
|
|
|
|
let key_share = key_storages[i].get(&document).unwrap().unwrap();
|
|
|
|
assert!(key_share.common_point.is_some());
|
|
|
|
assert!(key_share.encrypted_point.is_some());
|
2017-04-03 11:13:51 +02:00
|
|
|
}
|
|
|
|
}
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-02-20 16:13:21 +01:00
|
|
|
}
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn server_key_generation_and_storing_document_key_works_over_network_with_3_nodes() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2018-11-25 18:36:43 +01:00
|
|
|
let (key_servers, _, runtime) = make_key_servers(6090, 3);
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
let test_cases = [0, 1, 2];
|
|
|
|
for threshold in &test_cases {
|
|
|
|
// generate server key
|
|
|
|
let server_key_id = Random.generate().unwrap().secret().clone();
|
|
|
|
let requestor_secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), *threshold).unwrap();
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// generate document key (this is done by KS client so that document key is unknown to any KS)
|
|
|
|
let generated_key = Random.generate().unwrap().public().clone();
|
|
|
|
let encrypted_document_key = math::encrypt_secret(&generated_key, &server_public).unwrap();
|
|
|
|
|
|
|
|
// store document key
|
2018-04-03 16:54:34 +02:00
|
|
|
key_servers[0].store_document_key(&server_key_id, &signature.clone().into(),
|
|
|
|
encrypted_document_key.common_point, encrypted_document_key.encrypted_point).unwrap();
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// now let's try to retrieve key back
|
|
|
|
for key_server in key_servers.iter() {
|
2018-04-03 16:54:34 +02:00
|
|
|
let retrieved_key = key_server.restore_document_key(&server_key_id, &signature.clone().into()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let retrieved_key = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
2017-07-06 14:02:10 +02:00
|
|
|
let retrieved_key = Public::from_slice(&retrieved_key);
|
|
|
|
assert_eq!(retrieved_key, generated_key);
|
|
|
|
}
|
|
|
|
}
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn server_key_generation_and_message_signing_works_over_network_with_3_nodes() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2018-11-25 18:36:43 +01:00
|
|
|
let (key_servers, _, runtime) = make_key_servers(6100, 3);
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
let test_cases = [0, 1, 2];
|
|
|
|
for threshold in &test_cases {
|
|
|
|
// generate server key
|
|
|
|
let server_key_id = Random.generate().unwrap().secret().clone();
|
|
|
|
let requestor_secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), *threshold).unwrap();
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// sign message
|
|
|
|
let message_hash = H256::from(42);
|
2018-04-03 16:54:34 +02:00
|
|
|
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &combined_signature).unwrap();
|
2018-04-11 13:57:12 +02:00
|
|
|
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
|
|
|
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
2017-07-06 14:02:10 +02:00
|
|
|
|
|
|
|
// check signature
|
2018-03-01 09:59:21 +01:00
|
|
|
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-07-06 14:02:10 +02:00
|
|
|
}
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn decryption_session_is_delegated_when_node_does_not_have_key_share() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2019-02-18 13:38:19 +01:00
|
|
|
let (key_servers, key_storages, runtime) = make_key_servers(6110, 3);
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// generate document key
|
|
|
|
let threshold = 0;
|
|
|
|
let document = Random.generate().unwrap().secret().clone();
|
|
|
|
let secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// remove key from node0
|
2019-02-18 13:38:19 +01:00
|
|
|
key_storages[0].remove(&document).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// now let's try to retrieve key back by requesting it from node0, so that session must be delegated
|
2018-04-03 16:54:34 +02:00
|
|
|
let retrieved_key = key_servers[0].restore_document_key(&document, &signature.into()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
assert_eq!(retrieved_key, generated_key);
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-11-02 15:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2018-03-01 09:59:21 +01:00
|
|
|
fn schnorr_signing_session_is_delegated_when_node_does_not_have_key_share() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2019-02-18 13:38:19 +01:00
|
|
|
let (key_servers, key_storages, runtime) = make_key_servers(6114, 3);
|
2017-11-02 15:33:11 +01:00
|
|
|
let threshold = 1;
|
|
|
|
|
|
|
|
// generate server key
|
|
|
|
let server_key_id = Random.generate().unwrap().secret().clone();
|
|
|
|
let requestor_secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), threshold).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// remove key from node0
|
2019-02-18 13:38:19 +01:00
|
|
|
key_storages[0].remove(&server_key_id).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// sign message
|
|
|
|
let message_hash = H256::from(42);
|
2018-04-03 16:54:34 +02:00
|
|
|
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &combined_signature).unwrap();
|
2018-04-11 13:57:12 +02:00
|
|
|
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
|
|
|
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
2017-11-02 15:33:11 +01:00
|
|
|
|
|
|
|
// check signature
|
2018-03-01 09:59:21 +01:00
|
|
|
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2018-03-01 09:59:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn ecdsa_signing_session_is_delegated_when_node_does_not_have_key_share() {
|
2019-01-08 15:07:20 +01:00
|
|
|
let _ = ::env_logger::try_init();
|
2019-02-18 13:38:19 +01:00
|
|
|
let (key_servers, key_storages, runtime) = make_key_servers(6117, 4);
|
2018-03-01 09:59:21 +01:00
|
|
|
let threshold = 1;
|
|
|
|
|
|
|
|
// generate server key
|
|
|
|
let server_key_id = Random.generate().unwrap().secret().clone();
|
|
|
|
let requestor_secret = Random.generate().unwrap().secret().clone();
|
|
|
|
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
|
2018-04-03 16:54:34 +02:00
|
|
|
let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), threshold).unwrap();
|
2018-03-01 09:59:21 +01:00
|
|
|
|
|
|
|
// remove key from node0
|
2019-02-18 13:38:19 +01:00
|
|
|
key_storages[0].remove(&server_key_id).unwrap();
|
2018-03-01 09:59:21 +01:00
|
|
|
|
|
|
|
// sign message
|
|
|
|
let message_hash = H256::random();
|
2018-04-03 16:54:34 +02:00
|
|
|
let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
2018-05-05 11:02:33 +02:00
|
|
|
let signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &signature).unwrap();
|
2018-03-01 09:59:21 +01:00
|
|
|
let signature: H520 = signature[0..65].into();
|
|
|
|
|
|
|
|
// check signature
|
|
|
|
assert!(verify_public(&server_public, &signature.into(), &message_hash).unwrap());
|
2018-11-25 18:36:43 +01:00
|
|
|
drop(runtime);
|
2017-11-02 15:33:11 +01:00
|
|
|
}
|
2017-11-16 17:34:23 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn servers_set_change_session_works_over_network() {
|
2018-01-10 11:33:45 +01:00
|
|
|
// TODO [Test]
|
2017-11-16 17:34:23 +01:00
|
|
|
}
|
2017-02-20 16:13:21 +01:00
|
|
|
}
|