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/basics/StringUtilities.h>
24 #include <ripple/basics/base64.h>
25 #include <ripple/basics/contract.h>
26 #include <ripple/core/DatabaseCon.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  DatabaseCon::Setup setup;
258  setup.dataDir = getDatabasePath();
259  BEAST_EXPECT(!setup.useGlobalPragma);
260  DatabaseCon dbCon(
261  setup,
262  dbName.data(),
264  WalletDBInit);
265 
266  auto getPopulatedManifests =
267  [](ManifestCache const& cache) -> std::vector<Manifest const*> {
269  result.reserve(32);
270  cache.for_each_manifest(
271  [&result](Manifest const& man) { result.push_back(&man); });
272  return result;
273  };
274  auto sort = [](std::vector<Manifest const*> mv)
276  std::sort(
277  mv.begin(),
278  mv.end(),
279  [](Manifest const* lhs, Manifest const* rhs) {
280  return lhs->serialized < rhs->serialized;
281  });
282  return mv;
283  };
284  std::vector<Manifest const*> const inManifests(
285  sort(getPopulatedManifests(m)));
286 
287  jtx::Env env(*this);
288  auto& app = env.app();
289  auto unl = std::make_unique<ValidatorList>(
290  m,
291  m,
292  env.timeKeeper(),
293  app.config().legacy("database_path"),
294  env.journal);
295 
296  {
297  // save should not store untrusted master keys to db
298  // except for revocations
299  m.save(
300  dbCon,
301  "ValidatorManifests",
302  [&unl](PublicKey const& pubKey) {
303  return unl->listed(pubKey);
304  });
305 
306  ManifestCache loaded;
307 
308  loaded.load(dbCon, "ValidatorManifests");
309 
310  // check that all loaded manifests are revocations
311  std::vector<Manifest const*> const loadedManifests(
312  sort(getPopulatedManifests(loaded)));
313 
314  for (auto const& man : loadedManifests)
315  BEAST_EXPECT(man->revoked());
316  }
317  {
318  // save should store all trusted master keys to db
319  PublicKey emptyLocalKey;
322  std::string cfgManifest;
323  for (auto const& man : inManifests)
324  s1.push_back(
325  toBase58(TokenType::NodePublic, man->masterKey));
326  unl->load(emptyLocalKey, s1, keys);
327 
328  m.save(
329  dbCon,
330  "ValidatorManifests",
331  [&unl](PublicKey const& pubKey) {
332  return unl->listed(pubKey);
333  });
334  ManifestCache loaded;
335  loaded.load(dbCon, "ValidatorManifests");
336 
337  // check that the manifest caches are the same
338  std::vector<Manifest const*> const loadedManifests(
339  sort(getPopulatedManifests(loaded)));
340 
341  if (inManifests.size() == loadedManifests.size())
342  {
343  BEAST_EXPECT(std::equal(
344  inManifests.begin(),
345  inManifests.end(),
346  loadedManifests.begin(),
347  [](Manifest const* lhs, Manifest const* rhs) {
348  return *lhs == *rhs;
349  }));
350  }
351  else
352  {
353  fail();
354  }
355  }
356  {
357  // load config manifest
358  ManifestCache loaded;
359  std::vector<std::string> const emptyRevocation;
360 
361  std::string const badManifest = "bad manifest";
362  BEAST_EXPECT(!loaded.load(
363  dbCon, "ValidatorManifests", badManifest, 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, "ValidatorManifests", cfgManifest, 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, "ValidatorManifests", emptyManifest, badRevocation));
384 
385  auto const sk = randomSecretKey();
386  auto const keyType = KeyType::ed25519;
387  auto const pk = derivePublicKey(keyType, sk);
388  auto const kp = randomKeyPair(KeyType::secp256k1);
389  std::vector<std::string> const nonRevocation = {
390  makeManifestString(pk, sk, kp.first, kp.second, 0)};
391 
392  BEAST_EXPECT(!loaded.load(
393  dbCon, "ValidatorManifests", emptyManifest, nonRevocation));
394  BEAST_EXPECT(!loaded.revoked(pk));
395 
396  std::vector<std::string> const badSigRevocation = {
397  makeRevocationString(sk, keyType, true)};
398  BEAST_EXPECT(!loaded.load(
399  dbCon,
400  "ValidatorManifests",
401  emptyManifest,
402  badSigRevocation));
403  BEAST_EXPECT(!loaded.revoked(pk));
404 
405  std::vector<std::string> const cfgRevocation = {
406  makeRevocationString(sk, keyType)};
407  BEAST_EXPECT(loaded.load(
408  dbCon, "ValidatorManifests", emptyManifest, cfgRevocation));
409 
410  BEAST_EXPECT(loaded.revoked(pk));
411  }
412  }
413  boost::filesystem::remove(
414  getDatabasePath() / boost::filesystem::path(dbName));
415  }
416 
417  void
419  {
420  testcase("getSignature");
421  auto const sk = randomSecretKey();
422  auto const pk = derivePublicKey(KeyType::ed25519, sk);
423  auto const kp = randomKeyPair(KeyType::secp256k1);
424  auto const m = makeManifest(
425  sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
426 
427  STObject st(sfGeneric);
428  st[sfSequence] = 0;
429  st[sfPublicKey] = pk;
430  st[sfSigningPubKey] = kp.first;
431  Serializer ss;
434  auto const sig = sign(KeyType::secp256k1, kp.second, ss.slice());
435  BEAST_EXPECT(strHex(sig) == strHex(*m.getSignature()));
436 
437  auto const masterSig = sign(KeyType::ed25519, sk, ss.slice());
438  BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
439  }
440 
441  void
443  {
444  testcase("getKeys");
445 
446  ManifestCache cache;
447  auto const sk = randomSecretKey();
448  auto const pk = derivePublicKey(KeyType::ed25519, sk);
449 
450  // getSigningKey should return same key if there is no manifest
451  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
452 
453  // getSigningKey should return the ephemeral public key
454  // for the listed validator master public key
455  // getMasterKey should return the listed validator master key
456  // for that ephemeral public key
457  auto const kp0 = randomKeyPair(KeyType::secp256k1);
458  BEAST_EXPECT(
461  sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0)));
462  BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first);
463  BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk);
464 
465  // getSigningKey should return the latest ephemeral public key
466  // for the listed validator master public key
467  // getMasterKey should only return a master key for the latest
468  // ephemeral public key
469  auto const kp1 = randomKeyPair(KeyType::secp256k1);
470  BEAST_EXPECT(
473  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1)));
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 and getMasterKey should return the same keys if
479  // a new manifest is applied with the same signing key but a higher
480  // sequence
481  BEAST_EXPECT(
484  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2)));
485  BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
486  BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
487  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
488 
489  // getSigningKey should return boost::none for a revoked master public
490  // key getMasterKey should return boost::none for an ephemeral public
491  // key from a revoked master public key
492  BEAST_EXPECT(
495  BEAST_EXPECT(cache.revoked(pk));
496  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
497  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
498  BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
499  }
500 
501  void
503  {
504  testcase("validator token");
505 
506  {
507  auto const valSecret = parseBase58<SecretKey>(
509  "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
510 
511  // Format token string to test trim()
512  std::vector<std::string> const tokenBlob = {
513  " "
514  "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3ND"
515  "diNT\n",
516  " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2Iiwib"
517  "WFuaWZl \n",
518  "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncx"
519  "L3ZDeE\n",
520  "\t "
521  "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4"
522  "U0tG\t \t\n",
523  "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUz"
524  "ZQU2\n",
525  "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZ"
526  "eXd1\n",
527  "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZW"
528  "RGdj\n",
529  "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0i"
530  "fQ==\n"};
531 
532  auto const manifest =
533  "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
534  "vCxHXXLplc2GnMhAkE1agqXxBwD"
535  "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
536  "sAOkVB"
537  "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
538  "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
539  "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
540  "r7C0kw"
541  "2AiTzSCjIzditQ8=";
542 
543  auto const token = loadValidatorToken(tokenBlob);
544  BEAST_EXPECT(token);
545  BEAST_EXPECT(token->validationSecret == *valSecret);
546  BEAST_EXPECT(token->manifest == manifest);
547  }
548  {
549  std::vector<std::string> const badToken = {"bad token"};
550  BEAST_EXPECT(!loadValidatorToken(badToken));
551  }
552  }
553 
554  void
556  {
557  testcase("Versioning");
558 
559  auto const sk = generateSecretKey(KeyType::ed25519, randomSeed());
560  auto const pk = derivePublicKey(KeyType::ed25519, sk);
561 
562  auto const ssk = generateSecretKey(KeyType::secp256k1, randomSeed());
563  auto const spk = derivePublicKey(KeyType::secp256k1, ssk);
564 
565  auto buildManifestObject = [&](std::uint16_t version) {
566  STObject st(sfGeneric);
567  st[sfSequence] = 3;
568  st[sfPublicKey] = pk;
569  st[sfSigningPubKey] = spk;
570 
571  if (version != 0)
572  st[sfVersion] = version;
573 
574  sign(
575  st,
578  sk,
581 
582  Serializer s;
583  st.add(s);
584 
585  return std::string(static_cast<char const*>(s.data()), s.size());
586  };
587 
588  // We understand version 0 manifests:
589  BEAST_EXPECT(deserializeManifest(buildManifestObject(0)));
590 
591  // We don't understand any other versions:
592  BEAST_EXPECT(!deserializeManifest(buildManifestObject(1)));
593  BEAST_EXPECT(!deserializeManifest(buildManifestObject(2001)));
594  }
595 
596  void
598  {
599  std::array<KeyType, 2> const keyTypes{
601 
602  std::uint32_t sequence = 0;
603 
604  // public key with invalid type
605  std::array<std::uint8_t, 33> const badKey{
606  0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
607  0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
608  0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
609 
610  // Short public key:
611  std::array<std::uint8_t, 16> const shortKey{
612  0x03,
613  0x30,
614  0xE7,
615  0xFC,
616  0x9D,
617  0x56,
618  0xBB,
619  0x25,
620  0xD6,
621  0x89,
622  0x3B,
623  0xA3,
624  0xF3,
625  0x17,
626  0xAE,
627  0x5B};
628 
629  auto toString = [](STObject const& st) {
630  Serializer s;
631  st.add(s);
632 
633  return std::string(static_cast<char const*>(s.data()), s.size());
634  };
635 
636  for (auto const keyType : keyTypes)
637  {
638  auto const sk = generateSecretKey(keyType, randomSeed());
639  auto const pk = derivePublicKey(keyType, sk);
640 
641  for (auto const sKeyType : keyTypes)
642  {
643  auto const ssk = generateSecretKey(sKeyType, randomSeed());
644  auto const spk = derivePublicKey(sKeyType, ssk);
645 
646  auto buildManifestObject =
647  [&](std::uint32_t seq,
648  boost::optional<std::string> domain,
649  bool noSigningPublic = false,
650  bool noSignature = false) {
651  STObject st(sfGeneric);
652  st[sfSequence] = seq;
653  st[sfPublicKey] = pk;
654 
655  if (domain)
656  st[sfDomain] = makeSlice(*domain);
657 
658  if (!noSigningPublic)
659  st[sfSigningPubKey] = spk;
660 
661  sign(
662  st,
664  keyType,
665  sk,
667 
668  if (!noSignature)
669  sign(st, HashPrefix::manifest, sKeyType, ssk);
670 
671  return st;
672  };
673 
674  {
675  testcase << "deserializeManifest: normal manifest ("
676  << to_string(keyType) << " + "
677  << to_string(sKeyType) << ")";
678 
679  { // valid manifest without domain
680  auto const st =
681  buildManifestObject(++sequence, boost::none);
682 
683  auto const m = toString(st);
684  auto const manifest = deserializeManifest(m);
685 
686  BEAST_EXPECT(manifest);
687  BEAST_EXPECT(manifest->masterKey == pk);
688  BEAST_EXPECT(manifest->signingKey == spk);
689  BEAST_EXPECT(manifest->sequence == sequence);
690  BEAST_EXPECT(manifest->serialized == m);
691  BEAST_EXPECT(manifest->domain.empty());
692  BEAST_EXPECT(manifest->verify());
693  }
694 
695  { // invalid manifest (empty domain)
696  auto const st =
697  buildManifestObject(++sequence, std::string{});
698 
699  BEAST_EXPECT(!deserializeManifest(toString(st)));
700  }
701 
702  { // invalid manifest (domain too short)
703  auto const st =
704  buildManifestObject(++sequence, std::string{"a.b"});
705  BEAST_EXPECT(!deserializeManifest(toString(st)));
706  }
707  { // invalid manifest (domain too long)
708  std::string s(254, 'a');
709  auto const st =
710  buildManifestObject(++sequence, s + ".example.com");
711  BEAST_EXPECT(!deserializeManifest(toString(st)));
712  }
713  { // invalid manifest (domain component too long)
714  std::string s(72, 'a');
715  auto const st =
716  buildManifestObject(++sequence, s + ".example.com");
717  BEAST_EXPECT(!deserializeManifest(toString(st)));
718  }
719 
720  auto const st = buildManifestObject(
721  ++sequence, std::string{"example.com"});
722 
723  {
724  // valid manifest with domain
725  auto const m = toString(st);
726  auto const manifest = deserializeManifest(m);
727 
728  BEAST_EXPECT(manifest);
729  BEAST_EXPECT(manifest->masterKey == pk);
730  BEAST_EXPECT(manifest->signingKey == spk);
731  BEAST_EXPECT(manifest->sequence == sequence);
732  BEAST_EXPECT(manifest->serialized == m);
733  BEAST_EXPECT(manifest->domain == "example.com");
734  BEAST_EXPECT(manifest->verify());
735  }
736  {
737  // valid manifest with invalid signature
738  auto badSigSt = st;
739  badSigSt[sfPublicKey] = badSigSt[sfSigningPubKey];
740 
741  auto const m = toString(badSigSt);
742  auto const manifest = deserializeManifest(m);
743 
744  BEAST_EXPECT(manifest);
745  BEAST_EXPECT(manifest->masterKey == spk);
746  BEAST_EXPECT(manifest->signingKey == spk);
747  BEAST_EXPECT(manifest->sequence == sequence);
748  BEAST_EXPECT(manifest->serialized == m);
749  BEAST_EXPECT(manifest->domain == "example.com");
750  BEAST_EXPECT(!manifest->verify());
751  }
752  {
753  // reject missing sequence
754  auto badSt = st;
755  BEAST_EXPECT(badSt.delField(sfSequence));
756  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
757  }
758  {
759  // reject missing public key
760  auto badSt = st;
761  BEAST_EXPECT(badSt.delField(sfPublicKey));
762  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
763  }
764  {
765  // reject invalid public key type
766  auto badSt = st;
767  badSt[sfPublicKey] = makeSlice(badKey);
768  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
769  }
770  {
771  // reject short public key
772  auto badSt = st;
773  badSt[sfPublicKey] = makeSlice(shortKey);
774  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
775  }
776  {
777  // reject missing signing public key
778  auto badSt = st;
779  BEAST_EXPECT(badSt.delField(sfSigningPubKey));
780  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
781  }
782  {
783  // reject invalid signing public key type
784  auto badSt = st;
785  badSt[sfSigningPubKey] = makeSlice(badKey);
786  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
787  }
788  {
789  // reject short signing public key
790  auto badSt = st;
791  badSt[sfSigningPubKey] = makeSlice(shortKey);
792  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
793  }
794  {
795  // reject missing signature
796  auto badSt = st;
797  BEAST_EXPECT(badSt.delField(sfMasterSignature));
798  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
799  }
800  {
801  // reject missing signing key signature
802  auto badSt = st;
803  BEAST_EXPECT(badSt.delField(sfSignature));
804  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
805  }
806  }
807 
808  {
809  testcase << "deserializeManifest: revocation manifest ("
810  << to_string(keyType) << " + "
811  << to_string(sKeyType) << ")";
812 
813  // valid revocation
814  {
815  auto const st = buildManifestObject(
817  boost::none,
818  true,
819  true);
820 
821  auto const m = toString(st);
822  auto const manifest = deserializeManifest(m);
823 
824  BEAST_EXPECT(manifest);
825  BEAST_EXPECT(manifest->masterKey == pk);
826  BEAST_EXPECT(manifest->signingKey == PublicKey());
827  BEAST_EXPECT(manifest->revoked());
828  BEAST_EXPECT(manifest->domain.empty());
829  BEAST_EXPECT(manifest->serialized == m);
830  BEAST_EXPECT(manifest->verify());
831  }
832 
833  { // can't specify an ephemeral signing key
834  auto const st = buildManifestObject(
836  boost::none,
837  true,
838  false);
839 
840  BEAST_EXPECT(!deserializeManifest(toString(st)));
841  }
842  { // can't specify an ephemeral signature
843  auto const st = buildManifestObject(
845  boost::none,
846  false,
847  true);
848 
849  BEAST_EXPECT(!deserializeManifest(toString(st)));
850  }
851  { // can't specify an ephemeral key & signature
852  auto const st = buildManifestObject(
854  boost::none,
855  false,
856  false);
857 
858  BEAST_EXPECT(!deserializeManifest(toString(st)));
859  }
860  }
861  }
862  }
863  }
864 
865  void
867  {
868  testcase("Manifest Domain Names");
869 
870  auto const sk1 = generateSecretKey(KeyType::secp256k1, randomSeed());
871  auto const pk1 = derivePublicKey(KeyType::secp256k1, sk1);
872 
873  auto const sk2 = generateSecretKey(KeyType::secp256k1, randomSeed());
874  auto const pk2 = derivePublicKey(KeyType::secp256k1, sk2);
875 
876  auto test = [&](std::string domain) {
877  STObject st(sfGeneric);
878  st[sfSequence] = 7;
879  st[sfPublicKey] = pk1;
880  st[sfDomain] = makeSlice(domain);
881  st[sfSigningPubKey] = pk2;
882 
883  sign(
884  st,
887  sk1,
890 
891  Serializer s;
892  st.add(s);
893 
894  return deserializeManifest(
895  std::string(static_cast<char const*>(s.data()), s.size()));
896  };
897 
898  BEAST_EXPECT(test("example.com"));
899  BEAST_EXPECT(test("test.example.com"));
900  BEAST_EXPECT(test("example-domain.com"));
901  BEAST_EXPECT(test("xn--mxavchb.gr"));
902  BEAST_EXPECT(test("test.xn--mxavchb.gr"));
903  BEAST_EXPECT(test("123.gr"));
904  BEAST_EXPECT(test("x.yz"));
905  BEAST_EXPECT(test(std::string(63, 'a') + ".example.com"));
906  BEAST_EXPECT(test(std::string(63, 'a') + "." + std::string(63, 'b')));
907 
908  // No period
909  BEAST_EXPECT(!test("example"));
910 
911  // Leading period:
912  BEAST_EXPECT(!test(".com"));
913  BEAST_EXPECT(!test(".example.com"));
914 
915  // A trailing period is technically valid but we don't allow it
916  BEAST_EXPECT(!test("example.com."));
917 
918  // A component can't start or end with a dash
919  BEAST_EXPECT(!test("-example.com"));
920  BEAST_EXPECT(!test("example-.com"));
921 
922  // Empty component:
923  BEAST_EXPECT(!test("double..periods.example.com"));
924 
925  // TLD too short or too long:
926  BEAST_EXPECT(!test("example.x"));
927  BEAST_EXPECT(!test("example." + std::string(64, 'a')));
928 
929  // Invalid characters:
930  BEAST_EXPECT(!test("example.com-org"));
931  BEAST_EXPECT(!test("bang!.com"));
932  BEAST_EXPECT(!test("bang!.example.com"));
933 
934  // Too short
935  BEAST_EXPECT(!test("a.b"));
936 
937  // Single component too long:
938  BEAST_EXPECT(!test(std::string(64, 'a') + ".com"));
939  BEAST_EXPECT(!test(std::string(64, 'a') + ".example.com"));
940 
941  // Multiple components too long:
942  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
943  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
944 
945  // Overall too long:
946  BEAST_EXPECT(!test(
947  std::string(63, 'a') + "." + std::string(63, 'b') +
948  ".example.com"));
949  }
950 
951  void
952  run() override
953  {
954  ManifestCache cache;
955  {
956  testcase("apply");
957 
958  auto const sk_a = randomSecretKey();
959  auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a);
960  auto const kp_a = randomKeyPair(KeyType::secp256k1);
961  auto const s_a0 = makeManifest(
962  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 0);
963  auto const s_a1 = makeManifest(
964  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 1);
965  auto const s_aMax = makeRevocation(sk_a, KeyType::ed25519);
966 
967  auto const sk_b = randomSecretKey();
968  auto const kp_b = randomKeyPair(KeyType::secp256k1);
969  auto const s_b0 = makeManifest(
970  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 0);
971  auto const s_b1 = makeManifest(
972  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 1);
973  auto const s_b2 = makeManifest(
974  sk_b,
976  kp_b.second,
978  2,
979  true); // invalidSig
980  auto const fake = s_b1.serialized + '\0';
981 
982  // applyManifest should accept new manifests with
983  // higher sequence numbers
984  BEAST_EXPECT(
985  cache.applyManifest(clone(s_a0)) ==
987  BEAST_EXPECT(
989 
990  BEAST_EXPECT(
991  cache.applyManifest(clone(s_a1)) ==
993  BEAST_EXPECT(
995  BEAST_EXPECT(
997 
998  // applyManifest should accept manifests with max sequence numbers
999  // that revoke the master public key
1000  BEAST_EXPECT(!cache.revoked(pk_a));
1001  BEAST_EXPECT(s_aMax.revoked());
1002  BEAST_EXPECT(
1003  cache.applyManifest(clone(s_aMax)) ==
1005  BEAST_EXPECT(
1006  cache.applyManifest(clone(s_aMax)) ==
1008  BEAST_EXPECT(
1010  BEAST_EXPECT(
1012  BEAST_EXPECT(cache.revoked(pk_a));
1013 
1014  // applyManifest should reject manifests with invalid signatures
1015  BEAST_EXPECT(
1016  cache.applyManifest(clone(s_b0)) ==
1018  BEAST_EXPECT(
1020 
1021  BEAST_EXPECT(!deserializeManifest(fake));
1022  BEAST_EXPECT(
1023  cache.applyManifest(clone(s_b2)) ==
1025  }
1026  testLoadStore(cache);
1027  testGetSignature();
1028  testGetKeys();
1033  }
1034 };
1035 
1037 
1038 } // namespace test
1039 } // namespace ripple
ripple::test::Manifest_test
Definition: Manifest_test.cpp:38
ripple::ManifestCache::save
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> isTrusted)
Save cached manifests to database.
Definition: app/misc/impl/Manifest.cpp:528
ripple::Manifest::domain
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
Definition: Manifest.h:93
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:240
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
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:280
std::exception
STL class.
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:332
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::Manifest
Definition: Manifest.h:78
std::vector::reserve
T reserve(T... args)
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::Manifest::signingKey
PublicKey signingKey
The ephemeral key associated with this manifest.
Definition: Manifest.h:87
std::vector
STL class.
ripple::Manifest::serialized
std::string serialized
The manifest in serialized form.
Definition: Manifest.h:81
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:84
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:29
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:143
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:252
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:90
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:240
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::test::Manifest_test::Manifest_test
Manifest_test()
Definition: Manifest_test.cpp:86
std::sort
T sort(T... args)
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::test::Manifest_test::clone
Manifest clone(Manifest const &m)
Definition: Manifest_test.cpp:239
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
Definition: PublicKey.cpp:268
ripple::DatabaseCon::Setup::useGlobalPragma
bool useGlobalPragma
Definition: DatabaseCon.h:93
ripple::test::Manifest_test::testGetSignature
void testGetSignature()
Definition: Manifest_test.cpp:418
ripple::test::Manifest_test::randomNode
static PublicKey randomNode()
Definition: Manifest_test.cpp:42
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:597
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:205
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:328
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:179
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:268
std::uint16_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:33
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
ripple::STObject::addWithoutSigningFields
void addWithoutSigningFields(Serializer &s) const
Definition: STObject.h:358
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:952
ripple::KeyType::secp256k1
@ secp256k1
ripple::test::Manifest_test::testManifestVersioning
void testManifestVersioning()
Definition: Manifest_test.cpp:555
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:90
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:260
ripple::test::Manifest_test::testGetKeys
void testGetKeys()
Definition: Manifest_test.cpp:442
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:32
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:209
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::deserializeManifest
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:38
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::STObject::add
virtual void add(Serializer &s) const override
Definition: STObject.h:352
ripple::loadValidatorToken
boost::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob)
Definition: app/misc/impl/Manifest.cpp:223
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:124
std::vector::begin
T begin(T... args)
ripple::test::Manifest_test::testManifestDomainNames
void testManifestDomainNames()
Definition: Manifest_test.cpp:866
ripple::DatabaseCon
Definition: DatabaseCon.h:81
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
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:45
std::numeric_limits::max
T max(T... args)
ripple::WalletDBInit
constexpr std::array< char const *, 6 > WalletDBInit
Definition: DBInit.h:141
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:471
ripple::sfDomain
const SF_VL sfDomain
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:340
std::numeric_limits
std::string::data
T data(T... args)
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::Manifest_test::testValidatorToken
void testValidatorToken()
Definition: Manifest_test.cpp:502
ripple::TokenType::NodePrivate
@ NodePrivate
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:167