Sharing PKCS#11 modulesMultiple consumers of PKCS#11 in a processAs more and more applications and libraries use PKCS#11 we run
into a very basic problem. The PKCS#11 modules cannot be initialized and
finalized properly without coordination between the various consumers.
An example: An application might use GnuTLS for
TLS connections, and use libgcr for display of certificates. Both of
these want to load (and initialze) the same PKCS#11 modules. There are
many places where this situation occurs, including large applications
like Evolution which due to their dependencies end up using both NSS and
GnuTLS.Consumer A loads a PKCS#11 module and uses the module's
C_Initialize function to initialize it, which works as expected.
When consumer B initializes the module (also using C_Initialize),
the error code CKR_CRYPTOKI_ALREADY_INITIALIZED
is correctly returned. This is normal PKCS#11 specification
defined behavior for when a module is initalized twice in the
same process. If consumer B is aware of this situation they may
choose to ignore this error code.However when the consumer A is done with its use of the
PKCS#11 module it finalizes the module using the module's
C_Finalize function. This is expected of a well behaved PKCS#11
consumer. This then causes errors and/or crashes for consumer B,
which cannot know that the module has now been finalized out
from underneath it.It is necessary for the two consumers to coordinate their
initialization and finalization in some fashion. In
p11-kit we provide this coordination in a
loosely coupled, backwards compatible, and flexible way.Managed modulesp11-kit wraps PKCS#11 modules to manage
them and customize their functionality so that they are able
to be shared between multiple callers in the same process.Each caller that uses the
p11_kit_modules_load()
or p11_kit_module_load()
function gets independent wrapped PKCS#11 module(s). This is unless a caller
or module configuration specifies that a module should be used in an
unmanaged fashion.When modules are managed, the following aspects are wrapped and
coordinated:Calls to C_Initialize and
C_Finalize can be called by multiple
callers.The first time that the managed module
C_Initialize is called, the PKCS#11 module's actual
C_Initialize function is called. Subsequent calls by
other callers will cause p11-kit to increment an
internal initialization count, rather than calling
C_Initialize again.Multiple callers can call the managed
C_Initialize function concurrently from different
threads and p11-kit will guarantee that this managed
in a thread-safe manner.When the managed module C_Finalize is used
to finalize a module, each time it is called it decrements the internal
initialization count for that module. When the internal initialization
count reaches zero, the module's actual C_Finalize
function is called.Multiple callers can call the managed C_Finalize
function concurrently from different threads and p11-kit
will guarantee that this managed in a thread-safe manner.Call to C_CloseAllSessions only close the
sessions that the caller of the managed module has opened. This allows the
C_CloseAllSessions function to be used without closing
sessions for other callers of the same PKCS#11 module.