Skip to content

testingapisname/rust-hsm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

99 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rust-hsm

CI Security codecov License: MIT

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 (--json flag) - 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):

  1. .rust-hsm.toml (current directory)
  2. rust-hsm.toml (current directory)
  3. ~/.config/rust-hsm/config.toml
  4. ~/.rust-hsm.toml
  5. /app/.rust-hsm.toml (container)
  6. 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/           # 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: cryptoki Rust bindings (v0.10)
  • CLI Framework: clap with 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

⚠️ Important: SoftHSM is software-backed and provides no hardware security. Use this for:

  • 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-stdin option (planned feature) for automation

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published