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


//------------------------------------------------------------
// includes
//------------------------------------------------------------

#include <limits.h>
#include "jkl.h"
#include "jklutil.h"


// temporary resting place of useful constants

// Known CDSA CSP addins

static CSSM_GUID IBM_CYLINK_CSP_GUID = { 0xba047041, 0x31f4, 0x11d2, { 0xb1, 0xd4, 0x0, 0x20, 0x35, 0x68, 0xb, 0x0 } };
static CSSM_GUID IBM_BSAFE_CSP_GUID  = { 0xdda0c1e0, 0x7b73, 0x11d0, { 0x8e, 0x0c, 0x0, 0x04, 0xac, 0x60, 0x2b, 0x18 } };
static CSSM_GUID JONAH_TP_GUID       = { 0x7e25d1e0, 0x2658, 0x11d2, { 0x99, 0xbd, 0x0, 0x4, 0xac, 0xe8, 0x48, 0x5b } };

// supported signature algorithms

static unsigned long md2WithRSAEncryption_val[7]       = {1,2,840,113549,1,1,2};
static unsigned long md5WithRSAEncryption_val[7]       = {1,2,840,113549,1,1,4};
static unsigned long sha1WithRSAEncryption_val[7]      = {1,2,840,113549,1,1,5};
static unsigned long dsaWithSHA1_val[6]                = {1,2,840,10040,4,3};

// supported public key algorithms (dsa_alt used by BSAFE for DSA public key)

static unsigned long rsaEncryption_val[7]              = {1,2,840,113549,1,1,1};
static unsigned long dsa_val[6]                        = {1,2,840,10040,4,1};
static unsigned long dsa_alt_val[6]                    = {1,3,14,3,2,12};

// temporary resting place of useful constants


// workaround for buffer_t needs CSSM_MEMORYFUNCS constructor

void* xmalloc_func(uint32 handle, uint32 size);
void xfree_func(uint32 handle, void* memPtr);
void* xrealloc_func(uint32 handle, void* memPtr, uint32 size);
void* xcalloc_func(uint32 handle, uint32 num, uint32 size);


//*****************************************************************************
//
// ASN to CSSM Conversion Routines
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_asn_to_cssm
//------------------------------------------------------------

uint32
JKL_asn_to_cssm(const asn_octetstring& desKey,
                int numOfKeys,
                CSSM_KEY& cssmSecretKey,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   memset(&cssmSecretKey, 0, sizeof(CSSM_KEY));

   uint32 algID = compute3DESAlgorithm(numOfKeys);

   // extract raw DES key from octet string
      
   unsigned char* value;
   uint32 numOfBytes;
   if ((status = desKey.get_value(value, numOfBytes)) != 0)
      return status;

   // construct CSSM_KEY

   cssmSecretKey.KeyHeader.HeaderVersion   = CSSM_KEYHEADER_VERSION;
   cssmSecretKey.KeyHeader.CspId           = cssmGUID;
   cssmSecretKey.KeyHeader.AlgorithmId     = algID;
   cssmSecretKey.KeyHeader.KeySizeInBits   = 64 * numOfKeys;
   cssmSecretKey.KeyHeader.KeyClass        = CSSM_KEYCLASS_SESSION_KEY;
   cssmSecretKey.KeyHeader.KeyUsage        = CSSM_KEYUSE_ANY;
   cssmSecretKey.KeyHeader.WrapAlgorithmId = CSSM_ALGID_NONE;
   cssmSecretKey.KeyData.Data              = (uint8*)DefaultMalloc(numOfBytes);
   cssmSecretKey.KeyData.Length            = numOfBytes;
   memcpy(cssmSecretKey.KeyData.Data, value, numOfBytes);

   // CSP-specific stuff

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      cssmSecretKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW_BERDER;
      cssmSecretKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_BSAFE;
   } 
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      cssmSecretKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW;
      cssmSecretKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_NONE;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }

   return status;
}


//------------------------------------------------------------
// function: JKL_asn_to_cssm
//------------------------------------------------------------

