Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
uptane_test.cc
1 #include <gmock/gmock.h>
2 #include <gtest/gtest.h>
3 
4 #include <unistd.h>
5 
6 #include <algorithm>
7 #include <fstream>
8 #include <iostream>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include <boost/filesystem.hpp>
14 #include "json/json.h"
15 
16 #include "crypto/p11engine.h"
17 #include "httpfake.h"
18 #include "primary/initializer.h"
19 #include "primary/sotauptaneclient.h"
20 #include "storage/fsstorage_read.h"
21 #include "storage/invstorage.h"
22 #include "test_utils.h"
23 #include "uptane/secondaryinterface.h"
24 #include "uptane/tuf.h"
25 #include "uptane/uptanerepository.h"
26 #include "uptane_test_common.h"
27 #include "utilities/utils.h"
28 
29 #ifdef BUILD_P11
30 #ifndef TEST_PKCS11_MODULE_PATH
31 #define TEST_PKCS11_MODULE_PATH "/usr/local/softhsm/libsofthsm2.so"
32 #endif
33 #endif
34 
35 static Config config_common() {
36  Config config;
37  config.uptane.key_type = KeyType::kED25519;
38  return config;
39 }
40 
41 TEST(Uptane, Verify) {
42  TemporaryDirectory temp_dir;
43  auto http = std::make_shared<HttpFake>(temp_dir.Path());
44  Config config = config_common();
45  config.uptane.director_server = http->tls_server + "/director";
46  config.uptane.repo_server = http->tls_server + "/repo";
47 
48  config.storage.path = temp_dir.Path();
49  auto storage = INvStorage::newStorage(config.storage);
50  HttpResponse response = http->get(http->tls_server + "/director/root.json", HttpInterface::kNoLimit);
51  Uptane::Root root(Uptane::Root::Policy::kAcceptAll);
52  Uptane::Root(Uptane::RepositoryType::Director(), response.getJson(), root);
53 }
54 
55 /* Throw an exception if a TUF root is unsigned. */
56 TEST(Uptane, VerifyDataBad) {
57  TemporaryDirectory temp_dir;
58  auto http = std::make_shared<HttpFake>(temp_dir.Path());
59  Config config = config_common();
60  config.uptane.director_server = http->tls_server + "/director";
61  config.uptane.repo_server = http->tls_server + "/repo";
62 
63  config.storage.path = temp_dir.Path();
64  auto storage = INvStorage::newStorage(config.storage);
65  Json::Value data_json = http->get(http->tls_server + "/director/root.json", HttpInterface::kNoLimit).getJson();
66  data_json.removeMember("signatures");
67 
68  Uptane::Root root(Uptane::Root::Policy::kAcceptAll);
69  EXPECT_THROW(Uptane::Root(Uptane::RepositoryType::Director(), data_json, root), Uptane::UnmetThreshold);
70 }
71 
72 /* Throw an exception if a TUF root has unknown signature types. */
73 TEST(Uptane, VerifyDataUnknownType) {
74  TemporaryDirectory temp_dir;
75  auto http = std::make_shared<HttpFake>(temp_dir.Path());
76  Config config = config_common();
77  config.uptane.director_server = http->tls_server + "/director";
78  config.uptane.repo_server = http->tls_server + "/repo";
79 
80  config.storage.path = temp_dir.Path();
81  auto storage = INvStorage::newStorage(config.storage);
82  Json::Value data_json = http->get(http->tls_server + "/director/root.json", HttpInterface::kNoLimit).getJson();
83  data_json["signatures"][0]["method"] = "badsignature";
84  data_json["signatures"][1]["method"] = "badsignature";
85 
86  Uptane::Root root(Uptane::Root::Policy::kAcceptAll);
87  EXPECT_THROW(Uptane::Root(Uptane::RepositoryType::Director(), data_json, root), Uptane::SecurityException);
88 }
89 
90 /* Throw an exception if a TUF root has invalid key IDs. */
91 TEST(Uptane, VerifyDataBadKeyId) {
92  TemporaryDirectory temp_dir;
93  auto http = std::make_shared<HttpFake>(temp_dir.Path());
94  Config config = config_common();
95  config.uptane.director_server = http->tls_server + "/director";
96  config.uptane.repo_server = http->tls_server + "/repo";
97 
98  config.storage.path = temp_dir.Path();
99  auto storage = INvStorage::newStorage(config.storage);
100  Json::Value data_json = http->get(http->tls_server + "/director/root.json", HttpInterface::kNoLimit).getJson();
101 
102  data_json["signatures"][0]["keyid"] = "badkeyid";
103 
104  Uptane::Root root(Uptane::Root::Policy::kAcceptAll);
105  EXPECT_THROW(Uptane::Root(Uptane::RepositoryType::Director(), data_json, root), Uptane::BadKeyId);
106 }
107 
108 /* Throw an exception if a TUF root signature threshold is invalid. */
109 TEST(Uptane, VerifyDataBadThreshold) {
110  TemporaryDirectory temp_dir;
111  auto http = std::make_shared<HttpFake>(temp_dir.Path());
112  Config config = config_common();
113  config.uptane.director_server = http->tls_server + "/director";
114  config.uptane.repo_server = http->tls_server + "/repo";
115 
116  config.storage.path = temp_dir.Path();
117  auto storage = INvStorage::newStorage(config.storage);
118  Json::Value data_json = http->get(http->tls_server + "/director/root.json", HttpInterface::kNoLimit).getJson();
119  data_json["signed"]["roles"]["root"]["threshold"] = -1;
120  try {
121  Uptane::Root root(Uptane::Root::Policy::kAcceptAll);
122  Uptane::Root(Uptane::RepositoryType::Director(), data_json, root);
123  FAIL() << "Illegal threshold should have thrown an error.";
124  } catch (const Uptane::IllegalThreshold &ex) {
125  } catch (const Uptane::UnmetThreshold &ex) {
126  }
127 }
128 
129 /* Get manifest from primary.
130  * Get manifest from secondaries. */
131 TEST(Uptane, AssembleManifestGood) {
132  TemporaryDirectory temp_dir;
133  auto http = std::make_shared<HttpFake>(temp_dir.Path());
134  Config config = config_common();
135  config.storage.path = temp_dir.Path();
136  boost::filesystem::copy_file("tests/test_data/cred.zip", (temp_dir / "cred.zip").string());
137  boost::filesystem::copy_file("tests/test_data/firmware.txt", (temp_dir / "firmware.txt").string());
138  boost::filesystem::copy_file("tests/test_data/firmware_name.txt", (temp_dir / "firmware_name.txt").string());
139  config.provision.provision_path = temp_dir / "cred.zip";
140  config.provision.mode = ProvisionMode::kSharedCred;
141  config.uptane.director_server = http->tls_server + "/director";
142  config.uptane.repo_server = http->tls_server + "/repo";
143  config.provision.primary_ecu_serial = "testecuserial";
144  config.pacman.type = PACKAGE_MANAGER_NONE;
145  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
146 
147  auto storage = INvStorage::newStorage(config.storage);
148  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
149  EXPECT_NO_THROW(sota_client->initialize());
150 
151  Json::Value manifest = sota_client->AssembleManifest()["ecu_version_manifests"];
152  EXPECT_EQ(manifest.size(), 2);
153  EXPECT_EQ(manifest["testecuserial"]["signed"]["ecu_serial"].asString(), config.provision.primary_ecu_serial);
154  EXPECT_EQ(manifest["secondary_ecu_serial"]["signed"]["ecu_serial"].asString(), "secondary_ecu_serial");
155  // Manifest should not have an installation result yet.
156  EXPECT_FALSE(manifest["testecuserial"]["signed"].isMember("custom"));
157  EXPECT_FALSE(manifest["secondary_ecu_serial"]["signed"].isMember("custom"));
158 
159  std::string counter_str = manifest["testecuserial"]["signed"]["report_counter"].asString();
160  int64_t primary_ecu_report_counter = std::stoll(counter_str);
161  Json::Value manifest2 = sota_client->AssembleManifest()["ecu_version_manifests"];
162  std::string counter_str2 = manifest2["testecuserial"]["signed"]["report_counter"].asString();
163  int64_t primary_ecu_report_counter2 = std::stoll(counter_str2);
164  EXPECT_EQ(primary_ecu_report_counter2, primary_ecu_report_counter + 1);
165 }
166 
167 /* Bad signatures are ignored when assembling the manifest. */
168 TEST(Uptane, AssembleManifestBad) {
169  TemporaryDirectory temp_dir;
170  auto http = std::make_shared<HttpFake>(temp_dir.Path());
171  Config config = config_common();
172  config.storage.path = temp_dir.Path();
173  boost::filesystem::copy_file("tests/test_data/cred.zip", (temp_dir / "cred.zip").string());
174  boost::filesystem::copy_file("tests/test_data/firmware.txt", (temp_dir / "firmware.txt").string());
175  boost::filesystem::copy_file("tests/test_data/firmware_name.txt", (temp_dir / "firmware_name.txt").string());
176  config.provision.provision_path = temp_dir / "cred.zip";
177  config.provision.mode = ProvisionMode::kSharedCred;
178  config.uptane.director_server = http->tls_server + "/director";
179  config.uptane.repo_server = http->tls_server + "/repo";
180  config.provision.primary_ecu_serial = "testecuserial";
181  config.pacman.type = PACKAGE_MANAGER_NONE;
183  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
184 
185  /* Overwrite the secondary's keys on disk. */
186  std::string private_key, public_key;
187  ASSERT_TRUE(Crypto::generateKeyPair(ecu_config.key_type, &public_key, &private_key));
188  Utils::writeFile(ecu_config.full_client_dir / ecu_config.ecu_private_key, private_key);
189  public_key = Utils::readFile("tests/test_data/public.key");
190  Utils::writeFile(ecu_config.full_client_dir / ecu_config.ecu_public_key, public_key);
191 
192  auto storage = INvStorage::newStorage(config.storage);
193  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
194  EXPECT_NO_THROW(sota_client->initialize());
195 
196  Json::Value manifest = sota_client->AssembleManifest()["ecu_version_manifests"];
197  EXPECT_EQ(manifest.size(), 1);
198  EXPECT_EQ(manifest["testecuserial"]["signed"]["ecu_serial"].asString(), config.provision.primary_ecu_serial);
199  // Manifest should not have an installation result yet.
200  EXPECT_FALSE(manifest["testecuserial"]["signed"].isMember("custom"));
201  EXPECT_FALSE(manifest["secondary_ecu_serial"]["signed"].isMember("custom"));
202 }
203 
204 /* Get manifest from primary.
205  * Get manifest from secondaries.
206  * Send manifest to the server. */
207 TEST(Uptane, PutManifest) {
208  TemporaryDirectory temp_dir;
209  auto http = std::make_shared<HttpFake>(temp_dir.Path());
210  Config config = config_common();
211  config.storage.path = temp_dir.Path();
212  boost::filesystem::copy_file("tests/test_data/cred.zip", (temp_dir / "cred.zip").string());
213  boost::filesystem::copy_file("tests/test_data/firmware.txt", (temp_dir / "firmware.txt").string());
214  boost::filesystem::copy_file("tests/test_data/firmware_name.txt", (temp_dir / "firmware_name.txt").string());
215  config.provision.provision_path = temp_dir / "cred.zip";
216  config.provision.mode = ProvisionMode::kSharedCred;
217  config.uptane.director_server = http->tls_server + "/director";
218  config.uptane.repo_server = http->tls_server + "/repo";
219  config.provision.primary_ecu_serial = "testecuserial";
220  config.pacman.type = PACKAGE_MANAGER_NONE;
221  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
222 
223  auto storage = INvStorage::newStorage(config.storage);
224 
225  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
226  EXPECT_NO_THROW(sota_client->initialize());
227  EXPECT_TRUE(sota_client->putManifestSimple());
228 
229  Json::Value json = http->last_manifest;
230 
231  EXPECT_EQ(json["signatures"].size(), 1u);
232  EXPECT_EQ(json["signed"]["primary_ecu_serial"].asString(), "testecuserial");
233  EXPECT_EQ(
234  json["signed"]["ecu_version_manifests"]["testecuserial"]["signed"]["installed_image"]["filepath"].asString(),
235  "unknown");
236  EXPECT_EQ(json["signed"]["ecu_version_manifests"].size(), 2u);
237  EXPECT_EQ(json["signed"]["ecu_version_manifests"]["secondary_ecu_serial"]["signed"]["ecu_serial"].asString(),
238  "secondary_ecu_serial");
239  EXPECT_EQ(json["signed"]["ecu_version_manifests"]["secondary_ecu_serial"]["signed"]["installed_image"]["filepath"]
240  .asString(),
241  "test-package");
242 }
243 
244 class HttpPutManifestFail : public HttpFake {
245  public:
246  HttpPutManifestFail(const boost::filesystem::path &test_dir_in, std::string flavor = "")
247  : HttpFake(test_dir_in, flavor) {}
248  HttpResponse put(const std::string &url, const Json::Value &data) override {
249  (void)data;
250  return HttpResponse(url, 504, CURLE_OK, "");
251  }
252 };
253 
254 int num_events_PutManifestError = 0;
255 void process_events_PutManifestError(const std::shared_ptr<event::BaseEvent> &event) {
256  std::cout << event->variant << "\n";
257  if (event->variant == "PutManifestComplete") {
258  EXPECT_FALSE(std::static_pointer_cast<event::PutManifestComplete>(event)->success);
259  num_events_PutManifestError++;
260  }
261 }
262 
263 /*
264  * Send PutManifestComplete event if send is unsuccessful
265  */
266 TEST(Uptane, PutManifestError) {
267  TemporaryDirectory temp_dir;
268  auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path());
269 
270  Config conf("tests/config/basic.toml");
271  conf.storage.path = temp_dir.Path();
272 
273  auto storage = INvStorage::newStorage(conf.storage);
274  auto events_channel = std::make_shared<event::Channel>();
275  std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_PutManifestError;
276  events_channel->connect(f_cb);
277  num_events_PutManifestError = 0;
278  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http, events_channel);
279  EXPECT_NO_THROW(sota_client->initialize());
280  auto result = sota_client->putManifest();
281  EXPECT_FALSE(result);
282  EXPECT_EQ(num_events_PutManifestError, 1);
283 }
284 
285 /*
286  * Verify that failing to send the manifest will not prevent checking for
287  * updates (which is the only way to recover if something goes wrong with
288  * sending the manifest).
289  */
290 TEST(Uptane, FetchMetaFail) {
291  TemporaryDirectory temp_dir;
292  auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path(), "noupdates");
293 
294  Config conf("tests/config/basic.toml");
295  conf.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
296  conf.provision.primary_ecu_hardware_id = "primary_hw";
297  conf.uptane.director_server = http->tls_server + "/director";
298  conf.uptane.repo_server = http->tls_server + "/repo";
299  conf.storage.path = temp_dir.Path();
300  conf.tls.server = http->tls_server;
301 
302  auto storage = INvStorage::newStorage(conf.storage);
303  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
304 
305  EXPECT_NO_THROW(up->initialize());
306  result::UpdateCheck result = up->fetchMeta();
307  EXPECT_EQ(result.status, result::UpdateStatus::kNoUpdatesAvailable);
308 }
309 
310 unsigned int num_events_InstallTarget = 0;
311 unsigned int num_events_AllInstalls = 0;
312 void process_events_Install(const std::shared_ptr<event::BaseEvent> &event) {
313  if (event->variant == "InstallTargetComplete") {
314  auto concrete_event = std::static_pointer_cast<event::InstallTargetComplete>(event);
315  if (num_events_InstallTarget <= 1) {
316  EXPECT_TRUE(concrete_event->success);
317  } else {
318  EXPECT_FALSE(concrete_event->success);
319  }
320  num_events_InstallTarget++;
321  }
322  if (event->variant == "AllInstallsComplete") {
323  auto concrete_event = std::static_pointer_cast<event::AllInstallsComplete>(event);
324  if (num_events_AllInstalls == 0) {
325  EXPECT_TRUE(concrete_event->result.dev_report.isSuccess());
326  } else {
327  EXPECT_FALSE(concrete_event->result.dev_report.isSuccess());
328  EXPECT_EQ(concrete_event->result.dev_report.result_code, data::ResultCode::Numeric::kAlreadyProcessed);
329  }
330  num_events_AllInstalls++;
331  }
332 }
333 
334 /*
335  * Verify successful installation of a package.
336  *
337  * Identify ECU for each target.
338  * Check if there are updates to install for the primary.
339  * Install a binary update on the primary.
340  * Store installation result for primary.
341  * Store installation result for device.
342  * Check if an update is already installed.
343  */
344 TEST(Uptane, InstallFakeGood) {
345  Config conf("tests/config/basic.toml");
346  TemporaryDirectory temp_dir;
347  auto http = std::make_shared<HttpFake>(temp_dir.Path(), "hasupdates");
348  conf.uptane.director_server = http->tls_server + "director";
349  conf.uptane.repo_server = http->tls_server + "repo";
350  conf.pacman.type = PACKAGE_MANAGER_NONE;
351  conf.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
352  conf.provision.primary_ecu_hardware_id = "primary_hw";
353  conf.storage.path = temp_dir.Path();
354  conf.tls.server = http->tls_server;
355  UptaneTestCommon::addDefaultSecondary(conf, temp_dir, "secondary_ecu_serial", "secondary_hw");
356  conf.postUpdateValues();
357 
358  auto storage = INvStorage::newStorage(conf.storage);
359  auto events_channel = std::make_shared<event::Channel>();
360  std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
361  events_channel->connect(f_cb);
362  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http, events_channel);
363  EXPECT_NO_THROW(up->initialize());
364 
365  result::UpdateCheck update_result = up->fetchMeta();
366  EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
367  result::Download download_result = up->downloadImages(update_result.updates);
368  EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
369  result::Install install_result1 = up->uptaneInstall(download_result.updates);
370  EXPECT_TRUE(install_result1.dev_report.isSuccess());
371  EXPECT_EQ(install_result1.dev_report.result_code, data::ResultCode::Numeric::kOk);
372 
373  // Make sure operation_result and filepath were correctly written and formatted.
374  Json::Value manifest = up->AssembleManifest();
375  EXPECT_EQ(manifest["ecu_version_manifests"]["CA:FE:A6:D2:84:9D"]["signed"]["installed_image"]["filepath"].asString(),
376  "primary_firmware.txt");
377  EXPECT_EQ(
378  manifest["ecu_version_manifests"]["secondary_ecu_serial"]["signed"]["installed_image"]["filepath"].asString(),
379  "secondary_firmware.txt");
380 
381  EXPECT_EQ(num_events_InstallTarget, 2);
382  EXPECT_EQ(num_events_AllInstalls, 1);
383  Json::Value installation_report = manifest["installation_report"]["report"];
384  EXPECT_EQ(installation_report["result"]["success"].asBool(), true);
385  EXPECT_EQ(installation_report["result"]["code"].asString(), "OK");
386  EXPECT_EQ(installation_report["items"][0]["ecu"].asString(), "CA:FE:A6:D2:84:9D");
387  EXPECT_EQ(installation_report["items"][0]["result"]["success"].asBool(), true);
388  EXPECT_EQ(installation_report["items"][0]["result"]["code"].asString(), "OK");
389  EXPECT_EQ(installation_report["items"][1]["ecu"].asString(), "secondary_ecu_serial");
390  EXPECT_EQ(installation_report["items"][1]["result"]["success"].asBool(), true);
391  EXPECT_EQ(installation_report["items"][1]["result"]["code"].asString(), "OK");
392 
393  // second install
394  result::Install install_result2 = up->uptaneInstall(download_result.updates);
395  EXPECT_FALSE(install_result2.dev_report.isSuccess());
396  EXPECT_EQ(install_result2.dev_report.result_code, data::ResultCode::Numeric::kAlreadyProcessed);
397  EXPECT_EQ(num_events_InstallTarget, 2);
398  EXPECT_EQ(num_events_AllInstalls, 2);
399  manifest = up->AssembleManifest();
400  installation_report = manifest["installation_report"]["report"];
401  EXPECT_EQ(installation_report["result"]["success"].asBool(), false);
402 }
403 
404 /*
405  * Verify that installation will fail if the underlying data does not match the
406  * target.
407  */
408 TEST(Uptane, InstallFakeBad) {
409  Config conf("tests/config/basic.toml");
410  TemporaryDirectory temp_dir;
411  auto http = std::make_shared<HttpFake>(temp_dir.Path(), "hasupdates");
412  conf.uptane.director_server = http->tls_server + "director";
413  conf.uptane.repo_server = http->tls_server + "repo";
414  conf.pacman.type = PACKAGE_MANAGER_NONE;
415  conf.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
416  conf.provision.primary_ecu_hardware_id = "primary_hw";
417  conf.storage.path = temp_dir.Path();
418  conf.tls.server = http->tls_server;
419  UptaneTestCommon::addDefaultSecondary(conf, temp_dir, "secondary_ecu_serial", "secondary_hw");
420  conf.postUpdateValues();
421 
422  auto storage = INvStorage::newStorage(conf.storage);
423  std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
424  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
425  EXPECT_NO_THROW(up->initialize());
426 
427  result::UpdateCheck update_result = up->fetchMeta();
428  EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
429  result::Download download_result = up->downloadImages(update_result.updates);
430  EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
431 
432  std::string hash = download_result.updates[0].sha256Hash();
433  std::transform(hash.begin(), hash.end(), hash.begin(), ::toupper);
434  boost::filesystem::path image = temp_dir / "images" / hash;
435 
436  // Overwrite the file on disk with garbage so that the target verification
437  // fails. First read the existing data so we can re-write it later.
438  auto rhandle = storage->openTargetFile(download_result.updates[0]);
439  const uint64_t length = download_result.updates[0].length();
440  uint8_t content[length];
441  EXPECT_EQ(rhandle->rread(content, length), length);
442  rhandle->rclose();
443  auto whandle = storage->allocateTargetFile(download_result.updates[0]);
444  uint8_t content_bad[length + 1];
445  memset(content_bad, 0, length + 1);
446  EXPECT_EQ(whandle->wfeed(content_bad, 3), 3);
447  whandle->wcommit();
448 
449  result::Install install_result = up->uptaneInstall(download_result.updates);
450  EXPECT_FALSE(install_result.dev_report.isSuccess());
451  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kInternalError);
452 
453  // Try again with oversized data.
454  whandle = storage->allocateTargetFile(download_result.updates[0]);
455  EXPECT_EQ(whandle->wfeed(content_bad, length + 1), length + 1);
456  whandle->wcommit();
457 
458  install_result = up->uptaneInstall(download_result.updates);
459  EXPECT_FALSE(install_result.dev_report.isSuccess());
460  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kInternalError);
461 
462  // Try again with equally long data to make sure the hash check actually gets
463  // triggered.
464  whandle = storage->allocateTargetFile(download_result.updates[0]);
465  EXPECT_EQ(whandle->wfeed(content_bad, length), length);
466  whandle->wcommit();
467 
468  install_result = up->uptaneInstall(download_result.updates);
469  EXPECT_FALSE(install_result.dev_report.isSuccess());
470  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kInternalError);
471 
472  // Try with the real data, but incomplete.
473  whandle = storage->allocateTargetFile(download_result.updates[0]);
474  EXPECT_EQ(whandle->wfeed(reinterpret_cast<uint8_t *>(content), length - 1), length - 1);
475  whandle->wcommit();
476 
477  install_result = up->uptaneInstall(download_result.updates);
478  EXPECT_FALSE(install_result.dev_report.isSuccess());
479  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kInternalError);
480 
481  // Restore the original data to the file so that verification succeeds.
482  whandle = storage->allocateTargetFile(download_result.updates[0]);
483  EXPECT_EQ(whandle->wfeed(reinterpret_cast<uint8_t *>(content), length), length);
484  whandle->wcommit();
485 
486  install_result = up->uptaneInstall(download_result.updates);
487  EXPECT_TRUE(install_result.dev_report.isSuccess());
488  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
489 }
490 
491 bool EcuInstallationStartedReportGot = false;
492 class HttpFakeEvents : public HttpFake {
493  public:
494  HttpFakeEvents(const boost::filesystem::path &test_dir_in, std::string flavor = "")
495  : HttpFake(test_dir_in, std::move(flavor)) {}
496 
497  virtual HttpResponse handle_event(const std::string &url, const Json::Value &data) override {
498  for (const auto &event : data) {
499  if (event["eventType"]["id"].asString() == "EcuInstallationStarted") {
500  if (event["event"]["ecu"].asString() == "secondary_ecu_serial") {
501  EcuInstallationStartedReportGot = true;
502  }
503  }
504  }
505  return HttpResponse(url, 200, CURLE_OK, "");
506  }
507 };
508 
510  public:
511  explicit SecondaryInterfaceMock(Primary::VirtualSecondaryConfig &sconfig_in) : sconfig(std::move(sconfig_in)) {
512  std::string private_key, public_key;
513  if (!Crypto::generateKeyPair(sconfig.key_type, &public_key, &private_key)) {
514  throw std::runtime_error("Key generation failure");
515  }
516  public_key_ = PublicKey(public_key, sconfig.key_type);
517  Json::Value manifest_unsigned;
518  manifest_unsigned["key"] = "value";
519 
520  std::string b64sig = Utils::toBase64(
521  Crypto::Sign(sconfig.key_type, nullptr, private_key, Utils::jsonToCanonicalStr(manifest_unsigned)));
522  Json::Value signature;
523  signature["method"] = "rsassa-pss";
524  signature["sig"] = b64sig;
525  signature["keyid"] = public_key_.KeyId();
526  manifest_["signed"] = manifest_unsigned;
527  manifest_["signatures"].append(signature);
528  }
529  std::string Type() const override { return "mock"; }
530  PublicKey getPublicKey() const override { return public_key_; }
531 
532  Uptane::HardwareIdentifier getHwId() const override { return Uptane::HardwareIdentifier(sconfig.ecu_hardware_id); }
533  Uptane::EcuSerial getSerial() const override {
534  if (!sconfig.ecu_serial.empty()) {
535  return Uptane::EcuSerial(sconfig.ecu_serial);
536  }
537  return Uptane::EcuSerial(public_key_.KeyId());
538  }
539  Uptane::Manifest getManifest() const override { return manifest_; }
540  bool ping() const override { return true; }
541  MOCK_METHOD1(putMetadataMock, bool(const Uptane::RawMetaPack &));
542  MOCK_CONST_METHOD1(getRootVersionMock, int32_t(bool));
543 
544  bool putMetadata(const Uptane::RawMetaPack &meta_pack) override { return putMetadataMock(meta_pack); }
545  int32_t getRootVersion(bool director) const override { return getRootVersionMock(director); }
546 
547  bool putRoot(const std::string &, bool) override { return true; }
548  bool sendFirmware(const std::string &) override { return true; }
549  virtual data::ResultCode::Numeric install(const std::string &) override { return data::ResultCode::Numeric::kOk; }
550 
551  PublicKey public_key_;
552  Json::Value manifest_;
553 
555 };
556 
557 MATCHER_P(matchMeta, meta, "") {
558  return (arg.director_root == meta.director_root) && (arg.image_root == meta.image_root) &&
559  (arg.director_targets == meta.director_targets) && (arg.image_timestamp == meta.image_timestamp) &&
560  (arg.image_snapshot == meta.image_snapshot) && (arg.image_targets == meta.image_targets);
561 }
562 
563 /*
564  * Send metadata to secondary ECUs
565  * Send EcuInstallationStartedReport to server for secondaries
566  */
567 TEST(Uptane, SendMetadataToSeconadry) {
568  Config conf("tests/config/basic.toml");
569  TemporaryDirectory temp_dir;
570  auto http = std::make_shared<HttpFakeEvents>(temp_dir.Path(), "hasupdates");
571  conf.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
572  conf.provision.primary_ecu_hardware_id = "primary_hw";
573  conf.uptane.director_server = http->tls_server + "/director";
574  conf.uptane.repo_server = http->tls_server + "/repo";
575  conf.storage.path = temp_dir.Path();
576  conf.tls.server = http->tls_server;
577 
579  ecu_config.partial_verifying = false;
580  ecu_config.full_client_dir = temp_dir.Path();
581  ecu_config.ecu_serial = "secondary_ecu_serial";
582  ecu_config.ecu_hardware_id = "secondary_hw";
583  ecu_config.ecu_private_key = "sec.priv";
584  ecu_config.ecu_public_key = "sec.pub";
585  ecu_config.firmware_path = temp_dir / "firmware.txt";
586  ecu_config.target_name_path = temp_dir / "firmware_name.txt";
587  ecu_config.metadata_path = temp_dir / "secondary_metadata";
588 
589  auto sec = std::make_shared<SecondaryInterfaceMock>(ecu_config);
590  auto storage = INvStorage::newStorage(conf.storage);
591  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
592  up->addSecondary(sec);
593  EXPECT_NO_THROW(up->initialize());
594  result::UpdateCheck update_result = up->fetchMeta();
595  EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
596 
597  Uptane::RawMetaPack meta;
598  storage->loadLatestRoot(&meta.director_root, Uptane::RepositoryType::Director());
599  storage->loadNonRoot(&meta.director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
600  storage->loadLatestRoot(&meta.image_root, Uptane::RepositoryType::Image());
601  storage->loadNonRoot(&meta.image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
602  storage->loadNonRoot(&meta.image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
603  storage->loadNonRoot(&meta.image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
604 
605  EXPECT_CALL(*sec, putMetadataMock(matchMeta(meta)));
606  result::Download download_result = up->downloadImages(update_result.updates);
607  EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
608  result::Install install_result = up->uptaneInstall(download_result.updates);
609  EXPECT_TRUE(install_result.dev_report.isSuccess());
610  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
611  EXPECT_TRUE(EcuInstallationStartedReportGot);
612 }
613 
614 /* Register secondary ECUs with director. */
615 TEST(Uptane, UptaneSecondaryAdd) {
616  TemporaryDirectory temp_dir;
617  auto http = std::make_shared<HttpFake>(temp_dir.Path());
618  Config config = config_common();
619  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir / "cred.zip");
620  config.provision.provision_path = temp_dir / "cred.zip";
621  config.provision.mode = ProvisionMode::kSharedCred;
622  config.uptane.director_server = http->tls_server + "/director";
623  config.uptane.repo_server = http->tls_server + "/repo";
624  config.tls.server = http->tls_server;
625  config.provision.primary_ecu_serial = "testecuserial";
626  config.storage.path = temp_dir.Path();
627  config.pacman.type = PACKAGE_MANAGER_NONE;
628  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
629 
630  auto storage = INvStorage::newStorage(config.storage);
631  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
632  EXPECT_NO_THROW(sota_client->initialize());
633 
634  /* Verify the correctness of the metadata sent to the server about the
635  * secondary. */
636  Json::Value ecu_data = Utils::parseJSONFile(temp_dir / "post.json");
637  EXPECT_EQ(ecu_data["ecus"].size(), 2);
638  EXPECT_EQ(ecu_data["primary_ecu_serial"].asString(), config.provision.primary_ecu_serial);
639  EXPECT_EQ(ecu_data["ecus"][1]["ecu_serial"].asString(), "secondary_ecu_serial");
640  EXPECT_EQ(ecu_data["ecus"][1]["hardware_identifier"].asString(), "secondary_hardware");
641  EXPECT_EQ(ecu_data["ecus"][1]["clientKey"]["keytype"].asString(), "RSA");
642  EXPECT_TRUE(ecu_data["ecus"][1]["clientKey"]["keyval"]["public"].asString().size() > 0);
643 }
644 
645 /* Adding multiple secondaries with the same serial throws an error */
646 TEST(Uptane, UptaneSecondaryAddSameSerial) {
647  TemporaryDirectory temp_dir;
648  auto http = std::make_shared<HttpFake>(temp_dir.Path());
649  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir / "cred.zip");
650  Config config = config_common();
651  config.provision.provision_path = temp_dir / "cred.zip";
652  config.provision.mode = ProvisionMode::kSharedCred;
653  config.pacman.type = PACKAGE_MANAGER_NONE;
654  config.storage.path = temp_dir.Path();
655 
656  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
657 
658  auto storage = INvStorage::newStorage(config.storage);
659  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
660  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware_new");
661  EXPECT_THROW(sota_client->addSecondary(std::make_shared<Primary::VirtualSecondary>(
662  Primary::VirtualSecondaryConfig::create_from_file(config.uptane.secondary_config_file)[0])),
663  std::runtime_error);
664 }
665 
666 #if 0
667 // TODO: this test needs some refresh, it relies on the behaviour of
668 // UptaneTestCommon::TestUptaneClient which differs from actual SotaUptaneClient
669 /*
670  * Identify previously unknown secondaries
671  * Identify currently unavailable secondaries
672  */
673 TEST(Uptane, UptaneSecondaryMisconfigured) {
674  TemporaryDirectory temp_dir;
675  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir / "cred.zip");
676  auto http = std::make_shared<HttpFake>(temp_dir.Path());
677  {
678  Config config = config_common();
679  config.provision.provision_path = temp_dir / "cred.zip";
680  config.provision.mode = ProvisionMode::kSharedCred;
681  config.pacman.type = PACKAGE_MANAGER_NONE;
682  config.storage.path = temp_dir.Path();
683  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
684 
685  auto storage = INvStorage::newStorage(config.storage);
686  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
687  EXPECT_NO_THROW(sota_client->initialize());
688 
689  std::vector<MisconfiguredEcu> ecus;
690  storage->loadMisconfiguredEcus(&ecus);
691  EXPECT_EQ(ecus.size(), 0);
692  }
693  {
694  Config config = config_common();
695  config.provision.provision_path = temp_dir / "cred.zip";
696  config.provision.mode = ProvisionMode::kSharedCred;
697  config.pacman.type = PACKAGE_MANAGER_NONE;
698  config.storage.path = temp_dir.Path();
699  auto storage = INvStorage::newStorage(config.storage);
700  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "new_secondary_ecu_serial", "new_secondary_hardware");
701  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
702  EXPECT_NO_THROW(sota_client->initialize());
703 
704  std::vector<MisconfiguredEcu> ecus;
705  storage->loadMisconfiguredEcus(&ecus);
706  EXPECT_EQ(ecus.size(), 2);
707  if (ecus[0].serial.ToString() == "new_secondary_ecu_serial") {
708  EXPECT_EQ(ecus[0].state, EcuState::kNotRegistered);
709  EXPECT_EQ(ecus[1].serial.ToString(), "secondary_ecu_serial");
710  EXPECT_EQ(ecus[1].state, EcuState::kOld);
711  } else if (ecus[0].serial.ToString() == "secondary_ecu_serial") {
712  EXPECT_EQ(ecus[0].state, EcuState::kOld);
713  EXPECT_EQ(ecus[1].serial.ToString(), "new_secondary_ecu_serial");
714  EXPECT_EQ(ecus[1].state, EcuState::kNotRegistered);
715  } else {
716  FAIL() << "Unexpected secondary serial in storage: " << ecus[0].serial.ToString();
717  }
718  }
719  {
720  Config config = config_common();
721  config.provision.provision_path = temp_dir / "cred.zip";
722  config.provision.mode = ProvisionMode::kSharedCred;
723  config.pacman.type = PACKAGE_MANAGER_NONE;
724  config.storage.path = temp_dir.Path();
725  auto storage = INvStorage::newStorage(config.storage);
726  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hardware");
727  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
728  EXPECT_NO_THROW(sota_client->initialize());
729 
730  std::vector<MisconfiguredEcu> ecus;
731  storage->loadMisconfiguredEcus(&ecus);
732  EXPECT_EQ(ecus.size(), 0);
733  }
734 }
735 #endif
736 
737 /**
738  * Check that basic device info sent by aktualizr during provisioning matches
739  * our expectations.
740  *
741  * Ideally, we would compare what we have with what the server reports, but in
742  * lieu of that, we can check what we send via http.
743  */
744 class HttpFakeProv : public HttpFake {
745  public:
746  HttpFakeProv(const boost::filesystem::path &test_dir_in, std::string flavor = "")
747  : HttpFake(test_dir_in, std::move(flavor)) {}
748 
749  HttpResponse post(const std::string &url, const Json::Value &data) override {
750  std::cout << "post " << url << "\n";
751 
752  if (url.find("/devices") != std::string::npos) {
753  devices_count++;
754  EXPECT_EQ(data["deviceId"].asString(), "tst149_device_id");
755  return HttpResponse(Utils::readFile("tests/test_data/cred.p12"), 200, CURLE_OK, "");
756  } else if (url.find("/director/ecus") != std::string::npos) {
757  /* Register primary ECU with director. */
758  ecus_count++;
759  EXPECT_EQ(data["primary_ecu_serial"].asString(), "CA:FE:A6:D2:84:9D");
760  EXPECT_EQ(data["ecus"][0]["hardware_identifier"].asString(), "primary_hw");
761  EXPECT_EQ(data["ecus"][0]["ecu_serial"].asString(), "CA:FE:A6:D2:84:9D");
762  if (ecus_count == 1) {
763  return HttpResponse("{}", 200, CURLE_OK, "");
764  } else {
765  return HttpResponse(R"({"code":"ecu_already_registered"})", 409, CURLE_OK, "");
766  }
767  } else if (url.find("/events") != std::string::npos) {
768  return handle_event(url, data);
769  }
770  EXPECT_EQ(0, 1) << "Unexpected post to URL: " << url;
771  return HttpResponse("", 400, CURLE_OK, "");
772  }
773 
774  HttpResponse handle_event_single(const Json::Value &event) {
775  if (event["eventType"]["id"] == "DownloadProgressReport") {
776  return HttpResponse("", 200, CURLE_OK, "");
777  }
778  const std::string event_type = event["eventType"]["id"].asString();
779  const std::string serial = event["event"]["ecu"].asString();
780  std::cout << "Got " << event_type << " event\n";
781  ++events_seen;
782  switch (events_seen) {
783  case 0:
784  EXPECT_EQ(event_type, "SendDeviceDataComplete");
785  break;
786  case 1:
787  case 2:
788  case 3:
789  case 4:
790  if (event_type == "EcuDownloadStarted") {
791  if (serial == "CA:FE:A6:D2:84:9D") {
792  ++primary_download_start;
793  } else if (serial == "secondary_ecu_serial") {
794  ++secondary_download_start;
795  }
796  } else if (event_type == "EcuDownloadCompleted") {
797  if (serial == "CA:FE:A6:D2:84:9D") {
798  ++primary_download_complete;
799  } else if (serial == "secondary_ecu_serial") {
800  ++secondary_download_complete;
801  }
802  }
803  if (events_seen == 4) {
804  EXPECT_EQ(primary_download_start, 1);
805  EXPECT_EQ(primary_download_complete, 1);
806  EXPECT_EQ(secondary_download_start, 1);
807  EXPECT_EQ(secondary_download_complete, 1);
808  }
809  break;
810  case 5:
811  /* Send EcuInstallationStartedReport to server for primary. */
812  EXPECT_EQ(event_type, "EcuInstallationStarted");
813  EXPECT_EQ(serial, "CA:FE:A6:D2:84:9D");
814  break;
815  case 6:
816  /* Send EcuInstallationCompletedReport to server for primary. */
817  EXPECT_EQ(event_type, "EcuInstallationCompleted");
818  EXPECT_EQ(serial, "CA:FE:A6:D2:84:9D");
819  break;
820  case 7:
821  /* Send EcuInstallationStartedReport to server for secondaries. */
822  EXPECT_EQ(event_type, "EcuInstallationStarted");
823  EXPECT_EQ(serial, "secondary_ecu_serial");
824  break;
825  case 8:
826  /* Send EcuInstallationCompletedReport to server for secondaries. */
827  EXPECT_EQ(event_type, "EcuInstallationCompleted");
828  EXPECT_EQ(serial, "secondary_ecu_serial");
829  break;
830  default:
831  std::cout << "Unexpected event: " << event_type;
832  EXPECT_EQ(0, 1);
833  }
834  return HttpResponse("", 200, CURLE_OK, "");
835  }
836 
837  HttpResponse handle_event(const std::string &url, const Json::Value &data) override {
838  (void)url;
839  for (const Json::Value &ev : data) {
840  handle_event_single(ev);
841  }
842  return HttpResponse("", 200, CURLE_OK, "");
843  }
844 
845  HttpResponse put(const std::string &url, const Json::Value &data) override {
846  std::cout << "put " << url << "\n";
847  if (url.find("core/installed") != std::string::npos) {
848  /* Send a list of installed packages to the server. */
849  installed_count++;
850  EXPECT_EQ(data.size(), 1);
851  EXPECT_EQ(data[0]["name"].asString(), "fake-package");
852  EXPECT_EQ(data[0]["version"].asString(), "1.0");
853  } else if (url.find("/director/manifest") != std::string::npos) {
854  /* Get manifest from primary.
855  * Get primary installation result.
856  * Send manifest to the server. */
857  manifest_count++;
858  std::string file_primary;
859  std::string file_secondary;
860  std::string hash_primary;
861  std::string hash_secondary;
862  if (manifest_count <= 2) {
863  file_primary = "unknown";
864  file_secondary = "noimage";
865  // Check for default initial value of packagemanagerfake.
866  hash_primary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest("")));
867  hash_secondary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest("")));
868  } else {
869  file_primary = "primary_firmware.txt";
870  file_secondary = "secondary_firmware.txt";
871  const Json::Value json = Utils::parseJSON(Utils::readFile(meta_dir / "director/targets_hasupdates.json"));
872  const Json::Value targets_list = json["signed"]["targets"];
873  hash_primary = targets_list["primary_firmware.txt"]["hashes"]["sha256"].asString();
874  hash_secondary = targets_list["secondary_firmware.txt"]["hashes"]["sha256"].asString();
875  }
876  const Json::Value manifest = data["signed"]["ecu_version_manifests"];
877  const Json::Value manifest_primary = manifest["CA:FE:A6:D2:84:9D"]["signed"]["installed_image"];
878  const Json::Value manifest_secondary = manifest["secondary_ecu_serial"]["signed"]["installed_image"];
879  EXPECT_EQ(file_primary, manifest_primary["filepath"].asString());
880  EXPECT_EQ(file_secondary, manifest_secondary["filepath"].asString());
881  EXPECT_EQ(manifest_primary["fileinfo"]["hashes"]["sha256"].asString(), hash_primary);
882  EXPECT_EQ(manifest_secondary["fileinfo"]["hashes"]["sha256"].asString(), hash_secondary);
883  } else if (url.find("/system_info/network") != std::string::npos) {
884  /* Send networking info to the server. */
885  network_count++;
886  Json::Value nwinfo = Utils::getNetworkInfo();
887  EXPECT_EQ(nwinfo["local_ipv4"].asString(), data["local_ipv4"].asString());
888  EXPECT_EQ(nwinfo["mac"].asString(), data["mac"].asString());
889  EXPECT_EQ(nwinfo["hostname"].asString(), data["hostname"].asString());
890  } else if (url.find("/system_info") != std::string::npos) {
891  /* Send hardware info to the server. */
892  system_info_count++;
893  Json::Value hwinfo = Utils::getHardwareInfo();
894  EXPECT_EQ(hwinfo["id"].asString(), data["id"].asString());
895  EXPECT_EQ(hwinfo["description"].asString(), data["description"].asString());
896  EXPECT_EQ(hwinfo["class"].asString(), data["class"].asString());
897  EXPECT_EQ(hwinfo["product"].asString(), data["product"].asString());
898  } else {
899  EXPECT_EQ(0, 1) << "Unexpected put to URL: " << url;
900  }
901 
902  return HttpFake::put(url, data);
903  }
904 
905  size_t events_seen{0};
906  int devices_count{0};
907  int ecus_count{0};
908  int manifest_count{0};
909  int installed_count{0};
910  int system_info_count{0};
911  int network_count{0};
912 
913  private:
914  int primary_download_start{0};
915  int primary_download_complete{0};
916  int secondary_download_start{0};
917  int secondary_download_complete{0};
918 };
919 
920 /* Provision with a fake server and check for the exact number of expected
921  * calls to each endpoint.
922  * Use a provided hardware ID
923  * Send SendDeviceDataComplete event
924  */
925 TEST(Uptane, ProvisionOnServer) {
926  RecordProperty("zephyr_key", "OTA-984,TST-149");
927  TemporaryDirectory temp_dir;
928  Config config("tests/config/basic.toml");
929  auto http = std::make_shared<HttpFakeProv>(temp_dir.Path(), "hasupdates");
930  const std::string &server = http->tls_server;
931  config.provision.server = server;
932  config.tls.server = server;
933  config.uptane.director_server = server + "/director";
934  config.uptane.repo_server = server + "/repo";
935  config.provision.ecu_registration_endpoint = server + "/director/ecus";
936  config.provision.device_id = "tst149_device_id";
937  config.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
938  config.provision.primary_ecu_hardware_id = "primary_hw";
939  config.storage.path = temp_dir.Path();
940  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hw");
941 
942  auto storage = INvStorage::newStorage(config.storage);
943  auto events_channel = std::make_shared<event::Channel>();
944  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http, events_channel);
945 
946  EXPECT_EQ(http->devices_count, 0);
947  EXPECT_EQ(http->ecus_count, 0);
948  EXPECT_EQ(http->manifest_count, 0);
949  EXPECT_EQ(http->installed_count, 0);
950  EXPECT_EQ(http->system_info_count, 0);
951  EXPECT_EQ(http->network_count, 0);
952 
953  EXPECT_NO_THROW(up->initialize());
954  EcuSerials serials;
955  storage->loadEcuSerials(&serials);
956  EXPECT_EQ(serials[0].second.ToString(), "primary_hw");
957 
958  EXPECT_EQ(http->devices_count, 1);
959  EXPECT_EQ(http->ecus_count, 1);
960 
961  EXPECT_NO_THROW(up->sendDeviceData());
962  EXPECT_EQ(http->manifest_count, 1);
963  EXPECT_EQ(http->installed_count, 1);
964  EXPECT_EQ(http->system_info_count, 1);
965  EXPECT_EQ(http->network_count, 1);
966 
967  result::UpdateCheck update_result = up->fetchMeta();
968  EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
969  EXPECT_EQ(http->manifest_count, 2);
970 
971  // Test installation to make sure the metadata put to the server is correct.
972  result::Download download_result = up->downloadImages(update_result.updates);
973  EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
974  result::Install install_result = up->uptaneInstall(download_result.updates);
975  EXPECT_TRUE(install_result.dev_report.isSuccess());
976  EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
977  up->putManifest();
978 
979  EXPECT_EQ(http->devices_count, 1);
980  EXPECT_EQ(http->ecus_count, 1);
981  EXPECT_EQ(http->manifest_count, 3);
982  EXPECT_EQ(http->installed_count, 1);
983  EXPECT_EQ(http->system_info_count, 1);
984  EXPECT_EQ(http->network_count, 1);
985  EXPECT_EQ(http->events_seen, 8);
986 }
987 
988 /* Migrate from the legacy filesystem storage. */
989 TEST(Uptane, FsToSqlFull) {
990  TemporaryDirectory temp_dir;
991  Utils::copyDir("tests/test_data/prov", temp_dir.Path());
992  ASSERT_GE(chmod(temp_dir.Path().c_str(), S_IRWXU), 0);
993  StorageConfig config;
994  config.type = StorageType::kSqlite;
995  config.path = temp_dir.Path();
996 
997  FSStorageRead fs_storage(config);
998 
999  std::string public_key;
1000  std::string private_key;
1001  fs_storage.loadPrimaryKeys(&public_key, &private_key);
1002 
1003  std::string ca;
1004  std::string cert;
1005  std::string pkey;
1006  fs_storage.loadTlsCreds(&ca, &cert, &pkey);
1007 
1008  std::string device_id;
1009  fs_storage.loadDeviceId(&device_id);
1010 
1011  EcuSerials serials;
1012  fs_storage.loadEcuSerials(&serials);
1013 
1014  bool ecu_registered = fs_storage.loadEcuRegistered();
1015 
1016  std::vector<Uptane::Target> fs_installed_versions;
1017  std::vector<Uptane::Target> fixed_installed_versions;
1018  fs_storage.loadInstalledVersions(&fs_installed_versions, nullptr);
1019  // Add the serial/hwid mapping to match what the SQL storage will do when
1020  // reading it back after it has been copied from FS storage.
1021  for (auto &target : fs_installed_versions) {
1022  Json::Value dump = target.toDebugJson();
1023  dump["custom"]["ecuIdentifiers"][serials[0].first.ToString()]["hardwareId"] = serials[0].second.ToString();
1024  fixed_installed_versions.emplace_back(Uptane::Target(target.filename(), dump));
1025  }
1026 
1027  std::string director_root;
1028  std::string director_targets;
1029  std::string images_root;
1030  std::string images_targets;
1031  std::string images_timestamp;
1032  std::string images_snapshot;
1033 
1034  EXPECT_TRUE(fs_storage.loadLatestRoot(&director_root, Uptane::RepositoryType::Director()));
1035  EXPECT_TRUE(fs_storage.loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1036  EXPECT_TRUE(fs_storage.loadLatestRoot(&images_root, Uptane::RepositoryType::Image()));
1037  EXPECT_TRUE(fs_storage.loadNonRoot(&images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1038  EXPECT_TRUE(fs_storage.loadNonRoot(&images_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1039  EXPECT_TRUE(fs_storage.loadNonRoot(&images_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1040 
1041  EXPECT_TRUE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1042  EXPECT_TRUE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1043  EXPECT_TRUE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1044  EXPECT_TRUE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1045  EXPECT_TRUE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1046 
1047  boost::filesystem::path image_path = config.uptane_metadata_path.get(config.path) / "repo";
1048  boost::filesystem::path director_path = config.uptane_metadata_path.get(config.path) / "director";
1049  EXPECT_TRUE(boost::filesystem::exists(director_path / "1.root.json"));
1050  EXPECT_TRUE(boost::filesystem::exists(director_path / "targets.json"));
1051  EXPECT_TRUE(boost::filesystem::exists(image_path / "1.root.json"));
1052  EXPECT_TRUE(boost::filesystem::exists(image_path / "targets.json"));
1053  EXPECT_TRUE(boost::filesystem::exists(image_path / "timestamp.json"));
1054  EXPECT_TRUE(boost::filesystem::exists(image_path / "snapshot.json"));
1055  EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path, "device_id")));
1056  EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path, "is_registered")));
1057  EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path, "primary_ecu_serial")));
1058  EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path, "primary_ecu_hardware_id")));
1059  EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path, "secondaries_list")));
1060  auto sql_storage = INvStorage::newStorage(config);
1061 
1062  EXPECT_FALSE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1063  EXPECT_FALSE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1064  EXPECT_FALSE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1065  EXPECT_FALSE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1066  EXPECT_FALSE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1067 
1068  EXPECT_FALSE(boost::filesystem::exists(director_path / "root.json"));
1069  EXPECT_FALSE(boost::filesystem::exists(director_path / "targets.json"));
1070  EXPECT_FALSE(boost::filesystem::exists(director_path / "root.json"));
1071  EXPECT_FALSE(boost::filesystem::exists(director_path / "targets.json"));
1072  EXPECT_FALSE(boost::filesystem::exists(image_path / "timestamp.json"));
1073  EXPECT_FALSE(boost::filesystem::exists(image_path / "snapshot.json"));
1074  EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path, "device_id")));
1075  EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path, "is_registered")));
1076  EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path, "primary_ecu_serial")));
1077  EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path, "primary_ecu_hardware_id")));
1078  EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path, "secondaries_list")));
1079 
1080  std::string sql_public_key;
1081  std::string sql_private_key;
1082  sql_storage->loadPrimaryKeys(&sql_public_key, &sql_private_key);
1083 
1084  std::string sql_ca;
1085  std::string sql_cert;
1086  std::string sql_pkey;
1087  sql_storage->loadTlsCreds(&sql_ca, &sql_cert, &sql_pkey);
1088 
1089  std::string sql_device_id;
1090  sql_storage->loadDeviceId(&sql_device_id);
1091 
1092  EcuSerials sql_serials;
1093  sql_storage->loadEcuSerials(&sql_serials);
1094 
1095  bool sql_ecu_registered = sql_storage->loadEcuRegistered();
1096 
1097  std::vector<Uptane::Target> sql_installed_versions;
1098  sql_storage->loadPrimaryInstallationLog(&sql_installed_versions, true);
1099 
1100  std::string sql_director_root;
1101  std::string sql_director_targets;
1102  std::string sql_images_root;
1103  std::string sql_images_targets;
1104  std::string sql_images_timestamp;
1105  std::string sql_images_snapshot;
1106 
1107  sql_storage->loadLatestRoot(&sql_director_root, Uptane::RepositoryType::Director());
1108  sql_storage->loadNonRoot(&sql_director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
1109  sql_storage->loadLatestRoot(&sql_images_root, Uptane::RepositoryType::Image());
1110  sql_storage->loadNonRoot(&sql_images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
1111  sql_storage->loadNonRoot(&sql_images_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
1112  sql_storage->loadNonRoot(&sql_images_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
1113 
1114  EXPECT_EQ(sql_public_key, public_key);
1115  EXPECT_EQ(sql_private_key, private_key);
1116  EXPECT_EQ(sql_ca, ca);
1117  EXPECT_EQ(sql_cert, cert);
1118  EXPECT_EQ(sql_pkey, pkey);
1119  EXPECT_EQ(sql_device_id, device_id);
1120  EXPECT_EQ(sql_serials, serials);
1121  EXPECT_EQ(sql_ecu_registered, ecu_registered);
1122  EXPECT_TRUE(Uptane::MatchTargetVector(sql_installed_versions, fixed_installed_versions));
1123 
1124  EXPECT_EQ(sql_director_root, director_root);
1125  EXPECT_EQ(sql_director_targets, director_targets);
1126  EXPECT_EQ(sql_images_root, images_root);
1127  EXPECT_EQ(sql_images_targets, images_targets);
1128  EXPECT_EQ(sql_images_timestamp, images_timestamp);
1129  EXPECT_EQ(sql_images_snapshot, images_snapshot);
1130 }
1131 
1132 /* Import a list of installed packages into the storage. */
1133 TEST(Uptane, InstalledVersionImport) {
1134  Config config = config_common();
1135 
1136  TemporaryDirectory temp_dir;
1137  Utils::createDirectories(temp_dir / "import", S_IRWXU);
1138  config.storage.path = temp_dir.Path();
1139  config.import.base_path = temp_dir / "import";
1140  config.postUpdateValues();
1141 
1142  boost::filesystem::copy_file("tests/test_data/prov/installed_versions",
1143  temp_dir.Path() / "import/installed_versions");
1144 
1145  // test basic import
1146  auto storage = INvStorage::newStorage(config.storage);
1147  storage->importData(config.import);
1148 
1149  boost::optional<Uptane::Target> current_version;
1150  storage->loadPrimaryInstalledVersions(&current_version, nullptr);
1151  EXPECT_TRUE(!!current_version);
1152  EXPECT_EQ(current_version->filename(), "master-863de625f305413dc3be306afab7c3f39d8713045cfff812b3af83f9722851f0");
1153 
1154  // check that data is not re-imported later: store new data, reload a new
1155  // storage with import and see that the new data is still there
1156  Json::Value target_json;
1157  target_json["hashes"]["sha256"] = "a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1158  target_json["length"] = 123;
1159  Uptane::Target new_installed_version{"filename", target_json};
1160  storage->savePrimaryInstalledVersion(new_installed_version, InstalledVersionUpdateMode::kCurrent);
1161 
1162  auto new_storage = INvStorage::newStorage(config.storage);
1163  new_storage->importData(config.import);
1164 
1165  current_version = boost::none;
1166  new_storage->loadPrimaryInstalledVersions(&current_version, nullptr);
1167  EXPECT_TRUE(!!current_version);
1168  EXPECT_EQ(current_version->filename(), "filename");
1169 }
1170 
1171 /* Store a list of installed package versions. */
1172 TEST(Uptane, SaveAndLoadVersion) {
1173  TemporaryDirectory temp_dir;
1174  Config config = config_common();
1175  config.storage.path = temp_dir.Path();
1176  config.provision.device_id = "device_id";
1177  config.postUpdateValues();
1178  auto storage = INvStorage::newStorage(config.storage);
1179 
1180  Json::Value target_json;
1181  target_json["hashes"]["sha256"] = "a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1182  target_json["length"] = 123;
1183 
1184  Uptane::Target t("target_name", target_json);
1185  storage->savePrimaryInstalledVersion(t, InstalledVersionUpdateMode::kCurrent);
1186 
1187  boost::optional<Uptane::Target> current_version;
1188  storage->loadPrimaryInstalledVersions(&current_version, nullptr);
1189 
1190  EXPECT_TRUE(!!current_version);
1191  EXPECT_EQ(current_version->sha256Hash(), "a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d");
1192  EXPECT_EQ(current_version->length(), 123);
1193  EXPECT_TRUE(current_version->MatchTarget(t));
1194 }
1195 
1196 class HttpFakeUnstable : public HttpFake {
1197  public:
1198  HttpFakeUnstable(const boost::filesystem::path &test_dir_in) : HttpFake(test_dir_in, "hasupdates") {}
1199  HttpResponse get(const std::string &url, int64_t maxsize) override {
1200  if (unstable_valid_count >= unstable_valid_num) {
1201  return HttpResponse({}, 503, CURLE_OK, "");
1202  } else {
1203  // This if is a hack only required as long as we have to explicitly fetch
1204  // this to make the Director recognize new devices as "online".
1205  if (url.find("director/root.json") == std::string::npos) {
1206  ++unstable_valid_count;
1207  }
1208  return HttpFake::get(url, maxsize);
1209  }
1210  }
1211 
1212  void setUnstableValidNum(int num) {
1213  unstable_valid_num = num;
1214  unstable_valid_count = 0;
1215  }
1216 
1217  int unstable_valid_num{0};
1218  int unstable_valid_count{0};
1219 };
1220 
1221 /* Recover from an interrupted Uptane iteration.
1222  * Fetch metadata from the director.
1223  * Check metadata from the director.
1224  * Identify targets for known ECUs.
1225  * Fetch metadata from the images repo.
1226  * Check metadata from the images repo.
1227  *
1228  * This is a bit fragile because it depends upon a precise number of HTTP get
1229  * requests being made. If that changes, this test will need to be adjusted. */
1230 TEST(Uptane, restoreVerify) {
1231  TemporaryDirectory temp_dir;
1232  auto http = std::make_shared<HttpFakeUnstable>(temp_dir.Path());
1233  Config config("tests/config/basic.toml");
1234  config.storage.path = temp_dir.Path();
1235  config.pacman.type = PACKAGE_MANAGER_NONE;
1236  config.uptane.director_server = http->tls_server + "director";
1237  config.uptane.repo_server = http->tls_server + "repo";
1238  config.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
1239  config.provision.primary_ecu_hardware_id = "primary_hw";
1240  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hw");
1241  config.postUpdateValues();
1242 
1243  auto storage = INvStorage::newStorage(config.storage);
1244  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1245 
1246  EXPECT_NO_THROW(sota_client->initialize());
1247  sota_client->AssembleManifest();
1248  // 1st attempt, don't get anything
1249  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1250  EXPECT_FALSE(storage->loadLatestRoot(nullptr, Uptane::RepositoryType::Director()));
1251 
1252  // 2nd attempt, get director root.json
1253  http->setUnstableValidNum(1);
1254  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1255  EXPECT_TRUE(storage->loadLatestRoot(nullptr, Uptane::RepositoryType::Director()));
1256  EXPECT_FALSE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1257 
1258  // 3rd attempt, get director targets.json
1259  http->setUnstableValidNum(2);
1260  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1261  EXPECT_TRUE(storage->loadLatestRoot(nullptr, Uptane::RepositoryType::Director()));
1262  EXPECT_TRUE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1263  EXPECT_FALSE(storage->loadLatestRoot(nullptr, Uptane::RepositoryType::Image()));
1264 
1265  // 4th attempt, get images root.json
1266  http->setUnstableValidNum(3);
1267  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1268  EXPECT_TRUE(storage->loadLatestRoot(nullptr, Uptane::RepositoryType::Image()));
1269  EXPECT_FALSE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1270 
1271  // 5th attempt, get images timestamp.json
1272  http->setUnstableValidNum(4);
1273  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1274  EXPECT_TRUE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1275  EXPECT_FALSE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1276 
1277  // 6th attempt, get images snapshot.json
1278  http->setUnstableValidNum(5);
1279  EXPECT_FALSE(sota_client->uptaneIteration(nullptr, nullptr));
1280  EXPECT_TRUE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1281  EXPECT_FALSE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1282 
1283  // 7th attempt, get images targets.json, successful iteration
1284  http->setUnstableValidNum(6);
1285  EXPECT_TRUE(sota_client->uptaneIteration(nullptr, nullptr));
1286  EXPECT_TRUE(storage->loadNonRoot(nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1287 }
1288 
1289 /* Fetch metadata from the director.
1290  * Check metadata from the director.
1291  * Identify targets for known ECUs.
1292  * Fetch metadata from the images repo.
1293  * Check metadata from the images repo. */
1294 TEST(Uptane, offlineIteration) {
1295  TemporaryDirectory temp_dir;
1296  auto http = std::make_shared<HttpFake>(temp_dir.Path(), "hasupdates");
1297  Config config("tests/config/basic.toml");
1298  config.storage.path = temp_dir.Path();
1299  config.uptane.director_server = http->tls_server + "director";
1300  config.uptane.repo_server = http->tls_server + "repo";
1301  config.pacman.type = PACKAGE_MANAGER_NONE;
1302  config.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
1303  config.provision.primary_ecu_hardware_id = "primary_hw";
1304  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hw");
1305  config.postUpdateValues();
1306 
1307  auto storage = INvStorage::newStorage(config.storage);
1308  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1309  EXPECT_NO_THROW(sota_client->initialize());
1310 
1311  std::vector<Uptane::Target> targets_online;
1312  EXPECT_TRUE(sota_client->uptaneIteration(&targets_online, nullptr));
1313 
1314  std::vector<Uptane::Target> targets_offline;
1315  EXPECT_TRUE(sota_client->uptaneOfflineIteration(&targets_offline, nullptr));
1316  EXPECT_TRUE(Uptane::MatchTargetVector(targets_online, targets_offline));
1317 }
1318 
1319 /*
1320  * Ignore updates for unrecognized ECUs.
1321  * Reject targets which do not match a known ECU.
1322  */
1323 TEST(Uptane, IgnoreUnknownUpdate) {
1324  TemporaryDirectory temp_dir;
1325  auto http = std::make_shared<HttpFake>(temp_dir.Path(), "hasupdates");
1326  Config config("tests/config/basic.toml");
1327  config.storage.path = temp_dir.Path();
1328  config.uptane.director_server = http->tls_server + "director";
1329  config.uptane.repo_server = http->tls_server + "repo";
1330  config.pacman.type = PACKAGE_MANAGER_NONE;
1331  config.provision.primary_ecu_serial = "primary_ecu";
1332  config.provision.primary_ecu_hardware_id = "primary_hw";
1333  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hw");
1334  config.postUpdateValues();
1335 
1336  auto storage = INvStorage::newStorage(config.storage);
1337  auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1338 
1339  EXPECT_NO_THROW(sota_client->initialize());
1340  auto result = sota_client->fetchMeta();
1341  EXPECT_EQ(result.status, result::UpdateStatus::kError);
1342  EXPECT_STREQ(sota_client->getLastException().what(),
1343  "The target had an ECU ID that did not match the client's configured ECU id.");
1344  sota_client->last_exception = Uptane::Exception{"", ""};
1345  result = sota_client->checkUpdates();
1346  EXPECT_EQ(result.status, result::UpdateStatus::kError);
1347  EXPECT_STREQ(sota_client->getLastException().what(),
1348  "The target had an ECU ID that did not match the client's configured ECU id.");
1349  std::vector<Uptane::Target> packages_to_install = UptaneTestCommon::makePackage("testecuserial", "testecuhwid");
1350  sota_client->last_exception = Uptane::Exception{"", ""};
1351  auto report = sota_client->uptaneInstall(packages_to_install);
1352  EXPECT_STREQ(sota_client->getLastException().what(),
1353  "The target had an ECU ID that did not match the client's configured ECU id.");
1354  EXPECT_EQ(report.ecu_reports.size(), 0);
1355 }
1356 
1357 #ifdef BUILD_P11
1358 TEST(Uptane, Pkcs11Provision) {
1359  Config config;
1360  TemporaryDirectory temp_dir;
1361  Utils::createDirectories(temp_dir / "import", S_IRWXU);
1362  boost::filesystem::copy_file("tests/test_data/device_cred_prov/ca.pem", temp_dir / "import/root.crt");
1363  config.tls.cert_source = CryptoSource::kPkcs11;
1364  config.tls.pkey_source = CryptoSource::kPkcs11;
1365  config.p11.module = TEST_PKCS11_MODULE_PATH;
1366  config.p11.pass = "1234";
1367  config.p11.tls_clientcert_id = "01";
1368  config.p11.tls_pkey_id = "02";
1369  config.import.base_path = (temp_dir / "import").string();
1370  config.import.tls_cacert_path = BasedPath("root.crt");
1371 
1372  config.storage.path = temp_dir.Path();
1373  config.postUpdateValues();
1374 
1375  auto storage = INvStorage::newStorage(config.storage);
1376  storage->importData(config.import);
1377  auto http = std::make_shared<HttpFake>(temp_dir.Path(), "hasupdates");
1378  KeyManager keys(storage, config.keymanagerConfig());
1379  Initializer initializer(config.provision, storage, http, keys, {});
1380 
1381  EXPECT_TRUE(initializer.isSuccessful());
1382 }
1383 #endif
1384 
1385 #ifndef __NO_MAIN__
1386 int main(int argc, char **argv) {
1387  ::testing::InitGoogleTest(&argc, argv);
1388 
1389  logger_init();
1390  logger_set_threshold(boost::log::trivial::trace);
1391 
1392  return RUN_ALL_TESTS();
1393 }
1394 #endif
1395 
1396 // vim: set tabstop=2 shiftwidth=2 expandtab:
Uptane::UnmetThreshold
Definition: exceptions.h:53
HttpFake
Definition: httpfake.h:22
KeyManager
Definition: keymanager.h:13
data::ResultCode::Numeric::kAlreadyProcessed
Operation has already been processed.
SecondaryInterfaceMock
Definition: uptane_test.cc:509
BasedPath
Definition: utils.h:101
HttpFakeProv
Check that basic device info sent by aktualizr during provisioning matches our expectations.
Definition: uptane_test.cc:744
HttpFakeEvents
Definition: uptane_test.cc:492
StorageConfig
Definition: storage_config.h:15
result::UpdateCheck
Container for information about available updates.
Definition: results.h:38
data
General data structures.
Definition: types.cc:54
Uptane::HardwareIdentifier
Definition: tuf.h:143
HttpResponse
Definition: httpinterface.h:17
Config
Configuration object for an aktualizr instance running on a primary ECU.
Definition: config.h:74
Uptane::RawMetaPack
Definition: tuf.h:534
Uptane::EcuSerial
Definition: tuf.h:174
result::Download
Container for information about downloading an update.
Definition: results.h:117
PublicKey
Definition: crypto.h:26
Uptane::Exception
Definition: exceptions.h:10
Uptane::IllegalThreshold
Definition: exceptions.h:41
Primary::VirtualSecondaryConfig
Definition: virtualsecondary.h:11
HttpFakeUnstable
Definition: uptane_test.cc:1196
Uptane::BadKeyId
Definition: exceptions.h:88
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:13
Initializer
Definition: initializer.h:13
result::Install
Container for information about installing an update.
Definition: results.h:130
data::ResultCode::Numeric::kInternalError
SWM Internal integrity error.
Uptane::Target
Definition: tuf.h:238
data::ResultCode::Numeric
Numeric
Definition: types.h:128
Uptane::Root
Definition: tuf.h:384
Uptane
Base data types that are used in The Update Framework (TUF), part of UPTANE.
Definition: secondary_tcp_server.h:8
HttpPutManifestFail
Definition: aktualizr_test.cc:2114
Uptane::SecondaryInterface
Definition: secondaryinterface.h:12
Uptane::Manifest
Definition: manifest.h:13
FSStorageRead
Definition: fsstorage_read.h:7
event
Aktualizr status events.
Definition: events.h:18
Uptane::SecurityException
Definition: exceptions.h:21