Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

SecretStore: secretstore_signRawHash method #7336

Merged
merged 1 commit into from
Dec 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions parity/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ usage! {
"--jsonrpc-interface=[IP]",
"Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or all (all interfaces) or local.",

ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,secretstore,shh,shh_pubsub", or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
"--jsonrpc-apis=[APIS]",
"Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited list of API name. Possible name are all, safe, web3, eth, net, personal, parity, parity_set, traces, rpc, parity_accounts. You can also disable a specific API by putting '-' in the front: all,-personal.",

Expand Down Expand Up @@ -483,7 +483,7 @@ usage! {
"--ws-interface=[IP]",
"Specify the hostname portion of the WebSockets server, IP should be an interface's IP address, or all (all interfaces) or local.",

ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,secretstore,shh,shh_pubsub", or |c: &Config| otry!(c.websockets).apis.as_ref().map(|vec| vec.join(",")),
ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| otry!(c.websockets).apis.as_ref().map(|vec| vec.join(",")),
"--ws-apis=[APIS]",
"Specify the APIs available through the WebSockets interface. APIS is a comma-delimited list of API name. Possible name are web3, eth, pubsub, net, personal, parity, parity_set, traces, rpc, parity_accounts..",

Expand All @@ -504,7 +504,7 @@ usage! {
"--ipc-path=[PATH]",
"Specify custom path for JSON-RPC over IPC service.",

ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc,secretstore,shh,shh_pubsub", or |c: &Config| otry!(c.ipc).apis.as_ref().map(|vec| vec.join(",")),
ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc,shh,shh_pubsub", or |c: &Config| otry!(c.ipc).apis.as_ref().map(|vec| vec.join(",")),
"--ipc-apis=[APIS]",
"Specify custom API set available via JSON-RPC over IPC.",

Expand Down
11 changes: 6 additions & 5 deletions parity/rpc_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub enum Api {
Traces,
/// Rpc (Safe)
Rpc,
/// SecretStore (Safe)
/// SecretStore (UNSAFE: arbitrary hash signing)
SecretStore,
/// Whisper (Safe)
// TODO: _if_ someone guesses someone else's key or filter IDs they can remove
Expand Down Expand Up @@ -602,7 +602,6 @@ impl ApiSet {
Api::EthPubSub,
Api::Parity,
Api::Rpc,
Api::SecretStore,
Api::Whisper,
Api::WhisperPubSub,
].into_iter().cloned().collect();
Expand All @@ -627,6 +626,7 @@ impl ApiSet {
public_list.insert(Api::ParityAccounts);
public_list.insert(Api::ParitySet);
public_list.insert(Api::Signer);
public_list.insert(Api::SecretStore);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a question. Above you've added a comment SecretStore (UNSAFE: arbitrary hash signing), but here SecretStore is added to a SafeContext. Isn't it contradictory?

Copy link
Collaborator Author

@svyatonik svyatonik Dec 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also confused a bit :) If I understood correctly, there are:

  1. safe/unsafe APIs
  2. safe/unsafe API Contexts

So: SecretStore API is unsafe => it is only enabled when API context is safe. Here's couple of proofs I've found:

  1. https://github.com/paritytech/parity/blob/master/parity/rpc_apis.rs#L148 (reveres proof)
  2. ParityAccounts API, which is also unsafe, is included to the SafeContext API set

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, indeed that the reasoning, although It's extremely confusing (sorry about that:() Feel free to rename it.

public_list
},
ApiSet::All => {
Expand All @@ -636,6 +636,7 @@ impl ApiSet {
public_list.insert(Api::ParitySet);
public_list.insert(Api::Signer);
public_list.insert(Api::Personal);
public_list.insert(Api::SecretStore);
public_list
},
ApiSet::PubSub => [
Expand Down Expand Up @@ -686,7 +687,7 @@ mod test {
fn test_api_set_unsafe_context() {
let expected = vec![
// make sure this list contains only SAFE methods
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub,
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub,
].into_iter().collect();
assert_eq!(ApiSet::UnsafeContext.list_apis(), expected);
}
Expand All @@ -695,7 +696,7 @@ mod test {
fn test_api_set_ipc_context() {
let expected = vec![
// safe
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub,
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub,
// semi-safe
Api::ParityAccounts
].into_iter().collect();
Expand Down Expand Up @@ -737,7 +738,7 @@ mod test {
#[test]
fn test_safe_parsing() {
assert_eq!("safe".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub,
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub,
].into_iter().collect()));
}
}
13 changes: 8 additions & 5 deletions rpc/src/v1/impls/secretstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use v1::helpers::errors;
use v1::helpers::accounts::unwrap_provider;
use v1::helpers::secretstore::{encrypt_document, decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak};
use v1::traits::SecretStore;
use v1::types::{H160, H512, Bytes};
use v1::types::{H160, H256, H512, Bytes};

/// Parity implementation.
pub struct SecretStoreClient {
Expand Down Expand Up @@ -84,12 +84,15 @@ impl SecretStore for SecretStoreClient {
.map(Into::into)
}

fn sign_servers_set(&self, address: H160, password: String, servers_set: BTreeSet<H512>) -> Result<Bytes> {
let servers_set_keccak_value = ordered_servers_keccak(servers_set);
fn servers_set_hash(&self, servers_set: BTreeSet<H512>) -> Result<H256> {
Ok(ordered_servers_keccak(servers_set))
}

fn sign_raw_hash(&self, address: H160, password: String, raw_hash: H256) -> Result<Bytes> {
let store = self.account_provider()?;
store
.sign(address.into(), Some(password), servers_set_keccak_value.into())
.sign(address.into(), Some(password), raw_hash.into())
.map(|s| Bytes::new((*s).to_vec()))
.map_err(|e| errors::account("Could not sign servers set.", e))
.map_err(|e| errors::account("Could not sign raw hash.", e))
}
}
38 changes: 28 additions & 10 deletions rpc/src/v1/tests/mocked/secretstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use v1::metadata::Metadata;
use v1::SecretStoreClient;
use v1::traits::secretstore::SecretStore;
use v1::helpers::secretstore::ordered_servers_keccak;
use v1::types::H256;

struct Dependencies {
pub accounts: Arc<AccountProvider>,
Expand Down Expand Up @@ -100,7 +101,29 @@ fn rpc_secretstore_shadow_decrypt() {
}

#[test]
fn rpc_secretstore_sign_servers_set() {
fn rpc_secretstore_servers_set_hash() {
let deps = Dependencies::new();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let io = deps.default_client();

// execute hashing request
let hashing_request = r#"{"jsonrpc": "2.0", "method": "secretstore_serversSetHash", "params":[
["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]
], "id": 1}"#;
let hashing_response = io.handle_request_sync(&hashing_request).unwrap();
let hashing_response = hashing_response.replace(r#"{"jsonrpc":"2.0","result":"0x"#, "");
let hashing_response = hashing_response.replace(r#"","id":1}"#, "");
let hash: H256 = hashing_response.parse().unwrap();

let servers_set_keccak = ordered_servers_keccak(vec![
"843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91".parse().unwrap(),
"07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3".parse().unwrap()
].into_iter().collect());
assert_eq!(hash, servers_set_keccak);
}

#[test]
fn rpc_secretstore_sign_raw_hash() {
let deps = Dependencies::new();
let io = deps.default_client();

Expand All @@ -110,19 +133,14 @@ fn rpc_secretstore_sign_servers_set() {
deps.accounts.insert_account(key_pair.secret().clone(), "password").unwrap();

// execute signing request
let signing_request = r#"{"jsonrpc": "2.0", "method": "secretstore_signServersSet", "params":[
"0x00dfE63B22312ab4329aD0d28CaD8Af987A01932", "password",
["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]
let signing_request = r#"{"jsonrpc": "2.0", "method": "secretstore_signRawHash", "params":[
"0x00dfE63B22312ab4329aD0d28CaD8Af987A01932", "password", "0x0000000000000000000000000000000000000000000000000000000000000001"
], "id": 1}"#;
let signing_response = io.handle_request_sync(&signing_request).unwrap();
let signing_response = signing_response.replace(r#"{"jsonrpc":"2.0","result":"0x"#, "");
let signing_response = signing_response.replace(r#"","id":1}"#, "");
let signature: Signature = signing_response.parse().unwrap();

let servers_set_keccak = ordered_servers_keccak(vec![
"843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91".parse().unwrap(),
"07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3".parse().unwrap()
].into_iter().collect());
assert!(verify_public(key_pair.public(), &signature, &servers_set_keccak.into()).unwrap());
let hash = "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
assert!(verify_public(key_pair.public(), &signature, &hash).unwrap());
}
17 changes: 12 additions & 5 deletions rpc/src/v1/traits/secretstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use std::collections::BTreeSet;
use jsonrpc_core::Result;

use v1::types::{H160, H512, Bytes};
use v1::types::{H160, H256, H512, Bytes};

build_rpc_trait! {
/// Parity-specific rpc interface.
Expand All @@ -39,9 +39,16 @@ build_rpc_trait! {
#[rpc(name = "secretstore_shadowDecrypt")]
fn shadow_decrypt(&self, H160, String, H512, H512, Vec<Bytes>, Bytes) -> Result<Bytes>;

/// Sign servers set for use in ServersSetChange session.
/// Arguments: `account`, `password`, `servers_set`.
#[rpc(name = "secretstore_signServersSet")]
fn sign_servers_set(&self, H160, String, BTreeSet<H512>) -> Result<Bytes>;
/// Calculates the hash (keccak256) of servers set for using in ServersSetChange session.
/// Returned hash must be signed later by using `secretstore_signRawHash` method.
/// Arguments: `servers_set`.
#[rpc(name = "secretstore_serversSetHash")]
fn servers_set_hash(&self, BTreeSet<H512>) -> Result<H256>;

/// Generate recoverable ECDSA signature of raw hash.
/// Passed hash is treated as an input to the `sign` function (no prefixes added, no hash function is applied).
/// Arguments: `account`, `password`, `raw_hash`.
#[rpc(name = "secretstore_signRawHash")]
fn sign_raw_hash(&self, H160, String, H256) -> Result<Bytes>;
}
}