Files
xahaud/src/ripple/overlay/impl/Manifest.h
2016-04-20 05:16:32 -04:00

223 lines
8.0 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_OVERLAY_MANIFEST_H_INCLUDED
#define RIPPLE_OVERLAY_MANIFEST_H_INCLUDED
#include <ripple/app/misc/ValidatorList.h>
#include <ripple/basics/BasicConfig.h>
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/STExchange.h>
#include <ripple/beast/utility/Journal.h>
#include <boost/optional.hpp>
#include <string>
namespace ripple {
/*
Validator key manifests
-----------------------
Suppose the secret keys installed on a Ripple validator are compromised. Not
only do you have to generate and install new key pairs on each validator,
EVERY rippled needs to have its config updated with the new public keys, and
is vulnerable to forged validation signatures until this is done. The
solution is a new layer of indirection: A master secret key under
restrictive access control is used to sign a "manifest": essentially, a
certificate including the master public key, an ephemeral public key for
verifying validations (which will be signed by its secret counterpart), a
sequence number, and a digital signature.
The manifest has two serialized forms: one which includes the digital
signature and one which doesn't. There is an obvious causal dependency
relationship between the (latter) form with no signature, the signature
of that form, and the (former) form which includes that signature. In
other words, a message can't contain a signature of itself. The code
below stores a serialized manifest which includes the signature, and
dynamically generates the signatureless form when it needs to verify
the signature.
There are two stores of information within rippled related to manifests.
An instance of ManifestCache stores, for each trusted validator, (a) its
master public key, and (b) the most senior of all valid manifests it has
seen for that validator, if any. On startup, the [validator_keys] config
entries are used to prime the manifest cache with the trusted master keys.
At this point, the manifest cache has all the entries it will ever have,
but none of them have manifests. The [validation_manifest] config entry
(which is the manifest for this validator) is then decoded and added to
the manifest cache. Other manifests are added as "gossip" is received
from rippled peers.
The other data store (which does not involve manifests per se) contains
the set of active ephemeral validator keys. Keys are added to the set
when a manifest is accepted, and removed when that manifest is obsoleted.
When an ephemeral key is compromised, a new signing key pair is created,
along with a new manifest vouching for it (with a higher sequence number),
signed by the master key. When a rippled peer receives the new manifest,
it verifies it with the master key and (assuming it's valid) discards the
old ephemeral key and stores the new one. If the master key itself gets
compromised, a manifest with sequence number 0xFFFFFFFF will supersede a
prior manifest and discard any existing ephemeral key without storing a
new one. Since no further manifests for this master key will be accepted
(since no higher sequence number is possible), and no signing key is on
record, no validations will be accepted from the compromised validator.
*/
//------------------------------------------------------------------------------
struct Manifest
{
std::string serialized;
PublicKey masterKey;
PublicKey signingKey;
std::uint32_t sequence;
Manifest(std::string s, PublicKey pk, PublicKey spk, std::uint32_t seq);
Manifest(Manifest&& other) = default;
Manifest& operator=(Manifest&& other) = default;
bool verify () const;
uint256 hash () const;
bool revoked () const;
Blob getSignature () const;
};
boost::optional<Manifest> make_Manifest(std::string s);
inline bool operator==(Manifest const& lhs, Manifest const& rhs)
{
return lhs.serialized == rhs.serialized && lhs.masterKey == rhs.masterKey &&
lhs.signingKey == rhs.signingKey && lhs.sequence == rhs.sequence;
}
inline bool operator!=(Manifest const& lhs, Manifest const& rhs)
{
return !(lhs == rhs);
}
enum class ManifestDisposition
{
accepted = 0, // everything checked out
untrusted, // manifest declares a master key we don't trust
stale, // trusted master key, but seq is too old
invalid, // trusted and timely, but invalid signature
};
class DatabaseCon;
/** Remembers manifests with the highest sequence number. */
class ManifestCache
{
private:
struct MappedType
{
MappedType() = default;
MappedType(MappedType&&) = default;
MappedType& operator=(MappedType&&) = default;
MappedType(std::string comment,
std::string serialized,
PublicKey pk, PublicKey spk, std::uint32_t seq)
:comment (std::move(comment))
{
m.emplace (std::move(serialized), std::move(pk), std::move(spk),
seq);
}
std::string comment;
boost::optional<Manifest> m;
};
using MapType = hash_map<PublicKey, MappedType>;
mutable std::mutex mutex_;
MapType map_;
ManifestDisposition
canApply (PublicKey const& pk, std::uint32_t seq,
beast::Journal journal) const;
public:
ManifestCache() = default;
ManifestCache (ManifestCache const&) = delete;
ManifestCache& operator= (ManifestCache const&) = delete;
~ManifestCache() = default;
bool loadValidatorKeys(
Section const& keys,
beast::Journal journal);
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);
void load (
DatabaseCon& dbCon, ValidatorList& unl, beast::Journal journal);
void save (DatabaseCon& dbCon) const;
// A "for_each" for populated manifests only
template <class Function>
void
for_each_manifest(Function&& f) const
{
std::lock_guard<std::mutex> lock (mutex_);
for (auto const& e : map_)
{
if (auto const& m = e.second.m)
f(*m);
}
}
// A "for_each" for populated manifests only
// The PreFun is called with the maximum number of
// times EachFun will be called (useful for memory allocations)
template <class PreFun, class EachFun>
void
for_each_manifest(PreFun&& pf, EachFun&& f) const
{
std::lock_guard<std::mutex> lock (mutex_);
pf(map_.size ());
for (auto const& e : map_)
{
if (auto const& m = e.second.m)
f(*m);
}
}
};
} // ripple
#endif