Craton HSM
Security Policy
Security Policy
This page states the formal security policy enforced by Craton HSM. It is the reference operators should consult when asking "who is allowed to do what, and under what conditions." The policy is enforced by code; this page describes the enforcement rather than defining aspirational rules.
Longer-form material — design rationale, CSP inventory, lifecycle
mechanics — lives in the security-policy.md document inside the core
repository. This page is the product-facing subset.
Roles
| Role | PKCS#11 type | Purpose |
|---|---|---|
| Security Officer (SO) | CKU_SO | Token initialisation, user PIN management, reinitialisation |
| User | CKU_USER | All cryptographic operations; object creation and management |
| Unauthenticated | (no login) | Read public objects, compute digests, request random bytes |
Role membership is scoped to the session. Logging out (C_Logout) or
closing the session discards the authenticated state.
Allowed Operations Per Role
Operations marked "R/W" require a read-write session (CKF_RW_SESSION at
C_OpenSession time).
Token and PIN management
| Operation | SO | User | Unauthenticated |
|---|---|---|---|
C_InitToken | Yes (R/W) | No | No |
C_InitPIN (set user PIN) | Yes (R/W) | No | No |
C_SetPIN (change own PIN) | Yes | Yes | No |
C_Login | Yes | Yes | No |
C_Logout | Yes | Yes | No |
Key management
| Operation | SO | User | Unauthenticated |
|---|---|---|---|
C_GenerateKey (symmetric) | No | Yes | No |
C_GenerateKeyPair | No | Yes | No |
C_CreateObject | R/W (public only) | R/W | No |
C_CopyObject | R/W | R/W | No |
C_DestroyObject | R/W | R/W (own objects) | No |
C_WrapKey | No | Yes | No |
C_UnwrapKey | No | Yes | No |
C_DeriveKey | No | Yes | No |
C_SetAttributeValue | R/W | R/W | No |
Cryptographic operations
| Operation | SO | User | Unauthenticated |
|---|---|---|---|
C_Sign / C_SignUpdate / C_SignFinal | No | Yes | No |
C_Verify / C_VerifyUpdate / C_VerifyFinal | No | Yes | No |
C_Encrypt / C_EncryptUpdate / C_EncryptFinal | No | Yes | No |
C_Decrypt / C_DecryptUpdate / C_DecryptFinal | No | Yes | No |
C_Digest and multi-part digest | Yes | Yes | Yes |
C_GenerateRandom | Yes | Yes | Yes |
Object visibility
| Operation | SO | User | Unauthenticated |
|---|---|---|---|
C_GetAttributeValue — public objects | Yes | Yes | Yes |
C_GetAttributeValue — private objects (CKA_PRIVATE=true) | No | Yes | No |
C_FindObjects — public objects | Yes | Yes | Yes |
C_FindObjects — private objects | No | Yes | No |
C_GetAttributeValue(CKA_VALUE) on sensitive key | Returns CKR_ATTRIBUTE_SENSITIVE | Returns CKR_ATTRIBUTE_SENSITIVE unless CKA_SENSITIVE=false and CKA_EXTRACTABLE=true | No |
Key Attribute Enforcement
Generated keys default to maximum protection:
| Attribute | Default | Effect when true |
|---|---|---|
CKA_PRIVATE | true | Object is invisible to unauthenticated sessions |
CKA_SENSITIVE | true | CKA_VALUE cannot be read back |
CKA_EXTRACTABLE | false | Key material cannot be exported or wrapped out |
CKA_TOKEN | false | Session object by default; true requires a read-write session |
CKA_MODIFIABLE | true for most, but attribute changes that weaken protection are rejected |
CKA_SENSITIVE is monotonic — it can transition from false to true
but not back. CKA_EXTRACTABLE is monotonic in the other direction — it
can transition from true to false but not back. Attempts to weaken
protection via C_SetAttributeValue return CKR_ATTRIBUTE_READ_ONLY.
Lifecycle Attributes
Keys may carry CKA_START_DATE and CKA_END_DATE. The effective state
is computed on every operation:
| State | Condition | Permitted operations |
|---|---|---|
| Pre-activation | Current date < CKA_START_DATE | None |
| Active | No dates set, or within the range | All operations permitted by key usage attributes |
| Deactivated | Current date > CKA_END_DATE | Verify, decrypt, unwrap only |
| Compromised | Manually set | None |
| Destroyed | After C_DestroyObject | Handle is invalid |
Usage flags (CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT,
CKA_WRAP, CKA_UNWRAP, CKA_DERIVE) further restrict what an active
key can do. A signing request against a key without CKA_SIGN=true
returns CKR_KEY_FUNCTION_NOT_PERMITTED.
PIN Policy
Length and Character Set
| Setting | Default | Notes |
|---|---|---|
security.pin_min_length | 4 bytes | FIPS deployments should set this to at least 8 |
security.pin_max_length | 64 bytes | Upper bound on PIN input |
| Character set | Any bytes | The module does not enforce a character class; application guidance should recommend printable ASCII with mixed case, digits, and symbols |
Hashing and Comparison
- PBKDF2-HMAC-SHA256 with 600,000 iterations (configurable only upward).
- 32-byte per-PIN random salt from the OS CSPRNG.
- Constant-time comparison via
subtle::ConstantTimeEq. - The plaintext PIN is wiped from memory after verification.
Default PINs
C_InitToken establishes an initial SO PIN. Deployments must change it
during initial provisioning; the default "12345678" is a bootstrap
value only and is not suitable for production use.
Lockout
| Scope | Default | Behaviour |
|---|---|---|
| SO PIN failures | 10 | On threshold, C_Login returns CKR_PIN_LOCKED. Recovery requires token reinitialisation. |
| User PIN failures | 10 | On threshold, C_Login returns CKR_PIN_LOCKED. SO may reset the user PIN via C_InitPIN. |
Failed-attempt counters persist across process restarts. A successful login resets the counter.
Mechanism Policy
The module has two mechanism policies, selected by
algorithms.fips_approved_only:
| Mode | Behaviour |
|---|---|
| Non-FIPS (default) | All 41 mechanisms available. The fips_approved flag in the audit log indicates which operations used approved algorithms. |
| FIPS approved-only | Only approved mechanisms are available; non-approved mechanisms return CKR_MECHANISM_INVALID at *Init or generation time, and C_GetMechanismList returns only the approved subset. |
Always-enforced restrictions (independent of FIPS mode):
| Rule | Effect |
|---|---|
allow_weak_rsa = false (default) | RSA key generation and import below 2048 bits is rejected |
allow_sha1_signing = false (default) | SHA-1 combined signing mechanisms are rejected; SHA-1 digest-only remains available |
| AES-CBC / AES-CTR with all-zero IV | Rejected at C_EncryptInit |
| AES-GCM nonce reuse per key | Tracked via a per-key counter; approaching the 2^31 soft limit emits warnings; attempted reuse fails |
Session Policy
- A session cannot outlive the process that opened it. There is no
session persistence across
C_Finalizeor process exit. C_CloseAllSessionson a slot terminates every session and discards all in-flight operations.- A forked child receives
CKR_CRYPTOKI_NOT_INITIALIZEDfor every call until it callsC_Initializeitself. See fork-safety. - Only one process may hold the persistent database open at a time; concurrent access must go through the gRPC daemon.
Audit Policy
Every operation in the following set produces an audit entry, written synchronously before the PKCS#11 call returns:
Initialize, Finalize, Login, Logout, InitToken, InitPIN, SetPIN, GenerateKey, GenerateKeyPair, Sign, Verify, Encrypt, Decrypt, WrapKey, UnwrapKey, DeriveKey, Digest (when over non-public data), CreateObject, DestroyObject, GenerateRandom.
The log is append-only with chained SHA-256 hashes. See audit-scope.
Further Reading
- model — security model
- threat-model — adversaries and mitigations
- hardening — deployment hardening
- audit-scope — audit log coverage
- ../fips/fips-mode — enabling FIPS mode