Skip to content

PKCS#11 v3.0: scope decision & FFI foundation (G-28) #1153

Description

@Manuthor

Summary

The KMS implements Cryptoki (PKCS#11) v2.40 on both sides of the protocol: the provider side (crate/clients/pkcs11/module + crate/clients/pkcs11/provider, exposing KMS-managed keys as a PKCS#11 token) and the consumer side (crate/hsm/base_hsm + vendor loaders, talking to real HSMs). Both depend on the external pkcs11-sys crate (v0.2.25), which only binds the v2.40 header surface — no CK_INTERFACE, no C_GetInterfaceList/C_GetInterface, no message-based crypto function pointers, and none of the v3.0 mechanism constants (CKM_EDDSA, CKM_HKDF_DERIVE, CKM_SP800_108_*, etc.). This crate is the actual bottleneck for every other PKCS#11 v3.0 item in this milestone.

What PKCS#11 v3.0 adds (verified against the OASIS spec)

  • Interfaces model: C_GetInterfaceList/C_GetInterface supersede C_GetFunctionList (which is explicitly retained for backward compatibility, not removed).
  • Message-based crypto operations (C_MessageEncryptInit/C_EncryptMessage*/C_MessageEncryptFinal and Decrypt/Sign/Verify equivalents) — amortize per-call key/session setup across many small messages.
  • New native mechanisms: CKM_AES_GCM/CKM_AES_CCM/CKM_CHACHA20_POLY1305, the CKM_SHA3_* family, CKM_EDDSA/CKM_XEDDSA + Edwards/Montgomery key generation (Ed25519/Ed448/X25519/X448), CKM_HKDF_*, CKM_SP800_108_*_KDF.
  • Confirmed: CKM_PKCS5_PBKD2 (PBKDF2) is already a v2.40 mechanism — not blocked by this issue.

Scope of this issue

  1. FFI unblock — fork/vendor pkcs11-sys and regenerate the missing bindings via bindgen from the official v3.0/v3.1 headers (recommended option), or evaluate alternatives (switching to cryptoki/cryptoki-sys for the consumer side only, or hand-writing only the new pieces needed).
  2. Scope decision — confirm target: provider side, consumer side, or both; confirm target conformance level (interfaces + version bump only, vs. full native mechanism wiring).

Backward compatibility — verified, not a blocker

Traced crate/hsm/base_hsm/src/hsm_lib.rs: it resolves every Cryptoki function by stable C symbol name via libloading, never via C_GetFunctionList/C_GetInterfaceList. CK_INFO is byte-identical between v2.40 and v3.0. C_GetFunctionList itself is retained in v3.0 for backward compatibility. Any future consumer-side v3.0 adoption must be additive/optional (try C_GetInterfaceList, fall back to today's per-symbol resolution) so v2.x-only HSMs are never broken — this is a hard acceptance criterion for this whole milestone.

Estimate

M (fork/vendor + bindgen effort; no free lunch from existing crates).

Blocks

Depends on and blocks the rest of this milestone's PKCS#11 v3.0 items (provider/consumer rollout, EdDSA/X25519/HKDF/message-based AEAD HSM delegation).

Activity

  1. serene-kitfisto-8899 commented on Sep 4, 2026

    @serene-kitfisto-8899
    Contributor

    Delta Gap: Cosmian KMS PKCS#11 Interface vs. the OASIS PKCS#11 Standard

    Executive Summary

    Cosmian KMS's PKCS#11 interface (cosmian_pkcs11_module + cosmian_pkcs11 provider, forked from Google's native-pkcs11) implements a narrow, deliberately-scoped subset of PKCS#11 v2.40: of 68 classic Cryptoki functions, 30 have real working logic, 8 are implemented but hard-coded to reject (spec-legal negative responses), and 29 are pure CKR_FUNCTION_NOT_SUPPORTED stubs — including the entire Verify family, key wrapping/unwrapping, key derivation, on-token asymmetric key-pair generation, streaming multi-part encrypt/decrypt, and standalone digest operations.1 Of the 24 functions PKCS#11 v3.0 added on top of v2.40 (the Interfaces API C_GetInterfaceList/C_GetInterface, C_LoginUser, C_SessionCancel, and 20 message-based AEAD/sign/verify functions), zero are implemented anywhere in the codebase, confirmed both by exhaustive code search and by exported-symbol analysis of the built shared library.2 Mechanism coverage is similarly narrow: 11 mechanisms (RSA-PKCS/PSS signing, ECDSA, EdDSA, AES-CBC, AES key-gen) against 100+ mechanisms the current standard defines, with conspicuous absences of CKM_AES_GCM (no authenticated encryption), CKM_RSA_PKCS_OAEP, CKM_ECDH1_DERIVE (no key agreement despite advertising X25519/X448 key types), the entire SHA-3 family, and all key-wrap/KDF mechanisms.3 Remarkably, this exact gap is already the subject of active internal planning: nine GitHub issues opened two days before this research, under milestone "Sprint F · HSM Integration," lay out a concrete v3.0 adoption plan — including an issue whose central technical premise (that the pinned pkcs11-sys dependency lacks v3.0 bindings) this research independently disproves with byte-level evidence.4

    Confidence Assessment

    High confidence (directly verified against source code, byte-identical across three refs — develop@4c81498, main@6f53d68, and open PR #998):

    • The complete 68-function implementation inventory, the 11-mechanism list, the 6 object classes, and the KeyAlgorithm/SignatureAlgorithm/EncryptionAlgorithm enums.1
    • Total absence of the v3.0 Interfaces API and all 24 v3.0-introduced functions — confirmed via search_code (0 hits on 11 distinct terms), a manual repo-wide grep, and exported-symbol analysis of the cosmian_pkcs11 cdylib (exactly one #[no_mangle] export: C_GetFunctionList).2
    • The complete Backend trait (24 methods) → KMIP operation mapping, with real request-building code for Sign/Encrypt/Decrypt.5
    • The OASIS PKCS#11 v3.1 function catalogue (92 functions total, 24 new in v3.0, 0 new in v3.1), the Interfaces conformance requirement, and the full mandatory-requirement lists for the Baseline Provider, Extended Provider, Authentication Token, and Public Certificates Token profiles — all obtained by diffing the OASIS TC's own frozen header files (published/2-40-errata-1 vs published/3-01) and fetching the live v3.1 HTML spec directly.6
    • A factual correction to an internal GitHub issue: Issue PKCS#11 v3.0: scope decision & FFI foundation (G-28) #1153 claims the pinned pkcs11-sys v0.2.25 crate "only binds the v2.40 header surface." This research independently verified (SHA-256 checksum match against Cargo.lock, plus direct inspection of the vendored crate source and the upstream google/native-pkcs11 GitHub repo) that this is false — the crate fully binds CK_INTERFACE, C_GetInterfaceList/C_GetInterface, all 20 message-based crypto function pointers, and every cited v3.0 mechanism constant, at specific, quoted file/line locations.7 This does not change the conclusion that Cosmian's own code doesn't use these bindings — only that the "FFI is the bottleneck" framing in PKCS#11 v3.0: scope decision & FFI foundation (G-28) #1153 is incorrect; the missing bindings are not the blocker.

    Medium confidence (inferred from spec cross-references and dating, not line-by-line v2.40 diff): which mechanisms are "new in v3.0" vs. legacy since v2.40, for mechanism families outside RSA/AES/EC/digest/KDF (marked per-row in the mechanism table).3

    Assumption made: the research treats "the standard" as OASIS PKCS#11 v3.1 (ratified 2023, the latest full release; v3.2 exists in draft/early-adoption form with async ops, KEM encapsulation, and post-quantum mechanisms, but was explicitly excluded as out of scope for "the standard" in the sense the current codebase would reasonably target).6


    Architecture Overview

    graph TD
        App["Application: VeraCrypt / LUKS / Oracle TDE / OpenSSH"]
    
        subgraph Provider["cosmian_pkcs11 (provider crate — cdylib)"]
            LibRS["lib.rs — C_GetFunctionList entry point, ckms.toml config, auth modes"]
            CliBackend["backend.rs — CliBackend (impl Backend)"]
            KmsObj["kms_object.rs — KMIP request builders (kms_sign/encrypt/decrypt, locate, import, revoke, destroy)"]
            ObjTypes["pkcs11_private_key.rs / _public_key.rs / _symmetric_key.rs / _certificate.rs / _data_object.rs"]
        end
    
        subgraph ModuleCrate["cosmian_pkcs11_module (forked from google/native-pkcs11, v2.40 engine)"]
            Pkcs11RS["pkcs11.rs — extern C C_* functions + CK_FUNCTION_LIST (68 slots)"]
            Sessions["sessions.rs — Session state, sign/encrypt/decrypt/find dispatch"]
            CoreObj["core/object.rs — CKA_* attribute assembly (generic dispatcher)"]
            CoreMech["core/mechanism.rs — SUPPORTED_SIGNATURE_MECHANISMS (11 CKM_*)"]
            BackendTrait["traits/backend.rs — Backend trait (24 methods)"]
        end
    
        subgraph KMS["Cosmian KMS Server"]
            KMIP["KMIP 2.1: Sign / Encrypt / Decrypt / Locate / Get / Import / Revoke / Destroy / Query"]
        end
    
        App -- "dlopen libcosmian_pkcs11.so" --> LibRS
        LibRS -- registers --> CliBackend
        App -- "C_Sign / C_Encrypt / C_FindObjects / ..." --> Pkcs11RS
        Pkcs11RS --> Sessions
        Sessions --> CoreObj
        Sessions --> CoreMech
        Sessions -- "calls registered backend" --> BackendTrait
        BackendTrait -.implemented by.-> CliBackend
        CliBackend --> KmsObj
        CliBackend --> ObjTypes
        KmsObj -- "KMIP/REST over HTTPS" --> KMIP
    
    Loading

    Key architectural point: per-object-type files in the provider crate (pkcs11_private_key.rs etc.) do not build CK_ATTRIBUTEs themselves — they only implement thin trait accessors (remote_id(), algorithm(), rsa_modulus(), ...). All CKA_* attribute assembly happens once, generically, in cosmian_pkcs11_module::core::object::Object::attribute().5


    Component 1: Current Implementation — cosmian_pkcs11_module (the Cryptoki engine)

    Forked from Google's native-pkcs11 (commit cc26f7f8), adapted to proxy to a remote KMS.8 Implements the classic v2.40 single-entry-point model only: C_GetFunctionList → a 68-field CK_FUNCTION_LIST struct.1

    Function-by-function inventory (68 functions)

    Category Fully implemented Implemented but hard-coded reject Pure stub (CKR_FUNCTION_NOT_SUPPORTED)
    General-purpose C_Initialize, C_Finalize, C_GetInfo — —
    Slot/token mgmt C_GetSlotList(1 fixed slot), C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo C_InitToken, C_InitPIN, C_SetPIN (all → CKR_TOKEN_WRITE_PROTECTED) —
    Session mgmt C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_Login, C_Logout — C_GetOperationState, C_SetOperationState
    Object mgmt C_CreateObject(CKO_DATA only), C_DestroyObject, C_GetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal — C_CopyObject, C_GetObjectSize, C_SetAttributeValue
    Encrypt/Decrypt C_EncryptInit, C_Encrypt(single-shot), C_DecryptInit, C_Decrypt(single-shot) C_DecryptUpdate, C_DecryptFinal (real validation, then reject) C_EncryptUpdate, C_EncryptFinal
    Digest — — All 5: C_DigestInit/Digest/DigestUpdate/DigestKey/DigestFinal
    Sign C_SignInit(private keys only), C_Sign, C_SignUpdate(buffers in memory), C_SignFinal — C_SignRecoverInit, C_SignRecover
    Verify — — All 6: C_VerifyInit/Verify/VerifyUpdate/VerifyFinal/VerifyRecoverInit/VerifyRecover
    Dual-purpose — — All 4: C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate
    Key mgmt C_GenerateKey(AES-256 only) — C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey
    RNG C_GenerateRandom(real CSPRNG) C_SeedRandom(→ CKR_RANDOM_NO_RNG) —
    Parallel/events — C_GetFunctionStatus, C_CancelFunction (both → CKR_FUNCTION_NOT_PARALLEL, spec-correct for non-parallel tokens) C_WaitForSlotEvent

    *C_Login/C_Logout are no-ops in default auth mode; meaningful only in the OIDC-pin auth mode (see Component 2).

    Totals: 30 fully working · 8 implemented-but-hard-reject · 29 pure stubs = 67, plus C_GetFunctionList itself (implemented in the sibling provider crate) = 68.1

    Supported mechanisms (11 total)

    // crate/clients/pkcs11/module/src/core/mechanism.rs:40-52
    pub const SUPPORTED_SIGNATURE_MECHANISMS: &[CK_MECHANISM_TYPE] = &[
        CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA256_RSA_PKCS, CKM_SHA384_RSA_PKCS,
        CKM_SHA512_RSA_PKCS, CKM_ECDSA, CKM_EDDSA, CKM_RSA_PKCS_PSS,
        CKM_AES_KEY_GEN, CKM_AES_CBC, CKM_AES_CBC_PAD,
    ];

    Sign-capable: CKM_RSA_PKCS (dual-purpose sign+encrypt), CKM_SHA{1,256,384,512}_RSA_PKCS, CKM_ECDSA, CKM_EDDSA, CKM_RSA_PKCS_PSS (configurable MGF1/salt). Encrypt/decrypt-capable: CKM_AES_CBC/CKM_AES_CBC_PAD (single-shot only). Keygen: CKM_AES_KEY_GEN only.3

    Object classes and key algorithms

    6 CKO_* classes handled (CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY, CKO_CERTIFICATE — X.509 only, CKO_DATA, CKO_PROFILE); note CKO_PROFILE is structurally present (an Object::Profile(CK_PROFILE_ID) enum variant and attribute getter exist) but no code anywhere ever constructs one — it is dead/unreachable.1 11 key algorithms with OIDs: AES-256, RSA, EC P-256/P-384/P-521, Ed25519, Ed448, X25519, X448, secp224k1, secp256k1.1

    Cryptoki version reported

    pkcs11-sys v0.2.25 (external, from google/native-pkcs11) defines CRYPTOKI_VERSION_MAJOR=3, MINOR=1; C_GetInfo() reports these via CK_INFO.cryptokiVersion → the module claims Cryptoki v3.1.1 Separately, the static CK_FUNCTION_LIST.version field is hard-coded {major: 2, minor: 4} — this is expected, spec-compliant behavior, not a bug: the OASIS spec mandates this legacy struct stay frozen at 2.40 regardless of the module's true cryptokiVersion, precisely because the real v3.x function table (CK_FUNCTION_LIST_3_0) is a different struct obtained only via C_GetInterfaceList/C_GetInterface.6 Since Cosmian never implements those two functions, this "v3.1-claiming, v2.40-structured" module can never actually deliver on the v3.1 claim through any standard discovery path.


    Component 2: Current Implementation — cosmian_pkcs11 (provider / KMS bridge)

    Every PKCS#11 object is a thin proxy holding a remote KMIP UID; attribute values are fetched lazily via KMIP and cached.5

    Config and auth

    Config file ckms.toml (shared with the ckms CLI). Search order: CKMS_CONF env var → ckms.toml next to the loaded library → ~/.cosmian/ckms.toml → /etc/cosmian/ckms.toml.5 Two auth modes:

    • Modes 0/1 (default): C_Login is a no-op; KMS auth comes entirely from ckms.toml's static access token or mTLS client cert.
    • Mode 2 (pkcs11_use_pin_as_access_token = true): the PKCS#11 PIN passed to C_Login is treated as a short-lived OIDC/JWT bearer token (e.g. Oracle: ... IDENTIFIED BY 'eyJ...') — no credentials stored in ckms.toml.5

    Backend trait → KMIP operation mapping (complete, 24 methods)

    Backend method KMIP operation(s)
    token_label/token_manufacturer_id/token_model/token_serial_number/library_description/library_version none (static values)
    find_certificate none — stub, always Ok(None)
    find_all_certificates Locate(Certificate) + Get×N
    find_private_key / find_public_key / find_symmetric_key / find_data_object Get (single)
    find_all_private_keys / find_all_public_keys / find_all_symmetric_keys / find_all_data_objects Locate(tag-filtered) + Get/GetAttributes×N
    find_all_objects Locate×6 (one per system tag) + GetAttributes
    generate_key Import + Activate
    create_object Import (SecretData)
    revoke_object Revoke
    destroy_object Destroy
    encrypt Encrypt
    decrypt Decrypt
    remote_sign Sign

    Plus one call outside the trait: CliBackend::instantiate() issues KMIP Query (QueryServerInformation) once, to discover the vendor-ID string used to namespace tags.5

    Real KMIP request-building code (Sign)

    // crate/clients/pkcs11/provider/src/kms_object.rs:839-865 (excerpt)
    pub(crate) async fn kms_sign_async(
        kms_rest_client: &KmsClient, unique_identifier: &str,
        algorithm: &SignatureAlgorithm, data: &[u8],
    ) -> Pkcs11Result<Vec<u8>> {
        let (cryptographic_parameters, data_bytes, digested_data_bytes) = match algorithm {
            SignatureAlgorithm::Ecdsa => {
                // CKM_ECDSA: caller (OpenSSH) provides a pre-computed hash — sent as
                // digested_data to prevent double-hashing server-side.
                let digital_signature_algorithm = match data.len() {
                    48 => Some(DigitalSignatureAlgorithm::ECDSAWithSHA384),
                    64 => Some(DigitalSignatureAlgorithm::ECDSAWithSHA512),
                    _ => Some(DigitalSignatureAlgorithm::ECDSAWithSHA256),
                };
                (Some(CryptographicParameters{ digital_signature_algorithm, ..Default::default() }), None, Some(data.to_vec()))
            }
            SignatureAlgorithm::EdDsa => (None, Some(data.to_vec()), None), // raw message; Ed25519/Ed448 hash internally
            // ... RSA PKCS1v1.5 / PSS variants map to matching DigitalSignatureAlgorithm ...
        };
        let sign_request = Sign {
            unique_identifier: Some(UniqueIdentifier::TextString(unique_identifier.to_owned())),
            cryptographic_parameters, data: data_bytes.map(Zeroizing::new),
            digested_data: digested_data_bytes, ..Default::default()
        };
        let response = kms_rest_client.sign(sign_request).await?;
        response.signature_data.ok_or_else(|| Pkcs11Error::ServerError("...".to_owned()))
    }

    encrypt/decrypt follow the identical pattern, building KMIP Encrypt/Decrypt requests with CryptographicParameters{cryptographic_algorithm: AES/RSA, block_cipher_mode: CBC, padding_method: PKCS5/None/PKCS1v15}.5

    Error mapping

    ModuleError → CK_RV is not a uniform collapse: most locally-detected Cryptoki protocol violations map to spec-correct codes (BufferTooSmall→CKR_BUFFER_TOO_SMALL, MechanismInvalid→CKR_MECHANISM_INVALID, TokenWriteProtected→CKR_TOKEN_WRITE_PROTECTED, 15 more like these). Only the KMIP/remote-error catch-all (ModuleError::Backend) plus a handful of internal/generic variants (AlgorithmNotSupported, Default, FromUtf8, NullPtr, Todo, Cryptography, ...) collapse to CKR_GENERAL_ERROR — meaning the specific KMIP ErrorReason from a failed KMS call never survives into the CK_RV the PKCS#11 caller sees, only into a log line.9


    Component 3: The Standard — OASIS PKCS#11 v3.1

    Function catalogue (92 total: 68 from v2.40 + 24 new in v3.0; v3.1 adds zero new functions)

    Category v2.40 (68) New in v3.0 (24)
    General-purpose Initialize, Finalize, GetInfo, GetFunctionList GetInterfaceList, GetInterface
    Session mgmt OpenSession, CloseSession, ..., Login, Logout SessionCancel, LoginUser
    Encryption EncryptInit, Encrypt, EncryptUpdate, EncryptFinal 5 message-based: MessageEncryptInit, EncryptMessage, EncryptMessageBegin, EncryptMessageNext, MessageEncryptFinal
    Decryption (4 functions) 5 message-based (Decrypt equivalents)
    Signing SignInit, Sign, SignUpdate, SignFinal, SignRecover* 5 message-based (Sign equivalents)
    Verifying VerifyInit, Verify, VerifyUpdate, VerifyFinal, VerifyRecover* 5 message-based (Verify equivalents)
    (all others: slot/token, object, digest, key mgmt, RNG, parallel) unchanged —

    Verified by diffing the OASIS TC's own frozen header files published/2-40-errata-1/pkcs11f.h (68 entries) vs published/3-01/pkcs11f.h (92 entries).6 v3.1 is confirmed (via the spec's own revision history) to be a structural/editorial consolidation — the formerly-separate "Current Mechanisms" spec was merged into the base spec — plus two new profile IDs, not a new-API release.6

    The "Interfaces" API and its conformance implications — the central finding

    C_GetInterfaceList/C_GetInterface let one shared library expose multiple named, versioned function tables (e.g. the standard "PKCS 11" interface at {3,1} alongside a "Vendor X" interface) — introduced specifically because CK_FUNCTION_LIST (the legacy struct) is permanently frozen at the 2.40 ABI by design, and the real v3.x function table only reaches callers through this new discovery path.6

    Critically: every one of the four Provider-role conformance profiles in the OASIS Profiles v3.1 spec requires C_GetInterfaceList and C_GetInterface as part of their inherited Baseline Provider clause.610 Since Cosmian's module implements neither function anywhere, it cannot truthfully claim conformance to any currently-defined OASIS PKCS#11 v3.0/v3.1 Provider profile — regardless of how much other functionality it has, this one omission is a universal blocker.

    Profile requirements vs. Cosmian's actual coverage

    Profile Own mandatory requirements (beyond inherited Baseline) Cosmian gap
    Baseline Provider 16 functions incl. GetInterfaceList/GetInterface; zero mandatory mechanisms; a self-declaring CKO_PROFILE object Missing only GetInterfaceList/GetInterface; also never emits a CKO_PROFILE object at all (dead code path)
    Extended Provider + GetMechanismList, GetMechanismInfo, Login, LoginUser, Logout; zero mandatory mechanisms Has everything except LoginUser (+ inherited Baseline gap)
    Authentication Token (Provider) + Login, LoginUser, Logout, SignInit+(Sign and/or SignUpdate+SignFinal); CKO_PRIVATE_KEY/CKO_PUBLIC_KEY; zero mandatory mechanisms Cosmian already implements every crypto capability this profile needs (full sign support) — blocked solely by the inherited GetInterfaceList/GetInterface/LoginUser gap
    Public Certificates Token (Provider) CKO_CERTIFICATE; CKA_ID-matching rule between certs and their private/public keys, discoverable without login Cosmian has CKO_CERTIFICATE + CKA_ID-based lookup already — same sole blocker

    Extended Provider, Authentication Token, and Public Certificates Token are independent siblings that each build directly on Baseline Provider — not a chain requiring each other.10 The practical implication: implementing just C_GetInterfaceList/C_GetInterface (plus C_LoginUser) would bring Cosmian's existing functionality to the threshold of Baseline, Authentication Token, and Public Certificates Token conformance simultaneously — nothing else about the current sign/find/certificate logic would need to change.

    Mechanism inventory vs. Cosmian's 11

    Family Standard defines (selected) Cosmian has Gap
    RSA KeyPairGen, PKCS, PKCS_OAEP, PKCS_PSS, X_509, SHA3_*_RSA_PKCS, AES_KEY_WRAP PKCS, PKCS_PSS, SHA1/256/384/512_RSA_PKCS No OAEP encryption, no on-token keygen, no SHA-3 variants, no wrap
    AES KeyGen, ECB, CBC, CBC_PAD, CTR, GCM, CCM, CMAC, KEY_WRAP/_PAD/_KWP KeyGen, CBC, CBC_PAD No AEAD (GCM/CCM) at all — no authenticated encryption; no MAC; no key wrapping
    EC/EdDSA EC_KEY_PAIR_GEN, ECDSA(+SHA*), ECDH1_DERIVE, EC_EDWARDS/MONTGOMERY_KEY_PAIR_GEN, EDDSA ECDSA(raw only), EDDSA No on-token EC/Ed/X keygen, no ECDH key agreement despite declaring X25519/X448 key types
    Digest SHA-1/224/256/384/512, SHA3 family (none exposed via C_Digest*) 100% gap — digest exists only as an internal PSS/MGF1 parameter, never as a standalone operation
    KDF/derive DH_PKCS_DERIVE, HKDF_*, PKCS5_PBKD2, SP800_108_* (none — C_DeriveKey fully stubbed) 100% gap

    New-in-v3.0 mechanisms particularly relevant to a modern KMS: CKM_AES_GCM, CKM_RSA_PKCS_OAEP's SHA-3 options, CKM_EC_EDWARDS_KEY_PAIR_GEN/CKM_EC_MONTGOMERY_KEY_PAIR_GEN, CKM_EDDSA (Cosmian does have this one), CKM_HKDF_*, CKM_SHA3_* family.3


    The Project's Own Roadmap (discovered, not solicited)

    Nine GitHub issues opened 2026-09-02 (2 days before this research) under milestone "Sprint F · HSM Integration" (#7), authored by @Manuthor, directly plan this exact gap:4

    • #1153 "PKCS#11 v3.0: scope decision & FFI foundation" — frames vendoring/rebinding pkcs11-sys as the blocking prerequisite for all v3.0 work. This research disproves the issue's central technical claim: the pinned pkcs11-sys v0.2.25 already fully binds CK_INTERFACE, C_GetInterfaceList/C_GetInterface, all 20 message-based function pointers, and every cited v3.0 mechanism constant — verified via SHA-256 checksum match against Cargo.lock and direct source inspection.7 The FFI is not the bottleneck; only Cosmian's own consuming code needs to be written.
    • #1156 "PKCS#11 v3.0 rollout: provider interfaces, mechanisms, consumer side, tests" — the concrete plan: implement C_GetInterfaceList/C_GetInterface (registering a "PKCS 11" 3.x interface while keeping C_GetFunctionList for legacy callers), bump cryptokiVersion, wire native CKM_AES_GCM/CKM_EDDSA.
    • #1154 "HSM delegation Track A" — explicitly states: "Verify is explicitly out of scope for HSM delegation in all cases above — public keys are not sensitive, verification stays in software using the exported public key." This is the closest thing to an explicit design rationale found for the Verify gap, though it is written about the HSM-consumer side (crate/hsm/base_hsm), not the PKCS#11-provider side this report centers on — the same logic plausibly applies transitively but is not stated for the provider crate specifically.
    • #1157 "HSM delegation Track B" — plans message-based AEAD, HKDF, X25519 ECDH — for the HSM-consumer direction.

    Note on scope: issues #1154/#1157/#1158–1161 are about crate/hsm/base_hsm (KMS-as-PKCS#11-client, talking to physical HSMs) — architecturally distinct from crate/clients/pkcs11/module+provider (KMS-as-PKCS#11-server, this report's subject). Only #1153/#1156 directly address the provider side.


    Why the Gaps Likely Exist (design intent, inferred + partially confirmed)

    • CHANGELOG history11 shows the module was built incrementally for specific consumers: VeraCrypt (v4.14.0, 2024-03), LUKS (v4.16.0), OpenSSH (PR Add OpenSSH support #835, PR fix: OpenSSH authentication fails #1091/fix(openssh): cannot find private key issue #1112 fixing CKA_ID lookup bugs), Oracle TDE wallet migration (v5.21.0, adding CKM_AES_KEY_GEN/CBC/CBC_PAD and removing a blocking CKF_WRITE_PROTECTED flag). Every capability that exists was added because a specific integration needed it — none of Verify/Wrap/Derive/KeyPairGen were ever requested by these four consumers.
    • Provider README8 explicitly targets "a Veracrypt keyfiles provider" and "a LUKS keys provider," cites the v2.40 spec by URL, and states the module was forked because "Google did not seem to be interested in our PRs" upstream — i.e. it inherited v2.40 scope from its upstream origin rather than making an independent v3.0-vs-v2.40 choice at the time.
    • No in-code rationale comments exist near the cryptoki_fn_not_supported! stubs themselves — the "why" lives only in the 2026-09-02 roadmap issues, not in code comments.

    Key Repositories / Files Summary

    Path Role
    crate/clients/pkcs11/module/src/pkcs11.rs All 68 extern "C" fn C_* implementations + CK_FUNCTION_LIST
    crate/clients/pkcs11/module/src/core/mechanism.rs 11-mechanism whitelist
    crate/clients/pkcs11/module/src/core/object.rs 6 CKO_* classes, generic CKA_* attribute dispatcher
    crate/clients/pkcs11/module/src/traits/backend.rs Backend trait (24 methods)
    crate/clients/pkcs11/provider/src/lib.rs C_GetFunctionList entry point, config/auth
    crate/clients/pkcs11/provider/src/backend.rs CliBackend — Backend impl
    crate/clients/pkcs11/provider/src/kms_object.rs All KMIP request-building code
    Cosmian/kms#1153, #1156 Active v3.0 adoption roadmap
    oasis-tcs/pkcs11 OASIS TC repo — frozen headers per version, used for the function-count diff

    Footnotes

    Footnotes

    1. Complete function/mechanism/object/algorithm inventory of cosmian_pkcs11_module, verified via GitHub search_code/get_file_contents at commit 4c814981cf8b8ccbe8e38b2996effadc3ca315f8, cross-checked byte-identical against a local working tree and open PR feat: OPA server + Authentication server #998. Key files: crate/clients/pkcs11/module/src/pkcs11.rs (all function bodies, CK_FUNCTION_LIST at lines 139-211), core/mechanism.rs:40-52, core/object.rs:33-51, traits/key_algorithm.rs:9-76. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

    2. Absence of the v3.0 Interfaces API and all 24 v3.0-introduced functions confirmed via GitHub search_code (0 hits for C_GetInterfaceList, C_GetInterface, CK_INTERFACE, C_LoginUser, C_SessionCancel, all message-based function name pairs, CK_FUNCTION_LIST_3_0, and all CKP_* profile constants), plus manual exported-symbol analysis showing the cosmian_pkcs11 cdylib exports exactly one #[no_mangle] function (C_GetFunctionList, provider/src/lib.rs:90). ↩ ↩2

    3. Cosmian mechanism list per footnote 1. Standard mechanism inventory from OASIS "PKCS Check docker container #11 Cryptographic Token Interface Current Mechanisms Specification" v3.0 (v3.1 edition not separately published — merged into the base spec, see footnote 6): https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html — RSA §2.1, AES §2.13-2.17, EC §2.3, Digest §2.20-2.27, KDF/derive §2.4/2.39-2.43. ↩ ↩2 ↩3 ↩4

    4. All nine issues under milestone https://github.com/Cosmian/kms/milestone/7, fetched verbatim via GitHub API: #1153, #1154, #1155, #1156, #1157, #1158, #1159, #1160, #1161. All created 2026-09-02 by @Manuthor, labels enhancement+pkcs11, state OPEN. ↩ ↩2

    5. Provider architecture, config/auth model, and complete Backend→KMIP mapping table: provider/src/lib.rs:90-186, provider/src/backend.rs:214-243,597-620, provider/src/kms_object.rs:139-141,714-939, traits/backend.rs:120-179, client/src/config.rs:27-65. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

    6. OASIS PKCS#11 Cryptoki Base Specification v3.1: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html ("Conformance" chapter; CK_FUNCTION_LIST/CK_INFO definitions in the General Data Types chapter). PKCS#11 Cryptographic Token Interface Profiles v3.1: https://docs.oasis-open.org/pkcs11/pkcs11-profiles/v3.1/pkcs11-profiles-v3.1.html (§5.1 Baseline Provider, §5.3 Extended Provider, §5.4 Authentication Token, §5.5 Public Certificates Token, §6 Conformance clauses). Function-count diff verified against the OASIS TC's frozen headers at https://github.com/oasis-tcs/pkcs11 (published/2-40-errata-1/pkcs11f.h, published/3-01/pkcs11f.h). ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

    7. pkcs11-sys binding-surface verification: Cargo.lock:4753-4756 (pinned version/checksum 7f9274ee0f6bf35f62117a120fa66885f3839bd5b54f6a2a9783694e3fa90cb3), matched against the cached .crate archive SHA-256; vendored source at pkcs11-sys-0.2.25/src/pkcs11_unix.rs lines 1244 (CK_INTERFACE), 4515/4518 (C_GetInterfaceList/C_GetInterface), 5347+ (CK_FUNCTION_LIST_3_0), 4538-4620 (20 message-based function externs), 74/75/78 (CKP_BASELINE_PROVIDER/CKP_EXTENDED_PROVIDER/CKP_COMPLETE_PROVIDER), 734 (CKM_EDDSA); cross-checked identical against https://github.com/google/native-pkcs11 (pkcs11-sys/src/pkcs11_unix.rs). ↩ ↩2

    8. Fork provenance and stated scope: crate/clients/pkcs11/module/README.md ("forked from google/native-pkcs11 commit cc26f7f8..., Google did not seem to be interested in our PRs"); crate/clients/pkcs11/provider/README.md ("PKCS#11 2.40 standard," VeraCrypt/LUKS goals). ↩ ↩2

    9. ModuleError enum and CK_RV mapping: crate/clients/pkcs11/module/src/error/mod.rs:39-118 (enum) and :126-167 (impl From<ModuleError> for CK_RV). ↩

    10. Profile dependency hierarchy and per-profile mandatory-requirement lists: OASIS PKCS#11 Profiles v3.1, §2.1 "Profile Requirements," §5.1/§5.3/§5.4/§5.5, §6.1/§6.3/§6.4/§6.5 — https://docs.oasis-open.org/pkcs11/pkcs11-profiles/v3.1/pkcs11-profiles-v3.1.html. ↩ ↩2

    11. Root CHANGELOG.md entries: v4.14.0 (2024-03-27, VeraCrypt support, PR feat: PKCS11 provider library #208), v4.16.0 (2024-05-06, LUKS support), v5.21.0 (2026-04-21, Oracle TDE wallet migration, cosmian_pkcs11_verify diagnostic tool), v5.24.0 (2026-06-18, VeraCrypt CKO_DATA tagging), v5.26.0 (2026-08-07, OpenSSH CKA_ID fix, PR fix: OpenSSH authentication fails #1091); also PR #835 (OpenSSH support), PR #912 (Oracle TDE wallet migration), PR #1091/#1112 (OpenSSH CKA_ID bugfixes), issue #1111/#1076. ↩

  2. 120 remaining items

  3. added 10 commits that reference this issue on Oct 1, 2026
    6a3dd92
    329398b
    ac894b6
    a2444f1
    51136ac
    bb2606b
    acbcb00
    feff139
    e6954fd
    6c2b2d0
  4. added a commit that references this issue on Oct 7, 2026
    5a6b4f6
  5. added 3 commits that reference this issue on Oct 8, 2026
    5e89f4f
    1ce569e
    2dced39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions