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



#include "pkcsprivate.h"

extern CSSM_SPI_MEMORY_FUNCS CssmMemFuncs;



/*****************************************************************************
 * Function: SetupContext - Set up a CSSM_CONTEXT with capability info.
 *
 * Input:
 *  PkcsMechType    - PKCS11 mechanism type 
 *  pCssmContext    - Context to be set up.
 *  pCssmAttr     - Attribute list of two, one for mode, one for key range
 *  pCssmRange      - Key range
 *  pPkcsMechInfo   - PKCS11 mechanism info
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  None
 *
 */

void SetupContext(
  CK_MECHANISM_TYPE PkcsMechType,
  CSSM_CONTEXT_PTR pCssmContext,
  CSSM_CONTEXT_ATTRIBUTE_PTR pCssmAttr,
  CSSM_RANGE_PTR pCssmRange,
  CK_MECHANISM_INFO_PTR pPkcsMechInfo)
{

#ifdef _DEBUG
        Message((LPCTSTR) "Enter SetupContext");
#endif

  pCssmContext->NumberOfAttributes          = 2;
  pCssmContext->ContextAttributes           = pCssmAttr;
  pCssmContext->ContextAttributes->AttributeType    = CSSM_ATTRIBUTE_MODE;
  pCssmContext->ContextAttributes->AttributeLength  = 0;
  pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_NONE;
  
  switch (PkcsMechType)
  {
    case CKM_RSA_PKCS_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RSA_PKCS;
      break;
      
    case CKM_RSA_PKCS:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->ContextType       = CSSM_ALGCLASS_ASYMMETRIC;   
      break;

    case CKM_RSA_9796:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RSA_ISO9796;
      break;

    case CKM_RSA_X_509:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RSA_RAW;
      break;

#ifdef PKCS11_V20
    /* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS are */
    /* new for v2.0.  They are mechanisms which hash and sign. */
    case CKM_MD2_RSA_PKCS:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2WithRSA;
      break;

    case CKM_MD5_RSA_PKCS:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5WithRSA;
      break;

    case CKM_SHA1_RSA_PKCS:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1WithRSA;
      break;
#endif

    case CKM_DSA_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DSA;
      break;

    case CKM_DSA:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DSA;
      break;

#ifdef PKCS11_V20
    case CKM_DSA_SHA1:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1;
      break;
#endif

    case CKM_DH_PKCS_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DH;
      break;

    case CKM_DH_PKCS_DERIVE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DH;
      break;

    case CKM_RC2_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      break;

    case CKM_RC2_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_RC2_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_RC2_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      break;

#ifdef PKCS11_V20
    /* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new to v2.0 */
    case CKM_RC2_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      break;

    case CKM_RC2_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC2;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;
#endif

    case CKM_RC4_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC4;
      break;

    case CKM_RC4:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC4;
      break;

    case CKM_DES_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      break;

    case CKM_DES_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_DES_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_DES_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      break;

#ifdef PKCS11_V20
    /* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new to v2.0 */
    case CKM_DES_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      break;

    case CKM_DES_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_DES;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;
#endif

    case CKM_DES2_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES_2KEY;
      break;

    case CKM_DES3_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES_3KEY;
      break;

    case CKM_DES3_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES;      
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_DES3_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_DES3_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES;
      break;

#ifdef PKCS11_V20
    /* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, */
    /* CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, CKM_CDMF_MAC_GENERAL, */
    /* and CKM_CDMF_CBC_PAD are new to v2.0 */
    case CKM_DES3_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES;
      break;

    case CKM_DES3_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_3DES;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_CDMF_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      break;

    case CKM_CDMF_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_CDMF_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_CDMF_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      break;

    case CKM_CDMF_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      break;

    case CKM_CDMF_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CDMF;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;
#endif

    case CKM_MD2:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DIGEST;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2;
      break;

#ifdef PKCS11_V20
    /* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new to v2.0 */
    case CKM_MD2_HMAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2;
      break;

    case CKM_MD2_HMAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2;
      break;
#endif

    case CKM_MD5:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DIGEST;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5;
      break;

#ifdef PKCS11_V20
    /* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new to v2.0 */
    case CKM_MD5_HMAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5;
      break;

    case CKM_MD5_HMAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5;
      break;
#endif

    case CKM_SHA_1:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DIGEST;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1;
      break;

#ifdef PKCS11_V20
    /* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new to v2.0 */
    case CKM_SHA_1_HMAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1;
      break;

    case CKM_SHA_1_HMAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1;
      break;

    /* All the following mechanisms are new to v2.0 */
    case CKM_CAST_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      break;

    case CKM_CAST_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_CAST_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_CAST_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      break;

    case CKM_CAST_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      break;

    case CKM_CAST_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_CAST3_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST3;
      break;

    case CKM_CAST3_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST3;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_CAST3_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST3;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_CAST3_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST3;
      break;

    case CKM_CAST3_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      break;

    case CKM_CAST3_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST3;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_CAST5_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST5;
      break;

    case CKM_CAST5_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_CAST5_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_CAST5_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST;
      break;

    case CKM_CAST5_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST5;
      break;

    case CKM_CAST5_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_CAST5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_RC5_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      break;

    case CKM_RC5_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_RC5_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_RC5_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      break;

    case CKM_RC5_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      break;

    case CKM_RC5_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_RC5;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_IDEA_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      break;

    case CKM_IDEA_ECB:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB;
      break;

    case CKM_IDEA_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC;
      break;

    case CKM_IDEA_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      break;

    case CKM_IDEA_MAC_GENERAL:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      break;

    case CKM_IDEA_CBC_PAD:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_IDEA;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_GENERIC_SECRET_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_GenericSecret;
      break;

    case CKM_CONCATENATE_BASE_AND_KEY:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ConcatBaseAndKey;
      break;

    case CKM_CONCATENATE_BASE_AND_DATA:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ConcatBaseAndData;
      break;

    case CKM_CONCATENATE_DATA_AND_BASE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ConcatDataAndBase;
      break;

    case CKM_XOR_BASE_AND_DATA:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_XORBaseAndData;
      break;

    case CKM_EXTRACT_KEY_FROM_KEY:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ExtractFromKey;
      break;

    case CKM_SSL3_PRE_MASTER_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SSL3PreMasterGen;
      break;

    case CKM_SSL3_MASTER_KEY_DERIVE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SSL3MasterDerive;
      break;

    case CKM_SSL3_KEY_AND_MAC_DERIVE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SSL3KeyAndMacDerive;
      break;

    case CKM_SSL3_MD5_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SSL3MD5;
      break;

    case CKM_SSL3_SHA1_MAC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_MAC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SSL3SHA1;
      break;

    case CKM_MD5_KEY_DERIVATION:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5;
      break;

    case CKM_MD2_KEY_DERIVATION:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2;
      break;

    case CKM_SHA1_KEY_DERIVATION:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1;
      break;

    case CKM_PBE_MD2_DES_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD2_PBE;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_PBE_MD5_DES_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5_PBE;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_PBE_MD5_CAST_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5_PBE;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_PBE_MD5_CAST3_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5_PBE;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_PBE_MD5_CAST5_CBC:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MD5_PBE;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBCPadIV8;
      break;

    case CKM_KEY_WRAP_LYNKS:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_WrapLynks;
      break;

    case CKM_KEY_WRAP_SET_OAEP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_ASYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_WrapSET_OAEP;
      break;

    /* Fortezza mechanisms */
    case CKM_SKIPJACK_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      break;

    case CKM_SKIPJACK_ECB64:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB64;
      break;

    case CKM_SKIPJACK_CBC64:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC64;
      break;

    case CKM_SKIPJACK_OFB64:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_OFB64;
      break;

    case CKM_SKIPJACK_CFB64:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CFB64;
      break;

    case CKM_SKIPJACK_CFB32:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CFB32;
      break;

    case CKM_SKIPJACK_CFB16:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CFB16;
      break;

    case CKM_SKIPJACK_CFB8:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CFB8;
      break;

    case CKM_SKIPJACK_WRAP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_WRAP; 
      break;

    case CKM_SKIPJACK_PRIVATE_WRAP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_PRIVATE_WRAP; 
      break;

    case CKM_SKIPJACK_RELAYX:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SKIPJACK;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_RELAYX; 
      break;

    case CKM_KEA_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_KEA;
      break;

    case CKM_KEA_KEY_DERIVE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_KEA;
      break;

    case CKM_FORTEZZA_TIMESTAMP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_FortezzaTimestamp;
      break;

    case CKM_BATON_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      break;

    case CKM_BATON_ECB128:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB128;
      break;

    case CKM_BATON_ECB96:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB96;
      break;

    case CKM_BATON_CBC128:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC128;
      break;

    case CKM_BATON_COUNTER:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_COUNTER;
      break;

    case CKM_BATON_SHUFFLE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_SHUFFLE;
      break;

    case CKM_BATON_WRAP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_BATON;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_WRAP;
      break;

    case CKM_ECDSA_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ECDSA;
      break;

    case CKM_ECDSA:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_ECDSA;
      break;

    case CKM_ECDSA_SHA1:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SIGNATURE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_SHA1WithECDSA;
      break;

    case CKM_MAYFLY_KEY_PAIR_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MAYFLY;
      break;

    case CKM_MAYFLY_KEY_DERIVE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DERIVEKEY;
      pCssmContext->AlgorithmType       = CSSM_ALGID_MAYFLY;
      break;

    case CKM_JUNIPER_KEY_GEN:
      pCssmContext->ContextType       = CSSM_ALGCLASS_KEYGEN;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      break;

    case CKM_JUNIPER_ECB128:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_ECB128;
      break;

    case CKM_JUNIPER_CBC128:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_CBC128;
      break;

    case CKM_JUNIPER_COUNTER:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_COUNTER;
      break;

    case CKM_JUNIPER_SHUFFLE:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_SHUFFLE;
      break;

    case CKM_JUNIPER_WRAP:
      pCssmContext->ContextType       = CSSM_ALGCLASS_SYMMETRIC;
      pCssmContext->AlgorithmType       = CSSM_ALGID_JUNIPER;
      pCssmContext->ContextAttributes->Attribute.Uint32 = CSSM_ALGMODE_WRAP;
      break;

    case CKM_FASTHASH:
      pCssmContext->ContextType       = CSSM_ALGCLASS_DIGEST;
      pCssmContext->AlgorithmType       = CSSM_ALGID_FASTHASH;
      break;
#endif

    default:
      pCssmContext->ContextType       = CSSM_ALGCLASS_NONE;
      pCssmContext->AlgorithmType       = CSSM_ALGID_NONE;
      break;
  } 

  (pCssmContext->ContextAttributes + 1)->AttributeType = CSSM_ATTRIBUTE_KEY_LENGTH_RANGE;
  (pCssmContext->ContextAttributes + 1)->AttributeLength = sizeof(CSSM_RANGE);
  (pCssmContext->ContextAttributes + 1)->Attribute.Range = pCssmRange;
  pCssmRange->Min = pPkcsMechInfo->ulMinKeySize;
  pCssmRange->Max = pPkcsMechInfo->ulMaxKeySize;

#ifdef _DEBUG
  Message((LPCTSTR) "Exit SetupContext");
#endif
  return;
}



/*****************************************************************************
 * Function: GetCspInfo - Set up SERVICE_INFO for CSP.
 *
 * Input:
 *  CssmModuleHandle  - Module handle 
 *  pCssmService    - CSP service info
 *  PkcsInfo      - PKCS11 info
 *  pPkcsSlotList   - PKCS11 slot list containing slot ids
 *  NumSubServices    - Number of subservices or slots
 *  CssmSubServiceID  - Subservice id
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN GetCspInfo(
  CSSM_MODULE_HANDLE CssmModuleHandle,
  CSSM_SERVICE_INFO_PTR pCssmService,
  CK_INFO PkcsInfo,
  CK_SLOT_ID_PTR pPkcsSlotList,
  uint32 NumSubServices,
  uint32 CssmSubServiceID)
{

  uint32              CssmRc = CSSM_OK;
  CSSM_CSPSUBSERVICE_PTR      pCssmCspSubService = NULL;
  CSSM_HARDWARE_CSPSUBSERVICE_INFO_PTR pCssmHardware;
  CSSM_CSP_WRAPPEDPRODUCT_INFO_PTR pCssmCspWrappedProduct = NULL;
  CSSM_CONTEXT_PTR        pCssmContextList = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR    pCssmAttrList = NULL;
  CSSM_RANGE_PTR          pCssmRange = NULL;

  CK_RV             PkcsRc = CKR_OK;
  CK_SLOT_INFO          PkcsSlotInfo;
  CK_TOKEN_INFO         PkcsTokenInfo;
  CK_MECHANISM_TYPE_PTR     pPkcsMechList = NULL;
#ifdef PKCS11_V20
  CK_ULONG            PkcsMechCount;
#else
  CK_USHORT           PkcsMechCount;
#endif
  CK_MECHANISM_INFO       PkcsMechInfo;

  uint32              indexSubService;
  uint32              indexMechanism;
  uint32              ii;
  uint32              jj;
  uint32              kk;
  uint32              length;
  uint32              SlotID;


#ifdef _DEBUG
        Message((LPCTSTR) "Enter GetCspInfo");
#endif

  if ((length = strlen(PKCSMSM_CSP_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
    length = CSSM_MODULE_STRING_SIZE;
  memcpy(pCssmService->Description, PKCSMSM_CSP_DESCRIPTION, length); 

  pCssmService->Type = CSSM_SERVICE_CSP;
  pCssmService->Flags = CSSM_SERVICE_ISWRAPPEDPRODUCT;
  pCssmService->NumberOfSubServices = NumSubServices;
  
  // Allocate pCssmService->CspSubServiceList, A1+
  if ((pCssmService->CspSubServiceList = CssmMemFuncs.calloc_func(
      CssmModuleHandle, NumSubServices, sizeof(CSSM_CSPSUBSERVICE))) == NULL)
    return SetErr(CSSM_CALLOC_FAILED);

  //
  // Set up each SubService, i.e., token
  //

  for (indexSubService = 0; indexSubService < NumSubServices; indexSubService++)
  {
    pCssmCspSubService = pCssmService->CspSubServiceList + indexSubService;

    if (CssmSubServiceID != CSSM_ALL_SUBSERVICES)
      SlotID = CssmSubServiceID;
    else
      SlotID = *(pPkcsSlotList + indexSubService);

    pCssmCspSubService->SubServiceId = SlotID;  

    if ((length = strlen(PKCSMSM_CSP_SUBSERVICE_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmCspSubService->Description, PKCSMSM_CSP_SUBSERVICE_DESCRIPTION, length); 

    pCssmCspSubService->CspFlags = CSSM_CSP_STORES_PRIVATE_KEYS |
                    CSSM_CSP_STORES_PUBLIC_KEYS |
                    CSSM_CSP_STORES_SESSION_KEYS;

    pCssmCspSubService->CspType = CSSM_CSP_HARDWARE;

    
    //
    // Get info of each slot
    //

    pCssmHardware = &pCssmCspSubService->HardwareCspSubService;
    if ((PkcsRc = C_GetSlotInfo(SlotID, &PkcsSlotInfo)) != CKR_OK)
      break;

    memcpy(pCssmHardware->ReaderDescription, PkcsSlotInfo.slotDescription, 
         sizeof(PkcsSlotInfo.slotDescription));

    memcpy(pCssmHardware->ReaderVendor, PkcsSlotInfo.manufacturerID, 
         sizeof(PkcsSlotInfo.manufacturerID));

#ifdef PKCS11_V20
    pCssmHardware->ReaderHardwareVersion.Major = PkcsSlotInfo.hardwareVersion.major;
    pCssmHardware->ReaderHardwareVersion.Minor = PkcsSlotInfo.hardwareVersion.minor;
    pCssmHardware->ReaderFirmwareVersion.Major = PkcsSlotInfo.firmwareVersion.major;
    pCssmHardware->ReaderFirmwareVersion.Minor = PkcsSlotInfo.firmwareVersion.minor;
#endif

    pCssmHardware->ReaderFlags = PkcsSlotInfo.flags;


    //
    // Get info of each token if present
    //

    if (PkcsSlotInfo.flags & CKF_TOKEN_PRESENT)
    {
      if ((PkcsRc = C_GetTokenInfo(SlotID, &PkcsTokenInfo)) != CKR_OK)
        break;  

      memcpy(pCssmHardware->TokenDescription, PkcsTokenInfo.model, 
           sizeof(PkcsTokenInfo.model));
      memcpy(pCssmHardware->TokenVendor, PkcsTokenInfo.manufacturerID, 
           sizeof(PkcsTokenInfo.manufacturerID));
      memcpy(pCssmHardware->TokenSerialNumber, PkcsTokenInfo.serialNumber, 
           sizeof(PkcsTokenInfo.serialNumber));

#ifdef PKCS11_V20
      pCssmHardware->TokenHardwareVersion.Major = PkcsTokenInfo.hardwareVersion.major;
      pCssmHardware->TokenHardwareVersion.Minor = PkcsTokenInfo.hardwareVersion.minor;
      pCssmHardware->TokenFirmwareVersion.Major = PkcsTokenInfo.firmwareVersion.major;
      pCssmHardware->TokenFirmwareVersion.Minor = PkcsTokenInfo.firmwareVersion.minor;
#endif

      pCssmHardware->TokenFlags = PkcsTokenInfo.flags;

#ifdef PKCS11_V20
      pCssmHardware->TokenMaxSessionCount = PkcsTokenInfo.ulMaxSessionCount;
      pCssmHardware->TokenOpenedSessionCount = PkcsTokenInfo.ulSessionCount;
      pCssmHardware->TokenMaxRWSessionCount = PkcsTokenInfo.ulMaxRwSessionCount;
      pCssmHardware->TokenOpenedRWSessionCount = PkcsTokenInfo.ulRwSessionCount;
#else
      pCssmHardware->TokenMaxSessionCount = PkcsTokenInfo.usMaxSessionCount;
      pCssmHardware->TokenOpenedSessionCount = PkcsTokenInfo.usSessionCount;
      pCssmHardware->TokenMaxRWSessionCount = PkcsTokenInfo.usMaxRwSessionCount;
      pCssmHardware->TokenOpenedRWSessionCount = PkcsTokenInfo.usRwSessionCount;
#endif

      pCssmHardware->TokenTotalPublicMem = PkcsTokenInfo.ulTotalPublicMemory;
      pCssmHardware->TokenFreePublicMem = PkcsTokenInfo.ulFreePublicMemory;
      pCssmHardware->TokenTotalPrivateMem = PkcsTokenInfo.ulTotalPrivateMemory;
      pCssmHardware->TokenFreePrivateMem = PkcsTokenInfo.ulFreePrivateMemory;

#ifdef PKCS11_V20
      pCssmHardware->TokenMaxPinLen = PkcsTokenInfo.ulMaxPinLen;
      pCssmHardware->TokenMinPinLen = PkcsTokenInfo.ulMinPinLen;
#else
      pCssmHardware->TokenMaxPinLen = PkcsTokenInfo.usMaxPinLen;
      pCssmHardware->TokenMinPinLen = PkcsTokenInfo.usMinPinLen;
#endif

#ifdef PKCS11_V20
      memcpy(pCssmHardware->TokenUTCTime, PkcsTokenInfo.utcTime, 
           sizeof(PkcsTokenInfo.utcTime));
#endif

      memcpy(pCssmHardware->UserLabel, PkcsTokenInfo.label, 
           sizeof(PkcsTokenInfo.label));


      //
      // Allocate and set up CapabilityList based on PkcsMechanism 
      //

      if ((PkcsRc = C_GetMechanismList(SlotID, NULL_PTR, &PkcsMechCount)) != CKR_OK)
        break;

      if (PkcsMechCount > 0)
      {
        do 
        {
          // Allocate pPkcsMechList, A2+. 
          if ((pPkcsMechList = calloc(PkcsMechCount, sizeof(CK_MECHANISM_TYPE))) == NULL)
          {
            CssmRc = CSSM_CALLOC_FAILED;
            break;
          }

          if ((PkcsRc = C_GetMechanismList(SlotID, pPkcsMechList, &PkcsMechCount)) != CKR_OK)
            break;

          // Allocate pCssmContextList, A3+
          if ((pCssmContextList = CssmMemFuncs.calloc_func(
                      CssmModuleHandle, 
                      PkcsMechCount, 
                      sizeof(CSSM_CONTEXT))) == NULL)
          {
            CssmRc = CSSM_CALLOC_FAILED;
            break;
          }

    

          for (indexMechanism = 0, kk = 0; kk < PkcsMechCount; indexMechanism++, kk++)
          {
            if ((PkcsRc = C_GetMechanismInfo(SlotID, 
                             *(pPkcsMechList+kk), 
                             &PkcsMechInfo)) != CKR_OK)
            {
              if (PkcsRc == CKR_MECHANISM_INVALID)
              {
                --indexMechanism;
                continue;
              }
              else
                break;
              
            }
            
            // Allocate pCssmAttrList, A4+
            if ((pCssmAttrList = CssmMemFuncs.calloc_func(
                    CssmModuleHandle, 
                    2, 
                    sizeof(CSSM_CONTEXT_ATTRIBUTE))) == NULL)
            {
              CssmRc = CSSM_CALLOC_FAILED;
              break;
            }

            // Allocate pCssmRange, A5+
            if ((pCssmRange = CssmMemFuncs.calloc_func(
                      CssmModuleHandle, 
                      PkcsMechCount, 
                      sizeof(CSSM_RANGE))) == NULL)
            {
              CssmMemFuncs.free_func(CssmModuleHandle, pCssmAttrList);  
              CssmRc = CSSM_CALLOC_FAILED;
              break;
            }

            SetupContext(*(pPkcsMechList + kk),
                   pCssmContextList + indexMechanism,
                   pCssmAttrList,
                   pCssmRange,
                   &PkcsMechInfo);
          } /* for (indexMechanism = 0; indexMechanism < PkcsMechCount; indexMechanism++) */

          if (CssmRc != CSSM_OK || PkcsRc != CKR_OK)
          {
            // Deallocate pCssmRange, pCssmAttrList up to point of failure
            for (jj = 0; jj < indexMechanism; jj++)
            {
              pCssmAttrList = (pCssmContextList + jj)->ContextAttributes;
              pCssmRange = (pCssmAttrList + 1)->Attribute.Range;
              // Free pCssmRange, Error A5-
              CssmMemFuncs.free_func(CssmModuleHandle, pCssmRange);
              // Free pCssmAttrList, Error A4-
              CssmMemFuncs.free_func(CssmModuleHandle, pCssmAttrList);
            }
          }

          pCssmHardware->NumberOfCapabilities = indexMechanism;
          pCssmHardware->CapabilityList = pCssmContextList;
      
        } while (FALSE);

        // Free pPkcsMechList, A2-
        if (pPkcsMechList != NULL)
          free(pPkcsMechList);

        if ((CssmRc != CSSM_OK || PkcsRc != CKR_OK) && pCssmContextList != NULL)
        {
          // Free pCssmContextList, Error A3-
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmContextList);
          break;
        }
        
        // Reset pointers for next 'SubService' loop thru
        pPkcsMechList = NULL;
        pCssmContextList = NULL;

      }
    } /* if (PkcsSlotInfo.flags & CKF_TOKEN_PRESENT) */


    //
    // Set up WrappProductInfo
    //

    pCssmCspWrappedProduct = &pCssmCspSubService->WrappedProduct;

