rippled
Loading...
Searching...
No Matches
Manifest.h
1#pragma once
2
3#include <xrpl/basics/UnorderedContainers.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/protocol/PublicKey.h>
6#include <xrpl/protocol/SecretKey.h>
7
8#include <optional>
9#include <shared_mutex>
10#include <string>
11
12namespace xrpl {
13
14/*
15 Validator key manifests
16 -----------------------
17
18 Suppose the secret keys installed on a Ripple validator are compromised. Not
19 only do you have to generate and install new key pairs on each validator,
20 EVERY rippled needs to have its config updated with the new public keys, and
21 is vulnerable to forged validation signatures until this is done. The
22 solution is a new layer of indirection: A master secret key under
23 restrictive access control is used to sign a "manifest": essentially, a
24 certificate including the master public key, an ephemeral public key for
25 verifying validations (which will be signed by its secret counterpart), a
26 sequence number, and a digital signature.
27
28 The manifest has two serialized forms: one which includes the digital
29 signature and one which doesn't. There is an obvious causal dependency
30 relationship between the (latter) form with no signature, the signature
31 of that form, and the (former) form which includes that signature. In
32 other words, a message can't contain a signature of itself. The code
33 below stores a serialized manifest which includes the signature, and
34 dynamically generates the signatureless form when it needs to verify
35 the signature.
36
37 An instance of ManifestCache stores, for each trusted validator, (a) its
38 master public key, and (b) the most senior of all valid manifests it has
39 seen for that validator, if any. On startup, the [validator_token] config
40 entry (which contains the manifest for this validator) is decoded and
41 added to the manifest cache. Other manifests are added as "gossip"
42 received from rippled peers.
43
44 When an ephemeral key is compromised, a new signing key pair is created,
45 along with a new manifest vouching for it (with a higher sequence number),
46 signed by the master key. When a rippled peer receives the new manifest,
47 it verifies it with the master key and (assuming it's valid) discards the
48 old ephemeral key and stores the new one. If the master key itself gets
49 compromised, a manifest with sequence number 0xFFFFFFFF will supersede a
50 prior manifest and discard any existing ephemeral key without storing a
51 new one. These revocation manifests are loaded from the
52 [validator_key_revocation] config entry as well as received as gossip from
53 peers. Since no further manifests for this master key will be accepted
54 (since no higher sequence number is possible), and no signing key is on
55 record, no validations will be accepted from the compromised validator.
56*/
57
58//------------------------------------------------------------------------------
59
61{
64
67
69 // A revoked manifest does not have a signingKey
70 // This field is specified as "optional" in manifestFormat's
71 // SOTemplate
73
76
79
80 Manifest() = delete;
81
83 std::string const& serialized_,
84 PublicKey const& masterKey_,
85 std::optional<PublicKey> const& signingKey_,
86 std::uint32_t seq,
87 std::string const& domain_)
88 : serialized(serialized_)
89 , masterKey(masterKey_)
90 , signingKey(signingKey_)
91 , sequence(seq)
92 , domain(domain_)
93 {
94 }
95
96 Manifest(Manifest const& other) = delete;
98 operator=(Manifest const& other) = delete;
99 Manifest(Manifest&& other) = default;
100 Manifest&
101 operator=(Manifest&& other) = default;
102
104 bool
105 verify() const;
106
108 uint256
109 hash() const;
110
112 // The maximum possible sequence number means that the master key has
113 // been revoked
114 static bool
116
118 bool
119 revoked() const;
120
123 getSignature() const;
124
126 Blob
127 getMasterSignature() const;
128};
129
132to_string(Manifest const& m);
133
146
154
155template <
156 class T,
167inline bool
168operator==(Manifest const& lhs, Manifest const& rhs)
169{
170 // In theory, comparing the two serialized strings should be
171 // sufficient.
172 return lhs.sequence == rhs.sequence && lhs.masterKey == rhs.masterKey &&
173 lhs.signingKey == rhs.signingKey && lhs.domain == rhs.domain &&
174 lhs.serialized == rhs.serialized;
175}
176
177inline bool
178operator!=(Manifest const& lhs, Manifest const& rhs)
179{
180 return !(lhs == rhs);
181}
182
188
191 std::vector<std::string> const& blob,
193
196 accepted = 0,
197
199 stale,
200
203
206
208 invalid
209};
210
211inline std::string
213{
214 switch (m)
215 {
217 return "accepted";
219 return "stale";
221 return "badMasterKey";
223 return "badEphemeralKey";
225 return "invalid";
226 default:
227 return "unknown";
228 }
229}
230
231class DatabaseCon;
232
235{
236private:
239
242
245
247
248public:
252
255 sequence() const
256 {
257 return seq_.load();
258 }
259
271 getSigningKey(PublicKey const& pk) const;
272
284 getMasterKey(PublicKey const& pk) const;
285
292 getSequence(PublicKey const& pk) const;
293
300 getDomain(PublicKey const& pk) const;
301
308 getManifest(PublicKey const& pk) const;
309
318 bool
319 revoked(PublicKey const& pk) const;
320
334
351 bool
352 load(
353 DatabaseCon& dbCon,
354 std::string const& dbTable,
355 std::string const& configManifest,
356 std::vector<std::string> const& configRevocation);
357
368 void
369 load(DatabaseCon& dbCon, std::string const& dbTable);
370
381 void
382 save(
383 DatabaseCon& dbCon,
384 std::string const& dbTable,
385 std::function<bool(PublicKey const&)> const& isTrusted);
386
400 template <class Function>
401 void
402 for_each_manifest(Function&& f) const
403 {
404 std::shared_lock const lock{mutex_};
405 for (auto const& [_, manifest] : map_)
406 {
407 (void)_;
408 f(manifest);
409 }
410 }
411
428 template <class PreFun, class EachFun>
429 void
430 for_each_manifest(PreFun&& pf, EachFun&& f) const
431 {
432 std::shared_lock const lock{mutex_};
433 pf(map_.size());
434 for (auto const& [_, manifest] : map_)
435 {
436 (void)_;
437 f(manifest);
438 }
439 }
440};
441
442} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:40
static Sink & getNullSink()
Returns a Sink which does nothing.
Remembers manifests with the highest sequence number.
Definition Manifest.h:235
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition Manifest.h:402
std::atomic< std::uint32_t > seq_
Definition Manifest.h:246
std::shared_mutex mutex_
Definition Manifest.h:238
void for_each_manifest(PreFun &&pf, EachFun &&f) const
Invokes the callback once for every populated manifest.
Definition Manifest.h:430
bool load(DatabaseCon &dbCon, std::string const &dbTable, std::string const &configManifest, std::vector< std::string > const &configRevocation)
Populate manifest cache with manifests in database and config.
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
ManifestCache(beast::Journal j=beast::Journal(beast::Journal::getNullSink()))
Definition Manifest.h:249
std::optional< std::string > getDomain(PublicKey const &pk) const
Returns domain claimed by a given public key.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
std::uint32_t sequence() const
A monotonically increasing number used to detect new manifests.
Definition Manifest.h:255
hash_map< PublicKey, PublicKey > signingToMasterKeys_
Master public keys stored by current ephemeral public key.
Definition Manifest.h:244
std::optional< std::string > getManifest(PublicKey const &pk) const
Returns manifest corresponding to a given public key.
hash_map< PublicKey, Manifest > map_
Active manifests stored by master public key.
Definition Manifest.h:241
std::optional< std::uint32_t > getSequence(PublicKey const &pk) const
Returns master key's current manifest sequence.
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
beast::Journal j_
Definition Manifest.h:237
A public key.
Definition PublicKey.h:42
A secret key.
Definition SecretKey.h:18
An immutable linear range of bytes.
Definition Slice.h:26
T load(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:557
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:209
@ manifest
Manifest.
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal=beast::Journal(beast::Journal::getNullSink()))
ManifestDisposition
Definition Manifest.h:194
@ badMasterKey
The master key is not acceptable to us.
@ stale
Sequence is too old.
@ accepted
Manifest is valid.
@ badEphemeralKey
The ephemeral key is not acceptable to us.
@ invalid
Timely, but invalid signature.
Manifest(Manifest const &other)=delete
Manifest & operator=(Manifest const &other)=delete
PublicKey masterKey
The master key associated with this manifest.
Definition Manifest.h:66
Manifest(Manifest &&other)=default
std::string serialized
The manifest in serialized form.
Definition Manifest.h:63
Blob getMasterSignature() const
Returns manifest master key signature.
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
Definition Manifest.h:78
std::optional< Blob > getSignature() const
Returns manifest signature.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
Definition Manifest.h:72
std::uint32_t sequence
The sequence number of this manifest.
Definition Manifest.h:75
bool revoked() const
Returns true if manifest revokes master key.
uint256 hash() const
Returns hash of serialized manifest data.
bool verify() const
Returns true if manifest signature is valid.
Manifest & operator=(Manifest &&other)=default
Manifest()=delete
Manifest(std::string const &serialized_, PublicKey const &masterKey_, std::optional< PublicKey > const &signingKey_, std::uint32_t seq, std::string const &domain_)
Definition Manifest.h:82
std::string manifest
Definition Manifest.h:185
SecretKey validationSecret
Definition Manifest.h:186