def _initialize(self) -> None: """Setup a minimal valid repository.""" self.md_targets = Metadata(Targets(expires=self.safe_expiry)) self.md_snapshot = Metadata(Snapshot(expires=self.safe_expiry)) self.md_timestamp = Metadata(Timestamp(expires=self.safe_expiry)) self.md_root = Metadata(Root(expires=self.safe_expiry)) for role in TOP_LEVEL_ROLE_NAMES: key, signer = self.create_key() self.md_root.signed.add_key(key, role) self.add_signer(role, signer) self.publish_root()
def add_succinct_roles(self, delegator_name: str, bit_length: int, name_prefix: str) -> None: """Add succinct roles info to a delegator with name "delegator_name". Note that for each delegated role represented by succinct roles an empty Targets instance is created. """ delegator = self._get_delegator(delegator_name) if (delegator.delegations is not None and delegator.delegations.roles is not None): raise ValueError( "Can't add a succinct_roles when delegated roles are used") key, signer = self.create_key() succinct_roles = SuccinctRoles([], 1, bit_length, name_prefix) delegator.delegations = Delegations({}, None, succinct_roles) # Add targets metadata for all bins. for delegated_name in succinct_roles.get_roles(): self.md_delegates[delegated_name] = Metadata( Targets(expires=self.safe_expiry)) self.add_signer(delegated_name, signer) delegator.add_key(key)
def add_delegation(self, delegator_name: str, role: DelegatedRole, targets: Targets) -> None: """Add delegated target role to the repository.""" delegator = self._get_delegator(delegator_name) if (delegator.delegations is not None and delegator.delegations.succinct_roles is not None): raise ValueError("Can't add a role when succinct_roles is used") # Create delegation if delegator.delegations is None: delegator.delegations = Delegations({}, roles={}) assert delegator.delegations.roles is not None # put delegation last by default delegator.delegations.roles[role.name] = role # By default add one new key for the role key, signer = self.create_key() delegator.add_key(key, role.name) self.add_signer(role.name, signer) # Add metadata for the role if role.name not in self.md_delegates: self.md_delegates[role.name] = Metadata(targets, {})
def generate_all_files(dump: Optional[bool] = False, verify: Optional[bool] = False) -> None: """Generate a new repository and optionally verify it. Args: dump: Wheter to dump the newly generated files. verify: Whether to verify the newly generated files with the local staored. """ md_root = Metadata(Root(expires=EXPIRY)) md_timestamp = Metadata(Timestamp(expires=EXPIRY)) md_snapshot = Metadata(Snapshot(expires=EXPIRY)) md_targets = Metadata(Targets(expires=EXPIRY)) md_root.signed.add_key(keys["ed25519_0"], "root") md_root.signed.add_key(keys["ed25519_1"], "timestamp") md_root.signed.add_key(keys["ed25519_2"], "snapshot") md_root.signed.add_key(keys["ed25519_3"], "targets") for i, md in enumerate([md_root, md_timestamp, md_snapshot, md_targets]): assert isinstance(md, Metadata) signer = SSlibSigner({ "keytype": "ed25519", "scheme": "ed25519", "keyid": keyids[i], "keyval": { "public": public_values[i], "private": private_values[i], }, }) md.sign(signer) path = os.path.join(OUT_DIR, f"{md.signed.type}_with_ed25519.json") if verify: verify_generation(md, path) if dump: md.to_file(path, SERIALIZER)
# volatility of the bins role, it is recommended to require signature # thresholds and keep the keys offline in a real-world scenario. # NOTE: See "Targets delegation" and "Signature thresholds" paragraphs in # 'basic_repo.py' for more details for name in ["bin-n", "bins"]: keys[name] = generate_ed25519_key() # Targets roles # ------------- # NOTE: See "Targets" and "Targets delegation" paragraphs in 'basic_repo.py' # example for more details about the Targets object. # Create preliminary delegating targets role (bins) and add public key for # delegated targets (bin_n) to key store. Delegation details are update below. roles["bins"] = Metadata(Targets(expires=_in(365))) bin_n_key = Key.from_securesystemslib_key(keys["bin-n"]) roles["bins"].signed.delegations = Delegations( keys={bin_n_key.keyid: bin_n_key}, roles={}, ) # The hash bin generator yields an ordered list of incremental hash bin names # (ranges), plus the hash prefixes each bin is responsible for, e.g.: # # bin_n_name: 00-07 bin_n_hash_prefixes: 00 01 02 03 04 05 06 07 # 08-0f 08 09 0a 0b 0c 0d 0e 0f # 10-17 10 11 12 13 14 15 16 17 # ... ... # f8-ff f8 f9 fa fb fc fd fe ff assert roles["bins"].signed.delegations.roles is not None
# expiration intervals, whereas roles that change less and might use offline # keys (root, delegating targets) may have longer expiration intervals. SPEC_VERSION = ".".join(SPECIFICATION_VERSION) # Define containers for role objects and cryptographic keys created below. This # allows us to sign and write metadata in a batch more easily. roles: Dict[str, Metadata] = {} keys: Dict[str, Dict[str, Any]] = {} # Targets (integrity) # ------------------- # The targets role guarantees integrity for the files that TUF aims to protect, # i.e. target files. It does so by listing the relevant target files, along # with their hash and length. roles["targets"] = Metadata(Targets(expires=_in(7))) # For the purpose of this example we use the top-level targets role to protect # the integrity of this very example script. The metadata entry contains the # hash and length of this file at the local path. In addition, it specifies the # 'target path', which a client uses to locate the target file relative to a # configured mirror base URL. # # |----base URL---||-------target path-------| # e.g. tuf-examples.org/repo_example/basic_repo.py local_path = Path(__file__).resolve() target_path = f"{local_path.parts[-2]}/{local_path.parts[-1]}" target_file_info = TargetFile.from_file(target_path, str(local_path)) roles["targets"].signed.targets[target_path] = target_file_info