/* ***************************************************************** *
 * 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.                                                        *
 * ***************************************************************** */


#include "pkcsprivate.h"

extern CSSM_SPI_MEMORY_FUNCS  CssmMemFuncs;
extern CSSM_GUID CssmGuid;

CK_RV CK_ENTRY C_ExtractClearKeyObject(
  CK_SESSION_HANDLE hSession,
  CK_OBJECT_HANDLE_PTR phRefKey,
  CSSM_DATA_PTR pClearKeyData,
  uint32 hCSP); 

/*****************************************************************************
 * Function: toCdsaKeyClass 
 * 
 * Convert PKCS11 key class to CDSA key class
 *
 * Input:
 *  pkcs11KeyClass    - PKCS11 key class
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CDSA key class
 *
 */

uint32 toCdsaKeyClass(CK_OBJECT_CLASS pkcs11KeyClass)
{
  switch (pkcs11KeyClass)
  {
    case CKO_PUBLIC_KEY:
      return CSSM_KEYCLASS_PUBLIC_KEY;

    case CKO_PRIVATE_KEY:
      return CSSM_KEYCLASS_PRIVATE_KEY;

    case CKO_SECRET_KEY:
      return CSSM_KEYCLASS_SESSION_KEY;

    case CKO_VENDOR_DEFINED:
      return CSSM_KEYCLASS_OTHER;

    default:
      return CSSM_KEYCLASS_OTHER;
  }
}



/*****************************************************************************
 * Function: toPkcs11KeyClass
 * 
 * Convert CDSA key class to PKCS11 key class
 *
 * Input:
 *  cdsaKeyClass    - CDSA key class
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  PKCS11 key class
 *
 */

CK_OBJECT_CLASS toPkcs11KeyClass(uint32 cdsaKeyClass)
{
  switch (cdsaKeyClass)
  {
    case CSSM_KEYCLASS_PUBLIC_KEY:
      return CKO_PUBLIC_KEY;

    case CSSM_KEYCLASS_PRIVATE_KEY:
      return CKO_PRIVATE_KEY;

    case CSSM_KEYCLASS_SESSION_KEY:
      return CKO_SECRET_KEY;

    case CSSM_KEYCLASS_OTHER:
      return CKO_VENDOR_DEFINED;

    default:
      return CKO_VENDOR_DEFINED;
  }
}



/*****************************************************************************
 * Function: toCdsaAlgoId
 *
 * Convert PKCS11 key type to CDSA algoritm id
 *
 * Input:
 *  pkcs11KeyType   - PKCS11 key type
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CDSA algorithm id
 *
 */

uint32 toCdsaAlgoId(CK_KEY_TYPE pkcs11KeyType)
{
  switch (pkcs11KeyType)
  {
    case CKK_RSA:
      return CSSM_ALGID_RSA_PKCS;

    case CKK_DSA:
      return CSSM_ALGID_DSA;

    case CKK_DH:
      return CSSM_ALGID_DH;

    case CKK_GENERIC_SECRET:
      return CSSM_ALGID_GenericSecret;

    case CKK_RC2:
      return CSSM_ALGID_RC2;

    case CKK_RC4:
      return CSSM_ALGID_RC4;

    case CKK_DES:
      return CSSM_ALGID_DES;

    case CKK_DES2:
      return CSSM_ALGID_3DES_2KEY;

    case CKK_DES3:
      return CSSM_ALGID_3DES_3KEY;

    default:
      return CSSM_ALGID_NONE;
  }
}
    


/*****************************************************************************
 * Function: toPkcs11KeyType
 * 
 * Convert CDSA algoritm id to PKCS11 key type
 *
 * Input:
 *  cdsaAlgoId    - CDSA algorithm id
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  PKCS11 key type
 *
 */

CK_KEY_TYPE toPkcs11KeyType(uint32 cdsaAlgoId)
{
  switch (cdsaAlgoId)
  {
    case CSSM_ALGID_RSA_PKCS:
      return CKK_RSA;

    case CSSM_ALGID_DSA:
      return CKK_DSA;

    case CSSM_ALGID_DH:
      return CKK_DH;

    case CSSM_ALGID_GenericSecret:
      return CKK_GENERIC_SECRET;

    case CSSM_ALGID_RC2:
      return CKK_RC2;

    case CSSM_ALGID_RC4:
      return CKK_RC4;

    case CSSM_ALGID_DES:
      return CKK_DES;

    case CSSM_ALGID_3DES_2KEY:
      return CKK_DES2;

    case CSSM_ALGID_3DES_3KEY:
      return CKK_DES3;

    default:
      return CKK_VENDOR_DEFINED;
  }
}



/*****************************************************************************
 * Function: DataGetAttributes
 * 
 * Get attributes or key from unique record 
 *
 * Input:
 *  CssmDLDBHandle    - DL/DB handles 
 *  pCssmUniqueRecord - Unique record id
 *  CssmQueryFlags    - Query flags, return key in reference or data format 
 *   
 * Output:
 *  pCssmAttributes   - Record attributes
 *  pCssmData     - Record data, currently only keys are supported
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DataGetAttributes(
    CSSM_DL_DB_HANDLE CssmDLDBHandle,
  CSSM_DB_UNIQUE_RECORD_PTR pCssmUniqueRecord,
  CSSM_QUERY_FLAGS CssmQueryFlags,
    CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pCssmAttributes,
    CSSM_DATA_PTR pCssmData)
{
  MSMSESSION_PTR        pMsmSession = NULL;

  CSSM_DB_ATTRIBUTE_DATA_PTR  pCssmAttrData= NULL;

  CSSM_KEY_PTR        pCssmOutKey = NULL;
  uint32            CssmAlgoId;         /* Algoritm ID of key */
  uint32            CssmKeyClass;       /* Public/Private/Secret etc. */
  uint32            CssmKeySizeInBits = 0;    /* Size of actual key in bits */
  uint32            CssmKeyAttr = 0;      /* Attribute flags */
  uint32            CssmKeyUsage = 0;     /* Key use flags */
  CSSM_DATE_PTR       pCssmStartDate = NULL;    /* Effective date of key */
  CSSM_DATE_PTR       pCssmEndDate = NULL;
  CSSM_DATA         CssmModulus = {0, NULL};
  uint32            CssmModulusBits = 0;
  CSSM_DATA         CssmPublicExponent = {0, NULL};
  CSSM_DATA         CssmPrivateExponent = {0, NULL};
  CSSM_DATA         CssmPrimeOne = {0, NULL};
  CSSM_DATA         CssmPrimeTwo = {0, NULL};
  CSSM_DATA         CssmExponentOne = {0, NULL};
  CSSM_DATA         CssmExponentTwo = {0, NULL};
  CSSM_DATA         CssmCoefficient = {0, NULL};
  CSSM_DATA         CssmPrime = {0, NULL};
  CSSM_DATA         CssmSubPrime = {0, NULL};
  CSSM_DATA         CssmBase = {0, NULL};
  CSSM_DATA         CssmValue = {0, NULL};
  uint32            CssmExponentBits = 0;

  CSSM_DATA_PTR       pCssmLabel = NULL;

  CK_RV           PkcsRc;
  CK_ATTRIBUTE_PTR      pPkcsTemplate = NULL;
  CK_OBJECT_HANDLE      hPkcsObject;

