/* ***************************************************************** *
 * 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: QueryKeySizeInBits
 * 
 * Return key size/effective key size.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *   
 * Output:
 *  pCssmKeySize    - Key size/effective key size
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */


CSSM_RETURN CSSMAPI QueryKeySizeInBits(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
    CSSM_KEY_SIZE_PTR pCssmKeySize)
{

  MSMSESSION_PTR        pMsmSession;

  CSSM_CONTEXT_PTR      pCssmContext;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEffectiveKeyBitsAttr;

  CSSM_KEY_PTR        pCssmKey;
  
  CK_RV           PkcsRc;
  CK_OBJECT_HANDLE      hPkcsKey;



#ifdef PKCS11_V20
  CK_ULONG          PkcsValueLen;     // Required when variable
#else
  CK_USHORT         PkcsValueLen;     // Required when variable
#endif

  CK_ATTRIBUTE        PkcsTemplate[] = 
  {
    {CKA_VALUE_LEN, &PkcsValueLen, sizeof(PkcsValueLen)}
  };



  if (pCssmKeySize == NULL)
    return(CSSM_CSP_INVALID_POINTER);

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

  if ((pCssmContext = CSSM_GetContext(CssmCCHandle)) == NULL)
    return SetErr(CSSM_INVALID_CONTEXT_HANDLE);

  if (pCssmContext->ContextType != CSSM_ALGCLASS_SYMMETRIC) 
    return SetErr(CSSM_CSP_INVALID_CONTEXT);

  pCssmKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmKeyAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY); 
  
  pCssmKey = pCssmKeyAttr->Attribute.Key;

  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
    pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

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


    switch (pCssmKey->KeyHeader.AlgorithmId)
    {
      case CSSM_ALGID_RC2:
        if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                      hPkcsKey,
                      PkcsTemplate,
                      DIM(PkcsTemplate))) != CKR_OK)
        {
          CSSM_FreeContext(pCssmContext);
          return SetErr(PkcsRc);
        }

        pCssmKeySize->KeySizeInBits = PkcsValueLen * BITSPERBYTE;
        pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                   CSSM_ATTRIBUTE_EFFECTIVE_BITS);
        if (pCssmEffectiveKeyBitsAttr == NULL)
          return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);
        
        pCssmKeySize->EffectiveKeySizeInBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
        break;

      case CSSM_ALGID_RC4:
        if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                      hPkcsKey,
                      PkcsTemplate,
                      DIM(PkcsTemplate))) != CKR_OK)
        {
          CSSM_FreeContext(pCssmContext);
          return SetErr(PkcsRc);
        }

        pCssmKeySize->KeySizeInBits = PkcsValueLen * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        break;

      case CSSM_ALGID_DES:
        pCssmKeySize->KeySizeInBits = DESKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = (DESKEYLEN - 1) * BITSPERBYTE;
        break;

      case CSSM_ALGID_3DES_2KEY:
        pCssmKeySize->KeySizeInBits = DES2KEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = (DES2KEYLEN - 2) * BITSPERBYTE;
        break;

      case CSSM_ALGID_3DES_3KEY:
        pCssmKeySize->KeySizeInBits = DES3KEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = (DES3KEYLEN - 3) * BITSPERBYTE;
        break;

#ifdef PKCS11_V20           
      case CSSM_ALGID_RC5:
      case CSSM_ALGID_CAST:   
      case CSSM_ALGID_CAST3:
      case CSSM_ALGID_CAST5:
        if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                      hPkcsKey,
                      PkcsTemplate,
                      DIM(PkcsTemplate))) != CKR_OK)
        {
          CSSM_FreeContext(pCssmContext);
          return SetErr(PkcsRc);
        }

        pCssmKeySize->KeySizeInBits = PkcsValueLen * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = PkcsValueLen * BITSPERBYTE;
        break;
        if ((PkcsRc = C_GetAttributeValue(pMsmSession->PkcsSessionHandle,
                      hPkcsKey,
                      PkcsTemplate,
                      DIM(PkcsTemplate))) != CKR_OK)
        {
          CSSM_FreeContext(pCssmContext);
          return SetErr(PkcsRc);
        }

        pCssmKeySize->KeySizeInBits = PkcsValueLen * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = PkcsValueLen * BITSPERBYTE;
        break;

      case CSSM_ALGID_IDEA:
        pCssmKeySize->KeySizeInBits = IDEAKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = IDEAKEYLEN * BITSPERBYTE;
        break;

      case CSSM_ALGID_CDMF:
        pCssmKeySize->KeySizeInBits = CDMFKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = CDMFKEYLEN * BITSPERBYTE;
        break;

      case CSSM_ALGID_SKIPJACK:
        pCssmKeySize->KeySizeInBits = SKIPJACKKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = SKIPJACKKEYLEN * BITSPERBYTE;
        break;

      case CSSM_ALGID_BATON:
        pCssmKeySize->KeySizeInBits = BATONKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = BATONKEYLEN * BITSPERBYTE;
        break;

      case CSSM_ALGID_JUNIPER:
        pCssmKeySize->KeySizeInBits = JUNIPERKEYLEN * BITSPERBYTE;
        pCssmKeySize->EffectiveKeySizeInBits = JUNIPERKEYLEN * BITSPERBYTE;
        break;
