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

SecretStore: generating signatures #5764

Merged
merged 52 commits into from Jul 6, 2017
Merged

SecretStore: generating signatures #5764

merged 52 commits into from Jul 6, 2017

Conversation

svyatonik
Copy link
Collaborator

Requirements:

a set of N KeyServers, sharing KeyPair (public is known to every node, secret could be restored by t KeyServers) must be able to sign message (message hash).

Options:

  1. it is possible to generate N-of-N ECDSA-compatible signature
  2. it is possible to generate t-of-N ECDSA-compatible signature, but you must run t-of-t algorithm for every possible subset of t nodes
  3. it is possible to generate t-of-N EC-Schnorr signature

Of these options, 3rd one has been choosen for now.

Paper, on which current implementation is based:

https://www.researchgate.net/profile/A_Chronopoulos/publication/224386852_Efficient_multi-party_digital_signature_using_adaptive_secret_sharing_for_low-power_devices_in_wireless_networksPLEASE_REFERENCE_IN_YOUR_PAPERS/links/00b7d52c2a3fb5bf8e000000/Efficient-multi-party-digital-signature-using-adaptive-secret-sharing-for-low-power-devices-in-wireless-networksPLEASE-REFERENCE-IN-YOUR-PAPERS.pdf
also (important): http://www.wu.ece.ufl.edu/mypapers/notesMulti-partyDigitalSignature.pdf

PR outline:

  1. added relevant EC-math functions to secret_store/src/key_server_cluster/math.rs.
    1.1) there was same issue as with earlier ECDKG implementation - signing only worked for t-of-N groups, where t was even. This issue has been fixed.
    1.2) I have slightly changed signature calculation, as it was not compatible with some non-distributed EC-Schnorr implementation, I've found on github. Now it is compatible. And non-distributed code is also in math.rs (local_compute_signature())
    1.3) check_signature_share() from math.rs is currently not implemented, as suggested implementation from paper seems wrong.
  2. part of signing session is distributed key generation session (which is used as nonce when computing signature), so I had to separate key generation session from encryption session.
  3. as an side effect of (2), secret encryption now can be completed in three steps:
    3.1) client asks KeyServer to generate server key. KeyServer returns JointServerPublic to the client
    3.2) client generates and encrypts DocumentSecret (which is point on EC in this case) using following procedure:
    3.2.1) client generates random EC-field scalar k
    3.2.2) client computes CommonPoint = k * ECGenerationPoint
    3.2.3) client computes EncryptedDocumentSecret = DocumentSecret + k * JointServerPublic
    3.3) client posts pair { CommonPoint, EncryptedDocumentSecret } to KeyServer.
    3.4) in combination with 'shadow key retrieval', which was introduced before, this guarantees that KeyServer will never see unencrypted DocumentSecret. Previously DocumentSecret was generated on KeyServer.
  4. only 'author' of (3.2.1) request is allowed to submit (3.2.3) request. So I've made some changes to internal SecretStore database to support this. Previous versions of db are incompatible with this new version. Upgrade procedure has been added as a part of this PR, so that old dbs are automatically upgraded. Have some concerns:
    4.1) upgrade is implemented as a single im-place transaction => all db should fit into memory. I assume it is not an issue, because SecretStore is only starting its first deployment => db should be small.
    4.2) I have tested upgrade on my own database && everything seems to work (also have a test for it). But it would be better to make backup of SecretStore db befrore upgrading production nodes, as it could potentially lead to data loss.
  5. both decryption and signng sessions behave in the same manner: at the very beginning they're selecting t nodes out of all nodes, which have agreed to restore the secret/sign message for requester. So I've moved common code to consensus_session.rs.
  6. active sessions container now is a separate entity, living in the cluster_sessions.rs (previously there was a lot of duplicated code for getting/inserting/removing each kind of session)
  7. error text is returned as plain json string, if request has failed (@ngotchac request)

API changes:

Previous KeyServer API remains active - you still can simultaneously generate ServerKey && DocumentKey, retrieve DocumentKey && DocumentKey shadow.
In addition, following HTTP requests are now supported:

  1. to generate server key (without storing DocumentKey in db), caller must POST to the /shadow/{server_key_id}/{signature}/{threshold} URL:
curl -v -X POST http://localhost:8082/shadow/0000000000000000000000000000000000000000000000000000000000000000/de12681e0b8f7a428f12a6694a5f7e1324deef3d627744d95d51b862afc13799251831b3611ae436c452b54cdf5c4e78b361a396ae183e8b4c34519e895e623c00/1

result is JointServerPublic:

"0x07d6c0e4cecbe7a3ab3a8f5bd6439bb78ecd41f3e7487d34981668c50c62976e6f57eda20c9bd7026b4defa31141520a3480561b3c5bec5275d9d7f4f1e9d50a"
  1. to store DocumentKey, encrypted by client with JointServerPublic, caller must POST to the /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key}:
curl -v -X POST http://localhost:8082/shadow/0000000000000000000000000000000000000000000000000000000000000000/de12681e0b8f7a428f12a6694a5f7e1324deef3d627744d95d51b862afc13799251831b3611ae436c452b54cdf5c4e78b361a396ae183e8b4c34519e895e623c00/368244efaf441c2dabf7a723355a97b3b86f27bdb2827ae6f34ddece5132efd37af4ba808957b7113b4296bc4ae9ec7be38f9de6bae00504e775883a50d4658a/b7ad0603946987f1a154ae7f074e45da224eaa83704aac16a2d43a675d219654cf087b5d7aacce0790a65abbc1a495b26e71a5c6e9a4a71b543bf0048935bc13
  1. to sign message, caller must issue GET request to the /{server_key_id}/{signature}/{message_hash}
curl -v http://localhost:8082/0000000000000000000000000000000000000000000000000000000000000000/de12681e0b8f7a428f12a6694a5f7e1324deef3d627744d95d51b862afc13799251831b3611ae436c452b54cdf5c4e78b361a396ae183e8b4c34519e895e623c00/0000000000000000000000000000000000000000000000000000000000000001

result is signature of message_hash, encrypted with caller' public key:

"0x0410fe210ffdd38611b252e24c61b610d6ea8ec70f9f7186184441871839562cc18c94174af0c804973ce88a6f07ec7604b4b91821a6ca68ca348d16cd647fba494f8132ff36ad4654abd5cba6fb1fd98cacc12aaf3a0fe70010be91f5ab7b69db8f80e528be3baba70341721d6058ad66665363033f0cee963476da746e843d4006170ab549fa82f14eec7b420d542c3415a61fc3075f39e1529bc4e6f54f1170496393485f6ef271ad8b587c8fae8a18"

Next PRs (TODOs for me):

  1. add more tests (signing session restart, etc)
  2. SecretStore: dynamically generate KeyPairs #5502 + security review
  3. stress testing + potential performance fixes
  4. try to find an easy way to generate ECDSA-compatible signatures

@svyatonik svyatonik added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. labels Jun 5, 2017
// if session is completed => stop
let session = session.clone().expect("session.method() call finished with success; session exists; qed");
if session.is_finished() {
info!(target: "secretstore_net", "{}: signing session completed", data.self_key_pair.public());
Copy link
Contributor

Choose a reason for hiding this comment

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

sure there is a need to notify console of each session (info!) ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is convenient for me right now :) In production environment it could be a little annoying, as long as SecretStore is run along with synchronization. But one day (I hope :)) it will became a standalone IPC-module && creating/completion sessions would be its main 'side effect' => it would be great to see these notifications in console.
I could remove this for now, if you think it is annoying.

Copy link
Contributor

Choose a reason for hiding this comment

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

nah, if it is intentional, nevermind

return_bytes::<i32>(req, res, empty.map(|_| None))
}

fn return_server_pubic_key(req: HttpRequest, res: HttpResponse, server_public: Result<Public, Error>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

typo, should be server_public

let message_signature = signing_session.wait()?;

// compose two message signature components into single one
let mut combined_signature: Vec<u8> = Vec::with_capacity(64);
Copy link
Collaborator

Choose a reason for hiding this comment

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

could be just an array

// => do not use these in encryption session
let mut encrypted_data = self.key_storage.get(&session_id).map_err(|e| Error::KeyStorage(e.into()))?;
let disconnected_nodes: BTreeSet<_> = encrypted_data.id_numbers.keys().cloned().collect();
let disconnected_nodes: BTreeSet<_> = disconnected_nodes.difference(&cluster.nodes()).cloned().collect();
Copy link
Collaborator

@arkpar arkpar Jun 27, 2017

Choose a reason for hiding this comment

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

No need to collect here since all you do with the set is iterate it. Also applies to a few places like this below.

@arkpar arkpar added A8-looksgood 🦄 Pull request is reviewed well. and removed A0-pleasereview 🤓 Pull request needs code review. labels Jun 30, 2017
@keorn keorn merged commit 6334893 into master Jul 6, 2017
@arkpar arkpar deleted the secretstore_signing2 branch July 6, 2017 12:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. M4-core ⛓ Core client code / Rust.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants