/*
* The Initial Developer of the Original Code is International
* Business Machines Corporation. Portions created by IBM
* Corporation are Copyright (C) 2005 International Business
* Machines Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Common Public License as published by
* IBM Corporation; either version 1 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Common Public License for more details.
*
* You should have received a copy of the Common Public License
* along with this program; if not, a copy can be viewed at
* http://www.opensource.org/licenses/cpl1.0.php.
*/
#include <tpm_pkcs11.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <opencryptoki/pkcs11.h>
/*
* Global variables
*/
char * g_pszSoLib = TPM_OPENCRYPTOKI_SO;
void * g_pSoLib = NULL; // Handle of libopencryptoki library
CK_FUNCTION_LIST_PTR g_pFcnList = NULL; // Function List
BOOL g_bInit = FALSE; // Indicates if C_Initialize has been called
BOOL g_bTokenOpen = FALSE; // Indicates if the token has been opened
CK_SLOT_ID g_tSlotId; // Slot ID of the TPM token
CK_TOKEN_INFO g_tToken; // TPM token information
void
pkcsDebug( const char *a_pszName,
CK_RV a_tResult ) {
logDebug( _("%s success\n"), a_pszName );
}
void
pkcsError( const char *a_pszName,
CK_RV a_tResult ) {
logError( _("%s failed: 0x%08x (%ld)\n"), a_pszName, a_tResult, a_tResult );
}
void
pkcsResult( const char *a_pszName,
CK_RV a_tResult ) {
if ( a_tResult == CKR_OK )
pkcsDebug( a_pszName, a_tResult );
else
pkcsError( a_pszName, a_tResult );
}
void
pkcsResultException( const char *a_pszName,
CK_RV a_tResult,
CK_RV a_tExcept ) {
if ( ( a_tResult == CKR_OK ) || ( a_tResult == a_tExcept ) )
pkcsDebug( a_pszName, a_tResult );
else
pkcsError( a_pszName, a_tResult );
}
/*
* pkcsSlotInfo
* Display some information about the slot.
*/
void
pkcsSlotInfo(CK_SLOT_INFO *a_ptSlotInfo ) {
char szSlotDesc[ sizeof( a_ptSlotInfo->slotDescription ) + 1 ];
char szSlotMfr[ sizeof( a_ptSlotInfo->manufacturerID ) + 1 ];
memset( szSlotDesc, 0, sizeof( szSlotDesc ) );
memset( szSlotMfr, 0, sizeof( szSlotMfr ) );
strncpy( szSlotDesc, (char *)a_ptSlotInfo->slotDescription,
sizeof( a_ptSlotInfo->slotDescription ) );
strncpy( szSlotMfr, (char *)a_ptSlotInfo->manufacturerID,
sizeof( a_ptSlotInfo->manufacturerID ) );
logDebug( _("Slot description: %s\n"), szSlotDesc );
logDebug( _("Slot manufacturer: %s\n"), szSlotMfr );
if ( a_ptSlotInfo->flags & CKF_TOKEN_PRESENT )
logDebug( _("Token is present\n") );
else
logDebug( _("Token is not present\n") );
}
/*
* pkcsTokenInfo
* Display some information about the token.
*/
void
pkcsTokenInfo(CK_TOKEN_INFO *a_ptTokenInfo ) {
char szTokenLabel[ sizeof( a_ptTokenInfo->label ) + 1 ];
char szTokenMfr[ sizeof( a_ptTokenInfo->manufacturerID ) + 1 ];
char szTokenModel[ sizeof( a_ptTokenInfo->model ) + 1 ];
memset( szTokenLabel, 0, sizeof( szTokenLabel ) );
memset( szTokenMfr, 0, sizeof( szTokenMfr ) );
memset( szTokenModel, 0, sizeof( szTokenModel ) );
strncpy( szTokenLabel, (char *)a_ptTokenInfo->label,
sizeof( a_ptTokenInfo->label ) );
strncpy( szTokenMfr, (char *)a_ptTokenInfo->manufacturerID,
sizeof( a_ptTokenInfo->manufacturerID ) );
strncpy( szTokenModel, (char *)a_ptTokenInfo->model,
sizeof( a_ptTokenInfo->model ) );
logDebug( _("Token Label: %s\n"), szTokenLabel );
logDebug( _("Token manufacturer: %s\n"), szTokenMfr );
logDebug( _("Token model: %s\n"), szTokenModel );
if ( a_ptTokenInfo->flags & CKF_TOKEN_INITIALIZED )
logDebug( _("Token is initialized\n") );
else
logDebug( _("Token is not initialized\n") );
}
/*
* openToken
* Iterate through the available slots and tokens looking
* for the TPM token and "opening" it if it is found.
*/
CK_RV
openToken( char *a_pszTokenLabel ) {
CK_C_GetFunctionList fGetFunctionList;
int i;
CK_RV rv;
CK_ULONG ulSlots;
CK_SLOT_ID *ptSlots;
CK_SLOT_INFO tSlotInfo;
CK_TOKEN_INFO tTokenInfo;
char szTokenLabel[ sizeof( tTokenInfo.label ) ];
char *pszTokenLabel;
// Load the PKCS#11 library
g_pSoLib = dlopen( g_pszSoLib, RTLD_NOW );
if ( !g_pSoLib ) {
logError( _("The PKCS#11 library cannot be loaded: %s\n"), dlerror( ) );
rv = CKR_GENERAL_ERROR;
goto out;
}
fGetFunctionList = (CK_C_GetFunctionList)dlsym( g_pSoLib, "C_GetFunctionList" );
if ( !fGetFunctionList ) {
logError( _("Unable to find the C_GetFunctionList function: %s\n"), dlerror( ) );
rv = CKR_GENERAL_ERROR;
goto out;
}
rv = fGetFunctionList( &g_pFcnList );
pkcsResult( "C_GetFunctionList", rv );
if ( rv != CKR_OK )
goto out;
// Set the name of the TPM token
memset( szTokenLabel, ' ', sizeof( szTokenLabel ) );
if ( a_pszTokenLabel ) {
if ( strlen( a_pszTokenLabel ) > sizeof( szTokenLabel ) ) {
logError( _("The token label cannot be greater than %ld characters\n"), sizeof( szTokenLabel ) );
rv = CKR_GENERAL_ERROR;
goto out;
}
pszTokenLabel = a_pszTokenLabel;
}
else
pszTokenLabel = TPM_TOKEN_LABEL;
strncpy( szTokenLabel, pszTokenLabel, strlen( pszTokenLabel ) );
// Initialize the PKCS#11 library
rv = g_pFcnList->C_Initialize( NULL );
pkcsResult( "C_Initialize", rv );
if ( rv != CKR_OK )
goto out;
g_bInit = TRUE;
// Determine the number of slots that are present
rv = g_pFcnList->C_GetSlotList( FALSE, NULL, &ulSlots );
pkcsResult( "C_GetSlotList", rv );
if ( rv != CKR_OK )
goto out;
if ( ulSlots == 0 ) {
logError( _("No PKCS#11 slots present\n") );
rv = CKR_TOKEN_NOT_PRESENT;
goto out;
}
// Allocate a buffer to hold the slot ids
logDebug( _("Slots present: %ld\n"), ulSlots );
ptSlots = (CK_SLOT_ID_PTR)calloc( 1, sizeof( CK_SLOT_ID ) * ulSlots );
if ( !ptSlots ) {
logError( _("Unable to obtain memory for PKCS#11 slot IDs\n") );
rv = CKR_HOST_MEMORY;
goto out;
}
// Retrieve the list of slot ids that are present
rv = g_pFcnList->C_GetSlotList( FALSE, ptSlots, &ulSlots );
pkcsResult( "C_GetSlotList", rv );
if ( rv != CKR_OK )
goto out;
// Iterate through the slots looking for the TPM token
for ( i = 0; i < ulSlots; i++ ) {
// Obtain information about the slot
logDebug( _("Retrieving slot information for SlotID %ld\n"), ptSlots[ i ] );
rv = g_pFcnList->C_GetSlotInfo( ptSlots[ i ], &tSlotInfo );
pkcsResult( "C_GetSlotInfo", rv );
if ( rv != CKR_OK )
goto out;
pkcsSlotInfo( &tSlotInfo );
if ( tSlotInfo.flags & CKF_TOKEN_PRESENT ) {
// The slot token is present, obtain information about the token
logDebug( _("Retrieving token information for SlotID %ld\n"), ptSlots[ i ] );
rv = g_pFcnList->C_GetTokenInfo( ptSlots[ i ], &tTokenInfo );
pkcsResult( "C_GetTokenInfo", rv );
if ( rv != CKR_OK )
goto out;
pkcsTokenInfo( &tTokenInfo );
// Check for the TPM token
if ( !strncmp( (char *)tTokenInfo.label, szTokenLabel, sizeof( szTokenLabel ) ) ) {
g_bTokenOpen = TRUE;
g_tSlotId = ptSlots[ i ];
g_tToken = tTokenInfo;
break;
}
}
}
if ( !g_bTokenOpen ) {
logError( _("PKCS#11 TPM Token is not present\n") );
rv = CKR_TOKEN_NOT_PRESENT;
}
out:
if ( !g_bTokenOpen && g_bInit ) {
g_pFcnList->C_Finalize( NULL );
g_bInit = FALSE;
}
if ( !g_bTokenOpen && g_pSoLib ) {
dlclose( g_pSoLib );
g_pSoLib = NULL;
}
return rv;
}
/*
* closeToken
* "Close" the TPM token.
*/
CK_RV
closeToken( ) {
CK_RV rv = CKR_OK;
// Tear down the PKCS#11 environment
if ( g_bInit ) {
rv = g_pFcnList->C_Finalize( NULL );
pkcsResult( "C_Finalize", rv );
}
// Unload the