1 #ifndef AKTUALIZR_UPTANE_TUF_H_
2 #define AKTUALIZR_UPTANE_TUF_H_
13 #include "uptane/exceptions.h"
15 #include "crypto/crypto.h"
23 enum class Type { kUnknown = -1, kImage = 0, kDirector = 1 };
27 static constexpr
int Director() {
return static_cast<int>(Type::kDirector); }
28 static constexpr
int Image() {
return static_cast<int>(Type::kImage); }
29 RepositoryType(
int type) { type_ = static_cast<RepositoryType::Type>(type); }
31 if (repo_type ==
"director") {
32 type_ = RepositoryType::Type::kDirector;
33 }
else if (repo_type ==
"image") {
34 type_ = RepositoryType::Type::kImage;
36 throw std::runtime_error(std::string(
"Incorrect repo type: ") + repo_type);
39 operator int()
const {
return static_cast<int>(type_); }
40 operator const std::string()
const {
return toString(); }
42 std::string toString()
const {
43 if (type_ == RepositoryType::Type::kDirector) {
45 }
else if (type_ == RepositoryType::Type::kImage) {
53 using KeyId = std::string;
59 static const std::string ROOT;
60 static const std::string SNAPSHOT;
61 static const std::string TARGETS;
62 static const std::string TIMESTAMP;
67 static Role Timestamp() {
return Role{RoleEnum::kTimestamp}; }
69 static Role InvalidRole() {
return Role{RoleEnum::kInvalidRole}; }
73 static bool IsReserved(
const std::string &name) {
74 return (name == ROOT || name == TARGETS || name == SNAPSHOT || name == TIMESTAMP);
77 explicit Role(
const std::string &role_name,
bool delegation =
false);
78 std::string ToString()
const;
79 int ToInt()
const {
return static_cast<int>(role_); }
80 bool IsDelegation()
const {
return role_ == RoleEnum::kDelegation; }
81 bool operator==(
const Role &other)
const {
return name_ == other.name_; }
82 bool operator!=(
const Role &other)
const {
return !(*
this == other); }
83 bool operator<(
const Role &other)
const {
return name_ < other.name_; }
85 friend std::ostream &operator<<(std::ostream &os,
const Role &role);
90 enum class RoleEnum { kRoot = 0, kSnapshot = 1, kTargets = 2, kTimestamp = 3, kDelegation = 4, kInvalidRole = -1 };
92 explicit Role(RoleEnum role) : role_(role) {
93 if (role_ == RoleEnum::kRoot) {
95 }
else if (role_ == RoleEnum::kSnapshot) {
97 }
else if (role_ == RoleEnum::kTargets) {
99 }
else if (role_ == RoleEnum::kTimestamp) {
102 role_ = RoleEnum::kInvalidRole;
103 name_ =
"invalidrole";
111 std::ostream &operator<<(std::ostream &os,
const Role &role);
118 Version() : version_(ANY_VERSION) {}
119 explicit Version(
int v) : version_(v) {}
120 std::string RoleFileName(
const Role &role)
const;
121 int version()
const {
return version_; }
122 bool operator==(
const Version &rhs)
const {
return version_ == rhs.version_; }
123 bool operator!=(
const Version &rhs)
const {
return version_ != rhs.version_; }
124 bool operator<(
const Version &rhs)
const {
return version_ < rhs.version_; }
127 static const int ANY_VERSION = -1;
129 friend std::ostream &operator<<(std::ostream &os,
const Version &v);
135 : name(std::move(name_in)), len(len_in), hash(std::move(hash_in)) {}
141 std::ostream &operator<<(std::ostream &os,
const Version &v);
146 static const int kMinLength = 0;
147 static const int kMaxLength = 200;
154 if (kMaxLength < hwid.length()) {
155 throw std::out_of_range(
"Hardware Identifier too long");
159 std::string ToString()
const {
return hwid_; }
172 std::ostream &operator<<(std::ostream &os, const HardwareIdentifier &hwid);
177 static const int kMinLength = 1;
178 static const int kMaxLength = 64;
180 static EcuSerial Unknown() { return EcuSerial("Unknown"); }
181 explicit EcuSerial(const std::string &ecu_serial) : ecu_serial_(ecu_serial) {
182 if (ecu_serial.length() < kMinLength) {
183 throw std::out_of_range("Ecu serial identifier is too short");
185 if (kMaxLength < ecu_serial.length()) {
186 throw std::out_of_range("Ecu serial identifier is too long");
190 std::string ToString() const { return ecu_serial_; }
192 bool operator==(const EcuSerial &rhs) const { return ecu_serial_ == rhs.ecu_serial_; }
193 bool operator!=(const EcuSerial &rhs) const { return !(*this == rhs); }
195 bool operator<(const EcuSerial &rhs) const { return ecu_serial_ < rhs.ecu_serial_; }
196 friend std::ostream &operator<<(std::ostream &os, const EcuSerial &ecu_serial);
197 friend struct std::hash<Uptane::EcuSerial>;
200 std::string ecu_serial_;
203 std::ostream &operator<<(std::ostream &os, const EcuSerial &ecu_serial);
212 enum class Type { kSha256, kSha512, kUnknownAlgorithm };
214 static Hash generate(Type type, const std::string &data);
215 Hash(const std::string &type, const std::string &hash);
216 Hash(Type type, const std::string &hash);
218 bool HaveAlgorithm() const { return type_ != Type::kUnknownAlgorithm; }
219 bool operator==(const Hash &other) const;
220 bool operator!=(const Hash &other) const { return !operator==(other); }
221 std::string TypeString() const;
223 std::string HashString() const { return hash_; }
224 friend std::ostream &operator<<(std::ostream &os, const Hash &h);
226 static std::string encodeVector(const std::vector<Uptane::Hash> &hashes);
227 static std::vector<Uptane::Hash> decodeVector(std::string hashes_str);
234 std::ostream &operator<<(std::ostream &os, const Hash &h);
236 using EcuMap = std::map<EcuSerial, HardwareIdentifier>;
241 Target(std::string filename, const Json::Value &content);
244 Target(std::string filename, EcuMap ecus, std::vector<Hash> hashes, uint64_t length, std::string correlation_id = "");
246 static Target Unknown();
248 const EcuMap &ecus() const { return ecus_; }
249 std::string filename() const { return filename_; }
250 std::string sha256Hash() const;
251 std::string sha512Hash() const;
252 const std::vector<Hash> &hashes() const { return hashes_; };
253 const std::vector<HardwareIdentifier> &hardwareIds() const { return hwids_; };
254 std::string custom_version() const { return custom_["version"].asString(); }
255 Json::Value custom_data() const { return custom_; }
256 void updateCustom(Json::Value &custom) { custom_ = custom; };
257 std::string correlation_id() const { return correlation_id_; };
258 void setCorrelationId(std::string correlation_id) { correlation_id_ = std::move(correlation_id); };
259 uint64_t length() const { return length_; }
260 bool IsValid() const { return valid; }
261 std::string uri() const { return uri_; };
262 void setUri(std::string uri) { uri_ = std::move(uri); };
263 bool MatchHash(const Hash &hash) const;
265 bool IsForEcu(const EcuSerial &ecuIdentifier) const {
266 return (std::find_if(ecus_.cbegin(), ecus_.cend(), [&ecuIdentifier](std::pair<EcuSerial, HardwareIdentifier> pair) {
267 return pair.first == ecuIdentifier;
277 bool IsOstree() const;
278 std::string type() const { return type_; }
281 bool operator==(const Target &t2) = delete;
282 bool MatchTarget(const Target &t2) const;
283 Json::Value toDebugJson() const;
284 friend std::ostream &operator<<(std::ostream &os, const Target &t);
285 InstalledImageInfo getTargetImageInfo() const { return {filename(), length(), sha256Hash()}; }
289 std::string filename_;
292 std::vector<Hash> hashes_;
293 std::vector<HardwareIdentifier> hwids_;
296 std::string correlation_id_;
299 std::string hashString(Hash::Type type) const;
302 std::ostream &operator<<(std::ostream &os, const Target &t);
308 BaseMeta() = default;
309 explicit BaseMeta(const Json::Value &json);
310 BaseMeta(RepositoryType repo, const Role &role, const Json::Value &json, const std::shared_ptr<MetaWithKeys> &signer);
311 int version() const { return version_; }
312 TimeStamp expiry() const { return expiry_; }
313 bool isExpired(const TimeStamp &now) const { return expiry_.IsExpiredAt(now); }
314 Json::Value original() const { return original_object_; }
316 bool operator==(const BaseMeta &rhs) const { return version_ == rhs.version() && expiry_ == rhs.expiry(); }
321 Json::Value original_object_;
324 void init(const Json::Value &json);
327 class MetaWithKeys : public BaseMeta {
329 enum class Policy { kRejectAll, kAcceptAll, kCheck };
333 MetaWithKeys() { version_ = 0; }
339 MetaWithKeys(const Json::Value &json);
340 MetaWithKeys(RepositoryType repo, const Role &role, const Json::Value &json,
341 const std::shared_ptr<MetaWithKeys> &signer);
343 virtual ~MetaWithKeys() = default;
345 void ParseKeys(RepositoryType repo, const Json::Value &keys);
348 void ParseRole(RepositoryType repo, const Json::ValueConstIterator &it, const Role &role,
349 const std::string &meta_role);
365 virtual void UnpackSignedObject(RepositoryType repo, const Role &role, const Json::Value &signed_object);
367 bool operator==(const MetaWithKeys &rhs) const {
368 return version_ == rhs.version_ && expiry_ == rhs.expiry_ && keys_ == rhs.keys_ &&
369 keys_for_role_ == rhs.keys_for_role_ && thresholds_for_role_ == rhs.thresholds_for_role_;
373 static const int64_t kMinSignatures = 1;
374 static const int64_t kMaxSignatures = 1000;
376 std::map<KeyId, PublicKey> keys_;
377 std::set<std::pair<Role, KeyId>> keys_for_role_;
378 std::map<Role, int64_t> thresholds_for_role_;
382 class Root : public MetaWithKeys {
387 explicit Root(Policy policy = Policy::kRejectAll) : policy_(policy) { version_ = 0; }
393 Root(RepositoryType repo, const Json::Value &json);
394 Root(RepositoryType repo, const Json::Value &json, Root &root);
396 ~Root() override = default;
412 void UnpackSignedObject(RepositoryType repo, const Role &role, const Json::Value &signed_object) override;
414 bool operator==(const Root &rhs) const {
415 return version_ == rhs.version_ && expiry_ == rhs.expiry_ && keys_ == rhs.keys_ &&
416 keys_for_role_ == rhs.keys_for_role_ && thresholds_for_role_ == rhs.thresholds_for_role_ &&
417 policy_ == rhs.policy_;
424 static bool MatchTargetVector(const std::vector<Uptane::Target> &v1, const std::vector<Uptane::Target> &v2) {
425 if (v1.size() != v2.size()) {
428 for (size_t i = 0; i < v1.size(); ++i) {
429 if (!v1[i].MatchTarget(v2[i])) {
437 class Targets : public MetaWithKeys {
439 explicit Targets(const Json::Value &json);
440 Targets(RepositoryType repo, const Role &role, const Json::Value &json, const std::shared_ptr<MetaWithKeys> &signer);
442 ~Targets() override = default;
444 bool operator==(const Targets &rhs) const {
445 return version_ == rhs.version() && expiry_ == rhs.expiry() && MatchTargetVector(targets, rhs.targets);
448 const std::string &correlation_id() const { return correlation_id_; }
452 delegated_role_names_.clear();
453 paths_for_role_.clear();
454 terminating_role_.clear();
457 std::vector<Uptane::Target> getTargets(const Uptane::EcuSerial &ecu_id,
458 const Uptane::HardwareIdentifier &hw_id) const {
459 std::vector<Uptane::Target> result;
460 for (auto it = targets.begin(); it != targets.end(); ++it) {
461 auto found_loc = std::find_if(it->ecus().begin(), it->ecus().end(),
462 [ecu_id, hw_id](const std::pair<EcuSerial, HardwareIdentifier> &val) {
463 return ((ecu_id == val.first) && (hw_id == val.second));
466 if (found_loc != it->ecus().end()) {
467 result.push_back(*it);
473 std::vector<Uptane::Target> targets;
474 std::vector<std::string> delegated_role_names_;
475 std::map<Role, std::vector<std::string>> paths_for_role_;
476 std::map<Role, bool> terminating_role_;
479 void init(const Json::Value &json);
482 std::string correlation_id_;
485 class TimestampMeta : public BaseMeta {
487 explicit TimestampMeta(const Json::Value &json);
488 TimestampMeta(RepositoryType repo, const Json::Value &json, const std::shared_ptr<MetaWithKeys> &signer);
489 TimestampMeta() = default;
490 std::vector<Hash> snapshot_hashes() const { return snapshot_hashes_; };
491 int64_t snapshot_size() const { return snapshot_size_; };
492 int snapshot_version() const { return snapshot_version_; };
495 void init(const Json::Value &json);
497 std::vector<Hash> snapshot_hashes_;
498 int64_t snapshot_size_{0};
499 int snapshot_version_{-1};
502 class Snapshot : public BaseMeta {
504 explicit Snapshot(const Json::Value &json);
505 Snapshot(RepositoryType repo, const Json::Value &json, const std::shared_ptr<MetaWithKeys> &signer);
506 Snapshot() = default;
507 std::vector<Hash> role_hashes(const Uptane::Role &role) const;
508 int64_t role_size(const Uptane::Role &role) const;
509 int role_version(const Uptane::Role &role) const;
510 bool operator==(const Snapshot &rhs) const {
511 return version_ == rhs.version() && expiry_ == rhs.expiry() && role_size_ == rhs.role_size_ &&
512 role_version_ == rhs.role_version_ && role_hashes_ == rhs.role_hashes_;
516 void init(const Json::Value &json);
517 std::map<Uptane::Role, int64_t> role_size_;
518 std::map<Uptane::Role, int> role_version_;
519 std::map<Uptane::Role, std::vector<Hash>> role_hashes_;
524 Targets director_targets;
526 Targets image_targets;
527 TimestampMeta image_timestamp;
528 Snapshot image_snapshot;
529 bool isConsistent() const;
533 std::string director_root;
534 std::string director_targets;
535 std::string image_root;
536 std::string image_targets;
537 std::string image_timestamp;
538 std::string image_snapshot;
541 int extractVersionUntrusted(const std::string &meta);
547 struct hash<Uptane::HardwareIdentifier> {
548 size_t operator()(const Uptane::HardwareIdentifier &hwid) const { return std::hash<std::string>()(hwid.hwid_); }
552 struct hash<Uptane::EcuSerial> {
553 size_t operator()(const Uptane::EcuSerial &ecu_serial) const {
554 return std::hash<std::string>()(ecu_serial.ecu_serial_);