#endif

      default:
        CSSM_FreeContext(pCssmContext);
        return SetErr(CSSM_CSP_INVALID_ALGORITHM);
          
    }

  }
  else if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_RAW &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_RAW_FORMAT_CDSA &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
    pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    switch (pCssmKey->KeyHeader.AlgorithmId)
    {
      case CSSM_ALGID_RC2:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;

        pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                   CSSM_ATTRIBUTE_EFFECTIVE_BITS);
        if (pCssmEffectiveKeyBitsAttr == NULL)
          return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);
        
        pCssmKeySize->EffectiveKeySizeInBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
        break;

      case CSSM_ALGID_RC4:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;
        
        pCssmKeySize->EffectiveKeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        break;

      case CSSM_ALGID_DES:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;
        
        pCssmKeySize->EffectiveKeySizeInBits = (DESKEYLEN - 1) * BITSPERBYTE;
        break;

      case CSSM_ALGID_3DES_2KEY:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;
        
        pCssmKeySize->EffectiveKeySizeInBits = (DES2KEYLEN - 2) * BITSPERBYTE;
        break;

      case CSSM_ALGID_3DES_3KEY:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;
        
        pCssmKeySize->EffectiveKeySizeInBits = (DES3KEYLEN - 3) * BITSPERBYTE;
        break;

#ifdef PKCS11_V20           
      // Check this fow V2.0
      case CSSM_ALGID_RC5:
      case CSSM_ALGID_CAST:   
      case CSSM_ALGID_CAST3:
      case CSSM_ALGID_CAST5:
      case CSSM_ALGID_IDEA:
      case CSSM_ALGID_CDMF:
      case CSSM_ALGID_SKIPJACK:
      case CSSM_ALGID_BATON:
      case CSSM_ALGID_JUNIPER:
        if (pCssmKey->KeyHeader.KeySizeInBits < (pCssmKey->KeyData.Length * 8))
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;
        else
          pCssmKeySize->KeySizeInBits = pCssmKey->KeyData.Length * 8;
        
        pCssmKeySize->EffectiveKeySizeInBits = pCssmKey->KeyHeader.KeySizeInBits;

#endif

      default:
        CSSM_FreeContext(pCssmContext);
        return SetErr(CSSM_CSP_INVALID_ALGORITHM);
          
    }
    
  }
  else
  {
    CSSM_FreeContext(pCssmContext);
    return SetErr(CSSM_CSP_INVALID_KEY);
  }


  
  CSSM_FreeContext(pCssmContext);
  return CSSM_OK;

}



