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:

VariableDefaultPurpose
CRATON_HSM_CONFIGcraton_hsm.tomlAbsolute 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 with Configuration error: file has group/world-writable permissions.
  • Windows — no write permission for Everyone or Users. Strip inherited ACLs with icacls craton_hsm.toml /inheritance:r /grant:r "%USERNAME%:F".

Precedence

  1. Compile-time FIPS defaults if the build was produced with --features fips or CRATON_HSM_FIPS=1 is set.
  2. Values parsed from the config file at the path given by CRATON_HSM_CONFIG (or the default).
  3. 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_path and log_path must 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_length must be at least 4; pin_max_length must be at least pin_min_length.
  • pbkdf2_iterations must be in [100_000, 10_000_000]. SP 800-132 is the floor; the ceiling is a liveness guard.
  • max_failed_logins must be in [3, 100].
  • serial_number must be 1 to 16 ASCII-printable characters.
  • slot_count must be at least 1.
  • crypto_backend must be "rustcrypto" or "awslc".
  • log_level must be one of "all", "crypto", "auth", "admin", "none".

[token] — token and slot settings

FieldTypeDefaultDescription
labelstring"Craton HSM Token 0"Token display name returned by C_GetTokenInfo.
storage_pathstring"craton_hsm_store"Directory for the AES-256-GCM-encrypted redb object store. Relative, no traversal.
max_sessionsinteger100Concurrent PKCS#11 sessions.
max_rw_sessionsinteger10Subset of max_sessions allowed to be read-write.
persist_objectsboolfalsePersist token objects across restarts. In-memory mode (false) drops all objects on shutdown.
slot_countinteger1Number of virtual PKCS#11 slots to expose.
serial_numberstring"0000000000000001"Fixed-length serial returned by C_GetTokenInfo.

[security] — PIN and authentication

FieldTypeDefaultDescription
pin_min_lengthinteger8Minimum PIN length in bytes.
pin_max_lengthinteger64Maximum PIN length in bytes.
max_failed_loginsinteger10Failed login attempts before the PIN is locked.
pbkdf2_iterationsinteger600000PBKDF2-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

FieldTypeDefaultDescription
crypto_backendstring"rustcrypto"Backend: "rustcrypto" (open source) or "awslc" (FIPS-validated, enterprise).
fips_approved_onlyboolfalseRestrict mechanisms to FIPS 140-3 approved algorithms.
enable_pqcbooltrueEnable ML-KEM, ML-DSA, SLH-DSA mechanisms.
allow_weak_rsaboolfalsePermit RSA key sizes below 2048 bits.
allow_sha1_signingboolfalsePermit 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

FieldTypeDefaultDescription
enabledbooltrueEnable tamper-evident audit logging.
log_pathstring"craton_hsm_audit.jsonl"Append-only JSON-Lines audit log.
log_levelstring"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.

FieldTypeDefaultDescription
bindstring"127.0.0.1:5696"Listen address.
tls_certstring(none)PEM certificate for mTLS.
tls_keystring(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.

SectionEffect of change
[token]label, serial_numberRestart. Visible to PKCS#11 consumers after C_GetTokenInfo.
[token]storage_path, persist_objectsRestart. Changing storage mode mid-life requires a migration.
[security] — any fieldRestart. Existing PIN hashes remain at the iteration count they were created with until next C_SetPIN.
[algorithms] — any fieldRestart. 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.