p11ex logo

p11ex --- PKCS#11 bindings for Elixir

p11ex is an Elixir library that provides access to the PKCS#11 interface for cryptographic tokens such as Hardware Security Modules and smartcards. The library exposes most PKCS#11 functionality to Elixir, though it is not yet feature complete. Available functions include:

Some PKCS#11 functions require mechanism parameters as arguments. Common parameter types are supported and documented in the Elixir documentation.

Not Yet Supported

The following are not (yet) available. If you need one of them, please open an issue.

Tested PKCS#11 Modules

The test suite runs automatically against three software tokens:

Module Version Platforms Notes
SoftHSM 2.7.0 Linux (AMD64, ARM64), macOS (ARM64); OTP 27–29 The reference token and the only one with two tokens. Multi-part ECDSA with hashing (CKM_ECDSA_SHA256) is skipped: 2.7.0 lists it but rejects C_SignUpdate.
kryoptic 1.5.3, with post-quantum mechanisms Linux (AMD64); OTP 29 Offers the PKCS#11 2.40, 3.0 and 3.2 interfaces. Multi-part AES-GCM decryption is skipped until a release contains latchset/kryoptic#519.
NSS softoken as packaged in Ubuntu 26.04 (3.120) Linux (AMD64); OTP 29 Multi-part AES-GCM and Ed448 are unsupported. Ed25519 signing, single-part AES-GCM encryption and AES-CMAC verification are skipped because of NSS bugs (2075850, 2075851, 2075845).

kryoptic and NSS each provide a single token, so the tests that need two tokens run on SoftHSM only. Tests that depend on one module's behaviour are tagged in the suite (@tag :<module>_only, @tag unsupported_on: :<module>).

Additional tests are available for the Yubikey PKCS#11 module, though these do not run automatically as part of the build.

Concurrency and Schedulers

All PKCS#11 NIFs in p11ex run on the dirty I/O scheduler pool to prevent blocking the normal schedulers when calling slow HSM operations (network round-trips, USB transactions). This ensures the Erlang VM remains responsive even during long-running cryptographic operations.

For high-concurrency applications using network-attached HSMs, you may need to increase the dirty I/O scheduler pool size using the +SDio emulator flag (default is 10 threads). Example:

ERL_FLAGS="+SDio 20" mix test

Telemetry

p11ex emits :telemetry events for every operation that reaches the PKCS#11 module, plus session, token and module lifecycle events. This lets a host application track per-operation latency and error rates by PKCS#11 return code, which is what you need when the token is a network HSM. No reporter or metrics backend is bundled; attach your own handlers.

:telemetry.attach("p11ex-latency", [:p11ex, :session, :operation, :stop], fn _event, measurements, metadata, _config ->
duration = System.convert_time_unit(measurements.duration, :native, :microsecond)
IO.puts("#{metadata.operation} took #{duration}us (#{metadata.result})")
end, nil)

See the Telemetry guide for the full event reference, including which values are deliberately never emitted.

p11ex_cli --- CLI program to use PKCS#11 tokens

The project also includes a CLI program named p11ex_cli for working with cryptographic tokens. This program provides access to key p11ex functions.

Available Commands

For detailed documentation on each command, run p11ex_cli <command> --help.

EdDSA Support

p11ex_cli supports EdDSA signatures (Ed25519, Ed448). Use the sign command with the eddsa mechanism and digest none, since EdDSA signs the full message:

p11ex_cli sign --module /path/to/pkcs11-module.so --token-label my-token --pin-file pin.txt \
eddsa none label:my-ed25519-key input.txt output.sig

Release Process

Releases are made with manually triggered Forgejo Actions workflows on Codeberg: the library goes to Hex.pm, followed by optional Codeberg release notes and p11ex_cli binaries. See RELEASE.md for the checklist, the required secrets and troubleshooting.