Skip to content

Close the session when login fails in Token.open() - #247

Open
WiktorB2004 wants to merge 1 commit into
pyauth:masterfrom
WiktorB2004:fix/close-session-on-login-failure
Open

WiktorB2004 wants to merge 1 commit into
pyauth:masterfrom
WiktorB2004:fix/close-session-on-login-failure

Conversation

@WiktorB2004

Copy link
Copy Markdown

Fixes #246

Token.open() opens a session with C_OpenSession and then authenticates with C_Login. When authentication
raised (wrong or locked PIN, user already logged in, or protected authentication requested from a module without
CKF_PROTECTED_AUTHENTICATION_PATH), the exception propagated without closing the session. The caller never gets a
Session object, so the handle stayed open until C_Finalize.

This wraps the authentication block in try ... except BaseException:, calls C_CloseSession and re-raises. The
C_CloseSession return value is ignored on purpose so that it cannot mask the original error. BaseException
also covers KeyboardInterrupt during the (GIL-released) login.

Tests (tests/test_sessions.py, SoftHSMv2 only, like the neighbouring login tests):

  • test_failed_login_does_not_leak_session: a failed user login must not leave a read-only session behind. Detected
    without ctypes: a leftover read-only session makes a following security officer login fail with
    SessionReadOnlyExists.
  • test_unsupported_protected_auth_does_not_leak_session: same for the ArgumentsBad path.

Without the fix both tests fail, and the leaked session also makes later tests in the module fail (test_init_pin,
test_open_session_and_login_so). With the fix the full suite passes on SoftHSM2 2.6.1 (Debian 13, Python 3.13):
147 passed, 18 skipped. I did not run opencryptoki, Windows or macOS locally.

Token.open() opens a session with C_OpenSession and then authenticates
with C_Login. If authentication failed (wrong PIN, locked PIN, user
already logged in, or protected authentication requested from a module
that does not support it), the exception propagated without closing the
session, and since the caller never received a Session object, the
handle stayed open until C_Finalize. Close it before re-raising.

The C_CloseSession return value is ignored on purpose, so that it
cannot mask the original error.

@MatthiasValvekens MatthiasValvekens left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch; I'd factor the fix a bit differently, though.

Comment thread pkcs11/_pkcs11.pyx
pin_data = pin
pin_length = <CK_ULONG> len(pin)

except BaseException:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of catch-all except clauses where all the possible error cases are basically directly spelled out in the try: block.

I'd hoist the check that leads to ArgumentsBad to before the C_OpenSession invocation. Then you can simply branch on the return value of C_Login to decide whether to close the session and throw an error, or to wrap the session with Session.make(...).

Comment thread tests/test_sessions.py
with self.token.open(rw=True, so_pin=TOKEN_SO_PIN) as session:
self.assertIsInstance(session, pkcs11.Session)

@Only.softhsm2 # We don't have credentials to do this for other platforms

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Limiting this to @Only.softhsm2 is fine, but that comment is neither here nor there. Whether there are credentials or not is a property of the environment, not of the test code itself.

I'd just drop the comment.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 78.57143% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.29%. Comparing base (fc44b72) to head (b5d69f7).
⚠️ Report is 11 commits behind head on master.

Files with missing lines Patch % Lines
pkcs11/_pkcs11.pyx 78.57% 3 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #247      +/-   ##
==========================================
+ Coverage   91.52%   92.29%   +0.77%     
==========================================
  Files          15       15              
  Lines        2713     2790      +77     
  Branches       27       27              
==========================================
+ Hits         2483     2575      +92     
+ Misses        228      213      -15     
  Partials        2        2              
Flag Coverage Δ
unittests 92.29% <78.57%> (+0.77%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Token.open() leaks the session when C_Login fails

3 participants