Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ex-pkcs11-5.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include "pkcs11.h"
#include "pkcs11p6r.h" // optional, only needed if using P6R vendor extensions
// *** For this example to work Example #1 must be run successfully first. ***
// Copy the following files from example 1 into example 5: PKCS11, PKCS11.sig, pkcs11baseKey.txt,
// so that they don't have to be created for each example.
// ***
// Example 1 initializes the token with the Security Officer and normal user accounts.
//
//
int main(int argc,char *argv[])
{
CK_SLOT_INFO oneSlot;
CK_MECHANISM oneMech;
CK_ATTRIBUTE keyTemplate[10];
CK_UTF8CHAR label[50];
CK_SLOT_ID_PTR pSlotList = NULL_PTR;
CK_OBJECT_HANDLE hKey = 0;
CK_SESSION_HANDLE hSession = 0;
CK_BBOOL bTFlag = CK_TRUE;
CK_FLAGS flags = 0;
CK_ULONG ulSlotCount = 0;
CK_ULONG keyLength = 0;
CK_ULONG i = 0;
CK_RV rv = 0;
int match = 0;
// [A] We must first initialize the entire PKCS 11 library
memset( &initArgs, 0, sizeof( CK_C_INITIALIZE_ARGS ));
initArgs.flags = CKF_OS_LOCKING_OK; // -> let PKCS11 use its own locking
if (CKR_OK != (rv = C_Initialize( &initArgs ))) {
printf( "PKCS11 example5: failed C_Initialize (error:%lx)", rv );
return -1;
}
// [B] What slots are defined (see p6pkcs11.conf file)
if (CKR_OK == (rv = C_GetSlotList( CK_FALSE, NULL_PTR, &ulSlotCount )))
{
if (NULL_PTR == (pSlotList = (CK_SLOT_ID_PTR) malloc( ulSlotCount * sizeof( CK_SLOT_ID )))) {
printf( "PKCS11 example5: memory allocation failed" );
return -2;
}
// -> (re-)initialize a particular slot by its description (or all defined slots if desired)
if (CKR_OK == (rv = C_GetSlotList( CK_FALSE, pSlotList, &ulSlotCount )))
{
for( i=0; i < ulSlotCount; i++ )
{
if (CKR_OK == (rv = C_GetSlotInfo( pSlotList[i], (CK_SLOT_INFO_PTR)&oneSlot )))
{
// -> slot description field is a fixed 64 characters long and is not NULL terminated
match = strncmp( (const char*)oneSlot.slotDescription, "KMIP SLOT1 ", 64 );
if (0 == match)
{
// The normal user must login before he can save a key onto the token
// -> most things on a token require that we first create a session to the token in the slot
if (CKR_OK != (rv = C_OpenSession( pSlotList[i], flags, NULL, NULL, &hSession ))) {
printf( "PKCS11 example5: slot %ld failed to open a session (error:%lx)", pSlotList[i], rv );
break;
}
// Logging into the token in slot pSlotList[i] as a normal user
pUserPin = (CK_UTF8CHAR_PTR)"roggerrabbit";
if (CKR_OK == (rv = C_Login( hSession, CKU_USER, pUserPin, 12 )))
{
oneMech.pParameter = NULL_PTR;
oneMech.ulParameterLen = 0;
keyLength = 16; // in bytes
strncpy( (char*)label, "AES key Generated by the token", 30 );
keyTemplate[0].type = CKA_TOKEN;
keyTemplate[0].pValue = &bTFlag;
keyTemplate[0].ulValueLen = sizeof(CK_BBOOL);
keyTemplate[1].type = CKA_LABEL;
keyTemplate[1].pValue = label;
keyTemplate[1].ulValueLen = 30;
keyTemplate[2].type = CKA_VALUE_LEN;
keyTemplate[2].pValue = &keyLength;
keyTemplate[2].ulValueLen = sizeof(CK_ULONG);
keyTemplate[3].type = CKA_ENCRYPT;
keyTemplate[3].pValue = &bTFlag;
keyTemplate[3].ulValueLen = sizeof(CK_BBOOL);
keyTemplate[4].type = CKA_DECRYPT;
keyTemplate[4].pValue = &bTFlag;
keyTemplate[4].ulValueLen = sizeof(CK_BBOOL);
// ** For Thales nShield Connect in strict FIPS mode CKA_SENSTIVE must be set to CK_TRUE **
// Also, CKA_PRIVATE must be set to CK_TRUE, which is the default setting for this attribute set in our C_GenerateKey() method
//
// keyTemplate[5].type = CKA_SENSITIVE;
// keyTemplate[5].pValue = &bTFlag;
// keyTemplate[5].ulValueLen = sizeof(CK_BBOOL);
//
if ( CKR_OK != (rv = C_GenerateKey( hSession, &oneMech, (CK_ATTRIBUTE_PTR)keyTemplate, 5, &hKey )))
{
printf( "PKCS11 example5: slot %ld failed to generate key on token (error:%lx)", pSlotList[i], rv );
}
else
{ // -> encrypt test data using the chosen mechanism
CK_BYTE IV[16];
CK_BYTE data[70];
CK_BYTE decryptedData[70];
CK_ULONG decodedLength = 0;
CK_ULONG dataLength = 48;
CK_BYTE_PTR pCipherText = NULL_PTR;
CK_ULONG cipherLength = 0;
CK_ULONG m = 0;
CK_ULONG n = 0;
CK_ULONG q = 0;
CK_MECHANISM cryptoMech = { CKM_AES_CBC, IV, 16 }; // -> mechanisnm defined to have one parameter an IV
// -> initialize the Encrypt function based on the chosen mechanism (it needs an IV)
for( m=0; m < 16; m++ ) IV[m] = (CK_BYTE)m+5; // -> IV has to be the length of the AES block size
rv = C_EncryptInit( hSession, &cryptoMech, hKey );
// -> generate fake data to encrypt
for( m=0; m < 48; m++ ) data[m] = (CK_BYTE)m+3;
// -> first get the size of the buffer we need
dataLength = 48; // -> has to be a multiple of the block size, chosen mechanism does not do padding
rv = C_Encrypt( hSession, data, dataLength, NULL_PTR, &cipherLength );
pCipherText = (CK_BYTE_PTR) malloc( cipherLength );
for( n=0; n < cipherLength; n++ ) pCipherText[n] = 0;
// -> now encrypt the data
if (CKR_OK == (rv = C_Encrypt( hSession, data, dataLength, pCipherText, &cipherLength )))
{
// -> now show that encryption works by decrypting it to get the original data
if (CKR_OK == (rv = C_DecryptInit( hSession, &cryptoMech, hKey )))
{
decodedLength = 70;
rv = C_Decrypt( hSession, pCipherText, cipherLength, decryptedData, &decodedLength );
for( q=0; q < 48 && CKR_OK == rv; q++ )
{
if (data[q] != decryptedData[q]) {
printf("\n encryption process failed at offset %ld\n", q );
break;
}
}
}
}
free( pCipherText );
}
if (CKR_OK != (rv = C_Logout( hSession ))) {
printf( "PKCS11 example5: slot %ld failed to logout of token (error:%lx)", pSlotList[i], rv );
}
}
// Now we are done we have to close the session to the token
if (CKR_OK != (rv = C_CloseSession( hSession ))) {
printf( "PKCS11 example5: slot %ld failed to close an active token session (error:%lx)", pSlotList[i], rv );
break;
}
}
}
}
}
}
// [C] At the end we must tell the library we are done
if (NULL_PTR != pSlotList) free( pSlotList );
if (CKR_OK != (rv = C_Finalize( NULL_PTR ))) {
printf( "PKCS11 example5: failed C_Finalize %lx", rv );
return -3;
}
return 0;
}