/*****************************************************************************
 * Function: WrapKey 
 * 
 * Wrap a session or private key.
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmPassPhrase   - Not used
 *  pCssmKey      - Key to be wrapped
 *   
 * Output:
 *  pCssmWrappedKey   - Wrapped key if successful
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI WrapKey(
  CSSM_CSP_HANDLE CssmCSPHandle,
    CSSM_CC_HANDLE CssmCCHandle,
    const CSSM_CONTEXT_PTR pCssmContext,
    const CSSM_CRYPTO_DATA_PTR pCssmPassPhrase, 
    const CSSM_KEY_PTR pCssmKey,
    CSSM_WRAP_KEY_PTR pCssmWrappedKey)
{

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;


  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmWrappingKeyAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmModeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmInitVectorAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEffectiveKeyBitsAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmWordSizeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr = NULL;
  CSSM_KEY_PTR        pCssmWrappingKey;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsWrappingKey;
  CK_OBJECT_HANDLE      hPkcsKey;


#ifdef PKCS11_V20
  CK_RC2_PARAMS       PkcsRc2Params;
  CK_RC2_CBC_PARAMS     PkcsRc2CbcParams;
#else
  CK_USHORT         PkcsRc2Params;
#endif

#ifdef PKCS11_V20
  CK_RC5_PARAMS       PkcsRc5Params;
  CK_RC5_CBC_PARAMS     PkcsRc5CbcParams;
#endif

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



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

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

  pCssmWrappingKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmWrappingKeyAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY);
  
  pCssmWrappingKey = pCssmWrappingKeyAttr->Attribute.Key;
  
  if (pCssmWrappingKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmWrappingKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    (pCssmWrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY ||
     pCssmWrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY))
  {
    if (pCssmWrappingKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    hPkcsWrappingKey = *((CK_OBJECT_HANDLE*) pCssmWrappingKey->KeyData.Data);
  }
  else
    return SetErr(CSSM_CSP_INVALID_KEY);

  pCssmModeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_MODE);
  pCssmInitVectorAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_INIT_VECTOR);

  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_RSA_PKCS:
      if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
        PkcsMechanism.mechanism = CKM_RSA_PKCS;
      else
        return SetErr(CSSM_CSP_INVALID_KEY);
      break;

    case CSSM_ALGID_RSA_RAW:
      if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
        PkcsMechanism.mechanism = CKM_RSA_X_509;
      else
        return SetErr(CSSM_CSP_INVALID_KEY);
      break;

    case CSSM_ALGID_DES:
      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_ECB;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }

          break;

#ifdef PKCS11_V20

        case CSSM_ALGMODE_CBC:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_CBC;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }

          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_CBC_PAD;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }

          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_3DES_2KEY:
    case CSSM_ALGID_3DES_3KEY:
      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_ECB;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBC:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_CBC;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_CBC_PAD;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC2:
      pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                 CSSM_ATTRIBUTE_EFFECTIVE_BITS);
      if (pCssmEffectiveKeyBitsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);  

      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_ECB;
#ifdef PKCS11_V20
            PkcsRc2Params = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            PkcsMechanism.pParameter = &PkcsRc2Params;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2Params);
#else
            PkcsRc2Params = (CK_USHORT) pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            PkcsRc2Params = htons(PkcsRc2Params);
            PkcsMechanism.pParameter = &PkcsRc2Params;
            PkcsMechanism.usParameterLen = sizeof(PkcsRc2Params);
#endif
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

#ifdef PKCS11_V20
        
        case CSSM_ALGMODE_CBC:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_CBC;
            PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;

            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
              return SetErr(CSSM_CSP_INVALID_IV_SIZE);
            memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
            PkcsMechanism.pParameter = &PkcsRc2CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_CBC_PAD;
            PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
              return SetErr(CSSM_CSP_INVALID_IV_SIZE);
            memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
            PkcsMechanism.pParameter = &PkcsRc2CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }
      
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_RC5:
      pCssmWordSizeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_BLOCK_SIZE);
      if (pCssmWordSizeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PARAM);   
        //return SetErr(CSSM_CSP_PARAM_NO_BLOCK_SIZE);    

      pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
      if (pCssmRoundsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_ROUNDS);

      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_ECB;
            PkcsRc5Params.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;
            PkcsRc5Params.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            PkcsMechanism.pParameter = &PkcsRc5Params;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5Params);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
        
        case CSSM_ALGMODE_CBC:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_CBC;
            PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
            PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
            PkcsMechanism.pParameter = &PkcsRc5CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_CBC_PAD;
            PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
            PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
            PkcsMechanism.pParameter = &PkcsRc5CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;
#endif
    default:
      return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);      
  }


  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY ||
     pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY))
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);
  
    hPkcsKey = (CK_OBJECT_HANDLE) *(pCssmKey->KeyData.Data);
  }
  else
    return SetErr(CSSM_CSP_INVALID_KEY);


  // Buffer checking and allocation 

  if (pCssmWrappedKey == NULL)
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if (((pCssmWrappedKey->KeyData.Length == 0) && (pCssmWrappedKey->KeyData.Data != NULL)) ||
    ((pCssmWrappedKey->KeyData.Length != 0) && (pCssmWrappedKey->KeyData.Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);


  if (pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
  {
    length = pCssmKey->KeyHeader.KeySizeInBits / 8;
    if ((pCssmKey->KeyHeader.KeySizeInBits % 8) != 0)
      length++;
  }
  else
  {
    length = IBMPKCS11_REQWRAPPEDPRIVATEKEYBUFLEN;
  }

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


  // Now do the encryption
#ifdef PKCS11_V20
  if ((PkcsStatus = C_WrapKey(pMsmSession->PkcsSessionHandle, 
                &PkcsMechanism,
                hPkcsWrappingKey,
                hPkcsKey,
                pCssmWrappedKey->KeyData.Data,
                &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_WrapKey(pMsmSession->PkcsSessionHandle, 
                &PkcsMechanism,
                hPkcsWrappingKey,
                hPkcsKey,
                pCssmWrappedKey->KeyData.Data,
                &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle,  pCssmWrappedKey->KeyData.Data);
      pCssmWrappedKey->KeyData.Length = 0;
      pCssmWrappedKey->KeyData.Data = NULL;
    }

    return SetErr(PkcsStatus);
  }

  //
  // Set up KeyHeader
  //
  SetupKeyHeader(
    &pCssmWrappedKey->KeyHeader,
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ?
      CSSM_KEYBLOB_WRAPPED : CSSM_KEYBLOB_WRAPPED_BERDER,   /* See BlobType #define's */
    CSSM_KEYBLOB_RAW_FORMAT_PKCS11,               /* Raw or Reference format */
    pCssmKey->KeyHeader.AlgorithmId,              /* Algoritm ID of key */
    pCssmKey->KeyHeader.KeyClass,               /* Public/Private/Secret etc. */
    pCssmKey->KeyHeader.KeySizeInBits,              /* Size of actual key in bits */
    pCssmKey->KeyHeader.KeyAttr,                /* Attribute flags */
    pCssmKey->KeyHeader.KeyUsage,               /* Key use flags */
    &pCssmKey->KeyHeader.StartDate,               /* Effective date of key */
    &pCssmKey->KeyHeader.EndDate,               /* Expiration date of key */
    pCssmContext->AlgorithmType,                /* Wrap Algo */
    pCssmModeAttr == NULL ? 0 : pCssmModeAttr->Attribute.Uint32); /* Wrap Mode */
  
  pCssmWrappedKey->KeyData.Length = length;
  return CSSM_OK;
}



/*****************************************************************************
 * Function: UnwrapKey
 *
 * Unwrap a previously wrapped key.
 *
 * Input:
 *  CssmCSPHandle     - Attach session handle 
 *  CssmCCHandle      - Context handle
 *  pCssmContext      - Pointer to context 
 *  pCssmNewPassPhrase    - Not used
 *  pCssmWrappedKey     - Wrapped key
 *  CssmUnwrappedKeyAttr  - Unwrapped key's key attribute
 *  pCssmUnwrappedKeyLabel  - Unwrapped key's key label
 *   
 * Output:
 *  pCssmUnwrappedKey   - Unwrapped key if successful
 *   
 * Returns:
 *  CSSM_OK         - Successful      
 *  CSSM_FAIL       - Failed
 *
 */

CSSM_RETURN CSSMAPI UnwrapKey(
  CSSM_CSP_HANDLE CssmCSPHandle, 
    CSSM_CC_HANDLE CssmCCHandle,
    const CSSM_CONTEXT_PTR pCssmContext,
    const CSSM_CRYPTO_DATA_PTR pCssmNewPassPhrase,
    const CSSM_WRAP_KEY_PTR pCssmWrappedKey,
    uint32 CssmUnwrappedKeyAttr,
  const CSSM_DATA_PTR pCssmUnwrappedKeyLabel,
    CSSM_KEY_PTR pCssmUnwrappedKey)
{

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmUnwrappingKeyAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmModeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmInitVectorAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEffectiveKeyBitsAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmWordSizeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr = NULL;
  CSSM_KEY_PTR        pCssmUnwrappingKey;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsUnwrappingKey;
  CK_OBJECT_HANDLE      hPkcsUnwrappedKey;


//
//  Common Key Data
//

// Common Object Attrs  
  CK_OBJECT_CLASS       PkcsClass;        // Required
  CK_BBOOL          PkcsToken;        // FALSE
  CK_BBOOL          PkcsPrivate;      // FALSE
#ifdef PKCS11_V20
  CK_BBOOL          PkcsModifiable;     // TRUE
#endif
//  CK_CHAR_PTR         pPkcsObjectLabel;   // NULL, not used by CDSA

// Common Key Attrs
  CK_KEY_TYPE         PkcsKeyType;      // Required
//  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          PkcsSessionSensitive;   // FALSE
  CK_BBOOL          PkcsSessionEncrypt;     // Token default
  CK_BBOOL          PkcsSessionDecrypt;     // Token default
  CK_BBOOL          PkcsSessionSign;      // Token default
  CK_BBOOL          PkcsSessionVerify;      // Token default
  CK_BBOOL          PkcsSessionWrap;      // Token default
  CK_BBOOL          PkcsSessionUnwrap;      // Token default
//  CK_BBOOL          PkcsSessionExtractable;   // Token default
//  CK_BBOOL          PkcsSessionAlwaysSensitive; // Not setable
//  CK_BBOOL          PkcsSessionNeverExtractable;// Not setable
//  CK_CHAR_PTR         pPkcsSessionValue;      // Not setable
//  CK_ULONG          PkcsSessionValueLen;    // Required when variable

//
//  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
//  CK_ULONG          PkcsPublicModulusBits;    // Required
//  CK_BYTE_PTR         pPkcsPublicPublicExponent;  // 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


//
//  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
//  CK_BBOOL          PkcsPrivateExtractable;   // Token default
//  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        PkcsTemplate[PKCS_TOTAL_PRIVATE_ATTRS];

  int             ii = 0;
#ifdef PKCS11_V20
  CK_RC2_PARAMS       PkcsRc2Params;
  CK_RC2_CBC_PARAMS     PkcsRc2CbcParams;
#else
  CK_USHORT         PkcsRc2Params;
#endif

#ifdef PKCS11_V20
  CK_RC5_PARAMS       PkcsRc5Params;
  CK_RC5_CBC_PARAMS     PkcsRc5CbcParams;
#endif


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

  if (pCssmWrappedKey == NULL || pCssmUnwrappedKey == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  if ((pCssmUnwrappedKey->KeyData.Data == NULL && pCssmUnwrappedKey->KeyData.Length != 0) ||
    (pCssmUnwrappedKey->KeyData.Data != NULL && pCssmUnwrappedKey->KeyData.Length == 0))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
  
  if (pCssmWrappedKey->KeyData.Data == NULL || pCssmWrappedKey->KeyData.Length == 0)
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);


  pCssmModeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_MODE);
  pCssmInitVectorAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_INIT_VECTOR);

  pCssmUnwrappingKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmUnwrappingKeyAttr == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  pCssmUnwrappingKey = pCssmUnwrappingKeyAttr->Attribute.Key;
  if (pCssmUnwrappingKey == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  if (pCssmUnwrappingKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmUnwrappingKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    (pCssmUnwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY ||
     pCssmUnwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) 
  {
    if (pCssmUnwrappingKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
  
    hPkcsUnwrappingKey = (CK_OBJECT_HANDLE) *(pCssmUnwrappingKey->KeyData.Data);
  }
  else
    return SetErr(CSSM_CSP_INVALID_KEY);


  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_RSA_PKCS:
      if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
        PkcsMechanism.mechanism = CKM_RSA_PKCS;
      else
        return SetErr(CSSM_CSP_INVALID_KEY);
      break;      
      
    case CSSM_ALGID_RSA_RAW:
      if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
        PkcsMechanism.mechanism = CKM_RSA_X_509;
      else
        return SetErr(CSSM_CSP_INVALID_KEY);
      break;

    case CSSM_ALGID_DES:
      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_ECB;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

#ifdef PKCS11_V20
    
        case CSSM_ALGMODE_CBC:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_CBC;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
        
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }

          break;
    
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES_CBC_PAD;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }

          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_3DES_2KEY:
    case CSSM_ALGID_3DES_3KEY:
      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_ECB;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBC:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_CBC;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;

          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_DES3_CBC_PAD;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
            PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC2:
      if (pCssmUnwrappingKey->KeyHeader.AlgorithmId != CSSM_ALGID_RC2)
        return SetErr(CSSM_CSP_INVALID_KEY);

      pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                 CSSM_ATTRIBUTE_EFFECTIVE_BITS);
      if (pCssmEffectiveKeyBitsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);

      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_ECB;
#ifdef PKCS11_V20
            PkcsRc2Params = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            PkcsMechanism.pParameter = &PkcsRc2Params;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2Params);
#else
            PkcsRc2Params = (CK_USHORT) pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            PkcsRc2Params = htons(PkcsRc2Params);
            PkcsMechanism.pParameter = &PkcsRc2Params;
            PkcsMechanism.usParameterLen = sizeof(PkcsRc2Params);
#endif
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBC:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_CBC;
            PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;

            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
              return SetErr(CSSM_CSP_INVALID_IV_SIZE);
            memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
            PkcsMechanism.pParameter = &PkcsRc2CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;

        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC2_CBC_PAD;
            PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
              return SetErr(CSSM_CSP_INVALID_IV_SIZE);
            memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
            PkcsMechanism.pParameter = &PkcsRc2CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


