![]() | Cryptographic Token Interface Standard |
PKCS#11 |
Design goals
Cryptoki was intended from the beginning to be an interface between applications and all kinds of portable cryptographic devices, such as those based on smart cards, PCMCIA cards, and smart diskettes. There are already standards (de facto or official) for interfacing to these devices at some level. For instance, the mechanical characteristics and electrical connections are well-defined, as are the methods for supplying commands and receiving results. (See, for example, ISO 7816, or the PCMCIA specifications.)
What remained to be defined were particular commands for performing cryptography. It would not be enough simply to define command sets for each kind of device, as that would not solve the general problem of an application interface independent of the device. To do so is still a long-term goal, and would certainly contribute to interoperability. The primary goal of Cryptoki was a lower-level programming interface that abstracts the details of the devices, and presents to the application a common model of the cryptographic device, called a "cryptographic token" (or simply "token").
A secondary goal was resource-sharing. As desktop multi-tasking operating systems become more popular, a single device should be shared between more than one application. In addition, an application should be able to interface to more than one device at a given time.
It is not the goal of Cryptoki to be a generic interface to cryptographic operations or security services, although one certainly could build such operations and services with the functions that Cryptoki provides. Cryptoki is intended to complement, not compete with, such emerging and evolving interfaces as "Generic Security Services Application Programming Interface" (RFC's 1508 and 1509) and "Generic Cryptographic Service API" (GCS-API) from X/Open.
General model
Cryptoki's general model is illustrated in the following figure. The model begins with one or more applications that need to perform certain cryptographic operations, and ends with a cryptographic device, on which some or all of the operations are actually performed. A user may be associated with an application.
Cryptoki provides an interface to one or more cryptographic devices that are active in the system through a number of "slots". Each slot, which corresponds to a physical reader or other device interface, may contain a token. A token is "present in the slot" (typically) when a cryptographic device is present in the reader. Of course, since Cryptoki provides a logical view of slots and tokens, there may be other physical interpretations. It is possible that multiple slots may share the same physical reader. The point is that a system has some number of slots, and applications can connect to tokens in any or all of those slots.
A cryptographic device can perform some cryptographic operations, following a certain command set; these commands are typically passed through standard device drivers, for instance PCMCIA card services or socket services. Cryptoki makes the cryptographic device look logically like every other device, regardless of the implementation technology. Thus the application need not interface directly to the device drivers (or even know which ones are involved); Cryptoki hides these details. Indeed, the "device" may be implemented entirely in software (for instance, as a process running on a server)-- no special hardware is necessary.
Cryptoki would likely be implemented as a library supporting the functions in the interface, and applications would be linked to the library. An application may be linked to Cryptoki directly, or Cryptoki could be a so-called "shared" library (or dynamic link library), in which case the application would link the library dynamically. Shared libraries are fairly straightforward to produce in operating systems such as Microsoft WindowsTM, OS/2TM, and can be achieved, without too much difficulty, in UnixTM and DOS systems.
The dynamic approach would certainly have advantages as new libraries are made available, but from a security perspective, there are some drawbacks. In particular, if the library is easily replaced, then there is the possibility that an attacker can substitute a rogue library that intercepts a user's PIN. From a security perspective, therefore, direct linking is generally preferable. However, whether the linking is direct or dynamic, the programming interface between the application and a Cryptoki library remains the same.
The kinds of devices and capabilities supported will depend on the particular Cryptoki library. This standard specifies only the interface to the library, not its features. In particular, not all libraries will support all the mechanisms (algorithms) defined in this interface (since not all tokens are expected to support all the mechanisms), and libraries will likely support only a subset of all the kinds of cryptographic devices that are available. (The more kinds, the better, of course, and it is anticipated that libraries will be developed supporting multiple kinds of token, rather than just those from a single vendor.) It is expected that as applications are developed that interface to Cryptoki, standard library and token "profiles" will emerge.
Logical view of a token
Cryptoki's logical view of a token is a device that stores objects and can perform cryptographic functions. Cryptoki defines three classes of object: Data, Certificates, and Keys. A data object is defined by an application. A certificate object stores a public-key certificate. A key object stores a cryptographic key. The key may be a public key, a private key, or a secret key; each of these types of keys has subtypes for use in specific mechanisms. This view is illustrated in the following figure:
Objects are also classified according to their lifetime and visibility. "Token objects" are visible to all applications connected to the token, and remain in the token even after the "sessions" (connections between an application and the token) are closed and the token is removed from its slot. "Session objects" are more temporary: whenever a session is closed by any means, all session objects created by that session are automatically destroyed.
Further classification defines access requirements. "Public objects" are visible to all applications that have a session with the token. "Private objects" are visible to an application only after a user has been authenticated to the token by a PIN or some other token-dependent method (for example, a biometric device).
A token can create and destroy objects, manipulate them, and search for them. It can also perform cryptographic functions with objects. A token may have an internal random number generator. It is possible for the token to perform cryptographic operations in parallel with the application, assuming the underlying device has its own processor.
It is important to distinguish between the logical view of a token and the actual implementation, because not all cryptographic devices will have this concept of "objects," or be able to perform every kind of cryptographic function. Many devices will simply have fixed storage places for keys of a fixed algorithm, and be able to do a limited set of operations. Cryptoki's role is to translate this into the logical view, mapping attributes to fixed storage elements and so on. Not all Cryptoki libraries and tokens need to support every object type. It is expected that standard "profiles" will be developed, specifying sets of algorithms to be supported.
"Attributes" are characteristics that distinguish an instance of an object. In Cryptoki, there are general attributes, such as whether the object is private or public. There are also attributes particular to a particular type of object, such as a modulus or exponent for RSA keys.
Users
This version of Cryptoki recognizes two token user types. One type is a Security Officer (SO). The other type is the normal user. Only the normal user is allowed access to private objects on the token, and that access is granted only after the normal user has been authenticated. Some tokens may also require that a user be authenticated before any cryptographic function can be performed on the token, whether or not it involves private objects. The role of the SO is to initialize a token and to set the normal user's PIN (or otherwise define how the normal user may be authenticated), and possibly manipulate some public objects. The normal user cannot log in until the SO has set the normal user's PIN.
Other than the support for two types of user, Cryptoki does not address the relationship between the SO and a community of users. In particular, the SO and the normal user may be the same person or may be different, but such matters are outside the scope of this standard.
With respect to PINs that are entered through an application, Cryptoki assumes only that they are variable-length strings of characters from the set in Table 4 -3. Any translation to the device's requirements is left to the Cryptoki library. The following items are beyond the scope of Cryptoki:
Cryptoki requires that an application open one or more sessions with a token before the application has access to the token's objects and functions. A session provides a logical connection between the application and the token. A session can be a read/write (R/W) session or a read-only (R/O) session. Read/write and read-only refer to the access to token objects, not to session objects. In both session types, an application can create, read, write and destroy session objects, and read token objects. However, only in a read/write session can an application create, modify, and destroy token objects.
All processes or threads of a given application have access to exactly the same sessions and the same session objects. If several applications are running concurrently, it may or may not be the case that they all have access to the same sessions and the same session objects; this is implementation-dependent. Exactly what constitutes an "application" is also implementation-dependent: in some environments, it might be appropriate to consider an application to be a single process; in other environments, that might not be appropriate.
After a session is opened, the application has access to the token's public objects. To gain access to the token's private objects, the normal user must log in and be authenticated.
When a session is closed, any session objects which were created in that session are destroyed. This holds even for session objects which are "being used" by other sessions.
Cryptoki supports multiple sessions on multiple tokens. An application may have one or more sessions with one or more tokens. In general, a token may have multiple sessions with one or more applications. A particular token may allow only one session, or only one read/write session, at any given time, however.
An open session can be in one of several states. The session state determines allowable access to objects and functions that can be performed on them. The session states are described in Section and SECTION_ "Section ."
Read-only session states
A read-only session can be in one of two states, as illustrated in the following figure. When the session is initially opened, it is in either the "R/O Public Session" state (if there are no previously open sessions that are logged in) or the "R/O User Functions" state (if there is already an open session that is logged in). Note that read-only SO sessions do not exist.
The following table describes the session states:
Table 5-1, Read-Only Session States
State | Description |
R/O Public Session | The application has opened a read-only session. The application has read-only access to public token objects and read/write access to public session objects. |
R/O User Functions | The normal user has been authenticated to the token. The application has read-only access to all token objects (public or private) and read/write access to all session objects (public or private). |
Read/write session states
A read/write session can be in one of three states, as illustrated in the following figure. When the session is opened, it is in either the "R/W Public Session" state (if there are no previously open sessions that are logged in), the "R/W User Functions" state (if there is already an open session that the normal user is logged into), or the "R/W SO Functions" state (if there is already an open session that the SO is logged into).
The following table describes the session states:
Table 5-2, Read/Write Session States
State | Description |
R/W Public Session | The application has opened a read/write session. The application has read/write access to all public objects. |
R/W SO Functions | The Security Officer has been authenticated to the token. The application has read/write access only to public objects on the token, not to private objects. The SO can set the normal user's PIN. |
R/W User Functions | The normal user has been authenticated to the token. The application has read/write access to all objects. |
Permitted object accesses by sessions
The following table summarizes the kind of access each type of session has to each type of object. A given type of session has either read-only access, read/write access, or no access whatsoever to a given type of object.
Note that creating or deleting an object requires read/write access to it, e.g., a "R/O User Functions" session cannot create a token object.
Table 5-3, Access to Different Types Objects by Different Types of Sessions
| |||||
Type of object | |||||
Public session object | |||||
Private session object | |||||
Public token object | |||||
Private token object |
Session events
Session events cause the session state to change. The following table describes the events:
Event | Occurs when... |
Log In SO | the SO is authenticated to the token. |
Log In User | the normal user is authenticated to the token. |
Log Out | the application logs out the current user. |
Close Session | the application closes the session or an application closes all sessions. |
Device Removed | the device underlying the token has been removed from its slot. |
When the device is removed, all sessions are automatically logged out. Furthermore, all sessions with the device are closed (this latter behavior is new for v2.0 of Cryptoki)"an application cannot have a session with a token which is not present. In actuality, Cryptoki may not be constantly monitoring whether or not the token is present, and so the token's absence may not be noticed until a Cryptoki function is executed. If the token is re-inserted into the slot before that, Cryptoki may never know that it was missing.
Also new to Cryptoki v2.0 is the fact that all sessions that an application has with a token must have the same login/logout status (i.e., for a given application and token, one of the following holds: all sessions are public sessions; all sessions are SO sessions; or all sessions are user sessions). When an application's session logs in to a token, all of that application's sessions with that token become logged in, and when an application's session logs out of a token, all of that application's sessions with that token become logged out. Similarly, for example, if an application already has a R/O user session open with a token, and then opens a R/W session with that token, the R/W session is automatically logged in.
This implies that a given application may not simultaneously have SO sessions and user sessions open with a given token. It also implies that if an application has a R/W SO session with a token, then it may not open a R/O session with that token, since R/O SO sessions do not exist. For the same reason, if an application has a R/O session open, then it may not log any other session into the token as the SO.
The above restrictions on the login/logout status of a single application's sessions may also hold for sessions opened by different application. For example, it may be impossible for one application to have a R/O user session open with a token at the same time that another application has a R/W SO session open with the same token. Whether or not this is the case is implementation-dependent (see Section and Section for more information).
Session handles and object handles
A session handle is a Cryptoki-assigned value that identifies a session. It is akin to a file handle, and is specified to functions to indicate which session the function should act on. However, a session handle differs from a file handle in that all threads or processes of an application have equal access to all session handles. That is, anything that can be accomplished with a given file handle by one thread or process can also be accomplished with that file handle by any other thread or process belonging to the same application.
Cryptoki also has object handles, which are identifiers used to manipulate objects. Object handles are similar to session handles: all threads or processes of a given application have equal access to objects through object handles. The only exception to this is that R/O sessions only have read-only access to token objects, whereas R/W sessions have read/write access to token objects.
Valid session handles and object handles in Cryptoki always have nonzero values.
Capabilities of sessions
Very roughly speaking, there are three broad types of operations an open session can perform: administrative operations (such as logging in); object management operations (such as destroying an object on the token); and cryptographic operations (such as computing a message digest). In general, a single session can perform only one operation at a time. This is the reason that it may be desirable for a single application to open multiple sessions with a single token. For efficiency's sake, however, a single session can perform the following pairs of operation types simultaneously: message digesting and encryption; decryption and message digesting; signature or MACing and encryption; and decryption and verifying signatures or MACs. Details on performing simultaneous cryptographic operations in one session will be provided in Section .
Public Cryptoki libraries and private Cryptoki libraries
Cryptoki v2.0 implementations come in two essentially different varieties: "public Cryptoki libraries", in which all applications using a token have access to the same sessions and session objects (this was the only type of Cryptoki library in the Cryptoki v1.0 document), and "private Cryptoki libraries", in which each application has its own private set of sessions and session objects, which no other application can access.
Example of use of sessions
We give here a detailed and lengthy example of how applications can make use of sessions in a private Cryptoki library. Afterwards, we indicate how things would differ if we were making use of a public Cryptoki library, instead. We caution that our example is decidedly not meant to indicate how multiple applications should use Cryptoki simultaneously; rather, it is meant to clarify what uses of Cryptoki's sessions and objects and handles are permissible. In other words, instead of demonstrating good technique here, we demonstrate "pushing the envelope".
For our example, we suppose that two applications, A and B, are using a private Cryptoki library to access a single token. Each application has two processes running: A has processes A1 and A2, and B has processes B1 and B2.
Furthermore, since public Cryptoki libraries have no notion of which application "owns" a Cryptoki session, all sessions with a given token must have the same login/logout status. Because of this, if one application logs out one of its sessions, all sessions of all applications are logged out as well. It is therefore recommended that applications only make a C_Logout call under exceptional circumstances. Instead, when an application finishes using a token, it should close all "its" sessions (i.e., all the sessions that it was using) one at a time, and then call C_Finalize. Similarly, if an application using a public Cryptoki library calls C_CloseAllSessions, all session of all applications will be closed, and so an application should not normally execute such a call.
Applications should in general not intentionally attempt to share sessions or session objects with one another, even when they are using a public Cryptoki library (an application may not even know what type of Cryptoki library it is using, of course).
Function overview
The Cryptoki API consists of a number of functions, spanning slot and token management and object management, as well as cryptographic functions. These functions are presented in the following table:
Table 5-5, Summary of Cryptoki Functions
Category | Function | Description |
General | C_Initialize | initializes Cryptoki |
purpose functions | C_Finalize | clean up miscellaneous Cryptoki-associated resources |
C_GetInfo | obtains general information about Cryptoki | |
C_GetFunctionList | obtains entry points of Cryptoki library functions | |
Slot and token | C_GetSlotList | obtains a list of slots in the system |
management | C_GetSlotInfo | obtains information about a particular slot |
functions | C_GetTokenInfo | obtains information about a particular token |
C_GetMechanismList | obtains a list of mechanisms supported by a token | |
C_GetMechanismInfo | obtains information about a particular mechanism | |
C_InitToken | initializes a token | |
C_InitPIN | initializes the normal user's PIN | |
C_SetPIN | modifies the PIN of the current user | |
Session management functions | C_OpenSession | opens a connection between an application and a particular token or sets up an application callback for token insertion |
C_CloseSession | closes a session | |
C_CloseAllSessions | closes all sessions with a token | |
C_GetSessionInfo | obtains information about the session | |
C_GetOperationState | obtains the cryptographic operations state of a session | |
C_SetOperationState | sets the cryptographic operations state of a session | |
C_Login | logs into a token | |
C_Logout | logs out from a token | |
Object | C_CreateObject | creates an object |
management | C_CopyObject | creates a copy of an object |
functions | C_DestroyObject | destroys an object |
C_GetObjectSize | obtains the size of an object in bytes | |
C_GetAttributeValue | obtains an attribute value of an object | |
C_SetAttributeValue | modifies an attribute value of an object | |
C_FindObjectsInit | initializes an object search operation | |
C_FindObjects | continues an object search operation | |
C_FindObjectsFinal | finishes an object search operation | |
Encryption | C_EncryptInit | initializes an encryption operation |
functions | C_Encrypt | encrypts single-part data |
C_EncryptUpdate | continues a multiple-part encryption operation | |
C_EncryptFinal | finishes a multiple-part encryption operation | |
Decryption | C_DecryptInit | initializes a decryption operation |
functions | C_Decrypt | decrypts single-part encrypted data |
C_DecryptUpdate | continues a multiple-part decryption operation | |
C_DecryptFinal | finishes a multiple-part decryption operation | |
Message | C_DigestInit | initializes a message-digesting operation |
digesting | C_Digest | digests single-part data |
C_DigestUpdate | continues a multiple-part digesting operation | |
C_DigestKey | digests a key | |
C_DigestFinal | finishes a multiple-part digesting operation | |
Signing | C_SignInit | initializes a signature operation |
and MACing | C_Sign | signs single-part data |
functions | C_SignUpdate | continues a multiple-part signature operation |
C_SignFinal | finishes a multiple-part signature operation | |
C_SignRecoverInit | initializes a signature operation, where the data can be recovered from the signature | |
C_SignRecover | signs single-part data, where the data can be recovered from the signature | |
Functions for verifying | C_VerifyInit | initializes a verification operation |
signatures | C_Verify | verifies a signature on single-part data |
and MACs | C_VerifyUpdate | continues a multiple-part verification operation |
C_VerifyFinal | finishes a multiple-part verification operation | |
C_VerifyRecoverInit | initializes a verification operation where the data is recovered from the signature | |
C_VerifyRecover | verifies a signature on single-part data, where the data is recovered from the signature | |
Dual-purpose cryptographic | C_DigestEncryptUpdate | continues simutaneous multi-part digesting and encryption operations |
functions | C_DecryptDigestUpdate | continues simultaneous multi-part decryption and digesting operations |
C_SignEncryptUpdate | continues simultaneous multi-part signature and encryption operations | |
C_DecryptVerifyUpdate | continues simultaneous multi-part decryption and verification operations | |
Key | C_GenerateKey | generates a secret key |
management | C_GenerateKeyPair | generates a public-key/private-key pair |
functions | C_WrapKey | wraps (encrypts) a key |
C_UnwrapKey | unwraps (decrypts) a key | |
C_DeriveKey | derives a key from a base key | |
Random number generation | C_SeedRandom | mixes in additional seed material to the random number generator |
functions | C_GenerateRandom | generates random data |
Parallel function management | C_GetFunctionStatus | obtains updated status of a function running in parallel with the application |
functions | C_CancelFunction | cancels a function running in parallel with the application |
Callback function | application-supplied function to process notifications from Cryptoki |
Functions in the "Encryption functions", "Decryption functions", "Message digesting functions", "Signing and MACing functions", "Functionre for verifying signatures and MACs", "Dual-purpose cryptographic functions", "Key management functions", and "Random number generation" categories may run in parallel with the application if the token has the capability and the session is opened in this mode.