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



//*****************************************************************************
//
// Low-Level Cryptographic APIs: DigestData
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_DigestData
//------------------------------------------------------------

uint32
JKL_DigestData(CSSM_CSP_HANDLE cspHandle,
               CSSM_ALGORITHMS cssmDigestAlgorithm,
               const CSSM_DATA& cssmDataToDigest,
               asn_octetstring& digest)
{
   uint32 status;

   CSSM_DATA cssmDigest;

   if ((status = JKL_DigestData(cspHandle,
                                cssmDigestAlgorithm,
                                cssmDataToDigest,
                                cssmDigest)) != 0)
      return status;

   // The CSSM_DATA digest byte order varies by CSP; use
   // cssm_to_asn conversion routine to shield user from 
   // this unpleasant little fact...

   CSSM_GUID_PTR cssmGUID = CSSM_GetModuleGUIDFromHandle(cspHandle);

   status = JKL_cssm_to_asn(cssmDigest, digest, *cssmGUID);

   JKL_FreeData(cssmDigest);

   return 0;
}


//------------------------------------------------------------
// function: JKL_DigestData
//------------------------------------------------------------

uint32
JKL_DigestData(CSSM_CSP_HANDLE cspHandle,
               CSSM_ALGORITHMS cssmDigestAlgorithm,
               const CSSM_DATA& cssmDataToDigest,
               CSSM_DATA& cssmDigest)
{
   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateDigestContext(cspHandle,
                                           cssmDigestAlgorithm);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmDigest.Data = 0;
   cssmDigest.Length = 0;

   if (CSSM_FAIL == CSSM_DigestData(ccHandle,
                                    (const CSSM_DATA_PTR)&cssmDataToDigest,
                                    1,
                                    &cssmDigest))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//*****************************************************************************
//
// Low-Level Cryptographic APIs: RandomData
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_GenerateRandomData
//------------------------------------------------------------

uint32
JKL_GenerateRandomData(CSSM_CSP_HANDLE cspHandle,
                       uint32 randomDataSize,
                       CSSM_ALGORITHMS randAlgID,
                       CSSM_DATA& cssmRandomData)
{
   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateRandomGenContext(cspHandle,
                                              randAlgID,
                                              NULL,
                                              randomDataSize);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmRandomData.Data = 0;
   cssmRandomData.Length = 0;

   if (CSSM_FAIL == CSSM_GenerateRandom(ccHandle, &cssmRandomData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//*****************************************************************************
//
// Low-Level Cryptographic APIs: Generate Key-Pairs
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_GenerateKeyPair
//------------------------------------------------------------

uint32
JKL_GenerateKeyPair(CSSM_CSP_HANDLE cspHandle,
                    CSSM_ALGORITHMS cssmKeyPairType,
                    uint32 modulusBits,
                    CSSM_KEY& cssmPublicKey,
                    CSSM_KEY& cssmPrivateKey)
{
   CSSM_CC_HANDLE ccHandle;
   uint32 keyUsage = CSSM_KEYUSE_SIGN|CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   uint32 keyAttr = CSSM_KEYATTR_PERMANENT;

   ccHandle = CSSM_CSP_CreateKeyGenContext(cspHandle,
                                           cssmKeyPairType,
                                           NULL,
                                           modulusBits,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL);
   if (!ccHandle)
      return CSSM_GetError()->error;

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

   if (CSSM_FAIL == CSSM_GenerateKeyPair(ccHandle,
                                         keyUsage,
                                         keyAttr,
                                         NULL,
                                         &cssmPublicKey,
                                         keyUsage,
                                         keyAttr,
                                         NULL,
                                         &cssmPrivateKey))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//*****************************************************************************
//
// Low-Level Cryptographic APIs: Verification
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_VerifyData
//------------------------------------------------------------

uint32
JKL_VerifyData(CSSM_CSP_HANDLE cspHandle,
               const AlgorithmIdentifier& algorithmIdentifier,
               const SubjectPublicKeyInfo& signerPublicKeyInfo,
               const asn_bitstring& signature,
               const buffer_t& dataToVerify,
               bool& isVerified)
{
   uint32 status = 0;

   isVerified = false;

   // unfortunately, we must know which CSP we're using

   CSSM_GUID_PTR cssmGUID = CSSM_GetModuleGUIDFromHandle(cspHandle);

   // determine signature algorithm used by signer

   CSSM_ALGORITHMS cssmAlgorithmID;

   if ((status = JKL_asn_to_cssm(algorithmIdentifier, cssmAlgorithmID)) != 0)
      return status;

   // prepare data to be verified (shallow copy)

   CSSM_DATA cssmDataToVerify = {0,0}; 

   cssmDataToVerify.Data   = dataToVerify.data;
   cssmDataToVerify.Length = dataToVerify.data_len;

   // prepare signature

   CSSM_DATA cssmSignature = {0,0};

   if ((status = JKL_asn_to_cssm(signature, cssmSignature, *cssmGUID)) != 0)
      return status;

   // prepare public key

   CSSM_KEY cssmPublicKey;

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

   if ((status = JKL_asn_to_cssm(signerPublicKeyInfo, cssmPublicKey, *cssmGUID)) != 0)
      return status;
   
   // verify data

   CSSM_BOOL cssmIsVerified;

   status = JKL_VerifyData(cspHandle,
                           cssmAlgorithmID,
                           cssmPublicKey,
                           cssmSignature,
                           cssmDataToVerify,
                           cssmIsVerified);

   if (CSSM_TRUE == cssmIsVerified)
   {
      isVerified = true;
   }
   
   // free allocated memory

   JKL_FreeData(cssmPublicKey);
   JKL_FreeData(cssmSignature);

   return status;
}


//------------------------------------------------------------
// function: JKL_VerifyData
//------------------------------------------------------------

uint32
JKL_VerifyData(CSSM_CSP_HANDLE cspHandle,
               CSSM_ALGORITHMS cssmSignatureAlgorithm,
               CSSM_KEY& cssmPublicKey,
               const CSSM_DATA& cssmSignature,
               const CSSM_DATA& cssmDataToVerify,
               CSSM_BOOL& isVerified)
{
   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              cssmSignatureAlgorithm,
                                              NULL,
                                              &cssmPublicKey);
   if (!ccHandle)
      return CSSM_GetError()->error;

   isVerified = CSSM_VerifyData(ccHandle,
                                (const CSSM_DATA_PTR)&cssmDataToVerify,
                                1,
                                (const CSSM_DATA_PTR)&cssmSignature);

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//------------------------------------------------------------
// function: JKL_ValidateCertificateSignature
//------------------------------------------------------------

uint32
JKL_ValidateCertificateSignature(const x509_certificate& subject, 
                                 const x509_certificate& issuer,
                                 CSSM_CSP_HANDLE cspHandle,
                                 bool& isVerified)
{
   uint32 status = 0;

   // extract encoding from signed ASN object

   buffer_t tbsEncoding;

   if ((status = subject.tbsCertificate.write(tbsEncoding)) != 0)
      return status;

   // call common low-level verify API

   status = JKL_VerifyData(cspHandle,
                           subject.signatureAlgorithm,
                           issuer.tbsCertificate.subjectPublicKeyInfo,
                           subject.signature,
                           tbsEncoding,
                           isVerified);

   return status;
}


//------------------------------------------------------------
// function: JKL_ValidateCRLSignature
//------------------------------------------------------------

uint32
JKL_ValidateCRLSignature(const CertificateList& crl,
                         const x509_certificate& issuer,
                         CSSM_CSP_HANDLE cspHandle,
                         bool& isVerified)
{
   uint32 status = 0;

   // extract encoding from signed ASN object

   buffer_t tbsEncoding;

   if ((status = crl.tbsCertList.write(tbsEncoding)) != 0)
      return status;

   // call common low-level verify API

   status = JKL_VerifyData(cspHandle,
                           crl.signatureAlgorithm,
                           issuer.tbsCertificate.subjectPublicKeyInfo,
                           crl.signature,
                           tbsEncoding,
                           isVerified);

   return status;
}


//*****************************************************************************
//
// Low-Level Cryptographic APIs: Signature
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_SignData
//------------------------------------------------------------

uint32 
JKL_SignData(CSSM_CSP_HANDLE cspHandle,
             CSSM_ALGORITHMS cssmAlgorithmID,
             const CSSM_KEY& cssmPrivateKey,
             const CSSM_DATA& cssmDataToSign,
             CSSM_DATA& cssmSignature)
{
   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              cssmAlgorithmID,
                                              NULL,
                                              (const CSSM_KEY_PTR)&cssmPrivateKey);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmSignature.Data = 0;
   cssmSignature.Length = 0;

   if (CSSM_FAIL == CSSM_SignData(ccHandle,
                                  (const CSSM_DATA_PTR)&cssmDataToSign,
                                  1,
                                  &cssmSignature))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//------------------------------------------------------------
// function: JKL_SignCertificate
//------------------------------------------------------------

uint32
JKL_SignCertificate(x509_certificate& certToBeSigned, 
                    CSSM_CSP_HANDLE cspHandle, 
                    CSSM_ALGORITHMS cssmSignatureAlgorithmID,
                    const CSSM_KEY& cssmSignerPrivateKey)
{
   uint32 status = 0;

   // extract DER encoded TBS component

   buffer_t tbsBuffer;
   if ((status = certToBeSigned.tbsCertificate.write(tbsBuffer)) != 0)
      return status;

   // shallow copy TBS into CSSM_DATA

   CSSM_DATA cssmDataToSign;
   cssmDataToSign.Data   = tbsBuffer.data;
   cssmDataToSign.Length = tbsBuffer.data_len;

   // Perform signature

   CSSM_DATA cssmSignature;

   if ((status = JKL_SignData(cspHandle,
                              cssmSignatureAlgorithmID,
                              cssmSignerPrivateKey,
                              cssmDataToSign,
                              cssmSignature)) != 0)
      return status;

   // Copy algorithm identifier from TBS part 

   buffer_t copyBuffer;

   if ((status = certToBeSigned.tbsCertificate.signature.write(copyBuffer)) != 0)
      return status;

   if ((status = certToBeSigned.signatureAlgorithm.read(copyBuffer)) != 0)
      return status;

   // Store signature into certificate

   if ((status = JKL_cssm_to_asn(cssmSignature,
                                 certToBeSigned.signature,
                                 cssmSignerPrivateKey.KeyHeader.CspId)) != 0)
      return status;

   // clean up allocated memory

   JKL_FreeData( cssmSignature );

   return 0;
}


//------------------------------------------------------------
// function: JKL_SignCRL
//------------------------------------------------------------

uint32
JKL_SignCRL(CertificateList& crlToBeSigned, 
            CSSM_CSP_HANDLE cspHandle, 
            CSSM_ALGORITHMS cssmSignatureAlgorithmID,
            const CSSM_KEY& cssmSignerPrivateKey)
{
   uint32 status = 0;

   // extract DER encoded TBS component

   buffer_t tbsBuffer;
   if ((status = crlToBeSigned.tbsCertList.write(tbsBuffer)) != 0)
      return status;

   // shallow copy TBS into CSSM_DATA

   CSSM_DATA cssmDataToSign;
   cssmDataToSign.Data   = tbsBuffer.data;
   cssmDataToSign.Length = tbsBuffer.data_len;

   // Perform signature

   CSSM_DATA cssmSignature;

   if ((status = JKL_SignData(cspHandle,
                              cssmSignatureAlgorithmID,
                              cssmSignerPrivateKey,
                              cssmDataToSign,
                              cssmSignature)) != 0)
      return status;

   // Copy algorithm identifier from TBS part 

   buffer_t copyBuffer;

   if ((status = crlToBeSigned.tbsCertList.signature.write(copyBuffer)) != 0)
      return status;

   if ((status = crlToBeSigned.signatureAlgorithm.read(copyBuffer)) != 0)
      return status;

   // Store signature into certificate

   if ((status = JKL_cssm_to_asn(cssmSignature,
                                 crlToBeSigned.signature,
                                 cssmSignerPrivateKey.KeyHeader.CspId)) != 0)
      return status;

   // clean up allocated memory

   JKL_FreeData(cssmSignature);

   return 0;
}


//*****************************************************************************
//
// Low-Level Cryptographic APIs: DES Routines
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_DES3X_GenerateKey
//------------------------------------------------------------

uint32
JKL_3DES_GenerateKey(CSSM_CSP_HANDLE cspHandle,
                     CSSM_KEY& cssmSecretKey,
                     int numOfKeys)
{
   CSSM_CC_HANDLE ccHandle;
   uint32 keyUsage = CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   uint32 keyAttr = CSSM_KEYATTR_PERMANENT;

   uint32 algID = compute3DESAlgorithm(numOfKeys);

   uint32 keySizeInBits = 64 * numOfKeys;

   ccHandle = CSSM_CSP_CreateKeyGenContext(cspHandle,
                                           algID,
                                           NULL,
                                           keySizeInBits,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL);
   if (!ccHandle)
      return CSSM_GetError()->error;

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

   if (CSSM_FAIL == CSSM_GenerateKey(ccHandle,
                                     keyUsage,
                                     keyAttr,
                                     NULL,
                                     &cssmSecretKey))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}


//------------------------------------------------------------
// function: JKL_DES_GenerateIV
//------------------------------------------------------------

uint32
JKL_DES_GenerateIV(CSSM_CSP_HANDLE cspHandle,
                   CSSM_DATA& cssmInitializationVector)
{
   uint32 status = 0;

   if ((status = JKL_GenerateRandomData(cspHandle, 8, cssmInitializationVector)) != 0)
      return status;

   return 0;
}


//------------------------------------------------------------
// function: JKL_3DES_EncryptData
//------------------------------------------------------------

uint32
JKL_3DES_EncryptData(CSSM_CSP_HANDLE cspHandle,
                     int numOfKeys,
                     const CSSM_DATA& cssmInitializationVector,
                     const CSSM_KEY& cssmSecretKey,
                     const CSSM_DATA& cssmDataToEncrypt,
                     CSSM_DATA& cssmEncryptedData)
{
   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesEncrypted = 0;

   uint32 algID = compute3DESAlgorithm(numOfKeys);

   ccHandle = CSSM_CSP_CreateSymmetricContext(cspHandle,
                                              algID,
                                              CSSM_ALGMODE_CBCPadIV8,
                                              (const CSSM_KEY_PTR)&cssmSecretKey,
                                              (const CSSM_DATA_PTR)&cssmInitializationVector,
                                              CSSM_PADDING_NONE,
                                              0);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmEncryptedData.Length = 0;
   cssmEncryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_EncryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&cssmDataToEncrypt,
                                     1,
                                     &cssmEncryptedData,
                                     1,
                                     &numBytesEncrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   cssmEncryptedData.Length = numBytesEncrypted + remData.Length;
   cssmEncryptedData.Data = (uint8*)DefaultRealloc(cssmEncryptedData.Data, cssmEncryptedData.Length);
   memmove(cssmEncryptedData.Data + numBytesEncrypted, remData.Data, remData.Length);

   JKL_FreeData(remData);

   return 0;
}


//------------------------------------------------------------
// function: JKL_3DES_DecryptData
//------------------------------------------------------------

uint32
JKL_3DES_DecryptData(CSSM_CSP_HANDLE cspHandle,
                     int numOfKeys,
                     const CSSM_DATA& cssmInitializationVector,
                     const CSSM_KEY& cssmSecretKey,
                     const CSSM_DATA& cssmDataToDecrypt,
                     CSSM_DATA& cssmDecryptedData)
{
   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesDecrypted = 0;

   uint32 algID = compute3DESAlgorithm(numOfKeys);
   
   ccHandle = CSSM_CSP_CreateSymmetricContext(cspHandle,
                                              algID,
                                              CSSM_ALGMODE_CBCPadIV8,
                                              (const CSSM_KEY_PTR)&cssmSecretKey,
                                              (const CSSM_DATA_PTR)&cssmInitializationVector,
                                              CSSM_PADDING_NONE,
                                              0);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmDecryptedData.Length = 0;
   cssmDecryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_DecryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&cssmDataToDecrypt,
                                     1,
                                     &cssmDecryptedData,
                                     1,
                                     &numBytesDecrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   cssmDecryptedData.Length = numBytesDecrypted + remData.Length;
   cssmDecryptedData.Data = (uint8*)DefaultRealloc(cssmDecryptedData.Data, cssmDecryptedData.Length);
   memmove(cssmDecryptedData.Data + numBytesDecrypted, remData.Data, remData.Length);

   JKL_FreeData(remData);

   return 0;
}



//*****************************************************************************
//
// Misc. Utility Routines
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_FreeData
//------------------------------------------------------------
      
void 
JKL_FreeData(CSSM_DATA& cssmDataToFree)
{
   if (cssmDataToFree.Length)
      DefaultFree(cssmDataToFree.Data);
   cssmDataToFree.Length = 0;
   cssmDataToFree.Data   = 0;
}


//------------------------------------------------------------
// function: JKL_FreeData
//------------------------------------------------------------

void
JKL_FreeData(CSSM_DATA_PTR& cssmDataToFreePtr,  uint32 numOfElementsToFree)
{
   uint32 i;

   for (i = 0; i < numOfElementsToFree; i++)
   {
      JKL_FreeData(cssmDataToFreePtr[i]);
   }
   DefaultFree(cssmDataToFreePtr);
   cssmDataToFreePtr = 0;
}


//------------------------------------------------------------
// function: JKL_FreeData
//------------------------------------------------------------

void
JKL_FreeData(CSSM_KEY& cssmKeyDataToFree)
{
   DefaultFree(cssmKeyDataToFree.KeyData.Data);
   cssmKeyDataToFree.KeyData.Length = 0;
   cssmKeyDataToFree.KeyData.Data   = 0;
}


//------------------------------------------------------------
// function: JKL_CompareData
//------------------------------------------------------------

bool
JKL_CompareData(const CSSM_DATA& cssmData1, const CSSM_DATA& cssmData2)
{
   if (cssmData1.Length != cssmData2.Length)
      return false;

   if (memcmp(cssmData1.Data, cssmData2.Data, cssmData1.Length) != 0)
      return false;

   return true;
}




// deprecated

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

//uint32 
//JKL_asn_to_cssm(const PrivateKeyInfo& privateKeyInfo,
//                CSSM_KEY& cssmPrivateKey,
//                const CSSM_GUID& cssmCspGUID)
//{
//   return CSSM_CSP_OPERATION_UNSUPPORTED;
//}

// deprecated

//------------------------------------------------------------
// function: JKL_InitializeCSSM
//------------------------------------------------------------

uint32
JKL_InitializeCSSM(CSSM_MEMORY_FUNCS& memoryFuncs)
{
   //-------------------------------------------------
   // Initialize CSSM framework.
   // Save global copy of caller's CSSM memory 
   // functions; we will use them whenever we allocate 
   // CSSM_DATA or CSSM_KEY on user's behalf as part 
   // of asn_to_cssm routines
   //-------------------------------------------------

   gMemoryFuncs = memoryFuncs;

   CSSM_VERSION version = { CSSM_MAJOR, CSSM_MINOR };

   if (CSSM_FAIL == CSSM_Init(&version, &memoryFuncs, NULL))
      return CSSM_GetError()->error;

   return 0;
}



// obsolete

//------------------------------------------------------------
// function: JKL_GenerateRandomData
//------------------------------------------------------------

uint32
JKL_GenerateRandomData(CSSM_CSP_HANDLE cspHandle,
                       uint32 randomDataSize,
                       CSSM_DATA& cssmRandomData)
{
   CSSM_CC_HANDLE ccHandle;

   CSSM_GUID_PTR guidPtr = CSSM_GetModuleGUIDFromHandle(cspHandle);

   uint32 randAlgID = CSSM_ALGID_NONE;

   if ( CSSM_TRUE == CSSM_CompareGuids((*guidPtr), IBM_BSAFE_CSP_GUID) )
   {
      randAlgID = CSSM_ALGID_MD5Random;
   }
   else if ( CSSM_TRUE == CSSM_CompareGuids((*guidPtr), IBM_CYLINK_CSP_GUID) )
   {
      randAlgID = CSSM_ALGID_SHARandom;
   }

   ccHandle = CSSM_CSP_CreateRandomGenContext(cspHandle,
                                              randAlgID,
                                              NULL,
                                              randomDataSize);
   if (!ccHandle)
      return CSSM_GetError()->error;

   cssmRandomData.Data = 0;
   cssmRandomData.Length = 0;

   if (CSSM_FAIL == CSSM_GenerateRandom(ccHandle, &cssmRandomData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      return errcode;
   }

   CSSM_DeleteContext(ccHandle);

   return 0;
}
