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 #1028 from advancedtelematic/feat/aktualizr-repo-keys
Browse files Browse the repository at this point in the history
Generate for each role own key
  • Loading branch information
pattivacek authored Dec 14, 2018
2 parents a39ed7b + c10c7ed commit 6956afc
Show file tree
Hide file tree
Showing 34 changed files with 547 additions and 320 deletions.
8 changes: 4 additions & 4 deletions src/aktualizr_info/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ int main(int argc, char **argv) {
std::string director_targets;
std::string images_root;
std::string images_targets;
bool has_metadata = storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director);
storage->loadLatestRoot(&images_root, Uptane::RepositoryType::Images);
storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director, Uptane::Role::Targets());
storage->loadNonRoot(&images_targets, Uptane::RepositoryType::Images, Uptane::Role::Targets());
bool has_metadata = storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director());
storage->loadLatestRoot(&images_root, Uptane::RepositoryType::Image());
storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
storage->loadNonRoot(&images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());

std::string device_id;
if (!storage->loadDeviceId(&device_id)) {
Expand Down
6 changes: 3 additions & 3 deletions src/aktualizr_repo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

set(AKTUALIZR_REPO_SRC repo.cc)
set(AKTUALIZR_REPO_HDR repo.h)
set(AKTUALIZR_REPO_SRC repo.cc director_repo.cc image_repo.cc uptane_repo.cc)
set(AKTUALIZR_REPO_HDR repo.h director_repo.h image_repo.h uptane_repo.h)

set(AKTUALIZR_REPO_LIBS
aktualizr_static_lib
Expand All @@ -16,7 +16,7 @@ install(TARGETS aktualizr-repo

aktualizr_source_file_checks(${AKTUALIZR_REPO_SRC} ${AKTUALIZR_REPO_HDR})
list(APPEND TEST_LIBS ${AKTUALIZR_REPO_LIBS} aktualizr_repo_lib)
add_aktualizr_test(NAME aktualizr_repo SOURCES repo_test.cc PROJECT_WORKING_DIRECTORY)
add_aktualizr_test(NAME aktualizr_repo SOURCES repo_test.cc PROJECT_WORKING_DIRECTORY ARGS $<TARGET_FILE:aktualizr-repo>)
target_link_libraries(t_aktualizr_repo ${TEST_LIBS} aktualizr_repo_lib)

aktualizr_source_file_checks(${TEST_SOURCES} main.cc)
Expand Down
40 changes: 40 additions & 0 deletions src/aktualizr_repo/director_repo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "director_repo.h"

void DirectorRepo::addTarget(const std::string &target_name, const Json::Value &target, const std::string &hardware_id,
const std::string &ecu_serial) {
const boost::filesystem::path current = path_ / "repo/director/targets.json";
const boost::filesystem::path staging = path_ / "repo/director/staging/targets.json";

Json::Value director_targets;
if (boost::filesystem::exists(staging)) {
director_targets = Utils::parseJSONFile(staging);
} else if (boost::filesystem::exists(current)) {
director_targets = Utils::parseJSONFile(current)["signed"];
} else {
throw std::runtime_error(std::string("targets.json not found at ") + staging.c_str() + " or " + current.c_str() +
"!");
}
director_targets["targets"][target_name] = target;
director_targets["targets"][target_name]["custom"]["ecuIdentifiers"][ecu_serial]["hardwareId"] = hardware_id;
director_targets["version"] = (Utils::parseJSONFile(current)["signed"]["version"].asUInt()) + 1;
Utils::writeFile(staging, Utils::jsonToCanonicalStr(director_targets));
}

void DirectorRepo::signTargets() {
const boost::filesystem::path current = path_ / "repo/director/targets.json";
const boost::filesystem::path staging = path_ / "repo/director/staging/targets.json";
Json::Value targets_unsigned;

if (boost::filesystem::exists(staging)) {
targets_unsigned = Utils::parseJSONFile(staging);
} else if (boost::filesystem::exists(current)) {
targets_unsigned = Utils::parseJSONFile(current)["signed"];
} else {
throw std::runtime_error(std::string("targets.json not found at ") + staging.c_str() + " or " + current.c_str() +
"!");
}

Utils::writeFile(path_ / "repo/director/targets.json",
Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Targets(), targets_unsigned)));
boost::filesystem::remove(path_ / "repo/director/staging/targets.json");
}
15 changes: 15 additions & 0 deletions src/aktualizr_repo/director_repo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef DIRECTOR_REPO_H_
#define DIRECTOR_REPO_H_

#include "repo.h"

class DirectorRepo : public Repo {
public:
DirectorRepo(boost::filesystem::path path, const std::string &expires, std::string correlation_id)
: Repo(Uptane::RepositoryType::Director(), std::move(path), expires, std::move(correlation_id)) {}
void addTarget(const std::string &target_name, const Json::Value &target, const std::string &hardware_id,
const std::string &ecu_serial);
void signTargets();
};

#endif // DIRECTOR_REPO_H_
47 changes: 47 additions & 0 deletions src/aktualizr_repo/image_repo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "image_repo.h"

void ImageRepo::addImage(const boost::filesystem::path &image_path) {
boost::filesystem::path repo_dir(path_ / "repo/image");

boost::filesystem::path targets_path = repo_dir / "targets";
boost::filesystem::create_directories(targets_path);
if (image_path != targets_path / image_path.filename()) {
boost::filesystem::copy_file(image_path, targets_path / image_path.filename(),
boost::filesystem::copy_option::overwrite_if_exists);
}
std::string image = Utils::readFile(image_path);

Json::Value targets = Utils::parseJSONFile(repo_dir / "targets.json")["signed"];
std::string target_name = image_path.filename().string();
targets["targets"][target_name]["length"] = Json::UInt64(image.size());
targets["targets"][target_name]["hashes"]["sha256"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(image)));
targets["targets"][target_name]["hashes"]["sha512"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(image)));
targets["version"] = (targets["version"].asUInt()) + 1;

