@@ -1373,9 +1373,112 @@ def _verify_root_self_signed(self, signable):
13731373
13741374
13751375
1376+ def _validate_metadata_version (self , expected_version , metadata_role ,
1377+ version_downloaded ):
1378+ """
1379+ <Purpose>
1380+ Non-public method validating the metadata version number.
1381+ If the expected_version is unspecified, ensure that the version number
1382+ downloaded is equal or greater than the currently trusted version number
1383+ for 'metadata_role'.
1384+
1385+ <Arguments>
1386+ expected_version:
1387+ An integer or "None" value representing the expected and required
1388+ version number of the 'metadata_role' file downloaded.
1389+
1390+ metadata_role:
1391+ The role name of the metadata (e.g., 'root', 'targets').
1392+
1393+ version_downloaded:
1394+ The version of the newly downloaded metadata file.
1395+
1396+ <Exceptions>
1397+ tuf.exceptions.BadVersionNumberError:
1398+ In case the expected_version is not None and version_downloaded
1399+ is not equal to it.
1400+
1401+ tuf.exceptions.ReplayedMetadataError:
1402+ if expected_version is None and version_downloaded is lower than
1403+ the current version.
1404+ """
1405+
1406+ if expected_version is not None :
1407+ if version_downloaded != expected_version :
1408+ raise tuf .exceptions .BadVersionNumberError ('Downloaded'
1409+ ' version number: ' + repr (version_downloaded ) + '. Version'
1410+ ' number MUST be: ' + repr (expected_version ))
1411+
1412+ else :
1413+ try :
1414+ current_version = self .metadata ['current' ][metadata_role ]['version' ]
1415+
1416+ if version_downloaded < current_version :
1417+ raise tuf .exceptions .ReplayedMetadataError (metadata_role ,
1418+ version_downloaded , current_version )
1419+
1420+ except KeyError :
1421+ logger .info (metadata_role + ' not available locally.' )
1422+
1423+
1424+
1425+ def _validate_spec_version (self , metadata_spec_version ):
1426+ """
1427+ <Purpose>
1428+ Non-public method verifying a metadata specification version.
1429+ It is assumed that "spec_version" is in (major.minor.fix) format,
1430+ (for example: "1.4.3") and that releases with the same major version
1431+ number maintain backward compatibility.
1432+ Consequently, if the major version number of new metadata equals our
1433+ expected major version number, the new metadata is safe to parse.
1434+
1435+ <Arguments>
1436+ metadata_spec_version:
1437+ A string representing the metadata spec version. It is assumed that
1438+ it is in semantic versioning (major.minor.fix) format.
1439+
1440+ <Exceptions>
1441+ tuf.exceptions.UnsupportedSpecificationError:
1442+ In case the metadata major spec version is not supported.
1443+
1444+ securesystemslib.exceptions.FormatError:
1445+ In case the metadata_spec_version string is not in the expected format.
1446+ """
1447+
1448+ try :
1449+ metadata_spec_version_split = metadata_spec_version .split ('.' )
1450+ metadata_spec_major_version = int (metadata_spec_version_split [0 ])
1451+ metadata_spec_minor_version = int (metadata_spec_version_split [1 ])
1452+
1453+ code_spec_version_split = tuf .SPECIFICATION_VERSION .split ('.' )
1454+ code_spec_major_version = int (code_spec_version_split [0 ])
1455+ code_spec_minor_version = int (code_spec_version_split [1 ])
1456+
1457+ if metadata_spec_major_version != code_spec_major_version :
1458+ raise tuf .exceptions .UnsupportedSpecificationError (
1459+ 'Downloaded metadata that specifies an unsupported spec_version. '
1460+ 'This code supports major version number: ' +
1461+ repr (code_spec_major_version ) + '; however,'
1462+ 'metadata spec version is: ' + str (metadata_spec_version ))
1463+
1464+ # report to user if minor versions do not match, continue with update
1465+ if metadata_spec_minor_version != code_spec_minor_version :
1466+ logger .info ("Downloaded metadata that specifies a different minor " +
1467+ "spec_version." )
1468+ logger .info ("This code has version " + tuf .SPECIFICATION_VERSION +
1469+ " and the metadata lists version number " +
1470+ str (metadata_spec_version ) + "." )
1471+ logger .info ("The update will continue as the major versions match." )
1472+
1473+ except (ValueError , TypeError ) as error :
1474+ six .raise_from (securesystemslib .exceptions .FormatError ('Improperly'
1475+ ' formatted spec_version, which must be in major.minor.fix format' ),
1476+ error )
1477+
1478+
13761479
13771480 def _verify_metadata_file (self , metadata_file_object ,
1378- metadata_role ):
1481+ metadata_role , expected_version ):
13791482 """
13801483 <Purpose>
13811484 Non-public method that verifies a metadata file. An exception is
@@ -1390,15 +1493,29 @@ def _verify_metadata_file(self, metadata_file_object,
13901493 The role name of the metadata (e.g., 'root', 'targets',
13911494 'unclaimed').
13921495
1496+ expected_version:
1497+ An integer or "None" value representing the expected and required
1498+ version number of the 'metadata_role' file downloaded.
1499+
13931500 <Exceptions>
13941501 securesystemslib.exceptions.FormatError:
1395- In case the metadata file is valid JSON, but not valid TUF metadata.
1502+ In case the metadata file is valid JSON, but not valid TUF metadata
1503+ or when the metadata spec version is not in the rigth format.
13961504
13971505 tuf.exceptions.InvalidMetadataJSONError:
13981506 In case the metadata file is not valid JSON.
13991507
1508+ tuf.exceptions.UnsupportedSpecificationError:
1509+ In case the metadata spec version is not supported.
1510+
14001511 tuf.exceptions.ReplayedMetadataError:
1401- In case the downloaded metadata file is older than the current one.
1512+ In case the downloaded metadata file is older than the current one or
1513+ if expected_version is None and version_downloaded is lower than the
1514+ trusted current version.
1515+
1516+ tuf.exceptions.BadVersionNumberError:
1517+ In case the expected_version is not None and version_downloaded is not
1518+ equal to it.
14021519
14031520 tuf.exceptions.RepositoryError:
14041521 In case the repository is somehow inconsistent; e.g. a parent has not
@@ -1429,6 +1546,11 @@ def _verify_metadata_file(self, metadata_file_object,
14291546 # 'securesystemslib.exceptions.FormatError' if not.
14301547 tuf .formats .check_signable_object_format (metadata_signable )
14311548
1549+ self ._validate_spec_version (metadata_signable ['signed' ]['spec_version' ])
1550+
1551+ self ._validate_metadata_version (expected_version , metadata_role ,
1552+ metadata_signable ['signed' ]['version' ])
1553+
14321554 # Is 'metadata_signable' expired?
14331555 self ._ensure_not_expired (metadata_signable ['signed' ], metadata_role )
14341556
@@ -1482,8 +1604,8 @@ def _get_metadata_file(self, metadata_role, remote_filename,
14821604 downloaded.
14831605
14841606 expected_version:
1485- The expected and required version number of the 'metadata_role' file
1486- downloaded. 'expected_version' is an integer .
1607+ An integer representing the expected and required version number
1608+ of the 'metadata_role' file downloaded .
14871609
14881610 <Exceptions>
14891611 tuf.exceptions.NoWorkingMirrorError:
@@ -1510,85 +1632,9 @@ def _get_metadata_file(self, metadata_role, remote_filename,
15101632 try :
15111633 file_object = tuf .download .unsafe_download (file_mirror ,
15121634 upperbound_filelength )
1513- file_object .seek (0 )
1514-
1515- # Verify 'file_object' according to the callable function.
1516- # 'file_object' is also verified if decompressed above (i.e., the
1517- # uncompressed version).
1518- metadata_signable = \
1519- securesystemslib .util .load_json_string (file_object .read ().decode ('utf-8' ))
1520-
1521- # Determine if the specification version number is supported. It is
1522- # assumed that "spec_version" is in (major.minor.fix) format, (for
1523- # example: "1.4.3") and that releases with the same major version
1524- # number maintain backwards compatibility. Consequently, if the major
1525- # version number of new metadata equals our expected major version
1526- # number, the new metadata is safe to parse.
1527- try :
1528- metadata_spec_version = metadata_signable ['signed' ]['spec_version' ]
1529- metadata_spec_version_split = metadata_spec_version .split ('.' )
1530- metadata_spec_major_version = int (metadata_spec_version_split [0 ])
1531- metadata_spec_minor_version = int (metadata_spec_version_split [1 ])
1532-
1533- code_spec_version_split = tuf .SPECIFICATION_VERSION .split ('.' )
1534- code_spec_major_version = int (code_spec_version_split [0 ])
1535- code_spec_minor_version = int (code_spec_version_split [1 ])
1536-
1537- if metadata_spec_major_version != code_spec_major_version :
1538- raise tuf .exceptions .UnsupportedSpecificationError (
1539- 'Downloaded metadata that specifies an unsupported '
1540- 'spec_version. This code supports major version number: ' +
1541- repr (code_spec_major_version ) + '; however, the obtained '
1542- 'metadata lists version number: ' + str (metadata_spec_version ))
1543-
1544- #report to user if minor versions do not match, continue with update
1545- if metadata_spec_minor_version != code_spec_minor_version :
1546- logger .info ("Downloaded metadata that specifies a different minor " +
1547- "spec_version. This code has version " +
1548- str (tuf .SPECIFICATION_VERSION ) +
1549- " and the metadata lists version number " +
1550- str (metadata_spec_version ) +
1551- ". The update will continue as the major versions match." )
1552-
1553- except (ValueError , TypeError ) as error :
1554- six .raise_from (securesystemslib .exceptions .FormatError ('Improperly'
1555- ' formatted spec_version, which must be in major.minor.fix format' ),
1556- error )
1557-
1558- # If the version number is unspecified, ensure that the version number
1559- # downloaded is greater than the currently trusted version number for
1560- # 'metadata_role'.
1561- version_downloaded = metadata_signable ['signed' ]['version' ]
1562-
1563- if expected_version is not None :
1564- # Verify that the downloaded version matches the version expected by
1565- # the caller.
1566- if version_downloaded != expected_version :
1567- raise tuf .exceptions .BadVersionNumberError ('Downloaded'
1568- ' version number: ' + repr (version_downloaded ) + '. Version'
1569- ' number MUST be: ' + repr (expected_version ))
1570-
1571- # The caller does not know which version to download. Verify that the
1572- # downloaded version is at least greater than the one locally
1573- # available.
1574- else :
1575- # Verify that the version number of the locally stored
1576- # 'timestamp.json', if available, is less than what was downloaded.
1577- # Otherwise, accept the new timestamp with version number
1578- # 'version_downloaded'.
1579-
1580- try :
1581- current_version = \
1582- self .metadata ['current' ][metadata_role ]['version' ]
1583-
1584- if version_downloaded < current_version :
1585- raise tuf .exceptions .ReplayedMetadataError (metadata_role ,
1586- version_downloaded , current_version )
1587-
1588- except KeyError :
1589- logger .info (metadata_role + ' not available locally.' )
15901635
1591- self ._verify_metadata_file (file_object , metadata_role )
1636+ self ._verify_metadata_file (file_object , metadata_role ,
1637+ expected_version )
15921638
15931639 except Exception as exception :
15941640 # Remember the error from this mirror, and "reset" the target file.
0 commit comments