Skip to content

Commit

Permalink
Merge pull request #885 from trishankatdatadog:trishankatdatadog/corr…
Browse files Browse the repository at this point in the history
…ectly-rotate-root

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
  • Loading branch information
lukpueh committed Oct 7, 2019
2 parents be601bb + fce6fa5 commit 3d342e6
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 18 deletions.
67 changes: 49 additions & 18 deletions tuf/client/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
import securesystemslib.util
import six
import iso8601
import requests.exceptions

# The Timestamp role does not have signed metadata about it; otherwise we
# would need an infinite regress of metadata. Therefore, we use some
Expand Down Expand Up @@ -1125,28 +1126,58 @@ def _update_root_metadata(self, current_root_metadata):
None.
"""

# Retrieve the latest, remote root.json.
latest_root_metadata_file = self._get_metadata_file(
'root', 'root.json', DEFAULT_ROOT_UPPERLENGTH, None)
def neither_403_nor_404(mirror_error):
if isinstance(mirror_error, requests.exceptions.HTTPError):
if mirror_error.response.status_code in {403, 404}:
return False
return True

latest_root_metadata = securesystemslib.util.load_json_string(
latest_root_metadata_file.read().decode('utf-8'))
# Temporarily set consistent snapshot. Will be updated to whatever is set
# in the latest root.json after running through the intermediates with
# _update_metadata().
self.consistent_snapshot = True

# Following the spec, try downloading the N+1th root for a certain maximum
# number of times.
lower_bound = current_root_metadata['version'] + 1
upper_bound = lower_bound + tuf.settings.MAX_NUMBER_ROOT_ROTATIONS

# Try downloading the next root.
for next_version in range(lower_bound, upper_bound):
try:
# Thoroughly verify it.
self._update_metadata('root', DEFAULT_ROOT_UPPERLENGTH,
version=next_version)
# When we run into HTTP 403/404 error from ALL mirrors, break out of
# loop, because the next root metadata file is most likely missing.
except tuf.exceptions.NoWorkingMirrorError as exception:
for mirror_error in exception.mirror_errors.values():
# Otherwise, reraise the error, because it is not a simple HTTP
# error.
if neither_403_nor_404(mirror_error):
logging.exception('Misc error for root version '+str(next_version))
raise
else:
# Calling this function should give us a detailed stack trace
# including an HTTP error code, if any.
logging.exception('HTTP error for root version '+str(next_version))
# If we are here, then we ran into only 403 / 404 errors, which are
# good reasons to suspect that the next root metadata file does not
# exist.
break

next_version = current_root_metadata['version'] + 1
latest_version = latest_root_metadata['signed']['version']
# Ensure that the role and key information of the top-level roles is the
# latest. We do this whether or not Root needed to be updated, in order
# to ensure that, e.g., the entries in roledb for top-level roles are
# populated with expected keyid info so that roles can be validated. In
# certain circumstances, top-level metadata might be missing because it
# was marked obsolete and deleted after a failed attempt, and thus we
# should refresh them here as a protective measure. See Issue #736.
self._rebuild_key_and_role_db()

# update from the next version of root up to (and including) the latest
# version. For example:
# current = version 1
# latest = version 3
# update from 1.root.json to 3.root.json.
for version in range(next_version, latest_version + 1):
# Temporarily set consistent snapshot. Will be updated to whatever is set
# in the latest root.json after running through the intermediates with
# _update_metadata().
self.consistent_snapshot = True
self._update_metadata('root', DEFAULT_ROOT_UPPERLENGTH, version=version)
# Set our consistent snapshot property to what the latest root has said.
self.consistent_snapshot = \
self.metadata['current']['root']['consistent_snapshot']



Expand Down
4 changes: 4 additions & 0 deletions tuf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@
# to suspend execution for a specified amount of time. See
# theupdateframework/tuf/issue#338.
SLEEP_BEFORE_ROUND = None

# Maximum number of root metadata file rotations we should perform in order to
# prevent a denial-of-service (DoS) attack.
MAX_NUMBER_ROOT_ROTATIONS = 2**5

0 comments on commit 3d342e6

Please sign in to comment.