/* ***************************************************************** *
 * 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:    pkcstok.c 
// Description: This file contains cryptoki token 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 "pkcsjnh.h"
#include "pkcsint.h"
#include "pkcsllf.h"

CK_BBOOL        istrue = TRUE, isfalse = FALSE;

//
// Get Token information of the card        
//

CK_RV PKCS_get_token_information(CK_CHAR_PTR thandle, CK_TOKEN_INFO_PTR pInfo) {
    
    CK_RV rv;

    rv = PKCS_read_token_info(thandle, pInfo);
    
    return rv;

}

//
// Get Pin information of the card        
//

CK_RV PKCS_get_pin_information(CK_CHAR_PTR thandle, CRYPTO_TOKEN_SECURE_INFO_PTR pPinInfo) {
    
    CK_RV rv;

    rv = PKCS_read_token_pin_info(thandle, pPinInfo);
    
    return rv;

}

//
// Get Public objects off the card        
//

CK_RV PKCS_get_public_objects(CK_CHAR_PTR addr, TOKEN_OBJECT_PTR * pobject_list) {

    CRYPTO_PUBLIC_OBJECTS token_public;
    CRYPTO_PUBLIC_OBJECTS_PTR ptoken_public = &token_public;
    CK_RV rv;
    OBJECT_TEMPLATE_PTR   ptemplate, pt;
    TOKEN_OBJECT_PTR      ptoken_head, ptoken;
    CK_BYTE_PTR           pobject;
    CK_ULONG              numobjects, numtemplates;
	CK_BBOOL                          firstone;
	CK_ULONG *                        pulong;
	CK_ULONG                          objnum = 1;

	DEBUG_MSG("Enter PKCS_get_public_objects\n");

    ptoken_head = NULL_PTR;

    rv = PKCS_read_token_public_info(addr, &token_public);
				      
    numobjects = ptoken_public->numobjects;
	DEBUG_INFO("Number of public objects = %d\n", numobjects);

    if (numobjects > 0) {       // There are some objects
     
		/* allocate storage for first record */
		ptoken_head = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
		ptoken = ptoken_head;
		ptoken->pnext = NULL_PTR;
		DEBUG_INFO("Head of object list: %x\n", ptoken);
		ptoken->numtemplates = 0;
		ptoken->ohandle = objnum + PUBLIC_OBJECT;
		DEBUG_INFO("Object handle = %d\n", ptoken->ohandle);
		objnum++;
		numobjects--;
		DEBUG_MSG("Object found\n");

		/* Update token fields */
		DEBUG_INFO("ptoken_public = %x\n", ptoken_public);
		DEBUG_INFO("headp offset = %x\n", ptoken_public->headp_offset);
		pobject = ptoken_public->publicobject;
		DEBUG_INFO("pobject = %x\n", pobject);
		pulong = (CK_ULONG *)pobject;
		numtemplates = *pulong;
	DEBUG_INFO("Number of templates: %d\n", numtemplates);
		pobject = pobject + sizeof(CK_ULONG);
		firstone = TRUE;

		while (numtemplates > 0) {
			pt = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
			ptoken->numtemplates++;
			numtemplates--;
			DEBUG_INFO("Template %d\n", ptoken->numtemplates);                      
			if (!firstone) {
				ptemplate->pnext = pt;
				DEBUG_INFO("Template pointer to next template %x\n", ptemplate->pnext);
			} else {
				ptoken->pobject = pt;
				DEBUG_INFO("Object pointer to 1st template %x\n", ptoken->pobject);
				firstone = FALSE;
			}
			ptemplate = pt;
			pulong = (CK_ULONG *)pobject;
			ptemplate->attribute = *pulong;
			DEBUG_INFO("attribute = %d\n", ptemplate->attribute);
			pobject = pobject + sizeof(CK_ULONG);
			pulong = (CK_ULONG *)pobject;
			ptemplate->value_size = *pulong;
			DEBUG_INFO("object size: %d\n", ptemplate->value_size);
			pobject = pobject + sizeof(CK_ULONG);
			ptemplate->pvalue = (CK_BYTE_PTR)malloc(ptemplate->value_size);
			memcpy(ptemplate->pvalue, pobject, ptemplate->value_size);
			DEBUG_INFO("object value = %s\n", ptemplate->pvalue);
			pobject = pobject + ptemplate->value_size;
			ptemplate->pnext = NULL_PTR;
		}

		while (numobjects > 0) {
			DEBUG_MSG("Object found\n");
			ptoken->pnext = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
			ptoken = ptoken->pnext;
			ptoken->pnext = NULL_PTR;
			ptoken->numtemplates = 0;
			ptoken->ohandle = objnum + PUBLIC_OBJECT;
			DEBUG_INFO("Object handle = %d\n", ptoken->ohandle);
      
			pulong = (CK_ULONG *)pobject;
			numtemplates = *pulong;
		    DEBUG_INFO("Number of templates: %d\n", numtemplates);
			pobject = pobject + sizeof(CK_ULONG);
			firstone = TRUE;
	
			while (numtemplates > 0) {
				pt = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
				ptoken->numtemplates++;
				numtemplates--;
				DEBUG_INFO("Template %d\n", ptoken->numtemplates);                      
				if (!firstone) {
					ptemplate->pnext = pt;
					DEBUG_INFO("Template pointer to next template %x\n", ptemplate->pnext);
				} else {
					ptoken->pobject = pt;
					DEBUG_INFO("Object pointer to 1st template %x\n", ptoken->pobject);
					firstone = FALSE;
				}
				ptemplate = pt;
				pulong = (CK_ULONG *)pobject;
				ptemplate->attribute = *pulong;
				DEBUG_INFO("attribute = %d\n", ptemplate->attribute);
				pobject = pobject + sizeof(CK_ULONG);
				pulong = (CK_ULONG *)pobject;
				ptemplate->value_size = *pulong;
				DEBUG_INFO("object size: %d\n", ptemplate->value_size);
				pobject = pobject + sizeof(CK_ULONG);
				ptemplate->pvalue = (CK_BYTE_PTR)malloc(ptemplate->value_size);
				memcpy(ptemplate->pvalue, pobject, ptemplate->value_size);
				DEBUG_INFO("object value = %s\n", ptemplate->pvalue);
				pobject = pobject + ptemplate->value_size;
				ptemplate->pnext = NULL_PTR;
			}
			objnum++;
			numobjects--;
		} 

    } else {
		DEBUG_MSG("No defined objects\n");
    }

    *pobject_list = ptoken_head;
	DEBUG_INFO("Address of object list is %x\n", *pobject_list);

	DEBUG_MSG("Exit PKCS_get_public_objects\n");
    return rv;

}


