diff --git a/Cargo.lock b/Cargo.lock
index 1a370af35..4f7b0d510 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2145,6 +2145,7 @@ dependencies = [
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"stats 0.1.0",
"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)",
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vm 0.1.0",
diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml
index 9fd178dd8..beb42b8d2 100644
--- a/rpc/Cargo.toml
+++ b/rpc/Cargo.toml
@@ -24,6 +24,7 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
time = "0.1"
+tiny-keccak = "1.3"
tokio-timer = "0.1"
transient-hashmap = "0.4"
itertools = "0.5"
diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs
index 3d782d419..113ac19ff 100644
--- a/rpc/src/lib.rs
+++ b/rpc/src/lib.rs
@@ -37,6 +37,7 @@ extern crate semver;
extern crate serde;
extern crate serde_json;
extern crate time;
+extern crate tiny_keccak;
extern crate tokio_timer;
extern crate transient_hashmap;
diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs
index 39709e78e..4834611d8 100644
--- a/rpc/src/v1/helpers/secretstore.rs
+++ b/rpc/src/v1/helpers/secretstore.rs
@@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::collections::BTreeSet;
use rand::{Rng, OsRng};
use ethkey::{Public, Secret, math};
use crypto;
use bytes::Bytes;
use jsonrpc_core::Error;
use v1::helpers::errors;
+use v1::types::{H256, H512};
+use tiny_keccak::Keccak;
/// Initialization vector length.
const INIT_VEC_LEN: usize = 16;
@@ -61,11 +64,25 @@ pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result, encrypted_document: Bytes) -> Result {
let key = decrypt_with_shadow_coefficients(decrypted_secret, common_point, shadows)?;
decrypt_document(key.to_vec(), encrypted_document)
}
+/// Calculate Keccak(ordered servers set)
+pub fn ordered_servers_keccak(servers_set: BTreeSet) -> 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 {
// key is a previously distributely generated Public
if key.len() != 64 {
diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs
index 6ddb4a7a0..c34da62d4 100644
--- a/rpc/src/v1/impls/secretstore.rs
+++ b/rpc/src/v1/impls/secretstore.rs
@@ -16,6 +16,7 @@
//! SecretStore-specific rpc implementation.
+use std::collections::BTreeSet;
use std::sync::Arc;
use crypto::DEFAULT_MAC;
@@ -25,7 +26,7 @@ use ethcore::account_provider::AccountProvider;
use jsonrpc_core::Result;
use v1::helpers::errors;
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::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)
.map(Into::into)
}
+
+ fn sign_servers_set(&self, address: H160, password: String, servers_set: BTreeSet) -> Result {
+ 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))
+ }
}
diff --git a/rpc/src/v1/tests/mocked/secretstore.rs b/rpc/src/v1/tests/mocked/secretstore.rs
index ed278ced8..b0b01cb65 100644
--- a/rpc/src/v1/tests/mocked/secretstore.rs
+++ b/rpc/src/v1/tests/mocked/secretstore.rs
@@ -17,12 +17,14 @@
use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
+use ethkey::{KeyPair, Signature, verify_public};
use serde_json;
use jsonrpc_core::{IoHandler, Success};
use v1::metadata::Metadata;
use v1::SecretStoreClient;
use v1::traits::secretstore::SecretStore;
+use v1::helpers::secretstore::ordered_servers_keccak;
struct Dependencies {
pub accounts: Arc,
@@ -51,7 +53,7 @@ fn rpc_secretstore_encrypt_and_decrypt() {
let deps = Dependencies::new();
let io = deps.default_client();
- // insert new account && unlock it
+ // insert new account
let secret = "c1f1cfe279a5c350d13795bce162941967340c8a228e6ba175489afc564a5bef".parse().unwrap();
deps.accounts.insert_account(secret, "password").unwrap();
@@ -81,7 +83,7 @@ fn rpc_secretstore_shadow_decrypt() {
let deps = Dependencies::new();
let io = deps.default_client();
- // insert new account && unlock it
+ // insert new account
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().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();
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());
+}
diff --git a/rpc/src/v1/traits/secretstore.rs b/rpc/src/v1/traits/secretstore.rs
index e625cf331..f63bdce92 100644
--- a/rpc/src/v1/traits/secretstore.rs
+++ b/rpc/src/v1/traits/secretstore.rs
@@ -16,6 +16,7 @@
//! SecretStore-specific rpc interface.
+use std::collections::BTreeSet;
use jsonrpc_core::Result;
use v1::types::{H160, H512, Bytes};
@@ -37,5 +38,10 @@ build_rpc_trait! {
/// Arguments: `account`, `password`, `decrypted_secret`, `common_point`, `decrypt_shadows`, `data`.
#[rpc(name = "secretstore_shadowDecrypt")]
fn shadow_decrypt(&self, H160, String, H512, H512, Vec, Bytes) -> Result;
+
+ /// 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) -> Result;
}
}
diff --git a/secret_store/src/http_listener.rs b/secret_store/src/http_listener.rs
index 883389365..b6e48f1c5 100644
--- a/secret_store/src/http_listener.rs
+++ b/secret_store/src/http_listener.rs
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::collections::BTreeSet;
+use std::io::Read;
use std::sync::Arc;
use hyper::header;
use hyper::uri::RequestUri;
@@ -25,10 +27,10 @@ use serde::Serialize;
use serde_json;
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 types::all::{Error, Public, MessageHash, EncryptedMessageSignature, NodeAddress, RequestSignature, ServerKeyId,
- EncryptedDocumentKey, EncryptedDocumentKeyShadow};
+ EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId};
/// Key server http-requests listener. Available requests:
/// 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 shadow: GET /shadow/{server_key_id}/{signature}
/// 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 {
http_server: Option,
@@ -60,6 +63,8 @@ enum Request {
GetDocumentKeyShadow(ServerKeyId, RequestSignature),
/// Sign message.
SignMessage(ServerKeyId, RequestSignature, MessageHash),
+ /// Change servers set.
+ ChangeServersSet(RequestSignature, RequestSignature, BTreeSet),
}
/// Cloneable http handler
@@ -96,6 +101,12 @@ impl KeyServerHttpListener where T: KeyServer + 'static {
impl KeyServer for KeyServerHttpListener where T: KeyServer + 'static {}
+impl AdminSessionsServer for KeyServerHttpListener where T: KeyServer + 'static {
+ fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet) -> Result<(), Error> {
+ self.handler.key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)
+ }
+}
+
impl ServerKeyGenerator for KeyServerHttpListener where T: KeyServer + 'static {
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result {
self.handler.key_server.generate_key(key_id, signature, threshold)
@@ -134,17 +145,24 @@ impl Drop for KeyServerHttpListener where T: KeyServer + 'static {
}
impl HttpHandler for KeyServerHttpHandler 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::() {
warn!(target: "secretstore", "Ignoring {}-request {} with Origin header", req.method, req.uri);
*res.status_mut() = HttpStatusCode::NotFound;
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_uri = req.uri.clone();
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) => {
return_server_public_key(req, res, self.handler.key_server.generate_key(&document, &signature, threshold)
.map_err(|err| {
@@ -187,6 +205,13 @@ impl HttpHandler for KeyServerHttpHandler where T: KeyServer + 'static {
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 => {
warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri);
*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() {
Ok(path) => path,
Err(_) => return Request::Invalid,
@@ -272,6 +297,10 @@ fn parse_request(method: &HttpMethod, uri_path: &str) -> Request {
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 args_count = path.len() - args_offset;
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, 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 = 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)]
mod tests {
use hyper::method::Method as HttpMethod;
+ use ethkey::Public;
use key_server::tests::DummyKeyServer;
use types::all::NodeAddress;
use super::{parse_request, Request, KeyServerHttpListener};
@@ -326,48 +381,66 @@ mod tests {
#[test]
fn parse_request_successful() {
// 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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
2));
// 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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
"b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8".parse().unwrap(),
"1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb".parse().unwrap()));
// 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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
2));
// 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(),
"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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
// 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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
// 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(),
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".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]
fn parse_request_failed() {
- assert_eq!(parse_request(&HttpMethod::Get, ""), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/shadow"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "///2"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/shadow///2"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/a/b"), Request::Invalid);
- assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002"), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "/shadow", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "///2", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "/shadow///2", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/", Default::default()), Request::Invalid);
+ assert_eq!(parse_request(&HttpMethod::Get, "/a/b", Default::default()), 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);
}
}
diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs
index ac6c45489..0d23b99c8 100644
--- a/secret_store/src/key_server.rs
+++ b/secret_store/src/key_server.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::collections::BTreeSet;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc;
@@ -26,9 +27,9 @@ use super::acl_storage::AclStorage;
use super::key_storage::KeyStorage;
use super::key_server_set::KeyServerSet;
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,
- ClusterConfiguration, MessageHash, EncryptedMessageSignature};
+ ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId};
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration};
/// Secret store key server implementation
@@ -60,6 +61,14 @@ impl 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) -> 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 {
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result {
// recover requestor' public key from signature
@@ -153,7 +162,7 @@ impl KeyServerCore {
allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes,
acl_storage: acl_storage,
key_storage: key_storage,
- admin_public: None,
+ admin_public: config.admin_public.clone(),
};
let (stop, stopped) = futures::oneshot();
@@ -191,6 +200,7 @@ impl Drop for KeyServerCore {
#[cfg(test)]
pub mod tests {
+ use std::collections::BTreeSet;
use std::time;
use std::sync::Arc;
use std::net::SocketAddr;
@@ -204,14 +214,20 @@ pub mod tests {
use key_server_cluster::math;
use bigint::hash::H256;
use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
- EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature};
- use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
+ EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, NodeId};
+ use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
use super::KeyServerImpl;
pub struct 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) -> Result<(), Error> {
+ unimplemented!()
+ }
+ }
+
impl ServerKeyGenerator for DummyKeyServer {
fn generate_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result {
unimplemented!()
@@ -444,4 +460,9 @@ pub mod tests {
// check signature
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
+ }
}
diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs
index feb23c9ae..223caef21 100644
--- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs
+++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs
@@ -412,7 +412,7 @@ impl SessionImpl {
key_share: key_share,
result_computer: Arc::new(LargestSupportResultComputer {}),
transport: ServersSetChangeKeyVersionNegotiationTransport {
- id: key_id,
+ id: self.core.meta.id.clone(),
nonce: self.core.nonce,
cluster: self.core.cluster.clone(),
},
@@ -687,7 +687,7 @@ impl SessionImpl {
/// Create share change session.
fn create_share_change_session(core: &SessionCore, key_id: SessionId, master_node_id: NodeId, session_plan: ShareChangeSessionPlan) -> Result {
ShareChangeSession::new(ShareChangeSessionParams {
- session_id: key_id.clone(),
+ session_id: core.meta.id.clone(),
nonce: core.nonce,
meta: ShareChangeSessionMeta {
id: key_id,
@@ -726,7 +726,7 @@ impl SessionImpl {
key_share: key_share,
result_computer: Arc::new(LargestSupportResultComputer {}), // TODO: optimizations: could use modified Fast version
transport: ServersSetChangeKeyVersionNegotiationTransport {
- id: key_id,
+ id: core.meta.id.clone(),
nonce: core.nonce,
cluster: core.cluster.clone(),
},
@@ -855,11 +855,20 @@ impl SessionImpl {
/// Complete servers set change session.
fn complete_session(core: &SessionCore, data: &mut SessionData) -> Result<(), Error> {
debug_assert_eq!(core.meta.self_node_id, core.meta.master_node_id);
+
+ // send completion notification
core.cluster.broadcast(Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeCompleted(ServersSetChangeCompleted {
session: core.meta.id.clone().into(),
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.result = Some(Ok(()));
core.completed.notify_all();
diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs
index e907f6c13..087fc9245 100644
--- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs
+++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::collections::BTreeSet;
use std::sync::Arc;
use parking_lot::{Mutex, Condvar};
use bigint::hash::H256;
@@ -243,14 +244,19 @@ impl SessionImpl {
let mut data = self.data.lock();
let non_isolated_nodes = self.core.cluster.nodes();
- 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(key_version.id_numbers.keys()
+ let mut consensus_nodes: BTreeSet<_> = key_version.id_numbers.keys()
.filter(|n| non_isolated_nodes.contains(*n))
.cloned()
.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 {
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 {
- 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) {
@@ -1146,7 +1155,7 @@ mod tests {
// now check that:
// 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
assert_eq!(sessions[1].decrypted_secret().unwrap().unwrap(), EncryptedDocumentKeyShadow {
decrypted_secret: SECRET_PLAIN.into(),
diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs
index b6926751b..5c21d5786 100644
--- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs
+++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs
@@ -1322,7 +1322,7 @@ pub mod tests {
let mut core = Core::new().unwrap();
// 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);
// establish connections
diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session.rs
index 6ca47580e..2f33160fa 100644
--- a/secret_store/src/key_server_cluster/client_sessions/signing_session.rs
+++ b/secret_store/src/key_server_cluster/client_sessions/signing_session.rs
@@ -250,14 +250,19 @@ impl SessionImpl {
let mut data = self.data.lock();
let non_isolated_nodes = self.core.cluster.nodes();
- 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(key_version.id_numbers.keys()
+ let mut consensus_nodes: BTreeSet<_> = key_version.id_numbers.keys()
.filter(|n| non_isolated_nodes.contains(*n))
.cloned()
.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 {
let generation_session = GenerationSession::new(GenerationSessionParams {
@@ -355,7 +360,6 @@ impl SessionImpl {
Ok(())
}
-
/// When consensus-related message is received.
pub fn on_consensus_message(&self, sender: &NodeId, message: &SigningConsensusMessage) -> Result<(), Error> {
debug_assert!(self.core.meta.id == *message.session);
@@ -629,7 +633,10 @@ impl ClusterSession for SessionImpl {
}
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) {
diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs
index 23df97cb3..0a975c275 100644
--- a/secret_store/src/key_server_cluster/cluster.rs
+++ b/secret_store/src/key_server_cluster/cluster.rs
@@ -31,7 +31,7 @@ use bigint::hash::H256;
use key_server_cluster::{Error, NodeId, SessionId, AclStorage, KeyStorage, KeyServerSet, NodeKeyPair};
use key_server_cluster::cluster_sessions::{ClusterSession, ClusterSessions, GenerationSessionWrapper, EncryptionSessionWrapper,
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::message::{self, Message, ClusterMessage};
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 master = if is_initialization_message { sender.clone() } else { data.self_key_pair.public().clone() };
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,
Err(error) => {
// 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);
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");
@@ -969,7 +969,7 @@ impl ClusterClient for ClusterClientImpl {
};
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")
.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());
// 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();
// and try to sign message with generated key
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 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();
+ // 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
clusters[1].data.config.key_storage.remove(&Default::default()).unwrap();
diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs
index ce98bd878..254e3ecc6 100644
--- a/secret_store/src/key_server_cluster/cluster_sessions.rs
+++ b/secret_store/src/key_server_cluster/cluster_sessions.rs
@@ -66,7 +66,7 @@ pub struct SessionIdWithSubSession {
/// Generic cluster session.
pub trait ClusterSession {
/// Session identifier type.
- type Id: Ord + Clone;
+ type Id: ::std::fmt::Debug + Ord + Clone;
/// Session type name.
fn type_name() -> &'static str;
@@ -662,6 +662,13 @@ impl AdminSessionWrapper {
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 {
diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs
index 43d27d1fd..357786725 100644
--- a/secret_store/src/key_server_cluster/message.rs
+++ b/secret_store/src/key_server_cluster/message.rs
@@ -1163,7 +1163,7 @@ impl fmt::Display for ConsensusMessageWithServersSet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
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 {
match *self {
ConsensusMessageOfShareAdd::InitializeConsensusSession(_) => write!(f, "InitializeConsensusSession"),
- ConsensusMessageOfShareAdd::ConfirmConsensusInitialization(_) => write!(f, "ConfirmConsensusInitialization"),
+ ConsensusMessageOfShareAdd::ConfirmConsensusInitialization(ref msg) => write!(f, "ConfirmConsensusInitialization({})", msg.is_confirmed),
}
}
}
diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs
index 7ee4c5cc1..0982f40e3 100644
--- a/secret_store/src/traits.rs
+++ b/secret_store/src/traits.rs
@@ -14,10 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::collections::BTreeSet;
use ethkey::{KeyPair, Signature, Error as EthKeyError};
use bigint::hash::H256;
use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey,
- EncryptedDocumentKeyShadow};
+ EncryptedDocumentKeyShadow, NodeId};
/// Node key pair.
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;
}
+/// 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) -> Result<(), Error>;
+}
/// Key server.
-pub trait KeyServer: DocumentKeyServer + MessageSigner + Send + Sync {
+pub trait KeyServer: AdminSessionsServer + DocumentKeyServer + MessageSigner + Send + Sync {
}