Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
types.h
Go to the documentation of this file.
1 #ifndef TYPES_H_
2 #define TYPES_H_
3 /** \file */
4 
5 #include <algorithm>
6 #include <stdexcept>
7 
8 #include <json/json.h>
9 #include <boost/filesystem.hpp>
10 
11 // kSharedCredReuse is intended solely for testing. It should not be used in
12 // production.
13 enum class ProvisionMode { kSharedCred = 0, kDeviceCred, kSharedCredReuse, kDefault };
14 std::ostream &operator<<(std::ostream &os, ProvisionMode mode);
15 
16 enum class StorageType { kFileSystem = 0, kSqlite };
17 std::ostream &operator<<(std::ostream &os, StorageType stype);
18 
19 namespace utils {
20 /**
21  * @brief The BasedPath class
22  * Can represent an absolute or relative path, only readable through the BasePath::get() method.
23  *
24  * The intent is to avoid unintentional use of the "naked" relative path by
25  * mandating a base directory for each instantiation.
26  *
27  * TODO has to be moved into Utils namespace
28  */
29 class BasedPath {
30  public:
31  BasedPath(boost::filesystem::path p) : p_(std::move(p)) {}
32  boost::filesystem::path get(const boost::filesystem::path &base) const;
33  bool empty() const { return p_.empty(); }
34  bool operator==(const BasedPath &b) const { return p_ == b.p_; }
35  bool operator!=(const BasedPath &b) const { return !(*this == b); }
36 
37  private:
38  boost::filesystem::path p_;
39 };
40 
41 } // namespace utils
42 
43 // Keep these in sync with AKIpUptaneKeyType ASN.1 definitions.
44 enum class KeyType {
45  kED25519 = 0,
46  kFirstKnown = kED25519,
47  kRSA2048,
48  kRSA3072,
49  kRSA4096,
50  kLastKnown = kRSA4096,
51  kUnknown = 0xff
52 };
53 
54 inline std::ostream &operator<<(std::ostream &os, const KeyType kt) {
55  std::string kt_str;
56  switch (kt) {
57  case KeyType::kRSA2048:
58  kt_str = "RSA2048";
59  break;
60  case KeyType::kRSA3072:
61  kt_str = "RSA3072";
62  break;
63  case KeyType::kRSA4096:
64  kt_str = "RSA4096";
65  break;
66  case KeyType::kED25519:
67  kt_str = "ED25519";
68  break;
69  default:
70  kt_str = "unknown";
71  break;
72  }
73  os << '"' << kt_str << '"';
74  return os;
75 }
76 
77 inline std::istream &operator>>(std::istream &is, KeyType &kt) {
78  std::string kt_str;
79 
80  is >> kt_str;
81  std::transform(kt_str.begin(), kt_str.end(), kt_str.begin(), ::toupper);
82  kt_str.erase(std::remove(kt_str.begin(), kt_str.end(), '"'), kt_str.end());
83 
84  if (kt_str == "RSA2048") {
85  kt = KeyType::kRSA2048;
86  } else if (kt_str == "RSA3072") {
87  kt = KeyType::kRSA3072;
88  } else if (kt_str == "RSA4096") {
89  kt = KeyType::kRSA4096;
90  } else if (kt_str == "ED25519") {
91  kt = KeyType::kED25519;
92  } else {
93  kt = KeyType::kUnknown;
94  }
95  return is;
96 }
97 
98 enum class CryptoSource { kFile = 0, kPkcs11, kAndroid };
99 
100 inline std::ostream &operator<<(std::ostream &os, CryptoSource cs) {
101  std::string cs_str;
102  switch (cs) {
103  case CryptoSource::kFile:
104  cs_str = "file";
105  break;
106  case CryptoSource::kPkcs11:
107  cs_str = "pkcs11";
108  break;
109  default:
110  cs_str = "unknown";
111  break;
112  }
113  os << '"' << cs_str << '"';
114  return os;
115 }
116 
117 class PublicKey {
118  public:
119  PublicKey() = default;
120  explicit PublicKey(const boost::filesystem::path &path);
121 
122  explicit PublicKey(Json::Value uptane_json);
123 
124  PublicKey(const std::string &value, KeyType type);
125 
126  std::string Value() const { return value_; }
127 
128  KeyType Type() const { return type_; }
129  /**
130  * Verify a signature using this public key
131  */
132  bool VerifySignature(const std::string &signature, const std::string &message) const;
133  /**
134  * Uptane Json representation of this public key. Used in root.json
135  * and during provisioning.
136  */
137  Json::Value ToUptane() const;
138 
139  std::string KeyId() const;
140  bool operator==(const PublicKey &rhs) const;
141 
142  bool operator!=(const PublicKey &rhs) const { return !(*this == rhs); }
143 
144  private:
145  // std::string can be implicitly converted to a Json::Value. Make sure that
146  // the Json::Value constructor is not called accidentally.
147  PublicKey(std::string);
148  std::string value_;
149  KeyType type_{KeyType::kUnknown};
150 };
151 
152 /**
153  * @brief The Hash class The hash of a file or Uptane metadata.
154  * File hashes/checksums in Uptane include the length of the object,
155  * in order to defeat infinite download attacks.
156  */
157 class Hash {
158  public:
159  // order corresponds algorithm priority
160  enum class Type { kSha256, kSha512, kUnknownAlgorithm };
161 
162  static Hash generate(Type type, const std::string &data);
163  Hash(const std::string &type, const std::string &hash);
164  Hash(Type type, const std::string &hash);
165 
166  bool HaveAlgorithm() const { return type_ != Type::kUnknownAlgorithm; }
167  bool operator==(const Hash &other) const;
168  bool operator!=(const Hash &other) const { return !operator==(other); }
169  static std::string TypeString(Type type);
170  std::string TypeString() const;
171  Type type() const;
172  std::string HashString() const { return hash_; }
173  friend std::ostream &operator<<(std::ostream &os, const Hash &h);
174 
175  static std::string encodeVector(const std::vector<Hash> &hashes);
176  static std::vector<Hash> decodeVector(std::string hashes_str);
177 
178  private:
179  Type type_;
180  std::string hash_;
181 };
182 
183 std::ostream &operator<<(std::ostream &os, const Hash &h);
184 
185 // timestamp, compatible with tuf
186 class TimeStamp {
187  public:
188  static TimeStamp Now();
189  static struct tm CurrentTime();
190  /** An invalid TimeStamp */
192  explicit TimeStamp(std::string rfc3339);
193  explicit TimeStamp(struct tm time);
194  bool IsExpiredAt(const TimeStamp &now) const;
195  bool IsValid() const;
196  std::string ToString() const { return time_; }
197  bool operator<(const TimeStamp &other) const;
198  bool operator>(const TimeStamp &other) const;
199  friend std::ostream &operator<<(std::ostream &os, const TimeStamp &t);
200  bool operator==(const TimeStamp &rhs) const { return time_ == rhs.time_; }
201 
202  class InvalidTimeStamp : public std::domain_error {
203  public:
204  InvalidTimeStamp() : std::domain_error("invalid timestamp") {}
205  ~InvalidTimeStamp() noexcept override = default;
206  };
207 
208  private:
209  std::string time_;
210 };
211 
212 std::ostream &operator<<(std::ostream &os, const TimeStamp &t);
213 
214 /// General data structures.
215 namespace data {
216 
217 using UpdateRequestId = std::string;
218 struct Package {
219  std::string name;
220  std::string version;
221  Json::Value toJson() const;
222  static Package fromJson(const std::string & /*json_str*/);
223 };
224 
225 struct ResultCode {
226  // Keep these in sync with AKInstallationResultCode ASN.1 definitions.
227  enum class Numeric {
228  kOk = 0,
229  /// Operation has already been processed
230  kAlreadyProcessed = 1,
231  /// Metadata verification failed
232  kVerificationFailed = 3,
233  /// Package installation failed
234  kInstallFailed = 4,
235  /// Package download failed
236  kDownloadFailed = 5,
237  /// SWM Internal integrity error
238  kInternalError = 18,
239  /// Other error
240  kGeneralError = 19,
241  // Install needs to be finalized (e.g: reboot)
242  kNeedCompletion = 21,
243  // Customer specific
244  kCustomError = 22,
245  // Unknown
246  kUnknown = -1,
247  };
248 
249  // note: intentionally *not* explicit, to make the common case easier
250  ResultCode(ResultCode::Numeric in_num_code) : num_code(in_num_code) {}
251  ResultCode(ResultCode::Numeric in_num_code, std::string text_code_in)
252  : num_code(in_num_code), text_code(std::move(text_code_in)) {}
253 
254  bool operator==(const ResultCode &rhs) const { return num_code == rhs.num_code && toString() == rhs.toString(); }
255  bool operator!=(const ResultCode &rhs) const { return !(*this == rhs); }
256  friend std::ostream &operator<<(std::ostream &os, const ResultCode &result_code);
257 
258  Numeric num_code;
259  std::string text_code;
260 
261  // Allows to have a numeric code with a default representation, but also with
262  // any string representation. This is specifically useful for campaign success
263  // analysis, because the device installation report concatenates the
264  // individual ECU ResultCodes.
265  std::string toString() const {
266  if (text_code != "") {
267  return text_code;
268  }
269 
270  return std::string(string_repr.at(num_code));
271  }
272 
273  // non-lossy reprensation for serialization
274  std::string toRepr() const;
275  static ResultCode fromRepr(const std::string &repr);
276 
277  private:
278  static const std::map<Numeric, const char *> string_repr;
279 };
280 
281 std::ostream &operator<<(std::ostream &os, const ResultCode &result_code);
282 
284  InstallationResult() = default;
285  InstallationResult(ResultCode result_code_in, std::string description_in)
286  : success(result_code_in.num_code == ResultCode::Numeric::kOk ||
287  result_code_in.num_code == ResultCode::Numeric::kAlreadyProcessed),
288  result_code(std::move(result_code_in)),
289  description(std::move(description_in)) {}
290  InstallationResult(bool success_in, ResultCode result_code_in, std::string description_in)
291  : success(success_in), result_code(std::move(result_code_in)), description(std::move(description_in)) {}
292 
293  Json::Value toJson() const;
294  bool isSuccess() const { return success; };
295  bool needCompletion() const { return result_code == ResultCode::Numeric::kNeedCompletion; }
296 
297  bool success{true};
298  ResultCode result_code{ResultCode::Numeric::kOk};
299  std::string description;
300 };
301 
302 } // namespace data
303 
304 namespace Uptane {
305 
307  InstalledImageInfo() : name{""} {}
308  InstalledImageInfo(std::string name_in, uint64_t len_in, std::string hash_in)
309  : name(std::move(name_in)), len(len_in), hash(std::move(hash_in)) {}
310  std::string name;
311  uint64_t len{0};
312  std::string hash;
313 };
314 
316  public:
317  // https://github.com/advancedtelematic/ota-tuf/blob/master/libtuf/src/main/scala/com/advancedtelematic/libtuf/data/TufDataType.scala
318  static const int kMinLength = 0;
319  static const int kMaxLength = 200;
320 
321  static HardwareIdentifier Unknown() { return HardwareIdentifier("Unknown"); }
322  explicit HardwareIdentifier(const std::string &hwid) : hwid_(hwid) {
323  /* if (hwid.length() < kMinLength) {
324  throw std::out_of_range("Hardware Identifier too short");
325  } */
326  if (kMaxLength < hwid.length()) {
327  throw std::out_of_range("Hardware Identifier too long");
328  }
329  }
330 
331  std::string ToString() const { return hwid_; }
332 
333  bool operator==(const HardwareIdentifier &rhs) const { return hwid_ == rhs.hwid_; }
334  bool operator!=(const HardwareIdentifier &rhs) const { return !(*this == rhs); }
335 
336  bool operator<(const HardwareIdentifier &rhs) const { return hwid_ < rhs.hwid_; }
337  friend std::ostream &operator<<(std::ostream &os, const HardwareIdentifier &hwid);
338  friend struct std::hash<Uptane::HardwareIdentifier>;
339 
340  private:
341  std::string hwid_;
342 };
343 
344 std::ostream &operator<<(std::ostream &os, const HardwareIdentifier &hwid);
345 
346 class EcuSerial {
347  public:
348  // https://github.com/advancedtelematic/ota-tuf/blob/master/libtuf/src/main/scala/com/advancedtelematic/libtuf/data/TufDataType.scala
349  static const int kMinLength = 1;
350  static const int kMaxLength = 64;
351 
352  static EcuSerial Unknown() { return EcuSerial("Unknown"); }
353  explicit EcuSerial(const std::string &ecu_serial) : ecu_serial_(ecu_serial) {
354  if (ecu_serial.length() < kMinLength) {
355  throw std::out_of_range("Ecu serial identifier is too short");
356  }
357  if (kMaxLength < ecu_serial.length()) {
358  throw std::out_of_range("Ecu serial identifier is too long");
359  }
360  }
361 
362  std::string ToString() const { return ecu_serial_; }
363 
364  bool operator==(const EcuSerial &rhs) const { return ecu_serial_ == rhs.ecu_serial_; }
365  bool operator!=(const EcuSerial &rhs) const { return !(*this == rhs); }
366 
367  bool operator<(const EcuSerial &rhs) const { return ecu_serial_ < rhs.ecu_serial_; }
368  friend std::ostream &operator<<(std::ostream &os, const EcuSerial &ecu_serial);
369  friend struct std::hash<Uptane::EcuSerial>;
370 
371  private:
372  std::string ecu_serial_;
373 };
374 
375 std::ostream &operator<<(std::ostream &os, const EcuSerial &ecu_serial);
376 
377 using EcuMap = std::map<EcuSerial, HardwareIdentifier>;
378 
379 class Target {
380  public:
381  // From Uptane metadata
382  Target(std::string filename, const Json::Value &content);
383  // Internal use only. Only used for reading installed_versions list and by
384  // various tests.
385  Target(std::string filename, EcuMap ecus, std::vector<Hash> hashes, uint64_t length, std::string correlation_id = "");
386 
387  static Target Unknown();
388 
389  const EcuMap &ecus() const { return ecus_; }
390  std::string filename() const { return filename_; }
391  std::string sha256Hash() const;
392  std::string sha512Hash() const;
393  const std::vector<Hash> &hashes() const { return hashes_; }
394  const std::vector<HardwareIdentifier> &hardwareIds() const { return hwids_; }
395  std::string custom_version() const { return custom_["version"].asString(); }
396  Json::Value custom_data() const { return custom_; }
397  void updateCustom(Json::Value &custom) { custom_ = custom; }
398  std::string correlation_id() const { return correlation_id_; }
399  void setCorrelationId(std::string correlation_id) { correlation_id_ = std::move(correlation_id); }
400  uint64_t length() const { return length_; }
401  bool IsValid() const { return valid; }
402  std::string uri() const { return uri_; }
403  void setUri(std::string uri) { uri_ = std::move(uri); }
404  bool MatchHash(const Hash &hash) const;
405 
406  void InsertEcu(const std::pair<EcuSerial, HardwareIdentifier> &pair) { ecus_.insert(pair); }
407 
408  bool IsForEcu(const EcuSerial &ecuIdentifier) const {
409  return (std::find_if(ecus_.cbegin(), ecus_.cend(),
410  [&ecuIdentifier](const std::pair<EcuSerial, HardwareIdentifier> &pair) {
411  return pair.first == ecuIdentifier;
412  }) != ecus_.cend());
413  }
414 
415  /**
416  * Is this an OSTree target?
417  * OSTree targets need special treatment because the hash doesn't represent
418  * the contents of the update itself, instead it is the hash (name) of the
419  * root commit object.
420  */
421  bool IsOstree() const;
422  std::string type() const { return type_; }
423 
424  // Comparison is usually not meaningful. Use MatchTarget instead.
425  bool operator==(const Target &t2) = delete;
426  bool MatchTarget(const Target &t2) const;
427  Json::Value toDebugJson() const;
428  friend std::ostream &operator<<(std::ostream &os, const Target &t);
429  InstalledImageInfo getTargetImageInfo() const { return {filename(), length(), sha256Hash()}; }
430 
431  private:
432  bool valid{true};
433  std::string filename_;
434  std::string type_;
435  EcuMap ecus_; // Director only
436  std::vector<Hash> hashes_;
437  std::vector<HardwareIdentifier> hwids_; // Image repo only
438  Json::Value custom_;
439  uint64_t length_{0};
440  std::string correlation_id_;
441  std::string uri_;
442 
443  std::string hashString(Hash::Type type) const;
444 };
445 
446 std::ostream &operator<<(std::ostream &os, const Target &t);
447 
448 } // namespace Uptane
449 
450 struct SecondaryInfo {
451  SecondaryInfo() : serial(Uptane::EcuSerial::Unknown()), hw_id(Uptane::HardwareIdentifier::Unknown()) {}
452  SecondaryInfo(Uptane::EcuSerial serial_in, Uptane::HardwareIdentifier hw_id_in, std::string type_in,
453  PublicKey pub_key_in, std::string extra_in)
454  : serial(std::move(serial_in)),
455  hw_id(std::move(hw_id_in)),
456  type(std::move(type_in)),
457  pub_key(std::move(pub_key_in)),
458  extra(std::move(extra_in)) {}
459 
460  Uptane::EcuSerial serial;
461  Uptane::HardwareIdentifier hw_id;
462  std::string type;
463  PublicKey pub_key;
464 
465  std::string extra;
466 };
467 
468 #endif
TimeStamp()
An invalid TimeStamp.
Definition: types.h:191
General data structures.
Definition: types.h:215
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:157
Definition: types.h:19
The BasedPath class Can represent an absolute or relative path, only readable through the BasePath::g...
Definition: types.h:29
Base data types that are used in The Update Framework (TUF), part of Uptane.
Definition: types.h:304