Craton HSM
Enabling FIPS mode
Enabling FIPS mode
Craton HSM supports a FIPS-approved mode of operation when it is built against the AWS-LC backend and configured to reject non-approved mechanisms. This guide walks through the end-to-end enablement: pick the backend, rebuild, update the config, compute the integrity sidecar, and verify. For the policy reference — which mechanisms are approved, how the algorithm indicator works, what the self-tests cover — see FIPS mode and Self-tests.
Prerequisites
The FIPS build has a few extra native dependencies beyond the pure-Rust default:
| Tool | Why |
|---|---|
| CMake 3.x | AWS-LC uses CMake as its top-level build system. |
| Clang / LLVM | AWS-LC's Rust bindings require libclang for bindgen. |
| Go | AWS-LC's generator scripts are written in Go. |
On Windows, set the following before building:
LIBCLANG_PATH=C:\path\to\llvm\bin
AWS_LC_SYS_NO_ASM=1
1. Select the AWS-LC backend
FIPS deployments must use the awslc-backend feature. This swaps the pure-Rust RustCrypto implementations for AWS-LC, which holds a FIPS 140-3 certificate. The default rustcrypto-backend is not FIPS validated and will not produce an approved mode of operation.
See Enterprise / AWS-LC backend for licensing, support, and platform coverage notes before committing to this backend in production.
2. Rebuild with the FIPS features
cargo build --release --features awslc-backend --no-default-features
The resulting target/release/libcraton_hsm.so (or craton_hsm.dll on Windows) embeds the AWS-LC FIPS module. Do not copy a non-FIPS build into a FIPS deployment even if the filename is the same — the integrity check in step 4 will not catch a backend mismatch, only a post-build modification.
If you are distributing the library to other hosts, build once and ship the resulting binary plus its .hmac sidecar (step 4). Do not rebuild per host.
3. Configure for FIPS-approved only
Open craton_hsm.toml (or the path in CRATON_HSM_CONFIG) and apply the FIPS-approved-only policy:
[algorithms]
# Use the FIPS-certified backend.
crypto_backend = "awslc"
# Reject every non-FIPS mechanism at C_*Init time.
fips_approved_only = true
# PQC is not yet FIPS-approved (as of CMVP's current module list).
# Disable it in FIPS deployments.
enable_pqc = false
# Already default; listed for operator awareness.
# allow_weak_rsa = false # RSA < 2048 rejected.
# allow_sha1_signing = false # SHA-1 is digest-only, never signing.
With fips_approved_only = true the module registers only approved mechanisms. The table below summarises the cut:
| Category | Allowed | Blocked |
|---|---|---|
| Symmetric | AES-128/192/256 GCM, CBC, CTR, Key Wrap | — |
| RSA | RSA-2048 / 3072 / 4096 with PKCS#1 v1.5, PSS, OAEP | RSA < 2048 |
| ECDSA | P-256, P-384 | Any other curve |
| ECDH | P-256, P-384 | Any other curve |
| Digest | SHA-256 / 384 / 512, SHA3-256 / 384 / 512 | SHA-1 (digest available, signing blocked) |
| MAC | HMAC-SHA256 / 384 / 512 | — |
| EdDSA | — | Ed25519 (not FIPS-approved) |
| PQC | — | ML-KEM, ML-DSA, SLH-DSA, hybrids |
Key size minimums: RSA ≥ 2048, AES ≥ 128. Any C_GenerateKey / C_GenerateKeyPair below these is rejected.
4. Compute the integrity HMAC sidecar
Every C_Initialize verifies an HMAC-SHA256 of the shared library against a .hmac sidecar file. The sidecar is part of the POST — without it, the check is skipped and the module logs a warning (development mode). With it in place, a tampered binary is caught before any key material is touched.
Linux or macOS:
./tools/compute-integrity-hmac.sh target/release/libcraton_hsm.so
Windows:
.\tools\compute-integrity-hmac.ps1 -LibPath target\release\craton_hsm.dll
The script writes libcraton_hsm.hmac (or craton_hsm.hmac) next to the library. Recompute it after every rebuild; a stale sidecar triggers CKR_GENERAL_ERROR at C_Initialize and the module enters an error state that requires a process restart.
5. Verify the FIPS configuration
Start a session and confirm the module is behaving as expected.
C_Initialize passes POST
Enable info-level logs and launch any consumer. Look for the POST summary:
POST: integrity=OK
POST: KATs 16/16 passed (SHA-2, SHA-3, HMAC, AES-GCM, AES-CBC, AES-CTR, RSA, ECDSA, ML-DSA, ML-KEM, RNG, DRBG)
The counts include one software integrity test plus 16 algorithm KATs, for a total of 17 self-tests. See Self-tests for the complete list and what each test exercises.
Mechanism list matches the approved set
pkcs11-tool --module ./libcraton_hsm.so --list-mechanisms
Nothing outside the approved table above should appear. If CKM_EDDSA, CKM_ML_DSA_*, CKM_ML_KEM_*, or any non-approved mechanism shows up, fips_approved_only is not set or the build did not actually use the AWS-LC backend.
A sign / verify round trip shows fips_approved = true
Initialise a token, generate an RSA-2048 key, sign, verify:
pkcs11-tool --module ./libcraton_hsm.so --login --pin <USER_PIN> \
--keypairgen --key-type RSA:2048 --label fips-test --id 01
pkcs11-tool --module ./libcraton_hsm.so --login --pin <USER_PIN> \
--sign --mechanism SHA256-RSA-PKCS --label fips-test \
--input-file /etc/hostname --output-file sig.bin
pkcs11-tool --module ./libcraton_hsm.so \
--verify --mechanism SHA256-RSA-PKCS --label fips-test \
--input-file /etc/hostname --signature-file sig.bin
Inspect the audit log entry for that Sign call; the JSON record carries "fips_approved": true:
{
"operation": {
"Sign": {
"mechanism": 7,
"fips_approved": true
}
},
"result": "Success"
}
The same flag is exposed per session as last_operation_fips_approved (queryable through the craton-admin tooling) and is reserved on objects as the vendor attribute CKA_VENDOR_FIPS_APPROVED = 0x80000001.
craton-admin status
Where available, run the administrative CLI to confirm module state:
craton-admin status
The status output includes the active backend (awslc), the fips_approved_only flag, POST state, and whether the integrity sidecar was matched at C_Initialize. If your deployment does not ship craton-admin, the same information is available in the structured logs; see Self-tests for log field names.
What changes operationally
Switching to FIPS-approved mode is not purely cosmetic — a number of call sites that work in the default mode will start returning errors. Audit ahead of cutover.
| Change | Symptom | Fix |
|---|---|---|
| SHA-1 signing is rejected. | CKR_MECHANISM_INVALID for CKM_SHA1_RSA_PKCS, CKM_ECDSA_SHA1, etc. | Switch the caller to SHA-256 or stronger. SHA-1 remains available as a digest for non-signing purposes. |
| RSA below 2048 bits is rejected. | CKR_KEY_SIZE_RANGE at C_GenerateKeyPair or C_*Init. | Re-issue keys at 2048 or larger. |
| Ed25519 is blocked. | CKR_MECHANISM_INVALID for CKM_EDDSA. | Use ECDSA P-256 or P-384 in FIPS deployments. |
| PQC mechanisms are blocked. | CKR_MECHANISM_INVALID for CKM_ML_* / CKM_SLH_*. | Wait for CMVP approval, or run a parallel non-FIPS module for PQC-only workloads. See Post-quantum migration. |
| Failed POST locks the module. | Every subsequent call returns CKR_GENERAL_ERROR. | Restart the process; a failed self-test is not recoverable in place by design. |
Pairwise consistency runs on every C_GenerateKeyPair. | Slightly slower keygen than the default build. | No fix required — this is the conditional self-test mandated by IG 10.3.A. |
Continuous RNG health tests run on every C_GenerateRandom. | Extra work per random draw. | No fix required. |
Deployment checklist
- Built with
--features awslc-backend --no-default-features. -
crypto_backend = "awslc"incraton_hsm.toml. -
fips_approved_only = true. -
enable_pqc = false(unless you have an explicit non-FIPS side channel for PQC). -
.hmacsidecar computed against the exact binary being deployed. -
C_InitializereturnsCKR_OKand the log records all 17 self-tests passing. -
pkcs11-tool --list-mechanismsshows only approved mechanisms. - Token initialised with strong SO PIN and user PIN.
- A representative sign / verify path logs
fips_approved = true. -
cargo test --features awslc-backend --no-default-features -- --test-threads=1passes on the build host. - Audit log review procedure documented for the operator on-call rotation.