/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

//-----------------------------------------------------------------------
//
//      File Name:              scfunc.c
//
//      Description:    Pkcs11Msm smart card key functions 
//
//      Author:         Michael A. Crane
//
//      Version:                1.0
//
//      Comments:
//
//      Change Flags:
//
//              MAC000  08/08/98        Original Code   
//
//-----------------------------------------------------------------------

#include <stdio.h> 

#include <platform.h>
#include <asnbase.h>
#include <scfunc.h>
#include <appmem.h>
#include <cssm.h>
#include <cssmkeyformats.h>


#include <dsa.h>
#include <rsa.h>
#include <jkl.h>

#include <pkcsjnh.h>

#ifndef min
#define min(x,y) ((x<y)?x:y)
#endif

#define  PKCS11_library         "PKCS11.DLL"

CSSM_GUID                                               PkcsGuid = IBMPKCS11_GUID;
CSSM_VERSION                                    CssmVersion = {CSSM_MAJOR, CSSM_MINOR};
CSSM_VERSION                                    PkcsVersion = {IBMPKCS11_MAJOR_VERSION, IBMPKCS11_MINOR_VERSION};
CSSM_API_MEMORY_FUNCS                                   MemoryFuncs;


int                                                             gSessionCount;
int                                                             gModuleNextSlot;
CSSM_MODULE_HANDLE                              gModuleHandleList[MAX_HANDLES];
CSSM_ERROR_PTR                  pError;   

TIMEVALUE                       before, after;
unsigned long                   elapsed;
CSSM_DB_RECORD_ATTRIBUTE_DATA                   CssmRecordAttributes;
CSSM_SELECTION_PREDICATE                        CssmSelectionPredicate[12];
CSSM_QUERY                                      CssmQuery;


//
// Free Attribute Data List
//
uint32 scFreeAttributes(CSSM_DB_RECORD_ATTRIBUTE_DATA * pCssmRecordAttributes) {

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  uint32                                          ii = 0;
  uint32                                          jj = 0;
  CSSM_DATA_PTR                                   pCssmValue = NULL;
  uint8 *                                                 pdata;

  DEBUG_INFO("scFreeAttributes, numattributes = %d\n", 
             pCssmRecordAttributes->NumberOfAttributes);

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  for (jj = 0; jj < pCssmRecordAttributes->NumberOfAttributes; jj++)
  {
    pCssmAttrData = pCssmRecordAttributes->AttributeData + jj;
    pdata = pCssmAttrData->Value.Data;
//                      if (pdata != NULL)
//                    free(pdata);
  }

  MemoryFuncs.free_func(CssmRecordAttributes.AttributeData, MemoryFuncs.AllocRef);
  return 0;
}


//
// Find Serial Number
//
uint32 scGetSerialValue(CSSM_DB_RECORD_ATTRIBUTE_DATA * pCssmRecordAttributes, 
                        char * pserial) {

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  uint32                                          ii = 0;
  uint32                                          jj = 0;
  CSSM_DATA_PTR                                   pCssmValue = NULL;


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  for (jj = 0; jj < pCssmRecordAttributes->NumberOfAttributes; jj++)
  {
    pCssmAttrData = pCssmRecordAttributes->AttributeData + jj;
    if ((pCssmAttrData->Info.AttributeNumber == CKA_SERIAL_NUMBER) &&
        pCssmAttrData->Value.Data != NULL)
    {
      DEBUG_INFO("Length of serial = %x\n", pCssmAttrData->Value.Length);
      DEBUG_INFO("Serial = %s\n", pCssmAttrData->Value.Data);
      if (pserial != NULL) {
        DEBUG_INFO("pserial = %x\n", *pserial);
        memcpy(pserial, pCssmAttrData->Value.Data, pCssmAttrData->Value.Length);
      }
      return (uint32)pCssmAttrData->Value.Length;
    }
  }
  return 0;
}


//
// Find Certificate version field and extract it
//
uint32 scGetVersion(CSSM_DB_RECORD_ATTRIBUTE_DATA * pCssmRecordAttributes) {

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  uint32                                          ii = 0;
  uint32                                          jj = 0;
  CSSM_DATA_PTR                                   pCssmValue = NULL;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


  for (jj = 0; jj < pCssmRecordAttributes->NumberOfAttributes; jj++)
  {
    pCssmAttrData = pCssmRecordAttributes->AttributeData + jj;
    if ((pCssmAttrData->Info.AttributeNumber == CKA_ID) &&
        pCssmAttrData->Value.Data != NULL)
    {
      DEBUG_INFO("Length of data = %x\n", pCssmAttrData->Value.Length);
      DEBUG_INFO("Data = %x\n", *pCssmAttrData->Value.Data);
      return (uint32)*pCssmAttrData->Value.Data;
    }
  }
  return 0;
}


//
// Find Private Key version field and extract it
//
uint32 scGetPrivateVersion(CSSM_DB_RECORD_ATTRIBUTE_DATA * pCssmRecordAttributes) {

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  uint32                                          ii = 0;
  uint32                                          jj = 0;
  CSSM_DATA_PTR                                   pCssmValue = NULL;


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  for (jj = 0; jj < pCssmRecordAttributes->NumberOfAttributes; jj++)
  {
    pCssmAttrData = pCssmRecordAttributes->AttributeData + jj;
      if (pCssmAttrData->Info.AttributeNumber == CKA_APPLICATION &&
        pCssmAttrData->Value.Data != NULL)
      {
        DEBUG_INFO("Length of data = %x\n", pCssmAttrData->Value.Length);
        DEBUG_INFO("Data = %x\n", *pCssmAttrData->Value.Data);
        return (uint32)*pCssmAttrData->Value.Data;
      }
    }
  return 0;
}

//
// Find Value field and extract it
//

uint32 scGetCharValue(CSSM_DB_RECORD_ATTRIBUTE_DATA * pCssmRecordAttributes, char ** pvalue) {

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  uint32                                          ii = 0;
  uint32                                          jj = 0;
  CSSM_DATA_PTR                                   pCssmValue = NULL;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  for (jj = 0; jj < pCssmRecordAttributes->NumberOfAttributes; jj++)
  {
    pCssmAttrData = pCssmRecordAttributes->AttributeData + jj;
    if (pCssmAttrData->Info.AttributeNumber == CKA_VALUE &&
        pCssmAttrData->Value.Data != NULL)
    {
      DEBUG_INFO("Length of data = %x\n", pCssmAttrData->Value.Length);
      DEBUG_INFO("Data = %s\n", pCssmAttrData->Value.Data);
      *pvalue = (char *)pCssmAttrData->Value.Data;
      return (uint32)pCssmAttrData->Value.Length;
    }
  }
  return NULL;
}



//
// ModuleAttach - 
//

int scModuleAttach(
  uint32 subserviceID,
  char inputExclusive,
  char inputRW,
  char inputSerial)
{
  uint32                     CssmRc;
  CSSM_MODULE_HANDLE      hCssmModule;
  uint32                          subserviceFlags = 0;

  int                                     ii;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


  if (inputExclusive == 'y')
    subserviceFlags |= CSSM_CSP_SESSION_EXCLUSIVE;

  if (inputRW == 'y')
    subserviceFlags |= CSSM_CSP_SESSION_READWRITE;

  if (inputSerial == 'y')
    subserviceFlags |= CSSM_CSP_SESSION_SERIAL;


  hCssmModule = CSSM_ModuleAttach(&PkcsGuid, 
                &PkcsVersion,
                &MemoryFuncs, 
                subserviceID,                   // SlotID 
                subserviceFlags,                // Flags 
                subserviceID,                   // Nonce
                NULL, 
                NULL);
  if (hCssmModule == 0)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("CSSM_ModuleAttach fails, rc = %d\n", pError->error);
    return SC_MODULE_ATTACH_ERROR;
  }
  else
  {
    for (ii = 1; ii < gModuleNextSlot; ii++)
    {
      if (gModuleHandleList[ii] == 0)
        break;
    }

    if (ii == gModuleNextSlot)
    {
      if (gModuleNextSlot < MAX_HANDLES)
      {
        DEBUG_INFO("Session ID is %d\n", gModuleNextSlot);
        gModuleHandleList[gModuleNextSlot++] = hCssmModule;
        gSessionCount++;

        return gModuleNextSlot - 1;
      }
      else
      {
        DEBUG_INFO("Session limit of %d has been reached!\n", MAX_HANDLES);
        CssmRc = CSSM_ModuleDetach(hCssmModule); 
        if (CssmRc != SC_OK)
        {
          pError = CSSM_GetError();
          DEBUG_INFO("CSSM_ModuleDetach fails, rc = %d\n", pError->error);
        }

        return SC_SESSION_LIMIT;
                
      }
    }
    else
    {
      DEBUG_INFO("Session ID is %d\n", ii);
      gModuleHandleList[ii] = hCssmModule;
      gSessionCount++;

      return ii;
    }
  }
}



//
// ModuleDetach
//

uint32 scModuleDetach(
  int sessionID)
{
  uint32                     ret = SC_MODULE_DETACH_ERROR;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


  if ((sessionID < gModuleNextSlot) && (gModuleHandleList[sessionID] != 0))
  {
    ret = CSSM_ModuleDetach(gModuleHandleList[sessionID]); 
    if (ret != SC_OK)
    {
      pError = CSSM_GetError();
      DEBUG_INFO("CSSM_ModuleDetach fails, rc = %d\n", pError->error);
    }
    else
    {
      gSessionCount--;
      gModuleHandleList[sessionID] = 0;
    }
  }
  else
  {
    DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
  }

  return ret;
}

//
// Figure out if smart card is initialized
//
CSSM_BOOL scIsTokenInitialized(void * ptr) {
  CK_ULONG                ulCount;
  CK_SLOT_ID_PTR  pSlotList;
  CK_SLOT_INFO    slotInfo;
  CK_TOKEN_INFO   tokenInfo;
  CK_RV                   rv;

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_C_Initialize                 C_Initialize;
  CK_C_GetSlotList                          C_GetSlotList;
  CK_C_GetSlotInfo                          C_GetSlotInfo;
  CK_C_GetTokenInfo                         C_GetTokenInfo;
  CK_C_Finalize                   C_Finalize;
  char*                                       pLibName; 
  

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {
    DEBUG_INFO("PKCS library = %s\n", pLibName);

    C_Initialize    = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_GetSlotList   = (CK_C_GetSlotList) GetProcAddress(hPkcsModule, "C_GetSlotList");        
    C_GetSlotInfo   = (CK_C_GetSlotInfo) GetProcAddress(hPkcsModule, "C_GetSlotInfo");        
    C_GetTokenInfo  = (CK_C_GetTokenInfo) GetProcAddress(hPkcsModule, "C_GetTokenInfo");        
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_GetSlotList && C_GetSlotInfo && C_GetTokenInfo && C_Finalize)
    {
#endif

  DEBUG_MSG("In scIsTokenInitialized\n");

  // Get number of slots with inserted tokens

  DEBUG_MSG("Calling C_Initialize\n");
  rv = C_Initialize(NULL);
  DEBUG_INFO("rv = %x.  Calling C_GetSlotList\n", rv);
  rv = C_GetSlotList(TRUE, NULL_PTR, &ulCount);
  DEBUG_INFO("rv = %x\n", rv);
  DEBUG_INFO("C_GetSlotList returns with count of %d\n", ulCount);
  if ((rv==CKR_OK) && (ulCount>0)) {
    pSlotList =
 (CK_SLOT_ID_PTR)MemoryFuncs.malloc_func(ulCount*sizeof(CK_SLOT_ID),
                                         MemoryFuncs.AllocRef);
    rv = C_GetSlotList(TRUE, pSlotList, &ulCount);
    DEBUG_INFO("C_GetSlotList returns with %x\n", rv);
    rv = C_GetSlotInfo(pSlotList[0], &slotInfo);
    DEBUG_INFO("C_GetSlotInfo returns with %x\n", rv);
    rv = C_GetTokenInfo(pSlotList[0], &tokenInfo);
    DEBUG_INFO("C_GetTokenInfo returns with %x\n", rv);
    MemoryFuncs.free_func(pSlotList, MemoryFuncs.AllocRef);
    DEBUG_INFO("RC from C_GetTokenInfo = %x\n", rv);
    if (rv == CKR_OK) {
      DEBUG_INFO("tokenInfo.flags = %x\n", tokenInfo.flags);
      if (tokenInfo.flags & CKF_USER_PIN_INITIALIZED) {
        DEBUG_MSG("Exit scIsTokenInitialized = TRUE\n");
        rv = C_Finalize(NULL);
#ifndef STATIC_LINK
        FreeLibrary(hPkcsModule);
#endif
        return TRUE;
      }
    }
  }
  rv = C_Finalize(NULL);
#ifndef STATIC_LINK
    } else {
      DEBUG_MSG("One of the functions not defined\n");
    }
  } else {
    DEBUG_INFO("PKCS library %s failed to load\n",  pLibName);
  }
    
  FreeLibrary(hPkcsModule);
#endif
  DEBUG_MSG("Exit scIsTokenInitialized = FALSE\n");
  return FALSE;
}


//
// SC Login
//

uint32 scLogin(
  int sessionID,
  char* pPIN)
{
  uint32                     ret = SC_LOGIN_ERROR;
  CSSM_CRYPTO_DATA        CssmPIN;
  CSSM_DATA                       CssmPINData;
  CSSM_MODULE_HANDLE      hCssmModule;


  char                tmpBuf[256];

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  
  if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
  {

    CssmPINData.Data = (CK_CHAR_PTR)pPIN;
    CssmPINData.Length = strlen(pPIN);
    CssmPIN.Param = &CssmPINData;
    CssmPIN.Callback = NULL;
    CssmPIN.CallbackID = 0;

    ret = CSSM_CSP_Login(hCssmModule, &CssmPIN, NULL);
    if (ret != SC_OK)
    {
      pError = CSSM_GetError();
      DEBUG_INFO("CSSM_Login Fails,  RC = %d\n", pError->error);
    }

  }
  else
  {
    DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
  }

  return ret;
}



//
// scLogout
//

uint32 scLogout(
  int sessionID)
{
  uint32                     ret = SC_LOGOUT_ERROR;
  CSSM_MODULE_HANDLE      hCssmModule;


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }
  
  if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
  {
    ret = CSSM_CSP_Logout(hCssmModule);
    if (ret != SC_OK)
    {
      pError = CSSM_GetError();
      DEBUG_INFO("CSSM_Logout fails,  rc = %d\n", pError->error);
    }
  }
  else
  {
    DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
  }

  return ret;
}



//
// testGetModuleInfo
//

