SecretStore: expose restore_key_public in HTTP API (#10241)

This commit is contained in:
Svyatoslav Nikolsky 2019-06-05 15:04:00 +03:00 committed by David
parent f7dae48c17
commit 6be45367e9
9 changed files with 189 additions and 67 deletions

View File

@ -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 {

View File

@ -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,32 +818,61 @@ 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() {
let ml = MessageLoop::empty(3); fn run_test(key_common: CommonKeyData) {
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap(); let ml = MessageLoop::empty(3);
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap();
let version_id = (*math::generate_random_scalar().unwrap()).clone(); let version_id = (*math::generate_random_scalar().unwrap()).clone();
assert_eq!(ml.session(0).process_message(ml.node_id(1), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions { assert_eq!(ml.session(0).process_message(ml.node_id(1), &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(1), key_common: Some(CommonKeyData {
versions: vec![version_id.clone().into()] threshold: 1,
})), Ok(())); author: Default::default(),
assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions { public: Default::default(),
session: Default::default(), }),
sub_session: math::generate_random_scalar().unwrap().into(), versions: vec![version_id.clone().into()]
session_nonce: 0, })), Ok(()));
threshold: Some(2), assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
versions: vec![version_id.clone().into()] session: Default::default(),
})), Err(Error::InvalidMessage)); sub_session: math::generate_random_scalar().unwrap().into(),
session_nonce: 0,
key_common: Some(key_common),
versions: vec![version_id.clone().into()]
})), 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]
@ -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]

View File

@ -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;

View File

@ -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,
threshold: old_key_share.threshold, key_common: CommonKeyData {
author: old_key_share.author.clone().into(), threshold: old_key_share.threshold,
joint_public: old_key_share.public.clone().into(), author: old_key_share.author.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()

View File

@ -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 {

View File

@ -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,

View File

@ -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(),

View File

@ -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 {

View File

@ -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.