rippled
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 <ripple/app/main/DBInit.h>
21 #include <ripple/app/misc/Manifest.h>
22 #include <ripple/app/misc/ValidatorList.h>
23 #include <ripple/app/rdb/Wallet.h>
24 #include <ripple/basics/StringUtilities.h>
25 #include <ripple/basics/base64.h>
26 #include <ripple/basics/contract.h>
27 #include <ripple/protocol/STExchange.h>
28 #include <ripple/protocol/SecretKey.h>
29 #include <ripple/protocol/Sign.h>
30 #include <boost/algorithm/string.hpp>
31 #include <boost/filesystem.hpp>
32 #include <boost/utility/in_place_factory.hpp>
33 #include <test/jtx.h>
34 
35 namespace ripple {
36 namespace test {
37 
38 class Manifest_test : public beast::unit_test::suite
39 {
40 private:
41  static PublicKey
43  {
45  }
46 
47  static PublicKey
49  {
51  }
52 
53  static void
54  cleanupDatabaseDir(boost::filesystem::path const& dbPath)
55  {
56  using namespace boost::filesystem;
57  if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
58  return;
59  remove(dbPath);
60  }
61 
62  static void
63  setupDatabaseDir(boost::filesystem::path const& dbPath)
64  {
65  using namespace boost::filesystem;
66  if (!exists(dbPath))
67  {
68  create_directory(dbPath);
69  return;
70  }
71 
72  if (!is_directory(dbPath))
73  {
74  // someone created a file where we want to put our directory
75  Throw<std::runtime_error>(
76  "Cannot create directory: " + dbPath.string());
77  }
78  }
79  static boost::filesystem::path
81  {
82  return boost::filesystem::current_path() / "manifest_test_databases";
83  }
84 
85 public:
87  {
88  try
89  {
91  }
92  catch (std::exception const&)
93  {
94  }
95  }
97  {
98  try
99  {
101  }
102  catch (std::exception const&)
103  {
104  }
105  }
106 
109  PublicKey const& pk,
110  SecretKey const& sk,
111  PublicKey const& spk,
112  SecretKey const& ssk,
113  int seq)
114  {
115  STObject st(sfGeneric);
116  st[sfSequence] = seq;
117  st[sfPublicKey] = pk;
118  st[sfSigningPubKey] = spk;
119 
120  sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
121  sign(
122  st,
124  *publicKeyType(pk),
125  sk,
127 
128  Serializer s;
129  st.add(s);
130 
131  return base64_encode(
132  std::string(static_cast<char const*>(s.data()), s.size()));
133  }
134 
137  SecretKey const& sk,
138  KeyType type,
139  bool invalidSig = false)
140  {
141  auto const pk = derivePublicKey(type, sk);
142 
143  STObject st(sfGeneric);
145  st[sfPublicKey] = pk;
146 
147  sign(
148  st,
150  type,
151  invalidSig ? randomSecretKey() : sk,
153  BEAST_EXPECT(
154  invalidSig ^
156 
157  Serializer s;
158  st.add(s);
159 
160  return base64_encode(
161  std::string(static_cast<char const*>(s.data()), s.size()));
162  }
163 
164  Manifest
165  makeRevocation(SecretKey const& sk, KeyType type, bool invalidSig = false)
166  {
167  auto const pk = derivePublicKey(type, sk);
168 
169  STObject st(sfGeneric);
171  st[sfPublicKey] = pk;
172 
173  sign(
174  st,
176  type,
177  invalidSig ? randomSecretKey() : sk,
179  BEAST_EXPECT(
180  invalidSig ^
182 
183  Serializer s;
184  st.add(s);
185 
186  // m is non-const so it can be moved from
187  std::string m(static_cast<char const*>(s.data()), s.size());
188  if (auto r = deserializeManifest(std::move(m)))
189  return std::move(*r);
190  Throw<std::runtime_error>("Could not create a revocation manifest");
191  return *deserializeManifest(
192  std::string{}); // Silence compiler warning.
193  }
194 
195  Manifest
197  SecretKey const& sk,
198  KeyType type,
199  SecretKey const& ssk,
200  KeyType stype,
201  int seq,
202  bool invalidSig = false)
203  {
204  auto const pk = derivePublicKey(type, sk);
205  auto const spk = derivePublicKey(stype, ssk);
206 
207  STObject st(sfGeneric);
208  st[sfSequence] = seq;
209  st[sfPublicKey] = pk;
210  st[sfSigningPubKey] = spk;
211 
212  sign(st, HashPrefix::manifest, stype, ssk);
213  BEAST_EXPECT(verify(st, HashPrefix::manifest, spk));
214 
215  sign(
216  st,
218  type,
219  invalidSig ? randomSecretKey() : sk,
221  BEAST_EXPECT(
222  invalidSig ^
224 
225  Serializer s;
226  st.add(s);
227 
228  std::string m(
229  static_cast<char const*>(s.data()),
230  s.size()); // non-const so can be moved
231  if (auto r = deserializeManifest(std::move(m)))
232  return std::move(*r);
233  Throw<std::runtime_error>("Could not create a manifest");
234  return *deserializeManifest(
235  std::string{}); // Silence compiler warning.
236  }
237 
238  Manifest
239  clone(Manifest const& m)
240  {
241  Manifest m2;
242  m2.serialized = m.serialized;
243  m2.masterKey = m.masterKey;
244  m2.signingKey = m.signingKey;
245  m2.sequence = m.sequence;
246  m2.domain = m.domain;
247  return m2;
248  }
249 
250  void
252  {
253  testcase("load/store");
254 
255  std::string const dbName("ManifestCacheTestDB");
256  {
257  jtx::Env env(*this);
258  DatabaseCon::Setup setup;
259  setup.dataDir = getDatabasePath();
260  assert(!setup.useGlobalPragma);
261 
262  auto dbCon = makeTestWalletDB(setup, dbName);
263 
264  auto getPopulatedManifests =
265  [](ManifestCache const& cache) -> std::vector<Manifest const*> {
267  result.reserve(32);
268  cache.for_each_manifest(
269  [&result](Manifest const& man) { result.push_back(&man); });
270  return result;
271  };
272  auto sort = [](std::vector<Manifest const*> mv)
274  std::sort(
275  mv.begin(),
276  mv.end(),
277  [](Manifest const* lhs, Manifest const* rhs) {
278  return lhs->serialized < rhs->serialized;
279  });
280  return mv;
281  };
282  std::vector<Manifest const*> const inManifests(
283  sort(getPopulatedManifests(m)));
284 
285  auto& app = env.app();
286  auto unl = std::make_unique<ValidatorList>(
287  m,
288  m,
289  env.timeKeeper(),
290  app.config().legacy("database_path"),
291  env.journal);
292 
293  {
294  // save should not store untrusted master keys to db
295  // except for revocations
296  m.save(
297  *dbCon,
298  "ValidatorManifests",
299  [&unl](PublicKey const& pubKey) {
300  return unl->listed(pubKey);
301  });
302 
303  ManifestCache loaded;
304 
305  loaded.load(*dbCon, "ValidatorManifests");
306 
307  // check that all loaded manifests are revocations
308  std::vector<Manifest const*> const loadedManifests(
309  sort(getPopulatedManifests(loaded)));
310 
311  for (auto const& man : loadedManifests)
312  BEAST_EXPECT(man->revoked());
313  }
314  {
315  // save should store all trusted master keys to db
316  PublicKey emptyLocalKey;
319  std::string cfgManifest;
320  for (auto const& man : inManifests)
321  s1.push_back(
322  toBase58(TokenType::NodePublic, man->masterKey));
323  unl->load(emptyLocalKey, s1, keys);
324 
325  m.save(
326  *dbCon,
327  "ValidatorManifests",
328  [&unl](PublicKey const& pubKey) {
329  return unl->listed(pubKey);
330  });
331  ManifestCache loaded;
332  loaded.load(*dbCon, "ValidatorManifests");
333 
334  // check that the manifest caches are the same
335  std::vector<Manifest const*> const loadedManifests(
336  sort(getPopulatedManifests(loaded)));
337 
338  if (inManifests.size() == loadedManifests.size())
339  {
340  BEAST_EXPECT(std::equal(
341  inManifests.begin(),
342  inManifests.end(),
343  loadedManifests.begin(),
344  [](Manifest const* lhs, Manifest const* rhs) {
345  return *lhs == *rhs;
346  }));
347  }
348  else
349  {
350  fail();
351  }
352  }
353  {
354  // load config manifest
355  ManifestCache loaded;
356  std::vector<std::string> const emptyRevocation;
357 
358  std::string const badManifest = "bad manifest";
359  BEAST_EXPECT(!loaded.load(
360  *dbCon,
361  "ValidatorManifests",
362  badManifest,
363  emptyRevocation));
364 
365  auto const sk = randomSecretKey();
366  auto const pk = derivePublicKey(KeyType::ed25519, sk);
367  auto const kp = randomKeyPair(KeyType::secp256k1);
368 
369  std::string const cfgManifest =
370  makeManifestString(pk, sk, kp.first, kp.second, 0);
371 
372  BEAST_EXPECT(loaded.load(
373  *dbCon,
374  "ValidatorManifests",
375  cfgManifest,
376  emptyRevocation));
377  }
378  {
379  // load config revocation
380  ManifestCache loaded;
381  std::string const emptyManifest;
382 
383  std::vector<std::string> const badRevocation = {
384  "bad revocation"};
385  BEAST_EXPECT(!loaded.load(
386  *dbCon,
387  "ValidatorManifests",
388  emptyManifest,
389  badRevocation));
390 
391  auto const sk = randomSecretKey();
392  auto const keyType = KeyType::ed25519;
393  auto const pk = derivePublicKey(keyType, sk);
394  auto const kp = randomKeyPair(KeyType::secp256k1);
395  std::vector<std::string> const nonRevocation = {
396  makeManifestString(pk, sk, kp.first, kp.second, 0)};
397 
398  BEAST_EXPECT(!loaded.load(
399  *dbCon,
400  "ValidatorManifests",
401  emptyManifest,
402  nonRevocation));
403  BEAST_EXPECT(!loaded.revoked(pk));
404 
405  std::vector<std::string> const badSigRevocation = {
406  makeRevocationString(sk, keyType, true)};
407  BEAST_EXPECT(!loaded.load(
408  *dbCon,
409  "ValidatorManifests",
410  emptyManifest,
411  badSigRevocation));
412  BEAST_EXPECT(!loaded.revoked(pk));
413 
414  std::vector<std::string> const cfgRevocation = {
415  makeRevocationString(sk, keyType)};
416  BEAST_EXPECT(loaded.load(
417  *dbCon,
418  "ValidatorManifests",
419  emptyManifest,
420  cfgRevocation));
421 
422  BEAST_EXPECT(loaded.revoked(pk));
423  }
424  }
425  boost::filesystem::remove(
426  getDatabasePath() / boost::filesystem::path(dbName));
427  }
428 
429  void
431  {
432  testcase("getSignature");
433  auto const sk = randomSecretKey();
434  auto const pk = derivePublicKey(KeyType::ed25519, sk);
435  auto const kp = randomKeyPair(KeyType::secp256k1);
436  auto const m = makeManifest(
437  sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
438 
439  STObject st(sfGeneric);
440  st[sfSequence] = 0;
441  st[sfPublicKey] = pk;
442  st[sfSigningPubKey] = kp.first;
443  Serializer ss;
446  auto const sig = sign(KeyType::secp256k1, kp.second, ss.slice());
447  BEAST_EXPECT(strHex(sig) == strHex(*m.getSignature()));
448 
449  auto const masterSig = sign(KeyType::ed25519, sk, ss.slice());
450  BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
451  }
452 
453  void
455  {
456  testcase("getKeys");
457 
458  ManifestCache cache;
459  auto const sk = randomSecretKey();
460  auto const pk = derivePublicKey(KeyType::ed25519, sk);
461 
462  // getSigningKey should return same key if there is no manifest
463  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
464 
465  // getSigningKey should return the ephemeral public key
466  // for the listed validator master public key
467  // getMasterKey should return the listed validator master key
468  // for that ephemeral public key
469  auto const kp0 = randomKeyPair(KeyType::secp256k1);
470  BEAST_EXPECT(
473  sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0)));
474  BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first);
475  BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk);
476 
477  // getSigningKey should return the latest ephemeral public key
478  // for the listed validator master public key
479  // getMasterKey should only return a master key for the latest
480  // ephemeral public key
481  auto const kp1 = randomKeyPair(KeyType::secp256k1);
482  BEAST_EXPECT(
485  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1)));
486  BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
487  BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
488  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
489 
490  // getSigningKey and getMasterKey should fail if a new manifest is
491  // applied with the same signing key but a higher sequence
492  BEAST_EXPECT(
495  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2)));
496  BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
497  BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
498  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
499 
500  // getSigningKey should return std::nullopt for a revoked master public
501  // key getMasterKey should return std::nullopt for an ephemeral public
502  // key from a revoked master public key
503  BEAST_EXPECT(
506  BEAST_EXPECT(cache.revoked(pk));
507  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
508  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
509  BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
510  }
511 
512  void
514  {
515  testcase("validator token");
516 
517  {
518  auto const valSecret = parseBase58<SecretKey>(
520  "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
521 
522  // Format token string to test trim()
523  std::vector<std::string> const tokenBlob = {
524  " "
525  "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3ND"
526  "diNT\n",
527  " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2Iiwib"
528  "WFuaWZl \n",
529  "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncx"
530  "L3ZDeE\n",
531  "\t "
532  "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4"
533  "U0tG\t \t\n",
534  "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUz"
535  "ZQU2\n",
536  "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZ"
537  "eXd1\n",
538  "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZW"
539  "RGdj\n",
540  "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0i"
541  "fQ==\n"};
542 
543  auto const manifest =
544  "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
545  "vCxHXXLplc2GnMhAkE1agqXxBwD"
546  "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
547  "sAOkVB"
548  "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
549  "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
550  "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
551  "r7C0kw"
552  "2AiTzSCjIzditQ8=";
553 
554  auto const token = loadValidatorToken(tokenBlob);
555  BEAST_EXPECT(token);
556  BEAST_EXPECT(token->validationSecret == *valSecret);
557  BEAST_EXPECT(token->manifest == manifest);
558  }
559  {
560  std::vector<std::string> const badToken = {"bad token"};
561  BEAST_EXPECT(!loadValidatorToken(badToken));
562  }
563  }
564 
565  void
567  {
568  testcase("Versioning");
569 
570  auto const sk = generateSecretKey(KeyType::ed25519, randomSeed());
571  auto const pk = derivePublicKey(KeyType::ed25519, sk);
572 
573  auto const ssk = generateSecretKey(KeyType::secp256k1, randomSeed());
574  auto const spk = derivePublicKey(KeyType::secp256k1, ssk);
575 
576  auto buildManifestObject = [&](std::uint16_t version) {
577  STObject st(sfGeneric);
578  st[sfSequence] = 3;
579  st[sfPublicKey] = pk;
580  st[sfSigningPubKey] = spk;
581 
582  if (version != 0)
583  st[sfVersion] = version;
584 
585  sign(
586  st,
589  sk,
592 
593  Serializer s;
594  st.add(s);
595 
596  return std::string(static_cast<char const*>(s.data()), s.size());
597  };
598 
599  // We understand version 0 manifests:
600  BEAST_EXPECT(deserializeManifest(buildManifestObject(0)));
601 
602  // We don't understand any other versions:
603  BEAST_EXPECT(!deserializeManifest(buildManifestObject(1)));
604  BEAST_EXPECT(!deserializeManifest(buildManifestObject(2001)));
605  }
606 
607  void
609  {
610  std::array<KeyType, 2> const keyTypes{
612 
613  std::uint32_t sequence = 0;
614 
615  // public key with invalid type
616  std::array<std::uint8_t, 33> const badKey{
617  0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
618  0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
619  0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
620 
621  // Short public key:
622  std::array<std::uint8_t, 16> const shortKey{
623  0x03,
624  0x30,
625  0xE7,
626  0xFC,
627  0x9D,
628  0x56,
629  0xBB,
630  0x25,
631  0xD6,
632  0x89,
633  0x3B,
634  0xA3,
635  0xF3,
636  0x17,
637  0xAE,
638  0x5B};
639 
640  auto toString = [](STObject const& st) {
641  Serializer s;
642  st.add(s);
643 
644  return std::string(static_cast<char const*>(s.data()), s.size());
645  };
646 
647  for (auto const keyType : keyTypes)
648  {
649  auto const sk = generateSecretKey(keyType, randomSeed());
650  auto const pk = derivePublicKey(keyType, sk);
651 
652  for (auto const sKeyType : keyTypes)
653  {
654  auto const ssk = generateSecretKey(sKeyType, randomSeed());
655  auto const spk = derivePublicKey(sKeyType, ssk);
656 
657  auto buildManifestObject =
658  [&](std::uint32_t seq,
660  bool noSigningPublic = false,
661  bool noSignature = false) {
662  STObject st(sfGeneric);
663  st[sfSequence] = seq;
664  st[sfPublicKey] = pk;
665 
666  if (domain)
667  st[sfDomain] = makeSlice(*domain);
668 
669  if (!noSigningPublic)
670  st[sfSigningPubKey] = spk;
671 
672  sign(
673  st,
675  keyType,
676  sk,
678 
679  if (!noSignature)
680  sign(st, HashPrefix::manifest, sKeyType, ssk);
681 
682  return st;
683  };
684 
685  {
686  testcase << "deserializeManifest: normal manifest ("
687  << to_string(keyType) << " + "
688  << to_string(sKeyType) << ")";
689 
690  { // valid manifest without domain
691  auto const st =
692  buildManifestObject(++sequence, std::nullopt);
693 
694  auto const m = toString(st);
695  auto const manifest = deserializeManifest(m);
696 
697  BEAST_EXPECT(manifest);
698  BEAST_EXPECT(manifest->masterKey == pk);
699  BEAST_EXPECT(manifest->signingKey == spk);
700  BEAST_EXPECT(manifest->sequence == sequence);
701  BEAST_EXPECT(manifest->serialized == m);
702  BEAST_EXPECT(manifest->domain.empty());
703  BEAST_EXPECT(manifest->verify());
704  }
705 
706  { // invalid manifest (empty domain)
707  auto const st =
708  buildManifestObject(++sequence, std::string{});
709 
710  BEAST_EXPECT(!deserializeManifest(toString(st)));
711  }
712 
713  { // invalid manifest (domain too short)
714  auto const st =
715  buildManifestObject(++sequence, std::string{"a.b"});
716  BEAST_EXPECT(!deserializeManifest(toString(st)));
717  }
718  { // invalid manifest (domain too long)
719  std::string s(254, 'a');
720  auto const st =
721  buildManifestObject(++sequence, s + ".example.com");
722  BEAST_EXPECT(!deserializeManifest(toString(st)));
723  }
724  { // invalid manifest (domain component too long)
725  std::string s(72, 'a');
726  auto const st =
727  buildManifestObject(++sequence, s + ".example.com");
728  BEAST_EXPECT(!deserializeManifest(toString(st)));
729  }
730 
731  auto const st = buildManifestObject(
732  ++sequence, std::string{"example.com"});
733 
734  {
735  // valid manifest with domain
736  auto const m = toString(st);
737  auto const manifest = deserializeManifest(m);
738 
739  BEAST_EXPECT(manifest);
740  BEAST_EXPECT(manifest->masterKey == pk);
741  BEAST_EXPECT(manifest->signingKey == spk);
742  BEAST_EXPECT(manifest->sequence == sequence);
743  BEAST_EXPECT(manifest->serialized == m);
744  BEAST_EXPECT(manifest->domain == "example.com");
745  BEAST_EXPECT(manifest->verify());
746  }
747  {
748  // valid manifest with invalid signature
749  auto badSigSt = st;
750  badSigSt[sfSequence] = sequence + 1;
751 
752  auto const m = toString(badSigSt);
753  auto const manifest = deserializeManifest(m);
754 
755  BEAST_EXPECT(manifest);
756  BEAST_EXPECT(manifest->masterKey == pk);
757  BEAST_EXPECT(manifest->signingKey == spk);
758  BEAST_EXPECT(manifest->sequence == sequence + 1);
759  BEAST_EXPECT(manifest->serialized == m);
760  BEAST_EXPECT(manifest->domain == "example.com");
761  BEAST_EXPECT(!manifest->verify());
762  }
763  {
764  // reject missing sequence
765  auto badSt = st;
766  BEAST_EXPECT(badSt.delField(sfSequence));
767  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
768  }
769  {
770  // reject missing public key
771  auto badSt = st;
772  BEAST_EXPECT(badSt.delField(sfPublicKey));
773  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
774  }
775  {
776  // reject invalid public key type
777  auto badSt = st;
778  badSt[sfPublicKey] = makeSlice(badKey);
779  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
780  }
781  {
782  // reject short public key
783  auto badSt = st;
784  badSt[sfPublicKey] = makeSlice(shortKey);
785  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
786  }
787  {
788  // reject missing signing public key
789  auto badSt = st;
790  BEAST_EXPECT(badSt.delField(sfSigningPubKey));
791  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
792  }
793  {
794  // reject invalid signing public key type
795  auto badSt = st;
796  badSt[sfSigningPubKey] = makeSlice(badKey);
797  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
798  }
799  {
800  // reject short signing public key
801  auto badSt = st;
802  badSt[sfSigningPubKey] = makeSlice(shortKey);
803  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
804  }
805  {
806  // reject missing signature
807  auto badSt = st;
808  BEAST_EXPECT(badSt.delField(sfMasterSignature));
809  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
810  }
811  {
812  // reject missing signing key signature
813  auto badSt = st;
814  BEAST_EXPECT(badSt.delField(sfSignature));
815  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
816  }
817  {
818  // reject matching master & ephemeral keys
819  STObject st(sfGeneric);
820  st[sfSequence] = 314159;
821  st[sfPublicKey] = pk;
822  st[sfSigningPubKey] = pk;
823 
824  sign(
825  st,
827  keyType,
828  sk,
830 
831  sign(st, HashPrefix::manifest, sKeyType, sk);
832 
833  BEAST_EXPECT(!deserializeManifest(toString(st)));
834  }
835  }
836 
837  {
838  testcase << "deserializeManifest: revocation manifest ("
839  << to_string(keyType) << " + "
840  << to_string(sKeyType) << ")";
841 
842  // valid revocation
843  {
844  auto const st = buildManifestObject(
846  std::nullopt,
847  true,
848  true);
849 
850  auto const m = toString(st);
851  auto const manifest = deserializeManifest(m);
852 
853  BEAST_EXPECT(manifest);
854  BEAST_EXPECT(manifest->masterKey == pk);
855  BEAST_EXPECT(manifest->signingKey == PublicKey());
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(
865  std::nullopt,
866  true,
867  false);
868 
869  BEAST_EXPECT(!deserializeManifest(toString(st)));
870  }
871  { // can't specify an ephemeral signature
872  auto const st = buildManifestObject(
874  std::nullopt,
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(
883  std::nullopt,
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 
899  auto const sk1 = generateSecretKey(KeyType::secp256k1, randomSeed());
900  auto const pk1 = derivePublicKey(KeyType::secp256k1, sk1);
901 
902  auto const sk2 = generateSecretKey(KeyType::secp256k1, randomSeed());
903  auto const pk2 = derivePublicKey(KeyType::secp256k1, sk2);
904 
905  auto test = [&](std::string domain) {
906  STObject st(sfGeneric);
907  st[sfSequence] = 7;
908  st[sfPublicKey] = pk1;
909  st[sfDomain] = makeSlice(domain);
910  st[sfSigningPubKey] = pk2;
911 
912  sign(
913  st,
916  sk1,
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,
1070  randomSecretKey(),
1072  47);
1073  BEAST_EXPECT(
1074  cache.applyManifest(clone(s_c0)) ==
1076  }
1077 
1078  testLoadStore(cache);
1079  testGetSignature();
1080  testGetKeys();
1085  }
1086 };
1087 
1089 
1090 } // namespace test
1091 } // namespace ripple
ripple::test::Manifest_test
Definition: Manifest_test.cpp:38
ripple::Manifest::domain
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
Definition: Manifest.h:95
ripple::makeSlice
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:241
std::string
STL class.
std::equal
T equal(T... args)
ripple::test::Manifest_test::getDatabasePath
static boost::filesystem::path getDatabasePath()
Definition: Manifest_test.cpp:80
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: app/misc/impl/Manifest.cpp:303
std::exception
STL class.
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:327
ripple::loadValidatorToken
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal)
Definition: app/misc/impl/Manifest.cpp:244
ripple::Manifest
Definition: Manifest.h:80
std::vector::reserve
T reserve(T... args)
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::Manifest::signingKey
PublicKey signingKey
The ephemeral key associated with this manifest.
Definition: Manifest.h:89
std::vector
STL class.
ripple::Manifest::serialized
std::string serialized
The manifest in serialized form.
Definition: Manifest.h:83
std::vector::size
T size(T... args)
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
ripple::Manifest::masterKey
PublicKey masterKey
The master key associated with this manifest.
Definition: Manifest.h:86
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::test::Manifest_test::makeManifestString
std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Definition: Manifest_test.cpp:108
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:253
ripple::ManifestDisposition::badEphemeralKey
@ badEphemeralKey
The ephemeral key is not acceptable to us.
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:91
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::Manifest_test::Manifest_test
Manifest_test()
Definition: Manifest_test.cpp:86
ripple::makeTestWalletDB
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname)
makeTestWalletDB Opens a test wallet database with an arbitrary name.
Definition: Wallet.cpp:34
std::sort
T sort(T... args)
ripple::ManifestCache::save
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
Definition: app/misc/impl/Manifest.cpp:577
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
std::vector::push_back
T push_back(T... args)
ripple::test::Manifest_test::makeRevocationString
std::string makeRevocationString(SecretKey const &sk, KeyType type, bool invalidSig=false)
Definition: Manifest_test.cpp:136
ripple::sfVersion
const SF_UINT16 sfVersion
ripple::test::Manifest_test::~Manifest_test
~Manifest_test()
Definition: Manifest_test.cpp:96
ripple::KeyType::ed25519
@ ed25519
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::test::Manifest_test::clone
Manifest clone(Manifest const &m)
Definition: Manifest_test.cpp:239
ripple::DatabaseCon::Setup::useGlobalPragma
bool useGlobalPragma
Definition: DatabaseCon.h:94
ripple::test::Manifest_test::testGetSignature
void testGetSignature()
Definition: Manifest_test.cpp:430
ripple::test::Manifest_test::randomNode
static PublicKey randomNode()
Definition: Manifest_test.cpp:42
ripple::ManifestDisposition::badMasterKey
@ badMasterKey
The master key is not acceptable to us.
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::test::Manifest_test::makeRevocation
Manifest makeRevocation(SecretKey const &sk, KeyType type, bool invalidSig=false)
Definition: Manifest_test.cpp:165
ripple::test::Manifest_test::testManifestDeserialization
void testManifestDeserialization()
Definition: Manifest_test.cpp:608
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
ripple::sfMasterSignature
const SF_VL sfMasterSignature
std::array
STL class.
ripple::ManifestCache::revoked
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition: app/misc/impl/Manifest.cpp:351
ripple::test::Manifest_test::testLoadStore
void testLoadStore(ManifestCache &m)
Definition: Manifest_test.cpp:251
ripple::randomSeed
Seed randomSeed()
Create a seed using secure random numbers.
Definition: Seed.cpp:59
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
ripple::generateSecretKey
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:291
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:291
std::uint16_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
ripple::STObject::addWithoutSigningFields
void addWithoutSigningFields(Serializer &s) const
Definition: STObject.h:889
ripple::test::Manifest_test::randomMasterKey
static PublicKey randomMasterKey()
Definition: Manifest_test.cpp:48
ripple::test::Manifest_test::cleanupDatabaseDir
static void cleanupDatabaseDir(boost::filesystem::path const &dbPath)
Definition: Manifest_test.cpp:54
ripple::ManifestDisposition::invalid
@ invalid
Timely, but invalid signature.
ripple::KeyType
KeyType
Definition: KeyType.h:28
ripple::test::Manifest_test::run
void run() override
Definition: Manifest_test.cpp:981
ripple::KeyType::secp256k1
@ secp256k1
ripple::test::Manifest_test::testManifestVersioning
void testManifestVersioning()
Definition: Manifest_test.cpp:566
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::Serializer
Definition: Serializer.h:39
ripple::Manifest::sequence
std::uint32_t sequence
The sequence number of this manifest.
Definition: Manifest.h:92
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::test::Manifest_test::testGetKeys
void testGetKeys()
Definition: Manifest_test.cpp:454
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:231
ripple::STObject::add
void add(Serializer &s) const override
Definition: STObject.cpp:85
ripple::STObject
Definition: STObject.h:51
ripple::ManifestDisposition::stale
@ stale
Sequence is too old.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
std::vector::begin
T begin(T... args)
ripple::test::Manifest_test::testManifestDomainNames
void testManifestDomainNames()
Definition: Manifest_test.cpp:895
ripple::test::Manifest_test::makeManifest
Manifest makeManifest(SecretKey const &sk, KeyType type, SecretKey const &ssk, KeyType stype, int seq, bool invalidSig=false)
Definition: Manifest_test.cpp:196
ripple::test::Manifest_test::setupDatabaseDir
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
Definition: Manifest_test.cpp:63
ripple::sfSignature
const SF_VL sfSignature
ripple::TokenType::NodePublic
@ NodePublic
std::optional< std::string >
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::deserializeManifest
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:53
std::numeric_limits::max
T max(T... args)
ripple::ManifestCache::load
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: app/misc/impl/Manifest.cpp:520
ripple::sfDomain
const SF_VL sfDomain
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:363
std::numeric_limits
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::Manifest_test::testValidatorToken
void testValidatorToken()
Definition: Manifest_test.cpp:513
ripple::TokenType::NodePrivate
@ NodePrivate
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)