1 #include <gmock/gmock.h> 2 #include <gtest/gtest.h> 13 #include <boost/filesystem.hpp> 14 #include "json/json.h" 16 #include "crypto/p11engine.h" 18 #include "primary/initializer.h" 19 #include "primary/secondaryinterface.h" 20 #include "primary/sotauptaneclient.h" 21 #include "storage/fsstorage_read.h" 22 #include "storage/invstorage.h" 23 #include "test_utils.h" 24 #include "uptane/tuf.h" 25 #include "uptane/uptanerepository.h" 26 #include "uptane_test_common.h" 27 #include "utilities/utils.h" 30 #ifndef TEST_PKCS11_MODULE_PATH 31 #define TEST_PKCS11_MODULE_PATH "/usr/local/softhsm/libsofthsm2.so" 35 static Config config_common() {
37 config.uptane.key_type = KeyType::kED25519;
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";
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);
52 Uptane::Root(Uptane::RepositoryType::Director(), response.getJson(), root);
56 TEST(
Uptane, VerifyDataBad) {
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";
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");
73 TEST(
Uptane, VerifyDataUnknownType) {
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";
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";
91 TEST(
Uptane, VerifyDataBadKeyId) {
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";
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();
102 data_json[
"signatures"][0][
"keyid"] =
"badkeyid";
109 TEST(
Uptane, VerifyDataBadThreshold) {
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";
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;
122 Uptane::Root(Uptane::RepositoryType::Director(), data_json, root);
123 FAIL() <<
"Illegal threshold should have thrown an error.";
131 TEST(
Uptane, AssembleManifestGood) {
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");
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());
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");
156 EXPECT_FALSE(manifest[
"testecuserial"][
"signed"].isMember(
"custom"));
157 EXPECT_FALSE(manifest[
"secondary_ecu_serial"][
"signed"].isMember(
"custom"));
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);
168 TEST(
Uptane, AssembleManifestBad) {
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");
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);
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());
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);
200 EXPECT_FALSE(manifest[
"testecuserial"][
"signed"].isMember(
"custom"));
201 EXPECT_FALSE(manifest[
"secondary_ecu_serial"][
"signed"].isMember(
"custom"));
207 TEST(
Uptane, PutManifest) {
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 config.provision.provision_path = temp_dir /
"cred.zip";
214 config.provision.mode = ProvisionMode::kSharedCred;
215 config.uptane.director_server = http->tls_server +
"/director";
216 config.uptane.repo_server = http->tls_server +
"/repo";
217 config.provision.primary_ecu_serial =
"testecuserial";
218 config.pacman.type = PACKAGE_MANAGER_NONE;
220 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
221 boost::filesystem::copy_file(
"tests/test_data/firmware.txt", sec_config.firmware_path);
222 boost::filesystem::copy_file(
"tests/test_data/firmware_name.txt", sec_config.target_name_path);
224 auto storage = INvStorage::newStorage(config.storage);
226 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
227 EXPECT_NO_THROW(sota_client->initialize());
228 EXPECT_TRUE(sota_client->putManifestSimple());
230 Json::Value json = http->last_manifest;
232 EXPECT_EQ(json[
"signatures"].size(), 1u);
233 EXPECT_EQ(json[
"signed"][
"primary_ecu_serial"].asString(),
"testecuserial");
235 json[
"signed"][
"ecu_version_manifests"][
"testecuserial"][
"signed"][
"installed_image"][
"filepath"].asString(),
237 EXPECT_EQ(json[
"signed"][
"ecu_version_manifests"].size(), 2u);
238 EXPECT_EQ(json[
"signed"][
"ecu_version_manifests"][
"secondary_ecu_serial"][
"signed"][
"ecu_serial"].asString(),
239 "secondary_ecu_serial");
240 EXPECT_EQ(json[
"signed"][
"ecu_version_manifests"][
"secondary_ecu_serial"][
"signed"][
"installed_image"][
"filepath"]
249 HttpResponse put(
const std::string &url,
const Json::Value &
data)
override {
255 int num_events_PutManifestError = 0;
256 void process_events_PutManifestError(
const std::shared_ptr<event::BaseEvent> &
event) {
257 std::cout <<
event->variant <<
"\n";
258 if (event->variant ==
"PutManifestComplete") {
259 EXPECT_FALSE(std::static_pointer_cast<event::PutManifestComplete>(event)->success);
260 num_events_PutManifestError++;
267 TEST(
Uptane, PutManifestError) {
269 auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path());
271 Config conf(
"tests/config/basic.toml");
272 conf.storage.path = temp_dir.Path();
274 auto storage = INvStorage::newStorage(conf.storage);
275 auto events_channel = std::make_shared<event::Channel>();
276 std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_PutManifestError;
277 events_channel->connect(f_cb);
278 num_events_PutManifestError = 0;
279 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http, events_channel);
280 EXPECT_NO_THROW(sota_client->initialize());
281 auto result = sota_client->putManifest();
282 EXPECT_FALSE(result);
283 EXPECT_EQ(num_events_PutManifestError, 1);
291 TEST(
Uptane, FetchMetaFail) {
293 auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path(),
"noupdates");
295 Config conf(
"tests/config/basic.toml");
296 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
297 conf.provision.primary_ecu_hardware_id =
"primary_hw";
298 conf.uptane.director_server = http->tls_server +
"/director";
299 conf.uptane.repo_server = http->tls_server +
"/repo";
300 conf.storage.path = temp_dir.Path();
301 conf.tls.server = http->tls_server;
303 auto storage = INvStorage::newStorage(conf.storage);
304 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
306 EXPECT_NO_THROW(up->initialize());
308 EXPECT_EQ(result.status, result::UpdateStatus::kNoUpdatesAvailable);
311 unsigned int num_events_InstallTarget = 0;
312 unsigned int num_events_AllInstalls = 0;
313 void process_events_Install(
const std::shared_ptr<event::BaseEvent> &event) {
314 if (event->variant ==
"InstallTargetComplete") {
316 if (num_events_InstallTarget <= 1) {
317 EXPECT_TRUE(concrete_event->success);
319 EXPECT_FALSE(concrete_event->success);
321 num_events_InstallTarget++;
323 if (event->variant ==
"AllInstallsComplete") {
325 if (num_events_AllInstalls == 0) {
326 EXPECT_TRUE(concrete_event->result.dev_report.isSuccess());
327 }
else if (num_events_AllInstalls == 1) {
328 EXPECT_FALSE(concrete_event->result.dev_report.isSuccess());
331 EXPECT_FALSE(concrete_event->result.dev_report.isSuccess());
334 num_events_AllInstalls++;
350 TEST(
Uptane, InstallFakeGood) {
351 Config conf(
"tests/config/basic.toml");
353 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
354 conf.uptane.director_server = http->tls_server +
"director";
355 conf.uptane.repo_server = http->tls_server +
"repo";
356 conf.pacman.type = PACKAGE_MANAGER_NONE;
357 conf.pacman.images_path = temp_dir.Path() /
"images";
358 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
359 conf.provision.primary_ecu_hardware_id =
"primary_hw";
360 conf.storage.path = temp_dir.Path();
361 conf.tls.server = http->tls_server;
362 UptaneTestCommon::addDefaultSecondary(conf, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
363 conf.postUpdateValues();
365 auto storage = INvStorage::newStorage(conf.storage);
366 auto events_channel = std::make_shared<event::Channel>();
367 std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
368 events_channel->connect(f_cb);
369 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http, events_channel);
370 EXPECT_NO_THROW(up->initialize());
373 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
374 result::Download download_result = up->downloadImages(update_result.updates);
375 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
376 result::Install install_result1 = up->uptaneInstall(download_result.updates);
377 EXPECT_TRUE(install_result1.dev_report.isSuccess());
378 EXPECT_EQ(install_result1.dev_report.result_code, data::ResultCode::Numeric::kOk);
381 Json::Value manifest = up->AssembleManifest();
382 EXPECT_EQ(manifest[
"ecu_version_manifests"][
"CA:FE:A6:D2:84:9D"][
"signed"][
"installed_image"][
"filepath"].asString(),
383 "primary_firmware.txt");
385 manifest[
"ecu_version_manifests"][
"secondary_ecu_serial"][
"signed"][
"installed_image"][
"filepath"].asString(),
386 "secondary_firmware.txt");
388 EXPECT_EQ(num_events_InstallTarget, 2);
389 EXPECT_EQ(num_events_AllInstalls, 1);
390 Json::Value installation_report = manifest[
"installation_report"][
"report"];
391 EXPECT_EQ(installation_report[
"result"][
"success"].asBool(),
true);
392 EXPECT_EQ(installation_report[
"result"][
"code"].asString(),
"OK");
393 EXPECT_EQ(installation_report[
"items"][0][
"ecu"].asString(),
"CA:FE:A6:D2:84:9D");
394 EXPECT_EQ(installation_report[
"items"][0][
"result"][
"success"].asBool(),
true);
395 EXPECT_EQ(installation_report[
"items"][0][
"result"][
"code"].asString(),
"OK");
396 EXPECT_EQ(installation_report[
"items"][1][
"ecu"].asString(),
"secondary_ecu_serial");
397 EXPECT_EQ(installation_report[
"items"][1][
"result"][
"success"].asBool(),
true);
398 EXPECT_EQ(installation_report[
"items"][1][
"result"][
"code"].asString(),
"OK");
402 result::Install install_result2 = up->uptaneInstall(download_result.updates);
403 EXPECT_FALSE(install_result2.dev_report.isSuccess());
405 EXPECT_EQ(num_events_InstallTarget, 2);
406 EXPECT_EQ(num_events_AllInstalls, 2);
407 manifest = up->AssembleManifest();
408 installation_report = manifest[
"installation_report"][
"report"];
409 EXPECT_EQ(installation_report[
"result"][
"success"].asBool(),
false);
414 EXPECT_EQ(update_result2.status, result::UpdateStatus::kNoUpdatesAvailable);
418 boost::optional<Uptane::Target> current_version;
419 EXPECT_TRUE(storage->loadInstalledVersions(
"CA:FE:A6:D2:84:9D", ¤t_version,
nullptr));
420 const auto bad_target =
Uptane::Target(current_version->filename(), current_version->ecus(), std::vector<Hash>{},
421 current_version->length());
422 storage->saveInstalledVersion(
"CA:FE:A6:D2:84:9D", bad_target, InstalledVersionUpdateMode::kCurrent);
426 result::Install install_result3 = up->uptaneInstall(download_result.updates);
427 EXPECT_FALSE(install_result3.dev_report.isSuccess());
430 EXPECT_EQ(num_events_InstallTarget, 2);
431 EXPECT_EQ(num_events_AllInstalls, 3);
438 TEST(
Uptane, InstallFakeBad) {
439 Config conf(
"tests/config/basic.toml");
441 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
442 conf.uptane.director_server = http->tls_server +
"director";
443 conf.uptane.repo_server = http->tls_server +
"repo";
444 conf.pacman.type = PACKAGE_MANAGER_NONE;
445 conf.pacman.images_path = temp_dir.Path() /
"images";
446 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
447 conf.provision.primary_ecu_hardware_id =
"primary_hw";
448 conf.storage.path = temp_dir.Path();
449 conf.tls.server = http->tls_server;
450 UptaneTestCommon::addDefaultSecondary(conf, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
451 conf.postUpdateValues();
453 auto storage = INvStorage::newStorage(conf.storage);
454 std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
455 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
456 EXPECT_NO_THROW(up->initialize());
459 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
460 result::Download download_result = up->downloadImages(update_result.updates);
461 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
463 std::string hash = download_result.updates[0].sha256Hash();
464 std::transform(hash.begin(), hash.end(), hash.begin(), ::toupper);
465 auto image = (conf.pacman.images_path / hash).
string();
469 const uint64_t length = download_result.updates[0].length();
470 char content[length];
471 auto r = std::ifstream(image, std::ios::binary);
472 r.read(content, static_cast<std::streamsize>(length));
473 EXPECT_EQ(r.gcount(), length);
475 auto w = std::ofstream(image, std::ios::binary | std::ios::ate);
476 char content_bad[length + 1];
477 memset(content_bad, 0, length + 1);
478 w.write(content_bad, 3);
481 result::Install install_result = up->uptaneInstall(download_result.updates);
482 EXPECT_FALSE(install_result.dev_report.isSuccess());
486 w = std::ofstream(image, std::ios::binary | std::ios::ate);
487 w.write(content_bad, static_cast<std::streamsize>(length + 1));
490 install_result = up->uptaneInstall(download_result.updates);
491 EXPECT_FALSE(install_result.dev_report.isSuccess());
496 w = std::ofstream(image, std::ios::binary | std::ios::ate);
497 w.write(content_bad, static_cast<std::streamsize>(length));
500 install_result = up->uptaneInstall(download_result.updates);
501 EXPECT_FALSE(install_result.dev_report.isSuccess());
505 w = std::ofstream(image, std::ios::binary | std::ios::ate);
506 w.write(content, static_cast<std::streamsize>(length - 1));
509 install_result = up->uptaneInstall(download_result.updates);
510 EXPECT_FALSE(install_result.dev_report.isSuccess());
514 w = std::ofstream(image, std::ios::binary | std::ios::ate);
515 w.write(content, static_cast<std::streamsize>(length));
518 install_result = up->uptaneInstall(download_result.updates);
519 EXPECT_TRUE(install_result.dev_report.isSuccess());
520 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
523 bool EcuInstallationStartedReportGot =
false;
526 HttpFakeEvents(
const boost::filesystem::path &test_dir_in, std::string flavor =
"")
527 :
HttpFake(test_dir_in, std::move(flavor)) {}
529 virtual HttpResponse handle_event(
const std::string &url,
const Json::Value &
data)
override {
530 for (
const auto &event : data) {
531 if (event[
"eventType"][
"id"].asString() ==
"EcuInstallationStarted") {
532 if (event[
"event"][
"ecu"].asString() ==
"secondary_ecu_serial") {
533 EcuInstallationStartedReportGot =
true;
544 std::string private_key, public_key;
545 if (!Crypto::generateKeyPair(sconfig.key_type, &public_key, &private_key)) {
546 throw std::runtime_error(
"Key generation failure");
548 public_key_ =
PublicKey(public_key, sconfig.key_type);
549 Json::Value manifest_unsigned;
550 manifest_unsigned[
"key"] =
"value";
552 std::string b64sig = Utils::toBase64(
553 Crypto::Sign(sconfig.key_type,
nullptr, private_key, Utils::jsonToCanonicalStr(manifest_unsigned)));
554 Json::Value signature;
555 signature[
"method"] =
"rsassa-pss";
556 signature[
"sig"] = b64sig;
557 signature[
"keyid"] = public_key_.KeyId();
558 manifest_[
"signed"] = manifest_unsigned;
559 manifest_[
"signatures"].append(signature);
561 void init(std::shared_ptr<SecondaryProvider> secondary_provider_in)
override {
562 secondary_provider_ = std::move(secondary_provider_in);
564 std::string Type()
const override {
return "mock"; }
565 PublicKey getPublicKey()
const override {
return public_key_; }
569 if (!sconfig.ecu_serial.empty()) {
575 bool ping()
const override {
return true; }
576 MOCK_METHOD(
bool, putMetadataMock, (
const Uptane::MetaBundle &));
577 MOCK_METHOD(int32_t, getRootVersionMock, (
bool), (
const));
580 Uptane::MetaBundle meta_bundle;
581 if (!secondary_provider_->getMetadata(&meta_bundle, target)) {
583 "Unable to load stored metadata from Primary");
585 putMetadataMock(meta_bundle);
588 int32_t getRootVersion(
bool director)
const override {
return getRootVersionMock(director); }
600 std::shared_ptr<SecondaryProvider> secondary_provider_;
602 Json::Value manifest_;
607 MATCHER_P(matchMeta, meta_bundle,
"") {
return (arg == meta_bundle); }
613 TEST(
Uptane, SendMetadataToSecondary) {
614 Config conf(
"tests/config/basic.toml");
616 auto http = std::make_shared<HttpFakeEvents>(temp_dir.Path(),
"hasupdates");
617 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
618 conf.provision.primary_ecu_hardware_id =
"primary_hw";
619 conf.uptane.director_server = http->tls_server +
"/director";
620 conf.uptane.repo_server = http->tls_server +
"/repo";
621 conf.pacman.images_path = temp_dir.Path() /
"images";
622 conf.storage.path = temp_dir.Path();
623 conf.tls.server = http->tls_server;
626 ecu_config.partial_verifying =
false;
627 ecu_config.full_client_dir = temp_dir.Path();
628 ecu_config.ecu_serial =
"secondary_ecu_serial";
629 ecu_config.ecu_hardware_id =
"secondary_hw";
630 ecu_config.ecu_private_key =
"sec.priv";
631 ecu_config.ecu_public_key =
"sec.pub";
632 ecu_config.firmware_path = temp_dir /
"firmware.txt";
633 ecu_config.target_name_path = temp_dir /
"firmware_name.txt";
634 ecu_config.metadata_path = temp_dir /
"secondary_metadata";
636 auto sec = std::make_shared<SecondaryInterfaceMock>(ecu_config);
637 auto storage = INvStorage::newStorage(conf.storage);
638 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
639 up->addSecondary(sec);
640 EXPECT_NO_THROW(up->initialize());
642 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
644 Uptane::MetaBundle meta_bundle;
645 std::string metadata;
646 storage->loadLatestRoot(&metadata, Uptane::RepositoryType::Director());
647 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Director(), Uptane::Role::Root()), metadata);
648 storage->loadNonRoot(&metadata, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
649 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Director(), Uptane::Role::Targets()), metadata);
650 storage->loadLatestRoot(&metadata, Uptane::RepositoryType::Image());
651 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Root()), metadata);
652 storage->loadNonRoot(&metadata, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
653 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()), metadata);
654 storage->loadNonRoot(&metadata, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
655 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()), metadata);
656 storage->loadNonRoot(&metadata, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
657 meta_bundle.emplace(std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Targets()), metadata);
659 EXPECT_CALL(*sec, putMetadataMock(matchMeta(meta_bundle)));
660 result::Download download_result = up->downloadImages(update_result.updates);
661 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
662 result::Install install_result = up->uptaneInstall(download_result.updates);
663 EXPECT_TRUE(install_result.dev_report.isSuccess());
664 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
665 EXPECT_TRUE(EcuInstallationStartedReportGot);
669 TEST(
Uptane, UptaneSecondaryAdd) {
671 auto http = std::make_shared<HttpFake>(temp_dir.Path());
672 Config config = config_common();
673 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
674 config.provision.provision_path = temp_dir /
"cred.zip";
675 config.provision.mode = ProvisionMode::kSharedCred;
676 config.uptane.director_server = http->tls_server +
"/director";
677 config.uptane.repo_server = http->tls_server +
"/repo";
678 config.tls.server = http->tls_server;
679 config.provision.primary_ecu_serial =
"testecuserial";
680 config.storage.path = temp_dir.Path();
681 config.pacman.type = PACKAGE_MANAGER_NONE;
682 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
684 auto storage = INvStorage::newStorage(config.storage);
685 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
686 EXPECT_NO_THROW(sota_client->initialize());
690 Json::Value ecu_data = Utils::parseJSONFile(temp_dir /
"post.json");
691 EXPECT_EQ(ecu_data[
"ecus"].size(), 2);
692 EXPECT_EQ(ecu_data[
"primary_ecu_serial"].asString(), config.provision.primary_ecu_serial);
693 EXPECT_EQ(ecu_data[
"ecus"][1][
"ecu_serial"].asString(),
"secondary_ecu_serial");
694 EXPECT_EQ(ecu_data[
"ecus"][1][
"hardware_identifier"].asString(),
"secondary_hardware");
695 EXPECT_EQ(ecu_data[
"ecus"][1][
"clientKey"][
"keytype"].asString(),
"RSA");
696 EXPECT_TRUE(ecu_data[
"ecus"][1][
"clientKey"][
"keyval"][
"public"].asString().size() > 0);
700 TEST(
Uptane, UptaneSecondaryAddSameSerial) {
702 auto http = std::make_shared<HttpFake>(temp_dir.Path());
703 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
704 Config config = config_common();
705 config.provision.provision_path = temp_dir /
"cred.zip";
706 config.provision.mode = ProvisionMode::kSharedCred;
707 config.pacman.type = PACKAGE_MANAGER_NONE;
708 config.storage.path = temp_dir.Path();
710 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
712 auto storage = INvStorage::newStorage(config.storage);
713 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
714 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware_new");
715 EXPECT_THROW(sota_client->addSecondary(std::make_shared<Primary::VirtualSecondary>(
716 Primary::VirtualSecondaryConfig::create_from_file(config.uptane.secondary_config_file)[0])),
727 TEST(
Uptane, UptaneSecondaryMisconfigured) {
729 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
730 auto http = std::make_shared<HttpFake>(temp_dir.Path());
732 Config config = config_common();
733 config.provision.provision_path = temp_dir /
"cred.zip";
734 config.provision.mode = ProvisionMode::kSharedCred;
735 config.pacman.type = PACKAGE_MANAGER_NONE;
736 config.storage.path = temp_dir.Path();
737 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
739 auto storage = INvStorage::newStorage(config.storage);
740 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
741 EXPECT_NO_THROW(sota_client->initialize());
743 std::vector<MisconfiguredEcu> ecus;
744 storage->loadMisconfiguredEcus(&ecus);
745 EXPECT_EQ(ecus.size(), 0);
748 Config config = config_common();
749 config.provision.provision_path = temp_dir /
"cred.zip";
750 config.provision.mode = ProvisionMode::kSharedCred;
751 config.pacman.type = PACKAGE_MANAGER_NONE;
752 config.storage.path = temp_dir.Path();
753 auto storage = INvStorage::newStorage(config.storage);
754 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"new_secondary_ecu_serial",
"new_secondary_hardware");
755 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
756 EXPECT_NO_THROW(sota_client->initialize());
758 std::vector<MisconfiguredEcu> ecus;
759 storage->loadMisconfiguredEcus(&ecus);
760 EXPECT_EQ(ecus.size(), 2);
761 if (ecus[0].serial.ToString() ==
"new_secondary_ecu_serial") {
762 EXPECT_EQ(ecus[0].state, EcuState::kUnused);
763 EXPECT_EQ(ecus[1].serial.ToString(),
"secondary_ecu_serial");
764 EXPECT_EQ(ecus[1].state, EcuState::kOld);
765 }
else if (ecus[0].serial.ToString() ==
"secondary_ecu_serial") {
766 EXPECT_EQ(ecus[0].state, EcuState::kOld);
767 EXPECT_EQ(ecus[1].serial.ToString(),
"new_secondary_ecu_serial");
768 EXPECT_EQ(ecus[1].state, EcuState::kUnused);
770 FAIL() <<
"Unexpected Secondary serial in storage: " << ecus[0].serial.ToString();
774 Config config = config_common();
775 config.provision.provision_path = temp_dir /
"cred.zip";
776 config.provision.mode = ProvisionMode::kSharedCred;
777 config.pacman.type = PACKAGE_MANAGER_NONE;
778 config.storage.path = temp_dir.Path();
779 auto storage = INvStorage::newStorage(config.storage);
780 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
781 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
782 EXPECT_NO_THROW(sota_client->initialize());
784 std::vector<MisconfiguredEcu> ecus;
785 storage->loadMisconfiguredEcus(&ecus);
786 EXPECT_EQ(ecus.size(), 0);
800 HttpFakeProv(
const boost::filesystem::path &test_dir_in, std::string flavor,
Config &config_in)
801 :
HttpFake(test_dir_in, std::move(flavor)), config(config_in) {}
803 HttpResponse post(
const std::string &url,
const std::string &content_type,
const std::string &
data)
override {
804 std::cout <<
"post " << url <<
"\n";
806 if (url.find(
"/system_info/config") != std::string::npos) {
809 std::stringstream conf_ss;
810 config.writeToStream(conf_ss);
811 EXPECT_EQ(data, conf_ss.str());
812 EXPECT_EQ(content_type,
"application/toml");
814 EXPECT_EQ(0, 1) <<
"Unexpected post to URL: " << url;
816 return HttpFake::post(url, content_type, data);
819 HttpResponse post(
const std::string &url,
const Json::Value &data)
override {
820 std::cout <<
"post " << url <<
"\n";
822 if (url.find(
"/devices") != std::string::npos) {
824 EXPECT_EQ(data[
"deviceId"].asString(),
"tst149_device_id");
825 return HttpResponse(Utils::readFile(
"tests/test_data/cred.p12"), 200, CURLE_OK,
"");
826 }
else if (url.find(
"/director/ecus") != std::string::npos) {
829 EXPECT_EQ(data[
"primary_ecu_serial"].asString(),
"CA:FE:A6:D2:84:9D");
830 EXPECT_EQ(data[
"ecus"][0][
"hardware_identifier"].asString(),
"primary_hw");
831 EXPECT_EQ(data[
"ecus"][0][
"ecu_serial"].asString(),
"CA:FE:A6:D2:84:9D");
832 if (ecus_count == 1) {
835 return HttpResponse(R
"({"code":"ecu_already_registered"})", 409, CURLE_OK, "");
837 }
else if (url.find(
"/events") != std::string::npos) {
838 return handle_event(url, data);
840 EXPECT_EQ(0, 1) <<
"Unexpected post to URL: " << url;
844 HttpResponse handle_event_single(
const Json::Value &event) {
845 if (event[
"eventType"][
"id"] ==
"DownloadProgressReport") {
848 const std::string event_type =
event[
"eventType"][
"id"].asString();
849 const std::string serial =
event[
"event"][
"ecu"].asString();
850 std::cout <<
"Got " << event_type <<
" event\n";
852 switch (events_seen) {
854 EXPECT_EQ(event_type,
"SendDeviceDataComplete");
860 if (event_type ==
"EcuDownloadStarted") {
861 if (serial ==
"CA:FE:A6:D2:84:9D") {
862 ++primary_download_start;
863 }
else if (serial ==
"secondary_ecu_serial") {
864 ++secondary_download_start;
866 }
else if (event_type ==
"EcuDownloadCompleted") {
867 if (serial ==
"CA:FE:A6:D2:84:9D") {
868 ++primary_download_complete;
869 }
else if (serial ==
"secondary_ecu_serial") {
870 ++secondary_download_complete;
873 if (events_seen == 4) {
874 EXPECT_EQ(primary_download_start, 1);
875 EXPECT_EQ(primary_download_complete, 1);
876 EXPECT_EQ(secondary_download_start, 1);
877 EXPECT_EQ(secondary_download_complete, 1);
882 EXPECT_EQ(event_type,
"EcuInstallationStarted");
883 EXPECT_EQ(serial,
"CA:FE:A6:D2:84:9D");
887 EXPECT_EQ(event_type,
"EcuInstallationCompleted");
888 EXPECT_EQ(serial,
"CA:FE:A6:D2:84:9D");
892 EXPECT_EQ(event_type,
"EcuInstallationStarted");
893 EXPECT_EQ(serial,
"secondary_ecu_serial");
897 EXPECT_EQ(event_type,
"EcuInstallationCompleted");
898 EXPECT_EQ(serial,
"secondary_ecu_serial");
901 std::cout <<
"Unexpected event: " << event_type;
907 HttpResponse handle_event(
const std::string &url,
const Json::Value &data)
override {
909 for (
const Json::Value &ev : data) {
910 handle_event_single(ev);
915 HttpResponse put(
const std::string &url,
const Json::Value &data)
override {
916 std::cout <<
"put " << url <<
"\n";
917 if (url.find(
"core/installed") != std::string::npos) {
920 EXPECT_EQ(data.size(), 1);
921 EXPECT_EQ(data[0][
"name"].asString(),
"fake-package");
922 EXPECT_EQ(data[0][
"version"].asString(),
"1.0");
923 }
else if (url.find(
"/director/manifest") != std::string::npos) {
928 std::string file_primary;
929 std::string file_secondary;
930 std::string hash_primary;
931 std::string hash_secondary;
932 if (manifest_count <= 1) {
933 file_primary =
"unknown";
934 file_secondary =
"noimage";
936 hash_primary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(
"")));
937 hash_secondary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(
"")));
939 file_primary =
"primary_firmware.txt";
940 file_secondary =
"secondary_firmware.txt";
941 const Json::Value json = Utils::parseJSON(Utils::readFile(meta_dir /
"director/targets_hasupdates.json"));
942 const Json::Value targets_list = json[
"signed"][
"targets"];
943 hash_primary = targets_list[
"primary_firmware.txt"][
"hashes"][
"sha256"].asString();
944 hash_secondary = targets_list[
"secondary_firmware.txt"][
"hashes"][
"sha256"].asString();
946 const Json::Value manifest = data[
"signed"][
"ecu_version_manifests"];
947 const Json::Value manifest_primary = manifest[
"CA:FE:A6:D2:84:9D"][
"signed"][
"installed_image"];
948 const Json::Value manifest_secondary = manifest[
"secondary_ecu_serial"][
"signed"][
"installed_image"];
949 EXPECT_EQ(file_primary, manifest_primary[
"filepath"].asString());
950 EXPECT_EQ(file_secondary, manifest_secondary[
"filepath"].asString());
951 EXPECT_EQ(manifest_primary[
"fileinfo"][
"hashes"][
"sha256"].asString(), hash_primary);
952 EXPECT_EQ(manifest_secondary[
"fileinfo"][
"hashes"][
"sha256"].asString(), hash_secondary);
953 }
else if (url.find(
"/system_info/network") != std::string::npos) {
956 Json::Value nwinfo = Utils::getNetworkInfo();
957 EXPECT_EQ(nwinfo[
"local_ipv4"].asString(), data[
"local_ipv4"].asString());
958 EXPECT_EQ(nwinfo[
"mac"].asString(), data[
"mac"].asString());
959 EXPECT_EQ(nwinfo[
"hostname"].asString(), data[
"hostname"].asString());
960 }
else if (url.find(
"/system_info") != std::string::npos) {
963 if (system_info_count <= 2) {
964 Json::Value hwinfo = Utils::getHardwareInfo();
965 EXPECT_EQ(hwinfo[
"id"].asString(), data[
"id"].asString());
966 EXPECT_EQ(hwinfo[
"description"].asString(), data[
"description"].asString());
967 EXPECT_EQ(hwinfo[
"class"].asString(), data[
"class"].asString());
968 EXPECT_EQ(hwinfo[
"product"].asString(), data[
"product"].asString());
970 EXPECT_EQ(custom_hw_info, data);
973 EXPECT_EQ(0, 1) <<
"Unexpected put to URL: " << url;
976 return HttpFake::put(url, data);
979 size_t events_seen{0};
980 int devices_count{0};
982 int manifest_count{0};
983 int installed_count{0};
984 int system_info_count{0};
985 int network_count{0};
987 Json::Value custom_hw_info;
991 int primary_download_start{0};
992 int primary_download_complete{0};
993 int secondary_download_start{0};
994 int secondary_download_complete{0};
1002 TEST(
Uptane, ProvisionOnServer) {
1003 RecordProperty(
"zephyr_key",
"OTA-984,TST-149");
1005 Config config(
"tests/config/basic.toml");
1006 auto http = std::make_shared<HttpFakeProv>(temp_dir.Path(),
"hasupdates", config);
1007 const std::string &server = http->tls_server;
1008 config.provision.server = server;
1009 config.tls.server = server;
1010 config.uptane.director_server = server +
"/director";
1011 config.uptane.repo_server = server +
"/repo";
1012 config.provision.ecu_registration_endpoint = server +
"/director/ecus";
1013 config.provision.device_id =
"tst149_device_id";
1014 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
1015 config.provision.primary_ecu_hardware_id =
"primary_hw";
1016 config.pacman.images_path = temp_dir.Path() /
"images";
1017 config.storage.path = temp_dir.Path();
1018 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1019 logger_set_threshold(boost::log::trivial::trace);
1021 auto storage = INvStorage::newStorage(config.storage);
1022 auto events_channel = std::make_shared<event::Channel>();
1023 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http, events_channel);
1025 EXPECT_EQ(http->devices_count, 0);
1026 EXPECT_EQ(http->ecus_count, 0);
1027 EXPECT_EQ(http->manifest_count, 0);
1028 EXPECT_EQ(http->installed_count, 0);
1029 EXPECT_EQ(http->system_info_count, 0);
1030 EXPECT_EQ(http->network_count, 0);
1031 EXPECT_EQ(http->config_count, 0);
1033 EXPECT_NO_THROW(up->initialize());
1035 storage->loadEcuSerials(&serials);
1036 EXPECT_EQ(serials[0].second.ToString(),
"primary_hw");
1038 EXPECT_EQ(http->devices_count, 1);
1039 EXPECT_EQ(http->ecus_count, 1);
1041 EXPECT_NO_THROW(up->sendDeviceData());
1042 EXPECT_EQ(http->installed_count, 1);
1043 EXPECT_EQ(http->system_info_count, 1);
1044 EXPECT_EQ(http->network_count, 1);
1045 EXPECT_EQ(http->config_count, 1);
1048 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
1049 EXPECT_EQ(http->manifest_count, 1);
1052 result::Download download_result = up->downloadImages(update_result.updates);
1053 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
1054 result::Install install_result = up->uptaneInstall(download_result.updates);
1055 EXPECT_TRUE(install_result.dev_report.isSuccess());
1056 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
1059 EXPECT_EQ(http->devices_count, 1);
1060 EXPECT_EQ(http->ecus_count, 1);
1061 EXPECT_EQ(http->manifest_count, 2);
1062 EXPECT_EQ(http->installed_count, 1);
1063 EXPECT_EQ(http->system_info_count, 1);
1064 EXPECT_EQ(http->network_count, 1);
1065 EXPECT_EQ(http->config_count, 1);
1066 EXPECT_EQ(http->events_seen, 8);
1070 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1071 EXPECT_EQ(http->installed_count, 1);
1072 EXPECT_EQ(http->system_info_count, 1);
1073 EXPECT_EQ(http->network_count, 1);
1074 EXPECT_EQ(http->config_count, 1);
1077 storage->clearDeviceData();
1078 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1079 EXPECT_EQ(http->installed_count, 2);
1080 EXPECT_EQ(http->system_info_count, 2);
1081 EXPECT_EQ(http->network_count, 2);
1082 EXPECT_EQ(http->config_count, 2);
1085 http->custom_hw_info[
"hardware"] =
"test-hw";
1086 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1087 EXPECT_EQ(http->installed_count, 2);
1088 EXPECT_EQ(http->system_info_count, 3);
1089 EXPECT_EQ(http->network_count, 2);
1090 EXPECT_EQ(http->config_count, 2);
1093 http->custom_hw_info[
"hardware"] =
"test-hw";
1094 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1095 EXPECT_EQ(http->installed_count, 2);
1096 EXPECT_EQ(http->system_info_count, 3);
1097 EXPECT_EQ(http->network_count, 2);
1098 EXPECT_EQ(http->config_count, 2);
1102 TEST(
Uptane, FsToSqlFull) {
1104 Utils::copyDir(
"tests/test_data/prov", temp_dir.Path());
1105 ASSERT_GE(chmod(temp_dir.Path().c_str(), S_IRWXU), 0);
1107 config.type = StorageType::kSqlite;
1108 config.path = temp_dir.Path();
1112 std::string public_key;
1113 std::string private_key;
1114 fs_storage.loadPrimaryKeys(&public_key, &private_key);
1119 fs_storage.loadTlsCreds(&ca, &cert, &pkey);
1121 std::string device_id;
1122 fs_storage.loadDeviceId(&device_id);
1125 fs_storage.loadEcuSerials(&serials);
1127 bool ecu_registered = fs_storage.loadEcuRegistered();
1129 std::vector<Uptane::Target> fs_installed_versions;
1130 std::vector<Uptane::Target> fixed_installed_versions;
1131 fs_storage.loadInstalledVersions(&fs_installed_versions,
nullptr);
1134 for (
auto &target : fs_installed_versions) {
1135 Json::Value dump = target.toDebugJson();
1136 dump[
"custom"][
"ecuIdentifiers"][serials[0].first.ToString()][
"hardwareId"] = serials[0].second.ToString();
1137 fixed_installed_versions.emplace_back(
Uptane::Target(target.filename(), dump));
1140 std::string director_root;
1141 std::string director_targets;
1142 std::string image_root;
1143 std::string image_targets;
1144 std::string image_timestamp;
1145 std::string image_snapshot;
1147 EXPECT_TRUE(fs_storage.loadLatestRoot(&director_root, Uptane::RepositoryType::Director()));
1148 EXPECT_TRUE(fs_storage.loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1149 EXPECT_TRUE(fs_storage.loadLatestRoot(&image_root, Uptane::RepositoryType::Image()));
1150 EXPECT_TRUE(fs_storage.loadNonRoot(&image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1151 EXPECT_TRUE(fs_storage.loadNonRoot(&image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1152 EXPECT_TRUE(fs_storage.loadNonRoot(&image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1154 EXPECT_TRUE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1155 EXPECT_TRUE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1156 EXPECT_TRUE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1157 EXPECT_TRUE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1158 EXPECT_TRUE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1160 boost::filesystem::path image_path = config.uptane_metadata_path.get(config.path) /
"repo";
1161 boost::filesystem::path director_path = config.uptane_metadata_path.get(config.path) /
"director";
1162 EXPECT_TRUE(boost::filesystem::exists(director_path /
"1.root.json"));
1163 EXPECT_TRUE(boost::filesystem::exists(director_path /
"targets.json"));
1164 EXPECT_TRUE(boost::filesystem::exists(image_path /
"1.root.json"));
1165 EXPECT_TRUE(boost::filesystem::exists(image_path /
"targets.json"));
1166 EXPECT_TRUE(boost::filesystem::exists(image_path /
"timestamp.json"));
1167 EXPECT_TRUE(boost::filesystem::exists(image_path /
"snapshot.json"));
1168 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"device_id")));
1169 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"is_registered")));
1170 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_serial")));
1171 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_hardware_id")));
1172 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"secondaries_list")));
1173 auto sql_storage = INvStorage::newStorage(config);
1175 EXPECT_FALSE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1176 EXPECT_FALSE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1177 EXPECT_FALSE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1178 EXPECT_FALSE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1179 EXPECT_FALSE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1181 EXPECT_FALSE(boost::filesystem::exists(director_path /
"root.json"));
1182 EXPECT_FALSE(boost::filesystem::exists(director_path /
"targets.json"));
1183 EXPECT_FALSE(boost::filesystem::exists(director_path /
"root.json"));
1184 EXPECT_FALSE(boost::filesystem::exists(director_path /
"targets.json"));
1185 EXPECT_FALSE(boost::filesystem::exists(image_path /
"timestamp.json"));
1186 EXPECT_FALSE(boost::filesystem::exists(image_path /
"snapshot.json"));
1187 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"device_id")));
1188 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"is_registered")));
1189 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_serial")));
1190 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_hardware_id")));
1191 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"secondaries_list")));
1193 std::string sql_public_key;
1194 std::string sql_private_key;
1195 sql_storage->loadPrimaryKeys(&sql_public_key, &sql_private_key);
1198 std::string sql_cert;
1199 std::string sql_pkey;
1200 sql_storage->loadTlsCreds(&sql_ca, &sql_cert, &sql_pkey);
1202 std::string sql_device_id;
1203 sql_storage->loadDeviceId(&sql_device_id);
1205 EcuSerials sql_serials;
1206 sql_storage->loadEcuSerials(&sql_serials);
1208 bool sql_ecu_registered = sql_storage->loadEcuRegistered();
1210 std::vector<Uptane::Target> sql_installed_versions;
1211 sql_storage->loadPrimaryInstallationLog(&sql_installed_versions,
true);
1213 std::string sql_director_root;
1214 std::string sql_director_targets;
1215 std::string sql_image_root;
1216 std::string sql_image_targets;
1217 std::string sql_image_timestamp;
1218 std::string sql_image_snapshot;
1220 sql_storage->loadLatestRoot(&sql_director_root, Uptane::RepositoryType::Director());
1221 sql_storage->loadNonRoot(&sql_director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
1222 sql_storage->loadLatestRoot(&sql_image_root, Uptane::RepositoryType::Image());
1223 sql_storage->loadNonRoot(&sql_image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
1224 sql_storage->loadNonRoot(&sql_image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
1225 sql_storage->loadNonRoot(&sql_image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
1227 EXPECT_EQ(sql_public_key, public_key);
1228 EXPECT_EQ(sql_private_key, private_key);
1229 EXPECT_EQ(sql_ca, ca);
1230 EXPECT_EQ(sql_cert, cert);
1231 EXPECT_EQ(sql_pkey, pkey);
1232 EXPECT_EQ(sql_device_id, device_id);
1233 EXPECT_EQ(sql_serials, serials);
1234 EXPECT_EQ(sql_ecu_registered, ecu_registered);
1235 EXPECT_TRUE(Uptane::MatchTargetVector(sql_installed_versions, fixed_installed_versions));
1237 EXPECT_EQ(sql_director_root, director_root);
1238 EXPECT_EQ(sql_director_targets, director_targets);
1239 EXPECT_EQ(sql_image_root, image_root);
1240 EXPECT_EQ(sql_image_targets, image_targets);
1241 EXPECT_EQ(sql_image_timestamp, image_timestamp);
1242 EXPECT_EQ(sql_image_snapshot, image_snapshot);
1246 TEST(
Uptane, InstalledVersionImport) {
1247 Config config = config_common();
1250 Utils::createDirectories(temp_dir /
"import", S_IRWXU);
1251 config.storage.path = temp_dir.Path();
1252 config.import.base_path = temp_dir /
"import";
1253 config.postUpdateValues();
1255 boost::filesystem::copy_file(
"tests/test_data/prov/installed_versions",
1256 temp_dir.Path() /
"import/installed_versions");
1259 auto storage = INvStorage::newStorage(config.storage);
1260 storage->importData(config.import);
1262 boost::optional<Uptane::Target> current_version;
1263 storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1264 EXPECT_TRUE(!!current_version);
1265 EXPECT_EQ(current_version->filename(),
"master-863de625f305413dc3be306afab7c3f39d8713045cfff812b3af83f9722851f0");
1269 Json::Value target_json;
1270 target_json[
"hashes"][
"sha256"] =
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1271 target_json[
"length"] = 123;
1273 storage->savePrimaryInstalledVersion(new_installed_version, InstalledVersionUpdateMode::kCurrent);
1275 auto new_storage = INvStorage::newStorage(config.storage);
1276 new_storage->importData(config.import);
1278 current_version = boost::none;
1279 new_storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1280 EXPECT_TRUE(!!current_version);
1281 EXPECT_EQ(current_version->filename(),
"filename");
1285 TEST(
Uptane, SaveAndLoadVersion) {
1287 Config config = config_common();
1288 config.storage.path = temp_dir.Path();
1289 config.provision.device_id =
"device_id";
1290 config.postUpdateValues();
1291 auto storage = INvStorage::newStorage(config.storage);
1293 Json::Value target_json;
1294 target_json[
"hashes"][
"sha256"] =
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1295 target_json[
"length"] = 123;
1298 storage->savePrimaryInstalledVersion(t, InstalledVersionUpdateMode::kCurrent);
1300 boost::optional<Uptane::Target> current_version;
1301 storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1303 EXPECT_TRUE(!!current_version);
1304 EXPECT_EQ(current_version->sha256Hash(),
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d");
1305 EXPECT_EQ(current_version->length(), 123);
1306 EXPECT_TRUE(current_version->MatchTarget(t));
1312 HttpResponse get(
const std::string &url, int64_t maxsize)
override {
1313 if (unstable_valid_count >= unstable_valid_num) {
1316 ++unstable_valid_count;
1317 return HttpFake::get(url, maxsize);
1321 void setUnstableValidNum(
int num) {
1322 unstable_valid_num = num;
1323 unstable_valid_count = 0;
1326 int unstable_valid_num{0};
1327 int unstable_valid_count{0};
1339 TEST(
Uptane, restoreVerify) {
1341 auto http = std::make_shared<HttpFakeUnstable>(temp_dir.Path());
1342 Config config(
"tests/config/basic.toml");
1343 config.storage.path = temp_dir.Path();
1344 config.pacman.type = PACKAGE_MANAGER_NONE;
1345 config.uptane.director_server = http->tls_server +
"director";
1346 config.uptane.repo_server = http->tls_server +
"repo";
1347 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
1348 config.provision.primary_ecu_hardware_id =
"primary_hw";
1349 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1350 config.postUpdateValues();
1352 auto storage = INvStorage::newStorage(config.storage);
1353 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1355 EXPECT_NO_THROW(sota_client->initialize());
1356 sota_client->AssembleManifest();
1359 EXPECT_FALSE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1362 http->setUnstableValidNum(1);
1364 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1365 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1368 http->setUnstableValidNum(2);
1370 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1371 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1372 EXPECT_FALSE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Image()));
1375 http->setUnstableValidNum(3);
1377 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Image()));
1378 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1381 http->setUnstableValidNum(4);
1383 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1384 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1387 http->setUnstableValidNum(5);
1389 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1390 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1393 http->setUnstableValidNum(6);
1394 EXPECT_NO_THROW(sota_client->uptaneIteration(
nullptr,
nullptr));
1395 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1403 TEST(
Uptane, offlineIteration) {
1405 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1406 Config config(
"tests/config/basic.toml");
1407 config.storage.path = temp_dir.Path();
1408 config.uptane.director_server = http->tls_server +
"director";
1409 config.uptane.repo_server = http->tls_server +
"repo";
1410 config.pacman.type = PACKAGE_MANAGER_NONE;
1411 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
1412 config.provision.primary_ecu_hardware_id =
"primary_hw";
1413 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1414 config.postUpdateValues();
1416 auto storage = INvStorage::newStorage(config.storage);
1417 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1418 EXPECT_NO_THROW(sota_client->initialize());
1420 std::vector<Uptane::Target> targets_online;
1421 EXPECT_NO_THROW(sota_client->uptaneIteration(&targets_online,
nullptr));
1423 std::vector<Uptane::Target> targets_offline;
1424 EXPECT_NO_THROW(sota_client->uptaneOfflineIteration(&targets_offline,
nullptr));
1425 EXPECT_TRUE(Uptane::MatchTargetVector(targets_online, targets_offline));
1432 TEST(
Uptane, IgnoreUnknownUpdate) {
1434 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1435 Config config(
"tests/config/basic.toml");
1436 config.storage.path = temp_dir.Path();
1437 config.uptane.director_server = http->tls_server +
"director";
1438 config.uptane.repo_server = http->tls_server +
"repo";
1439 config.pacman.type = PACKAGE_MANAGER_NONE;
1440 config.provision.primary_ecu_serial =
"primary_ecu";
1441 config.provision.primary_ecu_hardware_id =
"primary_hw";
1442 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1443 config.postUpdateValues();
1445 auto storage = INvStorage::newStorage(config.storage);
1446 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1448 EXPECT_NO_THROW(sota_client->initialize());
1450 auto result = sota_client->fetchMeta();
1451 EXPECT_EQ(result.status, result::UpdateStatus::kError);
1452 std::vector<Uptane::Target> packages_to_install = UptaneTestCommon::makePackage(
"testecuserial",
"testecuhwid");
1453 auto report = sota_client->uptaneInstall(packages_to_install);
1454 EXPECT_EQ(report.ecu_reports.size(), 0);
1458 TEST(
Uptane, Pkcs11Provision) {
1461 Utils::createDirectories(temp_dir /
"import", S_IRWXU);
1462 boost::filesystem::copy_file(
"tests/test_data/device_cred_prov/ca.pem", temp_dir /
"import/root.crt");
1463 config.tls.cert_source = CryptoSource::kPkcs11;
1464 config.tls.pkey_source = CryptoSource::kPkcs11;
1465 config.p11.module = TEST_PKCS11_MODULE_PATH;
1466 config.p11.pass =
"1234";
1467 config.p11.tls_clientcert_id =
"01";
1468 config.p11.tls_pkey_id =
"02";
1469 config.import.base_path = (temp_dir /
"import").
string();
1472 config.storage.path = temp_dir.Path();
1473 config.postUpdateValues();
1475 auto storage = INvStorage::newStorage(config.storage);
1476 storage->importData(config.import);
1477 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1478 KeyManager keys(storage, config.keymanagerConfig());
1480 EXPECT_NO_THROW(
Initializer(config.provision, storage, http, keys, {}));
1485 int main(
int argc,
char **argv) {
1486 ::testing::InitGoogleTest(&argc, argv);
1489 logger_set_threshold(boost::log::trivial::trace);
1491 return RUN_ALL_TESTS();
All ECU installation attempts for an update have completed.
Check that basic device info sent by aktualizr during provisioning matches our expectations.
Container for information about downloading an update.
Configuration object for an aktualizr instance running on a Primary ECU.
Operation has already been processed.
An installation attempt on an ECU has completed.
Container for information about installing an update.
SWM Internal integrity error.
Container for information about available updates.
The BasedPath class Can represent an absolute or relative path, only readable through the BasePath::g...
Results of libaktualizr API calls.
Base data types that are used in The Update Framework (TUF), part of Uptane.