PKCS#11 Interface
The Dyber PKCS#11 module (libquac100_pkcs11.so) presents the QUAC 100 as a standard cryptographic token compliant with PKCS#11 v2.40 with post-quantum extensions. Applications that already work with hardware security modules — certificate authorities, code signing platforms, key management systems, database encryption — work with the QUAC 100 without modification.
Overview #
PKCS#11 (Public-Key Cryptography Standards #11) is the industry-standard API for cryptographic token interfaces. Originally designed for smart cards and HSMs, it defines a C-language interface for performing cryptographic operations and managing keys within tamper-resistant hardware. The Dyber PKCS#11 module extends this standard with post-quantum mechanism identifiers while maintaining full backward compatibility with existing PKCS#11 applications.
| Attribute | Value |
|---|---|
| Library (Linux) | libquac100_pkcs11.so |
| Library (Windows) | quac100_pkcs11.dll |
| PKCS#11 Version | 2.40 with PQC extensions |
| Slot Management | One slot per physical device, plus VF slots for SR-IOV |
| Token Capabilities | Key generation, signing, verification, encapsulation, decapsulation |
| Session Support | Multiple concurrent sessions per slot |
| Key Storage | Hardware-protected key storage with zeroization |
Architecture #
The PKCS#11 module is a shared library that implements the C_* function table defined by the PKCS#11 specification. It translates token operations into native QUAC 100 API calls, managing slot enumeration, session state, object handles, and mechanism dispatch internally.
Each physical QUAC 100 card appears as a single slot with one token. When SR-IOV is enabled, each virtual function appears as an additional slot, enabling multi-tenant HSM operation where each tenant has an isolated token with independent key storage and access controls.
Slot & Token Model #
/* Enumerate available slots */
CK_SLOT_ID slots[16];
CK_ULONG slot_count = 16;
C_GetSlotList(CK_TRUE, slots, &slot_count);
/* Get token info for first slot */
CK_TOKEN_INFO token_info;
C_GetTokenInfo(slots[0], &token_info);
printf("Token: %.32s\n", token_info.label);
printf("Model: %.16s\n", token_info.model); // "QUAC 100"
printf("Serial: %.16s\n", token_info.serialNumber);
Token initialization follows the standard PKCS#11 pattern with SO (Security Officer) and User PINs. The SO PIN controls token lifecycle operations (initialization, key destruction), while the User PIN controls day-to-day cryptographic operations. PINs are hashed and stored in the QUAC 100's secure enclave.
Session Management #
Sessions provide isolated contexts for cryptographic operations. The module supports both read-only (RO) and read-write (RW) sessions, with configurable maximum concurrent sessions per slot.
CK_SESSION_HANDLE session;
C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session);
C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR)"user-pin", 8);
/* ... perform operations ... */
C_Logout(session);
C_CloseSession(session);
PQC Mechanism IDs #
The module registers post-quantum mechanisms using vendor-defined mechanism IDs in the PKCS#11 vendor extension space. These IDs follow the conventions established by the OASIS PKCS#11 PQC profile working group.
| Mechanism | CKM Value | Operations |
|---|---|---|
CKM_KYBER_512 | 0x80000101 | KeyGen, Encapsulate, Decapsulate |
CKM_KYBER_768 | 0x80000102 | KeyGen, Encapsulate, Decapsulate |
CKM_KYBER_1024 | 0x80000103 | KeyGen, Encapsulate, Decapsulate |
CKM_DILITHIUM_2 | 0x80000201 | KeyGen, Sign, Verify |
CKM_DILITHIUM_3 | 0x80000202 | KeyGen, Sign, Verify |
CKM_DILITHIUM_5 | 0x80000203 | KeyGen, Sign, Verify |
CKM_SPHINCS_SHA2_128F | 0x80000301 | KeyGen, Sign, Verify |
CKM_SPHINCS_SHAKE_256F | 0x80000306 | KeyGen, Sign, Verify |
Key Operations #
/* Generate ML-DSA-65 key pair */
CK_MECHANISM mech = { CKM_DILITHIUM_3, NULL, 0 };
CK_OBJECT_HANDLE pub_key, priv_key;
CK_ATTRIBUTE pub_template[] = {
{ CKA_TOKEN, &ck_true, sizeof(CK_BBOOL) },
{ CKA_VERIFY, &ck_true, sizeof(CK_BBOOL) },
{ CKA_LABEL, "MySigningKey-pub", 16 }
};
CK_ATTRIBUTE priv_template[] = {
{ CKA_TOKEN, &ck_true, sizeof(CK_BBOOL) },
{ CKA_SIGN, &ck_true, sizeof(CK_BBOOL) },
{ CKA_SENSITIVE, &ck_true, sizeof(CK_BBOOL) },
{ CKA_EXTRACTABLE, &ck_false, sizeof(CK_BBOOL) },
{ CKA_LABEL, "MySigningKey-priv", 17 }
};
C_GenerateKeyPair(session, &mech,
pub_template, 3, priv_template, 4,
&pub_key, &priv_key);
/* Sign a message */
CK_MECHANISM sign_mech = { CKM_DILITHIUM_3, NULL, 0 };
C_SignInit(session, &sign_mech, priv_key);
CK_BYTE signature[4096];
CK_ULONG sig_len = sizeof(signature);
C_Sign(session, message, msg_len, signature, &sig_len);
/* Verify */
C_VerifyInit(session, &sign_mech, pub_key);
CK_RV rv = C_Verify(session, message, msg_len, signature, sig_len);
/* rv == CKR_OK means valid */
Certificate Operations #
The module supports X.509 certificate storage alongside PQC keys, enabling complete PKI workflows within the token. Certificates can be imported, stored, and associated with their corresponding private keys for CA operations.
/* Store an X.509 certificate */
CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
CK_ATTRIBUTE cert_template[] = {
{ CKA_CLASS, &cert_class, sizeof(cert_class) },
{ CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type) },
{ CKA_VALUE, cert_der, cert_der_len },
{ CKA_LABEL, "CA Root Certificate", 19 },
{ CKA_TOKEN, &ck_true, sizeof(CK_BBOOL) }
};
CK_OBJECT_HANDLE cert_handle;
C_CreateObject(session, cert_template, 5, &cert_handle);
Integration Examples #
OpenDNSSEC: Configure /etc/opendnssec/conf.xml with the QUAC 100 PKCS#11 module path to perform DNSSEC zone signing with ML-DSA keys.
EJBCA: Register the QUAC 100 token in EJBCA's Crypto Token configuration to issue PQC X.509 certificates from your certificate authority.
SoftHSM2 Migration: Export keys from SoftHSM2 using p11tool, import into QUAC 100 tokens with pkcs11-tool --module libquac100_pkcs11.so.
HSM Migration #
Organizations migrating from traditional HSMs (Thales Luna, Entrust nShield, Utimaco) can use the QUAC 100's PKCS#11 interface as a drop-in replacement. The migration workflow involves exporting wrapped keys from the source HSM (where supported), importing into the QUAC 100 token, and updating the PKCS#11 module path in application configuration files.
SoftHSM2 Compatibility #
The module is tested for drop-in compatibility with applications configured for SoftHSM2. The migration path is as simple as updating the module path in your PKCS#11 configuration.
# Before: SoftHSM2
module = /usr/lib/softhsm/libsofthsm2.so
# After: QUAC 100
module = /usr/lib/quac100/libquac100_pkcs11.so
Performance #
| Operation | QUAC 100 (HW) | SoftHSM2 (SW) | Speedup |
|---|---|---|---|
| ML-KEM-768 Keygen | 2.5 μs | 180 μs | 72× |
| ML-KEM-768 Encapsulate | 1.8 μs | 150 μs | 83× |
| ML-DSA-65 Sign | 4.2 μs | 350 μs | 83× |
| ML-DSA-65 Verify | 2.1 μs | 120 μs | 57× |
Performance includes PKCS#11 session management overhead. Direct native API calls are approximately 2–10× faster due to the elimination of PKCS#11 object handle translation.
Configuration #
The PKCS#11 module reads configuration from /etc/quac100/pkcs11.conf (Linux) or the registry (Windows). Key settings include maximum sessions per slot, key storage persistence mode, audit logging level, and PIN retry limits.
# /etc/quac100/pkcs11.conf
[general]
max_sessions = 64
log_level = info
audit_file = /var/log/quac100/pkcs11-audit.log
[token]
pin_retries = 5
auto_logout_seconds = 3600
key_storage = hardware # hardware | file | hybrid
Was this page helpful? Send feedback