Skip to main content
PKCS#11 (also called Cryptoki) is the OASIS standard API for interacting with cryptographic devices such as hardware security modules (HSMs), smart cards, and hardware tokens. It defines a vendor-neutral C interface that applications use to perform cryptographic operations — key generation, signing, encryption, and more — without needing to know the implementation details of the underlying device. SoftHSM v2 implements PKCS#11 version 3.2 (the pkcs11 header was updated to 3.2.0 in SoftHSM 2.7.0). The library is exposed as a shared object (libsofthsm2.so on Linux/macOS, softhsm2.dll on Windows) that any PKCS#11-aware application can load at runtime.

Loading the library

There are two common ways to load libsofthsm2.so from a C or C++ application.
#include <dlfcn.h>
#include "pkcs11.h"

void *lib = dlopen("/usr/lib/softhsm/libsofthsm2.so", RTLD_NOW);
if (!lib) {
    fprintf(stderr, "dlopen: %s\n", dlerror());
    return 1;
}

CK_C_GetFunctionList pGetFunctionList =
    (CK_C_GetFunctionList)dlsym(lib, "C_GetFunctionList");

CK_FUNCTION_LIST_PTR p11;
pGetFunctionList(&p11);
/* use p11->C_Initialize, p11->C_OpenSession, … */
When using dlopen, always call C_GetFunctionList to obtain the function-list pointer rather than resolving each symbol individually. This is the portable, spec-compliant approach and is how most PKCS#11 middleware works.

Initialization sequence

Every application that uses the library must follow this lifecycle:
1

C_Initialize

Initialize the library and optionally supply mutex callbacks for thread safety.
2

C_GetSlotList

Enumerate available slots (virtual token slots created by softhsm2-util).
3

C_OpenSession

Open a session on the chosen slot. Pass CKF_SERIAL_SESSION (and CKF_RW_SESSION for write operations) in the flags argument.
4

C_Login

Authenticate as CKU_USER (or CKU_SO for administrative operations) by providing the PIN.
5

Cryptographic operations

Perform key generation, signing, encryption, or any other operations. Most operations follow an InitUpdate (optional) → Final pattern.
6

C_CloseSession / C_Logout

Close the session when finished. Logout is implicit when the last session on a token is closed.
7

C_Finalize

Shut down the library cleanly before the process exits.

Minimal C example

#include <stdio.h>
#include <dlfcn.h>
#include "pkcs11.h"

int main(void)
{
    /* 1. Load the library */
    void *lib = dlopen("/usr/lib/softhsm/libsofthsm2.so", RTLD_NOW);
    CK_C_GetFunctionList pGetFL =
        (CK_C_GetFunctionList)dlsym(lib, "C_GetFunctionList");

    CK_FUNCTION_LIST_PTR p11;
    pGetFL(&p11);

    /* 2. Initialize */
    CK_RV rv = p11->C_Initialize(NULL_PTR);
    if (rv != CKR_OK) { fprintf(stderr, "C_Initialize: 0x%lx\n", rv); return 1; }

    /* 3. Get the first slot with a token */
    CK_ULONG slotCount;
    p11->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CK_SLOT_ID slots[slotCount];
    p11->C_GetSlotList(CK_TRUE, slots, &slotCount);

    /* 4. Open a read-write session */
    CK_SESSION_HANDLE hSession;
    p11->C_OpenSession(slots[0],
                       CKF_SERIAL_SESSION | CKF_RW_SESSION,
                       NULL_PTR, NULL_PTR, &hSession);

    /* 5. Log in as the normal user */
    CK_UTF8CHAR pin[] = "1234";
    p11->C_Login(hSession, CKU_USER, pin, sizeof(pin) - 1);

    /* … perform operations … */

    /* 6. Finalize */
    p11->C_Logout(hSession);
    p11->C_CloseSession(hSession);
    p11->C_Finalize(NULL_PTR);
    dlclose(lib);
    return 0;
}

Exported functions

