feat: add ZTS support and persistent HSM session pooling#81
Open
mroest wants to merge 1 commit into
Open
Conversation
Implement thread-safe PKCS#11 bindings and a per-thread session pool to reduce the cost of repeated C_OpenSession calls against hardware security modules (HSMs). Motivated by FrankenPHP worker-mode, where PHP threads are long-lived and session setup latency dominates. Process-wide library registry (pkcs11module.c) - pkcs11_lib_record holds dlhandle, functionList and a finalized flag - HashTable pkcs11_libs keyed by realpath, protected by pthread_mutex - Double-checked locking in Module::__construct prevents duplicate C_Initialize calls across threads - Library lifetime is module lifetime; C_Finalize/dlclose in MSHUTDOWN Per-thread session pool (php_pkcs11.h, pkcs11session.c) - ZEND_MODULE_GLOBALS adds a session_pool HashTable per thread - Pool key: "realpath:slotID:flags"; one entry per key (no linked list) - Pool holds unauthenticated sessions only: C_Logout is called before returning a handle to the pool, so every reuse requires fresh login - Tainted sessions (active C_*Init in flight) are closed on GC, never pooled, preventing state leakage across requests Stale-session resilience (pkcs11int.h) - PKCS11_SESSION_CALL: wraps C_*Init and single-shot ops; on stale errors (CKR_SESSION_HANDLE_INVALID etc.) evicts the pool entry, opens a fresh session, and retries the expression once - PKCS11_SESSION_EVICT: wraps C_*Update/C_*Final; evicts only because a new session cannot replay prior Init/Update state Module lifecycle (pkcs11.c) - PHP_MINIT initialises library registry and module globals - PHP_MSHUTDOWN sets finalized=true on each lib record before C_Finalize so that globals_dtor can skip C_CloseSession safely regardless of shutdown order - Non-ZTS build: globals_dtor called explicitly in MSHUTDOWN because ZEND_INIT_MODULE_GLOBALS ignores the destructor argument there - ZTS C_Initialize passes CKF_OS_LOCKING_OK; non-ZTS passes NULL All call sites wrapped (pkcs11key.c, pkcs11session.c, context files, pkcs11object.c, pkcs11digestcontext.c) Tests added (tests/0500-0511.phpt) - 0500: module object reuse across requests - 0501: failed constructor does not under-count - 0502: session pool reuse across requests - 0503: wrong credentials rejected on fresh and pooled sessions - 0504: GC cleanup does not crash; re-creation works - 0505: stale pool entry skipped via dead flag - 0506: separate library paths use independent pool entries - 0507: tainted session is closed, not pooled - 0508: ephemeral session issued when pool entry is in use - 0509: single-shot sign clears taint; pool reuse succeeds - 0510: wrong PIN on fresh session throws; correct PIN works - 0511: login succeeds after pool reuse, proving C_Logout ran
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #80
Implement thread-safe PKCS#11 bindings and a per-thread session pool to reduce the cost of repeated C_OpenSession calls against hardware security modules (HSMs). Motivated by FrankenPHP worker-mode, where PHP threads are long-lived and session setup latency dominates.
Process-wide library registry (pkcs11module.c)
Per-thread session pool (php_pkcs11.h, pkcs11session.c)
Stale-session resilience (pkcs11int.h)
Module lifecycle (pkcs11.c)
All call sites wrapped (pkcs11key.c, pkcs11session.c, context files, pkcs11object.c, pkcs11digestcontext.c)
Tests added (tests/0500-0511.phpt)