#ifdef PKCS11_V20
    case CSSM_ALGID_RC5:
      pCssmWordSizeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_BLOCK_SIZE);
      if (pCssmWordSizeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PARAM);   

      pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
      if (pCssmRoundsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_ROUNDS);

      if (pCssmModeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_MODE);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_ECB;
            PkcsRc5Params.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;
            PkcsRc5Params.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            PkcsMechanism.pParameter = &PkcsRc5Params;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5Params);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
        
        case CSSM_ALGMODE_CBC:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_CBC;
            PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
            PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
            PkcsMechanism.pParameter = &PkcsRc5CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          if (pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY ||
            pCssmWrappedKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
          {
            PkcsMechanism.mechanism = CKM_RC5_CBC_PAD;
            PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
            PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
            if (pCssmInitVectorAttr == NULL)
              return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
            PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
            PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
            PkcsMechanism.pParameter = &PkcsRc5CbcParams;
            PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          }
          else
          {
            return SetErr(CSSM_CSP_INVALID_KEY);
          }
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;
#endif
    default:
      return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);
  }

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

  PkcsTemplate[ii].type = CKA_START_DATE;
  PkcsTemplate[ii].pValue = &pCssmWrappedKey->KeyHeader.StartDate;
#ifdef PKCS11_V20
  PkcsTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
  PkcsTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif

  PkcsTemplate[ii].type = CKA_END_DATE;
  PkcsTemplate[ii].pValue = &pCssmWrappedKey->KeyHeader.EndDate;
#ifdef PKCS11_V20
  PkcsTemplate[ii++].ulValueLen = sizeof(CSSM_DATE);
#else
  PkcsTemplate[ii++].usValueLen = sizeof(CSSM_DATE);
#endif

  if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
    (pCssmWrappedKey->KeyHeader.KeyUsage & 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 (CssmUnwrappedKeyAttr & 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 (CssmUnwrappedKeyAttr & 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 (CssmUnwrappedKeyAttr & CSSM_KEYATTR_MODIFIABLE)
    PkcsModifiable = TRUE;
  else
    PkcsModifiable = FALSE;
    
  PkcsTemplate[ii].type = CKA_MODIFIABLE;
  PkcsTemplate[ii].pValue = &PkcsModifiable;
  PkcsTemplate[ii++].ulValueLen = sizeof(PkcsModifiable);
#endif

  switch (pCssmWrappedKey->KeyHeader.KeyClass)
  {
    case CSSM_KEYCLASS_PRIVATE_KEY:
      PkcsClass = CKO_PRIVATE_KEY;
      PkcsTemplate[ii].type = CKA_CLASS;
      PkcsTemplate[ii].pValue = &PkcsClass;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsClass);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsClass);
#endif  

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

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_DECRYPT))
        PkcsPrivateDecrypt = TRUE;
      else
        PkcsPrivateDecrypt = FALSE;
    
      PkcsTemplate[ii].type = CKA_DECRYPT;
      PkcsTemplate[ii].pValue = &PkcsPrivateDecrypt;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsPrivateDecrypt);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsPrivateDecrypt);
#endif  

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_SIGN))
        PkcsPrivateSign = TRUE;
      else
        PkcsPrivateSign = FALSE;
    
      PkcsTemplate[ii].type = CKA_SIGN;
      PkcsTemplate[ii].pValue = &PkcsPrivateSign;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsPrivateSign);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsPrivateSign);
#endif  

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_SIGN_RECOVER))
        PkcsPrivateSignRecover = TRUE;
      else
        PkcsPrivateSignRecover = FALSE;

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

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_UNWRAP))
        PkcsPrivateUnwrap = TRUE;
      else
        PkcsPrivateUnwrap = FALSE;
    
      PkcsTemplate[ii].type = CKA_WRAP;
      PkcsTemplate[ii].pValue = &PkcsPrivateUnwrap;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsPrivateUnwrap);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsPrivateUnwrap);
#endif
      break;
  
    case CSSM_KEYCLASS_SESSION_KEY:
      
      PkcsClass = CKO_SECRET_KEY;
      PkcsTemplate[ii].type = CKA_CLASS;
      PkcsTemplate[ii].pValue = &PkcsClass;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsClass);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsClass);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ENCRYPT))
        PkcsSessionEncrypt = TRUE;
      else
        PkcsSessionEncrypt = FALSE;
    
      PkcsTemplate[ii].type = CKA_ENCRYPT;
      PkcsTemplate[ii].pValue = &PkcsSessionEncrypt;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionEncrypt);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionEncrypt);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_DECRYPT))
        PkcsSessionDecrypt = TRUE;
      else
        PkcsSessionDecrypt = FALSE;
    
      PkcsTemplate[ii].type = CKA_DECRYPT;
      PkcsTemplate[ii].pValue = &PkcsSessionDecrypt;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionDecrypt);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionDecrypt);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_SIGN))
        PkcsSessionSign = TRUE;
      else
        PkcsSessionSign = FALSE;
    
      PkcsTemplate[ii].type = CKA_SIGN;
      PkcsTemplate[ii].pValue = &PkcsSessionSign;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionSign);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionSign);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_VERIFY))
        PkcsSessionVerify = TRUE;
      else
        PkcsSessionVerify = FALSE;
    
      PkcsTemplate[ii].type = CKA_VERIFY;
      PkcsTemplate[ii].pValue = &PkcsSessionVerify;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionVerify);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionVerify);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_WRAP))
        PkcsSessionWrap = TRUE;
      else
        PkcsSessionWrap = FALSE;
    
      PkcsTemplate[ii].type = CKA_WRAP;
      PkcsTemplate[ii].pValue = &PkcsSessionWrap;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionWrap);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionWrap);
