From 59f024487e0bcaedb773fd4066b2f95c733278c6 Mon Sep 17 00:00:00 2001 From: Milan Kubik Date: Thu, 12 Mar 2015 16:52:33 +0100 Subject: ipatests: port of p11helper test from github Ported the github hosted [1] script to use pytest's abilities and included it in ipatests/test_ipapython directory. [1]: https://github.com/spacekpe/freeipa-pkcs11/blob/master/python/run.py https://fedorahosted.org/freeipa/ticket/4829 Signed-off-by: Martin Basti Reviewed-By: Martin Basti --- ipatests/test_ipapython/test_ipap11helper.py | 276 +++++++++++++++++++++++++++ make-lint | 2 +- 2 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 ipatests/test_ipapython/test_ipap11helper.py diff --git a/ipatests/test_ipapython/test_ipap11helper.py b/ipatests/test_ipapython/test_ipap11helper.py new file mode 100644 index 000000000..32e87503d --- /dev/null +++ b/ipatests/test_ipapython/test_ipap11helper.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 FreeIPA Contributors see COPYING for license +# +""" +Test the `ipapython/ipap11helper/p11helper.c` module. +""" + + +from binascii import hexlify +import os +import os.path +import logging +import subprocess +import tempfile + +import pytest +from ipaplatform.paths import paths + +import _ipap11helper + + +CONFIG_DATA = """ +# SoftHSM v2 configuration file +directories.tokendir = %s/tokens +objectstore.backend = file +""" + +LIBSOFTHSM = paths.LIBSOFTHSM2_SO +SOFTHSM2_UTIL = paths.SOFTHSM2_UTIL + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger('t') + + +master_key_label = u"master-ž" # random non-ascii character to test unicode +master_key_id = "m" +replica1_key_label = u"replica1" +replica1_key_id = "id1" +replica1_import_label = u"replica1-import" +replica1_import_id = "id1-import" +replica1_new_label = u"replica1-new-label-ž" +replica2_key_label = u"replica2" +replica2_key_id = "id2" +replica_non_existent_label = u"replica-nonexistent" + + +@pytest.fixture(scope="module") +def p11(request): + token_path = tempfile.mkdtemp(prefix='pytest_', suffix='_pkcs11') + os.chdir(token_path) + os.mkdir('tokens') + + with open('softhsm2.conf', 'w') as cfg: + cfg.write(CONFIG_DATA % token_path) + os.environ['SOFTHSM2_CONF'] = os.path.join(token_path, 'softhsm2.conf') + subprocess.check_call([SOFTHSM2_UTIL, '--init-token', '--slot', '0', + '--label', 'test', '--pin', '1234', '--so-pin', + '1234']) + + try: + p11 = _ipap11helper.P11_Helper(0, "1234", LIBSOFTHSM) + except _ipap11helper.Error: + pytest.fail('Failed to initialize the helper object.', pytrace=False) + + def fin(): + try: + p11.finalize() + except _ipap11helper.Error: + pytest.fail('Failed to finalize the helper object.', pytrace=False) + finally: + del os.environ['SOFTHSM2_CONF'] + + request.addfinalizer(fin) + + return p11 + + +class test_p11helper(object): + def test_generate_master_key(self, p11): + assert p11.generate_master_key(master_key_label, master_key_id, + key_length=16, cka_wrap=True, + cka_unwrap=True) + + def test_search_for_master_key(self, p11): + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id) + assert len(master_key) == 1, "The master key should exist." + + def test_generate_replica_key_pair(self, p11): + assert p11.generate_replica_key_pair(replica1_key_label, + replica1_key_id, + pub_cka_wrap=True, + priv_cka_unwrap=True) + + def test_find_key(self, p11): + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_key_label, cka_wrap=True) + assert len(rep1_pub) == 1, ("replica key pair has to contain " + "1 pub key instead of %s" % len(rep1_pub)) + + rep1_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica1_key_label, cka_unwrap=True) + assert len(rep1_priv) == 1, ("replica key pair has to contain 1 " + "private key instead of %s" % + len(rep1_priv)) + + def test_find_key_by_uri(self, p11): + rep1_pub = p11.find_keys(uri="pkcs11:object=replica1;objecttype=public") + assert len(rep1_pub) == 1, ("replica key pair has to contain 1 pub " + "key instead of %s" % len(rep1_pub)) + + def test_get_attribute_from_object(self, p11): + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_key_label, cka_wrap=True)[0] + + iswrap = p11.get_attribute(rep1_pub, _ipap11helper.CKA_WRAP) + assert iswrap is True, "replica public key has to have CKA_WRAP = TRUE" + + def test_generate_replica_keypair_with_extractable_private_key(self, p11): + assert p11.generate_replica_key_pair(replica2_key_label, + replica2_key_id, + pub_cka_wrap=True, + priv_cka_unwrap=True, + priv_cka_extractable=True) + + def test_find_key_on_nonexistent_key_pair(self, p11): + test_list = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica_non_existent_label) + assert len(test_list) == 0, ("list should be empty because label " + "'%s' should not exist" % + replica_non_existent_label) + + def test_export_import_of_public_key(self, p11): + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_key_label, cka_wrap=True)[0] + pub = p11.export_public_key(rep1_pub) + + log.debug("Exported public key %s", hexlify(pub)) + with open("public_key.asn1.der", "wb") as f: + f.write(pub) + + rep1_pub_import = p11.import_public_key(replica1_import_label, + replica1_import_id, + pub, + cka_wrap=True) + log.debug('imported replica 1 public key: %s', rep1_pub_import) + + # test public key import + rep1_modulus_orig = p11.get_attribute(rep1_pub, + _ipap11helper.CKA_MODULUS) + rep1_modulus_import = p11.get_attribute(rep1_pub_import, + _ipap11helper.CKA_MODULUS) + log.debug('rep1_modulus_orig = 0x%s', hexlify(rep1_modulus_orig)) + log.debug('rep1_modulus_import = 0x%s', hexlify(rep1_modulus_import)) + assert rep1_modulus_import == rep1_modulus_orig + + rep1_pub_exp_orig = p11.get_attribute( + rep1_pub, _ipap11helper.CKA_PUBLIC_EXPONENT) + rep1_pub_exp_import = p11.get_attribute( + rep1_pub_import, _ipap11helper.CKA_PUBLIC_EXPONENT) + log.debug('rep1_pub_exp_orig = 0x%s', hexlify(rep1_pub_exp_orig)) + log.debug('rep1_pub_exp_import = 0x%s', hexlify(rep1_pub_exp_import)) + assert rep1_pub_exp_import == rep1_pub_exp_orig + + def test_wrap_unwrap_key_by_master_key_with_AES(self, p11): + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id)[0] + rep2_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica2_key_label, cka_unwrap=True)[0] + + log.debug("wrapping dnssec priv key by master key") + wrapped_priv = p11.export_wrapped_key( + rep2_priv, master_key, _ipap11helper.MECH_AES_KEY_WRAP_PAD + ) + assert wrapped_priv + + log.debug("wrapped_dnssec priv key: %s", hexlify(wrapped_priv)) + with open("wrapped_priv.der", "wb") as f: + f.write(wrapped_priv) + + assert p11.import_wrapped_private_key( + u'test_import_wrapped_priv', + '1', + wrapped_priv, + master_key, + _ipap11helper.MECH_AES_KEY_WRAP_PAD, + _ipap11helper.KEY_TYPE_RSA + ) + + def test_wrap_unwrap_key_by_master_key_with_RSA_PKCS(self, p11): + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id)[0] + rep2_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica2_key_label, cka_wrap=True)[0] + rep2_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica2_key_label, cka_unwrap=True)[0] + + wrapped = p11.export_wrapped_key(master_key, + rep2_pub, + _ipap11helper.MECH_RSA_PKCS) + assert wrapped + + log.debug("wrapped key MECH_RSA_PKCS (secret master wrapped by pub " + "key): %s", hexlify(wrapped)) + assert p11.import_wrapped_secret_key(u'test_import_wrapped', + '2', + wrapped, + rep2_priv, + _ipap11helper.MECH_RSA_PKCS, + _ipap11helper.KEY_TYPE_AES) + + def test_wrap_unwrap_by_master_key_with_RSA_PKCS_OAEP(self, p11): + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id)[0] + rep2_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica2_key_label, cka_wrap=True)[0] + rep2_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica2_key_label, cka_unwrap=True)[0] + + wrapped = p11.export_wrapped_key(master_key, + rep2_pub, + _ipap11helper.MECH_RSA_PKCS_OAEP) + assert wrapped + + log.debug("wrapped key MECH_RSA_PKCS_OAEP (secret master wrapped by " + "pub key): %s", hexlify(wrapped)) + + assert p11.import_wrapped_secret_key(u'test_import_wrapped', + '3', + wrapped, + rep2_priv, + _ipap11helper.MECH_RSA_PKCS_OAEP, + _ipap11helper.KEY_TYPE_AES) + + def test_set_attribute_on_object(self, p11): + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_key_label, cka_wrap=True)[0] + test_label = replica1_new_label + + p11.set_attribute(rep1_pub, _ipap11helper.CKA_LABEL, test_label) + assert p11.get_attribute(rep1_pub, _ipap11helper.CKA_LABEL) \ + == test_label, "The labels do not match." + + def test_do_not_generate_identical_master_keys(self, p11): + with pytest.raises(_ipap11helper.DuplicationError): + p11.generate_master_key(master_key_label, master_key_id, + key_length=16) + + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label) + assert len(master_key) == 1, ("There shouldn't be multiple keys " + "with the same label.") + + def test_delete_key(self, p11): + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id)[0] + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_new_label, cka_wrap=True)[0] + rep2_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica2_key_label, cka_unwrap=True)[0] + + for key in (rep1_pub, rep2_priv, master_key): + p11.delete_key(key) + + master_key = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY, + label=master_key_label, id=master_key_id) + assert len(master_key) == 0, "The master key should be deleted." + rep1_pub = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, + label=replica1_new_label, cka_wrap=True) + assert len(rep1_pub) == 0, ("The public key of replica1 pair should " + "be deleted.") + rep2_priv = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, + label=replica2_key_label, cka_unwrap=True) + assert len(rep2_priv) == 0, ("The private key of replica2 pair should" + " be deleted.") diff --git a/make-lint b/make-lint index bd0eb4d75..33adf38ff 100755 --- a/make-lint +++ b/make-lint @@ -57,7 +57,7 @@ class IPATypeChecker(TypeChecker): 'urlparse.ResultMixin': ['scheme', 'netloc', 'path', 'query', 'fragment', 'username', 'password', 'hostname', 'port'], 'urlparse.ParseResult': ['params'], - 'pytest': ['fixture', 'raises', 'skip', 'yield_fixture', 'mark'], + 'pytest': ['fixture', 'raises', 'skip', 'yield_fixture', 'mark', 'fail'], 'nose.tools': ['assert_equal', 'assert_raises'], 'datetime.tzinfo': ['houroffset', 'minoffset', 'utcoffset', 'dst'], -- cgit