Craton HSM
PKCS#11 Passthrough Backend
PKCS#11 Passthrough Backend
The craton-hsm-pkcs11 crate turns Craton HSM into an abstraction layer
over any vendor PKCS#11 token. All cryptographic operations are
delegated to the vendor library; Craton HSM supplies session management,
audit logging, and a uniform CryptoBackend API on top of a hardware
root of trust.
- Crate:
craton-hsm-pkcs11 - Backend type:
Pkcs11PassthroughBackend - License: BSL 1.1
- MSRV: Rust 1.75
- Status: production-ready
Architecture
+------------------------------------------+
| Pkcs11PassthroughBackend |
| +------------------------------------+ |
| | SessionPool | |
| | | |
| | Mutex<PooledSession> --+ | |
| | Mutex<PooledSession> --+-- N | |
| | Mutex<PooledSession> --+ | |
| | (each owns a KeyCache) | |
| +------------------------------------+ |
+-------------------+----------------------+
|
v
cryptoki::Pkcs11 (Arc)
|
v
vendor .so / .dll
- A shared
Arc<cryptoki::Pkcs11>context is wrapped by aSessionPoolofPooledSessioninstances. Each session owns aKeyCachefor imported key handles. - Default pool size is 8 (raised from 4 in the most recent hardening sweep).
- Lookup and crypto calls run sequentially under a single mutex, so there is no TOCTOU window on imported-key handles.
Configuration
use craton_hsm_pkcs11::{Pkcs11PassthroughBackend, Pkcs11PassthroughConfig};
use craton_hsm::crypto::backend::CryptoBackend;
use zeroize::Zeroizing;
let config = Pkcs11PassthroughConfig {
library_path: "/usr/lib/softhsm/libsofthsm2.so".into(),
slot_id: 0,
user_pin: Some(Zeroizing::new("1234".to_string())),
allow_software_keygen_fallback: false,
// ... other fields
};
let backend = Pkcs11PassthroughBackend::new(config)?;
# Ok::<(), craton_hsm::error::HsmError>(())
Key fields:
library_path— absolute path to the vendor PKCS#11.soor.dll. Load from a write-protected location; the library is not itself verified before loading.slot_id— numeric PKCS#11 slot identifier.user_pin— held inZeroizing<String>; redacted fromDebugoutput. TheSessionPoolhands exactly one owned copy toAuthPinper login.allow_software_keygen_fallback— off by default. When off, key generation failures surface directly instead of silently falling back to software.
This crate exposes no Cargo features; the vendor PKCS#11 library is
loaded at runtime via cryptoki / libloading.
Tested Hardware
See the compatibility matrix for the authoritative list. In summary:
| Vendor / Library | Version | Status |
|---|---|---|
| SoftHSM | 2.6.0+ | Tested — the default CI fixture |
| SoftHSM | 2.5.x | Best-effort |
| YubiHSM2 SDK | 2023.08+ | Supported; requires yubihsm-connector |
| Thales Luna Client | 10.x | Supported; firmware 7.x, mTLS to appliance |
| Utimaco CryptoServer | Se-Series (CP5) | Supported; SDK 4.40+ |
| nCipher nShield | Security World 13.x | Best-effort; requires hardserver |
| AWS CloudHSM | Client 5.x | Best-effort |
Only SoftHSM is exercised by CI. Other vendor libraries are validated pre-release against the listed versions; regression risk between Craton releases is low but not zero.
Security Properties
- No TOCTOU on imported-key handles. Each
PooledSessionowns itsKeyCache; lookup and the subsequent crypto call are sequential under one mutex. - AES-GCM nonce-reuse bound enforced per key. Each cache entry
tracks the encryption count and refuses further encryptions past the
configured ceiling (default
2^32, per NIST SP 800-38D §8.3). Cache eviction does not reset this counter. - Sticky high-water marks. Per-key counter high-water marks live in
a separate non-evictable
countersmap. A key evicted and re-imported resumes counting from its prior mark instead of silently resetting to zero. - Fail-closed software fallback. Software key-generation fallback
is off by default and must be opted into with
allow_software_keygen_fallback = true. - Domain-separated fingerprints. Cache keys are derived with a per-key-type domain tag and length-prefixed parts, preventing cross-type or concatenation collisions.
- Typed verification decoding. Verify results go through
error::VerifyOutcome/error::classify_verify_result, never string-matching of error text.
All unsafe FFI lives in the upstream cryptoki crate; this crate adds
no unsafe blocks of its own. RAII session handles guarantee
C_CloseSession on drop.
Limitations
- No built-in PIN rotation. Changing a PIN requires re-instantiating the backend with the new credential.
- No offline PKCS#11 module validation. The vendor
.so/.dllis loaded and trusted at its configured path. Deployments should load it from a write-protected directory. - Software key-generation fallback is explicit only. By design — silent software fallback would invalidate the hardware-backed trust model.
- Slot / token management (init, relabel, factory reset) is not exposed; use the vendor's own tooling for those operations.
Error Reporting
Failures surface through craton_hsm::error::HsmError, mapped from
cryptoki::error::Error and cryptoki::error::RvError via the crate's
error submodule.
Related Documents
- Compatibility matrix — tested vendor library versions.
- NXP HSE backend and Infineon TPM backend — first-class hardware backends that do not require a vendor PKCS#11 library.