Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
ipuptanesecondary.cc
1 #include <arpa/inet.h>
2 #include <netinet/tcp.h>
3 
4 #include "asn1/asn1_message.h"
5 #include "der_encoder.h"
6 #include "ipuptanesecondary.h"
7 #include "logging/logging.h"
8 
9 #include <memory>
10 
11 namespace Uptane {
12 
13 Uptane::SecondaryInterface::Ptr IpUptaneSecondary::connectAndCreate(const std::string& address, unsigned short port) {
14  LOG_INFO << "Connecting to and getting info about IP Secondary: " << address << ":" << port << "...";
15 
16  ConnectionSocket con_sock{address, port};
17 
18  if (con_sock.connect() == 0) {
19  LOG_INFO << "Connected to IP Secondary: "
20  << "(" << address << ":" << port << ")";
21  } else {
22  LOG_WARNING << "Failed to connect to a Secondary: " << std::strerror(errno);
23  return nullptr;
24  }
25 
26  return create(address, port, *con_sock);
27 }
28 
29 Uptane::SecondaryInterface::Ptr IpUptaneSecondary::create(const std::string& address, unsigned short port, int con_fd) {
30  Asn1Message::Ptr req(Asn1Message::Empty());
31  req->present(AKIpUptaneMes_PR_getInfoReq);
32 
33  auto m = req->getInfoReq();
34 
35  auto resp = Asn1Rpc(req, con_fd);
36 
37  if (resp->present() != AKIpUptaneMes_PR_getInfoResp) {
38  LOG_ERROR << "Failed to get info response message from Secondary";
39  throw std::runtime_error("Failed to obtain information about a Secondary: " + address + std::to_string(port));
40  }
41  auto r = resp->getInfoResp();
42 
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);
47  PublicKey pub_key = PublicKey(key, type);
48 
49  LOG_INFO << "Got info from IP Secondary: "
50  << "hardware ID: " << hw_id << " serial: " << serial;
51 
52  return std::make_shared<IpUptaneSecondary>(address, port, serial, hw_id, pub_key);
53 }
54 
55 SecondaryInterface::Ptr IpUptaneSecondary::connectAndCheck(const std::string& address, unsigned short port,
56  EcuSerial serial, HardwareIdentifier hw_id,
57  PublicKey pub_key) {
58  // try to connect:
59  // - if it succeeds compare with what we expect
60  // - otherwise, keep using what we know
61  try {
62  auto sec = IpUptaneSecondary::connectAndCreate(address, port);
63  if (sec != nullptr) {
64  auto s = sec->getSerial();
65  if (s != serial) {
66  LOG_ERROR << "Mismatch between Secondary serials " << s << " and " << serial;
67  return nullptr;
68  }
69  auto h = sec->getHwId();
70  if (h != hw_id) {
71  LOG_ERROR << "Mismatch between hardware IDs " << h << " and " << hw_id;
72  return nullptr;
73  }
74  auto p = sec->getPublicKey();
75  if (pub_key.Type() == KeyType::kUnknown) {
76  LOG_INFO << "Secondary " << s << " do not have a known public key";
77  } else if (p != pub_key) {
78  LOG_ERROR << "Mismatch between public keys " << p.Value() << " and " << pub_key.Value() << " for Secondary "
79  << serial;
80  return nullptr;
81  }
82  return sec;
83  }
84  } catch (std::exception& e) {
85  LOG_WARNING << "Could not connect to Secondary " << serial << " at " << address << ":" << port
86  << " using previously known registration data";
87  }
88 
89  return std::make_shared<IpUptaneSecondary>(address, port, std::move(serial), std::move(hw_id), std::move(pub_key));
90 }
91 
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)} {}
95 
96 bool IpUptaneSecondary::putMetadata(const RawMetaPack& meta_pack) {
97  LOG_INFO << "Sending Uptane metadata to the Secondary";
98  Asn1Message::Ptr req(Asn1Message::Empty());
99  req->present(AKIpUptaneMes_PR_putMetaReq);
100 
101  auto m = req->putMetaReq();
102  m->image.present = image_PR_json;
103  SetString(&m->image.choice.json.root, meta_pack.image_root); // NOLINT
104  SetString(&m->image.choice.json.targets, meta_pack.image_targets); // NOLINT
105  SetString(&m->image.choice.json.snapshot, meta_pack.image_snapshot); // NOLINT
106  SetString(&m->image.choice.json.timestamp, meta_pack.image_timestamp); // NOLINT
107 
108  m->director.present = director_PR_json;
109  SetString(&m->director.choice.json.root, meta_pack.director_root); // NOLINT
110  SetString(&m->director.choice.json.targets, meta_pack.director_targets); // NOLINT
111 
112  auto resp = Asn1Rpc(req, getAddr());
113 
114  if (resp->present() != AKIpUptaneMes_PR_putMetaResp) {
115  LOG_ERROR << "Failed to get response to sending manifest to Secondary";
116  return false;
117  }
118 
119  auto r = resp->putMetaResp();
120  return r->result == AKInstallationResult_success;
121 }
122 
123 bool IpUptaneSecondary::sendFirmware(const std::string& data) {
124  std::lock_guard<std::mutex> l(install_mutex);
125  LOG_INFO << "Sending firmware to the Secondary";
126  Asn1Message::Ptr req(Asn1Message::Empty());
127  req->present(AKIpUptaneMes_PR_sendFirmwareReq);
128 
129  auto m = req->sendFirmwareReq();
130  SetString(&m->firmware, data);
131  auto resp = Asn1Rpc(req, getAddr());
132 
133  if (resp->present() != AKIpUptaneMes_PR_sendFirmwareResp) {
134  LOG_ERROR << "Failed to get response to sending firmware to Secondary";
135  return false;
136  }
137 
138  auto r = resp->sendFirmwareResp();
139  return r->result == AKInstallationResult_success;
140 }
141 
142 data::ResultCode::Numeric IpUptaneSecondary::install(const std::string& target_name) {
143  LOG_INFO << "Invoking an installation of the target on the Secondary: " << target_name;
144 
145  Asn1Message::Ptr req(Asn1Message::Empty());
146  req->present(AKIpUptaneMes_PR_installReq);
147 
148  // prepare request message
149  auto req_mes = req->installReq();
150  SetString(&req_mes->hash, target_name);
151  // send request and receive response, a request-response type of RPC
152  auto resp = Asn1Rpc(req, getAddr());
153 
154  // invalid type of an response message
155  if (resp->present() != AKIpUptaneMes_PR_installResp) {
156  LOG_ERROR << "Failed to get response to an installation request to Secondary";
158  }
159 
160  // deserialize the response message
161  auto r = resp->installResp();
162 
163  return static_cast<data::ResultCode::Numeric>(r->result);
164 }
165 
166 Manifest IpUptaneSecondary::getManifest() const {
167  LOG_DEBUG << "Getting the manifest from Secondary with serial " << getSerial();
168  Asn1Message::Ptr req(Asn1Message::Empty());
169 
170  req->present(AKIpUptaneMes_PR_manifestReq);
171 
172  auto resp = Asn1Rpc(req, getAddr());
173 
174  if (resp->present() != AKIpUptaneMes_PR_manifestResp) {
175  LOG_ERROR << "Failed to get a response to a get manifest request to secondary";
176  return Json::Value();
177  }
178  auto r = resp->manifestResp();
179 
180  if (r->manifest.present != manifest_PR_json) {
181  LOG_ERROR << "Manifest wasn't in json format";
182  return Json::Value();
183  }
184  std::string manifest = ToString(r->manifest.choice.json); // NOLINT
185  return Utils::parseJSON(manifest);
186 }
187 
188 bool IpUptaneSecondary::ping() const {
189  Asn1Message::Ptr req(Asn1Message::Empty());
190  req->present(AKIpUptaneMes_PR_getInfoReq);
191 
192  auto m = req->getInfoReq();
193 
194  auto resp = Asn1Rpc(req, getAddr());
195 
196  return resp->present() == AKIpUptaneMes_PR_getInfoResp;
197 }
198 
199 } // namespace Uptane
General data structures.
Definition: types.cc:55
static Asn1Message::Ptr Empty()
Create a new Asn1Message, in order to fill it with data and send it.
Definition: asn1_message.h:46
SWM Internal integrity error.
Base data types that are used in The Update Framework (TUF), part of Uptane.