//
// Get Private objects off the card        
//

CK_RV PKCS_get_private_objects(CK_CHAR_PTR addr, TOKEN_OBJECT_PTR * pobject_list) {

    CRYPTO_PRIVATE_OBJECTS token_private;
    CRYPTO_PRIVATE_OBJECTS_PTR ptoken_private = &token_private;
    CK_RV rv;
    OBJECT_TEMPLATE_PTR   ptemplate, pt;
    TOKEN_OBJECT_PTR      ptoken_head, ptoken;
    CK_BYTE_PTR           pobject;
    CK_ULONG              numobjects, numtemplates;
	CK_BBOOL                          firstone;
	CK_ULONG *                        pulong;
	CK_ULONG                          objnum = 1;

	DEBUG_MSG("Enter PKCS_get_private_objects\n");

    ptoken_head = NULL_PTR;

    rv = PKCS_read_token_private_info(addr, &token_private);
				      
    numobjects = ptoken_private->numobjects;
	DEBUG_INFO("Number of private objects: %d\n", numobjects);
    
    if (numobjects > 0) {       // There are some objects
     
      /* allocate storage for first record */
      ptoken_head = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
      ptoken = ptoken_head;
      ptoken->pnext = NULL_PTR;
      DEBUG_INFO("Head of object list: %x\n", ptoken);
      ptoken->numtemplates = 0;
	  ptoken->ohandle = objnum + PRIVATE_OBJECT;
      DEBUG_INFO("Object handle = %d\n", ptoken->ohandle);
      objnum++;
	  numobjects--;
      DEBUG_MSG("Object found\n");

      /* Update token fields */
      DEBUG_INFO("ptoken_private = %x\n", ptoken_private);
	  DEBUG_INFO("headp offset = %x\n", ptoken_private->headp_offset);
	  pobject = (CK_BYTE_PTR)ptoken_private->privateobject;
	  DEBUG_INFO("pobject = %x\n", pobject);
      pulong = (CK_ULONG *)pobject;
	  numtemplates = *pulong;
	  DEBUG_INFO("Number of templates: %d\n", numtemplates);
	  pobject = pobject + sizeof(CK_ULONG);
	  firstone = TRUE;
	  
	  while (numtemplates > 0) {
		pt = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
		ptoken->numtemplates++;
		numtemplates--;
		DEBUG_INFO("Template %d\n", ptoken->numtemplates);                      
		if (!firstone) {
			ptemplate->pnext = pt;
			DEBUG_INFO("Template pointer to next template %x\n", ptemplate->pnext);
		} else {
			ptoken->pobject = pt;
			DEBUG_INFO("Object pointer to 1st template %x\n", ptoken->pobject);
			firstone = FALSE;
		}
		ptemplate = pt;
		pulong = (CK_ULONG *)pobject;
		ptemplate->attribute = *pulong;
		DEBUG_INFO("attribute = %d\n", ptemplate->attribute);
		pobject = pobject + sizeof(CK_ULONG);
		
		pulong = (CK_ULONG *)pobject;
		ptemplate->value_size = *pulong;
		DEBUG_INFO("object size: %d\n", ptemplate->value_size);
		pobject = pobject + sizeof(CK_ULONG);
		ptemplate->pvalue = (CK_BYTE_PTR)malloc(ptemplate->value_size);
		memcpy(ptemplate->pvalue, pobject, ptemplate->value_size);
		DEBUG_INFO("object value = %s\n", ptemplate->pvalue);
		pobject = pobject + ptemplate->value_size;
		ptemplate->pnext = NULL_PTR;
      } 

      while (numobjects > 0) {
		DEBUG_MSG("Object found\n");
		ptoken->pnext = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
		ptoken = ptoken->pnext;
		ptoken->pnext = NULL_PTR;
		ptoken->numtemplates = 0;
		ptoken->ohandle = objnum + PRIVATE_OBJECT;
		DEBUG_INFO("Object handle = %d\n", ptoken->ohandle);
      
		pulong = (CK_ULONG *)pobject;
		numtemplates = *pulong;
	    DEBUG_INFO("Number of templates: %d\n", numtemplates);
		pobject = pobject + sizeof(CK_ULONG);
		firstone = TRUE;

		while (numtemplates > 0) {
			pt = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
			ptoken->numtemplates++;
			numtemplates--;
			DEBUG_INFO("Template %d\n", ptoken->numtemplates);                      
			if (!firstone) {
				ptemplate->pnext = pt;
				DEBUG_INFO("Template pointer to next template %x\n", ptemplate->pnext);
			} else {
				ptoken->pobject = pt;
				DEBUG_INFO("Object pointer to 1st template %x\n", ptoken->pobject);
				firstone = FALSE;
			}
			ptemplate = pt;
			pulong = (CK_ULONG *)pobject;
			ptemplate->attribute = *pulong;
			DEBUG_INFO("attribute = %d\n", ptemplate->attribute);
			pobject = pobject + sizeof(CK_ULONG);
			pulong = (CK_ULONG *)pobject;
			ptemplate->value_size = *pulong;
			DEBUG_INFO("object size: %d\n", ptemplate->value_size);
			pobject = pobject + sizeof(CK_ULONG);
			ptemplate->pvalue = (CK_BYTE_PTR)malloc(ptemplate->value_size);
			memcpy(ptemplate->pvalue, pobject, ptemplate->value_size);
			DEBUG_INFO("object value = %s\n", ptemplate->pvalue);
			pobject = pobject + ptemplate->value_size;
			ptemplate->pnext = NULL_PTR;
		}
		objnum++;
		numobjects--;
      } 

    } else {
		DEBUG_MSG("No defined objects\n");
    }

    *pobject_list = ptoken_head;
	DEBUG_INFO("Returning object list %x\n", *pobject_list);

	DEBUG_MSG("Exit PKCS_get_private_objects\n");
    return rv;

}


