/* ***************************************************************** *
 * 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 "jkl.h"
#include "jklutil.h"


// temporary resting place of useful constaints
// 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 constaints


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


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

uint32
JKL_GenerateKeyPair(CSSM_ALGORITHMS cssmKeyPairType,
                    uint32 keySizeInBits,
                    SubjectPublicKeyInfo& subjectPublicKeyInfo,
                    PrivateKeyInfo& privateKeyInfo)
{
   uint32 status = 0;

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, cssmKeyPairType)) != 0)
      return status;

   // convert ASN Keys to CSSM Keys

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

   do
   {
      // generate key-pair with low-level API

      status = JKL_GenerateKeyPair(cspHandle,
                                   cssmKeyPairType,
                                   keySizeInBits,
                                   cssmPublicKey,
                                   cssmPrivateKey);
      if (status) break;

      // convert CSSM_KEY private key to ASN private key

      status = JKL_cssm_to_asn(cssmPublicKey, subjectPublicKeyInfo);
      if (status) break;

      // convert CSSM_KEY public key to ASN public key

      status = JKL_cssm_to_asn(cssmPrivateKey, privateKeyInfo);
      if (status) break;

   } while (0);

   // free allocated resources

   JKL_FreeData(cssmPublicKey);
   JKL_FreeData(cssmPrivateKey);

   return status;
}


//*****************************************************************************
//
// High-Level Cryptographic APIs: Digest
//
//*****************************************************************************


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

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

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, cssmDigestAlgorithm)) != 0)
      return status;

   // invoke low-level routine
   
   return JKL_DigestData(cspHandle,
                         cssmDigestAlgorithm,
                         cssmDataToDigest,
                         digest);
}


//*****************************************************************************
//
// High-Level Cryptographic APIs: Generate Random Data
//
//*****************************************************************************


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

uint32
JKL_GenerateRandomData(uint32 randomDataSize,
                       asn_octetstring& randomData)
{
   uint32 status = 0;

   // find CSP which supports this algorithm (SHA1 or MD5 or MD2)

   CSSM_CSP_HANDLE cspHandle = 0;
   CSSM_ALGORITHMS cssmAlgorithm;
   CSSM_ALGORITHMS cssmAlgorithms[3] = {CSSM_ALGID_SHARandom, 
                                        CSSM_ALGID_MD5Random, 
                                        CSSM_ALGID_MD2Random};

   for (int i = 0; i < 3; i++)
   {
      cssmAlgorithm = cssmAlgorithms[i];
      status = JKL_FindBestCSP(cspHandle, cssmAlgorithm);
      if (status == 0) break;
   }

   if (status != 0)
      return status;

   // generate random data

   CSSM_DATA cssmRandomData;

   memset(&cssmRandomData, 0, sizeof(CSSM_DATA));

   do
   {

      // invoke low-level routine

      status = JKL_GenerateRandomData(cspHandle,
                                      randomDataSize,
                                      cssmAlgorithm,
                                      cssmRandomData);
      if (status) break;

      // store in caller's ASN octet string

      status = randomData.set_value(cssmRandomData.Data, cssmRandomData.Length);
      if (status) break;

   } while (0);

   // free allocated resources

   JKL_FreeData(cssmRandomData);

   return status;
}


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


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

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

   // convert ASN algorithm to CSSM algorithm

   CSSM_ALGORITHMS algorithm;

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

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, algorithm)) != 0)
      return status;

   // invoke low-level routine
   
   return JKL_VerifyData(cspHandle,
                         algorithmIdentifier,
                         signerPublicKeyInfo,
                         signature,
                         dataToVerify,
                         isVerified);
}


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

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

   // extract encoding of ASN object

   buffer_t encoding;

   if ((status = dataToVerify.write(encoding)) != 0)
      return status;

   // invoke alternative high-level routine

   return JKL_VerifyData(algorithmIdentifier,
                         signerPublicKeyInfo,
                         signature,
                         encoding,
                         isVerified);
}


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

uint32
JKL_ValidateCertificateSignature(const x509_certificate& subject, 
                                 const x509_certificate& issuer,
                                 bool& isVerified)
{
   return JKL_VerifyData(subject.signatureAlgorithm,
                         issuer.tbsCertificate.subjectPublicKeyInfo,
                         subject.signature,
                         subject.tbsCertificate,
                         isVerified);
}


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

uint32
JKL_ValidateCRLSignature(const CertificateList& crl, 
                         const x509_certificate& issuer,
                         bool& isVerified)
{
   return JKL_VerifyData(crl.signatureAlgorithm,
                         issuer.tbsCertificate.subjectPublicKeyInfo,
                         crl.signature,
                         crl.tbsCertList,
                         isVerified);
}


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


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

uint32
JKL_SignData(const PrivateKeyInfo& privateKeyInfo,
             const SubjectPublicKeyInfo& subjectPublicKeyInfo,
             CSSM_ALGORITHMS cssmSignatureAlgorithmID,
             const buffer_t& dataToSign,
             asn_bitstring& signature)
{
   uint32 status = 0;

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, cssmSignatureAlgorithmID)) != 0)
      return status;

   // sign data

   CSSM_KEY cssmPrivateKey;
   CSSM_DATA cssmSignature;

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

   do
   {
      // convert ASN Private Key to CSSM Private Key

      CSSM_GUID_PTR cssmGUID = CSSM_GetModuleGUIDFromHandle(cspHandle);

      status = JKL_asn_to_cssm(privateKeyInfo, 
                               subjectPublicKeyInfo,
                               cssmPrivateKey, 
                               *cssmGUID);
      if (status) break;

      // invoke low-level routine

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

      status = JKL_SignData(cspHandle,
                            cssmSignatureAlgorithmID,
                            cssmPrivateKey,
                            cssmDataToSign,
                            cssmSignature);
      if (status) break;

      // convert CSSM signature to ASN signature

      status = JKL_cssm_to_asn(cssmSignature,
                               signature,
                               cssmPrivateKey.KeyHeader.CspId);
      if (status) break;

   } while (0);

   // free allocated resources

   JKL_FreeData(cssmPrivateKey);
   JKL_FreeData(cssmSignature);

   return status;
}


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

uint32
JKL_SignData(const PrivateKeyInfo& privateKeyInfo,
             const SubjectPublicKeyInfo& subjectPublicKeyInfo,
             CSSM_ALGORITHMS cssmSignatureAlgorithmID,
             const asn_object& dataToSign,
             asn_bitstring& signature)
{
   uint32 status = 0;

   // extract encoding of ASN object

   buffer_t encoding;

   if ((status = dataToSign.write(encoding)) != 0)
      return status;

   // invoke alternative high-level routine

   return JKL_SignData(privateKeyInfo,
                       subjectPublicKeyInfo,
                       cssmSignatureAlgorithmID,
                       encoding,
                       signature);
}


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

uint32
JKL_SignCertificate(const PrivateKeyInfo& privateKeyInfo,
                    const SubjectPublicKeyInfo& subjectPublicKeyInfo,
                    CSSM_ALGORITHMS cssmSignatureAlgorithmID,
                    x509_certificate& certToBeSigned)
{
   return JKL_SignData(privateKeyInfo,
                       subjectPublicKeyInfo,
                       cssmSignatureAlgorithmID,
                       certToBeSigned.tbsCertificate,
                       certToBeSigned.signature);
}


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

uint32
JKL_SignCRL(const PrivateKeyInfo& privateKeyInfo,
            const SubjectPublicKeyInfo& subjectPublicKeyInfo,
            CSSM_ALGORITHMS cssmSignatureAlgorithmID,
            CertificateList& crlToBeSigned)
{
   return JKL_SignData(privateKeyInfo,
                       subjectPublicKeyInfo,
                       cssmSignatureAlgorithmID,
                       crlToBeSigned.tbsCertList,
                       crlToBeSigned.signature);
}


//*****************************************************************************
//
// High-Level Cryptographic APIs: DES (1,2,3 key)
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_3DES_GenerateKey
//------------------------------------------------------------

uint32
JKL_3DES_GenerateKey(asn_octetstring& desKey,
                     asn_octetstring& IV,
                     int numOfKeys)
{
   uint32 status = 0;

   // which DES algorithm to use?

   uint32 algorithmID = compute3DESAlgorithm(numOfKeys);
   
   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, algorithmID)) != 0)
      return status;
   
   // generate key and IV

   CSSM_KEY cssmSecretKey;

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

   do
   {
      // generate CSSM key

      status = JKL_3DES_GenerateKey(cspHandle, cssmSecretKey, numOfKeys);
      if (status) break;

      // convert CSSM key to ASN octet string

      status = desKey.set_value(cssmSecretKey.KeyData.Data, cssmSecretKey.KeyData.Length);
      if (status) break;

      // generate IV

      status = JKL_GenerateRandomData(8, IV);
      if (status) break;

   } while (0);

   // free allocated resources

   JKL_FreeData(cssmSecretKey);

   return status;
}


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

uint32
JKL_3DES_EncryptData(const asn_octetstring& desKey,
                     const asn_octetstring& IV,
                     int numOfKeys,
                     const asn_octetstring& dataToEncrypt,
                     asn_octetstring& encryptedData)
{
   uint32 status = 0;

   // which DES algorithm to use?

   uint32 algorithmID = compute3DESAlgorithm(numOfKeys);

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, algorithmID)) != 0)
      return status;

   // encrypt data

   CSSM_KEY cssmSecretKey;
   CSSM_DATA cssmEncryptedData;

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

   do
   {
      // convert DES key to CSSM key

      CSSM_GUID_PTR cssmGUID = CSSM_GetModuleGUIDFromHandle(cspHandle);
   
      status = JKL_asn_to_cssm(desKey, 
                               numOfKeys, 
                               cssmSecretKey, 
                               *cssmGUID);
      if (status) break;

      // make shallow CSSM_DATA copies of IV and Data
   
      CSSM_DATA cssmIV;
      CSSM_DATA cssmDataToEncrypt;
   
      status = IV.get_value(cssmIV.Data, cssmIV.Length);
      if (status) break;

      status = dataToEncrypt.get_value(cssmDataToEncrypt.Data, cssmDataToEncrypt.Length);
      if (status) break;

      // encrypt data
   
      status = JKL_3DES_EncryptData(cspHandle,
                                    numOfKeys,
                                    cssmIV,
                                    cssmSecretKey,
                                    cssmDataToEncrypt,
                                    cssmEncryptedData);
      if (status) break;

      // store encrypted result in user's octet string
   
      status = encryptedData.set_value(cssmEncryptedData.Data, cssmEncryptedData.Length);
      if (status) break;

   } while (0);

   // clean up allocated memory

   JKL_FreeData(cssmSecretKey);
   JKL_FreeData(cssmEncryptedData);

   return status;
}


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

uint32
JKL_3DES_DecryptData(const asn_octetstring& desKey,
                     const asn_octetstring& IV,
                     int numOfKeys,
                     const asn_octetstring& dataToDecrypt,
                     asn_octetstring& decryptedData)
{
   uint32 status = 0;

   // which DES algorithm to use?

   uint32 algorithmID = compute3DESAlgorithm(numOfKeys);

   // find CSP which supports this algorithm

   CSSM_CSP_HANDLE cspHandle;

   if ((status = JKL_FindBestCSP(cspHandle, algorithmID)) != 0)
      return status;

   // decrypt data

   CSSM_KEY cssmSecretKey;
   CSSM_DATA cssmDecryptedData;

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

   do
   {
      // convert DES key to CSSM_KEY

      CSSM_GUID_PTR cssmGUID = CSSM_GetModuleGUIDFromHandle(cspHandle);

      status = JKL_asn_to_cssm(desKey, 
                               numOfKeys, 
                               cssmSecretKey, 
                               *cssmGUID);
      if (status) break;

      // make shallow copies of IV and Data

      CSSM_DATA cssmIV;
      CSSM_DATA cssmDataToDecrypt;

      status = IV.get_value(cssmIV.Data, cssmIV.Length);
      if (status) break;

      status = dataToDecrypt.get_value(cssmDataToDecrypt.Data, cssmDataToDecrypt.Length);
      if (status) break;

      // decrypt data

      status = JKL_3DES_DecryptData(cspHandle,
                                    numOfKeys,
                                    cssmIV,
                                    cssmSecretKey,
                                    cssmDataToDecrypt,
                                    cssmDecryptedData);
      if (status) break;

      // store decrypted result in user's octet string

      status = decryptedData.set_value(cssmDecryptedData.Data, cssmDecryptedData.Length);
      if (status) break;

   } while (0);

   // clean up allocated memory

   JKL_FreeData(cssmSecretKey);
   JKL_FreeData(cssmDecryptedData);

   return status;
}


//*****************************************************************************
//
// Key Size Calculation Routines
//
//*****************************************************************************


//------------------------------------------------------------
// function: JKL_ExtractRSAPublicKey
//------------------------------------------------------------

uint32
JKL_ExtractRSAPublicKey(const SubjectPublicKeyInfo& subjectPublicKeyInfo, 
                        RSAPublicKey& rsaPublicKey)
{
   uint32 status = 0;

   // extract subjectPublicKey

   unsigned char* p;
   unsigned bc;

   if ((status = subjectPublicKeyInfo.subjectPublicKey.get_value(p, bc)) != 0)
      return status;

   // extract RSA public key

   r_buffer_t encoding;

   encoding.data     = p;
   encoding.data_len = bc/8;

   if ((status = rsaPublicKey.read(encoding)) != 0)
      return status;

   return status;
}


//------------------------------------------------------------
// function: JKL_ExtractRSAPrivateKey
//------------------------------------------------------------

uint32
JKL_ExtractRSAPrivateKey(const PrivateKeyInfo& privateKeyInfo,
                         RSAPrivateKey& rsaPrivateKey)
{
   uint32 status = 0;
   
   // extract privateKey

   unsigned char* p;
   unsigned bc;

   if ((status = privateKeyInfo.privateKey.get_value(p, bc)) != 0)
      return status;

   // extract RSA private key

   r_buffer_t rsaKeyBuffer;

   rsaKeyBuffer.data     = p;
   rsaKeyBuffer.data_len = bc;

   if ((status = rsaPrivateKey.read(rsaKeyBuffer)) != 0)
      return status;

   return status;
}


//------------------------------------------------------------
// function: JKL_ExtractDSAPublicKey
//------------------------------------------------------------

uint32
JKL_ExtractDSAPublicKey(const SubjectPublicKeyInfo& subjectPublicKeyInfo,
                        DssParms& dssParms,
                        asn_integer& dsaPublicKey)
{
   uint32 status = 0;

   unsigned char* p;
   unsigned bc;

   // Extract DSA parameters

   buffer_t dssParmsBuffer;

   if ((status = subjectPublicKeyInfo.algorithm.parameters.write(dssParmsBuffer)) != 0)
      return status;

   if ((status = dssParms.read(dssParmsBuffer)) != 0)
      return status;

   // Extract public key

   if ((status = subjectPublicKeyInfo.subjectPublicKey.get_value(p, bc)) != 0)
      return status;

   r_buffer_t dsaPublicKeyBuffer;

   dsaPublicKeyBuffer.data     = p;
   dsaPublicKeyBuffer.data_len = bc/8;

   if ((status = dsaPublicKey.read(dsaPublicKeyBuffer)) != 0)
      return status;

   return status;
}


//------------------------------------------------------------
// function: JKL_ExtractDSAPrivateKey
//------------------------------------------------------------

uint32
JKL_ExtractDSAPrivateKey(const PrivateKeyInfo& privateKeyInfo,
                         DssPrivateParms& dssPrivateParms,
                         DssPrivateKey& privatekey)
{
   uint32 status = 0;

   r_buffer_t dsaPublicKeyBuffer;
   
   // Extract dssPrivateParams

   buffer_t encoding;

   if ((status = privateKeyInfo.privateKeyAlgorithm.parameters.write(encoding)) != 0)
      return status;

   if ((status = dssPrivateParms.read(encoding)) != 0)
      return status;

   // Extract x

   unsigned char* p;
   unsigned bc;

   if ((status = privateKeyInfo.privateKey.get_value(p, bc)) != 0)
      return status;

   r_buffer_t b;

   b.data     = p;
   b.data_len = bc;

   if ((status = privatekey.read(b)) != 0)
      return status;

   return status;
}


//------------------------------------------------------------
// function: JKL_ComputeKeySizeInBits
//------------------------------------------------------------

uint32
JKL_ComputeKeySizeInBits(const SubjectPublicKeyInfo& subjectPublicKeyInfo, 
                         long& keySizeInBits)
{
   uint32 status = 0;

   if ( subjectPublicKeyInfo.algorithm.algorithm.is_equal(rsaEncryption_val, 7) )
   {
      RSAPublicKey rsaPublicKey;

      if ((status = JKL_ExtractRSAPublicKey(subjectPublicKeyInfo, rsaPublicKey)) != 0)
         return status;

      if ((status = JKL_ComputeKeySizeInBits(rsaPublicKey.modulus, keySizeInBits)) != 0)
         return status;
   }
   else if ( subjectPublicKeyInfo.algorithm.algorithm.is_equal(dsa_val, 6) ||
             subjectPublicKeyInfo.algorithm.algorithm.is_equal(dsa_alt_val, 6) )
   {
      DssParms dssParms;
      asn_integer dsaPublicKey;

      if ((status = JKL_ExtractDSAPublicKey(subjectPublicKeyInfo,
                                            dssParms,
                                            dsaPublicKey)) != 0)
         return status;
      
      if ((status = JKL_ComputeKeySizeInBits(dssParms.p, keySizeInBits)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_ComputeKeySizeInBits
//------------------------------------------------------------

uint32
JKL_ComputeKeySizeInBits(const PrivateKeyInfo& privateKeyInfo,
                         long& keySizeInBits)
{
   uint32 status = 0;

   if ( privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(rsaEncryption_val, 7) )
   {
      RSAPrivateKey rsaPrivateKey;

      if ((status = JKL_ExtractRSAPrivateKey(privateKeyInfo,
                                             rsaPrivateKey)) != 0)
         return status;

      if ((status = JKL_ComputeKeySizeInBits(rsaPrivateKey.modulus, keySizeInBits)) != 0)
         return status;
   }
   else if ( privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(dsa_val, 6) ||
             privateKeyInfo.privateKeyAlgorithm.algorithm.is_equal(dsa_alt_val, 6) )
   {
      DssPrivateParms dssPrivateParms;
      DssPrivateKey privatekey;

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

      if ((status = dssPrivateParms.l.get_value(keySizeInBits)) != 0)
         return status;
   }
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
   }
   return status;
}


//------------------------------------------------------------
// function: JKL_ComputeKeySizeInBits
//------------------------------------------------------------

uint32 
JKL_ComputeKeySizeInBits(const asn_integer& modulus,
                         long& keySizeInBits)
{
   uint32 status = 0;

   keySizeInBits = 0;

   // extract DER encoding

   buffer_t encoding;

   if ((status = modulus.write(encoding)) != 0)
      return status;

	size_t len                 = encoding.data_len;
	const unsigned char* value = encoding.data;

	if ( *value != 0x02 )
      return CSSM_CSP_OPERATION_UNSUPPORTED;

	value++; // *value indicate the number of bytes of the key modulus or == 81, 82
	len--;

   // key size uses: one, two, three, or four bytes

	if (*value < 0x81)
   {
		keySizeInBits = *value;
	}
   else if (*value == 0x81)
   {
		keySizeInBits = value[1];
		value++;
		len--;
	}
   else if (*value == 0x82)
   {
		keySizeInBits = value[1]*256 + value[2];		
		value += 2;
		len -= 2;
	}
   else if (*value == 0x83)
   {
		keySizeInBits = value[1]*256*256 + value[2]*256 + value[3];		
		value += 3;
		len -= 3;	
	}
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
	}

	if (len > 1)
   {
		value++;
		len--;
	}
   else
   {
      return CSSM_CSP_OPERATION_UNSUPPORTED;
	}

	// Some leading 0 must be deduced from the key size as an integer

	while (len > 1 && *value == 0)
   {
		value++;
		len--;
		keySizeInBits--;
	}

	keySizeInBits *= 8; // convert to bits from bytes
	if (*value < 0x10)
      keySizeInBits -= 4; // the leading four bits of the first byte consists of 0's

	return status;
}

