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

//----------------------------------------------------------------------
// Filename:    pkcsmisc.c
// Description: This file contains cryptoki misc routines
//                              This file is machine-independent.
//
// Notice:              Copyright 1998 IBM Inc. All rights reserved.
//----------------------------------------------------------------------
//----------------------------------------
// includes
//----------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <time.h>

#include "pkcsjnh.h"
#include "pkcsint.h"

//
// Initialize token given the SO Pin to put on card
//

CK_RV PKCS_create_token_info(CRYPTO_TOKEN_HANDLE pfile, CK_CHAR_PTR pSOpin, CK_ULONG Pinlen) {

    CRYPTO_TOKEN        card;
    int                 dlen;

    DEBUG_MSG("Enter PKCS_create_token_info\n");

    if (!pfile) {
	 DEBUG_MSG("Token Not Recognized, exitting PKCS_create_token_info\n");
       return CKR_TOKEN_NOT_RECOGNIZED;
    }
       
    strcpy((char *)&card.token_info.label, TOKEN_LABEL);
    strcpy((char *)&card.token_info.manufacturerID, MANUFACTURER_ID);
    strcpy((char *)&card.token_info.model, TOKEN_MANUFACTURER);
    PKCS_generate_serial_number((CK_CHAR_PTR)&card.token_info.serialNumber, TOKEN_SN_LEN);
    card.token_info.flags = TOKEN_FLAGS;
    card.token_info.ulMaxSessionCount = TOKEN_MAX_SESSIONS;
    card.token_info.ulSessionCount = 0;
    card.token_info.ulMaxRwSessionCount = TOKEN_MAX_RW_SESSIONS;
    card.token_info.ulRwSessionCount = 0;
    card.token_info.ulMaxPinLen = TOKEN_MAX_PIN_LEN;
    card.token_info.ulMinPinLen = TOKEN_MIN_PIN_LEN;
    card.token_info.ulTotalPublicMemory = PUBLIC_OBJECT_SIZE;
    card.token_info.ulFreePublicMemory = PUBLIC_OBJECT_SIZE;
    card.token_info.ulTotalPrivateMemory = PRIVATE_OBJECT_SIZE;
    card.token_info.ulFreePrivateMemory = PRIVATE_OBJECT_SIZE;
    card.token_info.hardwareVersion.major = TOKEN_HARDWARE_MAJOR;
    card.token_info.hardwareVersion.minor = TOKEN_HARDWARE_MINOR;
    card.token_info.firmwareVersion.major = TOKEN_FIRMWARE_MAJOR;
    card.token_info.firmwareVersion.minor = TOKEN_FIRMWARE_MINOR;
    strcpy((char *)&card.token_info.utcTime, TOKEN_UTC);
 
    DEBUG_INFO("pSOpin = %x\n", pSOpin);
   
    if (!pSOpin) {
	// Get Initial Security Officer Pin
#ifdef JONAHINI
	card.token_secure.sopinlen = JONAH_get_initial_SO_pin((char *)&card.token_secure.sopin);
#else
      memcpy(card.token_secure.sopin, DEFAULT_SO_PIN, TOKEN_MAX_PIN_LEN);
      card.token_secure.sopinlen = strlen((char *)&card.token_secure.sopin);
#endif
    } else {
	// MAC Get hash of pSOpin & store on card
      memcpy(card.token_secure.sopin, pSOpin, TOKEN_MAX_PIN_LEN);
      card.token_secure.sopinlen = Pinlen;
    }

    strcpy((char *)&card.token_secure.userpin, "\0");
    card.token_secure.userpinlen = 0;
	card.token_secure.badsotries = 0;
 	card.token_secure.badusertries = 0;

    memset(&card.token_public.publicobject, NULL_PTR, PUBLIC_OBJECT_SIZE);
    card.token_public.headp_offset = NULL_PTR;
    card.token_public.freep_offset = NULL_PTR;
    card.token_public.numobjects = 0;
    memset(&card.token_private.privateobject, NULL_PTR, PRIVATE_OBJECT_SIZE);
    card.token_private.headp_offset = NULL_PTR;
    card.token_private.freep_offset = NULL_PTR;
    card.token_private.numobjects = 0;

	// Crypt the security information with the new Pin data
	PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
	
    dlen = fwrite((void *)&card, sizeof(CRYPTO_TOKEN), 1, pfile); 

    return CKR_OK;
   
}


