PKCS#11 Interface

SDK-P11-001 v1.0

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.

AttributeValue
Library (Linux)libquac100_pkcs11.so
Library (Windows)quac100_pkcs11.dll
PKCS#11 Version2.40 with PQC extensions
Slot ManagementOne slot per physical device, plus VF slots for SR-IOV
Token CapabilitiesKey generation, signing, verification, encapsulation, decapsulation
Session SupportMultiple concurrent sessions per slot
Key StorageHardware-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.

MechanismCKM ValueOperations
CKM_KYBER_5120x80000101KeyGen, Encapsulate, Decapsulate
CKM_KYBER_7680x80000102KeyGen, Encapsulate, Decapsulate
CKM_KYBER_10240x80000103KeyGen, Encapsulate, Decapsulate
CKM_DILITHIUM_20x80000201KeyGen, Sign, Verify
CKM_DILITHIUM_30x80000202KeyGen, Sign, Verify
CKM_DILITHIUM_50x80000203KeyGen, Sign, Verify
CKM_SPHINCS_SHA2_128F0x80000301KeyGen, Sign, Verify
CKM_SPHINCS_SHAKE_256F0x80000306KeyGen, 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.

Key migration is algorithm-dependent. Classical RSA/ECC keys can be imported directly. Post-quantum keys must be generated natively on the QUAC 100 since there is no interoperable PQC key wrapping standard for cross-HSM transport yet.

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 #

OperationQUAC 100 (HW)SoftHSM2 (SW)Speedup
ML-KEM-768 Keygen2.5 μs180 μs72×
ML-KEM-768 Encapsulate1.8 μs150 μs83×
ML-DSA-65 Sign4.2 μs350 μs83×
ML-DSA-65 Verify2.1 μs120 μs57×

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