#ifdef PKCS11_V20
    pCssmCspWrappedProduct->StandardVersion.Major = PkcsInfo.cryptokiVersion.major;
    pCssmCspWrappedProduct->StandardVersion.Minor = PkcsInfo.cryptokiVersion.minor;
#else
    pCssmCspWrappedProduct->StandardVersion.Major = PkcsInfo.version.major;
    pCssmCspWrappedProduct->StandardVersion.Minor = PkcsInfo.version.minor;
#endif

    if ((length = strlen(PKCS_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmCspWrappedProduct->StandardDescription, PKCS_DESCRIPTION, length);


#ifdef PKCS11_V20
    pCssmCspWrappedProduct->ProductVersion.Major = PkcsInfo.libraryVersion.major;
    pCssmCspWrappedProduct->ProductVersion.Minor = PkcsInfo.libraryVersion.minor;

    memcpy(pCssmCspWrappedProduct->ProductDescription, PkcsInfo.libraryDescription,
         sizeof(PkcsInfo.libraryDescription));
#endif


    memcpy(pCssmCspWrappedProduct->ProductVendor, PkcsInfo.manufacturerID,
         sizeof(PkcsInfo.manufacturerID));            

    pCssmCspWrappedProduct->ProductFlags = 0;

  } /* for (indexSubService = 0; indexSubService < NumSubServices; indexSubService++) */

  // Assert(pCssmService->CspSubServiceList != NULL)

  if (CssmRc != CSSM_OK || PkcsRc != CKR_OK)
  {
    // Must loop thru and free all previously set up SubService's  
    for (ii = 0; ii < indexSubService; ii++)
    {
      pCssmCspSubService = pCssmService->CspSubServiceList + ii;
      if ((pCssmContextList = pCssmCspSubService->HardwareCspSubService.CapabilityList) != NULL)
      {
        for (jj = 0; jj < pCssmCspSubService->HardwareCspSubService.NumberOfCapabilities; jj++)
        {
          pCssmAttrList = (pCssmContextList + jj)->ContextAttributes;
          pCssmRange = (pCssmAttrList + 1)->Attribute.Range;
          // Free pCssmRange, Error A5-
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmRange);
          // Free pCssmAttrList, Error A4-
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmAttrList);
        }
        // Free pCssmContextList, Error A3-
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmContextList);
      }
    }
    // Free pCssmService->CspSubServiceList, Error A1-
    CssmMemFuncs.free_func(CssmModuleHandle, pCssmService->CspSubServiceList);

    if (CssmRc != CSSM_OK)
      return SetErr(CssmRc);
    else
      return SetErr(PkcsRc);
  }