SoftHSM exports the complete PKCS#11 function set. The table below lists every function in the order they appear in CK_FUNCTION_LIST.
FunctionDescription
C_InitializeInitialize the Cryptoki library
C_FinalizeClean up and shut down the library
C_GetInfoReturn general information about the library
C_GetFunctionListReturn a pointer to the function-list structure
C_GetSlotListList available slots
C_GetSlotInfoReturn information about a specific slot
C_GetTokenInfoReturn information about the token in a slot
C_GetMechanismListList mechanisms supported by a token
C_GetMechanismInfoReturn information about a specific mechanism
C_InitTokenInitialize a token (sets the SO PIN and label)
C_InitPINInitialize the user PIN
C_SetPINChange the current user or SO PIN
C_OpenSessionOpen a session with a token
C_CloseSessionClose a session
C_CloseAllSessionsClose all sessions on a slot
C_GetSessionInfoReturn state information for a session
C_GetOperationStateSerialize the state of a running operation
C_SetOperationStateRestore a previously serialized operation state
C_LoginLog into a token
C_LogoutLog out from a token
C_CreateObjectCreate a new key or data object
C_CopyObjectCopy an existing object
C_DestroyObjectDestroy an object
C_GetObjectSizeReturn the size (in bytes) of an object
C_GetAttributeValueRead attributes from an object
C_SetAttributeValueModify attributes on an object
C_FindObjectsInitBegin a search for objects matching a template
C_FindObjectsContinue an active object search
C_FindObjectsFinalTerminate an object search
C_EncryptInitInitialize an encryption operation
C_EncryptEncrypt data in a single call
C_EncryptUpdateFeed data to a running encryption operation
C_EncryptFinalFinalize a multi-part encryption operation
C_DecryptInitInitialize a decryption operation
C_DecryptDecrypt data in a single call
C_DecryptUpdateFeed data to a running decryption operation
C_DecryptFinalFinalize a multi-part decryption operation
C_DigestInitInitialize a digest (hash) operation
C_DigestHash data in a single call
C_DigestUpdateFeed data to a running digest operation
C_DigestKeyInclude a key’s value in a running digest
C_DigestFinalFinalize a multi-part digest operation
C_SignInitInitialize a signing operation
C_SignSign data in a single call
C_SignUpdateFeed data to a running signing operation
C_SignFinalFinalize a multi-part signing operation
C_SignRecoverInitInitialize a signature-with-recovery operation
C_SignRecoverSign data, embedding it in the signature
C_VerifyInitInitialize a verification operation
C_VerifyVerify a signature in a single call
C_VerifyUpdateFeed data to a running verification operation
C_VerifyFinalFinalize a multi-part verification operation
C_VerifyRecoverInitInitialize a verify-with-recovery operation
C_VerifyRecoverVerify and recover the original signed data
C_DigestEncryptUpdateCombined digest + encrypt update step
C_DecryptDigestUpdateCombined decrypt + digest update step
C_SignEncryptUpdateCombined sign + encrypt update step
C_DecryptVerifyUpdateCombined decrypt + verify update step
C_GenerateKeyGenerate a secret (symmetric) key
C_GenerateKeyPairGenerate an asymmetric key pair
C_WrapKeyWrap (encrypt) a key for export
C_UnwrapKeyUnwrap (decrypt) an imported key
C_DeriveKeyDerive a new key from an existing base key
C_SeedRandomSeed the random number generator
C_GenerateRandomGenerate random bytes
C_GetFunctionStatusLegacy function (always returns CKR_FUNCTION_NOT_PARALLEL)
C_CancelFunctionLegacy function (always returns CKR_FUNCTION_NOT_PARALLEL)
C_WaitForSlotEventWait or poll for a slot event

Return values

Every function returns a CK_RV value. The most important return codes are:
ConstantValueMeaning
CKR_OK0x00000000Success
CKR_ARGUMENTS_BAD0x00000007Invalid argument passed to the function
CKR_CRYPTOKI_NOT_INITIALIZED0x00000190C_Initialize has not been called
CKR_DEVICE_ERROR0x00000030Internal device or implementation error
CKR_FUNCTION_FAILED0x00000006The function could not complete
CKR_KEY_HANDLE_INVALID0x00000060The key handle does not refer to a valid key
CKR_MECHANISM_INVALID0x00000070The mechanism is not supported
CKR_PIN_INCORRECT0x000000A0Wrong PIN supplied
CKR_SESSION_HANDLE_INVALID0x000000B3The session handle is not valid
CKR_TOKEN_NOT_PRESENT0x000000E0No token in the specified slot
CKR_USER_NOT_LOGGED_IN0x00000101Operation requires authentication
Return code values are defined in pkcs11.h. Always check the return value of every PKCS#11 call; functions that produce output (for example C_Encrypt) may return CKR_OK with a length value and NULL data pointer on the first call as a way of querying the required output buffer size.

Thread safety

SoftHSM is thread-safe. To use it from multiple threads you should either:
  • Pass NULL_PTR to C_Initialize, which causes SoftHSM to use OS-native mutexes internally, or
  • Supply a CK_C_INITIALIZE_ARGS structure with your own mutex callbacks.
CK_C_INITIALIZE_ARGS initArgs = { 0 };

/* Option A: let the library use OS mutexes */
initArgs.flags = CKF_OS_LOCKING_OK;
p11->C_Initialize(&initArgs);

/* Option B: supply custom mutex functions */
initArgs.CreateMutex  = myCreateMutex;
initArgs.DestroyMutex = myDestroyMutex;
initArgs.LockMutex    = myLockMutex;
initArgs.UnlockMutex  = myUnlockMutex;
p11->C_Initialize(&initArgs);
Do not share a CK_SESSION_HANDLE across threads. Each thread should open its own session with C_OpenSession.

PKCS#11 version

SoftHSM v2.7.0 and later implements PKCS#11 3.2 (Cryptoki version 3.2.0). The version is reported by C_GetInfo in the cryptokiVersion field and is also defined in the header:
#define CRYPTOKI_VERSION_MAJOR 3
#define CRYPTOKI_VERSION_MINOR 2
#define CRYPTOKI_VERSION_REVISION 0
A compatibility alias is also defined for older middleware that checks for the PKCS#11 2.x series:
#define CRYPTOKI_LEGACY_VERSION_MAJOR 2
#define CRYPTOKI_LEGACY_VERSION_MINOR 40

Build docs developers (and LLMs) love