#endif

      if ((pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_ANY) ||
        (pCssmWrappedKey->KeyHeader.KeyUsage & CSSM_KEYUSE_UNWRAP))
        PkcsSessionUnwrap = TRUE;
      else
        PkcsSessionUnwrap = FALSE;
    
      PkcsTemplate[ii].type = CKA_UNWRAP;
      PkcsTemplate[ii].pValue = &PkcsSessionUnwrap;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionUnwrap);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionUnwrap);
#endif

      if (CssmUnwrappedKeyAttr & CSSM_KEYATTR_SENSITIVE)
        PkcsSessionSensitive = TRUE;
      else
        PkcsSessionSensitive = FALSE;
    
      PkcsTemplate[ii].type = CKA_SENSITIVE;
      PkcsTemplate[ii].pValue = &PkcsSessionSensitive;
#ifdef PKCS11_V20
      PkcsTemplate[ii++].ulValueLen = sizeof(PkcsSessionSensitive);
#else
      PkcsTemplate[ii++].usValueLen = sizeof(PkcsSessionSensitive);
#endif      
      break;
  
    default:
      break;
  }

  

  switch (pCssmWrappedKey->KeyHeader.AlgorithmId)
  {
    case CSSM_ALGID_RC2:
      PkcsKeyType = CKK_RC2;
      break;

    case CSSM_ALGID_RC4:
      PkcsKeyType = CKK_RC4;
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_RC5:
      PkcsKeyType = CKK_RC5;
      break;
#endif

    case CSSM_ALGID_DES:
      PkcsKeyType = CKK_DES;
      break;

    case CSSM_ALGID_3DES_2KEY:
      PkcsKeyType = CKK_DES2;
      break;

    case CSSM_ALGID_3DES_3KEY:
      PkcsKeyType = CKK_DES3;
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_CAST:
      PkcsKeyType = CKK_CAST;
      break;

    case CSSM_ALGID_CAST3:
      PkcsKeyType = CKK_CAST3;
      break;

    case CSSM_ALGID_CAST5:
      PkcsKeyType = CKK_CAST5;
      break;

    case CSSM_ALGID_IDEA:
      PkcsKeyType = CKK_IDEA;
      break;

    case CSSM_ALGID_CDMF:
      PkcsKeyType = CKK_CDMF;
      break;

    case CSSM_ALGID_SKIPJACK:
      PkcsKeyType = CKK_SKIPJACK;
      break;

    case CSSM_ALGID_BATON:
      PkcsKeyType = CKK_BATON;
      break;

    case CSSM_ALGID_JUNIPER:
      PkcsKeyType = CKK_JUNIPER;
      break;

    case CSSM_ALGID_SSL3PreMasterGen:
      PkcsKeyType = CKK_GENERIC_SECRET;
      break;    
#endif

    case CSSM_ALGID_RSA_PKCS:
      PkcsKeyType = CKK_RSA;
      break;

    case CSSM_ALGID_DH:
      PkcsKeyType = CKK_DH;
      break;

    case CSSM_ALGID_DSA:
      PkcsKeyType = CKK_DSA;
      break;
      
#ifdef PKCS11_V20
    case CSSM_ALGID_ECDSA:
      PkcsKeyType = CKK_ECDSA;
      break;

    case CSSM_ALGID_MAYFLY:
      PkcsKeyType = CKK_MAYFLY;
      break;
#endif

    default:
      return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);
      break;
  
  }

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

#ifdef PKCS11_V20
  if ((PkcsStatus = C_UnwrapKey(pMsmSession->PkcsSessionHandle, 
                &PkcsMechanism,
                hPkcsUnwrappingKey,
                pCssmWrappedKey->KeyData.Data,
                pCssmWrappedKey->KeyData.Length,
                PkcsTemplate,
                ii,
                &hPkcsUnwrappedKey)) != CKR_OK)
#else
  if ((PkcsStatus = C_UnwrapKey(pMsmSession->PkcsSessionHandle, 
                &PkcsMechanism,
                hPkcsUnwrappingKey,
                pCssmWrappedKey->KeyData.Data,
                (CK_USHORT) pCssmWrappedKey->KeyData.Length,
                PkcsTemplate,
                (CK_USHORT)ii,
                &hPkcsUnwrappedKey)) != CKR_OK)
#endif
    return SetErr(PkcsStatus);

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

  *((CK_OBJECT_HANDLE*)pCssmUnwrappedKey->KeyData.Data) = hPkcsUnwrappedKey;

  SetupKeyHeader(
    &pCssmUnwrappedKey->KeyHeader,
    CSSM_KEYBLOB_REFERENCE,               /* See BlobType #define's */
    CSSM_KEYBLOB_REF_FORMAT_INTEGER,          /* Raw or Reference format */
    pCssmWrappedKey->KeyHeader.AlgorithmId,       /* Algoritm ID of key */
    pCssmWrappedKey->KeyHeader.KeyClass,        /* Public/Private/Secret etc. */
    pCssmWrappedKey->KeyHeader.KeySizeInBits,     /* Size of actual key in bits */
    CssmUnwrappedKeyAttr,         /* Attribute flags */
    pCssmWrappedKey->KeyHeader.KeyUsage,        /* Key use flags */
    &pCssmWrappedKey->KeyHeader.StartDate,        /* Effective date of key */
    &pCssmWrappedKey->KeyHeader.EndDate,        /* Expiration date of key */
    CSSM_ALGID_NONE,                  /* Wrap Algo */
    CSSM_ALGMODE_NONE);                 /* Wrap Mode */
  
  return CSSM_OK;
}



