SoftHSMv2
SoftHSMv2 is the software token most PKCS#11 code is first tested against, and the return values it hands back are chosen by one C++ file with a few habits the specification would not predict. The vague code with teeth is its everyday code. Slot numbers move the moment a token is initialised. The PIN counter never trips. None of that is a bug, and all of it is a surprise the first time a test that passed on SoftHSM meets a real device.
One code for almost everything
The library’s PKCS#11 entry points live in a single file, and the way it reports a failure is toreturn CKR_GENERAL_ERROR. That line appears 206 times in SoftHSM.cpp at the commit read. It is what comes back when the crypto backend refuses an operation, when a session exists but its token does not, and in two places where the code has a more specific answer and declines to use it. In C_GetAttributeValue and C_DigestKey an unauthenticated read of a private object produces CKR_USER_NOT_LOGGED_IN internally, and a comment at line 2084 explains that the specification does not list that code for the function, so the caller gets the general error instead.
The specification’s recoverable failure, CKR_FUNCTION_FAILED, is reserved for the object store. Ninety-eight of its hundred appearances are rv = CKR_FUNCTION_FAILED after an attribute could not be written to the token’s storage, and the other two follow a failed destroyObject. So on this library the two codes mean roughly the opposite of what the specification suggests. The general error is the ordinary one and the library is fine afterwards. The function failure means the files on disk did not take a write, which is the one situation worth stopping for.Slot 0 is a moving target
A fresh installation has one slot, numbered 0, with no token in it. Initialise a token there and the token is not in slot 0 any more. SlotManager numbers each token’s slot from the last eight hex digits of the token’s serial, masked to 31 bits so that a Java signed int survives it, then appends one empty slot numbered by the count of tokens. I ran it on this machine.softhsm2-util --init-token --free printed that the token “is reassigned to slot 1613085303”, the empty slot became slot 1, and opening a session on slot 0 returned CKR_SLOT_ID_INVALID. The serial is random, so the number differs on every machine and in every CI run. Code that hard-codes a slot survives until the first --init-token and no longer. --token-label and --serial exist for this reason.The PIN never locks
Token::loginUser compares the PIN, sets the CKF_USER_PIN_COUNT_LOW flag on a miss, and returns CKR_PIN_INCORRECT. There is no counter behind the flag and nothing in the library ever returns CKR_PIN_LOCKED. Five wrong PINs in a row on the token above produced five CKR_PIN_INCORRECT, and the right PIN then logged in. A retry loop that is harmless here will brick a production token. That is the single largest gap between what SoftHSM lets a test suite get away with and what an HSM will.Mechanisms are a config setting
The mechanism list is built atC_Initialize from a fixed table of 112 names, then filtered by slots.mechanisms in the configuration file, which takes either a positive list or a leading minus and a list to remove (lines 928 to 967). Mechanisms the build cannot support are dropped before that. The table below is from a build with GOST disabled against OpenSSL 3.0, and it has 103 entries with EdDSA present. A mechanism missing from the list is CKR_MECHANISM_INVALID at use time, and the reason may be a line in softhsm2.conf rather than anything in the code.
The list is the same on the empty slot and on a token, which is not true of hardware. None of the 103 sets CKF_HW, which is the honest answer.Mechanisms the token actually exposes
Read from a live token rather than from a document. The library
returns a list of integers, then names each one's key size range and the
operations it is good for. That last part lives in
C_GetMechanismInfo rather than in the mechanism list, and
most vendor status tools leave it out. OpenSC's pkcs11-tool
--list-mechanisms is the exception. The same rows sit beside every
other library's on the mechanism
table.
103 mechanisms, 0 of them vendor-defined.
0 set CKF_HW, which claims the operation is done in
hardware.
| Mechanism | Hex | Keys | Operations |
|---|---|---|---|
CKM_RSA_PKCS_KEY_PAIR_GEN | 0x00000000 | 512–16384 | generate_key_pair |
CKM_RSA_PKCS | 0x00000001 | 512–16384 | encrypt, decrypt, sign, verify, wrap, unwrap |
CKM_RSA_X_509 | 0x00000003 | 512–16384 | encrypt, decrypt, sign, verify |
CKM_MD5_RSA_PKCS | 0x00000005 | 512–16384 | sign, verify |
CKM_SHA1_RSA_PKCS | 0x00000006 | 512–16384 | sign, verify |
CKM_RSA_PKCS_OAEP | 0x00000009 | 512–16384 | encrypt, decrypt, wrap, unwrap |
CKM_RSA_PKCS_PSS | 0x0000000D | 512–16384 | sign, verify |
CKM_SHA1_RSA_PKCS_PSS | 0x0000000E | 512–16384 | sign, verify |
CKM_DSA_KEY_PAIR_GEN | 0x00000010 | 512–1024 | generate_key_pair |
CKM_DSA | 0x00000011 | 512–1024 | sign, verify |
CKM_DSA_SHA1 | 0x00000012 | 512–1024 | sign, verify |
CKM_DSA_SHA224 | 0x00000013 | 512–1024 | sign, verify |
CKM_DSA_SHA256 | 0x00000014 | 512–1024 | sign, verify |
CKM_DSA_SHA384 | 0x00000015 | 512–1024 | sign, verify |
CKM_DSA_SHA512 | 0x00000016 | 512–1024 | sign, verify |
CKM_DSA_SHA3_224 | 0x00000018 | 512–1024 | sign, verify |
CKM_DSA_SHA3_256 | 0x00000019 | 512–1024 | sign, verify |
CKM_DSA_SHA3_384 | 0x0000001A | 512–1024 | sign, verify |
CKM_DSA_SHA3_512 | 0x0000001B | 512–1024 | sign, verify |
CKM_DH_PKCS_KEY_PAIR_GEN | 0x00000020 | 512–10000 | generate_key_pair |
CKM_DH_PKCS_DERIVE | 0x00000021 | 512–10000 | derive |
CKM_SHA256_RSA_PKCS | 0x00000040 | 512–16384 | sign, verify |
CKM_SHA384_RSA_PKCS | 0x00000041 | 512–16384 | sign, verify |
CKM_SHA512_RSA_PKCS | 0x00000042 | 512–16384 | sign, verify |
CKM_SHA256_RSA_PKCS_PSS | 0x00000043 | 512–16384 | sign, verify |
CKM_SHA384_RSA_PKCS_PSS | 0x00000044 | 512–16384 | sign, verify |
CKM_SHA512_RSA_PKCS_PSS | 0x00000045 | 512–16384 | sign, verify |
CKM_SHA224_RSA_PKCS | 0x00000046 | 512–16384 | sign, verify |
CKM_SHA224_RSA_PKCS_PSS | 0x00000047 | 512–16384 | sign, verify |
CKM_SHA3_256_RSA_PKCS | 0x00000060 | 512–16384 | sign, verify |
CKM_SHA3_384_RSA_PKCS | 0x00000061 | 512–16384 | sign, verify |
CKM_SHA3_512_RSA_PKCS | 0x00000062 | 512–16384 | sign, verify |
CKM_SHA3_256_RSA_PKCS_PSS | 0x00000063 | 512–16384 | sign, verify |
CKM_SHA3_384_RSA_PKCS_PSS | 0x00000064 | 512–16384 | sign, verify |
CKM_SHA3_512_RSA_PKCS_PSS | 0x00000065 | 512–16384 | sign, verify |
CKM_SHA3_224_RSA_PKCS | 0x00000066 | 512–16384 | sign, verify |
CKM_SHA3_224_RSA_PKCS_PSS | 0x00000067 | 512–16384 | sign, verify |
CKM_DES_KEY_GEN | 0x00000120 | - | generate |
CKM_DES_ECB | 0x00000121 | - | encrypt, decrypt, wrap |
CKM_DES_CBC | 0x00000122 | - | encrypt, decrypt, wrap |
CKM_DES_CBC_PAD | 0x00000125 | - | encrypt, decrypt, wrap, unwrap |
CKM_DES2_KEY_GEN | 0x00000130 | - | generate |
CKM_DES3_KEY_GEN | 0x00000131 | - | generate |
CKM_DES3_ECB | 0x00000132 | - | encrypt, decrypt |
CKM_DES3_CBC | 0x00000133 | - | encrypt, decrypt, wrap |
CKM_DES3_CBC_PAD | 0x00000136 | - | encrypt, decrypt, wrap, unwrap |
CKM_DES3_CMAC | 0x00000138 | - | sign, verify |
CKM_MD5 | 0x00000210 | - | digest |
CKM_MD5_HMAC | 0x00000211 | 16–512 | sign, verify |
CKM_SHA_1 | 0x00000220 | - | digest |
CKM_SHA_1_HMAC | 0x00000221 | 20–512 | sign, verify |
CKM_SHA256 | 0x00000250 | - | digest |
CKM_SHA256_HMAC | 0x00000251 | 32–512 | sign, verify |
CKM_SHA224 | 0x00000255 | - | digest |
CKM_SHA224_HMAC | 0x00000256 | 28–512 | sign, verify |
CKM_SHA384 | 0x00000260 | - | digest |
CKM_SHA384_HMAC | 0x00000261 | 48–512 | sign, verify |
CKM_SHA512 | 0x00000270 | - | digest |
CKM_SHA512_HMAC | 0x00000271 | 64–512 | sign, verify |
CKM_SHA3_256 | 0x000002B0 | - | digest |
CKM_SHA3_256_HMAC | 0x000002B1 | 32–512 | sign, verify |
CKM_SHA3_224 | 0x000002B5 | - | digest |
CKM_SHA3_224_HMAC | 0x000002B6 | 28–512 | sign, verify |
CKM_SHA3_384 | 0x000002C0 | - | digest |
CKM_SHA3_384_HMAC | 0x000002C1 | 48–512 | sign, verify |
CKM_SHA3_512 | 0x000002D0 | - | digest |
CKM_SHA3_512_HMAC | 0x000002D1 | 64–512 | sign, verify |
CKM_GENERIC_SECRET_KEY_GEN | 0x00000350 | 1–134217728 | generate |
CKM_CONCATENATE_BASE_AND_KEY | 0x00000360 | 1–512 | derive |
CKM_CONCATENATE_BASE_AND_DATA | 0x00000362 | 1–512 | derive |
CKM_CONCATENATE_DATA_AND_BASE | 0x00000363 | 1–512 | derive |
CKM_ECDSA_KEY_PAIR_GEN | 0x00001040 | 112–521 | generate_key_pair, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA | 0x00001041 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA1 | 0x00001042 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA224 | 0x00001043 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA256 | 0x00001044 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA384 | 0x00001045 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA512 | 0x00001046 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA3_224 | 0x00001047 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA3_256 | 0x00001048 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA3_384 | 0x00001049 | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDSA_SHA3_512 | 0x0000104A | 112–521 | sign, verify, ec_f_p, ec_oid, ec_uncompress |
CKM_ECDH1_DERIVE | 0x00001050 | 112–521 | derive |
CKM_RSA_AES_KEY_WRAP | 0x00001054 | 512–16384 | wrap, unwrap |
CKM_EC_EDWARDS_KEY_PAIR_GEN | 0x00001055 | 255–448 | generate_key_pair |
CKM_EDDSA | 0x00001057 | 255–448 | sign, verify |
CKM_AES_KEY_GEN | 0x00001080 | 16–32 | generate |
CKM_AES_ECB | 0x00001081 | 16–32 | encrypt, decrypt |
CKM_AES_CBC | 0x00001082 | 16–32 | encrypt, decrypt, wrap, unwrap |
CKM_AES_CBC_PAD | 0x00001085 | 16–32 | encrypt, decrypt, wrap, unwrap |
CKM_AES_CTR | 0x00001086 | 16–32 | encrypt, decrypt |
CKM_AES_GCM | 0x00001087 | 16–32 | encrypt, decrypt |
CKM_AES_CMAC | 0x0000108A | 16–32 | sign, verify |
CKM_DES_ECB_ENCRYPT_DATA | 0x00001100 | - | derive |
CKM_DES_CBC_ENCRYPT_DATA | 0x00001101 | - | derive |
CKM_DES3_ECB_ENCRYPT_DATA | 0x00001102 | - | derive |
CKM_DES3_CBC_ENCRYPT_DATA | 0x00001103 | - | derive |
CKM_AES_ECB_ENCRYPT_DATA | 0x00001104 | - | derive |
CKM_AES_CBC_ENCRYPT_DATA | 0x00001105 | - | derive |
CKM_DSA_PARAMETER_GEN | 0x00002000 | 512–1024 | generate |
CKM_DH_PKCS_PARAMETER_GEN | 0x00002001 | 512–10000 | generate |
CKM_AES_KEY_WRAP | 0x00002109 | 16–2147483648 | wrap, unwrap |
CKM_AES_KEY_WRAP_PAD | 0x0000210A | 1–2147483648 | wrap, unwrap |
observed · Implementation of PKCS11
2.7 · Cryptoki 3.2 ·
slot 1613085303, token "demo" ·
C_GetMechanismInfo · 2026-09-10
Return values with a note for this library
CKR_SLOT_ID_INVALID· The library does not have that slot. Usually a number hard-coded from a machine where the enumeration came out differently.CKR_GENERAL_ERROR· Not a failed call but a broken library. The specification says nothing further will work, so retrying it is wasted effort.CKR_FUNCTION_FAILED· A recoverable failure. The library is still usable and the token unchanged, so this one is worth investigating rather than restarting.CKR_MECHANISM_INVALID· The mechanism is unknown here, or not valid for the operation you used it in. Check the slot's own list rather than the header you compiled against.CKR_PIN_INCORRECT· The credential was wrong. The important part is what your code does next, because automatic retries are how tokens get locked.CKR_PIN_LOCKED· The token has locked the PIN after too many failed attempts. On most HSMs this is not something you can wait out, and on some it destroys the partition.CKR_TOKEN_NOT_PRESENT· Better news than it looks: the slot identifier was right. On a network HSM this usually means the client cannot reach the partition rather than a missing card.CKR_USER_NOT_LOGGED_IN· A private object needs an authenticated session. Often a login that happened on a different session, or one that a token event quietly ended.
How this page was made
Read from the source at the commit linked above, with every claim pinned to a line. Counts of return sites are from a search over the library's own code and are only as exact as a search can be. The mechanism table is from a build of that commit on this machine, read with the same probe as the other pages here. It opens no session and never logs in.
Scope. Read from the SoftHSMv2 repository at the commit named above, the main branch a week before this page was written, and from a build of that commit on this machine with the OpenSSL backend. Counts of return sites are from searching the source text. The mechanism table depends on the crypto backend and the configure flags, so another build will differ. Nothing here is from a packaged release, and distribution packages lag the repository by a year or more.
Sources
- SoftHSMv2 repository at 884cb38, softhsm on GitHub. Read 2026-09-10. Used for every claim about which code is returned when, and the build behind the mechanism table.
- softhsm2.conf(5), SoftHSM project. Read 2026-09-10. Used for the slots.mechanisms and slots.removable settings.