uint32 GetModuleInfo(      )
{
  uint32                             ret = SC_MODULE_INFO_ERROR;
  CSSM_MODULE_INFO_PTR    pCssmModuleInfo;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  pCssmModuleInfo = CSSM_GetModuleInfo(
            &PkcsGuid,
            0,            // ServiceMask,
      CSSM_ALL_SUBSERVICES,           // SubserviceID,
      CSSM_INFO_LEVEL_ALL_ATTR);      // InfoLevel);
    
  if (pCssmModuleInfo == NULL)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("CSSM_GetModuleInfo fails,  rc = %d\n", pError->error);
  }
  else
  {
    CSSM_FreeModuleInfo(pCssmModuleInfo);
    ret = SC_OK;
  }

  return ret;
}



//
// testFreeModuleInfo
//

uint32 FreeModuleInfo( )
{
  uint32                             ret = SC_FREE_MODULE_INFO_ERROR;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }
  
  return ret;
}


//
// scInitToken -
//

uint32 scInitializeCard(const char * current_pin, 
      const char * newpin)
{
  int                                                 slotID=1;
  char*                                       pLibName; 
  uint32                             ret = SC_INITIALIZATION_ERROR;

  CK_RV                                   rc;
  CK_CHAR                                 token_label[] = "PKIX Token";

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_SESSION_HANDLE                                   session;
  CK_C_Initialize                 C_Initialize;
  CK_C_InitToken                  C_InitToken;
  CK_C_OpenSession                          C_OpenSession;
  CK_C_CloseSession                         C_CloseSession;
  CK_C_Login                                C_Login;      
  CK_C_Finalize                   C_Finalize;
  
  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {

    if (newpin == NULL) {
      newpin = current_pin;
    }

    C_Initialize    = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_InitToken             = (CK_C_InitToken) GetProcAddress(hPkcsModule, "C_InitToken");
    C_OpenSession   = (CK_C_OpenSession) GetProcAddress(hPkcsModule, "C_OpenSession");        
    C_CloseSession  = (CK_C_CloseSession) GetProcAddress(hPkcsModule, "C_CloseSession");
    C_Login             = (CK_C_Login) GetProcAddress(hPkcsModule, "C_Login");
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_InitToken && C_OpenSession && C_Login && C_CloseSession && C_Finalize)
    {
#endif

      if ((rc = C_Initialize(NULL)) == CKR_OK)
      {
        if ((rc = C_OpenSession(slotID, CKF_RW_SESSION|CKF_SERIAL_SESSION, 0, 0, &session)) == CKR_OK)
        {
          DEBUG_INFO("C_OpenSession(%d) succeeds!\n", slotID);
        }
        else
        {
          DEBUG_INFO("C_OpenSession(%d) fails!\n", slotID);
          return rc;
        }

        if ((rc = C_Login(session, CKU_SO, (CK_CHAR_PTR)current_pin, strlen(current_pin))) == CKR_OK)
        {
          DEBUG_INFO("C_Login(%d) succeeds!\n", slotID);
        }
        else
        {
          DEBUG_INFO("C_Login(%d) fails!\n", slotID);
          return rc;
        }
        
        if ((rc = C_InitToken(slotID, (CK_CHAR_PTR)newpin, strlen(newpin), (CK_CHAR_PTR)&token_label)) == CKR_OK)
        {
          DEBUG_INFO("C_InitToken(%d) succeeds!\n", slotID);
          ret = SC_OK;
        }
        else if (rc == CKR_FUNCTION_NOT_SUPPORTED)
        {
          DEBUG_MSG("C_InitToken not supported, assuming card already formatted\n");
          ret = SC_OK;
        }
        else
        {
          DEBUG_INFO("C_InitToken(%x) fails\n", rc);
          return rc;
        }

//                              if ((rc = C_CloseSession(session)) == CKR_OK)
//                              {
//                                      DEBUG_INFO("C_CloseSession(%d) succeeds!\n", slotID);
//                              }
//                              else
//                              {
//                                      DEBUG_INFO("C_CloseSession(%d) fails!\n", slotID);
//                                      return rc;
//                              }

      }
      else
      {
        DEBUG_MSG("C_Initialize fails!\n");
        return rc;
      }
      
      rc = C_Finalize(NULL);
      DEBUG_INFO("Rc from C_Finalize Session=%x\n", rc);

#ifndef STATIC_LINK
    }
    else
    {
      DEBUG_MSG("GetProcAddress fails!\n");
      return ret;
    }

    FreeLibrary(hPkcsModule);
  }
  else
  {
    DEBUG_INFO("\nLoadLibrary(%s) fails!\n", pkcsLibName);
    return ret;
  }
#endif

  return ret;
}



//
// scSetUserPIN -
//

uint32 scSetUserPin(const char * sopin, 
      const char * userpin)
{
  int                                                 slotID=1;
  char*                                       pLibName;
  uint32                             ret = SC_SET_USER_PIN_ERROR;

  CK_RV                                   rc;
  CK_SESSION_HANDLE               hSession;
  char                                    PIN[256];

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_C_Initialize                 C_Initialize;
  CK_C_OpenSession                C_OpenSession;
  CK_C_CloseSession               C_CloseSession;
  CK_C_Login                              C_Login;
  CK_C_InitPIN                    C_InitPIN;
  CK_C_Finalize                   C_Finalize;
#endif


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


#ifndef STATIC_LINK
  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {
    C_Initialize    = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_OpenSession   = (CK_C_OpenSession) GetProcAddress(hPkcsModule, "C_OpenSession");
    C_CloseSession  = (CK_C_CloseSession) GetProcAddress(hPkcsModule, "C_CloseSession");
    C_Login                 = (CK_C_Login) GetProcAddress(hPkcsModule, "C_Login");
    C_InitPIN               = (CK_C_InitPIN) GetProcAddress(hPkcsModule, "C_InitPIN");
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_OpenSession && C_CloseSession && C_Login && C_SetPIN && C_Finalize)
    {
#endif
      if ((rc = C_Initialize(NULL)) == CKR_OK)
      {
        if ((rc = C_OpenSession(slotID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &hSession)) == CKR_OK)
        {
          if ((rc = C_Login(hSession, CKU_SO, (CK_CHAR_PTR)sopin, strlen(sopin))) == CKR_OK)
          {
            DEBUG_MSG("C_Login(\"SO\") succeeds!\n");
            if ((rc = C_InitPIN(hSession, (CK_CHAR_PTR)userpin, strlen(userpin))) == CKR_OK)
            {
              DEBUG_INFO("C_InitPIN(\"%s\") succeeds!\n", userpin);
              if ((rc = C_CloseSession(hSession)) == CKR_OK)
              {
                DEBUG_INFO("C_Closession(%d) succeeds!\n", hSession);
                ret = SC_OK;
              }
              else
              {
                DEBUG_INFO("C_Closession(%d) fails!\n", hSession);
              }
            }
            else
            {
              DEBUG_INFO("C_SetPIN(\"%s\") fails!\n", userpin);
            }
          }
          else
          {
            DEBUG_MSG("C_Login(\"SO\") fails!\n");
          }
        }
        else
        {
          DEBUG_INFO("C_OpenSession(%x) fails!\n", rc);
        }
      }
      else
      {
        DEBUG_MSG("C_Initialize fails!\n");
      }
      
      rc = C_Finalize(NULL);
      DEBUG_INFO("Rc from C_Finalize Session=%x\n", rc);

#ifndef STATIC_LINK
    }
    else
    {
      DEBUG_MSG("GetProcAddress fails!\n");
    }

    FreeLibrary(hPkcsModule);
  }
  else
  {
    DEBUG_INFO("LoadLibrary(%s) fails!\n", pkcsLibName);
  }
#endif
  
  return ret;
}


//
// scChangeUserPIN -
//

uint32 scChangeUserPin(const char * current_pin, 
      const char * newpin)
{
  int                                                 slotID=1;
  char*                                       pLibName;
  uint32                             ret = SC_CHANGE_USER_PIN_ERROR;

  CK_RV                                   rc;
  CK_SESSION_HANDLE               hSession;
  char                                    PIN[256];

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_C_Initialize                 C_Initialize;
  CK_C_OpenSession                C_OpenSession;
  CK_C_CloseSession               C_CloseSession;
  CK_C_Login                              C_Login;
  CK_C_SetPIN                    C_SetPIN;
  CK_C_Finalize                   C_Finalize;
#endif


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

#ifndef STATIC_LINK
  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {

    C_Initialize    = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_OpenSession   = (CK_C_OpenSession) GetProcAddress(hPkcsModule, "C_OpenSession");
    C_CloseSession  = (CK_C_CloseSession) GetProcAddress(hPkcsModule, "C_CloseSession");
    C_Login                 = (CK_C_Login) GetProcAddress(hPkcsModule, "C_Login");
    C_SetPIN               = (CK_C_SetPIN) GetProcAddress(hPkcsModule, "C_SetPIN");
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_OpenSession && C_CloseSession && C_Login && C_SetPIN && C_Finalize)
    {
#endif
      if ((rc = C_Initialize(NULL)) == CKR_OK)
      {
        if ((rc = C_OpenSession(slotID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &hSession)) == CKR_OK)
        {
          if ((rc = C_Login(hSession, CKU_USER, (CK_CHAR_PTR)current_pin, strlen(current_pin))) == CKR_OK)
          {
            DEBUG_MSG("C_Login(\"SO\") succeeds!\n");
            if ((rc = C_SetPIN(hSession, (CK_CHAR_PTR)current_pin, strlen(current_pin), (CK_CHAR_PTR)newpin, strlen(newpin))) == CKR_OK)
            {
              DEBUG_INFO("C_SetPIN(\"%s\") succeeds!\n", current_pin);
              if ((rc = C_CloseSession(hSession)) == CKR_OK)
              {
                DEBUG_INFO("C_Closession(%d) succeeds!\n", hSession);
                ret = SC_OK;
              }
              else
              {
                DEBUG_INFO("C_Closession(%d) fails!\n", hSession);
              }
            }
            else
            {
              DEBUG_INFO("C_SetPIN(\"%s\") fails!\n", current_pin);
            }
          }
          else
          {
            DEBUG_MSG("C_Login(\"SO\") fails!\n");
          }
        }
        else
        {
          DEBUG_INFO("C_OpenSession(%d) fails!\n", slotID);
        }
      }
      else
      {
        DEBUG_MSG("C_Initialize fails!\n");
      }
      
      rc = C_Finalize(NULL);
      DEBUG_INFO("Rc from C_Finalize Session=%x\n", rc);

#ifndef STATIC_LINK
    }
    else
    {
      DEBUG_MSG("GetProcAddress fails!\n");
    }

    FreeLibrary(hPkcsModule);
  }
  else
  {
    DEBUG_INFO("LoadLibrary(%s) fails!\n", pkcsLibName);
  }
#endif
  
  return ret;
}





//
// scChangeSOPIN -
//

uint32 scChangeSOPin(const char * pSOPIN, 
      const char *pnewSOPIN)
{
  int                                                 slotID=1;
  char*                                       pLibName; 
  uint32                             ret = SC_CHANGE_SO_PIN_ERROR;

  CK_RV                                   rc;
  CK_SESSION_HANDLE               hSession;
  char                                    PIN[256];

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_C_Initialize                 C_Initialize;
  CK_C_OpenSession                        C_OpenSession;
  CK_C_CloseSession                       C_CloseSession;
  CK_C_Login                              C_Login;
  CK_C_InitPIN                    C_InitPIN;
  CK_C_Finalize                   C_Finalize;
#endif

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


#ifndef STATIC_LINK
  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {

    C_Initialize    = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_OpenSession   = (CK_C_OpenSession) GetProcAddress(hPkcsModule, "C_OpenSession");
    C_CloseSession  = (CK_C_CloseSession) GetProcAddress(hPkcsModule, "C_CloseSession");
    C_Login                 = (CK_C_Login) GetProcAddress(hPkcsModule, "C_Login");
    C_InitPIN               = (CK_C_InitPIN) GetProcAddress(hPkcsModule, "C_InitPIN");
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_OpenSession && C_CloseSession && C_Login && C_InitPIN && C_Finalize)
    {
#endif
      if ((rc = C_Initialize(NULL)) == CKR_OK)
      {
        if ((rc = C_OpenSession(slotID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &hSession)) == CKR_OK)
        {
          if ((rc = C_Login(hSession, CKU_SO, (CK_CHAR_PTR)pSOPIN, strlen(pSOPIN))) == CKR_OK)
          {
            DEBUG_MSG("C_Login(\"SO\") succeeds!\n");
            if ((rc = C_SetPIN(hSession, (CK_CHAR_PTR)pSOPIN, (CK_ULONG) strlen(pSOPIN), (CK_CHAR_PTR)pnewSOPIN, (CK_ULONG) strlen(pnewSOPIN))) == CKR_OK)
            {
              DEBUG_INFO("C_SetPIN(\"%s\") succeeds!\n", pnewSOPIN);
              if ((rc = C_CloseSession(hSession)) == CKR_OK)
              {
                DEBUG_INFO("C_Closession(%d) succeeds!\n", hSession);
                ret = SC_OK;
              }
              else
              {
                DEBUG_INFO("C_Closession(%d) fails!\n", hSession);
              }
            }
            else
            {
              DEBUG_INFO("C_SetPIN(\"%s\") fails!\n", pnewSOPIN);
            }
          }
          else
          {
            DEBUG_MSG("C_Login(\"SO\") fails!\n");
          }
        }
        else
        {
          DEBUG_INFO("C_OpenSession(%d) fails!\n", slotID);
        }
      }
      else
      {
        DEBUG_MSG("C_Initialize fails!\n");
      }
      
      rc = C_Finalize(NULL);
      DEBUG_INFO("Rc from C_Finalize Session=%x\n", rc);

#ifndef STATIC_LINK
    }
    else
    {
      DEBUG_MSG("GetProcAddress fails!\n");
    }

    FreeLibrary(hPkcsModule);
  }
  else
  {
    DEBUG_INFO("LoadLibrary(%s) fails!\n", pkcsLibName);
  }
#endif
  
  return ret;
}


//
// testCloseAllSessions
//

uint32 CloseAllSessions(
  char* pLibName, 
  int slotID)
{
  uint32             ret = SC_CLOSE_ALL_SESSIONS_ERROR;

  CK_RV                   rc;

#ifndef STATIC_LINK
  HINSTANCE                               hPkcsModule;
  char                                    pkcsLibName[256] = "";
  CK_C_Initialize                 C_Initialize;
  CK_C_CloseAllSessions   C_CloseAllSessions;
  CK_C_Finalize                   C_Finalize;
#endif

  int                                             ii;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  strcpy(pkcsLibName, PKCS11_library);
  pLibName = pkcsLibName;

#ifndef STATIC_LINK
  if ((hPkcsModule = LoadLibrary(pLibName)) != NULL)
  {

    C_Initialize            = (CK_C_Initialize) GetProcAddress(hPkcsModule, "C_Initialize");        
    C_CloseAllSessions      = (CK_C_CloseAllSessions) GetProcAddress(hPkcsModule, "C_CloseAllSessions");
    C_Finalize      = (CK_C_Finalize) GetProcAddress(hPkcsModule, "C_Finalize");        
  
    if (C_Initialize && C_CloseAllSessions && C_Finalize)
    {
#endif

      if ((rc = C_Initialize(NULL)) == CKR_OK)
      {
        if ((rc = C_CloseAllSessions(slotID)) == CKR_OK)
        {
          DEBUG_INFO("C_CloseAllSessions(%d) succeeds!\n", slotID);
          gSessionCount = 0;
          gModuleNextSlot = 1;
          for (ii = 0; ii < MAX_HANDLES; ii++)
          {
            gModuleHandleList[ii] = 0;
          }
          ret = SC_OK;
        }
        else
        {
          DEBUG_INFO("C_CloseAllSessions(%d) fails!\n", slotID);
        }

      }
      else
      {
        DEBUG_MSG("C_Initialize fails!\n");
      }
      
      rc = C_Finalize(NULL);
      DEBUG_INFO("Rc from C_Finalize Session=%x\n", rc);

#ifndef STATIC_LINK
    }
    else
    {
      DEBUG_MSG("GetProcAddress fails!\n");
    }

    FreeLibrary(hPkcsModule);
  }
  else
  {
    DEBUG_INFO("LoadLibrary(%s) fails!\n", pkcsLibName);
  }
#endif

  return ret;
}


