Skip to content

Commit

Permalink
Merge pull request #128 from fuzzykat/feature/ckm_extract_key_from_key
Browse files Browse the repository at this point in the history
add CKM_EXTRACT_KEY_FROM_KEY mechanism
  • Loading branch information
LudovicRousseau authored Jan 19, 2025
2 parents 6674d1e + 10903b7 commit 059aca2
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
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)

0 comments on commit 059aca2

Please sign in to comment.