Craton HSM

Configuration Reference

Craton HSM is configured via a TOML file. By default, it looks for craton_hsm.toml in the current working directory. Override the path with the CRATON_HSM_CONFIG environment variable.

If the config file is not found, secure defaults are used. If the config file exists but cannot be parsed or fails validation, C_Initialize returns CKR_GENERAL_ERROR (the module refuses to start with potentially misconfigured security parameters).

In FIPS mode (CRATON_HSM_FIPS=1 or --features fips), config files are ignored and hardcoded secure defaults are used.

Configuration Validation (v0.9.1)

The following validation rules are enforced on load:

  • storage_path and log_path: must be relative, no .. traversal, no UNC paths (\\server\share), no null bytes
  • pin_min_length ≥ 4; pin_max_length ≥ pin_min_length
  • pbkdf2_iterations ≥ 100,000
  • max_failed_logins: 3–100 (prevents accidental lockout or brute-force)
  • serial_number: 1–16 ASCII printable characters
  • slot_count ≥ 1
  • crypto_backend: must be "rustcrypto" or "awslc"
  • log_level: must be "all", "crypto", "auth", "admin", or "none"

Environment Variables

VariableDefaultDescription
CRATON_HSM_CONFIGcraton_hsm.tomlPath to the configuration file
RUST_LOG_FORMATtextcraton-hsm-daemon log formatter: text (human-readable, default), json (structured — consume directly in Loki / ELK / Datadog), or compact (slightly smaller per-record than text). Unknown values fall back to text and emit a warn! after init.

[token] — Token & Slot Settings

FieldTypeDefaultDescription
labelstring"Craton HSM Token 0"Token display name (returned by C_GetTokenInfo)
storage_pathstringplatform default (see below)Path to the redb persistent storage database. May be absolute or CWD-relative. Rejected: .. traversal, UNC paths, null bytes, and any component that is a symlink. Default: /var/lib/craton-hsm/store on Unix and %PROGRAMDATA%\craton-hsm\store on Windows when the parent system directory exists, otherwise falls back to the legacy relative craton_hsm_store (with a startup warning).
max_sessionsinteger100Maximum concurrent PKCS#11 sessions
max_rw_sessionsinteger10Maximum read-write sessions
persist_objectsboolfalsePersist token objects to disk (AES-256-GCM encrypted)
slot_countinteger1Number of virtual slots to expose (must be ≥ 1)
serial_numberstring"0000000000000001"Token serial number (max 16 chars, ASCII printable)

[security] — PIN & Authentication

FieldTypeDefaultDescription
pin_min_lengthinteger8Minimum PIN length in bytes (must be ≥ 4)
pin_max_lengthinteger64Maximum PIN length in bytes (must be ≥ pin_min_length)
max_failed_loginsinteger10Failed login attempts before PIN lockout (range: 3–100)
pbkdf2_iterationsinteger600000PBKDF2-HMAC-SHA256 iterations for PIN hashing (must be ≥ 100,000; SP 800-132)

[algorithms] — Cryptographic Policy

FieldTypeDefaultDescription
crypto_backendstring"rustcrypto"Crypto backend: "rustcrypto" (default) or "awslc" (requires craton_hsm-enterprise)
fips_approved_onlyboolfalseRestrict to FIPS 140-3 approved algorithms only
enable_pqcbooltrueEnable post-quantum mechanisms (ML-KEM, ML-DSA, SLH-DSA)
allow_weak_rsaboolfalseAllow RSA key sizes below 2048 bits
allow_sha1_signingboolfalseAllow SHA-1 in signing contexts (deprecated per SP 800-131A)
derived_keys_extractable_by_defaultboolfalseDerived keys whose template omits CKA_SENSITIVE / CKA_EXTRACTABLE are non-sensitive and extractable (see below). Not allowed with fips_approved_only

Derived key defaults

C_DeriveKey (and the daemon DeriveKey RPC) honour CKA_SENSITIVE and CKA_EXTRACTABLE in the derivation template. When the template leaves them unset, derived keys are sensitive and non-extractable, so their value cannot be read back.

Some callers read the derived secret without asking for a readable key. Java SunPKCS11's ECDH KeyAgreement is the common case. Either enable derived_keys_extractable_by_default, or keep the secure default and add this to the SunPKCS11 configuration:

attributes(generate, CKO_SECRET_KEY, CKK_GENERIC_SECRET) = {
  CKA_SENSITIVE = false
  CKA_EXTRACTABLE = true
}

FIPS Approved Mode

When fips_approved_only = true:

Allowed: RSA (>=2048), ECDSA (P-256, P-384), AES (GCM/CBC/CTR), SHA-256/384/512, SHA3-256/384/512, ECDH, AES Key Wrap

Blocked: EdDSA (Ed25519), SHA-1 signing, all PQC mechanisms, RSA < 2048

See FIPS Mode Guide for deployment details.

[audit] — Audit Logging

FieldTypeDefaultDescription
enabledbooltrueEnable tamper-evident audit logging
log_pathstring"craton_hsm_audit.jsonl"Path to the append-only audit log file
log_levelstring"all"Log verbosity: "all", "crypto", "auth", "admin", or "none"

[daemon] — gRPC Server (craton-hsm-daemon only)

FieldTypeDefaultDescription
bindstring"127.0.0.1:5696"gRPC listen address and port
tls_certstring(none)Path to PEM server certificate file
tls_keystring(none)Path to PEM server private-key file
tls_client_castring(none)PEM CA bundle for mandatory client-certificate validation (mTLS) on non-loopback binds
tls_client_crlstring(none)PEM/DER client-certificate revocation list, used with tls_client_ca
allow_unauthenticated_tlsboolfalseExplicitly permit server-authentication-only TLS on a non-loopback bind; only use behind an independent access-control boundary

TLS on 127.0.0.1 and [::1] may omit tls_client_ca for local development. Any non-loopback TLS listener fails closed without mTLS unless allow_unauthenticated_tls = true is explicitly set.

Example: Default Configuration

[token]
label = "Craton HSM Token 0"
storage_path = "craton_hsm_store"
max_sessions = 100
max_rw_sessions = 10
persist_objects = false
slot_count = 1

[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"

Example: FIPS 140-3 Deployment

[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"

Example: High-Session Server

[token]
max_sessions = 1000
max_rw_sessions = 100
persist_objects = true
slot_count = 4