//
// scDbOpen
//

int scDbOpen(
  int sessionID,
  char* pPIN,
  CSSM_BOOL privilegedMode)
{
  CSSM_DATA                                       CssmCredential;
  CSSM_USER_AUTHENTICATION        CssmUserAuthentication;
  CSSM_DB_ACCESS_TYPE                     CssmDbAccessType;
  CSSM_MODULE_HANDLE                      hCssmModule;
  CSSM_DB_HANDLE                          hCssmDbHandle;

  char                                            tempBuf[256];
  char                                            inputPrivilege;

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }


  if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
  {
    CssmDbAccessType.PrivilegedMode = privilegedMode;

    CssmCredential.Data = (CK_CHAR_PTR)pPIN;
    CssmCredential.Length = strlen(pPIN);
    CssmUserAuthentication.Credential = &CssmCredential;
    CssmUserAuthentication.MoreAuthenticationData = NULL;

    hCssmDbHandle = CSSM_DL_DbOpen(hCssmModule, NULL, &CssmDbAccessType, &CssmUserAuthentication, NULL);
    if (hCssmDbHandle == 0)
    {
      pError = CSSM_GetError();
      DEBUG_INFO("CSSM_DL_DbOpen fails, rc = %d\n", pError->error);
      return SC_DB_OPEN_ERROR;
    }

    DEBUG_INFO("DB Handle = %d\n", hCssmDbHandle);
    return hCssmDbHandle;
  }
  else
  {
    DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
    return SC_SESSION_ID_INVALID;
  }

}


//
// DbClose
//

uint32 scDbClose(
  int sessionID,
  CSSM_HANDLE dbHandle)
{
  uint32                                     ret = SC_DB_CLOSE_ERROR;

  uint32                                     CssmRc;
  CSSM_MODULE_HANDLE                      hCssmModule;
  CSSM_DL_DB_HANDLE                       hCssmDlDb;


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
  {
    hCssmDlDb.DLHandle = hCssmModule;
    
    hCssmDlDb.DBHandle = dbHandle;

    CssmRc = CSSM_DL_DbClose(hCssmDlDb);
    if (CssmRc != SC_OK)
    {
      pError = CSSM_GetError();
      DEBUG_INFO("CSSM_DL_DbClose fails, rc = %d\n", pError->error);
    }

    ret = SC_OK;
  }
  else
  {
    DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
  }

  return ret;
}


//
// PrivateKeyDataInsert -
//

uint32 scPrivateKeyDataInsert(
  int sessionID,
  CSSM_HANDLE dbHandle,
  char * key,
  int      keylen,
  CSSM_DATA_PTR precordid,
      char * pserial,
      int seriallen,
      char * psubject, 
      int subjectlen,
      char * pissuer, 
      int issuerlen,
      int version
)
{
  uint32                        ret = SC_PRIVATE_KEY_INSERT_ERROR;

  CSSM_MODULE_HANDLE                                      hCssmModule;
  CSSM_DL_DB_HANDLE                                       hCssmDlDb;
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                                       CssmData;
  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttributes;
  char                                                    pkix_label[] = TOKEN_LABEL;
  char                                                    pkix_application[] = TOKEN_APPLICATION;
  CSSM_KEY                                                pk;     
  CSSM_KEY_PTR                                    pCssmKey;
  CK_KEY_TYPE                                                     ktype;
  CK_BBOOL                                                        bprivate = TRUE;
  CK_BBOOL                                                        token_object = TRUE;
  CK_BBOOL                                                        modifiable_object = FALSE;
  CK_BBOOL                                                        sensitive = TRUE;
  CK_BBOOL                                                        sign = TRUE;
  CK_OBJECT_CLASS                                         oclass = CKO_PRIVATE_KEY;
  int                                                             extraexps = 0;

  // variables for parsing private dsa key
  PrivateKeyInfo privatekeyinfo;
  buffer_t encoding;
  r_buffer_t pkey;
  DssPrivateParms dssPrivateParms;
  RSAPrivateKey   rsaPrivateParms;
  unsigned char* p;
  unsigned bc;
  DssPrivateKey privatekey;
  r_buffer_t b;
  unsigned long rsaEncryption_val[7]              = {1,2,840,113549,1,1,1};
  unsigned long dsa_val[6]                        = {1,2,840,10040,4,1};
  unsigned long dsa_alt_val[6]                    = {1,3,14,3,2,12};

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  pkey.data = (unsigned char *)key;
  pkey.data_len = keylen;

  DEBUG_INFO("Private Key = %s\n", pkey.data);
  DEBUG_INFO("Private Key length = %d\n", pkey.data_len); 

  DEBUG_MSG("About to read private key into info struct\n");
  if (privatekeyinfo.read(pkey) != 0) {
    DEBUG_MSG("Failed to read in private key, continuing\n");
    // return SC_PRIVATE_KEY_READ_ERROR;
  }

  PrivateKeyInfo & keyinfo = privatekeyinfo;

  DEBUG_MSG("About to see what kind of algorithm\n");
  if ( keyinfo.privateKeyAlgorithm.algorithm.is_equal(rsaEncryption_val, 7) )
  {
    DEBUG_MSG("Algorithm is CSSM_ALGID_RSA_PKCS\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_RSA_PKCS;
  }
  else if ( keyinfo.privateKeyAlgorithm.algorithm.is_equal(dsa_val, 6) ||
      keyinfo.privateKeyAlgorithm.algorithm.is_equal(dsa_alt_val, 6) )
  {
    DEBUG_MSG("Algorithm is CSSM_ALGID_DSA\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_DSA;
  }
  else
  {
    DEBUG_MSG("Could not tell what algorithm, so note private key as is\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_NONE;
  }

  if (pk.KeyHeader.AlgorithmId == CSSM_ALGID_DSA) {
    // Extract dssPrivateParams

    DEBUG_MSG("encoding private key\n");
    if ((ret = privatekeyinfo.privateKeyAlgorithm.parameters.write(encoding)) != 0)
      return ret;
    if ((ret = dssPrivateParms.read(encoding)) != 0)
      return ret;

    DEBUG_MSG("Getting private key parts\n");
    // Extract x
    if ((ret = privatekeyinfo.privateKey.get_value(p, bc)) != 0)
      return ret;
    b.data     = p; 
    b.data_len = bc;
    if ((ret = privatekey.read(b)) != 0)
      return ret;

    // store these values as the private key
    long p, q, g, l;
    long & pval = p, & qval = q, & gval = g, & lval = l;
    dssPrivateParms.p.get_value(pval);
    DEBUG_INFO("DSS .p = %d\n", p); // is CKA_PRIME
    dssPrivateParms.q.get_value(qval);
    DEBUG_INFO("DSS .q = %d\n", q); // is CKA_SUBPRIME
    dssPrivateParms.g.get_value(gval);
    DEBUG_INFO("DSS .g = %d\n", g); // is CKA_BASE
    dssPrivateParms.g.get_value(lval);
    DEBUG_INFO("DSS .g = %d\n", l); // is CKA_VALUE
//DEBUG_INFO("DSS Value = %x\n", privatekey.x); // is CKA_VALUE (I think)
//DEBUG_INFO("size = %d\n", sizeof(privatekey.x));
    DEBUG_INFO("Key = %s\n", key);
    DEBUG_INFO("Key Length = %d\n", keylen);

    pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
    pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
    pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
    pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
    pk.KeyHeader.KeySizeInBits = 0;
    pk.KeyHeader.KeyAttr = CSSM_KEYATTR_NEVER_EXTRACTABLE;                        
    pk.KeyHeader.KeyUsage = 0;
    pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen, MemoryFuncs.AllocRef);
    memcpy(pk.KeyData.Data, key, keylen);
    pk.KeyData.Length = keylen;

    pCssmKey = &pk;
    ktype = CKK_DSA;

    if (pCssmKey != NULL) {
    
      if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0)) {
        hCssmDlDb.DLHandle = hCssmModule;       
        hCssmDlDb.DBHandle = dbHandle;

        do {
        
          CssmRecordAttributes.NumberOfAttributes = 12;
          CssmRecordAttributes.AttributeData = 
            (CSSM_DB_ATTRIBUTE_DATA *)MemoryFuncs.malloc_func(
                                              sizeof(CSSM_DB_ATTRIBUTE_DATA) * 12,
                                              MemoryFuncs.AllocRef);
          pCssmAttributes = CssmRecordAttributes.AttributeData;
          pCssmAttributes[0].Info.AttributeNumber = CKA_LABEL;
          pCssmAttributes[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[0].Value.Length = seriallen;
          pCssmAttributes[0].Value.Data = (CK_CHAR_PTR)pserial;
          pCssmAttributes[1].Info.AttributeNumber = CKA_CLASS;
          pCssmAttributes[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[1].Value.Length = sizeof(oclass);
          pCssmAttributes[1].Value.Data = (CK_CHAR_PTR)&oclass;
          pCssmAttributes[2].Info.AttributeNumber = CKA_TOKEN;
          pCssmAttributes[2].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[2].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[2].Value.Data = (CK_CHAR_PTR)&token_object;
          pCssmAttributes[3].Info.AttributeNumber = CKA_KEY_TYPE;
          pCssmAttributes[3].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[3].Value.Length = sizeof(ktype);
          pCssmAttributes[3].Value.Data = (CK_CHAR_PTR)&ktype;
          pCssmAttributes[4].Info.AttributeNumber = CKA_SUBJECT;
          pCssmAttributes[4].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[4].Value.Length = subjectlen;
          pCssmAttributes[4].Value.Data = (CK_CHAR_PTR)psubject;
          pCssmAttributes[5].Info.AttributeNumber = CKA_ID;
          pCssmAttributes[5].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[5].Value.Length = sizeof(version);
          pCssmAttributes[5].Value.Data = (CK_CHAR_PTR)&version;
          pCssmAttributes[6].Info.AttributeNumber = CKA_SENSITIVE;
          pCssmAttributes[6].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[6].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[6].Value.Data = (CK_CHAR_PTR)&sensitive;
          pCssmAttributes[7].Info.AttributeNumber = CKA_SIGN;
          pCssmAttributes[7].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[7].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[7].Value.Data = (CK_CHAR_PTR)&sign;
          pCssmAttributes[8].Info.AttributeNumber = CKA_PRIME;
          pCssmAttributes[8].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[8].Value.Length = sizeof(long);
          pCssmAttributes[8].Value.Data = (CK_CHAR_PTR)&p;
          pCssmAttributes[9].Info.AttributeNumber = CKA_SUBPRIME;
          pCssmAttributes[9].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[9].Value.Length = sizeof(long);
          pCssmAttributes[9].Value.Data = (CK_CHAR_PTR)&q;
          pCssmAttributes[10].Info.AttributeNumber = CKA_BASE;
          pCssmAttributes[10].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[10].Value.Length = sizeof(long);
          pCssmAttributes[10].Value.Data = (CK_CHAR_PTR)&g;
          pCssmAttributes[11].Info.AttributeNumber = CKA_VALUE;
          pCssmAttributes[11].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[11].Value.Length = sizeof(long);
          pCssmAttributes[11].Value.Data = (CK_CHAR_PTR)&l;

          CssmData.Data = (uint8*) pCssmKey;
          CssmData.Length = sizeof(CSSM_KEY);

          pCssmUniqueRecord = CSSM_DL_DataInsert(
                    hCssmDlDb,
                    CSSM_DL_DB_RECORD_GENERIC,                                                                              &CssmRecordAttributes,
                    NULL_PTR);

              if (pCssmUniqueRecord == NULL) {
            pError = CSSM_GetError();
            DEBUG_INFO("CSSM_DL_DataInsert fails,  rc = %d\n", pError->error);
	      return SC_PRIVATE_KEY_INSERT_ERROR;
          } else {       
            DEBUG_INFO("Handle of inserted key: 0x%08x\n", *((IBMPKCS11_CK_OBJECT_HANDLE*)pCssmUniqueRecord->RecordIdentifier.Data));
            MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                                  MemoryFuncs.AllocRef);
            MemoryFuncs.free_func(pCssmUniqueRecord, MemoryFuncs.AllocRef);
            MemoryFuncs.free_func(pCssmAttributes, MemoryFuncs.AllocRef);
            ret = SC_OK;
          }
        } while (0);
      }
    }
  } else if (pk.KeyHeader.AlgorithmId == CSSM_ALGID_RSA_PKCS) {
    // Extract rsaPrivateParams
    DEBUG_MSG("Decoding private key\n");
    if ((ret = privatekeyinfo.privateKeyAlgorithm.parameters.write(encoding)) != 0)
      return ret;
    if ((ret = rsaPrivateParms.read(encoding)) != 0)
      return ret;

    DEBUG_MSG("Getting RSA private key parts\n");

    // store these values as the private key
    DEBUG_INFO("RSA modulus = %x\n", rsaPrivateParms.modulus); // is CKA_MODULUS
    DEBUG_INFO("RSA public exponent= %x\n", rsaPrivateParms.publicExponent); // is CKA_PUBLIC_EXPONENT
    if (rsaPrivateParms.publicExponent.is_valid()) extraexps++; 
    DEBUG_INFO("RSA prvate exponent = %x\n", rsaPrivateParms.privateExponent); // is CKA_PRIVATE_EXPONENT
    DEBUG_INFO("RSA prime 1 = %x\n", rsaPrivateParms.prime1); // is CKA_PRIME_1
    if (rsaPrivateParms.prime1.is_valid()) extraexps++; 
    DEBUG_INFO("RSA prime 2 = %x\n", rsaPrivateParms.prime2); // is CKA_PRIME_2
    if (rsaPrivateParms.prime2.is_valid()) extraexps++; 
    DEBUG_INFO("RSA exponent 1 = %x\n", rsaPrivateParms.exponent1); // is CKA_EXPONENT_1
    if (rsaPrivateParms.exponent1.is_valid()) extraexps++; 
    DEBUG_INFO("RSA exponent 2 = %x\n", rsaPrivateParms.exponent2); // is CKA_EXPONENT_2
    if (rsaPrivateParms.exponent2.is_valid()) extraexps++; 
    DEBUG_INFO("RSA COEEFICIENT = %x\n", rsaPrivateParms.coefficient); // is CKA_COOEFICIENT
    if (rsaPrivateParms.coefficient.is_valid()) extraexps++; 

    pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
    pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
    pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
    pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
    pk.KeyHeader.KeySizeInBits = 0;
    pk.KeyHeader.KeyAttr = CSSM_KEYATTR_NEVER_EXTRACTABLE;                        
    pk.KeyHeader.KeyUsage = 0;
    pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen,
                                                           MemoryFuncs.AllocRef);
    memcpy(pk.KeyData.Data, key, keylen);
    pk.KeyData.Length = keylen;

    pCssmKey = &pk;
    ktype = CKK_RSA;
    if (pCssmKey != NULL) {
    
      if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0)) {
        hCssmDlDb.DLHandle = hCssmModule;       
        hCssmDlDb.DBHandle = dbHandle;

        do {
        
          CssmRecordAttributes.NumberOfAttributes = 11 + extraexps;
          CssmRecordAttributes.AttributeData = 
              (CSSM_DB_ATTRIBUTE_DATA *)MemoryFuncs.malloc_func(
                                sizeof(CSSM_DB_ATTRIBUTE_DATA) * (11 + extraexps),
                                MemoryFuncs.AllocRef);
          pCssmAttributes = CssmRecordAttributes.AttributeData;
          pCssmAttributes[0].Info.AttributeNumber = CKA_LABEL;
          pCssmAttributes[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[0].Value.Length = seriallen;
          pCssmAttributes[0].Value.Data = (CK_CHAR_PTR)pserial;
          pCssmAttributes[1].Info.AttributeNumber = CKA_CLASS;
          pCssmAttributes[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[1].Value.Length = sizeof(oclass);
          pCssmAttributes[1].Value.Data = (CK_CHAR_PTR)&oclass;
          pCssmAttributes[2].Info.AttributeNumber = CKA_TOKEN;
          pCssmAttributes[2].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[2].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[2].Value.Data = (CK_CHAR_PTR)&token_object;
          pCssmAttributes[3].Info.AttributeNumber = CKA_KEY_TYPE;
          pCssmAttributes[3].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[3].Value.Length = sizeof(ktype);
          pCssmAttributes[3].Value.Data = (CK_CHAR_PTR)&ktype;
          pCssmAttributes[4].Info.AttributeNumber = CKA_SUBJECT;
          pCssmAttributes[4].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[4].Value.Length = subjectlen;
          pCssmAttributes[4].Value.Data = (CK_CHAR_PTR)psubject;
          pCssmAttributes[5].Info.AttributeNumber = CKA_ID;
          pCssmAttributes[5].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[5].Value.Length = sizeof(version);
          pCssmAttributes[5].Value.Data = (CK_CHAR_PTR)&version;
          pCssmAttributes[6].Info.AttributeNumber = CKA_SENSITIVE;
          pCssmAttributes[6].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[6].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[6].Value.Data = (CK_CHAR_PTR)&sensitive;
          pCssmAttributes[7].Info.AttributeNumber = CKA_SIGN;
          pCssmAttributes[7].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[7].Value.Length = sizeof(CK_BBOOL);
          pCssmAttributes[7].Value.Data = (CK_CHAR_PTR)&sign;
          pCssmAttributes[8].Info.AttributeNumber = CKA_MODULUS;
          pCssmAttributes[8].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[8].Value.Length = sizeof(rsaPrivateParms.modulus);
          pCssmAttributes[8].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.modulus;
          pCssmAttributes[9].Info.AttributeNumber = CKA_PRIVATE_EXPONENT;
          pCssmAttributes[9].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          pCssmAttributes[9].Value.Length = sizeof(rsaPrivateParms.privateExponent);
          pCssmAttributes[9].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.privateExponent;
// The following parameters are optional in an RSA private key
          extraexps = 0;
          if (rsaPrivateParms.publicExponent.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_PUBLIC_EXPONENT;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.publicExponent);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.publicExponent;
          }
          if (rsaPrivateParms.prime1.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_PRIME_1;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.prime1);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.prime1;
          }
          if (rsaPrivateParms.prime2.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_PRIME_2;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.prime2);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.prime2;
          }
          if (rsaPrivateParms.exponent1.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_EXPONENT_1;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.exponent1);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.exponent1;
          }
          if (rsaPrivateParms.exponent2.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_EXPONENT_2;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.exponent2);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.exponent2;
          }
          if (rsaPrivateParms.coefficient.is_valid()) {
            extraexps++; 
            pCssmAttributes[9+extraexps].Info.AttributeNumber = CKA_COEFFICIENT;
            pCssmAttributes[9+extraexps].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            pCssmAttributes[9+extraexps].Value.Length = sizeof(rsaPrivateParms.coefficient);
            pCssmAttributes[9+extraexps].Value.Data = (CK_CHAR_PTR)&rsaPrivateParms.coefficient;
          }

          CssmData.Data = (uint8*) pCssmKey;
          CssmData.Length = sizeof(CSSM_KEY);

          pCssmUniqueRecord = CSSM_DL_DataInsert(
                    hCssmDlDb,
                    CSSM_DL_DB_RECORD_GENERIC,                                                                              &CssmRecordAttributes,
                    NULL_PTR);

              if (pCssmUniqueRecord == NULL) {
            pError = CSSM_GetError();
            DEBUG_INFO("CSSM_DL_DataInsert fails,  rc = %d\n", pError->error);
	      return SC_PRIVATE_KEY_INSERT_ERROR;
          } else {       
            DEBUG_INFO("Handle of inserted key: 0x%08x\n", 
                       *((IBMPKCS11_CK_OBJECT_HANDLE*)
                              pCssmUniqueRecord->RecordIdentifier.Data));
            MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                                  MemoryFuncs.AllocRef);
            MemoryFuncs.free_func(pCssmUniqueRecord, 
                                  MemoryFuncs.AllocRef);
            MemoryFuncs.free_func(pCssmAttributes, MemoryFuncs.AllocRef);
            ret = SC_OK;
          }
        } while (0);
      }
    }
  } 

  // MAC old pk stuff
  pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
  pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
  pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
