xrpld
Loading...
Searching...
No Matches
Manifest_test.cpp
1#include <test/jtx/Env.h>
2#include <test/unit_test/utils.h>
3
4#include <xrpld/app/misc/ValidatorList.h>
5
6#include <xrpl/basics/Slice.h>
7#include <xrpl/basics/base64.h>
8#include <xrpl/basics/contract.h>
9#include <xrpl/basics/strHex.h>
10#include <xrpl/beast/unit_test/suite.h>
11#include <xrpl/config/Constants.h>
12#include <xrpl/protocol/HashPrefix.h>
13#include <xrpl/protocol/KeyType.h>
14#include <xrpl/protocol/PublicKey.h>
15#include <xrpl/protocol/SField.h>
16#include <xrpl/protocol/STObject.h>
17#include <xrpl/protocol/SecretKey.h>
18#include <xrpl/protocol/Seed.h>
19#include <xrpl/protocol/Serializer.h>
20#include <xrpl/protocol/Sign.h>
21#include <xrpl/protocol/tokens.h>
22#include <xrpl/server/Manifest.h>
23#include <xrpl/server/Wallet.h>
24
25#include <algorithm>
26#include <array>
27#include <cassert>
28#include <cstdint>
29#include <exception>
30#include <filesystem>
31#include <limits>
32#include <memory>
33#include <optional>
34#include <stdexcept>
35#include <string>
36#include <utility>
37#include <vector>
38
39namespace xrpl::test {
40
42{
43private:
44 static PublicKey
49
50 static PublicKey
55
56 static void
58 {
59 using namespace std::filesystem;
60 if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
61 return;
62 remove(dbPath);
63 }
64
65 static void
67 {
68 using namespace std::filesystem;
69 if (!exists(dbPath))
70 {
71 create_directory(dbPath);
72 return;
73 }
74
75 if (!is_directory(dbPath))
76 {
77 // someone created a file where we want to put our directory
78 Throw<std::runtime_error>("Cannot create directory: " + dbPath.string());
79 }
80 }
83 {
84 return std::filesystem::current_path() / "manifest_test_databases";
85 }
86
87public:
89 {
90 try
91 {
93 }
94 catch (std::exception const&) // NOLINT(bugprone-empty-catch)
95 {
96 }
97 }
98 ~Manifest_test() override
99 {
100 try
101 {
103 }
104 catch (std::exception const&) // NOLINT(bugprone-empty-catch)
105 {
106 }
107 }
108
109 static std::string
111 PublicKey const& pk,
112 SecretKey const& sk,
113 PublicKey const& spk,
114 SecretKey const& ssk,
115 int seq)
116 {
118 st[sfSequence] = seq;
119 st[sfPublicKey] = pk;
120 st[sfSigningPubKey] = spk;
121
122 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
123 sign(st, HashPrefix::Manifest, *publicKeyType(spk), ssk);
124
125 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
126 sign(st, HashPrefix::Manifest, *publicKeyType(pk), sk, sfMasterSignature);
127
128 Serializer s;
129 st.add(s);
130
131 return base64Encode(std::string(static_cast<char const*>(s.data()), s.size()));
132 }
133
135 makeRevocationString(SecretKey const& sk, KeyType type, bool invalidSig = false)
136 {
137 auto const pk = derivePublicKey(type, sk);
138
141 st[sfPublicKey] = pk;
142
143 sign(
144 st, HashPrefix::Manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature);
145 BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::Manifest, pk, sfMasterSignature));
146
147 Serializer s;
148 st.add(s);
149
150 return base64Encode(std::string(static_cast<char const*>(s.data()), s.size()));
151 }
152
154 makeRevocation(SecretKey const& sk, KeyType type, bool invalidSig = false)
155 {
156 auto const pk = derivePublicKey(type, sk);
157
160 st[sfPublicKey] = pk;
161
162 sign(
163 st, HashPrefix::Manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature);
164 BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::Manifest, pk, sfMasterSignature));
165
166 Serializer s;
167 st.add(s);
168
169 std::string const m(static_cast<char const*>(s.data()), s.size());
170 if (auto r = deserializeManifest(m))
171 return std::move(*r);
172 Throw<std::runtime_error>("Could not create a revocation manifest");
173 return *deserializeManifest(std::string{}); // Silence compiler warning.
174 }
175
178 SecretKey const& sk,
179 KeyType type,
180 SecretKey const& ssk,
181 KeyType stype,
182 int seq,
183 bool invalidSig = false)
184 {
185 auto const pk = derivePublicKey(type, sk);
186 auto const spk = derivePublicKey(stype, ssk);
187
189 st[sfSequence] = seq;
190 st[sfPublicKey] = pk;
191 st[sfSigningPubKey] = spk;
192
193 sign(st, HashPrefix::Manifest, stype, ssk);
194 BEAST_EXPECT(verify(st, HashPrefix::Manifest, spk));
195
196 sign(
197 st, HashPrefix::Manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature);
198 BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::Manifest, pk, sfMasterSignature));
199
200 Serializer s;
201 st.add(s);
202
203 std::string const m(static_cast<char const*>(s.data()), s.size());
204 if (auto r = deserializeManifest(m))
205 return std::move(*r);
206 Throw<std::runtime_error>("Could not create a manifest");
207 return *deserializeManifest(std::string{}); // Silence compiler warning.
208 }
209
210 static Manifest
211 clone(Manifest const& m)
212 {
214 return m2;
215 }
216
217 void
219 {
220 testcase("load/store");
221
222 std::string const dbName("ManifestCacheTestDB");
223 {
224 jtx::Env env(*this);
225 DatabaseCon::Setup setup;
226 setup.dataDir = getDatabasePath();
227 assert(!setup.useGlobalPragma);
228
229 auto dbCon = makeTestWalletDB(setup, dbName, env.journal);
230
231 auto getPopulatedManifests =
232 [](ManifestCache const& cache) -> std::vector<Manifest const*> {
234 result.reserve(32);
235 cache.forEachManifest([&result](Manifest const& man) { result.push_back(&man); });
236 return result;
237 };
239 std::ranges::sort(mv, [](Manifest const* lhs, Manifest const* rhs) {
240 return lhs->serialized < rhs->serialized;
241 });
242 return mv;
243 };
244 std::vector<Manifest const*> const inManifests(sort(getPopulatedManifests(m)));
245
246 auto& app = env.app();
248 m, m, env.timeKeeper(), app.config().legacy(Sections::kDatabasePath), env.journal);
249
250 {
251 // save should not store untrusted master keys to db
252 // except for revocations
253 m.save(*dbCon, "ValidatorManifests", [&unl](PublicKey const& pubKey) {
254 return unl->listed(pubKey);
255 });
256
257 ManifestCache loaded;
258
259 loaded.load(*dbCon, "ValidatorManifests");
260
261 // check that all loaded manifests are revocations
262 std::vector<Manifest const*> const loadedManifests(
263 sort(getPopulatedManifests(loaded)));
264
265 for (auto const& man : loadedManifests)
266 BEAST_EXPECT(man->revoked());
267 }
268 {
269 // save should store all trusted master keys to db
271 std::vector<std::string> const keys;
272 s1.reserve(inManifests.size());
273
274 for (auto const& man : inManifests)
275 s1.push_back(toBase58(TokenType::NodePublic, man->masterKey));
276 unl->load({}, s1, keys);
277
278 m.save(*dbCon, "ValidatorManifests", [&unl](PublicKey const& pubKey) {
279 return unl->listed(pubKey);
280 });
281 ManifestCache loaded;
282 loaded.load(*dbCon, "ValidatorManifests");
283
284 // check that the manifest caches are the same
285 std::vector<Manifest const*> const loadedManifests(
286 sort(getPopulatedManifests(loaded)));
287
288 if (inManifests.size() == loadedManifests.size())
289 {
290 BEAST_EXPECT(
292 inManifests,
293 loadedManifests,
294 [](Manifest const* lhs, Manifest const* rhs) { return *lhs == *rhs; }));
295 }
296 else
297 {
298 fail();
299 }
300 }
301 {
302 // load config manifest
303 ManifestCache loaded;
304 std::vector<std::string> const emptyRevocation;
305
306 std::string const badManifest = "bad manifest";
307 BEAST_EXPECT(
308 !loaded.load(*dbCon, "ValidatorManifests", badManifest, emptyRevocation));
309
310 auto const sk = randomSecretKey();
311 auto const pk = derivePublicKey(KeyType::Ed25519, sk);
312 auto const kp = randomKeyPair(KeyType::Secp256k1);
313
314 std::string const cfgManifest = makeManifestString(pk, sk, kp.first, kp.second, 0);
315
316 BEAST_EXPECT(
317 loaded.load(*dbCon, "ValidatorManifests", cfgManifest, emptyRevocation));
318 }
319 {
320 // load config revocation
321 ManifestCache loaded;
322 std::string const emptyManifest;
323
324 std::vector<std::string> const badRevocation = {"bad revocation"};
325 BEAST_EXPECT(
326 !loaded.load(*dbCon, "ValidatorManifests", emptyManifest, badRevocation));
327
328 auto const sk = randomSecretKey();
329 auto const keyType = KeyType::Ed25519;
330 auto const pk = derivePublicKey(keyType, sk);
331 auto const kp = randomKeyPair(KeyType::Secp256k1);
332 std::vector<std::string> const nonRevocation = {
333 makeManifestString(pk, sk, kp.first, kp.second, 0)};
334
335 BEAST_EXPECT(
336 !loaded.load(*dbCon, "ValidatorManifests", emptyManifest, nonRevocation));
337 BEAST_EXPECT(!loaded.revoked(pk));
338
339 std::vector<std::string> const badSigRevocation = {
340 makeRevocationString(sk, keyType, true)};
341 BEAST_EXPECT(
342 !loaded.load(*dbCon, "ValidatorManifests", emptyManifest, badSigRevocation));
343 BEAST_EXPECT(!loaded.revoked(pk));
344
345 std::vector<std::string> const cfgRevocation = {makeRevocationString(sk, keyType)};
346 BEAST_EXPECT(
347 loaded.load(*dbCon, "ValidatorManifests", emptyManifest, cfgRevocation));
348
349 BEAST_EXPECT(loaded.revoked(pk));
350 }
351 }
353 }
354
355 void
357 {
358 testcase("getSignature");
359 auto const sk = randomSecretKey();
360 auto const pk = derivePublicKey(KeyType::Ed25519, sk);
361 auto const kp = randomKeyPair(KeyType::Secp256k1);
362 auto const m = makeManifest(sk, KeyType::Ed25519, kp.second, KeyType::Secp256k1, 0);
363
365 st[sfSequence] = 0;
366 st[sfPublicKey] = pk;
367 st[sfSigningPubKey] = kp.first;
368 Serializer ss;
371 auto const sig = sign(KeyType::Secp256k1, kp.second, ss.slice());
372 BEAST_EXPECT(
373 strHex(sig) ==
374 strHex(*m.getSignature())); // NOLINT(bugprone-unchecked-optional-access)
375
376 auto const masterSig = sign(KeyType::Ed25519, sk, ss.slice());
377 BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
378 }
379
380 void
382 {
383 testcase("getKeys");
384
385 ManifestCache cache;
386 auto const sk = randomSecretKey();
387 auto const pk = derivePublicKey(KeyType::Ed25519, sk);
388
389 // getSigningKey should return same key if there is no manifest
390 BEAST_EXPECT(cache.getSigningKey(pk) == pk);
391
392 // getSigningKey should return the ephemeral public key
393 // for the listed validator master public key
394 // getMasterKey should return the listed validator master key
395 // for that ephemeral public key
396 auto const kp0 = randomKeyPair(KeyType::Secp256k1);
397 BEAST_EXPECT(
399 cache.applyManifest(
402 BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first);
403 BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk);
404
405 // getSigningKey should return the latest ephemeral public key
406 // for the listed validator master public key
407 // getMasterKey should only return a master key for the latest
408 // ephemeral public key
409 auto const kp1 = randomKeyPair(KeyType::Secp256k1);
410 BEAST_EXPECT(
412 cache.applyManifest(
415 BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
416 BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
417 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
418
419 // getSigningKey and getMasterKey should fail if a new manifest is
420 // applied with the same signing key but a higher sequence
421 BEAST_EXPECT(
423 cache.applyManifest(
426 BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
427 BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
428 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
429
430 // getSigningKey should return std::nullopt for a revoked master public
431 // key getMasterKey should return std::nullopt for an ephemeral public
432 // key from a revoked master public key
433 BEAST_EXPECT(
435 cache.applyManifest(
437 BEAST_EXPECT(cache.revoked(pk));
438 BEAST_EXPECT(cache.getSigningKey(pk) == pk);
439 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
440 BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
441 }
442
443 void
445 {
446 testcase("validator token");
447
448 {
449 auto const valSecret = parseBase58<SecretKey>(
450 TokenType::NodePrivate, "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
451
452 // Format token string to test trim()
453 std::vector<std::string> const tokenBlob = {
454 " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
455 " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n",
456 "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n",
457 "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n",
458 "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
459 "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
460 "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
461 "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n",
462 };
463
464 auto const manifest =
465 "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
466 "vCxHXXLplc2GnMhAkE1agqXxBwD"
467 "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
468 "sAOkVB"
469 "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
470 "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
471 "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
472 "r7C0kw"
473 "2AiTzSCjIzditQ8=";
474
475 auto const token = loadValidatorToken(tokenBlob);
476 BEAST_EXPECT(token);
477 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
478 BEAST_EXPECT(test::equal(token->validationSecret, *valSecret));
479 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
480 BEAST_EXPECT(token->manifest == manifest);
481 }
482 {
483 std::vector<std::string> const badToken = {"bad token"};
484 BEAST_EXPECT(!loadValidatorToken(badToken));
485 }
486 }
487
488 void
490 {
491 testcase("Versioning");
492
494 auto const pk = derivePublicKey(KeyType::Ed25519, sk);
495
497 auto const spk = derivePublicKey(KeyType::Secp256k1, ssk);
498
499 auto buildManifestObject = [&](std::uint16_t version) {
501 st[sfSequence] = 3;
502 st[sfPublicKey] = pk;
503 st[sfSigningPubKey] = spk;
504
505 if (version != 0)
506 st[sfVersion] = version;
507
508 sign(st, HashPrefix::Manifest, KeyType::Ed25519, sk, sfMasterSignature);
510
511 Serializer s;
512 st.add(s);
513
514 return std::string(static_cast<char const*>(s.data()), s.size());
515 };
516
517 // We understand version 0 manifests:
518 BEAST_EXPECT(deserializeManifest(buildManifestObject(0)));
519
520 // We don't understand any other versions:
521 BEAST_EXPECT(!deserializeManifest(buildManifestObject(1)));
522 BEAST_EXPECT(!deserializeManifest(buildManifestObject(2001)));
523 }
524
525 void
527 {
529
530 std::uint32_t sequence = 0;
531
532 // public key with invalid type
533 std::array<std::uint8_t, 33> const badKey{
534 0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
535 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
536 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
537
538 // Short public key:
539 std::array<std::uint8_t, 16> const shortKey{
540 0x03,
541 0x30,
542 0xE7,
543 0xFC,
544 0x9D,
545 0x56,
546 0xBB,
547 0x25,
548 0xD6,
549 0x89,
550 0x3B,
551 0xA3,
552 0xF3,
553 0x17,
554 0xAE,
555 0x5B};
556
557 auto toString = [](STObject const& st) {
558 Serializer s;
559 st.add(s);
560
561 return std::string(static_cast<char const*>(s.data()), s.size());
562 };
563
564 for (auto const keyType : keyTypes)
565 {
566 auto const sk = generateSecretKey(keyType, randomSeed());
567 auto const pk = derivePublicKey(keyType, sk);
568
569 for (auto const sKeyType : keyTypes)
570 {
571 auto const ssk = generateSecretKey(sKeyType, randomSeed());
572 auto const spk = derivePublicKey(sKeyType, ssk);
573
574 auto buildManifestObject = [&](std::uint32_t seq,
576 bool noSigningPublic = false,
577 bool noSignature = false) {
579 st[sfSequence] = seq;
580 st[sfPublicKey] = pk;
581
582 if (domain)
583 st[sfDomain] = makeSlice(*domain);
584
585 if (!noSigningPublic)
586 st[sfSigningPubKey] = spk;
587
588 sign(st, HashPrefix::Manifest, keyType, sk, sfMasterSignature);
589
590 if (!noSignature)
591 sign(st, HashPrefix::Manifest, sKeyType, ssk);
592
593 return st;
594 };
595
596 {
597 testcase << "deserializeManifest: normal manifest (" << to_string(keyType)
598 << " + " << to_string(sKeyType) << ")";
599
600 { // valid manifest without domain
601 auto const st = buildManifestObject(++sequence, std::nullopt);
602
603 auto const m = toString(st);
604 auto const manifest = deserializeManifest(m);
605
606 BEAST_EXPECT(manifest);
607 // NOLINTBEGIN(bugprone-unchecked-optional-access)
608 BEAST_EXPECT(manifest->masterKey == pk);
609 BEAST_EXPECT(manifest->signingKey == spk);
610 BEAST_EXPECT(manifest->sequence == sequence);
611 BEAST_EXPECT(manifest->serialized == m);
612 BEAST_EXPECT(manifest->domain.empty());
613 BEAST_EXPECT(manifest->verify());
614 // NOLINTEND(bugprone-unchecked-optional-access)
615 }
616
617 { // invalid manifest (empty domain)
618 auto const st = buildManifestObject(++sequence, std::string{});
619
620 BEAST_EXPECT(!deserializeManifest(toString(st)));
621 }
622
623 { // invalid manifest (domain too short)
624 auto const st = buildManifestObject(++sequence, std::string{"a.b"});
625 BEAST_EXPECT(!deserializeManifest(toString(st)));
626 }
627 { // invalid manifest (domain too long)
628 std::string const s(254, 'a');
629 auto const st = buildManifestObject(++sequence, s + ".example.com");
630 BEAST_EXPECT(!deserializeManifest(toString(st)));
631 }
632 { // invalid manifest (domain component too long)
633 std::string const s(72, 'a');
634 auto const st = buildManifestObject(++sequence, s + ".example.com");
635 BEAST_EXPECT(!deserializeManifest(toString(st)));
636 }
637
638 auto const st = buildManifestObject(++sequence, std::string{"example.com"});
639
640 {
641 // valid manifest with domain
642 auto const m = toString(st);
643 auto const manifest = deserializeManifest(m);
644
645 BEAST_EXPECT(manifest);
646 // NOLINTBEGIN(bugprone-unchecked-optional-access)
647 BEAST_EXPECT(manifest->masterKey == pk);
648 BEAST_EXPECT(manifest->signingKey == spk);
649 BEAST_EXPECT(manifest->sequence == sequence);
650 BEAST_EXPECT(manifest->serialized == m);
651 BEAST_EXPECT(manifest->domain == "example.com");
652 BEAST_EXPECT(manifest->verify());
653 // NOLINTEND(bugprone-unchecked-optional-access)
654 }
655 {
656 // valid manifest with invalid signature
657 auto badSigSt = st;
658 badSigSt[sfSequence] = sequence + 1;
659
660 auto const m = toString(badSigSt);
661 auto const manifest = deserializeManifest(m);
662
663 BEAST_EXPECT(manifest);
664 // NOLINTBEGIN(bugprone-unchecked-optional-access)
665 BEAST_EXPECT(manifest->masterKey == pk);
666 BEAST_EXPECT(manifest->signingKey == spk);
667 BEAST_EXPECT(manifest->sequence == sequence + 1);
668 BEAST_EXPECT(manifest->serialized == m);
669 BEAST_EXPECT(manifest->domain == "example.com");
670 BEAST_EXPECT(!manifest->verify());
671 // NOLINTEND(bugprone-unchecked-optional-access)
672 }
673 {
674 // reject missing sequence
675 auto badSt = st;
676 BEAST_EXPECT(badSt.delField(sfSequence));
677 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
678 }
679 {
680 // reject missing public key
681 auto badSt = st;
682 BEAST_EXPECT(badSt.delField(sfPublicKey));
683 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
684 }
685 {
686 // reject invalid public key type
687 auto badSt = st;
688 badSt[sfPublicKey] = makeSlice(badKey);
689 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
690 }
691 {
692 // reject short public key
693 auto badSt = st;
694 badSt[sfPublicKey] = makeSlice(shortKey);
695 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
696 }
697 {
698 // reject missing signing public key
699 auto badSt = st;
700 BEAST_EXPECT(badSt.delField(sfSigningPubKey));
701 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
702 }
703 {
704 // reject invalid signing public key type
705 auto badSt = st;
706 badSt[sfSigningPubKey] = makeSlice(badKey);
707 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
708 }
709 {
710 // reject short signing public key
711 auto badSt = st;
712 badSt[sfSigningPubKey] = makeSlice(shortKey);
713 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
714 }
715 {
716 // reject missing signature
717 auto badSt = st;
718 BEAST_EXPECT(badSt.delField(sfMasterSignature));
719 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
720 }
721 {
722 // reject missing signing key signature
723 auto badSt = st;
724 BEAST_EXPECT(badSt.delField(sfSignature));
725 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
726 }
727 {
728 // reject matching master & ephemeral keys
730 st[sfSequence] = 314159;
731 st[sfPublicKey] = pk;
732 st[sfSigningPubKey] = pk;
733
734 sign(st, HashPrefix::Manifest, keyType, sk, sfMasterSignature);
735
736 sign(st, HashPrefix::Manifest, sKeyType, sk);
737
738 BEAST_EXPECT(!deserializeManifest(toString(st)));
739 }
740 }
741
742 {
743 testcase << "deserializeManifest: revocation manifest (" << to_string(keyType)
744 << " + " << to_string(sKeyType) << ")";
745
746 // valid revocation
747 {
748 auto const st = buildManifestObject(
749 std::numeric_limits<std::uint32_t>::max(), std::nullopt, true, true);
750
751 auto const m = toString(st);
752 auto const manifest = deserializeManifest(m);
753
754 BEAST_EXPECT(manifest);
755 // NOLINTBEGIN(bugprone-unchecked-optional-access)
756 BEAST_EXPECT(manifest->masterKey == pk);
757
758 // Since this manifest is revoked, it should not have a signingKey
759 BEAST_EXPECT(!manifest->signingKey);
760 BEAST_EXPECT(manifest->revoked());
761 BEAST_EXPECT(manifest->domain.empty());
762 BEAST_EXPECT(manifest->serialized == m);
763 BEAST_EXPECT(manifest->verify());
764 // NOLINTEND(bugprone-unchecked-optional-access)
765 }
766
767 { // can't specify an ephemeral signing key
768 auto const st = buildManifestObject(
769 std::numeric_limits<std::uint32_t>::max(), std::nullopt, true, false);
770
771 BEAST_EXPECT(!deserializeManifest(toString(st)));
772 }
773 { // can't specify an ephemeral signature
774 auto const st = buildManifestObject(
775 std::numeric_limits<std::uint32_t>::max(), std::nullopt, false, true);
776
777 BEAST_EXPECT(!deserializeManifest(toString(st)));
778 }
779 { // can't specify an ephemeral key & signature
780 auto const st = buildManifestObject(
781 std::numeric_limits<std::uint32_t>::max(), std::nullopt, false, false);
782
783 BEAST_EXPECT(!deserializeManifest(toString(st)));
784 }
785 }
786 }
787 }
788 }
789
790 void
792 {
793 testcase("Manifest Domain Names");
794
796 auto const pk1 = derivePublicKey(KeyType::Secp256k1, sk1);
797
799 auto const pk2 = derivePublicKey(KeyType::Secp256k1, sk2);
800
801 auto test = [&](std::string domain) {
803 st[sfSequence] = 7;
804 st[sfPublicKey] = pk1;
805 st[sfDomain] = makeSlice(domain);
806 st[sfSigningPubKey] = pk2;
807
808 sign(st, HashPrefix::Manifest, KeyType::Secp256k1, sk1, sfMasterSignature);
810
811 Serializer s;
812 st.add(s);
813
814 return deserializeManifest(std::string(static_cast<char const*>(s.data()), s.size()));
815 };
816
817 BEAST_EXPECT(test("example.com"));
818 BEAST_EXPECT(test("test.example.com"));
819 BEAST_EXPECT(test("example-domain.com"));
820 BEAST_EXPECT(test("xn--mxavchb.gr"));
821 BEAST_EXPECT(test("test.xn--mxavchb.gr"));
822 BEAST_EXPECT(test("123.gr"));
823 BEAST_EXPECT(test("x.yz"));
824 BEAST_EXPECT(test(std::string(63, 'a') + ".example.com"));
825 BEAST_EXPECT(test(std::string(63, 'a') + "." + std::string(63, 'b')));
826
827 // No period
828 BEAST_EXPECT(!test("example"));
829
830 // Leading period:
831 BEAST_EXPECT(!test(".com"));
832 BEAST_EXPECT(!test(".example.com"));
833
834 // A trailing period is technically valid but we don't allow it
835 BEAST_EXPECT(!test("example.com."));
836
837 // A component can't start or end with a dash
838 BEAST_EXPECT(!test("-example.com"));
839 BEAST_EXPECT(!test("example-.com"));
840
841 // Empty component:
842 BEAST_EXPECT(!test("double..periods.example.com"));
843
844 // TLD too short or too long:
845 BEAST_EXPECT(!test("example.x"));
846 BEAST_EXPECT(!test("example." + std::string(64, 'a')));
847
848 // Invalid characters:
849 BEAST_EXPECT(!test("example.com-org"));
850 BEAST_EXPECT(!test("bang!.com"));
851 BEAST_EXPECT(!test("bang!.example.com"));
852
853 // Too short
854 BEAST_EXPECT(!test("a.b"));
855
856 // Single component too long:
857 BEAST_EXPECT(!test(std::string(64, 'a') + ".com"));
858 BEAST_EXPECT(!test(std::string(64, 'a') + ".example.com"));
859
860 // Multiple components too long:
861 BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
862 BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
863
864 // Overall too long:
865 BEAST_EXPECT(!test(std::string(63, 'a') + "." + std::string(63, 'b') + ".example.com"));
866 }
867
868 void
869 run() override
870 {
871 ManifestCache cache;
872 {
873 testcase("apply");
874
875 auto const skA = randomSecretKey();
876 auto const pkA = derivePublicKey(KeyType::Ed25519, skA);
877 auto const kpA0 = randomKeyPair(KeyType::Secp256k1);
878 auto const kpA1 = randomKeyPair(KeyType::Secp256k1);
879 auto const sA0 =
880 makeManifest(skA, KeyType::Ed25519, kpA0.second, KeyType::Secp256k1, 0);
881 auto const sA1 =
882 makeManifest(skA, KeyType::Ed25519, kpA1.second, KeyType::Secp256k1, 1);
883 auto const sA2 =
884 makeManifest(skA, KeyType::Ed25519, kpA1.second, KeyType::Secp256k1, 2);
885 auto const sAMax = makeRevocation(skA, KeyType::Ed25519);
886
887 auto const skB = randomSecretKey();
888 auto const kpB0 = randomKeyPair(KeyType::Secp256k1);
889 auto const kpB1 = randomKeyPair(KeyType::Secp256k1);
890 auto const kpB2 = randomKeyPair(KeyType::Secp256k1);
891 auto const sB0 =
892 makeManifest(skB, KeyType::Ed25519, kpB0.second, KeyType::Secp256k1, 0);
893 auto const sB1 = makeManifest(
894 skB,
896 kpB1.second,
898 1,
899 true); // invalidSig
900 auto const sB2 = makeManifest(skB, KeyType::Ed25519, kpB2.second, KeyType::Ed25519, 2);
901
902 auto const fake = sB2.serialized + '\0';
903
904 // applyManifest should accept new manifests with
905 // higher sequence numbers
906 auto const seq0 = cache.sequence();
907 BEAST_EXPECT(
910 BEAST_EXPECT(cache.sequence() > seq0);
911
912 auto const seq1 = cache.sequence();
913 BEAST_EXPECT(
916 BEAST_EXPECT(cache.sequence() == seq1);
917
918 BEAST_EXPECT(
921 BEAST_EXPECT(
924 BEAST_EXPECT(
927
928 BEAST_EXPECT(
931
932 // applyManifest should accept manifests with max sequence numbers
933 // that revoke the master public key
934 BEAST_EXPECT(!cache.revoked(pkA));
935 BEAST_EXPECT(sAMax.revoked());
936 BEAST_EXPECT(
939 BEAST_EXPECT(
942 BEAST_EXPECT(
945 BEAST_EXPECT(
948 BEAST_EXPECT(cache.revoked(pkA));
949
950 // applyManifest should reject manifests with invalid signatures
951 BEAST_EXPECT(
954 BEAST_EXPECT(
957 BEAST_EXPECT(!deserializeManifest(fake));
958 BEAST_EXPECT(
961 BEAST_EXPECT(
964
965 auto const sC0 = makeManifest(
967 BEAST_EXPECT(
970 }
971
972 testLoadStore(cache);
974 testGetKeys();
979 }
980};
981
983
984} // namespace xrpl::test
A testsuite class.
Definition suite.h:52
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Remembers manifests with the highest sequence number.
Definition Manifest.h:374
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, ManifestRateLimitCapPolicy cap)
Add manifest to cache.
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:443
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.
A public key.
Definition PublicKey.h:53
void addWithoutSigningFields(Serializer &s) const
Definition STObject.h:994
void add(Serializer &s) const override
Definition STObject.cpp:123
A secret key.
Definition SecretKey.h:24
Slice slice() const noexcept
Definition Serializer.h:45
std::size_t size() const noexcept
Definition Serializer.h:51
void const * data() const noexcept
Definition Serializer.h:57
static Manifest clone(Manifest const &m)
void testLoadStore(ManifestCache &m)
static PublicKey randomMasterKey()
void run() override
Runs the suite.
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
static void cleanupDatabaseDir(std::filesystem::path const &dbPath)
std::string makeRevocationString(SecretKey const &sk, KeyType type, bool invalidSig=false)
Manifest makeManifest(SecretKey const &sk, KeyType type, SecretKey const &ssk, KeyType stype, int seq, bool invalidSig=false)
static PublicKey randomNode()
static std::filesystem::path getDatabasePath()
static void setupDatabaseDir(std::filesystem::path const &dbPath)
Manifest makeRevocation(SecretKey const &sk, KeyType type, bool invalidSig=false)
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
ManualTimeKeeper & timeKeeper()
Definition Env.h:313
beast::Journal const journal
Definition Env.h:204
T create_directory(T... args)
T current_path(T... args)
T equal(T... args)
T exists(T... args)
T is_directory(T... args)
T is_empty(T... args)
T make_unique(T... args)
T max(T... args)
void sign(json::Value &jv, Account const &account, json::Value &sigObject)
Sign automatically into a specific Json field of the jv object.
Definition utility.cpp:40
bool equal(STAmount const &sa1, STAmount const &sa2)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
KeyType
Definition KeyType.h:8
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Seed randomSeed()
Create a seed using secure random numbers.
Definition Seed.cpp:48
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:13
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
SField const sfGeneric
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
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.
@ Capped
Subject to the untrusted cap (unlisted peer gossip).
Definition Manifest.h:364
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
std::string base64Encode(std::uint8_t const *data, std::size_t len)
@ Manifest
Manifest.
Definition HashPrefix.h:84
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname, beast::Journal j)
makeTestWalletDB Opens a test wallet database with an arbitrary name.
Definition Wallet.cpp:50
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
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.
Definition Manifest.h:325
@ Accepted
Manifest is valid.
Definition Manifest.h:321
@ Invalid
Timely, but invalid signature.
Definition Manifest.h:329
@ BadEphemeralKey
The ephemeral key is not acceptable to us.
Definition Manifest.h:327
@ Stale
Sequence is too old.
Definition Manifest.h:323
T push_back(T... args)
T remove(T... args)
T reserve(T... args)
T size(T... args)
T sort(T... args)
std::filesystem::path dataDir
Definition DatabaseCon.h:82
PublicKey masterKey
The master key associated with this manifest.
Definition Manifest.h:84
std::string serialized
The manifest in serialized form.
Definition Manifest.h:79
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
Definition Manifest.h:102
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
Definition Manifest.h:92
std::uint32_t sequence
The sequence number of this manifest.
Definition Manifest.h:97
static constexpr auto kDatabasePath
Definition Constants.h:13