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 <<
"Failed to get a response to a version request from Secondary " << getSerial()
115 <<
"; assuming version 1.";
116 protocol_version = 1;
118 LOG_INFO <<
"Failed to get a response to a version request from Secondary " << getSerial()
119 <<
"; unable to determine protocol version.";
124 auto r = resp->versionResp();
125 const auto secondary_version =
static_cast<uint32_t
>(r->version);
126 if (secondary_version <= latest_version) {
127 LOG_DEBUG <<
"Using protocol version " << secondary_version <<
" for Secondary " << getSerial();
128 protocol_version = secondary_version;
130 LOG_ERROR <<
"Secondary protocol version is " << secondary_version <<
" but Primary only supports up to " 131 << latest_version <<
"! Communication will most likely fail!";
132 protocol_version = latest_version;
137 Uptane::MetaBundle meta_bundle;
138 if (!secondary_provider_->getMetadata(&meta_bundle, target)) {
140 "Unable to load stored metadata from Primary");
143 getSecondaryVersion();
145 LOG_INFO <<
"Sending Uptane metadata to the Secondary";
147 if (protocol_version == 2) {
148 put_result = putMetadata_v2(meta_bundle);
149 }
else if (protocol_version == 1) {
150 put_result = putMetadata_v1(meta_bundle);
152 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
154 "Unexpected protocol version: " + std::to_string(protocol_version));
161 req->present(AKIpUptaneMes_PR_putMetaReq);
163 auto m = req->putMetaReq();
164 m->director.present = director_PR_json;
166 SetString(&m->director.choice.json.root,
167 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Root()));
169 SetString(&m->director.choice.json.targets,
170 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Director(), Uptane::Role::Targets()));
172 m->image.present = image_PR_json;
174 SetString(&m->image.choice.json.root,
175 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Root()));
177 SetString(&m->image.choice.json.timestamp,
178 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()));
180 SetString(&m->image.choice.json.snapshot,
181 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()));
183 SetString(&m->image.choice.json.targets,
184 getMetaFromBundle(meta_bundle, Uptane::RepositoryType::Image(), Uptane::Role::Targets()));
186 auto resp = Asn1Rpc(req, getAddr());
188 if (resp->present() != AKIpUptaneMes_PR_putMetaResp) {
189 LOG_ERROR <<
"Failed to get response from sending metadata to Secondary";
191 "Failed to get response from sending metadata to Secondary");
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 <<
"Failed to get response from sending metadata to Secondary";
237 "Failed to get response from sending metadata to Secondary");
240 auto r = resp->putMetaResp2();
244 Manifest IpUptaneSecondary::getManifest()
const {
245 getSecondaryVersion();
247 LOG_DEBUG <<
"Getting the manifest from Secondary with serial " << getSerial();
250 req->present(AKIpUptaneMes_PR_manifestReq);
251 auto resp = Asn1Rpc(req, getAddr());
253 if (resp->present() != AKIpUptaneMes_PR_manifestResp) {
254 LOG_ERROR <<
"Failed to get a response to a manifest request to Secondary with serial " << getSerial();
255 return Json::Value();
257 auto r = resp->manifestResp();
259 if (r->manifest.present != manifest_PR_json) {
260 LOG_ERROR <<
"Manifest wasn't in json format";
261 return Json::Value();
263 std::string manifest = ToString(r->manifest.choice.json);
264 return Utils::parseJSON(manifest);
267 bool IpUptaneSecondary::ping()
const {
269 req->present(AKIpUptaneMes_PR_getInfoReq);
271 auto m = req->getInfoReq();
273 auto resp = Asn1Rpc(req, getAddr());
275 return resp->present() == AKIpUptaneMes_PR_getInfoResp;
280 if (protocol_version == 2) {
281 send_result = sendFirmware_v2(target);
282 }
else if (protocol_version == 1) {
283 send_result = sendFirmware_v1(target);
285 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
287 "Unexpected protocol version: " + std::to_string(protocol_version));
293 std::string data_to_send;
297 data_to_send = secondary_provider_->getTreehubCredentials();
299 std::stringstream sstr;
300 auto str = secondary_provider_->getTargetFileHandle(target);
302 data_to_send = sstr.str();
305 LOG_INFO <<
"Sending firmware to the Secondary, size: " << data_to_send.size();
307 req->present(AKIpUptaneMes_PR_sendFirmwareReq);
309 auto m = req->sendFirmwareReq();
310 SetString(&m->firmware, data_to_send);
311 auto resp = Asn1Rpc(req, getAddr());
313 if (resp->present() != AKIpUptaneMes_PR_sendFirmwareResp) {
314 LOG_ERROR <<
"Failed to get response to sending firmware to Secondary";
316 "Failed to get response to sending firmware to Secondary");
319 auto r = resp->sendFirmwareResp();
320 if (r->result == AKInstallationResult_success) {
327 LOG_INFO <<
"Instructing Secondary " << getSerial() <<
" to receive target " << target.filename();
329 return downloadOstreeRev(target);
331 return uploadFirmware(target);
337 if (protocol_version == 2) {
338 install_result = install_v2(target);
339 }
else if (protocol_version == 1) {
340 install_result = install_v1(target);
342 LOG_ERROR <<
"Unexpected protocol version: " << protocol_version;
344 "Unexpected protocol version: " + std::to_string(protocol_version));
347 return install_result;
351 LOG_INFO <<
"Invoking an installation of the target on the Secondary: " << target.filename();
354 req->present(AKIpUptaneMes_PR_installReq);
357 auto req_mes = req->installReq();
358 SetString(&req_mes->hash, target.filename());
360 auto resp = Asn1Rpc(req, getAddr());
363 if (resp->present() != AKIpUptaneMes_PR_installResp) {
364 LOG_ERROR <<
"Failed to get response to an installation request to Secondary";
366 "Failed to get response to an installation request to Secondary");
370 auto r = resp->installResp();
376 LOG_INFO <<
"Instructing Secondary " << getSerial() <<
" to install target " << target.filename();
377 return invokeInstallOnSecondary(target);
381 LOG_INFO <<
"Instructing Secondary ( " << getSerial() <<
" ) to download OSTree commit ( " << target.sha256Hash()
383 const std::string tls_creds = secondary_provider_->getTreehubCredentials();
385 req->present(static_cast<AKIpUptaneMes_PR>(AKIpUptaneMes_PR_downloadOstreeRevReq));
387 auto m = req->downloadOstreeRevReq();
388 SetString(&m->tlsCred, tls_creds);
389 auto resp = Asn1Rpc(req, getAddr());
391 if (resp->present() != AKIpUptaneMes_PR_downloadOstreeRevResp) {
392 LOG_ERROR <<
"Failed to get response to download ostree revision request";
394 "Failed to get response to download ostree revision request");
397 auto r = resp->downloadOstreeRevResp();
402 LOG_INFO <<
"Uploading the target image (" << target.filename() <<
") " 403 <<
"to the Secondary (" << getSerial() <<
")";
407 auto image_reader = secondary_provider_->getTargetFileHandle(target);
409 uint64_t image_size = target.length();
410 const size_t size = 1024;
411 size_t total_send_data = 0;
412 std::array<uint8_t, size> buf{};
415 while (total_send_data < image_size && upload_data_result.isSuccess()) {
416 image_reader.read(reinterpret_cast<char*>(buf.data()), buf.size());
417 upload_data_result = uploadFirmwareData(buf.data(),
static_cast<size_t>(image_reader.gcount()));
418 total_send_data +=
static_cast<size_t>(image_reader.gcount());
420 if (upload_data_result.isSuccess() && total_send_data == image_size) {
422 }
else if (!upload_data_result.isSuccess()) {
423 upload_result = upload_data_result;
427 image_reader.close();
428 return upload_result;
433 req->present(AKIpUptaneMes_PR_uploadDataReq);
435 auto m = req->uploadDataReq();
436 OCTET_STRING_fromBuf(&m->data, reinterpret_cast<const char*>(data), static_cast<int>(size));
437 auto resp = Asn1Rpc(req, getAddr());
439 if (resp->present() == AKIpUptaneMes_PR_NOTHING) {
440 LOG_ERROR <<
"Failed to get response to an uploading data request to Secondary";
442 "Failed to get response to an uploading data request to Secondary");
444 if (resp->present() != AKIpUptaneMes_PR_uploadDataResp) {
445 LOG_ERROR <<
"Invalid response to an uploading data request to Secondary";
447 "Invalid response to an uploading data request to Secondary");
450 auto r = resp->uploadDataResp();
456 req->present(AKIpUptaneMes_PR_installReq);
459 auto req_mes = req->installReq();
460 SetString(&req_mes->hash, target.filename());
462 auto resp = Asn1Rpc(req, getAddr());
465 if (resp->present() != AKIpUptaneMes_PR_installResp2) {
466 LOG_ERROR <<
"Failed to get response to an installation request to Secondary";
468 "Failed to get response to an installation request to Secondary");
472 auto r = resp->installResp2();
bool IsOstree() const
Is this an OSTree target? OSTree targets need special treatment because the hash doesn't represent th...
static Asn1Message::Ptr Empty()
Create a new Asn1Message, in order to fill it with data and send it.
Metadata verification failed.
SWM Internal integrity error.
Base data types that are used in The Update Framework (TUF), part of Uptane.