//      pk.KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
  pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
  pk.KeyHeader.KeySizeInBits = 0;
  pk.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;                        
  pk.KeyHeader.KeyUsage = 0;
  pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen,
                                                         MemoryFuncs.AllocRef);
  memcpy(pk.KeyData.Data, key, keylen);
  pk.KeyData.Length = keylen;

  pCssmKey = &pk;

  if (pCssmKey != NULL)
  {
    
    if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
    {
      hCssmDlDb.DLHandle = hCssmModule;       
      hCssmDlDb.DBHandle = dbHandle;

      do {
        oclass = CKO_DATA;
        CssmRecordAttributes.NumberOfAttributes = 7;
        CssmRecordAttributes.AttributeData = 
           (CSSM_DB_ATTRIBUTE_DATA *)MemoryFuncs.malloc_func(
                                      sizeof(CSSM_DB_ATTRIBUTE_DATA) * 7,
                                      MemoryFuncs.AllocRef);
        pCssmAttributes = CssmRecordAttributes.AttributeData;
        pCssmAttributes[0].Info.AttributeNumber = CKA_LABEL;
        pCssmAttributes[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[0].Value.Length = seriallen;
        pCssmAttributes[0].Value.Data = (CK_CHAR_PTR)pserial;
        pCssmAttributes[1].Info.AttributeNumber = CKA_CLASS;
        pCssmAttributes[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[1].Value.Length = sizeof(oclass);
        pCssmAttributes[1].Value.Data = (CK_CHAR_PTR)&oclass;
        pCssmAttributes[2].Info.AttributeNumber = CKA_TOKEN;
        pCssmAttributes[2].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[2].Value.Length = sizeof(CK_BBOOL);
        pCssmAttributes[2].Value.Data = (CK_CHAR_PTR)&token_object;
        pCssmAttributes[3].Info.AttributeNumber = CKA_MODIFIABLE;
        pCssmAttributes[3].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[3].Value.Length = sizeof(CK_BBOOL);
        pCssmAttributes[3].Value.Data = (CK_CHAR_PTR)&modifiable_object;
        pCssmAttributes[4].Info.AttributeNumber = CKA_PRIVATE;
        pCssmAttributes[4].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[4].Value.Length = sizeof(CK_BBOOL);
        pCssmAttributes[4].Value.Data = (CK_CHAR_PTR)&bprivate;
        pCssmAttributes[5].Info.AttributeNumber = CKA_APPLICATION;
        pCssmAttributes[5].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[5].Value.Length = sizeof(version);
        pCssmAttributes[5].Value.Data = (CK_CHAR_PTR)&version;
        pCssmAttributes[6].Info.AttributeNumber = CKA_VALUE;
        pCssmAttributes[6].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[6].Value.Length = keylen;
        pCssmAttributes[6].Value.Data = (CK_CHAR_PTR)key;

        CssmData.Data = (uint8*) pCssmKey;
        CssmData.Length = sizeof(CSSM_KEY);

        pCssmUniqueRecord = CSSM_DL_DataInsert(
                    hCssmDlDb,
                    CSSM_DL_DB_RECORD_GENERIC,
                    &CssmRecordAttributes,
                    NULL_PTR);

        if (pCssmUniqueRecord == NULL)
        {
          pError = CSSM_GetError();
          DEBUG_INFO("CSSM_DL_DataInsert fails,  rc = %d\n", pError->error);
          return SC_PRIVATE_KEY_INSERT_ERROR;
        }
        else
        {       
          DEBUG_INFO("Handle of inserted key: 0x%08x\n",                                           *((IBMPKCS11_CK_OBJECT_HANDLE*)
                           pCssmUniqueRecord->RecordIdentifier.Data));
          MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                                MemoryFuncs.AllocRef);
          MemoryFuncs.free_func(pCssmUniqueRecord,
                                MemoryFuncs.AllocRef);
          MemoryFuncs.free_func(pCssmAttributes,
                                MemoryFuncs.AllocRef);
          ret = SC_OK;
        }

//                              freeKey(pCssmKey, CSSM_TRUE);


      } while (0);
    }
    else
    {
      DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
    }
  }
  // MAC End old pk stuff

  return ret;
}




//
// PrivateKeyDataDelete -
//

uint32 scPrivateKeyDataDelete(
  int sessionID,
  CSSM_HANDLE dbHandle,
  char * key,
  int      keylen,
      char * pserial,
      int seriallen,
      char * psubject, 
      int subjectlen,
      char * pissuer, 
      int issuerlen,
      int version)

