Sharing PKCS#11 modules
Multiple consumers of PKCS#11 in a process
As 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.
Solution: p11-kit
p11-kit provides functions to
coordinate initialization and finalization of any PKCS#11
module. A module may be initialized any number of times using
the p11_kit_initialize_module() function. The first time that
p11_kit_initialize_module() is called for a module, that module's
C_Initialize function is used. Later invocations for the same
module cause p11-kit to increment an internal initialization
count, rather than calling C_Initialize again.
The p11_kit_finalize_module() 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 C_Finalize function is called.
This is done in a thread-safe manner. These functions can
be used on modules that the consumer loads themselves.
Solution: proxy module
When an application is aware of the fact that coordination
is necessary between multiple consumers of a PKCS#11 module, it
can link to p11-kit and use the functions there to provide
this coordination.
However most current consumers of PKCS#11 are ignorant of
this problem, and do not link to p11-kit. In order to solve this
multiple initialization problem for all applications,
p11-kit provides a proxy compatibility
module.
This proxy module acts like a normal PKCS#11 module, but
internally loads a preconfigured set of PKCS#11 modules and
coordinates their initialization and finalization. Each slot
in the configured modules is exposed as a slot of the
p11-kit proxy module. The proxy module is
then used as a normal PKCS#11 module would be. It can be loaded by
crypto libraries like NSS and behaves as expected.
The proxy module bends the PKCS#11 rules slightly. It does
not return the CKR_CRYPTOKI_ALREADY_INITIALIZED
error code as specified in PKCS#11. However this is a small
price to pay for this compatibility.