def test_metadata_root(self): root_path = os.path.join( self.repo_dir, 'metadata', 'root.json') root = Metadata.from_file(root_path) # Add a second key to root role root_key2 = import_ed25519_publickey_from_file( os.path.join(self.keystore_dir, 'root_key2.pub')) keyid = root_key2['keyid'] key_metadata = format_keyval_to_metadata( root_key2['keytype'], root_key2['scheme'], root_key2['keyval']) # Assert that root does not contain the new key self.assertNotIn(keyid, root.signed.roles['root']['keyids']) self.assertNotIn(keyid, root.signed.keys) # Add new root key root.signed.add_key('root', keyid, key_metadata) # Assert that key is added self.assertIn(keyid, root.signed.roles['root']['keyids']) self.assertIn(keyid, root.signed.keys) # Remove the key root.signed.remove_key('root', keyid) # Assert that root does not contain the new key anymore self.assertNotIn(keyid, root.signed.roles['root']['keyids']) self.assertNotIn(keyid, root.signed.keys)
def from_securesystemslib_key(cls, key_dict: Dict[str, Any]) -> "Key": """ Creates a Key object from a securesystemlib key dict representation removing the private key from keyval. """ key_meta = sslib_keys.format_keyval_to_metadata( key_dict["keytype"], key_dict["scheme"], key_dict["keyval"], ) return cls( key_dict["keyid"], key_meta["keytype"], key_meta["scheme"], key_meta["keyval"], )
def _save_project_configuration(metadata_directory, targets_directory, public_keys, prefix, threshold, layout_type, project_name): """ <Purpose> Persist the project's information to a file. The saved project information can later be loaded with Project.load_project(). <Arguments> metadata_directory: Where the project's metadata is located. targets_directory: The location of the target files for this project. public_keys: A list containing the public keys for the project role. prefix: The project's prefix (if any.) threshold: The threshold value for the project role. layout_type: The layout type being used by the project, "flat" stands for separated targets and metadata directories, "repo-like" emulates the layout used by the repository tools project_name: The name given to the project, this sets the metadata filename so it matches the one stored in upstream. <Exceptions> securesystemslib.exceptions.FormatError are also expected if any of the arguments are malformed. OSError may rise if the metadata_directory/project.cfg file exists and is non-writeable <Side Effects> A 'project.cfg' configuration file is created or overwritten. <Returns> None. """ # Schema check for the arguments. sslib_formats.PATH_SCHEMA.check_match(metadata_directory) sslib_formats.PATH_SCHEMA.check_match(prefix) sslib_formats.PATH_SCHEMA.check_match(targets_directory) formats.RELPATH_SCHEMA.check_match(project_name) cfg_file_directory = metadata_directory # Check whether the layout type is 'flat' or 'repo-like'. # If it is, the .cfg file should be saved in the previous directory. if layout_type == 'repo-like': cfg_file_directory = os.path.dirname(metadata_directory) junk, targets_directory = os.path.split(targets_directory) junk, metadata_directory = os.path.split(metadata_directory) # Can the file be opened? project_filename = os.path.join(cfg_file_directory, PROJECT_FILENAME) # Build the fields of the configuration file. project_config = {} project_config['prefix'] = prefix project_config['public_keys'] = {} project_config['metadata_location'] = metadata_directory project_config['targets_location'] = targets_directory project_config['threshold'] = threshold project_config['layout_type'] = layout_type project_config['project_name'] = project_name # Build a dictionary containing the actual keys. for key in public_keys: key_info = keydb.get_key(key) key_metadata = format_keyval_to_metadata(key_info['keytype'], key_info['scheme'], key_info['keyval']) project_config['public_keys'][key] = key_metadata # Save the actual file. with open(project_filename, 'wt', encoding='utf8') as fp: json.dump(project_config, fp)
def _generate_and_write_ecdsa_keypair(filepath=None, password=None, prompt=False): """Generates ecdsa key pair and writes custom JSON-formatted keys to disk. If a password is passed or entered on the prompt, the private key is encrypted using AES-256 in CTR mode, with the password strengthened in PBKDF2-HMAC-SHA256. NOTE: The custom key format includes 'ecdsa-sha2-nistp256' as signing scheme. Arguments: filepath (optional): The path to write the private key to. If not passed, the key is written to CWD using the keyid as filename. The public key is written to the same path as the private key using the suffix '.pub'. password (optional): An encryption password. prompt (optional): A boolean indicating if the user should be prompted for an encryption password. If the user enters an empty password, the key is not encrypted. Raises: UnsupportedLibraryError: pyca/cryptography is not available. FormatError: Arguments are malformed. ValueError: An empty string is passed as 'password', or both a 'password' is passed and 'prompt' is true. StorageError: Key files cannot be written. Side Effects: Prompts user for a password if 'prompt' is True. Writes key files to disk. Returns: The private key filepath. """ ecdsa_key = keys.generate_ecdsa_key() # Use passed 'filepath' or keyid as file name if not filepath: filepath = os.path.join(os.getcwd(), ecdsa_key['keyid']) formats.PATH_SCHEMA.check_match(filepath) password = _get_key_file_encryption_password(password, prompt, filepath) # Create intermediate directories as required util.ensure_parent_dir(filepath) # Use custom JSON format for ecdsa keys on-disk keytype = ecdsa_key['keytype'] keyval = ecdsa_key['keyval'] scheme = ecdsa_key['scheme'] ecdsakey_metadata_format = keys.format_keyval_to_metadata(keytype, scheme, keyval, private=False) # Write public key to <filepath>.pub file_object = tempfile.TemporaryFile() file_object.write(json.dumps(ecdsakey_metadata_format).encode('utf-8')) util.persist_temp_file(file_object, filepath + '.pub') # Encrypt private key if we have a password, store as JSON string otherwise if password is not None: ecdsa_key = keys.encrypt_key(ecdsa_key, password) else: ecdsa_key = json.dumps(ecdsa_key) # Write private key to <filepath> file_object = tempfile.TemporaryFile() file_object.write(ecdsa_key.encode('utf-8')) util.persist_temp_file(file_object, filepath) return filepath