diff --git a/.gitignore b/.gitignore index 8ab82f6..25bf4d3 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,7 @@ coverage.xml # Sphinx documentation docs/_build/ +_docbuild # PyBuilder target/ diff --git a/README.MD b/README.MD index d1ed3e3..f7d5362 100755 --- a/README.MD +++ b/README.MD @@ -1,68 +1,68 @@ -## Pycryptoki -[![Doc Status](https://readthedocs.org/projects/pycryptoki/badge/?version=latest)](http://pycryptoki.readthedocs.io/en/latest/) - -Pycryptoki is a python wrapper around the PKCS11 library. - -## Documentation - -Latest API documentation can be found on [readthedocs](http://pycryptoki.readthedocs.io/en/latest/index.html). - - -## Installation - -pip install git+https://github.com/gemalto/pycryptoki - -## Key Generation Example - -```py -from pycryptoki.default_templates import * -from pycryptoki.defines import * -from pycryptoki.key_generator import * -from pycryptoki.session_management import * -from pycryptoki.encryption import * - - -c_initialize_ex() -auth_session = c_open_session_ex(0) # HSM slot # in this example is 0 -login_ex(auth_session, 0, 'userpin') # 0 is still the slot number, ‘userpin’ should be replaced by your password (None if PED or no challenge) - -# Get some default templates -# They are simple python dictionaries, and can be modified to suit needs. -pub_template, priv_template = get_default_key_pair_template(CKM_RSA_PKCS_KEY_PAIR_GEN) - -# Modifying template would look like: -pub_template[CKA_LABEL] = "RSA PKCS Pub Key" -pub_template[CKA_MODULUS_BITS] = 2048 # 2048 key size - -pubkey, privkey = c_generate_key_pair_ex(auth_session, CKM_RSA_PKCS_KEY_PAIR_GEN, pub_template, priv_template) -print("Generated Private key at %s and Public key at %s" % (privkey, pubkey)) - -c_logout_ex(auth_session) -c_close_session_ex(auth_session) -c_finalize_ex() -``` -## Verbose logging - -If you want to see what calls to the C library are being performed, set pycryptoki logging to `DEBUG`: - -```py -import logging -logging.basicConfig(level=logging.DEBUG) -``` - -## Tests - -Test requirements can be installed via `pip install -r test_requirements.txt`. - -Unittests can be run on any environment via: -``` -py.test tests/unittests -``` - -Functional tests require an HSM to test against, and will actively test the integration - with the libCryptoki library. This *will* create and destroy objects on the HSM, so don't run - on a production HSM! - -``` -py.test tests/functional --slot= [--reset] [--password=] [--copassword=] [--user=] [--loglevel=] -``` +## Pycryptoki +[![Doc Status](https://readthedocs.org/projects/pycryptoki/badge/?version=latest)](http://pycryptoki.readthedocs.io/en/latest/) + +Pycryptoki is a python wrapper around the PKCS11 library. + +## Documentation + +Latest API documentation can be found on [readthedocs](http://pycryptoki.readthedocs.io/en/latest/index.html). + + +## Installation + +pip install git+https://github.com/gemalto/pycryptoki + +## Key Generation Example + +```py +from pycryptoki.default_templates import * +from pycryptoki.defines import * +from pycryptoki.key_generator import * +from pycryptoki.session_management import * +from pycryptoki.encryption import * + + +c_initialize_ex() +auth_session = c_open_session_ex(0) # HSM slot # in this example is 0 +login_ex(auth_session, 0, 'userpin') # 0 is still the slot number, ‘userpin’ should be replaced by your password (None if PED or no challenge) + +# Get some default templates +# They are simple python dictionaries, and can be modified to suit needs. +pub_template, priv_template = get_default_key_pair_template(CKM_RSA_PKCS_KEY_PAIR_GEN) + +# Modifying template would look like: +pub_template[CKA_LABEL] = "RSA PKCS Pub Key" +pub_template[CKA_MODULUS_BITS] = 2048 # 2048 key size + +pubkey, privkey = c_generate_key_pair_ex(auth_session, CKM_RSA_PKCS_KEY_PAIR_GEN, pub_template, priv_template) +print("Generated Private key at %s and Public key at %s" % (privkey, pubkey)) + +c_logout_ex(auth_session) +c_close_session_ex(auth_session) +c_finalize_ex() +``` +## Verbose logging + +If you want to see what calls to the C library are being performed, set pycryptoki logging to `DEBUG`: + +```py +import logging +logging.basicConfig(level=logging.DEBUG) +``` + +## Tests + +Test requirements can be installed via `pip install -r test_requirements.txt`. + +Unittests can be run on any environment via: +``` +py.test tests/unittests +``` + +Functional tests require an HSM to test against, and will actively test the integration + with the libCryptoki library. This *will* create and destroy objects on the HSM, so don't run + on a production HSM! + +``` +py.test tests/functional --slot= [--reset] [--password=] [--copassword=] [--user=] [--loglevel=] +``` diff --git a/docs/conf.py b/docs/conf.py index 4c8e615..7c939d7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -52,7 +52,7 @@ # General information about the project. project = u'Pycryptoki' -copyright = u'2016, Gemalto' +copyright = u'2018, Gemalto' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -61,7 +61,7 @@ # The short X.Y version. version = '2.1' # The full version, including alpha/beta/rc tags. -release = '2.1.0' +release = '2.1.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pycryptoki/common_utils.py b/pycryptoki/common_utils.py index eddef25..0e1e60b 100644 --- a/pycryptoki/common_utils.py +++ b/pycryptoki/common_utils.py @@ -2,12 +2,15 @@ Utilities for pycryptoki """ from six import b, string_types +import logging from _ctypes import pointer, POINTER from ctypes import c_ulong, cast, create_string_buffer from .cryptoki import CK_CHAR from .defines import CKR_OK +LOG = logging.getLogger(__name__) + class CException(Exception): """ @@ -93,6 +96,7 @@ def array(self): # If we get to this point, we have a specified size, a ctype, # And our array is still none, but we're trying to access it. # Therefore, we go ahead & allocate the memory + LOG.debug("Allocating %s buffer of size: %s", self.ctype, self._size.value) self._array = (self.ctype * self._size.value)() return cast(self._array, POINTER(self.ctype)) diff --git a/pycryptoki/cryptoki_helpers.py b/pycryptoki/cryptoki_helpers.py index 6003893..fe123dd 100755 --- a/pycryptoki/cryptoki_helpers.py +++ b/pycryptoki/cryptoki_helpers.py @@ -204,8 +204,9 @@ def luna_function(*args): return_value = late_binded_function(*args) return return_value except Exception as e: - raise CryptokiDLLException("Call to '%s(%s)' failed.".format(function_name, - ", ".join(args)), e) + raise CryptokiDLLException("Call to '{}({})' " + "failed.".format(function_name, + ", ".join([str(arg) for arg in args])), e) luna_function.__name__ = function_name return luna_function diff --git a/pycryptoki/daemon/rpyc_pycryptoki.py b/pycryptoki/daemon/rpyc_pycryptoki.py index 7500f5c..2e44a56 100755 --- a/pycryptoki/daemon/rpyc_pycryptoki.py +++ b/pycryptoki/daemon/rpyc_pycryptoki.py @@ -68,7 +68,8 @@ c_generate_key_pair, c_generate_key_pair_ex, c_generate_key, c_generate_key_ex, c_derive_key, c_derive_key_ex, - c_copy_object_ex, c_copy_object) + c_copy_object_ex, c_copy_object, ca_destroy_multiple_objects, + ca_destroy_multiple_objects_ex) from pycryptoki.key_management import (ca_generatemofn, ca_generatemofn_ex, ca_modifyusagecount, ca_modifyusagecount_ex) from pycryptoki.key_usage import (ca_clonemofn, ca_clonemofn_ex, @@ -124,7 +125,10 @@ ca_openapplicationID_ex, ca_openapplicationID, ca_closeapplicationID, ca_closeapplicationID_ex, ca_restart, ca_restart_ex, - ca_setapplicationID, ca_setapplicationID_ex) + ca_setapplicationID, ca_setapplicationID_ex, + c_get_slot_list, c_get_slot_list_ex, + c_get_slot_info, c_get_slot_info_ex, + c_get_info, c_get_info_ex) from pycryptoki.sign_verify import (c_sign, c_sign_ex, c_verify, c_verify_ex) from pycryptoki.token_management import (c_init_token, c_init_token_ex, @@ -237,6 +241,12 @@ def _rpyc_getattr(self, name): exposed_ca_setapplicationID = staticmethod(ca_setapplicationID) exposed_ca_restart_ex = staticmethod(ca_restart_ex) exposed_ca_restart = staticmethod(ca_restart) + exposed_c_get_slot_list = staticmethod(c_get_slot_list) + exposed_c_get_slot_list_ex = staticmethod(c_get_slot_list_ex) + exposed_c_get_slot_info = staticmethod(c_get_slot_info) + exposed_c_get_slot_info_ex = staticmethod(c_get_slot_info_ex) + exposed_c_get_info = staticmethod(c_get_info) + exposed_c_get_info_ex = staticmethod(c_get_info_ex) # object_attr_lookup.py exposed_c_find_objects = staticmethod(c_find_objects) @@ -362,6 +372,8 @@ def _rpyc_getattr(self, name): exposed_ca_generatemofn_ex = staticmethod(ca_generatemofn_ex) exposed_ca_modifyusagecount = staticmethod(ca_modifyusagecount) exposed_ca_modifyusagecount_ex = staticmethod(ca_modifyusagecount_ex) + exposed_ca_destroy_multiple_objects = staticmethod(ca_destroy_multiple_objects) + exposed_ca_destroy_multiple_objects_ex = staticmethod(ca_destroy_multiple_objects_ex) # key_usage.py exposed_ca_clonemofn = staticmethod(ca_clonemofn) diff --git a/pycryptoki/defines.py b/pycryptoki/defines.py index daba2eb..3645527 100755 --- a/pycryptoki/defines.py +++ b/pycryptoki/defines.py @@ -994,6 +994,8 @@ CKK_CAMELLIA = 0x00000025 CKK_ARIA = 0x00000026 CKK_VENDOR_DEFINED = 0x80000000 +CKK_EC_EDWARDS = (CKK_VENDOR_DEFINED + 0x12) +CKK_EC_MONTGOMERY = (CKK_VENDOR_DEFINED + 0x13) CKC_X_509 = 0x00000000 CKC_X_509_ATTR_CERT = 0x00000001 CKC_WTLS = 0x00000002 diff --git a/pycryptoki/encryption.py b/pycryptoki/encryption.py index 471e153..60ae0a3 100755 --- a/pycryptoki/encryption.py +++ b/pycryptoki/encryption.py @@ -265,7 +265,8 @@ def do_multipart_operation(h_session, if ret != CKR_OK: LOG.debug("%s call on chunk %.20s (%s/%s) Failed w/ ret %s (%s)", c_update_function.__name__, - chunk, index + 1, len(input_data_list), ret_vals_dictionary[ret], ret) + chunk, index + 1, len(input_data_list), + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) error = ret break @@ -279,7 +280,8 @@ def do_multipart_operation(h_session, if ret != CKR_OK: LOG.debug("%s call on chunk %.20s (%s/%s) Failed w/ ret %s (%s)", c_update_function.__name__, - chunk, index + 1, len(input_data_list), ret_vals_dictionary[ret], ret) + chunk, index + 1, len(input_data_list), + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) error = ret break @@ -293,21 +295,31 @@ def do_multipart_operation(h_session, CK_ULONG(MAX_BUFFER)) LOG.debug("%s call after a %s failure returned: %s (%s)", c_finalize_function.__name__, - c_update_function.__name__, ret_vals_dictionary[ret], ret) + c_update_function.__name__, + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) return error, b"".join(python_data) - # Finalizing multipart decrypt operation - fin_out_data_len = CK_ULONG() - # Get buffer size for data - ret = c_finalize_function(h_session, None, byref(fin_out_data_len)) - if ret != CKR_OK: - return ret, b"".join(python_data) + if output_buffer: + fin_out_data_len = CK_ULONG(max(output_buffer)) + fin_out_data = create_string_buffer(b"", fin_out_data_len.value) - fin_out_data = create_string_buffer(b"", fin_out_data_len.value) - output = cast(fin_out_data, CK_BYTE_PTR) - ret = c_finalize_function(h_session, output, byref(fin_out_data_len)) - if ret != CKR_OK: - return ret, b"".join(python_data) + ret = c_finalize_function(h_session, cast(fin_out_data, CK_BYTE_PTR), + byref(fin_out_data_len)) + if ret != CKR_OK: + return ret, b"".join(python_data) + else: + # Finalizing multipart decrypt operation + fin_out_data_len = CK_ULONG() + # Get buffer size for data + ret = c_finalize_function(h_session, None, byref(fin_out_data_len)) + if ret != CKR_OK: + return ret, b"".join(python_data) + + fin_out_data = create_string_buffer(b"", fin_out_data_len.value) + output = cast(fin_out_data, CK_BYTE_PTR) + ret = c_finalize_function(h_session, output, byref(fin_out_data_len)) + if ret != CKR_OK: + return ret, b"".join(python_data) if fin_out_data_len.value > 0: python_data.append(string_at(fin_out_data, fin_out_data_len.value)) diff --git a/pycryptoki/exceptions.py b/pycryptoki/exceptions.py index a41f4f3..cdbc33b 100644 --- a/pycryptoki/exceptions.py +++ b/pycryptoki/exceptions.py @@ -132,7 +132,7 @@ def check_luna_exception(ret, luna_function, args, kwargs): arg_string = "({})".format("\n".join(log_list)) LOG.debug("Call to %s returned %s (%s)", luna_function, - ret_vals_dictionary.get(ret, "Unknown"), ret) + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) if ret != CKR_OK: raise LunaCallException(ret, luna_function.__name__, arg_string) diff --git a/pycryptoki/key_generator.py b/pycryptoki/key_generator.py index 33dd84a..3356ad5 100755 --- a/pycryptoki/key_generator.py +++ b/pycryptoki/key_generator.py @@ -6,13 +6,13 @@ from .attributes import Attributes from .cryptoki import C_DeriveKey from .cryptoki import C_DestroyObject, CK_OBJECT_HANDLE, CK_ULONG, C_GenerateKey, \ - C_GenerateKeyPair, \ - C_CopyObject + C_GenerateKeyPair, CA_DestroyMultipleObjects, C_CopyObject from .default_templates import CKM_DES_KEY_GEN_TEMP, \ get_default_key_pair_template from .defines import CKM_DES_KEY_GEN, CKM_RSA_PKCS_KEY_PAIR_GEN from .mechanism import parse_mechanism from .exceptions import make_error_handle_function +from .common_utils import AutoCArray def c_destroy_object(h_session, h_object_value): @@ -28,6 +28,21 @@ def c_destroy_object(h_session, h_object_value): c_destroy_object_ex = make_error_handle_function(c_destroy_object) +def ca_destroy_multiple_objects(h_session, objects): + """Delete multiple objects corresponding to given object handles + + :param int h_session: Session handle + :param list objects: The handles of the objects to delete + :returns: Return code + """ + handles_count = len(objects) + handles = AutoCArray(data=objects, ctype=CK_ULONG) + ret = CA_DestroyMultipleObjects(h_session, handles_count, handles.array, byref(CK_ULONG())) + return ret + + +ca_destroy_multiple_objects_ex = make_error_handle_function(ca_destroy_multiple_objects) + def c_copy_object(h_session, h_object, template=None): """Method to call the C_CopyObject cryptoki command. diff --git a/pycryptoki/session_management.py b/pycryptoki/session_management.py index 35f3fb4..1f5b157 100755 --- a/pycryptoki/session_management.py +++ b/pycryptoki/session_management.py @@ -2,11 +2,10 @@ Methods responsible for managing a user's session and login/c_logout """ import logging -import re -from ctypes import cast, c_char_p, c_void_p, create_string_buffer, \ +from ctypes import cast, c_void_p, create_string_buffer, \ byref, pointer, string_at -from .common_utils import AutoCArray, refresh_c_arrays +from .common_utils import AutoCArray # cryptoki constants from .cryptoki import (CK_ULONG, CK_BBOOL, @@ -159,27 +158,56 @@ def c_get_info(): c_get_info_ex = make_error_handle_function(c_get_info) -def get_slot_info(description): - """Returns a slot with a certain descriptor +def c_get_slot_list(token_present=True): + """ + Get a list of all slots. + + :param bool token_present: If true, will only return slots that have a token present. + :return: List of slots + """ + slots = AutoCArray(ctype=CK_ULONG) - Limitation: Only returns the first slot it finds that fits the description + rc = C_GetSlotList(CK_BBOOL(token_present), + slots.array, + slots.size) + if rc != CKR_OK: + return rc, [] + rc = C_GetSlotList(CK_BBOOL(token_present), + slots.array, + slots.size) + return rc, [x for x in slots] - :param description: The name of the slot to find - :returns: THe result code, a Python dictionary representing the slots - """ - ret, slot_dict = get_slot_dict() +c_get_slot_list_ex = make_error_handle_function(c_get_slot_list) - return_dict = {} - for key in slot_dict: - if re.match(description, slot_dict[key]): - return_dict[key] = slot_dict[key] +def c_get_slot_info(slot): + """ + Get information about the given slot number. + + :param int slot: Target slot + :return: Dictionary of slot information + """ + slot_info = CK_SLOT_INFO() + slot_info_dict = {} + ret = C_GetSlotInfo(slot, byref(slot_info)) + if ret != CKR_OK: + return ret, {} - return ret, return_dict + slot_info_dict['slotDescription'] = string_at(slot_info.slotDescription, 64).rstrip() + slot_info_dict['manufacturerID'] = string_at(slot_info.manufacturerID, 32).rstrip() + slot_info_dict['flags'] = slot_info.flags + hw_version = "{}.{}".format(slot_info.hardwareVersion.major, + slot_info.hardwareVersion.minor) + slot_info_dict['hardwareVersion'] = hw_version + fw_version = "{}.{}.{}".format(slot_info.firmwareVersion.major, + slot_info.firmwareVersion.minor / 10, + slot_info.firmwareVersion.minor % 10) + slot_info_dict['firmwareVersion'] = fw_version + return ret, slot_info_dict -get_slot_info_ex = make_error_handle_function(get_slot_info) +c_get_slot_info_ex = make_error_handle_function(c_get_slot_info) def c_get_session_info(session): @@ -205,10 +233,11 @@ def c_get_session_info(session): c_get_session_info_ex = make_error_handle_function(c_get_session_info) -def c_get_token_info(slot_id): +def c_get_token_info(slot_id, rstrip=True): """Gets the token info for a given slot id - :param int slot_id: Slot index to get the token info for + :param int slot_id: Token slot ID + :param bool rstrip: If true, will strip trailing whitespace from char data. :returns: (retcode, A python dictionary representing the token info) :rtype: tuple """ @@ -218,10 +247,10 @@ def c_get_token_info(slot_id): ret = C_GetTokenInfo(CK_ULONG(slot_id), byref(c_token_info)) if ret == CKR_OK: - token_info['label'] = string_at(c_token_info.label) - token_info['manufacturerID'] = string_at(c_token_info.manufacturerID) - token_info['model'] = string_at(c_token_info.model) - token_info['serialNumber'] = string_at(c_token_info.serialNumber) + token_info['label'] = string_at(c_token_info.label, 32) + token_info['manufacturerID'] = string_at(c_token_info.manufacturerID, 32) + token_info['model'] = string_at(c_token_info.model, 16) + token_info['serialNumber'] = string_at(c_token_info.serialNumber, 16) token_info['flags'] = c_token_info.flags token_info['ulFreePrivateMemory'] = c_token_info.ulFreePrivateMemory token_info['ulTotalPrivateMemory'] = c_token_info.ulTotalPrivateMemory @@ -235,7 +264,13 @@ def c_get_token_info(slot_id): token_info['ulFreePublicMemory'] = c_token_info.ulFreePublicMemory token_info['hardwareVersion'] = c_token_info.hardwareVersion token_info['firmwareVersion'] = c_token_info.firmwareVersion - token_info['utcTime'] = string_at(c_token_info.utcTime) + token_info['utcTime'] = string_at(c_token_info.utcTime, 16) + if rstrip: + token_info['label'] = token_info['label'].rstrip() + token_info['manufacturerID'] = token_info['manufacturerID'].rstrip() + token_info['model'] = token_info['model'].rstrip() + token_info['serialNumber'] = token_info['serialNumber'].rstrip() + token_info['utcTime'] = token_info['utcTime'].rstrip() return ret, token_info @@ -243,31 +278,21 @@ def c_get_token_info(slot_id): c_get_token_info_ex = make_error_handle_function(c_get_token_info) -def get_slot_dict(): +def get_slot_dict(token_present=False): """Compiles a dictionary of the available slots :returns: A python dictionary of the available slots """ - slot_list = AutoCArray() - - @refresh_c_arrays(1) - def _get_slot_list(): - """ - Closure to refresh properties. - """ - return C_GetSlotList(CK_BBOOL(0), slot_list.array, slot_list.size) - - ret = _get_slot_list() - if ret != CKR_OK: - return ret, None - - slot_info = CK_SLOT_INFO() + slot_list = c_get_slot_list_ex(token_present) slot_dict = {} + ret = CKR_OK for slot in slot_list: - C_GetSlotInfo(slot, byref(slot_info)) - slot_description = str(cast(slot_info.slotDescription, c_char_p).value)[0:63].strip() - slot_dict[slot] = slot_description + ret, data = c_get_slot_info(slot) + if ret != CKR_OK: + LOG.error("C_GetSlotInfo failed at slot %s") + break + slot_dict[slot] = data return ret, slot_dict diff --git a/pycryptoki/sign_verify.py b/pycryptoki/sign_verify.py index 1fb4c31..ac511c5 100755 --- a/pycryptoki/sign_verify.py +++ b/pycryptoki/sign_verify.py @@ -123,7 +123,8 @@ def do_multipart_sign_or_digest(h_session, c_update_function, c_final_function, if ret != CKR_OK: LOG.debug("%s call on chunk %.20s (%s/%s) Failed w/ ret %s (%s)", c_update_function.__name__, - chunk, index + 1, len(input_data_list), ret_vals_dictionary[ret], ret) + chunk, index + 1, len(input_data_list), + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) error = ret break @@ -135,7 +136,8 @@ def do_multipart_sign_or_digest(h_session, c_update_function, c_final_function, CK_ULONG(MAX_BUFFER)) LOG.debug("%s call after a %s failure returned: %s (%s)", c_final_function.__name__, - c_update_function.__name__, ret_vals_dictionary[ret], ret) + c_update_function.__name__, + ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) return error, None if output_buffer is not None: @@ -192,7 +194,7 @@ def do_multipart_verify(h_session, input_data_list, signature): cast(create_string_buffer(b"", MAX_BUFFER), CK_BYTE_PTR), CK_ULONG(MAX_BUFFER)) LOG.debug("C_VerifyFinal call after a C_VerifyUpdate failure returned:" - " %s (%s)", ret_vals_dictionary[ret], ret) + " %s (%s)", ret_vals_dictionary.get(ret, "Unknown retcode"), str(hex(ret))) return error, None # Finalizing multipart decrypt operation diff --git a/setup.py b/setup.py index 26155c8..ec7be6d 100755 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ description="A python wrapper around the C cryptoki library.", author='Ashley Straw', url='https://github.com/gemalto/pycryptoki', - version='2.1.0', + version='2.1.1', packages=['pycryptoki', 'pycryptoki.daemon', 'pycryptoki.mechanism'], diff --git a/tests/functional/test_keys.py b/tests/functional/test_keys.py index 14ce0b8..02a0718 100755 --- a/tests/functional/test_keys.py +++ b/tests/functional/test_keys.py @@ -32,9 +32,9 @@ from pycryptoki.encryption import c_encrypt_ex, c_decrypt_ex from pycryptoki.key_generator import \ c_generate_key, c_generate_key_pair, c_derive_key, c_generate_key_ex, c_destroy_object, \ - c_derive_key_ex, c_generate_key_pair_ex + c_derive_key_ex, c_generate_key_pair_ex, ca_destroy_multiple_objects_ex from pycryptoki.mechanism import NullMech -from pycryptoki.object_attr_lookup import c_get_attribute_value_ex +from pycryptoki.object_attr_lookup import c_get_attribute_value_ex, c_find_objects_ex from pycryptoki.return_values import ret_vals_dictionary from pycryptoki.test_functions import verify_object_attributes from .util import get_session_template @@ -316,3 +316,29 @@ def test_x9_key_derive(self, auth_session, curve_type): for key in (pub_key1, prv_key1, pub_key2, prv_key2, derived_key1, derived_key2): if key: c_destroy_object(auth_session, key) + + def test_destroymultipleobjects(self): + """ + Test deletion of multiple keys + Tested by RSA key pair + """ + + key_type, pub_key_temp, priv_key_temp = pair_params(CKM_RSA_PKCS_KEY_PAIR_GEN) + session_pub_template = get_session_template(pub_key_temp) + session_priv_template = get_session_template(priv_key_temp) + ret, pub_key, prv_key = c_generate_key_pair(self.h_session, key_type, + session_pub_template, + session_priv_template) + + try: + + ret = ca_destroy_multiple_objects_ex(self.h_session, [pub_key, prv_key]) + self.verify_ret(ret, CKR_OK) + for templ in (session_pub_template, session_priv_template): + objs = c_find_objects_ex(self.h_session, templ, 1) + assert len(objs) == 0 + + except Exception: + for key in (pub_key, prv_key): + c_destroy_object(self.h_session, key) + diff --git a/tests/functional/test_session_management.py b/tests/functional/test_session_management.py index 00584c9..7da4a9b 100644 --- a/tests/functional/test_session_management.py +++ b/tests/functional/test_session_management.py @@ -35,5 +35,23 @@ def test_c_get_session_info(self): def test_get_slot_dict(self): """ get_slot_dict() """ ret, slot_dict = sess_mang.get_slot_dict() + logger.debug("Slots: %s", slot_dict) assert ret == CKR_OK assert isinstance(slot_dict, dict) + + def test_get_slot_dict_token_present(self): + """ + Verify this also works with token_present = True + """ + slot_dict = sess_mang.get_slot_dict_ex(token_present=True) + for slot in slot_dict.keys(): + assert sess_mang.c_get_token_info(slot)[0] == CKR_OK + + def test_get_slot_list(self): + """ + Verify get slot list works as expected. + """ + slot_list = sess_mang.c_get_slot_list_ex(token_present=True) + for slot in slot_list: + assert isinstance(slot, integer_types) + assert sess_mang.c_get_token_info(slot)[0] == CKR_OK