PKCS#11 Hardware Security Module (HSM)
PKCS#11 is a cryptographic token interface standard that provides a platform-independent API to cryptographic tokens such as hardware security modules (HSMs) and smart cards. It enables secure key storage and cryptographic operations in hardware, offering enhanced security for private key protection. The standard supports various cryptographic algorithms and provides fine-grained access control through PIN-based authentication. PKCS#11 tokens can generate, store, and use cryptographic keys without exposing them to the host system, making them ideal for high-security environments where private key protection is critical.
You can read more about PKCS#11 here.
RequirementsYour HSM must support:
- PKCS#11 interface
- secp256k1 elliptic curve (required for Ethereum)
- ECDSA signature generation
- AWS CloudHSM
- Nitrokey HSM 2
- Thales/SafeNet Luna HSMs (requires custom firmware/configuration)
- Utimaco HSMs (requires custom configuration)
- Ledger hardware wallets (requires unofficial PKCS#11 module)
Usage
To enable PKCS#11 you need to add the library path and authentication details to the YAML under the pkcs11
key.
Fields
library_path
This is the absolute path to your PKCS#11 library (.so file on Linux/macOS, .dll on Windows).
name: first-rrelayer
description: "my first rrelayer"
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: "/usr/lib/pkcs11/opensc-pkcs11.so"
Common library paths:
- SoftHSM:
/usr/lib/softhsm/libsofthsm2.so
or/opt/homebrew/lib/softhsm/libsofthsm2.so
- OpenSC:
/usr/lib/pkcs11/opensc-pkcs11.so
- Ledger: Platform-specific Ledger PKCS#11 library
pin (optional)
The PIN or password required to authenticate with your HSM slot.
name: first-rrelayer
description: "my first rrelayer"
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: "/usr/lib/pkcs11/opensc-pkcs11.so"
pin: "${HSM_PIN}"
slot_id (optional)
The specific slot ID to use if your HSM has multiple slots. If not specified, the first available slot will be used.
name: first-rrelayer
description: "my first rrelayer"
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: "/usr/lib/pkcs11/opensc-pkcs11.so"
pin: "${HSM_PIN}"
slot_id: 82907649
identity (required)
A unique identifier for this rrelayer instance. This identity is used to namespace key labels in the HSM, allowing multiple rrelayer instances to use the same HSM device without key conflicts.
The identity is combined with chain ID and wallet index to create unique labels like rrelayer-{identity}-wallet-{chain_id}-{wallet_index}
.
name: first-rrelayer
description: "my first rrelayer"
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: "/usr/lib/pkcs11/opensc-pkcs11.so"
pin: "${HSM_PIN}"
identity: "prod-relay-01"
test_mode (optional)
Enables testing mode for development and CI environments. When enabled, returns predetermined mock signatures instead of using the HSM for signing operations.
name: development-rrelayer
description: "Development rrelayer with mock HSM"
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: "/opt/homebrew/lib/softhsm/libsofthsm2.so"
pin: "1234"
slot_id: 82907649
identity: "dev-test"
test_mode: true
- Development environment testing
- CI/CD pipeline integration tests
- Configuration validation
- RRelayer integration testing
- Real HSM compatibility
- Actual PKCS#11 library functionality
- Hardware-specific behaviors
- Production signature generation
Complete Configuration Example
name: production-rrelayer
description: 'Production rrelayer with HSM'
api_config:
port: 3000
authentication_username: ${RRELAYER_AUTH_USERNAME}
authentication_password: ${RRELAYER_AUTH_PASSWORD}
signing_provider:
pkcs11:
library_path: '/usr/lib/pkcs11/cloudhsm-pkcs11.so'
pin: '${HSM_PIN}'
slot_id: 1
identity: 'prod-relay-01'
Key Management
The PKCS#11 provider automatically:
- Generates secp256k1 key pairs on the HSM for each wallet index and chain ID combination
- Derives Ethereum addresses using Keccak256 hashing
- Tags keys with unique labels combining identity, chain ID, and wallet index (
rrelayer-{identity}-wallet-{chain_id}-{wallet_index}
) - Maintains a cache mapping between wallet indices, chain IDs, and HSM key handles
- Ensures keys are unique per chain and wallet combination to prevent cross-chain replay attacks
Keys are generated on-demand when first accessed and remain on the HSM for subsequent use. The identity field ensures multiple rrelayer instances can safely share the same HSM device without key conflicts.
Security Considerations
- Private keys never leave the HSM device
- All cryptographic operations are performed within the HSM
- Authentication is required for each session
- Key generation uses hardware-based entropy
- Some HSMs support additional features like key backup and recovery
Troubleshooting
Common Issues
Library not found: Ensure the PKCS#11 library path is correct and the library is installed.
Authentication failed: Verify the PIN is correct and the slot is accessible.
secp256k1 not supported: Confirm your HSM supports the secp256k1 curve required for Ethereum.
Signature recovery failures: Some HSMs generate deterministic signatures (RFC 6979) that may be incompatible with Ethereum's signature recovery mechanism. The implementation attempts multiple recovery IDs to find a compatible signature. If no compatible signature is found, an error is returned with guidance to use an HSM with random nonce generation or one specifically designed for Ethereum.
Testing
For development and testing purposes, you can use SoftHSM:
# Install SoftHSM (macOS with Homebrew)
brew install softhsm
# Initialize a test slot
softhsm2-util --init-token --slot 0 --label "test-token" --pin 1234 --so-pin 5678
For development and testing environments, you can use the test_mode configuration:
signing_provider:
pkcs11:
library_path: '/opt/homebrew/lib/softhsm/libsofthsm2.so'
pin: '1234'
slot_id: 82907649
identity: 'test-relay'
test_mode: true # Returns mock signatures for testing