List all trusted validator keys under single config section:

Trusted master public keys can be listed under either [validators] or
[validator_keys] config sections. All keys listed under [validators] are
added to permanent trusted keys list regardless of key type.

A master public key is moved from permanent key list to manifest cache
when one of its manifests is received. This allows rippled operators to
list all trusted keys under the [validators] config section.
This commit is contained in:
wilsonianb
2016-03-17 16:01:05 -07:00
committed by seelabs
parent fdd2740f8b
commit 095f85f159
5 changed files with 193 additions and 10 deletions

View File

@@ -38,6 +38,15 @@ private:
randomSecretKey());
}
static
PublicKey
randomMasterKey ()
{
return derivePublicKey (
KeyType::ed25519,
randomSecretKey());
}
static
bool
isPresent (
@@ -60,6 +69,7 @@ private:
auto validators = std::make_unique <ValidatorList> (beast::Journal ());
std::vector<PublicKey> network;
network.reserve(8);
while (network.size () != 8)
network.push_back (randomNode());
@@ -86,13 +96,13 @@ private:
// Correct configuration
s1.append (format (network[0]));
s1.append (format (network[1]) + " Comment");
s1.append (format (network[2]) + " Multi Word Comment");
s1.append (format (network[3]) + " Leading Whitespace");
s1.append (format (network[4]) + " Trailing Whitespace ");
s1.append (format (network[5]) + " Leading & Trailing Whitespace ");
s1.append (format (network[6]) + " Leading, Trailing & Internal Whitespace ");
s1.append (format (network[7]) + " ");
s1.append (format (network[1], " Comment"));
s1.append (format (network[2], " Multi Word Comment"));
s1.append (format (network[3], " Leading Whitespace"));
s1.append (format (network[4], " Trailing Whitespace "));
s1.append (format (network[5], " Leading & Trailing Whitespace "));
s1.append (format (network[6], " Leading, Trailing & Internal Whitespace "));
s1.append (format (network[7], " "));
expect (validators->load (s1));
@@ -123,6 +133,17 @@ private:
expect (!validators->load (s5));
expect (!validators->trusted (node1));
expect (!validators->trusted (node2));
// Add Ed25519 master public keys to permanent validators list
auto const masterNode1 = randomMasterKey ();
auto const masterNode2 = randomMasterKey ();
Section s6;
s6.append (format (masterNode1));
s6.append (format (masterNode2, " Comment"));
expect (validators->load (s6));
expect (validators->trusted (masterNode1));
expect (validators->trusted (masterNode2));
}
void

View File

