From f6a177df497ad1d9067d53abb5a19531f75e31ce Mon Sep 17 00:00:00 2001 From: Joe Doss Date: Thu, 16 Apr 2026 10:52:44 -0500 Subject: [PATCH] Handle CKR_USER_ALREADY_LOGGED_IN in PKCS#11 session open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When both the Nitrokey HSM provider and the HSM cache backend open PKCS#11 sessions on the same slot, the second C_Login call fails with CKR_USER_ALREADY_LOGGED_IN because the slot only allows one login. The cache backend's open() raised ProviderError and fell back to live provider lookups, silently disabling the entire cache. This also happens across process restarts: if psi serve is killed before its finally block runs close()/logout(), the next serve process inherits a stale login on the slot. Treat CKR_USER_ALREADY_LOGGED_IN as success — the slot is already authenticated and the session is usable. --- psi/providers/nitrokeyhsm/pkcs11.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/psi/providers/nitrokeyhsm/pkcs11.py b/psi/providers/nitrokeyhsm/pkcs11.py index 39b1583..b966157 100644 --- a/psi/providers/nitrokeyhsm/pkcs11.py +++ b/psi/providers/nitrokeyhsm/pkcs11.py @@ -52,8 +52,11 @@ def open(self, pin: str) -> None: try: self._session.login(pin, CKU_USER) except PyKCS11Error as e: - msg = f"HSM login failed: {e}. Check your PIN." - raise ProviderError(msg, provider_name="nitrokeyhsm") from e + if "CKR_USER_ALREADY_LOGGED_IN" in str(e): + pass + else: + msg = f"HSM login failed: {e}. Check your PIN." + raise ProviderError(msg, provider_name="nitrokeyhsm") from e def close(self) -> None: """Log out and close the session."""