#ifdef PKCS11_V20
  CK_ULONG          PkcsAttrCount;
  CK_ULONG          ii;
  CK_ULONG          jj;
  CK_ULONG          kk;
#else
  CK_USHORT         PkcsAttrCount;
  CK_USHORT         ii;
  CK_USHORT         jj;
  CK_USHORT         kk;
#endif

  CK_OBJECT_CLASS       PkcsClass;
  CK_KEY_TYPE         PkcsKeyType;
  CK_BBOOL          PkcsSensitive = TRUE;
  CK_ATTRIBUTE        PkcsAttrs[] =
  {
    {CKA_CLASS,   &PkcsClass,   sizeof(PkcsClass)   },
    {CKA_KEY_TYPE,  &PkcsKeyType, sizeof(PkcsKeyType)   },
    {CKA_SENSITIVE, &PkcsSensitive, sizeof(PkcsSensitive) }
  };

  CSSM_SELECTION_PREDICATE_PTR  pPredicate = NULL;



#ifdef _DEBUG
printf("Enter Data GetAttributes\n");
#endif


  //
  // Handle & Pointer Validation
  //

  if ((pMsmSession = FindMsmSession(CssmDLDBHandle.DLHandle)) == NULL)
    return SetErr(CSSM_DL_INVALID_DL_HANDLE);

  if (CssmDLDBHandle.DBHandle != pMsmSession->CssmHandleInfo.SubServiceID)
    return SetErr(CSSM_DL_INVALID_DB_HANDLE);

  if (pCssmUniqueRecord == NULL || pCssmUniqueRecord->RecordIdentifier.Data == NULL ||
    pCssmAttributes == NULL || pCssmData == NULL)
    return SetErr(CSSM_DL_INVALID_PTR);


  hPkcsObject = *((CK_OBJECT_HANDLE_PTR) pCssmUniqueRecord->RecordIdentifier.Data);


  //
  // Get 'essential' attributes to set up GET template
  //

#ifdef _DEBUG
printf("JCW: Calling C_GetAttributeValue to find object class...\n");
#endif

  if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                    hPkcsObject,
                    PkcsAttrs,
                    DIM(PkcsAttrs))) != CKR_OK) {
    if ((PkcsRc != CKR_ATTRIBUTE_SENSITIVE) && 
      (PkcsRc != CKR_ATTRIBUTE_TYPE_INVALID))  // MAC - fixed shim bug
      return SetErr(PkcsRc);
  }

#ifdef _DEBUG
printf("JCW: returned from C_GetAttributeValue.  PkcsClass = %d\n", PkcsClass);
#endif

  switch (PkcsClass)
  {
    case CKO_DATA:
#ifdef _DEBUG
printf("JCW: CKO_DATA\n");
#endif
      PkcsAttrCount = PKCS_TOTAL_DATA_ATTRS;
      pCssmAttributes->DataRecordType = CSSM_DL_DB_RECORD_GENERIC;
      break;

    case CKO_CERTIFICATE:
#ifdef _DEBUG
printf("JCW: CKO_CERTIFICATE\n");
#endif
      PkcsAttrCount = PKCS_TOTAL_CERT_ATTRS;
      pCssmAttributes->DataRecordType = CSSM_DL_DB_RECORD_CERT;
      break;

    case CKO_PUBLIC_KEY:
#ifdef _DEBUG
printf("JCW: CKO_PUBLIC_KEY\n");
#endif
      PkcsAttrCount = PKCS_TOTAL_PUBLIC_ATTRS;
      pCssmAttributes->DataRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
      break;

    case CKO_PRIVATE_KEY:
#ifdef _DEBUG
printf("JCW: CKO_PRIVATE_KEY\n");
#endif
      PkcsAttrCount = PKCS_TOTAL_PRIVATE_ATTRS;
      pCssmAttributes->DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
      break;

    case CKO_SECRET_KEY:
#ifdef _DEBUG
printf("JCW: CKO_SECRET_KEY\n");
#endif
      PkcsAttrCount = PKCS_TOTAL_SECRET_ATTRS;
      pCssmAttributes->DataRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
      break;

    default:
#ifdef _DEBUG
printf("JCW: Unknown class!\n");
#endif
      return SetErr(CKR_ATTRIBUTE_TYPE_INVALID);
  }

  

  //
  // Allocate and set up GET template
  //

#ifdef _DEBUG
  printf("JCW: Allocating space for %d attributes\n", PkcsAttrCount);
#endif

  if ((pPkcsTemplate = (CK_ATTRIBUTE_PTR) calloc(PkcsAttrCount, sizeof(CK_ATTRIBUTE))) == NULL)
    return SetErr(CSSM_DL_MEMORY_ERROR);

  ii = 0;
  (pPkcsTemplate + ii++)->type = CKA_CLASS; 
  (pPkcsTemplate + ii++)->type = CKA_TOKEN;
  (pPkcsTemplate + ii++)->type = CKA_PRIVATE;
#ifdef PKCS11_V20
  (pPkcsTemplate + ii++)->type = CKA_MODIFIABLE;
#endif
  (pPkcsTemplate + ii++)->type = CKA_LABEL; 

  
  switch (PkcsClass)
  {
    case CKO_DATA:
      (pPkcsTemplate + ii++)->type = CKA_APPLICATION;
      (pPkcsTemplate + ii++)->type = CKA_VALUE; 
      break;

    case CKO_CERTIFICATE:
      (pPkcsTemplate + ii++)->type = CKA_CERTIFICATE_TYPE;
      (pPkcsTemplate + ii++)->type = CKA_SUBJECT;
      (pPkcsTemplate + ii++)->type = CKA_ID;
      (pPkcsTemplate + ii++)->type = CKA_ISSUER;
      (pPkcsTemplate + ii++)->type = CKA_SERIAL_NUMBER;
      (pPkcsTemplate + ii++)->type = CKA_VALUE; 
      break;

    case CKO_PUBLIC_KEY:
      (pPkcsTemplate + ii++)->type = CKA_KEY_TYPE;
      (pPkcsTemplate + ii++)->type = CKA_ID;
      (pPkcsTemplate + ii++)->type = CKA_START_DATE;
      (pPkcsTemplate + ii++)->type = CKA_END_DATE;
      (pPkcsTemplate + ii++)->type = CKA_DERIVE;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii++)->type = CKA_LOCAL; 
#endif
      (pPkcsTemplate + ii++)->type = CKA_SUBJECT;
      (pPkcsTemplate + ii++)->type = CKA_ENCRYPT;
      (pPkcsTemplate + ii++)->type = CKA_VERIFY;
      (pPkcsTemplate + ii++)->type = CKA_VERIFY_RECOVER;
      (pPkcsTemplate + ii++)->type = CKA_WRAP;
      
      switch (PkcsKeyType)
      {
        case CKK_RSA:
          (pPkcsTemplate + ii++)->type = CKA_MODULUS;
          (pPkcsTemplate + ii++)->type = CKA_PUBLIC_EXPONENT;
          break;

        case CKK_DSA:
#ifdef PKCS11_V20
        case CKK_ECDSA:
        case CKK_KEA:
        case CKK_MAYFLY:
#endif
          (pPkcsTemplate + ii++)->type = CKA_PRIME;
          (pPkcsTemplate + ii++)->type = CKA_SUBPRIME;
          (pPkcsTemplate + ii++)->type = CKA_BASE;
          (pPkcsTemplate + ii++)->type = CKA_VALUE;
          break;

        case CKK_DH:
          (pPkcsTemplate + ii++)->type = CKA_PRIME;
          (pPkcsTemplate + ii++)->type = CKA_BASE;
          (pPkcsTemplate + ii++)->type = CKA_VALUE;
          break;
      }   
    
      break;


    case CKO_PRIVATE_KEY:
      (pPkcsTemplate + ii++)->type = CKA_KEY_TYPE;
      (pPkcsTemplate + ii++)->type = CKA_ID;
      (pPkcsTemplate + ii++)->type = CKA_START_DATE;
      (pPkcsTemplate + ii++)->type = CKA_END_DATE;
      (pPkcsTemplate + ii++)->type = CKA_DERIVE;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii++)->type = CKA_LOCAL; 
#endif
      (pPkcsTemplate + ii++)->type = CKA_SUBJECT;
      (pPkcsTemplate + ii++)->type = CKA_SENSITIVE;
      (pPkcsTemplate + ii++)->type = CKA_DECRYPT;
      (pPkcsTemplate + ii++)->type = CKA_SIGN;
      (pPkcsTemplate + ii++)->type = CKA_SIGN_RECOVER;
      (pPkcsTemplate + ii++)->type = CKA_UNWRAP;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii++)->type = CKA_EXTRACTABLE;
      (pPkcsTemplate + ii++)->type = CKA_ALWAYS_SENSITIVE;
      (pPkcsTemplate + ii++)->type = CKA_NEVER_EXTRACTABLE;
#endif

      switch (PkcsKeyType)
      {
        case CKK_RSA:
          if (PkcsSensitive == FALSE)
          {
            (pPkcsTemplate + ii++)->type = CKA_MODULUS;
            (pPkcsTemplate + ii++)->type = CKA_PUBLIC_EXPONENT;
            (pPkcsTemplate + ii++)->type = CKA_PRIVATE_EXPONENT;
            (pPkcsTemplate + ii++)->type = CKA_PRIME_1;
            (pPkcsTemplate + ii++)->type = CKA_PRIME_2;
            (pPkcsTemplate + ii++)->type = CKA_EXPONENT_1;
            (pPkcsTemplate + ii++)->type = CKA_EXPONENT_2;
            (pPkcsTemplate + ii++)->type = CKA_COEFFICIENT;
          }
          break;

        case CKK_DSA:
#ifdef PKCS11_V20
        case CKK_ECDSA:
        case CKK_KEA:
        case CKK_MAYFLY:
#endif
          if (PkcsSensitive == FALSE)
          {
            (pPkcsTemplate + ii++)->type = CKA_PRIME;
            (pPkcsTemplate + ii++)->type = CKA_SUBPRIME;
            (pPkcsTemplate + ii++)->type = CKA_BASE;
            (pPkcsTemplate + ii++)->type = CKA_VALUE;
          }
          break;

        case CKK_DH:
          if (PkcsSensitive == FALSE)
          {
            (pPkcsTemplate + ii++)->type = CKA_PRIME;
            (pPkcsTemplate + ii++)->type = CKA_BASE;
            (pPkcsTemplate + ii++)->type = CKA_VALUE;
          }
          break;
      }   
      
      break;

    case CKO_SECRET_KEY:
      (pPkcsTemplate + ii++)->type = CKA_KEY_TYPE;
      (pPkcsTemplate + ii++)->type = CKA_ID;
      (pPkcsTemplate + ii++)->type = CKA_START_DATE;
      (pPkcsTemplate + ii++)->type = CKA_END_DATE;
      (pPkcsTemplate + ii++)->type = CKA_DERIVE;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii++)->type = CKA_LOCAL;
#endif
      (pPkcsTemplate + ii++)->type = CKA_SENSITIVE;
      (pPkcsTemplate + ii++)->type = CKA_ENCRYPT;
      (pPkcsTemplate + ii++)->type = CKA_DECRYPT;
      (pPkcsTemplate + ii++)->type = CKA_SIGN;
      (pPkcsTemplate + ii++)->type = CKA_VERIFY;
      (pPkcsTemplate + ii++)->type = CKA_WRAP;
      (pPkcsTemplate + ii++)->type = CKA_UNWRAP;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii++)->type = CKA_EXTRACTABLE;
      (pPkcsTemplate + ii++)->type = CKA_ALWAYS_SENSITIVE;
      (pPkcsTemplate + ii++)->type = CKA_NEVER_EXTRACTABLE;
#endif
      //@@
      if (PkcsSensitive == FALSE)
      {
        (pPkcsTemplate + ii++)->type = CKA_VALUE;
      }

      break;
  }



  //
  // Get lengths of attributes
  //
#ifdef _DEBUG
printf("JCW: Calling C_GetAttributeValue(Handle, obj, template, %d)\n", ii);
#endif

  if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                    hPkcsObject,
                    pPkcsTemplate,
                    ii)) != CKR_OK)
  { 
    free(pPkcsTemplate);
    return SetErr(PkcsRc);
  }


  //
  // Allocate memory for attributes
  //

  for (jj = 0; jj < ii; jj++)
  { 
#ifdef PKCS11_V20
    if ((pPkcsTemplate + jj)->ulValueLen != 0)
    {
      if (((pPkcsTemplate + jj)->pValue = CssmMemFuncs.calloc_func(
                          CssmDLDBHandle.DLHandle, 
                          1, 
                          (pPkcsTemplate + jj)->ulValueLen)) == NULL)
      {
        for (kk = 0; kk < jj; kk++)
          CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, (pPkcsTemplate + kk)->pValue); 
        
        free(pPkcsTemplate);
        return SetErr(CSSM_DL_MEMORY_ERROR);
      }
    } else {
#ifdef _DEBUG
      printf("Processing template = %x\n", (pPkcsTemplate+jj)->type);
      printf("Value allocated = %d\n", (pPkcsTemplate+jj)->ulValueLen);
#endif
    }
    
#else
    if ((pPkcsTemplate + jj)->usValueLen != 0)
    {
      if (((pPkcsTemplate + jj)->pValue = CssmMemFuncs.calloc_func(
                          CssmDLDBHandle.DLHandle, 
                          1, 
                          (pPkcsTemplate + jj)->usValueLen)) == NULL)
      {
        for (kk = 0; kk < jj; kk++)
          CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, (pPkcsTemplate + kk)->pValue); 
        
        free(pPkcsTemplate);
        return SetErr(CSSM_DL_MEMORY_ERROR);
      }
    }
#endif
  }

 

  //
  // Get the attributes
  //

  if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                    hPkcsObject,
                    pPkcsTemplate,
                    ii)) != CKR_OK)
  { 
    for (kk = 0; kk < ii; kk++)
      CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, (pPkcsTemplate + kk)->pValue); 
      
    free(pPkcsTemplate);
    return SetErr(PkcsRc);
  }


  //
  // If we get here we have data, with pPkcsTemplate and the attributes pointing to 
  // allocated memory which must be freed if anything fails. We must now convert PKCS 
  // data to CDSA data.
  //

  pCssmAttributes->AttributeData = NULL;


  do
  {
    //
    // Set up pCssmAttributes
    //
    
    // pCssmAttributes->DataRecordType set above.
    pCssmAttributes->SemanticInformation= 0;
    pCssmAttributes->NumberOfAttributes = ii;
    if ((pCssmAttributes->AttributeData = (CSSM_DB_ATTRIBUTE_DATA_PTR) CssmMemFuncs.calloc_func(
                          CssmDLDBHandle.DLHandle, 
                          ii, 
                          sizeof(CSSM_DB_ATTRIBUTE_DATA))) == NULL)
      break;


    for (jj = 0; jj < ii; jj++)
    { 
#ifdef _DEBUG
      printf("Type = %x ", (pPkcsTemplate+jj)->type);
      printf("Value len = %d ", (pPkcsTemplate+jj)->ulValueLen);
      printf("Data = %s\n", (pPkcsTemplate+jj)->pValue);
#endif
      // Set up individual attribute in list
      pCssmAttrData = pCssmAttributes->AttributeData + jj;

      pCssmAttrData->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER;
      pCssmAttrData->Info.AttributeNumber = (pPkcsTemplate + jj)->type;

  #ifdef PKCS11_V20
      pCssmAttrData->Value.Length = (pPkcsTemplate + jj)->ulValueLen;
  #else
      pCssmAttrData->Value.Length = (pPkcsTemplate + jj)->usValueLen;
  #endif

      pCssmAttrData->Value.Data = (pPkcsTemplate + jj)->pValue;


      // If object is a key, we want to collect info to set up a CDSA key later
      if (PkcsClass == CKO_SECRET_KEY || 
        PkcsClass == CKO_PUBLIC_KEY || 
        PkcsClass == CKO_PRIVATE_KEY)
      { 
        switch (pCssmAttrData->Info.AttributeNumber)
        {
          case CKA_CLASS:
            CssmKeyClass = toCdsaKeyClass(*((CK_OBJECT_CLASS*) pCssmAttrData->Value.Data));
            break;

          case CKA_KEY_TYPE:
            CssmAlgoId = toCdsaAlgoId(*((CK_KEY_TYPE*) pCssmAttrData->Value.Data));
            
            if (CssmAlgoId == CSSM_ALGID_DES)
              CssmKeySizeInBits = 8 * 8;
            else if (CssmAlgoId == CSSM_ALGID_3DES_2KEY)
              CssmKeySizeInBits = 16 * 8;
            else if (CssmAlgoId == CSSM_ALGID_3DES_3KEY)
              CssmKeySizeInBits = 24 * 8;

            break;

          case CKA_MODULUS:
            CssmModulus.Length = pCssmAttrData->Value.Length;
            CssmModulus.Data = pCssmAttrData->Value.Data;
            
            if (CssmKeySizeInBits == 0)
              CssmKeySizeInBits = pCssmAttrData->Value.Length * 8;
            
            if (CssmModulusBits == 0)
              CssmModulusBits = pCssmAttrData->Value.Length * 8;
            
            break;

          case CKA_PUBLIC_EXPONENT:
            CssmPublicExponent.Length = pCssmAttrData->Value.Length;
            CssmPublicExponent.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_PRIVATE_EXPONENT:
            CssmPrivateExponent.Length = pCssmAttrData->Value.Length;
            CssmPrivateExponent.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_PRIME_1:
            CssmPrimeOne.Length = pCssmAttrData->Value.Length;
            CssmPrimeOne.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_PRIME_2:
            CssmPrimeTwo.Length = pCssmAttrData->Value.Length;
            CssmPrimeTwo.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_EXPONENT_1:
            CssmExponentOne.Length = pCssmAttrData->Value.Length;
            CssmExponentOne.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_EXPONENT_2:
            CssmExponentTwo.Length = pCssmAttrData->Value.Length;
            CssmExponentTwo.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_COEFFICIENT:
            CssmCoefficient.Length = pCssmAttrData->Value.Length;
            CssmCoefficient.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_PRIME:
            CssmPrime.Length = pCssmAttrData->Value.Length;
            CssmPrime.Data = pCssmAttrData->Value.Data;

            if (CssmKeySizeInBits == 0)
              CssmKeySizeInBits = pCssmAttrData->Value.Length * 8;
            
            break;

          case CKA_SUBPRIME:
            CssmSubPrime.Length = pCssmAttrData->Value.Length;
            CssmSubPrime.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_BASE:
            CssmBase.Length = pCssmAttrData->Value.Length;
            CssmBase.Data = pCssmAttrData->Value.Data;
            break;

          case CKA_VALUE:
            CssmValue.Length = pCssmAttrData->Value.Length;
            CssmValue.Data = pCssmAttrData->Value.Data;

            if (CssmKeySizeInBits == 0)
              CssmKeySizeInBits = pCssmAttrData->Value.Length * 8;
            
            break;  
        
          case CKA_VALUE_LEN:
            CssmKeySizeInBits = *((uint32*) pCssmAttrData->Value.Data);
            break;

          case CKA_TOKEN:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_PERMANENT;
            break;
            
          case CKA_PRIVATE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_PRIVATE;
            break;

          case CKA_SENSITIVE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_SENSITIVE;
            break;

          case CKA_DERIVE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_DERIVE;
            break;
            
          case CKA_ENCRYPT:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_ENCRYPT;
            break;

          case CKA_VERIFY:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_VERIFY;
            break;

          case CKA_VERIFY_RECOVER:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_VERIFY_RECOVER;
            break;

          case CKA_WRAP:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_WRAP;
            break;

          case CKA_DECRYPT:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_DECRYPT;
            break;

          case CKA_SIGN:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_SIGN;
            break;

          case CKA_SIGN_RECOVER:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_SIGN_RECOVER;
            break;
            
          case CKA_UNWRAP:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyUsage |= CSSM_KEYUSE_UNWRAP;
            break;

#ifdef PKCS11_V20
          case CKA_EXTRACTABLE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_EXTRACTABLE;
            break;

          case CKA_ALWAYS_SENSITIVE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_ALWAYS_SENSITIVE;
            break;

          case CKA_NEVER_EXTRACTABLE:
            if (*((CK_BBOOL*) pCssmAttrData->Value.Data) == TRUE)
              CssmKeyAttr |= CSSM_KEYATTR_NEVER_EXTRACTABLE;
            break;
#endif

          case CKA_START_DATE:
            pCssmStartDate =  (CSSM_DATE_PTR) pCssmAttrData->Value.Data;
            break;
        
          case CKA_END_DATE:
            pCssmEndDate =  (CSSM_DATE_PTR) pCssmAttrData->Value.Data;
            break;

          case CKA_LABEL:
            pCssmLabel = &pCssmAttrData->Value;
            break;
        } /* switch */
      } /* if key */  
    } /* for loop */
    

    //
    // Set up CssmOutKey
    //

    if (PkcsClass == CKO_PUBLIC_KEY ||
      PkcsClass == CKO_PRIVATE_KEY ||
      PkcsClass == CKO_SECRET_KEY)
    {
 
      if ((pCssmOutKey = CssmMemFuncs.calloc_func(
                  pMsmSession->CssmModuleHandle, 
                  1, 
                  sizeof(CSSM_KEY))) == NULL)
        break;


      //
      // If return key in CDSA format
      //

      if (CssmQueryFlags & CSSM_QUERY_RETURN_DATA)
      {
        SetupKeyHeader(
          &pCssmOutKey->KeyHeader,
          CSSM_KEYBLOB_RAW,             /* See BlobType #define's */
          CSSM_KEYBLOB_RAW_FORMAT_CDSA,       /* Raw or Reference format */
          CssmAlgoId,                 /* Algoritm ID of key */
          CssmKeyClass,               /* Public/Private/Secret etc. */
          CssmKeySizeInBits,              /* Size of actual key in bits */
          CssmKeyAttr,                /* Attribute flags */
          CssmKeyUsage,               /* Key use flags */
          pCssmStartDate,               /* Effective date of key */
          pCssmEndDate,               /* Expiration date of key */
          CSSM_ALGID_NONE,              /* Wrap Algo */
          CSSM_ALGMODE_NONE);             /* Wrap Mode */

        if (CssmKeyClass == CSSM_KEYCLASS_PUBLIC_KEY)
        {
          if (CssmAlgoId ==  CSSM_ALGID_RSA_PKCS)
          {
            CSSM_RSA_PUBLIC_PTR pCssmRsaPublic = NULL;

            if ((pCssmRsaPublic = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle,
                                1, sizeof(CSSM_RSA_PUBLIC))) == NULL)
              break;

            // Set up modulus
            if ((pCssmRsaPublic->modulus.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmModulus.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPublic);
              break;
            }

            memcpy(pCssmRsaPublic->modulus.Data, CssmModulus.Data, CssmModulus.Length);
            pCssmRsaPublic->modulus.Length = CssmModulus.Length;

            
            // Set up modulus bits
            pCssmRsaPublic->modulusBits = CssmModulusBits;
            
            
            // Set up publicExponent
            if ((pCssmRsaPublic->publicExponent.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPublicExponent.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPublic->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPublic);
              break;
            }

            memcpy(pCssmRsaPublic->publicExponent.Data, 
                 CssmPublicExponent.Data, CssmPublicExponent.Length);
            pCssmRsaPublic->publicExponent.Length = CssmPublicExponent.Length;

            
            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmRsaPublic;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_RSA_PUBLIC);
          }
          else if (CssmAlgoId ==  CSSM_ALGID_DSA)
          {
            CSSM_DSA_PUBLIC_PTR pCssmDsaPublic = NULL;

            if ((pCssmDsaPublic = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle,
                                1, sizeof(CSSM_DSA_PUBLIC))) == NULL)
              break;


            // Set up prime
            if ((pCssmDsaPublic->prime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic);
              break;
            }

            memcpy(pCssmDsaPublic->prime.Data, CssmPrime.Data, CssmPrime.Length);
            pCssmDsaPublic->prime.Length = CssmPrime.Length;


            // Set up subPrime
            if ((pCssmDsaPublic->subPrime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmSubPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic);
              break;
            }

            memcpy(pCssmDsaPublic->subPrime.Data, CssmSubPrime.Data, CssmSubPrime.Length);
            pCssmDsaPublic->subPrime.Length = CssmSubPrime.Length;


            // Set up base
            if ((pCssmDsaPublic->base.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmBase.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->subPrime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic);
              break;
            }

            memcpy(pCssmDsaPublic->base.Data, CssmBase.Data, CssmBase.Length);
            pCssmDsaPublic->base.Length = CssmBase.Length;


            // Set up publicValue
            if ((pCssmDsaPublic->publicValue.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmValue.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->base.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->subPrime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPublic);
              break;
            }

            memcpy(pCssmDsaPublic->publicValue.Data, CssmValue.Data, CssmValue.Length);
            pCssmDsaPublic->publicValue.Length = CssmValue.Length;
            
            
            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmDsaPublic;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_DSA_PUBLIC);
          }
          else if (CssmAlgoId ==  CSSM_ALGID_DH)
          {
            CSSM_DH_PUBLIC_PTR  pCssmDhPublic = NULL;

            if ((pCssmDhPublic = CssmMemFuncs.calloc_func(
                        CssmDLDBHandle.DLHandle,
                        1, sizeof(CSSM_DH_PUBLIC))) == NULL)
              break;


            // Set up prime
            if ((pCssmDhPublic->prime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic);
              break;
            }

            memcpy(pCssmDhPublic->prime.Data, CssmPrime.Data, CssmPrime.Length);
            pCssmDhPublic->prime.Length = CssmPrime.Length;


            // Set up base
            if ((pCssmDhPublic->base.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmBase.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic);
              break;
            }

            memcpy(pCssmDhPublic->base.Data, CssmBase.Data, CssmBase.Length);
            pCssmDhPublic->base.Length = CssmBase.Length;


            // Set up publicValue
            if ((pCssmDhPublic->publicValue.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmValue.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic->base.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPublic);
              break;
            }

            memcpy(pCssmDhPublic->publicValue.Data, CssmValue.Data, CssmValue.Length);
            pCssmDhPublic->publicValue.Length = CssmValue.Length;
            
            
            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmDhPublic;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_DH_PUBLIC);
          }
        }
        else if (CssmKeyClass == CSSM_KEYCLASS_PRIVATE_KEY && PkcsSensitive == FALSE)
        {
          if (CssmAlgoId ==  CSSM_ALGID_RSA_PKCS)
          {
            CSSM_RSA_PRIVATE_PTR  pCssmRsaPrivate = NULL;

            if ((pCssmRsaPrivate = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle,
                                1, sizeof(CSSM_RSA_PRIVATE))) == NULL)
              break;

            // Set up modulus
            if ((pCssmRsaPrivate->modulus.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmModulus.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->modulus.Data, CssmModulus.Data, CssmModulus.Length);
            pCssmRsaPrivate->modulus.Length = CssmModulus.Length;
    
            
            // Set up publicExponent
            if ((pCssmRsaPrivate->publicExponent.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPublicExponent.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->publicExponent.Data, 
                 CssmPublicExponent.Data, 
                 CssmPublicExponent.Length);
            pCssmRsaPrivate->publicExponent.Length = CssmPublicExponent.Length;


            // Set up privateExponent
            if ((pCssmRsaPrivate->privateExponent.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrivateExponent.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->privateExponent.Data, 
                 CssmPrivateExponent.Data, 
                 CssmPrivateExponent.Length);
            pCssmRsaPrivate->privateExponent.Length = CssmPrivateExponent.Length;


            // Set up primeOne
            if ((pCssmRsaPrivate->primeOne.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrimeOne.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->privateExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->primeOne.Data, 
                 CssmPrimeOne.Data, 
                 CssmPrimeOne.Length);
            pCssmRsaPrivate->primeOne.Length = CssmPrimeOne.Length;


            // Set up primeTwo
            if ((pCssmRsaPrivate->primeTwo.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrimeTwo.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->privateExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->primeTwo.Data, 
                 CssmPrimeTwo.Data, 
                 CssmPrimeTwo.Length);
            pCssmRsaPrivate->primeTwo.Length = CssmPrimeTwo.Length;


            // Set up exponentOne
            if ((pCssmRsaPrivate->exponentOne.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmExponentOne.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeTwo.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->privateExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->exponentOne.Data, 
                 CssmExponentOne.Data, 
                 CssmExponentOne.Length);
            pCssmRsaPrivate->exponentOne.Length = CssmExponentOne.Length;


            // Set up exponentTwo
            if ((pCssmRsaPrivate->exponentTwo.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmExponentTwo.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->exponentOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeTwo.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->privateExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->exponentTwo.Data, 
                 CssmExponentTwo.Data, 
                 CssmExponentTwo.Length);
            pCssmRsaPrivate->exponentTwo.Length = CssmExponentTwo.Length;


            // Set up coefficient
            if ((pCssmRsaPrivate->coefficient.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmCoefficient.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->exponentTwo.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->exponentOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeTwo.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->primeOne.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->privateExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->publicExponent.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate->modulus.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmRsaPrivate);
              break;
            }

            memcpy(pCssmRsaPrivate->coefficient.Data, 
                 CssmCoefficient.Data, 
                 CssmCoefficient.Length);
            pCssmRsaPrivate->coefficient.Length = CssmCoefficient.Length;
            

            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmRsaPrivate;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_RSA_PRIVATE);
          }
          else if (CssmAlgoId ==  CSSM_ALGID_DSA)
          {
            CSSM_DSA_PRIVATE_PTR  pCssmDsaPrivate = NULL;

            if ((pCssmDsaPrivate = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle,
                                1, sizeof(CSSM_DSA_PRIVATE))) == NULL)
              break;


            // Set up prime
            if ((pCssmDsaPrivate->prime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate);
              break;
            }

            memcpy(pCssmDsaPrivate->prime.Data, CssmPrime.Data, CssmPrime.Length);
            pCssmDsaPrivate->prime.Length = CssmPrime.Length;


            // Set up subPrime
            if ((pCssmDsaPrivate->subPrime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmSubPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate);
              break;
            }

            memcpy(pCssmDsaPrivate->subPrime.Data, CssmSubPrime.Data, CssmSubPrime.Length);
            pCssmDsaPrivate->subPrime.Length = CssmSubPrime.Length;


            // Set up base
            if ((pCssmDsaPrivate->base.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmBase.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->subPrime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate);
              break;
            }

            memcpy(pCssmDsaPrivate->base.Data, CssmBase.Data, CssmBase.Length);
            pCssmDsaPrivate->base.Length = CssmBase.Length;


            // Set up privateValue
            if ((pCssmDsaPrivate->privateValue.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmValue.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->base.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->subPrime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDsaPrivate);
              break;
            }

            memcpy(pCssmDsaPrivate->privateValue.Data, CssmValue.Data, CssmValue.Length);
            pCssmDsaPrivate->privateValue.Length = CssmValue.Length;
            
            
            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmDsaPrivate;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_DSA_PRIVATE);
          }
          else if (CssmAlgoId ==  CSSM_ALGID_DH)
          {
            CSSM_DH_PRIVATE_PTR pCssmDhPrivate = NULL;

            if ((pCssmDhPrivate = CssmMemFuncs.calloc_func(
                        CssmDLDBHandle.DLHandle,
                        1, sizeof(CSSM_DH_PRIVATE))) == NULL)
              break;


            // Set up prime
            if ((pCssmDhPrivate->prime.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmPrime.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate);
              break;
            }

            memcpy(pCssmDhPrivate->prime.Data, CssmPrime.Data, CssmPrime.Length);
            pCssmDhPrivate->prime.Length = CssmPrime.Length;


            // Set up base
            if ((pCssmDhPrivate->base.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmBase.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate);
              break;
            }

            memcpy(pCssmDhPrivate->base.Data, CssmBase.Data, CssmBase.Length);
            pCssmDhPrivate->base.Length = CssmBase.Length;


            // Set up privateValue
            if ((pCssmDhPrivate->privateValue.Data = CssmMemFuncs.calloc_func(
                                CssmDLDBHandle.DLHandle, 
                                1, 
                                CssmValue.Length)) == NULL)
            {
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate->base.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate->prime.Data);
              CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmDhPrivate);
              break;
            }

            memcpy(pCssmDhPrivate->privateValue.Data, CssmValue.Data, CssmValue.Length);
            pCssmDhPrivate->privateValue.Length = CssmValue.Length;
            
            
            // Set up key data part
            pCssmOutKey->KeyData.Data = (uint8*) pCssmDhPrivate;
            pCssmOutKey->KeyData.Length = sizeof(CSSM_DH_PRIVATE);
          }
        }
        else if (CssmKeyClass == CSSM_KEYCLASS_SESSION_KEY)
        {

          // Get clear key data 

          PkcsRc = C_ExtractClearKeyObject(
                pMsmSession->PkcsSessionHandle,
                (CK_OBJECT_HANDLE_PTR)pCssmUniqueRecord->RecordIdentifier.Data,
                &pCssmOutKey->KeyData,
                CssmDLDBHandle.DLHandle);

          if  (PkcsRc != CKR_OK)
            break;

        }
      }
      else
      {

        SetupKeyHeader(
          &pCssmOutKey->KeyHeader,
          CSSM_KEYBLOB_REFERENCE,           /* See BlobType #define's */
          CSSM_KEYBLOB_REF_FORMAT_INTEGER,      /* Raw or Reference format */
          CssmAlgoId,                 /* Algoritm ID of key */
          CssmKeyClass,               /* Public/Private/Secret etc. */
          CssmKeySizeInBits,              /* Size of actual key in bits */
          CssmKeyAttr,                /* Attribute flags */
          CssmKeyUsage,               /* Key use flags */
          pCssmStartDate,               /* Effective date of key */
          pCssmEndDate,               /* Expiration date of key */
          CSSM_ALGID_NONE,              /* Wrap Algo */
          CSSM_ALGMODE_NONE);             /* Wrap Mode */

        
        if ((pCssmOutKey->KeyData.Data = CssmMemFuncs.calloc_func(
                          pMsmSession->CssmModuleHandle, 
                          1, 
                          sizeof(CK_OBJECT_HANDLE))) == NULL)
          break;

        *((CK_OBJECT_HANDLE_PTR) pCssmOutKey->KeyData.Data) = hPkcsObject;
        pCssmOutKey->KeyData.Length = sizeof(CK_OBJECT_HANDLE);
        
      }
      
      pCssmData->Data = (uint8*) pCssmOutKey;
      pCssmData->Length = sizeof(CSSM_KEY);
    }
 
    if (pPkcsTemplate != NULL) {
    }

    return CSSM_OK;

  } while (0);


  //
  // If we get here some memory allocation has failed, garbage collect all previously calloc's
  //

  if (pCssmOutKey != NULL)
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle,pCssmOutKey);

  if (pPkcsTemplate != NULL)
  {
    for (jj = 0; jj < ii; jj++)
      CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, (pPkcsTemplate + jj)->pValue);

    free(pPkcsTemplate);
  }

  return SetErr(CSSM_DL_MEMORY_ERROR);

}




/*****************************************************************************
 * Function: DataGetFirst 
 *
 * Find first record matching query predicate 
 *
 * Input:
 *  CssmDLDBHandle    - DL/DB handles 
 *  pCssmQuery      - Query predicate 
 *   
 * Output:
 *  pCssmResultsHandle  - Result handle, currently is a PKCS11 session handle
 *  pCssmEndOfDataStore - End of data flag
 *  pCssmAttributes   - Record attributes
 *  pCssmData     - Record data, currently only keys are supported
 *   
 * Returns:
 *  CSSM_DB_UNIQUE_RECORD_PTR - Successful      
 *  NULL            - Failed
 *
 */

CSSM_DB_UNIQUE_RECORD_PTR CSSMAPI DataGetFirst(
    CSSM_DL_DB_HANDLE CssmDLDBHandle,
    const CSSM_QUERY_PTR pCssmQuery,
    CSSM_HANDLE_PTR pCssmResultsHandle,
    CSSM_BOOL* pCssmEndOfDataStore,
    CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pCssmAttributes,
    CSSM_DATA_PTR pCssmData)
{
  MSMSESSION_PTR        pMsmSession = NULL;

  CSSM_DB_UNIQUE_RECORD_PTR pCssmUniqueRecord = NULL;
  CSSM_QUERY_FLAGS      CssmQueryFlags;

  CK_RV           PkcsRc;
  CK_ATTRIBUTE_PTR      pPkcsTemplate = NULL;
  CK_OBJECT_HANDLE      hPkcsObject;

#ifdef PKCS11_V20
  CK_ULONG          PkcsAttrCount;
  CK_ULONG          PkcsObjectCount;
  CK_ULONG          ii;
#else
  CK_USHORT         PkcsAttrCount;
  CK_USHORT         PkcsObjectCount;
  CK_USHORT         ii;
#endif


  CSSM_SELECTION_PREDICATE_PTR  pPredicate = NULL;



#ifdef _DEBUG
  printf("Enter DataGetFirst\n");
#endif


  //
  // Handle & Pointer Validation
  //

  if ((pMsmSession = FindMsmSession(CssmDLDBHandle.DLHandle)) == NULL) {
#ifdef _DEBUG
    printf("Get DLHandle Failed\n");
#endif
    return SetErrNull(CSSM_DL_INVALID_DL_HANDLE);
  }

  if (CssmDLDBHandle.DBHandle != pMsmSession->CssmHandleInfo.SubServiceID) {
#ifdef _DEBUG
    printf("DBHandle %x != Subserviceid %x\n",CssmDLDBHandle.DBHandle, pMsmSession->CssmHandleInfo.SubServiceID);
#endif
    return SetErrNull(CSSM_DL_INVALID_DB_HANDLE);
  }

  if (pCssmResultsHandle == NULL || pCssmEndOfDataStore == NULL ||
    pCssmAttributes == NULL || pCssmData == NULL) {
#ifdef _DEBUG
    printf("Result handle = %x\n", pCssmResultsHandle);
    printf("EndOfDataStore = %x\n", pCssmEndOfDataStore);
    printf("CssmAttributes = %x\n", pCssmAttributes);
    printf("pCssmData = %x\n", pCssmData );
#endif
    return SetErrNull(CSSM_DL_INVALID_PTR);
  }

  //
  // Init return value 
  //

  *pCssmEndOfDataStore = CSSM_FALSE;
  
  //
  // Set up ResultsHandle to PKCS session number
  //

  *pCssmResultsHandle = pMsmSession->PkcsSessionHandle;
#ifdef _DEBUG
  printf("Results handle = %x\n", *pCssmResultsHandle);
#endif

  //
  // Query input == NULL -> Find Everything
  //

  if (pCssmQuery == NULL)
  {
#ifdef _DEBUG
    printf("Query is NULL\n");
#endif
    pPkcsTemplate = NULL;
    PkcsAttrCount = 0;
    CssmQueryFlags = (uint32) ~CSSM_QUERY_RETURN_DATA;
  }
  else
  {
#ifdef _DEBUG
    printf("Query is not null\n");
    printf("Number predicates = %d\n", pCssmQuery->NumSelectionPredicates);
    printf("Query Flags = %x\n", pCssmQuery->QueryFlags);
#endif  
    PkcsAttrCount = pCssmQuery->NumSelectionPredicates;
    CssmQueryFlags = pCssmQuery->QueryFlags;

    // PKCS11 only supports 'AND' 
    if (pCssmQuery->Conjunctive != CSSM_DB_AND)
      return SetErrNull(CSSM_DL_CONJUNCTIVE_NOT_SUPPORTED);

    if (pCssmQuery->SelectionPredicate == NULL)
      return SetErrNull(CSSM_DL_INVALID_SELECTION_PTR);

    if (pCssmQuery->RecordType != CSSM_DL_DB_RECORD_PUBLIC_KEY &&
        pCssmQuery->RecordType != CSSM_DL_DB_RECORD_PRIVATE_KEY &&
      pCssmQuery->RecordType != CSSM_DL_DB_RECORD_SYMMETRIC_KEY &&
      pCssmQuery->RecordType != CSSM_DL_DB_RECORD_CERT &&
      pCssmQuery->RecordType != CSSM_DL_DB_RECORD_GENERIC)
        return SetErrNull(CSSM_DL_INVALID_RECORD_TYPE);

    // PKCS11 only supports 'EQUAL'
    // We only support attributes as 'NUMBER'
    for (ii = 0; ii < PkcsAttrCount; ii++)
    {
      pPredicate = pCssmQuery->SelectionPredicate + ii;

      if (pPredicate->DbOperator != CSSM_DB_EQUAL)
        return SetErrNull(CSSM_DL_OPERATOR_NOT_SUPPORTED);
      
      if (pPredicate->Attribute.Info.AttributeNameFormat != 
          CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER)
        return SetErrNull(CSSM_DL_INVALID_ATTRIBUTE_NAME_FORMAT);

      if (pPredicate->Attribute.Value.Data == NULL ||
        pPredicate->Attribute.Value.Length == 0)
        return SetErrNull(CSSM_DL_INVALID_DATA_POINTER);
    }


    //
    // Set up FIND template from Query input struct
    //

    if ((pPkcsTemplate = (CK_ATTRIBUTE_PTR) calloc(PkcsAttrCount, sizeof(CK_ATTRIBUTE))) == NULL)
      return SetErrNull(CSSM_DL_MEMORY_ERROR);


    for (ii = 0; ii < PkcsAttrCount; ii++)
    {
      pPredicate = pCssmQuery->SelectionPredicate + ii;
      (pPkcsTemplate + ii)->type = pPredicate->Attribute.Info.AttributeNumber;
      (pPkcsTemplate + ii)->pValue = (CK_VOID_PTR) pPredicate->Attribute.Value.Data;
#ifdef PKCS11_V20
      (pPkcsTemplate + ii)->ulValueLen = pPredicate->Attribute.Value.Length;
#else
      (pPkcsTemplate + ii)->usValueLen = pPredicate->Attribute.Value.Length;
#endif

    }


  }


  //
  // Init find operation
  //

#ifdef _DEBUG
  printf("About to call C_FindObjectsInit\n");
  printf("Session Handle = %x\n", pMsmSession->PkcsSessionHandle);
  printf("Attribute Count = %d\n", PkcsAttrCount);
#endif
  PkcsRc = C_FindObjectsInit(pMsmSession->PkcsSessionHandle, pPkcsTemplate, PkcsAttrCount);
  
  if  (PkcsRc != CKR_OK)
    return SetErrNull(PkcsRc);


  //
  // Find first matching object 
  //

  if ((PkcsRc = C_FindObjects(pMsmSession->PkcsSessionHandle,
                &hPkcsObject,
                1,
                &PkcsObjectCount)) != CKR_OK) {
    // Done with FIND template, free it!
    if (pPkcsTemplate != NULL)
      free(pPkcsTemplate);
    pPkcsTemplate = NULL;
    return SetErrNull(PkcsRc);
  }

  // Done with FIND template, free it!
  if (pPkcsTemplate != NULL)
    free(pPkcsTemplate);
  pPkcsTemplate = NULL;

  //
  // No match
  //

  if (PkcsObjectCount == 0)
  { 
#ifdef _DEBUG
    printf("No objects returned from C_FindObjects\n");
#endif
    *pCssmEndOfDataStore = CSSM_TRUE;
    return SetErrNull(CSSM_DL_NO_MORE_OBJECT);
  }


  //
  // Set up pCssmUniqueRecord
  //

  if ((pCssmUniqueRecord = CssmMemFuncs.calloc_func(CssmDLDBHandle.DLHandle, 
                            1, 
                            sizeof(CSSM_DB_UNIQUE_RECORD))) == NULL)
    return SetErrNull(CSSM_DL_MEMORY_ERROR);

  if ((pCssmUniqueRecord->RecordIdentifier.Data = CssmMemFuncs.calloc_func(
                            CssmDLDBHandle.DLHandle, 
                            1, 
                            sizeof(CK_OBJECT_HANDLE))) == NULL)
  {
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord);
    return SetErrNull(CSSM_DL_MEMORY_ERROR);
  }

  *((CK_OBJECT_HANDLE_PTR) pCssmUniqueRecord->RecordIdentifier.Data) = hPkcsObject;
  pCssmUniqueRecord->RecordIdentifier.Length = sizeof(CK_OBJECT_HANDLE);

  if (DataGetAttributes(CssmDLDBHandle, 
              pCssmUniqueRecord,
              CssmQueryFlags,
              pCssmAttributes,
              pCssmData) != CSSM_OK)
  {
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord->RecordIdentifier.Data);
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord);
    return NULL;
  }
  else
  {
    pMsmSession->CssmQueryFlags = CssmQueryFlags;
    return pCssmUniqueRecord;
  }
  
}



