@@ -1499,7 +1499,8 @@ def _verify_metadata_file(self, metadata_file_object,
14991499
15001500
15011501 def _get_metadata_file (self , metadata_role , remote_filename ,
1502- upperbound_filelength , expected_version , snapshot_merkle = False ):
1502+ upperbound_filelength , expected_version ,
1503+ verification_fn ):
15031504 """
15041505 <Purpose>
15051506 Non-public method that tries downloading, up to a certain length, a
@@ -1554,88 +1555,9 @@ def _get_metadata_file(self, metadata_role, remote_filename,
15541555 upperbound_filelength )
15551556 file_object .seek (0 )
15561557
1557- # Verify 'file_object' according to the callable function.
1558- # 'file_object' is also verified if decompressed above (i.e., the
1559- # uncompressed version).
1560- metadata_signable = \
1561- securesystemslib .util .load_json_string (file_object .read ().decode ('utf-8' ))
1562-
1563-
1564- # If this is a merkle tree snapshot, it will not be signed.
1565- if snapshot_merkle :
1566- return file_object
1567-
1568- # Determine if the specification version number is supported. It is
1569- # assumed that "spec_version" is in (major.minor.fix) format, (for
1570- # example: "1.4.3") and that releases with the same major version
1571- # number maintain backwards compatibility. Consequently, if the major
1572- # version number of new metadata equals our expected major version
1573- # number, the new metadata is safe to parse.
1574- try :
1575- metadata_spec_version = metadata_signable ['signed' ]['spec_version' ]
1576- metadata_spec_version_split = metadata_spec_version .split ('.' )
1577- metadata_spec_major_version = int (metadata_spec_version_split [0 ])
1578- metadata_spec_minor_version = int (metadata_spec_version_split [1 ])
1579-
1580- code_spec_version_split = tuf .SPECIFICATION_VERSION .split ('.' )
1581- code_spec_major_version = int (code_spec_version_split [0 ])
1582- code_spec_minor_version = int (code_spec_version_split [1 ])
1583-
1584- if metadata_spec_major_version != code_spec_major_version :
1585- raise tuf .exceptions .UnsupportedSpecificationError (
1586- 'Downloaded metadata that specifies an unsupported '
1587- 'spec_version. This code supports major version number: ' +
1588- repr (code_spec_major_version ) + '; however, the obtained '
1589- 'metadata lists version number: ' + str (metadata_spec_version ))
1590-
1591- #report to user if minor versions do not match, continue with update
1592- if metadata_spec_minor_version != code_spec_minor_version :
1593- logger .info ("Downloaded metadata that specifies a different minor " +
1594- "spec_version. This code has version " +
1595- str (tuf .SPECIFICATION_VERSION ) +
1596- " and the metadata lists version number " +
1597- str (metadata_spec_version ) +
1598- ". The update will continue as the major versions match." )
1599-
1600- except (ValueError , TypeError ) as error :
1601- six .raise_from (securesystemslib .exceptions .FormatError ('Improperly'
1602- ' formatted spec_version, which must be in major.minor.fix format' ),
1603- error )
1604-
1605- # If the version number is unspecified, ensure that the version number
1606- # downloaded is greater than the currently trusted version number for
1607- # 'metadata_role'.
1608- version_downloaded = metadata_signable ['signed' ]['version' ]
1609-
1610- if expected_version is not None :
1611- # Verify that the downloaded version matches the version expected by
1612- # the caller.
1613- if version_downloaded != expected_version :
1614- raise tuf .exceptions .BadVersionNumberError ('Downloaded'
1615- ' version number: ' + repr (version_downloaded ) + '. Version'
1616- ' number MUST be: ' + repr (expected_version ))
1617-
1618- # The caller does not know which version to download. Verify that the
1619- # downloaded version is at least greater than the one locally
1620- # available.
1621- else :
1622- # Verify that the version number of the locally stored
1623- # 'timestamp.json', if available, is less than what was downloaded.
1624- # Otherwise, accept the new timestamp with version number
1625- # 'version_downloaded'.
1626-
1627- try :
1628- current_version = \
1629- self .metadata ['current' ][metadata_role ]['version' ]
1630-
1631- if version_downloaded < current_version :
1632- raise tuf .exceptions .ReplayedMetadataError (metadata_role ,
1633- version_downloaded , current_version )
1634-
1635- except KeyError :
1636- logger .info (metadata_role + ' not available locally.' )
1637-
1638- self ._verify_metadata_file (file_object , metadata_role )
1558+ # Verify the file object using the provided function, if any
1559+ if verification_fn is not None :
1560+ verification_fn (metadata_role , file_object , expected_version )
16391561
16401562 except Exception as exception :
16411563 # Remember the error from this mirror, and "reset" the target file.
@@ -1657,6 +1579,89 @@ def _get_metadata_file(self, metadata_role, remote_filename,
16571579
16581580
16591581
1582+ def signable_verification (self , metadata_role , file_object , expected_version ):
1583+ # Verify 'file_object' according to the callable function.
1584+ # 'file_object' is also verified if decompressed above (i.e., the
1585+ # uncompressed version).
1586+ metadata_signable = \
1587+ securesystemslib .util .load_json_string (file_object .read ().decode ('utf-8' ))
1588+
1589+ # Determine if the specification version number is supported. It is
1590+ # assumed that "spec_version" is in (major.minor.fix) format, (for
1591+ # example: "1.4.3") and that releases with the same major version
1592+ # number maintain backwards compatibility. Consequently, if the major
1593+ # version number of new metadata equals our expected major version
1594+ # number, the new metadata is safe to parse.
1595+ try :
1596+ metadata_spec_version = metadata_signable ['signed' ]['spec_version' ]
1597+ metadata_spec_version_split = metadata_spec_version .split ('.' )
1598+ metadata_spec_major_version = int (metadata_spec_version_split [0 ])
1599+ metadata_spec_minor_version = int (metadata_spec_version_split [1 ])
1600+
1601+ code_spec_version_split = tuf .SPECIFICATION_VERSION .split ('.' )
1602+ code_spec_major_version = int (code_spec_version_split [0 ])
1603+ code_spec_minor_version = int (code_spec_version_split [1 ])
1604+
1605+ if metadata_spec_major_version != code_spec_major_version :
1606+ raise tuf .exceptions .UnsupportedSpecificationError (
1607+ 'Downloaded metadata that specifies an unsupported '
1608+ 'spec_version. This code supports major version number: ' +
1609+ repr (code_spec_major_version ) + '; however, the obtained '
1610+ 'metadata lists version number: ' + str (metadata_spec_version ))
1611+
1612+ #report to user if minor versions do not match, continue with update
1613+ if metadata_spec_minor_version != code_spec_minor_version :
1614+ logger .info ("Downloaded metadata that specifies a different minor " +
1615+ "spec_version. This code has version " +
1616+ str (tuf .SPECIFICATION_VERSION ) +
1617+ " and the metadata lists version number " +
1618+ str (metadata_spec_version ) +
1619+ ". The update will continue as the major versions match." )
1620+
1621+ except (ValueError , TypeError ) as error :
1622+ six .raise_from (securesystemslib .exceptions .FormatError ('Improperly'
1623+ ' formatted spec_version, which must be in major.minor.fix format' ),
1624+ error )
1625+
1626+ # If the version number is unspecified, ensure that the version number
1627+ # downloaded is greater than the currently trusted version number for
1628+ # 'metadata_role'.
1629+ version_downloaded = metadata_signable ['signed' ]['version' ]
1630+
1631+ if expected_version is not None :
1632+ # Verify that the downloaded version matches the version expected by
1633+ # the caller.
1634+ if version_downloaded != expected_version :
1635+ raise tuf .exceptions .BadVersionNumberError ('Downloaded'
1636+ ' version number: ' + repr (version_downloaded ) + '. Version'
1637+ ' number MUST be: ' + repr (expected_version ))
1638+
1639+ # The caller does not know which version to download. Verify that the
1640+ # downloaded version is at least greater than the one locally
1641+ # available.
1642+ else :
1643+ # Verify that the version number of the locally stored
1644+ # 'timestamp.json', if available, is less than what was downloaded.
1645+ # Otherwise, accept the new timestamp with version number
1646+ # 'version_downloaded'.
1647+
1648+ try :
1649+ current_version = \
1650+ self .metadata ['current' ][metadata_role ]['version' ]
1651+
1652+ if version_downloaded < current_version :
1653+ raise tuf .exceptions .ReplayedMetadataError (metadata_role ,
1654+ version_downloaded , current_version )
1655+
1656+ except KeyError :
1657+ logger .info (metadata_role + ' not available locally.' )
1658+
1659+ self ._verify_metadata_file (file_object , metadata_role )
1660+
1661+
1662+
1663+
1664+
16601665
16611666 def _get_file (self , filepath , verify_file_function , file_type , file_length ,
16621667 download_safely = True ):
@@ -1822,9 +1827,13 @@ def _update_metadata(self, metadata_role, upperbound_filelength, version=None,
18221827 remote_filename = os .path .join (
18231828 dirname , str (filename_version ) + '.' + basename )
18241829
1830+ verification_fn = None
1831+ if not snapshot_merkle :
1832+ verification_fn = self .signable_verification
1833+
18251834 metadata_file_object = \
18261835 self ._get_metadata_file (metadata_role , remote_filename ,
1827- upperbound_filelength , version , snapshot_merkle )
1836+ upperbound_filelength , version , verification_fn )
18281837
18291838 # The metadata has been verified. Move the metadata file into place.
18301839 # First, move the 'current' metadata file to the 'previous' directory
@@ -1855,7 +1864,7 @@ def _update_metadata(self, metadata_role, upperbound_filelength, version=None,
18551864 # stored for 'metadata_role'.
18561865 if snapshot_merkle :
18571866 # Snaphot merkle files are not signed
1858- updated_metadata_object = metadata_signable
1867+ updated_metadata_object = metadata_signable
18591868 else :
18601869 updated_metadata_object = metadata_signable ['signed' ]
18611870 current_metadata_object = self .metadata ['current' ].get (metadata_role )
0 commit comments