std::string signed_targets = Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Targets(), targets));
Utils::writeFile(repo_dir / "targets.json", signed_targets);

Json::Value snapshot = Utils::parseJSONFile(repo_dir / "snapshot.json")["signed"];
snapshot["version"] = (snapshot["version"].asUInt()) + 1;
snapshot["meta"]["targets.json"]["hashes"]["sha256"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_targets)));
snapshot["meta"]["targets.json"]["hashes"]["sha512"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(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::jsonToCanonicalStr(signTuf(Uptane::Role::Snapshot(), snapshot));
Utils::writeFile(repo_dir / "snapshot.json", signed_snapshot);

Json::Value timestamp = Utils::parseJSONFile(repo_dir / "timestamp.json")["signed"];
timestamp["version"] = (timestamp["version"].asUInt()) + 1;
timestamp["meta"]["snapshot.json"]["hashes"]["sha256"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(signed_snapshot)));
timestamp["meta"]["snapshot.json"]["hashes"]["sha512"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(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",
Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Timestamp(), timestamp)));
}
13 changes: 13 additions & 0 deletions src/aktualizr_repo/image_repo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef IMAGE_REPO_H_
#define IMAGE_REPO_H_

#include "repo.h"

class ImageRepo : public Repo {
public:
ImageRepo(boost::filesystem::path path, const std::string &expires, std::string correlation_id)
: Repo(Uptane::RepositoryType::Image(), std::move(path), expires, std::move(correlation_id)) {}
void addImage(const boost::filesystem::path &image_path);
};

#endif // IMAGE_REPO_H_
32 changes: 29 additions & 3 deletions src/aktualizr_repo/main.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <boost/program_options.hpp>
#include <iostream>
#include <istream>
#include <iterator>
#include <ostream>
#include <string>

#include "logging/logging.h"
#include "repo.h"
#include "uptane_repo.h"

namespace po = boost::program_options;

Expand All @@ -12,12 +15,14 @@ int main(int argc, char **argv) {
// clang-format off
desc.add_options()
("help,h", "print usage")
("command", po::value<std::string>(), "generate|image|addtarget|signtargets")
("command", po::value<std::string>(), "generate|sign|image|addtarget|signtargets")
("path", po::value<boost::filesystem::path>(), "path to the repository")
("filename", po::value<std::string>(), "path to the image")
("hwid", po::value<std::string>(), "target hardware identifier")
("serial", po::value<std::string>(), "target ECU serial")
("expires", po::value<std::string>(), "expiration time")
("keyname", po::value<std::string>(), "name of key's role")
("repotype", po::value<std::string>(), "director|image")
("correlationid", po::value<std::string>()->default_value(""), "correlation id")
("keytype", po::value<std::string>()->default_value("RSA2048"), "UPTANE key type");
// clang-format on
Expand Down Expand Up @@ -49,7 +54,7 @@ int main(int argc, char **argv) {
if (vm.count("correlationid") != 0) {
correlation_id = vm["correlationid"].as<std::string>();
}
Repo repo(vm["path"].as<boost::filesystem::path>(), expiration_time, correlation_id);
UptaneRepo repo(vm["path"].as<boost::filesystem::path>(), expiration_time, correlation_id);
std::string command = vm["command"].as<std::string>();
if (command == "generate") {
std::string key_type_arg = vm["keytype"].as<std::string>();
Expand All @@ -63,6 +68,27 @@ int main(int argc, char **argv) {
repo.addTarget(vm["filename"].as<std::string>(), vm["hwid"].as<std::string>(), vm["serial"].as<std::string>());
} else if (command == "signtargets") {
repo.signTargets();
} else if (command == "sign") {
if (vm.count("repotype") == 0 || vm.count("keyname") == 0) {
std::cerr << "--repotype or --keyname is missing\n";
exit(EXIT_FAILURE);
}
std::cin >> std::noskipws;
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string text_to_sign(it, end);

Repo base_repo(Uptane::RepositoryType(vm["repotype"].as<std::string>()),
vm["path"].as<boost::filesystem::path>(), expiration_time, correlation_id);

auto json_to_sign = Utils::parseJSON(text_to_sign);
if (json_to_sign == Json::nullValue) {
std::cerr << "Text to sign must be valid json\n";
exit(EXIT_FAILURE);
}

auto json_signed = base_repo.signTuf(Uptane::Role(vm["keyname"].as<std::string>()), json_to_sign);
std::cout << Utils::jsonToCanonicalStr(json_signed);
} else {
std::cout << desc << std::endl;
exit(EXIT_FAILURE);
Expand Down
Loading

0 comments on commit 6956afc

Please sign in to comment.