diff --git a/securesystemslib/interface.py b/securesystemslib/interface.py index c9ec7086..19a1ef4e 100755 --- a/securesystemslib/interface.py +++ b/securesystemslib/interface.py @@ -43,6 +43,7 @@ import securesystemslib.formats import securesystemslib.settings +import securesystemslib.storage import securesystemslib.util import securesystemslib.keys @@ -242,7 +243,8 @@ def generate_and_write_rsa_keypair(filepath=None, bits=DEFAULT_RSA_KEY_BITS, def import_rsa_privatekey_from_file(filepath, password=None, - scheme='rsassa-pss-sha256', prompt=False): + scheme='rsassa-pss-sha256', prompt=False, + storage_backend=None): """ Import the PEM file in 'filepath' containing the private key. @@ -272,6 +274,11 @@ def import_rsa_privatekey_from_file(filepath, password=None, If True the user is prompted for a passphrase to decrypt 'filepath'. Default is False. + storage_backend: + An object which implements + securesystemslib.storage.StorageBackendInterface. When no object is + passed a FilesystemBackend will be instantiated and used. + ValueError, if 'password' is passed and 'prompt' is True. @@ -344,9 +351,13 @@ def import_rsa_privatekey_from_file(filepath, password=None, logger.debug('No password was given. Attempting to import an' ' unencrypted file.') + if storage_backend is None: + storage_backend = securesystemslib.storage.FilesystemBackend() + # Read the contents of 'filepath' that should be a PEM formatted private key. - with open(filepath, 'rb') as file_object: - pem_key = file_object.read().decode('utf-8') + file_object = storage_backend.get(filepath) + pem_key = file_object.read().decode('utf-8') + file_object.close() # Convert 'pem_key' to 'securesystemslib.formats.RSAKEY_SCHEMA' format. # Raise 'securesystemslib.exceptions.CryptoError' if 'pem_key' is invalid. @@ -360,7 +371,8 @@ def import_rsa_privatekey_from_file(filepath, password=None, -def import_rsa_publickey_from_file(filepath, scheme='rsassa-pss-sha256'): +def import_rsa_publickey_from_file(filepath, scheme='rsassa-pss-sha256', + storage_backend=None): """ Import the RSA key stored in 'filepath'. The key object returned is in the @@ -374,6 +386,11 @@ def import_rsa_publickey_from_file(filepath, scheme='rsassa-pss-sha256'): scheme: The signature scheme used by the imported key. + storage_backend: + An object which implements + securesystemslib.storage.StorageBackendInterface. When no object is + passed a FilesystemBackend will be instantiated and used. + securesystemslib.exceptions.FormatError, if 'filepath' is improperly formatted. @@ -397,10 +414,14 @@ def import_rsa_publickey_from_file(filepath, scheme='rsassa-pss-sha256'): # Is 'scheme' properly formatted? securesystemslib.formats.RSA_SCHEME_SCHEMA.check_match(scheme) + if storage_backend is None: + storage_backend = securesystemslib.storage.FilesystemBackend() + # Read the contents of the key file that should be in PEM format and contains # the public portion of the RSA key. - with open(filepath, 'rb') as file_object: - rsa_pubkey_pem = file_object.read().decode('utf-8') + file_object = storage_backend.get(filepath) + rsa_pubkey_pem = file_object.read().decode('utf-8') + file_object.close() # Convert 'rsa_pubkey_pem' to 'securesystemslib.formats.RSAKEY_SCHEMA' format. try: @@ -587,7 +608,8 @@ def import_ed25519_publickey_from_file(filepath): -def import_ed25519_privatekey_from_file(filepath, password=None, prompt=False): +def import_ed25519_privatekey_from_file(filepath, password=None, prompt=False, + storage_backend=None): """ Import the encrypted ed25519 key file in 'filepath', decrypt it, and return @@ -610,6 +632,11 @@ def import_ed25519_privatekey_from_file(filepath, password=None, prompt=False): If True the user is prompted for a passphrase to decrypt 'filepath'. Default is False. + storage_backend: + An object which implements + securesystemslib.storage.StorageBackendInterface. When no object is + passed a FilesystemBackend will be instantiated and used. + securesystemslib.exceptions.FormatError, if the arguments are improperly formatted or the imported key object contains an invalid key type (i.e., @@ -634,6 +661,9 @@ def import_ed25519_privatekey_from_file(filepath, password=None, prompt=False): if password and prompt: raise ValueError("Passing 'password' and 'prompt' True is not allowed.") + if storage_backend is None: + storage_backend = securesystemslib.storage.FilesystemBackend() + # If 'password' was passed check format and that it is not empty. if password is not None: securesystemslib.formats.PASSWORD_SCHEMA.check_match(password) @@ -664,10 +694,11 @@ def import_ed25519_privatekey_from_file(filepath, password=None, prompt=False): # Finally, regardless of password, try decrypting the key, if necessary. # Otherwise, load it straight from the disk. - with open(filepath, 'rb') as file_object: - json_str = file_object.read() - return securesystemslib.keys.\ - import_ed25519key_from_private_json(json_str, password=password) + file_object = storage_backend.get(filepath) + json_str = file_object.read() + file_object.close() + return securesystemslib.keys.\ + import_ed25519key_from_private_json(json_str, password=password) @@ -832,7 +863,8 @@ def import_ecdsa_publickey_from_file(filepath): -def import_ecdsa_privatekey_from_file(filepath, password=None): +def import_ecdsa_privatekey_from_file(filepath, password=None, + storage_backend=None): """ Import the encrypted ECDSA key file in 'filepath', decrypt it, and return @@ -850,6 +882,11 @@ def import_ecdsa_privatekey_from_file(filepath, password=None): encrypted key file 'filepath' must be decrypted before the ECDSA key object can be returned. + storage_backend: + An object which implements + securesystemslib.storage.StorageBackendInterface. When no object is + passed a FilesystemBackend will be instantiated and used. + securesystemslib.exceptions.FormatError, if the arguments are improperly formatted or the imported key object contains an invalid key type (i.e., @@ -886,12 +923,16 @@ def import_ecdsa_privatekey_from_file(filepath, password=None): # Does 'password' have the correct format? securesystemslib.formats.PASSWORD_SCHEMA.check_match(password) + if storage_backend is None: + storage_backend = securesystemslib.storage.FilesystemBackend() + # Store the encrypted contents of 'filepath' prior to calling the decryption # routine. encrypted_key = None - with open(filepath, 'rb') as file_object: - encrypted_key = file_object.read() + file_object = storage_backend.get(filepath) + encrypted_key = file_object.read() + file_object.close() # Decrypt the loaded key file, calling the 'cryptography' library to generate # the derived encryption key from 'password'. Raise diff --git a/tests/test_interface.py b/tests/test_interface.py index 1a37213d..6d9181d4 100755 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -218,8 +218,8 @@ def test_import_rsa_privatekey_from_file(self): # Non-existent key file. nonexistent_keypath = os.path.join(temporary_directory, 'nonexistent_keypath') - self.assertRaises(IOError, interface.import_rsa_privatekey_from_file, - nonexistent_keypath, 'pw') + self.assertRaises(securesystemslib.exceptions.StorageError, + interface.import_rsa_privatekey_from_file, nonexistent_keypath, 'pw') # Invalid key file argument. invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile') @@ -252,8 +252,8 @@ def test_import_rsa_publickey_from_file(self): # Non-existent key file. nonexistent_keypath = os.path.join(temporary_directory, 'nonexistent_keypath') - self.assertRaises(IOError, interface.import_rsa_publickey_from_file, - nonexistent_keypath) + self.assertRaises(securesystemslib.exceptions.StorageError, + interface.import_rsa_publickey_from_file, nonexistent_keypath) # Invalid key file argument. invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile') @@ -426,8 +426,9 @@ def test_import_ed25519_privatekey_from_file(self): # Non-existent key file. nonexistent_keypath = os.path.join(temporary_directory, 'nonexistent_keypath') - self.assertRaises(IOError, interface.import_ed25519_privatekey_from_file, - nonexistent_keypath, 'pw') + self.assertRaises(securesystemslib.exceptions.StorageError, + interface.import_ed25519_privatekey_from_file, nonexistent_keypath, + 'pw') # Invalid key file argument. invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile') @@ -576,8 +577,8 @@ def test_import_ecdsa_privatekey_from_file(self): # Test invalid argument. # Non-existent key file. nonexistent_keypath = os.path.join(temporary_directory, 'nonexistent_keypath') - self.assertRaises(IOError, interface.import_ecdsa_privatekey_from_file, - nonexistent_keypath, 'pw') + self.assertRaises(securesystemslib.exceptions.StorageError, + interface.import_ecdsa_privatekey_from_file, nonexistent_keypath, 'pw') # Invalid key file argument. invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile')