//----------------------------------------------------------------------
// Filename:    pkcsmain.c
// Description: This file contains cryptoki 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"

// Function list
static CK_FUNCTION_LIST		function_list;
static CK_FUNCTION_LIST_PTR	pfunction_list = &function_list;

// Slot and token information
static CK_INFO_PTR             pcrypto_info = NULL_PTR;
static CK_ULONG                ulPopulatedSlots = 1;
static CRYPTO_SLOT_INFO_PTR    pcrypto_slot[CRYPTOKI_MAX_SLOTS] = {NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
															NULL_PTR, NULL_PTR,	NULL_PTR, NULL_PTR};

// Session information
static CRYPTO_SESSION_INFO_PTR pcrypto_session_info[CRYPTOKI_MAX_SESSIONS] = {	NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
																		NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
																		NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
																		NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR };

//----------------------------------------------------------------------
// Initialize Cryptoki
//----------------------------------------------------------------------

CK_RV C_Initialize(CK_VOID_PTR initptr)
{
    CK_RV       rv;

    DEBUG_MSG("Enter C_Initialize\n");

    rv = PKCS_init_cryptoki(&pcrypto_info);
    DEBUG_INFO("Pcrypto info %s\n", pcrypto_info);

    if (rv != CKR_OK) {
		DEBUG_INFO("Cryptoki failed to initialize, rc = %x\n", rv);
		return CKR_HOST_MEMORY;
    }

	pcrypto_slot[0] = (CRYPTO_SLOT_INFO_PTR) calloc(sizeof(CRYPTO_SLOT_INFO), 1);
	pcrypto_slot[0]->ppublic_object_list = NULL_PTR;
	pcrypto_slot[0]->pprivate_object_list = NULL_PTR;
	pcrypto_slot[0]->slot = NULL_PTR;
	// On C_Initialize, set event status flag to false
	pcrypto_slot[0]->slot_event = FALSE;

    rv = PKCS_init_slot(&pcrypto_slot[0]->slot);    
	DEBUG_INFO("Slot %s\n", pcrypto_slot[0]->slot);
	DEBUG_INFO("Slot description = %s\n", pcrypto_slot[0]->slot->slotDescription);

    if (rv != CKR_OK) {
		DEBUG_INFO("Slots failed to initialize, rc = %x\n", rv);
		return CKR_HOST_MEMORY;
    }
	
	DEBUG_MSG("Exit C_Initialize\n");
    return CKR_OK;
}

//----------------------------------------------------------------------
// Done with Cryptoki 
//----------------------------------------------------------------------

