@@ -1081,9 +1081,9 @@ def refresh(self, unsafely_update_root_if_necessary=True):
10811081 # require strict checks on its required length.
10821082 self ._update_metadata ('timestamp' , DEFAULT_TIMESTAMP_UPPERLENGTH )
10831083
1084- if 'merkle_root ' not in self .metadata ['current' ]['timestamp' ]:
1085- # If merkle root is set , do not update snapshot metadata. Instead,
1086- # we will download the relevant merkle path later when downloading
1084+ if 'rsa_acc ' not in self .metadata ['current' ]['timestamp' ]:
1085+ # If an RSA Accumulator is defined , do not update snapshot metadata. Instead,
1086+ # we will download the relevant proof files later when downloading
10871087 # a target.
10881088 self ._update_metadata_if_changed ('snapshot' ,
10891089 referenced_metadata = 'timestamp' )
@@ -1489,11 +1489,6 @@ def _get_metadata_file(self, metadata_role, remote_filename,
14891489 The expected and required version number of the 'metadata_role' file
14901490 downloaded. 'expected_version' is an integer.
14911491
1492- snapshot_merkle:
1493- Is the metadata file a snapshot merkle file? Snapshot merkle files
1494- are not signed and so should skip some of the verification steps here.
1495- Instead, they must be verified using verify_merkle_path.
1496-
14971492 <Exceptions>
14981493 tuf.exceptions.NoWorkingMirrorError:
14991494 The metadata could not be fetched. This is raised only when all known
@@ -1631,29 +1626,29 @@ def signable_verification(self, metadata_role, file_object, expected_version):
16311626
16321627
16331628
1634- def _update_merkle_metadata (self , merkle_filename , upperbound_filelength ,
1629+ def _update_rsa_acc_metadata (self , proof_filename , upperbound_filelength ,
16351630 version = None ):
16361631 """
16371632 <Purpose>
1638- Non-public method that downloads, verifies, and 'installs' the merkle
1639- metadata belonging to 'merkle_filename '. Calling this method implies
1640- that the 'merkle_filename ' on the repository is newer than the client's,
1633+ Non-public method that downloads, verifies, and 'installs' the proof
1634+ metadata belonging to 'proof_filename '. Calling this method implies
1635+ that the 'proof_filename ' on the repository is newer than the client's,
16411636 and thus needs to be re-downloaded. The current and previous metadata
16421637 stores are updated if the newly downloaded metadata is successfully
16431638 downloaded and verified. This method also assumes that the store of
16441639 top-level metadata is the latest and exists.
16451640
16461641 <Arguments>
1647- merkle_filename :
1648- The name of the metadata. This is a merkle tree file and should
1649- not end in '.json'. Examples: 'role1-merkle ', 'targets-merkle '
1642+ proof_filename :
1643+ The name of the metadata. This is an RSA accumulator proof file and should
1644+ not end in '.json'. Examples: 'role1-snapshot ', 'targets-snapshot '
16501645
16511646 upperbound_filelength:
16521647 The expected length, or upper bound, of the metadata file to be
16531648 downloaded.
16541649
16551650 version:
1656- The expected and required version number of the 'merkle_filename ' file
1651+ The expected and required version number of the 'proof_filename ' file
16571652 downloaded. 'version' is an integer.
16581653
16591654 <Exceptions>
@@ -1663,7 +1658,7 @@ def _update_merkle_metadata(self, merkle_filename, upperbound_filelength,
16631658 metadata have been tried and failed.
16641659
16651660 <Side Effects>
1666- The metadata file belonging to 'merkle_filenaem ' is downloaded from a
1661+ The metadata file belonging to 'proof_filename ' is downloaded from a
16671662 repository mirror. If the metadata is valid, it is stored in the
16681663 metadata store.
16691664
@@ -1673,7 +1668,7 @@ def _update_merkle_metadata(self, merkle_filename, upperbound_filelength,
16731668
16741669 # Construct the metadata filename as expected by the download/mirror
16751670 # modules.
1676- metadata_filename = merkle_filename + '.json'
1671+ metadata_filename = proof_filename + '.json'
16771672
16781673 # Attempt a file download from each mirror until the file is downloaded and
16791674 # verified. If the signature of the downloaded file is valid, proceed,
@@ -1703,7 +1698,7 @@ def _update_merkle_metadata(self, merkle_filename, upperbound_filelength,
17031698 verification_fn = None
17041699
17051700 metadata_file_object = \
1706- self ._get_metadata_file (merkle_filename , remote_filename ,
1701+ self ._get_metadata_file (proof_filename , remote_filename ,
17071702 upperbound_filelength , version , verification_fn )
17081703
17091704 # The metadata has been verified. Move the metadata file into place.
@@ -1732,16 +1727,16 @@ def _update_merkle_metadata(self, merkle_filename, upperbound_filelength,
17321727
17331728 # Extract the metadata object so we can store it to the metadata store.
17341729 # 'current_metadata_object' set to 'None' if there is not an object
1735- # stored for 'merkle_filename '.
1736- current_metadata_object = self .metadata ['current' ].get (merkle_filename )
1730+ # stored for 'proof_filename '.
1731+ current_metadata_object = self .metadata ['current' ].get (proof_filename )
17371732
17381733 # Finally, update the metadata and fileinfo stores, and rebuild the
1739- # key and role info for the top-level roles if 'merkle_filename ' is root.
1734+ # key and role info for the top-level roles if 'proof_filename ' is root.
17401735 # Rebuilding the key and role info is required if the newly-installed
17411736 # root metadata has revoked keys or updated any top-level role information.
17421737 logger .debug ('Updated ' + repr (current_filepath ) + '.' )
1743- self .metadata ['previous' ][merkle_filename ] = current_metadata_object
1744- self .metadata ['current' ][merkle_filename ] = updated_metadata_object
1738+ self .metadata ['previous' ][proof_filename ] = current_metadata_object
1739+ self .metadata ['current' ][proof_filename ] = updated_metadata_object
17451740
17461741
17471742
@@ -1865,39 +1860,52 @@ def _update_metadata(self, metadata_role, upperbound_filelength, version=None):
18651860
18661861
18671862
1868- def verify_merkle_path (self , metadata_role , version = None , merkle_root = None ):
1863+ def verify_rsa_acc_proof (self , metadata_role , version = None , rsa_acc = None ):
18691864 """
18701865 <Purpose>
1871- Download the merkle path associated with metadata_role and verify the hashes.
1866+ Download the RSA accumulator proof associated with metadata_role and verify the hashes.
18721867 <Arguments>
18731868 metadata_role:
18741869 The name of the metadata role. This should not include a file extension.
18751870 <Exceptions>
18761871 tuf.exceptions.RepositoryError:
1877- If the snapshot merkle file is invalid or the verification fails
1872+ If the snapshot rsa accumulator file is invalid or the verification fails
18781873 <Returns>
18791874 A dictionary containing the snapshot information about metadata role,
18801875 conforming to VERSIONINFO_SCHEMA or METADATA_FILEINFO_SCHEMA
18811876 """
1882- if not merkle_root :
1883- merkle_root = self .metadata ['current' ]['timestamp' ]['merkle_root' ]
1877+
1878+ # Modulus from https://en.wikipedia.org/wiki/RSA_numbers#RSA-2048
1879+ # We will want to generate a new one
1880+ # This is duplicate code from repo lib, should live somewhere else
1881+ Modulus = "2519590847565789349402718324004839857142928212620403202777713783604366202070759555626401852588078" + \
1882+ "4406918290641249515082189298559149176184502808489120072844992687392807287776735971418347270261896375014971" + \
1883+ "8246911650776133798590957000973304597488084284017974291006424586918171951187461215151726546322822168699875" + \
1884+ "4918242243363725908514186546204357679842338718477444792073993423658482382428119816381501067481045166037730" + \
1885+ "6056201619676256133844143603833904414952634432190114657544454178424020924616515723350778707749817125772467" + \
1886+ "962926386356373289912154831438167899885040445364023527381951378636564391212010397122822120720357"
1887+ m = int (Modulus , 10 )
1888+
1889+
1890+ if not rsa_acc :
1891+ rsa_acc = self .metadata ['current' ]['timestamp' ]['rsa_acc' ]
18841892
18851893 metadata_rolename = metadata_role + '-snapshot'
18861894
1887- # Download Merkle path
1895+ # Download RSA accumulator proof
18881896 upperbound_filelength = tuf .settings .MERKLE_FILELENGTH
1889- self ._update_merkle_metadata (metadata_rolename , upperbound_filelength , version )
1897+ self ._update_rsa_acc_metadata (metadata_rolename , upperbound_filelength , version )
18901898 metadata_directory = self .metadata_directory ['current' ]
18911899 metadata_filename = metadata_rolename + '.json'
18921900 metadata_filepath = os .path .join (metadata_directory , metadata_filename )
18931901
18941902 # Ensure the metadata path is valid/exists, else ignore the call.
18951903 if not os .path .exists (metadata_filepath ):
1896- # No merkle path found
1897- raise tuf .exceptions .RepositoryError ('No snapshot merkle file for ' +
1904+ # No RSA accumulator proof found
1905+ raise tuf .exceptions .RepositoryError ('No snapshot rsa accumulator proof file for ' +
18981906 metadata_role )
18991907 try :
1900- snapshot_merkle = securesystemslib .util .load_json_file (
1908+ snapshot_rsa_acc_proof = securesystemslib .util .load_json_file (
19011909 metadata_filepath )
19021910
19031911 # Although the metadata file may exist locally, it may not
@@ -1907,46 +1915,23 @@ def verify_merkle_path(self, metadata_role, version=None, merkle_root=None):
19071915 except securesystemslib .exceptions .Error :
19081916 return
19091917
1910- # verify the Merkle path
1911- tuf .formats .SNAPSHOT_MERKLE_SCHEMA .check_match (snapshot_merkle )
1918+ # check the format
1919+ tuf .formats .SNAPSHOT_RSA_ACC_SCHEMA .check_match (snapshot_rsa_acc_proof )
19121920
1913- # hash the contents to determine the leaf hash in the merkle tree
1914- contents = snapshot_merkle ['leaf_contents' ]
1921+ # canonicalize the contents to determine the RSA accumulator prime
1922+ contents = snapshot_rsa_acc_proof ['leaf_contents' ]
19151923 json_contents = securesystemslib .formats .encode_canonical (contents )
1916- digest_object = securesystemslib .hash .digest ()
1917- digest_object .update ((json_contents ).encode ('utf-8' ))
1918- node_hash = "a" + digest_object .hexdigest ()
1919-
1920- # For each hash in the merkle_path, determine if the current node is
1921- # a left of a right node using the path_directions, then combine
1922- # the hash from merkle_path with the current node_hash to determine
1923- # the next node_hash. At the end, the node_hash should match the hash
1924- # in merkle_root
1925- merkle_path = snapshot_merkle ['merkle_path' ]
1926- path_directions = snapshot_merkle ['path_directions' ]
1927-
1928- # If merkle_path and path_directions have different lengths,
1929- # the verification will not be possible
1930- if len (merkle_path ) != len (path_directions ):
1931- raise tuf .exceptions .RepositoryError ('Invalid merkle path for ' +
1932- metadata_role )
19331924
1934- for index in range (len (merkle_path )):
1935- i = str (index )
1936- if path_directions [i ] < 0 :
1937- # The current node is a left node
1938- digest_object = securesystemslib .hash .digest ()
1939- digest_object .update ((node_hash + merkle_path [i ]).encode ('utf-8' ))
1940- else :
1941- # The current node is a right node
1942- digest_object = securesystemslib .hash .digest ()
1943- digest_object .update ((merkle_path [i ] + node_hash ).encode ('utf-8' ))
1944- node_hash = "b" + digest_object .hexdigest ()
1925+ prime = repository_lib .hash_to_prime (json_contents )
1926+
1927+ # RSA accumulator proof
1928+ proof = snapshot_rsa_acc_proof ['rsa_acc_proof' ]
1929+ rsa_acc_proof_test = pow (proof , prime , m )
19451930
1946- # Does the result match the merkle root ?
1947- if node_hash != merkle_root :
1948- raise tuf .exceptions .RepositoryError ('The merkle root ' + merkle_root +
1949- ' does not match the hash ' + node_hash + ' for ' + metadata_role )
1931+ # Does the result match the RSA accumulator ?
1932+ if rsa_acc_proof_test != rsa_acc :
1933+ raise tuf .exceptions .RepositoryError ('RSA accumulator ' + rsa_acc +
1934+ ' does not match the proof ' + proof + ' for ' + metadata_role )
19501935
19511936 # return the verified snapshot contents
19521937 return contents
@@ -2025,9 +2010,9 @@ def _update_metadata_if_changed(self, metadata_role,
20252010
20262011 # Ensure the referenced metadata has been loaded. The 'root' role may be
20272012 # updated without having 'snapshot' available.
2028- # When snapshot merkle trees are used, there will not be a snapshot file.
2029- # Instead, if the snapshot merkle file is missing, this will error below.
2030- if 'merkle_root ' not in self .metadata ['current' ]['timestamp' ] and referenced_metadata not in self .metadata ['current' ]:
2013+ # When a snapshot rsa accumulator is used, there will not be a snapshot file.
2014+ # Instead, if the snapshot rsa proof is missing, this will error below.
2015+ if 'rsa_acc ' not in self .metadata ['current' ]['timestamp' ] and referenced_metadata not in self .metadata ['current' ]:
20312016 raise tuf .exceptions .RepositoryError ('Cannot update'
20322017 ' ' + repr (metadata_role ) + ' because ' + referenced_metadata + ' is'
20332018 ' missing.' )
@@ -2039,9 +2024,9 @@ def _update_metadata_if_changed(self, metadata_role,
20392024 repr (referenced_metadata )+ '. ' + repr (metadata_role ) +
20402025 ' may be updated.' )
20412026
2042- if 'merkle_root ' in self .metadata ['current' ]['timestamp' ]:
2043- # Download version information from merkle tree
2044- contents = self .verify_merkle_path (metadata_role )
2027+ if 'rsa_acc ' in self .metadata ['current' ]['timestamp' ]:
2028+ # Download version information from RSA accumulator proof
2029+ contents = self .verify_rsa_acc_proof (metadata_role )
20452030 expected_versioninfo = contents
20462031
20472032 else :
@@ -2621,10 +2606,10 @@ def _refresh_targets_metadata(self, rolename='targets',
26212606
26222607 roles_to_update = []
26232608
2624- # Add the role if it is listed in snapshot. If snapshot merkle
2625- # trees are used, the snapshot check will be done later when
2626- # the merkle tree is verified
2627- if 'merkle_root ' in self .metadata ['current' ]['timestamp' ] or rolename + '.json' in self .metadata ['current' ]['snapshot' ]['meta' ]:
2609+ # Add the role if it is listed in snapshot. If a snapshot rsa
2610+ # accumulator is used, the snapshot check will be done later when
2611+ # the proof is verified
2612+ if 'rsa_acc ' in self .metadata ['current' ]['timestamp' ] or rolename + '.json' in self .metadata ['current' ]['snapshot' ]['meta' ]:
26282613 roles_to_update .append (rolename )
26292614
26302615 if refresh_all_delegated_roles :
0 commit comments