uint32 
JKL_asn_to_cssm(const SubjectPublicKeyInfo& subjectPublicKeyInfo,
                CSSM_KEY& cssmPublicKey,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   memset(&cssmPublicKey, 0, sizeof(CSSM_KEY));

   // Check: what type of public-key cryptosystem is this?

   if ( subjectPublicKeyInfo.algorithm.algorithm.is_equal(rsaEncryption_val, 7) )
   {
      cssmPublicKey.KeyHeader.AlgorithmId  = CSSM_ALGID_RSA_PKCS;
   }
   else if ( subjectPublicKeyInfo.algorithm.algorithm.is_equal(dsa_val, 6) ||
             subjectPublicKeyInfo.algorithm.algorithm.is_equal(dsa_alt_val, 6) )
   {
     cssmPublicKey.KeyHeader.AlgorithmId  = CSSM_ALGID_DSA;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
      
   // compute key size 

   long keySizeInBits;

   if ((status = JKL_ComputeKeySizeInBits(subjectPublicKeyInfo, keySizeInBits)) != 0)
      return status;

   // CSP common stuff

   cssmPublicKey.KeyHeader.HeaderVersion   = CSSM_KEYHEADER_VERSION;
   cssmPublicKey.KeyHeader.CspId           = cssmGUID;
   cssmPublicKey.KeyHeader.KeySizeInBits   = keySizeInBits;
   cssmPublicKey.KeyHeader.KeyClass        = CSSM_KEYCLASS_PUBLIC_KEY;
   cssmPublicKey.KeyHeader.KeyUsage        = CSSM_KEYUSE_SIGN|CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   cssmPublicKey.KeyHeader.WrapAlgorithmId = CSSM_ALGID_NONE;

   // CSP-specific stuff

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      memory_funcs_t mems(0,xmalloc_func,xfree_func,xrealloc_func,xcalloc_func);
      buffer_t encoding(mems);
   
      if ((status = subjectPublicKeyInfo.write(encoding)) != 0)
         return status;

      cssmPublicKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW_BERDER;
      cssmPublicKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_BSAFE;

      cssmPublicKey.KeyData.Data              = encoding.data;
      cssmPublicKey.KeyData.Length            = encoding.data_len;

      encoding.detach();
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      cssmPublicKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW;
      cssmPublicKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_NONE;

      DssParms dssParms;
      asn_integer dsaPublicKey;

      if ((status = JKL_ExtractDSAPublicKey(subjectPublicKeyInfo,
                                            dssParms,
                                            dsaPublicKey)) != 0)
         return status;
      
      // Populate Cylink CSSM_DATA representation of public key

      if ((status = asn_to_cssm(dssParms, dsaPublicKey, cssmPublicKey.KeyData)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_asn_to_cssm
//------------------------------------------------------------

uint32 
JKL_asn_to_cssm(const PrivateKeyInfo& privateKeyInfo,
                const SubjectPublicKeyInfo& subjectPublicKeyInfo,
                CSSM_KEY& cssmPrivateKey,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   memset(&cssmPrivateKey, 0, sizeof(CSSM_KEY));

   // Check: what type of public-key cryptosystem is this?

   if ( privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(rsaEncryption_val, 7) )
   {
      cssmPrivateKey.KeyHeader.AlgorithmId  = CSSM_ALGID_RSA_PKCS;
   }
   else if ( privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(dsa_val, 6) ||
             privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(dsa_alt_val, 6) )
   {
      cssmPrivateKey.KeyHeader.AlgorithmId  = CSSM_ALGID_DSA;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   
   // compute key size 

   long keySizeInBits;

   if ((status = JKL_ComputeKeySizeInBits(subjectPublicKeyInfo, keySizeInBits)) != 0)
      return status;

   // CSP common stuff

   cssmPrivateKey.KeyHeader.HeaderVersion   = CSSM_KEYHEADER_VERSION;
   cssmPrivateKey.KeyHeader.CspId           = cssmGUID;
   cssmPrivateKey.KeyHeader.KeyClass        = CSSM_KEYCLASS_PRIVATE_KEY;
   cssmPrivateKey.KeyHeader.KeySizeInBits   = keySizeInBits;
   cssmPrivateKey.KeyHeader.KeyUsage        = CSSM_KEYUSE_SIGN|CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   cssmPrivateKey.KeyHeader.WrapAlgorithmId = CSSM_ALGID_NONE;

   // CSP-specific stuff

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      memory_funcs_t mems(0,xmalloc_func,xfree_func,xrealloc_func,xcalloc_func);
      buffer_t encoding(mems);
   
      if ((status = privateKeyInfo.write(encoding)) != 0)
         return status;
   
      cssmPrivateKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW_BERDER;
      cssmPrivateKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_BSAFE;
      cssmPrivateKey.KeyHeader.KeyClass        = CSSM_KEYCLASS_PRIVATE_KEY;

      cssmPrivateKey.KeyData.Data              = encoding.data;
      cssmPrivateKey.KeyData.Length            = encoding.data_len;

      encoding.detach();
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      cssmPrivateKey.KeyHeader.BlobType        = CSSM_KEYBLOB_RAW;
      cssmPrivateKey.KeyHeader.Format          = CSSM_KEYBLOB_RAW_FORMAT_NONE;
      cssmPrivateKey.KeyHeader.WrapAlgorithmId = CSSM_ALGID_NONE;

      // extract DSA private key

      DssPrivateParms dssPrivateParms;
      DssPrivateKey privatekey;

      if ((status = JKL_ExtractDSAPrivateKey(privateKeyInfo, 
                                             dssPrivateParms, 
                                             privatekey)) != 0)
         return status;

      // extract DSA public key

      DssParms dssParms;  // unused
      asn_integer dsaPublicKey;

      if ((status = JKL_ExtractDSAPublicKey(subjectPublicKeyInfo,
                                            dssParms,
                                            dsaPublicKey)) != 0)
         return status;

      // Populate Cylink CSSM_DATA representation of private key

      if ((status = asn_to_cssm(dssPrivateParms.p,
                                dssPrivateParms.q,
                                dssPrivateParms.g,
                                dsaPublicKey,
                                privatekey.x,
                                cssmPrivateKey.KeyData)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }

   return status;
}


//------------------------------------------------------------
// function: JKL_asn_to_cssm
//------------------------------------------------------------

uint32
JKL_asn_to_cssm(const AlgorithmIdentifier& algorithmIdentifier,
                CSSM_ALGORITHMS& cssmSignatureAlgorithmID)
{
   uint32 status = 0;

   if ( algorithmIdentifier.algorithm.is_equal(dsaWithSHA1_val, 6) )
   {
      cssmSignatureAlgorithmID = CSSM_ALGID_SHA1WithDSA;
   } 
   else if ( algorithmIdentifier.algorithm.is_equal(md5WithRSAEncryption_val, 7) )
   {
      cssmSignatureAlgorithmID = CSSM_ALGID_MD5WithRSA;
   } 
   else if ( algorithmIdentifier.algorithm.is_equal(md2WithRSAEncryption_val, 7) )
   {
      cssmSignatureAlgorithmID = CSSM_ALGID_MD2WithRSA;
   }
   else if ( algorithmIdentifier.algorithm.is_equal(sha1WithRSAEncryption_val, 7) )
   {
      cssmSignatureAlgorithmID = CSSM_ALGID_SHA1WithRSA;
   }
   else
   {
      cssmSignatureAlgorithmID = CSSM_ALGID_NONE;
      status = CSSM_CSP_OPERATION_UNSUPPORTED;
   }

   return status;
}


//------------------------------------------------------------
// function: JKL_asn_to_cssm
//------------------------------------------------------------

uint32
JKL_asn_to_cssm(const asn_bitstring& signature,
                CSSM_DATA& cssmSignature,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   // extract bit string (same for BSAFE and Cylink)

   size_t numOfBits;
   size_t numOfBytes;
   unsigned char* p;

   if ((status = signature.get_value(p, numOfBits)) != 0)
      return status;
   
   // compute number of bytes; add one if not even multiple of CHAR_BIT
   
   numOfBytes = numOfBits/CHAR_BIT;
   if (numOfBits % CHAR_BIT)
      numOfBytes++;

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      // BSAFE: contents of BIT STRING is signature

      cssmSignature.Data   = (uint8*)DefaultMalloc(numOfBytes);
      cssmSignature.Length = numOfBytes;
      memcpy(cssmSignature.Data, p, numOfBytes);
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      r_buffer_t shallowCopy;

      shallowCopy.data     = p;
      shallowCopy.data_len = numOfBytes;

      DssSigValue dsaSignature;
      if ((status = dsaSignature.read(shallowCopy)) != 0)
         return status;

      if ((status = asn_to_cssm(dsaSignature, cssmSignature)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//*****************************************************************************
//
// CSSM to ASN Conversion Routines
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_cssm_to_asn
//------------------------------------------------------------

uint32
JKL_cssm_to_asn(const CSSM_DATA& cssmSignature,
                asn_bitstring& signature,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      // BSAFE CSP returns X.509 DER BIT STRING

      r_buffer_t signatureBuffer;
      signatureBuffer.data     = cssmSignature.Data;
      signatureBuffer.data_len = cssmSignature.Length;
      if ((status = signature.set_value(signatureBuffer.data,signatureBuffer.data_len*8)) != 0)
         return status;
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      //------------------------------------------------------------
      // Cylink CSP returns r (20 bytes), s (20 bytes)
      // Must copy buffer because we need to reverse order of bytes
      //------------------------------------------------------------

      CSSM_DATA cssmScratchData;
      copy_cssm_data(cssmScratchData, cssmSignature);

      DssSigValue dsaSignature;
      if ((status = cssm_to_asn(cssmScratchData, dsaSignature)) != 0)
         return status;
      buffer_t signatureBuffer;
      if ((status = dsaSignature.write(signatureBuffer)) != 0)
         return status;
      if ((status = signature.set_value(signatureBuffer.data,signatureBuffer.data_len*8)) != 0)
         return status;

      JKL_FreeData(cssmScratchData);
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_cssm_to_asn
//------------------------------------------------------------

uint32
JKL_cssm_to_asn(const CSSM_KEY& cssmPublicKey,
                SubjectPublicKeyInfo& subjectPublicKeyInfo)
{
   uint32 status = 0;

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmPublicKey.KeyHeader.CspId, IBM_BSAFE_CSP_GUID) )
   {
      // BSAFE CSP returns X.509 DER SubjectPublicKeyInfo

      r_buffer_t keyBuffer;

      keyBuffer.data     = cssmPublicKey.KeyData.Data;
      keyBuffer.data_len = cssmPublicKey.KeyData.Length;
      if ((status = subjectPublicKeyInfo.read(keyBuffer)) != 0)
         return status;
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmPublicKey.KeyHeader.CspId, IBM_CYLINK_CSP_GUID) )
   {

      //--------------------
      // Cylink CSP returns (p,q,g,y) as (length/value) pairs
      //--------------------

      CSSM_DATA cssmScratchData;
      copy_cssm_data(cssmScratchData, cssmPublicKey.KeyData);

      DssParms dssParms;
      asn_integer dsaPublicKey;
      if ((status = cssm_to_asn(cssmScratchData, dssParms, dsaPublicKey)) != 0)
         return status;

      // set OID

#ifdef BSAFE_COMPATIBILITY
      if ((status = subjectPublicKeyInfo.algorithm.algorithm.set_value(dsa_alt_val, 6)) != 0)
#else
      if ((status = subjectPublicKeyInfo.algorithm.algorithm.set_value(dsa_val, 6)) != 0)
#endif
         return status;

      // set parameters

      buffer_t paramBuffer;

      if ((status = dssParms.write(paramBuffer)) != 0)
         return status;
      if ((status = subjectPublicKeyInfo.algorithm.parameters.read(paramBuffer)) != 0)
         return status;

      // set BIT STRING

      buffer_t publicKeyBuffer;

      if ((status = dsaPublicKey.write(publicKeyBuffer)) != 0)
         return status;
      if ((status = subjectPublicKeyInfo.subjectPublicKey.set_value(publicKeyBuffer.data, 8*publicKeyBuffer.data_len)) != 0)
         return status;

      JKL_FreeData(cssmScratchData);
   }
   else 
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_cssm_to_asn
//------------------------------------------------------------

static unsigned char kAsnNullBytes[2] = {0x05,0x00};

uint32
JKL_cssm_to_asn(CSSM_ALGORITHMS cssmSignatureAlgorithmID,
                AlgorithmIdentifier& algorithmIdentifier)
{
   uint32 status = 0;

   r_buffer_t nullBuffer;
   nullBuffer.data     = kAsnNullBytes;
   nullBuffer.data_len = sizeof(kAsnNullBytes)/sizeof(unsigned char);

   if ( CSSM_ALGID_SHA1WithDSA == cssmSignatureAlgorithmID )
   {
      if ((status = algorithmIdentifier.algorithm.set_value(dsaWithSHA1_val, 6)) != 0)
         return status;
   }
   else if ( CSSM_ALGID_MD5WithRSA == cssmSignatureAlgorithmID )
   {
      if ((status = algorithmIdentifier.algorithm.set_value(md5WithRSAEncryption_val, 7)) != 0)
         return status;
      if ((status = algorithmIdentifier.parameters.read(nullBuffer)) != 0)
         return status;
   } 
   else if ( CSSM_ALGID_MD2WithRSA == cssmSignatureAlgorithmID )
   {
      if ((status = algorithmIdentifier.algorithm.set_value(md2WithRSAEncryption_val, 7)) != 0)
         return status;
      if ((status = algorithmIdentifier.parameters.read(nullBuffer)) != 0)
         return status;
   }
   else if ( CSSM_ALGID_SHA1WithRSA == cssmSignatureAlgorithmID )
   {
      if ((status = algorithmIdentifier.algorithm.set_value(sha1WithRSAEncryption_val, 7)) != 0)
         return status;
      if ((status = algorithmIdentifier.parameters.read(nullBuffer)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_cssm_to_asn
//------------------------------------------------------------

uint32
JKL_cssm_to_asn(const CSSM_KEY& cssmPrivateKey,
                PrivateKeyInfo& privateKeyInfo)
{
   uint32 status = 0;

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmPrivateKey.KeyHeader.CspId, IBM_BSAFE_CSP_GUID) )
   {
      // BSAFE CSP returns PKC-5 DER PrivateKeyInfo

      r_buffer_t keyBuffer;
      keyBuffer.data     = cssmPrivateKey.KeyData.Data;
      keyBuffer.data_len = cssmPrivateKey.KeyData.Length;
      if ((status = privateKeyInfo.read(keyBuffer)) != 0)
         return status;
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmPrivateKey.KeyHeader.CspId, IBM_CYLINK_CSP_GUID) )
   {
      // Cylink CSP returns (p,q,g,y,x) as (length/value) pairs

      CSSM_DATA cssmScratchData;
      copy_cssm_data(cssmScratchData, cssmPrivateKey.KeyData);

      if ((status = privateKeyInfo.version.set_value(0)) != 0)
         return status;

#ifdef BSAFE_COMPATIBILITY
      if ((status = privateKeyInfo.privateKeyAlgorithm.algorithm.set_value(dsa_alt_val, 6)) != 0)
#else
      if ((status = privateKeyInfo.privateKeyAlgorithm.algorithm.set_value(dsa_val, 6)) != 0)
#endif
         return status;

      DssPrivateParms dssPrivateParms;
      DssPrivateKey dssPrivateKey;
      asn_integer dsaPublicKey;

      if ((status = dssPrivateParms.l.set_value(cssmPrivateKey.KeyHeader.KeySizeInBits)) != 0)
         return status;

      if ((status = cssm_to_asn(cssmScratchData, 
                                dssPrivateParms, 
                                dsaPublicKey, 
                                dssPrivateKey.x)) != 0)
         return status;

      buffer_t buffer;

      buffer.clear();
      if ((status = dssPrivateParms.write(buffer)) != 0)
         return status;
      if ((status = privateKeyInfo.privateKeyAlgorithm.parameters.read(buffer)) != 0)
         return status;

      buffer.clear();
      if ((status = dssPrivateKey.write(buffer)) != 0)
         return status;
      if ((status = privateKeyInfo.privateKey.set_value(buffer.data, buffer.data_len)) != 0)
         return status;

      JKL_FreeData(cssmScratchData);
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_cssm_to_asn
//------------------------------------------------------------

uint32
JKL_cssm_to_asn(const CSSM_DATA& cssmDigest,
                asn_octetstring& digest,
                const CSSM_GUID& cssmGUID)
{
   uint32 status = 0;

   if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_BSAFE_CSP_GUID) )
   {
      digest.set_value(cssmDigest.Data, cssmDigest.Length);
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids(cssmGUID, IBM_CYLINK_CSP_GUID) )
   {
      CSSM_DATA cssmDigestCopy;
      copy_cssm_data(cssmDigestCopy, cssmDigest);
      reverse_array(cssmDigestCopy.Data, cssmDigestCopy.Length);
      if ((status = digest.set_value(cssmDigestCopy.Data, cssmDigestCopy.Length)) != 0)
      {
         JKL_FreeData(cssmDigestCopy);
         return status;
      }
      JKL_FreeData(cssmDigestCopy);
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}

void* xmalloc_func(uint32 handle, uint32 size)
{
   return gMemoryFuncs.malloc_func(size, 0);
}

void xfree_func(uint32 handle, void* memPtr)
{
   gMemoryFuncs.free_func(memPtr, 0);
}

void* xrealloc_func(uint32 handle, void* memPtr, uint32 size)
{
   return gMemoryFuncs.realloc_func(memPtr, size, 0);
}

void* xcalloc_func(uint32 handle, uint32 num, uint32 size)
{
   return gMemoryFuncs.calloc_func(num, size, 0);
}
