Cryptographic Token Interface Standard

PKCS#11


General overview

Portable computing devices such as smart cards, PCMCIA cards, and smart diskettes are ideal tools for implementing public-key cryptography, as they provide a way to store the private-key component of a public-key/private-key pair securely, under the control of a single user. With such a device, a cryptographic application, rather than performing cryptographic operations itself, programs the device to perform the operations, with sensitive information such as private keys never being revealed. As more applications are developed for public-key cryptography, a standard programming interface for these devices becomes increasingly valuable. This standard addresses this need.

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.

v200_figure_1.gif
Figure 5-1, General Model

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:

v200_figure_2.gif
Figure 5-2, Object Hierarchy

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:

Sessions

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.

v200_figure_3.gif
Figure 5-3, Read-Only Session States

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).

v200_figure_4.gif
Figure 5-4, Read/Write Session States

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 session
       
Type of object
R/O Public
R/W Public
R/O User
R/W User
R/W SO
Public session object
R/W
R/W
R/W
R/W
R/W
Private session object    
R/W
R/W
 
Public token object
R/O
R/W
R/O
R/W
R/W
Private token object    
R/O
R/W
 

Session events

Session events cause the session state to change. The following table describes the events:

Table 5-4, Session 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.

  1. A1 and B1 each initialize the Cryptoki library by calling C_Initialize (the specifics of Cryptoki functions will be explained in Section). Note that exactly one call to C_Initialize should be made for each application (as opposed to one call for every process, for example).

  2. A1 opens a R/W session and receives the session handle 7 for the session. Since this is the first session to be opened for A, it is a public session.

  3. A2 opens a R/O session and receives the session handle 4. Since all of A 's existing sessions are public sessions, session 4 is also a public session.

  4. A1 attempts to log the SO in to session 7. The attempt fails, because if session 7 becomes an SO session, then session 4 does, as well, and R/O SO sessions do not exist. A1 receives an error message indicating that the existence of a R/O session has blocked this attempt to log in.

  5. A2 logs the normal user in to session 7. This turns session 7 into a R/W user session, and turns session 4 into a R/O user session. Note that because A1 and A2 belong to the same application, they have equal access to all sessions, and therefore, A2 is able to perform this action.

  6. A2 opens a R/W session and receives the session handle 9. Since all of A 's existing sessions are user sessions, session 9 is also a user session.

  7. A1 closes session 9.

  8. B1 attempts to log out session 4. The attempt fails, because A and B have no access rights to each other's sessions or objects. B1 receives an error message which indicates that there is no such session handle.

  9. B2 attempts to close session 4. The attempt fails in precisely the same way as B1 's attempt to log out session 4 failed.

  10. B1 opens a R/W session and receives the session handle 7. Note that, as far as B is concerned, this is the first occurrence of session handle 7. A 's session 7 and B 's session 7 are completely different sessions.

  11. B1 logs the SO in to [B 's] session 7. This turns B 's session 7 into a R/W SO session, and has no effect on either of A 's sessions.

  12. B2 attempts to open a R/O session. The attempt fails, since B already has an SO session open, and R/O SO sessions do not exist. B1 receives an error message indicating that the existence of an SO session has blocked this attempt to open a R/O session.

  13. A1 uses [A 's] session 7 to create a session object O1 of some sort and receives the object handle 7. Note that a Cryptoki implementation may or may not support separate spaces of handles for sessions and objects.

  14. B1 uses [B 's] session 7 to create a token object O2 of some sort and receives the object handle 7. As with session handles, different applications have no access rights to each other's object handles, and so B 's object handle 7 is entirely different from A 's object handle 7. Of course, since B1 is an SO session, it cannot create private objects, and so O2 must be a public object (if B1 attempted to create a private object, it would fail).

  15. B2 uses [B 's] session 7 to perform some operation to modify the object associated with [B 's] object handle 7. This modifies O2.

  16. A1 uses [A 's] session 4 to perform an object search operation to get a handle for O2. The search returns object handle 1. Note that A 's object handle 1 and B 's object handle 7 now point to the same object.

  17. A1 attempts to use [A 's] session 4 to modify the object associated with [A 's] object handle 1. The attempt fails, because A 's session 4 is a R/O session, and is therefore incapable of modifying O2, which is a token object. A1 receives an error message indicating that the session is a R/O session.

  18. A1 uses [A 's] session 7 to modify the object associated with [A 's] object handle 1. This time, since A 's session 7 is a R/W session, the attempt succeeds in modifying O2.

  19. B1 uses [B 's] session 7 to perform an object search operation to find O1. Since O1 is a session object belonging to A, however, the search does not succeed.

  20. A2 uses [A 's] session 4 to perform some operation to modify the object associated with [A 's] object handle 7. This operation modifies O1.

  21. A2 uses [A 's] session 7 to destroy the object associated with [A 's] object handle 1. This destroys O2.

  22. B1 attempts to perform some operation with the object associated with [B 's] object handle 7. The attempt fails, since there is no longer any such object. B1 receives an error message indicating that its object handle is invalid.

  23. A1 logs out [A 's] session 4. This turns A 's session 4 into a R/O public session, and turns A 's session 7 into a R/W public session.

  24. A1 closes [A 's] session 7. This destroys the session object O1, which was created by A 's session 7.

  25. A2 attempt to use [A 's] session 4 to perform some operation with the object associated with [A 's] object handle 7. The attempt fails, since there is no longer any such object.

  26. A2 executes a call to C_CloseAllSessions. This closes [A 's] session 4. At this point, if A were to open a new session, the session would not be logged in.

  27. B2 closes [B 's] session 7. At this point, if B were to open a new session, the session would not be logged in.

  28. A and B each call C_Finalize to indicate that they are done with the Cryptoki library.

If A and B were using a public Cryptoki library, then all processes using the library would have exactly the same access rights to sessions and objects. In other words, in a public library, there is no distinction made between processes belonging to different applications. Anything that can be done by one application's processes with a given session handle can also be done by another application's processes. For example, with a public library, step 8 above would have succeeded. Also, with a public library, step 10 could not return session handle 7, since session handle 7 was already in use.

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.


RSA Security Inc. Public-Key Cryptography Standards - PKCS#11 - v200