//
// Write user pin information onto the card
//

CK_RV PKCS_write_user_pin(CK_CHAR_PTR addr, CK_CHAR_PTR pPin, CK_ULONG Pinlen) {
    
    CK_RV rv;

    rv = PKCS_write_user_pin_info(addr, pPin, Pinlen);
    
    return rv;

}


//
// Write SO pin information onto the card
//

CK_RV PKCS_write_so_pin(CK_CHAR_PTR addr, CK_CHAR_PTR pPin, CK_ULONG Pinlen) {
    
    CK_RV rv;

    rv = PKCS_write_so_pin_info(addr, pPin, Pinlen);
    
    return rv;

}


//
// Write public information onto the card
//

CK_RV PKCS_write_public(CK_CHAR_PTR addr, TOKEN_OBJECT_PTR ptoken_head) {
    
    CK_RV rv;
    CRYPTO_PUBLIC_OBJECTS token_public;
    TOKEN_OBJECT_PTR  ptoken = ptoken_head;
    OBJECT_TEMPLATE_PTR  pobject;
    CK_ULONG i = 0, numtemplates;
	CK_ULONG *      pulong;
    CK_BYTE             object[2 * PUBLIC_OBJECT_SIZE];

    DEBUG_MSG("Enter PKCS_write_public\n");

    memset(&token_public, NULL_PTR, sizeof(CRYPTO_PUBLIC_OBJECTS));

    token_public.numobjects = 0;
    token_public.headp_offset = 0;
    token_public.freep_offset = 0;

    while (ptoken != NULL_PTR) {
		token_public.numobjects++;
		DEBUG_INFO("Object %d found\n", token_public.numobjects);
		pobject = ptoken->pobject;

		// Write number of templates in this object
		numtemplates = ptoken->numtemplates;
		memcpy(&object[i], &numtemplates, sizeof(CK_ULONG));
		i = i + sizeof(CK_ULONG);
		DEBUG_INFO("Number of Templates = %d\n", &numtemplates);
		
		while (numtemplates > 0) {
			if (pobject == NULL_PTR) {
				DEBUG_INFO("Template mismatch on object %d\n", numtemplates);
				return CKR_TEMPLATE_INCONSISTENT;
			}
			DEBUG_INFO("Attribute: %x ", pobject->attribute);
//                      memcpy(&object[i], &pobject->attribute, sizeof(CK_ULONG));
			pulong = (CK_ULONG *)&object[i];
			*pulong = pobject->attribute;
			i = i + sizeof(CK_ULONG);
			DEBUG_INFO("Size: %x ", pobject->value_size);
//                      memcpy(&object[i], &pobject->value_size, sizeof(CK_ULONG)); 
			pulong = (CK_ULONG *)&object[i];
			*pulong = pobject->value_size;
			i = i + sizeof(CK_ULONG);
			DEBUG_INFO("Value: %s\n", pobject->pvalue);
			memcpy(&object[i], pobject->pvalue, pobject->value_size);
			i = i + pobject->value_size;
			pobject = pobject->pnext;
			numtemplates--;
		}
		ptoken = ptoken->pnext;
		if (i > PUBLIC_OBJECT_SIZE)
			break;
    } 

    if (i > PUBLIC_OBJECT_SIZE) {
	return CKR_DEVICE_MEMORY;
    } else {
	memcpy(&token_public.publicobject, &object, i);
	DEBUG_INFO("Public offset pointer = %d\n", i);
	token_public.freep_offset = i;
    }

    rv = PKCS_write_public_info(addr, &token_public); 
    
    DEBUG_MSG("Exit PKCS_write_public\n");
    return rv;

}


