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/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" 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 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");
223 auto storage = INvStorage::newStorage(config.storage);
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());
229 Json::Value json = http->last_manifest;
231 EXPECT_EQ(json[
"signatures"].size(), 1u);
232 EXPECT_EQ(json[
"signed"][
"primary_ecu_serial"].asString(),
"testecuserial");
234 json[
"signed"][
"ecu_version_manifests"][
"testecuserial"][
"signed"][
"installed_image"][
"filepath"].asString(),
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"]
248 HttpResponse put(
const std::string &url,
const Json::Value &
data)
override {
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++;
266 TEST(
Uptane, PutManifestError) {
268 auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path());
270 Config conf(
"tests/config/basic.toml");
271 conf.storage.path = temp_dir.Path();
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);
290 TEST(
Uptane, FetchMetaFail) {
292 auto http = std::make_shared<HttpPutManifestFail>(temp_dir.Path(),
"noupdates");
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;
302 auto storage = INvStorage::newStorage(conf.storage);
303 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
305 EXPECT_NO_THROW(up->initialize());
307 EXPECT_EQ(result.status, result::UpdateStatus::kNoUpdatesAvailable);
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") {
315 if (num_events_InstallTarget <= 1) {
316 EXPECT_TRUE(concrete_event->success);
318 EXPECT_FALSE(concrete_event->success);
320 num_events_InstallTarget++;
322 if (event->variant ==
"AllInstallsComplete") {
324 if (num_events_AllInstalls == 0) {
325 EXPECT_TRUE(concrete_event->result.dev_report.isSuccess());
326 }
else if (num_events_AllInstalls == 1) {
327 EXPECT_FALSE(concrete_event->result.dev_report.isSuccess());
330 EXPECT_FALSE(concrete_event->result.dev_report.isSuccess());
333 num_events_AllInstalls++;
349 TEST(
Uptane, InstallFakeGood) {
350 Config conf(
"tests/config/basic.toml");
352 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
353 conf.uptane.director_server = http->tls_server +
"director";
354 conf.uptane.repo_server = http->tls_server +
"repo";
355 conf.pacman.type = PACKAGE_MANAGER_NONE;
356 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
357 conf.provision.primary_ecu_hardware_id =
"primary_hw";
358 conf.storage.path = temp_dir.Path();
359 conf.tls.server = http->tls_server;
360 UptaneTestCommon::addDefaultSecondary(conf, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
361 conf.postUpdateValues();
363 auto storage = INvStorage::newStorage(conf.storage);
364 auto events_channel = std::make_shared<event::Channel>();
365 std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
366 events_channel->connect(f_cb);
367 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http, events_channel);
368 EXPECT_NO_THROW(up->initialize());
371 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
372 result::Download download_result = up->downloadImages(update_result.updates);
373 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
374 result::Install install_result1 = up->uptaneInstall(download_result.updates);
375 EXPECT_TRUE(install_result1.dev_report.isSuccess());
376 EXPECT_EQ(install_result1.dev_report.result_code, data::ResultCode::Numeric::kOk);
379 Json::Value manifest = up->AssembleManifest();
380 EXPECT_EQ(manifest[
"ecu_version_manifests"][
"CA:FE:A6:D2:84:9D"][
"signed"][
"installed_image"][
"filepath"].asString(),
381 "primary_firmware.txt");
383 manifest[
"ecu_version_manifests"][
"secondary_ecu_serial"][
"signed"][
"installed_image"][
"filepath"].asString(),
384 "secondary_firmware.txt");
386 EXPECT_EQ(num_events_InstallTarget, 2);
387 EXPECT_EQ(num_events_AllInstalls, 1);
388 Json::Value installation_report = manifest[
"installation_report"][
"report"];
389 EXPECT_EQ(installation_report[
"result"][
"success"].asBool(),
true);
390 EXPECT_EQ(installation_report[
"result"][
"code"].asString(),
"OK");
391 EXPECT_EQ(installation_report[
"items"][0][
"ecu"].asString(),
"CA:FE:A6:D2:84:9D");
392 EXPECT_EQ(installation_report[
"items"][0][
"result"][
"success"].asBool(),
true);
393 EXPECT_EQ(installation_report[
"items"][0][
"result"][
"code"].asString(),
"OK");
394 EXPECT_EQ(installation_report[
"items"][1][
"ecu"].asString(),
"secondary_ecu_serial");
395 EXPECT_EQ(installation_report[
"items"][1][
"result"][
"success"].asBool(),
true);
396 EXPECT_EQ(installation_report[
"items"][1][
"result"][
"code"].asString(),
"OK");
400 result::Install install_result2 = up->uptaneInstall(download_result.updates);
401 EXPECT_FALSE(install_result2.dev_report.isSuccess());
403 EXPECT_EQ(num_events_InstallTarget, 2);
404 EXPECT_EQ(num_events_AllInstalls, 2);
405 manifest = up->AssembleManifest();
406 installation_report = manifest[
"installation_report"][
"report"];
407 EXPECT_EQ(installation_report[
"result"][
"success"].asBool(),
false);
412 EXPECT_EQ(update_result2.status, result::UpdateStatus::kNoUpdatesAvailable);
416 boost::optional<Uptane::Target> current_version;
417 EXPECT_TRUE(storage->loadInstalledVersions(
"CA:FE:A6:D2:84:9D", ¤t_version,
nullptr));
418 const auto bad_target =
Uptane::Target(current_version->filename(), current_version->ecus(), std::vector<Hash>{},
419 current_version->length());
420 storage->saveInstalledVersion(
"CA:FE:A6:D2:84:9D", bad_target, InstalledVersionUpdateMode::kCurrent);
424 result::Install install_result3 = up->uptaneInstall(download_result.updates);
425 EXPECT_FALSE(install_result3.dev_report.isSuccess());
428 EXPECT_EQ(num_events_InstallTarget, 2);
429 EXPECT_EQ(num_events_AllInstalls, 3);
436 TEST(
Uptane, InstallFakeBad) {
437 Config conf(
"tests/config/basic.toml");
439 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
440 conf.uptane.director_server = http->tls_server +
"director";
441 conf.uptane.repo_server = http->tls_server +
"repo";
442 conf.pacman.type = PACKAGE_MANAGER_NONE;
443 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
444 conf.provision.primary_ecu_hardware_id =
"primary_hw";
445 conf.storage.path = temp_dir.Path();
446 conf.tls.server = http->tls_server;
447 UptaneTestCommon::addDefaultSecondary(conf, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
448 conf.postUpdateValues();
450 auto storage = INvStorage::newStorage(conf.storage);
451 std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = process_events_Install;
452 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
453 EXPECT_NO_THROW(up->initialize());
456 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
457 result::Download download_result = up->downloadImages(update_result.updates);
458 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
460 std::string hash = download_result.updates[0].sha256Hash();
461 std::transform(hash.begin(), hash.end(), hash.begin(), ::toupper);
462 boost::filesystem::path image = temp_dir /
"images" / hash;
466 auto rhandle = storage->openTargetFile(download_result.updates[0]);
467 const uint64_t length = download_result.updates[0].length();
468 uint8_t content[length];
469 EXPECT_EQ(rhandle->rread(content, length), length);
471 auto whandle = storage->allocateTargetFile(download_result.updates[0]);
472 uint8_t content_bad[length + 1];
473 memset(content_bad, 0, length + 1);
474 EXPECT_EQ(whandle->wfeed(content_bad, 3), 3);
477 result::Install install_result = up->uptaneInstall(download_result.updates);
478 EXPECT_FALSE(install_result.dev_report.isSuccess());
482 whandle = storage->allocateTargetFile(download_result.updates[0]);
483 EXPECT_EQ(whandle->wfeed(content_bad, length + 1), length + 1);
486 install_result = up->uptaneInstall(download_result.updates);
487 EXPECT_FALSE(install_result.dev_report.isSuccess());
492 whandle = storage->allocateTargetFile(download_result.updates[0]);
493 EXPECT_EQ(whandle->wfeed(content_bad, length), length);
496 install_result = up->uptaneInstall(download_result.updates);
497 EXPECT_FALSE(install_result.dev_report.isSuccess());
501 whandle = storage->allocateTargetFile(download_result.updates[0]);
502 EXPECT_EQ(whandle->wfeed(reinterpret_cast<uint8_t *>(content), length - 1), length - 1);
505 install_result = up->uptaneInstall(download_result.updates);
506 EXPECT_FALSE(install_result.dev_report.isSuccess());
510 whandle = storage->allocateTargetFile(download_result.updates[0]);
511 EXPECT_EQ(whandle->wfeed(reinterpret_cast<uint8_t *>(content), length), length);
514 install_result = up->uptaneInstall(download_result.updates);
515 EXPECT_TRUE(install_result.dev_report.isSuccess());
516 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
519 bool EcuInstallationStartedReportGot =
false;
522 HttpFakeEvents(
const boost::filesystem::path &test_dir_in, std::string flavor =
"")
523 :
HttpFake(test_dir_in, std::move(flavor)) {}
525 virtual HttpResponse handle_event(
const std::string &url,
const Json::Value &
data)
override {
526 for (
const auto &event : data) {
527 if (event[
"eventType"][
"id"].asString() ==
"EcuInstallationStarted") {
528 if (event[
"event"][
"ecu"].asString() ==
"secondary_ecu_serial") {
529 EcuInstallationStartedReportGot =
true;
540 std::string private_key, public_key;
541 if (!Crypto::generateKeyPair(sconfig.key_type, &public_key, &private_key)) {
542 throw std::runtime_error(
"Key generation failure");
544 public_key_ =
PublicKey(public_key, sconfig.key_type);
545 Json::Value manifest_unsigned;
546 manifest_unsigned[
"key"] =
"value";
548 std::string b64sig = Utils::toBase64(
549 Crypto::Sign(sconfig.key_type,
nullptr, private_key, Utils::jsonToCanonicalStr(manifest_unsigned)));
550 Json::Value signature;
551 signature[
"method"] =
"rsassa-pss";
552 signature[
"sig"] = b64sig;
553 signature[
"keyid"] = public_key_.KeyId();
554 manifest_[
"signed"] = manifest_unsigned;
555 manifest_[
"signatures"].append(signature);
557 std::string Type()
const override {
return "mock"; }
558 PublicKey getPublicKey()
const override {
return public_key_; }
562 if (!sconfig.ecu_serial.empty()) {
568 bool ping()
const override {
return true; }
570 MOCK_METHOD(int32_t, getRootVersionMock, (
bool), (
const));
573 putMetadataMock(meta_pack);
576 int32_t getRootVersion(
bool director)
const override {
return getRootVersionMock(director); }
578 bool putRoot(
const std::string &,
bool)
override {
return true; }
579 bool sendFirmware(
const std::string &)
override {
return true; }
583 Json::Value manifest_;
588 MATCHER_P(matchMeta, meta,
"") {
589 return (arg.director_root == meta.director_root) && (arg.image_root == meta.image_root) &&
590 (arg.director_targets == meta.director_targets) && (arg.image_timestamp == meta.image_timestamp) &&
591 (arg.image_snapshot == meta.image_snapshot) && (arg.image_targets == meta.image_targets);
598 TEST(
Uptane, SendMetadataToSecondary) {
599 Config conf(
"tests/config/basic.toml");
601 auto http = std::make_shared<HttpFakeEvents>(temp_dir.Path(),
"hasupdates");
602 conf.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
603 conf.provision.primary_ecu_hardware_id =
"primary_hw";
604 conf.uptane.director_server = http->tls_server +
"/director";
605 conf.uptane.repo_server = http->tls_server +
"/repo";
606 conf.storage.path = temp_dir.Path();
607 conf.tls.server = http->tls_server;
610 ecu_config.partial_verifying =
false;
611 ecu_config.full_client_dir = temp_dir.Path();
612 ecu_config.ecu_serial =
"secondary_ecu_serial";
613 ecu_config.ecu_hardware_id =
"secondary_hw";
614 ecu_config.ecu_private_key =
"sec.priv";
615 ecu_config.ecu_public_key =
"sec.pub";
616 ecu_config.firmware_path = temp_dir /
"firmware.txt";
617 ecu_config.target_name_path = temp_dir /
"firmware_name.txt";
618 ecu_config.metadata_path = temp_dir /
"secondary_metadata";
620 auto sec = std::make_shared<SecondaryInterfaceMock>(ecu_config);
621 auto storage = INvStorage::newStorage(conf.storage);
622 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(conf, storage, http);
623 up->addSecondary(sec);
624 EXPECT_NO_THROW(up->initialize());
626 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
629 storage->loadLatestRoot(&meta.director_root, Uptane::RepositoryType::Director());
630 storage->loadNonRoot(&meta.director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
631 storage->loadLatestRoot(&meta.image_root, Uptane::RepositoryType::Image());
632 storage->loadNonRoot(&meta.image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
633 storage->loadNonRoot(&meta.image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
634 storage->loadNonRoot(&meta.image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
636 EXPECT_CALL(*sec, putMetadataMock(matchMeta(meta)));
637 result::Download download_result = up->downloadImages(update_result.updates);
638 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
639 result::Install install_result = up->uptaneInstall(download_result.updates);
640 EXPECT_TRUE(install_result.dev_report.isSuccess());
641 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
642 EXPECT_TRUE(EcuInstallationStartedReportGot);
646 TEST(
Uptane, UptaneSecondaryAdd) {
648 auto http = std::make_shared<HttpFake>(temp_dir.Path());
649 Config config = config_common();
650 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
651 config.provision.provision_path = temp_dir /
"cred.zip";
652 config.provision.mode = ProvisionMode::kSharedCred;
653 config.uptane.director_server = http->tls_server +
"/director";
654 config.uptane.repo_server = http->tls_server +
"/repo";
655 config.tls.server = http->tls_server;
656 config.provision.primary_ecu_serial =
"testecuserial";
657 config.storage.path = temp_dir.Path();
658 config.pacman.type = PACKAGE_MANAGER_NONE;
659 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
661 auto storage = INvStorage::newStorage(config.storage);
662 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
663 EXPECT_NO_THROW(sota_client->initialize());
667 Json::Value ecu_data = Utils::parseJSONFile(temp_dir /
"post.json");
668 EXPECT_EQ(ecu_data[
"ecus"].size(), 2);
669 EXPECT_EQ(ecu_data[
"primary_ecu_serial"].asString(), config.provision.primary_ecu_serial);
670 EXPECT_EQ(ecu_data[
"ecus"][1][
"ecu_serial"].asString(),
"secondary_ecu_serial");
671 EXPECT_EQ(ecu_data[
"ecus"][1][
"hardware_identifier"].asString(),
"secondary_hardware");
672 EXPECT_EQ(ecu_data[
"ecus"][1][
"clientKey"][
"keytype"].asString(),
"RSA");
673 EXPECT_TRUE(ecu_data[
"ecus"][1][
"clientKey"][
"keyval"][
"public"].asString().size() > 0);
677 TEST(
Uptane, UptaneSecondaryAddSameSerial) {
679 auto http = std::make_shared<HttpFake>(temp_dir.Path());
680 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
681 Config config = config_common();
682 config.provision.provision_path = temp_dir /
"cred.zip";
683 config.provision.mode = ProvisionMode::kSharedCred;
684 config.pacman.type = PACKAGE_MANAGER_NONE;
685 config.storage.path = temp_dir.Path();
687 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
689 auto storage = INvStorage::newStorage(config.storage);
690 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
691 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware_new");
692 EXPECT_THROW(sota_client->addSecondary(std::make_shared<Primary::VirtualSecondary>(
693 Primary::VirtualSecondaryConfig::create_from_file(config.uptane.secondary_config_file)[0])),
704 TEST(
Uptane, UptaneSecondaryMisconfigured) {
706 boost::filesystem::copy_file(
"tests/test_data/cred.zip", temp_dir /
"cred.zip");
707 auto http = std::make_shared<HttpFake>(temp_dir.Path());
709 Config config = config_common();
710 config.provision.provision_path = temp_dir /
"cred.zip";
711 config.provision.mode = ProvisionMode::kSharedCred;
712 config.pacman.type = PACKAGE_MANAGER_NONE;
713 config.storage.path = temp_dir.Path();
714 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
716 auto storage = INvStorage::newStorage(config.storage);
717 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
718 EXPECT_NO_THROW(sota_client->initialize());
720 std::vector<MisconfiguredEcu> ecus;
721 storage->loadMisconfiguredEcus(&ecus);
722 EXPECT_EQ(ecus.size(), 0);
725 Config config = config_common();
726 config.provision.provision_path = temp_dir /
"cred.zip";
727 config.provision.mode = ProvisionMode::kSharedCred;
728 config.pacman.type = PACKAGE_MANAGER_NONE;
729 config.storage.path = temp_dir.Path();
730 auto storage = INvStorage::newStorage(config.storage);
731 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"new_secondary_ecu_serial",
"new_secondary_hardware");
732 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
733 EXPECT_NO_THROW(sota_client->initialize());
735 std::vector<MisconfiguredEcu> ecus;
736 storage->loadMisconfiguredEcus(&ecus);
737 EXPECT_EQ(ecus.size(), 2);
738 if (ecus[0].serial.ToString() ==
"new_secondary_ecu_serial") {
739 EXPECT_EQ(ecus[0].state, EcuState::kNotRegistered);
740 EXPECT_EQ(ecus[1].serial.ToString(),
"secondary_ecu_serial");
741 EXPECT_EQ(ecus[1].state, EcuState::kOld);
742 }
else if (ecus[0].serial.ToString() ==
"secondary_ecu_serial") {
743 EXPECT_EQ(ecus[0].state, EcuState::kOld);
744 EXPECT_EQ(ecus[1].serial.ToString(),
"new_secondary_ecu_serial");
745 EXPECT_EQ(ecus[1].state, EcuState::kNotRegistered);
747 FAIL() <<
"Unexpected Secondary serial in storage: " << ecus[0].serial.ToString();
751 Config config = config_common();
752 config.provision.provision_path = temp_dir /
"cred.zip";
753 config.provision.mode = ProvisionMode::kSharedCred;
754 config.pacman.type = PACKAGE_MANAGER_NONE;
755 config.storage.path = temp_dir.Path();
756 auto storage = INvStorage::newStorage(config.storage);
757 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hardware");
758 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
759 EXPECT_NO_THROW(sota_client->initialize());
761 std::vector<MisconfiguredEcu> ecus;
762 storage->loadMisconfiguredEcus(&ecus);
763 EXPECT_EQ(ecus.size(), 0);
777 HttpFakeProv(
const boost::filesystem::path &test_dir_in, std::string flavor,
Config &config_in)
778 :
HttpFake(test_dir_in, std::move(flavor)), config(config_in) {}
780 HttpResponse post(
const std::string &url,
const std::string &content_type,
const std::string &
data)
override {
781 std::cout <<
"post " << url <<
"\n";
783 if (url.find(
"/system_info/config") != std::string::npos) {
786 std::stringstream conf_ss;
787 config.writeToStream(conf_ss);
788 EXPECT_EQ(data, conf_ss.str());
789 EXPECT_EQ(content_type,
"application/toml");
791 EXPECT_EQ(0, 1) <<
"Unexpected post to URL: " << url;
793 return HttpFake::post(url, content_type, data);
796 HttpResponse post(
const std::string &url,
const Json::Value &data)
override {
797 std::cout <<
"post " << url <<
"\n";
799 if (url.find(
"/devices") != std::string::npos) {
801 EXPECT_EQ(data[
"deviceId"].asString(),
"tst149_device_id");
802 return HttpResponse(Utils::readFile(
"tests/test_data/cred.p12"), 200, CURLE_OK,
"");
803 }
else if (url.find(
"/director/ecus") != std::string::npos) {
806 EXPECT_EQ(data[
"primary_ecu_serial"].asString(),
"CA:FE:A6:D2:84:9D");
807 EXPECT_EQ(data[
"ecus"][0][
"hardware_identifier"].asString(),
"primary_hw");
808 EXPECT_EQ(data[
"ecus"][0][
"ecu_serial"].asString(),
"CA:FE:A6:D2:84:9D");
809 if (ecus_count == 1) {
812 return HttpResponse(R
"({"code":"ecu_already_registered"})", 409, CURLE_OK, "");
814 }
else if (url.find(
"/events") != std::string::npos) {
815 return handle_event(url, data);
817 EXPECT_EQ(0, 1) <<
"Unexpected post to URL: " << url;
821 HttpResponse handle_event_single(
const Json::Value &event) {
822 if (event[
"eventType"][
"id"] ==
"DownloadProgressReport") {
825 const std::string event_type =
event[
"eventType"][
"id"].asString();
826 const std::string serial =
event[
"event"][
"ecu"].asString();
827 std::cout <<
"Got " << event_type <<
" event\n";
829 switch (events_seen) {
831 EXPECT_EQ(event_type,
"SendDeviceDataComplete");
837 if (event_type ==
"EcuDownloadStarted") {
838 if (serial ==
"CA:FE:A6:D2:84:9D") {
839 ++primary_download_start;
840 }
else if (serial ==
"secondary_ecu_serial") {
841 ++secondary_download_start;
843 }
else if (event_type ==
"EcuDownloadCompleted") {
844 if (serial ==
"CA:FE:A6:D2:84:9D") {
845 ++primary_download_complete;
846 }
else if (serial ==
"secondary_ecu_serial") {
847 ++secondary_download_complete;
850 if (events_seen == 4) {
851 EXPECT_EQ(primary_download_start, 1);
852 EXPECT_EQ(primary_download_complete, 1);
853 EXPECT_EQ(secondary_download_start, 1);
854 EXPECT_EQ(secondary_download_complete, 1);
859 EXPECT_EQ(event_type,
"EcuInstallationStarted");
860 EXPECT_EQ(serial,
"CA:FE:A6:D2:84:9D");
864 EXPECT_EQ(event_type,
"EcuInstallationCompleted");
865 EXPECT_EQ(serial,
"CA:FE:A6:D2:84:9D");
869 EXPECT_EQ(event_type,
"EcuInstallationStarted");
870 EXPECT_EQ(serial,
"secondary_ecu_serial");
874 EXPECT_EQ(event_type,
"EcuInstallationCompleted");
875 EXPECT_EQ(serial,
"secondary_ecu_serial");
878 std::cout <<
"Unexpected event: " << event_type;
884 HttpResponse handle_event(
const std::string &url,
const Json::Value &data)
override {
886 for (
const Json::Value &ev : data) {
887 handle_event_single(ev);
892 HttpResponse put(
const std::string &url,
const Json::Value &data)
override {
893 std::cout <<
"put " << url <<
"\n";
894 if (url.find(
"core/installed") != std::string::npos) {
897 EXPECT_EQ(data.size(), 1);
898 EXPECT_EQ(data[0][
"name"].asString(),
"fake-package");
899 EXPECT_EQ(data[0][
"version"].asString(),
"1.0");
900 }
else if (url.find(
"/director/manifest") != std::string::npos) {
905 std::string file_primary;
906 std::string file_secondary;
907 std::string hash_primary;
908 std::string hash_secondary;
909 if (manifest_count <= 1) {
910 file_primary =
"unknown";
911 file_secondary =
"noimage";
913 hash_primary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(
"")));
914 hash_secondary = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(
"")));
916 file_primary =
"primary_firmware.txt";
917 file_secondary =
"secondary_firmware.txt";
918 const Json::Value json = Utils::parseJSON(Utils::readFile(meta_dir /
"director/targets_hasupdates.json"));
919 const Json::Value targets_list = json[
"signed"][
"targets"];
920 hash_primary = targets_list[
"primary_firmware.txt"][
"hashes"][
"sha256"].asString();
921 hash_secondary = targets_list[
"secondary_firmware.txt"][
"hashes"][
"sha256"].asString();
923 const Json::Value manifest = data[
"signed"][
"ecu_version_manifests"];
924 const Json::Value manifest_primary = manifest[
"CA:FE:A6:D2:84:9D"][
"signed"][
"installed_image"];
925 const Json::Value manifest_secondary = manifest[
"secondary_ecu_serial"][
"signed"][
"installed_image"];
926 EXPECT_EQ(file_primary, manifest_primary[
"filepath"].asString());
927 EXPECT_EQ(file_secondary, manifest_secondary[
"filepath"].asString());
928 EXPECT_EQ(manifest_primary[
"fileinfo"][
"hashes"][
"sha256"].asString(), hash_primary);
929 EXPECT_EQ(manifest_secondary[
"fileinfo"][
"hashes"][
"sha256"].asString(), hash_secondary);
930 }
else if (url.find(
"/system_info/network") != std::string::npos) {
933 Json::Value nwinfo = Utils::getNetworkInfo();
934 EXPECT_EQ(nwinfo[
"local_ipv4"].asString(), data[
"local_ipv4"].asString());
935 EXPECT_EQ(nwinfo[
"mac"].asString(), data[
"mac"].asString());
936 EXPECT_EQ(nwinfo[
"hostname"].asString(), data[
"hostname"].asString());
937 }
else if (url.find(
"/system_info") != std::string::npos) {
940 if (system_info_count <= 2) {
941 Json::Value hwinfo = Utils::getHardwareInfo();
942 EXPECT_EQ(hwinfo[
"id"].asString(), data[
"id"].asString());
943 EXPECT_EQ(hwinfo[
"description"].asString(), data[
"description"].asString());
944 EXPECT_EQ(hwinfo[
"class"].asString(), data[
"class"].asString());
945 EXPECT_EQ(hwinfo[
"product"].asString(), data[
"product"].asString());
947 EXPECT_EQ(custom_hw_info, data);
950 EXPECT_EQ(0, 1) <<
"Unexpected put to URL: " << url;
953 return HttpFake::put(url, data);
956 size_t events_seen{0};
957 int devices_count{0};
959 int manifest_count{0};
960 int installed_count{0};
961 int system_info_count{0};
962 int network_count{0};
964 Json::Value custom_hw_info;
968 int primary_download_start{0};
969 int primary_download_complete{0};
970 int secondary_download_start{0};
971 int secondary_download_complete{0};
979 TEST(
Uptane, ProvisionOnServer) {
980 RecordProperty(
"zephyr_key",
"OTA-984,TST-149");
982 Config config(
"tests/config/basic.toml");
983 auto http = std::make_shared<HttpFakeProv>(temp_dir.Path(),
"hasupdates", config);
984 const std::string &server = http->tls_server;
985 config.provision.server = server;
986 config.tls.server = server;
987 config.uptane.director_server = server +
"/director";
988 config.uptane.repo_server = server +
"/repo";
989 config.provision.ecu_registration_endpoint = server +
"/director/ecus";
990 config.provision.device_id =
"tst149_device_id";
991 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
992 config.provision.primary_ecu_hardware_id =
"primary_hw";
993 config.storage.path = temp_dir.Path();
994 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
995 logger_set_threshold(boost::log::trivial::trace);
997 auto storage = INvStorage::newStorage(config.storage);
998 auto events_channel = std::make_shared<event::Channel>();
999 auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http, events_channel);
1001 EXPECT_EQ(http->devices_count, 0);
1002 EXPECT_EQ(http->ecus_count, 0);
1003 EXPECT_EQ(http->manifest_count, 0);
1004 EXPECT_EQ(http->installed_count, 0);
1005 EXPECT_EQ(http->system_info_count, 0);
1006 EXPECT_EQ(http->network_count, 0);
1007 EXPECT_EQ(http->config_count, 0);
1009 EXPECT_NO_THROW(up->initialize());
1011 storage->loadEcuSerials(&serials);
1012 EXPECT_EQ(serials[0].second.ToString(),
"primary_hw");
1014 EXPECT_EQ(http->devices_count, 1);
1015 EXPECT_EQ(http->ecus_count, 1);
1017 EXPECT_NO_THROW(up->sendDeviceData());
1018 EXPECT_EQ(http->installed_count, 1);
1019 EXPECT_EQ(http->system_info_count, 1);
1020 EXPECT_EQ(http->network_count, 1);
1021 EXPECT_EQ(http->config_count, 1);
1024 EXPECT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
1025 EXPECT_EQ(http->manifest_count, 1);
1028 result::Download download_result = up->downloadImages(update_result.updates);
1029 EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
1030 result::Install install_result = up->uptaneInstall(download_result.updates);
1031 EXPECT_TRUE(install_result.dev_report.isSuccess());
1032 EXPECT_EQ(install_result.dev_report.result_code, data::ResultCode::Numeric::kOk);
1035 EXPECT_EQ(http->devices_count, 1);
1036 EXPECT_EQ(http->ecus_count, 1);
1037 EXPECT_EQ(http->manifest_count, 2);
1038 EXPECT_EQ(http->installed_count, 1);
1039 EXPECT_EQ(http->system_info_count, 1);
1040 EXPECT_EQ(http->network_count, 1);
1041 EXPECT_EQ(http->config_count, 1);
1042 EXPECT_EQ(http->events_seen, 8);
1046 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1047 EXPECT_EQ(http->installed_count, 1);
1048 EXPECT_EQ(http->system_info_count, 1);
1049 EXPECT_EQ(http->network_count, 1);
1050 EXPECT_EQ(http->config_count, 1);
1053 storage->clearDeviceData();
1054 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1055 EXPECT_EQ(http->installed_count, 2);
1056 EXPECT_EQ(http->system_info_count, 2);
1057 EXPECT_EQ(http->network_count, 2);
1058 EXPECT_EQ(http->config_count, 2);
1061 http->custom_hw_info[
"hardware"] =
"test-hw";
1062 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1063 EXPECT_EQ(http->installed_count, 2);
1064 EXPECT_EQ(http->system_info_count, 3);
1065 EXPECT_EQ(http->network_count, 2);
1066 EXPECT_EQ(http->config_count, 2);
1069 http->custom_hw_info[
"hardware"] =
"test-hw";
1070 EXPECT_NO_THROW(up->sendDeviceData(http->custom_hw_info));
1071 EXPECT_EQ(http->installed_count, 2);
1072 EXPECT_EQ(http->system_info_count, 3);
1073 EXPECT_EQ(http->network_count, 2);
1074 EXPECT_EQ(http->config_count, 2);
1078 TEST(
Uptane, FsToSqlFull) {
1080 Utils::copyDir(
"tests/test_data/prov", temp_dir.Path());
1081 ASSERT_GE(chmod(temp_dir.Path().c_str(), S_IRWXU), 0);
1083 config.type = StorageType::kSqlite;
1084 config.path = temp_dir.Path();
1088 std::string public_key;
1089 std::string private_key;
1090 fs_storage.loadPrimaryKeys(&public_key, &private_key);
1095 fs_storage.loadTlsCreds(&ca, &cert, &pkey);
1097 std::string device_id;
1098 fs_storage.loadDeviceId(&device_id);
1101 fs_storage.loadEcuSerials(&serials);
1103 bool ecu_registered = fs_storage.loadEcuRegistered();
1105 std::vector<Uptane::Target> fs_installed_versions;
1106 std::vector<Uptane::Target> fixed_installed_versions;
1107 fs_storage.loadInstalledVersions(&fs_installed_versions,
nullptr);
1110 for (
auto &target : fs_installed_versions) {
1111 Json::Value dump = target.toDebugJson();
1112 dump[
"custom"][
"ecuIdentifiers"][serials[0].first.ToString()][
"hardwareId"] = serials[0].second.ToString();
1113 fixed_installed_versions.emplace_back(
Uptane::Target(target.filename(), dump));
1116 std::string director_root;
1117 std::string director_targets;
1118 std::string image_root;
1119 std::string image_targets;
1120 std::string image_timestamp;
1121 std::string image_snapshot;
1123 EXPECT_TRUE(fs_storage.loadLatestRoot(&director_root, Uptane::RepositoryType::Director()));
1124 EXPECT_TRUE(fs_storage.loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1125 EXPECT_TRUE(fs_storage.loadLatestRoot(&image_root, Uptane::RepositoryType::Image()));
1126 EXPECT_TRUE(fs_storage.loadNonRoot(&image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1127 EXPECT_TRUE(fs_storage.loadNonRoot(&image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1128 EXPECT_TRUE(fs_storage.loadNonRoot(&image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1130 EXPECT_TRUE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1131 EXPECT_TRUE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1132 EXPECT_TRUE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1133 EXPECT_TRUE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1134 EXPECT_TRUE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1136 boost::filesystem::path image_path = config.uptane_metadata_path.get(config.path) /
"repo";
1137 boost::filesystem::path director_path = config.uptane_metadata_path.get(config.path) /
"director";
1138 EXPECT_TRUE(boost::filesystem::exists(director_path /
"1.root.json"));
1139 EXPECT_TRUE(boost::filesystem::exists(director_path /
"targets.json"));
1140 EXPECT_TRUE(boost::filesystem::exists(image_path /
"1.root.json"));
1141 EXPECT_TRUE(boost::filesystem::exists(image_path /
"targets.json"));
1142 EXPECT_TRUE(boost::filesystem::exists(image_path /
"timestamp.json"));
1143 EXPECT_TRUE(boost::filesystem::exists(image_path /
"snapshot.json"));
1144 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"device_id")));
1145 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"is_registered")));
1146 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_serial")));
1147 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_hardware_id")));
1148 EXPECT_TRUE(boost::filesystem::exists(Utils::absolutePath(config.path,
"secondaries_list")));
1149 auto sql_storage = INvStorage::newStorage(config);
1151 EXPECT_FALSE(boost::filesystem::exists(config.uptane_public_key_path.get(config.path)));
1152 EXPECT_FALSE(boost::filesystem::exists(config.uptane_private_key_path.get(config.path)));
1153 EXPECT_FALSE(boost::filesystem::exists(config.tls_cacert_path.get(config.path)));
1154 EXPECT_FALSE(boost::filesystem::exists(config.tls_clientcert_path.get(config.path)));
1155 EXPECT_FALSE(boost::filesystem::exists(config.tls_pkey_path.get(config.path)));
1157 EXPECT_FALSE(boost::filesystem::exists(director_path /
"root.json"));
1158 EXPECT_FALSE(boost::filesystem::exists(director_path /
"targets.json"));
1159 EXPECT_FALSE(boost::filesystem::exists(director_path /
"root.json"));
1160 EXPECT_FALSE(boost::filesystem::exists(director_path /
"targets.json"));
1161 EXPECT_FALSE(boost::filesystem::exists(image_path /
"timestamp.json"));
1162 EXPECT_FALSE(boost::filesystem::exists(image_path /
"snapshot.json"));
1163 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"device_id")));
1164 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"is_registered")));
1165 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_serial")));
1166 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"primary_ecu_hardware_id")));
1167 EXPECT_FALSE(boost::filesystem::exists(Utils::absolutePath(config.path,
"secondaries_list")));
1169 std::string sql_public_key;
1170 std::string sql_private_key;
1171 sql_storage->loadPrimaryKeys(&sql_public_key, &sql_private_key);
1174 std::string sql_cert;
1175 std::string sql_pkey;
1176 sql_storage->loadTlsCreds(&sql_ca, &sql_cert, &sql_pkey);
1178 std::string sql_device_id;
1179 sql_storage->loadDeviceId(&sql_device_id);
1181 EcuSerials sql_serials;
1182 sql_storage->loadEcuSerials(&sql_serials);
1184 bool sql_ecu_registered = sql_storage->loadEcuRegistered();
1186 std::vector<Uptane::Target> sql_installed_versions;
1187 sql_storage->loadPrimaryInstallationLog(&sql_installed_versions,
true);
1189 std::string sql_director_root;
1190 std::string sql_director_targets;
1191 std::string sql_image_root;
1192 std::string sql_image_targets;
1193 std::string sql_image_timestamp;
1194 std::string sql_image_snapshot;
1196 sql_storage->loadLatestRoot(&sql_director_root, Uptane::RepositoryType::Director());
1197 sql_storage->loadNonRoot(&sql_director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
1198 sql_storage->loadLatestRoot(&sql_image_root, Uptane::RepositoryType::Image());
1199 sql_storage->loadNonRoot(&sql_image_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
1200 sql_storage->loadNonRoot(&sql_image_timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
1201 sql_storage->loadNonRoot(&sql_image_snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
1203 EXPECT_EQ(sql_public_key, public_key);
1204 EXPECT_EQ(sql_private_key, private_key);
1205 EXPECT_EQ(sql_ca, ca);
1206 EXPECT_EQ(sql_cert, cert);
1207 EXPECT_EQ(sql_pkey, pkey);
1208 EXPECT_EQ(sql_device_id, device_id);
1209 EXPECT_EQ(sql_serials, serials);
1210 EXPECT_EQ(sql_ecu_registered, ecu_registered);
1211 EXPECT_TRUE(Uptane::MatchTargetVector(sql_installed_versions, fixed_installed_versions));
1213 EXPECT_EQ(sql_director_root, director_root);
1214 EXPECT_EQ(sql_director_targets, director_targets);
1215 EXPECT_EQ(sql_image_root, image_root);
1216 EXPECT_EQ(sql_image_targets, image_targets);
1217 EXPECT_EQ(sql_image_timestamp, image_timestamp);
1218 EXPECT_EQ(sql_image_snapshot, image_snapshot);
1222 TEST(
Uptane, InstalledVersionImport) {
1223 Config config = config_common();
1226 Utils::createDirectories(temp_dir /
"import", S_IRWXU);
1227 config.storage.path = temp_dir.Path();
1228 config.import.base_path = temp_dir /
"import";
1229 config.postUpdateValues();
1231 boost::filesystem::copy_file(
"tests/test_data/prov/installed_versions",
1232 temp_dir.Path() /
"import/installed_versions");
1235 auto storage = INvStorage::newStorage(config.storage);
1236 storage->importData(config.import);
1238 boost::optional<Uptane::Target> current_version;
1239 storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1240 EXPECT_TRUE(!!current_version);
1241 EXPECT_EQ(current_version->filename(),
"master-863de625f305413dc3be306afab7c3f39d8713045cfff812b3af83f9722851f0");
1245 Json::Value target_json;
1246 target_json[
"hashes"][
"sha256"] =
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1247 target_json[
"length"] = 123;
1249 storage->savePrimaryInstalledVersion(new_installed_version, InstalledVersionUpdateMode::kCurrent);
1251 auto new_storage = INvStorage::newStorage(config.storage);
1252 new_storage->importData(config.import);
1254 current_version = boost::none;
1255 new_storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1256 EXPECT_TRUE(!!current_version);
1257 EXPECT_EQ(current_version->filename(),
"filename");
1261 TEST(
Uptane, SaveAndLoadVersion) {
1263 Config config = config_common();
1264 config.storage.path = temp_dir.Path();
1265 config.provision.device_id =
"device_id";
1266 config.postUpdateValues();
1267 auto storage = INvStorage::newStorage(config.storage);
1269 Json::Value target_json;
1270 target_json[
"hashes"][
"sha256"] =
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d";
1271 target_json[
"length"] = 123;
1274 storage->savePrimaryInstalledVersion(t, InstalledVersionUpdateMode::kCurrent);
1276 boost::optional<Uptane::Target> current_version;
1277 storage->loadPrimaryInstalledVersions(¤t_version,
nullptr);
1279 EXPECT_TRUE(!!current_version);
1280 EXPECT_EQ(current_version->sha256Hash(),
"a0fb2e119cf812f1aa9e993d01f5f07cb41679096cb4492f1265bff5ac901d0d");
1281 EXPECT_EQ(current_version->length(), 123);
1282 EXPECT_TRUE(current_version->MatchTarget(t));
1288 HttpResponse get(
const std::string &url, int64_t maxsize)
override {
1289 if (unstable_valid_count >= unstable_valid_num) {
1292 ++unstable_valid_count;
1293 return HttpFake::get(url, maxsize);
1297 void setUnstableValidNum(
int num) {
1298 unstable_valid_num = num;
1299 unstable_valid_count = 0;
1302 int unstable_valid_num{0};
1303 int unstable_valid_count{0};
1315 TEST(
Uptane, restoreVerify) {
1317 auto http = std::make_shared<HttpFakeUnstable>(temp_dir.Path());
1318 Config config(
"tests/config/basic.toml");
1319 config.storage.path = temp_dir.Path();
1320 config.pacman.type = PACKAGE_MANAGER_NONE;
1321 config.uptane.director_server = http->tls_server +
"director";
1322 config.uptane.repo_server = http->tls_server +
"repo";
1323 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
1324 config.provision.primary_ecu_hardware_id =
"primary_hw";
1325 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1326 config.postUpdateValues();
1328 auto storage = INvStorage::newStorage(config.storage);
1329 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1331 EXPECT_NO_THROW(sota_client->initialize());
1332 sota_client->AssembleManifest();
1335 EXPECT_FALSE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1338 http->setUnstableValidNum(1);
1340 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1341 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1344 http->setUnstableValidNum(2);
1346 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Director()));
1347 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
1348 EXPECT_FALSE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Image()));
1351 http->setUnstableValidNum(3);
1353 EXPECT_TRUE(storage->loadLatestRoot(
nullptr, Uptane::RepositoryType::Image()));
1354 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1357 http->setUnstableValidNum(4);
1359 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
1360 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1363 http->setUnstableValidNum(5);
1365 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
1366 EXPECT_FALSE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1369 http->setUnstableValidNum(6);
1370 EXPECT_NO_THROW(sota_client->uptaneIteration(
nullptr,
nullptr));
1371 EXPECT_TRUE(storage->loadNonRoot(
nullptr, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
1379 TEST(
Uptane, offlineIteration) {
1381 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1382 Config config(
"tests/config/basic.toml");
1383 config.storage.path = temp_dir.Path();
1384 config.uptane.director_server = http->tls_server +
"director";
1385 config.uptane.repo_server = http->tls_server +
"repo";
1386 config.pacman.type = PACKAGE_MANAGER_NONE;
1387 config.provision.primary_ecu_serial =
"CA:FE:A6:D2:84:9D";
1388 config.provision.primary_ecu_hardware_id =
"primary_hw";
1389 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1390 config.postUpdateValues();
1392 auto storage = INvStorage::newStorage(config.storage);
1393 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1394 EXPECT_NO_THROW(sota_client->initialize());
1396 std::vector<Uptane::Target> targets_online;
1397 EXPECT_NO_THROW(sota_client->uptaneIteration(&targets_online,
nullptr));
1399 std::vector<Uptane::Target> targets_offline;
1400 EXPECT_NO_THROW(sota_client->uptaneOfflineIteration(&targets_offline,
nullptr));
1401 EXPECT_TRUE(Uptane::MatchTargetVector(targets_online, targets_offline));
1408 TEST(
Uptane, IgnoreUnknownUpdate) {
1410 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1411 Config config(
"tests/config/basic.toml");
1412 config.storage.path = temp_dir.Path();
1413 config.uptane.director_server = http->tls_server +
"director";
1414 config.uptane.repo_server = http->tls_server +
"repo";
1415 config.pacman.type = PACKAGE_MANAGER_NONE;
1416 config.provision.primary_ecu_serial =
"primary_ecu";
1417 config.provision.primary_ecu_hardware_id =
"primary_hw";
1418 UptaneTestCommon::addDefaultSecondary(config, temp_dir,
"secondary_ecu_serial",
"secondary_hw");
1419 config.postUpdateValues();
1421 auto storage = INvStorage::newStorage(config.storage);
1422 auto sota_client = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
1424 EXPECT_NO_THROW(sota_client->initialize());
1426 auto result = sota_client->fetchMeta();
1427 EXPECT_EQ(result.status, result::UpdateStatus::kError);
1428 std::vector<Uptane::Target> packages_to_install = UptaneTestCommon::makePackage(
"testecuserial",
"testecuhwid");
1429 auto report = sota_client->uptaneInstall(packages_to_install);
1430 EXPECT_EQ(report.ecu_reports.size(), 0);
1434 TEST(
Uptane, Pkcs11Provision) {
1437 Utils::createDirectories(temp_dir /
"import", S_IRWXU);
1438 boost::filesystem::copy_file(
"tests/test_data/device_cred_prov/ca.pem", temp_dir /
"import/root.crt");
1439 config.tls.cert_source = CryptoSource::kPkcs11;
1440 config.tls.pkey_source = CryptoSource::kPkcs11;
1441 config.p11.module = TEST_PKCS11_MODULE_PATH;
1442 config.p11.pass =
"1234";
1443 config.p11.tls_clientcert_id =
"01";
1444 config.p11.tls_pkey_id =
"02";
1445 config.import.base_path = (temp_dir /
"import").
string();
1446 config.import.tls_cacert_path =
BasedPath(
"root.crt");
1448 config.storage.path = temp_dir.Path();
1449 config.postUpdateValues();
1451 auto storage = INvStorage::newStorage(config.storage);
1452 storage->importData(config.import);
1453 auto http = std::make_shared<HttpFake>(temp_dir.Path(),
"hasupdates");
1454 KeyManager keys(storage, config.keymanagerConfig());
1456 EXPECT_NO_THROW(
Initializer(config.provision, storage, http, keys, {}));
1461 int main(
int argc,
char **argv) {
1462 ::testing::InitGoogleTest(&argc, argv);
1465 logger_set_threshold(boost::log::trivial::trace);
1467 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.
Results of libaktualizr API calls.
Base data types that are used in The Update Framework (TUF), part of Uptane.