rippled
Loading...
Searching...
No Matches
Manifest_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/main/DBInit.h>
4#include <xrpld/app/misc/Manifest.h>
5#include <xrpld/app/misc/ValidatorList.h>
6#include <xrpld/app/rdb/Wallet.h>
7
8#include <xrpl/basics/base64.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/protocol/STExchange.h>
11#include <xrpl/protocol/SecretKey.h>
12#include <xrpl/protocol/Sign.h>
13
14#include <boost/algorithm/string.hpp>
15#include <boost/filesystem.hpp>
16#include <boost/utility/in_place_factory.hpp>
17
18namespace ripple {
19namespace test {
20
22{
23private:
24 static PublicKey
29
30 static PublicKey
35
36 static void
37 cleanupDatabaseDir(boost::filesystem::path const& dbPath)
38 {
39 using namespace boost::filesystem;
40 if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
41 return;
42 remove(dbPath);
43 }
44
45 static void
46 setupDatabaseDir(boost::filesystem::path const& dbPath)
47 {
48 using namespace boost::filesystem;
49 if (!exists(dbPath))
50 {
51 create_directory(dbPath);
52 return;
53 }
54
55 if (!is_directory(dbPath))
56 {
57 // someone created a file where we want to put our directory
58 Throw<std::runtime_error>(
59 "Cannot create directory: " + dbPath.string());
60 }
61 }
62 static boost::filesystem::path
64 {
65 return boost::filesystem::current_path() / "manifest_test_databases";
66 }
67
68public:
70 {
71 try
72 {
74 }
75 catch (std::exception const&)
76 {
77 }
78 }
80 {
81 try
82 {
84 }
85 catch (std::exception const&)
86 {
87 }
88 }
89
92 PublicKey const& pk,
93 SecretKey const& sk,
94 PublicKey const& spk,
95 SecretKey const& ssk,
96 int seq)
97 {
99 st[sfSequence] = seq;
100 st[sfPublicKey] = pk;
101 st[sfSigningPubKey] = spk;
102
103 sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
104 sign(
105 st,
107 *publicKeyType(pk),
108 sk,
109 sfMasterSignature);
110
111 Serializer s;
112 st.add(s);
113
114 return base64_encode(
115 std::string(static_cast<char const*>(s.data()), s.size()));
116 }
117
120 SecretKey const& sk,
121 KeyType type,
122 bool invalidSig = false)
123 {
124 auto const pk = derivePublicKey(type, sk);
125
128 st[sfPublicKey] = pk;
129
130 sign(
131 st,
133 type,
134 invalidSig ? randomSecretKey() : sk,
135 sfMasterSignature);
136 BEAST_EXPECT(
137 invalidSig ^
138 verify(st, HashPrefix::manifest, pk, sfMasterSignature));
139
140 Serializer s;
141 st.add(s);
142
143 return base64_encode(
144 std::string(static_cast<char const*>(s.data()), s.size()));
145 }
146
148 makeRevocation(SecretKey const& sk, KeyType type, bool invalidSig = false)
149 {
150 auto const pk = derivePublicKey(type, sk);
151
154 st[sfPublicKey] = pk;
155
156 sign(
157 st,
159 type,
160 invalidSig ? randomSecretKey() : sk,
161 sfMasterSignature);
162 BEAST_EXPECT(
163 invalidSig ^
164 verify(st, HashPrefix::manifest, pk, sfMasterSignature));
165
166 Serializer s;
167 st.add(s);
168
169 // m is non-const so it can be moved from
170 std::string m(static_cast<char const*>(s.data()), s.size());
171 if (auto r = deserializeManifest(std::move(m)))
172 return std::move(*r);
173 Throw<std::runtime_error>("Could not create a revocation manifest");
174 return *deserializeManifest(
175 std::string{}); // Silence compiler warning.
176 }
177
180 SecretKey const& sk,
181 KeyType type,
182 SecretKey const& ssk,
183 KeyType stype,
184 int seq,
185 bool invalidSig = false)
186 {
187 auto const pk = derivePublicKey(type, sk);
188 auto const spk = derivePublicKey(stype, ssk);
189
191 st[sfSequence] = seq;
192 st[sfPublicKey] = pk;
193 st[sfSigningPubKey] = spk;
194
195 sign(st, HashPrefix::manifest, stype, ssk);
196 BEAST_EXPECT(verify(st, HashPrefix::manifest, spk));
197
198 sign(
199 st,
201 type,
202 invalidSig ? randomSecretKey() : sk,
203 sfMasterSignature);
204 BEAST_EXPECT(
205 invalidSig ^
206 verify(st, HashPrefix::manifest, pk, sfMasterSignature));
207
208 Serializer s;
209 st.add(s);
210
211 std::string m(
212 static_cast<char const*>(s.data()),
213 s.size()); // non-const so can be moved
214 if (auto r = deserializeManifest(std::move(m)))
215 return std::move(*r);
216 Throw<std::runtime_error>("Could not create a manifest");
217 return *deserializeManifest(
218 std::string{}); // Silence compiler warning.
219 }
220
222 clone(Manifest const& m)
223 {
224 Manifest m2(
226 return m2;
227 }
228
229 void
231 {
232 testcase("load/store");
233
234 std::string const dbName("ManifestCacheTestDB");
235 {
236 jtx::Env env(*this);
237 DatabaseCon::Setup setup;
238 setup.dataDir = getDatabasePath();
239 assert(!setup.useGlobalPragma);
240
241 auto dbCon = makeTestWalletDB(setup, dbName, env.journal);
242
243 auto getPopulatedManifests =
244 [](ManifestCache const& cache) -> std::vector<Manifest const*> {
246 result.reserve(32);
247 cache.for_each_manifest(
248 [&result](Manifest const& man) { result.push_back(&man); });
249 return result;
250 };
251 auto sort = [](std::vector<Manifest const*> mv)
253 std::sort(
254 mv.begin(),
255 mv.end(),
256 [](Manifest const* lhs, Manifest const* rhs) {
257 return lhs->serialized < rhs->serialized;
258 });
259 return mv;
260 };
261 std::vector<Manifest const*> const inManifests(
262 sort(getPopulatedManifests(m)));
263
264 auto& app = env.app();
266 m,
267 m,
268 env.timeKeeper(),
269 app.config().legacy("database_path"),
270 env.journal);
271
272 {
273 // save should not store untrusted master keys to db
274 // except for revocations
275 m.save(
276 *dbCon,
277 "ValidatorManifests",
278 [&unl](PublicKey const& pubKey) {
279 return unl->listed(pubKey);
280 });
281
282 ManifestCache loaded;
283
284 loaded.load(*dbCon, "ValidatorManifests");
285
286 // check that all loaded manifests are revocations
287 std::vector<Manifest const*> const loadedManifests(
288 sort(getPopulatedManifests(loaded)));
289
290 for (auto const& man : loadedManifests)
291 BEAST_EXPECT(man->revoked());
292 }
293 {
294 // save should store all trusted master keys to db
297 std::string cfgManifest;
298 for (auto const& man : inManifests)
299 s1.push_back(
300 toBase58(TokenType::NodePublic, man->masterKey));
301 unl->load({}, s1, keys);
302
303 m.save(
304 *dbCon,
305 "ValidatorManifests",
306 [&unl](PublicKey const& pubKey) {
307 return unl->listed(pubKey);
308 });
309 ManifestCache loaded;
310 loaded.load(*dbCon, "ValidatorManifests");
311
312 // check that the manifest caches are the same
313 std::vector<Manifest const*> const loadedManifests(
314 sort(getPopulatedManifests(loaded)));
315
316 if (inManifests.size() == loadedManifests.size())
317 {
318 BEAST_EXPECT(std::equal(
319 inManifests.begin(),
320 inManifests.end(),
321 loadedManifests.begin(),
322 [](Manifest const* lhs, Manifest const* rhs) {
323 return *lhs == *rhs;
324 }));
325 }
326 else
327 {
328 fail();
329 }
330 }
331 {
332 // load config manifest
333 ManifestCache loaded;
334 std::vector<std::string> const emptyRevocation;
335
336 std::string const badManifest = "bad manifest";
337 BEAST_EXPECT(!loaded.load(
338 *dbCon,
339 "ValidatorManifests",
340 badManifest,
341 emptyRevocation));
342
343 auto const sk = randomSecretKey();
344 auto const pk = derivePublicKey(KeyType::ed25519, sk);
345 auto const kp = randomKeyPair(KeyType::secp256k1);
346
347 std::string const cfgManifest =
348 makeManifestString(pk, sk, kp.first, kp.second, 0);
349
350 BEAST_EXPECT(loaded.load(
351 *dbCon,
352 "ValidatorManifests",
353 cfgManifest,
354 emptyRevocation));
355 }
356 {
357 // load config revocation
358 ManifestCache loaded;
359 std::string const emptyManifest;
360
361 std::vector<std::string> const badRevocation = {
362 "bad revocation"};
363 BEAST_EXPECT(!loaded.load(
364 *dbCon,
365 "ValidatorManifests",
366 emptyManifest,
367 badRevocation));
368
369 auto const sk = randomSecretKey();
370 auto const keyType = KeyType::ed25519;
371 auto const pk = derivePublicKey(keyType, sk);
372 auto const kp = randomKeyPair(KeyType::secp256k1);
373 std::vector<std::string> const nonRevocation = {
374 makeManifestString(pk, sk, kp.first, kp.second, 0)};
375
376 BEAST_EXPECT(!loaded.load(
377 *dbCon,
378 "ValidatorManifests",
379 emptyManifest,
380 nonRevocation));
381 BEAST_EXPECT(!loaded.revoked(pk));
382
383 std::vector<std::string> const badSigRevocation = {
384 makeRevocationString(sk, keyType, true)};
385 BEAST_EXPECT(!loaded.load(
386 *dbCon,
387 "ValidatorManifests",
388 emptyManifest,
389 badSigRevocation));
390 BEAST_EXPECT(!loaded.revoked(pk));
391
392 std::vector<std::string> const cfgRevocation = {
393 makeRevocationString(sk, keyType)};
394 BEAST_EXPECT(loaded.load(
395 *dbCon,
396 "ValidatorManifests",
397 emptyManifest,
398 cfgRevocation));
399
400 BEAST_EXPECT(loaded.revoked(pk));
401 }
402 }
403 boost::filesystem::remove(
404 getDatabasePath() / boost::filesystem::path(dbName));
405 }
406
407 void
409 {
410 testcase("getSignature");
411 auto const sk = randomSecretKey();
412 auto const pk = derivePublicKey(KeyType::ed25519, sk);
413 auto const kp = randomKeyPair(KeyType::secp256k1);
414 auto const m = makeManifest(
415 sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
416
418 st[sfSequence] = 0;
419 st[sfPublicKey] = pk;
420 st[sfSigningPubKey] = kp.first;
421 Serializer ss;
424 auto const sig = sign(KeyType::secp256k1, kp.second, ss.slice());
425 BEAST_EXPECT(strHex(sig) == strHex(*m.getSignature()));
426
427 auto const masterSig = sign(KeyType::ed25519, sk, ss.slice());
428 BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
429 }
430
431 void
433 {
434 testcase("getKeys");
435
436 ManifestCache cache;
437 auto const sk = randomSecretKey();
438 auto const pk = derivePublicKey(KeyType::ed25519, sk);
439
440 // getSigningKey should return same key if there is no manifest
441 BEAST_EXPECT(cache.getSigningKey(pk) == pk);
442
443 // getSigningKey should return the ephemeral public key
444 // for the listed validator master public key
445 // getMasterKey should return the listed validator master key
446 // for that ephemeral public key
447 auto const kp0 = randomKeyPair(KeyType::secp256k1);
448 BEAST_EXPECT(
451 sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0)));
452 BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first);
453 BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk);
454
455 // getSigningKey should return the latest ephemeral public key
456 // for the listed validator master public key
457 // getMasterKey should only return a master key for the latest
458 // ephemeral public key
459 auto const kp1 = randomKeyPair(KeyType::secp256k1);
460 BEAST_EXPECT(
463 sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1)));
464 BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
465 BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
466 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
467
468 // getSigningKey and getMasterKey should fail if a new manifest is
469 // applied with the same signing key but a higher sequence
470 BEAST_EXPECT(
473 sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2)));
474 BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
475 BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
476 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
477
478 // getSigningKey should return std::nullopt for a revoked master public
479 // key getMasterKey should return std::nullopt for an ephemeral public
480 // key from a revoked master public key
481 BEAST_EXPECT(
484 BEAST_EXPECT(cache.revoked(pk));
485 BEAST_EXPECT(cache.getSigningKey(pk) == pk);
486 BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
487 BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
488 }
489
490 void
492 {
493 testcase("validator token");
494
495 {
496 auto const valSecret = parseBase58<SecretKey>(
498 "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
499
500 // Format token string to test trim()
501 std::vector<std::string> const tokenBlob = {
502 " "
503 "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3ND"
504 "diNT\n",
505 " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2Iiwib"
506 "WFuaWZl \n",
507 "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncx"
508 "L3ZDeE\n",
509 "\t "
510 "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4"
511 "U0tG\t \t\n",
512 "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUz"
513 "ZQU2\n",
514 "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZ"
515 "eXd1\n",
516 "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZW"
517 "RGdj\n",
518 "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0i"
519 "fQ==\n"};
520
521 auto const manifest =
522 "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
523 "vCxHXXLplc2GnMhAkE1agqXxBwD"
524 "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
525 "sAOkVB"
526 "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
527 "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
528 "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
529 "r7C0kw"
530 "2AiTzSCjIzditQ8=";
531
532 auto const token = loadValidatorToken(tokenBlob);
533 BEAST_EXPECT(token);
534 BEAST_EXPECT(token->validationSecret == *valSecret);
535 BEAST_EXPECT(token->manifest == manifest);
536 }
537 {
538 std::vector<std::string> const badToken = {"bad token"};
539 BEAST_EXPECT(!loadValidatorToken(badToken));
540 }
541 }
542
543 void
545 {
546 testcase("Versioning");
547
549 auto const pk = derivePublicKey(KeyType::ed25519, sk);
550
552 auto const spk = derivePublicKey(KeyType::secp256k1, ssk);
553
554 auto buildManifestObject = [&](std::uint16_t version) {
556 st[sfSequence] = 3;
557 st[sfPublicKey] = pk;
558 st[sfSigningPubKey] = spk;
559
560 if (version != 0)
561 st[sfVersion] = version;
562
563 sign(
564 st,
567 sk,
568 sfMasterSignature);
570
571 Serializer s;
572 st.add(s);
573
574 return std::string(static_cast<char const*>(s.data()), s.size());
575 };
576
577 // We understand version 0 manifests:
578 BEAST_EXPECT(deserializeManifest(buildManifestObject(0)));
579
580 // We don't understand any other versions:
581 BEAST_EXPECT(!deserializeManifest(buildManifestObject(1)));
582 BEAST_EXPECT(!deserializeManifest(buildManifestObject(2001)));
583 }
584
585 void
587 {
588 std::array<KeyType, 2> const keyTypes{
590
591 std::uint32_t sequence = 0;
592
593 // public key with invalid type
594 std::array<std::uint8_t, 33> const badKey{
595 0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
596 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
597 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
598
599 // Short public key:
600 std::array<std::uint8_t, 16> const shortKey{
601 0x03,
602 0x30,
603 0xE7,
604 0xFC,
605 0x9D,
606 0x56,
607 0xBB,
608 0x25,
609 0xD6,
610 0x89,
611 0x3B,
612 0xA3,
613 0xF3,
614 0x17,
615 0xAE,
616 0x5B};
617
618 auto toString = [](STObject const& st) {
619 Serializer s;
620 st.add(s);
621
622 return std::string(static_cast<char const*>(s.data()), s.size());
623 };
624
625 for (auto const keyType : keyTypes)
626 {
627 auto const sk = generateSecretKey(keyType, randomSeed());
628 auto const pk = derivePublicKey(keyType, sk);
629
630 for (auto const sKeyType : keyTypes)
631 {
632 auto const ssk = generateSecretKey(sKeyType, randomSeed());
633 auto const spk = derivePublicKey(sKeyType, ssk);
634
635 auto buildManifestObject =
636 [&](std::uint32_t seq,
638 bool noSigningPublic = false,
639 bool noSignature = false) {
641 st[sfSequence] = seq;
642 st[sfPublicKey] = pk;
643
644 if (domain)
645 st[sfDomain] = makeSlice(*domain);
646
647 if (!noSigningPublic)
648 st[sfSigningPubKey] = spk;
649
650 sign(
651 st,
653 keyType,
654 sk,
655 sfMasterSignature);
656
657 if (!noSignature)
658 sign(st, HashPrefix::manifest, sKeyType, ssk);
659
660 return st;
661 };
662
663 {
664 testcase << "deserializeManifest: normal manifest ("
665 << to_string(keyType) << " + "
666 << to_string(sKeyType) << ")";
667
668 { // valid manifest without domain
669 auto const st =
670 buildManifestObject(++sequence, std::nullopt);
671
672 auto const m = toString(st);
673 auto const manifest = deserializeManifest(m);
674
675 BEAST_EXPECT(manifest);
676 BEAST_EXPECT(manifest->masterKey == pk);
677 BEAST_EXPECT(manifest->signingKey == spk);
678 BEAST_EXPECT(manifest->sequence == sequence);
679 BEAST_EXPECT(manifest->serialized == m);
680 BEAST_EXPECT(manifest->domain.empty());
681 BEAST_EXPECT(manifest->verify());
682 }
683
684 { // invalid manifest (empty domain)
685 auto const st =
686 buildManifestObject(++sequence, std::string{});
687
688 BEAST_EXPECT(!deserializeManifest(toString(st)));
689 }
690
691 { // invalid manifest (domain too short)
692 auto const st =
693 buildManifestObject(++sequence, std::string{"a.b"});
694 BEAST_EXPECT(!deserializeManifest(toString(st)));
695 }
696 { // invalid manifest (domain too long)
697 std::string s(254, 'a');
698 auto const st =
699 buildManifestObject(++sequence, s + ".example.com");
700 BEAST_EXPECT(!deserializeManifest(toString(st)));
701 }
702 { // invalid manifest (domain component too long)
703 std::string s(72, 'a');
704 auto const st =
705 buildManifestObject(++sequence, s + ".example.com");
706 BEAST_EXPECT(!deserializeManifest(toString(st)));
707 }
708
709 auto const st = buildManifestObject(
710 ++sequence, std::string{"example.com"});
711
712 {
713 // valid manifest with domain
714 auto const m = toString(st);
715 auto const manifest = deserializeManifest(m);
716
717 BEAST_EXPECT(manifest);
718 BEAST_EXPECT(manifest->masterKey == pk);
719 BEAST_EXPECT(manifest->signingKey == spk);
720 BEAST_EXPECT(manifest->sequence == sequence);
721 BEAST_EXPECT(manifest->serialized == m);
722 BEAST_EXPECT(manifest->domain == "example.com");
723 BEAST_EXPECT(manifest->verify());
724 }
725 {
726 // valid manifest with invalid signature
727 auto badSigSt = st;
728 badSigSt[sfSequence] = sequence + 1;
729
730 auto const m = toString(badSigSt);
731 auto const manifest = deserializeManifest(m);
732
733 BEAST_EXPECT(manifest);
734 BEAST_EXPECT(manifest->masterKey == pk);
735 BEAST_EXPECT(manifest->signingKey == spk);
736 BEAST_EXPECT(manifest->sequence == sequence + 1);
737 BEAST_EXPECT(manifest->serialized == m);
738 BEAST_EXPECT(manifest->domain == "example.com");
739 BEAST_EXPECT(!manifest->verify());
740 }
741 {
742 // reject missing sequence
743 auto badSt = st;
744 BEAST_EXPECT(badSt.delField(sfSequence));
745 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
746 }
747 {
748 // reject missing public key
749 auto badSt = st;
750 BEAST_EXPECT(badSt.delField(sfPublicKey));
751 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
752 }
753 {
754 // reject invalid public key type
755 auto badSt = st;
756 badSt[sfPublicKey] = makeSlice(badKey);
757 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
758 }
759 {
760 // reject short public key
761 auto badSt = st;
762 badSt[sfPublicKey] = makeSlice(shortKey);
763 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
764 }
765 {
766 // reject missing signing public key
767 auto badSt = st;
768 BEAST_EXPECT(badSt.delField(sfSigningPubKey));
769 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
770 }
771 {
772 // reject invalid signing public key type
773 auto badSt = st;
774 badSt[sfSigningPubKey] = makeSlice(badKey);
775 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
776 }
777 {
778 // reject short signing public key
779 auto badSt = st;
780 badSt[sfSigningPubKey] = makeSlice(shortKey);
781 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
782 }
783 {
784 // reject missing signature
785 auto badSt = st;
786 BEAST_EXPECT(badSt.delField(sfMasterSignature));
787 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
788 }
789 {
790 // reject missing signing key signature
791 auto badSt = st;
792 BEAST_EXPECT(badSt.delField(sfSignature));
793 BEAST_EXPECT(!deserializeManifest(toString(badSt)));
794 }
795 {
796 // reject matching master & ephemeral keys
798 st[sfSequence] = 314159;
799 st[sfPublicKey] = pk;
800 st[sfSigningPubKey] = pk;
801
802 sign(
803 st,
805 keyType,
806 sk,
807 sfMasterSignature);
808
809 sign(st, HashPrefix::manifest, sKeyType, sk);
810
811 BEAST_EXPECT(!deserializeManifest(toString(st)));
812 }
813 }
814
815 {
816 testcase << "deserializeManifest: revocation manifest ("
817 << to_string(keyType) << " + "
818 << to_string(sKeyType) << ")";
819
820 // valid revocation
821 {
822 auto const st = buildManifestObject(
825 true,
826 true);
827
828 auto const m = toString(st);
829 auto const manifest = deserializeManifest(m);
830
831 BEAST_EXPECT(manifest);
832 BEAST_EXPECT(manifest->masterKey == pk);
833
834 // Since this manifest is revoked, it should not have
835 // a signingKey
836 BEAST_EXPECT(!manifest->signingKey);
837 BEAST_EXPECT(manifest->revoked());
838 BEAST_EXPECT(manifest->domain.empty());
839 BEAST_EXPECT(manifest->serialized == m);
840 BEAST_EXPECT(manifest->verify());
841 }
842
843 { // can't specify an ephemeral signing key
844 auto const st = buildManifestObject(
847 true,
848 false);
849
850 BEAST_EXPECT(!deserializeManifest(toString(st)));
851 }
852 { // can't specify an ephemeral signature
853 auto const st = buildManifestObject(
856 false,
857 true);
858
859 BEAST_EXPECT(!deserializeManifest(toString(st)));
860 }
861 { // can't specify an ephemeral key & signature
862 auto const st = buildManifestObject(
865 false,
866 false);
867
868 BEAST_EXPECT(!deserializeManifest(toString(st)));
869 }
870 }
871 }
872 }
873 }
874
875 void
877 {
878 testcase("Manifest Domain Names");
879
881 auto const pk1 = derivePublicKey(KeyType::secp256k1, sk1);
882
884 auto const pk2 = derivePublicKey(KeyType::secp256k1, sk2);
885
886 auto test = [&](std::string domain) {
888 st[sfSequence] = 7;
889 st[sfPublicKey] = pk1;
890 st[sfDomain] = makeSlice(domain);
891 st[sfSigningPubKey] = pk2;
892
893 sign(
894 st,
897 sk1,
898 sfMasterSignature);
900
901 Serializer s;
902 st.add(s);
903
904 return deserializeManifest(
905 std::string(static_cast<char const*>(s.data()), s.size()));
906 };
907
908 BEAST_EXPECT(test("example.com"));
909 BEAST_EXPECT(test("test.example.com"));
910 BEAST_EXPECT(test("example-domain.com"));
911 BEAST_EXPECT(test("xn--mxavchb.gr"));
912 BEAST_EXPECT(test("test.xn--mxavchb.gr"));
913 BEAST_EXPECT(test("123.gr"));
914 BEAST_EXPECT(test("x.yz"));
915 BEAST_EXPECT(test(std::string(63, 'a') + ".example.com"));
916 BEAST_EXPECT(test(std::string(63, 'a') + "." + std::string(63, 'b')));
917
918 // No period
919 BEAST_EXPECT(!test("example"));
920
921 // Leading period:
922 BEAST_EXPECT(!test(".com"));
923 BEAST_EXPECT(!test(".example.com"));
924
925 // A trailing period is technically valid but we don't allow it
926 BEAST_EXPECT(!test("example.com."));
927
928 // A component can't start or end with a dash
929 BEAST_EXPECT(!test("-example.com"));
930 BEAST_EXPECT(!test("example-.com"));
931
932 // Empty component:
933 BEAST_EXPECT(!test("double..periods.example.com"));
934
935 // TLD too short or too long:
936 BEAST_EXPECT(!test("example.x"));
937 BEAST_EXPECT(!test("example." + std::string(64, 'a')));
938
939 // Invalid characters:
940 BEAST_EXPECT(!test("example.com-org"));
941 BEAST_EXPECT(!test("bang!.com"));
942 BEAST_EXPECT(!test("bang!.example.com"));
943
944 // Too short
945 BEAST_EXPECT(!test("a.b"));
946
947 // Single component too long:
948 BEAST_EXPECT(!test(std::string(64, 'a') + ".com"));
949 BEAST_EXPECT(!test(std::string(64, 'a') + ".example.com"));
950
951 // Multiple components too long:
952 BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
953 BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
954
955 // Overall too long:
956 BEAST_EXPECT(!test(
957 std::string(63, 'a') + "." + std::string(63, 'b') +
958 ".example.com"));
959 }
960
961 void
962 run() override
963 {
964 ManifestCache cache;
965 {
966 testcase("apply");
967
968 auto const sk_a = randomSecretKey();
969 auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a);
970 auto const kp_a0 = randomKeyPair(KeyType::secp256k1);
971 auto const kp_a1 = randomKeyPair(KeyType::secp256k1);
972 auto const s_a0 = makeManifest(
973 sk_a, KeyType::ed25519, kp_a0.second, KeyType::secp256k1, 0);
974 auto const s_a1 = makeManifest(
975 sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 1);
976 auto const s_a2 = makeManifest(
977 sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 2);
978 auto const s_aMax = makeRevocation(sk_a, KeyType::ed25519);
979
980 auto const sk_b = randomSecretKey();
981 auto const kp_b0 = randomKeyPair(KeyType::secp256k1);
982 auto const kp_b1 = randomKeyPair(KeyType::secp256k1);
983 auto const kp_b2 = randomKeyPair(KeyType::secp256k1);
984 auto const s_b0 = makeManifest(
985 sk_b, KeyType::ed25519, kp_b0.second, KeyType::secp256k1, 0);
986 auto const s_b1 = makeManifest(
987 sk_b,
989 kp_b1.second,
991 1,
992 true); // invalidSig
993 auto const s_b2 = makeManifest(
994 sk_b, KeyType::ed25519, kp_b2.second, KeyType::ed25519, 2);
995
996 auto const fake = s_b2.serialized + '\0';
997
998 // applyManifest should accept new manifests with
999 // higher sequence numbers
1000 BEAST_EXPECT(
1001 cache.applyManifest(clone(s_a0)) ==
1003 BEAST_EXPECT(
1005
1006 BEAST_EXPECT(
1007 cache.applyManifest(clone(s_a1)) ==
1009 BEAST_EXPECT(
1011 BEAST_EXPECT(
1013
1014 BEAST_EXPECT(
1015 cache.applyManifest(clone(s_a2)) ==
1017
1018 // applyManifest should accept manifests with max sequence numbers
1019 // that revoke the master public key
1020 BEAST_EXPECT(!cache.revoked(pk_a));
1021 BEAST_EXPECT(s_aMax.revoked());
1022 BEAST_EXPECT(
1023 cache.applyManifest(clone(s_aMax)) ==
1025 BEAST_EXPECT(
1026 cache.applyManifest(clone(s_aMax)) ==
1028 BEAST_EXPECT(
1030 BEAST_EXPECT(
1032 BEAST_EXPECT(cache.revoked(pk_a));
1033
1034 // applyManifest should reject manifests with invalid signatures
1035 BEAST_EXPECT(
1036 cache.applyManifest(clone(s_b0)) ==
1038 BEAST_EXPECT(
1040 BEAST_EXPECT(!deserializeManifest(fake));
1041 BEAST_EXPECT(
1042 cache.applyManifest(clone(s_b1)) ==
1044 BEAST_EXPECT(
1045 cache.applyManifest(clone(s_b2)) ==
1047
1048 auto const s_c0 = makeManifest(
1049 kp_b2.second,
1053 47);
1054 BEAST_EXPECT(
1055 cache.applyManifest(clone(s_c0)) ==
1057 }
1058
1059 testLoadStore(cache);
1061 testGetKeys();
1066 }
1067};
1068
1069BEAST_DEFINE_TESTSUITE(Manifest, app, ripple);
1070
1071} // namespace test
1072} // namespace ripple
T begin(T... args)
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:530
Remembers manifests with the highest sequence number.
Definition Manifest.h:237
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition Manifest.cpp:292
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition Manifest.cpp:352
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition Manifest.cpp:364
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.
Definition Manifest.cpp:532
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
Definition Manifest.cpp:589
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition Manifest.cpp:304
A public key.
Definition PublicKey.h:43
void add(Serializer &s) const override
Definition STObject.cpp:122
void addWithoutSigningFields(Serializer &s) const
Definition STObject.h:944
A secret key.
Definition SecretKey.h:19
std::size_t size() const noexcept
Definition Serializer.h:53
void const * data() const noexcept
Definition Serializer.h:59
Slice slice() const noexcept
Definition Serializer.h:47
static PublicKey randomNode()
std::string makeRevocationString(SecretKey const &sk, KeyType type, bool invalidSig=false)
void run() override
Runs the suite.
Manifest makeManifest(SecretKey const &sk, KeyType type, SecretKey const &ssk, KeyType stype, int seq, bool invalidSig=false)
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
static PublicKey randomMasterKey()
static boost::filesystem::path getDatabasePath()
static void cleanupDatabaseDir(boost::filesystem::path const &dbPath)
Manifest makeRevocation(SecretKey const &sk, KeyType type, bool invalidSig=false)
std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Manifest clone(Manifest const &m)
void testLoadStore(ManifestCache &m)
A transaction testing environment.
Definition Env.h:102
Application & app()
Definition Env.h:242
beast::Journal const journal
Definition Env.h:143
ManualTimeKeeper & timeKeeper()
Definition Env.h:254
Set the domain on a JTx.
Definition domain.h:11
Set the regular signature on a JTx.
Definition sig.h:16
T end(T... args)
T equal(T... args)
T is_same_v
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:28
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition Manifest.cpp:35
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical=true) noexcept
Verify a signature on a message.
Seed randomSeed()
Create a seed using secure random numbers.
Definition Seed.cpp:47
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:16
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
@ 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.
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:225
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
KeyType
Definition KeyType.h:9
std::string base64_encode(std::uint8_t const *data, std::size_t len)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal)
Definition Manifest.cpp:245
SField const sfGeneric
@ manifest
Manifest.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T sort(T... args)
boost::filesystem::path dataDir
Definition DatabaseCon.h:75
std::string serialized
The manifest in serialized form.
Definition Manifest.h:64
std::uint32_t sequence
The sequence number of this manifest.
Definition Manifest.h:76
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
Definition Manifest.h:79
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
Definition Manifest.h:73
PublicKey masterKey
The master key associated with this manifest.
Definition Manifest.h:67
Set the sequence number on a JTx.
Definition seq.h:15