1#include <xrpl/server/Manifest.h>
3#include <xrpl/basics/Blob.h>
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/Slice.h>
6#include <xrpl/basics/StringUtilities.h>
7#include <xrpl/basics/base64.h>
8#include <xrpl/basics/base_uint.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/beast/utility/Journal.h>
11#include <xrpl/beast/utility/instrumentation.h>
12#include <xrpl/json/json_reader.h>
13#include <xrpl/json/json_value.h>
14#include <xrpl/protocol/HashPrefix.h>
15#include <xrpl/protocol/PublicKey.h>
16#include <xrpl/protocol/SField.h>
17#include <xrpl/protocol/SOTemplate.h>
18#include <xrpl/protocol/STExchange.h>
19#include <xrpl/protocol/STObject.h>
20#include <xrpl/protocol/Serializer.h>
21#include <xrpl/protocol/Sign.h>
22#include <xrpl/protocol/tokens.h>
23#include <xrpl/rdb/DatabaseCon.h>
24#include <xrpl/server/Wallet.h>
26#include <boost/algorithm/string/trim.hpp>
50 return "Revocation Manifest " + mk;
117 domain.
assign(
reinterpret_cast<char const*
>(d.data()), d.size());
140 if (!hasEphemeralKey)
143 if (!hasEphemeralSig)
146 auto const spk = st.
getFieldVL(sfSigningPubKey);
154 if (*signingKey == masterKey)
161 return Manifest(serialized, masterKey, signingKey, seq, domain);
165 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
170template <
class Stream>
179template <
class Stream>
189 <<
";OldSeq: " << oldSeq <<
";";
246 if (!
get(st, sfSignature))
274 for (
auto const& line : blob)
275 tokenStr += boost::algorithm::trim_copy(line);
282 if (r.
parse(tokenStr, token))
287 if (m.isString() && k.isString())
289 auto const key =
strUnHex(k.asString());
291 if (key && key->size() == 32)
294 .manifest = m.asString(), .validationSecret =
makeSlice(*key)};
303 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
312 auto const iter =
map_.find(pk);
314 if (iter !=
map_.end() && !iter->second.revoked())
315 return iter->second.signingKey;
335 auto const iter =
map_.find(pk);
337 if (iter !=
map_.end() && !iter->second.revoked())
338 return iter->second.sequence;
347 auto const iter =
map_.find(pk);
349 if (iter !=
map_.end() && !iter->second.revoked())
350 return iter->second.domain;
359 auto const iter =
map_.find(pk);
361 if (iter !=
map_.end() && !iter->second.revoked())
362 return iter->second.serialized;
371 auto const iter =
map_.find(pk);
373 if (iter !=
map_.end())
374 return iter->second.revoked();
388 auto prewriteCheck = [
this, &m](
auto const& iter,
bool checkSignature,
auto const& lock)
390 XRPL_ASSERT(lock.owns_lock(),
"xrpl::ManifestCache::applyManifest::prewriteCheck : locked");
393 if (iter !=
map_.end() && m.
sequence <= iter->second.sequence)
399 if (
auto stream =
j_.debug())
404 if (checkSignature && !m.
verify())
406 if (
auto stream =
j_.warn())
420 if (
auto stream =
j_.warn(); stream &&
revoked)
427 JLOG(
j_.warn()) <<
to_string(m) <<
": Master key already used as ephemeral key for "
438 <<
": is not revoked and the manifest has no "
439 "signing key. Hence, the manifest is "
450 <<
": Ephemeral key already used as ephemeral key for "
458 JLOG(
j_.warn()) <<
to_string(m) <<
": Ephemeral key used as master key for "
470 if (
auto d = prewriteCheck(
map_.find(m.
masterKey),
true, sl))
485 if (
auto d = prewriteCheck(iter,
false, sl))
491 if (iter ==
map_.end())
493 if (
auto stream =
j_.info())
504 map_.emplace(std::move(masterKey), std::move(m));
514 if (
auto stream =
j_.info())
518 *iter->second.signingKey);
528 iter->second = std::move(m);
550 load(dbCon, dbTable);
552 if (!configManifest.
empty())
557 JLOG(
j_.error()) <<
"Malformed validator_token in config";
563 JLOG(
j_.warn()) <<
"Configured manifest revokes public key";
568 JLOG(
j_.error()) <<
"Manifest in config was rejected";
573 if (!configRevocation.
empty())
578 configRevocation.
cbegin(),
579 configRevocation.
cend(),
583 for (
auto const& line : configRevocation)
584 revocationStr += boost::algorithm::trim_copy(line);
590 JLOG(
j_.error()) <<
"Invalid validator key revocation in config";
A generic endpoint for log messages.
Unserialize a JSON document into a Value.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
LockedSociSession checkoutDb()
std::atomic< std::uint32_t > seq_
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.
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.
hash_map< PublicKey, PublicKey > signingToMasterKeys_
Master public keys stored by current ephemeral public key.
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.
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.
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Defines the fields and their attributes within a STObject.
Blob getFieldVL(SField const &field) const
std::uint32_t getFieldU32(SField const &field) const
void applyTemplate(SOTemplate const &type)
uint256 getHash(HashPrefix prefix) const
bool isFieldPresent(SField const &field) const
void set(SOTemplate const &)
std::uint16_t getFieldU16(SField const &field) const
An immutable linear range of bytes.
bool empty() const noexcept
Return true if the byte range is empty.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Stream & logMftAct(Stream &s, std::string const &action, PublicKey const &pk, std::uint32_t seq)
std::string base64Decode(std::string_view data)
void saveManifests(soci::session &session, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted, hash_map< PublicKey, Manifest > const &map, beast::Journal j)
saveManifests Saves all given manifests to the database.
bool isProperlyFormedTomlDomain(std::string_view domain)
Determines if the given string looks like a TOML-file hosting domain.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
void getManifests(soci::session &session, std::string const &dbTable, ManifestCache &cache, beast::Journal j)
getManifests Loads a manifest from the wallet database and stores it in the cache.
std::vector< unsigned char > Blob
Storage for linear binary data.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal=beast::Journal(beast::Journal::getNullSink()))
@ BadMasterKey
The master key is not acceptable to us.
@ Accepted
Manifest is valid.
@ Invalid
Timely, but invalid signature.
@ BadEphemeralKey
The ephemeral key is not acceptable to us.
@ Stale
Sequence is too old.
static bool revoked(std::uint32_t sequence)
Returns true if manifest revokes master key.
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
Blob getMasterSignature() const
Returns manifest master key signature.
std::optional< Blob > getSignature() const
Returns manifest signature.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
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.