mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Add test_formats_rsakey_from_pem() test case and test conditions for improperly formatted PEM. Add test condition to verify trailing whitespace is removed and matches the expected PEM format generated internally. Public PEMs generated externally (with the expected trailing newline) was not previously considered.
287 lines
9.8 KiB
Python
Executable file
287 lines
9.8 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
"""
|
|
<Program Name>
|
|
test_keys.py
|
|
|
|
<Author>
|
|
Vladimir Diaz
|
|
|
|
<Started>
|
|
October 10, 2013.
|
|
|
|
<Copyright>
|
|
See LICENSE for licensing information.
|
|
|
|
<Purpose>
|
|
Test cases for test_keys.py.
|
|
TODO: test case for ed25519 key generation and refactor.
|
|
"""
|
|
|
|
# Help with Python 3 compatibility, where the print statement is a function, an
|
|
# implicit relative import is invalid, and the '/' operator performs true
|
|
# division. Example: print 'hello world' raises a 'SyntaxError' exception.
|
|
from __future__ import print_function
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import unittest
|
|
import logging
|
|
|
|
import tuf
|
|
import tuf.log
|
|
import tuf.formats
|
|
import tuf.keys
|
|
|
|
logger = logging.getLogger('tuf.test_keys')
|
|
|
|
KEYS = tuf.keys
|
|
FORMAT_ERROR_MSG = 'tuf.FormatError was raised! Check object\'s format.'
|
|
DATA = 'SOME DATA REQUIRING AUTHENTICITY.'
|
|
|
|
|
|
|
|
class TestKeys(unittest.TestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.rsakey_dict = KEYS.generate_rsa_key()
|
|
cls.ed25519key_dict = KEYS.generate_ed25519_key()
|
|
|
|
|
|
def test_generate_rsa_key(self):
|
|
_rsakey_dict = KEYS.generate_rsa_key()
|
|
|
|
# Check if the format of the object returned by generate() corresponds
|
|
# to RSAKEY_SCHEMA format.
|
|
self.assertEqual(None, tuf.formats.RSAKEY_SCHEMA.check_match(_rsakey_dict),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
# Passing a bit value that is <2048 to generate() - should raise
|
|
# 'tuf.FormatError'.
|
|
self.assertRaises(tuf.FormatError, KEYS.generate_rsa_key, 555)
|
|
|
|
# Passing a string instead of integer for a bit value.
|
|
self.assertRaises(tuf.FormatError, KEYS.generate_rsa_key, 'bits')
|
|
|
|
# NOTE if random bit value >=2048 (not 4096) is passed generate(bits)
|
|
# does not raise any errors and returns a valid key.
|
|
self.assertTrue(tuf.formats.RSAKEY_SCHEMA.matches(KEYS.generate_rsa_key(2048)))
|
|
self.assertTrue(tuf.formats.RSAKEY_SCHEMA.matches(KEYS.generate_rsa_key(4096)))
|
|
|
|
|
|
|
|
def test_format_keyval_to_metadata(self):
|
|
keyvalue = self.rsakey_dict['keyval']
|
|
keytype = self.rsakey_dict['keytype']
|
|
key_meta = KEYS.format_keyval_to_metadata(keytype, keyvalue)
|
|
|
|
# Check if the format of the object returned by this function corresponds
|
|
# to KEY_SCHEMA format.
|
|
self.assertEqual(None,
|
|
tuf.formats.KEY_SCHEMA.check_match(key_meta),
|
|
FORMAT_ERROR_MSG)
|
|
key_meta = KEYS.format_keyval_to_metadata(keytype, keyvalue, private=True)
|
|
|
|
# Check if the format of the object returned by this function corresponds
|
|
# to KEY_SCHEMA format.
|
|
self.assertEqual(None, tuf.formats.KEY_SCHEMA.check_match(key_meta),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
# Supplying a 'bad' keyvalue.
|
|
self.assertRaises(tuf.FormatError, KEYS.format_keyval_to_metadata,
|
|
'bad_keytype', keyvalue)
|
|
|
|
public = keyvalue['public']
|
|
del keyvalue['public']
|
|
self.assertRaises(tuf.FormatError, KEYS.format_keyval_to_metadata,
|
|
keytype, keyvalue)
|
|
keyvalue['public'] = public
|
|
|
|
|
|
|
|
def test_format_rsakey_from_pem(self):
|
|
pem = self.rsakey_dict['keyval']['public']
|
|
rsa_key = KEYS.format_rsakey_from_pem(pem)
|
|
|
|
# Check if the format of the object returned by this function corresponds
|
|
# to 'tuf.formats.RSAKEY_SCHEMA' format.
|
|
self.assertTrue(tuf.formats.RSAKEY_SCHEMA.matches(rsa_key))
|
|
|
|
# Verify whitespace is stripped.
|
|
self.assertEqual(rsa_key, KEYS.format_rsakey_from_pem(pem + '\n'))
|
|
|
|
# Supplying a 'bad_pem' argument.
|
|
self.assertRaises(tuf.FormatError, KEYS.format_rsakey_from_pem, 'bad_pem')
|
|
|
|
# Supplying an improperly formatted PEM.
|
|
# Strip the PEM header and footer.
|
|
pem_header = '-----BEGIN PUBLIC KEY-----'
|
|
pem_footer= '-----END PUBLIC KEY-----'
|
|
self.assertRaises(tuf.FormatError, KEYS.format_rsakey_from_pem,
|
|
pem[:len(pem_footer)])
|
|
self.assertRaises(tuf.FormatError, KEYS.format_rsakey_from_pem,
|
|
pem[len(pem_header):])
|
|
|
|
|
|
|
|
def test_format_metadata_to_key(self):
|
|
# Reconfiguring rsakey_dict to conform to KEY_SCHEMA
|
|
# i.e. {keytype: 'rsa', keyval: {public: pub_key, private: priv_key}}
|
|
keyid = self.rsakey_dict['keyid']
|
|
del self.rsakey_dict['keyid']
|
|
|
|
rsakey_dict_from_meta = KEYS.format_metadata_to_key(self.rsakey_dict)
|
|
|
|
# Check if the format of the object returned by this function corresponds
|
|
# to RSAKEY_SCHEMA format.
|
|
self.assertEqual(None,
|
|
tuf.formats.RSAKEY_SCHEMA.check_match(rsakey_dict_from_meta),
|
|
FORMAT_ERROR_MSG)
|
|
self.rsakey_dict['keyid'] = keyid
|
|
|
|
# Supplying a wrong number of arguments.
|
|
self.assertRaises(TypeError, KEYS.format_metadata_to_key)
|
|
args = (self.rsakey_dict, self.rsakey_dict)
|
|
self.assertRaises(TypeError, KEYS.format_metadata_to_key, *args)
|
|
|
|
# Supplying a malformed argument to the function - should get FormatError
|
|
keyval = self.rsakey_dict['keyval']
|
|
del self.rsakey_dict['keyval']
|
|
self.assertRaises(tuf.FormatError, KEYS.format_metadata_to_key,
|
|
self.rsakey_dict)
|
|
self.rsakey_dict['keyval'] = keyval
|
|
|
|
|
|
|
|
def test_helper_get_keyid(self):
|
|
keytype = self.rsakey_dict['keytype']
|
|
keyvalue = self.rsakey_dict['keyval']
|
|
|
|
# Check format of 'keytype'.
|
|
self.assertEqual(None, tuf.formats.KEYTYPE_SCHEMA.check_match(keytype),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
# Check format of 'keyvalue'.
|
|
self.assertEqual(None, tuf.formats.KEYVAL_SCHEMA.check_match(keyvalue),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
keyid = KEYS._get_keyid(keytype, keyvalue)
|
|
|
|
# Check format of 'keyid' - the output of '_get_keyid()' function.
|
|
self.assertEqual(None, tuf.formats.KEYID_SCHEMA.check_match(keyid),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
|
|
def test_create_signature(self):
|
|
# Creating a signature for 'DATA'.
|
|
rsa_signature = KEYS.create_signature(self.rsakey_dict, DATA)
|
|
ed25519_signature = KEYS.create_signature(self.ed25519key_dict, DATA)
|
|
|
|
# Check format of output.
|
|
self.assertEqual(None,
|
|
tuf.formats.SIGNATURE_SCHEMA.check_match(rsa_signature),
|
|
FORMAT_ERROR_MSG)
|
|
self.assertEqual(None,
|
|
tuf.formats.SIGNATURE_SCHEMA.check_match(ed25519_signature),
|
|
FORMAT_ERROR_MSG)
|
|
|
|
# Removing private key from 'rsakey_dict' - should raise a TypeError.
|
|
private = self.rsakey_dict['keyval']['private']
|
|
self.rsakey_dict['keyval']['private'] = ''
|
|
|
|
args = (self.rsakey_dict, DATA)
|
|
self.assertRaises(TypeError, KEYS.create_signature, *args)
|
|
|
|
# Supplying an incorrect number of arguments.
|
|
self.assertRaises(TypeError, KEYS.create_signature)
|
|
self.rsakey_dict['keyval']['private'] = private
|
|
|
|
|
|
|
|
def test_verify_signature(self):
|
|
# Creating a signature of 'DATA' to be verified.
|
|
rsa_signature = KEYS.create_signature(self.rsakey_dict, DATA)
|
|
ed25519_signature = KEYS.create_signature(self.ed25519key_dict, DATA)
|
|
|
|
# Verifying the 'signature' of 'DATA'.
|
|
verified = KEYS.verify_signature(self.rsakey_dict, rsa_signature, DATA)
|
|
self.assertTrue(verified, "Incorrect signature.")
|
|
|
|
# Verifying the 'ed25519_signature' of 'DATA'.
|
|
verified = KEYS.verify_signature(self.ed25519key_dict, ed25519_signature, DATA)
|
|
self.assertTrue(verified, "Incorrect signature.")
|
|
|
|
# Testing an invalid 'rsa_signature'. Same 'rsa_signature' is passed, with
|
|
# 'DATA' different than the original 'DATA' that was used
|
|
# in creating the 'rsa_signature'. Function should return 'False'.
|
|
|
|
# Modifying 'DATA'.
|
|
_DATA = '1111' + DATA + '1111'
|
|
|
|
# Verifying the 'signature' of modified '_DATA'.
|
|
verified = KEYS.verify_signature(self.rsakey_dict, rsa_signature, _DATA)
|
|
self.assertFalse(verified,
|
|
'Returned \'True\' on an incorrect signature.')
|
|
|
|
# Modifying 'signature' to pass an incorrect method since only
|
|
# 'PyCrypto-PKCS#1 PSS' is accepted.
|
|
rsa_signature['method'] = 'Biff'
|
|
|
|
args = (self.rsakey_dict, rsa_signature, DATA)
|
|
self.assertRaises(tuf.UnknownMethodError, KEYS.verify_signature, *args)
|
|
|
|
# Passing incorrect number of arguments.
|
|
self.assertRaises(TypeError, KEYS.verify_signature)
|
|
|
|
|
|
|
|
def test_create_rsa_encrypted_pem(self):
|
|
# Test valid arguments.
|
|
private = self.rsakey_dict['keyval']['private']
|
|
passphrase = 'secret'
|
|
encrypted_pem = KEYS.create_rsa_encrypted_pem(private, passphrase)
|
|
self.assertTrue(tuf.formats.PEMRSA_SCHEMA.matches(encrypted_pem))
|
|
|
|
# Test improperly formatted arguments.
|
|
self.assertRaises(tuf.FormatError, KEYS.create_rsa_encrypted_pem,
|
|
8, passphrase)
|
|
|
|
self.assertRaises(tuf.FormatError, KEYS.create_rsa_encrypted_pem,
|
|
private, 8)
|
|
|
|
# Test for missing required library.
|
|
KEYS._RSA_CRYPTO_LIBRARY = 'invalid'
|
|
self.assertRaises(tuf.UnsupportedLibraryError, KEYS.create_rsa_encrypted_pem,
|
|
private, passphrase)
|
|
KEYS._RSA_CRYPTO_LIBRARY = 'pycrypto'
|
|
|
|
|
|
|
|
def test_decrypt_key(self):
|
|
# Test valid arguments.
|
|
passphrase = 'secret'
|
|
encrypted_key = KEYS.encrypt_key(self.rsakey_dict, passphrase).encode('utf-8')
|
|
decrypted_key = KEYS.decrypt_key(encrypted_key, passphrase)
|
|
|
|
self.assertTrue(tuf.formats.ANYKEY_SCHEMA.matches(decrypted_key))
|
|
|
|
# Test improperly formatted arguments.
|
|
self.assertRaises(tuf.FormatError, KEYS.decrypt_key,
|
|
8, passphrase)
|
|
|
|
self.assertRaises(tuf.FormatError, KEYS.decrypt_key,
|
|
encrypted_key, 8)
|
|
|
|
# Test for missing required library.
|
|
KEYS._GENERAL_CRYPTO_LIBRARY = 'invalid'
|
|
self.assertRaises(tuf.UnsupportedLibraryError, KEYS.decrypt_key,
|
|
encrypted_key, passphrase)
|
|
KEYS._GENERAL_CRYPTO_LIBRARY = 'pycrypto'
|
|
|
|
|
|
|
|
# Run the unit tests.
|
|
if __name__ == '__main__':
|
|
unittest.main()
|