技术中心

■ PKCS #11: Cryptographic Token Interface Standard


This standard specifies an application programming interface (API), called "Cryptoki", to devices which hold cryptographic information and perform cryptographic functions. Cryptoki, short for "cryptographic token interface", follows a simple object-based approach, addressing the goals of technology independence and resource sharing, presenting to applications a common, logical view of the device called a "cryptographic token".

Cryptoki isolates an application from the details of the cryptographic device. The application does not have to change to interface to a different type of device or to run in a different environment; thus, the application is portable. How Cryptoki provides this isolation is beyond the scope of this document, although some conventions for the support of multiple types of device will be addressed here and possibly in a separate document.

A number of cryptographic mechanisms (algorithms) are supported in this version. In addition, new mechanisms can be added later without changing the general interface. It is possible that additional mechanisms will be published from time to time in separate documents; it is also possible for token vendors to define their own mechanisms.


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.

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 1508 and RFC 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 one or more cryptographic devices, on which some or all of the operations are actually performed. A user may or may not be associated with an application.

Figure 1    General Cryptoki Model

General Cryptoki 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 typically "present in the slot" 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 each 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 underlying "device" may be implemented entirely in software (for instance, as a process running on a server)—no special hardware is necessary.

Cryptoki is likely to be implemented as a library supporting the functions in the interface, and applications will be linked to the library. An application may be linked to Cryptoki directly; alternatively, Cryptoki can 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 Windows and OS/2, and can be achieved without too much difficulty in UNIX and DOS systems.

The dynamic approach certainly has advantages as new libraries are made available, but from a security perspective, there are some drawbacks. In particular, if a 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, although code-signing techniques can prevent many of the security risks of dynamic linking. In any case, 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 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:

Figure 2   Object Hierarchy

Object Hierarchy

Objects are also classified according to their lifetime and visibility. "Token objects" are visible to all applications connected to the token that have sufficient permission, and remain on 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. In addition, session objects are only visible to the application which created them.

Further classification defines access requirements. Applications are not required to log into the token to view "public objects"; however, to view "private objects", a user must be 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 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 that are specific 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, by some method outside the scope of this version of Cryptoki, how the normal user may be authenticated), and possibly to 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 . Any translation to the device's requirements is left to the Cryptoki library. The following issues are beyond the scope of Cryptoki:

  • Any padding of PINs.

  • How the PINs are generated (by the user, by the application, or by some other means).

PINs that are supplied by some means other than through an application (e.g., PINs entered via a PINpad on the token) are even more abstract. Cryptoki knows how to wait (if need be) for such a PIN to be supplied and used, and little more.


Applications and their use of Cryptoki

To Cryptoki, an application consists of a single address space and all the threads of control running in it. An application becomes a "Cryptoki application" by calling the Cryptoki function C_Initialize from one of its threads; after this call is made, the application can call other Cryptoki functions. When the application is done using Cryptoki, it calls the Cryptoki function C_Finalize and ceases to be a Cryptoki application.


Applications and processes

In general, on most platforms, the previous paragraph means that an application consists of a single process.
Consider a UNIX process P which becomes a Cryptoki application by calling C_Initialize, and then uses the fork() system call to create a child process C. Since P and C have separate address spaces (or will when one of them performs a write operation, if the operating system follows the copy-on-write paradigm), they are not part of the same application. Therefore, if C needs to use Cryptoki, it needs to perform its own C_Initialize call. Furthermore, if C needs to be logged into the token(s) that it will access via Cryptoki, it needs to log into them even if P already logged in, since P and C are completely separate applications.

In this particular case (when C is the child of a process which is a Cryptoki application), the behavior of Cryptoki is undefined if C tries to use it without its own C_Initialize call. Ideally, such an attempt would return the value CKR_CRYPTOKI_NOT_INITIALIZED; however, because of the way fork() works, insisting on this return value might have a bad impact on the performance of libraries. Therefore, the behavior of Cryptoki in this situation is left undefined. Applications should definitely not attempt to take advantage of any potential "shortcuts" which might (or might not!) be available because of this.

In the scenario specified above, C should actually call C_Initialize whether or not it needs to use Cryptoki; if it has no need to use Cryptoki, it should then call C_Finalize immediately thereafter. This (having the child immediately call C_Initialize and then call C_Finalize if the parent is using Cryptoki) is considered to be good Cryptoki programming practice, since it can prevent the existence of dangling duplicate resources that were created at the time of the fork() call; however, it is not required by Cryptoki.


Applications and threads

Some applications will access a Cryptoki library in a multi-threaded fashion. Cryptoki enables applications to provide information to libraries so that they can give appropriate support for multi-threading. In particular, when an application initializes a Cryptoki library with a call to C_Initialize, it can specify one of four possible multi-threading behaviors for the library:

  1. The application can specify that it will not be accessing the library concurrently from multiple threads, and so the library need not worry about performing any type of locking for the sake of thread-safety.

  2. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must be able to use native operation system synchronization primitives to ensure proper thread-safe behavior.

  3. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must use a set of application-supplied synchronization primitives to ensure proper thread-safe behavior.

  4. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must use either the native operation system synchronization primitives or a set of application-supplied synchronization primitives to ensure proper thread-safe behavior.

