PKCS 11
PKCS #11, also known as Cryptoki, is a Public-Key Cryptography Standard that defines a platform-independent application programming interface (API) for cryptographic tokens, enabling applications to perform operations such as encryption, decryption, digital signing, and key management on devices like hardware security modules (HSMs), smart cards, and software tokens without dependency on specific hardware details.[1] The standard provides a C-language interface that abstracts the underlying cryptographic hardware or software, allowing multiple applications to share resources on a single token while ensuring isolation and portability across platforms.[1] It models cryptographic devices as "tokens" containing "objects" such as keys, certificates, and data, with attributes that control access and behavior, and supports mechanisms for various algorithms including RSA, AES, and elliptic curve cryptography.[1][2] Originally developed by RSA Laboratories as part of the PKCS series in the mid-1990s to promote interoperability in public-key cryptography, the standard's first version (v1.0) was published on April 28, 1995.[3] Subsequent revisions addressed evolving needs, with version 2.20 (June 28, 2004) becoming the most widely adopted for its comprehensive support of cryptographic primitives and token management functions.[3] In 2013, maintenance transitioned to the OASIS PKCS 11 Technical Committee, which published version 2.40 as an official OASIS Standard on April 14, 2015, incorporating errata and enhancements for better integration with modern systems.[4] The current version, 3.1, approved as an OASIS Standard on August 10, 2023, introduces advanced features like improved key derivation functions, support for post-quantum cryptography mechanisms, and profiles for specific use cases such as mobile and cloud environments, while maintaining backward compatibility with prior versions.[4][1] Key components of PKCS #11 include slots (physical or logical interfaces to tokens), sessions (connections between applications and tokens), and a rich set of functions prefixed withC_ (e.g., C_Initialize for library setup, C_CreateObject for object instantiation, and C_Sign for signature generation), all defined in the pkcs11.h header file.[1] The API emphasizes security through user authentication (normal user and security officer roles), attribute-based access controls, and optional features like multi-threaded operation via mutex handling.[2] Widely implemented in libraries like OpenSSL's engine_pkcs11 and used in standards-compliant systems from vendors such as IBM, Thales, and Entrust, PKCS #11 facilitates secure key storage and operations in environments ranging from enterprise servers to embedded devices.[5][6]
Introduction
Overview
PKCS #11, also known as Cryptoki—from the words "cryptographic token interface"—is the Public-Key Cryptography Standards #11, a specification defining a platform-independent application programming interface (API) in the C programming language for managing cryptographic tokens.[7] This standard provides a technology-independent, object-based model that allows applications to interface with cryptographic hardware or software without dependency on specific vendors or platforms.[7] The primary goal of PKCS #11 is to enable secure and portable cryptographic operations, such as encryption, decryption, digital signing, and key management, by abstracting the underlying implementation details of tokens.[7] It supports resource sharing among multiple applications and promotes interoperability, ensuring that cryptographic services can be accessed consistently across diverse environments.[7] In this framework, a token serves as a logical abstraction of a cryptographic device, encompassing physical hardware like hardware security modules (HSMs) or smart cards, as well as software-based emulations.[7] Tokens store cryptographic objects, including private keys, public keys, and certificates, and execute operations on them while maintaining isolation from the application's direct access to sensitive data.[7] Originally developed and maintained by RSA Laboratories as part of the broader PKCS series, the standard's oversight transitioned to the Organization for the Advancement of Structured Information Standards (OASIS) in early 2013, where it continues to be updated by the OASIS PKCS #11 Technical Committee.[3]Purpose and Scope
PKCS #11, also known as Cryptoki, primarily aims to provide a platform-independent application programming interface (API) that enables applications to access cryptographic devices such as hardware security modules (HSMs) and smart cards in a portable manner, while allowing resource sharing among multiple applications and isolating them from the underlying hardware specifics.[1] This standardization ensures that cryptographic operations can be performed consistently across diverse environments without dependence on vendor-specific implementations.[1] The benefits of PKCS #11 include enhanced interoperability between applications and cryptographic tokens, supporting secure key storage and essential operations such as encryption, digital signing, and key generation.[1] Its scope is delimited to a C-language API for interacting with tokens, encompassing data types, functions, and basic interface components, but excludes wire protocols for communication or higher-level key management protocols.[1] Limitations of the standard include the allowance for vendor-defined extensions, which, while providing flexibility, must not conflict with the core specification to maintain compatibility, though they may reduce interoperability across different vendors' implementations.[1] Additionally, PKCS #11 does not mandate support for specific hardware or algorithms, leaving such decisions to implementers. In the broader context of cryptography, the standard facilitates compliance with FIPS 140-2 and FIPS 140-3 by enabling the validation of cryptographic modules that implement its interface.[8]History
Origins and Development
PKCS #11, part of the broader Public-Key Cryptography Standards (PKCS) series developed by RSA Laboratories starting in the early 1990s, emerged to standardize interfaces for public-key cryptography implementations across diverse hardware and software environments.[9] The project for PKCS #11 specifically launched in January 1994, driven by the increasing adoption of cryptographic hardware such as smart cards, PCMCIA tokens, and hardware security modules (HSMs), which necessitated a portable API for applications to access these devices without vendor-specific dependencies.[10] This effort addressed the growing needs of public key infrastructure (PKI) by abstracting tokens as logical entities, enabling uniform management of cryptographic objects like keys and certificates.[11] The initial version, PKCS #11 v1.0, was released in April 1995 following collaborative development involving over 130 contributors from industry, academia, and government representatives, including early integrations with vendors like Netscape for secure browser operations.[11] RSA Laboratories coordinated this process, soliciting feedback through public mailing lists to refine the Cryptoki interface, which provided functions for session management, object handling, and cryptographic operations while ensuring interoperability.[11] The standard emphasized technology independence, allowing applications to interact with tokens via a C-language API without knowledge of underlying hardware specifics, thus supporting the emerging ecosystem of secure e-commerce and authentication systems.[11] A key milestone came with version 2.01 in December 1997, which introduced enhanced multi-threaded support through flags like CKF_OS_LOCKING_OK in the C_Initialize function, enabling concurrent access and mutex handling for improved performance in multi-application environments.[12] This update also incorporated influences from contemporary standards to align PKCS #11 with broader interoperability goals.[12] Development faced challenges in balancing strict standardization with vendor flexibility, resulting in numerous optional features—such as mechanism support and attribute behaviors—to accommodate diverse token capabilities without mandating uniform implementation across all devices.[13] In 2013, stewardship transitioned to OASIS for continued evolution.[14]Major Versions
The PKCS #11 standard originated as a set of drafts and errata under RSA Laboratories before transitioning to the OASIS PKCS 11 Technical Committee in early 2013, where subsequent development followed formal OASIS standardization processes.[3] A separate historical mechanisms specification documents deprecated algorithms across versions for reference, ensuring continuity while focusing current implementations on supported operations. Version 2.01, released by RSA Laboratories on December 22, 1997, introduced core session management functions such as C_OpenSession and C_CloseSession for handling application-token interactions, alongside basic cryptographic mechanisms including RSA for public-key operations and DES for symmetric encryption.[15] This version established the foundational Cryptoki API structure, enabling platform-independent access to cryptographic tokens like smart cards and hardware security modules.[16] Version 2.20, published by RSA Security Inc. on June 28, 2004, standardized multi-part operations for functions like encryption and hashing—allowing incremental processing of large data streams—and enhanced object handling with refined attribute management for keys and certificates.[13] It gained widespread adoption due to its alignment with FIPS 140-2 validation requirements for cryptographic modules, serving as the basis for many commercial implementations.[8] Version 2.40, approved as an OASIS Standard on April 14, 2015, improved error handling by introducing return codes such as CKR_FUNCTION_NOT_PARALLEL to signal non-concurrent function execution, alongside clarifications on error priorities and conditions.[14] It added new attributes for enhanced token information, including CKA_START_DATE and CKA_END_DATE for certificate validity periods, CKA_PUBLIC_KEY_INFO for key details, and expansions to CK_TOKEN_INFO flags like CKF_USER_PIN_TO_BE_CHANGED to indicate PIN status.[14] Version 3.0, published as an OASIS Standard on June 15, 2020, marked the first major revision since 1997 by introducing message-based interfaces such as C_MessageEncryptInit for efficient streaming cryptographic operations, particularly supporting authenticated encryption with associated data (AEAD) modes like AES-GCM.[16] It unified the base specification and mechanisms document into a single standard, incorporating new algorithms including SHA-3 hashes, HKDF key derivation for TLS 1.3, and AES-XTS, while adding the CKO_PROFILE object class for programmatic module capability queries.[17] Version 3.1, approved as an OASIS Standard on July 23, 2023, provided minor refinements including enhanced conformance tests for object creation, attribute validation, and mechanism support to improve interoperability across consumer and provider implementations.[18] It introduced new attributes like CKA_ALWAYS_AUTHENTICATE for private keys, requiring re-authentication per operation to bolster security in sensitive environments, and added post-quantum support through mechanisms such as HSS (stateful hash-based signatures) per NIST SP 800-208.[18] This remains the current version as of November 2025.[18]Architecture
Cryptoki Model
Cryptoki serves as the primary interface layer in PKCS #11, providing a portable, technology-independent API that abstracts the complexities of diverse cryptographic devices into a uniform model for applications to interact with cryptographic tokens.[7] This abstraction allows software to manage security operations without direct dependence on underlying hardware specifics, such as smart cards, hardware security modules, or software-based tokens, ensuring compatibility across implementations.[19] In the high-level operational flow of the Cryptoki model, an application first initializes the PKCS #11 library using theC_Initialize function to establish the runtime environment.[20] It then discovers available slots—logical positions for tokens—via C_GetSlotList, opens sessions to specific tokens within those slots using C_OpenSession, and manipulates cryptographic objects through handles obtained from operations like C_CreateObject.[21][22][23] This sequence enables secure handling of keys, certificates, and other data while maintaining isolation from the physical token infrastructure.[22]
The model adheres to key principles that enhance its robustness and flexibility, including a logical separation of concerns where slots represent potential token holders independent of the actual tokens present, allowing for dynamic insertion and removal without disrupting the application.[24] It supports concurrent sessions across multiple tokens, with each session maintaining its own state—such as read-only public or read-write user modes—to facilitate parallel operations while preserving security boundaries.[25] Operations are inherently stateful, relying on session context to track ongoing cryptographic processes like encryption or signing.[26]
Conceptually, the Cryptoki model can be visualized as a hierarchical structure: the PKCS #11 library at the top level interfaces with the application; it connects to one or more slots, each potentially containing a token; sessions are established within tokens to perform operations; and objects within sessions represent the manipulable cryptographic entities.[26] This layered approach ensures modularity, with handles serving as opaque references to sessions and objects for efficient, secure access.[27]
Error handling in the Cryptoki model is standardized through return codes from all API functions, promoting reliability by explicitly signaling outcomes such as CKR_OK for successful completion or CKR_SLOT_ID_INVALID for attempts to access non-existent slots.[28] These codes, defined in the specification, allow applications to gracefully manage failures like token absence or session limits, ensuring robust integration in varied environments.[28]
Core Components
In the Cryptoki architecture of PKCS #11, slots represent logical positions where cryptographic tokens can be inserted, such as hardware security module readers or smart card interfaces.[24] Each slot is identified by a uniqueCK_SLOT_ID, which is a CK_ULONG data type serving as an opaque handle.[24] Applications discover available slots through the C_GetSlotList function, which returns an array of slot IDs, allowing enumeration of all supported positions in the system.[24] Slot information, including flags like CKF_TOKEN_PRESENT to indicate token presence, is retrieved via the CK_SLOT_INFO structure.[24]
Tokens provide the actual cryptographic capabilities within slots, embodying physical or logical devices that offer secure storage and processing functions.[24] When inserted into a slot, a token is described by the CK_TOKEN_INFO structure, which includes details such as its label, serial number, manufacturer ID, and various flags denoting supported features.[24] For instance, the CKF_RNG flag signals the presence of a random number generator on the token, while other flags indicate capabilities like write protection or login requirements.[24] Token details are queried using the C_GetTokenInfo function with the associated slot ID, enabling applications to assess the token's suitability for specific operations before establishing a connection.[24]
Sessions establish secure, logical connections between an application and a token, facilitating access to its resources.[25] Identified by a CK_SESSION_HANDLE, which is another CK_ULONG opaque value, sessions can be public or user-initiated and may operate in read-only or read-write modes.[25] Session states progress through phases such as read-only public session (CKS_RO_PUBLIC_SESSION), read-write user functions (CKS_RW_USER_FUNCTIONS), and others, reflecting the level of authentication and operational permissions.[25] These states manage the context for cryptographic operations, with session information retrievable via C_GetSessionInfo to monitor concurrency limits or error conditions.[25] Sessions are bound to a specific slot and token, ensuring isolation and security during interactions.
Objects serve as the fundamental data entities managed on tokens, encompassing keys, certificates, and other cryptographic items.[26] Each object is referenced by a CK_OBJECT_HANDLE, a CK_ULONG opaque identifier unique within its session.[26] Objects are classified by the CKA_CLASS attribute, which specifies types such as CKO_PUBLIC_KEY for public keys or CKO_CERTIFICATE for digital certificates.[26] They exist in two scopes: persistent objects stored durably on the token (indicated by CKA_TOKEN set to CK_TRUE) and session objects that reside temporarily in memory during an active session.[26] This distinction allows for secure, long-term storage of sensitive data while supporting ephemeral operations without token commitment.
Handles across components—such as CK_SLOT_ID, CK_SESSION_HANDLE, and CK_OBJECT_HANDLE—act as secure, opaque references that abstract underlying implementations and prevent direct memory access.[27] These handles ensure portability and security by invalidating upon events like user logout, token removal, or session closure, thereby protecting against unauthorized access or stale references in the Cryptoki interface.[27] Through this hierarchy—slots containing tokens, sessions connecting to tokens, and objects accessible via sessions—PKCS #11 provides a robust framework for token-based cryptography.[7]
Data Types and Objects
General Data Types
PKCS #11 defines a set of fundamental data types to ensure portability across platforms, forming the basis for the Cryptoki API's interactions with cryptographic tokens. These types include basic scalar and pointer types, as well as composite structures for conveying information about libraries, slots, tokens, sessions, and mechanisms. All structures are designed with fixed-size fields to promote consistency, and the specification mandates the use of#pragma pack(1) directives to enforce byte-aligned packing without padding, preventing platform-specific alignment issues.[1]
Basic scalar types in PKCS #11 primarily revolve around unsigned integers and characters for simplicity and efficiency. The core type CK_ULONG is an unsigned long integer, guaranteed to be at least 32 bits wide, used extensively for indices, lengths, counts, and flags throughout the API.[1] Pointer types include CK_BYTE_PTR, which is a pointer to an array of CK_BYTE (an unsigned 8-bit value), for handling binary data buffers, and CK_VOID_PTR for generic opaque data pointers where the exact type is not specified.[1] Additionally, CK_FLAGS is a bit field type based on CK_ULONG, enabling compact representation of boolean options and capabilities.[1]
Key structures begin with CK_VERSION, a simple pair of CK_BYTE fields for major and minor version numbers, used to indicate the version of the Cryptoki library or a token's firmware/hardware.[1] The CK_INFO structure provides comprehensive details about the Cryptoki library, including its cryptokiVersion (a CK_VERSION), a 32-character manufacturerID and libraryDescription (as CK_UTF8CHAR arrays), a flags field for library capabilities, and the libraryVersion (another CK_VERSION).[1] For cryptographic operations, the CK_MECHANISM structure specifies the algorithm via a mechanism field (an enumerated CK_MECHANISM_TYPE, such as CKM_RSA_PKCS for RSA PKCS#1 signing), along with a pParameter (CK_VOID_PTR) and ulParameterLen (CK_ULONG) for mechanism-specific parameters.[1]
Slot and token information is captured in dedicated structures to describe hardware and token states. CK_SLOT_INFO details a physical or logical slot, featuring a 64-character slotDescription and 32-character manufacturerID (both CK_UTF8CHAR), a flags field (e.g., CKF_TOKEN_PRESENT bit set if a token is inserted, CKF_REMOVABLE_DEVICE for hot-swappable slots), and hardwareVersion and firmwareVersion (both CK_VERSION).[1] The CK_TOKEN_INFO structure extends this for the token itself, with fields like a 32-character label, 32-character manufacturerID, 16-character model and serialNumber, various ul* counters (CK_ULONG) for session limits, PIN lengths, and memory capacities (public/private), a flags field (e.g., CKF_RNG if the token has a random number generator, CKF_WRITE_PROTECTED for read-only status), versions, and a 16-character utcTime for the token's clock.[1] Session management uses CK_SESSION_INFO, which includes the slotID (CK_ULONG), state (an enumerated CK_STATE like CKS_RO_USER_FUNCTIONS for read-only user sessions), flags (e.g., CKF_RW_SESSION for read-write access), and ulDeviceError (CK_ULONG) for hardware faults.[1]
Return values from API functions are standardized as CK_RV, a typedef of CK_ULONG representing enumerated outcomes, with CKR_OK defined as 0 for success and others like CKR_PIN_INCORRECT (0x000000A0) or CKR_DEVICE_ERROR (0x00000030) indicating specific failures.[1] To handle platform variations in pointer definitions, the specification employs CK_PTR as a macro (typically expanding to * or nothing in C++ contexts) for conditional pointers in structures, ensuring compatibility across compilers.[1] These general types underpin object attributes and API parameters, providing a consistent foundation for token operations.[1]
Objects and Attributes
In PKCS #11, objects represent the fundamental units of data storage and cryptographic material within a token, each characterized by a set of attributes that define their properties, values, and behaviors.[1] These attributes are managed through the CK_ATTRIBUTE structure, which consists of a type field (CK_ATTRIBUTE_TYPE, an unsigned long identifying the attribute, such as CKA_CLASS), a pointer to the value (void *pValue), and the length of the value in bytes (CK_ULONG ulValueLen).[1] Objects are created, queried, or modified using templates, which are arrays of CK_ATTRIBUTE structures specifying the desired attributes and their values for validation against the token's policies.[1] Objects are classified by their class via the CKA_CLASS attribute, which takes values from the CK_OBJECT_CLASS enumeration.[1] The defined classes include CKO_DATA for general-purpose data storage, CKO_CERTIFICATE for certificates, CKO_PUBLIC_KEY for public keys, CKO_PRIVATE_KEY for private keys, CKO_SECRET_KEY for symmetric keys, CKO_HW_FEATURE for hardware features like clocks or counters, CKO_DOMAIN_PARAMETERS for algorithm-specific parameters used in key generation, CKO_MECHANISM for mechanism objects, CKO_OTP_KEY for one-time password keys, and CKO_PROFILE for profile objects.[1] Each class determines the applicable attributes, with common ones shared across classes and class-specific ones providing detailed properties.[1] Common attributes apply to most objects and include CKA_TOKEN (boolean, true if stored persistently on the token, default false), CKA_PRIVATE (boolean, true if requiring user authentication for access, default depends on token), CKA_SENSITIVE (boolean, true if the object contains sensitive data that cannot be revealed in plain text), and CKA_EXTRACTABLE (boolean, true if the object can be extracted from the token, often false for private keys).[1] Another special attribute is CKA_NEVER_EXTRACTABLE (boolean, true if the object is permanently non-extractable, preventing future changes to extractability).[1] These attributes enforce security policies, such as protecting sensitive keys from export.[1] For key objects, the CKA_KEY_TYPE attribute specifies the algorithm via CK_KEY_TYPE values, such as CKK_RSA for RSA or CKK_AES for AES.[1] Public key objects include attributes like CKA_MODULUS (byte array for RSA modulus) and usage flags such as CKA_ENCRYPT (boolean, true if usable for encryption) and CKA_VERIFY (boolean, true if usable for signature verification).[1] Private key objects feature CKA_DECRYPT and CKA_SIGN for usage, alongside CKA_SENSITIVE and CKA_EXTRACTABLE to control access and export.[1] Secret key objects use CKA_VALUE (byte array holding the key bits) and support symmetric operations via flags like CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN, and CKA_VERIFY.[1] Certificate objects are defined by attributes such as CKA_CERTIFICATE_TYPE (CK_CERTIFICATE_TYPE, e.g., CKC_X_509 for X.509 certificates), CKA_SUBJECT (byte array with DER-encoded subject name), and CKA_VALUE (byte array containing the encoded certificate).[1] These allow storage of public-key or attribute certificates with metadata like issuer and serial number.[1] During object creation, templates are validated against token policies; for instance, attempting to set an invalid attribute type returns CKR_ATTRIBUTE_TYPE_INVALID, while inconsistent values (e.g., mismatched key type and parameters) yield CKR_TEMPLATE_INCONSISTENT, and read-only attributes like CKA_CLASS cannot be modified post-creation.[1] Copying objects preserves attributes unless explicitly modified in the template, subject to the same policy checks.[1]API Functions
Session and General Management
The session and general management functions in PKCS #11 provide the foundational interface for initializing the Cryptoki library, enumerating and querying hardware slots and tokens, establishing and controlling sessions, authenticating users, and supporting asynchronous operations where applicable, as defined in PKCS#11 version 3.1. These functions enable applications to interact with cryptographic tokens in a platform-independent manner, ensuring proper resource allocation and security boundaries before performing higher-level operations.[1] Library initialization begins with C_Initialize, which prepares the Cryptoki library for use by setting up threading models and other runtime parameters via an optional CK_C_INITIALIZE_ARGS structure; this function must be the first called and supports flags like CKF_LIBRARY_CANT_CREATE_OS_THREADS for custom mutex handling.[1] Following initialization, C_GetInfo retrieves essential library details, including the Cryptoki version, manufacturer ID, and flags indicating capabilities such as library threading support.[1] To conclude library usage, C_Finalize terminates all sessions, releases resources, and shuts down the library, ensuring no further function calls occur afterward.[1] Slot and token management functions allow discovery and configuration of physical or virtual cryptographic devices. C_GetSlotList enumerates available slots, optionally filtering for those containing tokens via the tokenPresent parameter, returning an array of CK_SLOT_ID values up to a specified count.[1] For a specific slot, C_GetTokenInfo queries the inserted token's properties, such as its label, serial number, maximum session count, and flags like CKF_RNG for random number generation support.[1] Event handling is facilitated by C_WaitForSlotEvent, which polls or blocks for changes like token insertion, using flags such as CKF_DONT_BLOCK for non-blocking behavior and returning the affected slot ID.[1] Token initialization via C_InitToken formats a new or uninitialized token, requiring the Security Officer (SO) PIN (CKU_SO user type) to set a new SO PIN and token label, effectively erasing existing contents.[1] Sessions represent logical connections to tokens and are managed through handles of type CK_SESSION_HANDLE (as defined in the general data types). C_OpenSession creates a new session for a given slot, specifying flags like CKF_RW_SESSION for read-write access or CKF_SERIAL_SESSION for serialized operations to prevent parallelism, along with an optional application-defined pointer and notification callback.[1] To end a specific session, C_CloseSession releases its resources and aborts any ongoing operations, while C_CloseAll terminates all sessions for the calling application on a particular slot.[1] Session status can be queried with C_GetSessionInfo, which returns details like the current state (public, user logged in, or SO logged in), device error code, and active flags.[1] User authentication within sessions is handled by login and PIN management functions, distinguishing between the normal user (CKU_USER) and the Security Officer (CKU_SO). C_Login authenticates a user by providing their PIN in a session, enabling access to protected resources and returning errors like CKR_PIN_INCORRECT if invalid; it requires the session to be in a public state.[1] Conversely, C_Logout revokes authentication, transitioning the session back to public and clearing sensitive credentials.[1] Administrative PIN operations include C_InitPIN, which the SO uses to set the initial user PIN in a read-write session, and C_SetPIN, allowing logged-in users to change their own PIN or the SO to modify the user PIN by supplying the old and new values.[1] Support for parallel or asynchronous operations is provided through monitoring and cancellation functions, though many implementations return CKR_FUNCTION_NOT_PARALLEL if unsupported. C_GetFunctionStatus checks whether an ongoing operation in the session has completed, useful in multi-threaded environments.[1] Similarly, C_CancelFunction attempts to abort a running operation, ensuring graceful interruption where parallelism is enabled.[1] Vendor extensions enhance flexibility in these management areas, particularly through mechanisms like CKM_VENDOR_DEFINED, which reserves mechanism codes starting from 0x80000000 for proprietary implementations of session-related behaviors or token interactions, allowing token vendors to extend standard functionality without conflicting with core PKCS #11 definitions.[1]Cryptographic Operations
PKCS #11 provides a suite of functions for performing cryptographic operations on tokens, enabling secure key management, data transformation, and authentication within a session, as defined in PKCS#11 version 3.1. These operations are designed to interact with cryptographic objects such as keys and certificates, leveraging specified mechanisms to ensure portability across hardware security modules (HSMs) and software tokens. All operations require an active session, as established through prior initialization functions.[1] Object management functions allow creation, modification, duplication, and deletion of cryptographic objects. TheC_CreateObject function creates a new object on a token or in a session using an attribute template that specifies properties like class, key type, and value; it requires a valid session handle and returns an object handle upon success, failing with errors such as CKR_TEMPLATE_INCONSISTENT if attributes are invalid or incomplete.[1] The C_CopyObject function duplicates an existing object, applying a template to modify attributes like CKA_TOKEN or CKA_PRIVATE, but only if the original object's CKA_COPYABLE attribute is true; it produces a new object handle while preserving sensitive attributes unless overridden.[1] To delete an object, C_DestroyObject removes it from the token, succeeding only if the object's CKA_DESTROYABLE attribute permits it and the session has appropriate rights.[1] Attribute inspection and updates are handled by C_GetAttributeValue and C_SetAttributeValue, which query or modify object properties via a template; the former returns lengths or values (or CK_UNAVAILABLE_INFORMATION for sensitive attributes), while the latter fails on read-only attributes like CKA_VALUE for secret keys, supporting partial updates for large attributes by first querying lengths.[1]
Searching for objects uses a three-step process to efficiently locate matching items without enumerating all token contents. C_FindObjectsInit initializes the search with an attribute template defining criteria, such as CKA_CLASS for keys or CKA_ID for identification, excluding hardware feature objects unless specified.[1] C_FindObjects then retrieves up to a specified maximum number of matching object handles into an array, returning the actual count and continuing from the previous state until no more objects are found.[1] The search is terminated by C_FindObjectsFinal, which releases resources and must be called to avoid resource leaks, failing if no operation was initialized.[1]
Key generation and wrapping functions support secure creation and transport of cryptographic keys. C_GenerateKey produces a symmetric secret key using a specified mechanism (e.g., for AES) and template, returning a handle for the new key object with attributes like CKA_VALUE_LEN.[1] For asymmetric cryptography, C_GenerateKeyPair generates a public-private key pair via a mechanism like RSA, using separate templates for each key's attributes (e.g., modulus size for public, private exponent for private), and returns handles for both.[1] Key wrapping secures export with C_WrapKey, which encrypts a target key using a wrapping key and mechanism, outputting the wrapped data or its length in a single-part operation.[1] Conversely, C_UnwrapKey decrypts wrapped key data with an unwrapping key, creating a new key object from a template that defines its properties.[1]
Encryption and decryption operations follow a similar pattern, supporting both single-part and multi-part data processing for efficiency with large inputs. C_EncryptInit prepares a session for encryption by specifying a mechanism and key handle, binding the operation to that context.[1] For single-part encryption, C_Encrypt processes the entire data block, returning the encrypted output or its length.[1] Multi-part encryption uses C_EncryptUpdate to encrypt sequential data chunks, accumulating state, followed by C_EncryptFinal to produce any final output (e.g., padding) and complete the operation.[1] Decryption mirrors this with C_DecryptInit, C_Decrypt, C_DecryptUpdate, and C_DecryptFinal, verifying and recovering plaintext while handling errors like invalid padding.[1]
Signing and verification functions enable digital signatures for integrity and authenticity. C_SignInit initializes signing with a mechanism and private key handle, preparing the session for data processing.[1] C_Sign generates a signature for single-part data, while multi-part uses C_SignUpdate and C_SignFinal for streaming.[1] Verification begins with C_VerifyInit using a public key, followed by C_Verify for single-part checks (returning CKR_SIGNATURE_INVALID on failure) or C_VerifyUpdate/C_VerifyFinal for multi-part.[1]
Hashing and random number generation provide foundational primitives. C_DigestInit sets up a hash operation with a mechanism (e.g., SHA-256), and C_Digest computes the digest for single-part data, with multi-part options via C_DigestUpdate and C_DigestFinal for incremental processing.[1] Randomness is managed by C_SeedRandom, which seeds the token's RNG with provided entropy, and C_GenerateRandom, which produces cryptographically secure random bytes up to a specified length, essential for nonces and keys.[1]
Introduced in version 3.0, the message interface enhances streaming operations for encryption, decryption, signing, and more, allowing finer control over partial processing without full multi-part commitment. C_MessageEncryptInit initializes message-based encryption with a mechanism and key, enabling subsequent calls.[1] C_MessageEncrypt encrypts single-part messages, while C_MessageEncryptUpdate handles partial data and C_MessageEncryptFinal completes the stream, supporting use cases like network protocols with variable-length payloads.[1] Similar functions exist for decryption (C_MessageDecrypt*), signing (C_MessageSign*), and verification (C_MessageVerify*), providing a unified streaming model.[1]
Mechanisms
Mechanism Framework
In PKCS #11, the mechanism framework provides a standardized way to specify and invoke cryptographic algorithms through the Cryptoki interface, allowing tokens to support a variety of operations while maintaining portability across implementations.[29] A mechanism is defined by theCK_MECHANISM structure, which includes a mechanism type identifier (from the CKM_* constants), a pointer to algorithm-specific parameters (pParameter), and the length of those parameters in bytes (ulParameterLen).[30] For example, the basic RSA PKCS #1 v1.5 mechanism (CKM_RSA_PKCS) typically requires no parameters, so pParameter is set to NULL and ulParameterLen to 0.[31] In contrast, the AES CBC mode (CKM_AES_CBC) uses a CK_AES_CBC_PARAMS structure containing an initialization vector (IV) as a byte pointer and its length.[32] Similarly, the ECDH key derivation mechanism (CKM_ECDH1_DERIVE) employs a CK_ECDH1_DERIVE_PARAMS structure that includes the peer's public value (as a byte array and length), an optional ephemeral public key handle, and key derivation function details.[33]
The framework enables mechanisms to declare support for specific cryptographic operations, such as encryption, decryption, signing, verification, and key derivation, through flags in the CK_MECHANISM_INFO structure.[34] These flags include CKF_ENCRYPT for encryption capability, CKF_SIGN for signing, CKF_VERIFY for verification, and CKF_DERIVE for key derivation, among others like CKF_HW indicating hardware acceleration.[34] Mechanism policies are token-specific and can be queried using the C_GetMechanismInfo function, which returns the CK_MECHANISM_INFO for a given slot and mechanism type, including minimum and maximum key sizes (ulMinKeySize and ulMaxKeySize) as well as supported flags such as CKG_MGF1 for mask generation functions in certain padding schemes.[35] This allows applications to discover and select appropriate mechanisms dynamically.
For handling large or streaming data, the framework supports multi-part operations following an initialize-update-finalize pattern, applicable to mechanisms that set relevant flags like CKF_SIGN or CKF_ENCRYPT.[36] These operations begin with an initialization call (e.g., C_EncryptInit), process data in chunks via update functions (e.g., C_EncryptUpdate), and conclude with a finalization step (e.g., C_EncryptFinal), enabling efficient processing without loading entire datasets into memory.[36]
In version 3.1 of the specification, the framework is extended with message-based mechanisms to support more flexible cryptographic processing, including new operations like C_MessageEncryptInit and dedicated flags such as CKF_MESSAGE_ENCRYPT, alongside additions like the CKM_SHA256_KDF for SHA-256-based key derivation.[1] These enhancements build on the core structure while integrating with functions like C_EncryptInit for traditional use cases, as detailed in the cryptographic operations section.[36]