#ifdef _DEBUG
  Message((LPCTSTR) "Exit GetCspInfo");
#endif

  return CSSM_OK;

}



/*****************************************************************************
 * Function: FreeCspInfo - Free all substructures of a CSP service info.
 *
 * Input:
 *  CssmModuleHandle  - Module handle 
 *  pCssmService    - CSP service info
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  None
 *
 */

void FreeCspInfo(
  CSSM_MODULE_HANDLE CssmModuleHandle,
  CSSM_SERVICE_INFO_PTR pCssmService)
{

  CSSM_CSPSUBSERVICE_PTR      pCssmCspSubService = NULL;
  CSSM_CONTEXT_PTR        pCssmContextList = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR    pCssmAttrList = NULL;
  CSSM_RANGE_PTR          pCssmRange = NULL;

  uint32              ii;
  uint32              jj;


#ifdef _DEBUG
  Message((LPCTSTR) "Enter FreeCspInfo");
#endif


  if (pCssmService->Type != CSSM_SERVICE_CSP)
    return;

  if (pCssmService->CspSubServiceList != NULL)
  {
    for (ii = 0; ii < pCssmService->NumberOfSubServices; ii++)
    {
      pCssmCspSubService = pCssmService->CspSubServiceList + ii;
      
      if ((pCssmContextList = pCssmCspSubService->HardwareCspSubService.CapabilityList) != NULL)
      {
        for (jj = 0; jj < pCssmCspSubService->HardwareCspSubService.NumberOfCapabilities; jj++)
        {
          pCssmAttrList = (pCssmContextList + jj)->ContextAttributes;
          pCssmRange = (pCssmAttrList + 1)->Attribute.Range;
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmRange);
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmAttrList);
        }

        CssmMemFuncs.free_func(CssmModuleHandle, pCssmContextList);
      }
    }
  
    CssmMemFuncs.free_func(CssmModuleHandle, pCssmService->CspSubServiceList);
  }

