Skip to content

Commit

Permalink
Merge pull request #12 from gemalto/merge_sep_16
Browse files Browse the repository at this point in the history
Merge sep 16
  • Loading branch information
astraw38 committed Sep 13, 2018
2 parents 3d77fd6 + 1e71575 commit b20091f
Show file tree
Hide file tree
Showing 33 changed files with 768 additions and 92 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Created by https://www.gitignore.io
.gitreview
.pytest_cache
### PyCharm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm

Expand Down Expand Up @@ -109,3 +110,6 @@ _docbuild
# PyBuilder
target/

#eclipse
.project
.pydevproject
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
# The short X.Y version.
version = '2.1'
# The full version, including alpha/beta/rc tags.
release = '2.1.1'
release = '2.1.3'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
3 changes: 2 additions & 1 deletion pycryptoki/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
CKA_MODIFIABLE, CKA_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, CKA_NEVER_EXTRACTABLE, \
CKA_CCM_PRIVATE, CKA_FINGERPRINT_SHA1, CKA_FINGERPRINT_SHA256, CKA_OUID, CKA_UNWRAP_TEMPLATE, \
CKA_DERIVE_TEMPLATE, \
CKA_X9_31_GENERATED, CKA_VALUE
CKA_X9_31_GENERATED, CKA_VALUE, CKA_BYTES_REMAINING

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -266,6 +266,7 @@ def to_sub_attributes(val, reverse=False):
CKA_VALUE_BITS: to_long,
CKA_USAGE_COUNT: to_long,
CKA_USAGE_LIMIT: to_long,
CKA_BYTES_REMAINING: to_long,

