Home | History | Annotate | Line # | Download | only in lib
      1 /*
      2  * The Initial Developer of the Original Code is International
      3  * Business Machines Corporation. Portions created by IBM
      4  * Corporation are Copyright (C) 2005 International Business
      5  * Machines Corporation. All Rights Reserved.
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the Common Public License as published by
      9  * IBM Corporation; either version 1 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * Common Public License for more details.
     16  *
     17  * You should have received a copy of the Common Public License
     18  * along with this program; if not, a copy can be viewed at
     19  * http://www.opensource.org/licenses/cpl1.0.php.
     20  */
     21 
     22 #include <tpm_pkcs11.h>
     23 
     24 #include <stdlib.h>
     25 #include <dlfcn.h>
     26 #include <opencryptoki/pkcs11.h>
     27 
     28 
     29 /*
     30  * Global variables
     31  */
     32 char *                g_pszSoLib = TPM_OPENCRYPTOKI_SO;
     33 void *                g_pSoLib   = NULL; // Handle of libopencryptoki library
     34 CK_FUNCTION_LIST_PTR  g_pFcnList = NULL; // Function List
     35 
     36 BOOL           g_bInit      = FALSE;	// Indicates if C_Initialize has been called
     37 BOOL           g_bTokenOpen = FALSE;	// Indicates if the token has been opened
     38 CK_SLOT_ID     g_tSlotId;		// Slot ID of the TPM token
     39 CK_TOKEN_INFO  g_tToken;		// TPM token information
     40 
     41 
     42 void
     43 pkcsDebug( const char *a_pszName,
     44            CK_RV       a_tResult ) {
     45 
     46 	logDebug( _("%s success\n"), a_pszName );
     47 }
     48 
     49 void
     50 pkcsError( const char *a_pszName,
     51            CK_RV       a_tResult ) {
     52 
     53 	logError( _("%s failed: 0x%08x (%ld)\n"), a_pszName, a_tResult, a_tResult );
     54 }
     55 
     56 void
     57 pkcsResult( const char *a_pszName,
     58             CK_RV       a_tResult ) {
     59 
     60 	if ( a_tResult == CKR_OK )
     61 		pkcsDebug( a_pszName, a_tResult );
     62 	else
     63 		pkcsError( a_pszName, a_tResult );
     64 }
     65 
     66 void
     67 pkcsResultException( const char *a_pszName,
     68                      CK_RV       a_tResult,
     69                      CK_RV       a_tExcept ) {
     70 
     71 	if ( ( a_tResult == CKR_OK ) || ( a_tResult == a_tExcept ) )
     72 		pkcsDebug( a_pszName, a_tResult );
     73 	else
     74 		pkcsError( a_pszName, a_tResult );
     75 }
     76 
     77 /*
     78  * pkcsSlotInfo
     79  *   Display some information about the slot.
     80  */
     81 void
     82 pkcsSlotInfo(CK_SLOT_INFO *a_ptSlotInfo ) {
     83 
     84 	char szSlotDesc[ sizeof( a_ptSlotInfo->slotDescription ) + 1 ];
     85 	char szSlotMfr[ sizeof( a_ptSlotInfo->manufacturerID ) + 1 ];
     86 
     87 	__memset( szSlotDesc, 0, sizeof( szSlotDesc ) );
     88 	__memset( szSlotMfr, 0, sizeof( szSlotMfr ) );
     89 
     90 	strncpy( szSlotDesc, (char *)a_ptSlotInfo->slotDescription,
     91 			sizeof( a_ptSlotInfo->slotDescription ) );
     92 	strncpy( szSlotMfr, (char *)a_ptSlotInfo->manufacturerID,
     93 			sizeof( a_ptSlotInfo->manufacturerID ) );
     94 
     95 	logDebug( _("Slot description: %s\n"), szSlotDesc );
     96 	logDebug( _("Slot manufacturer: %s\n"), szSlotMfr );
     97 	if ( a_ptSlotInfo->flags & CKF_TOKEN_PRESENT )
     98 		logDebug( _("Token is present\n") );
     99 	else
    100 		logDebug( _("Token is not present\n") );
    101 }
    102 
    103 /*
    104  * pkcsTokenInfo
    105  *   Display some information about the token.
    106  */
    107 void
    108 pkcsTokenInfo(CK_TOKEN_INFO *a_ptTokenInfo ) {
    109 
    110 	char szTokenLabel[ sizeof( a_ptTokenInfo->label ) + 1 ];
    111 	char szTokenMfr[ sizeof( a_ptTokenInfo->manufacturerID ) + 1 ];
    112 	char szTokenModel[ sizeof( a_ptTokenInfo->model ) + 1 ];
    113 
    114 	__memset( szTokenLabel, 0, sizeof( szTokenLabel ) );
    115 	__memset( szTokenMfr, 0, sizeof( szTokenMfr ) );
    116 	__memset( szTokenModel, 0, sizeof( szTokenModel ) );
    117 
    118 	strncpy( szTokenLabel, (char *)a_ptTokenInfo->label,
    119 			sizeof( a_ptTokenInfo->label ) );
    120 	strncpy( szTokenMfr, (char *)a_ptTokenInfo->manufacturerID,
    121 			sizeof( a_ptTokenInfo->manufacturerID ) );
    122 	strncpy( szTokenModel, (char *)a_ptTokenInfo->model,
    123 			sizeof( a_ptTokenInfo->model ) );
    124 
    125 	logDebug( _("Token Label: %s\n"), szTokenLabel );
    126 	logDebug( _("Token manufacturer: %s\n"), szTokenMfr );
    127 	logDebug( _("Token model: %s\n"), szTokenModel );
    128 
    129 	if ( a_ptTokenInfo->flags & CKF_TOKEN_INITIALIZED )
    130 		logDebug( _("Token is initialized\n") );
    131 	else
    132 		logDebug( _("Token is not initialized\n") );
    133 }
    134 
    135 /*
    136  * openToken
    137  *   Iterate through the available slots and tokens looking
    138  *   for the TPM token and "opening" it if it is found.
    139  */
    140 CK_RV
    141 openToken( char *a_pszTokenLabel ) {
    142 
    143 	CK_C_GetFunctionList  fGetFunctionList;
    144 
    145 	unsigned int  i;
    146 
    147 	CK_RV          rv;
    148 	CK_ULONG       ulSlots;
    149 	CK_SLOT_ID    *ptSlots = NULL;
    150 	CK_SLOT_INFO   tSlotInfo;
    151 	CK_TOKEN_INFO  tTokenInfo;
    152 
    153 	char  szTokenLabel[ sizeof( tTokenInfo.label ) ];
    154 	char *pszTokenLabel;
    155 
    156 	// Load the PKCS#11 library
    157 	g_pSoLib = dlopen( g_pszSoLib, RTLD_NOW );
    158 	if ( !g_pSoLib ) {
    159 		logError( _("The PKCS#11 library cannot be loaded: %s\n"), dlerror( ) );
    160 		rv = CKR_GENERAL_ERROR;
    161 		goto out;
    162 	}
    163 	fGetFunctionList = (CK_C_GetFunctionList)dlsym( g_pSoLib, "C_GetFunctionList" );
    164 	if ( !fGetFunctionList ) {
    165 		logError( _("Unable to find the C_GetFunctionList function: %s\n"), dlerror( ) );
    166 		rv = CKR_GENERAL_ERROR;
    167 		goto out;
    168 	}
    169 	rv = fGetFunctionList( &g_pFcnList );
    170 	pkcsResult( "C_GetFunctionList", rv );
    171 	if ( rv != CKR_OK )
    172 		goto out;
    173 
    174 	// Set the name of the TPM token
    175 	__memset( szTokenLabel, ' ', sizeof( szTokenLabel ) );
    176 	if ( a_pszTokenLabel ) {
    177 		if ( strlen( a_pszTokenLabel ) > sizeof( szTokenLabel ) ) {
    178 			logError( _("The token label cannot be greater than %ld characters\n"), sizeof( szTokenLabel ) );
    179 			rv = CKR_GENERAL_ERROR;
    180 			goto out;
    181 		}
    182 		pszTokenLabel = a_pszTokenLabel;
    183 	}
    184 	else
    185 		pszTokenLabel = TPM_TOKEN_LABEL;
    186 	strncpy( szTokenLabel, pszTokenLabel, strlen( pszTokenLabel ) );
    187 
    188 	// Initialize the PKCS#11 library
    189 	rv = g_pFcnList->C_Initialize( NULL );
    190 	pkcsResult( "C_Initialize", rv );
    191 	if ( rv != CKR_OK )
    192 		goto out;
    193 	g_bInit = TRUE;
    194 
    195 	// Determine the number of slots that are present
    196 	rv = g_pFcnList->C_GetSlotList( FALSE, NULL, &ulSlots );
    197 	pkcsResult( "C_GetSlotList", rv );
    198 	if ( rv != CKR_OK )
    199 		goto out;
    200 
    201 	if ( ulSlots == 0 ) {
    202 		logError( _("No PKCS#11 slots present\n") );
    203 		rv = CKR_TOKEN_NOT_PRESENT;
    204 		goto out;
    205 	}
    206 
    207 	// Allocate a buffer to hold the slot ids
    208 	logDebug( _("Slots present: %ld\n"), ulSlots );
    209 	ptSlots = (CK_SLOT_ID_PTR)calloc( 1, sizeof( CK_SLOT_ID ) * ulSlots );
    210 	if ( !ptSlots ) {
    211 		logError( _("Unable to obtain memory for PKCS#11 slot IDs\n") );
    212 		rv = CKR_HOST_MEMORY;
    213 		goto out;
    214 	}
    215 
    216 	// Retrieve the list of slot ids that are present
    217 	rv = g_pFcnList->C_GetSlotList( FALSE, ptSlots, &ulSlots );
    218 	pkcsResult( "C_GetSlotList", rv );
    219 	if ( rv != CKR_OK )
    220 		goto out;
    221 
    222 	// Iterate through the slots looking for the TPM token
    223 	for ( i = 0; i < ulSlots; i++ ) {
    224 		// Obtain information about the slot
    225 		logDebug( _("Retrieving slot information for SlotID %ld\n"), ptSlots[ i ] );
    226 		rv = g_pFcnList->C_GetSlotInfo( ptSlots[ i ], &tSlotInfo );
    227 		pkcsResult( "C_GetSlotInfo", rv );
    228 		if ( rv != CKR_OK )
    229 			goto out;
    230 		pkcsSlotInfo( &tSlotInfo );
    231 
    232 		if ( tSlotInfo.flags & CKF_TOKEN_PRESENT ) {
    233 			// The slot token is present, obtain information about the token
    234 			logDebug( _("Retrieving token information for SlotID %ld\n"), ptSlots[ i ] );
    235 			rv = g_pFcnList->C_GetTokenInfo( ptSlots[ i ], &tTokenInfo );
    236 			pkcsResult( "C_GetTokenInfo", rv );
    237 			if ( rv != CKR_OK )
    238 				goto out;
    239 			pkcsTokenInfo( &tTokenInfo );
    240 
    241 			// Check for the TPM token
    242 			if ( !strncmp( (char *)tTokenInfo.label, szTokenLabel, sizeof( szTokenLabel ) ) ) {
    243 				g_bTokenOpen = TRUE;
    244 				g_tSlotId = ptSlots[ i ];
    245 				g_tToken = tTokenInfo;
    246 				break;
    247 			}
    248 		}
    249 	}
    250 
    251 	if ( !g_bTokenOpen ) {
    252 		logError( _("PKCS#11 TPM Token is not present\n") );
    253 		rv = CKR_TOKEN_NOT_PRESENT;
    254 	}
    255 
    256 out:
    257 	if (rv != CKR_OK)
    258 		free(ptSlots);
    259 
    260 	if ( !g_bTokenOpen && g_bInit ) {
    261 		g_pFcnList->C_Finalize( NULL );
    262 		g_bInit = FALSE;
    263 	}
    264 
    265 	if ( !g_bTokenOpen && g_pSoLib ) {
    266 		dlclose( g_pSoLib );
    267 		g_pSoLib = NULL;
    268 	}
    269 
    270 	return rv;
    271 }
    272 
    273 /*
    274  * closeToken
    275  *   "Close" the TPM token.
    276  */
    277 CK_RV
    278 closeToken( ) {
    279 
    280 	CK_RV  rv = CKR_OK;
    281 
    282 	// Tear down the PKCS#11 environment
    283 	if ( g_bInit ) {
    284 		rv = g_pFcnList->C_Finalize( NULL );
    285 		pkcsResult( "C_Finalize", rv );
    286 	}
    287 
    288 	// Unload the PKCS#11 library
    289 	if ( g_pSoLib )
    290 		dlclose( g_pSoLib );
    291 
    292 	g_bTokenOpen = FALSE;
    293 	g_bInit      = FALSE;
    294 	g_pSoLib     = NULL;
    295 
    296 	return rv;
    297 }
    298 
    299 /*
    300  * initToken
    301  *   Invoke the PKCS#11 C_InitToken API.
    302  */
    303 CK_RV
    304 initToken( char *a_pszPin ) {
    305 
    306 	CK_RV  rv;
    307 
    308 	if ( !g_bTokenOpen )
    309 		return CKR_GENERAL_ERROR;
    310 
    311 	rv = g_pFcnList->C_InitToken( g_tSlotId, (CK_CHAR *)a_pszPin, strlen( a_pszPin ), g_tToken.label );
    312 	pkcsResult( "C_InitToken", rv );
    313 
    314 	return rv;
    315 }
    316 
    317 /*
    318  * openTokenSession
    319  *   Invoke the PKCS#11 C_OpenSession API.
    320  */
    321 CK_RV
    322 openTokenSession( CK_FLAGS           a_tType,
    323                   CK_SESSION_HANDLE *a_phSession ) {
    324 
    325 	CK_RV  rv;
    326 
    327 	if ( !g_bTokenOpen )
    328 		return CKR_GENERAL_ERROR;
    329 
    330 	a_tType |= CKF_SERIAL_SESSION; // This flag must always be set
    331 	rv = g_pFcnList->C_OpenSession( g_tSlotId, a_tType, NULL, NULL, a_phSession );
    332 	pkcsResult( "C_OpenSession", rv );
    333 
    334 	return rv;
    335 }
    336 
    337 /*
    338  * closeTokenSession
    339  *   Invoke the PKCS#11 C_CloseSession API.
    340  */
    341 CK_RV
    342 closeTokenSession( CK_SESSION_HANDLE  a_hSession ) {
    343 
    344 	CK_RV  rv;
    345 
    346 	if ( !g_bTokenOpen )
    347 		return CKR_GENERAL_ERROR;
    348 
    349 	rv = g_pFcnList->C_CloseSession( a_hSession );
    350 	pkcsResult( "C_CloseSession", rv );
    351 
    352 	return rv;
    353 }
    354 
    355 /*
    356  * closeAllTokenSessions
    357  *   Invoke the PKCS#11 C_CloseAllSessions API.
    358  */
    359 CK_RV
    360 closeAllTokenSessions( ) {
    361 
    362 	CK_RV  rv;
    363 
    364 	if ( !g_bTokenOpen )
    365 		return CKR_GENERAL_ERROR;
    366 
    367 	rv = g_pFcnList->C_CloseAllSessions( g_tSlotId );
    368 	pkcsResult( "C_CloseAllSessions", rv );
    369 
    370 	return rv;
    371 }
    372 
    373 /*
    374  * loginToken
    375  *   Invoke the PKCS#11 C_Login API for the specified user type.
    376  */
    377 CK_RV
    378 loginToken( CK_SESSION_HANDLE  a_hSession,
    379             CK_USER_TYPE       a_tType,
    380             char              *a_pszPin ) {
    381 
    382 	CK_RV  rv;
    383 
    384 	if ( !g_bTokenOpen )
    385 		return CKR_GENERAL_ERROR;
    386 
    387 	rv = g_pFcnList->C_Login( a_hSession, a_tType, (CK_CHAR *)a_pszPin, strlen( a_pszPin ) );
    388 	pkcsResult( "C_Login", rv );
    389 
    390 	return rv;
    391 }
    392 
    393 /*
    394  *   Invoke the PKCS#11 C_InitPin API.
    395  */
    396 CK_RV
    397 initPin( CK_SESSION_HANDLE  a_hSession,
    398          char              *a_pszPin ) {
    399 
    400 	CK_RV  rv;
    401 
    402 	if ( !g_bTokenOpen )
    403 		return CKR_GENERAL_ERROR;
    404 
    405 	rv = g_pFcnList->C_InitPIN( a_hSession, (CK_CHAR *)a_pszPin, strlen( a_pszPin ) );
    406 	pkcsResult( "C_InitPIN", rv );
    407 
    408 	return rv;
    409 }
    410 
    411 /*
    412  * setPin
    413  *   Invoke the PKCS#11 C_SetPIN API.
    414  */
    415 CK_RV
    416 setPin( CK_SESSION_HANDLE  a_hSession,
    417         char              *a_pszOldPin,
    418         char              *a_pszNewPin ) {
    419 
    420 	CK_RV  rv;
    421 
    422 	if ( !g_bTokenOpen )
    423 		return CKR_GENERAL_ERROR;
    424 
    425 	rv = g_pFcnList->C_SetPIN( a_hSession, (CK_CHAR *)a_pszOldPin, strlen( a_pszOldPin ),
    426 			(CK_CHAR *)a_pszNewPin, strlen( a_pszNewPin ) );
    427 	pkcsResult( "C_SetPIN", rv );
    428 
    429 	return rv;
    430 }
    431 
    432 /*
    433  * generateKey
    434  *   Invoke the PKCS#11 C_GenerateKey API to generate a key
    435  *   for the specified mechanism with the specified attributes.
    436  */
    437 CK_RV
    438 generateKey( CK_SESSION_HANDLE  a_hSession,
    439              CK_MECHANISM      *a_ptMechanism,
    440              CK_ATTRIBUTE      *a_ptAttrList,
    441              CK_ULONG           a_ulAttrCount,
    442              CK_OBJECT_HANDLE  *a_phObject ) {
    443 
    444 	CK_RV  rv;
    445 
    446 	if ( !g_bTokenOpen )
    447 		return CKR_GENERAL_ERROR;
    448 
    449 	rv = g_pFcnList->C_GenerateKey( a_hSession, a_ptMechanism, a_ptAttrList, a_ulAttrCount, a_phObject );
    450 	pkcsResult( "C_GenerateKey", rv );
    451 
    452 	return rv;
    453 }
    454 
    455 /*
    456  * createObject
    457  *   Invoke the PKCS#11 C_CreateObject API to create an object
    458  *   with the specified attributes.
    459  */
    460 CK_RV
    461 createObject( CK_SESSION_HANDLE  a_hSession,
    462               CK_ATTRIBUTE      *a_ptAttrList,
    463               CK_ULONG           a_ulAttrCount,
    464               CK_OBJECT_HANDLE  *a_phObject ) {
    465 
    466 	CK_RV  rv;
    467 
    468 	if ( !g_bTokenOpen )
    469 		return CKR_GENERAL_ERROR;
    470 
    471 	rv = g_pFcnList->C_CreateObject( a_hSession, a_ptAttrList, a_ulAttrCount, a_phObject );
    472 	pkcsResult( "C_CreateObject", rv );
    473 
    474 	return rv;
    475 }
    476 
    477 /*
    478  * destroyObject
    479  *   Invoke the PKCS#11 C_DestroyObject API.
    480  */
    481 CK_RV
    482 destroyObject( CK_SESSION_HANDLE  a_hSession,
    483                CK_OBJECT_HANDLE   a_hObject ) {
    484 
    485 	CK_RV  rv;
    486 
    487 	if ( !g_bTokenOpen )
    488 		return CKR_GENERAL_ERROR;
    489 
    490 	rv = g_pFcnList->C_DestroyObject( a_hSession, a_hObject );
    491 	pkcsResult( "C_DestroyObject", rv );
    492 
    493 	return rv;
    494 }
    495 
    496 /*
    497  * getObjectAttributes
    498  *   Invoke the PKCS#11 C_GetAttributeValue API to retrieve
    499  *   the specified attributes.
    500  */
    501 CK_RV
    502 getObjectAttributes( CK_SESSION_HANDLE  a_hSession,
    503                      CK_OBJECT_HANDLE   a_hObject,
    504                      CK_ATTRIBUTE      *a_ptAttrList,
    505                      CK_ULONG           a_ulAttrCount ) {
    506 
    507 	CK_RV  rv;
    508 
    509 	if ( !g_bTokenOpen )
    510 		return CKR_GENERAL_ERROR;
    511 
    512 	rv = g_pFcnList->C_GetAttributeValue( a_hSession, a_hObject, a_ptAttrList, a_ulAttrCount );
    513 	pkcsResultException( "C_GetAttributeValue", rv, CKR_ATTRIBUTE_TYPE_INVALID );
    514 
    515 	return rv;
    516 }
    517 
    518 /*
    519  * findObjects
    520  *   Return a list of object handles for all objects that
    521  *   match the specified attributes.
    522  */
    523 CK_RV
    524 findObjects( CK_SESSION_HANDLE  a_hSession,
    525              CK_ATTRIBUTE      *a_ptAttrList,
    526              CK_ULONG           a_ulAttrCount,
    527              CK_OBJECT_HANDLE **a_phObjList,
    528              CK_ULONG          *a_pulObjCount ) {
    529 
    530 	CK_RV             rv, rv_temp;
    531 	CK_ULONG          ulCount    = 0;
    532 	CK_ULONG          ulCurCount = 0;
    533 	CK_ULONG          ulMaxCount = 0;
    534 	CK_OBJECT_HANDLE *phObjList  = NULL;
    535 
    536 	*a_phObjList = NULL;
    537 	*a_pulObjCount = 0;
    538 
    539 	if ( !g_bTokenOpen )
    540 		return CKR_GENERAL_ERROR;
    541 
    542 	// Initialize the find operation
    543 	rv = g_pFcnList->C_FindObjectsInit( a_hSession, a_ptAttrList, a_ulAttrCount );
    544 	pkcsResult( "C_FindObjectsInit", rv );
    545 	if ( rv != CKR_OK )
    546 		goto out;
    547 
    548 	// Iterate until all object handles have been returned
    549 	do {
    550 		// Allocate (or increase) the object handle list buffer
    551 		CK_OBJECT_HANDLE *phTemp = phObjList;
    552 
    553 		ulMaxCount += TPM_FIND_MAX;
    554 		phObjList = (CK_OBJECT_HANDLE *)calloc( sizeof( CK_OBJECT_HANDLE ), ulMaxCount );
    555 		if ( !phObjList ) {
    556 			logError( _("Unable to obtain memory for object handle list\n") );
    557 			rv = CKR_HOST_MEMORY;
    558 			goto done;
    559 		}
    560 
    561 		// Copy the list of object handles
    562 		if ( phTemp ) {
    563 			memcpy( phObjList, phTemp, ulCurCount * sizeof( CK_OBJECT_HANDLE ) );
    564 			free( phTemp );
    565 		}
    566 
    567 		// Find the matching objects
    568 		rv = g_pFcnList->C_FindObjects( a_hSession, phObjList + ulCurCount, TPM_FIND_MAX, &ulCount );
    569 		pkcsResult( "C_FindObjects", rv );
    570 		if ( rv != CKR_OK )
    571 			goto done;
    572 
    573 		ulCurCount += ulCount;
    574 	} while ( ulCurCount == ulMaxCount );
    575 
    576 	*a_phObjList = phObjList;
    577 	*a_pulObjCount = ulCurCount;
    578 
    579 done:
    580 	// Terminate the find operation
    581 	rv_temp = g_pFcnList->C_FindObjectsFinal( a_hSession );
    582 	pkcsResult( "C_FindObjectsFinal", rv_temp );
    583 
    584 out:
    585 	if ( ( rv != CKR_OK ) && phObjList )
    586 		free( phObjList );
    587 
    588 	return rv;
    589 }
    590 
    591 /*
    592  * displayByteArray
    593  *   Format a byte array for display.
    594  */
    595 void
    596 displayByteArray( const char   *a_pszLabel,
    597                   CK_ATTRIBUTE *a_ptAttr,
    598                   int           a_bExtended ) {
    599 
    600 	const char *pszPre  = ( a_bExtended ) ? "\t" : "";
    601 	const char *pszPost = ( a_bExtended ) ? "\n" : "";
    602 
    603 	logMsg( "%s%s'", pszPre, a_pszLabel );
    604 
    605 	if ( a_ptAttr->ulValueLen )
    606 		logHex( a_ptAttr->ulValueLen, a_ptAttr->pValue );
    607 	else
    608 		logMsg( "(null)" );
    609 
    610 	logMsg( "'%s", pszPost );
    611 }
    612 
    613 /*
    614  * displayCertObject
    615  *   Format a certificate object for display.
    616  */
    617 CK_RV
    618 displayCertObject( CK_SESSION_HANDLE  a_hSession,
    619                    CK_OBJECT_HANDLE   a_hObject,
    620                    int                a_bExtended ) {
    621 
    622 	CK_RV                rv;
    623 	CK_OBJECT_CLASS  tClass;
    624 	CK_BBOOL             bToken;
    625 	CK_BBOOL             bPrivate;
    626 	CK_BBOOL             bModifiable;
    627 	CK_CHAR             *pszLabel    = NULL;
    628 	CK_CERTIFICATE_TYPE  tType;
    629 	CK_BBOOL             bTrusted;
    630 
    631 	CK_ATTRIBUTE  tCertList[] = {
    632 			{ CKA_CLASS, &tClass, sizeof( tClass ) },
    633 			{ CKA_TOKEN, &bToken, sizeof( bToken ) },
    634 			{ CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
    635 			{ CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) },
    636 			{ CKA_LABEL, NULL, 0 },
    637 			{ CKA_CERTIFICATE_TYPE, &tType, sizeof( tType ) },
    638 			{ CKA_TRUSTED, &bTrusted, sizeof( bTrusted ) },
    639 		};
    640 	CK_ATTRIBUTE  tX509List[] = {
    641 			{ CKA_SUBJECT, NULL, 0 },
    642 			{ CKA_ID, NULL, 0 },
    643 			{ CKA_ISSUER, NULL, 0 },
    644 			{ CKA_SERIAL_NUMBER, NULL, 0 },
    645 			{ CKA_VALUE, NULL, 0 },
    646 		};
    647 	CK_ATTRIBUTE  tX509AttrList[] = {
    648 			{ CKA_OWNER, NULL, 0 },
    649 			{ CKA_AC_ISSUER, NULL, 0 },
    650 			{ CKA_SERIAL_NUMBER, NULL, 0 },
    651 			{ CKA_ATTR_TYPES, NULL, 0 },
    652 			{ CKA_VALUE, NULL, 0 },
    653 		};
    654 	CK_ULONG      ulCertCount     = sizeof( tCertList ) / sizeof( CK_ATTRIBUTE );
    655 	CK_ULONG      ulX509Count     = sizeof( tX509List ) / sizeof( CK_ATTRIBUTE );
    656 	CK_ULONG      ulX509AttrCount = sizeof( tX509AttrList ) / sizeof( CK_ATTRIBUTE );
    657 	CK_ATTRIBUTE *ptAttrList;
    658 	CK_ULONG      ulAttrCount;
    659 
    660 	// Retrieve the common certificate attributes
    661 	rv = getObjectAttributes( a_hSession, a_hObject, tCertList, ulCertCount );
    662 	if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    663 		return rv;
    664 
    665 	// Allocate storage for the object label (extra byte for null
    666 	// terminated string)
    667 	if ( tCertList[ 4 ].ulValueLen > 0 ) {
    668 		pszLabel = tCertList[ 4 ].pValue = calloc( 1, tCertList[ 4 ].ulValueLen + 1 );
    669 
    670 		rv = getObjectAttributes( a_hSession, a_hObject, tCertList, ulCertCount );
    671 		if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    672 			return rv;
    673 	}
    674 
    675 	// Determine the attributes to retrieve based on the certficate type
    676 	switch ( tType ) {
    677 		case CKC_X_509:
    678 			ptAttrList = tX509List;
    679 			ulAttrCount = ulX509Count;
    680 			break;
    681 
    682 		case CKC_X_509_ATTR_CERT:
    683 			ptAttrList = tX509AttrList;
    684 			ulAttrCount = ulX509AttrCount;
    685 			break;
    686 
    687 		default:
    688 			ptAttrList = NULL;
    689 			ulAttrCount = 0;
    690 	}
    691 
    692 	if ( ptAttrList ) {
    693 		CK_ULONG  ulMalloc;
    694 
    695 		// Retrieve the specific certificate type attributes (for obtaining
    696 		// the attribute lengths)
    697 		rv = getObjectAttributes( a_hSession, a_hObject, ptAttrList, ulAttrCount );
    698 		if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    699 			return rv;
    700 
    701 		for ( ulMalloc = 0; ulMalloc < ulAttrCount; ulMalloc++ ) {
    702 			// Allocate the storage (with an extra byte for null terminated
    703 			// strings - just in case)
    704 			if ( ptAttrList[ ulMalloc ].ulValueLen > 0 )
    705 				ptAttrList[ ulMalloc ].pValue =
    706 					calloc( 1, ptAttrList[ ulMalloc ].ulValueLen );
    707 		}
    708 
    709 		// Now retrieve all the specific certificate type attributes
    710 		rv = getObjectAttributes( a_hSession, a_hObject, ptAttrList, ulAttrCount );
    711 		if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    712 			return rv;
    713 	}
    714 
    715 	if ( a_bExtended ) {
    716 		logMsg( _("Certificate Object\n") );
    717 		switch ( tType ) {
    718 			case CKC_X_509:
    719 				logMsg( _("\tX509 Certificate\n") );
    720 				break;
    721 
    722 			case CKC_X_509_ATTR_CERT:
    723 				logMsg( _("\tX509 Attribute Certificate\n") );
    724 				break;
    725 
    726 			default:
    727 				logMsg( _("\tUnknown Certificate Type (%08x)\n"), tType );
    728 		}
    729 		if ( tCertList[ 1 ].ulValueLen > 0 )
    730 			logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") );
    731 		if ( tCertList[ 2 ].ulValueLen > 0 )
    732 			logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") );
    733 		if ( tCertList[ 3 ].ulValueLen > 0 )
    734 			logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") );
    735 		if ( tCertList[ 4 ].ulValueLen > 0 )
    736 			logMsg( _("\tLabel: '%s'\n"), pszLabel );
    737 		if ( tCertList[ 5 ].ulValueLen > 0 )
    738 			logMsg( _("\tTrusted: %s\n"), bTrusted ? _("true") : _("false") );
    739 
    740 		// Display the attributes based on the certficate type
    741 		switch ( tType ) {
    742 			case CKC_X_509:
    743 				if ( tX509List[ 0 ].ulValueLen > 0 )
    744 					displayByteArray( _("Subject: "), &tX509List[ 0 ], a_bExtended );
    745 				if ( tX509List[ 1 ].ulValueLen > 0 ) {
    746 					logMsg( _("\tId: '%s' ("), tX509List[ 1 ].pValue );
    747 					displayByteArray( "", &tX509List[ 1 ], FALSE );
    748 					logMsg( ")\n" );
    749 				}
    750 				if ( tX509List[ 2 ].ulValueLen > 0 )
    751 					displayByteArray( _("Issuer: "), &tX509List[ 2 ], a_bExtended );
    752 				if ( tX509List[ 3 ].ulValueLen > 0 )
    753 					displayByteArray( _("Serial Number: "), &tX509List[ 3 ], a_bExtended );
    754 				if ( tX509List[ 4 ].ulValueLen > 0 )
    755 					displayByteArray( _("Value: "), &tX509List[ 4 ], a_bExtended );
    756 				break;
    757 
    758 			case CKC_X_509_ATTR_CERT:
    759 				if ( tX509AttrList[ 0 ].ulValueLen > 0 )
    760 					displayByteArray( _("Owner: "), &tX509AttrList[ 0 ], a_bExtended );
    761 				if ( tX509AttrList[ 1 ].ulValueLen > 0 )
    762 					displayByteArray( _("Issuer: "), &tX509AttrList[ 1 ], a_bExtended );
    763 				if ( tX509AttrList[ 2 ].ulValueLen > 0 )
    764 					displayByteArray( _("Serial Number: "), &tX509AttrList[ 2 ], a_bExtended );
    765 				if ( tX509AttrList[ 3 ].ulValueLen > 0 )
    766 					displayByteArray( _("Attribute Types: "), &tX509AttrList[ 3 ], a_bExtended );
    767 				if ( tX509AttrList[ 4 ].ulValueLen > 0 )
    768 					displayByteArray( _("Value: "), &tX509AttrList[ 4 ], a_bExtended );
    769 				break;
    770 		}
    771 	}
    772 	else {
    773 		// Display the attributes based on the certficate type
    774 		logMsg( _("Certificate: ") );
    775 		switch ( tType ) {
    776 			case CKC_X_509:
    777 				logMsg( _("Type: X509 Public Key") );
    778 				break;
    779 
    780 			case CKC_X_509_ATTR_CERT:
    781 				logMsg( _("Type: X509 Attribute") );
    782 				break;
    783 
    784 			default:
    785 				logMsg( _("Unknown Type (%08x)"), tType );
    786 		}
    787 
    788 		if ( tCertList[ 4 ].ulValueLen > 0 )
    789 			logMsg( _(", Label: '%s'"), pszLabel );
    790 
    791 		logMsg( "\n" );
    792 	}
    793 
    794 	return rv;
    795 }
    796 
    797 /*
    798  * displayAsymKeyObject
    799  *   Format an asymmetric key object for display.
    800  */
    801 CK_RV
    802 displayAsymKeyObject( CK_SESSION_HANDLE  a_hSession,
    803                       CK_OBJECT_HANDLE   a_hObject,
    804                       int                a_bExtended ) {
    805 
    806 	CK_RV            rv;
    807 	CK_OBJECT_CLASS  tClass;
    808 	CK_BBOOL         bToken;
    809 	CK_BBOOL         bPrivate;
    810 	CK_BBOOL         bModifiable;
    811 	CK_CHAR         *pszLabel     = NULL;
    812 	CK_KEY_TYPE      tType;
    813 	CK_CHAR         *pszId        = NULL;
    814 
    815 	CK_ATTRIBUTE  tKeyList[] = {
    816 			{ CKA_CLASS, &tClass, sizeof( tClass ) },
    817 			{ CKA_TOKEN, &bToken, sizeof( bToken ) },
    818 			{ CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
    819 			{ CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) },
    820 			{ CKA_LABEL, NULL, 0 },
    821 			{ CKA_KEY_TYPE, &tType, sizeof( tType ) },
    822 			{ CKA_SUBJECT, NULL, 0 },
    823 			{ CKA_ID, NULL, 0 },
    824 		};
    825 	CK_ULONG      ulKeyCount = sizeof( tKeyList ) / sizeof( CK_ATTRIBUTE );
    826 
    827 	// Retrieve the common key attributes
    828 	rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount );
    829 	if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    830 		return rv;
    831 
    832 	// Allocate storage for the object id
    833 	if ( ( tKeyList[ 4 ].ulValueLen > 0 ) || ( tKeyList[ 6 ].ulValueLen > 0 ) || ( tKeyList[ 7 ].ulValueLen > 0 ) ) {
    834 		if ( tKeyList[ 4 ].ulValueLen > 0 )
    835 			pszLabel = tKeyList[ 4 ].pValue =
    836 				calloc( 1, tKeyList[ 4 ].ulValueLen + 1 );
    837 
    838 		if ( tKeyList[ 6 ].ulValueLen > 0 )
    839 			tKeyList[ 6 ].pValue =
    840 				calloc( 1, tKeyList[ 6 ].ulValueLen + 1 );
    841 
    842 		if ( tKeyList[ 7 ].ulValueLen > 0 )
    843 			pszId = tKeyList[ 7 ].pValue =
    844 				calloc( 1, tKeyList[ 7 ].ulValueLen + 1 );
    845 
    846 		rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount );
    847 		if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    848 			return rv;
    849 	}
    850 
    851 	if ( a_bExtended ) {
    852 		logMsg( _("Key Object\n") );
    853 		switch ( tClass ) {
    854 			case CKO_PUBLIC_KEY:
    855 				logMsg( _("\tPublic Key\n") );
    856 				break;
    857 
    858 			case CKO_PRIVATE_KEY:
    859 				logMsg( _("\tPrivate Key\n") );
    860 				break;
    861 		}
    862 		if ( tKeyList[ 1 ].ulValueLen > 0 )
    863 			logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") );
    864 		if ( tKeyList[ 2 ].ulValueLen > 0 )
    865 			logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") );
    866 		if ( tKeyList[ 3 ].ulValueLen > 0 )
    867 			logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") );
    868 		if ( tKeyList[ 4 ].ulValueLen > 0 )
    869 			logMsg( _("\tLabel: '%s'\n"), pszLabel );
    870 		if ( tKeyList[ 5 ].ulValueLen > 0 )
    871 			logMsg( _("\tType: %ld\n"), tType );
    872 		if ( tKeyList[ 6 ].ulValueLen > 0 )
    873 			displayByteArray( _("Subject: "), &tKeyList[ 6 ], a_bExtended );
    874 		if ( tKeyList[ 7 ].ulValueLen > 0 ) {
    875 			logMsg( _("\tId: '%s' ("), pszId );
    876 			displayByteArray( "", &tKeyList[ 7 ], FALSE );
    877 			logMsg( ")\n" );
    878 		}
    879 	}
    880 	else {
    881 		switch ( tClass ) {
    882 			case CKO_PUBLIC_KEY:
    883 				logMsg( _("Public Key: ") );
    884 				break;
    885 
    886 			case CKO_PRIVATE_KEY:
    887 				logMsg( _("Private Key: ") );
    888 				break;
    889 		}
    890 
    891 		if ( tKeyList[ 5 ].ulValueLen > 0 )
    892 			logMsg( _("Type: %ld"), tType );
    893 		if ( tKeyList[ 4 ].ulValueLen > 0 )
    894 			logMsg( _(", Label: '%s'"), pszLabel );
    895 
    896 		logMsg( "\n" );
    897 	}
    898 
    899 	return rv;
    900 }
    901 
    902 /*
    903  * displaySymKeyObject
    904  *   Format a symmetric key object for display.
    905  */
    906 CK_RV
    907 displaySymKeyObject( CK_SESSION_HANDLE  a_hSession,
    908                      CK_OBJECT_HANDLE   a_hObject,
    909                      int                a_bExtended ) {
    910 
    911 	CK_RV            rv;
    912 	CK_OBJECT_CLASS  tClass;
    913 	CK_BBOOL         bToken;
    914 	CK_BBOOL         bPrivate;
    915 	CK_BBOOL         bModifiable;
    916 	CK_CHAR         *pszLabel     = NULL;
    917 	CK_KEY_TYPE      tType;
    918 
    919 	CK_ATTRIBUTE  tKeyList[] = {
    920 			{ CKA_CLASS, &tClass, sizeof( tClass ) },
    921 			{ CKA_TOKEN, &bToken, sizeof( bToken ) },
    922 			{ CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
    923 			{ CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) },
    924 			{ CKA_LABEL, NULL, 0 },
    925 			{ CKA_KEY_TYPE, &tType, sizeof( tType ) },
    926 		};
    927 	CK_ULONG      ulKeyCount = sizeof( tKeyList ) / sizeof( CK_ATTRIBUTE );
    928 
    929 	// Retrieve the common key attributes
    930 	rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount );
    931 	if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    932 		return rv;
    933 
    934 	// Allocate storage for the object id
    935 	if ( tKeyList[ 4 ].ulValueLen > 0 ) {
    936 		pszLabel = tKeyList[ 4 ].pValue =
    937 			calloc( 1, tKeyList[ 4 ].ulValueLen + 1 );
    938 
    939 		rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount );
    940 		if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) )
    941 			return rv;
    942 	}
    943 
    944 	if ( a_bExtended ) {
    945 		logMsg( _("Key Object\n") );
    946 		switch ( tClass ) {
    947 			case CKO_SECRET_KEY:
    948 				logMsg( _("\tSecret Key\n") );
    949 				break;
    950 		}
    951 		if ( tKeyList[ 1 ].ulValueLen > 0 )
    952 			logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") );
    953 		if ( tKeyList[ 2 ].ulValueLen > 0 )
    954 			logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") );
    955 		if ( tKeyList[ 3 ].ulValueLen > 0 )
    956 			logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") );
    957 		if ( tKeyList[ 4 ].ulValueLen > 0 )
    958 			logMsg( _("\tLabel: '%s'\n"), pszLabel );
    959 		if ( tKeyList[ 5 ].ulValueLen > 0 )
    960 			logMsg( _("\tType: %ld\n"), tType );
    961 	}
    962 	else {
    963 		switch ( tClass ) {
    964 			case CKO_SECRET_KEY:
    965 				logMsg( _("Secret Key: ") );
    966 				break;
    967 		}
    968 
    969 		if ( tKeyList[ 5 ].ulValueLen > 0 )
    970 			logMsg( _("Type: %ld"), tType );
    971 		if ( tKeyList[ 4 ].ulValueLen > 0 )
    972 			logMsg( _(", Label: '%s'"), pszLabel );
    973 
    974 		logMsg( "\n" );
    975 	}
    976 
    977 	return rv;
    978 }
    979 
    980 /*
    981  * displayObject
    982  *   Format and display objects.
    983  */
    984 CK_RV
    985 displayObject( CK_SESSION_HANDLE  a_hSession,
    986                CK_OBJECT_HANDLE   a_hObject,
    987 	       int                a_bExtended ) {
    988 
    989 	CK_RV            rv;
    990 	CK_OBJECT_CLASS  tClass;
    991 	CK_ATTRIBUTE     tAttr[] = {
    992 			{ CKA_CLASS, &tClass, sizeof( tClass ) },
    993 		};
    994 	CK_ULONG         ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
    995 
    996 	// Retrieve the class attribute of the object
    997 	rv = getObjectAttributes( a_hSession, a_hObject, tAttr, ulAttrCount );
    998 	if ( rv != CKR_OK )
    999 		return rv;
   1000 
   1001 	// Use the object class to determine how to format it for display
   1002 	switch ( tClass ) {
   1003 		case CKO_DATA:
   1004 			logMsg( _("Data object\n") );
   1005 			break;
   1006 
   1007 		case CKO_CERTIFICATE:
   1008 			displayCertObject( a_hSession, a_hObject, a_bExtended );
   1009 			break;
   1010 
   1011 		case CKO_PUBLIC_KEY:
   1012 		case CKO_PRIVATE_KEY:
   1013 			displayAsymKeyObject( a_hSession, a_hObject, a_bExtended );
   1014 			break;
   1015 
   1016 		case CKO_SECRET_KEY:
   1017 			displaySymKeyObject( a_hSession, a_hObject, a_bExtended );
   1018 			break;
   1019 
   1020 		case CKO_HW_FEATURE:
   1021 		case CKO_DOMAIN_PARAMETERS:
   1022 		default:
   1023 			logMsg( _("Object class=%ld\n"), tClass );
   1024 			break;
   1025 	}
   1026 
   1027 	return rv;
   1028 }
   1029 
   1030 /*
   1031  * checkKey
   1032  *   Check that the key object attributes match the key class
   1033  *   and key type specified.
   1034  */
   1035 CK_RV
   1036 checkKey( CK_SESSION_HANDLE  a_hSession,
   1037           CK_OBJECT_HANDLE   a_hObject,
   1038           CK_OBJECT_CLASS    a_tKeyClass,
   1039           CK_KEY_TYPE        a_tKeyType ) {
   1040 
   1041 	CK_RV  rv;
   1042 
   1043 	CK_OBJECT_CLASS  tClass;
   1044 	CK_KEY_TYPE      tType;
   1045 	CK_ATTRIBUTE     tAttr[] = {
   1046 			{ CKA_CLASS, &tClass, sizeof( tClass ) },
   1047 			{ CKA_KEY_TYPE, &tType, sizeof( tType ) },
   1048 		};
   1049 	CK_ULONG         ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
   1050 
   1051 	// Retrieve the class attribute and key type attribute of the object
   1052 	rv = getObjectAttributes( a_hSession, a_hObject, tAttr, ulAttrCount );
   1053 	if ( rv != CKR_OK )
   1054 		return rv;
   1055 
   1056 	if ( tClass != a_tKeyClass )
   1057 		return CKR_GENERAL_ERROR;
   1058 
   1059 	if ( tType != a_tKeyType )
   1060 		return CKR_GENERAL_ERROR;
   1061 
   1062 	return CKR_OK;
   1063 }
   1064 
   1065 /*
   1066  * encryptData
   1067  *   Use a callback mechanism to encrypt some data.
   1068  */
   1069 CK_RV
   1070 encryptData( CK_SESSION_HANDLE  a_hSession,
   1071              CK_OBJECT_HANDLE   a_hObject,
   1072              CK_MECHANISM      *a_ptMechanism,
   1073              TokenCryptGet      a_fGet,
   1074              TokenCryptPut      a_fPut ) {
   1075 
   1076 	CK_RV         rv;
   1077 	CK_BBOOL      bCancel       = FALSE;
   1078 
   1079 	CK_BYTE      *pbInData      = NULL;
   1080 	CK_ULONG      ulInDataLen   = 0;
   1081 	CK_BBOOL      bContinue     = TRUE;
   1082 
   1083 	CK_BYTE      *pbBuffer      = NULL;
   1084 	CK_ULONG      ulBufferLen   = 0;
   1085 	CK_ULONG      ulOutDataLen  = 0;
   1086 
   1087 	if ( !g_bTokenOpen )
   1088 		return CKR_GENERAL_ERROR;
   1089 
   1090 	// Check the key
   1091 	rv = checkKey( a_hSession, a_hObject, CKO_SECRET_KEY, CKK_AES );
   1092 	if ( rv != CKR_OK )
   1093 		goto out;
   1094 
   1095 	// Initialize the encryption operation
   1096 	rv = g_pFcnList->C_EncryptInit( a_hSession, a_ptMechanism, a_hObject );
   1097 	pkcsResult( "C_EncryptInit", rv );
   1098 	if ( rv != CKR_OK )
   1099 		goto out;
   1100 
   1101 	while ( bContinue ) {
   1102 		// Retrieve some data to encrypt
   1103 		if ( a_fGet( &pbInData, &ulInDataLen, &bContinue, TRUE ) == -1 ) {
   1104 			bCancel = TRUE;
   1105 			goto out;
   1106 		}
   1107 
   1108 		// Check the output buffer size needed
   1109 		rv = g_pFcnList->C_EncryptUpdate( a_hSession, pbInData, ulInDataLen,
   1110 			NULL, &ulOutDataLen );
   1111 		pkcsResult( "C_EncryptUpdate", rv );
   1112 		if ( rv != CKR_OK )
   1113 			goto out;
   1114 
   1115 		// Check if a larger buffer is needed
   1116 		if ( ulOutDataLen > ulBufferLen ) {
   1117 			free( pbBuffer );
   1118 			ulBufferLen = ulOutDataLen;
   1119 			pbBuffer = calloc( 1, ulBufferLen );
   1120 			if ( !pbBuffer ) {
   1121 				logError( _("Unable to obtain memory for the encrypted data buffer\n") );
   1122 				rv = CKR_HOST_MEMORY;
   1123 				goto out;
   1124 			}
   1125 		}
   1126 
   1127 		// Encrypt the input data
   1128 		rv = g_pFcnList->C_EncryptUpdate( a_hSession, pbInData, ulInDataLen,
   1129 			pbBuffer, &ulOutDataLen );
   1130 		pkcsResult( "C_EncryptUpdate", rv );
   1131 		if ( rv != CKR_OK )
   1132 			goto out;
   1133 
   1134 		if ( ulOutDataLen > 0 ) {
   1135 			if ( a_fPut( pbBuffer, ulOutDataLen, bContinue, TRUE ) == -1 ) {
   1136 				bCancel = TRUE;
   1137 				goto out;
   1138 			}
   1139 		}
   1140 	}
   1141 
   1142 out:
   1143 	// For AES any remaining data will cause an error, so provide
   1144 	// a buffer which will not be filled in anyway
   1145 	ulOutDataLen = ulBufferLen;
   1146 	rv = g_pFcnList->C_EncryptFinal( a_hSession, pbBuffer, &ulOutDataLen );
   1147 	pkcsResult( "C_EncryptFinal", rv );
   1148 
   1149 	free( pbBuffer );
   1150 
   1151 	if ( bCancel )
   1152 		rv = CKR_FUNCTION_CANCELED;
   1153 
   1154 	return rv;
   1155 }
   1156 
   1157 /*
   1158  * decryptData
   1159  *   Use a callback mechanism to decrypt some data.
   1160  */
   1161 CK_RV
   1162 decryptData( CK_SESSION_HANDLE  a_hSession,
   1163              CK_OBJECT_HANDLE   a_hObject,
   1164              CK_MECHANISM      *a_ptMechanism,
   1165              TokenCryptGet      a_fGet,
   1166              TokenCryptPut      a_fPut ) {
   1167 
   1168 	CK_RV         rv;
   1169 	CK_BBOOL      bCancel       = FALSE;
   1170 
   1171 	CK_BYTE      *pbInData      = NULL;
   1172 	CK_ULONG      ulInDataLen   = 0;
   1173 	CK_BBOOL      bContinue     = TRUE;
   1174 
   1175 	CK_BYTE      *pbBuffer      = NULL;
   1176 	CK_ULONG      ulBufferLen   = 0;
   1177 	CK_ULONG      ulOutDataLen  = 0;
   1178 
   1179 	if ( !g_bTokenOpen )
   1180 		return CKR_GENERAL_ERROR;
   1181 
   1182 	// Check the key
   1183 	rv = checkKey( a_hSession, a_hObject, CKO_SECRET_KEY, CKK_AES );
   1184 	if ( rv != CKR_OK )
   1185 		goto out;
   1186 
   1187 	// Initialize the decryption operation
   1188 	rv = g_pFcnList->C_DecryptInit( a_hSession, a_ptMechanism, a_hObject );
   1189 	pkcsResult( "C_DecryptInit", rv );
   1190 	if ( rv != CKR_OK )
   1191 		goto out;
   1192 
   1193 	while ( bContinue ) {
   1194 		// Retrieve some data to encrypt
   1195 		if ( a_fGet( &pbInData, &ulInDataLen, &bContinue, FALSE ) == -1 ) {
   1196 			bCancel = TRUE;
   1197 			goto out;
   1198 		}
   1199 
   1200 		// Check the output buffer size needed
   1201 		rv = g_pFcnList->C_DecryptUpdate( a_hSession, pbInData, ulInDataLen,
   1202 			NULL, &ulOutDataLen );
   1203 		pkcsResult( "C_DecryptUpdate", rv );
   1204 		if ( rv != CKR_OK )
   1205 			goto out;
   1206 
   1207 		// Check if a larger buffer is needed
   1208 		if ( ulOutDataLen > ulBufferLen ) {
   1209 			free( pbBuffer );
   1210 			ulBufferLen = ulOutDataLen;
   1211 			pbBuffer = calloc( 1, ulBufferLen );
   1212 			if ( !pbBuffer ) {
   1213 				logError( _("Unable to obtain memory for the encrypted data buffer\n") );
   1214 				rv = CKR_HOST_MEMORY;
   1215 				goto out;
   1216 			}
   1217 		}
   1218 
   1219 		// Decrypt the input data
   1220 		rv = g_pFcnList->C_DecryptUpdate( a_hSession, pbInData, ulInDataLen,
   1221 			pbBuffer, &ulOutDataLen );
   1222 		pkcsResult( "C_DecryptUpdate", rv );
   1223 		if ( rv != CKR_OK )
   1224 			goto out;
   1225 
   1226 		if ( a_fPut( pbBuffer, ulOutDataLen, bContinue, FALSE ) == -1 ) {
   1227 			bCancel = TRUE;
   1228 			goto out;
   1229 		}
   1230 	}
   1231 
   1232 out:
   1233 	// For AES any remaining data will cause an error, so provide
   1234 	// a buffer which will not be filled in anyway
   1235 	rv = g_pFcnList->C_DecryptFinal( a_hSession, pbBuffer, &ulOutDataLen );
   1236 	pkcsResult( "C_DecryptFinal", rv );
   1237 
   1238 	free( pbBuffer );
   1239 
   1240 	if ( bCancel )
   1241 		rv = CKR_FUNCTION_CANCELED;
   1242 
   1243 	return rv;
   1244 }
   1245 
   1246 /*
   1247  * isTokenInitialized
   1248  *   Returns an indicator as to whether the TPM token has been initialized.
   1249  */
   1250 BOOL
   1251 isTokenInitialized( ) {
   1252 
   1253 	if ( g_bTokenOpen && ( g_tToken.flags & CKF_TOKEN_INITIALIZED ) )
   1254 		return TRUE;
   1255 
   1256 	return FALSE;
   1257 }
   1258 
   1259 /*
   1260  * getMinPinLen
   1261  *   Returns the the minimum PIN length that the TPM token accepts.
   1262  */
   1263 int
   1264 getMinPinLen( ) {
   1265 
   1266 	if ( !g_bTokenOpen )
   1267 		return 0;
   1268 
   1269 	return (int)g_tToken.ulMinPinLen;
   1270 }
   1271 
   1272 /*
   1273  * getMaxPinLen
   1274  *   Returns the the maximum PIN length that the TPM token accepts.
   1275  */
   1276 int
   1277 getMaxPinLen( ) {
   1278 
   1279 	if ( !g_bTokenOpen )
   1280 		return 0;
   1281 
   1282 	return (int)g_tToken.ulMaxPinLen;
   1283 }
   1284