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


// This module is the only place that accesses the user's pin
// that opens her smart card. 

#include <platform.h>
#include <sections.h>
#include <jonahini.h>
#include <jkl.h>
#include <pkcs.h>
#include <cssmtype.h>
#include <oid.h>
#include <constants.h>
#include <sections.h>
#include <crmsg.h>
#include <keystore.h>
#include <crypto.h>



// The PIN should really be protected by a mutex, as the GUI can perform
// a login at any time.
static buffer_t MyPin(ASN_SECRET); 

static CSSM_CSP_HANDLE preferredCSPHandle;

int CR_InitKeyAccess(void) {

  int status = 0; 

  CSSM_GUID cylink_guid = *JKL_Get_CylinkCsp_GUID();
  if ((status = JKL_AttachCSP(cylink_guid, preferredCSPHandle)) != 0) {
    return status;
  };

  return status; 

};
 
// Reset the remembered pin to the new value 
int CR_SetPin(const utf8String newpin) {
  int status = 0; 

  if ((status = MyPin.clear()) != 0) {
    return status; 
  };


// Copy the PIN...
  if ((status = MyPin.append(newpin, strlen((char *)newpin))) != 0) {
    return status; 
  };

// NUL-terminate the PIN...
  if ((status = MyPin.append((unsigned char) 0)) != 0) {
    return status; 
  };

  return 0; 

}

int CR_DigestData(CSSM_ALGORITHMS &alg, r_buffer_t &inbuff, buffer_t &outbuff) {
  int status = 0;
  CSSM_DATA cssmin;
  asn_octetstring cssmout; 

  cssmin.Data = inbuff.data;
  cssmin.Length = inbuff.data_len;

  if ((status = JKL_DigestData(preferredCSPHandle, alg, cssmin, cssmout)) != 0) {
    return status;
  };

  if ((status = cssmout.get_value(outbuff.data, outbuff.data_len)) != 0) {
    return status; 
  };	

  return 0;

}

bool CR_IsSha1WithRsaOid(const asn_oid &oid) {
  return oid_equal(oid, sha1WithRsaOid, 7); 
}

bool CR_IsSha1WithDsaOid(const asn_oid &oid) {
  return oid_equal(oid, dsaWithSha1Oid, 6); 
}

bool CR_IsDsaOid(const asn_oid &oid) {
  return oid_equal(oid, dssOid, 6); 
}

// Returns the most recent of my self-issued certs
int CR_GetMyCert(x509_certificate &mycert) {

  int status = 0;
  unsigned char buff[EXPTEXTSIZE];
  utf8String me; 
  buffer_t serial, privkey, cert; 
  unsigned int v = 0;

  if (MyPin.data_len == 0) return CR_NOT_LOGGED_IN;

  me = buff; 
  if (!IniReadString(GEN_SECTION, GEN_NAME, (char *) me, EXPTEXTSIZE)) {
    return CR_NO_NAME;
  };

// Get the certificate 
  if ((status = JnhRetrieveKeySlot((char *)MyPin.data, 
                                   me, 
                                   me, 
                                   v, 
                                   &serial, // We don't care about the serial number 
                                   &privkey, // We don't care about the private key 
                                   &cert)) != 0) {
    return status; 
  };

  if ((status = mycert.read(cert)) != 0) {
    return status; 
  };
  
  return status; 
}

// Checks that the type of key is suitable for a particular algorithm 
// It expects a subject public key algorithm as the first argument 
int CR_CompareKeyAlg(AlgorithmIdentifier &keyalg, AlgorithmIdentifier &sigalg) {
  int status = 0;

// RSA key

// Diffie-Hellman Key Exchange Key

// DSA signature key 
  if (oid_equal(keyalg.algorithm, dssOid, 6)) {
    if (oid_equal(sigalg.algorithm, dsaWithSha1Oid, 6)) {
      return 0;
    } else {
      return CR_KEY_BADALG;
    };
  };

  return CR_KEY_NOALG; 
}

int CR_SignData(AlgorithmIdentifier &alg, r_buffer_t tosign, buffer_t &signature){
  int status = 0;
  unsigned char cbuff[EXPTEXTSIZE];
  utf8String me; 
  buffer_t privkey, cert, buff;
  x509_certificate mycert; 
  CSSM_KEY ckey;
  CSSM_DATA indata, outdata;
  PrivateKeyInfo keyinfo;
  CSSM_ALGORITHMS calg; 
  unsigned int v = 0; 
	
  if (MyPin.data_len == 0) return CR_NOT_LOGGED_IN;

  me = cbuff; 
  if (!IniReadString(GEN_SECTION, GEN_NAME, (char *)me, EXPTEXTSIZE)) 
    return CR_NO_NAME;

// Get our private key out of storage
  if ((status = 
         JnhRetrieveKeySlot((char *)MyPin.data, me, me, v, NULL, &privkey, &cert)) != 0)
    return status; 

  if ((status = mycert.read(cert)) != 0)
    return status; 

// Make a PrivateKeyInfo
  if ((status = keyinfo.read(privkey)) != 0)
    return status;

// Convert it to a CDSA key
  if ((status = JKL_asn_to_cssm(keyinfo, 
                                mycert.tbsCertificate.subjectPublicKeyInfo, 
                                ckey, 
                                *(CSSM_GUID_PTR)JKL_Get_CylinkCsp_GUID())) != 0)
    return status; 

// Make sure that our key can be used in the requested algorithm 
// To Be Implemented: we'll need a retrieve that takes the alg as input 
  if ((status = CR_CompareKeyAlg(
			mycert.tbsCertificate.subjectPublicKeyInfo.algorithm, alg)) != 0)
    goto cleanup;
/*
  if ((status = JKL_asn_to_cssm(alg, calg)) != 0)
    return status; 
*/
  calg = CSSM_ALGID_SHA1WithDSA;
	
  indata.Data = tosign.data;
  indata.Length = tosign.data_len;

// See if we have access to code for the desired sig alg

  if (CR_IsSha1WithDsaOid(alg.algorithm)) {
    if ((status = JKL_SignData(preferredCSPHandle, calg, ckey, indata, outdata)) != 0)
      goto cleanup;
  }
  else{ 
    status = CR_SIGALG_UNSUP; 
    goto cleanup;
  }


  signature.data = outdata.Data;
  signature.data_len = outdata.Length;

cleanup:
// free on all return paths after JKL_asn_to_cssm for ckey 
  JKL_FreeData(ckey); 

  return status; 

}