From 7f0f3b7d2b3640bfa041768a2ad1dc1007b96725 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Thu, 3 Nov 2016 18:20:03 -0400 Subject: Add keystore attribute tests; add wrapper for Python crypto. New test class to thrash the keystore attribute mechanism. Added wrapper classes to encapsulate the more obscure bits of the multiple Python public key APIs we're using in a single uniform API, which lets us simplify some of the tests considerably. --- unit-tests.py | 194 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 81 deletions(-) diff --git a/unit-tests.py b/unit-tests.py index cee3202..7074c6d 100644 --- a/unit-tests.py +++ b/unit-tests.py @@ -73,7 +73,6 @@ def log(msg): def main(): - preload_public_keys() from sys import argv global args args = parse_arguments(argv[1:]) @@ -298,19 +297,19 @@ class TestPKeyHashing(TestCaseLoggedIn): def load_sign_verify_rsa(self, alg, keylen, method): k1 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, - static_keys[HAL_KEY_TYPE_RSA_PRIVATE, keylen].exportKey("DER")) + PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, keylen].der) self.addCleanup(k1.delete) k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, - static_keys[HAL_KEY_TYPE_RSA_PUBLIC, keylen].exportKey("DER")) + PreloadedKey.db[HAL_KEY_TYPE_RSA_PUBLIC, keylen].der) self.addCleanup(k2.delete) method(alg, k1, k2) def load_sign_verify_ecdsa(self, alg, curve, method): k1 = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, curve, - static_keys[HAL_KEY_TYPE_EC_PRIVATE, curve].to_der()) + PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, curve].der) self.addCleanup(k1.delete) k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve, - static_keys[HAL_KEY_TYPE_EC_PUBLIC, curve].to_der()) + PreloadedKey.db[HAL_KEY_TYPE_EC_PUBLIC, curve].der) self.addCleanup(k2.delete) method(alg, k1, k2) @@ -437,6 +436,7 @@ class TestPKeyHashing(TestCaseLoggedIn): self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_local_local) +@unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package") class TestPKeyRSAInterop(TestCaseLoggedIn): @staticmethod @@ -447,21 +447,19 @@ class TestPKeyRSAInterop(TestCaseLoggedIn): def load_sign_verify_rsa(self, alg, pyhash, keylen): hamster = "Your mother was a hamster" - sk = static_keys[HAL_KEY_TYPE_RSA_PRIVATE, keylen] - vk = static_keys[HAL_KEY_TYPE_RSA_PUBLIC, keylen] - k1 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, sk.exportKey("DER")) + sk = PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, keylen] + vk = PreloadedKey.db[HAL_KEY_TYPE_RSA_PUBLIC, keylen] + k1 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, sk.der) self.addCleanup(k1.delete) - k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, vk.exportKey("DER")) + k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, vk.der) self.addCleanup(k2.delete) - sk = PKCS1_v1_5.PKCS115_SigScheme(sk) - vk = PKCS1_v1_5.PKCS115_SigScheme(vk) sig1 = k1.sign(hash = self.h(alg, hamster)) - sig2 = sk.sign(pyhash(hamster)) + sig2 = sk.sign(hamster, pyhash) self.assertEqual(sig1, sig2) k1.verify(signature = sig2, hash = self.h(alg, hamster)) k2.verify(signature = sig2, hash = self.h(alg, hamster)) - sk.verify(pyhash(hamster), sig1) - vk.verify(pyhash(hamster), sig1) + sk.verify(hamster, pyhash, sig1) + vk.verify(hamster, pyhash, sig1) def test_interop_rsa_1024_sha256(self): self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, SHA256, 1024) @@ -473,6 +471,7 @@ class TestPKeyRSAInterop(TestCaseLoggedIn): self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, SHA512, 4096) +@unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package") class TestPKeyECDSAInterop(TestCaseLoggedIn): @staticmethod @@ -481,28 +480,28 @@ class TestPKeyECDSAInterop(TestCaseLoggedIn): h.update(text) return h - def load_sign_verify_ecdsa(self, alg, curve): + def load_sign_verify_ecdsa(self, alg, pyhash, curve): hamster = "Your mother was a hamster" - sk = static_keys[HAL_KEY_TYPE_EC_PRIVATE, curve] - vk = static_keys[HAL_KEY_TYPE_EC_PUBLIC, curve] - k1 = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, curve, sk.to_der()) + sk = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, curve] + vk = PreloadedKey.db[HAL_KEY_TYPE_EC_PUBLIC, curve] + k1 = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, curve, sk.der) self.addCleanup(k1.delete) - k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve, vk.to_der()) + k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve, vk.der) self.addCleanup(k2.delete) sig1 = k1.sign(hash = self.h(alg, hamster)) - sig2 = sk.sign(hamster) + sig2 = sk.sign(hamster, pyhash) k1.verify(signature = sig2, hash = self.h(alg, hamster)) k2.verify(signature = sig2, hash = self.h(alg, hamster)) - vk.verify(sig1, hamster) + vk.verify(hamster, pyhash, sig1) def test_interop_ecdsa_p256_sha256(self): - self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256) + self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, SHA256, HAL_CURVE_P256) def test_interop_ecdsa_p384_sha384(self): - self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384) + self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, SHA384, HAL_CURVE_P384) def test_interop_ecdsa_p521_sha512(self): - self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521) + self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, SHA512, HAL_CURVE_P521) class TestPKeyList(TestCaseLoggedIn): @@ -511,22 +510,12 @@ class TestPKeyList(TestCaseLoggedIn): """ def load_keys(self, flags): - for keytype, curve in static_keys: - obj = static_keys[keytype, curve] - atr = (str(keytype), str(curve)) - if keytype in (HAL_KEY_TYPE_RSA_PRIVATE, HAL_KEY_TYPE_RSA_PUBLIC): - curve = HAL_CURVE_NONE - der = obj.exportKey("DER") - elif keytype in (HAL_KEY_TYPE_EC_PRIVATE, HAL_KEY_TYPE_EC_PUBLIC): - der = obj.to_der() - else: - raise ValueError - k = hsm.pkey_load(keytype, curve, der, flags) - self.addCleanup(lambda uuid: hsm.pkey_find(uuid, flags = flags).delete(), - k.uuid) - for i, a in enumerate(atr): - k.set_attribute(i, a) - k.close() + for obj in PreloadedKey.db.itervalues(): + with hsm.pkey_load(obj.keytype, obj.curve, obj.der, flags) as k: + self.addCleanup(lambda uuid: hsm.pkey_find(uuid, flags = flags).delete(), + k.uuid) + for i, a in enumerate((str(obj.keytype), str(obj.fn2))): + k.set_attribute(i, a) def ks_list(self, flags): self.load_keys(flags) @@ -549,7 +538,7 @@ class TestPKeyList(TestCaseLoggedIn): tags = [] for i in xrange(2): self.load_keys(flags) - tags.extend(static_keys) + tags.extend(PreloadedKey.db) uuids = set() for n, k in self.match(flags = flags): @@ -588,6 +577,29 @@ class TestPKeyList(TestCaseLoggedIn): def test_ks_match_volatile(self): self.ks_match(0) + +class TestPKeyAttribute(TestCaseLoggedIn): + """ + Attribute creation/lookup/deletion tests. + """ + + def load_and_fill(self, flags, n_keys = 1, n_attrs = 2): + for i in xrange(n_keys): + for obj in PreloadedKey.db.itervalues(): + with hsm.pkey_load(obj.keytype, obj.curve, obj.der, flags) as k: + self.addCleanup(lambda uuid: hsm.pkey_find(uuid, flags = flags).delete(), + k.uuid) + for j in xrange(n_attrs): + k.set_attribute(j, "Attribute {}".format(j)) + + def test_attribute_bloat_volatile(self): + self.load_and_fill(0, n_attrs = 192) + + def test_attribute_bloat_token(self): + self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128) + + +@unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package") class TestPkeyECDSAVerificationNIST(TestCaseLoggedIn): """ ECDSA verification tests based on Suite B Implementer's Guide to FIPS 186-3. @@ -633,34 +645,66 @@ class TestPkeyECDSAVerificationNIST(TestCaseLoggedIn): # # Preloaded keys should suffice for all of these. -if False: - class TestPKeyListMatch(TestCaseLoggedIn): - def test_pkey_list(self): - for flags in (0, HAL_KEY_FLAG_TOKEN): - hsm.pkey_list(flags = flags) - def test_pkey_match(self): - for f in (HAL_KEY_FLAG_TOKEN, 0): - hsm.pkey_match(flags = f) +class PreloadedKey(object): + """ + Keys for preload tests, here at the end because they're large. + For the moment, we use PKCS #1.5 format for RSA and secg format + for ECDSA, because those are the formats that everything + (including our own ASN.1 code) supports. Arguably, we should be + using PKCS #8 to get a single, consistent, self-identifying + private key format, but we're not there yet and it's not + particularly urgent given widespread availablity of conversion + tools (eg, "openssl pkcs8"). + """ -if False: - class TestPKeyAttribute(TestCaseLoggedIn): - pass + db = {} + def __init__(self, keytype, fn2, obj, der, keylen = None, curve = HAL_CURVE_NONE): + self.keytype = keytype + self.fn2 = fn2 + self.obj = obj + self.der = der + self.keylen = keylen + self.curve = curve + self.db[keytype, fn2] = self -# Keys for preload tests, here at the end because they're large. For -# the moment, we use PKCS #1.5 format for RSA and secg format for -# ECDSA, because those are the formats that everything (including our -# own ASN.1 code) supports. Arguably, we should be using PKCS #8 to -# get a single, consistent, self-identifying private key format, but -# we're not there yet and it's not particularly urgent given -# widespread availablity of conversion tools (eg, "openssl pkcs8"). +class PreloadedRSAKey(PreloadedKey): + + @classmethod + def importKey(cls, keylen, pem): + if pycrypto_loaded: + k1 = RSA.importKey(pem) + k2 = k1.publickey() + cls(HAL_KEY_TYPE_RSA_PRIVATE, keylen, k1, k1.exportKey("DER"), keylen = keylen) + cls(HAL_KEY_TYPE_RSA_PUBLIC, keylen, k2, k2.exportKey("DER"), keylen = keylen) + + def sign(self, text, hash): + return PKCS1_v1_5.PKCS115_SigScheme(self.obj).sign(hash(text)) + + def verify(self, text, hash, signature): + return PKCS1_v1_5.PKCS115_SigScheme(self.obj).verify(hash(text), signature) + +class PreloadedECKey(PreloadedKey): + + @classmethod + def importKey(cls, curve, pem): + if ecdsa_loaded: + k1 = ECDSA_SigningKey.from_pem(pem) + k2 = k1.get_verifying_key() + cls(HAL_KEY_TYPE_EC_PRIVATE, curve, k1, k1.to_der(), curve = curve) + cls(HAL_KEY_TYPE_EC_PUBLIC, curve, k2, k2.to_der(), curve = curve) + + def sign(self, text, hash): + return self.obj.sign(text, hashfunc = hash) + + def verify(self, text, hash, signature): + return self.obj.verify(signature, text, hashfunc = hash) -static_keys = {} # openssl genrsa 1024 -if pycrypto_loaded: static_keys[HAL_KEY_TYPE_RSA_PRIVATE, 1024] = RSA.importKey('''\ +PreloadedRSAKey.importKey(1024, '''\ -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQC95QlDOvlQhdCe/a7eIoX9SGPVfXfA8/62ilnF+NcwLrhxkr2R 4EVQB65+9AbxqM8Hqol6fhZzmDs48cl2tOFGJpE8iMhiFm4i6SGl2RXYaG0xi+lJ @@ -679,7 +723,7 @@ lsTSiPyQjc4dQQJxFduvWHLx28bx+l7FTav7FaKntCJo ''') # openssl genrsa 2048 -if pycrypto_loaded: static_keys[HAL_KEY_TYPE_RSA_PRIVATE, 2048] = RSA.importKey('''\ +PreloadedRSAKey.importKey(2048, '''\ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAsbvq6syhDXD/OMVAuLoMceGQLUIiezfShVqFfyMqADjqhFRW Wbonn0XV9ZkypU4Ib9n6PtLATNaefhpsUlI4s+20YTlQ7GiwJ9p97/N1o1u060ja @@ -710,7 +754,7 @@ EQfc0UFoFHyc3mYEKR4zHheqQG5OFBN89LqG3S+O69vc1qwCvNKL+Q== ''') # openssl genrsa 4096 -if pycrypto_loaded: static_keys[HAL_KEY_TYPE_RSA_PRIVATE, 4096] = RSA.importKey('''\ +PreloadedRSAKey.importKey(4096, '''\ -----BEGIN RSA PRIVATE KEY----- MIIJKAIBAAKCAgEAzWpYSQt+DrUNI+EJT/ko92wM2POfFnmm3Kc34nmuK6sez0DJ r9Vib9R5K46RNgqcUdAodjU6cy3/MZA53SqP7RwR/LQtWmK2a+T4iey2vQZ0iCDA @@ -765,26 +809,26 @@ dQYLBHIPcw6e0FdL3nTs44BpAqcK28N5eWbe/KaZ3EA0lHRmyOQ++WgU6jo= ''') # openssl ecparam -genkey -name prime256v1 | openssl ec -if ecdsa_loaded: static_keys[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256] = ECDSA_SigningKey.from_pem('''\ +PreloadedECKey.importKey(HAL_CURVE_P256, '''\ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIPBrVhD1iFF2e8wPkPf4N1038iR8xPgku/CVOT8lcSztoAoGCCqGSM49 AwEHoUQDQgAE3mB5BmN5Fa4fV74LsDWIpBUxktPqYGJ6WOBrjPs1HWkNU7JHO3qY 9yy+CXFSPb89GWQgb5wLtNPn4QYMj+KRTA== -----END EC PRIVATE KEY----- -''', SHA256) +''') # openssl ecparam -genkey -name secp384r1 | openssl ec -if ecdsa_loaded: static_keys[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P384] = ECDSA_SigningKey.from_pem('''\ +PreloadedECKey.importKey(HAL_CURVE_P384, '''\ -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDCVGo35Hbrf3Iys7mWRIm5yjg+6vPIgzbp2jCbDyszBo+wTxmQambG4 g8yocp4wM6+gBwYFK4EEACKhZANiAATYwa+M8T8jsNHKmMZTvPPflUIfrjuZZo1D 3kkkmN4r6cTNctjaeRdAfD0X40l4yPnGIP9ParuKVVl1y0TdQ7BS3g/Gj/LP33HD ESP8gFDIKFCWSDX0uhmy+HsGsPwgNoY= -----END EC PRIVATE KEY----- -''', SHA384) +''') # openssl ecparam -genkey -name secp521r1 | openssl ec -if ecdsa_loaded: static_keys[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P521] = ECDSA_SigningKey.from_pem('''\ +PreloadedECKey.importKey(HAL_CURVE_P521, '''\ -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBtf+LKhJNQEJRFQ2cGQPcviwfp9IKSnD5EFTqAPtv7/+t2FtmdHHP /fWIlZ7jcC5N9dWy6bKGu3+FqwgZAYLpsqigBwYFK4EEACOhgYkDgYYABADdfcUe @@ -792,19 +836,7 @@ P0oAZQ5308v5ijcg4hePvhvVi+QKcrwmE9kirXCFoYN1tzPmXZmw8lNJenrbwaNz opJR84LBHnomGPogAQGF0aRk0jE8w1j1oMfrrzV6vCWnkh7pyzsDnrLU1HrkWeqw ihzwMzYJgFzToDH+fCh7nrBFZZZ9P9gPYMlSM5UMeA== -----END EC PRIVATE KEY----- -''', SHA512) - -# Public key objects corresponding to the private key objects above. - -def preload_public_keys(): - for keytag, k in static_keys.items(): - keytype, len_or_curve = keytag - if keytype == HAL_KEY_TYPE_RSA_PRIVATE: - static_keys[HAL_KEY_TYPE_RSA_PUBLIC, len_or_curve] = k.publickey() - elif keytype == HAL_KEY_TYPE_EC_PRIVATE: - static_keys[HAL_KEY_TYPE_EC_PUBLIC, len_or_curve] = k.get_verifying_key() - else: - raise TypeError +''') if __name__ == "__main__": -- cgit v1.2.3