808bits

CKR_SESSION_HANDLE_INVALID

PKCS#11 return value · 0x000000B3 · decimal 179
hex 0x000000B3 decimal 179 name CKR_SESSION_HANDLE_INVALID

A session handle is a number that means something only to the library instance that issued it, in the process that asked for it. Almost every report of this error is a handle that outlived one of those conditions, and the interesting question is which. Three of the four common answers have nothing to do with sessions at all, which is why the code reads as mysterious the first time you hit it.

What the token is reporting

You passed a session handle the library cannot resolve. Either it never issued that handle, or it did and the session behind it no longer exists, or the library itself has been reset since.

Likely causes

Ordered by how often they turn out to be the answer. That ordering is a judgement from experience, not a measured frequency.

The process forked and the child kept using the parent's handles

This is the one that catches people. A PKCS#11 library’s state is per-process, and a fork copies the memory without telling the token. The child inherits handles that the library on the other side of the connection has never heard of, and the first call fails. Any preforking server model reproduces it, which is why it so often looks like “works in testing, fails under the web server”.

Check it: Log the process id next to every handle you use, and compare it against the process id that opened the session. If they differ, this is your answer and nothing else needs checking.

Fix: Initialize the library after the fork, not before, and never share handles across a fork. If the library supports the locking arguments to initialization, that still does not make handles survive a fork.

Something called C_Finalize

Finalizing tears down every session in the process. In a single application that is easy to see, but in a process where two components each load the same library, one component’s shutdown invalidates the other’s handles. Anything using a shared cryptographic provider is exposed to this.

Check it: Search the whole process, dependencies included, for a finalize call. If a library you depend on wraps PKCS#11, assume it will finalize at some point unless its documentation promises otherwise.

The session was closed and the handle was cached

Handles can be reused, which makes this worse than a simple failure. A handle you closed can be handed back out for a new session, so a stale handle sometimes fails and sometimes silently addresses the wrong session.

Check it: Look for handles stored in anything longer-lived than the session: connection pools, thread locals, caches and retry wrappers are the usual places.

The token went away and took its sessions with it

A removal, a reset or a failover invalidates every session on that token. The first call afterwards may report the missing device, and later calls report only the invalid handle, so what you see depends on the order your code happens to make calls in.

Check it: Check whether a device event was reported to any part of the application just before the first failure, and check the token is still present.

Which calls return it

C_GetSessionInfo, C_FindObjectsInit, C_SignInit, C_Logout, C_CloseSession

What it is not

It is not a sign that the session was opened wrongly. A session that opened and worked was valid. Something invalidated it afterwards, so look for the event rather than re-reading your open call.

Often confused with

  • CKR_OBJECT_HANDLE_INVALID: The same shape of mistake one level down. Object handles are scoped to the session, so a session that survives a fork intact will still hand you meaningless object handles.
  • CKR_CRYPTOKI_NOT_INITIALIZED: What you get when the library was finalized and nothing re-initialized it. Which of the two you see after a fork depends on the library.

See also

Sources

Every description, cause and check on this page is written from scratch. The specification is cited for the constant's name and its number, which are facts, and for nothing else.