rust-hsm
A Rust PKCS#11 CLI tool for interfacing with SoftHSM2 in a Docker container. Provides repeatable HSM-style workflows for token management, key generation, and cryptographic operations using PKCS#11.
Vision: A Swiss Army knife for HSM operations - from troubleshooting to benchmarking to automation.
Features
✅ Implemented:
- Token initialization and management
- User PIN setup
- RSA keypair generation (2048/4096 bits)
- ECDSA keypair generation (P-256/P-384 curves)
- Sign/verify operations with SHA-256+RSA (CKM_SHA256_RSA_PKCS)
- Sign/verify operations with ECDSA (CKM_ECDSA with manual SHA-256 hashing)
- RSA encryption/decryption (CKM_RSA_PKCS)
- Public key export in PEM format (RSA & ECDSA)
- Key deletion from HSM
- Symmetric key generation (AES-128/192/256)
- Symmetric encryption/decryption (AES-GCM with IV management)
- Hash operations (SHA-256, SHA-512, SHA-224, SHA-1) - no login required
- HMAC operations (SHA-1/224/256/384/512) - message authentication with hash functions
- CMAC operations (AES-based) - message authentication with block cipher
- Random number generation - secure random bytes from HSM's RNG (C_GenerateRandom)
- Performance benchmarking - comprehensive suite testing all operations with detailed metrics
- Mechanism discovery - list all PKCS#11 mechanisms supported by HSM
- Detailed mechanism capabilities - show encrypt/decrypt/sign/verify/wrap/unwrap capabilities
- Object listing and inspection
- Detailed object attributes - show key type, flags (tok/prv/r/w/loc), capabilities, security attributes
- Key attribute inspection - detailed CKA_* attribute display
- Key fingerprints - SHA-256 hash of public keys for verification
- Module and slot information
- PIN input from stdin (secure, no shell history)
- Comprehensive logging with PKCS#11 function names
- Key wrap/unwrap operations (AES Key Wrap RFC 3394)
- CSR generation (X.509 Certificate Signing Requests for RSA & ECDSA keys)
-
JSON output (
--jsonflag) - Machine-parseable output for automation, CI/CD, and fleet auditing -
Observability & Analysis:
- observe-core - Event logging with redaction-first design
- observe-cryptoki - Transparent PKCS#11 operation tracing
- analyze - Comprehensive log analysis with percentile stats, per-function metrics, and error summaries
-
Troubleshooting commands:
- explain-error - Decode PKCS#11 error codes with context-aware guidance (35+ errors)
- find-key - Fuzzy key search with Levenshtein distance matching
- diff-keys - Side-by-side key comparison with attribute severity indicators
- End-to-end test suite (43 tests including troubleshooting validation)
Architecture
Project Structure
rust-hsm/
├── crates/
│ ├── rust-hsm-core/ # Reusable PKCS#11 library
│ │ ├── src/
│ │ │ ├── lib.rs # Public API exports
│ │ │ └── pkcs11/ # Core PKCS#11 modules
│ │ └── Cargo.toml
│ ├── rust-hsm-cli/ # CLI application
│ │ ├── src/
│ │ │ ├── main.rs # Command-line interface
│ │ │ ├── cli.rs # Argument parsing
│ │ │ └── config.rs # Configuration handling
│ │ └── Cargo.toml
│ ├── observe-core/ # Observability event logging
│ │ ├── src/
│ │ │ ├── lib.rs # Event schema, redaction, sinks
│ │ │ └── ... # FileSink implementation
│ │ └── Cargo.toml
│ ├── observe-cryptoki/ # PKCS#11 operation tracing
│ │ ├── src/
│ │ │ ├── lib.rs # ObservedPkcs11, ObservedSession
│ │ │ └── ... # Transparent wrappers
│ │ └── Cargo.toml
│ └── rust-hsm-analyze/ # Log analysis engine
│ ├── src/
│ │ ├── lib.rs # Public exports
│ │ ├── parser.rs # JSON Lines parser
│ │ └── analyzer.rs # Statistics engine
│ └── Cargo.toml
└── docker/ # Docker container setup
Deployment
Single Docker container with both SoftHSM2 and the Rust CLI:
+-------------------+
| rust-hsm-app |
|-------------------|
| - rust-hsm-cli |
| - rust-hsm-core |
| - SoftHSM2 |
| - Token storage |
+-------------------+
│
└─ Volume: tokens:/tokens (persistent)
Library Usage
The rust-hsm-core library can be embedded in other Rust applications:
# Cargo.toml [dependencies] rust-hsm-core = { git = "https://github.com/testingapisname/rust-hsm" }
use rust_hsm_core::keys; fn main() -> anyhow::Result<()> { // Generate an RSA keypair keys::gen_keypair( "/usr/lib/softhsm/libsofthsm2.so", "MY_TOKEN", "user-pin-123456", "signing-key", "rsa", Some(2048), false, )?; // Sign data keys::sign( "/usr/lib/softhsm/libsofthsm2.so", "MY_TOKEN", "user-pin-123456", "signing-key", "data.txt", "signature.bin", )?; Ok(()) }
Configuration File (Optional)
To avoid repeating --label and other parameters on every command, create a configuration file:
# .rust-hsm.toml or ~/.config/rust-hsm/config.toml default_token_label = "DEV_TOKEN" pkcs11_module = "/usr/lib/softhsm/libsofthsm2.so"
Supported locations (checked in order):
-
.rust-hsm.toml(current directory) -
rust-hsm.toml(current directory) ~/.config/rust-hsm/config.toml~/.rust-hsm.toml-
/app/.rust-hsm.toml(container) - Custom path via
--config /path/to/config.toml
With configuration, commands become shorter:
# Before: must specify --label every time docker exec rust-hsm-app rust-hsm-cli gen-keypair --label DEV_TOKEN --user-pin 123456 --key-label my-key # After: --label uses config default docker exec rust-hsm-app rust-hsm-cli gen-keypair --user-pin 123456 --key-label my-key
See config.example.toml for all options.
Quick Start
# Build and start the container docker compose up -d --build # Initialize a token docker exec rust-hsm-app rust-hsm-cli init-token --label DEV_TOKEN --so-pin 1234 # Set user PIN docker exec rust-hsm-app rust-hsm-cli init-pin --label DEV_TOKEN --so-pin 1234 --user-pin 123456 # Generate RSA keypair docker exec rust-hsm-app rust-hsm-cli gen-keypair \ --label DEV_TOKEN --user-pin 123456 \ --key-label signing-key --key-type rsa --bits 2048 # Create test data and sign it docker exec rust-hsm-app bash -c "echo 'Hello World' > /app/data.txt" docker exec rust-hsm-app rust-hsm-cli sign \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --input /app/data.txt --output /app/data.sig # Verify signature docker exec rust-hsm-app rust-hsm-cli verify \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --input /app/data.txt --signature /app/data.sig # Encrypt data with RSA public key docker exec rust-hsm-app bash -c "echo 'Secret data' > /app/secret.txt" docker exec rust-hsm-app rust-hsm-cli encrypt \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --input /app/secret.txt --output /app/secret.enc # Decrypt with RSA private key docker exec rust-hsm-app rust-hsm-cli decrypt \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --input /app/secret.enc --output /app/secret-decrypted.txt # Export public key (for sharing or external verification) docker exec rust-hsm-app rust-hsm-cli export-pubkey \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --output /app/signing-key.pub.pem # Generate AES-256 key for symmetric encryption docker exec rust-hsm-app rust-hsm-cli gen-symmetric-key \ --label DEV_TOKEN --user-pin 123456 --key-label aes-key --bits 256 # Encrypt larger data with AES-GCM (no RSA size limits) docker exec rust-hsm-app bash -c "echo 'Large data that would not fit in RSA' > /app/large-data.txt" docker exec rust-hsm-app rust-hsm-cli encrypt-symmetric \ --label DEV_TOKEN --user-pin 123456 --key-label aes-key \ --input /app/large-data.txt --output /app/large-data.enc # Decrypt with AES-GCM docker exec rust-hsm-app rust-hsm-cli decrypt-symmetric \ --label DEV_TOKEN --user-pin 123456 --key-label aes-key \ --input /app/large-data.enc --output /app/large-data-decrypted.txt # Delete a key when no longer needed docker exec rust-hsm-app rust-hsm-cli delete-key \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key # Wrap a key for secure backup or migration (AES Key Wrap - RFC 3394) # First, generate a Key Encryption Key (KEK) docker exec rust-hsm-app rust-hsm-cli gen-symmetric-key \ --label DEV_TOKEN --user-pin 123456 --key-label kek --bits 256 # Generate an extractable key to wrap docker exec rust-hsm-app rust-hsm-cli gen-symmetric-key \ --label DEV_TOKEN --user-pin 123456 --key-label secret-key --bits 256 --extractable # Wrap the key (output is encrypted key material - 40 bytes for AES-256) docker exec rust-hsm-app rust-hsm-cli wrap-key \ --label DEV_TOKEN --user-pin 123456 --key-label secret-key \ --wrapping-key-label kek --output /app/wrapped-key.bin # Unwrap the key to restore it (e.g., after disaster recovery) docker exec rust-hsm-app rust-hsm-cli unwrap-key \ --label DEV_TOKEN --user-pin 123456 --key-label restored-key \ --wrapping-key-label kek --input /app/wrapped-key.bin --key-type aes # Generate Certificate Signing Request (CSR) for submitting to a CA docker exec rust-hsm-app rust-hsm-cli gen-csr \ --label DEV_TOKEN --user-pin 123456 --key-label signing-key \ --subject "CN=test.example.com,O=TestOrg,C=US" --output /app/test.csr # Verify CSR with OpenSSL docker exec rust-hsm-app openssl req -in /app/test.csr -noout -text
Security: Using PIN from stdin
For better security (avoiding PINs in shell history or process lists), use --pin-stdin:
# Initialize token with PIN from stdin echo "my-secure-so-pin" | docker exec -i rust-hsm-app \ rust-hsm-cli init-token --label DEV_TOKEN --pin-stdin # Set user PIN with both PINs from stdin (one per line) printf "my-secure-so-pin\nmy-secure-user-pin" | docker exec -i rust-hsm-app \ rust-hsm-cli init-pin --label DEV_TOKEN --so-pin-stdin --user-pin-stdin # Generate keypair with PIN from stdin echo "my-secure-user-pin" | docker exec -i rust-hsm-app \ rust-hsm-cli gen-keypair --label DEV_TOKEN --pin-stdin \ --key-label signing-key --key-type rsa --bits 2048 # Sign with PIN from stdin echo "my-secure-user-pin" | docker exec -i rust-hsm-app \ rust-hsm-cli sign --label DEV_TOKEN --pin-stdin --key-label signing-key \ --input /app/data.txt --output /app/data.sig
Automation & JSON Output
Transform rust-hsm from a human-friendly CLI into automation-first infrastructure tooling with the --json flag.
Commands with JSON Support
-
list-slots --json- Slot and token information -
list-objects --json [--detailed]- Object inventory with attributes -
list-mechanisms --json [--detailed]- Mechanism capabilities -
inspect-key --json- Detailed key attributes and fingerprints
Example: CI/CD Validation
# Verify key exists and get fingerprint docker exec rust-hsm-app rust-hsm-cli inspect-key \ --label PROD_TOKEN --user-pin $PIN --key-label signing-key --json \ | jq -r '.objects[0].fingerprint' # Output: 7b:ca:ae:4e:4c:be:24:5e:ae:4c:9a:a1:78:ba:12:0a:a8:24:57:d6
Example: Fleet Auditing
# List all keys across multiple tokens for token in TOKEN1 TOKEN2 TOKEN3; do echo "=== $token ===" docker exec rust-hsm-app rust-hsm-cli list-objects \ --label $token --user-pin $PIN --json \ | jq -r '.objects[].label' done
Example: PowerShell Automation
# Get all RSA keys with key sizes $objects = docker exec rust-hsm-app rust-hsm-cli list-objects ` --label DEV_TOKEN --user-pin 123456 --json --detailed | ConvertFrom-Json $objects.objects | Where-Object { $_.key_type -like "*val: 0*" } | ForEach-Object { [PSCustomObject]@{ Label = $_.label KeySize = $_.key_size_bits Handle = $_.handle } }
Example: Automated Key Rotation
#!/bin/bash # Check if key is older than 90 days, rotate if needed OLD_KEY_FP=$(docker exec rust-hsm-app rust-hsm-cli inspect-key \ --label PROD_TOKEN --user-pin $PIN --key-label prod-key --json \ | jq -r '.objects[0].fingerprint') # Generate new key docker exec rust-hsm-app rust-hsm-cli gen-keypair \ --label PROD_TOKEN --user-pin $PIN --key-label prod-key-new --key-type rsa # Verify new key NEW_KEY_FP=$(docker exec rust-hsm-app rust-hsm-cli inspect-key \ --label PROD_TOKEN --user-pin $PIN --key-label prod-key-new --json \ | jq -r '.objects[0].fingerprint') echo "Old: $OLD_KEY_FP" echo "New: $NEW_KEY_FP"
Example: Monitoring & Alerting
# Count objects per token for capacity monitoring OBJECT_COUNT=$(docker exec rust-hsm-app rust-hsm-cli list-objects \ --label PROD_TOKEN --user-pin $PIN --json \ | jq '.object_count') if [ $OBJECT_COUNT -gt 100 ]; then echo "WARNING: Token has $OBJECT_COUNT objects" # Send alert to monitoring system fi
Example: Compliance Reporting
# Generate report of all non-extractable keys docker exec rust-hsm-app rust-hsm-cli list-objects \ --label PROD_TOKEN --user-pin $PIN --json --detailed \ | jq '.objects[] | select(.flags.extractable == false) | {label, key_type, key_size_bits}'
Available Commands
Information Commands
# Display PKCS#11 module information rust-hsm-cli info # List all slots and tokens rust-hsm-cli list-slots # List objects on a token (simple output) rust-hsm-cli list-objects --label <TOKEN> --user-pin <PIN> # List objects with detailed attributes (like p11ls) rust-hsm-cli list-objects --label <TOKEN> --user-pin <PIN> --detailed # Shows: object type, flags (tok/prv/pub/r/w/loc), capabilities (sig/vfy/enc/dec/wra/unw), # security attributes (sen/ase/nxt/XTR), and key sizes
Token Management
# Initialize a new token rust-hsm-cli init-token --label <TOKEN> --so-pin <SO_PIN> # Set user PIN (must be done after init-token) rust-hsm-cli init-pin --label <TOKEN> --so-pin <SO_PIN> --user-pin <USER_PIN>
Key Operations
# Generate RSA keypair rust-hsm-cli gen-keypair \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --key-type rsa --bits <2048|4096> # Generate ECDSA keypair (P-256) rust-hsm-cli gen-keypair \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --key-type p256 # Generate ECDSA keypair (P-384) rust-hsm-cli gen-keypair \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --key-type p384 # Sign data (automatically detects RSA vs ECDSA) rust-hsm-cli sign \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> --output <SIGNATURE_FILE> # Verify signature (automatically detects RSA vs ECDSA) rust-hsm-cli verify \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> --signature <SIGNATURE_FILE> # Export public key in PEM format (for sharing or external verification) rust-hsm-cli export-pubkey \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --output <PEM_FILE> # Encrypt data with RSA public key (max 245 bytes for 2048-bit key) rust-hsm-cli encrypt \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> --output <ENCRYPTED_FILE> # Decrypt data with RSA private key rust-hsm-cli decrypt \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <ENCRYPTED_FILE> --output <DECRYPTED_FILE> # Delete a keypair from the token rust-hsm-cli delete-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> # Generate symmetric key (AES-128/192/256) rust-hsm-cli gen-symmetric-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --bits <128|192|256> # Generate extractable symmetric key (for key wrapping) rust-hsm-cli gen-symmetric-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --bits <128|192|256> \ --extractable # Encrypt data with AES-GCM (no size limits, includes IV and auth tag) rust-hsm-cli encrypt-symmetric \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> --output <ENCRYPTED_FILE> # Decrypt data with AES-GCM rust-hsm-cli decrypt-symmetric \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <ENCRYPTED_FILE> --output <DECRYPTED_FILE> # Wrap a key for secure export (AES Key Wrap - RFC 3394) rust-hsm-cli wrap-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_TO_WRAP> \ --wrapping-key-label <KEK_LABEL> \ --output <WRAPPED_KEY_FILE> # Unwrap an encrypted key for secure import rust-hsm-cli unwrap-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <NEW_KEY_NAME> \ --wrapping-key-label <KEK_LABEL> \ --input <WRAPPED_KEY_FILE> \ --key-type aes # Generate Certificate Signing Request (CSR) from keypair rust-hsm-cli gen-csr \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --subject "CN=example.com,O=MyOrg,C=US" \ --output <CSR_FILE>
Hash Operations
# Hash data with SHA-256 (default, no login required) rust-hsm-cli hash \ --input <FILE> \ --output <HASH_FILE> # Hash data with SHA-512 rust-hsm-cli hash \ --algorithm sha512 \ --input <FILE> \ --output <HASH_FILE> # Supported algorithms: sha256 (default), sha512, sha224, sha1
HMAC Operations (Message Authentication with Hash Functions)
# Generate HMAC key (256-bit generic secret) rust-hsm-cli gen-hmac-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --bits 256 # Generate HMAC-SHA256 rust-hsm-cli hmac-sign \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --algorithm sha256 \ --input <FILE> \ --output <HMAC_FILE> # Verify HMAC rust-hsm-cli hmac-verify \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --algorithm sha256 \ --input <FILE> \ --hmac <HMAC_FILE> # Supported algorithms: sha1, sha224, sha256, sha384, sha512
CMAC Operations (Message Authentication with AES)
# Generate CMAC key (AES-128/192/256) rust-hsm-cli gen-cmac-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --bits 256 # Generate CMAC (16-byte MAC) rust-hsm-cli cmac-sign \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> \ --output <CMAC_FILE> # Generate truncated CMAC (e.g., 8 bytes) rust-hsm-cli cmac-sign \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> \ --output <CMAC_FILE> \ --mac-len 8 # Verify CMAC rust-hsm-cli cmac-verify \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --input <FILE> \ --cmac <CMAC_FILE>
HMAC vs CMAC:
- HMAC: Hash-based (SHA family), outputs 32/64 bytes, widely supported
- CMAC: Block cipher-based (AES), outputs 16 bytes, faster for short messages
- Both provide message authentication and integrity verification
Key Inspection
# Display detailed key attributes (CKA_* values) rust-hsm-cli inspect-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> # Shows: CKA_CLASS, CKA_KEY_TYPE, CKA_SENSITIVE, CKA_EXTRACTABLE, # CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT, etc. # Public keys also display SHA-256 fingerprint: # FINGERPRINT (SHA-256): ec:bb:93:16:a4:7c:... (colon-separated hex) # Get key inspection in JSON format (includes fingerprint) rust-hsm-cli inspect-key \ --label <TOKEN> --user-pin <PIN> \ --key-label <KEY_NAME> \ --json
Random Number Generation
# Generate 32 random bytes (hex output to stdout) rust-hsm-cli gen-random --bytes 32 # Generate random bytes to binary file rust-hsm-cli gen-random --bytes 64 --output /app/random.bin # Generate random bytes to hex file rust-hsm-cli gen-random --bytes 32 --output /app/random.hex --hex # Use HSM RNG for secure key generation, IVs, nonces, etc. # No authentication required - RNG is accessible without login
Performance Benchmarking
Run comprehensive performance benchmarks across all cryptographic operations:
# Run full benchmark suite with 100 iterations per test echo '123456' | rust-hsm-cli benchmark --label TEST --iterations 100 --pin-stdin # Benchmark a specific application key (auto-detects key type) echo '123456' | rust-hsm-cli benchmark --label TEST --key-label my-app-key --iterations 100 --pin-stdin # Run with custom iteration count echo '123456' | rust-hsm-cli benchmark --label TEST --iterations 1000 --pin-stdin # Quick benchmark (fewer iterations) echo '123456' | rust-hsm-cli benchmark --label TEST --iterations 10 --pin-stdin
Benchmark Modes:
- Full Suite: Tests all operations with temporary keys (default)
-
Specific Key: Tests operations available for a specific key using
--key-label
Full Suite Tests:
- Signing: RSA-2048, RSA-4096, ECDSA-P256, ECDSA-P384
- Verification: RSA-2048, ECDSA-P256
- Encryption: RSA-2048, AES-256-GCM (1KB data)
- Hashing: SHA-256, SHA-384, SHA-512 (1KB data)
- MACs: HMAC-SHA256, AES-CMAC
- Random Generation: 32 bytes
Specific Key Tests (auto-detected):
- RSA keys: Sign, Verify, Encrypt operations
- ECDSA keys: Sign, Verify operations
- AES keys: Encrypt (if CKA_ENCRYPT), CMAC (if CKA_SIGN)
- HMAC keys: HMAC-SHA256 operation
Output includes:
- Operations per second (ops/sec)
- Average latency (milliseconds)
- Latency percentiles: P50, P95, P99
Example benchmark results (SoftHSM2 on typical hardware):
Operation Ops/sec Avg (ms) P50 (ms) P95 (ms) P99 (ms)
RSA-2048 Sign 1304.2 0.77 0.74 0.94 1.19
RSA-4096 Sign 235.5 4.25 4.27 4.79 5.09
ECDSA-P-256 Sign 12433.0 0.08 0.06 0.14 0.99
ECDSA-P-384 Sign 1297.2 0.77 0.72 0.96 1.15
AES-256-GCM Encrypt (1KB) 28240.4 0.04 0.02 0.05 0.29
SHA-256 Hash (1KB) 384457.2 0.00 0.00 0.00 0.06
Note: Benchmarks automatically create temporary test keys. Keys persist on token for subsequent runs to improve performance.
Discovery Commands
# List all PKCS#11 mechanisms supported by the HSM rust-hsm-cli list-mechanisms # List mechanisms with detailed capabilities (like p11slotinfo) rust-hsm-cli list-mechanisms --detailed # Shows flags: enc=encrypt, dec=decrypt, sig=sign, vfy=verify, hsh=digest, # gkp=generate_key_pair, wra=wrap, unw=unwrap, der=derive # List mechanisms for a specific slot rust-hsm-cli list-mechanisms --slot 404614813 # List mechanisms for specific slot with details rust-hsm-cli list-mechanisms --slot 404614813 --detailed
Project Structure
rust-hsm/
README.md
.github/
copilot-instructions.md # AI agent guidance
docker/
Dockerfile # Single container with SoftHSM2 + Rust CLI
softhsm2.conf # SoftHSM configuration
entrypoint.sh # Container startup script
compose.yaml # Docker Compose configuration
crates/
rust-hsm-cli/
Cargo.toml
src/
main.rs # CLI entry point
pkcs11/
mod.rs # Module exports
errors.rs # Custom error types
info.rs # Module info command
slots.rs # Slot listing
token.rs # Token management
keys.rs # Key operations (gen, sign, verify)
objects.rs # Object listing
rust-hsm/
README.md
.github/
copilot-instructions.md # AI agent guidance
docker/
Dockerfile # Single container with SoftHSM2 + Rust CLI
softhsm2.conf # SoftHSM configuration
entrypoint.sh # Container startup script
compose.yaml # Docker Compose configuration
crates/
rust-hsm-cli/ # Modular CLI with organized command handlers
Cargo.toml
src/
main.rs # Clean 35-line entry point
cli.rs # Command definitions
config.rs # Configuration handling
commands/ # Modular command handlers
mod.rs # Main dispatcher
common.rs # Shared utilities (PIN, config)
info.rs # Information commands
token.rs # Token management
keys.rs # Key management
crypto.rs # Sign/verify/encrypt/decrypt
symmetric.rs # Symmetric operations
key_wrap.rs # Key wrapping
mac.rs # HMAC/CMAC operations
util.rs # Benchmark/audit/troubleshooting
analyze.rs # Log analysis
rust-hsm-core/ # Core PKCS#11 operations
src/
pkcs11/ # PKCS#11 functionality
observe-core/ # Observability event schema
observe-cryptoki/ # Cryptoki observability wrapper
rust-hsm-analyze/ # Log analysis and statistics
Technical Details
Technology Stack
-
PKCS#11 Library:
cryptokiRust bindings (v0.10) -
CLI Framework:
clapwith subcommands -
Logging:
tracing+tracing-subscriber - SoftHSM Version: 2.6.1
- Rust Version: 1.83
PKCS#11 Session Lifecycle
All operations follow: init → open session → login → operation → logout → finalize
Cryptographic Operations
RSA:
- Key Generation: 2048/4096-bit keys with public exponent 65537
- Signing: SHA-256 with RSA PKCS#1 v1.5 (
CKM_SHA256_RSA_PKCS) - Encryption: PKCS#1 v1.5 padding (
CKM_RSA_PKCS) - max 245 bytes for 2048-bit keys - Hashing: Built-in to mechanism
ECDSA:
- Key Generation: P-256 (secp256r1) and P-384 (secp384r1) curves
- Signing: ECDSA (
CKM_ECDSA) - Hashing: Manual SHA-256 before signing (PKCS#11 ECDSA mechanism expects pre-hashed data)
AES:
- Key Generation: 128/192/256-bit keys
- Encryption: AES-GCM (
CKM_AES_GCM) with 96-bit random IV and 128-bit authentication tag - IV Management: Random IV generated per encryption, prepended to ciphertext for storage
Key Storage: Token-resident private/secret keys (sensitive, non-extractable)
Container Details
- Base Image: Debian Bookworm Slim
- Build: Multi-stage (Rust builder + slim runtime)
-
Token Storage: Persistent Docker volume at
/tokens
Logging
The CLI uses structured logging with multiple levels. Set the RUST_LOG environment variable to control verbosity:
# Info level (default) - shows major operations docker exec rust-hsm-app rust-hsm-cli info # Debug level - detailed PKCS#11 operations RUST_LOG=debug docker exec rust-hsm-app rust-hsm-cli gen-keypair \ --label DEV_TOKEN --user-pin 123456 --key-label test-key --key-type rsa # Trace level - includes raw data and attribute dumps RUST_LOG=trace docker exec rust-hsm-app rust-hsm-cli sign \ --label DEV_TOKEN --user-pin 123456 --key-label test-key \ --input /app/data.txt --output /app/data.sig
Log Levels:
-
info- Operation milestones (token found, key generated, signature created) -
debug- PKCS#11 library calls (initialization, sessions, login, mechanism selection) -
trace- Raw data dumps (attributes, hashes, signatures, slot IDs)
Observability & Analysis
The CLI includes comprehensive observability features for monitoring, debugging, and analyzing HSM operations:
Enable Observability in configuration file:
# .rust-hsm.toml default_token_label = "DEV_TOKEN" pkcs11_module = "/usr/lib/softhsm/libsofthsm2.so" observe_enabled = true observe_log_file = "/app/rust-hsm-observe.json"
What Gets Logged:
- Every PKCS#11 function call (C_Initialize, C_Sign, etc.)
- Timestamp with nanosecond precision (RFC3339)
- Return codes (numeric + symbolic name like CKR_OK)
- Duration in milliseconds
- Slot/session handles, mechanisms
- What is NOT logged: PINs, key material, plaintext/ciphertext, attribute values
Analyze Logs:
# View operation statistics docker exec rust-hsm-app rust-hsm-cli analyze \ --log-file /app/rust-hsm-observe.json # Example output: # === PKCS#11 Session Analysis === # Total Operations: 35 # Success Rate: 100.00% # Error Count: 0 # # --- Overall Timing --- # Total Duration: 43.91ms # Average: 1.25ms # P50: 0.77ms P95: 1.88ms P99: 13.46ms # # --- Per-Function Statistics --- # C_Initialize: 5 calls, avg 4.11ms # C_Sign: 5 calls, avg 0.84ms # JSON output for automation docker exec rust-hsm-app rust-hsm-cli analyze \ --log-file /app/rust-hsm-observe.json --format json
Use Cases:
- Performance benchmarking: Track P95/P99 latencies over time
- Debugging: Understand operation sequences and failures
- Security audit: Monitor access patterns and errors
- Capacity planning: Measure operations per second under load
- Provider comparison: Benchmark SoftHSM2 vs Kryoptic
See docs/commands/observability.md for complete documentation.
Environment Variables
-
PKCS11_MODULE- Path to PKCS#11 library (default:/usr/lib/softhsm/libsofthsm2.so) -
SOFTHSM2_CONF- SoftHSM configuration file (default:/etc/softhsm2.conf) -
TOKEN_LABEL- Default token label -
USER_PIN- Default user PIN -
SO_PIN- Default SO PIN
Development
Building
# Build container docker compose build # Rebuild after code changes docker compose up -d --build
Testing
# Run automated test suite (automatically cleans up test tokens) docker exec rust-hsm-app /app/test.sh # Clean up accumulated test tokens manually docker exec -e AUTO_CONFIRM=yes rust-hsm-app /app/cleanup-test-tokens.sh # Or run cleanup interactively docker exec -it rust-hsm-app /app/cleanup-test-tokens.sh # Or run individual commands docker exec rust-hsm-app rust-hsm-cli info docker exec rust-hsm-app rust-hsm-cli list-slots # Reset token storage (deletes all tokens and slots) docker compose down docker volume rm rust-hsm_tokens docker compose up -d
The test suite (test.sh) validates all 43 operations including:
- Token management (init, PIN setup, deletion)
- RSA & ECDSA keypair generation (RSA-2048/4096, P-256, P-384)
- Sign/verify operations with multiple algorithms
- Symmetric encryption (AES-128/192/256 with GCM)
- Key wrap/unwrap (AES Key Wrap RFC 3394)
- Hash operations (SHA-256/512)
- HMAC/CMAC operations
- Public key export (PEM format)
- CSR generation
- Random number generation
- Troubleshooting commands (explain-error, find-key, diff-keys)
- Automatic cleanup: Test tokens are removed after each run to prevent slot accumulation
Debugging
# View container logs docker compose logs -f # Enter container shell docker exec -it rust-hsm-app bash # Check SoftHSM configuration docker exec rust-hsm-app cat /etc/softhsm2.conf # List token files docker exec rust-hsm-app ls -la /tokens
Security Notes
- Development and testing
- Learning PKCS#11 workflows
- Integration testing with HSM-like interfaces
Not suitable for production cryptographic operations.
Best Practices
- Never hardcode PINs in code or commit them to version control
- Use environment variables or secure secret management for PINs
- PINs are never logged by the CLI (only non-sensitive data)
- Private keys are marked as sensitive and non-extractable
- Consider using
--pin-stdinoption (planned feature) for automation
0 commit comments