1 #include "managedsecondary.h"
7 #include <boost/algorithm/hex.hpp>
8 #include <boost/filesystem.hpp>
10 #include "crypto/crypto.h"
11 #include "logging/logging.h"
12 #include "uptane/manifest.h"
13 #include "uptane/tuf.h"
14 #include "uptane/uptanerepository.h"
15 #include "utilities/exceptions.h"
16 #include "utilities/fault_injection.h"
17 #include "utilities/utils.h"
28 bool isConsistent()
const;
32 : sconfig(std::move(sconfig_in)), current_meta(new
MetaPack()), meta_bundle_(new
Uptane::MetaBundle) {
34 std::string public_key_string;
36 if (!loadKeys(&public_key_string, &private_key)) {
37 if (!Crypto::generateKeyPair(sconfig.key_type, &public_key_string, &private_key)) {
38 LOG_ERROR <<
"Could not generate rsa keys for secondary " << ManagedSecondary::getSerial() <<
"@"
39 << sconfig.ecu_hardware_id;
40 throw std::runtime_error(
"Unable to generate secondary rsa keys");
45 public_key_ =
PublicKey(public_key_string, sconfig.key_type);
49 ManagedSecondary::~ManagedSecondary() { current_meta.reset(
nullptr); }
51 void ManagedSecondary::Initialize() {
54 if (!boost::filesystem::is_directory(sconfig.metadata_path)) {
55 Utils::createDirectories(sconfig.metadata_path, S_IRWXU);
57 if (stat(sconfig.metadata_path.c_str(), &st) < 0) {
58 throw std::runtime_error(std::string(
"Could not check metadata directory permissions: ") + std::strerror(errno));
60 if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
61 throw std::runtime_error(
"Secondary metadata directory has unsafe permissions");
64 if (!boost::filesystem::is_directory(sconfig.full_client_dir)) {
65 Utils::createDirectories(sconfig.full_client_dir, S_IRWXU);
67 if (stat(sconfig.full_client_dir.c_str(), &st) < 0) {
68 throw std::runtime_error(std::string(
"Could not check client directory permissions: ") + std::strerror(errno));
70 if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
71 throw std::runtime_error(
"Secondary client directory has unsafe permissions");
74 storeKeys(public_key_.Value(), private_key);
77 void ManagedSecondary::rawToMeta() {
79 current_meta->director_root =
81 Utils::parseJSON(Uptane::getMetaFromBundle(*meta_bundle_, Uptane::RepositoryType::Director(),
82 Uptane::Role::Root())));
84 Uptane::getMetaFromBundle(*meta_bundle_, Uptane::RepositoryType::Director(), Uptane::Role::Targets())));
85 current_meta->image_root =
Uptane::Root(Uptane::RepositoryType::Image(),
86 Utils::parseJSON(Uptane::getMetaFromBundle(
87 *meta_bundle_, Uptane::RepositoryType::Image(), Uptane::Role::Root())));
89 Uptane::getMetaFromBundle(*meta_bundle_, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp())));
91 Uptane::getMetaFromBundle(*meta_bundle_, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot())));
93 Uptane::getMetaFromBundle(*meta_bundle_, Uptane::RepositoryType::Image(), Uptane::Role::Targets())));
97 Uptane::MetaBundle temp_bundle;
98 if (!secondary_provider_->getMetadata(&temp_bundle, target)) {
100 "Unable to load stored metadata from Primary");
104 detected_attack =
"";
106 meta_bundle_.reset(
new Uptane::MetaBundle(std::move(temp_bundle)));
108 if (!current_meta->isConsistent()) {
110 "Error verifying metadata received from Primary");
117 int ManagedSecondary::getRootVersion(
const bool director)
const {
119 return current_meta->director_root.version();
121 return current_meta->image_root.version();
125 const Uptane::RepositoryType repo = (director) ? Uptane::RepositoryType::Director() : Uptane::RepositoryType::Image();
126 Uptane::Root &prev_root = (director) ? current_meta->director_root : current_meta->image_root;
127 const std::string prev_raw_root = Uptane::getMetaFromBundle(*meta_bundle_, repo, Uptane::Role::Root());
131 if (new_root.version() == prev_root.version() + 1) {
132 prev_root = new_root;
133 meta_bundle_->insert({std::make_pair(repo, Uptane::Role::Root()), root});
135 detected_attack =
"Tried to update Root version " + std::to_string(prev_root.version()) +
" with version " +
136 std::to_string(new_root.version());
139 if (!current_meta->isConsistent()) {
152 auto str = secondary_provider_->getTargetFileHandle(target);
153 std::ofstream out_file(sconfig.firmware_path.string(), std::ios::binary);
154 out_file << str.rdbuf();
158 Utils::writeFile(sconfig.target_name_path, target.filename());
164 if (!getFirmwareInfo(firmware_info)) {
165 return Json::Value(Json::nullValue);
168 Json::Value manifest = Uptane::ManifestIssuer::assembleManifest(firmware_info, getSerial());
172 manifest[
"attacks_detected"] = detected_attack;
174 Json::Value signed_ecu_version;
176 std::string b64sig = Utils::toBase64(Crypto::RSAPSSSign(
nullptr, private_key, Utils::jsonToCanonicalStr(manifest)));
177 Json::Value signature;
178 signature[
"method"] =
"rsassa-pss";
179 signature[
"sig"] = b64sig;
181 signature[
"keyid"] = public_key_.KeyId();
182 signed_ecu_version[
"signed"] = manifest;
183 signed_ecu_version[
"signatures"] = Json::Value(Json::arrayValue);
184 signed_ecu_version[
"signatures"].append(signature);
186 return signed_ecu_version;
192 if (!boost::filesystem::exists(sconfig.target_name_path) || !boost::filesystem::exists(sconfig.firmware_path)) {
193 firmware_info.name = std::string(
"noimage");
196 firmware_info.name = Utils::readFile(sconfig.target_name_path.string());
197 content = Utils::readFile(sconfig.firmware_path.string());
199 firmware_info.hash = Uptane::ManifestIssuer::generateVersionHashStr(content);
200 firmware_info.len = content.size();
205 void ManagedSecondary::storeKeys(
const std::string &pub_key,
const std::string &priv_key) {
206 Utils::writeFile((sconfig.full_client_dir / sconfig.ecu_private_key), priv_key);
207 Utils::writeFile((sconfig.full_client_dir / sconfig.ecu_public_key), pub_key);
210 bool ManagedSecondary::loadKeys(std::string *pub_key, std::string *priv_key) {
211 boost::filesystem::path public_key_path = sconfig.full_client_dir / sconfig.ecu_public_key;
212 boost::filesystem::path private_key_path = sconfig.full_client_dir / sconfig.ecu_private_key;
214 if (!boost::filesystem::exists(public_key_path) || !boost::filesystem::exists(private_key_path)) {
218 *priv_key = Utils::readFile(private_key_path.string());
219 *pub_key = Utils::readFile(public_key_path.string());
223 bool MetaPack::isConsistent()
const {
226 if (!director_root.original().empty()) {
228 Uptane::Root new_root(Uptane::RepositoryType::Director(), director_root.original(), new_root);
229 if (!director_targets.original().empty()) {
230 Uptane::Targets(Uptane::RepositoryType::Director(), Uptane::Role::Targets(), director_targets.original(),
231 std::make_shared<Uptane::MetaWithKeys>(original_root));
234 }
catch (
const std::logic_error &exc) {
235 LOG_WARNING <<
"Inconsistent metadata: " << exc.what();