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")
|
||||
.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 {
|
||||
@ -237,6 +253,10 @@ pub mod tests {
|
||||
fn generate_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result<Public, Error> {
|
||||
unimplemented!("test-only")
|
||||
}
|
||||
|
||||
fn restore_key_public(&self, _key_id: &ServerKeyId, _author: &Requester) -> Result<Public, Error> {
|
||||
unimplemented!("test-only")
|
||||
}
|
||||
}
|
||||
|
||||
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_schnorr::SessionImpl as SchnorrSigningSession;
|
||||
use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions,
|
||||
KeyVersions, KeyVersionsError, FailedKeyVersionContinueAction};
|
||||
KeyVersions, KeyVersionsError, FailedKeyVersionContinueAction, CommonKeyData};
|
||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||
|
||||
// TODO [Opt]: change sessions so that versions are sent by chunks.
|
||||
@ -97,8 +97,8 @@ struct SessionData {
|
||||
pub state: SessionState,
|
||||
/// Initialization confirmations.
|
||||
pub confirmations: Option<BTreeSet<NodeId>>,
|
||||
/// Key threshold.
|
||||
pub threshold: Option<usize>,
|
||||
/// Common key data that nodes have agreed upon.
|
||||
pub key_share: Option<DocumentKeyShare>,
|
||||
/// { Version => Nodes }
|
||||
pub versions: Option<BTreeMap<H256, BTreeSet<NodeId>>>,
|
||||
/// Session result.
|
||||
@ -167,12 +167,11 @@ pub struct LargestSupportResultComputer;
|
||||
impl<T> SessionImpl<T> where T: SessionTransport {
|
||||
/// Create new session.
|
||||
pub fn new(params: SessionParams<T>) -> Self {
|
||||
let threshold = params.key_share.as_ref().map(|key_share| key_share.threshold);
|
||||
SessionImpl {
|
||||
core: SessionCore {
|
||||
meta: params.meta,
|
||||
sub_session: params.sub_session,
|
||||
key_share: params.key_share,
|
||||
key_share: params.key_share.clone(),
|
||||
result_computer: params.result_computer,
|
||||
transport: params.transport,
|
||||
nonce: params.nonce,
|
||||
@ -181,7 +180,12 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
||||
data: Mutex::new(SessionData {
|
||||
state: SessionState::WaitingForInitialization,
|
||||
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,
|
||||
result: None,
|
||||
continue_with: None,
|
||||
@ -195,12 +199,6 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
||||
&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.
|
||||
pub fn version_holders(&self, version: &H256) -> Result<BTreeSet<NodeId>, Error> {
|
||||
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")
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn initialize(&self, connected_nodes: BTreeSet<NodeId>) -> Result<(), Error> {
|
||||
// check state
|
||||
@ -322,7 +326,11 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
||||
session: self.core.meta.id.clone().into(),
|
||||
sub_session: self.core.sub_session.clone().into(),
|
||||
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|
|
||||
key_share.versions.iter().rev()
|
||||
.filter(|v| v.id_numbers.contains_key(sender))
|
||||
@ -357,12 +365,25 @@ impl<T> SessionImpl<T> where T: SessionTransport {
|
||||
|
||||
// remember versions that sender have
|
||||
{
|
||||
match message.threshold.clone() {
|
||||
Some(threshold) if data.threshold.is_none() => {
|
||||
data.threshold = Some(threshold);
|
||||
match message.key_common.as_ref() {
|
||||
Some(key_common) if data.key_share.is_none() => {
|
||||
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 => 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 confirmations = data.confirmations.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
|
||||
// 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
|
||||
@ -590,7 +612,7 @@ impl SessionResultComputer for LargestSupportResultComputer {
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::collections::{VecDeque, BTreeMap, BTreeSet};
|
||||
use ethereum_types::{H512, Address};
|
||||
use ethereum_types::{H512, H160, Address};
|
||||
use ethkey::public_to_address;
|
||||
use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage,
|
||||
DocumentKeyShare, DocumentKeyShareVersion};
|
||||
@ -600,7 +622,10 @@ mod tests {
|
||||
use key_server_cluster::cluster_sessions::ClusterSession;
|
||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||
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::{
|
||||
SessionImpl, SessionTransport, SessionParams, FastestResultComputer, LargestSupportResultComputer,
|
||||
SessionResultComputer, SessionState, ContinueAction, FailedContinueAction,
|
||||
@ -759,7 +784,11 @@ mod tests {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: Some(10),
|
||||
key_common: Some(CommonKeyData {
|
||||
threshold: 10,
|
||||
author: Default::default(),
|
||||
public: Default::default(),
|
||||
}),
|
||||
versions: Vec::new(),
|
||||
})), Err(Error::InvalidStateForRequest));
|
||||
}
|
||||
@ -775,7 +804,12 @@ mod tests {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: Some(0),
|
||||
key_common: Some(CommonKeyData {
|
||||
threshold: 0,
|
||||
author: Default::default(),
|
||||
public: Default::default(),
|
||||
}),
|
||||
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Ok(()));
|
||||
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
||||
@ -784,32 +818,61 @@ mod tests {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: Some(0),
|
||||
key_common: Some(CommonKeyData {
|
||||
threshold: 0,
|
||||
author: Default::default(),
|
||||
public: Default::default(),
|
||||
}),
|
||||
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Ok(()));
|
||||
assert_eq!(ml.session(0).data.lock().state, SessionState::Finished);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negotiation_fails_if_wrong_threshold_sent() {
|
||||
let ml = MessageLoop::empty(3);
|
||||
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap();
|
||||
fn negotiation_fails_if_wrong_common_data_sent() {
|
||||
fn run_test(key_common: CommonKeyData) {
|
||||
let ml = MessageLoop::empty(3);
|
||||
ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap();
|
||||
|
||||
let version_id = (*math::generate_random_scalar().unwrap()).clone();
|
||||
assert_eq!(ml.session(0).process_message(ml.node_id(1), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: Some(1),
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Ok(()));
|
||||
assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: Some(2),
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Err(Error::InvalidMessage));
|
||||
let version_id = (*math::generate_random_scalar().unwrap()).clone();
|
||||
assert_eq!(ml.session(0).process_message(ml.node_id(1), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
key_common: Some(CommonKeyData {
|
||||
threshold: 1,
|
||||
author: Default::default(),
|
||||
public: Default::default(),
|
||||
}),
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Ok(()));
|
||||
assert_eq!(ml.session(0).process_message(ml.node_id(2), &KeyVersionNegotiationMessage::KeyVersions(KeyVersions {
|
||||
session: Default::default(),
|
||||
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]
|
||||
@ -822,7 +885,7 @@ mod tests {
|
||||
session: Default::default(),
|
||||
sub_session: math::generate_random_scalar().unwrap().into(),
|
||||
session_nonce: 0,
|
||||
threshold: None,
|
||||
key_common: None,
|
||||
versions: vec![version_id.clone().into()]
|
||||
})), Err(Error::InvalidMessage));
|
||||
}
|
||||
@ -832,9 +895,9 @@ mod tests {
|
||||
let nodes = MessageLoop::prepare_nodes(2);
|
||||
let version_id = (*math::generate_random_scalar().unwrap()).clone();
|
||||
nodes.values().nth(0).unwrap().insert(Default::default(), DocumentKeyShare {
|
||||
author: Default::default(),
|
||||
author: H160::from_low_u64_be(2),
|
||||
threshold: 1,
|
||||
public: Default::default(),
|
||||
public: H512::from_low_u64_be(3),
|
||||
common_point: None,
|
||||
encrypted_point: None,
|
||||
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
|
||||
assert!(ml.session(0).data.lock().state != SessionState::Finished);
|
||||
|
||||
// check that upon completion, threshold is known
|
||||
assert_eq!(ml.session(0).key_threshold(), Ok(1));
|
||||
// check that upon completion, commmon key data is known
|
||||
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]
|
||||
|
@ -800,7 +800,7 @@ impl SessionImpl {
|
||||
.wait()?
|
||||
.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_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
|
||||
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::message::{Message, ShareAddMessage, ShareAddConsensusMessage, ConsensusMessageOfShareAdd,
|
||||
InitializeConsensusSessionOfShareAdd, KeyShareCommon, NewKeysDissemination, ShareAddError,
|
||||
ConfirmConsensusInitialization};
|
||||
ConfirmConsensusInitialization, CommonKeyData};
|
||||
use key_server_cluster::jobs::job_session::JobTransport;
|
||||
use key_server_cluster::jobs::dummy_job::{DummyJob, DummyJobTransport};
|
||||
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
|
||||
data.state = SessionState::WaitingForKeysDissemination;
|
||||
data.new_key_share = Some(NewKeyShare {
|
||||
threshold: message.threshold,
|
||||
author: message.author.clone().into(),
|
||||
joint_public: message.joint_public.clone().into(),
|
||||
threshold: message.key_common.threshold,
|
||||
author: message.key_common.author.clone().into(),
|
||||
joint_public: message.key_common.public.clone().into(),
|
||||
common_point: message.common_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 {
|
||||
session: core.meta.id.clone().into(),
|
||||
session_nonce: core.nonce,
|
||||
threshold: old_key_share.threshold,
|
||||
author: old_key_share.author.clone().into(),
|
||||
joint_public: old_key_share.public.clone().into(),
|
||||
key_common: CommonKeyData {
|
||||
threshold: old_key_share.threshold,
|
||||
author: old_key_share.author.into(),
|
||||
public: old_key_share.public.into(),
|
||||
},
|
||||
common_point: old_key_share.common_point.clone().map(Into::into),
|
||||
encrypted_point: old_key_share.encrypted_point.clone().map(Into::into),
|
||||
id_numbers: old_key_version.id_numbers.iter()
|
||||
|
@ -970,12 +970,8 @@ pub struct KeyShareCommon {
|
||||
pub session: MessageSessionId,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Key threshold.
|
||||
pub threshold: usize,
|
||||
/// Author of key share entry.
|
||||
pub author: SerializableAddress,
|
||||
/// Joint public.
|
||||
pub joint_public: SerializablePublic,
|
||||
/// Common key data.
|
||||
pub key_common: CommonKeyData,
|
||||
/// Common (shared) encryption point.
|
||||
pub common_point: Option<SerializablePublic>,
|
||||
/// Encrypted point.
|
||||
@ -1026,12 +1022,23 @@ pub struct KeyVersions {
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Key threshold.
|
||||
pub threshold: Option<usize>,
|
||||
/// Common key data, shared by all versions.
|
||||
pub key_common: Option<CommonKeyData>,
|
||||
/// Key versions.
|
||||
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.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct KeyVersionsError {
|
||||
|
@ -34,8 +34,7 @@ type CurrentSerializableDocumentKeyShare = SerializableDocumentKeyShareV3;
|
||||
type CurrentSerializableDocumentKeyVersion = SerializableDocumentKeyShareVersionV3;
|
||||
|
||||
/// Encrypted key share, stored by key storage on the single key server.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(test, derive(Default))]
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct DocumentKeyShare {
|
||||
/// Author of the entry.
|
||||
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 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 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 shadow: GET /shadow/{server_key_id}/{signature}
|
||||
/// 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),
|
||||
/// Generate encryption key.
|
||||
GenerateDocumentKey(ServerKeyId, RequestSignature, usize),
|
||||
/// Request public portion of server key.
|
||||
GetServerKey(ServerKeyId, RequestSignature),
|
||||
/// Request encryption key of given document for given requestor.
|
||||
GetDocumentKey(ServerKeyId, RequestSignature),
|
||||
/// Request shadow of encryption key of given document for given requestor.
|
||||
@ -155,6 +158,15 @@ impl KeyServerHttpHandler {
|
||||
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) => {
|
||||
return_document_key(&req_uri, cors, self.handler.key_server.upgrade()
|
||||
.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);
|
||||
}
|
||||
|
||||
let (prefix, args_offset) = if &path[0] == "shadow" || &path[0] == "schnorr" || &path[0] == "ecdsa"
|
||||
{ (&*path[0], 1) } else { ("", 0) };
|
||||
let is_known_prefix = &path[0] == "shadow" || &path[0] == "schnorr" || &path[0] == "ecdsa" || &path[0] == "server";
|
||||
let (prefix, args_offset) = if is_known_prefix { (&*path[0], 1) } else { ("", 0) };
|
||||
let args_count = path.len() - args_offset;
|
||||
if args_count < 2 || path[args_offset].is_empty() || path[args_offset + 1].is_empty() {
|
||||
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),
|
||||
("", 3, &HttpMethod::POST, Some(Ok(threshold)), _, _, _) =>
|
||||
Request::GenerateDocumentKey(document, signature, threshold),
|
||||
("server", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||
Request::GetServerKey(document, signature),
|
||||
("", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||
Request::GetDocumentKey(document, signature),
|
||||
("shadow", 2, &HttpMethod::GET, _, _, _, _) =>
|
||||
@ -466,6 +480,10 @@ mod tests {
|
||||
Request::GenerateDocumentKey(H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
|
||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||
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
|
||||
assert_eq!(parse_request(&HttpMethod::GET, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||
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> {
|
||||
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 {
|
||||
|
@ -40,6 +40,10 @@ pub trait ServerKeyGenerator {
|
||||
/// `threshold + 1` is the minimal number of nodes, required to restore private key.
|
||||
/// Result is a public portion of SK.
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user