All notable changes are documented here. The format follows Keep a Changelog, and this project adheres to Semantic Versioning.
This file tracks the pkcs11ex Hex package specifically. The sister packages (sign_core, soft_signer, pkcs11ex_audit) maintain their own changelogs in their respective directories.
[Unreleased]
Changed
Pkcs11ex.Slot.Pool.register/2logs a warning when the same slot is re-registered with a different pool size. Previously silent — config drift between two startup paths could go unnoticed.Pkcs11ex.PKCS12.unsupported_kdf_from_output/1regex tightened. The previous\d+(?:\.\d+)+matched the first dot-separated number anywhere in the openssl error — including the openssl version string ("OpenSSL 3.2.1"), which would be mis-reported as the unsupported KDF OID. New patterns anchor to "unknown algorithm <oid>", "unsupported algorithm <oid>", "OID = <oid>", "(OID: <oid>)" and require ≥ 3 OID arcs to filter out short version strings.Mix.Tasks.Pkcs11ex.ImportP12moduledoc spells out the BEAM-heap threat model around the plaintext PKCS#1 RSA private key transit. The implementation is unchanged; the threat model is now explicit so operators can size their mitigations.
Changed
- NIF surfaces
CKR_USER_ALREADY_LOGGED_INas the typed atom:user_already_logged_ininstead of an opaque{:pkcs11_error, msg}tuple.Pkcs11ex.Slot.Servermatches on the atom directly, dropping the substring-match-on-error-message helper that would silently break on cryptoki release wording changes. - Pinned
:rustlerto~> 0.37.0(was~> 0.36).Vec<u8>encoding shape differs between 0.36 and 0.37; the loose constraint left the NIF return shape ABI-unstable, which had to be papered over with multi-shape return handling inPkcs11ex.sign_bytes/2andPkcs11ex.Slot.Server. Pin removes the ambiguity; redundant return-shape branches dropped. - Configurable
Pkcs11ex.Slot.ServerGenServer.call timeouts — per-call:call_timeoutopt and:slot_call_timeoutapplication-env knob. Previously hardcoded at 30s for sign/verify/login/logout/status and 60s forimport_keypair, which silently truncated long-running operations on slow cloud HSMs. - Protocol consolidation re-enabled in
:test. The fixture-onlyJWSTestSigner(with itsdefimpl SignCore.Signer) moved totest/support/, gated byelixirc_paths(:test). Previouslyconsolidate_protocols: Mix.env() != :testworked around the in-testdefimpl; production and test now run with identical consolidation behavior.
[0.1.0]
Initial Hex release. The repository hosts a family of packages from a single git tree (Phoenix-style monorepo); this changelog covers the pkcs11ex package — the PKCS#11 hardware provider.
Added — Hex publish setup
- Conditional
:sign_coreand:pkcs11ex_auditdeps: path during monorepo dev, Hex when consuming the published tarball. - Tightened
package: files: …whitelist to shiplib/, the Rust NIF source, specs, README, and CHANGELOG.
Added — monorepo split
Pkcs11ex.Signerstruct — implementsSignCore.Signerprotocol. Supports both the slot-ref form (%Pkcs11ex.Signer{slot_ref: :foo, key_ref: :bar}) and the explicit-module form (%Pkcs11ex.Signer{module: ..., slot_id: ..., key_label: ...}).Pkcs11ex.PDF,Pkcs11ex.XML,Pkcs11ex.JWS— convenience wrappers aroundSignCore.{PDF,XML,JWS}. Translate the historical option ergonomics (signer: {slot_ref, key_ref},module:/slot_id:/key_label:) into aPkcs11ex.Signerstruct that the format adapters dispatch on.Pkcs11ex.X509— backwards-compat alias forSignCore.X509.- Format-adapter primitives (PDF Reader/Writer, CMS, XML/XAdES, X509, Policy, Algorithm) extracted into the new
sign_corepackage — seesign_core/CHANGELOG.md.
Added — Phase 5 (Compliance) complete
- B-T sign for PDF (
tsa_url:opt) — attaches an RFC 3161 TimeStampToken asid-aa-signatureTimeStampTokenin CMSunsignedAttrs. - B-T sign for XML (
tsa_url:opt) — attaches a<xades:SignatureTimeStamp>under<xades:UnsignedSignatureProperties>per ETSI EN 319 132-1 §5.4.1. Pkcs11ex.Audit.Anchor.RFC3161.extract_token/1— strips PKIStatusInfo from a TimeStampResp and surfaces the bare TST. Used by both PDF and XML B-T attach paths.- Telemetry meta + error-class wiring for the new
{:bt_failed, …}errors.
Added — Phase 4 (Format Expansion) complete
- PAdES B-B —
Pkcs11ex.PDF.sign/2andverify/2. Hand-rolled CMS encoder over OTP's'CryptographicMessageSyntax-2009'codec; minimal trailer/xref reader and incremental-update writer; no full PDF parser. PSS signature parameters (RSASSA-PSS-params) encoded canonically for OpenSSL / BouncyCastle compatibility. - XAdES B-B —
Pkcs11ex.XML.sign/2andverify/2. Exclusive XML Canonicalization 1.0 via vendored + patchedxmerl_c14n;<xades:SigningCertificateV2>with RFC 5035 IssuerSerial. - 6-step verify pipeline for both formats: locate, append-attack detection, parse, allowlist gate, message digest match, signature math.
- Conformance suite —
pdfsig(Poppler) andxmlsec1(libxmlsec1) accept the output. Opt-in viamix test --include conformance. - SafeNet eToken end-to-end test harness (
test/pkcs11ex/safenet/). Validated against a real SafeNet Token JC with a self-generated RSA-2048 keypair under PSS-SHA-256.
Added — Phase 3 (Cloud)
:cloud_hsmslot type — login is a no-op (cloud auth via libkmsp11 / IAM, not PKCS#11 user PIN).Slot.login/2returns{:error, :no_pin_required}.:driver_configenv-var passthrough —KMS_PKCS11_CONFIGset automatically for libkmsp11 drivers beforemodule_load.examples/gcp-cloud-hsm/— runnable runtime.exs + kmsp11.yaml + README walkthrough (gcloud kms setup, Workload Identity Federation auth).
Added — Phase 2 (Hybrid)
- Per-slot persistent session model (
parking_lot::Mutex<cryptoki::Session>Rustler resource). Pkcs11ex.SlotSupervisor+Pkcs11ex.Slot.ServerGenServer — round-robin session pool for cloud HSMs.pin_callbacklifecycle (config-resolved MFA, PIN never enters GenServer state, Rust-sideZeroizing<Vec<u8>>).:signerresolution insign_bytes/2and JWS.- Inactivity timeout +
:reauthenticationpolicy (:prompt/:fail). mix pkcs11ex.import_p12task.
Added — Phase 1 (PoC)
- Initial Mix project with Rustler bridge, OTP application scaffold, configuration files.
Pkcs11ex.Native— Rust NIF over thecryptokicrate.Pkcs11ex.sign_bytes/2andverify_bytes/4Layer 2 primitives.Pkcs11ex.JWS— RFC 7797 detached JWS, PS256.Pkcs11ex.Policy.PinnedRegistry(default trust policy; SPKI pinning).Pkcs11ex.PKCS12read-only loader (openssl CLI backing).- Specifications in
docs/specs/:specs.md(architecture, threat model) andapi.md(configuration, behaviours, surface, error taxonomy). - Toolchain pins (
.tool-versions): Elixir 1.19+, Erlang/OTP 28+, Rust 1.85+.