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