diff --git a/PyKCS11/__init__.py b/PyKCS11/__init__.py index 8cabb33..1383ec0 100644 --- a/PyKCS11/__init__.py +++ b/PyKCS11/__init__.py @@ -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 diff --git a/src/opensc/pkcs11.h b/src/opensc/pkcs11.h index 45d3b91..a6a4581 100644 --- a/src/opensc/pkcs11.h +++ b/src/opensc/pkcs11.h @@ -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) @@ -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; @@ -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 diff --git a/src/pykcs11.i b/src/pykcs11.i index 52c68af..99b2a8d 100644 --- a/src/pykcs11.i +++ b/src/pykcs11.i @@ -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; @@ -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; diff --git a/test/test_derive.py b/test/test_derive.py index 2045929..6e82b3d 100644 --- a/test/test_derive.py +++ b/test/test_derive.py @@ -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)