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_ATTRIBUTE_READ_ONLY· The attribute cannot be changed on this object, or cannot be supplied at creation because the token sets it. Computed flags, identity, or a locked object.CKR_ATTRIBUTE_SENSITIVE· The attribute exists and the token will not disclose it. Private key material behind CKA_SENSITIVE or a false CKA_EXTRACTABLE. Not a fault.CKR_ATTRIBUTE_TYPE_INVALID· The object has no such attribute, or this library never stored it. Common when reading fields that only exist for another key type, and in object dumps.CKR_DATA_INVALID· Right length, wrong content. A DigestInfo the token cannot parse, an EC point in the wrong encoding, or on a card, a status word with nowhere else to go.CKR_DATA_LEN_RANGE· Input length the mechanism does not accept. A block cipher without padding, RSA input longer than the modulus, or a raw signing mechanism given a message.CKR_ENCRYPTED_DATA_INVALID· Ciphertext the token could not decrypt: bad padding, the wrong key, a failed tag. Some libraries use it for every decrypt failure, against padding oracles.CKR_FUNCTION_NOT_SUPPORTED· The library exports the function and will not perform it. Usually a v3.0 message call, a dual-function update, or a wrap on a token that never wraps.CKR_KEY_TYPE_INCONSISTENT· The key's type does not fit the mechanism. An EC key on an RSA mechanism, an Edwards key on ECDSA, or a find that returned the certificate instead.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_MECHANISM_PARAM_INVALID· The mechanism is known and its parameter is wrong. A missing IV, an OAEP hash pairing the token refuses, or a GCM tag length out of range.CKR_OPERATION_ACTIVE· An Init was called while the session already holds an operation of that kind. A multi-part operation that was never finished, or two threads on one session.CKR_OPERATION_NOT_INITIALIZED· Sign, Update or Final with no matching Init on this session. An Init whose failure was ignored, an operation the library reset, or a session shared by threads.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_LEN_RANGE· The PIN is too short or too long for this token. The limits are in the token info and are applied before the PIN is looked at, so the PIN may also be wrong.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_TEMPLATE_INCOMPLETE· The template does not fully specify the object. A missing CKA_CLASS or CKA_KEY_TYPE on create, a missing CKA_VALUE_LEN on generate, or a vendor rule.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_TOKEN_NOT_RECOGNIZED· The library saw a device in the slot and has no driver for it, or the card answered in a way it could not parse. A smart card code far more than an HSM one.CKR_USER_ALREADY_LOGGED_IN· A login on a token that already has that user logged in through another session. Two components sharing a token, or a retry after a login that succeeded.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.CKR_DOMAIN_PARAMS_INVALID· The domain parameters are not ones this token accepts. An EC curve the token lacks or in the wrong encoding, or DH parameters given where the token makes them.CKR_CRYPTOKI_ALREADY_INITIALIZED· C_Initialize on a library that is already initialized in this process. Usually two components sharing one module, or a fork the library did not notice.
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.