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