Skip to content

Commit

Permalink
Add validator token to config (RIPD-1386)
Browse files Browse the repository at this point in the history
  • Loading branch information
wilsonianb committed Feb 1, 2017
1 parent 87909e9 commit 4ae8fa6
Show file tree
Hide file tree
Showing 29 changed files with 372 additions and 192 deletions.
13 changes: 9 additions & 4 deletions bin/python/ripple/util/Sign.py
Expand Up @@ -2,7 +2,7 @@

from __future__ import print_function

import base64, os, random, struct, sys
import base64, binascii, json, os, random, struct, sys
import ed25519
import ecdsa
import hashlib
Expand Down Expand Up @@ -188,9 +188,14 @@ def perform_check(s, print=print):

def perform_sign(
seq, validation_pk_human, validation_sk_human, master_sk_human, print=print):
print('[validation_manifest]')
print(wrap(get_signature(
int(seq), validation_pk_human, validation_sk_human, master_sk_human)))
manifest = get_signature(
int(seq), validation_pk_human, validation_sk_human, master_sk_human)

print('[validator_token]')
print(wrap(base64.b64encode(json.dumps({
"validation_secret_key": binascii.b2a_hex(Base58.decode_version(validation_sk_human)[1]),
"manifest": manifest},
separators=(',', ':')))))

