Craton HSM
Configuration
Configuration
Craton HSM is configured through a single TOML file. Every field has a secure default, so a missing config is not an error — the module starts with built-in defaults. A config file that exists but fails to parse or fails validation causes C_Initialize to return CKR_GENERAL_ERROR: the module refuses to start with unknown security parameters rather than silently falling back.
This page lists every field, its default, the rules the loader enforces, and which changes require a restart.
File location
By default the module looks for craton_hsm.toml in the current working directory. Override the path with an environment variable:
| Variable | Default | Purpose |
|---|---|---|
CRATON_HSM_CONFIG | craton_hsm.toml | Absolute or relative path to the config file. |
In FIPS mode (CRATON_HSM_FIPS=1, or a build with --features fips) the config file is ignored entirely and hardcoded FIPS-approved defaults are used. This is intentional: the validated boundary does not admit runtime configuration.
File permissions
The config file must be readable only by the process owner.
- Unix — mode
0600. A group- or world-writable file is rejected withConfiguration error: file has group/world-writable permissions. - Windows — no write permission for
EveryoneorUsers. Strip inherited ACLs withicacls craton_hsm.toml /inheritance:r /grant:r "%USERNAME%:F".
Precedence
- Compile-time FIPS defaults if the build was produced with
--features fipsorCRATON_HSM_FIPS=1is set. - Values parsed from the config file at the path given by
CRATON_HSM_CONFIG(or the default). - Built-in defaults for any field the config file does not set.
There is no environment-variable layer for individual config fields. Everything that is not FIPS-locked goes through the TOML file.
Validation rules
The following checks are enforced on load. Any failure aborts startup.
storage_pathandlog_pathmust be relative, with no..traversal, no UNC prefix (\\server\share), no null bytes, and no symlink components. Paths pointing into known-sensitive directories (.git,.ssh,.aws,.gnupg) are rejected.pin_min_lengthmust be at least4;pin_max_lengthmust be at leastpin_min_length.pbkdf2_iterationsmust be in[100_000, 10_000_000]. SP 800-132 is the floor; the ceiling is a liveness guard.max_failed_loginsmust be in[3, 100].serial_numbermust be 1 to 16 ASCII-printable characters.slot_countmust be at least1.crypto_backendmust be"rustcrypto"or"awslc".log_levelmust be one of"all","crypto","auth","admin","none".
[token] — token and slot settings
| Field | Type | Default | Description |
|---|---|---|---|
label | string | "Craton HSM Token 0" | Token display name returned by C_GetTokenInfo. |
storage_path | string | "craton_hsm_store" | Directory for the AES-256-GCM-encrypted redb object store. Relative, no traversal. |
max_sessions | integer | 100 | Concurrent PKCS#11 sessions. |
max_rw_sessions | integer | 10 | Subset of max_sessions allowed to be read-write. |
persist_objects | bool | false | Persist token objects across restarts. In-memory mode (false) drops all objects on shutdown. |
slot_count | integer | 1 | Number of virtual PKCS#11 slots to expose. |
serial_number | string | "0000000000000001" | Fixed-length serial returned by C_GetTokenInfo. |
[security] — PIN and authentication
| Field | Type | Default | Description |
|---|---|---|---|
pin_min_length | integer | 8 | Minimum PIN length in bytes. |
pin_max_length | integer | 64 | Maximum PIN length in bytes. |
max_failed_logins | integer | 10 | Failed login attempts before the PIN is locked. |
pbkdf2_iterations | integer | 600000 | PBKDF2-HMAC-SHA256 iterations for PIN hashing. |
The hash algorithm is PBKDF2-HMAC-SHA256 and is not configurable; this is a FIPS constraint. PIN verification applies exponential backoff independently of max_failed_logins (100 ms base, doubling per failure, capped at 5 s) to rate-limit online guessing before the lockout triggers.
[algorithms] — cryptographic policy
| Field | Type | Default | Description |
|---|---|---|---|
crypto_backend | string | "rustcrypto" | Backend: "rustcrypto" (open source) or "awslc" (FIPS-validated, enterprise). |
fips_approved_only | bool | false | Restrict mechanisms to FIPS 140-3 approved algorithms. |
enable_pqc | bool | true | Enable ML-KEM, ML-DSA, SLH-DSA mechanisms. |
allow_weak_rsa | bool | false | Permit RSA key sizes below 2048 bits. |
allow_sha1_signing | bool | false | Permit SHA-1 in signing contexts (deprecated per SP 800-131A). |
When fips_approved_only = true the PQC mechanisms, EdDSA, SHA-1 signing, and RSA below 2048 bits are refused with CKR_MECHANISM_INVALID regardless of the individual toggles above. See ../fips/self-tests.
[audit] — audit logging
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable tamper-evident audit logging. |
log_path | string | "craton_hsm_audit.jsonl" | Append-only JSON-Lines audit log. |
log_level | string | "all" | One of "all", "crypto", "auth", "admin", "none". |
The audit log is created with owner-only permissions (0600 / owner-only ACL). The process must own the file; see ./monitoring for the chained-hash format and verification procedure.
[daemon] — gRPC server
Used only by craton-hsm-daemon. The in-process PKCS#11 library ignores this section.
| Field | Type | Default | Description |
|---|---|---|---|
bind | string | "127.0.0.1:5696" | Listen address. |
tls_cert | string | (none) | PEM certificate for mTLS. |
tls_key | string | (none) | PEM private key for mTLS. |
Binding to a non-loopback address without TLS configured requires an explicit allow_insecure = true, and should only be used inside a private network with other controls in place. See ../security/hardening.
Reloadable vs. restart-required
The daemon has no SIGHUP reload path today. All changes require a restart of craton-hsm-daemon, or re-C_Initialize for the in-process library.
| Section | Effect of change |
|---|---|
[token] — label, serial_number | Restart. Visible to PKCS#11 consumers after C_GetTokenInfo. |
[token] — storage_path, persist_objects | Restart. Changing storage mode mid-life requires a migration. |
[security] — any field | Restart. Existing PIN hashes remain at the iteration count they were created with until next C_SetPIN. |
[algorithms] — any field | Restart. Policy is checked on every mechanism call but loaded at init. |
[audit] | Restart. Log rotation is done out of band (see runbook). |
[daemon] | Restart. TLS material is re-read on restart only. |
Full example
[token]
label = "Craton HSM Token 0"
storage_path = "craton_hsm_store"
max_sessions = 100
max_rw_sessions = 10
persist_objects = true
slot_count = 1
serial_number = "0000000000000001"
[security]
pin_min_length = 8
pin_max_length = 64
max_failed_logins = 10
pbkdf2_iterations = 600000
[algorithms]
crypto_backend = "rustcrypto"
fips_approved_only = false
enable_pqc = true
allow_weak_rsa = false
allow_sha1_signing = false
[audit]
enabled = true
log_path = "craton_hsm_audit.jsonl"
log_level = "all"
[daemon]
bind = "127.0.0.1:5696"
tls_cert = "tls.crt"
tls_key = "tls.key"
FIPS-approved profile
[algorithms]
crypto_backend = "awslc"
fips_approved_only = true
enable_pqc = false
allow_weak_rsa = false
allow_sha1_signing = false
[security]
pbkdf2_iterations = 600000
max_failed_logins = 5
[audit]
enabled = true
log_level = "all"
See ../fips/self-tests for the validated boundary and ./runbook for operational procedures.