CK_RV C_Finalize(CK_VOID_PTR finalptr)
{
	CK_RV	rv;
	CK_SLOT_ID	slotID = 1;

    DEBUG_MSG("Enter C_Finalize\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_Finalize called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Find session call came from, if not valid, return CKR_SESSION_CLOSED (maybe)

    // Free Public Data off the card other sessions open to token
    if (pcrypto_slot[slotID-1]->ppublic_object_list != NULL_PTR) {
		rv = PKCS_free_objects(pcrypto_slot[slotID-1]->ppublic_object_list);
		pcrypto_slot[slotID-1]->ppublic_object_list = NULL_PTR;
		if (rv != CKR_OK) {
			DEBUG_INFO("Failed freeing public data during C_Finalize, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_MSG("Have freed public object memory\n");
		}
    }
	
    // Free Private Data off the card other sessions open to token
    if (pcrypto_slot[slotID-1]->pprivate_object_list != NULL_PTR) {
		rv = PKCS_free_objects(pcrypto_slot[slotID-1]->pprivate_object_list);
		pcrypto_slot[slotID-1]->pprivate_object_list = NULL_PTR;
		if (rv != CKR_OK) {
		DEBUG_INFO("Failed freeing public data during C_Finalize, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_MSG("Have freed private object memory\n");
		}
    }

    rv = PKCS_finalize_slot(&pcrypto_slot[0]->slot);    

    /* If last instance of Cryptoki, free structures */
    free(pcrypto_info);
	pcrypto_info = NULL_PTR;
    free(pcrypto_slot[slotID-1]);
	pcrypto_slot[slotID-1] = NULL_PTR;

    DEBUG_MSG("Exit C_Finalize\n");

    return CKR_OK;
}

//----------------------------------------------------------------------
// Get cryptoki general info  
//----------------------------------------------------------------------

CK_RV C_GetInfo(CK_INFO_PTR infoptr)   
{
    DEBUG_MSG("Enter C_GetInfo\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetInfo called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
    
	memcpy(infoptr, pcrypto_info, sizeof(CK_INFO));
//    *infoptr = (CK_INFO_PTR)pcrypto_info;

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


//----------------------------------------------------------------------
// Get function list  
//      This is the only cryptoki function that can be called before
//      C_Initialize
//----------------------------------------------------------------------

CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR flptr)
{
	DEBUG_MSG("Enter C_GetFunctionList\n");

	// Set function list values
    function_list.version.major = 2;
    function_list.version.minor = 01;
	function_list.C_Initialize = &C_Initialize;
	function_list.C_Finalize = &C_Finalize;
	function_list.C_GetInfo = &C_GetInfo;
	function_list.C_GetFunctionList = &C_GetFunctionList;
	function_list.C_GetSlotList = &C_GetSlotList;
	function_list.C_GetSlotInfo = &C_GetSlotInfo;
	function_list.C_GetTokenInfo = &C_GetTokenInfo;
	function_list.C_GetMechanismList = &C_GetMechanismList;
	function_list.C_GetMechanismInfo = &C_GetMechanismInfo;
	function_list.C_InitToken = &C_InitToken;
	function_list.C_InitPIN = &C_InitPIN;
	function_list.C_SetPIN = &C_SetPIN;
	function_list.C_OpenSession = &C_OpenSession;
	function_list.C_CloseSession = &C_CloseSession;
	function_list.C_CloseAllSessions = &C_CloseAllSessions;
	function_list.C_GetSessionInfo = &C_GetSessionInfo;
	function_list.C_GetOperationState = &C_GetOperationState;
	function_list.C_SetOperationState = &C_SetOperationState;
	function_list.C_Login = &C_Login;
	function_list.C_Logout = &C_Logout;
	function_list.C_CreateObject = &C_CreateObject;
	function_list.C_CopyObject = &C_CopyObject;
	function_list.C_DestroyObject = &C_DestroyObject;
	function_list.C_GetObjectSize = &C_GetObjectSize;
	function_list.C_GetAttributeValue = &C_GetAttributeValue;
	function_list.C_SetAttributeValue = &C_SetAttributeValue;
	function_list.C_FindObjectsInit = &C_FindObjectsInit;
	function_list.C_FindObjects = &C_FindObjects;
	function_list.C_FindObjectsFinal = &C_FindObjectsFinal;
	function_list.C_EncryptInit = &C_EncryptInit;
	function_list.C_Encrypt = &C_Encrypt;
	function_list.C_EncryptUpdate = &C_EncryptUpdate;
	function_list.C_EncryptFinal = &C_EncryptFinal;
	function_list.C_DecryptInit = &C_DecryptInit;
	function_list.C_Decrypt = &C_Decrypt;
	function_list.C_DecryptUpdate = &C_DecryptUpdate;
	function_list.C_DecryptFinal = &C_DecryptFinal;
	function_list.C_DigestInit = &C_DigestInit;
	function_list.C_Digest = &C_Digest;
	function_list.C_DigestUpdate = &C_DigestUpdate;
	function_list.C_DigestKey = &C_DigestKey;
	function_list.C_DigestFinal = &C_DigestFinal;
	function_list.C_SignInit = &C_SignInit;
	function_list.C_Sign = &C_Sign;
	function_list.C_SignUpdate = &C_SignUpdate;
	function_list.C_SignFinal = &C_SignFinal;
	function_list.C_SignRecoverInit = &C_SignRecoverInit;
	function_list.C_SignRecover = &C_SignRecover;
	function_list.C_VerifyInit = &C_VerifyInit;
	function_list.C_Verify = &C_Verify;
	function_list.C_VerifyUpdate = &C_VerifyUpdate;
	function_list.C_VerifyFinal = &C_VerifyFinal;
	function_list.C_VerifyRecoverInit = &C_VerifyRecoverInit;
	function_list.C_VerifyRecover = &C_VerifyRecover;
	function_list.C_DigestEncryptUpdate = &C_DigestEncryptUpdate;
	function_list.C_DecryptDigestUpdate = &C_DecryptDigestUpdate;
	function_list.C_SignEncryptUpdate = &C_SignEncryptUpdate;
	function_list.C_DecryptVerifyUpdate = &C_DecryptVerifyUpdate;
	function_list.C_GenerateKey = &C_GenerateKey;
	function_list.C_GenerateKeyPair = &C_GenerateKeyPair;
	function_list.C_WrapKey = &C_WrapKey;
	function_list.C_UnwrapKey = &C_UnwrapKey;
	function_list.C_DeriveKey = &C_DeriveKey;
	function_list.C_SeedRandom = &C_SeedRandom;
	function_list.C_GenerateRandom = &C_GenerateRandom;
	function_list.C_GetFunctionStatus = &C_GetFunctionStatus;
	function_list.C_CancelFunction = &C_CancelFunction;
	function_list.C_WaitForSlotEvent = &C_WaitForSlotEvent;

	*flptr = pfunction_list;
		
    DEBUG_MSG("Exit C_GetFunctionList\n");
	return CKR_OK;      
}


//----------------------------------------------------------------------
// Get Slot info about this system
//----------------------------------------------------------------------

CK_RV C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
{
    CK_ULONG    ulpslots=1;
	CK_SLOT_ID	slotid = 1;

    DEBUG_MSG("Enter C_GetSlotList\n");
    
    if (!pcrypto_info) {
		DEBUG_MSG("C_GetSlotList called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	while (ulpslots <= ulPopulatedSlots) {
		if (!tokenPresent) {
			if (pcrypto_slot[ulpslots-1]->slot->slotDescription) {
				if (pSlotList != NULL_PTR) {
					// pulCount contains number of slots in buffer
					if (slotid > *pulCount) {
						return CKR_BUFFER_TOO_SMALL;
					}
					pSlotList[slotid-1] = ulpslots;
				}
				slotid++;
			}
		} else {
		    if (pSlotList != NULL_PTR) {
				// pulCount contains number of slots in buffer
				if (slotid > *pulCount) {
					return CKR_BUFFER_TOO_SMALL;
				}
				pSlotList[slotid-1] = ulpslots;
			}
			slotid++;
		}
		ulpslots++;
	}

	// If slot pointer is null, just want the number
	if (pSlotList == NULL_PTR) {
		*pulCount = slotid-1;
	}
    
    DEBUG_MSG("Exit C_GetSlotList\n");
    return CKR_OK;
}


//----------------------------------------------------------------------
// Wait for an slot event
// The dilema here is how to trigger a slot event.  I suppose, we need
// to keep the addresses of where to fill in the slot event, and keep state
// data on each of the slots.  When any state changes, probably need a
// routine to take the slot that changed state and notify any slots in the 
// waiting queue.  Once notified, it can be removed from the wait queue.
//----------------------------------------------------------------------

CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
{
    DEBUG_MSG("Enter C_WaitForSlotEvent\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_WaitForSlotEvent called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
    
	if (pSlot) {
		if (pcrypto_slot[0]->slot_event) {
			*pSlot = 1;
			pcrypto_slot[0]->slot_event = FALSE;
		} else {
			if (flags & CKF_DONT_BLOCK) {
				return CKR_NO_EVENT;
			} else {
				// Wait for slot event to occur
				while (pcrypto_slot[0]->slot_event) {
					//
					pcrypto_slot[0]->slot_event = FALSE;
				}
			}
		}
	} else {
		return CKR_GENERAL_ERROR;
	}

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

//----------------------------------------------------------------------
// Get Information about a slot
//----------------------------------------------------------------------

CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
{
    DEBUG_MSG("Enter C_GetSlotInfo\n");
	
    if (!pcrypto_info) {
		DEBUG_MSG("C_GetSlotInfo called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	
    if ((slotID > 0) && (slotID <= ulPopulatedSlots)) {
		/* Make sure slot has been intialized */

		DEBUG_MSG("Slot is valid, copying slot info\n");
		DEBUG_INFO("Address of Info copy to %x\n", pInfo);
		DEBUG_INFO("Address of Info copy from %x\n", pcrypto_slot[slotID-1]);
		DEBUG_INFO("Size of slot info %x\n", sizeof(CK_SLOT_INFO));
	    
		memcpy(pInfo, (pcrypto_slot[slotID-1]->slot), sizeof(CK_SLOT_INFO));
    }
	
    DEBUG_MSG("Exit C_GetSlotInfo\n");
    return CKR_OK;
}


//----------------------------------------------------------------------
// Get information about a card
//----------------------------------------------------------------------

CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
{
    CRYPTO_TOKEN_HANDLE thandle=NULL_PTR;
    CK_RV               rv=CKR_OK, rc;
	CK_BBOOL			needtokillsession=FALSE;	
	CK_SESSION_HANDLE	mysession;
	CK_TOKEN_INFO		tokeninfo;

    DEBUG_MSG("Enter C_GetTokenInfo\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetTokenInfo called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

    /* If null, establish connection with token */
    if (!thandle) {
		DEBUG_MSG("Not connected to the token \n");

		/* Open session with token                   */
		DEBUG_INFO("slot description = %s\n", pcrypto_slot[slotID-1]->slot->slotDescription);
		DEBUG_INFO("Address of session information = %x\n", pcrypto_session_info);

		// Get a free session
		mysession = PKCS_Get_Available_Session((CRYPTO_SESSION_INFO_PTR *)&pcrypto_session_info, CRYPTOKI_MAX_SESSIONS, slotID, TOKEN_MAX_SESSIONS);
		if (mysession <= 0) {
			DEBUG_MSG("No available sessions\n");
			return CKR_SESSION_COUNT;
		}

	    /* Set up the cryptoki information          */
	    	pcrypto_session_info[mysession-1] = (CRYPTO_SESSION_INFO_PTR) calloc(sizeof(CRYPTO_SESSION_INFO), 1);
		pcrypto_session_info[mysession-1]->session_handle = mysession;
		pcrypto_session_info[mysession-1]->session_notification = NULL_PTR;
		pcrypto_session_info[mysession-1]->session_pApplication = NULL_PTR;
		pcrypto_session_info[mysession-1]->session_flags = 0;
		pcrypto_session_info[mysession-1]->session_slot = slotID;
		pcrypto_session_info[mysession-1]->session_state = CKS_RW_PUBLIC_SESSION;
		pcrypto_session_info[mysession-1]->ulDeviceError = NULL_PTR;    
		pcrypto_session_info[mysession-1]->maxpinlen = TOKEN_MAX_PIN_LEN;    
		pcrypto_session_info[mysession-1]->minpinlen = TOKEN_MIN_PIN_LEN;
		pcrypto_session_info[mysession-1]->psearch_object = NULL_PTR;
		pcrypto_session_info[mysession-1]->search_count = 0;
		pcrypto_session_info[mysession-1]->search_session = 0;
		// addin process/thread identification information

		pcrypto_session_info[mysession-1]->token_handle = PKCS_open_card_session(pcrypto_slot[slotID-1]->slot->slotDescription, pcrypto_session_info[mysession-1]);
		if (!pcrypto_session_info[mysession-1]->token_handle) {
			DEBUG_MSG("Could not set up session to smart card\n");
			return CKR_DEVICE_ERROR;
		}
 	
		needtokillsession = TRUE;
    }

    /* Now get the token information */
    DEBUG_MSG("Getting token information off the card\n");
    rv = PKCS_get_token_information((CK_CHAR_PTR)pcrypto_slot[slotID-1]->slot->slotDescription, &tokeninfo);
    DEBUG_INFO("rv from get token info = %x\n", rv);

	if (needtokillsession) {
	    rc =  PKCS_close_card_session(pcrypto_session_info[mysession-1]->token_handle);  

	    /* Find session and free ended session */
		free(pcrypto_session_info[mysession-1]);
		pcrypto_session_info[mysession-1] = NULL_PTR;
	}

    if (pInfo) {
		memcpy(pInfo, &tokeninfo, sizeof(CK_TOKEN_INFO));
	} else {
		DEBUG_MSG("C_GetTokenInfo called with NULL pointer to put information\n");
    }

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

//----------------------------------------------------------------------
// Get Card Mechanism Lit
//----------------------------------------------------------------------

CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
{
    DEBUG_MSG("Enter C_GetMechanismList\n");
    
    if (!pcrypto_info) {
	DEBUG_MSG("C_GetMechanismList called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
      
    *pulCount = 1;

    if (!pMechanismList) {
      DEBUG_MSG("No mechanism ptr, just returning number of mechanisms\n");
    } else {
      DEBUG_MSG("Mechanism ptr defined, need to get both mechanisms & number of mechanisms\n");
      *pMechanismList = CKM_DSA;
    }

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

//----------------------------------------------------------------------
// Get information about a particular mechanism on the card
//----------------------------------------------------------------------

CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo)
{
	
    DEBUG_MSG("Enter C_GetMechanismInfo\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_GetMechanismInfo called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
    
    pInfo = NULL_PTR;

    DEBUG_MSG("Exit C_GetMechanismInfo\n");

    return CKR_OK;      
}

//----------------------------------------------------------------------
// Initialize Virutal Smart Card
//----------------------------------------------------------------------

CK_RV C_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel)
{
    CK_RV				rv;
    CRYPTO_TOKEN_HANDLE token_handle;
	CK_SESSION_HANDLE	mysession;
	CK_BBOOL			needtokillsession=FALSE;	

    DEBUG_MSG("Enter C_InitToken\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_InitToken called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	DEBUG_INFO("Slot id %x\n", slotID);
	DEBUG_INFO("Pin %s\n", pPin);
	DEBUG_INFO("Pin Length %x\n", ulPinLen);
	DEBUG_INFO("Label %s\n", pLabel);

	// Find session call came from, if not valid, return CKR_SESSION_CLOSED (maybe)
    
	// Find the Exclusive session
	mysession = PKCS_Get_Exclusive_Session((CRYPTO_SESSION_INFO_PTR *)&pcrypto_session_info, CRYPTOKI_MAX_SESSIONS, slotID);
	if (mysession <= 0) {
		mysession = PKCS_Get_Available_Session((CRYPTO_SESSION_INFO_PTR *)&pcrypto_session_info, CRYPTOKI_MAX_SESSIONS, slotID, TOKEN_MAX_SESSIONS);
		if (mysession <= 0) {
			DEBUG_MSG("No available sessions\n");
			return CKR_SESSION_COUNT;
		}

	    /* Set up the cryptoki information          */ 	
	    pcrypto_session_info[mysession-1] = (CRYPTO_SESSION_INFO_PTR) calloc(sizeof(CRYPTO_SESSION_INFO), 1);
		pcrypto_session_info[mysession-1]->session_handle = mysession;
		pcrypto_session_info[mysession-1]->session_notification = NULL_PTR;
		pcrypto_session_info[mysession-1]->session_pApplication = NULL_PTR;
		pcrypto_session_info[mysession-1]->session_flags = 0;
		pcrypto_session_info[mysession-1]->session_slot = slotID;
		pcrypto_session_info[mysession-1]->session_state = CKS_RW_SO_FUNCTIONS;
		pcrypto_session_info[mysession-1]->ulDeviceError = NULL_PTR;    
		pcrypto_session_info[mysession-1]->maxpinlen = TOKEN_MAX_PIN_LEN;    
		pcrypto_session_info[mysession-1]->minpinlen = TOKEN_MIN_PIN_LEN;
		pcrypto_session_info[mysession-1]->psearch_object = NULL_PTR;
		pcrypto_session_info[mysession-1]->search_count = 0;
		pcrypto_session_info[mysession-1]->search_session = 0;
		// addin process/thread identification information

		pcrypto_session_info[mysession-1]->token_handle = PKCS_open_card_session(pcrypto_slot[slotID-1]->slot->slotDescription, pcrypto_session_info[mysession-1]);
		if (!pcrypto_session_info[mysession-1]->token_handle) {
			DEBUG_MSG("Could not set up session to smart card\n");
			return CKR_DEVICE_ERROR;
		}

		needtokillsession = TRUE;	
	}

    /* Check to see a R/W SO session is already established  */
	if (pcrypto_session_info[mysession-1]->session_state != CKS_RW_SO_FUNCTIONS) {
		DEBUG_MSG("Not signed on as SO\n");
		return CKR_USER_TYPE_INVALID;
	}

	/* Open session with token                   */
    token_handle = PKCS_token_init(pcrypto_slot[slotID-1]->slot->slotDescription, pPin, ulPinLen);


	if (needtokillsession) {
	    rv =  PKCS_close_card_session(pcrypto_session_info[mysession-1]->token_handle);  
	} else {
		/* Close session, the card is now clean */
		rv =  PKCS_close_card_session(token_handle);
	}

    /* Find session and free ended session */
    free(pcrypto_session_info[mysession-1]);
	pcrypto_session_info[mysession-1] = NULL_PTR;

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


//----------------------------------------------------------------------
// Initialize User Pin on Smart Card
//----------------------------------------------------------------------

CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
    CK_SLOT_ID  slot;
    CK_RV       rv;

    DEBUG_MSG("Enter C_InitPIN\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_InitPin called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID
     
    /* Check to see a R/W SO session is already established  */
	if (pcrypto_session_info[hSession-1]->session_state != CKS_RW_SO_FUNCTIONS) {
		DEBUG_MSG("Not signed on as SO\n");
		return CKR_USER_TYPE_INVALID;
	}

    /* Get slot to update */
    slot = pcrypto_session_info[hSession-1]->session_slot;

    /* If so can set user pin */
    rv = PKCS_write_user_pin((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription, pPin, ulPinLen);
    DEBUG_INFO("RC from update the user pin: %x\n", rv);    

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


//----------------------------------------------------------------------
// Set Pin of current logged on user
//----------------------------------------------------------------------

CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
{
    CK_SLOT_ID  slot; 
    CK_RV       rv;

    DEBUG_MSG("Enter C_SetPIN\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_SetPIN called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	/* Check to see a R/W SO session is already established  */
	if (pcrypto_session_info[hSession-1]->session_state != CKS_RW_USER_FUNCTIONS) {
		DEBUG_MSG("Not a RW user session\n");
		if (pcrypto_session_info[hSession-1]->session_state != CKS_RW_SO_FUNCTIONS) {
			DEBUG_MSG("Not a RW SO session\n");
			return CKR_SESSION_READ_ONLY;
		}
	}

    /* Get slot to update */
    slot = pcrypto_session_info[hSession-1]->session_slot;

	if (pcrypto_session_info[hSession-1]->session_state == CKS_RW_USER_FUNCTIONS) {
		// The only way CKS_RW_USER_FUNCTIONS get get is if the user is
		// logged on.  So set the user pin
		rv = PKCS_write_user_pin((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription, pNewPin, ulNewLen);
		DEBUG_INFO("RC from update the user pin: %x\n", rv);
	} else {
		if (pcrypto_session_info[hSession-1]->session_state == CKS_RW_SO_FUNCTIONS) {
			// The only way CKS_RW_SO_FUNCTIONS get get is if the SO is
			// logged on.  So set the so pin
			rv = PKCS_write_so_pin((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription, pNewPin, ulNewLen);
		} else {
			DEBUG_MSG("Not a valid session\n");
			return CKR_SESSION_READ_ONLY;
		}
	}

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


//----------------------------------------------------------------------
// Open Session to the Smart Card
//----------------------------------------------------------------------

CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
{
    CK_RV				rv;
	CK_SESSION_HANDLE	mysession;

    DEBUG_MSG("Enter C_OpenSession\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_OpenSession called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	if (CKF_SERIAL_SESSION & flags) {
		DEBUG_MSG("This is a Serial Session\n");
	} else {
		DEBUG_MSG("Only Serial sessions supported in this version of PKCS#11\n");
		return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
	}

	// Get a free session
	mysession = PKCS_Get_Available_Session((CRYPTO_SESSION_INFO_PTR *)&pcrypto_session_info, CRYPTOKI_MAX_SESSIONS, slotID, TOKEN_MAX_SESSIONS);
	if (mysession <= 0) {
		DEBUG_MSG("No available sessions\n");
		return CKR_SESSION_COUNT;
	}

    /* Set up the cryptoki information          */
    pcrypto_session_info[mysession-1] = (CRYPTO_SESSION_INFO_PTR) calloc(sizeof(CRYPTO_SESSION_INFO), 1);
    pcrypto_session_info[mysession-1]->session_handle = mysession;
    pcrypto_session_info[mysession-1]->session_notification = Notify;
    pcrypto_session_info[mysession-1]->session_pApplication = pApplication;
    pcrypto_session_info[mysession-1]->session_flags = flags;
    pcrypto_session_info[mysession-1]->session_slot = slotID;
    pcrypto_session_info[mysession-1]->session_state = CKS_RW_PUBLIC_SESSION;
    pcrypto_session_info[mysession-1]->ulDeviceError = NULL_PTR;    
    pcrypto_session_info[mysession-1]->maxpinlen = TOKEN_MAX_PIN_LEN;    
    pcrypto_session_info[mysession-1]->minpinlen = TOKEN_MIN_PIN_LEN;
	pcrypto_session_info[mysession-1]->psearch_object = NULL_PTR;
    pcrypto_session_info[mysession-1]->search_count = 0;
    pcrypto_session_info[mysession-1]->search_session = 0;
	// addin process/thread identification information

    /* Open session with token                   */
    pcrypto_session_info[mysession-1]->token_handle = PKCS_open_card_session(pcrypto_slot[slotID-1]->slot->slotDescription, pcrypto_session_info[mysession-1]);
    if (!pcrypto_session_info[mysession-1]->token_handle) {
    	DEBUG_MSG("Could not set up session to smart card\n");
	return CKR_DEVICE_ERROR;
    } 	
    memcpy(phSession, &mysession, sizeof(CK_SESSION_HANDLE));
 
    // Get Public Data off the card if no other sessions open to token
    if (pcrypto_slot[slotID-1]->ppublic_object_list == NULL_PTR) {
		pcrypto_slot[slotID-1]->ppublic_object_list = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
		rv = PKCS_get_public_objects(pcrypto_slot[slotID-1]->slot->slotDescription, &pcrypto_slot[slotID-1]->ppublic_object_list);
		if (rv != CKR_OK) {
			DEBUG_INFO("Failed getting public data off card at open session, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_INFO("Address of card public data is %x \n", pcrypto_slot[slotID-1]->ppublic_object_list);
		}
		pcrypto_slot[slotID-1]->pprivate_object_list = NULL_PTR;
    }

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


//----------------------------------------------------------------------
// Close Session to Smart Card
//----------------------------------------------------------------------

CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
{
    CK_RV rv;
	CK_SLOT_ID slotID;

    DEBUG_MSG("Enter C_CloseSession\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_CloseSession called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// If session already closed, you are done!
	if (pcrypto_session_info[hSession-1]) {
		slotID = pcrypto_session_info[hSession-1]->session_slot;
	} else {
		return CKR_SESSION_CLOSED;
	}

    // Free Public Data off the card other sessions open to token
    if (pcrypto_slot[slotID-1]->ppublic_object_list != NULL_PTR) {
		rv = PKCS_free_objects(pcrypto_slot[slotID-1]->ppublic_object_list);
		pcrypto_slot[slotID-1]->ppublic_object_list = NULL_PTR;
		if (rv != CKR_OK) {
			DEBUG_INFO("Failed freeing public data during close session, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_MSG("Have freed public object memory\n");
		}
    }
	
    // Free Private Data off the card other sessions open to token
    if (pcrypto_slot[slotID-1]->pprivate_object_list != NULL_PTR) {
		rv = PKCS_free_objects(pcrypto_slot[slotID-1]->pprivate_object_list);
		pcrypto_slot[slotID-1]->pprivate_object_list = NULL_PTR;
		if (rv != CKR_OK) {
		DEBUG_INFO("Failed freeing public data during C_Finalize, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_MSG("Have freed private object memory\n");
		}
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

    rv =  PKCS_close_card_session(pcrypto_session_info[hSession-1]->token_handle);  

    /* Find session and free ended session */
    free(pcrypto_session_info[hSession-1]);
	pcrypto_session_info[hSession-1] = NULL_PTR;

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

//----------------------------------------------------------------------
// Close all sessions to a slot
//----------------------------------------------------------------------

CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
{
    CK_RV rv;
	CK_ULONG	i=0;

    DEBUG_MSG("Enter C_CloseAllSessions\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_CloseAllSessions called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Find a free session
	while (i < 1) {	// CRYPTOKI_MAX_SESSIONS
		if (pcrypto_session_info[i] != NULL_PTR) {
			DEBUG_INFO("%d is an active session\n", i+1);
			if (strcmp(pcrypto_slot[slotID-1]->slot->slotDescription, (CK_CHAR *)pcrypto_session_info[i]->token_handle) == 0) {
				DEBUG_INFO("Session %d will be closed\n", i+1);
			    rv =  PKCS_close_card_session(pcrypto_session_info[i]->token_handle);  
				free(pcrypto_session_info[i]);
				pcrypto_session_info[i] = NULL_PTR;
			} else {
				DEBUG_INFO("Session %d isn't for our token\n", i+1);
			}
		} else {
			DEBUG_INFO("Session %d is not active\n", i+1);
		}
		i++;
	}

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


//----------------------------------------------------------------------
// Get information about the session
//----------------------------------------------------------------------

CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
{
    DEBUG_MSG("Enter C_GetSessionInfo\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetSessionInfo called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

    /* Fill in fields of session information structure */
    pInfo->slotID        = pcrypto_session_info[hSession-1]->session_slot;
    pInfo->state         = pcrypto_session_info[hSession-1]->session_state;
    pInfo->flags         = pcrypto_session_info[hSession-1]->session_flags;
    pInfo->ulDeviceError = pcrypto_session_info[hSession-1]->ulDeviceError;
	
    DEBUG_MSG("Exit C_GetSessionInfo\n");
    return CKR_OK;       
}


//----------------------------------------------------------------------
// Gets the stae of the crypto operation in a session
//----------------------------------------------------------------------

CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen)
{
    DEBUG_MSG("Enter C_GetOperationState\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetOperationState called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	pOperationState = NULL_PTR;
	*pulOperationStateLen = 0;

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


//----------------------------------------------------------------------
// Restore the state of the crypto operation
//----------------------------------------------------------------------

CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
{
    DEBUG_MSG("Enter C_SetOperationState\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_SetOperationState called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

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


//----------------------------------------------------------------------
// Logs on a user into a token      
//----------------------------------------------------------------------

CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
    CRYPTO_TOKEN_SECURE_INFO        pininfo;
    CK_RV                           rv;
    CK_SLOT_ID                      slot;              
//    CK_CHAR					hashPIN[PIN_HASH_LEN];
//    CK_ULONG				hashPINLen = PIN_HASH_LEN;

// MAC Change checking to check hash against stored hash instead of real value

    DEBUG_MSG("Enter C_Login\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_Login called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	if ((hSession <= 0) || (hSession > CRYPTOKI_MAX_SESSIONS)) {
		DEBUG_INFO("Invalid session %d\n", hSession);
		return CKR_SESSION_HANDLE_INVALID;
	}

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

    /* Make sure pin is of a valid length */
    if ((ulPinLen < pcrypto_session_info[hSession-1]->minpinlen) || 
		(ulPinLen > pcrypto_session_info[hSession-1]->maxpinlen)) {
		DEBUG_INFO("Invalid pin length of %d\n", ulPinLen);
		return CKR_PIN_INCORRECT;
    }

	/* Get token & slot information */
    slot = pcrypto_session_info[hSession-1]->session_slot;
    DEBUG_INFO("Login: Slot = %x\n", slot);
    DEBUG_INFO("Token = %s\n", pcrypto_slot[slot-1]->slot->slotDescription);

	/* Get security information off the card */
    rv = PKCS_get_pin_information((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription, &pininfo);
    DEBUG_INFO("rv from get pin info = %x\n", rv);
    if (rv != CKR_OK) {
		DEBUG_INFO("Error getting pin info, rc = %x\n", rv);
		return rv;
    }
					     
    DEBUG_INFO("User pin: %s\n", pininfo.userpin);
    DEBUG_INFO("SO pin: %s\n", pininfo.sopin);

//    PKCS_hash(pPin, ulPinLen, &hashPIN, &hashPINLen);
//    DEBUG_INFO("hash of pin :%s\n", hashPIN);
//    DEBUG_INFO("hash pin len :%d\n", hashPINLen);
	
	if (pininfo.badsotries >= TOKEN_LOGON_TRIES) {
		DEBUG_MSG("Card locked due to number of invalid SO Logins\n");
		return CKR_TOKEN_WRITE_PROTECTED;
	}

    /* Compare pin to what's on smart card */
    DEBUG_INFO("User Type = %x\n", userType);
    switch (userType)
    {
	case CKU_SO:
		if (pininfo.sopinlen != ulPinLen) {
			DEBUG_MSG("SO pin's of different lengths\n");
			DEBUG_INFO2("Pin1 len: %d, Pin2 len %d\n", pininfo.sopinlen, ulPinLen);
			rv = PKCS_invalid_so_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
			return CKR_PIN_INCORRECT;
		}
		if (strncmp((char *)&pininfo.sopin, pPin, ulPinLen) != 0) {
			DEBUG_MSG("SO Pin's fail to compare\n");
			DEBUG_INFO("SO Pin:  %s\n", pininfo.sopin);
			DEBUG_INFO("SO Pin len: %d\n", pininfo.sopinlen);
			DEBUG_INFO("Entered Pin: %s\n", pPin);
			DEBUG_INFO("Pin len: %d\n", ulPinLen);
			rv = PKCS_invalid_so_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
			return CKR_PIN_INCORRECT;
		}
		switch (pcrypto_session_info[hSession-1]->session_state) 
		{
		case CKS_RO_PUBLIC_SESSION:
			DEBUG_MSG("SO Login, Public Session: error\n");
			return CKR_SESSION_READ_ONLY_EXISTS; 
			break;
		case CKS_RO_USER_FUNCTIONS:
			DEBUG_MSG("SO Login, RO Session: error\n");
			return CKR_SESSION_READ_ONLY_EXISTS;
			break;
		case CKS_RW_PUBLIC_SESSION:
			DEBUG_MSG("SO Login, RW Public, setting session\n");
			pcrypto_session_info[hSession-1]->session_state = CKS_RW_SO_FUNCTIONS;
			break;
		case CKS_RW_SO_FUNCTIONS:
			DEBUG_MSG("SO login, RW SO, already logged in\n");
			return CKR_USER_ALREADY_LOGGED_IN;
			break;
		case CKS_RW_USER_FUNCTIONS:
			DEBUG_MSG("SO login, RW User already logged in\n");
			return CKR_USER_ALREADY_LOGGED_IN;
			break;
		default:
			DEBUG_MSG("SO login, invalid session state: error\n");
			return CKR_GENERAL_ERROR;
		}
		// MAC put so pin & len into function to be re-hashed
		rv = PKCS_reset_so_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
 		break;
	case CKU_USER:
		if (pininfo.badusertries >= TOKEN_LOGON_TRIES) {
			DEBUG_MSG("Card locked due to number of invalid User Logins\n");
			return CKR_TOKEN_WRITE_PROTECTED;
		}
		if (pininfo.userpinlen != ulPinLen) {
			DEBUG_MSG("User pin's of different lengths\n");
			DEBUG_INFO2("Pin1 len: %d, Pin2 len %d\n", pininfo.userpinlen, ulPinLen);
			rv = PKCS_invalid_user_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
			return CKR_PIN_INCORRECT;
		}
		if (strncmp((char *)&pininfo.userpin, pPin, ulPinLen) != 0) {
			DEBUG_MSG("User Pin's fail to compare\n");
			DEBUG_INFO("User Pin:  %s\n", pininfo.userpin);
			DEBUG_INFO("User pin len: %d\n", pininfo.userpinlen);
			DEBUG_INFO("Entered Pin: %s\n", pPin);
			DEBUG_INFO("Pin len: %d\n", ulPinLen);
			rv = PKCS_invalid_user_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
			return CKR_PIN_INCORRECT;
		}
		switch (pcrypto_session_info[hSession-1]->session_state) 
		{
		case CKS_RO_PUBLIC_SESSION:
			DEBUG_MSG("User login, RO Public, seting state\n");
			pcrypto_session_info[hSession-1]->session_state = CKS_RO_USER_FUNCTIONS;
			break;
		case CKS_RO_USER_FUNCTIONS:
			DEBUG_MSG("User login, RO User:  already logged in\n");
			return CKR_USER_ALREADY_LOGGED_IN;
			break;
		case CKS_RW_PUBLIC_SESSION:
			DEBUG_MSG("User login, RW Publc:  setting state\n");
			pcrypto_session_info[hSession-1]->session_state = CKS_RW_USER_FUNCTIONS;
			break;
		case CKS_RW_SO_FUNCTIONS:
			DEBUG_MSG("User login, RW SO:  already logged in\n");
			return CKR_USER_ALREADY_LOGGED_IN;
			break;
		case CKS_RW_USER_FUNCTIONS:
			DEBUG_MSG("User login, RW user:  already logged in\n");
			return CKR_USER_ALREADY_LOGGED_IN;
			break;
		default:
			DEBUG_MSG("User login, invalid session:  error\n");
			return CKR_GENERAL_ERROR;
		}
		// Get Private Data off the card if no other private sessions
		if (pcrypto_slot[slot-1]->pprivate_object_list == NULL_PTR) {
			pcrypto_slot[slot-1]->pprivate_object_list = (TOKEN_OBJECT *)calloc(sizeof(TOKEN_OBJECT), 1);
			// MAC get random number from security area
			// MAC use to decrypt private objects
			rv = PKCS_get_private_objects(pcrypto_slot[slot-1]->slot->slotDescription, &pcrypto_slot[slot-1]->pprivate_object_list);
			if (rv != CKR_OK) {
				DEBUG_INFO("Failed getting private data off card at open session, rc = %x\n", rv);
				return rv;
			} else {
				DEBUG_INFO("Address of card private data is %x \n", pcrypto_slot[slot-1]->pprivate_object_list);
			}
		}
		// MAC put pPin & ulPin as parm to reset for hash
		rv = PKCS_reset_user_attempts((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription);
		break;
	default:
		DEBUG_MSG("User Type Invalid\n");
		return CKR_USER_TYPE_INVALID;
	}
    
    DEBUG_MSG("Exit C_Login\n");
	return CKR_OK;       
}

//----------------------------------------------------------------------
// Log out the user from the token
//----------------------------------------------------------------------

CK_RV C_Logout(CK_SESSION_HANDLE hSession)
{
	CK_RV		rv;
	CK_SLOT_ID	slotID = pcrypto_session_info[hSession-1]->session_slot;
 
	DEBUG_MSG("Enter C_Logout\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_Logout called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

    // Free Private Data off the card other sessions open to token
    if (pcrypto_slot[slotID-1]->pprivate_object_list != NULL_PTR) {
		rv = PKCS_free_objects(pcrypto_slot[slotID-1]->pprivate_object_list);
		pcrypto_slot[slotID-1]->pprivate_object_list = NULL_PTR;
		if (rv != CKR_OK) {
			DEBUG_INFO("Failed freeing private data during logout session, rc = %x\n", rv);
			return rv;
		} else {
			DEBUG_MSG("Have freed private object memory\n");
		}
    }
    
    pcrypto_session_info[hSession-1]->session_state = CKS_RW_PUBLIC_SESSION;

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


//----------------------------------------------------------------------
// Creates a new object on the token
//----------------------------------------------------------------------

CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
{
     CK_SLOT_ID  slot;
     CK_RV rv;

    DEBUG_MSG("Enter C_CreateObject\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_CreateObject called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

    /* Get slot to update */
    slot = pcrypto_session_info[hSession-1]->session_slot;

    /* If so can set user pin */
    rv = PKCS_add_object((CK_CHAR_PTR)pcrypto_slot[slot-1]->slot->slotDescription, &pcrypto_slot[slot-1]->pprivate_object_list, &pcrypto_slot[slot-1]->ppublic_object_list, pTemplate, ulCount, phObject);

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


//----------------------------------------------------------------------
// Copy one object to another, creating a new object on the copy
//----------------------------------------------------------------------

CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject)
{
    DEBUG_MSG("Enter C_CopyObject\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_CopyObject called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	phNewObject = NULL_PTR;

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


//----------------------------------------------------------------------
// Destroy an object on the token  
//----------------------------------------------------------------------

CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
{
    CK_RV	rv;
    CK_SLOT_ID                      slot;              

	DEBUG_MSG("Enter C_DestroyObject\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_DestroyObject called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	/* Get token & slot information */
    slot = pcrypto_session_info[hSession-1]->session_slot;

	rv = PKCS_destroy_object(&pcrypto_slot[slot-1]->pprivate_object_list, &pcrypto_slot[slot-1]->ppublic_object_list, hObject);

    DEBUG_MSG("Exit C_DestroyObject\n");

	return rv;       
}


//----------------------------------------------------------------------
// Get the size of an object        
//----------------------------------------------------------------------

CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
{
	CK_RV rv;
	CK_SLOT_ID	slot;

    DEBUG_MSG("Enter C_GetObjectSize\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetObjectSize called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	/* Get token & slot information */
    slot = pcrypto_session_info[hSession-1]->session_slot;

	DEBUG_INFO("Going to look for object %x\n", hObject);
	rv = PKCS_get_object_size(pcrypto_slot[slot-1]->pprivate_object_list, pcrypto_slot[slot-1]->ppublic_object_list, hObject, pulSize);

	if (rv != CKR_OK) {
		*pulSize = 0;
		return CKR_OBJECT_HANDLE_INVALID;
	}

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


//----------------------------------------------------------------------
// Obtain the value of one or more object attributes
//----------------------------------------------------------------------

CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
{
    CK_RV	rv;
	CK_SLOT_ID	slot;
	
	DEBUG_MSG("Enter C_GetAttributeValue\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_GetAttributeValue called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	/* Get token & slot information */
    slot = pcrypto_session_info[hSession-1]->session_slot;

	DEBUG_INFO("Going to look for object %x\n", hObject);
	rv = PKCS_get_object_data(pcrypto_slot[slot-1]->pprivate_object_list, pcrypto_slot[slot-1]->ppublic_object_list, pTemplate, ulCount, hObject);

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

}


//----------------------------------------------------------------------
// Set the value of one or more attributes
//----------------------------------------------------------------------

CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
{
    DEBUG_MSG("Enter C_SetAttributeValue\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_SetAttributeValue called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID
   
    DEBUG_MSG("Exit C_SetAttributeValue\n");

	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initializes a search for a token and session objects
//----------------------------------------------------------------------

CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
{
	CK_ULONG			j;
	CK_ATTRIBUTE_PTR	pcurr, myptr=NULL, ptemp;

    DEBUG_MSG("Enter C_FindObjectsInit\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_FindObjectsInit called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID
	pcurr = pTemplate;
	ptemp = (CK_ATTRIBUTE_PTR)malloc((sizeof(CK_ATTRIBUTE_TYPE) + sizeof(CK_VOID_PTR) +
											sizeof(CK_ULONG)) * ulCount);
	for (j = 1; j <= ulCount; j++) {
		DEBUG_INFO("Copying template, attr = %x ", pcurr->type);
		if (!myptr) {
			DEBUG_INFO("Our version of template = %x\n", ptemp);	
			myptr = ptemp;
		} 

		ptemp->type = pcurr->type;
		ptemp->pValue = (CK_VOID_PTR)malloc(pcurr->ulValueLen);
		memcpy(ptemp->pValue, pcurr->pValue, pcurr->ulValueLen);
		ptemp->ulValueLen = pcurr->ulValueLen;

		pcurr = pcurr++;
		ptemp = ptemp++;
	}

	pcrypto_session_info[hSession-1]->psearch_object = myptr;
    pcrypto_session_info[hSession-1]->search_count = ulCount;
    pcrypto_session_info[hSession-1]->search_session = hSession;
	pcrypto_session_info[hSession-1]->current_object = 0;

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


//----------------------------------------------------------------------
// Continue a search for token and session objects
//----------------------------------------------------------------------

CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
{
	CK_RV	rv;
	CK_SLOT_ID	slot;

    DEBUG_MSG("Enter C_FindObjects\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_FindObjects called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID

	/* Get token & slot information */
    slot = pcrypto_session_info[hSession-1]->session_slot;

	if (hSession != pcrypto_session_info[hSession-1]->search_session) {
		DEBUG_INFO("Session doesn't match current search session: %x\n", hSession);
		return CKR_SESSION_HANDLE_INVALID;
	}

    // Find an instance of a template
	rv = PKCS_find_object(pcrypto_slot[slot-1]->pprivate_object_list, pcrypto_slot[slot-1]->ppublic_object_list, pcrypto_session_info[hSession-1]->psearch_object, pcrypto_session_info[hSession-1]->search_count, &pcrypto_session_info[hSession-1]->current_object, phObject, ulMaxObjectCount, pulObjectCount);
   
    DEBUG_MSG("Exit C_FindObjects\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a search for token and session objects
//----------------------------------------------------------------------

CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
{
	CK_ULONG			j; 
	CK_ATTRIBUTE_PTR	ptemp;

	DEBUG_MSG("Enter C_FindObjectsFinal\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_FindObjectsFinal called when cryptoki not initialized\n");
 		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	// Match hSession with session data, if not valid, return CKR_SESSION_HANDLE_INVALID
		
	ptemp = pcrypto_session_info[hSession-1]->psearch_object;
	for (j = 1; j <= pcrypto_session_info[hSession-1]->search_count; j++) {
		DEBUG_INFO("Cleaning template, attr = %x ", ptemp->type);
		free(ptemp->pValue);
		free(ptemp);
		ptemp = ptemp++;
	}

	pcrypto_session_info[hSession-1]->psearch_object = NULL_PTR;
    pcrypto_session_info[hSession-1]->search_count = 0;
    pcrypto_session_info[hSession-1]->search_session = 0;
	pcrypto_session_info[hSession-1]->current_object = 0;

    DEBUG_MSG("Exit C_FindObjectsFinal\n");

	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize an enryption operation
//----------------------------------------------------------------------

CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_EncryptInit\n");

    if (!pcrypto_info) {
		DEBUG_MSG("C_EncryptInit called when cryptoki not initialized\n");
		return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_EncryptInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Encrypt a single part data       
//----------------------------------------------------------------------

CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
{
    DEBUG_MSG("Enter C_Encrypt\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_Encrypt called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pEncryptedData = NULL_PTR;
	*pulEncryptedDataLen = 0;

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


//----------------------------------------------------------------------
// Continue a muliple-part encryption operation
//----------------------------------------------------------------------

CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
{
    DEBUG_MSG("Enter C_EncryptUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_EncryptUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pEncryptedPart = NULL_PTR;
	*pulEncryptedPartLen = 0;
			     
    DEBUG_MSG("Exit C_EncryptUpdate\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a muliple part encryption operation
//----------------------------------------------------------------------

CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
{
    DEBUG_MSG("Enter C_EncryptFinal\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_EncryptFinal called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }

	pLastEncryptedPart = NULL_PTR;
	*pulLastEncryptedPartLen = 0;
				   
    DEBUG_MSG("Exit C_EncryptFinal\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a decryption operation
//----------------------------------------------------------------------

CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{
    DEBUG_MSG("Enter C_DecryptInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DecryptInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
				  
    DEBUG_MSG("Exit C_DecryptInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Decrypts a single part encrypted data
//----------------------------------------------------------------------

CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
    DEBUG_MSG("Enter C_Decrypt\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_Decrpt called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pData = NULL_PTR;
	*pulDataLen = 0;
				 
    DEBUG_MSG("Exit C_Decrypt\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Continues a multiple part decryption operation
//----------------------------------------------------------------------

CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
{
    DEBUG_MSG("Enter C_DecryptUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DecryptUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pPart = NULL_PTR;
	*pulPartLen = 0;
			     
    DEBUG_MSG("Exit C_DecryptUpdate\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a multiple part decryption operation
//----------------------------------------------------------------------

CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
{
    DEBUG_MSG("Enter C_DecryptFinal\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DecryptFinal called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pLastPart = NULL_PTR;
	*pulLastPartLen = 0;
				   
    DEBUG_MSG("Exit C_DecryptFinal\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a message digesting operation
//----------------------------------------------------------------------

CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
{

    DEBUG_MSG("Enter C_DigestInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DigestInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }                             
    DEBUG_MSG("Exit C_DigestInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Digest a single part data        
//----------------------------------------------------------------------

CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
{
    DEBUG_MSG("Enter C_Digest\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_Digest called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pDigest = NULL_PTR;
	*pulDigestLen = 0;
				
    DEBUG_MSG("Exit C_Digest\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Continues a multiple part message digesting operation
//----------------------------------------------------------------------

CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{

    DEBUG_MSG("Enter C_DigestUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DigestUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }                       
    DEBUG_MSG("Exit C_DigestUpdate\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Continues a multi-part digest by digesting the secret key
//----------------------------------------------------------------------

CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_DigestKey\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DigestKey called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_DigestKey\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a multiple part mesage digesting operation
//----------------------------------------------------------------------

CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
{
    DEBUG_MSG("Enter C_DigestFinal\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DigestFinal called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pDigest = NULL_PTR;
	*pulDigestLen = 0;
			       
    DEBUG_MSG("Exit C_DigestFinal\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a signing operation   
//----------------------------------------------------------------------

CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_SignInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_SignInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Sign a single part encrypted data
//----------------------------------------------------------------------

CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
{
    DEBUG_MSG("Enter C_Sign\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_Sign called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pSignature = NULL_PTR;
	*pulSignatureLen = 0;
			      
    DEBUG_MSG("Exit C_Sign\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Continues a multiple part signing operation
//----------------------------------------------------------------------

CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{

    DEBUG_MSG("Enter C_SignUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_SignUpdate\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a multiple part signing operation
//----------------------------------------------------------------------

CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
{
    DEBUG_MSG("Enter C_SignFinal\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignFinal called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pSignature = NULL_PTR;
	*pulSignatureLen = 0;
				
    DEBUG_MSG("Exit C_SignFinal\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a signing operation where the digest can be recovered
//----------------------------------------------------------------------

CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_SignRecoverInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignRecoverInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_SignRecoverInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Signs single part encrypted data for recovery
//----------------------------------------------------------------------

CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
{
    DEBUG_MSG("Enter C_SignRecover\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignRecover called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pSignature = NULL_PTR;
	*pulSignatureLen = 0;
				     
    DEBUG_MSG("Exit C_SignRecover\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a verification operation
//----------------------------------------------------------------------

CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_VerifyInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_VerifyInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_VerifyInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Verifies a signature in a single part operation
//----------------------------------------------------------------------

CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
{

    DEBUG_MSG("Enter C_Verify\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_Verify called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_Verify\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Continues a multiple part verification operation
//----------------------------------------------------------------------

CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{

    DEBUG_MSG("Enter C_VerifyUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_VerifyUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_VerifyUpdate\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Finish a multiple part decryption operation
//----------------------------------------------------------------------

CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
{

    DEBUG_MSG("Enter C_VerifyFinal\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_VerifyFinal called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_VerifyFinal\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Initialize a signature verification operation, where data is recovered
//----------------------------------------------------------------------

CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{

    DEBUG_MSG("Enter C_VerifyRecoverInit\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_VerifyRecoverInit called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_VerifyRecoverInit\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Decrypts a single part encrypted data
//----------------------------------------------------------------------

CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
    DEBUG_MSG("Enter C_VerifyRecover\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_VerifyRecover called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pData = NULL_PTR;
	*pulDataLen = 0;

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


//----------------------------------------------------------------------
// Continues a multiple part digest & encryption operation
//----------------------------------------------------------------------

CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
{
    DEBUG_MSG("Enter C_DigestEncryptUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DigestEncryptUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pEncryptedPart = NULL_PTR;
	*pulEncryptedPartLen = 0;

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


//----------------------------------------------------------------------
// Continues a multiple part digest & decryption operation
//----------------------------------------------------------------------

CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
{
    DEBUG_MSG("Enter C_DecryptDigestUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DecryptDigestUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pPart = NULL_PTR;
	*pulPartLen = 0;

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


//----------------------------------------------------------------------
// Continues a multiple part signing & encryption operation
//----------------------------------------------------------------------

CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
{
    DEBUG_MSG("Enter C_SignEncryptUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SignEncryptUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pEncryptedPart = NULL_PTR;
	*pulEncryptedPartLen = 0;

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


//----------------------------------------------------------------------
// Continues a multiple part verify & decryption operation
//----------------------------------------------------------------------

CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
{
    DEBUG_MSG("Enter C_DecryptVerifyUpdate\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DecryptVerifyUpdate called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pPart = NULL_PTR;
	*pulPartLen = 0;

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


//----------------------------------------------------------------------
// Generates a secret Key, creating a new key object      
//----------------------------------------------------------------------

CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
{
    DEBUG_MSG("Enter C_GenerateKey\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_GenerateKey called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	phKey = NULL_PTR;

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


//----------------------------------------------------------------------
// Generate a public/private key pair, creating new objects
//----------------------------------------------------------------------

CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, 
				  CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,  
				  CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
{
    DEBUG_MSG("Enter C_GenerateKeyPair\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_GenerateKeyPair called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	phPublicKey = NULL_PTR;
	phPrivateKey = NULL_PTR;

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


//----------------------------------------------------------------------
// Wrap (encrypts) a key                                    
//----------------------------------------------------------------------

CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
			  CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) 
{
    DEBUG_MSG("Enter C_WrapKey\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_WrapKey called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	pWrappedKey = NULL_PTR;
	*pulWrappedKeyLen = 0;   

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


//----------------------------------------------------------------------
// Unwraps (decrypts) a wrapped key, creating a new key object
//----------------------------------------------------------------------

CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
			    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
			    CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) 
{
    DEBUG_MSG("Enter C_UnwrapKey\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_UnwrapKey called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	phKey = NULL_PTR;

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


//----------------------------------------------------------------------
// Derives a key from a base key, creating a new key object
//----------------------------------------------------------------------

CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
			    CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
{
    DEBUG_MSG("Enter C_DeriveKey\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_DeriveKey called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
	phKey = NULL_PTR;

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


//----------------------------------------------------------------------
// Adds seed material into the cards number generator
//----------------------------------------------------------------------

CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen)
{

    DEBUG_MSG("Enter C_SeedRandom\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SeedRandom called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_SeedRandom\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Generate random data                               
//----------------------------------------------------------------------

CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen)
{

    DEBUG_MSG("Enter C_GenerateRandom\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_GenerateRandom called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_GenerateRandom\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Get Status of an executing function           
//----------------------------------------------------------------------

CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
{

    DEBUG_MSG("Enter C_GetFunctionStatus\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_GetFunctionStatus called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_GetFunctionStatus\n");
	return CKR_OK;       
}


//----------------------------------------------------------------------
// Request an executing function to cancel       
//----------------------------------------------------------------------

CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession)
{

    DEBUG_MSG("Enter C_CancelFunction\n");

    if (!pcrypto_info) {
	DEBUG_MSG("C_SetAttributeValue called when cryptoki not initialized\n");
	return CKR_CRYPTOKI_NOT_INITIALIZED;
    }
   
    DEBUG_MSG("Exit C_CancelFunction\n");
	return CKR_OK;       
}

