2 #include <netinet/tcp.h>
7 #include "ipuptanesecondary.h"
8 #include "logging/logging.h"
9 #include "storage/invstorage.h"
13 SecondaryInterface::Ptr IpUptaneSecondary::connectAndCreate(
const std::string& address,
unsigned short port) {
14 LOG_INFO <<
"Connecting to and getting info about IP Secondary: " << address <<
":" << port <<
"...";
18 if (con_sock.connect() == 0) {
19 LOG_INFO <<
"Connected to IP Secondary: "
20 <<
"(" << address <<
":" << port <<
")";
22 LOG_WARNING <<
"Failed to connect to a Secondary: " << std::strerror(errno);
26 return create(address, port, *con_sock);
29 SecondaryInterface::Ptr IpUptaneSecondary::create(
const std::string& address,
unsigned short port,
int con_fd) {
31 req->present(AKIpUptaneMes_PR_getInfoReq);
33 auto m = req->getInfoReq();
34 auto resp = Asn1Rpc(req, con_fd);
36 if (resp->present() != AKIpUptaneMes_PR_getInfoResp) {
37 LOG_ERROR <<
"IP Secondary failed to respond to information request at " << address <<
":" << port;
38 return std::make_shared<IpUptaneSecondary>(address, port, EcuSerial::Unknown(), HardwareIdentifier::Unknown(),
41 auto r = resp->getInfoResp();
43 EcuSerial serial = EcuSerial(ToString(r->ecuSerial));
44 HardwareIdentifier hw_id = HardwareIdentifier(ToString(r->hwId));
45 std::string key = ToString(r->key);
46 auto type =
static_cast<KeyType
>(r->keyType);
49 LOG_INFO <<
"Got ECU information from IP Secondary: "
50 <<
"hardware ID: " << hw_id <<
" serial: " << serial;
52 return std::make_shared<IpUptaneSecondary>(address, port, serial, hw_id, pub_key);
55 SecondaryInterface::Ptr IpUptaneSecondary::connectAndCheck(
const std::string& address,
unsigned short port,
56 EcuSerial serial, HardwareIdentifier hw_id,
62 auto sec = IpUptaneSecondary::connectAndCreate(address, port);
64 auto s = sec->getSerial();
65 if (s != serial && serial != EcuSerial::Unknown()) {
66 LOG_WARNING <<
"Expected IP Secondary at " << address <<
":" << port <<
" with serial " << serial
67 <<
" but found " << s;
69 auto h = sec->getHwId();
70 if (h != hw_id && hw_id != HardwareIdentifier::Unknown()) {
71 LOG_WARNING <<
"Expected IP Secondary at " << address <<
":" << port <<
" with hardware ID " << hw_id
72 <<
" but found " << h;
74 auto p = sec->getPublicKey();
75 if (p.Type() == KeyType::kUnknown) {
76 LOG_ERROR <<
"IP Secondary at " << address <<
":" << port <<
" has an unknown key type!";
78 }
else if (p != pub_key && pub_key.Type() != KeyType::kUnknown) {
79 LOG_WARNING <<
"Expected IP Secondary at " << address <<
":" << port <<
" with public key:\n"
80 << pub_key.Value() <<
"... but found:\n"
85 }
catch (std::exception& e) {
86 LOG_WARNING <<
"Could not connect to IP Secondary at " << address <<
":" << port <<
" with serial " << serial;
89 return std::make_shared<IpUptaneSecondary>(address, port, std::move(serial), std::move(hw_id), std::move(pub_key));
92 IpUptaneSecondary::IpUptaneSecondary(
const std::string& address,
unsigned short port, EcuSerial serial,
93 HardwareIdentifier hw_id,
PublicKey pub_key)
94 : addr_{address, port}, serial_{std::move(serial)}, hw_id_{std::move(hw_id)}, pub_key_{std::move(pub_key)} {}
101 void IpUptaneSecondary::getSecondaryVersion()
const {
102 LOG_DEBUG <<
"Negotiating the protocol version with Secondary " << getSerial();
103 const uint32_t latest_version = 2;
105 req->present(AKIpUptaneMes_PR_versionReq);
106 auto m = req->versionReq();
107 m->version = latest_version;
108 auto resp = Asn1Rpc(req, getAddr());
110 if (resp->present() != AKIpUptaneMes_PR_versionResp) {
114 LOG_DEBUG <<
"Secondary " << getSerial() <<
" failed to respond to a version request; assuming version 1.";
115 protocol_version = 1;
117 LOG_INFO <<
"Secondary " << getSerial()
118 <<
" failed to respond to a version request; unable to determine protocol version.";
123 auto r = resp->versionResp();
124 const auto secondary_version =
static_cast<uint32_t
>(r->version);
125 if (secondary_version <= latest_version) {
126 LOG_DEBUG <<
"Using protocol version " << secondary_version <<
" for Secondary " << getSerial();
127 protocol_version = secondary_version;
129 LOG_ERROR <<
"Secondary protocol version is " << secondary_version <<
" but Primary only supports up to "
130 << latest_version <<
"! Communication will most likely fail!";
131 protocol_version = latest_version;
136 Uptane::MetaBundle meta_bundle;
137 if (!secondary_provider_->getMetadata(&meta_bundle, target)) {
139 "Unable to load stored metadata from Primary");
142 getSecondaryVersion();
144 LOG_INFO <<
"Sending Uptane metadata to the Secondary";
146 if (protocol_version == 2) {
147 put_result = putMetadata_v2(meta_bundle);
148 }
else if (protocol_version == 1) {
149 put_result = putMetadata_v1(meta_bundle);
151 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
153 "Unexpected protocol version: " + std::to_string(protocol_version));
160 req->present(AKIpUptaneMes_PR_putMetaReq);
162 auto m = req->putMetaReq();
163 m->director.present = director_PR_json;
165 SetString(&m->director.choice.json.root,
166 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Root()));
168 SetString(&m->director.choice.json.targets,
169 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
171 m->image.present = image_PR_json;
173 SetString(&m->image.choice.json.root,
174 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Root()));
176 SetString(&m->image.choice.json.timestamp,
177 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
179 SetString(&m->image.choice.json.snapshot,
180 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
182 SetString(&m->image.choice.json.targets,
183 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
185 auto resp = Asn1Rpc(req, getAddr());
187 if (resp->present() != AKIpUptaneMes_PR_putMetaResp) {
188 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a request to receive metadata.";
191 "Secondary " + getSerial().ToString() +
" failed to respond to a request to receive metadata.");
194 auto r = resp->putMetaResp();
195 if (r->result == AKInstallationResult_success) {
199 "Error sending metadata to Secondary");
203 void IpUptaneSecondary::addMetadata(
const Uptane::MetaBundle& meta_bundle,
const Uptane::RepositoryType repo,
204 const Uptane::Role& role, AKMetaCollection_t& collection) {
205 auto* meta_json = Asn1Allocation<AKMetaJson_t>();
206 SetString(&meta_json->role, role.ToString());
207 SetString(&meta_json->json, getMetaFromBundle(meta_bundle, repo, role));
208 ASN_SEQUENCE_ADD(&collection, meta_json);
213 req->present(AKIpUptaneMes_PR_putMetaReq2);
215 auto m = req->putMetaReq2();
216 m->directorRepo.present = directorRepo_PR_collection;
217 m->imageRepo.present = imageRepo_PR_collection;
220 addMetadata(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Root(), m->directorRepo.choice.collection);
221 addMetadata(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Targets(),
222 m->directorRepo.choice.collection);
224 addMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Root(), m->imageRepo.choice.collection);
226 addMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp(), m->imageRepo.choice.collection);
228 addMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot(), m->imageRepo.choice.collection);
230 addMetadata(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Targets(), m->imageRepo.choice.collection);
232 auto resp = Asn1Rpc(req, getAddr());
234 if (resp->present() != AKIpUptaneMes_PR_putMetaResp2) {
235 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a request to receive metadata.";
238 "Secondary " + getSerial().ToString() +
" failed to respond to a request to receive metadata.");
241 auto r = resp->putMetaResp2();
245 Manifest IpUptaneSecondary::getManifest()
const {
246 getSecondaryVersion();
248 LOG_DEBUG <<
"Getting the manifest from Secondary with serial " << getSerial();
251 req->present(AKIpUptaneMes_PR_manifestReq);
252 auto resp = Asn1Rpc(req, getAddr());
254 if (resp->present() != AKIpUptaneMes_PR_manifestResp) {
255 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a manifest request.";
256 return Json::Value();
258 auto r = resp->manifestResp();
260 if (r->manifest.present != manifest_PR_json) {
261 LOG_ERROR <<
"Manifest wasn't in json format";
262 return Json::Value();
264 std::string manifest = ToString(r->manifest.choice.json);
265 return Utils::parseJSON(manifest);
268 bool IpUptaneSecondary::ping()
const {
270 req->present(AKIpUptaneMes_PR_getInfoReq);
272 auto m = req->getInfoReq();
274 auto resp = Asn1Rpc(req, getAddr());
276 return resp->present() == AKIpUptaneMes_PR_getInfoResp;
281 if (protocol_version == 2) {
282 send_result = sendFirmware_v2(target);
283 }
else if (protocol_version == 1) {
284 send_result = sendFirmware_v1(target);
286 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
288 "Unexpected protocol version: " + std::to_string(protocol_version));
294 std::string data_to_send;
298 data_to_send = secondary_provider_->getTreehubCredentials();
300 std::stringstream sstr;
301 auto str = secondary_provider_->getTargetFileHandle(target);
303 data_to_send = sstr.str();
306 LOG_INFO <<
"Sending firmware to the Secondary, size: " << data_to_send.size();
308 req->present(AKIpUptaneMes_PR_sendFirmwareReq);
310 auto m = req->sendFirmwareReq();
311 SetString(&m->firmware, data_to_send);
312 auto resp = Asn1Rpc(req, getAddr());
314 if (resp->present() != AKIpUptaneMes_PR_sendFirmwareResp) {
315 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a request to receive firmware.";
318 "Secondary " + getSerial().ToString() +
" failed to respond to a request to receive firmware.");
321 auto r = resp->sendFirmwareResp();
322 if (r->result == AKInstallationResult_success) {
329 LOG_INFO <<
"Instructing Secondary " << getSerial() <<
" to receive target " << target.filename();
331 return downloadOstreeRev(target);
333 return uploadFirmware(target);
339 if (protocol_version == 2) {
340 install_result = install_v2(target);
341 }
else if (protocol_version == 1) {
342 install_result = install_v1(target);
344 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
346 "Unexpected protocol version: " + std::to_string(protocol_version));
349 return install_result;
353 LOG_INFO <<
"Invoking an installation of the target on the Secondary: " << target.filename();
356 req->present(AKIpUptaneMes_PR_installReq);
359 auto req_mes = req->installReq();
360 SetString(&req_mes->hash, target.filename());
362 auto resp = Asn1Rpc(req, getAddr());
365 if (resp->present() != AKIpUptaneMes_PR_installResp) {
366 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to an installation request.";
369 "Secondary " + getSerial().ToString() +
" failed to respond to an installation request.");
373 auto r = resp->installResp();
379 LOG_INFO <<
"Instructing Secondary " << getSerial() <<
" to install target " << target.filename();
380 return invokeInstallOnSecondary(target);
384 LOG_INFO <<
"Instructing Secondary ( " << getSerial() <<
" ) to download OSTree commit ( " << target.sha256Hash()
386 const std::string tls_creds = secondary_provider_->getTreehubCredentials();
388 req->present(
static_cast<AKIpUptaneMes_PR
>(AKIpUptaneMes_PR_downloadOstreeRevReq));
390 auto m = req->downloadOstreeRevReq();
391 SetString(&m->tlsCred, tls_creds);
392 auto resp = Asn1Rpc(req, getAddr());
394 if (resp->present() != AKIpUptaneMes_PR_downloadOstreeRevResp) {
395 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a request to download an OSTree commit.";
397 data::ResultCode::Numeric::kUnknown,
398 "Secondary " + getSerial().ToString() +
" failed to respond to a request to download an OSTree commit.");
401 auto r = resp->downloadOstreeRevResp();
406 LOG_INFO <<
"Uploading the target image (" << target.filename() <<
") "
407 <<
"to the Secondary (" << getSerial() <<
")";
411 auto image_reader = secondary_provider_->getTargetFileHandle(target);
413 uint64_t image_size = target.length();
414 const size_t size = 1024;
415 size_t total_send_data = 0;
416 std::array<uint8_t, size> buf{};
419 while (total_send_data < image_size && upload_data_result.isSuccess()) {
420 image_reader.read(
reinterpret_cast<char*
>(buf.data()), buf.size());
421 upload_data_result = uploadFirmwareData(buf.data(),
static_cast<size_t>(image_reader.gcount()));
422 total_send_data +=
static_cast<size_t>(image_reader.gcount());
424 if (upload_data_result.isSuccess() && total_send_data == image_size) {
426 }
else if (!upload_data_result.isSuccess()) {
427 upload_result = upload_data_result;
431 image_reader.close();
432 return upload_result;
437 req->present(AKIpUptaneMes_PR_uploadDataReq);
439 auto m = req->uploadDataReq();
440 OCTET_STRING_fromBuf(&m->data,
reinterpret_cast<const char*
>(
data),
static_cast<int>(size));
441 auto resp = Asn1Rpc(req, getAddr());
443 if (resp->present() == AKIpUptaneMes_PR_NOTHING) {
444 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to a request to receive firmware data.";
446 data::ResultCode::Numeric::kUnknown,
447 "Secondary " + getSerial().ToString() +
" failed to respond to a request to receive firmware data.");
449 if (resp->present() != AKIpUptaneMes_PR_uploadDataResp) {
450 LOG_ERROR <<
"Secondary " << getSerial() <<
" returned an invalid response to a request to receive firmware data.";
453 "Secondary " + getSerial().ToString() +
" returned an invalid reponse to a request to receive firmware data.");
456 auto r = resp->uploadDataResp();
462 req->present(AKIpUptaneMes_PR_installReq);
465 auto req_mes = req->installReq();
466 SetString(&req_mes->hash, target.filename());
468 auto resp = Asn1Rpc(req, getAddr());
471 if (resp->present() != AKIpUptaneMes_PR_installResp2) {
472 LOG_ERROR <<
"Secondary " << getSerial() <<
" failed to respond to an installation request.";
474 data::ResultCode::Numeric::kUnknown,
475 "Secondary " + getSerial().ToString() +
" failed to respond to an installation request.");
479 auto r = resp->installResp2();