Craton HSM
Migration from SoftHSM v2
Migration from SoftHSM v2
This guide walks through replacing SoftHSMv2 with Craton HSM as the PKCS#11 provider for an existing deployment. The two modules expose the same C_GetFunctionList surface, so application code rarely needs to change; the work is in moving key material, updating the module registration, and verifying mechanism compatibility.
Read this page end-to-end before you start. Some transitions — notably anything involving non-extractable keys — cannot be reversed once the old token is destroyed.
Scope and caveats
- Non-extractable keys cannot be migrated. If a SoftHSMv2 key was generated with
CKA_EXTRACTABLE = FALSE(orCKA_SENSITIVE = TRUEcombined with no wrap path), the private material is not recoverable. Those keys must be re-generated on Craton HSM and their corresponding certificates or bindings re-issued. - Mechanism support differs on the margins. Craton HSM adds post-quantum mechanisms and a hybrid suite; SoftHSMv2 supports a handful of legacy mechanisms (for example raw RSA) that Craton HSM deliberately does not. Audit your call sites before cutover — see mechanism compatibility below.
- AES-GCM parameters. SoftHSMv2 requires a populated
CK_GCM_PARAMSblock; Craton HSM accepts a null mechanism parameter and generates a deterministic per-key counter nonce. If you were passing explicit GCM parameters, keep doing so — the call still works.
Inventory the existing token
Run a full mechanism and object listing against SoftHSMv2 before touching anything:
# Mechanisms the token advertises
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-mechanisms
# Slots and labels
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-slots
# Objects per slot
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \
--token-label "Your-Token-Label" --list-objects --login
Record, for every key:
- CKA_LABEL
- CKA_ID
- CKA_KEY_TYPE and size (RSA-2048, ECDSA P-256, AES-256, ...)
- CKA_EXTRACTABLE, CKA_SENSITIVE, CKA_TOKEN, CKA_PRIVATE
- Permitted operations: CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE
Craton HSM preserves these attributes on import. A short script that writes them to a CSV before migration gives you a diff target after cutover.
Install Craton HSM alongside SoftHSMv2
Build or download the library per Installation. Copy it into a directory that your consumers can open, but do not yet update their module path:
sudo install -m 0755 target/release/libcraton_hsm.so /usr/lib/pkcs11/libcraton_hsm.so
Initialise a fresh Craton HSM token with the SO PIN and a user PIN. Reuse the SoftHSMv2 label so application config lookups do not need to change:
pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so \
--init-token --label "Your-Token-Label" --so-pin <SO_PIN>
pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so \
--init-pin --so-pin <SO_PIN> --pin <USER_PIN>
See Quickstart for the full first-token flow.
Attribute mapping
Craton HSM honours the standard PKCS#11 v3.0 attributes. The important differences when importing SoftHSMv2 objects:
| Attribute | SoftHSMv2 | Craton HSM |
|---|---|---|
CKA_TOKEN | Persists to tokens/<uuid>/ | Persists to the configured storage_path, AES-GCM encrypted under a KEK. |
CKA_PRIVATE | Enforced at session level | Enforced at session level; the session must be logged in for private objects. |
CKA_SENSITIVE | Blocks C_GetAttributeValue of private material | Same behaviour. |
CKA_EXTRACTABLE | Required to be TRUE for C_WrapKey | Same requirement. |
CKA_DERIVE | Supported for ECDH | Supported for ECDH P-256/P-384 and for hybrid X25519+ML-KEM-768 derive. |
CKA_MODIFIABLE | Controls C_SetAttributeValue | Same behaviour; immutable attributes refuse in-place change. |
CKA_ID | Arbitrary byte string | Arbitrary byte string; preserved on import. |
CKA_VENDOR_FIPS_APPROVED | Not defined | Reserved at 0x80000001 for algorithm-indicator queries. |
Unknown attributes supplied to C_CreateObject are rejected with CKR_ATTRIBUTE_TYPE_INVALID. If you are using vendor-defined attributes from SoftHSMv2, strip them before import.
Moving keys
Extractable private keys
If CKA_EXTRACTABLE = TRUE, wrap the key out of SoftHSMv2 under a symmetric wrapping key and unwrap it into Craton HSM. The recommended mechanism is AES Key Wrap (RFC 3394, CKM_AES_KEY_WRAP).
# 1. Generate a transient AES-256 wrapping key on SoftHSMv2
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin <USER_PIN> \
--keygen --key-type AES:32 --label migration-wrap --id 0001 \
--usage-wrap
# 2. Wrap the private key out of SoftHSMv2
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin <USER_PIN> \
--wrap --mechanism AES-KEY-WRAP \
--wrap-key-label migration-wrap --label my-signing-key \
--output-file my-signing-key.wrapped
# 3. Import the wrapping key into Craton HSM (by value, via a sealed channel)
pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so --login --pin <USER_PIN> \
--write-object wrapping-key.bin --type secrkey --key-type AES:32 \
--label migration-wrap --id 0001
# 4. Unwrap into Craton HSM
pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so --login --pin <USER_PIN> \
--unwrap --mechanism AES-KEY-WRAP \
--wrap-key-label migration-wrap \
--input-file my-signing-key.wrapped \
--type privkey --key-type RSA --label my-signing-key
# 5. Destroy the wrapping key on both tokens
The wrapping key itself has to cross the gap somehow. The safest path is to generate it on an operator workstation that has both modules loaded, wrap out of SoftHSM, unwrap into Craton, then delete. Do not write the plaintext wrapping key to long-term storage.
Non-extractable private keys
These are not recoverable. The migration path is:
- Generate a new key on Craton HSM with the same label, ID, and permitted operations.
- Issue a new certificate (or equivalent binding) against the new public key.
- Deploy the new certificate to consumers.
- Only after the new certificate is in use everywhere, destroy the old SoftHSM key.
Public objects and certificates
Public keys (CKO_PUBLIC_KEY) and certificates (CKO_CERTIFICATE) are always extractable. Export them from SoftHSMv2 with pkcs11-tool --read-object and import them into Craton HSM with --write-object. The CKA_ID should be reused so that certificate-to-key binding by ID continues to work.
Symmetric keys
CKO_SECRET_KEY objects follow the same pattern as extractable private keys: wrap with CKM_AES_KEY_WRAP or CKM_AES_KEY_WRAP_PAD, transfer, unwrap.
Cutover: pointing consumers at Craton HSM
Most Linux distributions centralise PKCS#11 module registration in /etc/pkcs11/modules/. One .module file per provider:
# /etc/pkcs11/modules/craton-hsm.module
module: /usr/lib/pkcs11/libcraton_hsm.so
For p11-kit-aware applications (NSS, GnuTLS, openssl with the PKCS#11 engine) nothing further is required — they will enumerate both modules until you remove softhsm2.module.
For applications that hard-code a single module path, update the path in their configuration directly. Common locations:
| Consumer | Location |
|---|---|
OpenSSL engine (libengine_pkcs11) | openssl.cnf → MODULE_PATH |
| Java SunPKCS11 | sunpkcs11.cfg → library = ... |
| NSS | modutil -dbdir ... -add "Craton HSM" -libfile /usr/lib/pkcs11/libcraton_hsm.so |
| systemd services | Environment=PKCS11_MODULE=... or the service's own config |
Run both modules side by side for as long as your rollback window requires. Craton HSM acquires an exclusive file lock on its own storage_path, so it cannot corrupt SoftHSMv2's token directory even if both are loaded into the same process.
Verification checklist
Before retiring the SoftHSMv2 token, confirm each item:
-
C_Initializeon Craton HSM returnsCKR_OK; the POST log shows the 17 self-tests passing. -
pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so --list-mechanismsadvertises every mechanism your applications use. - Every migrated key is listed with matching
CKA_LABEL,CKA_ID, andCKA_KEY_TYPEagainst the pre-migration inventory. - For each migrated signing key, a
C_Sign+C_Verifyround trip succeeds. - For each migrated wrapping key, a known test wrap/unwrap succeeds.
- Every certificate still resolves to its private key by
CKA_ID. - Applications complete one representative transaction end-to-end against Craton HSM.
- Audit log records the expected
Sign/Verify/Encryptentries withfips_approvedset correctly for your build. - SO PIN and user PIN have been rotated away from any temporary migration values.
After the checklist passes and the rollback window closes, remove softhsm2.module from /etc/pkcs11/modules/, decommission the SoftHSMv2 token directory (rm -rf /var/lib/softhsm/tokens/* or wherever it lived), and capture the first encrypted backup of the Craton HSM token — see the operator runbook if you have set one up in your navigation.
Mechanism compatibility
Before cutover, match the two modules' mechanism lists against your workload:
- RSA. 2048 / 3072 / 4096 with PKCS#1 v1.5, PSS, and OAEP on both. Raw RSA (
CKM_RSA_X_509) is available on SoftHSMv2; Craton HSM does not expose it — applications should move to PSS or OAEP. - ECDSA. P-256 and P-384 on both. Craton HSM's FIPS mode restricts EC to these curves.
- EdDSA. Ed25519 is supported outside FIPS mode on Craton HSM and on SoftHSMv2 builds that include it.
- AES. GCM, CBC, CTR, Key Wrap on both; see the note on GCM parameters above.
- Digest / MAC. SHA-256/384/512, SHA3, HMAC-SHA256/384/512 on both.
- Post-quantum. ML-KEM-512/768/1024, ML-DSA-44/65/87, and SLH-DSA variants are Craton HSM only — SoftHSMv2 does not implement them. See Post-quantum migration when you are ready to phase them in.
Troubleshooting
CKR_CRYPTOKI_NOT_INITIALIZEDimmediately afterfork(). Expected. Craton HSM rejects calls from a forked child until the child re-runsC_Initialize— see fork safety (or the fork-safety note in the source tree) for the rationale.CKR_GENERAL_ERRORwithDatabase at <path> is locked by another process. Two processes are opening the samestorage_path. Either run one process, or route them throughcraton-hsm-daemon.- Mismatched
CKA_IDafter import.pkcs11-tool --write-objectwill generate a random ID unless you pass--id. Always supply the original ID explicitly.