#ifdef _DEBUG
  Message((LPCTSTR) "Exit FreeCspInfo");
#endif

  return;
}



/*****************************************************************************
 * Function: GetDlInfo - Set up SERVICE_INFO for DL.
 *
 * Input:
 *  CssmModuleHandle  - Module handle 
 *  pCssmService    - DL service info
 *  PkcsInfo      - PKCS11 info
 *  pPkcsSlotList   - PKCS11 slot list containing slot ids
 *  NumSubServices    - Number of subservices or slots
 *  CssmSubServiceID  - Subservice id
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN GetDlInfo(
  CSSM_MODULE_HANDLE CssmModuleHandle,
  CSSM_SERVICE_INFO_PTR pCssmService,
  CK_INFO PkcsInfo,
  CK_SLOT_ID_PTR pPkcsSlotList,
  uint32 NumSubServices,
  uint32 CssmSubServiceID)
{

  uint32              CssmRc = CSSM_OK;
  CSSM_DLSUBSERVICE_PTR     pCssmDlSubService = NULL;
  CSSM_DL_WRAPPEDPRODUCT_INFO_PTR pCssmDlWrappedProduct = NULL;
  CSSM_DLSUBSERVICE_PTR     pCssmDLSubServices = NULL;
  CSSM_DBINFO_PTR         pCssmDBInfos = NULL;

  CK_RV             PkcsRc = CKR_OK;
  CK_SLOT_INFO          PkcsSlotInfo;
  CK_MECHANISM_TYPE_PTR     pPkcsMechList = NULL;

  uint32              indexSubService;
  uint32              ii;
  uint32              length;
  uint32              SlotID;


#ifdef _DEBUG
  Message((LPCTSTR) "Enter GetDlInfo");
#endif

  if ((length = strlen(PKCSMSM_CSP_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
    length = CSSM_MODULE_STRING_SIZE;

  memcpy(pCssmService->Description, PKCSMSM_DL_DESCRIPTION, length); 

  pCssmService->Type = CSSM_SERVICE_DL;
  pCssmService->Flags = CSSM_SERVICE_ISWRAPPEDPRODUCT;
  pCssmService->NumberOfSubServices = NumSubServices;


  // Allocate pCssmService->DlSubServiceList, A1+
  if ((pCssmService->DlSubServiceList = CssmMemFuncs.calloc_func(
      CssmModuleHandle, NumSubServices, sizeof(CSSM_DLSUBSERVICE))) == NULL)
    return SetErr(CSSM_CALLOC_FAILED);


  //
  // Set up each SubService
  //

  for (indexSubService = 0; indexSubService < NumSubServices; indexSubService++)
  {
    pCssmDlSubService = pCssmService->DlSubServiceList + indexSubService;

    if (CssmSubServiceID != CSSM_ALL_SUBSERVICES)
      SlotID = CssmSubServiceID;
    else
      SlotID = *(pPkcsSlotList + indexSubService);

    pCssmDlSubService->SubServiceId = SlotID; 

    if ((length = strlen(PKCSMSM_DL_SUBSERVICE_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmDlSubService->Description, PKCSMSM_DL_SUBSERVICE_DESCRIPTION, length); 

    pCssmDlSubService->Type = CSSM_DL_PKCS11;
    
    pCssmDlSubService->AuthenticationMechanism = CSSM_AUTHENTICATION_PASSWORD;


    pCssmDlSubService->NumberOfRelOperatorTypes = 1;
    // Allocate pCssmDlSubService->RelOperatorTypes, A2+
    if ((pCssmDlSubService->RelOperatorTypes = CssmMemFuncs.calloc_func(
        CssmModuleHandle, 1, sizeof(CSSM_DB_OPERATOR))) == NULL)
    {
      CssmRc = CSSM_CALLOC_FAILED;
      break;
    }
    *(pCssmDlSubService->RelOperatorTypes) = CSSM_DB_EQUAL;


    pCssmDlSubService->NumberOfConjOperatorTypes = 1;
    // Allocate pCssmDlSubService->ConjOperatorTypes, A3+
    if ((pCssmDlSubService->ConjOperatorTypes = CssmMemFuncs.calloc_func(
        CssmModuleHandle, 1, sizeof(CSSM_DB_CONJUNCTIVE))) == NULL)
    {
      CssmRc = CSSM_CALLOC_FAILED;
      break;
    }
    *(pCssmDlSubService->ConjOperatorTypes) = CSSM_DB_AND;
    

    pCssmDlSubService->QueryLimitsSupported = FALSE;
    
    //
    // Get info of each slot
    //

    if ((PkcsRc = C_GetSlotInfo(SlotID, &PkcsSlotInfo)) != CKR_OK)
      break;

    //
    // Get info of token if present
    //
    
    if (PkcsSlotInfo.flags & CKF_TOKEN_PRESENT)
    {
      pCssmDlSubService->NumberOfDataStores = 1;
      
      // Allocate pCssmDlSubService->DataStoreInfo, A4+
      if ((pCssmDlSubService->DataStoreInfo = CssmMemFuncs.calloc_func(
          CssmModuleHandle, 1, sizeof(CSSM_DBINFO))) == NULL)
      {
        CssmRc = CSSM_CALLOC_FAILED;
        break;
      }

      pCssmDlSubService->DataStoreInfo->AuthenticationMechanism = CSSM_AUTHENTICATION_PASSWORD;
      pCssmDlSubService->DataStoreInfo->IsLocal = TRUE; 

      // Allocate pCssmDlSubService->DataStoreNames, A5+
      if ((pCssmDlSubService->DataStoreNames = CssmMemFuncs.calloc_func(
          CssmModuleHandle, 1, sizeof(CSSM_NAME_LIST))) == NULL)
      {
        CssmRc = CSSM_CALLOC_FAILED;
        break;
      }

    }
    else
    {
      pCssmDlSubService->NumberOfDataStores = 0;
    }


    //
    // Set up WrappProductInfo
    //

    pCssmDlWrappedProduct = &pCssmDlSubService->WrappedProduct;

#ifdef PKCS11_V20
    pCssmDlWrappedProduct->StandardVersion.Major = PkcsInfo.cryptokiVersion.major;
    pCssmDlWrappedProduct->StandardVersion.Minor = PkcsInfo.cryptokiVersion.minor;
#else
    pCssmDlWrappedProduct->StandardVersion.Major = PkcsInfo.version.major;
    pCssmDlWrappedProduct->StandardVersion.Minor = PkcsInfo.version.minor;
#endif

    if ((length = strlen(PKCS_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmDlWrappedProduct->StandardDescription, PKCS_DESCRIPTION, length);


#ifdef PKCS11_V20
    pCssmDlWrappedProduct->ProductVersion.Major = PkcsInfo.libraryVersion.major;
    pCssmDlWrappedProduct->ProductVersion.Minor = PkcsInfo.libraryVersion.minor;

    memcpy(pCssmDlWrappedProduct->ProductDescription, PkcsInfo.libraryDescription,
         sizeof(PkcsInfo.libraryDescription));
#endif

    memcpy(pCssmDlWrappedProduct->ProductVendor, PkcsInfo.manufacturerID,
         sizeof(PkcsInfo.manufacturerID));            

    pCssmDlWrappedProduct->ProductFlags = 0;

  } /* for (indexSubService = 0; indexSubService < NumSubServices; indexSubService++) */


  //
  // If error, free memory 
  //

  if (CssmRc != CSSM_OK || PkcsRc != CKR_OK)
  {
    // Assert (pCssmService->DlSubServiceList != NULL)

    for (ii = 0; ii <= indexSubService; ii++)
    {
      pCssmDlSubService = pCssmService->DlSubServiceList + ii;

      // Free pCssmDlSubService->DataStoreNames, A4-
      if (pCssmDlSubService->DataStoreInfo != NULL)
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmDlSubService->DataStoreNames);

      // Free pCssmDlSubService->DataStoreInfo, A4-
      if (pCssmDlSubService->DataStoreInfo != NULL)
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmDlSubService->DataStoreInfo);
      
      // Free pCssmDlSubService->ConjOperatorTypes, A3-
      if (pCssmDlSubService->ConjOperatorTypes != NULL)
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmDlSubService->ConjOperatorTypes);
      
      // Free pCssmDlSubService->RelOperatorTypes, A2-
      if (pCssmDlSubService->RelOperatorTypes != NULL)
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmDlSubService->RelOperatorTypes);
    } 

    // Free pCssmService->DlSubServiceList, A2-
    CssmMemFuncs.free_func(CssmModuleHandle, pCssmService->DlSubServiceList);

    if (CssmRc != CSSM_OK)
      return SetErr(CssmRc);
    else
      return SetErr(PkcsRc);
  }


