Current section
Files
Jump to
Current section
Files
README.md
<div align="right">
<img src="img/p11ex-logo-400x400.png" alt="p11ex logo" width="100">
</div>
# p11ex --- PKCS#11 bindings for Elixir
`p11ex` is an Elixir library that provides access to the [PKCS#11 interface](https://docs.oasis-open.org/pkcs11/pkcs11-base/v3.1/os/pkcs11-base-v3.1-os.html) 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:
- `C_CloseAllSessions`: Close all open sessions for a token
- `C_CloseSession`: Close a PKCS#11 session
- `C_CopyObject`: Copy an object, optionally changing attributes
- `C_CreateObject`: Create an object, e.g. to import a key
- `C_DecryptInit`, `C_Decrypt`, `C_DecryptUpdate`, and `C_DecryptFinal`: Decryption in chunks and as a complete block
- `C_DeriveKey`: Derive a key from a base key (e.g. ECDH)
- `C_DestroyObject`: Delete objects in the token or session
- `C_DigestInit`, `C_Digest`, `C_DigestUpdate`, `C_DigestFinal`: Compute a hash digest in the token
- `C_EncryptInit`, `C_Encrypt`, `C_EncryptUpdate`, and `C_EncryptFinal`: Encryption in chunks and as a complete block
- `C_FindObjects`: Search for objects stored in the token
- `C_GenerateKey`: Generate a symmetric key
- `C_GenerateKeyPair`: Generate asymmetric key pair
- `C_GenerateRandom`: Generate random bytes using the token
- `C_GetAttributeValue`: Retrieve attributes of an object
- `C_GetInfo`: Retrieve general information about the loaded PKCS#11 module
- `C_GetMechanismInfo`: Retrieve information about a mechanism
- `C_GetMechanismList`: List cryptographic mechanisms supported by token
- `C_GetSessionInfo`: Retrieve status information about a session
- `C_GetSlotList`: List tokens
- `C_GetTokenInfo`: Retrieve information about a token
- `C_InitPIN`: Set the user PIN (as SO)
- `C_InitToken`: Initialize a token with an SO PIN and a label
- `C_Login`: Authenticate an open session
- `C_Logout`: Deauthenticate an open session
- `C_OpenSession`: Open a new PKCS#11 session
- `C_SeedRandom`: Mix additional seed material into the token's RNG
- `C_SetAttributeValue`: Change attributes of an object
- `C_SetPIN`: Change the PIN of the logged-in user
- `C_SignInit`, `C_Sign`, `C_SignUpdate`, `C_SignFinal`: Sign data in chunks and as a complete block
- `C_UnwrapKey`: Decrypt an exported key into the token
- `C_VerifyInit`, `C_Verify`: Verify a signature
- `C_WrapKey`: Encrypt an extractable key and make it exportable
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.
- **Multi-part verification**: `C_VerifyUpdate` and `C_VerifyFinal`. Signatures over large inputs must be verified with `C_Verify` in one call.
- **Mechanism parameters** for mechanisms other than AES-GCM, AES-CBC/CBC-PAD/OFB, AES-CTR, AES-CCM, AES-CMAC-GENERAL, RSA-PSS (`CKM_RSA_PKCS_PSS` only, see below), RSA-OAEP, EdDSA and ECDH1-DERIVE. Notably, the CFB/CTS/XTS modes, `CKM_RSA_AES_KEY_WRAP` and the HKDF and SP800-108 key derivation mechanisms cannot be used yet. Mechanisms that take no parameters work regardless of whether they are named in the library.
- **RSA-PSS mechanisms that digest on the token**: `CKM_SHA1_RSA_PKCS_PSS`, `CKM_SHA224_RSA_PKCS_PSS`, `CKM_SHA256_RSA_PKCS_PSS`, `CKM_SHA384_RSA_PKCS_PSS` and `CKM_SHA512_RSA_PKCS_PSS`. These take `CK_RSA_PKCS_PSS_PARAMS` as well, but the parameters are only wired up for `CKM_RSA_PKCS_PSS`. Use `CKM_RSA_PKCS_PSS` instead and digest the data before signing.
- **PKCS#11 3.0 additions**: the module is loaded via `C_GetFunctionList`, so the 3.0 function set is unavailable. This includes the message-based API (`C_EncryptMessage` and friends), `C_LoginUser` and `C_SessionCancel`.
- **Miscellaneous**: `C_WaitForSlotEvent`, `C_GetObjectSize`, `C_DigestKey`, the operation-state functions and the legacy recovery and dual-function operations.
## Tested PKCS#11 Modules
The test suite runs automatically against three software tokens:
| Module | Version | Platforms | Notes |
|--------|---------|-----------|-------|
| [SoftHSM](https://github.com/softhsm/softHSMv2) | 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](https://github.com/latchset/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](https://github.com/latchset/kryoptic/pull/519). |
| [NSS softoken](https://firefox-source-docs.mozilla.org/security/nss/) | 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](https://bugzilla.mozilla.org/show_bug.cgi?id=2075850), [2075851](https://bugzilla.mozilla.org/show_bug.cgi?id=2075851), [2075845](https://bugzilla.mozilla.org/show_bug.cgi?id=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](https://developers.yubico.com/yubico-piv-tool/YKCS11/), 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:
```bash
ERL_FLAGS="+SDio 20" mix test
```
## Telemetry
`p11ex` emits [`:telemetry`](https://hexdocs.pm/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.
```elixir
: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](guides/telemetry.md) 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
- `list-slots`: List available PKCS#11 slots/tokens
- `list-objects`: List objects (keys, certificates) on a token
- `key-gen-aes`: Generate AES symmetric keys
- `export-pubk`: Export public keys (RSA, EC, EdDSA)
- `sign`: Sign data with RSA, EC, or EdDSA algorithms
- `key-wrap` / `key-unwrap`: Wrap/unwrap keys for secure transport
- `kcv-gen`: Compute Key Check Value (fingerprint) of secret keys
- `bench-aes-encrypt-block`: Benchmark AES encryption performance
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:
```bash
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](RELEASE.md) for the checklist, the required secrets and troubleshooting.