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 */
32char *                g_pszSoLib = TPM_OPENCRYPTOKI_SO;
33void *                g_pSoLib   = NULL; // Handle of libopencryptoki library
34CK_FUNCTION_LIST_PTR  g_pFcnList = NULL; // Function List
35
36BOOL           g_bInit      = FALSE;	// Indicates if C_Initialize has been called
37BOOL           g_bTokenOpen = FALSE;	// Indicates if the token has been opened
38CK_SLOT_ID     g_tSlotId;		// Slot ID of the TPM token
39CK_TOKEN_INFO  g_tToken;		// TPM token information
40
41
42void
43pkcsDebug( const char *a_pszName,
44           CK_RV       a_tResult ) {
45
46	logDebug( _("%s success\n"), a_pszName );
47}
48
49void
50pkcsError( 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
56void
57pkcsResult( 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
66void
67pkcsResultException( 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 */
81void
82pkcsSlotInfo(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 */
107void
108pkcsTokenInfo(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 */
140CK_RV
141openToken( 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
256out:
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 */
277CK_RV
278closeToken( ) {
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 */
303CK_RV
304initToken( 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 */
321CK_RV
322openTokenSession( 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 */
341CK_RV
342closeTokenSession( 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 */
359CK_RV
360closeAllTokenSessions( ) {
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 */
377CK_RV
378loginToken( 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 */
396CK_RV
397initPin( 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 */
415CK_RV
416setPin( 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 */
437CK_RV
438generateKey( 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 */
460CK_RV
461createObject( 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 */
481CK_RV
482destroyObject( 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 */
501CK_RV
502getObjectAttributes( 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 */
523CK_RV
524findObjects( 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
579done:
580	// Terminate the find operation
581	rv_temp = g_pFcnList->C_FindObjectsFinal( a_hSession );
582	pkcsResult( "C_FindObjectsFinal", rv_temp );
583
584out:
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 */
595void
596displayByteArray( 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 */
617CK_RV
618displayCertObject( 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 */
801CK_RV
802displayAsymKeyObject( 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 */
906CK_RV
907displaySymKeyObject( 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 */
984CK_RV
985displayObject( 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 */
1035CK_RV
1036checkKey( 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 */
1069CK_RV
1070encryptData( 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
1142out:
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 */
1161CK_RV
1162decryptData( 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
1232out:
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 */
1250BOOL
1251isTokenInitialized( ) {
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 */
1263int
1264getMinPinLen( ) {
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 */
1276int
1277getMaxPinLen( ) {
1278
1279	if ( !g_bTokenOpen )
1280		return 0;
1281
1282	return (int)g_tToken.ulMaxPinLen;
1283}
1284