@@ -206,6 +206,12 @@ ManifestCache::configManifest (
}
}
bool
ManifestCache::trusted (PublicKey const& identity) const
{
return map_.count(identity);
}
void
ManifestCache::addTrustedKey (PublicKey const& pk, std::string comment)
{
@@ -222,6 +228,13 @@ ManifestCache::addTrustedKey (PublicKey const& pk, std::string comment)
value.comment = std::move(comment);
}
std::size_t
ManifestCache::size () const
{
std::lock_guard <std::mutex> lock (mutex_);
return map_.size ();
}
ManifestDisposition
ManifestCache::canApply (PublicKey const& pk, std::uint32_t seq,
beast::Journal journal) const
@@ -263,6 +276,16 @@ ManifestDisposition
ManifestCache::applyManifest (
Manifest m, ValidatorList& unl, beast::Journal journal)
{
/*
Move master public key from permanent trusted key list
to manifest cache.
*/
if (auto unlComment = unl.member (m.masterKey))
{
addTrustedKey (m.masterKey, *unlComment);
unl.removePermanentKey (m.masterKey);
}
{
std::lock_guard<std::mutex> lock (mutex_);
@@ -388,6 +411,11 @@ void ManifestCache::load (
{
Throw<std::runtime_error> ("Unverifiable manifest in db");
}
// Remove master public key from permanent trusted key list
if (unl.trusted(mo->masterKey))
unl.removePermanentKey (mo->masterKey);
// add trusted key
map_[mo->masterKey];

View File

@@ -168,8 +168,17 @@ public:
void configManifest (Manifest m, ValidatorList& unl, beast::Journal journal);
/** Determines whether a node is in the trusted master key list */
bool
trusted (
PublicKey const& identity) const;
void addTrustedKey (PublicKey const& pk, std::string comment);
/** The number of installed trusted master keys */
std::size_t
size () const;
ManifestDisposition
applyManifest (
Manifest m, ValidatorList& unl, beast::Journal journal);

View File

@@ -438,7 +438,8 @@ OverlayImpl::setupValidatorKeyManifests (BasicConfig const& config,
journal_);
if (!loaded)
Throw<std::runtime_error> ("Unable to load validator keys");
Throw<std::runtime_error> (
"Unable to load keys from [validator_keys]");
auto const validation_manifest =
config.section ("validation_manifest");

View File

@@ -36,6 +36,20 @@ namespace tests {
class manifest_test : public ripple::TestSuite
{
private:
static PublicKey randomNode ()
{
return derivePublicKey (
KeyType::secp256k1,
randomSecretKey());
}
static PublicKey randomMasterKey ()
{
return derivePublicKey (
KeyType::ed25519,
randomSecretKey());
}
static void cleanupDatabaseDir (boost::filesystem::path const& dbPath)
{
using namespace boost::filesystem;
@@ -122,7 +136,95 @@ public:
return Manifest (m.serialized, m.masterKey, m.signingKey, m.sequence);
}
void testLoadStore (ManifestCache const& m, ValidatorList& unl)
void
testConfigLoad ()
{
testcase ("Config Load");
ManifestCache cache;
beast::Journal journal;
std::vector<PublicKey> network;
network.reserve(8);
while (network.size () != 8)
network.push_back (randomMasterKey());
auto format = [](
PublicKey const &publicKey,
char const* comment = nullptr)
{
auto ret = toBase58(
TokenType::TOKEN_NODE_PUBLIC,
publicKey);
if (comment)
ret += comment;
return ret;
};
Section s1;
// Correct (empty) configuration
expect (cache.loadValidatorKeys (s1, journal));
expect (cache.size() == 0);
// Correct configuration
s1.append (format (network[0]));
s1.append (format (network[1], " Comment"));
s1.append (format (network[2], " Multi Word Comment"));
s1.append (format (network[3], " Leading Whitespace"));
s1.append (format (network[4], " Trailing Whitespace "));
s1.append (format (network[5], " Leading & Trailing Whitespace "));
s1.append (format (network[6], " Leading, Trailing & Internal Whitespace "));
s1.append (format (network[7], " "));
expect (cache.loadValidatorKeys (s1, journal));
for (auto const& n : network)
expect (cache.trusted (n));
// Incorrect configurations:
Section s2;
s2.append ("NotAPublicKey");
expect (!cache.loadValidatorKeys (s2, journal));
Section s3;
s3.append (format (network[0], "!"));
expect (!cache.loadValidatorKeys (s3, journal));
Section s4;
s4.append (format (network[0], "! Comment"));
expect (!cache.loadValidatorKeys (s4, journal));
// Check if we properly terminate when we encounter
// a malformed or unparseable entry:
auto const masterKey1 = randomMasterKey();
auto const masterKey2 = randomMasterKey ();
Section s5;
s5.append (format (masterKey1, "XXX"));
s5.append (format (masterKey2));
expect (!cache.loadValidatorKeys (s5, journal));
expect (!cache.trusted (masterKey1));
expect (!cache.trusted (masterKey2));
// Reject secp256k1 permanent validator keys
auto const node1 = randomNode ();
auto const node2 = randomNode ();
Section s6;
s6.append (format (node1));
s6.append (format (node2, " Comment"));
expect (!cache.loadValidatorKeys (s6, journal));
expect (!cache.trusted (node1));
expect (!cache.trusted (node2));
}
void testLoadStore (ManifestCache const& m, ValidatorList& unl,
PublicKey& pk)
{
testcase ("load/store");
@@ -138,7 +240,14 @@ public:
ManifestCache loaded;
beast::Journal journal;
// load should remove master key from permanent key list
expect (m.trusted(pk));
expect (unl.insertPermanentKey(pk, "trusted key"));
expect (unl.trusted(pk));
loaded.load (dbCon, unl, journal);
expect (!unl.trusted(pk));
expect (loaded.trusted(pk));
auto getPopulatedManifests =
[](ManifestCache const& cache) -> std::vector<Manifest const*>
@@ -206,6 +315,7 @@ public:
ManifestCache cache;
beast::Journal journal;
auto unl = std::make_unique<ValidatorList> (journal);
PublicKey pk;
{
testcase ("apply");
auto const accepted = ManifestDisposition::accepted;
@@ -246,8 +356,22 @@ public:
expect (!ripple::make_Manifest(fake));
expect (cache.applyManifest (clone (s_b2), *unl, journal) == invalid);
// When trusted permanent key is found as manifest master key
// move to manifest cache
auto const sk_c = randomSecretKey();
pk = derivePublicKey(KeyType::ed25519, sk_c);
auto const kp_c = randomKeyPair(KeyType::secp256k1);
auto const s_c0 = make_Manifest (KeyType::ed25519, sk_c, kp_c.first, 0);
expect (unl->insertPermanentKey(pk, "trusted key"));
expect (unl->trusted(pk));
expect (!cache.trusted(pk));
expect (cache.applyManifest(clone (s_c0), *unl, journal) == accepted);
expect (!unl->trusted(pk));
expect (cache.trusted(pk));
}
testLoadStore (cache, *unl);
testConfigLoad();
testLoadStore (cache, *unl, pk);
testGetSignature ();
}
};