Cryptographic Token Interface Standard |
PKCS#11 |
Cryptoki provides the following functions for slot and token management:
CK_RV C_GetSlotList( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount);
C_GetSlotList is used to obtain a list of slots in the system.
tokenPresent | indicates whether the list obtained includes only those slots with a token present (TRUE), or all slots (FALSE); |
pulCount | points to the location that receives the number of slots. |
All slots which C_GetSlotList reports must be able to be queried as valid slots by C_GetSlotInfo. Furthermore, the set of slots accessible through a Cryptoki library is fixed at the time that C_Initialize is called. If an application calls C_Initialize and C_GetSlotList, and then the user hooks up a new hardware device, that device cannot suddenly appear as a new slot if C_GetSlotList is called again. To recognize the new device, C_Initialize needs to be called again (and to be able to call C_Initialize successfully, C_Finalize needs to be called first). Even if C_Initialize is successfully called, it may or may not be the case that the new device will then be successfully recognized. On some platforms, it may be necessary to restart the entire system.
CK_ULONG ulSlotCount, ulSlotWithTokenCount; CK_SLOT_ID_PTR pSlotList, pSlotWithTokenList; CK_RV rv; /* Get list of all slots */ rv = C_GetSlotList(FALSE, NULL_PTR, &ulSlotCount); if (rv == CKR_OK) { pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); rv = C_GetSlotList(FALSE, pSlotList, &ulSlotCount); if (rv == CKR_OK) { /* Now use that list of all slots */ . . . } free(pSlotList); } /* Get list of all slots with a token present */ pSlotWithTokenList = (CK_SLOT_ID_PTR) malloc(0); ulSlotWithTokenCount = 0; while (1) { rv = C_GetSlotList( TRUE, pSlotWithTokenList, ulSlotWithTokenCount); if (rv != CKR_BUFFER_TOO_SMALL) break; pSlotWithTokenList = realloc( pSlotWithTokenList, ulSlotWithTokenList*sizeof(CK_SLOT_ID)); } if (rv == CKR_OK) { /* Now use that list of all slots with a token present */ . . . } free(pSlotWithTokenList);
CK_RV C_GetSlotInfo( CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo);
C_GetSlotInfo obtains information about a particular slot in the system.
slotID | is the ID of the slot; |
pInfo | points to the location that receives the slot information. |
CK_RV C_GetTokenInfo( CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo);
C_GetTokenInfo obtains information about a particular token in the system.
slotID | is the ID of the token's slot; |
pInfo | points to the location that receives the token information. |
CK_ULONG ulCount; CK_SLOT_ID_PTR pSlotList; CK_SLOT_INFO slotInfo; CK_TOKEN_INFO tokenInfo; CK_RV rv; rv = C_GetSlotList(FALSE, NULL_PTR, &ulCount); if ((rv == CKR_OK) && (ulCount > 0)) { pSlotList = (CK_SLOT_ID_PTR) malloc(ulCount*sizeof(CK_SLOT_ID)); rv = C_GetSlotList(FALSE, pSlotList, &ulCount); assert(rv == CKR_OK); /* Get slot information for first slot */ rv = C_GetSlotInfo(pSlotList[0], &slotInfo); assert(rv == CKR_OK); /* Get token information for first slot */ rv = C_GetTokenInfo(pSlotList[0], &tokenInfo); if (rv == CKR_TOKEN_NOT_PRESENT) { . . . } . . . free(pSlotList); }
CK_RV C_WaitForSlotEvent( CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved);
C_WaitForSlotEvent waits for a slot event, such as token insertion or token removal, to occur.
flags | determines whether or not the C_WaitForSlotEvent call blocks (i.e., waits for a slot event to occur); |
pSlot | points to a location which will receive the ID of the slot that the event occurred in. |
pReserved | is reserved for future versions: for this version of Cryptoki, it should be NULL_PTR. |
#define CKF_DONT_BLOCK 1
Internally, each Cryptoki application has a flag for each slot which is used to track whether or not any unrecognized events involving that slot have occurred. When an application initially calls C_Initialize, every slot's event flag is cleared. Whenever a slot event occurs, the flag corresponding to the slot in which the event occurred is set.
If C_WaitForSlotEvent is called with the CKF_DONT_BLOCK flag set in the flags argument, and some slot's event flag is set, then that event flag is cleared, and the call returns with the ID of that slot in the location pointed to by pSlot. If more than one slot's event flag is set at the time of the call, one such slot is chosen by the library to have its event flag cleared and to have its slot ID returned.
If C_WaitForSlotEvent is called with the CKF_DONT_BLOCK flag set in the flags argument, and no slot's event flag is set, then the call returns with the value CKR_NO_EVENT. In this case, the contents of the location pointed to by pSlot when C_WaitForSlotEvent are undefined.
If C_WaitForSlotEvent is called with the CKF_DONT_BLOCK flag clear in the flags argument, then the call behaves as above, except that it will block. That is, if no slot's event flag is set at the time of the call, C_WaitForSlotEvent will wait until some slot's event flag becomes set. If a thread of an application has a C_WaitForSlotEvent call blocking when another thread of that application calls C_Finalize, the C_WaitForSlotEvent call returns with the value CKR_CRYPTOKI_NOT_INITIALIZED.
Although the parameters supplied to C_Initialize can in general allow for safe multi-threaded access to a Cryptoki library, C_WaitForSlotEvent is exceptional in that the behavior of Cryptoki is undefined if multiple threads of a single application make simultaneous calls to C_WaitForSlotEvent.
CK_FLAGS flags = 0; CK_SLOT_ID slotID; CK_SLOT_INFO slotInfo; . . . /* Block and wait for a slot event */ rv = C_WaitForSlotEvent(flags, &slotID, NULL_PTR); assert(rv == CKR_OK); /* See what's up with that slot */ rv = C_GetSlotInfo(slotID, &slotInfo); assert(rv == CKR_OK); . . .
CK_RV C_GetMechanismList( CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount);
C_GetMechanismList is used to obtain a list of mechanism types supported by a token.
SlotID | is the ID of the token's slot; |
pulCount | points to the location that receives the number of mechanisms. |
CK_SLOT_ID slotID; CK_ULONG ulCount; CK_MECHANISM_TYPE_PTR pMechanismList; CK_RV rv; . . . rv = C_GetMechanismList(slotID, NULL_PTR, &ulCount); if ((rv == CKR_OK) && (ulCount > 0)) { pMechanismList = (CK_MECHANISM_TYPE_PTR) malloc(ulCount*sizeof(CK_MECHANISM_TYPE)); rv = C_GetMechanismList(slotID, pMechanismList, &ulCount); if (rv == CKR_OK) { . . . } free(pMechanismList); }
CK_RV C_GetMechanismInfo( CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo);
C_GetMechanismInfo obtains information about a particular mechanism possibly supported by a token.
slotID | is the ID of the token's slot; |
type | is the type of mechanism; |
pInfo | points to the location that receives the mechanism information. |
CK_SLOT_ID slotID; CK_MECHANISM_INFO info; CK_RV rv; . . . /* Get information about the CKM_MD2 mechanism for this token */ rv = C_GetMechanismInfo(slotID, CKM_MD2, &info); if (rv == CKR_OK) { if (info.flags & CKF_DIGEST) { . . . } }
CK_RV C_InitToken( CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel);
C_InitToken initializes a token.
slotID | is the ID of the token's slot; |
pPin | points to the SO's initial PIN (which need not be null-terminated); |
ulPinLen | is the length in bytes of the PIN; |
pLabel | points to the 32-byte label of the token (which must be padded with blank characters, and which must not be null-terminated). |
When a token is initialized, all objects that can be destroyed are destroyed (i.e., all except for "indestructible" objects such as keys built into the token). Also, access by the normal user is disabled until the SO sets the normal user's PIN. Depending on the token, some "default" objects may be created, and attributes of some objects may be set to default values.
If the token has a "protected authentication path", as indicated by the CKF_PROTECTED_AUTHENTICATION_PATH flag in its CK_TOKEN_INFO being set, then that means that there is some way for a user to be authenticated to the token without having the application send a PIN through the Cryptoki library. One such possibility is that the user enters a PIN on a PINpad on the token itself, or on the slot device. To initialize a token with such a protected authentication path, the pPin parameter to C_InitToken should be NULL_PTR. During the execution of C_InitToken, the SO's PIN will be entered through the protected authentication path.
If the token has a protected authentication path other than a PINpad, then it is token-dependent whether or not C_InitToken can be used to initialize the token.
A token cannot be initialized if Cryptoki detects that any application has an open session with it; when a call to C_InitToken is made under such circumstances, the call fails with error CKR_SESSION_EXISTS. Unfortunately, it may happen when C_InitToken is called that some other application does have an open session with the token, but Cryptoki cannot detect this, because it cannot detect anything about other applications using the token. If this is the case, then the consequences of the C_InitToken call are undefined.
The C_InitToken function may not be sufficient to properly initialize complex tokens. In these situations, an initialization mechanism outside the scope of Cryptoki must be employed. The definition of "complex token" is product specific.
CK_SLOT_ID slotID; CK_CHAR_PTR pin = "MyPIN"; CK_UTF8CHAR label[32]; CK_RV rv; . . . memset(label, ' ', sizeof(label)); memcpy(label, "My first token", strlen("My first token")); rv = C_InitToken(slotID, pin, strlen(pin), label); if (rv == CKR_OK) { . . . }
CK_RV C_InitPIN( CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen);
C_InitPIN initializes the normal user's PIN.
hSession | is the session's handle; |
pPin | points to the normal user's PIN; ulPinLen is the length in bytes of the PIN. |
If the token has a "protected authentication path", as indicated by the CKF_PROTECTED_AUTHENTICATION_PATH flag in its CK_TOKEN_INFO being set, then that means that there is some way for a user to be authenticated to the token without having the application send a PIN through the Cryptoki library. One such possibility is that the user enters a PIN on a PINpad on the token itself, or on the slot device. To initialize the normal user's PIN on a token with such a protected authentication path, the pPin parameter to C_InitPIN should be NULL_PTR. During the execution of C_InitPIN, the SO will enter the new PIN through the protected authentication path.
If the token has a protected authentication path other than a PINpad, then it is token-dependent whether or not C_InitPIN can be used to initialize the normal user's token access.
CK_SESSION_HANDLE hSession; CK_CHAR newPin[]= {"NewPIN"}; CK_RV rv; rv = C_InitPIN(hSession, newPin, sizeof(newPin)); if (rv == CKR_OK) { . . . }
CK_RV C_SetPIN( CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen);
C_SetPIN modifies the PIN of the user that is currently logged in.
hSession | is the session's handle; |
pOldPin | points to the old PIN; |
ulOldLen | is the length in bytes of the old PIN; pNewPin points to the new PIN; |
ulNewLen | is the length in bytes of the new PIN. |
If the token has a "protected authentication path", as indicated by the CKF_PROTECTED_AUTHENTICATION_PATH flag in its CK_TOKEN_INFO being set, then that means that there is some way for a user to be authenticated to the token without having the application send a PIN through the Cryptoki library. One such possibility is that the user enters a PIN on a PINpad on the token itself, or on the slot device. To modify the current user's PIN on a token with such a protected authentication path, the pOldPin and pNewPin parameters to C_SetPIN should be NULL_PTR. During the execution of C_SetPIN, the current user will enter the old PIN and the new PIN through the protected authentication path. It is not specified how the PINpad should be used to enter two PINs; this varies.
If the token has a protected authentication path other than a PINpad, then it is token-dependent whether or not C_SetPIN can be used to modify the current user's PIN.
CK_SESSION_HANDLE hSession; CK_CHAR oldPin[] = {"OldPIN"}; CK_CHAR newPin[] = {"NewPIN"}; CK_RV rv; rv = C_SetPIN( hSession, oldPin, sizeof(oldPin), newPin, sizeof(newPin)); if (rv == CKR_OK) { . . . }