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 image_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 image_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 image_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 image_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(image_root, Uptane::RepositoryType::Image(), Uptane::Version(1));
142  storage->storeNonRoot(image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
143  storage->storeNonRoot(image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
144  storage->storeNonRoot(image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
145 
146  std::string loaded_director_root;
147  std::string loaded_director_targets;
148  std::string loaded_image_root;
149  std::string loaded_image_targets;
150  std::string loaded_image_timestamp;
151  std::string loaded_image_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_image_root, Uptane::RepositoryType::Image()));
157  EXPECT_TRUE(storage->loadNonRoot(&loaded_image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
158  EXPECT_TRUE(
159  storage->loadNonRoot(&loaded_image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
160  EXPECT_TRUE(storage->loadNonRoot(&loaded_image_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(image_root, loaded_image_root);
164  EXPECT_EQ(image_targets, loaded_image_targets);
165  EXPECT_EQ(image_timestamp, loaded_image_timestamp);
166  EXPECT_EQ(image_snapshot, loaded_image_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_image_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_FALSE(storage->hasPendingInstall());
325  EXPECT_TRUE(!!current);
326  EXPECT_EQ(current->filename(), "update.bin");
327  EXPECT_EQ(current->sha256Hash(), "2561");
328  EXPECT_EQ(current->hashes(), hashes);
329  EXPECT_EQ(current->ecus(), primary_ecu);
330  EXPECT_EQ(current->correlation_id(), "corrid");
331  EXPECT_EQ(current->length(), 1);
332  EXPECT_EQ(current->custom_data()["foo"], "bar");
333  EXPECT_EQ(current->custom_data()["version"], 42);
334  }
335 
336  // Set t2 as a pending version
337  Uptane::Target t2{"update2.bin", primary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "2562"}}, 2};
338  storage->savePrimaryInstalledVersion(t2, InstalledVersionUpdateMode::kPending);
339 
340  {
341  boost::optional<Uptane::Target> pending;
342  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, &pending));
343  EXPECT_TRUE(!!pending);
344  EXPECT_TRUE(storage->hasPendingInstall());
345  EXPECT_EQ(pending->filename(), "update2.bin");
346  }
347 
348  // Set t3 as the new pending
349  Uptane::Target t3{"update3.bin", primary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "2563"}}, 3};
350  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kPending);
351 
352  {
353  boost::optional<Uptane::Target> pending;
354  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, &pending));
355  EXPECT_TRUE(!!pending);
356  EXPECT_TRUE(storage->hasPendingInstall());
357  EXPECT_EQ(pending->filename(), "update3.bin");
358  }
359 
360  // Set t3 as current: should replace the pending flag but not create a new
361  // version
362  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kCurrent);
363  {
364  boost::optional<Uptane::Target> current;
365  boost::optional<Uptane::Target> pending;
366  EXPECT_TRUE(storage->loadInstalledVersions("primary", &current, &pending));
367  EXPECT_TRUE(!!current);
368  EXPECT_EQ(current->filename(), "update3.bin");
369  EXPECT_FALSE(!!pending);
370  EXPECT_FALSE(storage->hasPendingInstall());
371 
372  std::vector<Uptane::Target> log;
373  storage->loadInstallationLog("primary", &log, true);
374  EXPECT_EQ(log.size(), 2);
375  EXPECT_EQ(log.back().filename(), "update3.bin");
376  }
377 
378  // Set t1 as current: the log should have grown even though we rolled back
379  {
380  storage->savePrimaryInstalledVersion(t1, InstalledVersionUpdateMode::kCurrent);
381  std::vector<Uptane::Target> log;
382  storage->loadInstallationLog("primary", &log, true);
383  EXPECT_EQ(log.size(), 3);
384  EXPECT_EQ(log.back().filename(), "update.bin");
385  EXPECT_FALSE(storage->hasPendingInstall());
386  }
387 
388  // Set t2 as the new pending and t3 as current afterwards: the pending flag
389  // should disappear
390  storage->savePrimaryInstalledVersion(t2, InstalledVersionUpdateMode::kPending);
391  storage->savePrimaryInstalledVersion(t3, InstalledVersionUpdateMode::kCurrent);
392 
393  {
394  boost::optional<Uptane::Target> current;
395  boost::optional<Uptane::Target> pending;
396  EXPECT_TRUE(storage->loadInstalledVersions("primary", &current, &pending));
397  EXPECT_TRUE(!!current);
398  EXPECT_EQ(current->filename(), "update3.bin");
399  EXPECT_FALSE(!!pending);
400  EXPECT_FALSE(storage->hasPendingInstall());
401 
402  std::vector<Uptane::Target> log;
403  storage->loadInstallationLog("primary", &log, true);
404  EXPECT_EQ(log.size(), 4);
405  EXPECT_EQ(log.back().filename(), "update3.bin");
406  EXPECT_EQ(log[0].custom_data()["foo"], "bar");
407  }
408 
409  // Add a secondary installed version
410  Uptane::EcuMap secondary_ecu{{Uptane::EcuSerial("secondary1"), Uptane::HardwareIdentifier("secondary_hw")}};
411  Uptane::Target tsec{"secondary.bin", secondary_ecu, {Uptane::Hash{Uptane::Hash::Type::kSha256, "256s"}}, 4};
412  storage->saveInstalledVersion("secondary_1", tsec, InstalledVersionUpdateMode::kCurrent);
413 
414  {
415  EXPECT_TRUE(storage->loadInstalledVersions("primary", nullptr, nullptr));
416  EXPECT_TRUE(storage->loadInstalledVersions("secondary_1", nullptr, nullptr));
417 
418  std::vector<Uptane::Target> log;
419  storage->loadInstallationLog("secondary_1", &log, true);
420  EXPECT_EQ(log.size(), 1);
421  EXPECT_EQ(log.back().filename(), "secondary.bin");
422  }
423 }
424 
425 /*
426  * Load and store an ecu installation result in an SQL database.
427  * Load and store a device installation result in an SQL database.
428  */
429 TEST(storage, load_store_installation_results) {
430  TemporaryDirectory temp_dir;
431  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
432 
433  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
434  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
435  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
436  storage->storeEcuSerials(serials);
437 
438  storage->saveEcuInstallationResult(Uptane::EcuSerial("secondary_2"), data::InstallationResult());
439  storage->saveEcuInstallationResult(Uptane::EcuSerial("primary"), data::InstallationResult());
440  storage->saveEcuInstallationResult(Uptane::EcuSerial("primary"),
442 
443  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> res;
444  EXPECT_TRUE(storage->loadEcuInstallationResults(&res));
445  EXPECT_EQ(res.size(), 2);
446  EXPECT_EQ(res.at(0).first.ToString(), "primary");
447  EXPECT_EQ(res.at(0).second.result_code.num_code, data::ResultCode::Numeric::kGeneralError);
448  EXPECT_EQ(res.at(1).first.ToString(), "secondary_2");
449  EXPECT_EQ(res.at(1).second.result_code.num_code, data::ResultCode::Numeric::kOk);
450 
451  storage->storeDeviceInstallationResult(data::InstallationResult(data::ResultCode::Numeric::kGeneralError, ""), "raw",
452  "corrid");
453 
454  data::InstallationResult dev_res;
455  std::string report;
456  std::string correlation_id;
457  EXPECT_TRUE(storage->loadDeviceInstallationResult(&dev_res, &report, &correlation_id));
458  EXPECT_EQ(dev_res.result_code.num_code, data::ResultCode::Numeric::kGeneralError);
459  EXPECT_EQ(report, "raw");
460  EXPECT_EQ(correlation_id, "corrid");
461 
462  storage->clearInstallationResults();
463  res.clear();
464  EXPECT_FALSE(storage->loadEcuInstallationResults(&res));
465  EXPECT_EQ(res.size(), 0);
466  EXPECT_FALSE(storage->loadDeviceInstallationResult(&dev_res, &report, &correlation_id));
467 }
468 
469 /* Load and store targets. */
470 TEST(storage, store_target) {
471  TemporaryDirectory temp_dir;
472  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
473 
474  Json::Value target_json;
475  target_json["hashes"]["sha256"] = "hash";
476  target_json["length"] = 2;
477  Uptane::Target target("some.deb", target_json);
478 
479  // write
480  {
481  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
482  const uint8_t wb[] = "ab";
483  fhandle->wfeed(wb, 1);
484  fhandle->wfeed(wb + 1, 1);
485  fhandle->wcommit();
486  }
487 
488  // read
489  {
490  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
491  uint8_t rb[3] = {0};
492  EXPECT_EQ(rhandle->rsize(), 2);
493  rhandle->rread(rb, 1);
494  rhandle->rread(rb + 1, 1);
495  rhandle->rclose();
496  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
497  }
498 
499  // write again
500  {
501  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
502  const uint8_t wb[] = "ab";
503  fhandle->wfeed(wb, 1);
504  fhandle->wfeed(wb + 1, 1);
505  fhandle->wcommit();
506  }
507 
508  // delete
509  {
510  storage->removeTargetFile(target.filename());
511  EXPECT_THROW(storage->openTargetFile(target), StorageTargetRHandle::ReadError);
512  EXPECT_THROW(storage->removeTargetFile(target.filename()), std::runtime_error);
513  }
514 
515  // write stream
516  {
517  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
518  std::stringstream("ab") >> *fhandle;
519  }
520 
521  // read stream
522  {
523  std::stringstream sstr;
524  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
525  sstr << *rhandle;
526  EXPECT_STREQ(sstr.str().c_str(), "ab");
527  }
528 }
529 
530 /*
531  * List targets currently in storage.
532  * Remove a target binary from storage.
533  */
534 TEST(storage, list_remove_targets) {
535  TemporaryDirectory temp_dir;
536  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
537 
538  Json::Value target_json;
539  target_json["hashes"]["sha256"] = "HASH";
540  target_json["length"] = 2;
541  Uptane::Target target("some.deb", target_json);
542 
543  auto tfs = storage->getTargetFiles();
544  EXPECT_EQ(tfs.size(), 0);
545 
546  // write
547  {
548  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
549  const uint8_t wb[] = "ab";
550  fhandle->wfeed(wb, 1);
551  fhandle->wfeed(wb + 1, 1);
552  fhandle->wcommit();
553  }
554 
555  tfs = storage->getTargetFiles();
556  ASSERT_EQ(tfs.size(), 1);
557 
558  auto tf = tfs.at(0);
559 
560  EXPECT_EQ(tf.filename(), "some.deb");
561  EXPECT_EQ(tf.length(), 2);
562  EXPECT_EQ(tf.hashes().size(), 1);
563  EXPECT_EQ(tf.hashes().at(0), Uptane::Hash(Uptane::Hash::Type::kSha256, "HASH"));
564 
565  // note: implementation specific
566  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "images" / "HASH"));
567 
568  storage->removeTargetFile(tf.filename());
569 
570  tfs = storage->getTargetFiles();
571  EXPECT_EQ(tfs.size(), 0);
572  EXPECT_FALSE(boost::filesystem::exists(temp_dir.Path() / "images" / "HASH"));
573 }
574 
575 TEST(storage, load_store_secondary_info) {
576  TemporaryDirectory temp_dir;
577  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
578 
579  // note: this can be done before the ecu is known
580  storage->saveSecondaryData(Uptane::EcuSerial("secondary_2"), "data2");
581 
582  EcuSerials serials{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")},
583  {Uptane::EcuSerial("secondary_1"), Uptane::HardwareIdentifier("secondary_hw")},
584  {Uptane::EcuSerial("secondary_2"), Uptane::HardwareIdentifier("secondary_hw")}};
585  storage->storeEcuSerials(serials);
586 
587  storage->saveSecondaryInfo(Uptane::EcuSerial("secondary_1"), "ip", PublicKey("key1", KeyType::kED25519));
588 
589  testing::internal::CaptureStdout();
590  storage->saveSecondaryInfo(Uptane::EcuSerial("primary"), "ip",
591  PublicKey("key0", KeyType::kRSA2048)); // should show an error
592  EXPECT_NE(std::string::npos, testing::internal::GetCapturedStdout().find("Can't save secondary"));
593 
594  std::vector<SecondaryInfo> sec_infos;
595  EXPECT_TRUE(storage->loadSecondariesInfo(&sec_infos));
596 
597  ASSERT_EQ(sec_infos.size(), 2);
598  EXPECT_EQ(sec_infos[0].serial.ToString(), "secondary_1");
599  EXPECT_EQ(sec_infos[0].hw_id.ToString(), "secondary_hw");
600  EXPECT_EQ(sec_infos[0].type, "ip");
601  EXPECT_EQ(sec_infos[0].pub_key.Value(), "key1");
602  EXPECT_EQ(sec_infos[0].pub_key.Type(), KeyType::kED25519);
603  EXPECT_EQ(sec_infos[1].pub_key.Type(), KeyType::kUnknown);
604  EXPECT_EQ(sec_infos[1].type, "");
605  EXPECT_EQ(sec_infos[1].extra, "data2");
606 
607  // test update of data
608  storage->saveSecondaryInfo(Uptane::EcuSerial("secondary_1"), "ip", PublicKey("key2", KeyType::kED25519));
609  storage->saveSecondaryData(Uptane::EcuSerial("secondary_1"), "data1");
610  EXPECT_TRUE(storage->loadSecondariesInfo(&sec_infos));
611 
612  ASSERT_EQ(sec_infos.size(), 2);
613  EXPECT_EQ(sec_infos[0].pub_key.Value(), "key2");
614  EXPECT_EQ(sec_infos[0].extra, "data1");
615 }
616 
617 TEST(storage, checksum) {
618  TemporaryDirectory temp_dir;
619  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
620 
621  Json::Value target_json1;
622  target_json1["hashes"]["sha256"] = "hash1";
623  target_json1["length"] = 2;
624  Uptane::Target target1("some.deb", target_json1);
625  Json::Value target_json2;
626  target_json2["length"] = 2;
627  target_json2["hashes"]["sha256"] = "hash2";
628  Uptane::Target target2("some.deb", target_json2);
629 
630  // write target1
631  {
632  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target1);
633  const uint8_t wb[] = "ab";
634  fhandle->wfeed(wb, 2);
635  fhandle->wcommit();
636  }
637 
638  // read target 1
639  {
640  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target1);
641  uint8_t rb[3] = {0};
642  EXPECT_EQ(rhandle->rsize(), 2);
643  rhandle->rread(rb, 2);
644  rhandle->rclose();
645  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
646  }
647 
648  // read target 2
649  { EXPECT_THROW(storage->openTargetFile(target2), StorageTargetRHandle::ReadError); }
650 }
651 
652 TEST(storage, partial) {
653  TemporaryDirectory temp_dir;
654  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
655 
656  Json::Value target_json;
657  target_json["hashes"]["sha256"] = "hash1";
658  target_json["length"] = 3;
659  Uptane::Target target("some.deb", target_json);
660 
661  // write partial target
662  {
663  std::unique_ptr<StorageTargetWHandle> fhandle = storage->allocateTargetFile(target);
664  const uint8_t wb[] = "a";
665  fhandle->wfeed(wb, 1);
666  fhandle->wcommit();
667  }
668 
669  // read and check partial target
670  {
671  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
672  uint8_t rb[2] = {0};
673  EXPECT_EQ(rhandle->rsize(), 1);
674  EXPECT_TRUE(rhandle->isPartial());
675  rhandle->rread(rb, 1);
676  rhandle->rclose();
677  EXPECT_STREQ(reinterpret_cast<char *>(rb), "a");
678  }
679 
680  // Append without committing, should commit in whandle destructor
681  {
682  std::unique_ptr<StorageTargetWHandle> whandle = storage->openTargetFile(target)->toWriteHandle();
683  const uint8_t wb[] = "b";
684  whandle->wfeed(wb, 1);
685  }
686 
687  // read and check partial target
688  {
689  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
690  uint8_t rb[3] = {0};
691  EXPECT_EQ(rhandle->rsize(), 2);
692  EXPECT_TRUE(rhandle->isPartial());
693  rhandle->rread(rb, 2);
694  rhandle->rclose();
695  EXPECT_STREQ(reinterpret_cast<char *>(rb), "ab");
696  }
697 
698  // Append partial
699  {
700  std::unique_ptr<StorageTargetWHandle> whandle = storage->openTargetFile(target)->toWriteHandle();
701  const uint8_t wb[] = "c";
702  whandle->wfeed(wb, 1);
703  whandle->wcommit();
704  }
705 
706  // Check full target
707  {
708  std::unique_ptr<StorageTargetRHandle> rhandle = storage->openTargetFile(target);
709  EXPECT_EQ(rhandle->rsize(), 3);
710  EXPECT_FALSE(rhandle->isPartial());
711  }
712 }
713 
714 /* Import keys and credentials from file into storage. */
715 TEST(storage, import_data) {
716  TemporaryDirectory temp_dir;
717  std::unique_ptr<INvStorage> storage = Storage(temp_dir.Path());
718  boost::filesystem::create_directories(temp_dir / "import");
719 
720  ImportConfig import_config;
721  import_config.base_path = temp_dir.Path() / "import";
722  import_config.uptane_private_key_path = BasedPath("private");
723  import_config.uptane_public_key_path = BasedPath("public");
724  import_config.tls_cacert_path = BasedPath("ca");
725  import_config.tls_clientcert_path = BasedPath("cert");
726  import_config.tls_pkey_path = BasedPath("pkey");
727 
728  Utils::writeFile(import_config.uptane_private_key_path.get(import_config.base_path).string(),
729  std::string("uptane_private_1"));
730  Utils::writeFile(import_config.uptane_public_key_path.get(import_config.base_path).string(),
731  std::string("uptane_public_1"));
732  Utils::writeFile(import_config.tls_cacert_path.get(import_config.base_path).string(), std::string("tls_cacert_1"));
733  Utils::writeFile(import_config.tls_clientcert_path.get(import_config.base_path).string(), std::string("tls_cert_1"));
734  Utils::writeFile(import_config.tls_pkey_path.get(import_config.base_path).string(), std::string("tls_pkey_1"));
735 
736  // Initially the storage is empty
737  EXPECT_FALSE(storage->loadPrimaryPublic(nullptr));
738  EXPECT_FALSE(storage->loadPrimaryPrivate(nullptr));
739  EXPECT_FALSE(storage->loadTlsCa(nullptr));
740  EXPECT_FALSE(storage->loadTlsCert(nullptr));
741  EXPECT_FALSE(storage->loadTlsPkey(nullptr));
742 
743  storage->importData(import_config);
744 
745  std::string primary_public;
746  std::string primary_private;
747  std::string tls_ca;
748  std::string tls_cert;
749  std::string tls_pkey;
750 
751  // the data has been imported
752  EXPECT_TRUE(storage->loadPrimaryPublic(&primary_public));
753  EXPECT_TRUE(storage->loadPrimaryPrivate(&primary_private));
754  EXPECT_TRUE(storage->loadTlsCa(&tls_ca));
755  EXPECT_TRUE(storage->loadTlsCert(&tls_cert));
756  EXPECT_TRUE(storage->loadTlsPkey(&tls_pkey));
757 
758  EXPECT_EQ(primary_private, "uptane_private_1");
759  EXPECT_EQ(primary_public, "uptane_public_1");
760  EXPECT_EQ(tls_ca, "tls_cacert_1");
761  EXPECT_EQ(tls_cert, "tls_cert_1");
762  EXPECT_EQ(tls_pkey, "tls_pkey_1");
763 
764  Utils::writeFile(import_config.uptane_private_key_path.get(import_config.base_path).string(),
765  std::string("uptane_private_2"));
766  Utils::writeFile(import_config.uptane_public_key_path.get(import_config.base_path).string(),
767  std::string("uptane_public_2"));
768  Utils::writeFile(import_config.tls_cacert_path.get(import_config.base_path).string(), std::string("tls_cacert_2"));
769  Utils::writeFile(import_config.tls_clientcert_path.get(import_config.base_path).string(), std::string("tls_cert_2"));
770  Utils::writeFile(import_config.tls_pkey_path.get(import_config.base_path).string(), std::string("tls_pkey_2"));
771 
772  storage->importData(import_config);
773 
774  EXPECT_TRUE(storage->loadPrimaryPublic(&primary_public));
775  EXPECT_TRUE(storage->loadPrimaryPrivate(&primary_private));
776  EXPECT_TRUE(storage->loadTlsCa(&tls_ca));
777  EXPECT_TRUE(storage->loadTlsCert(&tls_cert));
778  EXPECT_TRUE(storage->loadTlsPkey(&tls_pkey));
779 
780  // only root cert is being updated
781  EXPECT_EQ(primary_private, "uptane_private_1");
782  EXPECT_EQ(primary_public, "uptane_public_1");
783  EXPECT_EQ(tls_ca, "tls_cacert_2");
784  EXPECT_EQ(tls_cert, "tls_cert_1");
785  EXPECT_EQ(tls_pkey, "tls_pkey_1");
786 }
787 
788 #ifndef __NO_MAIN__
789 int main(int argc, char **argv) {
790  ::testing::InitGoogleTest(&argc, argv);
791  logger_init();
792  logger_set_threshold(boost::log::trivial::trace);
793 
794  std::cout << "Running tests for SQLStorage" << std::endl;
795  current_storage_type = StorageType::kSqlite;
796  int res_sql = RUN_ALL_TESTS();
797 
798  return res_sql; // 0 indicates success
799 }
800 #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