//
// Write private information onto the card
//

CK_RV PKCS_write_private(CK_CHAR_PTR addr, TOKEN_OBJECT_PTR ptoken_head) {
    
    CK_RV rv;
    CRYPTO_PRIVATE_OBJECTS token_private;
    TOKEN_OBJECT_PTR  ptoken = ptoken_head;
    OBJECT_TEMPLATE_PTR  pobject;
    CK_ULONG i = 0, numtemplates;
	CK_ULONG *      pulong;
    CK_BYTE             object[2 * PRIVATE_OBJECT_SIZE];

    DEBUG_MSG("Enter PKCS_write_private\n");

    memset(&token_private, NULL_PTR, sizeof(CRYPTO_PRIVATE_OBJECTS));

    token_private.numobjects = 0;
    token_private.headp_offset = 0;
    token_private.freep_offset = 0;

    while (ptoken != NULL_PTR) {
		token_private.numobjects++;
		DEBUG_INFO("Object %d found\n", token_private.numobjects);
		pobject = ptoken->pobject;

		// Write number of templates
		numtemplates = ptoken->numtemplates;
		memcpy(&object[i], &numtemplates, sizeof(CK_ULONG));
		i = i + sizeof(CK_ULONG);
		DEBUG_INFO("Number of Templates = %d\n", numtemplates);

		while (numtemplates > 0) {
			DEBUG_INFO("Iteration %d\n", numtemplates);
			if (pobject == NULL_PTR) {
				DEBUG_INFO("Template mismatch on template %d\n", numtemplates);
				return CKR_TEMPLATE_INCONSISTENT;
			}
			DEBUG_INFO("Attribute: %x ", pobject->attribute);
//                      memcpy(&object[i], &pobject->attribute, sizeof(CK_ULONG));
			pulong = (CK_ULONG *)&object[i];
			*pulong = pobject->attribute;
			i = i + sizeof(CK_ULONG);
			DEBUG_INFO("Size: %x ", pobject->value_size);
//                      memcpy(&object[i], &pobject->value_size, sizeof(CK_ULONG)); 
			pulong = (CK_ULONG *)&object[i];
			*pulong = pobject->value_size;
			i = i + sizeof(CK_ULONG);
			DEBUG_INFO("Value: %s\n", pobject->pvalue);
			memcpy(&object[i], pobject->pvalue, pobject->value_size);
			i = i + pobject->value_size;
			pobject = pobject->pnext;
			numtemplates--;
		}
		ptoken = ptoken->pnext;
		if (i > PRIVATE_OBJECT_SIZE)
			break;
	} 

    if (i > PRIVATE_OBJECT_SIZE) {
	return CKR_DEVICE_MEMORY;
    } else {
	memcpy(&token_private.privateobject, &object, i);
	DEBUG_INFO("Private offset pointer in hex= %x\n", i);
	token_private.freep_offset = i;
    }

    rv = PKCS_write_private_info(addr, &token_private); 
    
    DEBUG_MSG("Exit PKCS_write_private\n");
    return rv;
}


