SecretStore: expose restore_key_public in HTTP API (#10241)
This commit is contained in:
parent
f7dae48c17
commit
6be45367e9
@ -78,6 +78,22 @@ impl ServerKeyGenerator for KeyServerImpl {
|
|||||||
.expect("when wait is called without timeout it always returns Some; qed")
|
.expect("when wait is called without timeout it always returns Some; qed")
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn restore_key_public(&self, key_id: &ServerKeyId, author: &Requester) -> Result<Public, Error> {
|
||||||
|
// recover requestor' public key from signature
|
||||||
|
let address = author.address(key_id).map_err(Error::InsufficientRequesterData)?;
|
||||||
|
|
||||||
|
// negotiate key version && retrieve common key data
|
||||||
|
let negotiation_session = self.data.lock().cluster.new_key_version_negotiation_session(*key_id)?;
|
||||||
|
negotiation_session.wait()
|
||||||
|
.and_then(|_| negotiation_session.common_key_data())
|
||||||
|
.and_then(|key_share| if key_share.author == address {
|
||||||
|
Ok(key_share.public)
|
||||||
|
} else {
|
||||||
|
Err(Error::AccessDenied)
|
||||||
|
})
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentKeyServer for KeyServerImpl {
|
impl DocumentKeyServer for KeyServerImpl {
|
||||||
@ -237,6 +253,10 @@ pub mod tests {
|
|||||||
fn generate_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result<Public, Error> {
|
fn generate_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result<Public, Error> {
|
||||||
unimplemented!("test-only")
|
unimplemented!("test-only")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn restore_key_public(&self, _key_id: &ServerKeyId, _author: &Requester) -> Result<Public, Error> {
|
||||||
|
unimplemented!("test-only")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentKeyServer for DummyKeyServer {
|
impl DocumentKeyServer for DummyKeyServer {
|
||||||
|
@ -26,7 +26,7 @@ use key_server_cluster::decryption_session::SessionImpl as DecryptionSession;
|
|||||||
use key_server_cluster::signing_session_ecdsa::SessionImpl as EcdsaSigningSession;
|
use key_server_cluster::signing_session_ecdsa::SessionImpl as EcdsaSigningSession;
|
||||||
use key_server_cluster::signing_session_schnorr::SessionImpl as SchnorrSigningSession;
|
use key_server_cluster::signing_session_schnorr::SessionImpl as SchnorrSigningSession;
|
||||||
use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions,
|
use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions,
|
||||||
KeyVersions, KeyVersionsError, FailedKeyVersionContinueAction};
|
KeyVersions, KeyVersionsError, FailedKeyVersionContinueAction, CommonKeyData};
|
||||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||||
|
|
||||||
// TODO [Opt]: change sessions so that versions are sent by chunks.
|
// TODO [Opt]: change sessions so that versions are sent by chunks.
|
||||||
@ -97,8 +97,8 @@ struct SessionData {
|
|||||||
pub state: SessionState,
|
pub state: SessionState,
|
||||||
/// Initialization confirmations.
|
/// Initialization confirmations.
|
||||||
pub confirmations: Option<BTreeSet<NodeId>>,
|
pub confirmations: Option<BTreeSet<NodeId>>,
|
||||||
/// Key threshold.
|
/// Common key data that nodes have agreed upon.
|
||||||
pub threshold: Option<usize>,
|
pub key_share: Option<DocumentKeyShare>,
|
||||||
/// { Version => Nodes }
|
/// { Version => Nodes }
|
||||||
pub versions: Option<BTreeMap<H256, BTreeSet<NodeId>>>,
|
pub versions: Option<BTreeMap<H256, BTreeSet<NodeId>>>,
|
||||||
/// Session result.
|
/// Session result.
|
||||||
@ -167,12 +167,11 @@ pub struct LargestSupportResultComputer;
|
|||||||
impl<T> SessionImpl<T> where T: SessionTransport {
|
impl<T> SessionImpl<T> where T: SessionTransport {
|
||||||
/// Create new session.
|
/// Create new session.
|
||||||
pub fn new(params: SessionParams<T>) -> Self {
|
pub fn new(params: SessionParams<T>) -> Self {
|
||||||
let threshold = params.key_share.as_ref().map(|key_share| key_share.threshold);
|
|
||||||
SessionImpl {
|
SessionImpl {
|
||||||
core: SessionCore {
|
core: SessionCore {
|
||||||
meta: params.meta,
|
meta: params.meta,
|
||||||
sub_session: params.sub_session,
|
sub_session: params.sub_session,
|
||||||
key_share: params.key_share,
|
key_share: params.key_share.clone(),
|
||||||
result_computer: params.result_computer,
|
result_computer: params.result_computer,
|
||||||
transport: params.transport,
|
transport: params.transport,
|
||||||
nonce: params.nonce,
|
nonce: params.nonce,
|
||||||
@ -181,7 +180,12 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
data: Mutex::new(SessionData {
|
data: Mutex::new(SessionData {
|
||||||
state: SessionState::WaitingForInitialization,
|
state: SessionState::WaitingForInitialization,
|
||||||
confirmations: None,
|
confirmations: None,
|
||||||
threshold: threshold,
|
key_share: params.key_share.map(|key_share| DocumentKeyShare {
|
||||||
|
threshold: key_share.threshold,
|
||||||
|
author: key_share.author,
|
||||||
|
public: key_share.public,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
versions: None,
|
versions: None,
|
||||||
result: None,
|
result: None,
|
||||||
continue_with: None,
|
continue_with: None,
|
||||||
@ -195,12 +199,6 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
&self.core.meta
|
&self.core.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return key threshold.
|
|
||||||
pub fn key_threshold(&self) -> Result<usize, Error> {
|
|
||||||
self.data.lock().threshold.clone()
|
|
||||||
.ok_or(Error::InvalidStateForRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return result computer reference.
|
/// Return result computer reference.
|
||||||
pub fn version_holders(&self, version: &H256) -> Result<BTreeSet<NodeId>, Error> {
|
pub fn version_holders(&self, version: &H256) -> Result<BTreeSet<NodeId>, Error> {
|
||||||
Ok(self.data.lock().versions.as_ref().ok_or(Error::InvalidStateForRequest)?
|
Ok(self.data.lock().versions.as_ref().ok_or(Error::InvalidStateForRequest)?
|
||||||
@ -229,6 +227,12 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
.expect("wait_session returns Some if called without timeout; qed")
|
.expect("wait_session returns Some if called without timeout; qed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve common key data (author, threshold, public), if available.
|
||||||
|
pub fn common_key_data(&self) -> Result<DocumentKeyShare, Error> {
|
||||||
|
self.data.lock().key_share.clone()
|
||||||
|
.ok_or(Error::InvalidStateForRequest)
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize session.
|
/// Initialize session.
|
||||||
pub fn initialize(&self, connected_nodes: BTreeSet<NodeId>) -> Result<(), Error> {
|
pub fn initialize(&self, connected_nodes: BTreeSet<NodeId>) -> Result<(), Error> {
|
||||||
// check state
|
// check state
|
||||||
@ -322,7 +326,11 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
session: self.core.meta.id.clone().into(),
|
session: self.core.meta.id.clone().into(),
|
||||||
sub_session: self.core.sub_session.clone().into(),
|
sub_session: self.core.sub_session.clone().into(),
|
||||||
session_nonce: self.core.nonce,
|
session_nonce: self.core.nonce,
|
||||||
threshold: self.core.key_share.as_ref().map(|key_share| key_share.threshold),
|
key_common: self.core.key_share.as_ref().map(|key_share| CommonKeyData {
|
||||||
|
threshold: key_share.threshold,
|
||||||
|
author: key_share.author.into(),
|
||||||
|
public: key_share.public.into(),
|
||||||
|
}),
|
||||||
versions: self.core.key_share.as_ref().map(|key_share|
|
versions: self.core.key_share.as_ref().map(|key_share|
|
||||||
key_share.versions.iter().rev()
|
key_share.versions.iter().rev()
|
||||||
.filter(|v| v.id_numbers.contains_key(sender))
|
.filter(|v| v.id_numbers.contains_key(sender))
|
||||||
@ -357,12 +365,25 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
|
|
||||||
// remember versions that sender have
|
// remember versions that sender have
|
||||||
{
|
{
|
||||||
match message.threshold.clone() {
|
match message.key_common.as_ref() {
|
||||||
Some(threshold) if data.threshold.is_none() => {
|
Some(key_common) if data.key_share.is_none() => {
|
||||||
data.threshold = Some(threshold);
|
data.key_share = Some(DocumentKeyShare {
|
||||||
|
threshold: key_common.threshold,
|
||||||
|
author: key_common.author.clone().into(),
|
||||||
|
public: key_common.public.clone().into(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Some(key_common) => {
|
||||||
|
let prev_key_share = data.key_share.as_ref()
|
||||||
|
.expect("data.key_share.is_none() is matched by previous branch; qed");
|
||||||
|
if prev_key_share.threshold != key_common.threshold ||
|
||||||
|
prev_key_share.author.as_bytes() != key_common.author.as_bytes() ||
|
||||||
|
prev_key_share.public.as_bytes() != key_common.public.as_bytes()
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(threshold) if data.threshold.as_ref() == Some(&threshold) => (),
|
|
||||||
Some(_) => return Err(Error::InvalidMessage),
|
|
||||||
None if message.versions.is_empty() => (),
|
None if message.versions.is_empty() => (),
|
||||||
None => return Err(Error::InvalidMessage),
|
None => return Err(Error::InvalidMessage),
|
||||||
}
|
}
|
||||||
@ -388,7 +409,8 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
let reason = "this field is filled on master node when initializing; try_complete is only called on initialized master node; qed";
|
let reason = "this field is filled on master node when initializing; try_complete is only called on initialized master node; qed";
|
||||||
let confirmations = data.confirmations.as_ref().expect(reason);
|
let confirmations = data.confirmations.as_ref().expect(reason);
|
||||||
let versions = data.versions.as_ref().expect(reason);
|
let versions = data.versions.as_ref().expect(reason);
|
||||||
if let Some(result) = core.result_computer.compute_result(data.threshold.clone(), confirmations, versions) {
|
let threshold = data.key_share.as_ref().map(|key_share| key_share.threshold);
|
||||||
|
if let Some(result) = core.result_computer.compute_result(threshold, confirmations, versions) {
|
||||||
// when the master node processing decryption service request, it starts with a key version negotiation session
|
// when the master node processing decryption service request, it starts with a key version negotiation session
|
||||||
// if the negotiation fails, only master node knows about it
|
// if the negotiation fails, only master node knows about it
|
||||||
// => if the error is fatal, only the master will know about it and report it to the contract && the request will never be rejected
|
// => if the error is fatal, only the master will know about it and report it to the contract && the request will never be rejected
|
||||||
@ -590,7 +612,7 @@ impl SessionResultComputer for LargestSupportResultComputer {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::{VecDeque, BTreeMap, BTreeSet};
|
use std::collections::{VecDeque, BTreeMap, BTreeSet};
|
||||||
use ethereum_types::{H512, Address};
|
use ethereum_types::{H512, H160, Address};
|
||||||
use ethkey::public_to_address;
|
use ethkey::public_to_address;
|
||||||
use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage,
|
use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage,
|
||||||
DocumentKeyShare, DocumentKeyShareVersion};
|
DocumentKeyShare, DocumentKeyShareVersion};
|
||||||
@ -600,7 +622,10 @@ mod tests {
|
|||||||
use key_server_cluster::cluster_sessions::ClusterSession;
|
use key_server_cluster::cluster_sessions::ClusterSession;
|
||||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||||
use key_server_cluster::decryption_session::create_default_decryption_session;
|
use key_server_cluster::decryption_session::create_default_decryption_session;
|
||||||
use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions, KeyVersions};
|
use key_server_cluster::message::{
|
||||||
|
Message, KeyVersionNegotiationMessage, RequestKeyVersions,
|
||||||
|
CommonKeyData, KeyVersions,
|
||||||
|
};
|
||||||
use super::{
|
use super::{
|
||||||
SessionImpl, SessionTransport, SessionParams, FastestResultComputer, LargestSupportResultComputer,
|
SessionImpl, SessionTransport, SessionParams, FastestResultComputer, LargestSupportResultComputer,
|
||||||
SessionResultComputer, SessionState, ContinueAction, FailedContinueAction,
|
SessionResultComputer, SessionState, ContinueAction, FailedContinueAction,
|
||||||
@ -759,7 +784,11 @@ mod tests {
|
|||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: Some(10),
|
key_common: Some(CommonKeyData {
|
||||||
|
threshold: 10,
|
||||||
|
author: Default::default(),
|
||||||
|
public: Default::default(),
|
||||||
|
}),
|
||||||
versions: Vec::new(),
|
versions: Vec::new(),
|
||||||
})), Err(Error::InvalidStateForRequest));
|
})), Err(Error::InvalidStateForRequest));
|
||||||
}
|
}
|
||||||
@ -775,7 +804,12 @@ mod tests {
|
|||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: Some(0),
|
key_common: Some(CommonKeyData {
|
||||||
|
threshold: 0,
|
||||||
|
author: Default::default(),
|
||||||
|
public: Default::default(),
|
||||||
|
}),
|
||||||
|
|
||||||
versions: vec![version_id.clone().into()]
|
versions: vec![version_id.clone().into()]
|
||||||
})), Ok(()));
|
})), Ok(()));
|
||||||
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
||||||
@ -784,14 +818,20 @@ mod tests {
|
|||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: Some(0),
|
key_common: Some(CommonKeyData {
|
||||||
|
threshold: 0,
|
||||||
|
author: Default::default(),
|
||||||
|
public: Default::default(),
|
||||||
|
}),
|
||||||
|
|
||||||
versions: vec![version_id.clone().into()]
|
versions: vec![version_id.clone().into()]
|
||||||
})), Ok(()));
|
})), Ok(()));
|
||||||
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn negotiation_fails_if_wrong_threshold_sent() {
|
fn negotiation_fails_if_wrong_common_data_sent() {
|
||||||
|
fn run_test(key_common: CommonKeyData) {
|
||||||
let ml = MessageLoop::empty(3);
|
let ml = MessageLoop::empty(3);
|
||||||
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap();
|
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap();
|
||||||
|
|
||||||
@ -800,18 +840,41 @@ mod tests {
|
|||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: Some(1),
|
key_common: Some(CommonKeyData {
|
||||||
|
threshold: 1,
|
||||||
|
author: Default::default(),
|
||||||
|
public: Default::default(),
|
||||||
|
}),
|
||||||
versions: vec![version_id.clone().into()]
|
versions: vec![version_id.clone().into()]
|
||||||
})), Ok(()));
|
})), Ok(()));
|
||||||
assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: Some(2),
|
key_common: Some(key_common),
|
||||||
versions: vec![version_id.clone().into()]
|
versions: vec![version_id.clone().into()]
|
||||||
})), Err(Error::InvalidMessage));
|
})), Err(Error::InvalidMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_test(CommonKeyData {
|
||||||
|
threshold: 2,
|
||||||
|
author: Default::default(),
|
||||||
|
public: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test(CommonKeyData {
|
||||||
|
threshold: 1,
|
||||||
|
author: H160::from_low_u64_be(1).into(),
|
||||||
|
public: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test(CommonKeyData {
|
||||||
|
threshold: 1,
|
||||||
|
author: H160::from_low_u64_be(2).into(),
|
||||||
|
public: Default::default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn negotiation_fails_if_threshold_empty_when_versions_are_not_empty() {
|
fn negotiation_fails_if_threshold_empty_when_versions_are_not_empty() {
|
||||||
let ml = MessageLoop::empty(2);
|
let ml = MessageLoop::empty(2);
|
||||||
@ -822,7 +885,7 @@ mod tests {
|
|||||||
session: Default::default(),
|
session: Default::default(),
|
||||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||||
session_nonce: 0,
|
session_nonce: 0,
|
||||||
threshold: None,
|
key_common: None,
|
||||||
versions: vec![version_id.clone().into()]
|
versions: vec![version_id.clone().into()]
|
||||||
})), Err(Error::InvalidMessage));
|
})), Err(Error::InvalidMessage));
|
||||||
}
|
}
|
||||||
@ -832,9 +895,9 @@ mod tests {
|
|||||||
let nodes = MessageLoop::prepare_nodes(2);
|
let nodes = MessageLoop::prepare_nodes(2);
|
||||||
let version_id = (*math::generate_random_scalar().unwrap()).clone();
|
let version_id = (*math::generate_random_scalar().unwrap()).clone();
|
||||||
nodes.values().nth(0).unwrap().insert(Default::default(), DocumentKeyShare {
|
nodes.values().nth(0).unwrap().insert(Default::default(), DocumentKeyShare {
|
||||||
author: Default::default(),
|
author: H160::from_low_u64_be(2),
|
||||||
threshold: 1,
|
threshold: 1,
|
||||||
public: Default::default(),
|
public: H512::from_low_u64_be(3),
|
||||||
common_point: None,
|
common_point: None,
|
||||||
encrypted_point: None,
|
encrypted_point: None,
|
||||||
versions: vec![DocumentKeyShareVersion {
|
versions: vec![DocumentKeyShareVersion {
|
||||||
@ -848,8 +911,13 @@ mod tests {
|
|||||||
// we can't be sure that node has given key version because previous ShareAdd session could fail
|
// we can't be sure that node has given key version because previous ShareAdd session could fail
|
||||||
assert!(ml.session(0).data.lock().state != SessionState::Finished);
|
assert!(ml.session(0).data.lock().state != SessionState::Finished);
|
||||||
|
|
||||||
// check that upon completion, threshold is known
|
// check that upon completion, commmon key data is known
|
||||||
assert_eq!(ml.session(0).key_threshold(), Ok(1));
|
assert_eq!(ml.session(0).common_key_data(), Ok(DocumentKeyShare {
|
||||||
|
author: H160::from_low_u64_be(2),
|
||||||
|
threshold: 1,
|
||||||
|
public: H512::from_low_u64_be(3),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -800,7 +800,7 @@ impl SessionImpl {
|
|||||||
.wait()?
|
.wait()?
|
||||||
.expect("initialize_share_change_session is only called on share change master; negotiation session completes with some on master; qed");
|
.expect("initialize_share_change_session is only called on share change master; negotiation session completes with some on master; qed");
|
||||||
let selected_version_holders = negotiation_session.version_holders(&selected_version)?;
|
let selected_version_holders = negotiation_session.version_holders(&selected_version)?;
|
||||||
let selected_version_threshold = negotiation_session.key_threshold()?;
|
let selected_version_threshold = negotiation_session.common_key_data()?.threshold;
|
||||||
|
|
||||||
// prepare session change plan && check if something needs to be changed
|
// prepare session change plan && check if something needs to be changed
|
||||||
let old_nodes_set = selected_version_holders;
|
let old_nodes_set = selected_version_holders;
|
||||||
|
@ -25,7 +25,7 @@ use key_server_cluster::cluster_sessions::ClusterSession;
|
|||||||
use key_server_cluster::math;
|
use key_server_cluster::math;
|
||||||
use key_server_cluster::message::{Message, ShareAddMessage, ShareAddConsensusMessage, ConsensusMessageOfShareAdd,
|
use key_server_cluster::message::{Message, ShareAddMessage, ShareAddConsensusMessage, ConsensusMessageOfShareAdd,
|
||||||
InitializeConsensusSessionOfShareAdd, KeyShareCommon, NewKeysDissemination, ShareAddError,
|
InitializeConsensusSessionOfShareAdd, KeyShareCommon, NewKeysDissemination, ShareAddError,
|
||||||
ConfirmConsensusInitialization};
|
ConfirmConsensusInitialization, CommonKeyData};
|
||||||
use key_server_cluster::jobs::job_session::JobTransport;
|
use key_server_cluster::jobs::job_session::JobTransport;
|
||||||
use key_server_cluster::jobs::dummy_job::{DummyJob, DummyJobTransport};
|
use key_server_cluster::jobs::dummy_job::{DummyJob, DummyJobTransport};
|
||||||
use key_server_cluster::jobs::servers_set_change_access_job::{ServersSetChangeAccessJob, ServersSetChangeAccessRequest};
|
use key_server_cluster::jobs::servers_set_change_access_job::{ServersSetChangeAccessJob, ServersSetChangeAccessRequest};
|
||||||
@ -469,9 +469,9 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
// update data
|
// update data
|
||||||
data.state = SessionState::WaitingForKeysDissemination;
|
data.state = SessionState::WaitingForKeysDissemination;
|
||||||
data.new_key_share = Some(NewKeyShare {
|
data.new_key_share = Some(NewKeyShare {
|
||||||
threshold: message.threshold,
|
threshold: message.key_common.threshold,
|
||||||
author: message.author.clone().into(),
|
author: message.key_common.author.clone().into(),
|
||||||
joint_public: message.joint_public.clone().into(),
|
joint_public: message.key_common.public.clone().into(),
|
||||||
common_point: message.common_point.clone().map(Into::into),
|
common_point: message.common_point.clone().map(Into::into),
|
||||||
encrypted_point: message.encrypted_point.clone().map(Into::into),
|
encrypted_point: message.encrypted_point.clone().map(Into::into),
|
||||||
});
|
});
|
||||||
@ -645,9 +645,11 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
|||||||
core.transport.send(new_node, ShareAddMessage::KeyShareCommon(KeyShareCommon {
|
core.transport.send(new_node, ShareAddMessage::KeyShareCommon(KeyShareCommon {
|
||||||
session: core.meta.id.clone().into(),
|
session: core.meta.id.clone().into(),
|
||||||
session_nonce: core.nonce,
|
session_nonce: core.nonce,
|
||||||
|
key_common: CommonKeyData {
|
||||||
threshold: old_key_share.threshold,
|
threshold: old_key_share.threshold,
|
||||||
author: old_key_share.author.clone().into(),
|
author: old_key_share.author.into(),
|
||||||
joint_public: old_key_share.public.clone().into(),
|
public: old_key_share.public.into(),
|
||||||
|
},
|
||||||
common_point: old_key_share.common_point.clone().map(Into::into),
|
common_point: old_key_share.common_point.clone().map(Into::into),
|
||||||
encrypted_point: old_key_share.encrypted_point.clone().map(Into::into),
|
encrypted_point: old_key_share.encrypted_point.clone().map(Into::into),
|
||||||
id_numbers: old_key_version.id_numbers.iter()
|
id_numbers: old_key_version.id_numbers.iter()
|
||||||
|
@ -970,12 +970,8 @@ pub struct KeyShareCommon {
|
|||||||
pub session: MessageSessionId,
|
pub session: MessageSessionId,
|
||||||
/// Session-level nonce.
|
/// Session-level nonce.
|
||||||
pub session_nonce: u64,
|
pub session_nonce: u64,
|
||||||
/// Key threshold.
|
/// Common key data.
|
||||||
pub threshold: usize,
|
pub key_common: CommonKeyData,
|
||||||
/// Author of key share entry.
|
|
||||||
pub author: SerializableAddress,
|
|
||||||
/// Joint public.
|
|
||||||
pub joint_public: SerializablePublic,
|
|
||||||
/// Common (shared) encryption point.
|
/// Common (shared) encryption point.
|
||||||
pub common_point: Option<SerializablePublic>,
|
pub common_point: Option<SerializablePublic>,
|
||||||
/// Encrypted point.
|
/// Encrypted point.
|
||||||
@ -1026,12 +1022,23 @@ pub struct KeyVersions {
|
|||||||
pub sub_session: SerializableSecret,
|
pub sub_session: SerializableSecret,
|
||||||
/// Session-level nonce.
|
/// Session-level nonce.
|
||||||
pub session_nonce: u64,
|
pub session_nonce: u64,
|
||||||
/// Key threshold.
|
/// Common key data, shared by all versions.
|
||||||
pub threshold: Option<usize>,
|
pub key_common: Option<CommonKeyData>,
|
||||||
/// Key versions.
|
/// Key versions.
|
||||||
pub versions: Vec<SerializableH256>,
|
pub versions: Vec<SerializableH256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Common key data.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct CommonKeyData {
|
||||||
|
/// Key threshold.
|
||||||
|
pub threshold: usize,
|
||||||
|
/// Author of the key entry.
|
||||||
|
pub author: SerializableAddress,
|
||||||
|
/// Joint public.
|
||||||
|
pub public: SerializablePublic,
|
||||||
|
}
|
||||||
|
|
||||||
/// When key versions error has occured.
|
/// When key versions error has occured.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct KeyVersionsError {
|
pub struct KeyVersionsError {
|
||||||
|
@ -34,8 +34,7 @@ type CurrentSerializableDocumentKeyShare = SerializableDocumentKeyShareV3;
|
|||||||
type CurrentSerializableDocumentKeyVersion = SerializableDocumentKeyShareVersionV3;
|
type CurrentSerializableDocumentKeyVersion = SerializableDocumentKeyShareVersionV3;
|
||||||
|
|
||||||
/// Encrypted key share, stored by key storage on the single key server.
|
/// Encrypted key share, stored by key storage on the single key server.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
#[cfg_attr(test, derive(Default))]
|
|
||||||
pub struct DocumentKeyShare {
|
pub struct DocumentKeyShare {
|
||||||
/// Author of the entry.
|
/// Author of the entry.
|
||||||
pub author: Address,
|
pub author: Address,
|
||||||
|
@ -40,6 +40,7 @@ use jsonrpc_server_utils::cors::{self, AllowCors, AccessControlAllowOrigin};
|
|||||||
/// To generate server key: POST /shadow/{server_key_id}/{signature}/{threshold}
|
/// To generate server key: POST /shadow/{server_key_id}/{signature}/{threshold}
|
||||||
/// To store pregenerated encrypted document key: POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key}
|
/// To store pregenerated encrypted document key: POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key}
|
||||||
/// To generate server && document key: POST /{server_key_id}/{signature}/{threshold}
|
/// To generate server && document key: POST /{server_key_id}/{signature}/{threshold}
|
||||||
|
/// To get public portion of server key: GET /server/{server_key_id}/{signature}
|
||||||
/// 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 generate Schnorr signature with server key: GET /schnorr/{server_key_id}/{signature}/{message_hash}
|
/// To generate Schnorr signature with server key: GET /schnorr/{server_key_id}/{signature}/{message_hash}
|
||||||
@ -64,6 +65,8 @@ enum Request {
|
|||||||
StoreDocumentKey(ServerKeyId, RequestSignature, Public, Public),
|
StoreDocumentKey(ServerKeyId, RequestSignature, Public, Public),
|
||||||
/// Generate encryption key.
|
/// Generate encryption key.
|
||||||
GenerateDocumentKey(ServerKeyId, RequestSignature, usize),
|
GenerateDocumentKey(ServerKeyId, RequestSignature, usize),
|
||||||
|
/// Request public portion of server key.
|
||||||
|
GetServerKey(ServerKeyId, RequestSignature),
|
||||||
/// Request encryption key of given document for given requestor.
|
/// Request encryption key of given document for given requestor.
|
||||||
GetDocumentKey(ServerKeyId, RequestSignature),
|
GetDocumentKey(ServerKeyId, RequestSignature),
|
||||||
/// Request shadow of encryption key of given document for given requestor.
|
/// Request shadow of encryption key of given document for given requestor.
|
||||||
@ -155,6 +158,15 @@ impl KeyServerHttpHandler {
|
|||||||
err
|
err
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
Request::GetServerKey(document, signature) => {
|
||||||
|
return_server_public_key(&req_uri, cors, self.handler.key_server.upgrade()
|
||||||
|
.map(|key_server| key_server.restore_key_public(&document, &signature.into()))
|
||||||
|
.unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into())))
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!(target: "secretstore", "GetServerKey request {} has failed with: {}", req_uri, err);
|
||||||
|
err
|
||||||
|
}))
|
||||||
|
},
|
||||||
Request::GetDocumentKey(document, signature) => {
|
Request::GetDocumentKey(document, signature) => {
|
||||||
return_document_key(&req_uri, cors, self.handler.key_server.upgrade()
|
return_document_key(&req_uri, cors, self.handler.key_server.upgrade()
|
||||||
.map(|key_server| key_server.restore_document_key(&document, &signature.into()))
|
.map(|key_server| key_server.restore_document_key(&document, &signature.into()))
|
||||||
@ -361,8 +373,8 @@ fn parse_request(method: &HttpMethod, uri_path: &str, body: &[u8]) -> Request {
|
|||||||
return parse_admin_request(method, path, body);
|
return parse_admin_request(method, path, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (prefix, args_offset) = if &path[0] == "shadow" || &path[0] == "schnorr" || &path[0] == "ecdsa"
|
let is_known_prefix = &path[0] == "shadow" || &path[0] == "schnorr" || &path[0] == "ecdsa" || &path[0] == "server";
|
||||||
{ (&*path[0], 1) } else { ("", 0) };
|
let (prefix, args_offset) = if is_known_prefix { (&*path[0], 1) } else { ("", 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() {
|
||||||
return Request::Invalid;
|
return Request::Invalid;
|
||||||
@ -388,6 +400,8 @@ fn parse_request(method: &HttpMethod, uri_path: &str, body: &[u8]) -> Request {
|
|||||||
Request::StoreDocumentKey(document, signature, common_point, encrypted_key),
|
Request::StoreDocumentKey(document, signature, common_point, encrypted_key),
|
||||||
("", 3, &HttpMethod::POST, Some(Ok(threshold)), _, _, _) =>
|
("", 3, &HttpMethod::POST, Some(Ok(threshold)), _, _, _) =>
|
||||||
Request::GenerateDocumentKey(document, signature, threshold),
|
Request::GenerateDocumentKey(document, signature, threshold),
|
||||||
|
("server", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||||
|
Request::GetServerKey(document, signature),
|
||||||
("", 2, &HttpMethod::GET, _, _, _, _) =>
|
("", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||||
Request::GetDocumentKey(document, signature),
|
Request::GetDocumentKey(document, signature),
|
||||||
("shadow", 2, &HttpMethod::GET, _, _, _, _) =>
|
("shadow", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||||
@ -466,6 +480,10 @@ mod tests {
|
|||||||
Request::GenerateDocumentKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
Request::GenerateDocumentKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
||||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||||
2));
|
2));
|
||||||
|
// GET /server/{server_key_id}/{signature} => get public portion of server key
|
||||||
|
assert_eq!(parse_request(&HttpMethod::GET, "/server/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||||
|
Request::GetServerKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
||||||
|
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
||||||
// GET /{server_key_id}/{signature} => get document key
|
// GET /{server_key_id}/{signature} => get document key
|
||||||
assert_eq!(parse_request(&HttpMethod::GET, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
assert_eq!(parse_request(&HttpMethod::GET, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||||
Request::GetDocumentKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
Request::GetDocumentKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
||||||
|
@ -75,6 +75,10 @@ impl ServerKeyGenerator for Listener {
|
|||||||
fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<Public, Error> {
|
fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<Public, Error> {
|
||||||
self.key_server.generate_key(key_id, author, threshold)
|
self.key_server.generate_key(key_id, author, threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn restore_key_public(&self, key_id: &ServerKeyId, author: &Requester) -> Result<Public, Error> {
|
||||||
|
self.key_server.restore_key_public(key_id, author)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentKeyServer for Listener {
|
impl DocumentKeyServer for Listener {
|
||||||
|
@ -40,6 +40,10 @@ pub trait ServerKeyGenerator {
|
|||||||
/// `threshold + 1` is the minimal number of nodes, required to restore private key.
|
/// `threshold + 1` is the minimal number of nodes, required to restore private key.
|
||||||
/// Result is a public portion of SK.
|
/// Result is a public portion of SK.
|
||||||
fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<Public, Error>;
|
fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result<Public, Error>;
|
||||||
|
/// Retrieve public portion of previously generated SK.
|
||||||
|
/// `key_id` is identifier of previously generated SK.
|
||||||
|
/// `author` is the same author, that has created the server key.
|
||||||
|
fn restore_key_public(&self, key_id: &ServerKeyId, author: &Requester) -> Result<Public, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Document key (DK) server.
|
/// Document key (DK) server.
|
||||||
|
Loading…
Reference in New Issue
Block a user