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.