/*****************************************************************************
 * Function: DeriveKey 
 * 
 * Derive a session key from another key and/or data.
 *
 * Input:
 *  CssmCSPHandle     - Attach session handle 
 *  CssmCCHandle      - Context handle
 *  pCssmContext      - Pointer to context 
 *  pCssmBaseKey      - Base key
 *  pCssmParam        - Base param
 *  CssmDerivedKeyUsage   - Derived key's key usage
 *  CssmDerivedKeyAttr    - Derived key's key attribute
 *  pCssmDerivedKeyLabel  - Derived key's key label
 *   
 * Output:
 *  pCssmDerivedKey     - Derived key if successful
 *   
 * Returns:
 *  CSSM_OK         - Successful      
 *  CSSM_FAIL       - Failed
 *
 */

CSSM_RETURN CSSMAPI DeriveKey(
  CSSM_CSP_HANDLE CssmCSPHandle,
    CSSM_CC_HANDLE CssmCCHandle,
    const CSSM_CONTEXT_PTR pCssmContext,
    const CSSM_KEY_PTR pCssmBaseKey,
    CSSM_DATA_PTR pCssmParam,
    uint32 CssmDerivedKeyUsage,
    uint32 CssmDerivedKeyAttr,
  const CSSM_DATA_PTR pCssmDerivedKeyLabel,
    CSSM_KEY_PTR pCssmDerivedKey)
{

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmAlgIdAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyLengthAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmSeedAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmPassPhraseAttr;
  
  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsBaseKey;
  CK_OBJECT_HANDLE      hPkcsDerivedKey;


  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         bMsmLabel = FALSE;
  CSSM_BOOL         bMsmKeyUsage = FALSE;
  CSSM_BOOL         bMsmKeyAttr = FALSE;
  CSSM_BOOL         bMsmStartDate = FALSE;
  CSSM_BOOL         bMsmEndDate = FALSE;



//
//  Common Key Data
//
  
// Common Object Attrs  
//  CK_OBJECT_CLASS       PkcsObjectClass;    // Required, supplied by C_GenerateKey
//  CK_BBOOL          PkcsToken;        // FALSE
//  CK_BBOOL          PkcsPrivate;      // FALSE
//  CK_BBOOL          PkcsModifiable;     // TRUE
//  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
//  CK_BBOOL          PkcsExtractable;    // Token default
//  CK_BBOOL          PkcsAlwaysSensitive;  // Not setable
//  CK_BBOOL          PkcsNeverExtractable; // Not setable
//  CK_CHAR_PTR         pPkcsValue;       // Not setable
  CK_ULONG          PkcsValueLen;     // Required when variable

  CK_ATTRIBUTE        PkcsTemplate[PKCS_TOTAL_SECRET_ATTRS];

#ifdef PKCS11_V20
  CK_KEY_DERIVATION_STRING_DATA PkcsStringData;
  CK_EXTRACT_PARAMS       PkcsExtractParams;
#endif

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

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

  if (pCssmContext->ContextType != CSSM_ALGCLASS_DERIVEKEY)
    return SetErr(CSSM_CSP_INVALID_CONTEXT);

  if (pCssmBaseKey == NULL || pCssmDerivedKey == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  if ((pCssmDerivedKey->KeyData.Data == NULL && pCssmDerivedKey->KeyData.Length != 0) ||
    (pCssmDerivedKey->KeyData.Data != NULL && pCssmDerivedKey->KeyData.Length == 0))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
  
  if (pCssmBaseKey->KeyData.Data == NULL || pCssmBaseKey->KeyData.Length == 0)
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);

  

  pCssmAlgIdAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ALG_ID);
  if (pCssmAlgIdAttr != NULL)
  {
    switch (pCssmAlgIdAttr->Attribute.Uint32)
    {
      case CSSM_ALGID_GenericSecret:
        PkcsKeyType = CKK_GENERIC_SECRET;
        break;

      case CSSM_ALGID_RC2:
        PkcsKeyType = CKK_RC2;
        break;

      case CSSM_ALGID_RC4:
        PkcsKeyType = CKK_RC4;
        break;

#ifdef PKCS11_V20
      case CSSM_ALGID_RC5:
        PkcsKeyType = CKK_RC5;
        break;
#endif

      case CSSM_ALGID_DES:
        PkcsKeyType = CKK_DES;
        break;

      case CSSM_ALGID_3DES_2KEY:
        PkcsKeyType = CKK_DES2;
        break;

      case CSSM_ALGID_3DES_3KEY:
        PkcsKeyType = CKK_DES3;
        break;
        
#ifdef PKCS11_V20
      case CSSM_ALGID_CAST:
        PkcsKeyType = CKK_CAST;
        break;

      case CSSM_ALGID_CAST3:
        PkcsKeyType = CKK_CAST3;
        break;

      case CSSM_ALGID_CAST5:
        PkcsKeyType = CKK_CAST5;
        break;

      case CSSM_ALGID_IDEA:
        PkcsKeyType = CKK_IDEA;
        break;

      case CSSM_ALGID_SKIPJACK:
        PkcsKeyType = CKK_SKIPJACK;
        break;

      case CSSM_ALGID_BATON:
        PkcsKeyType = CKK_BATON;
        break;

      case CSSM_ALGID_JUNIPER:
        PkcsKeyType = CKK_JUNIPER;
        break;

      case CSSM_ALGID_CDMF:
        PkcsKeyType = CKK_CDMF;
        break;
#endif

      default:
        return SetErr(CSSM_CSP_INVALID_ALGORITHM);
    }
      
    PkcsTemplate[ii].type = CKA_KEY_TYPE;
    PkcsTemplate[ii].pValue = &PkcsKeyType;
#ifdef PKCS11_V20
    PkcsTemplate[ii++].ulValueLen = sizeof(PkcsKeyType);
#else
    PkcsTemplate[ii++].usValueLen = sizeof(PkcsKeyType);
#endif

  }
  else
    return SetErr(CSSM_CSP_PARAM_NO_ALG_ID);

  pCssmKeyLengthAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY_LENGTH);
  if (pCssmKeyLengthAttr != NULL)
  {
    PkcsValueLen = pCssmKeyLengthAttr->Attribute.Uint32;

    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
  }
  else
    return SetErr(CSSM_CSP_PARAM_NO_KEY_LENGTH);


  pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
  pCssmSeedAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_SEED);
  pCssmPassPhraseAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_PASSPHRASE);


  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_DH:
      PkcsMechanism.mechanism = CKM_DH_PKCS_DERIVE;
      PkcsMechanism.pParameter = pCssmParam->Data;
