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 (or CKA_SENSITIVE = TRUE combined 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_PARAMS block; 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:

AttributeSoftHSMv2Craton HSM
CKA_TOKENPersists to tokens/<uuid>/Persists to the configured storage_path, AES-GCM encrypted under a KEK.
CKA_PRIVATEEnforced at session levelEnforced at session level; the session must be logged in for private objects.
CKA_SENSITIVEBlocks C_GetAttributeValue of private materialSame behaviour.
CKA_EXTRACTABLERequired to be TRUE for C_WrapKeySame requirement.
CKA_DERIVESupported for ECDHSupported for ECDH P-256/P-384 and for hybrid X25519+ML-KEM-768 derive.
CKA_MODIFIABLEControls C_SetAttributeValueSame behaviour; immutable attributes refuse in-place change.
CKA_IDArbitrary byte stringArbitrary byte string; preserved on import.
CKA_VENDOR_FIPS_APPROVEDNot definedReserved 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:

  1. Generate a new key on Craton HSM with the same label, ID, and permitted operations.
  2. Issue a new certificate (or equivalent binding) against the new public key.
  3. Deploy the new certificate to consumers.
  4. 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:

ConsumerLocation
OpenSSL engine (libengine_pkcs11)openssl.cnfMODULE_PATH
Java SunPKCS11sunpkcs11.cfglibrary = ...
NSSmodutil -dbdir ... -add "Craton HSM" -libfile /usr/lib/pkcs11/libcraton_hsm.so
systemd servicesEnvironment=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_Initialize on Craton HSM returns CKR_OK; the POST log shows the 17 self-tests passing.
  • pkcs11-tool --module /usr/lib/pkcs11/libcraton_hsm.so --list-mechanisms advertises every mechanism your applications use.
  • Every migrated key is listed with matching CKA_LABEL, CKA_ID, and CKA_KEY_TYPE against the pre-migration inventory.
  • For each migrated signing key, a C_Sign + C_Verify round 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 / Encrypt entries with fips_approved set 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_INITIALIZED immediately after fork(). Expected. Craton HSM rejects calls from a forked child until the child re-runs C_Initialize — see fork safety (or the fork-safety note in the source tree) for the rationale.
  • CKR_GENERAL_ERROR with Database at <path> is locked by another process. Two processes are opening the same storage_path. Either run one process, or route them through craton-hsm-daemon.
  • Mismatched CKA_ID after import. pkcs11-tool --write-object will generate a random ID unless you pass --id. Always supply the original ID explicitly.