← blog

Why we rewrote SoftHSM in Rust

Buffer overflows in attribute parsing, use-after-free in session lifecycle, double-free in error paths. The case for a PKCS#11 v3.0 HSM with zero unsafe in crypto paths.

by Victor Bobrovskiy

SoftHSMv2 is the de-facto open-source software HSM. It is written in C++. It has also accumulated a decade of CVEs whose root cause is the choice of language — buffer overflows in attribute parsing, use-after-free in session lifecycle, double-free in error paths, data races in concurrent access. These are not bugs that get fixed once. They are a tax you pay forever on the implementation language.

Craton HSM is our answer: a PKCS#11 v3.0-compliant software HSM written in pure Rust, drop-in compatible with SoftHSMv2 as a dynamically loadable shared library. Same 70+ C ABI exports. Same deployment story. Different guarantees.

What we keep

PKCS#11 v3.0 surface. Any application that speaks PKCS#11 — OpenSSL engines, Java providers, Firefox NSS, pkcs11-tool — works without modification.

Deployment shapes. In-process shared library (.so / .dll / .dylib), gRPC daemon with mutual TLS, or Kubernetes sidecar behind a distroless image.

Audit transparency. Tamper-evident chained SHA-256 audit log, algorithm indicator in every entry per FIPS IG 2.4.C.

What changes

Zero unsafe code in cryptographic paths. The FFI boundary is audited and minimal; everything above it is safe Rust.

ZeroizeOnDrop on every key. Key bytes never appear in logs, debug output, or error messages. Constant-time PIN and HMAC comparison.

Post-quantum by default. ML-DSA-44/65/87, ML-KEM-512/768/1024, SLH-DSA, and hybrid ML-DSA-65 + ECDSA composite signatures — 41 mechanisms including 9 PQC where SoftHSMv2 has zero.

FIPS 140-3 Level 1 readiness. 17 power-on self-tests on every C_Initialize: software integrity (HMAC-SHA256 of module binary), 16 known-answer tests covering SHA-2/3, HMAC, AES-GCM/CBC/CTR, ECDSA, RSA-2048, ML-DSA-44, ML-KEM-768, and the DRBG, plus a continuous RNG health test.

Pluggable backends. RustCrypto (pure Rust) by default. aws-lc-rs (FIPS-validated) available through craton-hsm-enterprise — same API, different hardening posture.

The numbers

On a mid-tier server (Xeon, no AES-NI disabled):

  • Ed25519 sign: 43.79 μs
  • AES-256-GCM 4 KB: 3.633 μs
  • RSA-2048 sign: 1.927 ms
  • ML-DSA-44 sign: 711.9 μs
  • ML-KEM-768 encapsulate: 74.46 μs

With the aws-lc-rs backend: RSA-2048 verify runs 8.3× faster, ECDSA verify 4.5× faster. Same API, different engine, a --features aws-lc away.

Where this goes

The regulatory environment is converging: White House ONCD, CISA, the EU Cyber Resilience Act, UN R155, FIPS 140-3 itself — all pushing toward memory-safe implementations of cryptographic primitives. This is not a technology bet. It is the direction of travel.

If you are running SoftHSMv2 in production and would rather not carry the C++ CVE stream into the next decade, the migration is mechanically a library swap — and the audit conversation is much easier when you can point at a language-level guarantee instead of a patching cadence.

Read the docs: /docs/craton-hsm. Source: github.com/craton-co/craton-hsm-core.