Add opt-in no_login_cache to release the token login session on key free.#657
Open
dantecmelo wants to merge 4 commits into
Open
Add opt-in no_login_cache to release the token login session on key free.#657dantecmelo wants to merge 4 commits into
dantecmelo wants to merge 4 commits into
Conversation
Signing with one short-lived process per file against a token with a hard session limit (e.g. YubiHSM 2, 16 sessions) exhausts sessions: libp11 skips its teardown at process exit (g_shutdown_mode set by the atexit handler), so the cached login session is never released; and on the YubiHSM only C_Logout (not C_CloseSession) frees the authenticated session. This adds an opt-in 'no_login_cache' provider parameter and a public PKCS11_set_no_login_cache() API. When set, the token is logged out and its sessions are closed as soon as a private key object is freed (RSA/EC finish callbacks), during normal runtime instead of at the skipped exit. Re-login happens on the next key load. Behaviour is unchanged when the parameter is unset. Signed-off-by: Dante Melo <dante_melo@hotmail.com>
Signed-off-by: Dante Melo <dante_melo@hotmail.com>
The opt-in no_login_cache option released the login session only from the RSA/EC method finish callbacks. Those never run on the provider path: keymgmt_load() transfers ownership of the wrapped P11_KEYDATA to OpenSSL, so the legacy EVP_PKEY libp11 wraps never reaches refcount 0 during a run -- the finish callbacks would only fire at process exit, which libp11 deliberately skips (g_shutdown_mode). As a result the token login session was still leaked and the 17th short-lived signing process failed with CKR_SESSION_COUNT. Hook the provider's own key-free instead. keymgmt_free() now calls p11_keydata_release_login(), which -- for a private key when no_login_cache is set -- calls the new pkcs11_release_login_for_pkey() to locate the slot via the wrapped key's RSA/EC ex-data and release the login session during healthy runtime (C_Logout + close sessions). Covers RSA and ECDSA. The existing finish-callback hooks are kept for the engine front-end. Files: - p11_key.c / libp11-int.h: pkcs11_release_login_for_pkey() - provider_helpers.c / .h: p11_keydata_release_login() (+ libp11-int.h include) - provider.c: call it from keymgmt_free() NOTE: still contains temporary LIBP11-DBG instrumentation; remove before the PR. Signed-off-by: Dante Melo <dante_melo@hotmail.com>
Signing one file per short-lived process against a token with a hard limit on concurrent authenticated sessions (e.g. YubiHSM 2, 16 sessions) exhausts them: libp11 skips its teardown at process exit (g_shutdown_mode), so the cached login session is never released, and on the YubiHSM only C_Logout (not C_CloseSession) frees the authenticated session. After 16 files the 17th fails with CKR_SESSION_COUNT. Add an opt-in no_login_cache provider parameter (and a public PKCS11_set_no_login_cache() API). When set, the token is logged out and its sessions closed as soon as a private key is freed, during normal runtime instead of at the skipped exit. For the OpenSSL 3 provider this happens in keymgmt_free (the legacy RSA/EC finish callbacks never run there, since keymgmt_load transfers ownership of the wrapped key); the engine path uses the finish callbacks. Covers RSA and ECDSA. Behaviour is unchanged when the parameter is unset. Signed-off-by: Dante Melo <dante_melo@hotmail.com>
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.
Pull Request Type
Related Issue
Issue number: N/A
Current Behavior
libp11 caches the token login session for the lifetime of the process and would
normally release it at exit. However, its exit-time teardown is deliberately
skipped: the
atexithandler inutil_uri.csetsg_shutdown_mode, which makesUTIL_CTX_free_libp11skipPKCS11_release_all_slots/C_Finalize(to avoidcalling into the module during OpenSSL's teardown). As a result the login session
is never released.
On a token with a hard limit on concurrent authenticated sessions — notably the
YubiHSM 2 (max 16) — running one short-lived
opensslprocess per file leaks onesession per process (on the YubiHSM,
C_CloseSessiondoes not free theauthenticated session; only
C_Logout/C_Finalizedoes). After 16 files the17th fails with
CKR_SESSION_COUNT("could not read private key").New Behavior
Adds an opt-in
no_login_cacheprovider parameter (envPKCS11_NO_LOGIN_CACHE)and a matching public
PKCS11_set_no_login_cache()API. When enabled, the tokenis logged out and its sessions are closed as soon as a private key object is
freed — during normal runtime instead of at the skipped exit. Re-login happens
automatically on the next key load. With the parameter unset, behaviour is
byte-for-byte unchanged.
Scope of Changes
pkcs11_slot_logout_session_only()(p11_slot.c), a per-context/per-slotno_login_cacheflag, and the publicPKCS11_set_no_login_cache()(
p11_front.c,libp11.h,libp11.exports).no_login_cacheparameter mirroringforce_login(
provider_helpers.c,util_uri.c,util.h). Because the provider'skeymgmt_loadtransfers ownership of the key to OpenSSL, the wrapped key'slegacy RSA/EC
finishcallback does not run during the process — so the logoutis triggered from
keymgmt_free(provider.c) viap11_keydata_release_login(),which reaches the slot through the wrapped key's RSA/EC ex-data
(
pkcs11_release_login_for_pkey()inp11_key.c).finishcallbacks (
p11_rsa.c,p11_ec.c), where keys are freed via that path.Testing
Verified on a YubiHSM 2 (max 16 sessions) with the OpenSSL 3 provider on Debian:
a 50-iteration loop of
openssl dgst -sha512 -sign, one process per file,previously failed at the 17th with
CKR_SESSION_COUNT; withno_login_cache = 1it now completes all 50. A PKCS#11 trace shows one
C_Logoutper key free, andthe device's active session count returns to baseline between runs.
Additional Notes
byte-for-byte unchanged.
pkcs11_wipe_cacheorpkcs11_get_session, so it cannot re-enter the key-freecallback or nest
slot->lock; it is idempotent via a locklesslogged_incheck.scope — libp11 has no per-key finish callback for it, so there is no equivalent
hook.
process that signs repeatedly benefits from the cached login, so it should
leave the option off — hence opt-in.
is the behaviour libp11 adopted to avoid an exit-time crash/deadlock (cf. Library cleanup issues with OpenSSL - libp11 - yubihsm_pkcs11.so chain #527).
License Declaration