diff --git a/tests/test_repository_lib.py b/tests/test_repository_lib.py index 5be7d40ed6..044b4555d7 100755 --- a/tests/test_repository_lib.py +++ b/tests/test_repository_lib.py @@ -52,6 +52,7 @@ import tuf.repository_tool as repo_tool import securesystemslib +import securesystemslib.interface import six logger = logging.getLogger('tuf.test_repository_lib') @@ -100,49 +101,6 @@ def tearDown(self): - def test_generate_and_write_rsa_keypair(self): - - # Test normal case. - temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) - test_keypath = os.path.join(temporary_directory, 'rsa_key') - - repo_lib.generate_and_write_rsa_keypair(test_keypath, password='pw') - self.assertTrue(os.path.exists(test_keypath)) - self.assertTrue(os.path.exists(test_keypath + '.pub')) - - # Ensure the generated key files are importable. - imported_pubkey = \ - repo_lib.import_rsa_publickey_from_file(test_keypath + '.pub') - self.assertTrue(securesystemslib.formats.RSAKEY_SCHEMA.matches(imported_pubkey)) - - imported_privkey = \ - repo_lib.import_rsa_privatekey_from_file(test_keypath, 'pw') - self.assertTrue(securesystemslib.formats.RSAKEY_SCHEMA.matches(imported_privkey)) - - # Custom 'bits' argument. - os.remove(test_keypath) - os.remove(test_keypath + '.pub') - repo_lib.generate_and_write_rsa_keypair(test_keypath, bits=2048, - password='pw') - self.assertTrue(os.path.exists(test_keypath)) - self.assertTrue(os.path.exists(test_keypath + '.pub')) - - - # Test improperly formatted arguments. - self.assertRaises(securesystemslib.exceptions.FormatError, repo_lib.generate_and_write_rsa_keypair, - 3, bits=2048, password='pw') - self.assertRaises(securesystemslib.exceptions.FormatError, repo_lib.generate_and_write_rsa_keypair, - test_keypath, bits='bad', password='pw') - self.assertRaises(securesystemslib.exceptions.FormatError, repo_lib.generate_and_write_rsa_keypair, - test_keypath, bits=2048, password=3) - - - # Test invalid 'bits' argument. - self.assertRaises(securesystemslib.exceptions.FormatError, repo_lib.generate_and_write_rsa_keypair, - test_keypath, bits=1024, password='pw') - - - def test_import_rsa_privatekey_from_file(self): # Test normal case. temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) @@ -179,125 +137,13 @@ def test_import_rsa_privatekey_from_file(self): - def test_import_rsa_publickey_from_file(self): - # Test normal case. - temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) - - # Load one of the pre-generated key files from 'tuf/tests/repository_data'. - key_filepath = os.path.join('repository_data', 'keystore', - 'root_key.pub') - self.assertTrue(os.path.exists(key_filepath)) - - imported_rsa_key = repo_lib.import_rsa_publickey_from_file(key_filepath) - self.assertTrue(securesystemslib.formats.RSAKEY_SCHEMA.matches(imported_rsa_key)) - - - # Test improperly formatted argument. - self.assertRaises(securesystemslib.exceptions.FormatError, - repo_lib.import_rsa_privatekey_from_file, 3) - - - # Test invalid argument. - # Non-existent key file. - nonexistent_keypath = os.path.join(temporary_directory, - 'nonexistent_keypath') - self.assertRaises(IOError, repo_lib.import_rsa_publickey_from_file, - nonexistent_keypath) - - # Invalid key file argument. - invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile') - with open(invalid_keyfile, 'wb') as file_object: - file_object.write(b'bad keyfile') - self.assertRaises(securesystemslib.exceptions.Error, repo_lib.import_rsa_publickey_from_file, - invalid_keyfile) - - - - def test_generate_and_write_ed25519_keypair(self): - - # Test normal case. - temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) - test_keypath = os.path.join(temporary_directory, 'ed25519_key') - - repo_lib.generate_and_write_ed25519_keypair(test_keypath, password='pw') - self.assertTrue(os.path.exists(test_keypath)) - self.assertTrue(os.path.exists(test_keypath + '.pub')) - - # Ensure the generated key files are importable. - imported_pubkey = \ - repo_lib.import_ed25519_publickey_from_file(test_keypath + '.pub') - self.assertTrue(securesystemslib.formats.ED25519KEY_SCHEMA.matches(imported_pubkey)) - - imported_privkey = \ - repo_lib.import_ed25519_privatekey_from_file(test_keypath, 'pw') - self.assertTrue(securesystemslib.formats.ED25519KEY_SCHEMA.matches(imported_privkey)) - - - # Test improperly formatted arguments. - self.assertRaises(securesystemslib.exceptions.FormatError, - repo_lib.generate_and_write_ed25519_keypair, - 3, password='pw') - self.assertRaises(securesystemslib.exceptions.FormatError, repo_lib.generate_and_write_rsa_keypair, - test_keypath, password=3) - - - - def test_import_ed25519_publickey_from_file(self): - # Test normal case. - # Generate ed25519 keys that can be imported. - temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) - ed25519_keypath = os.path.join(temporary_directory, 'ed25519_key') - repo_lib.generate_and_write_ed25519_keypair(ed25519_keypath, password='pw') - - imported_ed25519_key = \ - repo_lib.import_ed25519_publickey_from_file(ed25519_keypath + '.pub') - self.assertTrue(securesystemslib.formats.ED25519KEY_SCHEMA.matches(imported_ed25519_key)) - - - # Test improperly formatted argument. - self.assertRaises(securesystemslib.exceptions.FormatError, - repo_lib.import_ed25519_publickey_from_file, 3) - - - # Test invalid argument. - # Non-existent key file. - nonexistent_keypath = os.path.join(temporary_directory, - 'nonexistent_keypath') - self.assertRaises(IOError, repo_lib.import_ed25519_publickey_from_file, - nonexistent_keypath) - - # Invalid key file argument. - invalid_keyfile = os.path.join(temporary_directory, 'invalid_keyfile') - with open(invalid_keyfile, 'wb') as file_object: - file_object.write(b'bad keyfile') - - self.assertRaises(securesystemslib.exceptions.Error, repo_lib.import_ed25519_publickey_from_file, - invalid_keyfile) - - # Invalid public key imported (contains unexpected keytype.) - keytype = imported_ed25519_key['keytype'] - keyval = imported_ed25519_key['keyval'] - scheme = imported_ed25519_key['scheme'] - ed25519key_metadata_format = \ - securesystemslib.keys.format_keyval_to_metadata(keytype, scheme, - keyval, private=False) - - ed25519key_metadata_format['keytype'] = 'invalid_keytype' - with open(ed25519_keypath + '.pub', 'wb') as file_object: - file_object.write(json.dumps(ed25519key_metadata_format).encode('utf-8')) - - self.assertRaises(securesystemslib.exceptions.FormatError, - repo_lib.import_ed25519_publickey_from_file, - ed25519_keypath + '.pub') - - - def test_import_ed25519_privatekey_from_file(self): # Test normal case. # Generate ed25519 keys that can be imported. temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) ed25519_keypath = os.path.join(temporary_directory, 'ed25519_key') - repo_lib.generate_and_write_ed25519_keypair(ed25519_keypath, password='pw') + securesystemslib.interface.generate_and_write_ed25519_keypair( + ed25519_keypath, password='pw') imported_ed25519_key = \ repo_lib.import_ed25519_privatekey_from_file(ed25519_keypath, 'pw') @@ -709,8 +555,8 @@ def test_sign_metadata(self): # Sign with a valid, but not a threshold, key. targets_public_keypath = os.path.join(keystore_path, 'targets_key.pub') - targets_public_key = \ - repo_lib.import_ed25519_publickey_from_file(targets_public_keypath) + targets_public_key = securesystemslib.interface.\ + import_ed25519_publickey_from_file(targets_public_keypath) # sign_metadata() expects the private key 'root_metadata' to be in # 'tuf.keydb'. Remove any public keys that may be loaded before diff --git a/tuf/developer_tool.py b/tuf/developer_tool.py index 78197ec6b4..2bd34fa658 100755 --- a/tuf/developer_tool.py +++ b/tuf/developer_tool.py @@ -53,15 +53,35 @@ import six -# These imports provide the interface for 'developer_tool.py', since the -# imports are made there. -from securesystemslib.keys import format_keyval_to_metadata - from tuf.repository_tool import Targets from tuf.repository_lib import _check_role_keys -from tuf.repository_lib import generate_targets_metadata from tuf.repository_lib import _metadata_is_partially_loaded + +# Copy API +# pylint: disable=unused-import + +# Copy generic repository API functions to be used via `developer_tool` +from tuf.repository_lib import ( + generate_targets_metadata, + create_tuf_client_directory, + disable_console_log_messages) + +# Copy key-related API functions to be used via `developer_tool` +from tuf.repository_lib import ( + import_rsa_privatekey_from_file) + +from securesystemslib.keys import ( + format_keyval_to_metadata) + +from securesystemslib.interface import ( + generate_and_write_rsa_keypair, + generate_and_write_ed25519_keypair, + import_rsa_publickey_from_file, + import_ed25519_publickey_from_file, + import_ed25519_privatekey_from_file) + + # See 'log.py' to learn how logging is handled in TUF. logger = logging.getLogger('tuf.developer_tool') @@ -986,35 +1006,6 @@ def _strip_prefix_from_targets_metadata(targets_metadata, prefix): -# Wrapper functions that we wish to make available here from repository_lib.py. -# Users are expected to call functions provided by repository_tool.py. We opt -# for this approach, as opposed to using import statements to achieve the -# equivalent, to avoid linter warnings for unused imports. -def generate_and_write_rsa_keypair(filepath, bits, password): - return repo_lib.generate_and_write_rsa_keypair(filepath, bits, password) - -def generate_and_write_ed25519_keypair(filepath, password): - return repo_lib.generate_and_write_ed25519_keypair(filepath, password) - -def import_rsa_publickey_from_file(filepath): - return repo_lib.import_rsa_publickey_from_file(filepath) - -def import_ed25519_publickey_from_file(filepath): - return repo_lib.import_ed25519_publickey_from_file(filepath) - -def import_rsa_privatekey_from_file(filepath, password): - return repo_lib.import_rsa_privatekey_from_file(filepath, password) - -def import_ed25519_privatekey_from_file(filepath, password): - return repo_lib.import_ed25519_privatekey_from_file(filepath, password) - -def create_tuf_client_directory(repository_directory, client_directory): - return repo_lib.create_tuf_client_directory(repository_directory, client_directory) - -def disable_console_log_messages(): - return repo_lib.disable_console_log_messages() - - if __name__ == '__main__': diff --git a/tuf/repository_lib.py b/tuf/repository_lib.py index 22f12de7c2..371a9dff49 100755 --- a/tuf/repository_lib.py +++ b/tuf/repository_lib.py @@ -63,13 +63,6 @@ iso8601_logger = logging.getLogger('iso8601') iso8601_logger.disabled = True -# Recommended RSA key sizes: -# http://www.emc.com/emc-plus/rsa-labs/historical/twirl-and-rsa-key-size.htm#table1 -# According to the document above, revised May 6, 2003, RSA keys of -# size 3072 provide security through 2031 and beyond. 2048-bit keys -# are the recommended minimum and are good from the present through 2030. -DEFAULT_RSA_KEY_BITS = 3072 - # The extension of TUF metadata. METADATA_EXTENSION = '.json' @@ -752,42 +745,6 @@ def _log_warning_if_expires_soon(rolename, expires_iso8601_timestamp, -def generate_and_write_rsa_keypair(filepath, bits=DEFAULT_RSA_KEY_BITS, - password=None): - """ - - Generate an RSA key file, create an encrypted PEM string (using 'password' - as the pass phrase), and store it in 'filepath'. The public key portion of - the generated RSA key is stored in <'filepath'>.pub. - - - filepath: - The public and private key files are saved to .pub, , - respectively. - - bits: - The number of bits of the generated RSA key. - - password: - The password used to encrypt 'filepath'. - - - securesystemslib.exceptions.FormatError, if the arguments are improperly - formatted. - - - Writes key files to '' and '.pub'. - - - None. - """ - - securesystemslib.interface.generate_and_write_rsa_keypair( - filepath, bits, password) - - - - def import_rsa_privatekey_from_file(filepath, password=None): """ @@ -840,111 +797,6 @@ def import_rsa_privatekey_from_file(filepath, password=None): -def import_rsa_publickey_from_file(filepath): - """ - - Import the RSA key stored in 'filepath'. The key object returned is a TUF - key, specifically 'securesystemslib.RSAKEY_SCHEMA'. If the RSA PEM - in 'filepath' contains a private key, it is discarded. - - - filepath: - .pub file, an RSA PEM file. - - - securesystemslib.exceptions.FormatError, if 'filepath' is improperly formatted. - - securesystemslib.exceptions.Error, if a valid RSA key object cannot be - generated. This may be caused by an improperly formatted PEM file. - - - 'filepath' is read and its contents extracted. - - - An RSA key object conformant to 'securesystemslib.RSAKEY_SCHEMA'. - """ - - return securesystemslib.interface.import_rsa_publickey_from_file(filepath) - - - - - -def generate_and_write_ed25519_keypair(filepath, password=None): - """ - - Generate an Ed25519 key file, create an encrypted TUF key (using 'password' - as the pass phrase), and store it in 'filepath'. The public key portion of - the generated ED25519 key is stored in <'filepath'>.pub. Which cryptography - library performs the cryptographic decryption is determined by the string - set in 'settings.ED25519_CRYPTO_LIBRARY'. - - The Ed25519 private key is encrypted with AES-256 and CTR the mode of - operation. The password is strengthened with PBKDF2-HMAC-SHA256. - - - filepath: - The public and private key files are saved to .pub and - , respectively. - - password: - The password, or passphrase, to encrypt the private portion of the - generated ed25519 key. A symmetric encryption key is derived from - 'password', so it is not directly used. - - - securesystemslib.exceptions.FormatError, if the arguments are improperly - formatted. - - securesystemslib.exceptions.CryptoError, if 'filepath' cannot be encrypted. - - securesystemslib.exceptions.UnsupportedLibraryError, if 'filepath' cannot be - encrypted due to an invalid configuration setting (i.e., invalid - 'tuf.settings.py' setting). - - - Writes key files to '' and '.pub'. - - - None. - """ - - securesystemslib.interface.generate_and_write_ed25519_keypair( - filepath, password) - - - - - -def import_ed25519_publickey_from_file(filepath): - """ - - Load the ED25519 public key object (conformant to - 'securesystemslib.KEY_SCHEMA') stored in 'filepath'. Return - 'filepath' in securesystemslib.ED25519KEY_SCHEMA format. - - If the TUF key object in 'filepath' contains a private key, it is discarded. - - - filepath: - .pub file, a TUF public key file. - - - securesystemslib.exceptions.FormatError, if 'filepath' is improperly - formatted or is an unexpected key type. - - - The contents of 'filepath' is read and saved. - - - An ED25519 key object conformant to - 'securesystemslib.ED25519KEY_SCHEMA'. - """ - - return securesystemslib.interface.import_ed25519_publickey_from_file(filepath) - - - def import_ed25519_privatekey_from_file(filepath, password=None): diff --git a/tuf/repository_tool.py b/tuf/repository_tool.py index a461ab0a93..b79507310e 100755 --- a/tuf/repository_tool.py +++ b/tuf/repository_tool.py @@ -54,6 +54,37 @@ import six +# Copy API +# pylint: disable=unused-import + +# Copy generic repository API functions to be used via `repository_tool` +from tuf.repository_lib import ( + create_tuf_client_directory, + disable_console_log_messages) + + +# Copy key-related API functions to be used via `repository_tool` +from tuf.repository_lib import ( + import_rsa_privatekey_from_file, + import_ed25519_privatekey_from_file) + +from securesystemslib.interface import ( + generate_and_write_rsa_keypair, + generate_and_write_ecdsa_keypair, + generate_and_write_ed25519_keypair, + import_rsa_publickey_from_file, + import_ecdsa_publickey_from_file, + import_ed25519_publickey_from_file, + import_ecdsa_privatekey_from_file) + +from securesystemslib.keys import ( + generate_rsa_key, + generate_ecdsa_key, + generate_ed25519_key, + import_rsakey_from_pem, + import_ecdsakey_from_pem) + + # See 'log.py' to learn how logging is handled in TUF. logger = logging.getLogger('tuf.repository_tool') @@ -3153,63 +3184,6 @@ def append_signature(signature, metadata_filepath): file_object.move(metadata_filepath) -# Wrapper functions that we wish to make available here from securesystemslib. -# Users are expected to call functions provided by repository_tool.py. We opt -# for wrapper functions, instead of using the import statements to achieve the -# equivalent, to avoid linter warnings for unused imports. -def generate_and_write_ed25519_keypair(filepath=None, password=None): - return repo_lib.generate_and_write_ed25519_keypair(filepath, password) - -def generate_ed25519_key(scheme='ed25519'): - return securesystemslib.keys.generate_ed25519_key(scheme) - -def import_ed25519_publickey_from_file(filepath): - return repo_lib.import_ed25519_publickey_from_file(filepath) - -def import_ed25519_privatekey_from_file(filepath, password=None): - return repo_lib.import_ed25519_privatekey_from_file(filepath, password) - -# NOTE: securesystemslib cannot presently import an Ed25519 key from PEM. - -def generate_and_write_rsa_keypair(filepath=None, - bits=repo_lib.DEFAULT_RSA_KEY_BITS, password=None): - return repo_lib.generate_and_write_rsa_keypair(filepath, bits, password) - -def generate_rsa_key(bits=DEFAULT_RSA_KEY_BITS, scheme='rsassa-pss-sha256'): - return securesystemslib.keys.generate_rsa_key(bits, scheme) - -def import_rsa_publickey_from_file(filepath): - return repo_lib.import_rsa_publickey_from_file(filepath) - -def import_rsa_privatekey_from_file(filepath, password=None): - return repo_lib.import_rsa_privatekey_from_file(filepath, password) - -def import_rsakey_from_pem(pem, scheme='rsassa-pss-sha256'): - return securesystemslib.keys.import_rsakey_from_pem(pem, scheme) - -def generate_and_write_ecdsa_keypair(filepath=None, password=None): - return securesystemslib.interface.generate_and_write_ecdsa_keypair( - filepath, password) - -def generate_ecdsa_key(scheme='ecdsa-sha2-nistp256'): - return securesystemslib.keys.generate_ecdsa_key(scheme) - -def import_ecdsa_privatekey_from_file(filepath, password=None): - return securesystemslib.interface.import_ecdsa_privatekey_from_file( - filepath, password) - -def import_ecdsa_publickey_from_file(filepath): - return securesystemslib.interface.import_ecdsa_publickey_from_file(filepath) - -def import_ecdsakey_from_pem(pem, scheme='ecdsa-sha2-nistp256'): - return securesystemslib.keys.import_ecdsakey_from_pem(pem, scheme) - -def create_tuf_client_directory(repository_directory, client_directory): - return repo_lib.create_tuf_client_directory( - repository_directory, client_directory) - -def disable_console_log_messages(): - return repo_lib.disable_console_log_messages()