/* ***************************************************************** *
 * 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_GUID CssmGuid;
extern CSSM_SPI_MEMORY_FUNCS CssmMemFuncs;



/*****************************************************************************
 * Function: SetupKeyHeader
 *
 * Input:
 *  BlobType      - BlobType of key
 *  Format        - Foemat of key
 *  AlgorithmId     - Algoritm ID of key 
 *  KeyClass      - Public/Private/Secret etc.
 *  KeySizeInBits   - Size of session key/modulus/prime in bits 
 *  KeyAttr       - Attribute flags 
 *  KeyUsage      - Key usage flags
 *  pStartDate      - Effective date of key
 *  pEndDate      - Expiration date of key
 *  WrapAlgorithmId   - Wrap algorithm id 
 *  WrapMode      - Wrap algorithm mode
 *   
 * Output:
 *  pKeyHeader      - Filled in key header
 *   
 * Returns:
 *  None        
 *
 */

void SetupKeyHeader(
  CSSM_KEYHEADER_PTR  pKeyHeader, 
  uint32        BlobType,     /* See BlobType #define's */
  uint32        Format,       /* Raw or Reference format */
  uint32        AlgorithmId,    /* Algoritm ID of key */
  uint32        KeyClass,     /* Public/Private/Secret etc. */
  uint32        KeySizeInBits,    /* Size of actual key/modulus/prime in bits */
  uint32        KeyAttr,      /* Attribute flags */
  uint32        KeyUsage,     /* Key use flags */
  CSSM_DATE*      pStartDate,     /* Effective date of key */
  CSSM_DATE*      pEndDate,     /* Expiration date of key */
  uint32        WrapAlgorithmId,  /* CSSM_ALGID_XXX */
  uint32        WrapMode)     /* CSSM_ALGMODE_XXX */
{

  if (pKeyHeader == NULL)
    return;

  memset(pKeyHeader, 0, sizeof(CSSM_KEYHEADER));
  pKeyHeader->HeaderVersion = CSSM_KEYHEADER_VERSION; 
  memcpy(&pKeyHeader->CspId, &CssmGuid, sizeof(CSSM_GUID));
  pKeyHeader->BlobType = BlobType;
  pKeyHeader->Format = Format;
  pKeyHeader->AlgorithmId = AlgorithmId;
  pKeyHeader->KeyClass = KeyClass;
  pKeyHeader->KeySizeInBits = KeySizeInBits;
  pKeyHeader->KeyAttr = KeyAttr;
  pKeyHeader->KeyUsage = KeyUsage;
  if (pStartDate != NULL)
  { 
    memcpy(&pKeyHeader->StartDate, pStartDate, sizeof(CSSM_DATE));
  }
  if (pEndDate != NULL)
  { 
    memcpy(&pKeyHeader->EndDate, pEndDate, sizeof(CSSM_DATE));
  }
  
  pKeyHeader->WrapAlgorithmId = WrapAlgorithmId;
  pKeyHeader->Reserved = 0;
  return;

}



/*****************************************************************************
 * Function: GenerateKey 
 * 
 * Generate symmetic or session key.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  CssmKeyUsage    - Key usage flag
 *  CssmKeyAttr     - Key attribute flag
 *  pCssmKeyLabel   - Key label
 *   
 * Output:
 *  pCssmKey      - Generated key if successful
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI GenerateKey(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  uint32 CssmKeyUsage,
    uint32 CssmKeyAttr,
  const CSSM_DATA_PTR pCssmKeyLabel,
  CSSM_KEY_PTR pCssmKey)
{

  MSMSESSION_PTR        pMsmSession;
#ifdef PKCS11_V20
  uint8           MsmInitVector[IVLEN];
#endif
//  CSSM_BOOL         bMsmKeyUsage = FALSE;
//  CSSM_BOOL         bMsmKeyAttr = FALSE;
  CSSM_BOOL         bMsmStartDate = FALSE;
  CSSM_BOOL         bMsmEndDate = FALSE;


  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyLengthAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmStartDateAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEndDateAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmSeedAttr;

  CSSM_BOOL         bSeedAllocated;
  CSSM_DATA         Seed;
  CSSM_DATA_PTR       pSeed;


#ifdef PKCS11_V20
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmPassPhraseAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmSaltAttr;
  CSSM_CRYPTO_DATA_PTR    pCssmPassPhrase;
  CSSM_DATA_PTR       pCssmPassPhraseData;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmVersionAttr;
#endif
  
  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsKey;


//
//  Common Key Data
//
  
// Common Object Attrs  
//  CK_OBJECT_CLASS       PkcsObjectClass;    // Required, supplied by C_GenerateKey
  CK_BBOOL          PkcsToken;        // FALSE
  CK_BBOOL          PkcsPrivate;      // FALSE
#ifdef PKCS11_V20
  CK_BBOOL          PkcsModifiable;     // TRUE
#endif
//  CK_CHAR_PTR         pPkcsObjectLabel;   // NULL

// Common Key Attrs
//  CK_KEY_TYPE         PkcsKeyType;      // Required, supplied by C_GenerateKey
//  CK_CHAR_PTR         pPkcsId;        // NULL
//  CK_DATE           PkcsStartDate;      // Empty
//  CK_DATE           PkcsEndDate;      // Empty
  CK_BBOOL          PkcsDerive;       // FALSE
//  CK_BBOOL          PkcsLocal;        // Not setable

//
//  Secret Key Data
//

  CK_BBOOL          PkcsSensitive;      // FALSE
  CK_BBOOL          PkcsEncrypt;      // Token default
  CK_BBOOL          PkcsDecrypt;      // Token default
  CK_BBOOL          PkcsSign;       // Token default
  CK_BBOOL          PkcsVerify;       // Token default
  CK_BBOOL          PkcsWrap;       // Token default
  CK_BBOOL          PkcsUnwrap;       // Token default
#ifdef PKCS11_V20
  CK_BBOOL          PkcsExtractable;    // Token default
#endif
//  CK_BBOOL          PkcsAlwaysSensitive;  // Not setable
//  CK_BBOOL          PkcsNeverExtractable; // Not setable
//  CK_CHAR_PTR         pPkcsValue;       // Not setable
#ifdef PKCS11_V20
  CK_ULONG          PkcsValueLen;     // Required when variable
#else
  CK_USHORT         PkcsValueLen;     // Required when variable
#endif
  CK_ATTRIBUTE        PkcsTemplate[PKCS_TOTAL_SECRET_ATTRS];

#ifdef PKCS11_V20
  int             ii = 0;
#else
  CK_USHORT         ii = 0;
#endif

#ifdef PKCS11_V20
  CK_PBE_PARAMS       PkcsPbeParams;
  CK_VERSION          PkcsSslVersion;
#endif


  uint8           KeyID[KEYIDLEN];

  

  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if (pCssmContext->ContextType != CSSM_ALGCLASS_KEYGEN)
    return SetErr(CSSM_CSP_INVALID_CONTEXT_HANDLE);

  if (pCssmKey == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  if (((pCssmKey->KeyData.Length == 0) && (pCssmKey->KeyData.Data != NULL)) ||
    ((pCssmKey->KeyData.Length != 0) && (pCssmKey->KeyData.Data == NULL)))
    return SetErr(CSSM_CSP_ERR_KEYBUF_LENGTH);
  
  // Get Label
  if (pCssmKeyLabel != NULL && pCssmKeyLabel->Data != NULL)
  {
    PkcsTemplate[ii].type = CKA_LABEL;
    PkcsTemplate[ii].pValue = pCssmKeyLabel->Data;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = pCssmKeyLabel->Length;
#else
    PkcsTemplate[ii++].usValueLen = (CK_USHORT) pCssmKeyLabel->Length;
#endif
  }


  // Get StartDate
  pCssmStartDateAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_START_DATE);
  if (pCssmStartDateAttr != NULL)
  {
    PkcsTemplate[ii].type = CKA_START_DATE;
    PkcsTemplate[ii].pValue = pCssmStartDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif
    bMsmStartDate = TRUE;
  } 


  // Get EndDate
  pCssmEndDateAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_END_DATE);
  if (pCssmEndDateAttr != NULL)
  {
    PkcsTemplate[ii].type = CKA_END_DATE;
    PkcsTemplate[ii].pValue = pCssmEndDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif
    bMsmEndDate = TRUE;
  } 


  // Parse KeyUsage
  if (CssmKeyUsage != 0)
  {
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_DERIVE))
      PkcsDerive = TRUE;
    else
      PkcsDerive = FALSE;
    
    PkcsTemplate[ii].type = CKA_DERIVE;
    PkcsTemplate[ii].pValue = &PkcsDerive;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsDerive);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsDerive);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_ENCRYPT))
      PkcsEncrypt = TRUE;
    else
      PkcsEncrypt = FALSE;
    
    PkcsTemplate[ii].type = CKA_ENCRYPT;
    PkcsTemplate[ii].pValue = &PkcsEncrypt;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsEncrypt);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsEncrypt);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_DECRYPT))
      PkcsDecrypt = TRUE;
    else
      PkcsDecrypt = FALSE;
    
    PkcsTemplate[ii].type = CKA_DECRYPT;
    PkcsTemplate[ii].pValue = &PkcsDecrypt;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsDecrypt);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsDecrypt);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_SIGN))
      PkcsSign = TRUE;
    else
      PkcsSign = FALSE;
    
    PkcsTemplate[ii].type = CKA_SIGN;
    PkcsTemplate[ii].pValue = &PkcsSign;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSign);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsSign);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_VERIFY))
      PkcsVerify = TRUE;
    else
      PkcsVerify = FALSE;
    
    PkcsTemplate[ii].type = CKA_VERIFY;
    PkcsTemplate[ii].pValue = &PkcsVerify;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsVerify);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsVerify);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_WRAP))
      PkcsWrap = TRUE;
    else
      PkcsWrap = FALSE;
    
    PkcsTemplate[ii].type = CKA_WRAP;
    PkcsTemplate[ii].pValue = &PkcsWrap;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsWrap);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsWrap);
#endif
    if ((CssmKeyUsage & CSSM_KEYUSE_ANY) || (CssmKeyUsage & CSSM_KEYUSE_UNWRAP))
      PkcsUnwrap = TRUE;
    else
      PkcsUnwrap = FALSE;
    
    PkcsTemplate[ii].type = CKA_UNWRAP;
    PkcsTemplate[ii].pValue = &PkcsUnwrap;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsUnwrap);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsUnwrap);
#endif  

  }   


  // Parse KeyAttr
  if (CssmKeyAttr != 0)
  {
    if (CssmKeyAttr & CSSM_KEYATTR_PERMANENT)
      PkcsToken = TRUE;
    else
      PkcsToken = FALSE;
    
    PkcsTemplate[ii].type = CKA_TOKEN;
    PkcsTemplate[ii].pValue = &PkcsToken;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsToken);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsToken);
#endif
    if (CssmKeyAttr & CSSM_KEYATTR_PRIVATE)
      PkcsPrivate = TRUE;
    else
      PkcsPrivate = FALSE;
    
    PkcsTemplate[ii].type = CKA_PRIVATE;
    PkcsTemplate[ii].pValue = &PkcsPrivate;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsPrivate);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsPrivate);
#endif

#ifdef PKCS11_V20
    if (CssmKeyAttr & CSSM_KEYATTR_MODIFIABLE)
      PkcsModifiable = TRUE;
    else
      PkcsModifiable = FALSE;

    PkcsTemplate[ii].type = CKA_MODIFIABLE;
    PkcsTemplate[ii].pValue = &PkcsModifiable;
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsModifiable);
#endif
    if (CssmKeyAttr & CSSM_KEYATTR_SENSITIVE)
      PkcsSensitive = TRUE;
    else
      PkcsSensitive = FALSE;
    
    PkcsTemplate[ii].type = CKA_SENSITIVE;
    PkcsTemplate[ii].pValue = &PkcsSensitive;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSensitive);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsSensitive);
#endif
  
#ifdef PKCS11_V20
    PkcsTemplate[ii].type = CKA_EXTRACTABLE;
    PkcsTemplate[ii].pValue = &PkcsExtractable;
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsExtractable);

    if (CssmKeyAttr & CSSM_KEYATTR_EXTRACTABLE)
      PkcsExtractable = TRUE;
    else
      PkcsExtractable = FALSE;
#endif
    
  }   


  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_RC2:
      PkcsMechanism.mechanism = CKM_RC2_KEY_GEN;
      break;

    case CSSM_ALGID_RC4:
      PkcsMechanism.mechanism = CKM_RC4_KEY_GEN;
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_RC5:
      PkcsMechanism.mechanism = CKM_RC5_KEY_GEN;
      break;
#endif

    case CSSM_ALGID_DES:
      PkcsMechanism.mechanism = CKM_DES_KEY_GEN;
      break;

    case CSSM_ALGID_3DES_2KEY:
      PkcsMechanism.mechanism = CKM_DES2_KEY_GEN;
      break;

    case CSSM_ALGID_3DES_3KEY:
      PkcsMechanism.mechanism = CKM_DES3_KEY_GEN;
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_CAST:
      PkcsMechanism.mechanism = CKM_CAST_KEY_GEN;
      break;

    case CSSM_ALGID_CAST3:
      PkcsMechanism.mechanism = CKM_CAST3_KEY_GEN;
      break;

    case CSSM_ALGID_CAST5:
      PkcsMechanism.mechanism = CKM_CAST5_KEY_GEN;
      break;

    case CSSM_ALGID_IDEA:
      PkcsMechanism.mechanism = CKM_IDEA_KEY_GEN;
      break;

    case CSSM_ALGID_CDMF:
      PkcsMechanism.mechanism = CKM_CDMF_KEY_GEN;
      break;

    case CSSM_ALGID_SKIPJACK:
      PkcsMechanism.mechanism = CKM_SKIPJACK_KEY_GEN;
      break;

    case CSSM_ALGID_BATON:
      PkcsMechanism.mechanism = CKM_BATON_KEY_GEN;
      break;

    case CSSM_ALGID_JUNIPER:
      PkcsMechanism.mechanism = CKM_JUNIPER_KEY_GEN;
      break;

    case CSSM_ALGID_MD2_PBE:
    case CSSM_ALGID_MD5_PBE:

      if (pCssmContext->AlgorithmType == CSSM_ALGID_MD2_PBE)
        PkcsMechanism.mechanism = CKM_PBE_MD2_DES_CBC;
      else
        PkcsMechanism.mechanism = CKM_PBE_MD5_DES_CBC;

      PkcsPbeParams.pInitVector = MsmInitVector;

      pCssmPassPhraseAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_PASSPHRASE);
      if (pCssmPassPhraseAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PASSWORD);

      pCssmPassPhrase = pCssmPassPhraseAttr->Attribute.Crypto;
      if (pCssmPassPhrase->Callback)
      {
        pCssmPassPhraseData = pCssmPassPhrase->Callback(&CssmMemFuncs, pCssmPassPhrase->CallbackID);
        if (pCssmPassPhraseData != NULL)
        {
          PkcsPbeParams.pPassword = pCssmPassPhraseData->Data;
          PkcsPbeParams.ulPasswordLen = pCssmPassPhraseData->Length;
        }
        else
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
      }
      else
      { 
        if (pCssmPassPhrase->Param != NULL)
        {
          PkcsPbeParams.pPassword = pCssmPassPhrase->Param->Data;
          PkcsPbeParams.ulPasswordLen = pCssmPassPhrase->Param->Length;
        }
        else
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
      }

      pCssmSaltAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_SALT);
      if (pCssmSaltAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PASSWORD);

      PkcsPbeParams.pSalt = pCssmSaltAttr->Attribute.Data->Data;
      PkcsPbeParams.ulSaltLen = pCssmSaltAttr->Attribute.Data->Length;

      pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
      if (pCssmRoundsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_ROUNDS);
      
      PkcsPbeParams.ulIteration = pCssmRoundsAttr->Attribute.Uint32;

      PkcsMechanism.pParameter = &PkcsPbeParams;
      PkcsMechanism.ulParameterLen = sizeof(PkcsPbeParams);

      break;
    
    case CSSM_ALGID_SSL3PreMasterGen:
      PkcsMechanism.mechanism = CKM_SSL3_PRE_MASTER_KEY_GEN;
      pCssmVersionAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_VERSION);
      if (pCssmVersionAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PARAM);
        //return SetErr(CSSM_CSP_PARAM_NO_VERSION);
      PkcsSslVersion.major = pCssmVersionAttr->Attribute.Version->Major;
      PkcsSslVersion.minor = pCssmVersionAttr->Attribute.Version->Minor;
      PkcsMechanism.pParameter = &PkcsSslVersion;
      PkcsMechanism.ulParameterLen = sizeof(PkcsSslVersion);

      break;
#endif

    default:
      return SetErr(CSSM_CSP_INVALID_ALGORITHM);
      break;
  
  }


  // Get KeySizeInBits and convert to bytes
  pCssmKeyLengthAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY_LENGTH);
  if (pCssmKeyLengthAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY_LENGTH);

  PkcsValueLen = pCssmKeyLengthAttr->Attribute.Uint32 / BITSPERBYTE;
  if ((pCssmKeyLengthAttr->Attribute.Uint32 % BITSPERBYTE) != 0)
    PkcsValueLen++;

  PkcsTemplate[ii].type = CKA_VALUE_LEN;
  PkcsTemplate[ii].pValue = &PkcsValueLen;
#ifdef PKCS11_V20
  PkcsTemplate[ii++].ulValueLen = sizeof(PkcsValueLen); 
#else
  PkcsTemplate[ii++].usValueLen = sizeof(PkcsValueLen); 
#endif



  //
  // Generate KeyID Attribute
  //


  bSeedAllocated = CSSM_FALSE;
  pCssmSeedAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_SEED);
  if (pCssmSeedAttr == NULL)
  {
    if ((Seed.Data = (uint8*) CssmMemFuncs.malloc_func(CssmCSPHandle, DEFAULTSEEDLEN)) == NULL)
    { 
      return SetErr(CSSM_CALLOC_FAILED);
    }

    Seed.Length = DEFAULTSEEDLEN;
    if (GetSeed(&Seed) == CSSM_FAIL)
      return CSSM_FAIL;

    bSeedAllocated = CSSM_TRUE;
  }
  else
  {
    if (pCssmSeedAttr->Attribute.Crypto != NULL)
    {
      if (pCssmSeedAttr->Attribute.Crypto->Callback == NULL)
      {
        if (pCssmSeedAttr->Attribute.Crypto->Param != NULL &&
          pCssmSeedAttr->Attribute.Crypto->Param->Data != NULL &&
          pCssmSeedAttr->Attribute.Crypto->Param->Length != 0)
        {
          Seed.Data   = pCssmSeedAttr->Attribute.Crypto->Param->Data;
          Seed.Length = pCssmSeedAttr->Attribute.Crypto->Param->Length;
        }
        else
        {
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
        }
      }
      else
      {
        pSeed = pCssmSeedAttr->Attribute.Crypto->Callback(
                NULL, 
                pCssmSeedAttr->Attribute.Crypto->CallbackID);
        if (pSeed->Data == NULL || pSeed->Length == 0)
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
        Seed.Data = pSeed->Data;
        Seed.Length = pSeed->Length;
      }
    }
    else
    {
      return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
    }
  }


#ifdef PKCS11_V20
  if ((PkcsStatus = C_SeedRandom(pMsmSession->PkcsSessionHandle,  
                   Seed.Data, 
                   Seed.Length)) != CKR_OK)
#else
  if ((PkcsStatus = C_SeedRandom(pMsmSession->PkcsSessionHandle,  
                   Seed.Data, 
                   (CK_USHORT)Seed.Length)) != CKR_OK)
#endif
    return SetErr(PkcsStatus);

  if (bSeedAllocated == CSSM_TRUE)
    CssmMemFuncs.free_func(CssmCSPHandle, Seed.Data); 

  
  if ((PkcsStatus = C_GenerateRandom(pMsmSession->PkcsSessionHandle,  
                     KeyID, 
                     sizeof(KeyID))) != CKR_OK)
    return SetErr(PkcsStatus);


  PkcsTemplate[ii].type = CKA_ID;
  PkcsTemplate[ii].pValue = KeyID;
#ifdef PKCS11_V20
  PkcsTemplate[ii++].ulValueLen = sizeof(KeyID);
#else
  PkcsTemplate[ii++].usValueLen = sizeof(KeyID);
#endif


  if ((PkcsStatus = C_GenerateKey(pMsmSession->PkcsSessionHandle,
                  &PkcsMechanism,
                  PkcsTemplate,
                  ii,
                  &hPkcsKey)) != CKR_OK)
    return SetErr(PkcsStatus);


  if (pCssmKey->KeyData.Data == NULL)
  {
    if ((pCssmKey->KeyData.Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                 1,
                                 sizeof(hPkcsKey))) == NULL)
    { 
      return SetErr(CSSM_CALLOC_FAILED);
    }
  }
  else if (pCssmKey->KeyData.Length < sizeof(hPkcsKey))
    return SetErr(CSSM_CSP_ERR_KEYBUF_LENGTH);

  pCssmKey->KeyData.Length = sizeof(hPkcsKey);

  *((CK_OBJECT_HANDLE*)pCssmKey->KeyData.Data) = hPkcsKey;

  SetupKeyHeader(
    &pCssmKey->KeyHeader, 
    CSSM_KEYBLOB_REFERENCE,                   /* See BlobType #define's */
    CSSM_KEYBLOB_REF_FORMAT_INTEGER,              /* Raw or Reference format */
    pCssmContext->AlgorithmType,                /* Algoritm ID of key */
    CSSM_KEYCLASS_SESSION_KEY,                  /* Public/Private/Secret etc. */
    pCssmKeyLengthAttr->Attribute.Uint32,           /* Size of actual key in bits */
    CssmKeyAttr,                        /* Attribute flags */
    CssmKeyUsage,                       /* Key use flags */
    bMsmStartDate ? pCssmStartDateAttr->Attribute.Date : NULL,  /* Effective date of key */
    bMsmEndDate ?  pCssmEndDateAttr->Attribute.Date : NULL,   /* Expiration date of key */
    CSSM_ALGID_NONE,                      /* Wrap Algo */
    CSSM_ALGMODE_NONE);                     /* Wrap Algo */

  
  return CSSM_OK;
} 



/*****************************************************************************
 * Function: GenerateKeyPair 
 * 
 * Generate public/private key pair.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  CssmPublicKeyUsage  - Public key usage flag
 *  CssmPublicKeyAttr - Public key attribute flag
 *  pCssmPublicKeyLabel - Public key label
 *  CssmPrivateKeyUsage - Private key usage flag
 *  CssmPrivateKeyAttr  - Private key attribute flag
 *  pCssmPrivateKeyLabel- Private key label
 *   
 * Output:
 *  pCssmPublicKey    - Generated public key if successful
 *  pCssmPrivateKey   - Generated private key if successful
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI GenerateKeyPair(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  uint32 CssmPublicKeyUsage,
    uint32 CssmPublicKeyAttr,
  const CSSM_DATA_PTR pCssmPublicKeyLabel,
  CSSM_KEY_PTR pCssmPublicKey,
  uint32 CssmPrivateKeyUsage,
    uint32 CssmPrivateKeyAttr,
  const CSSM_DATA_PTR pCssmPrivateKeyLabel,
  CSSM_KEY_PTR pCssmPrivateKey)
{

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         bMsmStartDate = FALSE;
  CSSM_BOOL         bMsmEndDate = FALSE;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyLengthAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmStartDateAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEndDateAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmAlgoParamsAttr;

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmSeedAttr;

  CSSM_BOOL         bSeedAllocated;
  CSSM_DATA         Seed;
  CSSM_DATA_PTR       pSeed;

  uint8           KeyID[KEYIDLEN];



  
  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsPublicKey;
  CK_OBJECT_HANDLE      hPkcsPrivateKey;

//
//  Common Key Data
//

// Common Object Attrs  
//  CK_OBJECT_CLASS       PkcsObjectClass;    // Required, supplied by C_GenerateKeyPair
  CK_BBOOL          PkcsPublicToken;    // FALSE
  CK_BBOOL          PkcsPrivateToken;   // FALSE
  CK_BBOOL          PkcsPublicPrivate;    // FALSE
  CK_BBOOL          PkcsPrivatePrivate;   // FALSE

#ifdef PKCS11_V20
  CK_BBOOL          PkcsModifiable;     // TRUE
  CK_BBOOL          PkcsPublicModifiable;     // TRUE
  CK_BBOOL          PkcsPrivateModifiable;      // TRUE
#endif
//  CK_CHAR_PTR         pPkcsObjectLabel;   // NULL, not used by CDSA

// Common Key Attrs
//  CK_KEY_TYPE         PkcsKeyType;      // Required, supplied by C_GenerateKeyPair
//  CK_CHAR_PTR         pPkcsId;        // NULL
//  CK_DATE           PkcsStartDate;      // Empty
//  CK_DATE           PkcsEndDate;      // Empty
  CK_BBOOL          PkcsPublicDerive;   // FALSE
  CK_BBOOL          PkcsPrivateDerive;    // FALSE

//  CK_BBOOL          PkcsLocal;        // Not setable


//
//  Public Key Data
//

// Common Public Key Attrs
//  CK_CHAR_PTR         pPkcsPublicSubject;     // Empty, not used by CDSA
  CK_BBOOL          PkcsPublicEncrypt;      // Token default
  CK_BBOOL          PkcsPublicVerify;     // Token default
//  CK_BBOOL          PkcsPublicVerifyRecover;  // Token default
  CK_BBOOL          PkcsPublicWrap;       // Token default

// RSA Specific Attrs
//  CK_BYTE_PTR         pPkcsPublicModulus;     // Supplied by C_GenerateKeyPair
#ifdef PKCS11_V20
  CK_ULONG          PkcsPublicModulusBits;    // Required
#else
  CK_USHORT         PkcsPublicModulusBits;    // Required
#endif
//  CK_BYTE           PkcsPublicPublicExponent = 3; // Required


// DSA, ECDSA, DH, KEA, MAYFLY Specific Attrs
//  CK_BYTE_PTR         pPkcsPublicPrime;     // Required
//  CK_BYTE_PTR         pPkcsPublicSubPrime;    // Required except by DH
//  CK_BYTE_PTR         pPkcsPublicBase;      // Required
//  CK_BYTE_PTR         pPkcsPublicValue;     // Supplied by C_GenerateKeyPair

  CK_ATTRIBUTE        PkcsPublicTemplate[PKCS_TOTAL_PUBLIC_ATTRS];


//
//  Private Key Data
//

// Common Private Key Attrs 
//  CK_CHAR_PTR         pPkcsPrivateSubject;    // Empty, not used by CDSA
  CK_BBOOL          PkcsPrivateSensitive;   // FALSE
  CK_BBOOL          PkcsPrivateDecrypt;     // Token default
  CK_BBOOL          PkcsPrivateSign;      // Token default
//  CK_BBOOL          PkcsPrivateSignRecover;   // Token default
  CK_BBOOL          PkcsPrivateUnwrap;      // Token default
#ifdef PKCS11_V20
  CK_BBOOL          PkcsPrivateExtractable;   // Token default
#endif
//  CK_BBOOL          PkcsPrivateAlwaysSensitive; // Not setable
//  CK_BBOOL          PkcsPrivateNeverExtractable;// Not setable

// RSA Specific Attrs
//  CK_BYTE_PTR         pPkcsPrivateModulus;    // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivatePublicExponent; // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivatePrivateExponent;// Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivatePrime_1;    // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivatePrime_2;    // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateExponent_1;   // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateExponent_2;   // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateCoefficient;  // Supplied by C_GenerateKeyPair

// DSA, ECDSA, DH, KEA, MAYFLY Specific Attrs
//  CK_BYTE_PTR         pPkcsPrivatePrime;      // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateSubPrime;   // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateBase;     // Supplied by C_GenerateKeyPair
//  CK_BYTE_PTR         pPkcsPrivateValue;      // Supplied by C_GenerateKeyPair
//  CK_ULONG          PkcsPrivateValueBits    // Supplied by C_GenerateKeyPair

  CK_ATTRIBUTE        PkcsPrivateTemplate[PKCS_TOTAL_PRIVATE_ATTRS];


#ifdef PKCS11_V20
  int             ii = 0;
  int             jj = 0; 
#else
  CK_USHORT         ii = 0;
  CK_USHORT         jj = 0; 
#endif

  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if (pCssmContext->ContextType != CSSM_ALGCLASS_KEYGEN)
    return SetErr(CSSM_CSP_INVALID_CONTEXT_HANDLE);

  if (pCssmPublicKey == NULL || pCssmPrivateKey == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  if (((pCssmPublicKey->KeyData.Length == 0) && (pCssmPublicKey->KeyData.Data != NULL)) ||
    ((pCssmPublicKey->KeyData.Length != 0) && (pCssmPublicKey->KeyData.Data == NULL)) ||
    ((pCssmPrivateKey->KeyData.Length == 0) && (pCssmPrivateKey->KeyData.Data != NULL)) ||
    ((pCssmPrivateKey->KeyData.Length != 0) && (pCssmPrivateKey->KeyData.Data == NULL)))
    return SetErr(CSSM_CSP_ERR_KEYBUF_LENGTH);
  
  //
  // CKA_LABEL
  //

  if (pCssmPublicKeyLabel != NULL && pCssmPublicKeyLabel->Data != NULL)
  {
    PkcsPublicTemplate[ii].type = CKA_LABEL;
    PkcsPublicTemplate[ii].pValue = pCssmPublicKeyLabel->Data;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = pCssmPublicKeyLabel->Length;
#else
    PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT) pCssmPublicKeyLabel->Length;
#endif
  }

  if (pCssmPrivateKeyLabel != NULL && pCssmPrivateKeyLabel->Data != NULL)
  {
    PkcsPrivateTemplate[jj].type = CKA_LABEL;
    PkcsPrivateTemplate[jj].pValue = pCssmPrivateKeyLabel->Data;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = pCssmPrivateKeyLabel->Length;
#else
    PkcsPrivateTemplate[jj++].usValueLen = (CK_USHORT) pCssmPrivateKeyLabel->Length;
#endif
  } 


  // Get StartDate
  pCssmStartDateAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_START_DATE);
  if (pCssmStartDateAttr != NULL)
  {
    PkcsPublicTemplate[ii].type = CKA_START_DATE;
    PkcsPublicTemplate[ii].pValue = pCssmStartDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif
    PkcsPrivateTemplate[jj].type = CKA_START_DATE;
    PkcsPrivateTemplate[jj].pValue = pCssmStartDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(CSSM_DATE);
#endif
    bMsmStartDate = TRUE;
  } 


  // Get EndDate
  pCssmEndDateAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_END_DATE);
  if (pCssmEndDateAttr != NULL)
  {
    PkcsPublicTemplate[ii].type = CKA_END_DATE;
    PkcsPublicTemplate[ii].pValue = pCssmEndDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif
    PkcsPrivateTemplate[jj].type = CKA_END_DATE;
    PkcsPrivateTemplate[jj].pValue = pCssmEndDateAttr->Attribute.Date;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(CSSM_DATE);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(CSSM_DATE);
#endif
    bMsmEndDate = TRUE;
  } 


  // Parse KeyUsage
  if (CssmPublicKeyUsage != 0)
  {

    //
    // CKA_DERIVE
    //

    if ((CssmPublicKeyUsage & CSSM_KEYUSE_ANY) || (CssmPublicKeyUsage & CSSM_KEYUSE_DERIVE))
      PkcsPublicDerive = TRUE;
    else
      PkcsPublicDerive = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_DERIVE;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicDerive;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicDerive);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicDerive);
#endif


    //
    // CKA_ENCRYPT
    //

    if ((CssmPublicKeyUsage & CSSM_KEYUSE_ANY) || (CssmPublicKeyUsage & CSSM_KEYUSE_ENCRYPT))
      PkcsPublicEncrypt = TRUE;
    else
      PkcsPublicEncrypt = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_ENCRYPT;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicEncrypt;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicEncrypt);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicEncrypt);
#endif


    //
    // CKA_VERIFY
    //

    if ((CssmPublicKeyUsage & CSSM_KEYUSE_ANY) || (CssmPublicKeyUsage & CSSM_KEYUSE_VERIFY))
      PkcsPublicVerify = TRUE;
    else
      PkcsPublicVerify = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_VERIFY;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicVerify;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicVerify);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicVerify);
#endif

    //
    // CKA_WRAP
    //

    if ((CssmPublicKeyUsage & CSSM_KEYUSE_ANY) || (CssmPublicKeyUsage & CSSM_KEYUSE_WRAP))
      PkcsPublicWrap = TRUE;
    else
      PkcsPublicWrap = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_WRAP;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicWrap;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicWrap);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicWrap);
#endif

  }   


  if (CssmPrivateKeyUsage != 0)
  {

    //
    // CKA_DERIVE
    //

    if ((CssmPrivateKeyUsage & CSSM_KEYUSE_ANY) || (CssmPrivateKeyUsage & CSSM_KEYUSE_DERIVE))
      PkcsPrivateDerive = TRUE;
    else
      PkcsPrivateDerive = FALSE;

    PkcsPrivateTemplate[jj].type = CKA_DERIVE;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateDerive;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateDerive);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateDerive);
#endif


    //
    // CKA_DECRYPT
    //

    if ((CssmPrivateKeyUsage & CSSM_KEYUSE_ANY) || (CssmPrivateKeyUsage & CSSM_KEYUSE_DECRYPT))
      PkcsPrivateDecrypt = TRUE;
    else
      PkcsPrivateDecrypt = FALSE;
    
    PkcsPrivateTemplate[jj].type = CKA_DECRYPT;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateDecrypt;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateDecrypt);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateDecrypt);



    //
    // CKA_SIGN
    //

    if ((CssmPrivateKeyUsage & CSSM_KEYUSE_ANY) || (CssmPrivateKeyUsage & CSSM_KEYUSE_SIGN))
      PkcsPrivateSign = TRUE;
    else
      PkcsPrivateSign = FALSE;
    
    PkcsPrivateTemplate[jj].type = CKA_SIGN;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateSign;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateSign);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateSign);
#endif



    //
    // CKA_UNWRAP
    //

    if ((CssmPrivateKeyUsage & CSSM_KEYUSE_ANY) || (CssmPrivateKeyUsage & CSSM_KEYUSE_UNWRAP))
      PkcsPrivateUnwrap = TRUE;
    else
      PkcsPrivateUnwrap = FALSE;
    
    PkcsPrivateTemplate[jj].type = CKA_UNWRAP;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateUnwrap;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateUnwrap);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateUnwrap);
#endif

#endif    

  }   


  // Parse KeyAttr
  if (CssmPublicKeyAttr != 0)
  {
    //
    // CKA_TOKEN
    //

    if (CssmPublicKeyAttr & CSSM_KEYATTR_PERMANENT)
      PkcsPublicToken = TRUE;
    else
      PkcsPublicToken = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_TOKEN;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicToken;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicToken);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicToken);
#endif


    //
    // CKA_PRIVATE
    //

    if (CssmPublicKeyAttr & CSSM_KEYATTR_PRIVATE)
      PkcsPublicPrivate = TRUE;
    else
      PkcsPublicPrivate = FALSE;
  
    PkcsPublicTemplate[ii].type = CKA_PRIVATE;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicPrivate;
#ifdef PKCS11_V20
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicPrivate);
#else
    PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicPrivate);
#endif


#ifdef PKCS11_V20

    //
    // CKA_MODIFIABLE
    //

    if (CssmPublicKeyAttr & CSSM_KEYATTR_MODIFIABLE)
      PkcsPublicModifiable = TRUE;
    else
      PkcsPublicModifiable = FALSE;
    
    PkcsPublicTemplate[ii].type = CKA_MODIFIABLE;
    PkcsPublicTemplate[ii].pValue = &PkcsPublicModifiable;
    PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicModifiable);

#endif

  }   


  // Parse KeyAttr
  if (CssmPrivateKeyAttr != 0)
  {
    //
    // CKA_TOKEN
    //

    if (CssmPrivateKeyAttr & CSSM_KEYATTR_PERMANENT)
      PkcsPrivateToken = TRUE;
    else
      PkcsPrivateToken = FALSE;

    PkcsPrivateTemplate[jj].type = CKA_TOKEN;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateToken;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateToken);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateToken);
#endif


    //
    // CKA_PRIVATE
    //

    if (CssmPrivateKeyAttr & CSSM_KEYATTR_PRIVATE)
      PkcsPrivatePrivate = TRUE;
    else
      PkcsPrivatePrivate = FALSE;
  
    PkcsPrivateTemplate[jj].type = CKA_PRIVATE;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivatePrivate;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivatePrivate);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivatePrivate);
#endif


#ifdef PKCS11_V20

    //
    // CKA_MODIFIABLE
    //

    if (CssmPrivateKeyAttr & CSSM_KEYATTR_MODIFIABLE)
      PkcsPrivateModifiable = TRUE;
    else
      PkcsPrivateModifiable = FALSE;
    
    PkcsPrivateTemplate[jj].type = CKA_MODIFIABLE;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateModifiable;
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateModifiable);
#endif

    //
    // CKA_SENSITIVE
    //

    if (CssmPrivateKeyAttr & CSSM_KEYATTR_SENSITIVE)
      PkcsPrivateSensitive = TRUE;
    else
      PkcsPrivateSensitive = FALSE;
    
    PkcsPrivateTemplate[jj].type = CKA_SENSITIVE;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateSensitive;
#ifdef PKCS11_V20
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateSensitive);
#else
    PkcsPrivateTemplate[jj++].usValueLen = sizeof(PkcsPrivateSensitive);
#endif


#ifdef PKCS11_V20

    //
    // CKA_EXTRACTABLE
    //

    PkcsPrivateTemplate[jj].type = CKA_EXTRACTABLE;
    PkcsPrivateTemplate[jj].pValue = &PkcsPrivateExtractable;
    PkcsPrivateTemplate[jj++].ulValueLen = sizeof(PkcsPrivateExtractable);
    if (CssmPrivateKeyAttr & CSSM_KEYATTR_EXTRACTABLE)
      PkcsPrivateExtractable = TRUE;
    else
      PkcsPrivateExtractable = FALSE;
#endif

  }   



  pCssmKeyLengthAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY_LENGTH);
  if (pCssmKeyLengthAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY_LENGTH);


  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_RSA_PKCS:
      PkcsMechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;

      //
      // CKA_MODULUS_BITS
      //

      PkcsPublicModulusBits = pCssmKeyLengthAttr->Attribute.Uint32;
      PkcsPublicTemplate[ii].type = CKA_MODULUS_BITS;
      PkcsPublicTemplate[ii].pValue = &PkcsPublicModulusBits;
#ifdef PKCS11_V20
      PkcsPublicTemplate[ii++].ulValueLen = sizeof(PkcsPublicModulusBits);
#else
      PkcsPublicTemplate[ii++].usValueLen = sizeof(PkcsPublicModulusBits);
#endif

      //
      // CKA_PUBLIC_EXPONENT
      //

      PkcsPublicTemplate[ii].type = CKA_PUBLIC_EXPONENT;

      pCssmAlgoParamsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ALG_PARAMS);
      if (pCssmAlgoParamsAttr != NULL && pCssmAlgoParamsAttr->Attribute.Data->Data != NULL)
      {
        PkcsPublicTemplate[ii].pValue = pCssmAlgoParamsAttr->Attribute.Data->Data;
#ifdef PKCS11_V20
        PkcsPublicTemplate[ii++].ulValueLen = pCssmAlgoParamsAttr->Attribute.Data->Length;
#else
        PkcsPublicTemplate[ii++].usValueLen = pCssmAlgoParamsAttr->Attribute.Data->Length;
#endif
      } 
      else
      {
        return SetErr(CSSM_CSP_PARAM_NO_ALG_PARAMS);
      }

      break;

    case CSSM_ALGID_DH:
      PkcsMechanism.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN;

      pCssmAlgoParamsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ALG_PARAMS);
      if (pCssmAlgoParamsAttr != NULL && pCssmAlgoParamsAttr->Attribute.Data->Data != NULL)
      {
        CSSM_DH_PUBLIC_PTR pCssmDhPublic = (CSSM_DH_PUBLIC_PTR) pCssmAlgoParamsAttr->Attribute.Data->Data;
        
        if (pCssmDhPublic->prime.Data != NULL && pCssmDhPublic->prime.Length != 0)
        {
          PkcsPublicTemplate[ii].type = CKA_PRIME;
          PkcsPublicTemplate[ii].pValue = pCssmDhPublic->prime.Data;
#ifdef PKCS11_V20
          PkcsPublicTemplate[ii++].ulValueLen = pCssmDhPublic->prime.Length;
#else
          PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT)pCssmDhPublic->prime.Length;
#endif
        }
        else
          return SetErr(CSSM_CSP_PARAM_NO_PRIME);

        if (pCssmDhPublic->base.Data != NULL && pCssmDhPublic->base.Length != 0)
        {
      
          PkcsPublicTemplate[ii].pValue = pCssmDhPublic->base.Data;
#ifdef PKCS11_V20
          PkcsPublicTemplate[ii++].ulValueLen = pCssmDhPublic->base.Length;
#else
          PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT) pCssmDhPublic->base.Length;
#endif
        }
        else
          return SetErr(CSSM_CSP_PARAM_NO_BASE);
      }

      break;

    case CSSM_ALGID_DSA:
#ifdef PKCS11_V20
    case CSSM_ALGID_KEA:
    case CSSM_ALGID_ECDSA:
    case CSSM_ALGID_MAYFLY:
#endif
      switch (pCssmContext->AlgorithmType)
      {
        case CSSM_ALGID_DSA:
          PkcsMechanism.mechanism = CKM_DSA_KEY_PAIR_GEN;
          break;
#ifdef PKCS11_V20
        case CSSM_ALGID_ECDSA:
          PkcsMechanism.mechanism = CKM_ECDSA_KEY_PAIR_GEN;
          break;
    
        case CSSM_ALGID_KEA:
          PkcsMechanism.mechanism = CKM_KEA_KEY_PAIR_GEN;
          break;
    
        case CSSM_ALGID_MAYFLY:
          PkcsMechanism.mechanism = CKM_MAYFLY_KEY_PAIR_GEN;
          break;
#endif
      }

      pCssmAlgoParamsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ALG_PARAMS);
      if (pCssmAlgoParamsAttr != NULL && pCssmAlgoParamsAttr->Attribute.Data->Data != NULL)
      {
        CSSM_DSA_PUBLIC_PTR pCssmDsaPublic = (CSSM_DSA_PUBLIC_PTR) pCssmAlgoParamsAttr->Attribute.Data->Data;
        
        if (pCssmDsaPublic->prime.Data != NULL && pCssmDsaPublic->prime.Length != 0)
        {
          PkcsPublicTemplate[ii].type = CKA_PRIME;
          PkcsPublicTemplate[ii].pValue = pCssmDsaPublic->prime.Data;
#ifdef PKCS11_V20
          PkcsPublicTemplate[ii++].ulValueLen = pCssmDsaPublic->prime.Length;
#else
          PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT)pCssmDsaPublic->prime.Length;
#endif
        }
        else
          return SetErr(CSSM_CSP_PARAM_NO_PRIME);

        if (pCssmDsaPublic->subPrime.Data != NULL && pCssmDsaPublic->subPrime.Length != 0)
        {
          PkcsPublicTemplate[ii].type = CKA_PRIME;
          PkcsPublicTemplate[ii].pValue = pCssmDsaPublic->subPrime.Data;
#ifdef PKCS11_V20
          PkcsPublicTemplate[ii++].ulValueLen = pCssmDsaPublic->subPrime.Length;
#else
          PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT)pCssmDsaPublic->subPrime.Length;
#endif
        }
        else
          return SetErr(CSSM_CSP_PARAM_NO_SUBPRIME);

        if (pCssmDsaPublic->base.Data != NULL && pCssmDsaPublic->base.Length != 0)
        {
      
          PkcsPublicTemplate[ii].pValue = pCssmDsaPublic->base.Data;
#ifdef PKCS11_V20
          PkcsPublicTemplate[ii++].ulValueLen = pCssmDsaPublic->base.Length;
#else
          PkcsPublicTemplate[ii++].usValueLen = (CK_USHORT) pCssmDsaPublic->base.Length;
#endif
        }
        else
          return SetErr(CSSM_CSP_PARAM_NO_BASE);
      }

      break;

    
    default:
      return SetErr(CSSM_CSP_INVALID_ALGORITHM);
      break;
  
  }


  //
  // Generate KeyID Attribute
  //

  bSeedAllocated = CSSM_FALSE;
  pCssmSeedAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_SEED);
  if (pCssmSeedAttr == NULL)
  {
    if ((Seed.Data = CssmMemFuncs.malloc_func(CssmCSPHandle, DEFAULTSEEDLEN)) == NULL)
    { 
      return SetErr(CSSM_CALLOC_FAILED);
    }

    Seed.Length = DEFAULTSEEDLEN;
    if (GetSeed(&Seed) == CSSM_FAIL)
      return CSSM_FAIL;

    bSeedAllocated = CSSM_TRUE;
  }
  else
  {
    if (pCssmSeedAttr->Attribute.Crypto != NULL)
    {
      if (pCssmSeedAttr->Attribute.Crypto->Callback == NULL)
      {
        if (pCssmSeedAttr->Attribute.Crypto->Param != NULL &&
          pCssmSeedAttr->Attribute.Crypto->Param->Data != NULL &&
          pCssmSeedAttr->Attribute.Crypto->Param->Length != 0)
        {
          Seed.Data   = pCssmSeedAttr->Attribute.Crypto->Param->Data;
          Seed.Length = pCssmSeedAttr->Attribute.Crypto->Param->Length;
        }
        else
        {
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
        }
      }
      else
      {
        pSeed = pCssmSeedAttr->Attribute.Crypto->Callback(
                NULL, 
                pCssmSeedAttr->Attribute.Crypto->CallbackID);
        if (pSeed->Data == NULL || pSeed->Length == 0)
          return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
        Seed.Data = pSeed->Data;
        Seed.Length = pSeed->Length;
      }
    }
    else
    {
      return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
    }
  }


#ifdef PKCS11_V20
  if ((PkcsStatus = C_SeedRandom(pMsmSession->PkcsSessionHandle,  
                   Seed.Data, 
                   Seed.Length)) != CKR_OK)
#else
  if ((PkcsStatus = C_SeedRandom(pMsmSession->PkcsSessionHandle,  
                   Seed.Data, 
                   (CK_USHORT)Seed.Length)) != CKR_OK)
#endif
    return SetErr(PkcsStatus);

  if (bSeedAllocated == CSSM_TRUE)
    CssmMemFuncs.free_func(CssmCSPHandle, Seed.Data);
  
  
  if ((PkcsStatus = C_GenerateRandom(pMsmSession->PkcsSessionHandle,  
                     KeyID, 
                     sizeof(KeyID))) != CKR_OK)
    return SetErr(PkcsStatus);


  PkcsPublicTemplate[ii].type = CKA_ID;
  PkcsPublicTemplate[ii].pValue = KeyID;
#ifdef PKCS11_V20
  PkcsPublicTemplate[ii++].ulValueLen = sizeof(KeyID);
#else
  PkcsPublicTemplate[ii++].usValueLen = sizeof(KeyID);
#endif

  PkcsPrivateTemplate[jj].type = CKA_ID;
  PkcsPrivateTemplate[jj].pValue = KeyID;
#ifdef PKCS11_V20
  PkcsPrivateTemplate[jj++].ulValueLen = sizeof(KeyID);
#else
  PkcsPrivateTemplate[jj++].usValueLen = sizeof(KeyID);
#endif


  //
  // Generate Key Pair
  //

#ifdef PKCS11_V20
  if ((PkcsStatus = C_GenerateKeyPair(pMsmSession->PkcsSessionHandle,
                    &PkcsMechanism,
                    PkcsPublicTemplate,
                    ii,
                    PkcsPrivateTemplate,
                    jj,
                    &hPkcsPublicKey,
                    &hPkcsPrivateKey)) != CKR_OK)
    return SetErr(PkcsStatus);
#else
  if ((PkcsStatus = C_GenerateKeyPair(pMsmSession->PkcsSessionHandle,
                    &PkcsMechanism,
                    PkcsPublicTemplate,
                    ii,
                    PkcsPrivateTemplate,
                    jj,
                    &hPkcsPrivateKey,
                    &hPkcsPublicKey)) != CKR_OK)
    return SetErr(PkcsStatus);
#endif

  if (pCssmPublicKey->KeyData.Data == NULL)
  {
    if ((pCssmPublicKey->KeyData.Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                   1,
                                   sizeof(hPkcsPublicKey))) == NULL)
    {
      return SetErr(CSSM_CALLOC_FAILED);
    }
    else
    {
      MsmBufferAllocated = CSSM_TRUE;
    }
  }
  else if (pCssmPublicKey->KeyData.Length < sizeof(hPkcsPublicKey))
    return SetErr(CSSM_CSP_ERR_KEYBUF_LENGTH);

  pCssmPublicKey->KeyData.Length = sizeof(hPkcsPublicKey);

  *((CK_OBJECT_HANDLE*)pCssmPublicKey->KeyData.Data) = hPkcsPublicKey;

  SetupKeyHeader(
    &pCssmPublicKey->KeyHeader, 
    CSSM_KEYBLOB_REFERENCE,                   /* See BlobType #define's */
    CSSM_KEYBLOB_REF_FORMAT_INTEGER,              /* Raw or Reference format */
    pCssmContext->AlgorithmType,                /* Algoritm ID of key */
    CSSM_KEYCLASS_PUBLIC_KEY,                 /* Public/Private/Secret etc. */
    pCssmKeyLengthAttr->Attribute.Uint32,           /* Size of actual key in bits */
    CssmPublicKeyAttr,                      /* Attribute flags */
    CssmPublicKeyUsage,                     /* Key use flags */
    bMsmStartDate ? pCssmStartDateAttr->Attribute.Date : NULL,  /* Effective date of key */
    bMsmEndDate ?  pCssmEndDateAttr->Attribute.Date : NULL,   /* Expiration date of key */
    CSSM_ALGID_NONE,                      /* Wrap Algo */
    CSSM_ALGMODE_NONE);


  if (pCssmPrivateKey->KeyData.Data == NULL)
  {
    if ((pCssmPrivateKey->KeyData.Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                    1,
                                    sizeof(hPkcsPrivateKey))) == NULL)
    {
      if (MsmBufferAllocated == CSSM_TRUE)
      {
        CssmMemFuncs.free_func(CssmCSPHandle, pCssmPublicKey->KeyData.Data);
        pCssmPublicKey->KeyData.Data = NULL;
        pCssmPublicKey->KeyData.Length = 0;
      }
      return SetErr(CSSM_CALLOC_FAILED);
    }
  }
  else if (pCssmPrivateKey->KeyData.Length < sizeof(hPkcsPrivateKey))
  {
    if (MsmBufferAllocated == CSSM_TRUE)
    {
      CssmMemFuncs.free_func(CssmCSPHandle, pCssmPublicKey->KeyData.Data);
      pCssmPublicKey->KeyData.Data = NULL;
      pCssmPublicKey->KeyData.Length = 0;
    }
    return SetErr(CSSM_CSP_ERR_KEYBUF_LENGTH);
  }


  pCssmPrivateKey->KeyData.Length = sizeof(hPkcsPrivateKey);

  *((CK_OBJECT_HANDLE*)pCssmPrivateKey->KeyData.Data) = hPkcsPrivateKey;


  SetupKeyHeader(
    &pCssmPrivateKey->KeyHeader, 
    CSSM_KEYBLOB_REFERENCE,                   /* See BlobType #define's */
    CSSM_KEYBLOB_REF_FORMAT_INTEGER,              /* Raw or Reference format */
    pCssmContext->AlgorithmType,                /* Algoritm ID of key */
    CSSM_KEYCLASS_PRIVATE_KEY,                  /* Public/Private/Secret etc. */
    pCssmKeyLengthAttr->Attribute.Uint32,           /* Size of actual key in bits */
    CssmPrivateKeyAttr,                     /* Attribute flags */
    CssmPrivateKeyUsage,                    /* Key use flags */
    bMsmStartDate ? pCssmStartDateAttr->Attribute.Date : NULL,  /* Effective date of key */
    bMsmEndDate ?  pCssmEndDateAttr->Attribute.Date : NULL,   /* Expiration date of key */
    CSSM_ALGID_NONE,                      /* Wrap Algo */
    CSSM_ALGMODE_NONE);
  
  return CSSM_OK;
} 