//
// Create initial token
//

CRYPTO_TOKEN_HANDLE PKCS_create_token(CK_CHAR_PTR pslot, CK_CHAR_PTR pSOpin, CK_ULONG Pinlen) {
    
    CRYPTO_TOKEN_HANDLE pfile = NULL_PTR;
    int                 num;
    CK_RV               rv;

    DEBUG_MSG("Enter PKCS_create_token\n");

    if (!pfile) {
        pfile = fopen((const char *)pslot, "w+b");
    }
                                  
    if (!pfile) {
      // An error occurred creating the token
      DEBUG_MSG("Error creating token\n");
      return NULL_PTR;
    }

    /* Now write Token Fields to card */
    rv = PKCS_create_token_info(pfile, pSOpin, Pinlen);

	if (rv != CKR_OK) {
		return NULL_PTR;
	}

    num = fclose(pfile);

    DEBUG_MSG("Exit PKCS_create_token\n");
    return pfile;
      
}


//
// Open session                             
//

CRYPTO_TOKEN_HANDLE PKCS_open_card(CK_CHAR_PTR pslot, CK_STATE state) {
    
    CRYPTO_TOKEN_HANDLE pfile;

    DEBUG_MSG("Enter PKCS_open_card\n");

    switch (state)
    {
      case CKS_RW_PUBLIC_SESSION :
        pfile = fopen((const char *)pslot, "r+b"); break;
      case CKS_RW_SO_FUNCTIONS :
        pfile = fopen((const char *)pslot, "r+b"); break;
      case CKS_RW_USER_FUNCTIONS :
        pfile = fopen((const char *)pslot, "r+b"); break;
      case CKS_RO_PUBLIC_SESSION :
        pfile = fopen((const char *)pslot, "rb"); break;
      case CKS_RO_USER_FUNCTIONS :
        pfile = fopen((const char *)pslot, "rb"); break;
      default: /* Should not occur */ 
        return NULL;
    }

    if (!pfile) {
        DEBUG_MSG("Token not there, creating blank one\n");        
        /* Token not there.  Create the file token in the VSC */
        pfile = PKCS_create_token(pslot , NULL_PTR, 0);
        if (!pfile) {
		return NULL;
	  }
    }

    fclose(pfile);
    DEBUG_MSG("Exit PKCS_open_card\n");
    return pfile;
}


//
// Initialize a card                             
//

CRYPTO_TOKEN_HANDLE PKCS_init_card(CK_CHAR_PTR pslot, CK_CHAR_PTR pSOpin, CK_ULONG Pinlen) {
    
    CRYPTO_TOKEN_HANDLE pfile;

    DEBUG_MSG("Enter PKCS_init_card\n");

    pfile = fopen((const char *)pslot, "r+b");

    pfile = PKCS_create_token(pslot , pSOpin, Pinlen);

    fclose(pfile);

    DEBUG_MSG("Exit PKCS_init_card\n");
    return pfile;
}


//
// Read in token info                       
//

CK_RV PKCS_read_token_info(CK_CHAR_PTR addr, CK_TOKEN_INFO_PTR pInfo) {
    
    int                 numbytes=0, i=0, ptoken;
    CRYPTO_TOKEN        card;

    DEBUG_MSG("JCW: Entering PKCS_read_token_info!\n");
    DEBUG_INFO("Size of token info %x\n", sizeof(CK_TOKEN_INFO));
   
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }
   
    DEBUG_INFO("JCW: Reading entire file in %d byte chunks\n", sizeof(CRYPTO_TOKEN));
    DEBUG_INFO("JCW: Card buffer starts at %p\n", &card);

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                               
         numbytes = numbytes + i;
         DEBUG_INFO("JCW: Read a chunk size %d\n", i);
         DEBUG_INFO("     Total read = %d bytes\n", numbytes);
    }

    DEBUG_INFO("JCW: Done reading file.  Total size = %d bytes\n", numbytes);

    i = close(ptoken);

    if (numbytes > 0) {
        DEBUG_INFO("JCW: Copying %d bytes from card.token_info\n", sizeof(CK_TOKEN_INFO));
        DEBUG_INFO("     Source address = (%p)\n", &card.token_info);
        memcpy(pInfo, &card.token_info, sizeof(CK_TOKEN_INFO));
        DEBUG_INFO("pInfo = %s\n", (char *)pInfo);
        return CKR_OK;
    } else {
        return CKR_TOKEN_NOT_RECOGNIZED;
    }
}
 