//
// Initialize a token                        
//

CRYPTO_TOKEN_HANDLE PKCS_token_init(CK_CHAR_PTR pslot, CK_CHAR_PTR pSOpin, CK_ULONG Pinlen) {
    
    CRYPTO_TOKEN_HANDLE         thandle;

    thandle = PKCS_init_card(pslot, pSOpin, Pinlen); 
    
    return thandle;

}


//
// Add new object onto the token
//

CK_RV PKCS_add_object(CK_CHAR_PTR addr, TOKEN_OBJECT_PTR * private_head, TOKEN_OBJECT_PTR * public_head, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) {
    
    CK_RV rv;
    TOKEN_OBJECT_PTR  ptoken_head, ptoken;
    TOKEN_OBJECT_PTR  ptoken_obj;   // object to be added to list
    OBJECT_TEMPLATE_PTR pobject, pnobject;
    CK_BBOOL            isprivate = TRUE, istoken = FALSE, bval, ishead = FALSE;

    DEBUG_MSG("Enter PKCS_add_object\n");

    if (pTemplate == NULL_PTR) {
      DEBUG_MSG("Template pointer is null\n");
      return CKR_TEMPLATE_INCOMPLETE;
    }

    ptoken_obj = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
    ptoken_obj->numtemplates = ulCount;
	DEBUG_INFO("Number of object templates %d\n", ulCount);
    ptoken_obj->pnext = NULL_PTR;
    if (ulCount > 0) {
      pobject = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
      ptoken_obj->pobject = pobject;
    } else {
      // Error case
      DEBUG_MSG("Error in template\n");
      return CKR_TEMPLATE_INCONSISTENT;
    }
    
    while (ulCount > 0) {
	  // Check to see if this is the private template
      if (pTemplate->type == CKA_PRIVATE) {
		memcpy(&bval,pTemplate->pValue, pTemplate->ulValueLen); 
		  DEBUG_INFO("Found the Private Template: %x\n", bval);
		if (!bval) {
			DEBUG_MSG("This is a public object\n");
			isprivate = FALSE;
		}
      }
      if (pTemplate->type == CKA_TOKEN) {
		memcpy(&bval,pTemplate->pValue, pTemplate->ulValueLen); 
		  DEBUG_INFO("Found the Token Template: %x\n", bval);
		if (bval) {
			DEBUG_MSG("This is a token object\n");
			istoken = TRUE;
		}
      }
	  DEBUG_INFO("Attribute: %x ", pTemplate->type);
      pobject->attribute = pTemplate->type;
	  DEBUG_INFO("Size: %d ", pTemplate->ulValueLen);
      pobject->value_size = pTemplate->ulValueLen;
	  DEBUG_INFO("value: %s\n", pTemplate->pValue);
      pobject->pvalue = (CK_BYTE_PTR)malloc(pTemplate->ulValueLen);
      memcpy(pobject->pvalue, pTemplate->pValue, pTemplate->ulValueLen);
      ulCount--;
	  DEBUG_INFO("pTemplate before, %x\n", pTemplate);
      pTemplate++;
	  DEBUG_INFO("pTemplate after, %x\n", pTemplate)
	  if (ulCount > 0) {
		pobject->pnext = (OBJECT_TEMPLATE *)calloc(sizeof(OBJECT_TEMPLATE), 1);
		pobject = pobject->pnext;
      } else {
		pobject->pnext = NULL_PTR;
      }
    }

    // See which list to add object to
    if (isprivate) {
		/* Check to see you have proper authority */
		ptoken_head = *private_head;
    } else {
		/* Check to see you have proper authority */
		ptoken_head = *public_head;
    }
    ptoken = ptoken_head;
	DEBUG_INFO("Token head = %x\n", ptoken);

	*phObject = 1;
    
	// If first object in chain, becomes head
    if (ptoken_head == NULL_PTR) {
		ishead = TRUE;
		ptoken_head = ptoken_obj;
		if (isprivate) {
			*private_head = ptoken_obj;
			DEBUG_INFO("Address of private head %x\n", *private_head);
		} else {
			*public_head = ptoken_obj;
			DEBUG_INFO("Address of public head %x\n", *public_head);
		}
    } else {
		while (ptoken->pnext != NULL_PTR) {
			ptoken = ptoken->pnext;
			*phObject = *phObject + 1;
		} 
		// Add new to end of chain      
		ptoken->pnext = ptoken_obj;
    }

    // Check to see if object is a token object.  If it is, don't need to
    // write it to the card.
    if (isprivate) {
	DEBUG_MSG("Writing private object\n");
	ptoken_obj->ohandle = *phObject + PRIVATE_OBJECT;
	DEBUG_INFO("Object handle = %d\n", ptoken_obj->ohandle);
	if (istoken) {
		rv = PKCS_write_private(addr, ptoken_head); 
	} else {
		DEBUG_MSG("Object is a session object\n");
	}
    } else {
	DEBUG_MSG("Writing public object\n");
	ptoken_obj->ohandle = *phObject + PUBLIC_OBJECT;
	DEBUG_INFO("Object handle = %d\n", ptoken_obj->ohandle);
	if (istoken) {
		rv = PKCS_write_public(addr, ptoken_head);
	} else {
		DEBUG_MSG("Object is a session object\n");
	}
    }

    if (rv) {
	// A problem adding the object
	DEBUG_INFO("Error writing object, rc = %x\n", rv);
	if (ishead) {
		if (isprivate) {
			DEBUG_MSG("Resetting private head\n");
			*private_head = NULL_PTR;
		 } else {
			DEBUG_MSG("Resetting public head\n");
			*public_head = NULL_PTR;
		 }
	} else {
		DEBUG_MSG("Getting rid of pointer to object we failed to add\n");
		ptoken->pnext = NULL_PTR;
	}

	// Now free memory you created
	pobject = ptoken_obj->pobject;
	pnobject = pobject;
      while (pnobject != NULL_PTR) {
	pnobject = pobject->pnext;
	free(pobject);
		pobject = pnobject;
	}

	// Free head
	free(ptoken_obj);
	
	return rv;
    }

    DEBUG_INFO("Object handle to return %x\n", *phObject);

    DEBUG_MSG("Exit PKCS_add_object\n");
    return rv;

}


