1 #include "aktualizr_secondary.h"
3 #include "crypto/keymanager.h"
4 #include "logging/logging.h"
5 #include "update_agent.h"
6 #include "uptane/manifest.h"
7 #include "utilities/utils.h"
13 : config_(std::move(config)),
14 storage_(std::move(storage)),
15 keys_(std::make_shared<
KeyManager>(storage_, config_.keymanagerConfig())) {
17 manifest_issuer_ = std::make_shared<Uptane::ManifestIssuer>(keys_, ecu_serial_);
21 PublicKey AktualizrSecondary::publicKey()
const {
return keys_->UptanePublicKey(); }
27 if (getInstalledImageInfo(installed_image_info)) {
28 manifest = manifest_issuer_->assembleAndSignManifest(installed_image_info);
35 return doFullVerification(metadata);
39 if (!pending_target_.IsValid()) {
40 LOG_ERROR <<
"Aborting target image installation; no valid target found.";
42 "Aborting target image installation; no valid target found.");
45 auto target_name = pending_target_.filename();
46 auto result = installPendingTarget(pending_target_);
48 switch (
result.result_code.num_code) {
49 case data::ResultCode::Numeric::kOk: {
50 storage_->saveInstalledVersion(ecu_serial_.ToString(), pending_target_, InstalledVersionUpdateMode::kCurrent);
51 pending_target_ = Uptane::Target::Unknown();
52 LOG_INFO <<
"The target has been successfully installed: " << target_name;
55 case data::ResultCode::Numeric::kNeedCompletion: {
56 storage_->saveInstalledVersion(ecu_serial_.ToString(), pending_target_, InstalledVersionUpdateMode::kPending);
57 LOG_INFO <<
"The target has been successfully installed, but a reboot is required to be applied: " << target_name;
61 LOG_INFO <<
"Failed to install the target: " << target_name;
80 director_repo_.updateMeta(*storage_, metadata);
81 }
catch (
const std::exception& e) {
82 LOG_ERROR <<
"Failed to update Director metadata: " << e.what();
84 std::string(
"Failed to update Director metadata: ") + e.what());
92 image_repo_.updateMeta(*storage_, metadata);
93 }
catch (
const std::exception& e) {
94 LOG_ERROR <<
"Failed to update Image repo metadata: " << e.what();
96 std::string(
"Failed to update Image repo metadata: ") + e.what());
100 if (!director_repo_.matchTargetsWithImageTargets(*(image_repo_.getTargets()))) {
101 LOG_ERROR <<
"Targets metadata from the Director and Image repositories do not match";
103 "Targets metadata from the Director and Image repositories do not match");
106 auto targetsForThisEcu = director_repo_.getTargets(serial(), hwID());
108 if (targetsForThisEcu.size() != 1) {
109 LOG_ERROR <<
"Invalid number of targets (should be 1): " << targetsForThisEcu.size();
112 "Invalid number of targets (should be 1): " + std::to_string(targetsForThisEcu.size()));
115 if (!isTargetSupported(targetsForThisEcu[0])) {
116 LOG_ERROR <<
"The given target type is not supported: " << targetsForThisEcu[0].type();
118 "The given target type is not supported: " + targetsForThisEcu[0].type());
121 pending_target_ = targetsForThisEcu[0];
123 LOG_INFO <<
"Metadata verified, new update found.";
127 void AktualizrSecondary::uptaneInitialize() {
128 if (keys_->generateUptaneKeyPair().empty()) {
129 throw std::runtime_error(
"Failed to generate Uptane key pair");
133 EcuSerials ecu_serials;
135 if (storage_->loadEcuSerials(&ecu_serials)) {
136 ecu_serial_ = ecu_serials[0].first;
137 hardware_id_ = ecu_serials[0].second;
141 std::string ecu_serial_local = config_.uptane.ecu_serial;
142 if (ecu_serial_local.empty()) {
143 ecu_serial_local = keys_->UptanePublicKey().KeyId();
146 std::string ecu_hardware_id = config_.uptane.ecu_hardware_id;
147 if (ecu_hardware_id.empty()) {
148 ecu_hardware_id = Utils::getHostname();
149 if (ecu_hardware_id.empty()) {
150 throw std::runtime_error(
"Failed to define ECU hardware ID");
155 storage_->storeEcuSerials(ecu_serials);
156 ecu_serial_ = ecu_serials[0].first;
157 hardware_id_ = ecu_serials[0].second;
167 storage_->importInstalledVersions(config_.import.base_path);
170 void AktualizrSecondary::initPendingTargetIfAny() {
172 director_repo_.checkMetaOffline(*storage_);
173 }
catch (
const std::exception& e) {
174 LOG_INFO <<
"No valid metadata found in storage.";
178 auto targetsForThisEcu = director_repo_.getTargets(ecu_serial_, hardware_id_);
180 if (targetsForThisEcu.size() != 1) {
181 LOG_ERROR <<
"Invalid number of targets (should be 1): " << targetsForThisEcu.size();
185 if (!isTargetSupported(targetsForThisEcu[0])) {
186 LOG_ERROR <<
"The given target type is not supported: " << targetsForThisEcu[0].type();
190 pending_target_ = targetsForThisEcu[0];
193 void AktualizrSecondary::registerHandlers() {
194 registerHandler(AKIpUptaneMes_PR_getInfoReq,
195 std::bind(&AktualizrSecondary::getInfoHdlr,
this, std::placeholders::_1, std::placeholders::_2));
197 registerHandler(AKIpUptaneMes_PR_versionReq,
198 std::bind(&AktualizrSecondary::versionHdlr, std::placeholders::_1, std::placeholders::_2));
200 registerHandler(AKIpUptaneMes_PR_manifestReq,
201 std::bind(&AktualizrSecondary::getManifestHdlr,
this, std::placeholders::_1, std::placeholders::_2));
203 registerHandler(AKIpUptaneMes_PR_putMetaReq2,
204 std::bind(&AktualizrSecondary::putMetaHdlr,
this, std::placeholders::_1, std::placeholders::_2));
206 registerHandler(AKIpUptaneMes_PR_installReq,
207 std::bind(&AktualizrSecondary::installHdlr,
this, std::placeholders::_1, std::placeholders::_2));
212 LOG_INFO <<
"Received an information request message; sending requested information.";
214 out_msg.present(AKIpUptaneMes_PR_getInfoResp);
215 auto info_resp = out_msg.getInfoResp();
217 SetString(&info_resp->ecuSerial, serial().ToString());
218 SetString(&info_resp->hwId, hwID().ToString());
219 info_resp->keyType =
static_cast<AKIpUptaneKeyType_t
>(publicKey().Type());
220 SetString(&info_resp->key, publicKey().Value());
222 return ReturnCode::kOk;
226 const uint32_t version = 2;
227 auto version_req = in_msg.versionReq();
228 const auto primary_version =
static_cast<uint32_t
>(version_req->version);
229 if (primary_version < version) {
230 LOG_ERROR <<
"Primary protocol version is " << primary_version <<
" but Secondary version is " << version
231 <<
"! Communication will most likely fail!";
232 }
else if (primary_version > version) {
233 LOG_INFO <<
"Primary protocol version is " << primary_version <<
" but Secondary version is " << version
234 <<
". Please consider upgrading the Secondary.";
237 out_msg.present(AKIpUptaneMes_PR_versionResp);
238 auto version_resp = out_msg.versionResp();
239 version_resp->version = version;
241 return ReturnCode::kOk;
244 AktualizrSecondary::ReturnCode AktualizrSecondary::getManifestHdlr(
Asn1Message& in_msg,
Asn1Message& out_msg)
const {
246 if (last_msg_ != AKIpUptaneMes_PR_manifestReq) {
247 LOG_INFO <<
"Received a manifest request message; sending requested manifest.";
249 LOG_DEBUG <<
"Received another manifest request message; sending the same manifest.";
252 out_msg.present(AKIpUptaneMes_PR_manifestResp);
253 auto manifest_resp = out_msg.manifestResp();
254 manifest_resp->manifest.present = manifest_PR_json;
255 SetString(&manifest_resp->manifest.choice.json, Utils::jsonToStr(getManifest()));
257 LOG_TRACE <<
"Manifest: \n" << getManifest();
258 return ReturnCode::kOk;
263 auto key = std::make_pair(repo, role);
264 if (meta_bundle.count(key) > 0) {
265 LOG_WARNING << repo.toString() <<
" metadata in contains multiple " << role.ToString() <<
" objects.";
268 meta_bundle.emplace(key, std::move(json));
271 AktualizrSecondary::ReturnCode AktualizrSecondary::putMetaHdlr(
Asn1Message& in_msg,
Asn1Message& out_msg) {
272 LOG_INFO <<
"Received a put metadata request message; verifying contents...";
273 auto md = in_msg.putMetaReq2();
274 Uptane::MetaBundle meta_bundle;
276 if (md->directorRepo.present == directorRepo_PR_collection) {
278 const int director_meta_count = md->directorRepo.choice.collection.list.count;
279 for (
int i = 0; i < director_meta_count; i++) {
281 const AKMetaJson_t
object = *md->directorRepo.choice.collection.list.array[i];
282 const std::string role = ToString(
object.role);
283 std::string json = ToString(
object.json);
284 LOG_DEBUG <<
"Received Director repo " << role <<
" metadata:\n" << json;
285 if (role == Uptane::Role::ROOT) {
286 copyMetadata(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Root(), json);
287 }
else if (role == Uptane::Role::TARGETS) {
288 copyMetadata(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Targets(), json);
290 LOG_WARNING <<
"Director metadata in unknown format:" << md->directorRepo.present;
295 if (md->imageRepo.present == imageRepo_PR_collection) {
297 const int image_meta_count = md->imageRepo.choice.collection.list.count;
298 for (
int i = 0; i < image_meta_count; i++) {
300 const AKMetaJson_t
object = *md->imageRepo.choice.collection.list.array[i];
301 const std::string role = ToString(
object.role);
302 std::string json = ToString(
object.json);
303 LOG_DEBUG <<
"Received Image repo " << role <<
" metadata:\n" << json;
304 if (role == Uptane::Role::ROOT) {
305 copyMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Root(), json);
306 }
else if (role == Uptane::Role::TIMESTAMP) {
307 copyMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp(), json);
308 }
else if (role == Uptane::Role::SNAPSHOT) {
309 copyMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot(), json);
310 }
else if (role == Uptane::Role::TARGETS) {
311 copyMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Targets(), json);
313 LOG_WARNING <<
"Image metadata in unknown format:" << md->imageRepo.present;
318 if (meta_bundle.size() != 6) {
319 LOG_WARNING <<
"Metadata received from Primary is incomplete: " << md->imageRepo.present;
324 auto m = out_msg.present(AKIpUptaneMes_PR_putMetaResp2).putMetaResp2();
325 m->result =
static_cast<AKInstallationResultCode_t
>(
result.result_code.num_code);
326 SetString(&m->description,
result.description);
328 return ReturnCode::kOk;
331 AktualizrSecondary::ReturnCode AktualizrSecondary::installHdlr(
Asn1Message& in_msg,
Asn1Message& out_msg) {
333 LOG_INFO <<
"Received an installation request message; attempting installation...";
336 auto m = out_msg.present(AKIpUptaneMes_PR_installResp2).installResp2();
337 m->result =
static_cast<AKInstallationResultCode_t
>(
result.result_code.num_code);
338 SetString(&m->description,
result.description);
340 if (data::ResultCode::Numeric::kNeedCompletion ==
result.result_code.num_code) {
341 return ReturnCode::kRebootRequired;
344 return ReturnCode::kOk;