/*****************************************************************************
 * Function: DataGetNext - Find next record  
 *
 * Input:
 *  CssmDLDBHandle    - DL/DB handles 
 *  CssmResultsHandle - Result handle returned from DatagetFirst
 *   
 * Output:
 *  pCssmEndOfDataStore - End of data flag
 *  pCssmAttributes   - Record attributes
 *  pCssmData     - Record data, currently only keys are supported
 *   
 * Returns:
 *  CSSM_DB_UNIQUE_RECORD_PTR - Successful      
 *  NULL            - Failed
 *
 */

CSSM_DB_UNIQUE_RECORD_PTR CSSMAPI DataGetNext(
    CSSM_DL_DB_HANDLE CssmDLDBHandle,
    CSSM_HANDLE CssmResultsHandle,
    CSSM_BOOL *pCssmEndOfDataStore,
    CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pCssmAttributes, 
    CSSM_DATA_PTR pCssmData)
{

  MSMSESSION_PTR        pMsmSession = NULL;

  CSSM_DB_UNIQUE_RECORD_PTR pCssmUniqueRecord = NULL;

  CK_RV           PkcsRc;
  CK_ATTRIBUTE_PTR      pPkcsTemplate = NULL;
  CK_OBJECT_HANDLE      hPkcsObject;

#ifdef PKCS11_V20
  CK_ULONG          PkcsObjectCount;
#else
  CK_USHORT         PkcsObjectCount;
#endif



#ifdef _DEBUG
printf("Enter Data GetNext\n");
#endif

  //
  // Handle & Pointer Validation
  //

  if ((pMsmSession = FindMsmSession(CssmDLDBHandle.DLHandle)) == NULL)
    return SetErrNull(CSSM_DL_INVALID_DL_HANDLE);

  if (CssmDLDBHandle.DBHandle != pMsmSession->CssmHandleInfo.SubServiceID)
    return SetErrNull(CSSM_DL_INVALID_DB_HANDLE);

  if (CssmResultsHandle != pMsmSession->PkcsSessionHandle)
    return SetErrNull(CSSM_DL_INVALID_RESULTS_HANDLE);

  if (pCssmEndOfDataStore == NULL || pCssmAttributes == NULL || pCssmData == NULL)
    return SetErrNull(CSSM_DL_INVALID_PTR);



  //
  // Init return value
  //

  *pCssmEndOfDataStore = CSSM_FALSE;



  //
  // Find next matching object 
  //

  if ((PkcsRc = C_FindObjects(pMsmSession->PkcsSessionHandle,
                &hPkcsObject,
                1,
                &PkcsObjectCount)) != CKR_OK)
    return SetErrNull(PkcsRc);


  //
  // No match
  //

  if (PkcsObjectCount == 0)
  { 
    *pCssmEndOfDataStore = CSSM_TRUE;
    return SetErrNull(CSSM_DL_NO_MORE_OBJECT);
  }


  //
  // Set up pCssmUniqueRecord
  //

  if ((pCssmUniqueRecord = CssmMemFuncs.calloc_func(CssmDLDBHandle.DLHandle, 
                            1, 
                            sizeof(CSSM_DB_UNIQUE_RECORD))) == NULL)
    return SetErrNull(CSSM_DL_MEMORY_ERROR);


  if ((pCssmUniqueRecord->RecordIdentifier.Data = CssmMemFuncs.calloc_func(
                            CssmDLDBHandle.DLHandle, 
                            1, 
                            sizeof(CK_OBJECT_HANDLE))) == NULL)
  {
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord);
    return SetErrNull(CSSM_DL_MEMORY_ERROR);
  }

  *((CK_OBJECT_HANDLE_PTR) pCssmUniqueRecord->RecordIdentifier.Data) = hPkcsObject;
  pCssmUniqueRecord->RecordIdentifier.Length = sizeof(CK_OBJECT_HANDLE);


  if (DataGetAttributes(CssmDLDBHandle, 
              pCssmUniqueRecord,
              pMsmSession->CssmQueryFlags,
              pCssmAttributes,
              pCssmData) != CSSM_OK)
  {
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord->RecordIdentifier.Data);
    CssmMemFuncs.free_func(CssmDLDBHandle.DLHandle, pCssmUniqueRecord);
    return NULL;
  }
  else
  {
    return pCssmUniqueRecord;
  }
  
}


#ifdef PKCS11_V20

//
// DataAbortQuery
//

CSSM_RETURN CSSMAPI DataAbortQuery(
  CSSM_DL_DB_HANDLE CssmDLDBHandle,
    CSSM_HANDLE ResultsHandle)
{

  CK_RV           PkcsRc;

  MSMSESSION_PTR        pMsmSession;

#ifdef _DEBUG
printf("Enter DataAbortQuery\n");
#endif


  if ((pMsmSession = FindMsmSession(CssmDLDBHandle.DLHandle)) != NULL)
  {
    if ((PkcsRc = C_FindObjectsFinal(pMsmSession->PkcsSessionHandle)) != CKR_OK)
    { 
      return SetErr(PkcsRc);
    }
  }
  else
  {
    return SetErr(CSSM_DL_INVALID_DL_HANDLE);
  }

}

#endif

