/* * 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 #include #include #include /* * 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; unsigned int i; CK_RV rv; CK_ULONG ulSlots; CK_SLOT_ID *ptSlots = NULL; 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 (rv != CKR_OK) free(ptSlots); 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 PKCS#11 library if ( g_pSoLib ) dlclose( g_pSoLib ); g_bTokenOpen = FALSE; g_bInit = FALSE; g_pSoLib = NULL; return rv; } /* * initToken * Invoke the PKCS#11 C_InitToken API. */ CK_RV initToken( char *a_pszPin ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_InitToken( g_tSlotId, (CK_CHAR *)a_pszPin, strlen( a_pszPin ), g_tToken.label ); pkcsResult( "C_InitToken", rv ); return rv; } /* * openTokenSession * Invoke the PKCS#11 C_OpenSession API. */ CK_RV openTokenSession( CK_FLAGS a_tType, CK_SESSION_HANDLE *a_phSession ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; a_tType |= CKF_SERIAL_SESSION; // This flag must always be set rv = g_pFcnList->C_OpenSession( g_tSlotId, a_tType, NULL, NULL, a_phSession ); pkcsResult( "C_OpenSession", rv ); return rv; } /* * closeTokenSession * Invoke the PKCS#11 C_CloseSession API. */ CK_RV closeTokenSession( CK_SESSION_HANDLE a_hSession ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_CloseSession( a_hSession ); pkcsResult( "C_CloseSession", rv ); return rv; } /* * closeAllTokenSessions * Invoke the PKCS#11 C_CloseAllSessions API. */ CK_RV closeAllTokenSessions( ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_CloseAllSessions( g_tSlotId ); pkcsResult( "C_CloseAllSessions", rv ); return rv; } /* * loginToken * Invoke the PKCS#11 C_Login API for the specified user type. */ CK_RV loginToken( CK_SESSION_HANDLE a_hSession, CK_USER_TYPE a_tType, char *a_pszPin ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_Login( a_hSession, a_tType, (CK_CHAR *)a_pszPin, strlen( a_pszPin ) ); pkcsResult( "C_Login", rv ); return rv; } /* * Invoke the PKCS#11 C_InitPin API. */ CK_RV initPin( CK_SESSION_HANDLE a_hSession, char *a_pszPin ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_InitPIN( a_hSession, (CK_CHAR *)a_pszPin, strlen( a_pszPin ) ); pkcsResult( "C_InitPIN", rv ); return rv; } /* * setPin * Invoke the PKCS#11 C_SetPIN API. */ CK_RV setPin( CK_SESSION_HANDLE a_hSession, char *a_pszOldPin, char *a_pszNewPin ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_SetPIN( a_hSession, (CK_CHAR *)a_pszOldPin, strlen( a_pszOldPin ), (CK_CHAR *)a_pszNewPin, strlen( a_pszNewPin ) ); pkcsResult( "C_SetPIN", rv ); return rv; } /* * generateKey * Invoke the PKCS#11 C_GenerateKey API to generate a key * for the specified mechanism with the specified attributes. */ CK_RV generateKey( CK_SESSION_HANDLE a_hSession, CK_MECHANISM *a_ptMechanism, CK_ATTRIBUTE *a_ptAttrList, CK_ULONG a_ulAttrCount, CK_OBJECT_HANDLE *a_phObject ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_GenerateKey( a_hSession, a_ptMechanism, a_ptAttrList, a_ulAttrCount, a_phObject ); pkcsResult( "C_GenerateKey", rv ); return rv; } /* * createObject * Invoke the PKCS#11 C_CreateObject API to create an object * with the specified attributes. */ CK_RV createObject( CK_SESSION_HANDLE a_hSession, CK_ATTRIBUTE *a_ptAttrList, CK_ULONG a_ulAttrCount, CK_OBJECT_HANDLE *a_phObject ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_CreateObject( a_hSession, a_ptAttrList, a_ulAttrCount, a_phObject ); pkcsResult( "C_CreateObject", rv ); return rv; } /* * destroyObject * Invoke the PKCS#11 C_DestroyObject API. */ CK_RV destroyObject( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_DestroyObject( a_hSession, a_hObject ); pkcsResult( "C_DestroyObject", rv ); return rv; } /* * getObjectAttributes * Invoke the PKCS#11 C_GetAttributeValue API to retrieve * the specified attributes. */ CK_RV getObjectAttributes( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, CK_ATTRIBUTE *a_ptAttrList, CK_ULONG a_ulAttrCount ) { CK_RV rv; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; rv = g_pFcnList->C_GetAttributeValue( a_hSession, a_hObject, a_ptAttrList, a_ulAttrCount ); pkcsResultException( "C_GetAttributeValue", rv, CKR_ATTRIBUTE_TYPE_INVALID ); return rv; } /* * findObjects * Return a list of object handles for all objects that * match the specified attributes. */ CK_RV findObjects( CK_SESSION_HANDLE a_hSession, CK_ATTRIBUTE *a_ptAttrList, CK_ULONG a_ulAttrCount, CK_OBJECT_HANDLE **a_phObjList, CK_ULONG *a_pulObjCount ) { CK_RV rv, rv_temp; CK_ULONG ulCount = 0; CK_ULONG ulCurCount = 0; CK_ULONG ulMaxCount = 0; CK_OBJECT_HANDLE *phObjList = NULL; *a_phObjList = NULL; *a_pulObjCount = 0; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; // Initialize the find operation rv = g_pFcnList->C_FindObjectsInit( a_hSession, a_ptAttrList, a_ulAttrCount ); pkcsResult( "C_FindObjectsInit", rv ); if ( rv != CKR_OK ) goto out; // Iterate until all object handles have been returned do { // Allocate (or increase) the object handle list buffer CK_OBJECT_HANDLE *phTemp = phObjList; ulMaxCount += TPM_FIND_MAX; phObjList = (CK_OBJECT_HANDLE *)calloc( sizeof( CK_OBJECT_HANDLE ), ulMaxCount ); if ( !phObjList ) { logError( _("Unable to obtain memory for object handle list\n") ); rv = CKR_HOST_MEMORY; goto done; } // Copy the list of object handles if ( phTemp ) { memcpy( phObjList, phTemp, ulCurCount * sizeof( CK_OBJECT_HANDLE ) ); free( phTemp ); } // Find the matching objects rv = g_pFcnList->C_FindObjects( a_hSession, phObjList + ulCurCount, TPM_FIND_MAX, &ulCount ); pkcsResult( "C_FindObjects", rv ); if ( rv != CKR_OK ) goto done; ulCurCount += ulCount; } while ( ulCurCount == ulMaxCount ); *a_phObjList = phObjList; *a_pulObjCount = ulCurCount; done: // Terminate the find operation rv_temp = g_pFcnList->C_FindObjectsFinal( a_hSession ); pkcsResult( "C_FindObjectsFinal", rv_temp ); out: if ( ( rv != CKR_OK ) && phObjList ) free( phObjList ); return rv; } /* * displayByteArray * Format a byte array for display. */ void displayByteArray( const char *a_pszLabel, CK_ATTRIBUTE *a_ptAttr, int a_bExtended ) { const char *pszPre = ( a_bExtended ) ? "\t" : ""; const char *pszPost = ( a_bExtended ) ? "\n" : ""; logMsg( "%s%s'", pszPre, a_pszLabel ); if ( a_ptAttr->ulValueLen ) logHex( a_ptAttr->ulValueLen, a_ptAttr->pValue ); else logMsg( "(null)" ); logMsg( "'%s", pszPost ); } /* * displayCertObject * Format a certificate object for display. */ CK_RV displayCertObject( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, int a_bExtended ) { CK_RV rv; CK_OBJECT_CLASS tClass; CK_BBOOL bToken; CK_BBOOL bPrivate; CK_BBOOL bModifiable; CK_CHAR *pszLabel = NULL; CK_CERTIFICATE_TYPE tType; CK_BBOOL bTrusted; CK_ATTRIBUTE tCertList[] = { { CKA_CLASS, &tClass, sizeof( tClass ) }, { CKA_TOKEN, &bToken, sizeof( bToken ) }, { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) }, { CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) }, { CKA_LABEL, NULL, 0 }, { CKA_CERTIFICATE_TYPE, &tType, sizeof( tType ) }, { CKA_TRUSTED, &bTrusted, sizeof( bTrusted ) }, }; CK_ATTRIBUTE tX509List[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_ID, NULL, 0 }, { CKA_ISSUER, NULL, 0 }, { CKA_SERIAL_NUMBER, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; CK_ATTRIBUTE tX509AttrList[] = { { CKA_OWNER, NULL, 0 }, { CKA_AC_ISSUER, NULL, 0 }, { CKA_SERIAL_NUMBER, NULL, 0 }, { CKA_ATTR_TYPES, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; CK_ULONG ulCertCount = sizeof( tCertList ) / sizeof( CK_ATTRIBUTE ); CK_ULONG ulX509Count = sizeof( tX509List ) / sizeof( CK_ATTRIBUTE ); CK_ULONG ulX509AttrCount = sizeof( tX509AttrList ) / sizeof( CK_ATTRIBUTE ); CK_ATTRIBUTE *ptAttrList; CK_ULONG ulAttrCount; // Retrieve the common certificate attributes rv = getObjectAttributes( a_hSession, a_hObject, tCertList, ulCertCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; // Allocate storage for the object label (extra byte for null // terminated string) if ( tCertList[ 4 ].ulValueLen > 0 ) { pszLabel = tCertList[ 4 ].pValue = calloc( 1, tCertList[ 4 ].ulValueLen + 1 ); rv = getObjectAttributes( a_hSession, a_hObject, tCertList, ulCertCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; } // Determine the attributes to retrieve based on the certficate type switch ( tType ) { case CKC_X_509: ptAttrList = tX509List; ulAttrCount = ulX509Count; break; case CKC_X_509_ATTR_CERT: ptAttrList = tX509AttrList; ulAttrCount = ulX509AttrCount; break; default: ptAttrList = NULL; ulAttrCount = 0; } if ( ptAttrList ) { CK_ULONG ulMalloc; // Retrieve the specific certificate type attributes (for obtaining // the attribute lengths) rv = getObjectAttributes( a_hSession, a_hObject, ptAttrList, ulAttrCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; for ( ulMalloc = 0; ulMalloc < ulAttrCount; ulMalloc++ ) { // Allocate the storage (with an extra byte for null terminated // strings - just in case) if ( ptAttrList[ ulMalloc ].ulValueLen > 0 ) ptAttrList[ ulMalloc ].pValue = calloc( 1, ptAttrList[ ulMalloc ].ulValueLen ); } // Now retrieve all the specific certificate type attributes rv = getObjectAttributes( a_hSession, a_hObject, ptAttrList, ulAttrCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; } if ( a_bExtended ) { logMsg( _("Certificate Object\n") ); switch ( tType ) { case CKC_X_509: logMsg( _("\tX509 Certificate\n") ); break; case CKC_X_509_ATTR_CERT: logMsg( _("\tX509 Attribute Certificate\n") ); break; default: logMsg( _("\tUnknown Certificate Type (%08x)\n"), tType ); } if ( tCertList[ 1 ].ulValueLen > 0 ) logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") ); if ( tCertList[ 2 ].ulValueLen > 0 ) logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") ); if ( tCertList[ 3 ].ulValueLen > 0 ) logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") ); if ( tCertList[ 4 ].ulValueLen > 0 ) logMsg( _("\tLabel: '%s'\n"), pszLabel ); if ( tCertList[ 5 ].ulValueLen > 0 ) logMsg( _("\tTrusted: %s\n"), bTrusted ? _("true") : _("false") ); // Display the attributes based on the certficate type switch ( tType ) { case CKC_X_509: if ( tX509List[ 0 ].ulValueLen > 0 ) displayByteArray( _("Subject: "), &tX509List[ 0 ], a_bExtended ); if ( tX509List[ 1 ].ulValueLen > 0 ) { logMsg( _("\tId: '%s' ("), tX509List[ 1 ].pValue ); displayByteArray( "", &tX509List[ 1 ], FALSE ); logMsg( ")\n" ); } if ( tX509List[ 2 ].ulValueLen > 0 ) displayByteArray( _("Issuer: "), &tX509List[ 2 ], a_bExtended ); if ( tX509List[ 3 ].ulValueLen > 0 ) displayByteArray( _("Serial Number: "), &tX509List[ 3 ], a_bExtended ); if ( tX509List[ 4 ].ulValueLen > 0 ) displayByteArray( _("Value: "), &tX509List[ 4 ], a_bExtended ); break; case CKC_X_509_ATTR_CERT: if ( tX509AttrList[ 0 ].ulValueLen > 0 ) displayByteArray( _("Owner: "), &tX509AttrList[ 0 ], a_bExtended ); if ( tX509AttrList[ 1 ].ulValueLen > 0 ) displayByteArray( _("Issuer: "), &tX509AttrList[ 1 ], a_bExtended ); if ( tX509AttrList[ 2 ].ulValueLen > 0 ) displayByteArray( _("Serial Number: "), &tX509AttrList[ 2 ], a_bExtended ); if ( tX509AttrList[ 3 ].ulValueLen > 0 ) displayByteArray( _("Attribute Types: "), &tX509AttrList[ 3 ], a_bExtended ); if ( tX509AttrList[ 4 ].ulValueLen > 0 ) displayByteArray( _("Value: "), &tX509AttrList[ 4 ], a_bExtended ); break; } } else { // Display the attributes based on the certficate type logMsg( _("Certificate: ") ); switch ( tType ) { case CKC_X_509: logMsg( _("Type: X509 Public Key") ); break; case CKC_X_509_ATTR_CERT: logMsg( _("Type: X509 Attribute") ); break; default: logMsg( _("Unknown Type (%08x)"), tType ); } if ( tCertList[ 4 ].ulValueLen > 0 ) logMsg( _(", Label: '%s'"), pszLabel ); logMsg( "\n" ); } return rv; } /* * displayAsymKeyObject * Format an asymmetric key object for display. */ CK_RV displayAsymKeyObject( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, int a_bExtended ) { CK_RV rv; CK_OBJECT_CLASS tClass; CK_BBOOL bToken; CK_BBOOL bPrivate; CK_BBOOL bModifiable; CK_CHAR *pszLabel = NULL; CK_KEY_TYPE tType; CK_CHAR *pszId = NULL; CK_ATTRIBUTE tKeyList[] = { { CKA_CLASS, &tClass, sizeof( tClass ) }, { CKA_TOKEN, &bToken, sizeof( bToken ) }, { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) }, { CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) }, { CKA_LABEL, NULL, 0 }, { CKA_KEY_TYPE, &tType, sizeof( tType ) }, { CKA_SUBJECT, NULL, 0 }, { CKA_ID, NULL, 0 }, }; CK_ULONG ulKeyCount = sizeof( tKeyList ) / sizeof( CK_ATTRIBUTE ); // Retrieve the common key attributes rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; // Allocate storage for the object id if ( ( tKeyList[ 4 ].ulValueLen > 0 ) || ( tKeyList[ 6 ].ulValueLen > 0 ) || ( tKeyList[ 7 ].ulValueLen > 0 ) ) { if ( tKeyList[ 4 ].ulValueLen > 0 ) pszLabel = tKeyList[ 4 ].pValue = calloc( 1, tKeyList[ 4 ].ulValueLen + 1 ); if ( tKeyList[ 6 ].ulValueLen > 0 ) tKeyList[ 6 ].pValue = calloc( 1, tKeyList[ 6 ].ulValueLen + 1 ); if ( tKeyList[ 7 ].ulValueLen > 0 ) pszId = tKeyList[ 7 ].pValue = calloc( 1, tKeyList[ 7 ].ulValueLen + 1 ); rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; } if ( a_bExtended ) { logMsg( _("Key Object\n") ); switch ( tClass ) { case CKO_PUBLIC_KEY: logMsg( _("\tPublic Key\n") ); break; case CKO_PRIVATE_KEY: logMsg( _("\tPrivate Key\n") ); break; } if ( tKeyList[ 1 ].ulValueLen > 0 ) logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") ); if ( tKeyList[ 2 ].ulValueLen > 0 ) logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") ); if ( tKeyList[ 3 ].ulValueLen > 0 ) logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") ); if ( tKeyList[ 4 ].ulValueLen > 0 ) logMsg( _("\tLabel: '%s'\n"), pszLabel ); if ( tKeyList[ 5 ].ulValueLen > 0 ) logMsg( _("\tType: %ld\n"), tType ); if ( tKeyList[ 6 ].ulValueLen > 0 ) displayByteArray( _("Subject: "), &tKeyList[ 6 ], a_bExtended ); if ( tKeyList[ 7 ].ulValueLen > 0 ) { logMsg( _("\tId: '%s' ("), pszId ); displayByteArray( "", &tKeyList[ 7 ], FALSE ); logMsg( ")\n" ); } } else { switch ( tClass ) { case CKO_PUBLIC_KEY: logMsg( _("Public Key: ") ); break; case CKO_PRIVATE_KEY: logMsg( _("Private Key: ") ); break; } if ( tKeyList[ 5 ].ulValueLen > 0 ) logMsg( _("Type: %ld"), tType ); if ( tKeyList[ 4 ].ulValueLen > 0 ) logMsg( _(", Label: '%s'"), pszLabel ); logMsg( "\n" ); } return rv; } /* * displaySymKeyObject * Format a symmetric key object for display. */ CK_RV displaySymKeyObject( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, int a_bExtended ) { CK_RV rv; CK_OBJECT_CLASS tClass; CK_BBOOL bToken; CK_BBOOL bPrivate; CK_BBOOL bModifiable; CK_CHAR *pszLabel = NULL; CK_KEY_TYPE tType; CK_ATTRIBUTE tKeyList[] = { { CKA_CLASS, &tClass, sizeof( tClass ) }, { CKA_TOKEN, &bToken, sizeof( bToken ) }, { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) }, { CKA_MODIFIABLE, &bModifiable, sizeof( bModifiable ) }, { CKA_LABEL, NULL, 0 }, { CKA_KEY_TYPE, &tType, sizeof( tType ) }, }; CK_ULONG ulKeyCount = sizeof( tKeyList ) / sizeof( CK_ATTRIBUTE ); // Retrieve the common key attributes rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; // Allocate storage for the object id if ( tKeyList[ 4 ].ulValueLen > 0 ) { pszLabel = tKeyList[ 4 ].pValue = calloc( 1, tKeyList[ 4 ].ulValueLen + 1 ); rv = getObjectAttributes( a_hSession, a_hObject, tKeyList, ulKeyCount ); if ( ( rv != CKR_OK ) && ( rv != CKR_ATTRIBUTE_TYPE_INVALID ) ) return rv; } if ( a_bExtended ) { logMsg( _("Key Object\n") ); switch ( tClass ) { case CKO_SECRET_KEY: logMsg( _("\tSecret Key\n") ); break; } if ( tKeyList[ 1 ].ulValueLen > 0 ) logMsg( _("\tToken Object: %s\n"), bToken ? _("true") : _("false") ); if ( tKeyList[ 2 ].ulValueLen > 0 ) logMsg( _("\tPrivate Object: %s\n"), bPrivate ? _("true") : _("false") ); if ( tKeyList[ 3 ].ulValueLen > 0 ) logMsg( _("\tModifiable Object: %s\n"), bModifiable ? _("true") : _("false") ); if ( tKeyList[ 4 ].ulValueLen > 0 ) logMsg( _("\tLabel: '%s'\n"), pszLabel ); if ( tKeyList[ 5 ].ulValueLen > 0 ) logMsg( _("\tType: %ld\n"), tType ); } else { switch ( tClass ) { case CKO_SECRET_KEY: logMsg( _("Secret Key: ") ); break; } if ( tKeyList[ 5 ].ulValueLen > 0 ) logMsg( _("Type: %ld"), tType ); if ( tKeyList[ 4 ].ulValueLen > 0 ) logMsg( _(", Label: '%s'"), pszLabel ); logMsg( "\n" ); } return rv; } /* * displayObject * Format and display objects. */ CK_RV displayObject( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, int a_bExtended ) { CK_RV rv; CK_OBJECT_CLASS tClass; CK_ATTRIBUTE tAttr[] = { { CKA_CLASS, &tClass, sizeof( tClass ) }, }; CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE ); // Retrieve the class attribute of the object rv = getObjectAttributes( a_hSession, a_hObject, tAttr, ulAttrCount ); if ( rv != CKR_OK ) return rv; // Use the object class to determine how to format it for display switch ( tClass ) { case CKO_DATA: logMsg( _("Data object\n") ); break; case CKO_CERTIFICATE: displayCertObject( a_hSession, a_hObject, a_bExtended ); break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: displayAsymKeyObject( a_hSession, a_hObject, a_bExtended ); break; case CKO_SECRET_KEY: displaySymKeyObject( a_hSession, a_hObject, a_bExtended ); break; case CKO_HW_FEATURE: case CKO_DOMAIN_PARAMETERS: default: logMsg( _("Object class=%ld\n"), tClass ); break; } return rv; } /* * checkKey * Check that the key object attributes match the key class * and key type specified. */ CK_RV checkKey( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, CK_OBJECT_CLASS a_tKeyClass, CK_KEY_TYPE a_tKeyType ) { CK_RV rv; CK_OBJECT_CLASS tClass; CK_KEY_TYPE tType; CK_ATTRIBUTE tAttr[] = { { CKA_CLASS, &tClass, sizeof( tClass ) }, { CKA_KEY_TYPE, &tType, sizeof( tType ) }, }; CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE ); // Retrieve the class attribute and key type attribute of the object rv = getObjectAttributes( a_hSession, a_hObject, tAttr, ulAttrCount ); if ( rv != CKR_OK ) return rv; if ( tClass != a_tKeyClass ) return CKR_GENERAL_ERROR; if ( tType != a_tKeyType ) return CKR_GENERAL_ERROR; return CKR_OK; } /* * encryptData * Use a callback mechanism to encrypt some data. */ CK_RV encryptData( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, CK_MECHANISM *a_ptMechanism, TokenCryptGet a_fGet, TokenCryptPut a_fPut ) { CK_RV rv; CK_BBOOL bCancel = FALSE; CK_BYTE *pbInData = NULL; CK_ULONG ulInDataLen = 0; CK_BBOOL bContinue = TRUE; CK_BYTE *pbBuffer = NULL; CK_ULONG ulBufferLen = 0; CK_ULONG ulOutDataLen = 0; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; // Check the key rv = checkKey( a_hSession, a_hObject, CKO_SECRET_KEY, CKK_AES ); if ( rv != CKR_OK ) goto out; // Initialize the encryption operation rv = g_pFcnList->C_EncryptInit( a_hSession, a_ptMechanism, a_hObject ); pkcsResult( "C_EncryptInit", rv ); if ( rv != CKR_OK ) goto out; while ( bContinue ) { // Retrieve some data to encrypt if ( a_fGet( &pbInData, &ulInDataLen, &bContinue, TRUE ) == -1 ) { bCancel = TRUE; goto out; } // Check the output buffer size needed rv = g_pFcnList->C_EncryptUpdate( a_hSession, pbInData, ulInDataLen, NULL, &ulOutDataLen ); pkcsResult( "C_EncryptUpdate", rv ); if ( rv != CKR_OK ) goto out; // Check if a larger buffer is needed if ( ulOutDataLen > ulBufferLen ) { free( pbBuffer ); ulBufferLen = ulOutDataLen; pbBuffer = calloc( 1, ulBufferLen ); if ( !pbBuffer ) { logError( _("Unable to obtain memory for the encrypted data buffer\n") ); rv = CKR_HOST_MEMORY; goto out; } } // Encrypt the input data rv = g_pFcnList->C_EncryptUpdate( a_hSession, pbInData, ulInDataLen, pbBuffer, &ulOutDataLen ); pkcsResult( "C_EncryptUpdate", rv ); if ( rv != CKR_OK ) goto out; if ( ulOutDataLen > 0 ) { if ( a_fPut( pbBuffer, ulOutDataLen, bContinue, TRUE ) == -1 ) { bCancel = TRUE; goto out; } } } out: // For AES any remaining data will cause an error, so provide // a buffer which will not be filled in anyway ulOutDataLen = ulBufferLen; rv = g_pFcnList->C_EncryptFinal( a_hSession, pbBuffer, &ulOutDataLen ); pkcsResult( "C_EncryptFinal", rv ); free( pbBuffer ); if ( bCancel ) rv = CKR_FUNCTION_CANCELED; return rv; } /* * decryptData * Use a callback mechanism to decrypt some data. */ CK_RV decryptData( CK_SESSION_HANDLE a_hSession, CK_OBJECT_HANDLE a_hObject, CK_MECHANISM *a_ptMechanism, TokenCryptGet a_fGet, TokenCryptPut a_fPut ) { CK_RV rv; CK_BBOOL bCancel = FALSE; CK_BYTE *pbInData = NULL; CK_ULONG ulInDataLen = 0; CK_BBOOL bContinue = TRUE; CK_BYTE *pbBuffer = NULL; CK_ULONG ulBufferLen = 0; CK_ULONG ulOutDataLen = 0; if ( !g_bTokenOpen ) return CKR_GENERAL_ERROR; // Check the key rv = checkKey( a_hSession, a_hObject, CKO_SECRET_KEY, CKK_AES ); if ( rv != CKR_OK ) goto out; // Initialize the decryption operation rv = g_pFcnList->C_DecryptInit( a_hSession, a_ptMechanism, a_hObject ); pkcsResult( "C_DecryptInit", rv ); if ( rv != CKR_OK ) goto out; while ( bContinue ) { // Retrieve some data to encrypt if ( a_fGet( &pbInData, &ulInDataLen, &bContinue, FALSE ) == -1 ) { bCancel = TRUE; goto out; } // Check the output buffer size needed rv = g_pFcnList->C_DecryptUpdate( a_hSession, pbInData, ulInDataLen, NULL, &ulOutDataLen ); pkcsResult( "C_DecryptUpdate", rv ); if ( rv != CKR_OK ) goto out; // Check if a larger buffer is needed if ( ulOutDataLen > ulBufferLen ) { free( pbBuffer ); ulBufferLen = ulOutDataLen; pbBuffer = calloc( 1, ulBufferLen ); if ( !pbBuffer ) { logError( _("Unable to obtain memory for the encrypted data buffer\n") ); rv = CKR_HOST_MEMORY; goto out; } } // Decrypt the input data rv = g_pFcnList->C_DecryptUpdate( a_hSession, pbInData, ulInDataLen, pbBuffer, &ulOutDataLen ); pkcsResult( "C_DecryptUpdate", rv ); if ( rv != CKR_OK ) goto out; if ( a_fPut( pbBuffer, ulOutDataLen, bContinue, FALSE ) == -1 ) { bCancel = TRUE; goto out; } } out: // For AES any remaining data will cause an error, so provide // a buffer which will not be filled in anyway rv = g_pFcnList->C_DecryptFinal( a_hSession, pbBuffer, &ulOutDataLen ); pkcsResult( "C_DecryptFinal", rv ); free( pbBuffer ); if ( bCancel ) rv = CKR_FUNCTION_CANCELED; return rv; } /* * isTokenInitialized * Returns an indicator as to whether the TPM token has been initialized. */ BOOL isTokenInitialized( ) { if ( g_bTokenOpen && ( g_tToken.flags & CKF_TOKEN_INITIALIZED ) ) return TRUE; return FALSE; } /* * getMinPinLen * Returns the the minimum PIN length that the TPM token accepts. */ int getMinPinLen( ) { if ( !g_bTokenOpen ) return 0; return (int)g_tToken.ulMinPinLen; } /* * getMaxPinLen * Returns the the maximum PIN length that the TPM token accepts. */ int getMaxPinLen( ) { if ( !g_bTokenOpen ) return 0; return (int)g_tToken.ulMaxPinLen; }