def perform_verify(
seq, validation_pk_human, master_pk_human, signature, print=print):
Expand Down
16 changes: 7 additions & 9 deletions bin/python/ripple/util/ValidatorManifestTest.py
Expand Up @@ -104,9 +104,7 @@
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
[validation_seed]
{validation_seed}
#vaidation_public_key: {validation_public_key}
#validation_public_key: {validation_public_key}
# Other rippled's trusting this validator need this key
[validator_keys]
Expand All @@ -119,8 +117,8 @@
expire = 1
auto_connect = 1
[validation_manifest]
{validation_manifest}
[validator_token]
{validator_token}
[rpc_startup]
{{ "command": "log_level", "severity": "debug" }}
Expand Down Expand Up @@ -201,7 +199,7 @@ def sign_manifest(seq, validation_pk, master_secret):
result = []
for l in r.splitlines():
l.strip()
if not l or l == '[validation_manifest]':
if not l or l == '[validator_token]':
continue
result.append(l)
return '\n'.join(result)
Expand Down Expand Up @@ -430,7 +428,7 @@ def new_config_ephemeral_key(
if rm_dbs and os.path.exists(db_dir):
shutil.rmtree(db_dir)
os.makedirs(db_dir)
# replace the validation_manifest section with `signed`
# replace the validator_token section with `signed`
bak = config_file + '.bak'
if is_windows() and os.path.isfile(bak):
os.remove(bak)
Expand All @@ -440,7 +438,7 @@ def new_config_ephemeral_key(
with open(config_file, 'w') as out:
for l in src:
sl = l.strip()
if not in_manifest and sl == '[validation_manifest]':
if not in_manifest and sl == '[validator_token]':
in_manifest = True
elif in_manifest:
if sl.startswith('[') or sl.startswith('#'):
Expand Down Expand Up @@ -539,7 +537,7 @@ def get_configs(manifest_seq):
sibling_ip = '127.0.0.1'
sibling_port = port_nums[sibling_index][1]
d = {
'validation_manifest': s,
'validator_token': s,
'all_validator_keys': all_validator_keys,
'node_db_type': node_db_type,
'node_db_path': node_db_path,
Expand Down
14 changes: 9 additions & 5 deletions bin/python/ripple/util/test_Sign.py
Expand Up @@ -141,9 +141,13 @@ def test_sign(self):
Sign.perform_sign(self.SEQUENCE, public, private, private, print=self.print)
self.assertEquals(
self.results,
[[['[validation_manifest]'], {}],
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2dnZ2dnZ2\n'
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HIaARlzvcd79/wT068\n'
'e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTxkpticBJAzo5VrUEr0U47sHvu\n'
'IjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH1HyQmsZsROTeHR0irojvYgx7JLaiAA=='],
[[['[validator_token]'], {}],
[['eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiNmI2YjZiNmI2YjZiNmI2YjZiNmI2Yj\n'
'ZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YiIsIm1hbmlm\n'
'ZXN0IjoiSkFBQUFCZHhJZTJESUtVWmQ5akRqS2lra254bkRmV0NIa1NYWVpSZUZlbn\n'
'ZzbW9WQ2RJdzZuTWhBbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJk\n'
'bloyZG5aMmRrWXdSQUlnWHlvYkhBOHNEUXhtREpOTEU2SElhQVJsenZjZDc5L3dUMD\n'
'Y4ZTExM2dVa0NJSGtJNTQwSlFUMkxId0FENy95M3dGRTVYM2xFWE1mZ1pSa3BMWlR4\n'
'a3B0aWNCSkF6bzVWclVFcjBVNDdzSHZ1SWpicklOTENUTTZwQVNjQTg5OUc5a3BNV2\n'
'V4Ylh2MWNlSWJUUDVKSDFIeVFtc1pzUk9UZUhSMGlyb2p2WWd4N0pMYWlBQT09In0='],
{}]])
41 changes: 16 additions & 25 deletions doc/manifest-tool-guide.md
Expand Up @@ -8,7 +8,7 @@ Validators use two types of key pairs: *master keys* and *ephemeral
keys*. Ephemeral keys are used to sign and verify validations. Master keys are
used to sign and verify manifests that change ephemeral keys. The master secret
key should be tightly controlled. The ephemeral secret key needs to be present
in the config file.
in the config file in the form of a token.

## Validator Keys

Expand All @@ -28,10 +28,9 @@ Sample output:
paamfhAn5m1NM4UUu5mmvVaHQy8Fb65bkpbaNrvKwX3YMKdjzi2
```

The first value is the master public key. Add the public key to the config
for this validator. A one-word comment must be added after the key (for example
*ThisServersName*). Any other rippled trusting the validator needs to add the
master public key to its config. Only add keys received from trusted sources.
The first value is the master public key. Any other rippled trusting the
validator needs to add the master public key to its config. Only add keys
received from trusted sources.

The second value is the corresponding master secret key. **DO NOT INSTALL THIS
IN THE CONFIG**. The master secret key will be used to sign manifests that
Expand Down Expand Up @@ -63,17 +62,6 @@ Sample output:
}
```

Add the `validation_seed` value (the ephemeral secret key) to this validator's
config. It is recommended to add the ephemeral public key and the sequence
number as a comment as well (sequence numbers are be explained below):

```
[validation_seed]
sh8bLqqkGBknGcsgRTrFMxcciwytm
# validation_public_key: n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX
# sequence number: 1
```

A manifest is a signed message used to inform other servers of this validator's
ephemeral public key. A manifest contains a sequence number, the new ephemeral
public key, and it is signed with both the ephemeral and master secret keys.
Expand All @@ -95,15 +83,18 @@ For example:
Sample output:

```
[validation_manifest]
JAAAAAFxIe3t8rIb4Ba8JHI97CbwpxmTq0LhN/7ZAbsNaSwrbHaypHMhAzTuu07YGOvVvB3+
aS0jhP+q0TVgTjGJKhx+yTY1Da3ddkYwRAIgDkmIt3dPNsfeCH3ApMZgpwqG4JwtIlKEymqK
S7v+VqkCIFQXg20ZMpXXT86vmLdlmPspgeUN1scWsuFoPYUUJywycBJAl93+/bZbfZ4quTeM
5y80/OSIcVoWPcHajwrAl68eiAW4MVFeJXvShXNfnT+XsxMjDh0VpOkhvyp971i1MgjBAA==
```

Copy this to the config for this validator. Don't forget to update the comment
noting the sequence number.
[validator_token]
eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiN2VkMWM2ZDVmMTBhOGUyYWNmZWE0OW
NkNzE5ZjhiZjZhMWI1Yjg2M2Q3N2QxMDE1MjVkNGQxOWU4ZWYwNjU1OSIsIm1hbmlm
ZXN0IjoiSkFBQUFBRnhJZTNVZ3lXb3QwdFpSTFBNbDQ1dit5YkdPanJYNkE5c1JIcU
lJWUlZSTZjREhuTWhBNlNqWWZnWnJsTHFXU2UrNzlWUkZnOWJEeVZKNDMvYmV6Zkxu
dWkxVzhQdWRrWXdSQUlnY09KWmVpdmFaOW1abmM4Y1N4bUlOVGVYSUlKOE5oTXprRD
lrWThseGRkc0NJRk1OU3k5Qmo4VHNQWlV4NzNwYUJ0RmxpaDZWOTlSRXNnU3V6Wlhr
BXMHNWTVZXR09QUnY0Ylg2dDVmYi9haUtoNkZyRVdtYk5YeXpRNmI5TGhDQT09In0=
```

Copy this to the config for this validator. It is recommended to add the
sequence number as a comment as well.

## Revoking a key

Expand Down
10 changes: 10 additions & 0 deletions doc/rippled-example.cfg
Expand Up @@ -566,6 +566,15 @@
#
#
#
# [validator_token]
#
# This is an alternative to [validation_seed] that allows rippled to perform
# validation without having to store the validator keys on the network
# connected server. The field should contain a base64-encoded blob.
# External tools are available for generating validator keys and tokens.
#
#
#
# [validators_file]
#
# Path or name of a file that contains the validation public keys of nodes
Expand Down Expand Up @@ -600,6 +609,7 @@
# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
#
#
#
# [path_search]
# When searching for paths, the default search aggressiveness. This can take
# exponentially more resources as the size is increased.
Expand Down
5 changes: 5 additions & 0 deletions src/ripple/app/ledger/LedgerConsensus.h
Expand Up @@ -62,6 +62,11 @@ class LedgerConsensus : public Traits

virtual bool peerPosition (Pos_t const& position) = 0;

virtual PublicKey const& getValidationPublicKey () const = 0;

virtual void setValidationKeys (
SecretKey const& valSecret, PublicKey const& valPublic) = 0;

virtual void startRound (
LgrID_t const& prevLCLHash,
std::shared_ptr<Ledger const> const& prevLedger,
Expand Down
16 changes: 14 additions & 2 deletions src/ripple/app/ledger/impl/LedgerConsensusImp.cpp
Expand Up @@ -73,8 +73,6 @@ LedgerConsensusImp<Traits>::LedgerConsensusImp (
, ourID_ (calcNodeID (app.nodeIdentity().first))
, state_ (State::open)
, closeTime_ {}
, valPublic_ (app_.config().VALIDATION_PUB)
, valSecret_ (app_.config().VALIDATION_PRIV)
, consensusFail_ (false)
, roundTime_ (0)
, closePercent_ (0)
Expand Down Expand Up @@ -1781,6 +1779,20 @@ void LedgerConsensusImp<Traits>::addLoad(STValidation::ref val)
val->setFieldU32(sfLoadFee, fee);
}

template <class Traits>
PublicKey const& LedgerConsensusImp<Traits>::getValidationPublicKey () const
{
return valPublic_;
}

template <class Traits>
void LedgerConsensusImp<Traits>::setValidationKeys (
SecretKey const& valSecret, PublicKey const& valPublic)
{
valSecret_ = valSecret;
valPublic_ = valPublic;
}

//------------------------------------------------------------------------------
std::shared_ptr <LedgerConsensus<RCLCxTraits>>
make_LedgerConsensus (
Expand Down
10 changes: 10 additions & 0 deletions src/ripple/app/ledger/impl/LedgerConsensusImp.h
Expand Up @@ -354,6 +354,16 @@ class LedgerConsensusImp
// nodes that have bowed out of this consensus process
hash_set<NodeID_t> deadNodes_;
beast::Journal j_;

public:
/** Returns validation public key */
PublicKey const&
getValidationPublicKey () const override;

/** Set validation private and public key pair. */
void
setValidationKeys (
SecretKey const& valSecret, PublicKey const& valPublic) override;
};

//------------------------------------------------------------------------------
Expand Down
68 changes: 51 additions & 17 deletions src/ripple/app/main/Application.cpp
Expand Up @@ -66,6 +66,7 @@
#include <ripple/overlay/Cluster.h>
#include <ripple/overlay/make_Overlay.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/STParsedJSON.h>
#include <ripple/protocol/types.h>
Expand Down Expand Up @@ -1102,26 +1103,59 @@ bool ApplicationImp::setup()
return false;
}

if (!validatorManifests_->load (
getWalletDB (), "ValidatorManifests",
config().section (SECTION_VALIDATION_MANIFEST).lines()))
{
JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
return false;
}
PublicKey valPublic;
SecretKey valSecret;
std::string manifest;
if (config().exists (SECTION_VALIDATOR_TOKEN))
{
if (auto const token = ValidatorToken::make_ValidatorToken (
config().section (SECTION_VALIDATOR_TOKEN).lines ()))
{
valSecret = token->validationSecret;
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
manifest = std::move(token->manifest);
}
else
{
JLOG(m_journal.fatal()) <<
"Invalid entry in validator token configuration.";
return false;
}
}
else if (config().exists (SECTION_VALIDATION_SEED))
{
auto const seed = parseBase58<Seed>(
config().section (SECTION_VALIDATION_SEED).lines ().front());
if (!seed)
Throw<std::runtime_error> (
"Invalid seed specified in [" SECTION_VALIDATION_SEED "]");
valSecret = generateSecretKey (KeyType::secp256k1, *seed);
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
}

if (!validatorManifests_->load (
getWalletDB (), "ValidatorManifests", manifest))
{
JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
return false;
}

publisherManifests_->load (
getWalletDB (), "PublisherManifests");
publisherManifests_->load (
getWalletDB (), "PublisherManifests");

// Setup trusted validators
if (!validators_->load (
config_->VALIDATION_PUB,
config().section (SECTION_VALIDATORS).values (),
config().section (SECTION_VALIDATOR_LIST_KEYS).values ()))
{
JLOG(m_journal.fatal()) <<
"Invalid entry in validator configuration.";
return false;
m_networkOPs->setValidationKeys (valSecret, valPublic);

// Setup trusted validators
if (!validators_->load (
valPublic,
config().section (SECTION_VALIDATORS).values (),
config().section (SECTION_VALIDATOR_LIST_KEYS).values ()))
{
JLOG(m_journal.fatal()) <<
"Invalid entry in validator configuration.";
return false;
}
}

if (!validatorSites_->load (
Expand Down
2 changes: 2 additions & 0 deletions src/ripple/app/main/Application.h
Expand Up @@ -57,6 +57,8 @@ class OrderBookDB;
class Overlay;
class PathRequests;
class PendingSaves;
class PublicKey;
class SecretKey;
class AccountIDCache;
class STLedgerEntry;
class TimeKeeper;
Expand Down
7 changes: 4 additions & 3 deletions src/ripple/app/main/NodeIdentity.cpp
Expand Up @@ -23,6 +23,7 @@
#include <ripple/app/main/NodeIdentity.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/core/ConfigSections.h>
#include <boost/format.hpp>
#include <boost/optional.hpp>

Expand All @@ -32,14 +33,14 @@ std::pair<PublicKey, SecretKey>
loadNodeIdentity (Application& app)
{
// If a seed is specified in the configuration file use that directly.
if (!app.config().NODE_SEED.empty ())
if (app.config().exists(SECTION_NODE_SEED))
{
auto const seed = parseBase58<Seed>(
app.config().NODE_SEED);
app.config().section(SECTION_NODE_SEED).lines().front());

if (!seed)
Throw<std::runtime_error>(
"NodeIdentity: Bad [node_seed] specified");
"NodeIdentity: Bad [" SECTION_NODE_SEED "] specified");

auto secretKey =
generateSecretKey (KeyType::secp256k1, *seed);
Expand Down

0 comments on commit 4ae8fa6

Please sign in to comment.