Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
storage_common_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <memory>
4 #include <string>
5 
6 #include <boost/filesystem.hpp>
7 
8 #include "logging/logging.h"
9 #include "storage/sqlstorage.h"
10 #include "utilities/types.h"
11 #include "utilities/utils.h"
12 
13 StorageType current_storage_type{StorageType::kSqlite};
14 
15 std::unique_ptr<INvStorage> Storage(const boost::filesystem::path &dir) {
16  StorageConfig storage_config;
17  storage_config.type = current_storage_type;
18  storage_config.path = dir;
19 
20  if (storage_config.type == StorageType::kSqlite) {
21  return std::unique_ptr<INvStorage>(new SQLStorage(storage_config, false));
22  } else {
23  throw std::runtime_error("Invalid config type");
24  }
25 }
26 
27 StorageConfig MakeConfig(StorageType type, const boost::filesystem::path &storage_dir) {
28  StorageConfig config;
29 
30  config.type = type;
31  if (config.type == StorageType::kSqlite) {
32  config.sqldb_path = storage_dir / "test.db";
33  } else {
34  throw std::runtime_error("Invalid config type");
35  }
36  return config;
37 }
38 
39 /* Load and store primary keys. */
40 TEST(storage, load_store_primary_keys) {
41  TemporaryDirectory temp_dir;
42  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
43 
44  storage->storePrimaryKeys("", "");
45  storage->storePrimaryKeys("pr_public", "pr_private");
46 
47  std::string pubkey;
48  std::string privkey;
49 
50  EXPECT_TRUE(storage->loadPrimaryKeys(&pubkey, &privkey));
51  EXPECT_EQ(pubkey, "pr_public");
52  EXPECT_EQ(privkey, "pr_private");
53  storage->clearPrimaryKeys();
54  EXPECT_FALSE(storage->loadPrimaryKeys(nullptr, nullptr));
55 }
56 
57 /* Load and store TLS credentials. */
58 TEST(storage, load_store_tls) {
59  TemporaryDirectory temp_dir;
60  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
61 
62  storage->storeTlsCreds("", "", "");
63  storage->storeTlsCreds("ca", "cert", "priv");
64  std::string ca;
65  std::string cert;
66  std::string priv;
67 
68  EXPECT_TRUE(storage->loadTlsCreds(&ca, &cert, &priv));
69 
70  EXPECT_EQ(ca, "ca");
71  EXPECT_EQ(cert, "cert");
72  EXPECT_EQ(priv, "priv");
73  storage->clearTlsCreds();
74  EXPECT_FALSE(storage->loadTlsCreds(nullptr, nullptr, nullptr));
75 }
76 
77 /* Load and store Uptane metadata. */
78 TEST(storage, load_store_metadata) {
79  TemporaryDirectory temp_dir;
80  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
81 
82  Json::Value root_json;
83  root_json["_type"] = "Root";
84  root_json["consistent_snapshot"] = false;
85  root_json["expires"] = "2038-01-19T03:14:06Z";
86  root_json["keys"]["firstid"]["keytype"] = "ed25519";
87  root_json["keys"]["firstid"]["keyval"]["public"] = "firstval";
88  root_json["keys"]["secondid"]["keytype"] = "ed25519";
89  root_json["keys"]["secondid"]["keyval"]["public"] = "secondval";
90 
91  root_json["roles"]["root"]["threshold"] = 1;
92  root_json["roles"]["root"]["keyids"][0] = "firstid";
93  root_json["roles"]["snapshot"]["threshold"] = 1;
94  root_json["roles"]["snapshot"]["keyids"][0] = "firstid";
95  root_json["roles"]["targets"]["threshold"] = 1;
96  root_json["roles"]["targets"]["keyids"][0] = "firstid";
97  root_json["roles"]["timestamp"]["threshold"] = 1;
98  root_json["roles"]["timestamp"]["keyids"][0] = "firstid";
99 
100  Json::Value meta_root;
101  meta_root["signed"] = root_json;
102  std::string director_root = Utils::jsonToStr(meta_root);
103  std::string images_root = Utils::jsonToStr(meta_root);
104 
105  Json::Value targets_json;
106  targets_json["_type"] = "Targets";
107  targets_json["expires"] = "2038-01-19T03:14:06Z";
108  targets_json["targets"]["file1"]["custom"]["ecu_identifier"] = "ecu1";
109  targets_json["targets"]["file1"]["custom"]["hardware_identifier"] = "hw1";
110  targets_json["targets"]["file1"]["hashes"]["sha256"] = "12ab";
111  targets_json["targets"]["file1"]["length"] = 1;
112  targets_json["targets"]["file2"]["custom"]["ecu_identifier"] = "ecu2";
113  targets_json["targets"]["file2"]["custom"]["hardware_identifier"] = "hw2";
114  targets_json["targets"]["file2"]["hashes"]["sha512"] = "12ab";
115  targets_json["targets"]["file2"]["length"] = 11;
116 
117  Json::Value meta_targets;
118  meta_targets["signed"] = targets_json;
119  std::string director_targets = Utils::jsonToStr(meta_targets);
120  std::string images_targets = Utils::jsonToStr(meta_targets);
121 
122  Json::Value timestamp_json;
123  timestamp_json["signed"]["_type"] = "Timestamp";
124  timestamp_json["signed"]["expires"] = "2038-01-19T03:14:06Z";
125  std::string images_timestamp = Utils::jsonToStr(timestamp_json);
126 
127  Json::Value snapshot_json;
128  snapshot_json["_type"] = "Snapshot";
129  snapshot_json["expires"] = "2038-01-19T03:14:06Z";
130  snapshot_json["meta"]["root.json"]["version"] = 1;
131  snapshot_json["meta"]["targets.json"]["version"] = 2;
132  snapshot_json["meta"]["timestamp.json"]["version"] = 3;
133  snapshot_json["meta"]["snapshot.json"]["version"] = 4;
134 
135  Json::Value meta_snapshot;
136  meta_snapshot["signed"] = snapshot_json;
137  std::string images_snapshot = Utils::jsonToStr(meta_snapshot);
138 
139  storage->storeRoot(director_root, Uptane::RepositoryType::Director(), Uptane::Version(1));
140  storage->storeNonRoot(director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
141  storage->storeRoot(images_root, Uptane::RepositoryType::Image(), Uptane::Version(1));
142  storage->storeNonRoot(images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
143  storage->storeNonRoot(images_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
144  storage->storeNonRoot(images_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
145 
146  std::string loaded_director_root;
147  std::string loaded_director_targets;
148  std::string loaded_images_root;
149  std::string loaded_images_targets;
150  std::string loaded_images_timestamp;
151  std::string loaded_images_snapshot;
152 
153  EXPECT_TRUE(storage->loadLatestRoot(&loaded_director_root, Uptane::RepositoryType::Director()));
154  EXPECT_TRUE(
155  storage->loadNonRoot(&loaded_director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
156  EXPECT_TRUE(storage->loadLatestRoot(&loaded_images_root, Uptane::RepositoryType::Image()));
157  EXPECT_TRUE(storage->loadNonRoot(&loaded_images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
158  EXPECT_TRUE(
159  storage->loadNonRoot(&loaded_images_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
160  EXPECT_TRUE(storage->loadNonRoot(&loaded_images_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
161  EXPECT_EQ(director_root, loaded_director_root);
162  EXPECT_EQ(director_targets, loaded_director_targets);
163  EXPECT_EQ(images_root, loaded_images_root);
164  EXPECT_EQ(images_targets, loaded_images_targets);
165  EXPECT_EQ(images_timestamp, loaded_images_timestamp);
166  EXPECT_EQ(images_snapshot, loaded_images_snapshot);
167 
168  storage->clearNonRootMeta(Uptane::RepositoryType::Director());
169  storage->clearNonRootMeta(Uptane::RepositoryType::Image());
170  EXPECT_FALSE(
171  storage->loadNonRoot(&loaded_director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
172  EXPECT_FALSE(
173  storage->loadNonRoot(&loaded_images_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
174 }
175 
176 /* Load and store Uptane roots. */
177 TEST(storage, load_store_root) {
178  TemporaryDirectory temp_dir;
179  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
180 
181  Json::Value root_json;
182  root_json["_type"] = "Root";
183  root_json["consistent_snapshot"] = false;
184  root_json["expires"] = "2038-01-19T03:14:06Z";
185  root_json["keys"]["firstid"]["keytype"] = "ed25519";
186  root_json["keys"]["firstid"]["keyval"]["public"] = "firstval";
187  root_json["keys"]["secondid"]["keytype"] = "ed25519";
188  root_json["keys"]["secondid"]["keyval"]["public"] = "secondval";
189 
190  root_json["roles"]["root"]["threshold"] = 1;
191  root_json["roles"]["root"]["keyids"][0] = "firstid";
192  root_json["roles"]["snapshot"]["threshold"] = 1;
193  root_json["roles"]["snapshot"]["keyids"][0] = "firstid";
194  root_json["roles"]["targets"]["threshold"] = 1;
195  root_json["roles"]["targets"]["keyids"][0] = "firstid";
196  root_json["roles"]["timestamp"]["threshold"] = 1;
197  root_json["roles"]["timestamp"]["keyids"][0] = "firstid";
198 
199  Json::Value meta_root;
200  meta_root["signed"] = root_json;
201 
202  std::string loaded_root;
203 
204  storage->storeRoot(Utils::jsonToStr(meta_root), Uptane::RepositoryType::Director(), Uptane::Version(2));
205  EXPECT_TRUE(storage->loadRoot(&loaded_root, Uptane::RepositoryType::Director(), Uptane::Version(2)));
206  EXPECT_EQ(Utils::jsonToStr(meta_root), loaded_root);
207 
208  EXPECT_TRUE(storage->loadLatestRoot(&loaded_root, Uptane::RepositoryType::Director()));
209  EXPECT_EQ(Utils::jsonToStr(meta_root), loaded_root);
210 }
211 
212 /* Load and store the device ID. */
213 TEST(storage, load_store_deviceid) {
214  TemporaryDirectory temp_dir;
215  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
216 
217  storage->storeDeviceId("");
218  storage->storeDeviceId("device_id");
219 
220  std::string device_id;
221 
222  EXPECT_TRUE(storage->loadDeviceId(&device_id));
223 
224  EXPECT_EQ(device_id, "device_id");
225  storage->clearDeviceId();
226  EXPECT_FALSE(storage->loadDeviceId(nullptr));
227 }
228 
229 /* Load and store ECU serials.
230  * Preserve ECU ordering between store and load calls.
231  */
232 TEST(storage, load_store_ecu_serials) {
233  TemporaryDirectory temp_dir;
234  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
235 
236  storage->storeEcuSerials({{Uptane::EcuSerial("a"), Uptane::HardwareIdentifier("")}});
237  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
238  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
239  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
240  storage->storeEcuSerials(serials);
241 
242  EcuSerials serials_out;
243 
244  EXPECT_TRUE(storage->loadEcuSerials(&serials_out));
245 
246  EXPECT_EQ(serials, serials_out);
247  storage->clearEcuSerials();
248  EXPECT_FALSE(storage->loadEcuSerials(nullptr));
249 }
250 
251 /* Load and store a list of misconfigured ECUs. */
252 TEST(storage, load_store_misconfigured_ecus) {
253  TemporaryDirectory temp_dir;
254  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
255 
256  std::vector<MisconfiguredEcu> ecus;
257  ecus.push_back(MisconfiguredEcu(Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw"),
258  EcuState::kNotRegistered));
259 
260  storage->storeMisconfiguredEcus(ecus);
261 
262  std::vector<MisconfiguredEcu> ecus_out;
263 
264  EXPECT_TRUE(storage->loadMisconfiguredEcus(&ecus_out));
265 
266  EXPECT_EQ(ecus_out.size(), ecus.size());
267  EXPECT_EQ(ecus_out[0].serial, Uptane::EcuSerial("primary"));
268  EXPECT_EQ(ecus_out[0].hardware_id, Uptane::HardwareIdentifier("primary_hw"));
269  EXPECT_EQ(ecus_out[0].state, EcuState::kNotRegistered);
270 
271  storage->clearMisconfiguredEcus();
272  ecus_out.clear();
273  EXPECT_FALSE(storage->loadMisconfiguredEcus(&ecus_out));
274 }
275 
276 /* Load and store a flag indicating successful registration. */
277 TEST(storage, load_store_ecu_registered) {
278  TemporaryDirectory temp_dir;
279  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
280 
281  EXPECT_THROW(storage->storeEcuRegistered(), std::runtime_error);
282  storage->storeDeviceId("test");
283  storage->storeEcuRegistered();
284  storage->storeEcuRegistered();
285 
286  EXPECT_TRUE(storage->loadEcuRegistered());
287 
288  storage->clearEcuRegistered();
289  EXPECT_FALSE(storage->loadEcuRegistered());
290 }
291 
292 /* Load and store installed versions. */
293 TEST(storage, load_store_installed_versions) {
294  TemporaryDirectory temp_dir;
295  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
296 
297  // Test lazy primary installed version: primary ecu serial is not defined yet
298  const std::vector<Uptane::Hash> hashes = {
299  Uptane::Hash{Uptane::Hash::Type::kSha256, "2561"},
300  Uptane::Hash{Uptane::Hash::Type::kSha512, "5121"},
301  };
302  Uptane::EcuMap primary_ecu{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")}};
303  Uptane::Target t1{"update.bin", primary_ecu, hashes, 1, "corrid"};
304  Json::Value custom;
305  custom["version"] = 42;
306  custom["foo"] = "bar";
307  t1.updateCustom(custom);
308  storage->savePrimaryInstalledVersion(t1, InstalledVersionUpdateMode::kCurrent);
309  {
310  std::vector<Uptane::Target> log;
311  storage->loadPrimaryInstallationLog(&log, true);
312  EXPECT_EQ(log.size(), 1);
313  EXPECT_EQ(log[0].filename(), "update.bin");
314  }
315 
316  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
317  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
318  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
319  storage->storeEcuSerials(serials);
320 
321  {
322  boost::optional<Uptane::Target> current;
323  EXPECT_TRUE(storage->loadInstalledVersions("primary", &current, nullptr));
324  EXPECT_TRUE(!!current);
325  EXPECT_EQ(current->filename(), "update.bin");
326  EXPECT_EQ(current->sha256Hash(), "2561");
327  EXPECT_EQ(current->hashes(), hashes);
328  EXPECT_EQ(current->ecus(), primary_ecu);
329  EXPECT_EQ(current->correlation_id(), "corrid");
330  EXPECT_EQ(current->length(), 1);
331  EXPECT_EQ(current->custom_data()["foo"], "bar");
332  EXPECT_EQ(current->custom_data()["version"], 42);
333  }
334 
335  // Set t2 as a pending version
336  Uptane::Target t2{"update2.bin", primary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "2562"}}, 2};
337  storage->savePrimaryInstalledVersion(t2, InstalledVersionUpdateMode::kPending);
338 
339  {
340  boost::optional<Uptane::Target> pending;
341  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, &pending));
342  EXPECT_TRUE(!!pending);
343  EXPECT_EQ(pending->filename(), "update2.bin");
344  }
345 
346  // Set t3 as the new pending
347  Uptane::Target t3{"update3.bin", primary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "2563"}}, 3};
348  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kPending);
349 
350  {
351  boost::optional<Uptane::Target> pending;
352  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, &pending));
353  EXPECT_TRUE(!!pending);
354  EXPECT_EQ(pending->filename(), "update3.bin");
355  }
356 
357  // Set t3 as current: should replace the pending flag but not create a new
358  // version
359  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kCurrent);
360  {
361  boost::optional<Uptane::Target> current;
362  boost::optional<Uptane::Target> pending;
363  EXPECT_TRUE(storage->loadInstalledVersions("primary", &current, &pending));
364  EXPECT_TRUE(!!current);
365  EXPECT_EQ(current->filename(), "update3.bin");
366  EXPECT_FALSE(!!pending);
367 
368  std::vector<Uptane::Target> log;
369  storage->loadInstallationLog("primary", &log, true);
370  EXPECT_EQ(log.size(), 2);
371  EXPECT_EQ(log.back().filename(), "update3.bin");
372  }
373 
374  // Set t1 as current: the log should have grown even though we rolled back
375  {
376  storage->savePrimaryInstalledVersion(t1, InstalledVersionUpdateMode::kCurrent);
377  std::vector<Uptane::Target> log;
378  storage->loadInstallationLog("primary", &log, true);
379  EXPECT_EQ(log.size(), 3);
380  EXPECT_EQ(log.back().filename(), "update.bin");
381  }
382 
383  // Set t2 as the new pending and t3 as current afterwards: the pending flag
384  // should disappear
385  storage->savePrimaryInstalledVersion(t2, InstalledVersionUpdateMode::kPending);
386  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kCurrent);
387 
388  {
389  boost::optional<Uptane::Target> current;
390  boost::optional<Uptane::Target> pending;
391  EXPECT_TRUE(storage->loadInstalledVersions("primary", &current, &pending));
392  EXPECT_TRUE(!!current);
393  EXPECT_EQ(current->filename(), "update3.bin");
394  EXPECT_FALSE(!!pending);
395 
396  std::vector<Uptane::Target> log;
397  storage->loadInstallationLog("primary", &log, true);
398  EXPECT_EQ(log.size(), 4);
399  EXPECT_EQ(log.back().filename(), "update3.bin");
400  EXPECT_EQ(log[0].custom_data()["foo"], "bar");
401  }
402 
403  // Add a secondary installed version
404  Uptane::EcuMap secondary_ecu{{Uptane::EcuSerial("secondary1"), Uptane::HardwareIdentifier("secondary_hw")}};
405  Uptane::Target tsec{"secondary.bin", secondary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "256s"}}, 4};
406  storage->saveInstalledVersion("secondary_1", tsec, InstalledVersionUpdateMode::kCurrent);
407 
408  {
409  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, nullptr));
410  EXPECT_TRUE(storage->loadInstalledVersions("secondary_1", nullptr, nullptr));
411 
412  std::vector<Uptane::Target> log;
413  storage->loadInstallationLog("secondary_1", &log, true);
414  EXPECT_EQ(log.size(), 1);
415  EXPECT_EQ(log.back().filename(), "secondary.bin");
416  }
417 }
418 
419 /*
420  * Load and store an ecu installation result in an SQL database.
421  * Load and store a device installation result in an SQL database.
422  */
423 TEST(storage, load_store_installation_results) {
424  TemporaryDirectory temp_dir;
425  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
426 
427  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
428  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
429  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
430  storage->storeEcuSerials(serials);
431 
432  storage->saveEcuInstallationResult(Uptane::EcuSerial("secondary_2"), data::InstallationResult());
433  storage->saveEcuInstallationResult(Uptane::EcuSerial("primary"), data::InstallationResult());
434  storage->saveEcuInstallationResult(Uptane::EcuSerial("primary"),
436 
437  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> res;
438  EXPECT_TRUE(storage->loadEcuInstallationResults(&res));
439  EXPECT_EQ(res.size(), 2);
440  EXPECT_EQ(res.at(0).first.ToString(), "primary");
441  EXPECT_EQ(res.at(0).second.result_code.num_code, data::ResultCode::Numeric::kGeneralError);
442  EXPECT_EQ(res.at(1).first.ToString(), "secondary_2");
443  EXPECT_EQ(res.at(1).second.result_code.num_code, data::ResultCode::Numeric::kOk);
444 
445  storage->storeDeviceInstallationResult(data::InstallationResult(data::ResultCode::Numeric::kGeneralError, ""), "raw",
446  "corrid");
447 
448  data::InstallationResult dev_res;
449  std::string report;
450  std::string correlation_id;
451  EXPECT_TRUE(storage->loadDeviceInstallationResult(&dev_res, &report, &correlation_id));
452  EXPECT_EQ(dev_res.result_code.num_code, data::ResultCode::Numeric::kGeneralError);
453  EXPECT_EQ(report, "raw");
454  EXPECT_EQ(correlation_id, "corrid");
455 
456  storage->clearInstallationResults();
457  res.clear();
458  EXPECT_FALSE(storage->loadEcuInstallationResults(&res));
459  EXPECT_EQ(res.size(), 0);
460  EXPECT_FALSE(storage->loadDeviceInstallationResult(&dev_res, &report, &correlation_id));
461 }
462 
463 /* Load and store targets. */
464 TEST(storage, store_target) {
465  TemporaryDirectory temp_dir;
466  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
467 
468  Json::Value target_json;
469  target_json["hashes"]["sha256"] = "hash";
470  target_json["length"] = 2;
471  Uptane::Target target("some.deb", target_json);
472 
473  // write
474  {
475  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
476  const uint8_t wb[] = "ab";
477  fhandle->wfeed(wb, 1);
478  fhandle->wfeed(wb + 1, 1);
479  fhandle->wcommit();
480  }
481 
482  // read
483  {
484  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
485  uint8_t rb[3] = {0};
486  EXPECT_EQ(rhandle->rsize(), 2);
487  rhandle->rread(rb, 1);
488  rhandle->rread(rb + 1, 1);
489  rhandle->rclose();
490  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
491  }
492 
493  // write again
494  {
495  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
496  const uint8_t wb[] = "ab";
497  fhandle->wfeed(wb, 1);
498  fhandle->wfeed(wb + 1, 1);
499  fhandle->wcommit();
500  }
501 
502  // delete
503  {
504  storage->removeTargetFile(target.filename());
505  EXPECT_THROW(storage->openTargetFile(target), StorageTargetRHandle::ReadError);
506  EXPECT_THROW(storage->removeTargetFile(target.filename()), std::runtime_error);
507  }
508 
509  // write stream
510  {
511  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
512  std::stringstream("ab") >> *fhandle;
513  }
514 
515  // read stream
516  {
517  std::stringstream sstr;
518  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
519  sstr << *rhandle;
520  EXPECT_STREQ(sstr.str().c_str(), "ab");
521  }
522 }
523 
524 /*
525  * List targets currently in storage.
526  * Remove a target binary from storage.
527  */
528 TEST(storage, list_remove_targets) {
529  TemporaryDirectory temp_dir;
530  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
531 
532  Json::Value target_json;
533  target_json["hashes"]["sha256"] = "HASH";
534  target_json["length"] = 2;
535  Uptane::Target target("some.deb", target_json);
536 
537  auto tfs = storage->getTargetFiles();
538  EXPECT_EQ(tfs.size(), 0);
539 
540  // write
541  {
542  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
543  const uint8_t wb[] = "ab";
544  fhandle->wfeed(wb, 1);
545  fhandle->wfeed(wb + 1, 1);
546  fhandle->wcommit();
547  }
548 
549  tfs = storage->getTargetFiles();
550  ASSERT_EQ(tfs.size(), 1);
551 
552  auto tf = tfs.at(0);
553 
554  EXPECT_EQ(tf.filename(), "some.deb");
555  EXPECT_EQ(tf.length(), 2);
556  EXPECT_EQ(tf.hashes().size(), 1);
557  EXPECT_EQ(tf.hashes().at(0), Uptane::Hash(Uptane::Hash::Type::kSha256, "HASH"));
558 
559  // note: implementation specific
560  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "images" / "HASH"));
561 
562  storage->removeTargetFile(tf.filename());
563 
564  tfs = storage->getTargetFiles();
565  EXPECT_EQ(tfs.size(), 0);
566  EXPECT_FALSE(boost::filesystem::exists(temp_dir.Path() / "images" / "HASH"));
567 }
568 
569 TEST(storage, load_store_secondary_info) {
570  TemporaryDirectory temp_dir;
571  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
572 
573  // note: this can be done before the ecu is known
574  storage->saveSecondaryData(Uptane::EcuSerial("secondary_2"), "data2");
575 
576  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
577  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
578  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
579  storage->storeEcuSerials(serials);
580 
581  storage->saveSecondaryInfo(Uptane::EcuSerial("secondary_1"), "ip", PublicKey("key1", KeyType::kED25519));
582 
583  testing::internal::CaptureStdout();
584  storage->saveSecondaryInfo(Uptane::EcuSerial("primary"), "ip",
585  PublicKey("key0", KeyType::kRSA2048)); // should show an error
586  EXPECT_NE(std::string::npos, testing::internal::GetCapturedStdout().find("Can't save secondary"));
587 
588  std::vector<SecondaryInfo> sec_infos;
589  EXPECT_TRUE(storage->loadSecondariesInfo(&sec_infos));
590 
591  ASSERT_EQ(sec_infos.size(), 2);
592  EXPECT_EQ(sec_infos[0].serial.ToString(), "secondary_1");
593  EXPECT_EQ(sec_infos[0].hw_id.ToString(), "secondary_hw");
594  EXPECT_EQ(sec_infos[0].type, "ip");
595  EXPECT_EQ(sec_infos[0].pub_key.Value(), "key1");
596  EXPECT_EQ(sec_infos[0].pub_key.Type(), KeyType::kED25519);
597  EXPECT_EQ(sec_infos[1].pub_key.Type(), KeyType::kUnknown);
598  EXPECT_EQ(sec_infos[1].type, "");
599  EXPECT_EQ(sec_infos[1].extra, "data2");
600 
601  // test update of data
602  storage->saveSecondaryInfo(Uptane::EcuSerial("secondary_1"), "ip", PublicKey("key2", KeyType::kED25519));
603  storage->saveSecondaryData(Uptane::EcuSerial("secondary_1"), "data1");
604  EXPECT_TRUE(storage->loadSecondariesInfo(&sec_infos));
605 
606  ASSERT_EQ(sec_infos.size(), 2);
607  EXPECT_EQ(sec_infos[0].pub_key.Value(), "key2");
608  EXPECT_EQ(sec_infos[0].extra, "data1");
609 }
610 
611 TEST(storage, checksum) {
612  TemporaryDirectory temp_dir;
613  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
614 
615  Json::Value target_json1;
616  target_json1["hashes"]["sha256"] = "hash1";
617  target_json1["length"] = 2;
618  Uptane::Target target1("some.deb", target_json1);
619  Json::Value target_json2;
620  target_json2["length"] = 2;
621  target_json2["hashes"]["sha256"] = "hash2";
622  Uptane::Target target2("some.deb", target_json2);
623 
624  // write target1
625  {
626  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target1);
627  const uint8_t wb[] = "ab";
628  fhandle->wfeed(wb, 2);
629  fhandle->wcommit();
630  }
631 
632  // read target 1
633  {
634  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target1);
635  uint8_t rb[3] = {0};
636  EXPECT_EQ(rhandle->rsize(), 2);
637  rhandle->rread(rb, 2);
638  rhandle->rclose();
639  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
640  }
641 
642  // read target 2
643  { EXPECT_THROW(storage->openTargetFile(target2), StorageTargetRHandle::ReadError); }
644 }
645 
646 TEST(storage, partial) {
647  TemporaryDirectory temp_dir;
648  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
649 
650  Json::Value target_json;
651  target_json["hashes"]["sha256"] = "hash1";
652  target_json["length"] = 3;
653  Uptane::Target target("some.deb", target_json);
654 
655  // write partial target
656  {
657  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
658  const uint8_t wb[] = "a";
659  fhandle->wfeed(wb, 1);
660  fhandle->wcommit();
661  }
662 
663  // read and check partial target
664  {
665  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
666  uint8_t rb[2] = {0};
667  EXPECT_EQ(rhandle->rsize(), 1);
668  EXPECT_TRUE(rhandle->isPartial());
669  rhandle->rread(rb, 1);
670  rhandle->rclose();
671  EXPECT_STREQ(reinterpret_cast<char *>(rb), "a");
672  }
673 
674  // Append without committing, should commit in whandle destructor
675  {
676  std::unique_ptr<StorageTargetWHandle> whandle = storage->openTargetFile(target)->toWriteHandle();
677  const uint8_t wb[] = "b";
678  whandle->wfeed(wb, 1);
679  }
680 
681  // read and check partial target
682  {
683  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
684  uint8_t rb[3] = {0};
685  EXPECT_EQ(rhandle->rsize(), 2);
686  EXPECT_TRUE(rhandle->isPartial());
687  rhandle->rread(rb, 2);
688  rhandle->rclose();
689  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
690  }
691 
692  // Append partial
693  {
694  std::unique_ptr<StorageTargetWHandle> whandle = storage->openTargetFile(target)->toWriteHandle();
695  const uint8_t wb[] = "c";
696  whandle->wfeed(wb, 1);
697  whandle->wcommit();
698  }
699 
700  // Check full target
701  {
702  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
703  EXPECT_EQ(rhandle->rsize(), 3);
704  EXPECT_FALSE(rhandle->isPartial());
705  }
706 }
707 
708 /* Import keys and credentials from file into storage. */
709 TEST(storage, import_data) {
710  TemporaryDirectory temp_dir;
711  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
712  boost::filesystem::create_directories(temp_dir / "import");
713 
714  ImportConfig import_config;
715  import_config.base_path = temp_dir.Path() / "import";
716  import_config.uptane_private_key_path = BasedPath("private");
717  import_config.uptane_public_key_path = BasedPath("public");
718  import_config.tls_cacert_path = BasedPath("ca");
719  import_config.tls_clientcert_path = BasedPath("cert");
720  import_config.tls_pkey_path = BasedPath("pkey");
721 
722  Utils::writeFile(import_config.uptane_private_key_path.get(import_config.base_path).string(),
723  std::string("uptane_private_1"));
724  Utils::writeFile(import_config.uptane_public_key_path.get(import_config.base_path).string(),
725  std::string("uptane_public_1"));
726  Utils::writeFile(import_config.tls_cacert_path.get(import_config.base_path).string(), std::string("tls_cacert_1"));
727  Utils::writeFile(import_config.tls_clientcert_path.get(import_config.base_path).string(), std::string("tls_cert_1"));
728  Utils::writeFile(import_config.tls_pkey_path.get(import_config.base_path).string(), std::string("tls_pkey_1"));
729 
730  // Initially the storage is empty
731  EXPECT_FALSE(storage->loadPrimaryPublic(nullptr));
732  EXPECT_FALSE(storage->loadPrimaryPrivate(nullptr));
733  EXPECT_FALSE(storage->loadTlsCa(nullptr));
734  EXPECT_FALSE(storage->loadTlsCert(nullptr));
735  EXPECT_FALSE(storage->loadTlsPkey(nullptr));
736 
737  storage->importData(import_config);
738 
739  std::string primary_public;
740  std::string primary_private;
741  std::string tls_ca;
742  std::string tls_cert;
743  std::string tls_pkey;
744 
745  // the data has been imported
746  EXPECT_TRUE(storage->loadPrimaryPublic(&primary_public));
747  EXPECT_TRUE(storage->loadPrimaryPrivate(&primary_private));
748  EXPECT_TRUE(storage->loadTlsCa(&tls_ca));
749  EXPECT_TRUE(storage->loadTlsCert(&tls_cert));
750  EXPECT_TRUE(storage->loadTlsPkey(&tls_pkey));
751 
752  EXPECT_EQ(primary_private, "uptane_private_1");
753  EXPECT_EQ(primary_public, "uptane_public_1");
754  EXPECT_EQ(tls_ca, "tls_cacert_1");
755  EXPECT_EQ(tls_cert, "tls_cert_1");
756  EXPECT_EQ(tls_pkey, "tls_pkey_1");
757 
758  Utils::writeFile(import_config.uptane_private_key_path.get(import_config.base_path).string(),
759  std::string("uptane_private_2"));
760  Utils::writeFile(import_config.uptane_public_key_path.get(import_config.base_path).string(),
761  std::string("uptane_public_2"));
762  Utils::writeFile(import_config.tls_cacert_path.get(import_config.base_path).string(), std::string("tls_cacert_2"));
763  Utils::writeFile(import_config.tls_clientcert_path.get(import_config.base_path).string(), std::string("tls_cert_2"));
764  Utils::writeFile(import_config.tls_pkey_path.get(import_config.base_path).string(), std::string("tls_pkey_2"));
765 
766  storage->importData(import_config);
767 
768  EXPECT_TRUE(storage->loadPrimaryPublic(&primary_public));
769  EXPECT_TRUE(storage->loadPrimaryPrivate(&primary_private));
770  EXPECT_TRUE(storage->loadTlsCa(&tls_ca));
771  EXPECT_TRUE(storage->loadTlsCert(&tls_cert));
772  EXPECT_TRUE(storage->loadTlsPkey(&tls_pkey));
773 
774  // only root cert is being updated
775  EXPECT_EQ(primary_private, "uptane_private_1");
776  EXPECT_EQ(primary_public, "uptane_public_1");
777  EXPECT_EQ(tls_ca, "tls_cacert_2");
778  EXPECT_EQ(tls_cert, "tls_cert_1");
779  EXPECT_EQ(tls_pkey, "tls_pkey_1");
780 }
781 
782 #ifndef __NO_MAIN__
783 int main(int argc, char **argv) {
784  ::testing::InitGoogleTest(&argc, argv);
785  logger_init();
786  logger_set_threshold(boost::log::trivial::trace);
787 
788  std::cout << "Running tests for SQLStorage" << std::endl;
789  current_storage_type = StorageType::kSqlite;
790  int res_sql = RUN_ALL_TESTS();
791 
792  return res_sql; // 0 indicates success
793 }
794 #endif
data::ResultCode::Numeric::kGeneralError
Other error.
types.h
data::InstallationResult
Definition: types.h:182
Uptane::Version
Metadata version numbers.
Definition: tuf.h:116
BasedPath
Definition: utils.h:101
StorageConfig
Definition: storage_config.h:15
MisconfiguredEcu
Definition: invstorage.h:28
Uptane::HardwareIdentifier
Definition: tuf.h:143
Uptane::Hash
The hash of a file or TUF metadata.
Definition: tuf.h:209
Uptane::EcuSerial
Definition: tuf.h:174
PublicKey
Definition: crypto.h:26
TemporaryDirectory
Definition: utils.h:82
Uptane::Target
Definition: tuf.h:238
SQLStorage
Definition: sqlstorage.h:18
ImportConfig
Definition: storage_config.h:34
StorageTargetRHandle::ReadError
Definition: invstorage.h:63