Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
iterator.cc
1 #include "iterator.h"
2 
3 namespace Uptane {
4 
5 Targets getTrustedDelegation(const Role &delegate_role, const Targets &parent_targets,
6  const ImageRepository &image_repo, INvStorage &storage, Fetcher &fetcher,
7  const bool offline) {
8  std::string delegation_meta;
9  auto version_in_snapshot = image_repo.getRoleVersion(delegate_role);
10 
11  if (storage.loadDelegation(&delegation_meta, delegate_role)) {
12  auto version = extractVersionUntrusted(delegation_meta);
13 
14  if (version > version_in_snapshot) {
15  throw SecurityException("image", "Rollback attempt on delegated targets");
16  } else if (version < version_in_snapshot) {
17  delegation_meta.clear();
18  storage.deleteDelegation(delegate_role);
19  }
20  }
21 
22  bool delegation_remote = delegation_meta.empty();
23  if (delegation_remote) {
24  // Don't fetch anything remote if we are supposed to already have it.
25  if (offline) {
26  throw Uptane::DelegationMissing(delegate_role.ToString());
27  }
28  if (!fetcher.fetchLatestRole(&delegation_meta, Uptane::kMaxImageTargetsSize, RepositoryType::Image(),
29  delegate_role)) {
30  throw Uptane::DelegationMissing(delegate_role.ToString());
31  }
32  }
33 
34  if (!image_repo.verifyRoleHashes(delegation_meta, delegate_role, false)) {
35  throw Uptane::DelegationHashMismatch(delegate_role.ToString());
36  }
37 
38  auto delegation = ImageRepository::verifyDelegation(delegation_meta, delegate_role, parent_targets);
39  if (delegation == nullptr) {
40  throw SecurityException("image", "Delegation verification failed");
41  }
42 
43  if (delegation_remote) {
44  if (delegation->version() != version_in_snapshot) {
45  throw VersionMismatch("image", delegate_role.ToString());
46  }
47  storage.storeDelegation(delegation_meta, delegate_role);
48  }
49 
50  return *delegation;
51 }
52 
53 LazyTargetsList::DelegationIterator::DelegationIterator(const ImageRepository &repo,
54  std::shared_ptr<INvStorage> storage,
55  std::shared_ptr<Fetcher> fetcher, bool is_end)
56  : repo_{repo}, storage_{std::move(storage)}, fetcher_{std::move(fetcher)}, is_end_{is_end} {
57  tree_ = std::make_shared<DelegatedTargetTreeNode>();
58  tree_node_ = tree_.get();
59 
60  tree_node_->role = Role::Targets();
61  cur_targets_ = repo_.getTargets();
62 }
63 
64 void LazyTargetsList::DelegationIterator::renewTargetsData() {
65  auto role = tree_node_->role;
66 
67  if (role == Role::Targets()) {
68  cur_targets_ = repo_.getTargets();
69  } else {
70  // go to the top of the delegation tree
71  std::stack<std::vector<std::shared_ptr<DelegatedTargetTreeNode>>::size_type> indices;
72  auto *node = tree_node_->parent;
73  while (node->parent != nullptr) {
74  indices.push(node->parent_idx);
75  node = node->parent;
76  }
77 
78  auto parent_targets = repo_.getTargets();
79  while (!indices.empty()) {
80  auto idx = indices.top();
81  indices.pop();
82 
83  auto fetched_role = Role(parent_targets->delegated_role_names_[idx], true);
84  parent_targets = std::make_shared<const Targets>(
85  getTrustedDelegation(fetched_role, *parent_targets, repo_, *storage_, *fetcher_, false));
86  }
87  cur_targets_ =
88  std::make_shared<Targets>(getTrustedDelegation(role, *parent_targets, repo_, *storage_, *fetcher_, false));
89  }
90 }
91 
92 bool LazyTargetsList::DelegationIterator::operator==(const LazyTargetsList::DelegationIterator &other) const {
93  if (is_end_ && other.is_end_) {
94  return true;
95  }
96 
97  return is_end_ == other.is_end_ && tree_node_->role == other.tree_node_->role && target_idx_ == other.target_idx_;
98 }
99 
100 const Target &LazyTargetsList::DelegationIterator::operator*() {
101  if (is_end_) {
102  throw std::runtime_error("Inconsistent delegation iterator"); // TODO(OTA-2178): UptaneException
103  }
104 
105  if (!cur_targets_) {
106  renewTargetsData();
107  }
108 
109  if (!cur_targets_ || target_idx_ >= cur_targets_->targets.size()) {
110  throw std::runtime_error("Inconsistent delegation iterator"); // TODO(OTA-2178): UptaneException
111  }
112 
113  return cur_targets_->targets[target_idx_];
114 }
115 
116 LazyTargetsList::DelegationIterator LazyTargetsList::DelegationIterator::operator++() {
117  if (is_end_) {
118  return *this;
119  }
120 
121  if (!cur_targets_) {
122  renewTargetsData();
123  }
124 
125  // first iterate over current role's targets
126  if (target_idx_ + 1 < cur_targets_->targets.size()) {
127  ++target_idx_;
128  return *this;
129  }
130 
131  // then go to children delegations
132  if (terminating_ || level_ >= kDelegationsMaxDepth) {
133  // but only if this delegation is not terminating
134  is_end_ = true;
135  return *this;
136  }
137 
138  // populate the next level of the delegation tree if it's not populated yet
139  if (cur_targets_->delegated_role_names_.size() != tree_node_->children.size()) {
140  tree_node_->children.clear();
141 
142  for (std::vector<std::shared_ptr<DelegatedTargetTreeNode>>::size_type i = 0;
143  i < cur_targets_->delegated_role_names_.size(); ++i) {
144  auto new_node = std::make_shared<DelegatedTargetTreeNode>();
145 
146  new_node->role = Role(cur_targets_->delegated_role_names_[i], true);
147  new_node->parent = tree_node_;
148  new_node->parent_idx = i;
149 
150  tree_node_->children.push_back(new_node);
151  }
152  }
153 
154  if (children_idx_ < tree_node_->children.size()) {
155  auto *new_tree_node = tree_node_->children[children_idx_].get();
156  target_idx_ = 0;
157  children_idx_ = 0;
158  ++level_;
159 
160  auto terminating_it = cur_targets_->terminating_role_.find(new_tree_node->role);
161  if (terminating_it == cur_targets_->terminating_role_.end()) {
162  throw std::runtime_error("Inconsistent delegation tree");
163  }
164  terminating_ = terminating_it->second;
165 
166  cur_targets_.reset();
167  tree_node_ = new_tree_node;
168  return *this;
169  }
170 
171  // then go to the parent delegation
172  if (tree_node_->parent != nullptr) {
173  auto *new_tree_node = tree_node_->parent;
174  children_idx_ = tree_node_->parent_idx + 1;
175  --level_;
176  terminating_ = false;
177 
178  cur_targets_.reset();
179  tree_node_ = new_tree_node;
180  renewTargetsData();
181  target_idx_ = cur_targets_->targets.size(); // mark targets as exhausted
182  return ++(*this); // reiterate to find the next target
183  }
184 
185  // then give up
186  is_end_ = true;
187  return *this;
188 }
189 
190 } // namespace Uptane
Uptane::DelegationMissing
Definition: exceptions.h:123
Uptane::DelegationHashMismatch
Definition: exceptions.h:115
Uptane
Base data types that are used in The Update Framework (TUF), part of Uptane.
Definition: secondary_tcp_server.h:8
INvStorage
Definition: invstorage.h:126