{
  uint32                        ret = SC_PRIVATE_KEY_INSERT_ERROR;

  CSSM_MODULE_HANDLE                                      hCssmModule;
  CSSM_DL_DB_HANDLE                                       hCssmDlDb;
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                                       CssmData;
  char                                                    pkix_label[] = TOKEN_LABEL;
  char                                                    pkix_application[] = TOKEN_APPLICATION;
  CSSM_KEY                                                pk;     
  CSSM_KEY_PTR                                    pCssmKey;
  CK_KEY_TYPE                                                     ktype;
  CK_BBOOL                                                        bprivate = TRUE;
  CK_BBOOL                                                        token_object = TRUE;
  CK_BBOOL                                                        modifiable_object = FALSE;
  CK_BBOOL                                                        sensitive = TRUE;
  CK_BBOOL                                                        sign = TRUE;
  CK_OBJECT_CLASS                                  oclass;
  int                                                             extraexps = 0;
  uint32              ii;
  uint32              jj;
  CSSM_HANDLE             CssmResultsHandle;
  CSSM_BOOL                             CssmEndOfDataStore;
  CSSM_DATA                                       CssmRecordData;

  // variables for parsing private dsa key
  PrivateKeyInfo privatekeyinfo;
  buffer_t encoding;
  r_buffer_t pkey;
  DssPrivateParms dssPrivateParms;
  RSAPrivateKey   rsaPrivateParms;
  unsigned char* p;
  unsigned bc;
  DssPrivateKey privatekey;
  r_buffer_t b;
  unsigned long rsaEncryption_val[7]              = {1,2,840,113549,1,1,1};
  unsigned long dsa_val[6]                        = {1,2,840,10040,4,1};
  unsigned long dsa_alt_val[6]                    = {1,3,14,3,2,12};

  pkey.data = (unsigned char *)key;
  pkey.data_len = keylen;
  DEBUG_INFO("Private Key = %s\n", pkey.data);
  DEBUG_INFO("Private Key length = %d\n", pkey.data_len); 

  DEBUG_MSG("About to read private key into info struct\n");
  if (privatekeyinfo.read(pkey) != 0) {
    DEBUG_MSG("Couldn't read in key\n");
    //return SC_PRIVATE_KEY_READ_ERROR;
  }

  PrivateKeyInfo & keyinfo = privatekeyinfo;

  DEBUG_MSG("About to see what kind of algorithm\n");
  if ( keyinfo.privateKeyAlgorithm.algorithm.is_equal(rsaEncryption_val, 7) )
  {
    DEBUG_MSG("Algorithm is CSSM_ALGID_RSA_PKCS\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_RSA_PKCS;
  }
  else if ( keyinfo.privateKeyAlgorithm.algorithm.is_equal(dsa_val, 6) ||
      keyinfo.privateKeyAlgorithm.algorithm.is_equal(dsa_alt_val, 6) )
  {
    DEBUG_MSG("Algorithm is CSSM_ALGID_DSA\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_DSA;
  }
  else
  {
    DEBUG_MSG("Could not tell what algorithm, so note private key as is\n");
    pk.KeyHeader.AlgorithmId = CSSM_ALGID_NONE;
  }

  if (pk.KeyHeader.AlgorithmId == CSSM_ALGID_DSA) {
    // Extract dssPrivateParams

    DEBUG_MSG("encoding private key\n");
    if ((ret = privatekeyinfo.privateKeyAlgorithm.parameters.write(encoding)) != 0)
      return ret;
    if ((ret = dssPrivateParms.read(encoding)) != 0)
      return ret;

    DEBUG_MSG("Getting private key parts\n");
    // Extract x
    if ((ret = privatekeyinfo.privateKey.get_value(p, bc)) != 0)
      return ret;
    b.data     = p; 
    b.data_len = bc;
    if ((ret = privatekey.read(b)) != 0)
      return ret;

    // store these values as the private key
    long p, q, g, l;
    long & pval = p, & qval = q, & gval = g, & lval = l;
    dssPrivateParms.p.get_value(pval);
    DEBUG_INFO("DSS .p = %d\n", p); // is CKA_PRIME
    dssPrivateParms.q.get_value(qval);
    DEBUG_INFO("DSS .q = %d\n", q); // is CKA_SUBPRIME
    dssPrivateParms.g.get_value(gval);
    DEBUG_INFO("DSS .g = %d\n", g); // is CKA_BASE
    dssPrivateParms.g.get_value(lval);
    DEBUG_INFO("DSS .g = %d\n", l); // is CKA_VALUE
//DEBUG_INFO("DSS Value = %x\n", privatekey.x); // is CKA_VALUE (I think)
//DEBUG_INFO("size = %d\n", sizeof(privatekey.x));
    DEBUG_INFO("Key = %s\n", key);
    DEBUG_INFO("Key Length = %d\n", keylen);

    pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
    pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
    pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
    pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
    pk.KeyHeader.KeySizeInBits = 0;
    pk.KeyHeader.KeyAttr = CSSM_KEYATTR_NEVER_EXTRACTABLE;                        
    pk.KeyHeader.KeyUsage = 0;
    pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen, MemoryFuncs.AllocRef);
    memcpy(pk.KeyData.Data, key, keylen);
    pk.KeyData.Length = keylen;

    pCssmKey = &pk;
    ktype = CKK_DSA;

    if (pCssmKey != NULL) {
    
      if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0)) {
        hCssmDlDb.DLHandle = hCssmModule;       
        hCssmDlDb.DBHandle = dbHandle;
      
        ii = 0;
        jj = 0;

        if (pserial != NULL) {
          if (seriallen > 0) {
            // We're looking for a serial
            CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_LABEL;
            CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pserial;
            CssmSelectionPredicate[ii++].Attribute.Value.Length = seriallen;
            DEBUG_INFO("serial = %s\n", *pserial);
            DEBUG_INFO("seriallen = %d\n", seriallen);
          }
        }

        if (version > 0) {
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_APPLICATION;
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) &version;
          CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(version);
          DEBUG_INFO("version = %d\n", version);  
        }

        // Tack on the type because we're looking for the Private key data blob
        oclass = CKO_PRIVATE_KEY;
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_CLASS;
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*)&oclass;
        CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(oclass);

        for (jj = 0; jj < ii; jj++)
        {
          CssmSelectionPredicate[jj].DbOperator = CSSM_DB_EQUAL;
          CssmSelectionPredicate[jj].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        }
 
        CssmQuery.RecordType = CSSM_DL_DB_RECORD_GENERIC;
        CssmQuery.Conjunctive = CSSM_DB_AND;
        CssmQuery.NumSelectionPredicates = ii;
        CssmQuery.SelectionPredicate = CssmSelectionPredicate;
        CssmQuery.QueryLimits.TimeLimit = 0;
        CssmQuery.QueryLimits.SizeLimit = 1;
        CssmQuery.QueryFlags = CSSM_QUERY_RETURN_DATA;

        DEBUG_MSG("Calling CSSM_DL_DataGetFirst\n");
        pCssmUniqueRecord = CSSM_DL_DataGetFirst(
                   hCssmDlDb,
                  &CssmQuery,
                  &CssmResultsHandle,
                  &CssmEndOfDataStore,
                  &CssmRecordAttributes,
                  &CssmRecordData);

        if (pCssmUniqueRecord == NULL) {
          pError = CSSM_GetError();
          DEBUG_INFO("CSSM_DL_DataDelete fails,  rc = %d\n", pError->error);
        } else {       
          DEBUG_MSG("Record found\n");
          ret = CSSM_DL_DataDelete(
                hCssmDlDb,
                CSSM_DL_DB_RECORD_GENERIC,                                                                                              pCssmUniqueRecord);
          DEBUG_INFO("RC from DL_DELETE = %x\n", ret);
        }
        MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                              MemoryFuncs.AllocRef);
        MemoryFuncs.free_func(pCssmUniqueRecord,
                              MemoryFuncs.AllocRef);
      }
    }
  } else if (pk.KeyHeader.AlgorithmId == CSSM_ALGID_RSA_PKCS) {
    // Extract rsaPrivateParams
    DEBUG_MSG("Decoding private key\n");
    if ((ret = privatekeyinfo.privateKeyAlgorithm.parameters.write(encoding)) != 0)
      return ret;
    if ((ret = rsaPrivateParms.read(encoding)) != 0)
      return ret;

    DEBUG_MSG("Getting RSA private key parts\n");

    // store these values as the private key
    DEBUG_INFO("RSA modulus = %x\n", rsaPrivateParms.modulus); // is CKA_MODULUS
    DEBUG_INFO("RSA public exponent= %x\n", rsaPrivateParms.publicExponent); // is CKA_PUBLIC_EXPONENT
    if (rsaPrivateParms.publicExponent.is_valid()) extraexps++; 
    DEBUG_INFO("RSA prvate exponent = %x\n", rsaPrivateParms.privateExponent); // is CKA_PRIVATE_EXPONENT
    DEBUG_INFO("RSA prime 1 = %x\n", rsaPrivateParms.prime1); // is CKA_PRIME_1
    if (rsaPrivateParms.prime1.is_valid()) extraexps++; 
    DEBUG_INFO("RSA prime 2 = %x\n", rsaPrivateParms.prime2); // is CKA_PRIME_2
    if (rsaPrivateParms.prime2.is_valid()) extraexps++; 
    DEBUG_INFO("RSA exponent 1 = %x\n", rsaPrivateParms.exponent1); // is CKA_EXPONENT_1
    if (rsaPrivateParms.exponent1.is_valid()) extraexps++; 
    DEBUG_INFO("RSA exponent 2 = %x\n", rsaPrivateParms.exponent2); // is CKA_EXPONENT_2
    if (rsaPrivateParms.exponent2.is_valid()) extraexps++; 
    DEBUG_INFO("RSA COEEFICIENT = %x\n", rsaPrivateParms.coefficient); // is CKA_COOEFICIENT
    if (rsaPrivateParms.coefficient.is_valid()) extraexps++; 

    pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
    pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
    pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
    pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
    pk.KeyHeader.KeySizeInBits = 0;
    pk.KeyHeader.KeyAttr = CSSM_KEYATTR_NEVER_EXTRACTABLE;                        
    pk.KeyHeader.KeyUsage = 0;
    pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen, MemoryFuncs.AllocRef);
    memcpy(pk.KeyData.Data, key, keylen);
    pk.KeyData.Length = keylen;

    pCssmKey = &pk;
    ktype = CKK_RSA;
    if (pCssmKey != NULL) {
    
      if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0)) {
        hCssmDlDb.DLHandle = hCssmModule;       
        hCssmDlDb.DBHandle = dbHandle;
      
        ii = 0;
        jj = 0;

        if (pserial != NULL) {
          if (seriallen > 0) {
            // We're looking for a serial
            CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_LABEL;
            CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
            CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pserial;
            CssmSelectionPredicate[ii++].Attribute.Value.Length = seriallen;
            DEBUG_INFO("serial = %s\n", *pserial);
            DEBUG_INFO("seriallen = %d\n", seriallen);
          }
        }

        if (version > 0) {
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_APPLICATION;
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) &version;
          CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(version);
          DEBUG_INFO("version = %d\n", version);  
        }

        // Tack on the type because we're looking for the Private key data blob
        oclass = CKO_PRIVATE_KEY;
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_CLASS;
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*)&oclass;
        CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(oclass);

        for (jj = 0; jj < ii; jj++)
        {
          CssmSelectionPredicate[jj].DbOperator = CSSM_DB_EQUAL;
          CssmSelectionPredicate[jj].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        }
 
        CssmQuery.RecordType = CSSM_DL_DB_RECORD_GENERIC;
        CssmQuery.Conjunctive = CSSM_DB_AND;
        CssmQuery.NumSelectionPredicates = ii;
        CssmQuery.SelectionPredicate = CssmSelectionPredicate;
        CssmQuery.QueryLimits.TimeLimit = 0;
        CssmQuery.QueryLimits.SizeLimit = 1;
        CssmQuery.QueryFlags = CSSM_QUERY_RETURN_DATA;

        DEBUG_MSG("Calling CSSM_DL_DataGetFirst\n");
        pCssmUniqueRecord = CSSM_DL_DataGetFirst(
                   hCssmDlDb,
                  &CssmQuery,
                  &CssmResultsHandle,
                  &CssmEndOfDataStore,
                  &CssmRecordAttributes,
                  &CssmRecordData);

              if (pCssmUniqueRecord == NULL) {
            pError = CSSM_GetError();
            DEBUG_INFO("CSSM_DL_DataDelete fails,  rc = %d\n", pError->error);
          } else {       
            DEBUG_MSG("Record found\n");
                        
            ret = CSSM_DL_DataDelete(
                  hCssmDlDb,
                  CSSM_DL_DB_RECORD_GENERIC,                                                                                                pCssmUniqueRecord);
            DEBUG_INFO("RC from DL_DELETE = %x\n", ret);
          }
          MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                                MemoryFuncs.AllocRef);
          MemoryFuncs.free_func(pCssmUniqueRecord,
                                MemoryFuncs.AllocRef);
      }
    }
  } 

  // MAC old pk stuff
  pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
  pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
  pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
//      pk.KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
  pk.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
  pk.KeyHeader.KeySizeInBits = 0;
  pk.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;                        
  pk.KeyHeader.KeyUsage = 0;
  pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen, MemoryFuncs.AllocRef);
  memcpy(pk.KeyData.Data, key, keylen);
  pk.KeyData.Length = keylen;

  pCssmKey = &pk;

  if (pCssmKey != NULL)
  {
    
    if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
    {
      hCssmDlDb.DLHandle = hCssmModule;       
      hCssmDlDb.DBHandle = dbHandle;
      
      ii = 0;
      jj = 0;

      if (pserial != NULL) {
        if (seriallen > 0) {
          // We're looking for a serial
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_LABEL;
          CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
          CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pserial;
          CssmSelectionPredicate[ii++].Attribute.Value.Length = seriallen;
          DEBUG_INFO("serial = %s\n", *pserial);
          DEBUG_INFO("seriallen = %d\n", seriallen);
        }
      }

      if (version > 0) {
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_APPLICATION;
        CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) &version;
        CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(version);
        DEBUG_INFO("version = %d\n", version);  
      }

      // Tack on the type because we're looking for the Private key data blob
      oclass = CKO_DATA;
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_CLASS;
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
      CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*)&oclass;
      CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(oclass);

      for (jj = 0; jj < ii; jj++)
      {
        CssmSelectionPredicate[jj].DbOperator = CSSM_DB_EQUAL;
        CssmSelectionPredicate[jj].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
      }
 
      CssmQuery.RecordType = CSSM_DL_DB_RECORD_GENERIC;
      CssmQuery.Conjunctive = CSSM_DB_AND;
      CssmQuery.NumSelectionPredicates = ii;
      CssmQuery.SelectionPredicate = CssmSelectionPredicate;
      CssmQuery.QueryLimits.TimeLimit = 0;
      CssmQuery.QueryLimits.SizeLimit = 1;
      CssmQuery.QueryFlags = CSSM_QUERY_RETURN_DATA;

      DEBUG_MSG("Calling CSSM_DL_DataGetFirst\n");
      pCssmUniqueRecord = CSSM_DL_DataGetFirst(
                 hCssmDlDb,
                &CssmQuery,
                &CssmResultsHandle,
                &CssmEndOfDataStore,
                &CssmRecordAttributes,
                &CssmRecordData);

            if (pCssmUniqueRecord == NULL) {
          pError = CSSM_GetError();
          DEBUG_INFO("CSSM_DL_DataDelete fails,  rc = %d\n", pError->error);
        } else {       
          DEBUG_MSG("Record found\n");          
          ret = CSSM_DL_DataDelete(
                hCssmDlDb,
                CSSM_DL_DB_RECORD_GENERIC,                                                                                              pCssmUniqueRecord);
          DEBUG_INFO("RC from DL_DELETE = %x\n", ret);
        }
        MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                              MemoryFuncs.AllocRef);
        MemoryFuncs.free_func(pCssmUniqueRecord,
                              MemoryFuncs.AllocRef);

//                              freeKey(pCssmKey, CSSM_TRUE);

    }
    else
    {
      DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
    }
  }
  // MAC End old pk stuff

  return ret;
}




//
// CertificateDataInsert -
//