#ifdef PKCS11_V20
      PkcsMechanism.ulParameterLen = pCssmParam->Length;
#else
      PkcsMechanism.usParameterLen = (CK_USHORT) pCssmParam->Length;
#endif
      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_MD2:
      PkcsMechanism.mechanism = CKM_MD2_KEY_DERIVATION;
      break;

    case CSSM_ALGID_MD5:
      PkcsMechanism.mechanism = CKM_MD5_KEY_DERIVATION;
      break;

    case CSSM_ALGID_SHA1:
      PkcsMechanism.mechanism = CKM_SHA1_KEY_DERIVATION;
      break;

    case CSSM_ALGID_ConcatBaseAndKey:
      PkcsMechanism.mechanism = CKM_CONCATENATE_BASE_AND_KEY;
      PkcsMechanism.pParameter = pCssmParam->Data;
      PkcsMechanism.ulParameterLen = pCssmParam->Length;
      break;

    case CSSM_ALGID_ConcatBaseAndData:
      PkcsMechanism.mechanism = CKM_CONCATENATE_BASE_AND_DATA;
      PkcsStringData.pData = pCssmParam->Data;
      PkcsStringData.ulLen = pCssmParam->Length;
      PkcsMechanism.pParameter = &PkcsStringData;
      PkcsMechanism.ulParameterLen = sizeof(PkcsStringData);

      break;

    case CSSM_ALGID_ConcatDataAndBase:
      PkcsMechanism.mechanism = CKM_CONCATENATE_DATA_AND_BASE;
      PkcsStringData.pData = pCssmParam->Data;
      PkcsStringData.ulLen = pCssmParam->Length;
      PkcsMechanism.pParameter = &PkcsStringData;
      PkcsMechanism.ulParameterLen = sizeof(PkcsStringData);
      break;

    case CSSM_ALGID_XORBaseAndData:
      PkcsMechanism.mechanism = CKM_XOR_BASE_AND_DATA;
      PkcsStringData.pData = pCssmParam->Data;
      PkcsStringData.ulLen = pCssmParam->Length;
      PkcsMechanism.pParameter = &PkcsStringData;
      PkcsMechanism.ulParameterLen = sizeof(PkcsStringData);
      break;

    case CSSM_ALGID_ExtractFromKey:
      PkcsMechanism.mechanism = CKM_EXTRACT_KEY_FROM_KEY;
      PkcsExtractParams = *((CK_EXTRACT_PARAMS*) pCssmParam->Data);
      PkcsMechanism.pParameter = &PkcsExtractParams;
      PkcsMechanism.ulParameterLen = sizeof(PkcsExtractParams);
      break;
#endif    
    default:
      return SetErr(CSSM_CSP_INVALID_ALGORITHM);
      break;
  
  }


  hPkcsBaseKey = *((CK_OBJECT_HANDLE*)pCssmBaseKey->KeyData.Data); 

  if ((PkcsStatus = C_DeriveKey(pMsmSession->PkcsSessionHandle,
                  &PkcsMechanism,
                  hPkcsBaseKey,
                  PkcsTemplate, 
                  ii,
                  &hPkcsDerivedKey)) != 0)
    return SetErr(PkcsStatus);


  pCssmDerivedKey->KeyData.Length = sizeof(hPkcsDerivedKey);
  if (pCssmDerivedKey->KeyData.Data == NULL)
    if ((pCssmDerivedKey->KeyData.Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                      1,
                                        pCssmDerivedKey->KeyData.Length)) == NULL)
    return SetErr(CSSM_CALLOC_FAILED);



  SetupKeyHeader(
    &pCssmDerivedKey->KeyHeader, 
    CSSM_KEYBLOB_REFERENCE,               /* See BlobType #define's */
    CSSM_KEYBLOB_REF_FORMAT_INTEGER,          /* Raw or Reference format */
    pCssmAlgIdAttr->Attribute.Uint32,         /* Algoritm ID of key */
    CSSM_KEYCLASS_SESSION_KEY,              /* Public/Private/Secret etc. */
    PkcsValueLen * 8,                 /* Size of actual key in bits */
    CssmDerivedKeyAttr,                 /* Attribute flags */
    CssmDerivedKeyUsage,                /* Key use flags */
    NULL,                       /* Effective date of key */
    NULL,                       /* Expiration date of key */
    CSSM_ALGID_NONE,                  /* Wrap Algo */ 
    CSSM_ALGMODE_NONE);                 /* Wrap Mode */

  
  return CSSM_OK;
}
