SecretStore: servers set change session api (#6925)
* SecretStore: first key versions flush * SecretStore: key versions in encryption session * SecretStore: flush key versions negotiation session * SecretStore: connected key version negotiation session to cluster * SecretStore: cluster sessions container refactoring * SecretStore: flush * SecretStore: flush key versions * SecretStore: flush * SecretStore: delegation proto * SecretStore: decryption_session_is_delegated_when_node_does_not_have_key_share * SecretStore: fixed version in decryption session * SecretStore: signing_session_is_delegated_when_node_does_not_have_key_share * SecretStore: started restoring admin sessions * SecretStore: restoring admin sessions * SecretStore: removed obsolete ShareRemove && ShareMove sessions * SecretStore: ShareAdd math tests only require old_t+1 nodes * SecretStore: ShareAdd revamp using new math backend * SecretStore: do not include isolated nodes into consensus_group * SecretStore: ServersSetChange + ShareAdd revamp * removed debug printlns * SecretStore: key version negotiation tests * SecretStore: removed debug/merge artifacts * SecretStore: fixed master node selection * SecretStore: cleanup + tests + fixes * SecretStore: uncommented tests * SecretStore: cleaning up * SecretStore: cleaning up + tests * SecretStore: cleaning up * SecretStore: cleaning up && tests * SecretStore: fixing TODOs * SecretStore: fixing TODOs + cleanup * SecretStore: fixing TODOs * SecretStore: nodes_add_to_the_node_with_obsolete_version * SecretStore: nodes_add_fails_when_not_enough_share_owners_are_connected * SecretStore: tests * SecretStore: signing && delegation tests * SecretStore: signing && decryption tests when some nodes are isolated * SecretStore: sessions_are_removed_when_initialization_fails * SecretStore: ceaning up * SecretStore: removed obsolete comments * SecretStore: signing_session_completes_if_node_does_not_have_a_share * SecretStore: initial ServersSetChange API * SecretStore: added secretstore_signServersSet RPC * SecretStore: ChangeServersSet parse tests * SecretStore: fixes after manual ServersSetChange tests * lost file * fixed network ports overlap in tests * lost files
This commit is contained in:
parent
605cd5cd9f
commit
e16f6fb9d9
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2145,6 +2145,7 @@ dependencies = [
|
|||||||
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stats 0.1.0",
|
"stats 0.1.0",
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vm 0.1.0",
|
"vm 0.1.0",
|
||||||
|
@ -24,6 +24,7 @@ serde = "1.0"
|
|||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
|
tiny-keccak = "1.3"
|
||||||
tokio-timer = "0.1"
|
tokio-timer = "0.1"
|
||||||
transient-hashmap = "0.4"
|
transient-hashmap = "0.4"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
|
@ -37,6 +37,7 @@ extern crate semver;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
extern crate tiny_keccak;
|
||||||
extern crate tokio_timer;
|
extern crate tokio_timer;
|
||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
|
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
// 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::collections::BTreeSet;
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
use ethkey::{Public, Secret, math};
|
use ethkey::{Public, Secret, math};
|
||||||
use crypto;
|
use crypto;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
|
use v1::types::{H256, H512};
|
||||||
|
use tiny_keccak::Keccak;
|
||||||
|
|
||||||
/// Initialization vector length.
|
/// Initialization vector length.
|
||||||
const INIT_VEC_LEN: usize = 16;
|
const INIT_VEC_LEN: usize = 16;
|
||||||
@ -61,11 +64,25 @@ pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result<Byt
|
|||||||
Ok(document)
|
Ok(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decrypt document given secret shadow.
|
||||||
pub fn decrypt_document_with_shadow(decrypted_secret: Public, common_point: Public, shadows: Vec<Secret>, encrypted_document: Bytes) -> Result<Bytes, Error> {
|
pub fn decrypt_document_with_shadow(decrypted_secret: Public, common_point: Public, shadows: Vec<Secret>, encrypted_document: Bytes) -> Result<Bytes, Error> {
|
||||||
let key = decrypt_with_shadow_coefficients(decrypted_secret, common_point, shadows)?;
|
let key = decrypt_with_shadow_coefficients(decrypted_secret, common_point, shadows)?;
|
||||||
decrypt_document(key.to_vec(), encrypted_document)
|
decrypt_document(key.to_vec(), encrypted_document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate Keccak(ordered servers set)
|
||||||
|
pub fn ordered_servers_keccak(servers_set: BTreeSet<H512>) -> H256 {
|
||||||
|
let mut servers_set_keccak = Keccak::new_keccak256();
|
||||||
|
for server in servers_set {
|
||||||
|
servers_set_keccak.update(&server.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut servers_set_keccak_value = [0u8; 32];
|
||||||
|
servers_set_keccak.finalize(&mut servers_set_keccak_value);
|
||||||
|
|
||||||
|
servers_set_keccak_value.into()
|
||||||
|
}
|
||||||
|
|
||||||
fn into_document_key(key: Bytes) -> Result<Bytes, Error> {
|
fn into_document_key(key: Bytes) -> Result<Bytes, Error> {
|
||||||
// key is a previously distributely generated Public
|
// key is a previously distributely generated Public
|
||||||
if key.len() != 64 {
|
if key.len() != 64 {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! SecretStore-specific rpc implementation.
|
//! SecretStore-specific rpc implementation.
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crypto::DEFAULT_MAC;
|
use crypto::DEFAULT_MAC;
|
||||||
@ -25,7 +26,7 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::helpers::accounts::unwrap_provider;
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::helpers::secretstore::{encrypt_document, decrypt_document, decrypt_document_with_shadow};
|
use v1::helpers::secretstore::{encrypt_document, decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak};
|
||||||
use v1::traits::SecretStore;
|
use v1::traits::SecretStore;
|
||||||
use v1::types::{H160, H512, Bytes};
|
use v1::types::{H160, H512, Bytes};
|
||||||
|
|
||||||
@ -82,4 +83,13 @@ impl SecretStore for SecretStoreClient {
|
|||||||
decrypt_document_with_shadow(decrypted_secret.into(), common_point.into(), shadows, data.0)
|
decrypt_document_with_shadow(decrypted_secret.into(), common_point.into(), shadows, data.0)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sign_servers_set(&self, address: H160, password: String, servers_set: BTreeSet<H512>) -> Result<Bytes> {
|
||||||
|
let servers_set_keccak_value = ordered_servers_keccak(servers_set);
|
||||||
|
let store = self.account_provider()?;
|
||||||
|
store
|
||||||
|
.sign(address.into(), Some(password), servers_set_keccak_value.into())
|
||||||
|
.map(|s| Bytes::new((*s).to_vec()))
|
||||||
|
.map_err(|e| errors::account("Could not sign servers set.", e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,14 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
use ethkey::{KeyPair, Signature, verify_public};
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use jsonrpc_core::{IoHandler, Success};
|
use jsonrpc_core::{IoHandler, Success};
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::SecretStoreClient;
|
use v1::SecretStoreClient;
|
||||||
use v1::traits::secretstore::SecretStore;
|
use v1::traits::secretstore::SecretStore;
|
||||||
|
use v1::helpers::secretstore::ordered_servers_keccak;
|
||||||
|
|
||||||
struct Dependencies {
|
struct Dependencies {
|
||||||
pub accounts: Arc<AccountProvider>,
|
pub accounts: Arc<AccountProvider>,
|
||||||
@ -51,7 +53,7 @@ fn rpc_secretstore_encrypt_and_decrypt() {
|
|||||||
let deps = Dependencies::new();
|
let deps = Dependencies::new();
|
||||||
let io = deps.default_client();
|
let io = deps.default_client();
|
||||||
|
|
||||||
// insert new account && unlock it
|
// insert new account
|
||||||
let secret = "c1f1cfe279a5c350d13795bce162941967340c8a228e6ba175489afc564a5bef".parse().unwrap();
|
let secret = "c1f1cfe279a5c350d13795bce162941967340c8a228e6ba175489afc564a5bef".parse().unwrap();
|
||||||
deps.accounts.insert_account(secret, "password").unwrap();
|
deps.accounts.insert_account(secret, "password").unwrap();
|
||||||
|
|
||||||
@ -81,7 +83,7 @@ fn rpc_secretstore_shadow_decrypt() {
|
|||||||
let deps = Dependencies::new();
|
let deps = Dependencies::new();
|
||||||
let io = deps.default_client();
|
let io = deps.default_client();
|
||||||
|
|
||||||
// insert new account && unlock it
|
// insert new account
|
||||||
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap();
|
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap();
|
||||||
deps.accounts.insert_account(secret, "password").unwrap();
|
deps.accounts.insert_account(secret, "password").unwrap();
|
||||||
|
|
||||||
@ -96,3 +98,31 @@ fn rpc_secretstore_shadow_decrypt() {
|
|||||||
let decryption_response = io.handle_request_sync(&decryption_request).unwrap();
|
let decryption_response = io.handle_request_sync(&decryption_request).unwrap();
|
||||||
assert_eq!(decryption_response, r#"{"jsonrpc":"2.0","result":"0xdeadbeef","id":1}"#);
|
assert_eq!(decryption_response, r#"{"jsonrpc":"2.0","result":"0xdeadbeef","id":1}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_secretstore_sign_servers_set() {
|
||||||
|
let deps = Dependencies::new();
|
||||||
|
let io = deps.default_client();
|
||||||
|
|
||||||
|
// insert new account
|
||||||
|
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap();
|
||||||
|
let key_pair = KeyPair::from_secret(secret).unwrap();
|
||||||
|
deps.accounts.insert_account(key_pair.secret().clone(), "password").unwrap();
|
||||||
|
|
||||||
|
// execute signing request
|
||||||
|
let signing_request = r#"{"jsonrpc": "2.0", "method": "secretstore_signServersSet", "params":[
|
||||||
|
"0x00dfE63B22312ab4329aD0d28CaD8Af987A01932", "password",
|
||||||
|
["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
|
||||||
|
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]
|
||||||
|
], "id": 1}"#;
|
||||||
|
let signing_response = io.handle_request_sync(&signing_request).unwrap();
|
||||||
|
let signing_response = signing_response.replace(r#"{"jsonrpc":"2.0","result":"0x"#, "");
|
||||||
|
let signing_response = signing_response.replace(r#"","id":1}"#, "");
|
||||||
|
let signature: Signature = signing_response.parse().unwrap();
|
||||||
|
|
||||||
|
let servers_set_keccak = ordered_servers_keccak(vec![
|
||||||
|
"843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91".parse().unwrap(),
|
||||||
|
"07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3".parse().unwrap()
|
||||||
|
].into_iter().collect());
|
||||||
|
assert!(verify_public(key_pair.public(), &signature, &servers_set_keccak.into()).unwrap());
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! SecretStore-specific rpc interface.
|
//! SecretStore-specific rpc interface.
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
|
|
||||||
use v1::types::{H160, H512, Bytes};
|
use v1::types::{H160, H512, Bytes};
|
||||||
@ -37,5 +38,10 @@ build_rpc_trait! {
|
|||||||
/// Arguments: `account`, `password`, `decrypted_secret`, `common_point`, `decrypt_shadows`, `data`.
|
/// Arguments: `account`, `password`, `decrypted_secret`, `common_point`, `decrypt_shadows`, `data`.
|
||||||
#[rpc(name = "secretstore_shadowDecrypt")]
|
#[rpc(name = "secretstore_shadowDecrypt")]
|
||||||
fn shadow_decrypt(&self, H160, String, H512, H512, Vec<Bytes>, Bytes) -> Result<Bytes>;
|
fn shadow_decrypt(&self, H160, String, H512, H512, Vec<Bytes>, Bytes) -> Result<Bytes>;
|
||||||
|
|
||||||
|
/// Sign servers set for use in ServersSetChange session.
|
||||||
|
/// Arguments: `account`, `password`, `servers_set`.
|
||||||
|
#[rpc(name = "secretstore_signServersSet")]
|
||||||
|
fn sign_servers_set(&self, H160, String, BTreeSet<H512>) -> Result<Bytes>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +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 std::collections::BTreeSet;
|
||||||
|
use std::io::Read;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use hyper::header;
|
use hyper::header;
|
||||||
use hyper::uri::RequestUri;
|
use hyper::uri::RequestUri;
|
||||||
@ -25,10 +27,10 @@ use serde::Serialize;
|
|||||||
use serde_json;
|
use serde_json;
|
||||||
use url::percent_encoding::percent_decode;
|
use url::percent_encoding::percent_decode;
|
||||||
|
|
||||||
use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
use traits::{ServerKeyGenerator, AdminSessionsServer, DocumentKeyServer, MessageSigner, KeyServer};
|
||||||
use serialization::{SerializableEncryptedDocumentKeyShadow, SerializableBytes, SerializablePublic};
|
use serialization::{SerializableEncryptedDocumentKeyShadow, SerializableBytes, SerializablePublic};
|
||||||
use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, NodeAddress, RequestSignature, ServerKeyId,
|
use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, NodeAddress, RequestSignature, ServerKeyId,
|
||||||
EncryptedDocumentKey, EncryptedDocumentKeyShadow};
|
EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId};
|
||||||
|
|
||||||
/// Key server http-requests listener. Available requests:
|
/// Key server http-requests listener. Available requests:
|
||||||
/// To generate server key: POST /shadow/{server_key_id}/{signature}/{threshold}
|
/// To generate server key: POST /shadow/{server_key_id}/{signature}/{threshold}
|
||||||
@ -37,6 +39,7 @@ use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, NodeAddr
|
|||||||
/// To get document key: GET /{server_key_id}/{signature}
|
/// To get document key: GET /{server_key_id}/{signature}
|
||||||
/// To get document key shadow: GET /shadow/{server_key_id}/{signature}
|
/// To get document key shadow: GET /shadow/{server_key_id}/{signature}
|
||||||
/// To sign message with server key: GET /{server_key_id}/{signature}/{message_hash}
|
/// To sign message with server key: GET /{server_key_id}/{signature}/{message_hash}
|
||||||
|
/// To change servers set: POST /admin/servers_set_change/{old_signature}/{new_signature} + BODY: json array of hex-encoded nodes ids
|
||||||
|
|
||||||
pub struct KeyServerHttpListener<T: KeyServer + 'static> {
|
pub struct KeyServerHttpListener<T: KeyServer + 'static> {
|
||||||
http_server: Option<HttpListening>,
|
http_server: Option<HttpListening>,
|
||||||
@ -60,6 +63,8 @@ enum Request {
|
|||||||
GetDocumentKeyShadow(ServerKeyId, RequestSignature),
|
GetDocumentKeyShadow(ServerKeyId, RequestSignature),
|
||||||
/// Sign message.
|
/// Sign message.
|
||||||
SignMessage(ServerKeyId, RequestSignature, MessageHash),
|
SignMessage(ServerKeyId, RequestSignature, MessageHash),
|
||||||
|
/// Change servers set.
|
||||||
|
ChangeServersSet(RequestSignature, RequestSignature, BTreeSet<NodeId>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cloneable http handler
|
/// Cloneable http handler
|
||||||
@ -96,6 +101,12 @@ impl<T> KeyServerHttpListener<T> where T: KeyServer + 'static {
|
|||||||
|
|
||||||
impl<T> KeyServer for KeyServerHttpListener<T> where T: KeyServer + 'static {}
|
impl<T> KeyServer for KeyServerHttpListener<T> where T: KeyServer + 'static {}
|
||||||
|
|
||||||
|
impl<T> AdminSessionsServer for KeyServerHttpListener<T> where T: KeyServer + 'static {
|
||||||
|
fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet<NodeId>) -> Result<(), Error> {
|
||||||
|
self.handler.key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> ServerKeyGenerator for KeyServerHttpListener<T> where T: KeyServer + 'static {
|
impl<T> ServerKeyGenerator for KeyServerHttpListener<T> where T: KeyServer + 'static {
|
||||||
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<Public, Error> {
|
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<Public, Error> {
|
||||||
self.handler.key_server.generate_key(key_id, signature, threshold)
|
self.handler.key_server.generate_key(key_id, signature, threshold)
|
||||||
@ -134,17 +145,24 @@ impl<T> Drop for KeyServerHttpListener<T> where T: KeyServer + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
|
impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
|
||||||
fn handle(&self, req: HttpRequest, mut res: HttpResponse) {
|
fn handle(&self, mut req: HttpRequest, mut res: HttpResponse) {
|
||||||
if req.headers.has::<header::Origin>() {
|
if req.headers.has::<header::Origin>() {
|
||||||
warn!(target: "secretstore", "Ignoring {}-request {} with Origin header", req.method, req.uri);
|
warn!(target: "secretstore", "Ignoring {}-request {} with Origin header", req.method, req.uri);
|
||||||
*res.status_mut() = HttpStatusCode::NotFound;
|
*res.status_mut() = HttpStatusCode::NotFound;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut req_body = Default::default();
|
||||||
|
if let Err(error) = req.read_to_string(&mut req_body) {
|
||||||
|
warn!(target: "secretstore", "Error {} reading body of {}-request {}", error, req.method, req.uri);
|
||||||
|
*res.status_mut() = HttpStatusCode::BadRequest;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let req_method = req.method.clone();
|
let req_method = req.method.clone();
|
||||||
let req_uri = req.uri.clone();
|
let req_uri = req.uri.clone();
|
||||||
match &req_uri {
|
match &req_uri {
|
||||||
&RequestUri::AbsolutePath(ref path) => match parse_request(&req_method, &path) {
|
&RequestUri::AbsolutePath(ref path) => match parse_request(&req_method, &path, &req_body) {
|
||||||
Request::GenerateServerKey(document, signature, threshold) => {
|
Request::GenerateServerKey(document, signature, threshold) => {
|
||||||
return_server_public_key(req, res, self.handler.key_server.generate_key(&document, &signature, threshold)
|
return_server_public_key(req, res, self.handler.key_server.generate_key(&document, &signature, threshold)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -187,6 +205,13 @@ impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
|
|||||||
err
|
err
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
Request::ChangeServersSet(old_set_signature, new_set_signature, new_servers_set) => {
|
||||||
|
return_empty(req, res, self.handler.key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!(target: "secretstore", "ChangeServersSet request {} has failed with: {}", req_uri, err);
|
||||||
|
err
|
||||||
|
}));
|
||||||
|
},
|
||||||
Request::Invalid => {
|
Request::Invalid => {
|
||||||
warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri);
|
warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri);
|
||||||
*res.status_mut() = HttpStatusCode::BadRequest;
|
*res.status_mut() = HttpStatusCode::BadRequest;
|
||||||
@ -261,7 +286,7 @@ fn return_error(mut res: HttpResponse, err: Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_request(method: &HttpMethod, uri_path: &str) -> Request {
|
fn parse_request(method: &HttpMethod, uri_path: &str, body: &str) -> Request {
|
||||||
let uri_path = match percent_decode(uri_path.as_bytes()).decode_utf8() {
|
let uri_path = match percent_decode(uri_path.as_bytes()).decode_utf8() {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(_) => return Request::Invalid,
|
Err(_) => return Request::Invalid,
|
||||||
@ -272,6 +297,10 @@ fn parse_request(method: &HttpMethod, uri_path: &str) -> Request {
|
|||||||
return Request::Invalid;
|
return Request::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if path[0] == "admin" {
|
||||||
|
return parse_admin_request(method, path, body);
|
||||||
|
}
|
||||||
|
|
||||||
let (is_shadow_request, args_offset) = if &path[0] == "shadow" { (true, 1) } else { (false, 0) };
|
let (is_shadow_request, args_offset) = if &path[0] == "shadow" { (true, 1) } else { (false, 0) };
|
||||||
let args_count = path.len() - args_offset;
|
let args_count = path.len() - args_offset;
|
||||||
if args_count < 2 || path[args_offset].is_empty() || path[args_offset + 1].is_empty() {
|
if args_count < 2 || path[args_offset].is_empty() || path[args_offset + 1].is_empty() {
|
||||||
@ -308,9 +337,35 @@ fn parse_request(method: &HttpMethod, uri_path: &str) -> Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_admin_request(method: &HttpMethod, path: Vec<String>, body: &str) -> Request {
|
||||||
|
let args_count = path.len();
|
||||||
|
if *method != HttpMethod::Post || args_count != 4 || path[1] != "servers_set_change" {
|
||||||
|
return Request::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_set_signature = match path[2].parse() {
|
||||||
|
Ok(signature) => signature,
|
||||||
|
_ => return Request::Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_set_signature = match path[3].parse() {
|
||||||
|
Ok(signature) => signature,
|
||||||
|
_ => return Request::Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_servers_set: BTreeSet<SerializablePublic> = match serde_json::from_str(body) {
|
||||||
|
Ok(new_servers_set) => new_servers_set,
|
||||||
|
_ => return Request::Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
Request::ChangeServersSet(old_set_signature, new_set_signature,
|
||||||
|
new_servers_set.into_iter().map(Into::into).collect())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hyper::method::Method as HttpMethod;
|
use hyper::method::Method as HttpMethod;
|
||||||
|
use ethkey::Public;
|
||||||
use key_server::tests::DummyKeyServer;
|
use key_server::tests::DummyKeyServer;
|
||||||
use types::all::NodeAddress;
|
use types::all::NodeAddress;
|
||||||
use super::{parse_request, Request, KeyServerHttpListener};
|
use super::{parse_request, Request, KeyServerHttpListener};
|
||||||
@ -326,48 +381,66 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn parse_request_successful() {
|
fn parse_request_successful() {
|
||||||
// POST /shadow/{server_key_id}/{signature}/{threshold} => generate server key
|
// POST /shadow/{server_key_id}/{signature}/{threshold} => generate server key
|
||||||
assert_eq!(parse_request(&HttpMethod::Post, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/2"),
|
assert_eq!(parse_request(&HttpMethod::Post, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/2", Default::default()),
|
||||||
Request::GenerateServerKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::GenerateServerKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
2));
|
2));
|
||||||
// POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key} => store encrypted document key
|
// POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key} => store encrypted document key
|
||||||
assert_eq!(parse_request(&HttpMethod::Post, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8/1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb"),
|
assert_eq!(parse_request(&HttpMethod::Post, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8/1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb", Default::default()),
|
||||||
Request::StoreDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::StoreDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
"b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8".parse().unwrap(),
|
"b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8".parse().unwrap(),
|
||||||
"1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb".parse().unwrap()));
|
"1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb".parse().unwrap()));
|
||||||
// POST /{server_key_id}/{signature}/{threshold} => generate server && document key
|
// POST /{server_key_id}/{signature}/{threshold} => generate server && document key
|
||||||
assert_eq!(parse_request(&HttpMethod::Post, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/2"),
|
assert_eq!(parse_request(&HttpMethod::Post, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/2", Default::default()),
|
||||||
Request::GenerateDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::GenerateDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
2));
|
2));
|
||||||
// GET /{server_key_id}/{signature} => get document key
|
// GET /{server_key_id}/{signature} => get document key
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01"),
|
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||||
Request::GetDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::GetDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/%30000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01"),
|
assert_eq!(parse_request(&HttpMethod::Get, "/%30000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||||
Request::GetDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::GetDocumentKey("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
||||||
// GET /shadow/{server_key_id}/{signature} => get document key shadow
|
// GET /shadow/{server_key_id}/{signature} => get document key shadow
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01"),
|
assert_eq!(parse_request(&HttpMethod::Get, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||||
Request::GetDocumentKeyShadow("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::GetDocumentKeyShadow("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
||||||
// GET /{server_key_id}/{signature}/{message_hash} => sign message with server key
|
// GET /{server_key_id}/{signature}/{message_hash} => sign message with server key
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c"),
|
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c", Default::default()),
|
||||||
Request::SignMessage("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
Request::SignMessage("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
"281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c".parse().unwrap()));
|
"281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c".parse().unwrap()));
|
||||||
|
// POST /admin/servers_set_change/{old_set_signature}/{new_set_signature} + body
|
||||||
|
let node1: Public = "843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91".parse().unwrap();
|
||||||
|
let node2: Public = "07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3".parse().unwrap();
|
||||||
|
let nodes = vec![node1, node2].into_iter().collect();
|
||||||
|
assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/b199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01",
|
||||||
|
&r#"["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
|
||||||
|
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#),
|
||||||
|
Request::ChangeServersSet(
|
||||||
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
|
"b199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
|
nodes,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_request_failed() {
|
fn parse_request_failed() {
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, ""), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/shadow"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/shadow", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "///2"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "///2", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/shadow///2"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/shadow///2", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/a/b"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/a/b", Default::default()), Request::Invalid);
|
||||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002"), Request::Invalid);
|
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002", Default::default()), Request::Invalid);
|
||||||
|
assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/xxx/yyy",
|
||||||
|
&r#"["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
|
||||||
|
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#),
|
||||||
|
Request::Invalid);
|
||||||
|
assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", ""),
|
||||||
|
Request::Invalid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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::collections::BTreeSet;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
@ -26,9 +27,9 @@ 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, NodeKeyPair};
|
use traits::{AdminSessionsServer, 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, NodeId};
|
||||||
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration};
|
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration};
|
||||||
|
|
||||||
/// Secret store key server implementation
|
/// Secret store key server implementation
|
||||||
@ -60,6 +61,14 @@ impl KeyServerImpl {
|
|||||||
|
|
||||||
impl KeyServer for KeyServerImpl {}
|
impl KeyServer for KeyServerImpl {}
|
||||||
|
|
||||||
|
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
|
||||||
|
.new_servers_set_change_session(None, new_servers_set, old_set_signature, new_set_signature)?;
|
||||||
|
servers_set_change_session.wait().map_err(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ServerKeyGenerator for KeyServerImpl {
|
impl ServerKeyGenerator for KeyServerImpl {
|
||||||
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<Public, Error> {
|
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<Public, Error> {
|
||||||
// recover requestor' public key from signature
|
// recover requestor' public key from signature
|
||||||
@ -153,7 +162,7 @@ impl KeyServerCore {
|
|||||||
allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes,
|
allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes,
|
||||||
acl_storage: acl_storage,
|
acl_storage: acl_storage,
|
||||||
key_storage: key_storage,
|
key_storage: key_storage,
|
||||||
admin_public: None,
|
admin_public: config.admin_public.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (stop, stopped) = futures::oneshot();
|
let (stop, stopped) = futures::oneshot();
|
||||||
@ -191,6 +200,7 @@ impl Drop for KeyServerCore {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::time;
|
use std::time;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@ -204,14 +214,20 @@ pub mod tests {
|
|||||||
use key_server_cluster::math;
|
use key_server_cluster::math;
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
|
use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
|
||||||
EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature};
|
EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, NodeId};
|
||||||
use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
||||||
use super::KeyServerImpl;
|
use super::KeyServerImpl;
|
||||||
|
|
||||||
pub struct DummyKeyServer;
|
pub struct DummyKeyServer;
|
||||||
|
|
||||||
impl KeyServer for DummyKeyServer {}
|
impl KeyServer for DummyKeyServer {}
|
||||||
|
|
||||||
|
impl AdminSessionsServer for DummyKeyServer {
|
||||||
|
fn change_servers_set(&self, _old_set_signature: RequestSignature, _new_set_signature: RequestSignature, _new_servers_set: BTreeSet<NodeId>) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ServerKeyGenerator for DummyKeyServer {
|
impl ServerKeyGenerator for DummyKeyServer {
|
||||||
fn generate_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result<Public, Error> {
|
fn generate_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result<Public, Error> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
@ -444,4 +460,9 @@ pub mod tests {
|
|||||||
// check signature
|
// check signature
|
||||||
assert_eq!(math::verify_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
assert_eq!(math::verify_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn servers_set_change_session_works_over_network() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,7 +412,7 @@ impl SessionImpl {
|
|||||||
key_share: key_share,
|
key_share: key_share,
|
||||||
result_computer: Arc::new(LargestSupportResultComputer {}),
|
result_computer: Arc::new(LargestSupportResultComputer {}),
|
||||||
transport: ServersSetChangeKeyVersionNegotiationTransport {
|
transport: ServersSetChangeKeyVersionNegotiationTransport {
|
||||||
id: key_id,
|
id: self.core.meta.id.clone(),
|
||||||
nonce: self.core.nonce,
|
nonce: self.core.nonce,
|
||||||
cluster: self.core.cluster.clone(),
|
cluster: self.core.cluster.clone(),
|
||||||
},
|
},
|
||||||
@ -687,7 +687,7 @@ impl SessionImpl {
|
|||||||
/// Create share change session.
|
/// Create share change session.
|
||||||
fn create_share_change_session(core: &SessionCore, key_id: SessionId, master_node_id: NodeId, session_plan: ShareChangeSessionPlan) -> Result<ShareChangeSession, Error> {
|
fn create_share_change_session(core: &SessionCore, key_id: SessionId, master_node_id: NodeId, session_plan: ShareChangeSessionPlan) -> Result<ShareChangeSession, Error> {
|
||||||
ShareChangeSession::new(ShareChangeSessionParams {
|
ShareChangeSession::new(ShareChangeSessionParams {
|
||||||
session_id: key_id.clone(),
|
session_id: core.meta.id.clone(),
|
||||||
nonce: core.nonce,
|
nonce: core.nonce,
|
||||||
meta: ShareChangeSessionMeta {
|
meta: ShareChangeSessionMeta {
|
||||||
id: key_id,
|
id: key_id,
|
||||||
@ -726,7 +726,7 @@ impl SessionImpl {
|
|||||||
key_share: key_share,
|
key_share: key_share,
|
||||||
result_computer: Arc::new(LargestSupportResultComputer {}), // TODO: optimizations: could use modified Fast version
|
result_computer: Arc::new(LargestSupportResultComputer {}), // TODO: optimizations: could use modified Fast version
|
||||||
transport: ServersSetChangeKeyVersionNegotiationTransport {
|
transport: ServersSetChangeKeyVersionNegotiationTransport {
|
||||||
id: key_id,
|
id: core.meta.id.clone(),
|
||||||
nonce: core.nonce,
|
nonce: core.nonce,
|
||||||
cluster: core.cluster.clone(),
|
cluster: core.cluster.clone(),
|
||||||
},
|
},
|
||||||
@ -855,11 +855,20 @@ impl SessionImpl {
|
|||||||
/// Complete servers set change session.
|
/// Complete servers set change session.
|
||||||
fn complete_session(core: &SessionCore, data: &mut SessionData) -> Result<(), Error> {
|
fn complete_session(core: &SessionCore, data: &mut SessionData) -> Result<(), Error> {
|
||||||
debug_assert_eq!(core.meta.self_node_id, core.meta.master_node_id);
|
debug_assert_eq!(core.meta.self_node_id, core.meta.master_node_id);
|
||||||
|
|
||||||
|
// send completion notification
|
||||||
core.cluster.broadcast(Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeCompleted(ServersSetChangeCompleted {
|
core.cluster.broadcast(Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeCompleted(ServersSetChangeCompleted {
|
||||||
session: core.meta.id.clone().into(),
|
session: core.meta.id.clone().into(),
|
||||||
session_nonce: core.nonce,
|
session_nonce: core.nonce,
|
||||||
})))?;
|
})))?;
|
||||||
|
|
||||||
|
// if we are on the set of nodes that are being removed from the cluster, let's clear database
|
||||||
|
if !data.new_nodes_set.as_ref()
|
||||||
|
.expect("new_nodes_set is filled during initialization; session is completed after initialization; qed")
|
||||||
|
.contains(&core.meta.self_node_id) {
|
||||||
|
core.key_storage.clear().map_err(|e| Error::KeyStorage(e.into()))?;
|
||||||
|
}
|
||||||
|
|
||||||
data.state = SessionState::Finished;
|
data.state = SessionState::Finished;
|
||||||
data.result = Some(Ok(()));
|
data.result = Some(Ok(()));
|
||||||
core.completed.notify_all();
|
core.completed.notify_all();
|
||||||
|
@ -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::collections::BTreeSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::{Mutex, Condvar};
|
use parking_lot::{Mutex, Condvar};
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
@ -243,14 +244,19 @@ impl SessionImpl {
|
|||||||
|
|
||||||
let mut data = self.data.lock();
|
let mut data = self.data.lock();
|
||||||
let non_isolated_nodes = self.core.cluster.nodes();
|
let non_isolated_nodes = self.core.cluster.nodes();
|
||||||
data.consensus_session.consensus_job_mut().transport_mut().version = Some(version.clone());
|
let mut consensus_nodes: BTreeSet<_> = key_version.id_numbers.keys()
|
||||||
data.version = Some(version.clone());
|
|
||||||
data.is_shadow_decryption = Some(is_shadow_decryption);
|
|
||||||
data.consensus_session.initialize(key_version.id_numbers.keys()
|
|
||||||
.filter(|n| non_isolated_nodes.contains(*n))
|
.filter(|n| non_isolated_nodes.contains(*n))
|
||||||
.cloned()
|
.cloned()
|
||||||
.chain(::std::iter::once(self.core.meta.self_node_id.clone()))
|
.chain(::std::iter::once(self.core.meta.self_node_id.clone()))
|
||||||
.collect())?;
|
.collect();
|
||||||
|
if let Some(&DelegationStatus::DelegatedFrom(delegation_master, _)) = data.delegation_status.as_ref() {
|
||||||
|
consensus_nodes.remove(&delegation_master);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.consensus_session.consensus_job_mut().transport_mut().version = Some(version.clone());
|
||||||
|
data.version = Some(version.clone());
|
||||||
|
data.is_shadow_decryption = Some(is_shadow_decryption);
|
||||||
|
data.consensus_session.initialize(consensus_nodes)?;
|
||||||
|
|
||||||
if data.consensus_session.state() == ConsensusSessionState::ConsensusEstablished {
|
if data.consensus_session.state() == ConsensusSessionState::ConsensusEstablished {
|
||||||
self.core.disseminate_jobs(&mut data.consensus_session, &version, is_shadow_decryption)?;
|
self.core.disseminate_jobs(&mut data.consensus_session, &version, is_shadow_decryption)?;
|
||||||
@ -502,7 +508,10 @@ impl ClusterSession for SessionImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_finished(&self) -> bool {
|
fn is_finished(&self) -> bool {
|
||||||
self.data.lock().result.is_some()
|
let data = self.data.lock();
|
||||||
|
data.consensus_session.state() == ConsensusSessionState::Failed
|
||||||
|
|| data.consensus_session.state() == ConsensusSessionState::Finished
|
||||||
|
|| data.result.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_node_timeout(&self, node: &NodeId) {
|
fn on_node_timeout(&self, node: &NodeId) {
|
||||||
@ -1146,7 +1155,7 @@ mod tests {
|
|||||||
|
|
||||||
// now check that:
|
// now check that:
|
||||||
// 1) 4 of 5 sessions are in Finished state
|
// 1) 4 of 5 sessions are in Finished state
|
||||||
assert_eq!(sessions.iter().filter(|s| s.state() == ConsensusSessionState::Finished).count(), 5);
|
assert_eq!(sessions.iter().filter(|s| s.state() == ConsensusSessionState::Finished).count(), 4);
|
||||||
// 2) 1 session has decrypted key value
|
// 2) 1 session has decrypted key value
|
||||||
assert_eq!(sessions[1].decrypted_secret().unwrap().unwrap(), EncryptedDocumentKeyShadow {
|
assert_eq!(sessions[1].decrypted_secret().unwrap().unwrap(), EncryptedDocumentKeyShadow {
|
||||||
decrypted_secret: SECRET_PLAIN.into(),
|
decrypted_secret: SECRET_PLAIN.into(),
|
||||||
|
@ -1322,7 +1322,7 @@ pub mod tests {
|
|||||||
let mut core = Core::new().unwrap();
|
let mut core = Core::new().unwrap();
|
||||||
|
|
||||||
// prepare cluster objects for each node
|
// prepare cluster objects for each node
|
||||||
let clusters = make_clusters(&core, 6022, num_nodes);
|
let clusters = make_clusters(&core, 6031, num_nodes);
|
||||||
run_clusters(&clusters);
|
run_clusters(&clusters);
|
||||||
|
|
||||||
// establish connections
|
// establish connections
|
||||||
|
@ -250,14 +250,19 @@ impl SessionImpl {
|
|||||||
|
|
||||||
let mut data = self.data.lock();
|
let mut data = self.data.lock();
|
||||||
let non_isolated_nodes = self.core.cluster.nodes();
|
let non_isolated_nodes = self.core.cluster.nodes();
|
||||||
data.consensus_session.consensus_job_mut().transport_mut().version = Some(version.clone());
|
let mut consensus_nodes: BTreeSet<_> = key_version.id_numbers.keys()
|
||||||
data.version = Some(version.clone());
|
|
||||||
data.message_hash = Some(message_hash);
|
|
||||||
data.consensus_session.initialize(key_version.id_numbers.keys()
|
|
||||||
.filter(|n| non_isolated_nodes.contains(*n))
|
.filter(|n| non_isolated_nodes.contains(*n))
|
||||||
.cloned()
|
.cloned()
|
||||||
.chain(::std::iter::once(self.core.meta.self_node_id.clone()))
|
.chain(::std::iter::once(self.core.meta.self_node_id.clone()))
|
||||||
.collect())?;
|
.collect();
|
||||||
|
if let Some(&DelegationStatus::DelegatedFrom(delegation_master, _)) = data.delegation_status.as_ref() {
|
||||||
|
consensus_nodes.remove(&delegation_master);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.consensus_session.consensus_job_mut().transport_mut().version = Some(version.clone());
|
||||||
|
data.version = Some(version.clone());
|
||||||
|
data.message_hash = Some(message_hash);
|
||||||
|
data.consensus_session.initialize(consensus_nodes)?;
|
||||||
|
|
||||||
if data.consensus_session.state() == ConsensusSessionState::ConsensusEstablished {
|
if data.consensus_session.state() == ConsensusSessionState::ConsensusEstablished {
|
||||||
let generation_session = GenerationSession::new(GenerationSessionParams {
|
let generation_session = GenerationSession::new(GenerationSessionParams {
|
||||||
@ -355,7 +360,6 @@ impl SessionImpl {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// When consensus-related message is received.
|
/// When consensus-related message is received.
|
||||||
pub fn on_consensus_message(&self, sender: &NodeId, message: &SigningConsensusMessage) -> Result<(), Error> {
|
pub fn on_consensus_message(&self, sender: &NodeId, message: &SigningConsensusMessage) -> Result<(), Error> {
|
||||||
debug_assert!(self.core.meta.id == *message.session);
|
debug_assert!(self.core.meta.id == *message.session);
|
||||||
@ -629,7 +633,10 @@ impl ClusterSession for SessionImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_finished(&self) -> bool {
|
fn is_finished(&self) -> bool {
|
||||||
self.data.lock().result.is_some()
|
let data = self.data.lock();
|
||||||
|
data.consensus_session.state() == ConsensusSessionState::Failed
|
||||||
|
|| data.consensus_session.state() == ConsensusSessionState::Finished
|
||||||
|
|| data.result.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_node_timeout(&self, node: &NodeId) {
|
fn on_node_timeout(&self, node: &NodeId) {
|
||||||
|
@ -31,7 +31,7 @@ use bigint::hash::H256;
|
|||||||
use key_server_cluster::{Error, NodeId, SessionId, AclStorage, KeyStorage, KeyServerSet, NodeKeyPair};
|
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, AdminSessionWrapper, KeyNegotiationSessionWrapper, SessionIdWithSubSession,
|
DecryptionSessionWrapper, SigningSessionWrapper, AdminSessionWrapper, KeyNegotiationSessionWrapper, SessionIdWithSubSession,
|
||||||
ClusterSessionsContainer, SERVERS_SET_CHANGE_SESSION_ID, create_cluster_view};
|
ClusterSessionsContainer, SERVERS_SET_CHANGE_SESSION_ID, create_cluster_view, AdminSessionCreationData};
|
||||||
use key_server_cluster::cluster_sessions_creator::{ClusterSessionCreator, IntoSessionId};
|
use key_server_cluster::cluster_sessions_creator::{ClusterSessionCreator, IntoSessionId};
|
||||||
use key_server_cluster::message::{self, Message, ClusterMessage};
|
use key_server_cluster::message::{self, Message, ClusterMessage};
|
||||||
use key_server_cluster::generation_session::{Session as GenerationSession};
|
use key_server_cluster::generation_session::{Session as GenerationSession};
|
||||||
@ -519,7 +519,7 @@ impl ClusterCore {
|
|||||||
let creation_data = SC::creation_data_from_message(&message)?;
|
let creation_data = SC::creation_data_from_message(&message)?;
|
||||||
let master = if is_initialization_message { sender.clone() } else { data.self_key_pair.public().clone() };
|
let master = if is_initialization_message { sender.clone() } else { data.self_key_pair.public().clone() };
|
||||||
let cluster = create_cluster_view(data, requires_all_connections(&message))?;
|
let cluster = create_cluster_view(data, requires_all_connections(&message))?;
|
||||||
sessions.insert(cluster, master, session_id.clone(), Some(message.session_nonce().ok_or(Error::InvalidMessage)?), message.is_exclusive_session_message(), creation_data)
|
sessions.insert(cluster, master, session_id, Some(message.session_nonce().ok_or(Error::InvalidMessage)?), message.is_exclusive_session_message(), creation_data)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,7 +536,7 @@ impl ClusterCore {
|
|||||||
Ok(session) => session,
|
Ok(session) => session,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// this is new session => it is not yet in container
|
// this is new session => it is not yet in container
|
||||||
warn!(target: "secretstore_net", "{}: {} session initialization error '{}' when requested for new session from node {}",
|
warn!(target: "secretstore_net", "{}: {} session read error '{}' when requested for session from node {}",
|
||||||
data.self_key_pair.public(), S::type_name(), error, sender);
|
data.self_key_pair.public(), S::type_name(), error, sender);
|
||||||
if message.is_initialization_message() {
|
if message.is_initialization_message() {
|
||||||
let session_id = message.into_session_id().expect("session_id only fails for cluster messages; only session messages are passed to process_message; qed");
|
let session_id = message.into_session_id().expect("session_id only fails for cluster messages; only session messages are passed to process_message; qed");
|
||||||
@ -969,7 +969,7 @@ impl ClusterClient for ClusterClientImpl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let cluster = create_cluster_view(&self.data, true)?;
|
let cluster = create_cluster_view(&self.data, true)?;
|
||||||
let session = self.data.sessions.admin_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, true, None)?;
|
let session = self.data.sessions.admin_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, true, Some(AdminSessionCreationData::ServersSetChange))?;
|
||||||
let initialization_result = session.as_servers_set_change().expect("servers set change session is created; qed")
|
let initialization_result = session.as_servers_set_change().expect("servers set change session is created; qed")
|
||||||
.initialize(new_nodes_set, old_set_signature, new_set_signature);
|
.initialize(new_nodes_set, old_set_signature, new_set_signature);
|
||||||
|
|
||||||
@ -1294,15 +1294,26 @@ pub mod tests {
|
|||||||
assert!(session.joint_public_and_secret().unwrap().is_ok());
|
assert!(session.joint_public_and_secret().unwrap().is_ok());
|
||||||
|
|
||||||
// now remove share from node2
|
// now remove share from node2
|
||||||
|
assert!((0..3).all(|i| clusters[i].data.sessions.generation_sessions.is_empty()));
|
||||||
clusters[2].data.config.key_storage.remove(&Default::default()).unwrap();
|
clusters[2].data.config.key_storage.remove(&Default::default()).unwrap();
|
||||||
|
|
||||||
// and try to sign message with generated key
|
// and try to sign message with generated key
|
||||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||||
let session0 = clusters[0].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
let session0 = clusters[0].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||||
let session = clusters[0].data.sessions.signing_sessions.first().unwrap();
|
let session = clusters[0].data.sessions.signing_sessions.first().unwrap();
|
||||||
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished());
|
|
||||||
|
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i|
|
||||||
|
clusters[i].data.sessions.signing_sessions.is_empty()));
|
||||||
session0.wait().unwrap();
|
session0.wait().unwrap();
|
||||||
|
|
||||||
|
// and try to sign message with generated key using node that has no key share
|
||||||
|
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||||
|
let session2 = clusters[2].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||||
|
let session = clusters[2].data.sessions.signing_sessions.first().unwrap();
|
||||||
|
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i|
|
||||||
|
clusters[i].data.sessions.signing_sessions.is_empty()));
|
||||||
|
session2.wait().unwrap();
|
||||||
|
|
||||||
// now remove share from node1
|
// now remove share from node1
|
||||||
clusters[1].data.config.key_storage.remove(&Default::default()).unwrap();
|
clusters[1].data.config.key_storage.remove(&Default::default()).unwrap();
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ pub struct SessionIdWithSubSession {
|
|||||||
/// Generic cluster session.
|
/// Generic cluster session.
|
||||||
pub trait ClusterSession {
|
pub trait ClusterSession {
|
||||||
/// Session identifier type.
|
/// Session identifier type.
|
||||||
type Id: Ord + Clone;
|
type Id: ::std::fmt::Debug + Ord + Clone;
|
||||||
|
|
||||||
/// Session type name.
|
/// Session type name.
|
||||||
fn type_name() -> &'static str;
|
fn type_name() -> &'static str;
|
||||||
@ -662,6 +662,13 @@ impl AdminSessionWrapper {
|
|||||||
cluster: cluster,
|
cluster: cluster,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn wait(&self) -> Result<(), Error> {
|
||||||
|
match *self.session {
|
||||||
|
AdminSession::ShareAdd(ref session) => session.wait(),
|
||||||
|
AdminSession::ServersSetChange(ref session) => session.wait(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShareAddSession for AdminSessionWrapper {
|
impl ShareAddSession for AdminSessionWrapper {
|
||||||
|
@ -1163,7 +1163,7 @@ impl fmt::Display for ConsensusMessageWithServersSet {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ConsensusMessageWithServersSet::InitializeConsensusSession(_) => write!(f, "InitializeConsensusSession"),
|
ConsensusMessageWithServersSet::InitializeConsensusSession(_) => write!(f, "InitializeConsensusSession"),
|
||||||
ConsensusMessageWithServersSet::ConfirmConsensusInitialization(_) => write!(f, "ConfirmConsensusInitialization"),
|
ConsensusMessageWithServersSet::ConfirmConsensusInitialization(ref msg) => write!(f, "ConfirmConsensusInitialization({})", msg.is_confirmed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1172,7 +1172,7 @@ impl fmt::Display for ConsensusMessageOfShareAdd {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ConsensusMessageOfShareAdd::InitializeConsensusSession(_) => write!(f, "InitializeConsensusSession"),
|
ConsensusMessageOfShareAdd::InitializeConsensusSession(_) => write!(f, "InitializeConsensusSession"),
|
||||||
ConsensusMessageOfShareAdd::ConfirmConsensusInitialization(_) => write!(f, "ConfirmConsensusInitialization"),
|
ConsensusMessageOfShareAdd::ConfirmConsensusInitialization(ref msg) => write!(f, "ConfirmConsensusInitialization({})", msg.is_confirmed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
// 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::collections::BTreeSet;
|
||||||
use ethkey::{KeyPair, Signature, Error as EthKeyError};
|
use ethkey::{KeyPair, Signature, Error as EthKeyError};
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey,
|
use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey,
|
||||||
EncryptedDocumentKeyShadow};
|
EncryptedDocumentKeyShadow, NodeId};
|
||||||
|
|
||||||
/// Node key pair.
|
/// Node key pair.
|
||||||
pub trait NodeKeyPair: Send + Sync {
|
pub trait NodeKeyPair: Send + Sync {
|
||||||
@ -81,7 +82,15 @@ pub trait MessageSigner: ServerKeyGenerator {
|
|||||||
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error>;
|
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Administrative sessions server.
|
||||||
|
pub trait AdminSessionsServer {
|
||||||
|
/// Change servers set so that nodes in new_servers_set became owners of shares for all keys.
|
||||||
|
/// And old nodes (i.e. cluste nodes except new_servers_set) have clear databases.
|
||||||
|
/// WARNING: newly generated keys will be distributed among all cluster nodes. So this session
|
||||||
|
/// must be followed with cluster nodes change (either via contract, or config files).
|
||||||
|
fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet<NodeId>) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Key server.
|
/// Key server.
|
||||||
pub trait KeyServer: DocumentKeyServer + MessageSigner + Send + Sync {
|
pub trait KeyServer: AdminSessionsServer + DocumentKeyServer + MessageSigner + Send + Sync {
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user