// 
// This function takes a template and copies the templates up to a
// max number into a location.  It returns the number of objects that
// match

CK_RV PKCS_find_object(TOKEN_OBJECT_PTR private_head, TOKEN_OBJECT_PTR public_head, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG_PTR pcurrobj, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) {

    CK_RV                                       rv = CKR_OK;
    TOKEN_OBJECT_PTR            ptoken;
    OBJECT_TEMPLATE_PTR         pobject;
    CK_ULONG                            numtemplates;

    DEBUG_MSG("Enter PKCS_find_object\n");

    if (pTemplate == NULL_PTR) {
      DEBUG_MSG("Template pointer is null\n");
      return CKR_TEMPLATE_INCOMPLETE;
    }

	*pulObjectCount = 0;

	ptoken = public_head;
    while (ptoken != NULL_PTR) {
		pobject = ptoken->pobject;

		// Write number of templates
		numtemplates = ptoken->numtemplates;
		DEBUG_INFO("Number of Templates = %d\n", numtemplates);

		// See if my template matches this object
		if (*pcurrobj < ptoken->ohandle) {
			if (PKCS_template_match(pobject, numtemplates, pTemplate, ulCount)) {
				// write this template to object list
				*phObject = ptoken->ohandle;
				DEBUG_INFO("Object has matched, handle = %d\n", *phObject);
				phObject = phObject++;
				(*pulObjectCount)++;
				*pcurrobj = ptoken->ohandle;
				if (*pulObjectCount == ulMaxObjectCount) {
					DEBUG_MSG("Max objects reached\n");
					break;
				}
			} else {
				*pcurrobj = ptoken->ohandle;
			}
		}
		ptoken = ptoken->pnext;
	} 
    
	if (*pulObjectCount < ulMaxObjectCount) {
		ptoken = private_head;
		while (ptoken != NULL_PTR) {
			pobject = ptoken->pobject;
			// Write number of templates
			numtemplates = ptoken->numtemplates;
			DEBUG_INFO("Number of Templates = %d\n", numtemplates);
			// See if my template matches this object
			if (*pcurrobj < ptoken->ohandle) {
				if (PKCS_template_match(pobject, numtemplates, pTemplate, ulCount)) {
					// write this template to object list
					*phObject = ptoken->ohandle;
					DEBUG_INFO("Object has matched, handle = %d\n", *phObject);
					phObject = phObject++;
					(*pulObjectCount)++;
					*pcurrobj = ptoken->ohandle;
					if (*pulObjectCount == ulMaxObjectCount) {
						DEBUG_MSG("Max objects reached\n");
						break;
					}
				} else {
					*pcurrobj = ptoken->ohandle;
				}
			}
			ptoken = ptoken->pnext;
		}
	}
 
	DEBUG_MSG("Exit PKCS_find_object\n");
    return rv;
}



// 
// This function searches the token object list to
// get the specified object.  It records the size
// of the object templates for that object.                          