The 3rd and 4th types of behavior listed above are appropriate for multi-threaded applications which are not using the native operating system thread model. The application-supplied synchronization primitives consist of four functions for handling mutex (mutual exclusion) objects in the application’s threading model. Mutex objects are simple objects which can be in either of two states at any given time: unlocked or locked. If a call is made by a thread to lock a mutex which is already locked, that thread blocks (waits) until the mutex is unlocked; then it locks it and the call returns. If more than one thread is blocking on a particular mutex, and that mutex becomes unlocked, then exactly one of those threads will get the lock on the mutex and return control to the caller (the other blocking threads will continue to block and wait for their turn).

In addition to providing the above thread-handling information to a Cryptoki library at initialization time, an application can also specify whether or not application threads executing library calls may use native operating system calls to spawn new threads.


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 1    Summary of Cryptoki Functions

Category Function Description
General purpose functions C_Initialize initializes Cryptoki
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 management functions C_GetSlotList obtains a list of slots in the system
C_GetSlotInfo obtains information about a particular slot
C_GetTokenInfo obtains information about a particular token
C_WaitForSlotEvent waits for a slot event (token insertion, removal, etc.) to occur
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 management functions C_CreateObject creates an object
C_CopyObject creates a copy of an object
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 functions C_EncryptInit initializes an encryption operation
C_Encrypt encrypts single-part data
C_EncryptUpdate continues a multiple-part encryption operation
C_EncryptFinal finishes a multiple-part encryption operation
Decryption functions C_DecryptInit initializes a decryption operation
C_Decrypt decrypts single-part encrypted data
C_DecryptUpdate continues a multiple-part decryption operation
C_DecryptFinal finishes a multiple-part decryption operation
Message digesting functions C_DigestInit initializes a message-digesting operation
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 and MACing functions C_SignInit initializes a signature operation
C_Sign signs single-part data
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 signatures and MACs C_VerifyInit initializes a verification operation
C_Verify verifies a signature on single-part data
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 functions C_DigestEncryptUpdate continues simultaneous multiple-part digesting and encryption operations
C_DecryptDigestUpdate continues simultaneous multiple-part decryption and digesting operations
C_SignEncryptUpdate continues simultaneous multiple-part signature and encryption operations
C_DecryptVerifyUpdate continues simultaneous multiple-part decryption and verification operations
Key management functions C_GenerateKey generates a secret key
C_GenerateKeyPair generates a public-key/private-key pair
C_WrapKey wraps (encrypts) a key
C_UnwrapKey unwraps (decrypts) a key
C_DeriveKey derives a key from a base key
Random number eneration functions C_SeedRandom mixes in additional seed material to the random number generator
C_GenerateRandom generates random data
Parallel function anagement functions C_GetFunctionStatus legacy function which always returns CKR_FUNCTION_NOT_PARALLEL
C_CancelFunction legacy function which always returns CKR_FUNCTION_NOT_PARALLEL


Security considerations

As an interface to cryptographic devices, Cryptoki provides a basis for security in a computer or communications system. Two of the particular features of the interface that facilitate such security are the following:

  1. Access to private objects on the token, and possibly to cryptographic functions and/or certificates on the token as well, requires a PIN. Thus, possessing the cryptographic device that implements the token may not be sufficient to use it; the PIN may also be needed.

  2. Additional protection can be given to private keys and secret keys by marking them as "sensitive" or "unextractable". Sensitive keys cannot be revealed in plaintext off the token, and unextractable keys cannot be revealed off the token even when encrypted (though they can still be used as keys).

It is expected that access to private, sensitive, or unextractable objects by means other than Cryptoki (e.g., other programming interfaces, or reverse engineering of the device) would be difficult.

If a device does not have a tamper-proof environment or protected memory in which to store private and sensitive objects, the device may encrypt the objects with a master key which is perhaps derived from the user's PIN. The particular mechanism for protecting private objects is left to the device implementation, however.

Based on these features it should be possible to design applications in such a way that the token can provide adequate security for the objects the applications manage.

Of course, cryptography is only one element of security, and the token is only one component in a system. While the token itself may be secure, one must also consider the security of the operating system by which the application interfaces to it, especially since the PIN may be passed through the operating system. This can make it easy for a rogue application on the operating system to obtain the PIN; it is also possible that other devices monitoring communication lines to the cryptographic device can obtain the PIN. Rogue applications and devices may also change the commands sent to the cryptographic device to obtain services other than what the application requested.

It is important to be sure that the system is secure against such attack. Cryptoki may well play a role here; for instance, a token may be involved in the "booting up" of the system.

We note that none of the attacks just described can compromise keys marked "sensitive," since a key that is sensitive will always remain sensitive. Similarly, a key that is unextractable cannot be modified to be extractable.
An application may also want to be sure that the token is "legitimate" in some sense (for a variety of reasons, including export restrictions and basic security). This is outside the scope of the present standard, but it can be achieved by distributing the token with a built-in, certified public/private-key pair, by which the token can prove its identity. The certificate would be signed by an authority (presumably the one indicating that the token is "legitimate") whose public key is known to the application. The application would verify the certificate and challenge the token to prove its identity by signing a time-varying message with its built-in private key.

Once a normal user has been authenticated to the token, Cryptoki does not restrict which cryptographic operations the user may perform; the user may perform any operation supported by the token. Some tokens may not even require any type of authentication to make use of its cryptographic functions.


© 1994-2004 RSA Security Inc. All rights reserved.


 © 上海天存信息技术有限公司,2002-2007  法律条款    联系我们