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  auto const ret = strUnHex(
606  "9930E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02"
607  "0");
608  auto const badKey = Slice{ret->data(), ret->size()};
609 
610  // short public key
611  auto const retShort = strUnHex("0330");
612  auto const shortKey = Slice{retShort->data(), retShort->size()};
613 
614  auto toString = [](STObject const& st) {
615  Serializer s;
616  st.add(s);
617 
618  return std::string(static_cast<char const*>(s.data()), s.size());
619  };
620 
621  for (auto const keyType : keyTypes)
622  {
623  auto const sk = generateSecretKey(keyType, randomSeed());
624  auto const pk = derivePublicKey(keyType, sk);
625 
626  for (auto const sKeyType : keyTypes)
627  {
628  auto const ssk = generateSecretKey(sKeyType, randomSeed());
629  auto const spk = derivePublicKey(sKeyType, ssk);
630 
631  auto buildManifestObject =
632  [&](std::uint32_t seq,
633  boost::optional<std::string> domain,
634  bool noSigningPublic = false,
635  bool noSignature = false) {
636  STObject st(sfGeneric);
637  st[sfSequence] = seq;
638  st[sfPublicKey] = pk;
639 
640  if (domain)
641  st[sfDomain] = makeSlice(*domain);
642 
643  if (!noSigningPublic)
644  st[sfSigningPubKey] = spk;
645 
646  sign(
647  st,
649  keyType,
650  sk,
652 
653  if (!noSignature)
654  sign(st, HashPrefix::manifest, sKeyType, ssk);
655 
656  return st;
657  };
658 
659  {
660  testcase << "deserializeManifest: normal manifest ("
661  << to_string(keyType) << " + "
662  << to_string(sKeyType) << ")";
663 
664  { // valid manifest without domain
665  auto const st =
666  buildManifestObject(++sequence, boost::none);
667 
668  auto const m = toString(st);
669  auto const manifest = deserializeManifest(m);
670 
671  BEAST_EXPECT(manifest);
672  BEAST_EXPECT(manifest->masterKey == pk);
673  BEAST_EXPECT(manifest->signingKey == spk);
674  BEAST_EXPECT(manifest->sequence == sequence);
675  BEAST_EXPECT(manifest->serialized == m);
676  BEAST_EXPECT(manifest->domain.empty());
677  BEAST_EXPECT(manifest->verify());
678  }
679 
680  { // invalid manifest (empty domain)
681  auto const st =
682  buildManifestObject(++sequence, std::string{});
683 
684  BEAST_EXPECT(!deserializeManifest(toString(st)));
685  }
686 
687  { // invalid manifest (domain too short)
688  auto const st =
689  buildManifestObject(++sequence, std::string{"a.b"});
690  BEAST_EXPECT(!deserializeManifest(toString(st)));
691  }
692  { // invalid manifest (domain too long)
693  std::string s(254, 'a');
694  auto const st =
695  buildManifestObject(++sequence, s + ".example.com");
696  BEAST_EXPECT(!deserializeManifest(toString(st)));
697  }
698  { // invalid manifest (domain component too long)
699  std::string s(72, 'a');
700  auto const st =
701  buildManifestObject(++sequence, s + ".example.com");
702  BEAST_EXPECT(!deserializeManifest(toString(st)));
703  }
704 
705  auto const st = buildManifestObject(
706  ++sequence, std::string{"example.com"});
707 
708  {
709  // valid manifest with domain
710  auto const m = toString(st);
711  auto const manifest = deserializeManifest(m);
712 
713  BEAST_EXPECT(manifest);
714  BEAST_EXPECT(manifest->masterKey == pk);
715  BEAST_EXPECT(manifest->signingKey == spk);
716  BEAST_EXPECT(manifest->sequence == sequence);
717  BEAST_EXPECT(manifest->serialized == m);
718  BEAST_EXPECT(manifest->domain == "example.com");
719  BEAST_EXPECT(manifest->verify());
720  }
721  {
722  // valid manifest with invalid signature
723  auto badSigSt = st;
724  badSigSt[sfPublicKey] = badSigSt[sfSigningPubKey];
725 
726  auto const m = toString(badSigSt);
727  auto const manifest = deserializeManifest(m);
728 
729  BEAST_EXPECT(manifest);
730  BEAST_EXPECT(manifest->masterKey == spk);
731  BEAST_EXPECT(manifest->signingKey == spk);
732  BEAST_EXPECT(manifest->sequence == sequence);
733  BEAST_EXPECT(manifest->serialized == m);
734  BEAST_EXPECT(manifest->domain == "example.com");
735  BEAST_EXPECT(!manifest->verify());
736  }
737  {
738  // reject missing sequence
739  auto badSt = st;
740  BEAST_EXPECT(badSt.delField(sfSequence));
741  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
742  }
743  {
744  // reject missing public key
745  auto badSt = st;
746  BEAST_EXPECT(badSt.delField(sfPublicKey));
747  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
748  }
749  {
750  // reject invalid public key type
751  auto badSt = st;
752  badSt[sfPublicKey] = badKey;
753  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
754  }
755  {
756  // reject short public key
757  auto badSt = st;
758  badSt[sfPublicKey] = shortKey;
759  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
760  }
761  {
762  // reject missing signing public key
763  auto badSt = st;
764  BEAST_EXPECT(badSt.delField(sfSigningPubKey));
765  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
766  }
767  {
768  // reject invalid signing public key type
769  auto badSt = st;
770  badSt[sfSigningPubKey] = badKey;
771  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
772  }
773  {
774  // reject short signing public key
775  auto badSt = st;
776  badSt[sfSigningPubKey] = shortKey;
777  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
778  }
779  {
780  // reject missing signature
781  auto badSt = st;
782  BEAST_EXPECT(badSt.delField(sfMasterSignature));
783  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
784  }
785  {
786  // reject missing signing key signature
787  auto badSt = st;
788  BEAST_EXPECT(badSt.delField(sfSignature));
789  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
790  }
791  }
792 
793  {
794  testcase << "deserializeManifest: revocation manifest ("
795  << to_string(keyType) << " + "
796  << to_string(sKeyType) << ")";
797 
798  // valid revocation
799  {
800  auto const st = buildManifestObject(
802  boost::none,
803  true,
804  true);
805 
806  auto const m = toString(st);
807  auto const manifest = deserializeManifest(m);
808 
809  BEAST_EXPECT(manifest);
810  BEAST_EXPECT(manifest->masterKey == pk);
811  BEAST_EXPECT(manifest->signingKey == PublicKey());
812  BEAST_EXPECT(manifest->revoked());
813  BEAST_EXPECT(manifest->domain.empty());
814  BEAST_EXPECT(manifest->serialized == m);
815  BEAST_EXPECT(manifest->verify());
816  }
817 
818  { // can't specify an ephemeral signing key
819  auto const st = buildManifestObject(
821  boost::none,
822  true,
823  false);
824 
825  BEAST_EXPECT(!deserializeManifest(toString(st)));
826  }
827  { // can't specify an ephemeral signature
828  auto const st = buildManifestObject(
830  boost::none,
831  false,
832  true);
833 
834  BEAST_EXPECT(!deserializeManifest(toString(st)));
835  }
836  { // can't specify an ephemeral key & signature
837  auto const st = buildManifestObject(
839  boost::none,
840  false,
841  false);
842 
843  BEAST_EXPECT(!deserializeManifest(toString(st)));
844  }
845  }
846  }
847  }
848  }
849 
850  void
852  {
853  testcase("Manifest Domain Names");
854 
855  auto const sk1 = generateSecretKey(KeyType::secp256k1, randomSeed());
856  auto const pk1 = derivePublicKey(KeyType::secp256k1, sk1);
857 
858  auto const sk2 = generateSecretKey(KeyType::secp256k1, randomSeed());
859  auto const pk2 = derivePublicKey(KeyType::secp256k1, sk2);
860 
861  auto test = [&](std::string domain) {
862  STObject st(sfGeneric);
863  st[sfSequence] = 7;
864  st[sfPublicKey] = pk1;
865  st[sfDomain] = makeSlice(domain);
866  st[sfSigningPubKey] = pk2;
867 
868  sign(
869  st,
872  sk1,
875 
876  Serializer s;
877  st.add(s);
878 
879  return deserializeManifest(
880  std::string(static_cast<char const*>(s.data()), s.size()));
881  };
882 
883  BEAST_EXPECT(test("example.com"));
884  BEAST_EXPECT(test("test.example.com"));
885  BEAST_EXPECT(test("example-domain.com"));
886  BEAST_EXPECT(test("xn--mxavchb.gr"));
887  BEAST_EXPECT(test("test.xn--mxavchb.gr"));
888  BEAST_EXPECT(test("123.gr"));
889  BEAST_EXPECT(test("x.yz"));
890  BEAST_EXPECT(test(std::string(63, 'a') + ".example.com"));
891  BEAST_EXPECT(test(std::string(63, 'a') + "." + std::string(63, 'b')));
892 
893  // No period
894  BEAST_EXPECT(!test("example"));
895 
896  // Leading period:
897  BEAST_EXPECT(!test(".com"));
898  BEAST_EXPECT(!test(".example.com"));
899 
900  // A trailing period is technically valid but we don't allow it
901  BEAST_EXPECT(!test("example.com."));
902 
903  // A component can't start or end with a dash
904  BEAST_EXPECT(!test("-example.com"));
905  BEAST_EXPECT(!test("example-.com"));
906 
907  // Empty component:
908  BEAST_EXPECT(!test("double..periods.example.com"));
909 
910  // TLD too short or too long:
911  BEAST_EXPECT(!test("example.x"));
912  BEAST_EXPECT(!test("example." + std::string(64, 'a')));
913 
914  // Invalid characters:
915  BEAST_EXPECT(!test("example.com-org"));
916  BEAST_EXPECT(!test("bang!.com"));
917  BEAST_EXPECT(!test("bang!.example.com"));
918 
919  // Too short
920  BEAST_EXPECT(!test("a.b"));
921 
922  // Single component too long:
923  BEAST_EXPECT(!test(std::string(64, 'a') + ".com"));
924  BEAST_EXPECT(!test(std::string(64, 'a') + ".example.com"));
925 
926  // Multiple components too long:
927  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
928  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
929 
930  // Overall too long:
931  BEAST_EXPECT(!test(
932  std::string(63, 'a') + "." + std::string(63, 'b') +
933  ".example.com"));
934  }
935 
936  void
937  run() override
938  {
939  ManifestCache cache;
940  {
941  testcase("apply");
942 
943  auto const sk_a = randomSecretKey();
944  auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a);
945  auto const kp_a = randomKeyPair(KeyType::secp256k1);
946  auto const s_a0 = makeManifest(
947  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 0);
948  auto const s_a1 = makeManifest(
949  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 1);
950  auto const s_aMax = makeRevocation(sk_a, KeyType::ed25519);
951 
952  auto const sk_b = randomSecretKey();
953  auto const kp_b = randomKeyPair(KeyType::secp256k1);
954  auto const s_b0 = makeManifest(
955  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 0);
956  auto const s_b1 = makeManifest(
957  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 1);
958  auto const s_b2 = makeManifest(
959  sk_b,
961  kp_b.second,
963  2,
964  true); // invalidSig
965  auto const fake = s_b1.serialized + '\0';
966 
967  // applyManifest should accept new manifests with
968  // higher sequence numbers
969  BEAST_EXPECT(
970  cache.applyManifest(clone(s_a0)) ==
972  BEAST_EXPECT(
974 
975  BEAST_EXPECT(
976  cache.applyManifest(clone(s_a1)) ==
978  BEAST_EXPECT(
980  BEAST_EXPECT(
982 
983  // applyManifest should accept manifests with max sequence numbers
984  // that revoke the master public key
985  BEAST_EXPECT(!cache.revoked(pk_a));
986  BEAST_EXPECT(s_aMax.revoked());
987  BEAST_EXPECT(
988  cache.applyManifest(clone(s_aMax)) ==
990  BEAST_EXPECT(
991  cache.applyManifest(clone(s_aMax)) ==
993  BEAST_EXPECT(
995  BEAST_EXPECT(
997  BEAST_EXPECT(cache.revoked(pk_a));
998 
999  // applyManifest should reject manifests with invalid signatures
1000  BEAST_EXPECT(
1001  cache.applyManifest(clone(s_b0)) ==
1003  BEAST_EXPECT(
1005 
1006  BEAST_EXPECT(!deserializeManifest(fake));
1007  BEAST_EXPECT(
1008  cache.applyManifest(clone(s_b2)) ==
1010  }
1011  testLoadStore(cache);
1012  testGetSignature();
1013  testGetKeys();
1018  }
1019 };
1020 
1022 
1023 } // namespace test
1024 } // 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:546
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:301
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
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::vector::reserve
T reserve(T... args)
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::sfSigningPubKey
const SF_Blob sfSigningPubKey(access, STI_VL, 3, "SigningPubKey")
Definition: SField.h:460
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::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:356
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::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::sfMasterSignature
const SF_Blob sfMasterSignature(access, STI_VL, 18, "MasterSignature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:475
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::Slice::data
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:96
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::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:72
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::sfSignature
const SF_Blob sfSignature(access, STI_VL, 6, "Signature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:462
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::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
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:349
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:289
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:364
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:937
ripple::sfVersion
const SF_U16 sfVersion(access, STI_UINT16, 16, "Version")
Definition: SField.h:351
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::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:458
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:358
ripple::loadValidatorToken
boost::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob)
Definition: app/misc/impl/Manifest.cpp:244
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:851
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::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:67
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:489
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:361
std::numeric_limits
std::string::data
T data(T... args)
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
ripple::sfDomain
const SF_Blob sfDomain(access, STI_VL, 7, "Domain")
Definition: SField.h:463