#ifdef _DEBUG
  Message((LPCTSTR) "Exit GetDlInfo");
#endif

  return CSSM_OK;

}



/*****************************************************************************
 * Function: GetMsmInfo - Set up and return module info.
 *
 * Input:
 *  CssmModuleHandle    - Module handle 
 *  CssmServiceMask     - Service Mask of services requiring info
 *  CssmSubServiceID    - Subservice id
 *  CssmInfoLevel     - Only CSSM_INFO_LEVEL_ALL_ATTR is supported
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CSSM_MODULE_INFO_PTR  - Successful      
 *  NULL          - Failed
 *
 */

CSSM_MODULE_INFO_PTR CSSMAPI GetMsmInfo(
  CSSM_MODULE_HANDLE CssmModuleHandle,
  CSSM_SERVICE_MASK CssmServiceMask,
    uint32 CssmSubServiceID,
    CSSM_INFO_LEVEL CssmInfoLevel)
{

  uint32              CssmRc = CSSM_OK;
  CSSM_MODULE_INFO_PTR      pCssmModuleInfo = NULL;
  CSSM_SERVICE_INFO_PTR     pCssmService = NULL;

  CK_RV             PkcsRc = CKR_OK;
  CK_INFO             PkcsInfo;
  CK_SLOT_ID_PTR          pPkcsSlotList = NULL;
#ifdef PKCS11_V20
  CK_ULONG            PkcsSlotCount;
#else
  CK_USHORT           PkcsSlotCount;
#endif

  CSSM_SERVICE_MASK       LocalServiceMask;
  uint32              ii;
  uint32              length;
  uint32              NumServices;
  uint32              NumSubServices;

#ifdef _DEBUG
  Message((LPCTSTR) "Enter GetMsmInfo");
#endif


  //
  // Check parameters and set up needed info. 
  //

  NumServices = 0;
  LocalServiceMask = 0;

  if (CssmServiceMask == 0 || CssmServiceMask & CSSM_SERVICE_CSP)
  {
    LocalServiceMask |= CSSM_SERVICE_CSP;
    NumServices++;
  }

  if (CssmServiceMask == 0 || CssmServiceMask & CSSM_SERVICE_DL)
  {
    LocalServiceMask |= CSSM_SERVICE_DL;
    NumServices++;
  }

  if (NumServices == 0)
    return SetErrNull(CSSM_INVALID_SERVICE_MASK);

  if (CssmInfoLevel != CSSM_INFO_LEVEL_ALL_ATTR)
    return SetErrNull(CSSM_INVALID_INFO_LEVEL);


  //
  // Get Cryptoki info and slot list
  //

  if ((PkcsRc = C_GetInfo(&PkcsInfo)) != CKR_OK)    // Get first level Cryptoki info
    return SetErrNull(PkcsRc);
  
  if ((PkcsRc = C_GetSlotList(FALSE, NULL_PTR, &PkcsSlotCount)) != CKR_OK) // Get number of slots
    return SetErrNull(PkcsRc);

  if (PkcsSlotCount == 0)
    return SetErrNull(CSSM_CSP_NO_SLOT);

  // Allocate pPkcsSlotList, A1+
  if ((pPkcsSlotList = calloc(PkcsSlotCount, sizeof(CK_SLOT_ID))) == NULL)
    return SetErrNull(CSSM_CALLOC_FAILED);

  if ((PkcsRc = C_GetSlotList(FALSE, pPkcsSlotList, &PkcsSlotCount)) != CKR_OK)
  {
    // Free pPkcsSlotList, EA1-
    free(pPkcsSlotList);
    return SetErrNull(PkcsRc);
  }


  //
  // Verify SubServiceID and set up NumSubServices
  //

  if (CssmSubServiceID != CSSM_ALL_SUBSERVICES)
  {
    for (ii = 0; ii < PkcsSlotCount; ii++)
    {
      if (CssmSubServiceID == *(pPkcsSlotList + ii))
        break;
    }

    if (ii == PkcsSlotCount)
    {
      // Free pPkcsSlotList, EA1-
      free(pPkcsSlotList);  
      return SetErrNull(CSSM_INVALID_SUBSERVICEID);
    }
  }

  if (CssmSubServiceID == CSSM_ALL_SUBSERVICES)
    NumSubServices = PkcsSlotCount;
  else
    NumSubServices = 1;


  do 
  {

    //
    //
    // Allocate and set up pCssmModuleInfo, A2+   
    //
    //

    if ((pCssmModuleInfo = CssmMemFuncs.calloc_func(
        CssmModuleHandle, 1, sizeof(CSSM_MODULE_INFO))) == NULL)
    {
      CssmRc = CSSM_CALLOC_FAILED;
      break;
    }

    //
    // Set up ModuleInfo
    //

    pCssmModuleInfo->Version.Major = IBMPKCS11_MAJOR_VERSION;
    pCssmModuleInfo->Version.Minor = IBMPKCS11_MINOR_VERSION;

    pCssmModuleInfo->CompatibleCSSMVersion.Major = CSSM_MAJOR;
    pCssmModuleInfo->CompatibleCSSMVersion.Minor = CSSM_MINOR;

    if ((length = strlen(PKCSMSM_DESCRIPTION)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmModuleInfo->Description, PKCSMSM_DESCRIPTION, length);
    
    if ((length = strlen(PKCSMSM_VENDOR)) > CSSM_MODULE_STRING_SIZE)
      length = CSSM_MODULE_STRING_SIZE;
    memcpy(pCssmModuleInfo->Vendor, PKCSMSM_VENDOR, length); 

    pCssmModuleInfo->Flags = CSSM_MODULE_THREADSAFE | CSSM_MODULE_EXPORTABLE;

    pCssmModuleInfo->ServiceMask = LocalServiceMask;
    pCssmModuleInfo->NumberOfServices = NumServices;
    
    // Allocate pCssmModuleInfo->ServiceList, A3+
    if ((pCssmModuleInfo->ServiceList = CssmMemFuncs.calloc_func(
        CssmModuleHandle, NumServices, sizeof(CSSM_SERVICE_INFO))) == NULL)
    {
      CssmRc = CSSM_CALLOC_FAILED;
      break;
    }

  } while (0);


  if (CssmRc != CSSM_OK)
  {
    if (pCssmModuleInfo != NULL)
    {
      // Free pCssmModuleInfo->ServiceList, EA3-
      if (pCssmModuleInfo->ServiceList != NULL)
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo->ServiceList);

      // Free pCssmModuleInfo, EA2-
      CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo);
    }

    // Free pPkcsSlotList, EA1-
    free(pPkcsSlotList);
    return SetErrNull(CssmRc);
  }


  //
  // Set up ServiceInfo for CSP
  //

  pCssmService = pCssmModuleInfo->ServiceList;
  
  if (LocalServiceMask & CSSM_SERVICE_CSP)
  {
    if ((CssmRc = GetCspInfo(CssmModuleHandle, pCssmService, PkcsInfo, pPkcsSlotList, 
                 NumSubServices, CssmSubServiceID)) != CSSM_OK)
    {
      if (pCssmModuleInfo != NULL)
      {
        // Free pCssmModuleInfo->ServiceList, EA3-
        if (pCssmModuleInfo->ServiceList != NULL)
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo->ServiceList);

        // Free pCssmModuleInfo, EA2-
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo);
      }

      // Free pPkcsSlotList, EA1-
      free(pPkcsSlotList);
      return SetErrNull(CssmRc);

    }
    else
    {
      pCssmService++;
    } 
  }
  


  //
  // Set up ServiceInfo for DL
  //

  if (LocalServiceMask & CSSM_SERVICE_DL)
  {
    if ((CssmRc = GetDlInfo(CssmModuleHandle, pCssmService, PkcsInfo, pPkcsSlotList, 
                NumSubServices, CssmSubServiceID)) != CSSM_OK)
    {
      if (pCssmModuleInfo != NULL)
      {
        // Free Csp substructures
        FreeCspInfo(CssmModuleHandle, pCssmModuleInfo->ServiceList);
        
        // Free pCssmModuleInfo->ServiceList, EA3-
        if (pCssmModuleInfo->ServiceList != NULL)
          CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo->ServiceList);

        // Free pCssmModuleInfo, EA2-
        CssmMemFuncs.free_func(CssmModuleHandle, pCssmModuleInfo);
      }

      // Free pPkcsSlotList, EA1-
      free(pPkcsSlotList);
      return SetErrNull(CssmRc);

    }
  }
    
  //
  // If we get here, all is well
  //

  free(pPkcsSlotList);

#ifdef _DEBUG
  Message((LPCTSTR) "Exit GetMsmInfo");
#endif

  return pCssmModuleInfo;

}