uint32 scCertificateDataInsert(
  int sessionID,
  CSSM_HANDLE dbHandle,
  char * key,
  int      keylen,
  CSSM_DATA_PTR precordid,
      char * pserial,
      int seriallen,
      char * psubject, 
      int subjectlen,
      char * pissuer, 
      int issuerlen,
      int version)
{
  uint32                                                     ret = SC_OK;

  CSSM_MODULE_HANDLE                                      hCssmModule;
  CSSM_DL_DB_HANDLE                                       hCssmDlDb;
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                                       CssmData;
  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttributes;
  char                                                    pkix_label[] = TOKEN_LABEL;
  CSSM_KEY                                                pk;     
  CSSM_KEY_PTR                                    pCssmKey;
  CK_BBOOL                                                        bprivate = FALSE;
  CK_BBOOL                                                        token_object = TRUE;
  CK_BBOOL                                                        modifiable_object = FALSE;
  CK_OBJECT_CLASS                                         oclass = CKO_CERTIFICATE;
  CK_CERTIFICATE_TYPE                                     cert_type = CKC_X_509;
int jj;

  pk.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
  pk.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
  pk.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_CDSA;
  pk.KeyHeader.KeyClass = CSSM_KEYCLASS_OTHER;
  pk.KeyHeader.KeySizeInBits = 0;
  pk.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
  pk.KeyHeader.KeyUsage = 0;
  pk.KeyData.Data = (CK_CHAR_PTR)MemoryFuncs.malloc_func(keylen, MemoryFuncs.AllocRef);
  memcpy(pk.KeyData.Data, key, keylen);
  pk.KeyData.Length = keylen;

  pCssmKey = &pk;
    
    if ((sessionID < gModuleNextSlot) && ((hCssmModule = gModuleHandleList[sessionID]) != 0))
    {
      hCssmDlDb.DLHandle = hCssmModule;       
      hCssmDlDb.DBHandle = dbHandle;

        CssmRecordAttributes.NumberOfAttributes = 10;
        CssmRecordAttributes.AttributeData = 
              (CSSM_DB_ATTRIBUTE_DATA *)MemoryFuncs.malloc_func(
                                         sizeof(CSSM_DB_ATTRIBUTE_DATA) * 10,
                                         MemoryFuncs.AllocRef);
        pCssmAttributes = CssmRecordAttributes.AttributeData;
        pCssmAttributes[0].Info.AttributeNumber = CKA_LABEL;
        pCssmAttributes[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[0].Value.Length = strlen((const char *)&pkix_label);  
        pCssmAttributes[0].Value.Data = (CK_CHAR_PTR)&pkix_label;
        pCssmAttributes[1].Info.AttributeNumber = CKA_VALUE;
        pCssmAttributes[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[1].Value.Length = keylen;
        pCssmAttributes[1].Value.Data = (CK_CHAR_PTR)key;
        pCssmAttributes[2].Info.AttributeNumber = CKA_SERIAL_NUMBER;
        pCssmAttributes[2].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[2].Value.Length = seriallen;
        pCssmAttributes[2].Value.Data = (CK_CHAR_PTR)pserial;
        pCssmAttributes[3].Info.AttributeNumber = CKA_SUBJECT;
        pCssmAttributes[3].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[3].Value.Length = subjectlen;
        pCssmAttributes[3].Value.Data = (CK_CHAR_PTR)psubject;
        pCssmAttributes[4].Info.AttributeNumber = CKA_ISSUER;
        pCssmAttributes[4].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[4].Value.Length = issuerlen;
        pCssmAttributes[4].Value.Data = (CK_CHAR_PTR)pissuer;
        pCssmAttributes[5].Info.AttributeNumber = CKA_ID;
        pCssmAttributes[5].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[5].Value.Length = sizeof(version);
        pCssmAttributes[5].Value.Data = (CK_CHAR_PTR)&version;
        pCssmAttributes[6].Info.AttributeNumber = CKA_CLASS;
        pCssmAttributes[6].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[6].Value.Length = sizeof(oclass);
        pCssmAttributes[6].Value.Data = (CK_CHAR_PTR)&oclass;
        pCssmAttributes[7].Info.AttributeNumber = CKA_TOKEN;
        pCssmAttributes[7].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[7].Value.Length = sizeof(CK_BBOOL);
        pCssmAttributes[7].Value.Data = (CK_CHAR_PTR)&token_object;
        pCssmAttributes[8].Info.AttributeNumber = CKA_CERTIFICATE_TYPE;
        pCssmAttributes[8].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
        pCssmAttributes[8].Value.Length = sizeof(cert_type);
        pCssmAttributes[8].Value.Data = (CK_CHAR_PTR)&cert_type;
                        pCssmAttributes[9].Info.AttributeNumber = CKA_PRIVATE;
                        pCssmAttributes[9].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
                        pCssmAttributes[9].Value.Length = sizeof(CK_BBOOL);
                        pCssmAttributes[9].Value.Data = (CK_CHAR_PTR)&bprivate;  
//                              pCssmAttributes[8].Info.AttributeNumber = CKA_MODIFIABLE;
//                              pCssmAttributes[8].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
//                              pCssmAttributes[8].Value.Length = sizeof(CK_BBOOL);
//                              pCssmAttributes[8].Value.Data = (CK_CHAR_PTR)&modifiable_object;

        CssmData.Data = (uint8*) pCssmKey;
        CssmData.Length = sizeof(CSSM_KEY);

        pCssmUniqueRecord = CSSM_DL_DataInsert(
                    hCssmDlDb,
                    CSSM_DL_DB_RECORD_CERT,
                    &CssmRecordAttributes,
                    NULL_PTR);

        if (pCssmUniqueRecord == NULL) {
          pError = CSSM_GetError();
          DEBUG_INFO("CSSM_DL_DataInsert fails,  rc = %d\n", pError->error);
          ret = SC_CERTIFICATE_INSERT_ERROR;
        } else {       
          DEBUG_INFO("Handle of inserted key: 0x%08x\n",                      *((IBMPKCS11_CK_OBJECT_HANDLE*)
                              pCssmUniqueRecord->RecordIdentifier.Data));
          MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                                MemoryFuncs.AllocRef);
          MemoryFuncs.free_func(pCssmUniqueRecord,
                                MemoryFuncs.AllocRef);
          MemoryFuncs.free_func(pCssmAttributes,
                                MemoryFuncs.AllocRef);
        }

    }
    else
    {
      DEBUG_INFO("Session ID = %d is not valid\n", sessionID);
      ret = SC_SESSION_ID_INVALID;
    }
 
  return ret;
}



//
// scgetFirstPrivateKey -
//

CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR scFirstPrivateKeyRetrieve(
  CSSM_DL_DB_HANDLE hCssmDlDb,
  char ** key,
  int  * keylen,
  char ** pserial,
  int  * seriallen,
  char ** psubject, 
  char ** pissuer, 
  uint32  * pversion,
  CSSM_HANDLE_PTR pCssmResultsHandle,
  CSSM_BOOL *pCssmEndOfDataStore)
{
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                                       CssmRecordData;
  CSSM_KEY_PTR                                            pCssmKey;

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  CSSM_DATA_PTR                                           pCssmLabel = NULL;

  IBMPKCS11_CK_OBJECT_CLASS                                               PkcsObjectClass;
  IBMPKCS11_CK_KEY_TYPE                                                   PkcsKeyType;
  IBMPKCS11_CK_BBOOL                                                      PkcsKeyUse[9];

  uint32                                                          ii = 0;
  uint32                                                          jj = 0;

  DEBUG_MSG("Enter scFirstPriavteKeyRetrieve\n");

  if (pserial != NULL) {
    if (*seriallen > 0) {
      // We're looking for a serial
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_LABEL;
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
      CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pserial;
      CssmSelectionPredicate[ii++].Attribute.Value.Length = *seriallen;
      DEBUG_INFO("serial = %s\n", *pserial);
      DEBUG_INFO("seriallen = %d\n", *seriallen);
    }
  }

  if (pversion != NULL) {
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_APPLICATION;
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
    CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) pversion;
    CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(*pversion);
    DEBUG_INFO("version = %d\n", *pversion);  
  }

  // Tack on the type because we're looking for the Private key data blob
  CK_OBJECT_CLASS                                         oclass = CKO_DATA;
  CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_CLASS;
  CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
  CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*)&oclass;
  CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(oclass);

  for (jj = 0; jj < ii; jj++)
  {
    CssmSelectionPredicate[jj].DbOperator = CSSM_DB_EQUAL;
    CssmSelectionPredicate[jj].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
  }
 
  CssmQuery.RecordType = CSSM_DL_DB_RECORD_GENERIC;
  CssmQuery.Conjunctive = CSSM_DB_AND;
  CssmQuery.NumSelectionPredicates = ii;
  CssmQuery.SelectionPredicate = CssmSelectionPredicate;
  CssmQuery.QueryLimits.TimeLimit = 0;
  CssmQuery.QueryLimits.SizeLimit = 1;
  CssmQuery.QueryFlags = CSSM_QUERY_RETURN_DATA;

  DEBUG_MSG("Calling CSSM_DL_DataGetFirst\n");
  pCssmUniqueRecord = CSSM_DL_DataGetFirst(
             hCssmDlDb,
             &CssmQuery,
             pCssmResultsHandle,
             pCssmEndOfDataStore,
             &CssmRecordAttributes,
             &CssmRecordData);

  if (pCssmUniqueRecord) 
  {
    DEBUG_INFO("Number of attributes = %d\n", CssmRecordAttributes.NumberOfAttributes);
    for (jj = 0; jj < CssmRecordAttributes.NumberOfAttributes; jj++)
    {
      pCssmAttrData = CssmRecordAttributes.AttributeData + jj;
      DEBUG_INFO("Attribute Data = %x\n", pCssmAttrData->Info.AttributeNumber);
      if (pCssmAttrData->Info.AttributeNumber == CKA_VALUE &&
        pCssmAttrData->Value.Data != NULL)
      {
        if ((pCssmLabel = (CSSM_DATA_PTR) MemoryFuncs.calloc_func(
                                                  1, 
                                                  sizeof(CSSM_DATA),
                                                  MemoryFuncs.AllocRef)
            ) != NULL)
        {    
          if ((pCssmLabel->Data = 
               (unsigned char *)MemoryFuncs.calloc_func(1, 
                                                        pCssmAttrData->Value.Length,
                                                        MemoryFuncs.AllocRef)
              ) != NULL)
          {
            DEBUG_INFO("Found it, Data = %s\n", pCssmAttrData->Value.Data);
            memcpy(pCssmLabel->Data, pCssmAttrData->Value.Data, pCssmAttrData->Value.Length);
            pCssmLabel->Length = pCssmAttrData->Value.Length;
          }
        }
      }

//                      free(pCssmAttrData->Value.Data);
    }

//              free(CssmRecordAttributes.AttributeData);

    if (pCssmUniqueRecord) {
      DEBUG_INFO("Data = %s\n", pCssmUniqueRecord->RecordIdentifier.Data);
      MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                            MemoryFuncs.AllocRef);
      MemoryFuncs.free_func(pCssmUniqueRecord,
                            MemoryFuncs.AllocRef);

    }
    DEBUG_INFO("CssmRecordData = %x\n", CssmRecordData.Data);
    DEBUG_MSG("Exit scFirstPrivateKeyRetrieve, everything is OK\n");
    return &CssmRecordAttributes;
  }
  else
  {
    DEBUG_MSG("Exiting scFirstPrivateKeyRetrieve, null is returned\n");
    DEBUG_INFO("End of data store = %x\n", *pCssmEndOfDataStore);
    return NULL;
  }
}


//
// scgetFirstKey -
//

CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR scFirstCertificateRetrieve(
  CSSM_DL_DB_HANDLE hCssmDlDb,
  char ** key,
  int  * keylen,
  char ** pserial,
  int  * seriallen,
  char ** psubject, 
  char ** pissuer, 
  uint32  * pversion,
  CSSM_HANDLE_PTR pCssmResultsHandle,
  CSSM_BOOL *pCssmEndOfDataStore)
{
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                                       CssmRecordData;
  CSSM_KEY_PTR                                            pCssmKey;

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  CSSM_DATA_PTR                                           pCssmLabel = NULL;

  IBMPKCS11_CK_OBJECT_CLASS                                               PkcsObjectClass;
  IBMPKCS11_CK_KEY_TYPE                                                   PkcsKeyType;
  IBMPKCS11_CK_BBOOL                                                      PkcsKeyUse[9];

  uint32                                                          ii = 0;
  uint32                                                          jj = 0;

  DEBUG_MSG("Enter scFirstCertificateRetrieve\n");

  if (pserial != NULL) {
    if (*seriallen > 0) {
      // We're looking for a serial
      DEBUG_INFO("seriallen = %d\n", *seriallen);
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_SERIAL_NUMBER;
      CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
      CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pserial;
      CssmSelectionPredicate[ii++].Attribute.Value.Length = *seriallen;
      DEBUG_INFO("serial = %s\n", *pserial);
      DEBUG_INFO("seriallen = %d\n", *seriallen);
    }
  }

  if (psubject != NULL) {
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_SUBJECT;
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
    CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *psubject;
    CssmSelectionPredicate[ii++].Attribute.Value.Length = strlen(*psubject);
    DEBUG_INFO("subject = %s\n", *psubject);
  }

  if (pissuer != NULL) {
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_ISSUER;
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
    CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) *pissuer;
    CssmSelectionPredicate[ii++].Attribute.Value.Length = strlen(*pissuer);
    DEBUG_INFO("issuer = %s\n", *pissuer);
  }

  if (pversion != NULL) {
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNumber = CKA_ID;
    CssmSelectionPredicate[ii].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
    CssmSelectionPredicate[ii].Attribute.Value.Data = (uint8*) pversion;
    CssmSelectionPredicate[ii++].Attribute.Value.Length = sizeof(*pversion);
    DEBUG_INFO("version = %d\n", *pversion);  
  }

  for (jj = 0; jj < ii; jj++)
  {
    CssmSelectionPredicate[jj].DbOperator = CSSM_DB_EQUAL;
    CssmSelectionPredicate[jj].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
  }
 
  CssmQuery.RecordType = CSSM_DL_DB_RECORD_CERT;
  CssmQuery.Conjunctive = CSSM_DB_AND;
  CssmQuery.NumSelectionPredicates = ii;
  CssmQuery.SelectionPredicate = CssmSelectionPredicate;
  CssmQuery.QueryLimits.TimeLimit = 0;
  CssmQuery.QueryLimits.SizeLimit = 1;
  CssmQuery.QueryFlags = CSSM_QUERY_RETURN_DATA;

  DEBUG_MSG("Calling CSSM_DL_DataGetFirst\n");
  pCssmUniqueRecord = CSSM_DL_DataGetFirst(
             hCssmDlDb,
             &CssmQuery,
             pCssmResultsHandle,
             pCssmEndOfDataStore,
             &CssmRecordAttributes,
             &CssmRecordData);

//      if (pCssmUniqueRecord != NULL && *pCssmEndOfDataStore == FALSE)
  if (pCssmUniqueRecord) 
  {
    DEBUG_INFO("Number of attributes = %d\n", CssmRecordAttributes.NumberOfAttributes);
    for (jj = 0; jj < CssmRecordAttributes.NumberOfAttributes; jj++)
    {
      pCssmAttrData = CssmRecordAttributes.AttributeData + jj;
      DEBUG_INFO("Attribute Data = %x\n", pCssmAttrData->Info.AttributeNumber);
      if (pCssmAttrData->Info.AttributeNumber == CKA_VALUE &&
        pCssmAttrData->Value.Data != NULL)
      {
        if ((pCssmLabel = (CSSM_DATA_PTR) MemoryFuncs.calloc_func(
                                                  1, 
                                                  sizeof(CSSM_DATA),
                                                  MemoryFuncs.AllocRef)
            ) != NULL)
        {    
          if ((pCssmLabel->Data = (unsigned char *)MemoryFuncs.calloc_func(
                                                     1, 
                                                     pCssmAttrData->Value.Length,
                                                     MemoryFuncs.AllocRef)
              ) != NULL)
          {
            DEBUG_INFO("Found it, Data = %s\n", pCssmAttrData->Value.Data);
            memcpy(pCssmLabel->Data, pCssmAttrData->Value.Data, pCssmAttrData->Value.Length);
            pCssmLabel->Length = pCssmAttrData->Value.Length;
          }
        }
      }

//                      free(pCssmAttrData->Value.Data);
    }

//              free(CssmRecordAttributes.AttributeData);

    if (pCssmUniqueRecord) {
      DEBUG_INFO("Data = %s\n", pCssmUniqueRecord->RecordIdentifier.Data);
      MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                            MemoryFuncs.AllocRef);
      MemoryFuncs.free_func(pCssmUniqueRecord,
                            MemoryFuncs.AllocRef);
    }
    DEBUG_INFO("CssmRecordData = %x\n", CssmRecordData.Data);
    DEBUG_MSG("Exit scGetFirstCertificate, everything is OK\n");
    return &CssmRecordAttributes;
  }
  else
  {
    DEBUG_MSG("Exiting scGetFirstCertificate, null is returned\n");
    DEBUG_INFO("End of data store = %x\n", *pCssmEndOfDataStore);
    return NULL;
  }
}



//
// scgetNextKey -
//

CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR scGetNextCertificate(
  CSSM_DL_DB_HANDLE hCssmDlDb,
  CSSM_HANDLE_PTR pCssmResultsHandle,
  CSSM_BOOL *pCssmEndOfDataStore)
{
  CSSM_DB_UNIQUE_RECORD_PTR                       pCssmUniqueRecord;
  CSSM_DATA                                               CssmRecordData;
  CSSM_KEY_PTR                                    pCssmKey;

  CSSM_DB_ATTRIBUTE_DATA_PTR                      pCssmAttrData;
  CSSM_DATA_PTR                                   pCssmLabel = NULL;

  IBMPKCS11_CK_OBJECT_CLASS                       PkcsObjectClass;
  IBMPKCS11_CK_KEY_TYPE                           PkcsKeyType;
  IBMPKCS11_CK_BBOOL                              PkcsKeyUse[9];

  uint32                                          ii = 0;
  uint32                                          jj = 0;

  pCssmUniqueRecord = CSSM_DL_DataGetNext(
             hCssmDlDb,
             *pCssmResultsHandle,
             pCssmEndOfDataStore,
             &CssmRecordAttributes,
             &CssmRecordData);

  if (pCssmUniqueRecord) 
  {
    DEBUG_INFO("Number of attributes = %d\n", CssmRecordAttributes.NumberOfAttributes);
    for (jj = 0; jj < CssmRecordAttributes.NumberOfAttributes; jj++)
    {
      pCssmAttrData = CssmRecordAttributes.AttributeData + jj;
      DEBUG_INFO("Attribute Data = %x\n", pCssmAttrData->Info.AttributeNumber);
      if (pCssmAttrData->Info.AttributeNumber == CKA_VALUE &&
        pCssmAttrData->Value.Data != NULL)
      {
        if ((pCssmLabel = (CSSM_DATA_PTR) MemoryFuncs.calloc_func(
                                              1, 
                                              sizeof(CSSM_DATA),
                                              MemoryFuncs.AllocRef)
            ) != NULL)
        {    
          if ((pCssmLabel->Data = (unsigned char *)MemoryFuncs.calloc_func(
                                                        1, 
                                                        pCssmAttrData->Value.Length,
                                                        MemoryFuncs.AllocRef)
              ) != NULL)
          {
            DEBUG_INFO("Found it, Data = %s\n", pCssmAttrData->Value.Data);
            memcpy(pCssmLabel->Data, pCssmAttrData->Value.Data, pCssmAttrData->Value.Length);
            pCssmLabel->Length = pCssmAttrData->Value.Length;
          }
        }
      }

    }


    if (pCssmUniqueRecord) {
      DEBUG_INFO("Data = %s\n", pCssmUniqueRecord->RecordIdentifier.Data);
      MemoryFuncs.free_func(pCssmUniqueRecord->RecordIdentifier.Data,
                            MemoryFuncs.AllocRef);
      MemoryFuncs.free_func(pCssmUniqueRecord,
                            MemoryFuncs.AllocRef);
    }
    DEBUG_INFO("CssmRecordData = %x\n", CssmRecordData.Data);
    DEBUG_MSG("Exit scGetNextCertificate, everything is OK\n");
    return &CssmRecordAttributes;
  }
  else
  {
    DEBUG_MSG("Exiting scGetNextCertificate, null is returned\n");
    DEBUG_INFO("End of data store = %x\n", *pCssmEndOfDataStore);
    return NULL;
  }
}


//
// scCertificateRetrieve
//      Routine to get proper certificate from card
//    

uint32 scCertificateRetrieve(
  int sessionID,
  CSSM_HANDLE dbHandle,
  char ** key,
  int  * keylen,
  char ** pserial,
  int  * seriallen,
  char ** psubject, 
  char ** pissuer, 
  uint32  * pversion)
{
  CSSM_HANDLE             CssmResultsHandle, CssmRecordAttributes;
  CSSM_BOOL               CssmEndOfDataStore;
  CSSM_BOOL                       returnlatest, returnserial;
  uint32 *                      pversionori;
  uint32                        versionCurr, tversion;
  CSSM_DL_DB_HANDLE               hCssmDlDb;
  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pCssmRecordAttributes, pCssmRecordAttributesCurr;                
  char *                          pdkey;
  int                                     dkeylen;

  DEBUG_MSG("Enter scCertificateRetrieve\n");

  DEBUG_INFO("*pversion = %x\n", *pversion);
  if (*pversion == 0) {
    returnlatest = TRUE;
    pversionori = pversion;
    pversion = NULL;
  } else {
    returnlatest = FALSE;
  }

  if (*seriallen == 0) {
    returnserial = TRUE;
  } else {
    returnserial = FALSE;
  }

  hCssmDlDb.DLHandle = gModuleHandleList[sessionID];
  DEBUG_INFO("Module Handle %x\n", hCssmDlDb.DLHandle);
  hCssmDlDb.DBHandle = dbHandle;
  DEBUG_INFO("DB Handle = %x\n", hCssmDlDb.DBHandle);

  DEBUG_MSG("Getting first cert\n");
  pCssmRecordAttributes = scFirstCertificateRetrieve(
    hCssmDlDb,
    key,
    keylen,
    pserial,
    seriallen,
    psubject, 
    pissuer, 
    pversion,
    &CssmResultsHandle,
    &CssmEndOfDataStore);
  
  if (pCssmRecordAttributes) {
    // Figure out what certificate to return
    if (returnlatest) {
      DEBUG_MSG("Get Latest Certificate by Version\n");
      pCssmRecordAttributesCurr = pCssmRecordAttributes;
      versionCurr = scGetVersion(pCssmRecordAttributes);
      dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
      *keylen = dkeylen;
      *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
      memcpy(*key, (char *)pdkey, dkeylen);
      if (returnserial) 
        *seriallen = scGetSerialValue(pCssmRecordAttributes, *pserial);
      DEBUG_INFO("Certificate Version: %x\n", versionCurr);
      DEBUG_INFO("Length of Certificate Returned = %d\n", *keylen);
      DEBUG_INFO("Certificate returned = %s\n", *key);
      if (scFreeAttributes(pCssmRecordAttributes)) {
        DEBUG_MSG("Failed freeing data attributes\n");
        return SC_FREE_ATTRIBUTES_ERROR;
      }

      // Get next version
      while (pCssmRecordAttributes) {
        pCssmRecordAttributes = scGetNextCertificate(
          hCssmDlDb,
          &CssmResultsHandle,
          &CssmEndOfDataStore);
        if (pCssmRecordAttributes) {
          tversion = scGetVersion(pCssmRecordAttributes);
          if (versionCurr < tversion) {
                versionCurr = tversion;
                pCssmRecordAttributesCurr = pCssmRecordAttributes;
            dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
            *keylen = dkeylen;
            *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
            memcpy(*key, (char *)pdkey, dkeylen);
            if (returnserial) 
              *seriallen = scGetSerialValue(pCssmRecordAttributes, *pserial);
            DEBUG_INFO("Certificate Version: %x\n", versionCurr);
            DEBUG_INFO("Length of Certificate Returned = %d\n", *keylen);
            DEBUG_INFO("Certificate returned = %s\n", *key);
            if (scFreeAttributes(pCssmRecordAttributes)) {
              DEBUG_MSG("Failed freeing data attributes\n");
              return SC_FREE_ATTRIBUTES_ERROR;
            }
          }
          *pversionori = versionCurr;
          DEBUG_INFO("Version returned is %d\n", *pversionori);
        }
      }
    } else {
      // Find exact key
      DEBUG_MSG("Get a specific Certificate key version\n");
      pCssmRecordAttributesCurr = pCssmRecordAttributes;
      versionCurr = scGetVersion(pCssmRecordAttributes);
      DEBUG_INFO("First Version = %x\n", versionCurr);
      dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
      *keylen = dkeylen;
      *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
      memcpy(*key, (char *)pdkey, dkeylen);
      if (returnserial) 
        *seriallen = scGetSerialValue(pCssmRecordAttributes, *pserial);
      DEBUG_INFO("Certificate Version: %x\n", versionCurr);
      DEBUG_INFO("Length of Key Returned = %d\n", *keylen);
      DEBUG_INFO("Key returned = %s\n", *key);
      if (scFreeAttributes(pCssmRecordAttributes)) {
        DEBUG_MSG("Failed freeing data attributes\n");
        return SC_FREE_ATTRIBUTES_ERROR;
      }
      while ((versionCurr != *pversion) && pCssmRecordAttributes) {
        pCssmRecordAttributes = scGetNextCertificate(
          hCssmDlDb,
          &CssmResultsHandle,
          &CssmEndOfDataStore);
        if (pCssmRecordAttributes) {
          tversion = scGetVersion(pCssmRecordAttributes);
          DEBUG_INFO("Certificate Version: %x\n", tversion);
          if (versionCurr < tversion) {
            DEBUG_MSG("New older version found = %x\n");
                versionCurr = tversion;
                pCssmRecordAttributesCurr = pCssmRecordAttributes;
            dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
            *keylen = dkeylen;
            *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
            memcpy(*key, (char *)pdkey, dkeylen);
            if (returnserial) 
              *seriallen = scGetSerialValue(pCssmRecordAttributes, *pserial);
            DEBUG_INFO("Length of Key Returned = %d\n", *keylen);
            DEBUG_INFO("Certificate returned = %s\n", *key);
            if (scFreeAttributes(pCssmRecordAttributes)) {
              DEBUG_MSG("Failed freeing data attributes\n");
              return SC_FREE_ATTRIBUTES_ERROR;
            }
          }
        }
      }
      if (versionCurr != *pversion) {
        DEBUG_MSG("Error, requrested version not found\n");
        return SC_INVALID_VERSION;
      }
    }
    return SC_OK;
  } else {
    return SC_CDSA_RECORD_ATTRIBUTES_ERROR;
  }
}


//
// scPrivateKeyRetrieve
//      Routine to get proper Key from card
//    

uint32 scPrivateKeyRetrieve(
  int sessionID,
  CSSM_HANDLE dbHandle,
  char ** key,
  int  * keylen,
  char ** pserial,
  int  * seriallen,
  char ** psubject, 
  char ** pissuer, 
  uint32  * pversion)
{
  CSSM_HANDLE             CssmResultsHandle, CssmRecordAttributes;
  CSSM_BOOL               CssmEndOfDataStore;
  CSSM_BOOL                       returnlatest;
  uint32 *                      pversionori;
  uint32                        versionCurr, tversion;
  CSSM_DL_DB_HANDLE               hCssmDlDb;
  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pCssmRecordAttributes, pCssmRecordAttributesCurr;                
  char *                          pdkey;
  int                                     dkeylen;

  DEBUG_MSG("Enter scPrivateKeyRetrieve\n");

  DEBUG_INFO("*pversion = %x\n", *pversion);
  if (*pversion == 0) {
    returnlatest = TRUE;
    pversionori = pversion;
    pversion = NULL;
  } else {
    returnlatest = FALSE;
  }

  hCssmDlDb.DLHandle = gModuleHandleList[sessionID];
  DEBUG_INFO("Module Handle %x\n", hCssmDlDb.DLHandle);
  hCssmDlDb.DBHandle = dbHandle;
  DEBUG_INFO("DB Handle = %x\n", hCssmDlDb.DBHandle);

  DEBUG_MSG("Getting first cert\n");
  pCssmRecordAttributes = scFirstPrivateKeyRetrieve(
    hCssmDlDb,
    key,
    keylen,
    pserial,
    seriallen,
    psubject, 
    pissuer, 
    pversion,
    &CssmResultsHandle,
    &CssmEndOfDataStore);
  
  if (pCssmRecordAttributes) {
    // Figure out what key to return
    if (returnlatest) {
      // Get first key
      DEBUG_MSG("Get Latest Private Key by Version\n");
      pCssmRecordAttributesCurr = pCssmRecordAttributes;
      versionCurr = scGetPrivateVersion(pCssmRecordAttributes);
      DEBUG_INFO("First Version = %x\n", versionCurr);
      dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
      *keylen = dkeylen;
      *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
      memcpy(*key, (char *)pdkey, dkeylen);
      DEBUG_INFO("Certificate Version: %x\n", versionCurr);
      DEBUG_INFO("Length of Certificate Returned = %d\n", *keylen);
      DEBUG_INFO("Certificate returned = %s\n", *key);
      if (scFreeAttributes(pCssmRecordAttributes)) {
        DEBUG_MSG("Failed freeing data attributes\n");
        return SC_FREE_ATTRIBUTES_ERROR;
      }
      while (pCssmRecordAttributes) {
        pCssmRecordAttributes = scGetNextCertificate(
          hCssmDlDb,
          &CssmResultsHandle,
          &CssmEndOfDataStore);
        if (pCssmRecordAttributes) {
          tversion = scGetPrivateVersion(pCssmRecordAttributes);
          DEBUG_INFO("Certificate Version: %x\n", tversion);
          if (versionCurr < tversion) {
            DEBUG_MSG("New older version found = %x\n");
                versionCurr = tversion;
                pCssmRecordAttributesCurr = pCssmRecordAttributes;
            dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
            *keylen = dkeylen;
            *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
            memcpy(*key, (char *)pdkey, dkeylen);
            DEBUG_INFO("Length of Certificate Returned = %d\n", *keylen);
            DEBUG_INFO("Certificate returned = %s\n", *key);
            if (scFreeAttributes(pCssmRecordAttributes)) {
              DEBUG_MSG("Failed freeing data attributes\n");
              return SC_FREE_ATTRIBUTES_ERROR;
            }
          }
          *pversionori = versionCurr;
          DEBUG_INFO("Version returned is %d\n", *pversionori);
        }
      }
    } else {
      // Find exact key
      DEBUG_MSG("Get a specific private key version\n");
      pCssmRecordAttributesCurr = pCssmRecordAttributes;
      versionCurr = scGetPrivateVersion(pCssmRecordAttributes);
      DEBUG_INFO("First Version = %x\n", versionCurr);
      dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
      *keylen = dkeylen;
      *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
      memcpy(*key, (char *)pdkey, dkeylen);
      DEBUG_INFO("Certificate Version: %x\n", versionCurr);
      DEBUG_INFO("Length of Key Returned = %d\n", *keylen);
      DEBUG_INFO("Key returned = %s\n", *key);
      if (scFreeAttributes(pCssmRecordAttributes)) {
        DEBUG_MSG("Failed freeing data attributes\n");
        return SC_FREE_ATTRIBUTES_ERROR;
      }
      while ((versionCurr != *pversion) && pCssmRecordAttributes) {
        pCssmRecordAttributes = scGetNextCertificate(
          hCssmDlDb,
          &CssmResultsHandle,
          &CssmEndOfDataStore);
        if (pCssmRecordAttributes) {
          tversion = scGetPrivateVersion(pCssmRecordAttributes);
          DEBUG_INFO("Certificate Version: %x\n", tversion);
          if (versionCurr < tversion) {
            DEBUG_MSG("New older version found = %x\n");
                versionCurr = tversion;
                pCssmRecordAttributesCurr = pCssmRecordAttributes;
            dkeylen = scGetCharValue(pCssmRecordAttributes, &pdkey);
            *keylen = dkeylen;
            *key = (char *)MemoryFuncs.malloc_func(dkeylen, MemoryFuncs.AllocRef);
            memcpy(*key, (char *)pdkey, dkeylen);
            DEBUG_INFO("Length of Key Returned = %d\n", *keylen);
            DEBUG_INFO("Certificate returned = %s\n", *key);
            if (scFreeAttributes(pCssmRecordAttributes)) {
              DEBUG_MSG("Failed freeing data attributes\n");
              return SC_FREE_ATTRIBUTES_ERROR;
            }
          }
        }
      }
      if (versionCurr != *pversion) {
        DEBUG_MSG("Error, requrested version not found\n");
        return SC_INVALID_VERSION;
      }
    }
    return SC_OK;
  } else {
    return SC_CDSA_RECORD_ATTRIBUTES_ERROR;
  }
}