# int, bool
CKA_TOKEN: to_bool,
Expand Down
104 changes: 82 additions & 22 deletions pycryptoki/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
Backup related commands
"""
import logging
from ctypes import byref
from ctypes import byref, c_ulong

from .common_utils import AutoCArray, refresh_c_arrays
from .cryptoki import CA_OpenSecureToken, CA_CloseSecureToken, CA_Extract, CA_Insert, \
CK_ULONG, \
CA_SIMExtract, CK_BYTE, string_at, create_string_buffer, POINTER, cast, pointer, \
CK_BYTE_PTR, c_ubyte, CA_SIMInsert
CK_BYTE_PTR, c_ubyte, CA_SIMInsert, CA_SIMMultiSign
from .defines import (CKA_SIM_NO_AUTHORIZATION, CKA_SIM_PASSWORD, CKA_SIM_CHALLENGE,
CKA_SIM_SECURE_PORT, CKA_SIM_PORTABLE_NO_AUTHORIZATION,
CKA_SIM_PORTABLE_PASSWORD, CKA_SIM_PORTABLE_CHALLENGE,
CKA_SIM_PORTABLE_SECURE_PORT)
CKA_SIM_PORTABLE_SECURE_PORT, CKR_OK)
from .exceptions import make_error_handle_function
from .mechanism import parse_mechanism

Expand Down Expand Up @@ -117,16 +117,10 @@ def ca_sim_extract(h_session, key_handles, authform, auth_secrets=None, subset_s
if auth_secrets is None:
auth_secrets = []

if authform not in SIM_AUTH_FORMS:
raise ValueError("Invalid authform, import and use SIM_AUTH to select an authentication "
"type.")

if subset_size > len(auth_secrets):
raise ValueError("Subset size cannot be larger than the N value (length of auth secrets)")

auth_secrets = AutoCArray(data=[cast(pointer(create_string_buffer(x, len(x))),
CK_BYTE_PTR) for x in auth_secrets],
ctype=POINTER(CK_BYTE))
auth_secret_sizes = AutoCArray(data=[c_ulong(len(x)) for x in auth_secrets])
c_auth_secrets = AutoCArray(data=[cast(pointer(create_string_buffer(x, len(x))),
CK_BYTE_PTR) for x in auth_secrets],
ctype=POINTER(CK_BYTE))
c_key_handles = AutoCArray(key_handles)
blob_data = AutoCArray(ctype=c_ubyte)

Expand All @@ -140,7 +134,7 @@ def extract():
len(c_key_handles), c_key_handles.array,
CK_ULONG(len(auth_secrets)), CK_ULONG(subset_size),
authform,
auth_secrets.size, auth_secrets.array,
auth_secret_sizes.array, c_auth_secrets.array,
delete_after_extract,
bloblen, blobarr)

Expand Down Expand Up @@ -171,13 +165,10 @@ def ca_sim_insert(h_session, blob_data, authform, auth_secrets=None):
if auth_secrets is None:
auth_secrets = []

if authform not in SIM_AUTH_FORMS:
raise ValueError("Invalid authform, import and use SIM_AUTH to select an authentication "
"type.")

auth_secrets = AutoCArray(data=[cast(pointer(create_string_buffer(x, len(x))),
CK_BYTE_PTR) for x in auth_secrets],
ctype=POINTER(CK_BYTE))
auth_secret_sizes = AutoCArray(data=[c_ulong(len(x)) for x in auth_secrets])
c_auth_secrets = AutoCArray(data=[cast(create_string_buffer(x, len(x)), CK_BYTE_PTR)
for x in auth_secrets],
ctype=POINTER(CK_BYTE))
c_key_handles = AutoCArray()
c_blob_data = create_string_buffer(blob_data, len(blob_data))

Expand All @@ -189,7 +180,7 @@ def insert():
key_array, key_array_len = c_key_handles.array, c_key_handles.size
return CA_SIMInsert(h_session,
CK_ULONG(len(auth_secrets)), authform,
auth_secrets.size, auth_secrets.array,
auth_secret_sizes.array, c_auth_secrets.array,
len(blob_data), cast(c_blob_data, POINTER(CK_BYTE)),
key_array_len, key_array)

Expand All @@ -202,3 +193,72 @@ def insert():


ca_sim_insert_ex = make_error_handle_function(ca_sim_insert)

# This was taken from ckdemo.cpp
MAX_SIG_SIZE = 3000


def ca_sim_multisign(h_session, blob_data, data_to_sign, mechanism, authform, auth_secrets=None):
"""
Sign data using keys that were extracted to a SIM blob.
:param int h_session: Session handle
:param str blob_data: Read in raw wrapped key data. Typically read in from a file.
:param data_to_sign: List of bytestring data to sign
:param mechanism: Mechanism to use with the Sign operation
:param int authform: Type of authentication to use. See :class:`pycryptoki.backup.SIM_AUTH`
for details
:param list[str] auth_secrets: Authorization secrets to use (Length will correspond to the
``N`` value in ckdemo)
:return: retcode, signature list
"""

if auth_secrets is None:
auth_secrets = []

c_mechanism = parse_mechanism(mechanism)

auth_secret_sizes = AutoCArray(data=[c_ulong(len(x)) for x in auth_secrets])
c_auth_secrets = AutoCArray(data=[cast(create_string_buffer(x, len(x)),
CK_BYTE_PTR) for x in auth_secrets],
ctype=POINTER(CK_BYTE))
c_blob_data = create_string_buffer(blob_data, len(blob_data))

# Output array of signatures (array of pointers
signatures = (CK_BYTE_PTR * len(data_to_sign))()
# Output signature sizes.
signature_lens = (CK_ULONG * len(data_to_sign))()
for index in range(len(signatures)):
signatures[index] = cast(create_string_buffer(MAX_SIG_SIZE), CK_BYTE_PTR)
signature_lens[index] = MAX_SIG_SIZE

# Input data sizes
data_lens = AutoCArray([len(x) for x in data_to_sign])
data_buffers = [cast(create_string_buffer(chunk, len(chunk)), CK_BYTE_PTR)
for chunk in data_to_sign]

# Input data to sign -- array of pointers
input_data = AutoCArray(ctype=CK_BYTE_PTR,
data=data_buffers)

ret = CA_SIMMultiSign(h_session,
byref(c_mechanism),
CK_ULONG(len(auth_secrets)),
authform,
auth_secret_sizes.array,
c_auth_secrets.array,
len(blob_data),
cast(c_blob_data, CK_BYTE_PTR),
len(data_to_sign),
data_lens.array,
input_data.array,
signature_lens,
signatures)
py_sigs = []
if ret == CKR_OK:
for sig, sig_len in zip(signatures, signature_lens):
py_sigs.append(string_at(sig, sig_len))
return ret, py_sigs


ca_sim_multisign_ex = make_error_handle_function(ca_sim_multisign)
Empty file.
98 changes: 98 additions & 0 deletions pycryptoki/ca_extensions/hsm_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Methods responsible for retrieving hsm info from the K7 card
"""
import logging
from ctypes import c_ulong, byref, cast, POINTER
from pycryptoki.cryptoki import (CA_GetNumberOfAllowedContainers, CA_RetrieveLicenseList,
CA_GetHSMStorageInformation, CA_GetTSV)
from pycryptoki.exceptions import make_error_handle_function
from pycryptoki.defines import CKR_OK

LOG = logging.getLogger(__name__)


def ca_retrieve_license_list(slot):
"""Gets the license info for a given slot id
:param int slot_id: Slot index to get the license id's
:returns: (A python list representing the license id's)
:rtype: list
"""

license_len = c_ulong()
ret = CA_RetrieveLicenseList(slot, byref(license_len), None)
if ret == CKR_OK:
licenses = (c_ulong * license_len.value)()
ret = CA_RetrieveLicenseList(slot, license_len, cast(licenses, POINTER(c_ulong)))
LOG.info("Getting license id. slot=%s", slot)
if ret != CKR_OK:
return ret, []
else:
return ret, []
return ret, [(licenses[x], licenses[x + 1]) for x in range(0, license_len.value, 2)]


ca_retrieve_license_list_ex = make_error_handle_function(ca_retrieve_license_list)


def ca_retrieve_allowed_containers(slot):
"""Gets the maximum allowed container number for a given slot id
:param int slot_id: Slot index to get the maximum allowed container number
:returns: (ret code, A unsigned integer representing the maximum allowed container number)
:rtype: unsigned integer
"""

