Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
Merge pull request #839 from advancedtelematic/bugfix/alwaysupdatemeta
Browse files Browse the repository at this point in the history
Fix images metadata update process
  • Loading branch information
pattivacek committed Jul 5, 2018
2 parents 2995e51 + 9123458 commit 8c61812
Show file tree
Hide file tree
Showing 47 changed files with 488 additions and 1,171 deletions.
17 changes: 9 additions & 8 deletions src/aktualizr_repo/repo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void Repo::generateRepo(const std::string &repo_type, KeyType key_type) {
root["roles"]["targets"] = role;
root["roles"]["timestamp"] = role;

std::string signed_root = Utils::jsonToStr(signTuf(repo_type, root));
std::string signed_root = Utils::jsonToCanonicalStr(signTuf(repo_type, root));
Utils::writeFile(repo_dir / "root.json", signed_root);
Utils::writeFile(repo_dir / "1.root.json", signed_root);

Expand All @@ -95,7 +95,7 @@ void Repo::generateRepo(const std::string &repo_type, KeyType key_type) {
targets["expires"] = expiration_time_;
targets["version"] = 1;
targets["targets"] = Json::objectValue;
std::string signed_targets = Utils::jsonToStr(signTuf(repo_type, targets));
std::string signed_targets = Utils::jsonToCanonicalStr(signTuf(repo_type, targets));
Utils::writeFile(repo_dir / "targets.json", signed_targets);

Json::Value snapshot;
Expand All @@ -110,7 +110,7 @@ void Repo::generateRepo(const std::string &repo_type, KeyType key_type) {
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_targets)));
snapshot["meta"]["targets.json"]["length"] = static_cast<Json::UInt>(signed_targets.length());
snapshot["meta"]["targets.json"]["version"] = 1;
std::string signed_snapshot = Utils::jsonToStr(signTuf(repo_type, snapshot));
std::string signed_snapshot = Utils::jsonToCanonicalStr(signTuf(repo_type, snapshot));
Utils::writeFile(repo_dir / "snapshot.json", signed_snapshot);

Json::Value timestamp;
Expand All @@ -121,7 +121,7 @@ void Repo::generateRepo(const std::string &repo_type, KeyType key_type) {
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_snapshot)));
timestamp["meta"]["snapshot.json"]["length"] = static_cast<Json::UInt>(signed_snapshot.length());
timestamp["meta"]["snapshot.json"]["version"] = 1;
Utils::writeFile(repo_dir / "timestamp.json", signTuf(repo_type, timestamp));
Utils::writeFile(repo_dir / "timestamp.json", Utils::jsonToCanonicalStr(signTuf(repo_type, timestamp)));
}

void Repo::generateRepo(KeyType key_type) {
Expand All @@ -146,7 +146,7 @@ void Repo::addImage(const boost::filesystem::path &image_path) {
targets["targets"][target_name]["hashes"]["sha256"] = hash;
targets["version"] = (targets["version"].asUInt()) + 1;

std::string signed_targets = Utils::jsonToStr(signTuf("image", targets));
std::string signed_targets = Utils::jsonToCanonicalStr(signTuf("image", targets));
Utils::writeFile(repo_dir / "targets.json", signed_targets);

Json::Value snapshot = Utils::parseJSONFile(repo_dir / "snapshot.json")["signed"];
Expand All @@ -155,7 +155,7 @@ void Repo::addImage(const boost::filesystem::path &image_path) {
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_targets)));
snapshot["meta"]["targets.json"]["length"] = static_cast<Json::UInt>(signed_targets.length());
snapshot["meta"]["targets.json"]["version"] = targets["version"].asUInt();
std::string signed_snapshot = Utils::jsonToStr(signTuf("image", snapshot));
std::string signed_snapshot = Utils::jsonToCanonicalStr(signTuf("image", snapshot));
Utils::writeFile(repo_dir / "snapshot.json", signed_snapshot);