CK_RV PKCS_get_object_size(TOKEN_OBJECT_PTR private_head, TOKEN_OBJECT_PTR public_head, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR object_size) {

    CK_RV                                       rv = CKR_OK;
    TOKEN_OBJECT_PTR            ptoken;
    OBJECT_TEMPLATE_PTR         pobject;
	CK_ULONG                                objcount=0;

    DEBUG_MSG("Enter PKCS_get_object_size\n");

	if (hObject < PRIVATE_OBJECT) {
		DEBUG_MSG("Looking for public object\n");
		// Make sure you can look at public object
		ptoken = public_head;
	} else {
		DEBUG_MSG("Looking for private object\n");
		// Make sure you can look at private object
		ptoken = private_head;
	}
    
	DEBUG_INFO("Looking for object %d\n", hObject);
    while (ptoken != NULL_PTR) {
		DEBUG_INFO("Object handle %d\n", ptoken->ohandle);
		if (ptoken->ohandle == hObject) {
			break;
		}
		ptoken = ptoken->pnext;
    }

	DEBUG_INFO("Token pointer is %x\n", ptoken);
	if (ptoken == NULL_PTR) {
		DEBUG_MSG("Object handle not found\n");
		return CKR_OBJECT_HANDLE_INVALID;
	}

	// We have the right object, now get the data
	pobject = ptoken->pobject;
	while (pobject != NULL_PTR) {
		objcount = objcount + sizeof(CK_ATTRIBUTE_TYPE) + sizeof(CK_VOID_PTR) + sizeof(CK_ULONG);
		pobject = pobject->pnext;
	 }
 
	*object_size = objcount;

	DEBUG_MSG("Exit PKCS_get_object_size\n");
    return rv;
}



// 
// This function searches the token object list to
// get the specified object.  It fills in the
// template with the requested information

CK_RV PKCS_get_object_data(TOKEN_OBJECT_PTR private_head, 
			   TOKEN_OBJECT_PTR public_head, 
			   CK_ATTRIBUTE_PTR pTemplate, 
			   CK_ULONG ulCount, 
			   CK_OBJECT_HANDLE hObject) {

  CK_RV                       rv = CKR_OK;
  TOKEN_OBJECT_PTR              ptoken;
  OBJECT_TEMPLATE_PTR           pobject;
  CK_ATTRIBUTE_PTR              pattr = pTemplate;

  DEBUG_MSG("Enter PKCS_get_object_data\n");

  DEBUG_INFO("JCW: On entry, pattr->pValue == %p\n", pattr->pValue);

  if (pTemplate == NULL_PTR) {
    DEBUG_MSG("Template pointer is null\n");
    return CKR_TEMPLATE_INCOMPLETE;
  }

  if (hObject < PRIVATE_OBJECT) {
    DEBUG_MSG("Looking for public object\n");
// Make sure you can look at public object
    ptoken = public_head;
  } else {
    DEBUG_MSG("Looking for private object\n");
// Make sure you can look at private object
    ptoken = private_head;
  }
    
  DEBUG_INFO("Looking for object %d\n", hObject);
  while (ptoken != NULL_PTR) {
    DEBUG_INFO("Object handle %d\n", ptoken->ohandle);
    if (ptoken->ohandle == hObject) {
      break;
    }
    ptoken = ptoken->pnext;
  }

  DEBUG_INFO("Token pointer is %p\n", ptoken);
  if (ptoken == NULL_PTR) {
    DEBUG_MSG("Object handle not found\n");
    return CKR_OBJECT_HANDLE_INVALID;
  }

// Make sure that object is viewable

// We have the right object, now get the data
  while (ulCount > 0) {
// find template
    DEBUG_INFO("JCW: Start of search loop, pattr->type == %x\n", pattr->type);
    DEBUG_INFO("     pattr->ulValueLen == %d\n", pattr->ulValueLen);
    DEBUG_INFO("     pattr->pValue == %p\n", pattr->pValue);
    pobject = ptoken->pobject;
    DEBUG_INFO("Type to look for %x\n", pattr->type);
    while (pobject != NULL_PTR) {
      DEBUG_INFO("Type in this template %x\n", pobject->attribute);
      if (pobject->attribute == pattr->type) {
	break;
      }
      pobject = pobject->pnext;
    }
		
// Handle no attribute case
    if (pobject == NULL_PTR) {
      DEBUG_MSG("JCW: Attribute not on card, checking for default\n");
      switch (pattr->type) {
		case CKA_PRIVATE :
			pattr->ulValueLen = sizeof(CK_BBOOL);
			break;
		case CKA_MODIFIABLE :
			pattr->ulValueLen = sizeof(CK_BBOOL);
			break;
		case CKA_TOKEN :
			pattr->ulValueLen = sizeof(CK_BBOOL);
			break;
		case CKA_LABEL :
			pattr->ulValueLen = 0;
			break;
		default:
			pattr->ulValueLen = -1;
		goto goon;
      }
    }
    DEBUG_MSG("JCW: Found attribute!\n");

// Handle NULL_PTR case
    if (pattr->pValue == NULL_PTR) {
	if (pobject != NULL_PTR) {
	pattr->ulValueLen = pobject->value_size;
	}
	DEBUG_INFO("Template ptr is null, length %d returned\n",
		     pattr->ulValueLen);
      goto goon;
    }

// Handle normal case
    if (pobject != NULL_PTR) {
	if (pattr->ulValueLen >= pobject->value_size) {
	DEBUG_MSG("Template found, copying\n");
	DEBUG_INFO("JCW: Copying %d bytes\n", pobject->value_size);
	DEBUG_INFO("     Source address = %p\n", pobject->pvalue);
	DEBUG_INFO("     Target address = %p\n", pattr->pValue);
			pattr->ulValueLen = pobject->value_size;
	memcpy(pattr->pValue, pobject->pvalue, pobject->value_size);
	DEBUG_MSG("JCW: Copy done\n");
	goto goon;
	}
    } else {
		DEBUG_INFO("Default attribute type is %x\n", pattr->type);
		DEBUG_INFO("Pointer to value = %x\n", pattr->pValue);
	      switch (pattr->type) {
			case CKA_PRIVATE :
				memcpy(pattr->pValue, &istrue, sizeof(CK_BBOOL));
				break;
			case CKA_MODIFIABLE :
				memcpy(pattr->pValue, &istrue, sizeof(CK_BBOOL));
				break;
			case CKA_TOKEN :
				memcpy(pattr->pValue, &isfalse, sizeof(CK_BBOOL));
				break;
			case CKA_LABEL :
				break;
			default:
			goto goon;
	}
	goto goon;
    }
		
// Should not get here, but if so...
    pattr->ulValueLen = -1;
  
goon:
    ulCount--;
    pattr++;
  }
 
  DEBUG_MSG("Exit PKCS_get_object_data\n");
  return rv;
}


