PKCS#11 is a standardized interface for cryptographic tokens. From RSA Laboratories:
This standard specifies an API, called Cryptoki, to devices which hold cryptographic information and perform cryptographic functions. Cryptoki, pronounced crypto-key and short for cryptographic token interface, follows a simple object-based approach, addressing the goals of technology independence (any kind of device) and resource sharing (multiple applications accessing multiple devices), presenting to applications a common, logical view of the device called a cryptographic token.
The core specification can be found at http://www.rsa.com/rsalabs/node.asp?id=2133 along with the required C/C++ header files pkcs11.h, pkcs11t.h, and pkcs11f.h. These outline the standard data types and functions found in a PKCS#11 library provided by a cryptographic token provider/manufacturer.
The first thing you’ll need to do is create a project (this article doesn’t cover any of the setup for a normal C/C++ console application) and add the RSA Laboratories header files found on their site. Alternately you may also have been provided customized header files from the cryptographic token vendor. In either case, create a source file and add those headers to it.
Now that the DLL is loaded, we need to initialize the Cryptoki library. This is done using the PKCS#11 function C_Initialize(). The function I’ve outlined below is called LoadProc() [Load Process] and takes our DLL handle (hLib) and searches the DLL for a process or function specified in the variable “func”. For instance, to grab a pointer to C_Initialize() we need to write: LoadProc(hLib, “C_Initialize”) and it should return a non-null value pointing the imported function. Before we can really use that function we need to define what the prototype of the function is. In this case, C_Initialize_decl should be prototyped as:
typedef int (*C_Initialize_decl)(void *);
We can then call the proper LoadProc function like this:
C_Initialize = (C_Initialize_decl)LoadProc(hLib,“C_Initialize”);
Here’s the complete LoadProc() function. This version does the error checking up-front and aborts on error. Most implementations will do the error check after this function so that it can decide if it’s worth aborting over or not.
Once we have a valid pointer to C_Initialize() we can actually perform the routine. Now that the process is attached to a local function pointer variable all we have to do is simply:
C_Initialize() should return CKR_OK is all went well. If not, you should dump the error code and compare it to the CKR_* values in pkcs11t.h. That wraps up how to load a DLL and call an imported function. I hope you enjoyed and stay tuned for more!