Json::Value timestamp = Utils::parseJSONFile(repo_dir / "timestamp.json")["signed"];
Expand All @@ -164,7 +164,7 @@ void Repo::addImage(const boost::filesystem::path &image_path) {
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_snapshot)));
timestamp["meta"]["snapshot.json"]["length"] = static_cast<Json::UInt>(signed_snapshot.length());
timestamp["meta"]["snapshot.json"]["version"] = snapshot["version"].asUInt();
Utils::writeFile(repo_dir / "timestamp.json", signTuf("image", timestamp));
Utils::writeFile(repo_dir / "timestamp.json", Utils::jsonToCanonicalStr(signTuf("image", timestamp)));
}

void Repo::addTarget(const std::string &target_name, const std::string &hardware_id, const std::string &ecu_serial) {
Expand All @@ -188,7 +188,8 @@ void Repo::addTarget(const std::string &target_name, const std::string &hardware
void Repo::signTargets() {
std::string private_key = Utils::readFile(path_ / "keys/director/private.key");
Json::Value targets_unsigned = Utils::parseJSONFile(path_ / "repo/director/staging/targets.json");
Utils::writeFile(path_ / "repo/director/targets.json", signTuf("director", targets_unsigned));
Utils::writeFile(path_ / "repo/director/targets.json",
Utils::jsonToCanonicalStr(signTuf("director", targets_unsigned)));
boost::filesystem::remove(path_ / "repo/director/staging/targets.json");
}

Expand Down
191 changes: 168 additions & 23 deletions src/libaktualizr/primary/sotauptaneclient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ bool SotaUptaneClient::updateDirectorMeta() {

if (local_version > remote_version) {
return false;
} else if (local_version == remote_version) {
return true;
} else if (local_version < remote_version) {
storage->storeNonRoot(director_targets, Uptane::RepositoryType::Director, Uptane::Role::Targets());
}
storage->storeNonRoot(director_targets, Uptane::RepositoryType::Director, Uptane::Role::Targets());

if (director_repo.targetsExpired()) {
last_exception = Uptane::ExpiredMetadata("director", "targets");
return false;
Expand Down Expand Up @@ -304,7 +304,7 @@ bool SotaUptaneClient::updateImagesMeta() {
}
}

// Update Image Roots Metadata
// Update Image Root Metadata
{
std::string images_root;
if (!uptane_fetcher.fetchLatestRole(&images_root, Uptane::kMaxRootSize, Uptane::RepositoryType::Images,
Expand Down Expand Up @@ -358,10 +358,10 @@ bool SotaUptaneClient::updateImagesMeta() {

if (local_version > remote_version) {
return false;
} else if (local_version == remote_version) {
return true;
} else if (local_version < remote_version) {
storage->storeNonRoot(images_timestamp, Uptane::RepositoryType::Images, Uptane::Role::Timestamp());
}
storage->storeNonRoot(images_timestamp, Uptane::RepositoryType::Images, Uptane::Role::Timestamp());

if (images_repo.timestampExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "timestamp");
return false;
Expand All @@ -387,18 +387,16 @@ bool SotaUptaneClient::updateImagesMeta() {
local_version = -1;
}

if (local_version > remote_version) {
return false;
} else if (local_version == remote_version) {
return true;
}

if (!images_repo.verifySnapshot(images_snapshot)) {
last_exception = images_repo.getLastException();
return false;
}

storage->storeNonRoot(images_snapshot, Uptane::RepositoryType::Images, Uptane::Role::Snapshot());
if (local_version > remote_version) {
return false;
} else if (local_version < remote_version) {
storage->storeNonRoot(images_snapshot, Uptane::RepositoryType::Images, Uptane::Role::Snapshot());
}

if (images_repo.snapshotExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "snapshot");
Expand All @@ -425,16 +423,135 @@ bool SotaUptaneClient::updateImagesMeta() {
local_version = -1;
}

if (!images_repo.verifyTargets(images_targets)) {
last_exception = images_repo.getLastException();
return false;
}

if (local_version > remote_version) {
return false;
} else if (local_version == remote_version) {
return true;
} else if (local_version < remote_version) {
storage->storeNonRoot(images_targets, Uptane::RepositoryType::Images, Uptane::Role::Targets());
}

if (images_repo.targetsExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "targets");
return false;
}
}
return true;
}

bool SotaUptaneClient::checkDirectorMetaOffline() {
director_repo.resetMeta();
// Load Director Root Metadata
{
std::string director_root;
if (!storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director)) {
return false;
}

if (!director_repo.initRoot(director_root)) {
last_exception = director_repo.getLastException();
return false;
}

if (director_repo.rootExpired()) {
last_exception = Uptane::ExpiredMetadata("director", "root");
return false;
}
}

// Load Director Targets Metadata
{
std::string director_targets;

if (!storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director, Uptane::Role::Targets())) {
return false;
}

if (!director_repo.verifyTargets(director_targets)) {
last_exception = director_repo.getLastException();
return false;
}

if (director_repo.targetsExpired()) {
last_exception = Uptane::ExpiredMetadata("director", "targets");
return false;
}
}

return true;
}

bool SotaUptaneClient::checkImagesMetaOffline() {
images_repo.resetMeta();
// Load Images Root Metadata
{
std::string images_root;
if (!storage->loadLatestRoot(&images_root, Uptane::RepositoryType::Images)) {
return false;
}

if (!images_repo.initRoot(images_root)) {
last_exception = images_repo.getLastException();
return false;
}

if (images_repo.rootExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "root");
return false;
}
}

// Load Images Timestamp Metadata
{
std::string images_timestamp;
if (!storage->loadNonRoot(&images_timestamp, Uptane::RepositoryType::Images, Uptane::Role::Timestamp())) {
return false;
}

if (!images_repo.verifyTimestamp(images_timestamp)) {
last_exception = images_repo.getLastException();
return false;
}

if (images_repo.timestampExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "timestamp");
return false;
}
}

// Load Images Snapshot Metadata
{
std::string images_snapshot;

if (!storage->loadNonRoot(&images_snapshot, Uptane::RepositoryType::Images, Uptane::Role::Snapshot())) {
return false;
}

if (!images_repo.verifySnapshot(images_snapshot)) {
last_exception = images_repo.getLastException();
return false;
}

if (images_repo.snapshotExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "snapshot");
return false;
}
}