//
// Read Pin info off token           
//

CK_RV PKCS_read_token_pin_info(CK_CHAR_PTR addr, CRYPTO_TOKEN_SECURE_INFO_PTR ptoken_secure) {
    
    int                 numbytes=0, i=0, ptoken;
    CRYPTO_TOKEN        card;

    DEBUG_MSG("JCW: Entering PKCS_read_token_pin_info\n");

    DEBUG_INFO("Size of pin info %x\n", sizeof(CRYPTO_TOKEN_SECURE_INFO));
   
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    if (numbytes > 0) {
        DEBUG_MSG("JCW: Decrypting security region\n");
		// Decrypt the information first and then write it to the memory
   		PKCS_decrypt_data((CK_CHAR *)&card.token_secure,
                                  sizeof(CRYPTO_TOKEN_SECURE_INFO));
        memcpy(ptoken_secure, &card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        DEBUG_INFO("security info: %s\n", (char *)ptoken_secure);
        return CKR_OK;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Read Public info off token           
//

CK_RV PKCS_read_token_public_info(CK_CHAR_PTR addr, CRYPTO_PUBLIC_OBJECTS_PTR ptoken_public) {
    
    int                 numbytes=0, i=0, ptoken;
    CRYPTO_TOKEN        card;

    DEBUG_MSG("JCW: Entering PKCS_read_token_public_info\n");
    DEBUG_INFO("Size of public objects %x\n", sizeof(CRYPTO_PUBLIC_OBJECTS));

    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    DEBUG_INFO("JCW: Reading entire card in %d byte chunks\n", sizeof(CRYPTO_TOKEN));
    DEBUG_INFO("     Buffer starts at %p\n", &card);

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
         DEBUG_INFO("JCW: Read one chunk, size = %d bytes\n", i);
         DEBUG_INFO("     Total read = %d bytes\n", numbytes);
    }
    DEBUG_INFO("JCW: Finished reading card, size = %d bytes\n", numbytes);


    if (numbytes > 0) {
        DEBUG_INFO("JCW: Copying %d bytes of public objects\n",
                   sizeof(CRYPTO_PUBLIC_OBJECTS));
        DEBUG_INFO("     Address of target buffer = %p\n",
                   ptoken_public);
        DEBUG_INFO("     Address of public objects = %p\n",
                   &card.token_public);
        memcpy(ptoken_public, &card.token_public, sizeof(CRYPTO_PUBLIC_OBJECTS));
        DEBUG_INFO("public info: %s\n", (char *)ptoken_public);
        return CKR_OK;
    } else {
        DEBUG_MSG("Couldn't read public info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Read Private info off token           
//

CK_RV PKCS_read_token_private_info(CK_CHAR_PTR addr, CRYPTO_PRIVATE_OBJECTS_PTR ptoken_private) {
    
    int                 numbytes=0, i=0, ptoken;
    CRYPTO_TOKEN        card;

    DEBUG_MSG("JCW: Entering PKCS_read_token_private_info\n");

    DEBUG_INFO("Size of private objects %x\n", sizeof(CRYPTO_PRIVATE_OBJECTS));
   
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    DEBUG_INFO("JCW: Reading entire card in %d byte chunks\n", sizeof(CRYPTO_TOKEN));
    DEBUG_INFO("     Buffer starts at %p\n", &card);

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
         DEBUG_INFO("JCW: Read one chunk, size = %d bytes\n", i);
         DEBUG_INFO("     Total read = %d bytes\n", numbytes);
    }
    DEBUG_INFO("JCW: Finished reading card, size = %d bytes\n", numbytes);

    if (numbytes > 0) {
        DEBUG_INFO("JCW: Copying %d bytes of private objects\n",
                   sizeof(CRYPTO_PRIVATE_OBJECTS));
        DEBUG_INFO("     Address of target buffer = %p\n",
                   ptoken_private);
        DEBUG_INFO("     Address of private objects = %p\n",
                   &card.token_private);
        memcpy(ptoken_private, &card.token_private, sizeof(CRYPTO_PRIVATE_OBJECTS));
        DEBUG_INFO("private info: %s\n", (char *)ptoken_private);
        return CKR_OK;
    } else {
        DEBUG_MSG("Couldn't read private info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}



//
// Update token
//

CK_RV PKCS_update_token(CK_CHAR_PTR pslot, CRYPTO_TOKEN * pcard) {
    
    CRYPTO_TOKEN_HANDLE pfile = NULL_PTR;
    int                 num;

    DEBUG_MSG("Enter PKCS_update_token\n");

    if (!pfile) {
        pfile = fopen((const char *)pslot, "w+b");
    }
                                  
    /* Now write Token Fields to card */
    DEBUG_INFO("JCW: writing entire card (%d bytes)\n", sizeof(CRYPTO_TOKEN));
    DEBUG_INFO("     Buffer starts at %p\n", pcard);

    num = fwrite((void *)pcard, sizeof(CRYPTO_TOKEN), 1, pfile); 

    num = fclose(pfile);

    DEBUG_MSG("Exit PKCS_update_token\n");
    return CKR_OK;
      
}



//
// Write User Pin info onto token           
//

CK_RV PKCS_write_user_pin_info(CK_CHAR_PTR addr, CK_CHAR_PTR pPin, CK_ULONG Pinlen) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    DEBUG_INFO("Size of pin info %x\n", sizeof(CRYPTO_TOKEN_SECURE_INFO));
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
	  // MAC get hash of user pin and store on card
        memcpy(&card.token_secure.userpin, pPin, TOKEN_MAX_PIN_LEN);
         card.token_secure.userpinlen = Pinlen;
         card.token_info.flags = card.token_info.flags | CKF_USER_PIN_INITIALIZED;
       DEBUG_INFO("New pin number: %s\n", (char *)pPin);
		// Re-crypt the security information with the new Pin data
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Write SO Pin info onto token           
//

CK_RV PKCS_write_so_pin_info(CK_CHAR_PTR addr, CK_CHAR_PTR pPin, CK_ULONG Pinlen) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    DEBUG_INFO("Size of pin info %x\n", sizeof(CRYPTO_TOKEN_SECURE_INFO));
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
	  // MAC hash so pin and put on card
        memcpy(&card.token_secure.sopin, pPin, TOKEN_MAX_PIN_LEN);
        card.token_secure.sopinlen = Pinlen;
        DEBUG_INFO("New pin number: %s\n", (char *)pPin);
		// Re-crypt the security information with the new Pin data
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}



//
// Write User bad attempts onto token           
//

CK_RV PKCS_invalid_user_attempts(CK_CHAR_PTR addr) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        card.token_secure.badusertries++;
	  // MAC hash user pin again and restore on card
        DEBUG_INFO("Number of bad user attempts: %d\n", card.token_secure.badusertries);
		// Re-crypt the security information with the new Pin data
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Reset User bad attempts onto token           
//

CK_RV PKCS_reset_user_attempts(CK_CHAR_PTR addr) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        card.token_secure.badusertries = 0;
        DEBUG_INFO("Number of bad user attempts: %d\n", card.token_secure.badusertries);
		// Re-crypt the security information with the new Pin data
	  // MAC get user pin again and do 1 hash to store on card
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Write SO bad attempts onto token           
//

CK_RV PKCS_invalid_so_attempts(CK_CHAR_PTR addr) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        card.token_secure.badsotries++;
	  // MAC re hash so pin and restore on card
        DEBUG_INFO("Number of bad so attempts: %d\n", card.token_secure.badsotries);
		// Re-crypt the security information with the new Pin data
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}


//
// Reset SO bad attempts onto token           
//

CK_RV PKCS_reset_so_attempts(CK_CHAR_PTR addr) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
		// Decrypt the security info read off the card
		PKCS_decrypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        card.token_secure.badsotries = 0;
        DEBUG_INFO("Number of bad so attempts: %d\n", card.token_secure.badsotries);
	  // MAC get SO pin from parameter and re-hash on card
		// Re-crypt the security information with the new Pin data
		PKCS_crypt_data((CK_CHAR *)&card.token_secure, sizeof(CRYPTO_TOKEN_SECURE_INFO));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read security info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}

//
// Write Public info onto token           
//

CK_RV PKCS_write_public_info(CK_CHAR_PTR addr, CRYPTO_PUBLIC_OBJECTS_PTR ptoken_public) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    DEBUG_INFO("Size of public info %x\n", sizeof(CRYPTO_PUBLIC_OBJECTS));
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
        // Update public memory settings
		card.token_info.ulFreePublicMemory = PUBLIC_OBJECT_SIZE - ptoken_public->freep_offset;
        memcpy(&card.token_public, ptoken_public, sizeof(CRYPTO_PUBLIC_OBJECTS));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
	    return rv;
    } else {
        DEBUG_MSG("Couldn't read token info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}

//
// Write Private info onto token           
//

CK_RV PKCS_write_private_info(CK_CHAR_PTR addr, CRYPTO_PRIVATE_OBJECTS_PTR ptoken_private) {
    
    int                      numbytes=0, i=0, ptoken; 
    CRYPTO_TOKEN             card;
    CK_RV                    rv;

    DEBUG_INFO("Size of priavate info %x\n", sizeof(CRYPTO_PRIVATE_OBJECTS));
    
    if ((ptoken = open((const char *)addr, O_BINARY, 0)) == -1) {
         DEBUG_INFO("cat: can't open %s\n", addr);
         return CKR_TOKEN_NOT_PRESENT;
    }

    while ((i = read(ptoken, &card+numbytes, sizeof(CRYPTO_TOKEN))) > 0)
    {                                                            
         numbytes = numbytes + i;
    }

    i = close(ptoken);
    
    if (numbytes > 0) {
        // Update private memory settings
		card.token_info.ulFreePrivateMemory = PRIVATE_OBJECT_SIZE - ptoken_private->freep_offset;
        memcpy(&card.token_private, ptoken_private, sizeof(CRYPTO_PRIVATE_OBJECTS));
        rv = PKCS_update_token(addr, &card);
        DEBUG_INFO("RC from update token: %x\n", rv);
        return rv;
    } else {
        DEBUG_MSG("Couldn't read token info\n");
        return CKR_TOKEN_NOT_RECOGNIZED;
    }

}

// 
// This function checks a template against one of the token templates
//

CK_BBOOL PKCS_template_match(OBJECT_TEMPLATE_PTR pobject, CK_ULONG numtemplates, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) {

	CK_ATTRIBUTE_PTR	ptemp;
	OBJECT_TEMPLATE_PTR	pobj;
	CK_ULONG i, j;
	CK_ULONG matches = 0;

	DEBUG_MSG("Enter PKCS_template_match\n");
	DEBUG_INFO("Number of templates to match = %d\n", ulCount);

	// Find all templates
	if (ulCount == 0) {
		return TRUE;
	}

	ptemp = pTemplate;
	DEBUG_INFO("pTemplate = %x\n", pTemplate);

	for (i = 1; i <= ulCount; i++) {
		pobj = pobject;
		DEBUG_INFO("Looking for attr %x ", ptemp->type);
		DEBUG_INFO("size %x ", ptemp->ulValueLen);
		for (j = 1; j <= numtemplates; j++) {
			DEBUG_INFO("Looking in object, attr = %x ", pobj->attribute);
			DEBUG_INFO("size %x ", pobj->value_size);
			if ((pobj->attribute == ptemp->type) && 
				(pobj->value_size == ptemp->ulValueLen) &&
				(memcmp(pobj->pvalue, ptemp->pValue, ptemp->ulValueLen) == 0)) {
					DEBUG_MSG("Attribute has matched\n");
					matches++;
			}
			DEBUG_INFO("pobj = %x\n", pobj);
			pobj = pobj->pnext;
			DEBUG_INFO("pobj now = %x\n", pobj);
		}
		ptemp++;
	}
	
	DEBUG_INFO("Number of templates %d\n", ulCount);
	DEBUG_INFO("Number of matches %d\n", matches);

	if (matches == ulCount) {
		return TRUE;
	} else {
		return FALSE;
	}
}


// 
// Delete an objects memory
//

CK_RV PKCS_delete_object_memory(TOKEN_OBJECT_PTR ptoken) {

    CK_RV					rv = CKR_OK;
    OBJECT_TEMPLATE_PTR     ptemplate, pt;
	CK_ULONG				numtemplates;

	numtemplates = ptoken->numtemplates;
	ptemplate = ptoken->pobject;

	while (numtemplates > 0) {
		if (ptemplate == NULL_PTR) {
			// error case
			rv =  CKR_GENERAL_ERROR;
		}

		if (ptemplate->pvalue != NULL_PTR) {
			free(ptemplate->pvalue);
		}

		pt = ptemplate;
		ptemplate = ptemplate->pnext;
		free(pt);
		numtemplates--;
	}

	free(ptoken);

	return rv;
}

