Session Management
hsmkey provides session management utilities for PKCS#11 operations. This guide covers the SessionPool class and best practices.
SessionPool Class
The SessionPool class manages PKCS#11 library instances and sessions.
Basic Usage
from hsmkey import SessionPool
pool = SessionPool(
module_path="/usr/lib/softhsm/libsofthsm2.so",
token_label="my-token",
user_pin="12345678"
)
# Use context manager for automatic session cleanup
with pool.session() as session:
# Work with session
pass
# Session is automatically closed
hsm_session Context Manager
For simple use cases, use the hsm_session context manager:
from hsmkey import hsm_session
with hsm_session(module_path, token_label, pin) as session:
# Work with session
key = HSMJWK.from_hsm(session, key_label="my-key")
Session Lifecycle
Opening Sessions
Sessions are opened when you enter the context manager:
with pool.session() as session:
# Session is now open and logged in
pass
# Session is closed and logged out
Read-Write Sessions
By default, sessions are read-only. For operations that modify the token, use a read-write session:
with pool.session(rw=True) as session:
# Can perform write operations
pass
Best Practices
1. Keep Sessions Short
Open sessions only when needed and close them promptly:
# Good: Short session
def sign_data(data):
with pool.session() as session:
key = HSMJWK.from_hsm(session, key_label="my-key")
jws = JWS(data)
jws.add_signature(key, alg="RS256", protected=...)
return jws.serialize(compact=True)
# Bad: Long-lived session
session = pool.open_session() # Don't keep open
# ... later ...
session.close()
2. Cache Keys Within Sessions
Load keys once and reuse them within a session:
with pool.session() as session:
# Load key once
key = HSMJWK.from_hsm(session, key_label="my-key")
# Reuse for multiple operations
for data in items:
jws = JWS(data)
jws.add_signature(key, alg="RS256", protected=...)
3. Batch Operations
Keep related operations in the same session:
# Efficient: Single session for batch
with pool.session() as session:
key = HSMJWK.from_hsm(session, key_label="my-key")
tokens = []
for i in range(100):
jws = JWS(f'{{"id": {i}}}'.encode())
jws.add_signature(key, alg="RS256", protected=...)
tokens.append(jws.serialize(compact=True))
# Inefficient: New session for each operation
tokens = []
for i in range(100):
with pool.session() as session: # Unnecessary overhead
key = HSMJWK.from_hsm(session, key_label="my-key")
jws = JWS(f'{{"id": {i}}}'.encode())
jws.add_signature(key, alg="RS256", protected=...)
tokens.append(jws.serialize(compact=True))
4. Error Handling
Handle session errors gracefully:
from hsmkey.exceptions import HSMSessionError, HSMPinError
try:
with pool.session() as session:
key = HSMJWK.from_hsm(session, key_label="my-key")
except HSMPinError:
print("Invalid PIN")
except HSMSessionError as e:
print(f"Session error: {e}")
PKCS#11 Considerations
Session Limits
Most PKCS#11 tokens have limits on concurrent sessions. Avoid opening too many sessions simultaneously:
# Be careful with concurrent access
# PKCS#11 tokens may not support multiple simultaneous logins
Login State
When a session is opened with a PIN, the user is logged in. Some tokens only allow one login at a time per token:
# This may fail with "UserAlreadyLoggedIn" on some tokens
with pool.session() as session1:
with pool.session() as session2: # May fail
pass
For concurrent operations, use a single session with proper synchronization.
Module Caching
The SessionPool caches PKCS#11 library instances by module path.
This is efficient when using multiple pools with the same module:
pool1 = SessionPool(module_path, "token1", "pin1")
pool2 = SessionPool(module_path, "token2", "pin2")
# Both pools share the same library instance
Environment Variables
Common environment variables for HSM configuration:
# SoftHSM2 configuration path
export SOFTHSM2_CONF="$HOME/.config/softhsm/softhsm2.conf"
# Custom module path
export HSM_MODULE="/path/to/libpkcs11.so"
# Token settings
export HSM_TOKEN="my-token"
export HSM_PIN="12345678"
Then in Python:
import os
pool = SessionPool(
module_path=os.environ.get("HSM_MODULE", "/usr/lib/softhsm/libsofthsm2.so"),
token_label=os.environ.get("HSM_TOKEN", "default-token"),
user_pin=os.environ.get("HSM_PIN")
)