// Load Images Targets Metadata
{
std::string images_targets;
if (!storage->loadNonRoot(&images_targets, Uptane::RepositoryType::Images, Uptane::Role::Targets())) {
return false;
}

if (!images_repo.verifyTargets(images_targets)) {
last_exception = images_repo.getLastException();
return false;
}
storage->storeNonRoot(images_targets, Uptane::RepositoryType::Images, Uptane::Role::Targets());

if (images_repo.targetsExpired()) {
last_exception = Uptane::ExpiredMetadata("repo", "targets");
Expand All @@ -451,6 +568,7 @@ bool SotaUptaneClient::getNewTargets(std::vector<Uptane::Target> *new_targets) {
for (auto ecus_it = targets_it->ecus().cbegin(); ecus_it != targets_it->ecus().cend(); ++ecus_it) {
Uptane::EcuSerial ecu_serial = ecus_it->first;
Uptane::HardwareIdentifier hw_id = ecus_it->second;

auto hwid_it = hw_ids.find(ecu_serial);
if (hwid_it == hw_ids.end()) {
LOG_WARNING << "Unknown ECU ID in director targets metadata: " << ecu_serial.ToString();
Expand All @@ -465,7 +583,7 @@ bool SotaUptaneClient::getNewTargets(std::vector<Uptane::Target> *new_targets) {

auto images_it = installed_images.find(ecu_serial);
if (images_it == installed_images.end()) {
LOG_WARNING << "Unknown ECU ID in director targets metadata: " << ecu_serial.ToString();
LOG_WARNING << "Unknown ECU ID on the device: " << ecu_serial.ToString();
is_new = false;
break;
}
Expand Down Expand Up @@ -507,14 +625,13 @@ bool SotaUptaneClient::downloadImages(const std::vector<Uptane::Target> &targets
}

bool SotaUptaneClient::uptaneIteration() {
// Uptane step 1 (build the vehicle version manifest):
if (!updateDirectorMeta()) {
LOG_ERROR << "Failed to update director metadata: " << last_exception.what();
return false;
}
std::vector<Uptane::Target> targets;
if (!getNewTargets(&targets)) {
LOG_ERROR << "Inconsistency between director and images targets metadata";
LOG_ERROR << "Inconsistency between director metadata and existent ECUs";
return false;
}

Expand All @@ -525,10 +642,37 @@ bool SotaUptaneClient::uptaneIteration() {
LOG_INFO << "got new updates";

if (!updateImagesMeta()) {
LOG_ERROR << "Failed to update image metadata";
LOG_ERROR << "Failed to update images metadata: " << last_exception.what();
return false;
}

return true;
}

bool SotaUptaneClient::uptaneOfflineIteration(std::vector<Uptane::Target> *targets) {
if (!checkDirectorMetaOffline()) {
LOG_ERROR << "Failed to check director metadata: " << last_exception.what();
return false;
}
std::vector<Uptane::Target> tmp_targets;
if (!getNewTargets(&tmp_targets)) {
LOG_ERROR << "Inconsistency between director metadata and existent ECUs";
return false;
}

if (tmp_targets.empty()) {
*targets = std::move(tmp_targets);
return true;
}

LOG_INFO << "got new updates";

if (!checkImagesMetaOffline()) {
LOG_ERROR << "Failed to check images metadata: " << last_exception.what();
return false;
}

*targets = std::move(tmp_targets);
return true;
}

Expand Down Expand Up @@ -565,9 +709,10 @@ void SotaUptaneClient::runForever(const std::shared_ptr<command::Channel> &comma
*events_channel << std::make_shared<event::Error>("Could not update metadata.");
}
} else if (command->variant == "CheckUpdates") {
AssembleManifest(); // populates list of connected devices and installed images
std::vector<Uptane::Target> updates;
if (!getNewTargets(&updates)) {
LOG_ERROR << "Inconsistency between director and images targets metadata";
if (!uptaneOfflineIteration(&updates)) {
LOG_ERROR << "Invalid UPTANE metadata in storage";
} else {
if (!updates.empty()) {
*events_channel << std::make_shared<event::UpdateAvailable>(updates);
Expand Down
5 changes: 5 additions & 0 deletions src/libaktualizr/primary/sotauptaneclient.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <gtest/gtest.h>
#include <json/json.h>
#include <atomic>
#include <map>
Expand Down Expand Up @@ -30,6 +31,7 @@ class SotaUptaneClient {
bool initialize();
bool updateMeta();
bool uptaneIteration();
bool uptaneOfflineIteration(std::vector<Uptane::Target> *targets);
bool downloadImages(const std::vector<Uptane::Target> &targets);
void runForever(const std::shared_ptr<command::Channel> &commands_channel);
Json::Value AssembleManifest();
Expand All @@ -40,6 +42,7 @@ class SotaUptaneClient {
std::map<Uptane::EcuSerial, std::shared_ptr<Uptane::SecondaryInterface> > secondaries;

private:
FRIEND_TEST(Uptane, offlineIteration);
bool isInstalledOnPrimary(const Uptane::Target &target);
std::vector<Uptane::Target> findForEcu(const std::vector<Uptane::Target> &targets, const Uptane::EcuSerial &ecu_id);
data::InstallOutcome PackageInstall(const Uptane::Target &target);
Expand All @@ -59,6 +62,8 @@ class SotaUptaneClient {
void rotateSecondaryRoot(Uptane::RepositoryType repo, Uptane::SecondaryInterface &secondary);
bool updateDirectorMeta();
bool updateImagesMeta();
bool checkImagesMetaOffline();
bool checkDirectorMetaOffline();

Config &config;
std::shared_ptr<event::Channel> events_channel;
Expand Down
Loading

0 comments on commit 8c61812

Please sign in to comment.