Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ex-pkcs11-9.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include "pkcs11.h"
#include "pkcs11p6r.h"
// *** For this example to work Example #1 must be run successfully first. ***
// Copy the following files from example 1 into example 9: PKCS11, PKCS11.sig, pkcs11baseKey.txt,
// so that they don't have to be created for each example. Make sure example 1 has the Thales token
// define, if not change the p6pkcs11.conf file and re-run that example.
//
// Also the Thales HSM token must be defined in the p6pkcs11.conf file. See "Thales HSM Integration"
// in PKCS11 documentation. Thales HSM tokens are initialized via the HSM directly.
// Also see example 8 to see how to find the Thales HSM slot identifiers to be used in the p6pkcs11.conf file
//
// ***
// Example 1 initializes the token with the Security Officer and normal user accounts.
//
//
int main(int argc,char *argv[])
{
CK_SLOT_INFO oneSlot;
CK_ATTRIBUTE keyTemplate[5];
CK_ATTRIBUTE keyTemplate2[10];
CK_BYTE IV[16];
CK_BYTE data[70];
CK_BYTE cipherText[300];
CK_BYTE decryptedData[70];
CK_BYTE buffer[400];
CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
CK_KEY_TYPE keyType = CKK_AES;
CK_UTF8CHAR label[] = "AES secret key 1";
CK_UTF8CHAR label2[] = "An AES secret key object";
CK_MECHANISM cryptoMech = { CKM_AES_CBC, IV, 16 }; // -> defined to have one parameter an IV
CK_SLOT_ID_PTR pSlotList = NULL_PTR;
CK_OBJECT_HANDLE hKey1 = 0;
CK_OBJECT_HANDLE hKey2 = 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 dataLength = 0;
CK_ULONG cipherLength = 0;
CK_ULONG deLength = 0;
CK_ULONG i = 0;
CK_ULONG j = 0;
CK_ULONG m = 0;
CK_ULONG n = 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;
if (CKR_OK != (rv = C_Initialize( &initArgs ))) {
printf( "PKCS11 example9: 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 example9: memory allocation failed" );
return -2;
}
// -> select the Thales token in a slot by its description
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, Thales slot description format used
// -> "F64B-7400-405E" was the module identifier generated by the Thales nShield Connect on initialization
match = strncmp( (const char*)oneSlot.slotDescription, "F64B-7400-405E Rt1 slot 0 ", 64 );
if (0 == match)
{
rv = C_OpenSession( pSlotList[i], flags, NULL, NULL, &hSession );
if (CKR_OK == rv)
{
// -> we created a card set with 2 cards that requires both of the cards
// -> the smart card set is a token to the Thales nShield Connect HSM
// -> for this to work the first card must be in the HSM already before this code is run
CK_ULONG ulCardsRequired = 0;
CK_ULONG ulCardsInSet = 0;
CK_ULONG ulSharesLeft = 0;
CK_ULONG loginCount = 0;
rv = Thales_C_LoginBegin( hSession, CKU_USER, &ulCardsRequired, &ulCardsInSet );
if (CKR_OK == rv)
{
loginCount++;
pUserPin = (CK_UTF8CHAR_PTR)"123456"; // -> was set at the HSM as a smart card passphrase
rv = Thales_C_LoginNext( hSession, CKU_USER, pUserPin, 6, &ulSharesLeft );
// -> ulSharesLeft should be 1 here since in our example our card set only had 2 cards
}
// -> I had to step though the debugger to change the card in time in the HSM for this to work. Maybe have a larger card timeout??
if (CKR_OK == rv)
{
loginCount++;
rv = Thales_C_LoginNext( hSession, CKU_USER, pUserPin, 6, &ulSharesLeft );
// -> ulSharesLeft should be 0 here since in our example our card set only had 2 cards
// -> one LoginNext call per required card in the card set
}
if (CKR_OK == rv)
{
loginCount++;
rv = Thales_C_LoginEnd( hSession, CKU_USER );
if (CKR_OK == rv) loginCount++;
}
if (4 == loginCount)
{
// -> test the case where CKA_CLASS and CKA_KEY_TYPE are assummed from the mechanism, with usage flags set at default values
keyLength = 32;
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 = 16;
keyTemplate[2].type = CKA_VALUE_LEN;
keyTemplate[2].pValue = &keyLength;
keyTemplate[2].ulValueLen = sizeof(CK_ULONG);
if (CKR_OK == (rv = C_GenerateKey( hSession, &oneMech, (CK_ATTRIBUTE_PTR)keyTemplate, 3, &hKey1 )))
{
for ( j=0; j< 16; j++) buffer[j] = j+5;
keyTemplate2[0].type = CKA_CLASS;
keyTemplate2[0].pValue = &objClass;
keyTemplate2[0].ulValueLen = sizeof(CK_OBJECT_CLASS);
keyTemplate2[1].type = CKA_KEY_TYPE;
keyTemplate2[1].pValue = &keyType;
keyTemplate2[1].ulValueLen = sizeof(CK_KEY_TYPE);
keyTemplate2[2].type = CKA_TOKEN;
keyTemplate2[2].pValue = &bTFlag;
keyTemplate2[2].ulValueLen = sizeof(CK_BBOOL);
keyTemplate2[3].type = CKA_LABEL;
keyTemplate2[3].pValue = label2;
keyTemplate2[3].ulValueLen = 24;
keyTemplate2[4].type = CKA_ENCRYPT;
keyTemplate2[4].pValue = &bTFlag;
keyTemplate2[4].ulValueLen = sizeof(CK_BBOOL);
keyTemplate2[5].type = CKA_VALUE;
keyTemplate2[5].pValue = buffer;
keyTemplate2[5].ulValueLen = 16;
// -> encrypt this data using the chosen mechanism
rv = C_CreateObject( hSession, (CK_ATTRIBUTE_PTR)keyTemplate2, 6, &hKey2 );
if (CKR_OK == rv && NULL_PTR != hKey1)
{
for( m=0; m < 16; m++ ) IV[m] = m+5;
if (CKR_OK == (rv = C_EncryptInit( hSession, &cryptoMech, hKey1 )))
{
dataLength = 48;
cipherLength = 0;
for( m=0; m < dataLength; m++ ) data[m] = m+3;
for( n=0; n < 300; n++ ) cipherText[n] = 0;
dataLength = 48;
rv = C_Encrypt( hSession, data, dataLength, NULL_PTR, &cipherLength );
if (CKR_OK != rv && 48 != cipherLength) {
printf( "PKCS11 example9: C_Encrypt 1 CKR_OK and 48 expected, got %ld and %ld", rv, cipherLength );
}
// -> now do the actual encryption
rv = C_Encrypt( hSession, data, dataLength, cipherText, &cipherLength );
if ((CKR_OK != rv && 48 != cipherLength) || 0 == cipherText[0] || 0 == cipherText[1]) {
printf( "PKCS11 example9: C_Encrypt 2 failed CKR_OK and 48, got %ld and %ld", rv, cipherLength );
}
// -> now decrypt the data and show that we get the original data back
if (CKR_OK == (rv = C_DecryptInit( hSession, &cryptoMech, hKey1 )))
{
rv = C_Decrypt( hSession, cipherText, cipherLength, NULL_PTR, &deLength ); // verify length
if (CKR_OK != rv && 48 != deLength) {
printf( "PKCS11 example9: C_Encrypt 1 CKR_OK and 48 expected, got %ld and %ld", rv, deLength );
}
rv = C_Decrypt( hSession, cipherText, cipherLength, decryptedData, &deLength );
for( j=0; j < 48; j++ )
{
if (data[j] != decryptedData[j]) {
printf( "PKCS11 example9: C_Decrypt original data mismatch Thales token, at {%ld} (%c) (%c)", j, data[j], decryptedData[j] );
}
}
}
}
}
}
if (NULL_PTR != hKey1) {
rv = C_DestroyObject( hSession, hKey1 );
}
if (NULL_PTR != hKey2) {
rv = C_DestroyObject( hSession, hKey2 );
}
if (CKR_OK != (rv = C_Logout( hSession ))) {
printf( "PKCS11 example9: 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 example9: slot %ld failed to close an active token session (error:%lx)", pSlotList[i], rv );
}
}
}
}
}
}
}
// [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 example9: failed C_Finalize %lx", rv );
return -3;
}
return 0;
}