Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add CKM_EXTRACT_KEY_FROM_KEY mechanism #128

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions PyKCS11/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,26 @@ def __init__(self, data):
super().__init__(data, CKM_XOR_BASE_AND_DATA)


class EXTRACT_KEY_FROM_KEY_Mechanism():
"""CKM_EXTRACT_KEY_FROM_KEY key derivation mechanism"""

def __init__(self, extractParams):
"""
:param extractParams: the index of the first bit of the original key to be used in the newly-derived key.
For example if extractParams=5 then the 5 first bits are skipped and not used.
"""
self._param = PyKCS11.LowLevel.CK_EXTRACT_PARAMS()
self._param.assign(extractParams)

self._mech = PyKCS11.LowLevel.CK_MECHANISM()
self._mech.mechanism = CKM_EXTRACT_KEY_FROM_KEY
self._mech.pParameter = self._param
self._mech.ulParameterLen = PyKCS11.LowLevel.CK_EXTRACT_PARAMS_LENGTH

def to_native(self):
return self._mech


class DigestSession(object):
def __init__(self, lib, session, mecha):
self._lib = lib
Expand Down
7 changes: 7 additions & 0 deletions src/opensc/pkcs11.h
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,8 @@ struct ck_key_derivation_string_data {
unsigned long ulLen;
} ;

typedef unsigned long ck_extract_params;

#define CKF_HW (1 << 0)
#define CKF_ENCRYPT (1 << 8)
#define CKF_DECRYPT (1 << 9)
Expand Down Expand Up @@ -1354,6 +1356,9 @@ typedef struct ck_ecdh1_derive_params *CK_ECDH1_DERIVE_PARAMS_PTR;
typedef struct ck_key_derivation_string_data CK_KEY_DERIVATION_STRING_DATA;
typedef struct ck_key_derivation_string_data *CK_KEY_DERIVATION_STRING_DATA_PTR;

typedef ck_extract_params CK_EXTRACT_PARAMS;
typedef ck_extract_params *CK_EXTRACT_PARAMS_PTR;

typedef struct ck_function_list CK_FUNCTION_LIST;
typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
Expand Down Expand Up @@ -1432,6 +1437,8 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;

#undef ck_rsa_pkcs_pss_params

#undef ck_extract_params

#undef ck_rv_t
#undef ck_notify_t

Expand Down
8 changes: 8 additions & 0 deletions src/pykcs11.i
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ typedef struct CK_DATE{
if( SWIG_IsOK( res2 ) )
break;

res2 = SWIG_ConvertPtr($input, &arg2, $descriptor(CK_EXTRACT_PARAMS*), 0);
if( SWIG_IsOK( res2 ) )
break;

res2 = SWIG_ConvertPtr($input, &arg2, $descriptor(CK_OBJECT_HANDLE*), 0);
if( SWIG_IsOK( res2 ) )
break;
Expand Down Expand Up @@ -492,6 +496,10 @@ typedef struct CK_KEY_DERIVATION_STRING_DATA {

%constant int CK_KEY_DERIVATION_STRING_DATA_LENGTH = sizeof(CK_KEY_DERIVATION_STRING_DATA);

%pointer_class(unsigned long, CK_EXTRACT_PARAMS);

%constant int CK_EXTRACT_PARAMS_LENGTH = sizeof(CK_EXTRACT_PARAMS);

typedef struct CK_MECHANISM_INFO {
%immutable;
unsigned long ulMinKeySize;
Expand Down
32 changes: 32 additions & 0 deletions test/test_derive.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,35 @@ def test_deriveKey_CKM_XOR_BASE_AND_DATA(self):

# cleanup
self.session.destroyObject(derivedKey)

def test_deriveKey_CKM_EXTRACT_KEY_FROM_KEY(self):
if self.manufacturer.startswith("SoftHSM"):
self.skipTest("SoftHSM does not support CKM_EXTRACT_KEY_FROM_KEY")

# sample from the PKCS#11 specification 3.0, section 2.43.7
# see https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061466
baseKeyTemplate = self.genericKeyTemplate + [
(PyKCS11.CKA_DERIVE, PyKCS11.CK_TRUE),
(PyKCS11.CKA_VALUE, [0x32, 0x9f, 0x84, 0xa9])]

# create a base key
baseKey = self.session.createObject(baseKeyTemplate)

expectedDerivedKeyValue = [0x95, 0x26]

derivedKeyTemplate = self.genericKeyTemplate + [(
PyKCS11.CKA_VALUE_LEN, len(expectedDerivedKeyValue))]

# extract bytes from the base key
mechanism = PyKCS11.EXTRACT_KEY_FROM_KEY_Mechanism(21)
derivedKey = self.session.deriveKey(
baseKey, derivedKeyTemplate, mechanism)
self.assertIsNotNone(derivedKey)

derivedKeyValue = self.getCkaValue(derivedKey)

# match: check derived key value
self.assertSequenceEqual(expectedDerivedKeyValue, derivedKeyValue)

self.session.destroyObject(baseKey)
self.session.destroyObject(derivedKey)
Loading