PKCS#11 support for Python
python-pkcs11 provides Python bindings for PKCS#11, a standard for cryptographic tokens. It allows interaction with hardware security modules (HSMs) and smart cards using a native Python API. The library is actively maintained with frequent minor releases, ensuring compatibility with the latest Python versions and addressing specific token behaviors. The current version is 0.9.4.
Common errors
-
pkcs11.exceptions.PKCS11Error: CKR_LIBRARY_LOAD_FAILED
cause The specified PKCS#11 shared library (.so, .dll) could not be loaded. This often indicates an incorrect path, missing file, or architecture mismatch.fixVerify the absolute path to your PKCS#11 shared library. Ensure it exists, is readable, and matches your Python interpreter's architecture (e.g., 64-bit Python with 64-bit library). For Linux, check `LD_LIBRARY_PATH` or `/etc/ld.so.conf`. -
ModuleNotFoundError: No module named 'pkcs11'
cause The `python-pkcs11` package has not been installed in your Python environment.fixRun `pip install python-pkcs11` to install the library. -
pkcs11.exceptions.PKCS11Error: CKR_TOKEN_NOT_PRESENT
cause The selected PKCS#11 slot does not have a cryptographic token (e.g., smart card, HSM) inserted or initialized, or the token is not responding.fixEnsure your hardware token is properly inserted and initialized. For SoftHSM2, ensure you have created and initialized a token (e.g., `softhsm2-util --init-token --slot 0 --label 'my-token' --pin 1234 --so-pin 123456`). -
TypeError: argument of type 'NoneType' is not iterable
cause Attempting to iterate or access attributes on a `None` object, typically returned when `lib.get_token()` or `lib.get_slot()` doesn't find a matching token/slot.fixAlways check if the result of `get_token()` or `get_slot()` is `None` before attempting to use it. For example: `token = lib.get_token(token_label='my-token'); if token: session = token.open()`.
Warnings
- gotcha This library requires a system-level PKCS#11 shared library (e.g., `libsofthsm2.so` on Linux, `pkcs11.dll` on Windows) to be installed and accessible. `python-pkcs11` itself is a wrapper, not a complete PKCS#11 implementation.
- breaking In v0.5.0, the default mechanism for wrapping AES keys changed from ECB to `AES_KEY_WRAP` to align with the updated PKCS#11 v2.4 specification. This may break existing applications that implicitly relied on ECB for AES key wrapping.
- gotcha Some PKCS#11 tokens or implementations may not handle multi-attribute fetches in a compliant way, leading to errors when trying to retrieve all object attributes at once. While v0.9.3 includes a mitigation, it can still cause unexpected behavior.
- gotcha Version 0.9.0 introduced internal restructuring to better support loading and unloading multiple PKCS#11 libraries. While not a direct API break for common use, advanced users managing multiple library instances might need to adapt their approach.
Install
-
pip install python-pkcs11
Imports
- pkcs11
import pkcs11
- lib
from pkcs11 import lib
lib = pkcs11.lib(library_path)
Quickstart
import pkcs11
import os
# Set the path to your PKCS#11 shared library
# For testing, you might use SoftHSM2: /usr/lib/softhsm/libsofthsm2.so (Linux)
# or a vendor-specific driver.
PKCS11_LIBRARY_PATH = os.environ.get('PKCS11_LIBRARY', '/usr/local/lib/softhsm/libsofthsm2.so')
try:
# Load the PKCS#11 library
lib = pkcs11.lib(PKCS11_LIBRARY_PATH)
# List available slots (where tokens/smart cards are inserted)
slots = lib.get_slots()
if not slots:
print(f"No PKCS#11 slots found for library: {PKCS11_LIBRARY_PATH}")
print("Please ensure your PKCS#11 library is correctly configured and tokens are present.")
else:
print(f"Found {len(slots)} PKCS#11 slots:")
for i, slot in enumerate(slots):
try:
token_info = slot.get_token_info()
print(f" Slot {i}: '{token_info.label}' (serial: {token_info.serial_number})")
except pkcs11.exceptions.PKCS11Error as e:
if e.rv == pkcs11.CKR_TOKEN_NOT_PRESENT:
print(f" Slot {i}: No token present")
else:
print(f" Slot {i}: Error getting token info: {e}")
except pkcs11.exceptions.PKCS11Error as e:
print(f"Failed to load PKCS#11 library at '{PKCS11_LIBRARY_PATH}': {e}")
print("Please check the path and ensure the library is installed and accessible.")
except FileNotFoundError:
print(f"PKCS#11 library not found at '{PKCS11_LIBRARY_PATH}'")
print("Ensure the path is correct and the PKCS#11 shared library (e.g., .so, .dll) is installed.")