808bits

CKR_CRYPTOKI_ALREADY_INITIALIZED

PKCS#11 return value · 0x00000191 · decimal 401
hex 0x00000191 decimal 401 name CKR_CRYPTOKI_ALREADY_INITIALIZED

Library state is per process, so the second component in a process to load the same module and initialise it gets this code, and what happens next depends entirely on whether the caller treats the answer as an error. Most of the pain is in that handling: one side finalises and the other side's sessions die, or the child of a fork inherits an initialised flag for a library that no longer works in that process.

What the token is reporting

The library already has state in this process and declined to initialise again. Nothing was changed. The existing initialisation, and every session under it, is intact.

Likely causes

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

Two components in one process load the same module

A TLS stack and the application, an OpenSSL provider plus direct use, a JVM provider next to native code. Each believes it owns the library. The second to initialise gets this code, and if it responds by finalising, it tears down the first one’s sessions, since finalise is per process too.

Check it: Log every initialise and finalise with the calling component. Look in particular for a provider or plugin that initialises on load.

Fix: Treat the code as success and carry on. Never finalise from the component that received it.

A fork, and the child inherited the flag

The child has a copy of the parent’s memory, including the initialised flag, and a library that checks only the flag returns this code to the child’s initialise. The child’s inherited handles do not work. Some libraries notice the process id changed and reinitialise silently, and those do not produce this code at all.

Check it: Compare the current process id with the one that performed the initialise. Preforking servers are the usual place.

Fix: In the child, finalise and then initialise, or use a library that registers fork handlers.

A recovery path that reinitialises after an error

Error handlers that respond to any failure by initialising again, on the theory that the library might have been finalised, get this code on every failure that was not that.

Check it: Trace the calls. An initialise that follows a failed operation rather than a finalise is the pattern.

A recursive initialise from inside initialise

Loading a crypto library’s configuration during initialise can load a provider that calls straight back into the same PKCS#11 module. One open source library special-cases this. Others return the code, and the outer initialise then fails in confusing ways.

Check it: Take a stack trace at the failing call and look for the same library twice in it.

Which calls return it

C_Initialize

What it is not

It is not a threading problem. Concurrent initialise calls from threads are serialised, and only one of them wins. It is also not fatal, and a caller that treats it as success is behaving correctly.

Often confused with

  • CKR_CRYPTOKI_NOT_INITIALIZED: The twin. After a fork one library says already initialised and another says not initialised, for the same underlying reason.
  • CKR_SESSION_HANDLE_INVALID: What the fork case turns into once the child stops trying to initialise and starts using the inherited handles.

By library

SoftHSMv2

A plain flag check with no process id comparison ([SoftHSM.cpp](https:/ /github.com/softhsm/SoftHSMv2/blob/884cb38f3d2012a0447bd5f50dbd29c42998 7c41/src/lib/SoftHSM.cpp#L490-L499)). A forked child that inherited an initialised SoftHSM gets this code and has to finalise first.

OpenSC

Compares the current process id with the one that initialised and, if they differ, finalises and starts over before the flag is consulted (pkcs11-global.c). The child of a fork does not see this code from OpenSC.

IBM opencryptoki

Registers fork handlers. The child’s handler finalises so that the child starts clean and its own initialise succeeds ([api_interface.c](h ttps://github.com/opencryptoki/opencryptoki/blob/430a47d7478236891ff174 d096b55e04026981a8/usr/lib/api/api_interface.c#L425-L452)). The comment in the source puts it well: a forked child is no PKCS#11 application after fork. The recursive case through OpenSSL configuration is special-cased in the same file.

YubiHSM 2

A single flag check in the initialise function, so it behaves like SoftHSM across a fork.

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.