allowed_partition_number = c_ulong()
ret = CA_GetNumberOfAllowedContainers(slot, byref(allowed_partition_number))
LOG.info("Getting allowed maximum container number. slot=%s", slot)
return ret, allowed_partition_number


ca_retrieve_allowed_containers_ex = make_error_handle_function(ca_retrieve_allowed_containers)


def ca_retrieve_hsm_storage_info(slot):
"""Gets the hsm storage info for a given slot id
:param int slot_id: Slot index to get the hsm storage info
:returns: (ret code, hsm_storage_info dictionary)
:rtype: dictionary
"""

hsm_storage_info = {}

container_overhead = c_ulong()
total_hsm_storage = c_ulong()
used_hsm_storage = c_ulong()
free_hsm_storage = c_ulong()
ret = CA_GetHSMStorageInformation(slot, byref(container_overhead), byref(total_hsm_storage),
byref(used_hsm_storage), byref(free_hsm_storage))
LOG.info("Getting allowed maximum container number. slot=%s", slot)

if ret == CKR_OK:
hsm_storage_info['ContainerOverhead'] = container_overhead
hsm_storage_info['TotalHsmStorage'] = total_hsm_storage
hsm_storage_info['UsedHsmStorage'] = used_hsm_storage
hsm_storage_info['FreeHsmStorage'] = free_hsm_storage
return ret, hsm_storage_info


ca_retrieve_hsm_storage_info_ex = make_error_handle_function(ca_retrieve_hsm_storage_info)


def ca_get_tsv(slot):
"""Get the TSV(Module State Vector) for a given slot id
:param int slot_id: Slot index to get the TSV(Module State Vector)
:returns: (ret code, TSV)
:rtype: tuple
"""

tsv = c_ulong()
ret = CA_GetTSV(slot, byref(tsv))
LOG.info("Getting Module state vector. slot=%s", slot)
return ret, tsv


ca_get_tsv_ex = make_error_handle_function(ca_get_tsv)
63 changes: 63 additions & 0 deletions pycryptoki/ca_extensions/object_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Module to work with objects, specifically dealing with ca_extension functions
"""

import logging
from ctypes import byref, cast, c_ubyte
from _ctypes import POINTER

from pycryptoki.attributes import to_byte_array
from pycryptoki.ca_extensions.session import ca_get_session_info_ex
from pycryptoki.cryptoki import CK_ULONG, CK_SLOT_ID, CA_GetObjectHandle, CA_DestroyMultipleObjects
from pycryptoki.defines import CKR_OK
from pycryptoki.exceptions import make_error_handle_function
from pycryptoki.common_utils import AutoCArray


LOG = logging.getLogger(__name__)


def ca_get_object_handle(slot, session, objectouid):
"""
Calls CA_GetObjectHandle to get the object handle from OUID
:param slot: partition slot number
:param session: session id that was opened to run the function
:param objectouid: OUID, a string of the hex value that maps to object handle
:return: a tuple containing the return code and the object handle mapping the given OUID
"""
objecttype = CK_ULONG()
objecthandle = CK_ULONG()
# ulContainerNumber is required which is of type CK_ULONG
container_number = ca_get_session_info_ex(session)['containerNumber']
ouid, size_ouid = to_byte_array(int(objectouid, 16))
c_ouid = cast(ouid, POINTER(c_ubyte))

ret = CA_GetObjectHandle(CK_SLOT_ID(slot),
container_number,
c_ouid,
byref(objecttype),
byref(objecthandle))
if ret != CKR_OK:
return ret, None

return ret, objecthandle.value


ca_get_object_handle_ex = make_error_handle_function(ca_get_object_handle)


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)
41 changes: 41 additions & 0 deletions pycryptoki/ca_extensions/session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Module to work with sessions, specifically dealing with ca_extension functions
"""

import logging
from ctypes import byref

from pycryptoki.cryptoki import CK_ULONG, CK_SESSION_HANDLE, CA_GetSessionInfo
from pycryptoki.defines import CKR_OK
from pycryptoki.exceptions import make_error_handle_function


LOG = logging.getLogger(__name__)


def ca_get_session_info(session):
"""
ca extension function that returns session information
:param session: session handle
:return: tuple of return code and session info dict
"""
session_info = {}
h_session = CK_SESSION_HANDLE(session)
aid_hi = CK_ULONG()
aid_lo = CK_ULONG()
container = CK_ULONG()
auth_level = CK_ULONG()
ret = CA_GetSessionInfo(h_session, byref(aid_hi), byref(aid_lo), byref(container), byref(auth_level))
if ret != CKR_OK:
return ret, None

session_info['aidHigh'] = aid_hi.value
session_info['aidLow'] = aid_lo.value
session_info['containerNumber'] = container.value
session_info['authenticationLevel'] = auth_level.value

return ret, session_info


ca_get_session_info_ex = make_error_handle_function(ca_get_session_info)
Loading

0 comments on commit b20091f

Please sign in to comment.