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/misc/Manifest.h>
21 #include <ripple/app/misc/ValidatorList.h>
22 #include <ripple/basics/base64.h>
23 #include <ripple/basics/contract.h>
24 #include <ripple/basics/StringUtilities.h>
25 #include <test/jtx.h>
26 #include <ripple/core/DatabaseCon.h>
27 #include <ripple/app/main/DBInit.h>
28 #include <ripple/protocol/SecretKey.h>
29 #include <ripple/protocol/Sign.h>
30 #include <ripple/protocol/STExchange.h>
31 #include <boost/filesystem.hpp>
32 #include <boost/algorithm/string.hpp>
33 #include <boost/utility/in_place_factory.hpp>
34 
35 namespace ripple {
36 namespace test {
37 
38 class Manifest_test : public beast::unit_test::suite
39 {
40 private:
42  {
43  return derivePublicKey (
45  randomSecretKey());
46  }
47 
49  {
50  return derivePublicKey (
52  randomSecretKey());
53  }
54 
55  static void cleanupDatabaseDir (boost::filesystem::path const& dbPath)
56  {
57  using namespace boost::filesystem;
58  if (!exists (dbPath) || !is_directory (dbPath) || !is_empty (dbPath))
59  return;
60  remove (dbPath);
61  }
62 
63  static void 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> ("Cannot create directory: " +
76  dbPath.string ());
77  }
78  }
79  static boost::filesystem::path getDatabasePath ()
80  {
81  return boost::filesystem::current_path () / "manifest_test_databases";
82  }
83 
84 public:
86  {
87  try
88  {
90  }
91  catch (std::exception const&)
92  {
93  }
94  }
96  {
97  try
98  {
100  }
101  catch (std::exception const&)
102  {
103  }
104  }
105 
108  PublicKey const& pk,
109  SecretKey const& sk,
110  PublicKey const& spk,
111  SecretKey const& ssk,
112  int seq)
113  {
114  STObject st(sfGeneric);
115  st[sfSequence] = seq;
116  st[sfPublicKey] = pk;
117  st[sfSigningPubKey] = spk;
118 
119  sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
122 
123  Serializer s;
124  st.add(s);
125 
126  return base64_encode (std::string(
127  static_cast<char const*> (s.data()), s.size()));
128  }
129 
132  SecretKey const& sk,
133  KeyType type,
134  bool invalidSig = false)
135  {
136  auto const pk = derivePublicKey(type, sk);
137 
138  STObject st(sfGeneric);
140  st[sfPublicKey] = pk;
141 
142  sign(st, HashPrefix::manifest, type,
143  invalidSig ? randomSecretKey() : sk, sfMasterSignature);
144  BEAST_EXPECT(invalidSig ^ verify(
146 
147  Serializer s;
148  st.add(s);
149 
150  return base64_encode (std::string(
151  static_cast<char const*> (s.data()), s.size()));
152  }
153 
154  Manifest
156  SecretKey const& sk, KeyType type, bool invalidSig = false)
157  {
158  auto const pk = derivePublicKey(type, sk);
159 
160  STObject st(sfGeneric);
162  st[sfPublicKey] = pk;
163 
164  sign(st, HashPrefix::manifest, type,
165  invalidSig ? randomSecretKey() : sk, sfMasterSignature);
166  BEAST_EXPECT(invalidSig ^ verify(
168 
169  Serializer s;
170  st.add(s);
171 
172  std::string const m (static_cast<char const*> (s.data()), s.size());
173  if (auto r = deserializeManifest(std::move(m)))
174  return std::move(*r);
175  Throw<std::runtime_error> ("Could not create a revocation manifest");
176  return *deserializeManifest(std::move(m)); // Silence compiler warning.
177  }
178 
179  Manifest
181  SecretKey const& sk, KeyType type, SecretKey const& ssk, KeyType stype,
182  int seq, bool invalidSig = false)
183  {
184  auto const pk = derivePublicKey(type, sk);
185  auto const spk = derivePublicKey(stype, ssk);
186 
187  STObject st(sfGeneric);
188  st[sfSequence] = seq;
189  st[sfPublicKey] = pk;
190  st[sfSigningPubKey] = spk;
191 
192  sign(st, HashPrefix::manifest, stype, ssk);
193  BEAST_EXPECT(verify(st, HashPrefix::manifest, spk));
194 
195  sign(st, HashPrefix::manifest, type,
196  invalidSig ? randomSecretKey() : sk, sfMasterSignature);
197  BEAST_EXPECT(invalidSig ^ verify(
199 
200  Serializer s;
201  st.add(s);
202 
203  std::string const m (static_cast<char const*> (s.data()), s.size());
204  if (auto r = deserializeManifest(std::move(m)))
205  return std::move (*r);
206  Throw<std::runtime_error> ("Could not create a manifest");
207  return *deserializeManifest(std::move(m)); // Silence compiler warning.
208  }
209 
210  Manifest
211  clone (Manifest const& m)
212  {
213  Manifest m2;
214  m2.serialized = m.serialized;
215  m2.masterKey = m.masterKey;
216  m2.signingKey = m.signingKey;
217  m2.sequence = m.sequence;
218  m2.domain = m.domain;
219  return m2;
220  }
221 
223  {
224  testcase ("load/store");
225 
226  std::string const dbName("ManifestCacheTestDB");
227  {
228  DatabaseCon::Setup setup;
229  setup.dataDir = getDatabasePath ();
230  DatabaseCon dbCon(
231  setup,
232  dbName.data(),
234  WalletDBInit);
235 
236  auto getPopulatedManifests =
237  [](ManifestCache const& cache) -> std::vector<Manifest const*>
238  {
240  result.reserve (32);
241  cache.for_each_manifest (
242  [&result](Manifest const& man) {result.push_back (&man);});
243  return result;
244  };
245  auto sort =
247  {
248  std::sort (mv.begin (), mv.end (),
249  [](Manifest const* lhs, Manifest const* rhs)
250  { return lhs->serialized < rhs->serialized; });
251  return mv;
252  };
253  std::vector<Manifest const*> const inManifests (
254  sort (getPopulatedManifests (m)));
255 
256  jtx::Env env (*this);
257  auto& app = env.app();
258  auto unl = std::make_unique<ValidatorList> (
259  m, m, env.timeKeeper(),
260  app.config().legacy("database_path"),
261  env.journal);
262 
263  {
264  // save should not store untrusted master keys to db
265  // except for revocations
266  m.save (dbCon, "ValidatorManifests",
267  [&unl](PublicKey const& pubKey)
268  {
269  return unl->listed (pubKey);
270  });
271 
272  ManifestCache loaded;
273 
274  loaded.load (dbCon, "ValidatorManifests");
275 
276  // check that all loaded manifests are revocations
277  std::vector<Manifest const*> const loadedManifests (
278  sort (getPopulatedManifests (loaded)));
279 
280  for (auto const& man : loadedManifests)
281  BEAST_EXPECT(man->revoked());
282  }
283  {
284  // save should store all trusted master keys to db
285  PublicKey emptyLocalKey;
288  std::string cfgManifest;
289  for (auto const& man : inManifests)
290  s1.push_back (toBase58(
291  TokenType::NodePublic, man->masterKey));
292  unl->load (emptyLocalKey, s1, keys);
293 
294  m.save (dbCon, "ValidatorManifests",
295  [&unl](PublicKey const& pubKey)
296  {
297  return unl->listed (pubKey);
298  });
299  ManifestCache loaded;
300  loaded.load (dbCon, "ValidatorManifests");
301 
302  // check that the manifest caches are the same
303  std::vector<Manifest const*> const loadedManifests (
304  sort (getPopulatedManifests (loaded)));
305 
306  if (inManifests.size () == loadedManifests.size ())
307  {
308  BEAST_EXPECT(std::equal
309  (inManifests.begin (), inManifests.end (),
310  loadedManifests.begin (),
311  [](Manifest const* lhs, Manifest const* rhs)
312  {return *lhs == *rhs;}));
313  }
314  else
315  {
316  fail ();
317  }
318  }
319  {
320  // load config manifest
321  ManifestCache loaded;
322  std::vector<std::string> const emptyRevocation;
323 
324  std::string const badManifest = "bad manifest";
325  BEAST_EXPECT(! loaded.load (
326  dbCon, "ValidatorManifests", badManifest, emptyRevocation));
327 
328  auto const sk = randomSecretKey();
329  auto const pk = derivePublicKey(KeyType::ed25519, sk);
330  auto const kp = randomKeyPair(KeyType::secp256k1);
331 
332  std::string const cfgManifest =
333  makeManifestString (pk, sk, kp.first, kp.second, 0);
334 
335  BEAST_EXPECT(loaded.load (
336  dbCon, "ValidatorManifests", cfgManifest, emptyRevocation));
337  }
338  {
339  // load config revocation
340  ManifestCache loaded;
341  std::string const emptyManifest;
342 
343  std::vector<std::string> const badRevocation = { "bad revocation" };
344  BEAST_EXPECT(! loaded.load (
345  dbCon, "ValidatorManifests", emptyManifest, badRevocation));
346 
347  auto const sk = randomSecretKey();
348  auto const keyType = KeyType::ed25519;
349  auto const pk = derivePublicKey(keyType, sk);
350  auto const kp = randomKeyPair(KeyType::secp256k1);
351  std::vector<std::string> const nonRevocation =
352  { makeManifestString (pk, sk, kp.first, kp.second, 0) };
353 
354  BEAST_EXPECT(! loaded.load (
355  dbCon, "ValidatorManifests", emptyManifest, nonRevocation));
356  BEAST_EXPECT(! loaded.revoked(pk));
357 
358  std::vector<std::string> const badSigRevocation =
359  { makeRevocationString (sk, keyType, true) };
360  BEAST_EXPECT(! loaded.load (
361  dbCon, "ValidatorManifests", emptyManifest, badSigRevocation));
362  BEAST_EXPECT(! loaded.revoked(pk));
363 
364  std::vector<std::string> const cfgRevocation =
365  { makeRevocationString (sk, keyType) };
366  BEAST_EXPECT(loaded.load (
367  dbCon, "ValidatorManifests", emptyManifest, cfgRevocation));
368 
369  BEAST_EXPECT(loaded.revoked(pk));
370  }
371  }
372  boost::filesystem::remove (getDatabasePath () /
373  boost::filesystem::path (dbName));
374  }
375 
377  {
378  testcase ("getSignature");
379  auto const sk = randomSecretKey();
380  auto const pk = derivePublicKey(KeyType::ed25519, sk);
381  auto const kp = randomKeyPair(KeyType::secp256k1);
382  auto const m = makeManifest (
383  sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
384 
385  STObject st(sfGeneric);
386  st[sfSequence] = 0;
387  st[sfPublicKey] = pk;
388  st[sfSigningPubKey] = kp.first;
389  Serializer ss;
392  auto const sig = sign(KeyType::secp256k1, kp.second, ss.slice());
393  BEAST_EXPECT(strHex(sig) == strHex(*m.getSignature()));
394 
395  auto const masterSig = sign(KeyType::ed25519, sk, ss.slice());
396  BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
397  }
398 
399  void testGetKeys()
400  {
401  testcase ("getKeys");
402 
403  ManifestCache cache;
404  auto const sk = randomSecretKey();
405  auto const pk = derivePublicKey(KeyType::ed25519, sk);
406 
407  // getSigningKey should return same key if there is no manifest
408  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
409 
410  // getSigningKey should return the ephemeral public key
411  // for the listed validator master public key
412  // getMasterKey should return the listed validator master key
413  // for that ephemeral public key
414  auto const kp0 = randomKeyPair(KeyType::secp256k1);
415  BEAST_EXPECT(ManifestDisposition::accepted ==
417  sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0)));
418  BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first);
419  BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk);
420 
421  // getSigningKey should return the latest ephemeral public key
422  // for the listed validator master public key
423  // getMasterKey should only return a master key for the latest
424  // ephemeral public key
425  auto const kp1 = randomKeyPair(KeyType::secp256k1);
426  BEAST_EXPECT(ManifestDisposition::accepted ==
428  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1)));
429  BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
430  BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
431  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
432 
433  // getSigningKey and getMasterKey should return the same keys if
434  // a new manifest is applied with the same signing key but a higher
435  // sequence
436  BEAST_EXPECT(ManifestDisposition::accepted ==
438  sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2)));
439  BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first);
440  BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk);
441  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
442 
443  // getSigningKey should return boost::none for a revoked master public key
444  // getMasterKey should return boost::none for an ephemeral public key
445  // from a revoked master public key
446  BEAST_EXPECT(ManifestDisposition::accepted ==
448  sk, KeyType::ed25519)));
449  BEAST_EXPECT(cache.revoked(pk));
450  BEAST_EXPECT(cache.getSigningKey(pk) == pk);
451  BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first);
452  BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
453  }
454 
456  {
457  testcase ("validator token");
458 
459  {
460  auto const valSecret = parseBase58<SecretKey>(
462  "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
463 
464  // Format token string to test trim()
465  std::vector<std::string> const tokenBlob = {
466  " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
467  " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n",
468  "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n",
469  "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n",
470  "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
471  "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
472  "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
473  "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"
474  };
475 
476  auto const manifest =
477  "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwD"
478  "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+sAOkVB"
479  "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
480  "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFOr7C0kw"
481  "2AiTzSCjIzditQ8=";
482 
483  auto const token = ValidatorToken::make_ValidatorToken(tokenBlob);
484  BEAST_EXPECT(token);
485  BEAST_EXPECT(token->validationSecret == *valSecret);
486  BEAST_EXPECT(token->manifest == manifest);
487  }
488  {
489  std::vector<std::string> const badToken = { "bad token" };
490  BEAST_EXPECT(! ValidatorToken::make_ValidatorToken(badToken));
491  }
492  }
493 
495  {
496  testcase ("Versioning");
497 
498  auto const sk = generateSecretKey (KeyType::ed25519, randomSeed ());
499  auto const pk = derivePublicKey(KeyType::ed25519, sk);
500 
501  auto const ssk = generateSecretKey (KeyType::secp256k1, randomSeed ());
502  auto const spk = derivePublicKey(KeyType::secp256k1, ssk);
503 
504  auto buildManifestObject = [&](std::uint16_t version)
505  {
506  STObject st(sfGeneric);
507  st[sfSequence] = 3;
508  st[sfPublicKey] = pk;
509  st[sfSigningPubKey] = spk;
510 
511  if (version != 0)
512  st[sfVersion] = version;
513 
516 
517  Serializer s;
518  st.add(s);
519 
520  return std::string (static_cast<char const*>(s.data()), s.size());
521  };
522 
523  // We understand version 0 manifests:
524  BEAST_EXPECT(deserializeManifest(buildManifestObject(0)));
525 
526  // We don't understand any other versions:
527  BEAST_EXPECT(!deserializeManifest(buildManifestObject(1)));
528  BEAST_EXPECT(!deserializeManifest(buildManifestObject(2001)));
529  }
530 
532  {
533  std::array<KeyType, 2> const keyTypes {{
536 
537  std::uint32_t sequence = 0;
538 
539  // public key with invalid type
540  auto const ret = strUnHex("9930E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020");
541  auto const badKey = Slice{ret->data(), ret->size()};
542 
543  // short public key
544  auto const retShort = strUnHex("0330");
545  auto const shortKey = Slice{retShort->data(), retShort->size()};
546 
547  auto toString = [](STObject const& st)
548  {
549  Serializer s;
550  st.add(s);
551 
552  return std::string (static_cast<char const*> (s.data()), s.size());
553  };
554 
555  for (auto const keyType : keyTypes)
556  {
557  auto const sk = generateSecretKey (keyType, randomSeed ());
558  auto const pk = derivePublicKey(keyType, sk);
559 
560  for (auto const sKeyType : keyTypes)
561  {
562  auto const ssk = generateSecretKey (sKeyType, randomSeed ());
563  auto const spk = derivePublicKey(sKeyType, ssk);
564 
565  auto buildManifestObject = [&](
567  boost::optional<std::string> domain,
568  bool noSigningPublic = false,
569  bool noSignature = false)
570  {
571  STObject st(sfGeneric);
572  st[sfSequence] = seq;
573  st[sfPublicKey] = pk;
574 
575  if (domain)
576  st[sfDomain] = makeSlice(*domain);
577 
578  if (! noSigningPublic)
579  st[sfSigningPubKey] = spk;
580 
581  sign(st, HashPrefix::manifest, keyType, sk, sfMasterSignature);
582 
583  if (! noSignature)
584  sign(st, HashPrefix::manifest, sKeyType, ssk);
585 
586  return st;
587  };
588 
589  {
590  testcase << "deserializeManifest: normal manifest (" <<
591  to_string(keyType) << " + " <<
592  to_string(sKeyType) << ")";
593 
594  { // valid manifest without domain
595  auto const st = buildManifestObject(
596  ++sequence, boost::none);
597 
598  auto const m = toString(st);
599  auto const manifest = deserializeManifest(m);
600 
601  BEAST_EXPECT(manifest);
602  BEAST_EXPECT(manifest->masterKey == pk);
603  BEAST_EXPECT(manifest->signingKey == spk);
604  BEAST_EXPECT(manifest->sequence == sequence);
605  BEAST_EXPECT(manifest->serialized == m);
606  BEAST_EXPECT(manifest->domain.empty());
607  BEAST_EXPECT(manifest->verify());
608  }
609 
610  { // invalid manifest (empty domain)
611  auto const st = buildManifestObject(
612  ++sequence, std::string{});
613 
614  BEAST_EXPECT(!deserializeManifest(toString(st)));
615  }
616 
617  { // invalid manifest (domain too short)
618  auto const st = buildManifestObject(
619  ++sequence, std::string{"a.b"});
620  BEAST_EXPECT(!deserializeManifest(toString(st)));
621  }
622  { // invalid manifest (domain too long)
623  std::string s(254, 'a');
624  auto const st = buildManifestObject(
625  ++sequence, s + ".example.com");
626  BEAST_EXPECT(!deserializeManifest(toString(st)));
627  }
628  { // invalid manifest (domain component too long)
629  std::string s(72, 'a');
630  auto const st = buildManifestObject(
631  ++sequence, s + ".example.com");
632  BEAST_EXPECT(!deserializeManifest(toString(st)));
633  }
634 
635  auto const st = buildManifestObject(
636  ++sequence, std::string{"example.com"});
637 
638  {
639  // valid manifest with domain
640  auto const m = toString(st);
641  auto const manifest = deserializeManifest(m);
642 
643  BEAST_EXPECT(manifest);
644  BEAST_EXPECT(manifest->masterKey == pk);
645  BEAST_EXPECT(manifest->signingKey == spk);
646  BEAST_EXPECT(manifest->sequence == sequence);
647  BEAST_EXPECT(manifest->serialized == m);
648  BEAST_EXPECT(manifest->domain == "example.com");
649  BEAST_EXPECT(manifest->verify());
650  }
651  {
652  // valid manifest with invalid signature
653  auto badSigSt = st;
654  badSigSt[sfPublicKey] = badSigSt[sfSigningPubKey];
655 
656  auto const m = toString(badSigSt);
657  auto const manifest = deserializeManifest(m);
658 
659  BEAST_EXPECT(manifest);
660  BEAST_EXPECT(manifest->masterKey == spk);
661  BEAST_EXPECT(manifest->signingKey == spk);
662  BEAST_EXPECT(manifest->sequence == sequence);
663  BEAST_EXPECT(manifest->serialized == m);
664  BEAST_EXPECT(manifest->domain == "example.com");
665  BEAST_EXPECT(!manifest->verify());
666  }
667  {
668  // reject missing sequence
669  auto badSt = st;
670  BEAST_EXPECT(badSt.delField(sfSequence));
671  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
672  }
673  {
674  // reject missing public key
675  auto badSt = st;
676  BEAST_EXPECT(badSt.delField(sfPublicKey));
677  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
678  }
679  {
680  // reject invalid public key type
681  auto badSt = st;
682  badSt[sfPublicKey] = badKey;
683  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
684  }
685  {
686  // reject short public key
687  auto badSt = st;
688  badSt[sfPublicKey] = shortKey;
689  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
690  }
691  {
692  // reject missing signing public key
693  auto badSt = st;
694  BEAST_EXPECT(badSt.delField(sfSigningPubKey));
695  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
696  }
697  {
698  // reject invalid signing public key type
699  auto badSt = st;
700  badSt[sfSigningPubKey] = badKey;
701  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
702  }
703  {
704  // reject short signing public key
705  auto badSt = st;
706  badSt[sfSigningPubKey] = shortKey;
707  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
708  }
709  {
710  // reject missing signature
711  auto badSt = st;
712  BEAST_EXPECT(badSt.delField(sfMasterSignature));
713  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
714  }
715  {
716  // reject missing signing key signature
717  auto badSt = st;
718  BEAST_EXPECT(badSt.delField(sfSignature));
719  BEAST_EXPECT(!deserializeManifest(toString(badSt)));
720  }
721  }
722 
723  {
724  testcase << "deserializeManifest: revocation manifest (" <<
725  to_string(keyType) << " + " <<
726  to_string(sKeyType) << ")";
727 
728  // valid revocation
729  {
730  auto const st = buildManifestObject(
732  boost::none, true, true);
733 
734  auto const m = toString(st);
735  auto const manifest = deserializeManifest(m);
736 
737  BEAST_EXPECT(manifest);
738  BEAST_EXPECT(manifest->masterKey == pk);
739  BEAST_EXPECT(manifest->signingKey == PublicKey());
740  BEAST_EXPECT(manifest->revoked());
741  BEAST_EXPECT(manifest->domain.empty());
742  BEAST_EXPECT(manifest->serialized == m);
743  BEAST_EXPECT(manifest->verify());
744  }
745 
746  { // can't specify an ephemeral signing key
747  auto const st = buildManifestObject(
749  boost::none, true, false);
750 
751  BEAST_EXPECT(!deserializeManifest(toString(st)));
752  }
753  { // can't specify an ephemeral signature
754  auto const st = buildManifestObject(
756  boost::none, false, true);
757 
758  BEAST_EXPECT(!deserializeManifest(toString(st)));
759  }
760  { // can't specify an ephemeral key & signature
761  auto const st = buildManifestObject(
763  boost::none, false, false);
764 
765  BEAST_EXPECT(!deserializeManifest(toString(st)));
766  }
767  }
768  }
769  }
770  }
771 
773  {
774  testcase ("Manifest Domain Names");
775 
776  auto const sk1 = generateSecretKey (KeyType::secp256k1, randomSeed());
777  auto const pk1 = derivePublicKey(KeyType::secp256k1, sk1);
778 
779  auto const sk2 = generateSecretKey (KeyType::secp256k1, randomSeed());
780  auto const pk2 = derivePublicKey(KeyType::secp256k1, sk2);
781 
782  auto test = [&](std::string domain)
783  {
784  STObject st(sfGeneric);
785  st[sfSequence] = 7;
786  st[sfPublicKey] = pk1;
787  st[sfDomain] = makeSlice(domain);
788  st[sfSigningPubKey] = pk2;
789 
792 
793  Serializer s;
794  st.add(s);
795 
796  return deserializeManifest(
797  std::string(static_cast<char const*> (s.data()), s.size()));
798  };
799 
800  BEAST_EXPECT(test("example.com"));
801  BEAST_EXPECT(test("test.example.com"));
802  BEAST_EXPECT(test("example-domain.com"));
803  BEAST_EXPECT(test("xn--mxavchb.gr"));
804  BEAST_EXPECT(test("test.xn--mxavchb.gr"));
805  BEAST_EXPECT(test("123.gr"));
806  BEAST_EXPECT(test("x.yz"));
807  BEAST_EXPECT(test(std::string(63, 'a') + ".example.com"));
808  BEAST_EXPECT(test(std::string(63, 'a') + "." + std::string(63, 'b')));
809 
810 
811  // No period
812  BEAST_EXPECT(!test("example"));
813 
814  // Leading period:
815  BEAST_EXPECT(!test(".com"));
816  BEAST_EXPECT(!test(".example.com"));
817 
818  // A trailing period is technically valid but we don't allow it
819  BEAST_EXPECT(!test("example.com."));
820 
821  // A component can't start or end with a dash
822  BEAST_EXPECT(!test("-example.com"));
823  BEAST_EXPECT(!test("example-.com"));
824 
825  // Empty component:
826  BEAST_EXPECT(!test("double..periods.example.com"));
827 
828  // TLD too short or too long:
829  BEAST_EXPECT(!test("example.x"));
830  BEAST_EXPECT(!test("example." + std::string(64, 'a')));
831 
832  // Invalid characters:
833  BEAST_EXPECT(!test("example.com-org"));
834  BEAST_EXPECT(!test("bang!.com"));
835  BEAST_EXPECT(!test("bang!.example.com"));
836 
837  // Too short
838  BEAST_EXPECT(!test("a.b"));
839 
840  // Single component too long:
841  BEAST_EXPECT(!test(std::string(64, 'a') + ".com"));
842  BEAST_EXPECT(!test(std::string(64, 'a') + ".example.com"));
843 
844  // Multiple components too long:
845  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
846  BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b')));
847 
848  // Overall too long:
849  BEAST_EXPECT(!test(std::string(63, 'a') + "." + std::string(63, 'b') + ".example.com"));
850  }
851 
852  void
853  run() override
854  {
855  ManifestCache cache;
856  {
857  testcase ("apply");
858 
859  auto const sk_a = randomSecretKey();
860  auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a);
861  auto const kp_a = randomKeyPair(KeyType::secp256k1);
862  auto const s_a0 = makeManifest (
863  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 0);
864  auto const s_a1 = makeManifest (
865  sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 1);
866  auto const s_aMax = makeRevocation (sk_a, KeyType::ed25519);
867 
868  auto const sk_b = randomSecretKey();
869  auto const kp_b = randomKeyPair(KeyType::secp256k1);
870  auto const s_b0 = makeManifest (
871  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 0);
872  auto const s_b1 = makeManifest (
873  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 1);
874  auto const s_b2 = makeManifest (
875  sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 2,
876  true); // invalidSig
877  auto const fake = s_b1.serialized + '\0';
878 
879  // applyManifest should accept new manifests with
880  // higher sequence numbers
881  BEAST_EXPECT(cache.applyManifest (clone (s_a0)) == ManifestDisposition::accepted);
882  BEAST_EXPECT(cache.applyManifest (clone (s_a0)) == ManifestDisposition::stale);
883 
884  BEAST_EXPECT(cache.applyManifest (clone (s_a1)) == ManifestDisposition::accepted);
885  BEAST_EXPECT(cache.applyManifest (clone (s_a1)) == ManifestDisposition::stale);
886  BEAST_EXPECT(cache.applyManifest (clone (s_a0)) == ManifestDisposition::stale);
887 
888  // applyManifest should accept manifests with max sequence numbers
889  // that revoke the master public key
890  BEAST_EXPECT(!cache.revoked (pk_a));
891  BEAST_EXPECT(s_aMax.revoked ());
892  BEAST_EXPECT(cache.applyManifest (clone (s_aMax)) == ManifestDisposition::accepted);
893  BEAST_EXPECT(cache.applyManifest (clone (s_aMax)) == ManifestDisposition::stale);
894  BEAST_EXPECT(cache.applyManifest (clone (s_a1)) == ManifestDisposition::stale);
895  BEAST_EXPECT(cache.applyManifest (clone (s_a0)) == ManifestDisposition::stale);
896  BEAST_EXPECT(cache.revoked (pk_a));
897 
898  // applyManifest should reject manifests with invalid signatures
899  BEAST_EXPECT(cache.applyManifest (clone (s_b0)) == ManifestDisposition::accepted);
900  BEAST_EXPECT(cache.applyManifest (clone (s_b0)) == ManifestDisposition::stale);
901 
902  BEAST_EXPECT(!deserializeManifest(fake));
903  BEAST_EXPECT(cache.applyManifest (clone (s_b2)) == ManifestDisposition::invalid);
904  }
905  testLoadStore (cache);
906  testGetSignature ();
907  testGetKeys ();
912  }
913 };
914 
916 
917 } // test
918 } // 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:543
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:199
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:79
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:80
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:317
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::Manifest
Definition: Manifest.h:78
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:43
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:442
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:340
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:227
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:107
ripple::sfMasterSignature
const SF_Blob sfMasterSignature(access, STI_VL, 18, "MasterSignature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:457
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:87
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:143
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:249
ripple::ValidatorToken::make_ValidatorToken
static boost::optional< ValidatorToken > make_ValidatorToken(std::vector< std::string > const &tokenBlob)
Definition: app/misc/impl/Manifest.cpp:243
ripple::Serializer::add32
int add32(std::uint32_t)
Definition: Serializer.cpp:46
ripple::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:69
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:86
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:237
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::test::Manifest_test::Manifest_test
Manifest_test()
Definition: Manifest_test.cpp:85
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:444
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:79
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:131
ripple::test::Manifest_test::~Manifest_test
~Manifest_test()
Definition: Manifest_test.cpp:95
ripple::KeyType::ed25519
@ ed25519
ripple::test::Manifest_test::clone
Manifest clone(Manifest const &m)
Definition: Manifest_test.cpp:211
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
Definition: PublicKey.cpp:277
ripple::test::Manifest_test::testGetSignature
void testGetSignature()
Definition: Manifest_test.cpp:376
ripple::test::Manifest_test::randomNode
static PublicKey randomNode()
Definition: Manifest_test.cpp:41
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:155
ripple::test::Manifest_test::testManifestDeserialization
void testManifestDeserialization()
Definition: Manifest_test.cpp:531
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:228
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:222
ripple::randomSeed
Seed randomSeed()
Create a seed using secure random numbers.
Definition: Seed.cpp:61
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:67
ripple::generateSecretKey
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:199
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:348
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:55
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:853
ripple::sfVersion
const SF_U16 sfVersion(access, STI_UINT16, 16, "Version")
Definition: SField.h:335
ripple::KeyType::secp256k1
@ secp256k1
ripple::test::Manifest_test::testManifestVersioning
void testManifestVersioning()
Definition: Manifest_test.cpp:494
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::Serializer
Definition: Serializer.h:43
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:286
ripple::test::Manifest_test::testGetKeys
void testGetKeys()
Definition: Manifest_test.cpp:399
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:213
ripple::STObject
Definition: STObject.h:51
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:440
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:37
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:73
ripple::STObject::add
virtual void add(Serializer &s) const override
Definition: STObject.h:343
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:132
std::vector::begin
T begin(T... args)
ripple::test::Manifest_test::testManifestDomainNames
void testManifestDomainNames()
Definition: Manifest_test.cpp:772
ripple::DatabaseCon
Definition: DatabaseCon.h:77
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:180
ripple::test::Manifest_test::setupDatabaseDir
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
Definition: Manifest_test.cpp:63
ripple::TokenType::NodePublic
@ NodePublic
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
std::numeric_limits::max
T max(T... args)
ripple::WalletDBInit
constexpr std::array< char const *, 6 > WalletDBInit
Definition: DBInit.h:152
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:487
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:455
ripple::TokenType::NodePrivate
@ NodePrivate
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:184
ripple::sfDomain
const SF_Blob sfDomain(access, STI_VL, 7, "Domain")
Definition: SField.h:445