From 6e88d9d937fde81848016c75f18e7ef5a47fc385 Mon Sep 17 00:00:00 2001 From: Matthias Valvekens Date: Fri, 19 Jun 2026 23:21:42 +0200 Subject: [PATCH] C_GetInterface for PKCS#11 3.0, 3.2 APIs This commit adds the plumbing needed to obtain and propagate the v3.0 and v3.2 function list at runtime. This is necessary to support ML-KEM and other new features. --- extern/load_module.c | 2 + extern/load_module.h | 3 +- pkcs11/_pkcs11.pxd | 165 +++++++++++++++++++++++++++++++++++++++++++ pkcs11/_pkcs11.pyx | 35 ++++++++- 4 files changed, 201 insertions(+), 4 deletions(-) diff --git a/extern/load_module.c b/extern/load_module.c index a4565ec9..d6fa3057 100644 --- a/extern/load_module.c +++ b/extern/load_module.c @@ -38,6 +38,7 @@ static P11_HANDLE* p11_open(PyObject *path_str) { result = (P11_HANDLE*) PyMem_Malloc(sizeof(P11_HANDLE)); result->lib_handle = handle; result->get_function_list_ptr = ptr; + result->get_interface_ptr = GetProcAddress(handle, "C_GetInterface"); } } return result; @@ -85,6 +86,7 @@ static P11_HANDLE* p11_open(PyObject *path_str) { result = (P11_HANDLE*) PyMem_Malloc(sizeof(P11_HANDLE)); result->lib_handle = handle; result->get_function_list_ptr = ptr; + result->get_interface_ptr = dlsym(handle, "C_GetInterface"); } } return result; diff --git a/extern/load_module.h b/extern/load_module.h index a574fe0c..360fa4a3 100644 --- a/extern/load_module.h +++ b/extern/load_module.h @@ -12,7 +12,8 @@ typedef void *LIB_HANDLE; #ifndef P11_HANDLE typedef struct P11_HANDLE { LIB_HANDLE lib_handle; - void * get_function_list_ptr; + void *get_function_list_ptr; + void *get_interface_ptr; /* C_GetInterface direct export; NULL for v2.0 libs */ } P11_HANDLE; #endif diff --git a/pkcs11/_pkcs11.pxd b/pkcs11/_pkcs11.pxd index ba1903d1..cfa53801 100644 --- a/pkcs11/_pkcs11.pxd +++ b/pkcs11/_pkcs11.pxd @@ -280,6 +280,11 @@ cdef extern from '../extern/cryptoki.h': CK_ULONG ulContextDataLen CK_BYTE *pContextData + ctypedef struct CK_INTERFACE: + CK_UTF8CHAR *pInterfaceName + void *pFunctionList + CK_FLAGS flags + cdef struct CK_FUNCTION_LIST: CK_VERSION version ## pointers to library functions are stored here @@ -600,10 +605,170 @@ cdef extern from '../extern/cryptoki.h': CK_SLOT_ID *slot, void *pRserved) nogil + + cdef struct CK_FUNCTION_LIST_3_0: + CK_RV C_GetInterfaceList(CK_INTERFACE *pInterfacesList, + CK_ULONG *pulCount) nogil + + CK_RV C_GetInterface(CK_UTF8CHAR *pInterfaceName, + CK_VERSION *pVersion, + CK_INTERFACE **ppInterface, + CK_FLAGS flags) nogil + + CK_RV C_LoginUser(CK_SESSION_HANDLE hSession, + CK_USER_TYPE userType, + CK_UTF8CHAR *pPin, + CK_ULONG ulPinLen, + CK_UTF8CHAR *pUsername, + CK_ULONG ulUsernameLen) nogil + + CK_RV C_SessionCancel(CK_SESSION_HANDLE hSession, + CK_FLAGS flags) nogil + + CK_RV C_MessageEncryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM *pMechanism, + CK_OBJECT_HANDLE hKey) nogil + + CK_RV C_EncryptMessage(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pAssociatedData, + CK_ULONG ulAssociatedDataLen, + CK_BYTE *pPlaintext, + CK_ULONG ulPlaintextLen, + CK_BYTE *pCiphertext, + CK_ULONG *pulCiphertextLen) nogil + + CK_RV C_EncryptMessageBegin(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pAssociatedData, + CK_ULONG ulAssociatedDataLen) nogil + + CK_RV C_EncryptMessageNext(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pPlaintextPart, + CK_ULONG ulPlaintextPartLen, + CK_BYTE *pCiphertextPart, + CK_ULONG *pulCiphertextPartLen, + CK_FLAGS flags) nogil + + CK_RV C_MessageEncryptFinal(CK_SESSION_HANDLE hSession) nogil + + CK_RV C_MessageDecryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM *pMechanism, + CK_OBJECT_HANDLE hKey) nogil + + CK_RV C_DecryptMessage(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pAssociatedData, + CK_ULONG ulAssociatedDataLen, + CK_BYTE *pCiphertext, + CK_ULONG ulCiphertextLen, + CK_BYTE *pPlaintext, + CK_ULONG *pulPlaintextLen) nogil + + CK_RV C_DecryptMessageBegin(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pAssociatedData, + CK_ULONG ulAssociatedDataLen) nogil + + CK_RV C_DecryptMessageNext(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pCiphertextPart, + CK_ULONG ulCiphertextPartLen, + + CK_ULONG *pulPlaintextPartLen, + CK_FLAGS flags) nogil + + CK_RV C_MessageDecryptFinal(CK_SESSION_HANDLE hSession) nogil + + CK_RV C_MessageSignInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM *pMechanism, + CK_OBJECT_HANDLE hKey) nogil + + CK_RV C_SignMessage(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pData, + CK_ULONG ulDataLen, + CK_BYTE *pSignature, + CK_ULONG *pulSignatureLen) nogil + + CK_RV C_SignMessageBegin(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen) nogil + + CK_RV C_SignMessageNext(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pData, + CK_ULONG ulDataLen, + CK_BYTE *pSignature, + CK_ULONG *pulSignatureLen) nogil + + CK_RV C_MessageSignFinal(CK_SESSION_HANDLE hSession) nogil + + CK_RV C_MessageVerifyInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM *pMechanism, + CK_OBJECT_HANDLE hKey) nogil + + CK_RV C_VerifyMessage(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pData, + CK_ULONG ulDataLen, + CK_BYTE *pSignature, + CK_ULONG ulSignatureLen) nogil + + CK_RV C_VerifyMessageBegin(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen) nogil + + CK_RV C_VerifyMessageNext(CK_SESSION_HANDLE hSession, + void *pParameter, + CK_ULONG ulParameterLen, + CK_BYTE *pData, + CK_ULONG ulDataLen, + CK_BYTE *pSignature, + CK_ULONG ulSignatureLen) nogil + + CK_RV C_MessageVerifyFinal(CK_SESSION_HANDLE hSession) nogil + + + cdef struct CK_FUNCTION_LIST_3_2: + CK_RV C_EncapsulateKey(CK_SESSION_HANDLE session, + CK_MECHANISM *mechanism, + CK_OBJECT_HANDLE public_key, + CK_ATTRIBUTE *template, + CK_ULONG count, + CK_BYTE *ciphertext, + CK_ULONG *ciphertext_len, + CK_OBJECT_HANDLE *key) nogil + CK_RV C_DecapsulateKey(CK_SESSION_HANDLE session, + CK_MECHANISM *mechanism, + CK_OBJECT_HANDLE private_key, + CK_ATTRIBUTE *template, + CK_ULONG count, + CK_BYTE *ciphertext, + CK_ULONG ciphertext_len, + CK_OBJECT_HANDLE *key) nogil + # The only external API call that must be defined in a PKCS#11 library # All other APIs are taken from the CK_FUNCTION_LIST table ctypedef CK_RV (*C_GetFunctionList_ptr) (CK_FUNCTION_LIST **) nogil +ctypedef CK_RV (*C_GetInterface_ptr)( + CK_UTF8CHAR *pInterfaceName, + CK_VERSION *pVersion, + CK_INTERFACE **ppInterface, + CK_FLAGS flags +) nogil + ctypedef CK_RV (*KeyOperationInit) ( CK_SESSION_HANDLE session, CK_MECHANISM *mechanism, diff --git a/pkcs11/_pkcs11.pyx b/pkcs11/_pkcs11.pyx index 48b0dda1..e8bb4cfb 100644 --- a/pkcs11/_pkcs11.pyx +++ b/pkcs11/_pkcs11.pyx @@ -35,9 +35,13 @@ cdef class lib(HasFuncList) cdef class HasFuncList: cdef CK_FUNCTION_LIST *funclist + cdef CK_FUNCTION_LIST_3_0 *funclist30 + cdef CK_FUNCTION_LIST_3_2 *funclist32 def __cinit__(self, *args, **kwargs): self.funclist = NULL + self.funclist30 = NULL + self.funclist32 = NULL cdef assertRV(rv) with gil: @@ -451,6 +455,8 @@ cdef class Token(HasFuncList, types.Token): cdef Token token = Token.__new__(Token) token.funclist = slot.funclist + token.funclist30 = slot.funclist30 + token.funclist32 = slot.funclist32 token.slot = slot token.label = _CK_UTF8CHAR_to_str(label) token.serial = serial_number.rstrip() @@ -870,6 +876,8 @@ cdef class Session(HasFuncList, types.Session): cdef Session session = Session.__new__(Session) session.funclist = token.funclist + session.funclist30 = token.funclist30 + session.funclist32 = token.funclist32 session.token = token session.handle = handle @@ -1960,6 +1968,7 @@ _CLASS_MAP = { cdef extern from "../extern/load_module.c": ctypedef struct P11_HANDLE: void *get_function_list_ptr + void *get_interface_ptr object p11_error() P11_HANDLE* p11_open(object path_str) @@ -2063,6 +2072,25 @@ cdef class lib(HasFuncList): self._cryptoki_version = info.cryptokiVersion self._library_version = info.libraryVersion + # Prefer v3.2, fall back to v3.0. PKCS#11 3.0+ libraries export + # C_GetInterface as a direct symbol; older libraries leave it absent. + cdef C_GetInterface_ptr get_interface + cdef CK_INTERFACE *iface + cdef CK_VERSION ver + if self._p11_handle.get_interface_ptr != NULL: + get_interface = self._p11_handle.get_interface_ptr + ver.major = 3 + ver.minor = 2 + retval = get_interface("PKCS 11", &ver, &iface, 0) + if retval == CKR_OK and iface != NULL: + self.funclist32 = iface.pFunctionList + else: + ver.major = 3 + ver.minor = 0 + retval = get_interface("PKCS 11", &ver, &iface, 0) + if retval == CKR_OK and iface != NULL: + self.funclist30 = iface.pFunctionList + @property def library_version(self): """Hardware version (:class:`tuple`).""" @@ -2117,9 +2145,10 @@ cdef class lib(HasFuncList): retval = self.funclist.C_GetSlotInfo(slot_id, &info) assertRV(retval) - slots.append( - Slot.make(self.funclist, slot_id, info, self._cryptoki_version) - ) + slot = Slot.make(self.funclist, slot_id, info, self._cryptoki_version) + slot.funclist30 = self.funclist30 + slot.funclist32 = self.funclist32 + slots.append(slot) return slots