Improve ValidatorList invalid UNL manifest logging (#5804)

This change raises logging severity from `INFO` to `WARN` when handling UNL manifest signed with an unexpected / invalid key. It also changes the internal error code for an invalid format of UNL manifest to `invalid` (from `untrusted`).

This is a follow up to problems experienced by an UNL node due to old manifest key configured in `validators.txt`, which would be easier to diagnose with improved logging.

It also replaces a log line with `UNREACHABLE` for an impossible situation when we match UNL manifest key against a configured key which has an invalid type (we cannot configure such a key because of checks when loading configured keys).
This commit is contained in:
Bronek Kozicki
2025-09-25 15:14:29 +01:00
committed by GitHub
parent 73ff54143d
commit 51c5f2bfc9
3 changed files with 44 additions and 16 deletions

View File

@@ -768,6 +768,24 @@ private:
expectUntrusted(lists.at(7)); expectUntrusted(lists.at(7));
expectTrusted(lists.at(2)); expectTrusted(lists.at(2));
// try empty or mangled manifest
checkResult(
trustedKeys->applyLists(
"", version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri),
publisherPublic,
ListDisposition::invalid,
ListDisposition::invalid);
checkResult(
trustedKeys->applyLists(
base64_encode("not a manifest"),
version,
{{blob7, sig7, {}}, {blob6, sig6, {}}},
siteUri),
publisherPublic,
ListDisposition::invalid,
ListDisposition::invalid);
// do not use list from untrusted publisher // do not use list from untrusted publisher
auto const untrustedManifest = base64_encode(makeManifestString( auto const untrustedManifest = base64_encode(makeManifestString(
randomMasterKey(), randomMasterKey(),

View File

@@ -877,7 +877,7 @@ private:
verify( verify(
lock_guard const&, lock_guard const&,
Json::Value& list, Json::Value& list,
std::string const& manifest, Manifest manifest,
std::string const& blob, std::string const& blob,
std::string const& signature); std::string const& signature);

View File

@@ -1149,21 +1149,33 @@ ValidatorList::applyList(
Json::Value list; Json::Value list;
auto const& manifest = localManifest ? *localManifest : globalManifest; auto const& manifest = localManifest ? *localManifest : globalManifest;
auto [result, pubKeyOpt] = verify(lock, list, manifest, blob, signature); auto m = deserializeManifest(base64_decode(manifest));
if (!m)
{
JLOG(j_.warn()) << "UNL manifest cannot be deserialized";
return PublisherListStats{ListDisposition::invalid};
}
auto [result, pubKeyOpt] =
verify(lock, list, std::move(*m), blob, signature);
if (!pubKeyOpt) if (!pubKeyOpt)
{ {
JLOG(j_.info()) << "ValidatorList::applyList unable to retrieve the " JLOG(j_.warn())
"master public key from the verify function\n"; << "UNL manifest is signed with an unrecognized master public key";
return PublisherListStats{result}; return PublisherListStats{result};
} }
if (!publicKeyType(*pubKeyOpt)) if (!publicKeyType(*pubKeyOpt))
{ { // LCOV_EXCL_START
JLOG(j_.info()) << "ValidatorList::applyList Invalid Public Key type" // This is an impossible situation because we will never load an
" retrieved from the verify function\n "; // invalid public key type (see checks in `ValidatorList::load`) however
// we can only arrive here if the key used by the manifest matched one of
// the loaded keys
UNREACHABLE(
"ripple::ValidatorList::applyList : invalid public key type");
return PublisherListStats{result}; return PublisherListStats{result};
} } // LCOV_EXCL_STOP
PublicKey pubKey = *pubKeyOpt; PublicKey pubKey = *pubKeyOpt;
if (result > ListDisposition::pending) if (result > ListDisposition::pending)
@@ -1356,19 +1368,17 @@ std::pair<ListDisposition, std::optional<PublicKey>>
ValidatorList::verify( ValidatorList::verify(
ValidatorList::lock_guard const& lock, ValidatorList::lock_guard const& lock,
Json::Value& list, Json::Value& list,
std::string const& manifest, Manifest manifest,
std::string const& blob, std::string const& blob,
std::string const& signature) std::string const& signature)
{ {
auto m = deserializeManifest(base64_decode(manifest)); if (!publisherLists_.count(manifest.masterKey))
if (!m || !publisherLists_.count(m->masterKey))
return {ListDisposition::untrusted, {}}; return {ListDisposition::untrusted, {}};
PublicKey masterPubKey = m->masterKey; PublicKey masterPubKey = manifest.masterKey;
auto const revoked = m->revoked(); auto const revoked = manifest.revoked();
auto const result = publisherManifests_.applyManifest(std::move(*m)); auto const result = publisherManifests_.applyManifest(std::move(manifest));
if (revoked && result == ManifestDisposition::accepted) if (revoked && result == ManifestDisposition::accepted)
{ {
@@ -1796,7 +1806,7 @@ ValidatorList::getAvailable(
if (!keyBlob || !publicKeyType(makeSlice(*keyBlob))) if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
{ {
JLOG(j_.info()) << "Invalid requested validator list publisher key: " JLOG(j_.warn()) << "Invalid requested validator list publisher key: "
<< pubKey; << pubKey;
return {}; return {};
} }