def test_generate_and_write_ecdsa_keypair(self): # Test normal case. temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) test_keypath = os.path.join(temporary_directory, 'ecdsa_key') returned_path = interface.generate_and_write_ecdsa_keypair( test_keypath, password='******') self.assertTrue(os.path.exists(test_keypath)) self.assertTrue(os.path.exists(test_keypath + '.pub')) self.assertEqual(returned_path, test_keypath) # Ensure the generated key files are importable. imported_pubkey = \ interface.import_ecdsa_publickey_from_file(test_keypath + '.pub') self.assertTrue( securesystemslib.formats.ECDSAKEY_SCHEMA.matches(imported_pubkey)) imported_privkey = \ interface.import_ecdsa_privatekey_from_file(test_keypath, 'pw') self.assertTrue( securesystemslib.formats.ECDSAKEY_SCHEMA.matches(imported_privkey)) # Test for a default filepath. If 'filepath' is not given, the key's # KEYID is used as the filename. The key is saved to the current working # directory. default_keypath = interface.generate_and_write_ecdsa_keypair( password='******') self.assertTrue(os.path.exists(default_keypath)) self.assertTrue(os.path.exists(default_keypath + '.pub')) written_key = interface.import_ecdsa_publickey_from_file( default_keypath + '.pub') self.assertEqual(written_key['keyid'], os.path.basename(default_keypath)) os.remove(default_keypath) os.remove(default_keypath + '.pub') # Test improperly formatted arguments. self.assertRaises(securesystemslib.exceptions.FormatError, interface.generate_and_write_ecdsa_keypair, 3, password='******') self.assertRaises(securesystemslib.exceptions.FormatError, interface.generate_and_write_ecdsa_keypair, test_keypath, password=3)
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, 'ecdsa_key') interface.generate_and_write_ecdsa_keypair(test_keypath, password='******') self.assertTrue(os.path.exists(test_keypath)) self.assertTrue(os.path.exists(test_keypath + '.pub')) # Ensure the generated key files are importable. imported_pubkey = \ interface.import_ecdsa_publickey_from_file(test_keypath + '.pub') self.assertTrue(securesystemslib.formats.ECDSAKEY_SCHEMA.matches(imported_pubkey)) imported_privkey = \ interface.import_ecdsa_privatekey_from_file(test_keypath, 'pw') self.assertTrue(securesystemslib.formats.ECDSAKEY_SCHEMA.matches(imported_privkey)) # Test improperly formatted arguments. self.assertRaises(securesystemslib.exceptions.FormatError, interface.generate_and_write_ecdsa_keypair, 3, password='******') self.assertRaises(securesystemslib.exceptions.FormatError, interface.generate_and_write_ecdsa_keypair, test_keypath, password=3)
def test_import_ecdsa_publickey_from_file(self): # Test normal case. # Generate ecdsa keys that can be imported. temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory) ecdsa_keypath = os.path.join(temporary_directory, 'ecdsa_key') interface.generate_and_write_ecdsa_keypair(ecdsa_keypath, password='******') imported_ecdsa_key = \ interface.import_ecdsa_publickey_from_file(ecdsa_keypath + '.pub') self.assertTrue( securesystemslib.formats.ECDSAKEY_SCHEMA.matches( imported_ecdsa_key)) # Test improperly formatted argument. self.assertRaises(securesystemslib.exceptions.FormatError, interface.import_ecdsa_publickey_from_file, 3) # Test invalid argument. # Non-existent key file. nonexistent_keypath = os.path.join(temporary_directory, 'nonexistent_keypath') self.assertRaises(securesystemslib.exceptions.StorageError, interface.import_ecdsa_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, interface.import_ecdsa_publickey_from_file, invalid_keyfile) # Invalid public key imported (contains unexpected keytype.) keytype = imported_ecdsa_key['keytype'] keyval = imported_ecdsa_key['keyval'] scheme = imported_ecdsa_key['scheme'] ecdsakey_metadata_format = \ securesystemslib.keys.format_keyval_to_metadata(keytype, scheme, keyval, private=False) ecdsakey_metadata_format['keytype'] = 'invalid_keytype' with open(ecdsa_keypath + '.pub', 'wb') as file_object: file_object.write( json.dumps(ecdsakey_metadata_format).encode('utf-8')) self.assertRaises(securesystemslib.exceptions.FormatError, interface.import_ecdsa_publickey_from_file, ecdsa_keypath + '.pub')
def create_and_set_keys(keystore_dir, repo_obj): for rolename in ('root', 'timestamp', 'snapshot', 'targets'): passphrase = os.environ.get('{}_PASSPHRASE'.format(rolename.upper())) if not passphrase: passphrase = get_password( prompt='Enter password for {}: '.format(rolename), confirm=True) private_keypath = str(get_private_keypath(keystore_dir, rolename)) public_keypath = get_public_keypath(private_keypath) generate_and_write_ecdsa_keypair(private_keypath, password=passphrase) private = import_ecdsa_privatekey_from_file(private_keypath, passphrase) public = import_ecdsa_publickey_from_file(public_keypath) role_obj = getattr(repo_obj, rolename) role_obj.load_signing_key(private) role_obj.add_verification_key(public)
def test_ecdsa(self): """Test ecdsa key _generation and import interface functions. """ # TEST: Generate default keys and import # Assert location and format fn_default = "default" fn_default_ret = _generate_and_write_ecdsa_keypair(filepath=fn_default) pub = import_ecdsa_publickey_from_file(fn_default + ".pub") priv = import_ecdsa_privatekey_from_file(fn_default) self.assertEqual(fn_default, fn_default_ret) self.assertTrue(ECDSAKEY_SCHEMA.matches(pub)) self.assertTrue(PUBLIC_KEY_SCHEMA.matches(pub)) self.assertTrue(ECDSAKEY_SCHEMA.matches(priv)) # NOTE: There is no private key schema, at least check it has a value self.assertTrue(priv["keyval"]["private"]) # TEST: Generate unencrypted keys with empty prompt # Assert importable with empty prompt password and without password fn_empty_prompt = "empty_prompt" with mock.patch("securesystemslib.interface.get_password", return_value=""): _generate_and_write_ecdsa_keypair(filepath=fn_empty_prompt) import_ecdsa_privatekey_from_file(fn_empty_prompt, prompt=True) import_ecdsa_privatekey_from_file(fn_empty_prompt) # TEST: Generate keys with auto-filename, i.e. keyid # Assert filename is keyid fn_keyid = _generate_and_write_ecdsa_keypair() pub = import_ecdsa_publickey_from_file(fn_keyid + ".pub") priv = import_ecdsa_privatekey_from_file(fn_keyid) self.assertTrue( os.path.basename(fn_keyid) == pub["keyid"] == priv["keyid"]) # TEST: Generate two key pairs with encrypted private keys using ... pw = "pw" fn_encrypted = "encrypted" fn_prompt = "prompt" # ... a passed pw ... _generate_and_write_ecdsa_keypair(filepath=fn_encrypted, password=pw) with mock.patch("securesystemslib.interface.get_password", return_value=pw): # ... and a prompted pw. _generate_and_write_ecdsa_keypair(filepath=fn_prompt, prompt=True) # Assert that both private keys are importable using the prompted pw ... import_ecdsa_privatekey_from_file(fn_prompt, prompt=True) import_ecdsa_privatekey_from_file(fn_encrypted, prompt=True) # ... and the passed pw. import_ecdsa_privatekey_from_file(fn_prompt, password=pw) import_ecdsa_privatekey_from_file(fn_encrypted, password=pw) # TEST: Import existing keys with encrypted private key (test regression) # Assert format pub = import_ecdsa_publickey_from_file(self.path_ecdsa + ".pub") priv = import_ecdsa_privatekey_from_file(self.path_ecdsa, "password") self.assertTrue(ECDSAKEY_SCHEMA.matches(pub)) self.assertTrue(PUBLIC_KEY_SCHEMA.matches(pub)) self.assertTrue(ECDSAKEY_SCHEMA.matches(priv)) # NOTE: There is no private key schema, at least check it has a value self.assertTrue(priv["keyval"]["private"]) # FIXME: Should 'import_ecdsa_publickey_from_file' be able to import a # an ed25519 public key? I think it should not, but it is: import_ecdsa_publickey_from_file(self.path_ed25519 + ".pub") self.assertTrue(ECDSAKEY_SCHEMA.matches(pub)) # TEST: Generation errors for idx, (kwargs, err_msg) in enumerate([ # Error on empty password ({ "password": "" }, "encryption password must be 1 or more characters long"), # Error on 'password' and 'prompt=True' ({ "password": pw, "prompt": True }, "passing 'password' and 'prompt=True' is not allowed") ]): with self.assertRaises(ValueError, msg="(row {})".format(idx)) as ctx: _generate_and_write_ecdsa_keypair(**kwargs) self.assertEqual( err_msg, str(ctx.exception), "expected: '{}' got: '{}' (row {})".format( err_msg, ctx.exception, idx)) # Error on bad argument format for idx, kwargs in enumerate([ { "filepath": 123456 }, # Not a string { "password": 123456 }, # Not a string { "prompt": "not-a-bool" } ]): with self.assertRaises(FormatError, msg="(row {})".format(idx)): _generate_and_write_ecdsa_keypair(**kwargs) # TEST: Import errors # Error on public key import... for idx, (fn, err_msg) in enumerate([ # Error on invalid json (custom key format) (fn_encrypted, "Cannot deserialize to a Python object"), # Error on invalid custom key format (self.path_no_key, "Missing key") ]): with self.assertRaises(Error, msg="(row {})".format(idx)) as ctx: import_ecdsa_publickey_from_file(fn) self.assertTrue( err_msg in str(ctx.exception), "expected: '{}' got: '{}' (row {})".format( err_msg, ctx.exception, idx)) # Error on private key import... for idx, (args, kwargs, err, err_msg) in enumerate([ # Error on not an ecdsa private key ([self.path_ed25519], {}, Error, "Cannot deserialize to a Python object"), # Error on not encrypted ([fn_default], { "password": pw }, CryptoError, "Invalid encrypted file."), # Error on encrypted but no pw ([fn_encrypted], {}, Error, "Cannot deserialize to a Python object" ), # Error on encrypted but empty pw ([fn_encrypted], { "password": "" }, CryptoError, "Decryption failed."), # Error on encrypted but bad pw passed ([fn_encrypted], { "password": "******" }, CryptoError, "Decryption failed."), # Error on pw and prompt ([fn_default], { "password": pw, "prompt": True }, ValueError, "passing 'password' and 'prompt=True' is not allowed") ]): with self.assertRaises(err, msg="(row {})".format(idx)) as ctx: import_ecdsa_privatekey_from_file(*args, **kwargs) self.assertTrue( err_msg in str(ctx.exception), "expected: '{}' got: '{}' (row {})".format( err_msg, ctx.exception, idx)) # Error on encrypted but bad pw prompted err_msg = ("Decryption failed") with self.assertRaises(CryptoError) as ctx, mock.patch( "securesystemslib.interface.get_password", return_value="bad_pw"): import_ecdsa_privatekey_from_file(fn_encrypted, prompt=True) self.assertTrue( err_msg in str(ctx.exception), "expected: '{}' got: '{}'".format(err_msg, ctx.exception)) # Error on bad path format with self.assertRaises(FormatError): import_ecdsa_publickey_from_file(123456) with self.assertRaises(FormatError): import_ecdsa_privatekey_from_file(123456) # Error on bad password format with self.assertRaises(FormatError): # bad password import_ecdsa_privatekey_from_file(fn_default, password=123456) # Error on bad prompt format with self.assertRaises(FormatError): import_ecdsa_privatekey_from_file(fn_default, prompt="not-a-bool")