// 
// This function searches the token object list to
// get the specified object.  It then destroys
// the object memory and deletes it from the card

CK_RV PKCS_destroy_object(TOKEN_OBJECT_PTR * private_head, TOKEN_OBJECT_PTR * public_head, CK_OBJECT_HANDLE hObject) {

    CK_RV                                       rv = CKR_OK;
    TOKEN_OBJECT_PTR            ptoken, ptoken_previous = NULL_PTR;

    DEBUG_MSG("Enter PKCS_destroy_object\n");

	if (hObject < PRIVATE_OBJECT) {
		DEBUG_MSG("Looking for public object\n");
		// Make sure you have authority to delete private object
		ptoken = *public_head;
	} else {
		DEBUG_MSG("Looking for private object\n");
		// Make sure you have authority to delete public object
		ptoken = *private_head;
	}
    
	DEBUG_INFO("Looking for object %d\n", hObject);
    while (ptoken != NULL_PTR) {
		DEBUG_INFO("Object handle %d\n", ptoken->ohandle);
		if (ptoken->ohandle == hObject) {
			break;
		}
		ptoken_previous = ptoken;
		ptoken = ptoken->pnext;
    }

	DEBUG_INFO("Token pointer is %x\n", ptoken);
	if (ptoken == NULL_PTR) {
		DEBUG_MSG("Object handle not found\n");
		return CKR_OBJECT_HANDLE_INVALID;
	}


	// Make sure object is deletable

	// remove the object from the queue
	if (ptoken_previous == NULL_PTR) {
		if (hObject < PRIVATE_OBJECT) {
			DEBUG_MSG("Resetting public object head\n");
			*public_head = ptoken->pnext;
		} else {
			DEBUG_MSG("Resetting private object head\n");
			*private_head = ptoken->pnext;
		}
	} else {
		DEBUG_MSG("Removing ptoken from list\n");
		ptoken_previous->pnext = ptoken->pnext;
	}

	// Delete memory of this object
    rv = PKCS_delete_object_memory(ptoken);

	DEBUG_MSG("Exit PKCS_destroy_object\n");
    return rv;
}


//
// Free objects
//

CK_RV PKCS_free_objects(TOKEN_OBJECT_PTR ptoken_head) {
    
    CK_RV rv;
    TOKEN_OBJECT_PTR  ptoken = ptoken_head;
	CK_ULONG                  i = ptoken->numtemplates;

    DEBUG_MSG("Enter PKCS_free_objects\n");

    while (ptoken != NULL_PTR) {
		DEBUG_INFO("Going to delete token at %x\n", ptoken);
		rv = PKCS_delete_object_memory(ptoken);
		if (rv != CKR_OK) {
			DEBUG_INFO("Failed to free object, rc = %x\n", rv);
		}
		ptoken = ptoken->pnext;
    } 
    
    DEBUG_MSG("Exit PKCS_free_objects\n");
    return rv;

}