//
// Initialize the sc interface 
//
uint32 scInit(CSSM_MEMORY_FUNCS& memoryFuncs)
{
  DEBUG_MSG("Enter scInit\n");
  DEBUG_INFO("malloc before = %x\n", MemoryFuncs.malloc_func);

  memcpy(&MemoryFuncs, &memoryFuncs, sizeof(MemoryFuncs));
  
  DEBUG_INFO("malloc after = %x\n", MemoryFuncs.malloc_func);
  DEBUG_MSG("Exit scInit\n");

  return SC_OK;         
}

//
// store a public key on the smart card - 
//

uint32 scCreateCertificate(
  const char * ppin, 
  const utf8String psubject,
  const utf8String pissuer,
  uint32 version,
  const r_buffer_t & serial,
  const r_buffer_t & pubkey)
{
  uint32                             CssmRc;
  CSSM_DATA_PTR                               precordid;

  char                                    mainChoice;
  int                                             ii;
  char                                    *pPIN = NULL;
  int                                     sessionid, rv, dbhandle;


  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  CssmRc = CSSM_Init(&CssmVersion, &MemoryFuncs, NULL);
  if (CssmRc != SC_OK)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("\nCSSM_Init fails, rc = %d", pError->error);
    exit(pError->error);
  }


  gSessionCount = 0;
  gModuleNextSlot = 1;
  
  sessionid = scModuleAttach(1, 'y', 'y', 'y');
  if (sessionid <= 0) {
    DEBUG_INFO("Problem with moduleattach, sessionid = %x\n", sessionid);
    return sessionid;
  }

  dbhandle = scDbOpen(sessionid, (char *)ppin, CSSM_FALSE);
  if (dbhandle <= 0) {
    DEBUG_INFO("Problem with DBOpen, handle = %x\n", dbhandle);
    return dbhandle;
  }

  rv = scCertificateDataInsert(sessionid, 
                               dbhandle, 
                               (char *)pubkey.data, 
                               pubkey.data_len, 
                               precordid, 
                               (char *)serial.data, 
                               serial.data_len, 
                               (char *)psubject, 
                               strlen((char *)psubject), 
                               (char *)pissuer, 
                               strlen((char *)psubject), 
                               version);
  if (rv != SC_OK) {
    DEBUG_INFO("problem with public key insert, rv = %x\n", rv);
    return rv;
  }                        


  rv = scDbClose(sessionid, dbhandle);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with DBClose, rv = %x\n", rv);
    return rv;
  }

  rv = scModuleDetach(sessionid);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with Module Detach, rv = %x\n", rv);
    return rv;
  }
  
  return SC_OK;         
}


//
// store a key pair on the smart card - 
//
uint32 scCreateKeySlot(
  const char * ppin, 
  const utf8String psubject,
  const utf8String pissuer,
  uint32 version,
  const r_buffer_t & serial,
  const r_buffer_t & privkey,
  const r_buffer_t & pubkey)
{
  uint32                             CssmRc;
  CSSM_DATA_PTR                               precordid;

  char                                    mainChoice;
  int                                             ii;
  char                                    *pPIN = NULL;
  int                                     sessionid, rv, dbhandle;


  DEBUG_MSG("In scCreateKeyslot \n");

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  CssmRc = CSSM_Init(&CssmVersion, &MemoryFuncs, NULL);
  if (CssmRc != SC_OK)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("CSSM_Init fails, rc = %d\n", pError->error);
    exit(pError->error);
  }


  gSessionCount = 0;
  gModuleNextSlot = 1;
  
  sessionid = scModuleAttach(1, 'y', 'y', 'y');
  if (sessionid <= 0) {
    DEBUG_INFO("Problem with moduleattach, sessionid = %x\n", sessionid);
    return sessionid;
  }

  dbhandle = scDbOpen(sessionid, (char *)ppin, CSSM_FALSE);
  if (dbhandle <= 0) {
    DEBUG_INFO("Problem with DBOpen, handle = %x\n", dbhandle);
    return dbhandle;
  }

  if (pubkey.data_len > 0) {
    rv = scCertificateDataInsert(sessionid, 
                                 dbhandle, 
                                 (char *)pubkey.data, 
                                 pubkey.data_len, 
                                 precordid, 
                                 (char *)serial.data, 
                                 serial.data_len, 
                                 (char *)psubject, 
                                 strlen((char *)psubject), 
                                 (char *)pissuer, 
                                 strlen((char *)psubject), 
                                 version);
    if (rv != SC_OK) {
      DEBUG_INFO("problem with public key insert, rv = %x\n", rv);
      return rv;
    }
  } else {
    if ((serial.data_len > 0) || (privkey.data_len == 0)) {
      DEBUG_MSG("Null public key only allowed if null serial & not null private key\n");
      return SC_KEYSLOT_INVALID_PARAMETER;
    }
  }

  rv = scPrivateKeyDataInsert(sessionid, 
                              dbhandle, 
                              (char *)privkey.data,                          
                              privkey.data_len, 
                              precordid, 
                              (char *)serial.data, 
                              serial.data_len, 
                              (char *)psubject, 
                              strlen((char *)psubject), 
                              (char *)pissuer, 
                              strlen((char *)pissuer), 
                              version);
  if (rv != SC_OK) {
    DEBUG_INFO("problem with private key insert, rv = %x\n", rv);
    return rv;
  }

  rv = scDbClose(sessionid, dbhandle);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with DBClose, rv = %x\n", rv);
    return rv;
  }

  rv = scModuleDetach(sessionid);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with Module Detach, rv = %x\n", rv);
    return rv;
  }

  return SC_OK;         
}


//
// scRetrieveKeySlot
//      Routine to get the Cert/Private key 
uint32 scRetrieveKeySlot(
  const char * ppin, 
  const utf8String psubject, 
  const utf8String pissuer, 
  uint32 &   version, 
  buffer_t * serial, 
  buffer_t * privkey, 
  buffer_t * cert )
{
  uint32                         CssmRc;
  CK_BBOOL                       getserial = FALSE;
  char                           mainChoice;
  int                            ii;
  char                           *pPIN = NULL;
  int                            sessionid, rv, dbhandle;
  char *                         pserial, * pprivkey, * pcert;
  int                            lserial, lprivkey, lcert;
  uint32 *                       pversion;
  char                           theserial[128];

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  CssmRc = CSSM_Init(&CssmVersion, &MemoryFuncs, NULL);
  if (CssmRc != SC_OK)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("CSSM_Init fails, rc = %d\n", pError->error);
    exit(pError->error);
  }


  gSessionCount = 0;
  gModuleNextSlot = 1;
  
  sessionid = scModuleAttach(1, 'y', 'y', 'y');
  if (sessionid <= 0) {
    DEBUG_INFO("Problem with moduleattach, sessionid = %x\n", sessionid);
    return sessionid;
  }

  dbhandle = scDbOpen(sessionid, (char *)ppin, CSSM_FALSE);
  if (dbhandle <= 0) {
    DEBUG_INFO("Problem with DBOpen, handle = %x\n", dbhandle);
    return dbhandle;
  }

  // Set up calling values
  pserial = NULL;
  if (serial == NULL) {
    pserial = (char *)&(theserial[0]);
    lserial = 0;
    // getserial is FALSE
  } else {
    lserial = serial->data_len;
    pserial = (char *)&(theserial[0]);
    if (lserial == 0) {
      getserial = TRUE;
    } else {
      memcpy(theserial, serial->data, min(sizeof(theserial),lserial));
    }
    
  }

  pversion = &version;

  if (cert != NULL) {
    // Get certificate
    rv = scCertificateRetrieve(sessionid, 
                               dbhandle, 
                               (char **)&pcert, 
                               &lcert, 
                               (char **)&pserial, 
                               &lserial, 
                               (char **)&psubject, 
                               (char **)&pissuer, 
                               (uint32 *)pversion);
        
    if (rv) {
      DEBUG_INFO("Error returned from scCertificateRetrieve=%x\n", rv);
      return rv;
    }
    DEBUG_INFO("Certificate %s\n", (char *)pcert);
    DEBUG_INFO("Cert length is %d\n", lcert);
  cert->clear();
    cert->append((unsigned char *)pcert, lcert);
    MemoryFuncs.free_func(pcert, MemoryFuncs.AllocRef);
    if (getserial) {
      serial->clear();
      serial->append((unsigned char *)(&(theserial[0])), serial->data_len);
      DEBUG_INFO("Serial number returned = %s\n", serial->data);
      DEBUG_INFO("Serial length = %d\n", serial->data_len); 
    }
  } else {
    DEBUG_MSG("Cert is NULL\n");
    return SC_KEYRETRIEVE_INVALID_PARAMETER;
  }

  if (privkey != NULL) {
        // Get corresponding private key
  rv = scPrivateKeyRetrieve(sessionid, 
                            dbhandle, 
                            (char **)&pprivkey, 
                            &lprivkey, 
                            (char **)&pserial, 
                            &lserial, 
                            (char **)&psubject, 
                            (char **)&pissuer, 
                            (uint32 *)pversion);
  if (rv != SC_OK) {
        DEBUG_INFO("problem with retrieving private key data, rv = %x\n", rv);
        return rv;
  }
    DEBUG_INFO("Private Key length = %d\n", lprivkey);
    DEBUG_INFO("Private Key = %s\n", (char *)pprivkey);
    privkey->clear();
    privkey->append((unsigned char *)pprivkey, lprivkey);
    DEBUG_INFO("Serial returned was %s\n", pserial);
    DEBUG_INFO("Version returned was %d\n", pversion);
    MemoryFuncs.free_func(pprivkey, MemoryFuncs.AllocRef);
  }
      
      // Set return values for caller
  if (getserial && (serial != NULL)) {
  serial->clear();
    serial->append((unsigned char *)pserial, lserial);
  }

  if ((pserial != NULL) && (pserial != (char *)&theserial)) {
    MemoryFuncs.free_func(pserial, MemoryFuncs.AllocRef);
  };

  rv = scDbClose(sessionid, dbhandle);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with DBClose, rv = %x\n", rv);
    return rv;
  }

  rv = scModuleDetach(sessionid);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with Module Detach, rv = %x\n", rv);
    return rv;
  }

  return SC_OK;
}



//
// update a key pair on the smart card.  This only occurs if a private key
// was previously put on the card with a null serial number and no public
// key exists that matches the criteria.
//
uint32 scUpdateKeySlot(
  const char * ppin, 
  const utf8String psubject,
  const utf8String pissuer,
  uint32 version,
  const r_buffer_t & serial,
  const r_buffer_t & privkey,
  const r_buffer_t & pubkey)
{
  uint32                             CssmRc;
  CSSM_DATA_PTR                               precordid;

  char                                    mainChoice;
  int                                             ii;
  char                                    *pPIN = NULL;
  int                                     sessionid, rv, dbhandle;


  DEBUG_MSG("In scUpdateKeyslot \n");

  if ((pubkey.data_len <= 0) || (serial.data_len <= 0) || (privkey.data_len <= 0)) {
    DEBUG_MSG("cert, private key or serial number invalid\n");
    return SC_KEYSLOT_INVALID_PARAMETER;
  }

  if (!MemoryFuncs.malloc_func || !MemoryFuncs.free_func ||
    !MemoryFuncs.realloc_func || !MemoryFuncs.calloc_func) {
      DEBUG_MSG("A required memory function is not defined\n");
      return SC_MEMORY_FUNCTION_UNDEFINED;
  }

  CssmRc = CSSM_Init(&CssmVersion, &MemoryFuncs, NULL);
  if (CssmRc != SC_OK)
  {
    pError = CSSM_GetError();
    DEBUG_INFO("CSSM_Init fails, rc = %d\n", pError->error);
    exit(pError->error);
  }

  gSessionCount = 0;
  gModuleNextSlot = 1;
  
  sessionid = scModuleAttach(1, 'y', 'y', 'y');
  if (sessionid <= 0) {
    DEBUG_INFO("Problem with moduleattach, sessionid = %x\n", sessionid);
    return sessionid;
  }

  dbhandle = scDbOpen(sessionid, (char *)ppin, CSSM_FALSE);
  if (dbhandle <= 0) {
    DEBUG_INFO("Problem with DBOpen, handle = %x\n", dbhandle);
    return dbhandle;
  }


  // Find private key by deleting it.
  rv = scPrivateKeyDataDelete(sessionid, dbhandle, (char *)privkey.data,                          
  privkey.data_len, (char *)NULL, 0, 
  (char *)psubject, strlen((char *)psubject), (char *)pissuer, 
  strlen((char *)pissuer), version);
  if (rv != SC_OK) {
    DEBUG_INFO("problem with private key delete, rv = %x\n", rv);
    return rv;
  }

  // Put public key onto card
  if (pubkey.data_len > 0) {
    rv = scCertificateDataInsert(sessionid, 
                                 dbhandle, 
                                 (char *)pubkey.data, 
                                 pubkey.data_len, 
                                 precordid, 
                                 (char *)serial.data, 
                                 serial.data_len, 
                                 (char *)psubject, 
                                 strlen((char *)psubject), 
                                 (char *)pissuer, 
                                 strlen((char *)psubject), 
                                 version);
    if (rv != SC_OK) {
      DEBUG_INFO("problem with public key insert, rv = %x\n", rv);
      return rv;
    }
  } else {
    if ((serial.data_len > 0) || (privkey.data_len == 0)) {
      DEBUG_MSG("Null public key only allowed if null serial & not null private key\n");
      return SC_KEYUPDATE_INVALID_PARAMETER;
    }
  }

  // re-insert private key
  rv = scPrivateKeyDataInsert(sessionid, 
                              dbhandle, 
                              (char *)privkey.data,                          
                              privkey.data_len, 
                              precordid, 
                              (char *)serial.data, 
                              serial.data_len, 
                              (char *)psubject, 
                              strlen((char *)psubject), 
                              (char *)pissuer, 
                              strlen((char *)pissuer), 
                              version);
  if (rv != SC_OK) {
    DEBUG_INFO("problem with private key insert, rv = %x\n", rv);
    return rv;
  }

  rv = scDbClose(sessionid, dbhandle);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with DBClose, rv = %x\n", rv);
    return rv;
  }

  rv = scModuleDetach(sessionid);
  if (rv != SC_OK) {
    DEBUG_INFO("Problem with Module Detach, rv = %x\n", rv);
    return rv;
  }

  return SC_OK;         
}
