/*--------------------------------------------------------------*
 *	UniMate Drive PKCS#11 Sample
 *	2015-04-10
 *--------------------------------------------------------------*/

#include "global.h"

CK_FUNCTION_LIST_PTR fl = 0;

CK_OBJECT_HANDLE find_object(CK_SESSION_HANDLE hSess, CK_ATTRIBUTE * t, CK_ULONG size)
{
	CK_OBJECT_HANDLE list[1];
	CK_ULONG found = 0;
	
	/* initialize the search for any object with attribute 't'
	 */
	if (CKR_OK != fl->C_FindObjectsInit (hSess, t, size))
	{
		leave("C_FindObjectsInit failed.\n");
		return 0;
	}
	
	/* find the objects which match, we ask for only a single match
	 * since we know there is only one on the UniMate Drive(InitToken creates a single public/private key pair)
	 */
	if (CKR_OK != fl->C_FindObjects(hSess, list, 1, &found))
	{
		leave("C_FindObjects failed.\n");
		return 0;
	}
	
	/* cleanup the search
	 */
	if (CKR_OK != fl->C_FindObjectsFinal(hSess))
	{
		leave ("C_FindObjectsFinal failed.\n");
		return 0;
	}
	
	/* either return NULL if nothing matches or return the object handle
	 * of the matching object
	 */
	if (found < 1)
		return NULL;
	
	return (list[0]);
}

int exportPubKey()
{
	CK_ULONG slot_count = 100;
	CK_SLOT_ID slots[100];
	CK_SESSION_HANDLE session;
	CK_BBOOL         bFalse = FALSE;
	CK_BBOOL         bTrue = TRUE;
	CK_KEY_TYPE      key_type  = CKK_RSA;
	int loop = 0;

	/* setup public key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and public to all
	 * users of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY;
	CK_ULONG vecModulusBits  = 2048;
	CK_BYTE public_exponent[] = { 0x01, 0x00, 0x01 };
	CK_BBOOL b = TRUE;
	CK_BYTE KID = 0;
	CK_CHAR	label_public[] = labelPu;
	CK_ATTRIBUTE public_key_template[] = 
	{
		{ CKA_ENCRYPT,			&b,					sizeof (b) },
		{ CKA_CLASS,			&class_public_key,  sizeof (class_public_key) },
		{ CKA_LABEL,			label_public,       sizeof (label_public) },
		{ CKA_KEY_TYPE,			&key_type,          sizeof (key_type) },
		{ CKA_TOKEN,			&bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,			&bFalse,            sizeof (bFalse) },
		{ CKA_MODULUS_BITS,		&vecModulusBits,	sizeof (vecModulusBits) },
		{ CKA_PUBLIC_EXPONENT,	&public_exponent,	sizeof (public_exponent) },
	};

	CK_OBJECT_HANDLE public_key;

	CK_CHAR rsa_v[0x100] = {0};
	CK_ATTRIBUTE pub_get_a[1] = {
		{CKA_MODULUS, rsa_v,sizeof(rsa_v)}
	};

	printf("Export PublicKey Sample:\n");
	
	fl = InitFunctionList();
	if (fl == 0)
		return leave("Can't get function list. \n");
	
	/* Initialize the PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Initialize (0))
		return leave("C_Initialize failed...");                       
	
	/* Get list of slots containing UniMate Drives
	 */
	
	if (PKCS_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
		return leave("C_GetSlotList failed...");

	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	printf ("UniMate Drive Found.\n");
	/* open a read/write session on the first UniMate Drive found
	 */
	if (PKCS_OK != fl->C_OpenSession(slots[0], 
		(CKF_SERIAL_SESSION | CKF_RW_SESSION), 0, 0, &session)
		)
		return leave("C_OpenSession failed.\n");
	
	/* login as user so we can use the public and private
	 * keys on the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Login(session, CKU_USER, USER_PIN, 8))
		return leave("C_Login failed.\n");

	public_key = find_object(session, public_key_template, 1);
	if( !public_key )
		return leave("Cannot find public_key");

	fl->C_GetAttributeValue(session,public_key,pub_get_a,1);

	printf("Public_key.n = ");
	for(loop;loop<sizeof(rsa_v);loop++)
	{
		printf("%x",rsa_v[loop]);
	}

	printf("\n");

	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");
    
	/* close open session
	 */
	if (PKCS_OK != fl->C_CloseSession (session))
		return leave("C_CloseSession failed.\n");
	
	
	/* close PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Finalize(0))
		return leave("C_Finalize failed.\n");
    Finalize();

	return PKCS_OK;
}

int generateRSA()
{
	
	CK_RV rv;
	CK_ULONG slot_count = 100;
	CK_SLOT_ID slots[100];
	CK_SESSION_HANDLE session;
	CK_BBOOL         bFalse = FALSE;
	CK_BBOOL         bTrue = TRUE;
	CK_KEY_TYPE      key_type  = CKK_RSA;

	/* setup public key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and public to all
	 * users of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY;
	CK_ULONG vecModulusBits  = 2048;
	CK_BYTE public_exponent[] = { 0x01, 0x00, 0x01 };
	CK_BBOOL b = TRUE;
	CK_BYTE KID = 0;
	CK_CHAR	label_public[] = labelPu;
	CK_CHAR label_private[] = labelPr;
	CK_ATTRIBUTE public_key_template[] = 
	{
		{ CKA_ENCRYPT,			&b,					sizeof (b) },
		{ CKA_CLASS,			&class_public_key,  sizeof (class_public_key) },
		{ CKA_LABEL,			label_public,       sizeof (label_public) },
		{ CKA_KEY_TYPE,			&key_type,          sizeof (key_type) },
		{ CKA_TOKEN,			&bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,			&bFalse,            sizeof (bFalse) },
		{ CKA_MODULUS_BITS,		&vecModulusBits,	sizeof (vecModulusBits) },
		{ CKA_PUBLIC_EXPONENT,	&public_exponent,	sizeof (public_exponent) },
	};
	
	/* setup private key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and private to only
	 * the user of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_private_key = CKO_PRIVATE_KEY;
	CK_ATTRIBUTE private_key_template[] = 
	{
		{ CKA_DECRYPT,  &b,					sizeof (b) },
		{ CKA_SIGN,		&b,					sizeof (b) },
		{ CKA_CLASS,    &class_private_key, sizeof (class_private_key) },
		{ CKA_LABEL,    label_private,      sizeof (label_private) },
		{ CKA_KEY_TYPE, &key_type,          sizeof (key_type) },
		{ CKA_TOKEN,    &bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,  &bTrue,             sizeof (bTrue) },
		{ CKA_KEY_ID,   &KID,				sizeof (KID) },
	};
	/* setup mechanism to generate RSA key pair
	 */
	CK_MECHANISM mechanism = {0};
	CK_OBJECT_HANDLE public_key;
	CK_OBJECT_HANDLE private_key;
	
	printf("Generate RSA-2048 Keypair Sample:\n");
	
	fl = InitFunctionList();
	if (fl == 0)
		return leave("Can't get function list. \n");
	
	/* Initialize the PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Initialize (0))
		return leave("C_Initialize failed...");                       
	
	/* Get list of slots containing UniMate Drive
	 */
	if (PKCS_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
		return leave("C_GetSlotList failed...");

	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	printf ("UniMate Drive Found.\n");
	/* open a read/write session on the first UniMate Drive found
	 */
	if (PKCS_OK != fl->C_OpenSession(slots[0], 
		(CKF_SERIAL_SESSION | CKF_RW_SESSION), 0, 0, &session))
		return leave("C_OpenSession failed.\n");
	
	/* login as user so we can use the public and private
	 * keys on the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Login(session, CKU_USER, USER_PIN, 8))
		return leave("C_Login failed.\n");
	
	/* Try to find the two keys using the find_object utility function if exist,
	 * or generate new key pair.
	*/
	mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
	private_key = find_object(session, private_key_template, 1);
	public_key = find_object(session,  public_key_template,  1);
	
	if (!(public_key && private_key))
	{
		printf ("Wait For Generating RSA-2048 Keypair Now ... \n");
		rv = fl->C_GenerateKeyPair(session,&mechanism, public_key_template, 8,
			private_key_template,7,&public_key,&private_key);
		if(PKCS_OK !=rv)
		{
			fl->C_Logout(session);
			fl->C_CloseSession(session);
			return leave("C_GenerateKeyPair failed.  Please run InitToken first.");
		}

		printf ("Generating RSA-2048 Keypair Succeed.\n");
	}
	else
	{
		printf("Keypair already exists.\n");
	}
	
	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");
    
	/* close open session
	 */
	if (PKCS_OK != fl->C_CloseSession (session))
		return leave("C_CloseSession failed.\n");
	
	
	/* close PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Finalize(0))
		return leave("C_Finalize failed.\n");
    Finalize();
	
	return PKCS_OK;
}


int ReloadPIN( CK_SESSION_HANDLE hSession )
{
	CK_RV rv;
	/* Login as SO
	 */
	rv = fl->C_Login(hSession, CKU_SO, USER_PIN, 8);
	if (CKR_OK != rv)
		return leave ("C_Login failed.\n");

	/* change PIN
	 */
	rv = fl->C_SetPIN( hSession, USER_PIN, 8, ADMIN_PIN, 8 );
	if(CKR_OK != rv)
		return leave("C_SetPIN(ADMIN_PIN) failed.\n");

	/* logout of the UniMate Drive
	*/
	if (PKCS_OK != fl->C_Logout (hSession))
		return leave("C_Logout failed.\n");

	/* Login as USER
	 */
	rv = fl->C_Login(hSession, CKU_USER, ADMIN_PIN, 8);
	if (CKR_OK != rv)
		return leave ("C_Login failed.\n");

	/* Change USER PIN
	 */
	rv = fl->C_SetPIN( hSession, ADMIN_PIN, 8, USER_PIN, 8 );
	if(CKR_OK != rv)
		return leave("C_SetPIN(USER_PIN) failed.\n");

	/* logout of the UniMate Drive
	*/
	if (PKCS_OK != fl->C_Logout (hSession))
		return leave("C_Logout failed.\n");

	return CKR_OK;
}

int ModifyPin()
{
	CK_RV rv;
	CK_ULONG slot_count = 100;
	CK_SLOT_ID slots[100];
	CK_SESSION_HANDLE session;
	
	CK_CHAR_PTR pNewSOPin = NULL;
	CK_CHAR_PTR pNewUSERPin = NULL;
	CK_CHAR_PTR pOldSOPin = ADMIN_PIN;
	CK_CHAR_PTR pOldUSERPin = USER_PIN;
	
	printf("Modify PIN Sample:\n");
	
	fl = InitFunctionList();
	if (fl == 0)
		return leave("Can't get function list. \n");
	
	/* Initialize the PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Initialize (0))
		return leave("C_Initialize failed...");                       
	
	/* Get list of slots containing UniMate Drive
	 */
	
	if (PKCS_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
		return leave("C_GetSlotList failed...");

	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	printf ("UniMate Drive Found.\n");
	/* open a read/write session on the first UniMate Drive found
	 */
	if (PKCS_OK != fl->C_OpenSession(slots[0], 
		(CKF_SERIAL_SESSION | CKF_RW_SESSION), 0, 0, &session) )
		return leave("C_OpenSession failed.\n");

	/* Login as SO
	 */
	printf("Logging in UniMate Drive as SO with password of Admin.\n");
	printf("Old admin PIN:%s\n",ADMIN_PIN);
	rv = fl->C_Login(session, CKU_SO, ADMIN_PIN, 8);
	if (CKR_OK != rv)
		return leave ("C_Login failed.\n");

	/* change PIN
	 */
	pNewSOPin = USER_PIN;
	rv = fl->C_SetPIN( session, pOldSOPin, 8, pNewSOPin, 8 );
	if(CKR_OK != rv)
		return leave("C_SetPIN(ADMIN_PIN) failed.\n");

	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");

	/* Check NewSOPin
	 */
	rv = fl->C_Login(session, CKU_SO, pNewSOPin, 8);
	if (PKCS_OK != rv)
		return leave("C_Login failed.\n");

	printf("Changing SO PIN Succeed.\n");
	printf("New admin PIN:%s\n",USER_PIN);
	
	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");	


	/* Login as USER
	 */
	printf("Logging in UniMate Drive as USER with password of User.\n");
	printf("Old user PIN:%s\n",USER_PIN);
	rv = fl->C_Login(session, CKU_USER, USER_PIN, 8);
	if (CKR_OK != rv)
		return leave ("C_Login failed.\n");

	/* Change USER PIN
	 */
	pNewUSERPin = ADMIN_PIN;
	rv = fl->C_SetPIN( session, pOldUSERPin, 8, pNewUSERPin, 8 );
	if(CKR_OK != rv)
		return leave("C_SetPIN(USER_PIN) failed.\n");

	/* logout of the UniMate Drive
	*/
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");

	/* Check NewUSERPin
	 */
	rv = fl->C_Login(session, CKU_USER, pNewUSERPin, strlen(pNewUSERPin));
	if (PKCS_OK != rv)
		return leave("C_Login failed.\n");

	printf("Changing USER PIN Succeed.\n");
	printf("New user PIN:%s\n",pNewUSERPin);

	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");

	/* PIN Recovery 
	 */
	printf("PIN Reloads.\n");
	ReloadPIN( session );

	/* close open session
	 */
	if (PKCS_OK != fl->C_CloseSession (session))
		return leave("C_CloseSession failed.\n");
		
	/* close PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Finalize(0))
		return leave("C_Finalize failed.\n");
    Finalize();
		
	return PKCS_OK;
}

int ReadSN()
{
	CK_FUNCTION_LIST_PTR	fl;
	unsigned long slot_count = 100;
	CK_SLOT_ID slots[100];
	char SN[100];
	unsigned long i;
	unsigned long j;
	
	printf ("Read SN Sample:\n");

	fl = InitFunctionList();
	if (fl == 0)
		return leave ("Can't get function list. \n");;
	
	/* Initialize the PKCS #11 library
	 */
	if (CKR_OK != fl->C_Initialize (0))
		return leave ("C_Initialize failed...\n");
	
	/* get a list of all the slots containing UniMate Drive
	 */
	if (CKR_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
		return leave ("C_GetSlotList failed...\n");
	
	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	/* loop across all the slots which have tokens
	 */
	for (i = 0; i < slot_count; i++)
	{
		/* get the slot information 
		 */
		CK_SLOT_ID slot = slots[0];
		CK_TOKEN_INFO token_info;
		if (CKR_OK != fl->C_GetTokenInfo(slot, &token_info))
			return leave("C_GetSlotInfo failed...\n");

		/* Display slot information(see definition of CK_SLOT_INFO for more info)
		 */
		printf("Hardware SN: ");
		strcpy(SN, (char*)token_info.serialNumber);
		SN[17] = 0;
		
		printf("%s\n", SN);
	}
	/* close PKCS #11 library
	 */
	if (CKR_OK != fl->C_Finalize(0))
	{
		return leave ("C_Finalize failed...\n");
	}
	Finalize();

	return PKCS_OK;
}

CK_BYTE message[100];   
CK_BYTE signature[500];    
CK_ULONG signature_length = 500;

int sign()
{
	CK_RV rv;
	CK_ULONG slot_count = 100;
	CK_SLOT_ID slots[100];
	CK_SESSION_HANDLE session;
	CK_BBOOL         bFalse = FALSE;
	CK_BBOOL         bTrue = TRUE;
	CK_KEY_TYPE      key_type  = CKK_RSA;
	int loop = 0;

	/* setup public key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and public to all
	 * users of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY;
	CK_ULONG vecModulusBits  = 2048;
	CK_BYTE public_exponent[] = { 0x01, 0x00, 0x01 };
	CK_BBOOL b = TRUE;
	CK_BYTE KID = 0;
	CK_CHAR	label_public[] = labelPu;
	CK_CHAR label_private[] = labelPr;
	CK_ATTRIBUTE public_key_template[] = 
	{
		{ CKA_ENCRYPT,			&b,					sizeof (b) },
		{ CKA_CLASS,			&class_public_key,  sizeof (class_public_key) },
		{ CKA_LABEL,			label_public,       sizeof (label_public) },
		{ CKA_KEY_TYPE,			&key_type,          sizeof (key_type) },
		{ CKA_TOKEN,			&bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,			&bFalse,            sizeof (bFalse) },
		{ CKA_MODULUS_BITS,		&vecModulusBits,	sizeof (vecModulusBits) },
		{ CKA_PUBLIC_EXPONENT,	&public_exponent,	sizeof (public_exponent) },
	};
	
	/* setup private key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and private to only
	 * the user of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_private_key = CKO_PRIVATE_KEY;
	CK_ATTRIBUTE private_key_template[] = 
	{
		{ CKA_DECRYPT,  &b,					sizeof (b) },
		{ CKA_SIGN,		&b,					sizeof (b) },
		{ CKA_CLASS,    &class_private_key, sizeof (class_private_key) },
		{ CKA_LABEL,    label_private,      sizeof (label_private) },
		{ CKA_KEY_TYPE, &key_type,          sizeof (key_type) },
		{ CKA_TOKEN,    &bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,  &bTrue,             sizeof (bTrue) },
		{ CKA_KEY_ID,   &KID,				sizeof (KID) },
	};
	/* setup mechanism to generate RSA key pair
	 */
	CK_MECHANISM mechanism = {0};
	CK_OBJECT_HANDLE public_key;
	CK_OBJECT_HANDLE private_key;
	
	printf("Sign with Sha512 Sample:\n");
	
	fl = InitFunctionList();
	if (fl == 0)
		return leave("Can't get function list. \n");
	
	/* Initialize the PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Initialize (0))
		return leave("C_Initialize failed...");                       
	
	/* Get list of slots containing UniMate Drive
	 */
	
	if (PKCS_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
		return leave("C_GetSlotList failed...");

	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	printf ("Found UniMate Drive.\n");
	/* open a read/write session on the first UniMate found
	 */
	if (PKCS_OK != fl->C_OpenSession(slots[0], 
		(CKF_SERIAL_SESSION | CKF_RW_SESSION), 0, 0, &session))
		return leave("C_OpenSession failed.\n");
	
	/* login as user so we can use the public and private
	 * keys on the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Login(session, CKU_USER, USER_PIN, 8))
		return leave("C_Login failed.\n");
	
	/* Try to find the two keys using the find_object utility function if exist,
	 * or generate new key pair.
	 */
	mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
	private_key = find_object(session, private_key_template, 1);
	public_key = find_object(session,  public_key_template,  1);
	
	if (!(public_key && private_key))
	{
		printf ("Wait For Generate RSA PKCS KEY PAIR Now ... \n");
		rv = fl->C_GenerateKeyPair(session,&mechanism, public_key_template, 8,
			private_key_template,7,&public_key,&private_key);
		if(PKCS_OK != rv)
		{
			fl->C_Logout(session);
			fl->C_CloseSession(session);
			return leave("C_GenerateKeyPair failed.  Please run InitToken first.");
		}
	}
	
	/* setup the RSA mechanism
	 */
	memset (&mechanism, 0, sizeof (mechanism));
	mechanism.mechanism = CKM_SHA512_RSA_PKCS;
	

	/* setup the message we will sign
	 */
 
	strcpy((char *) message, "body of the message");

	printf("The Mechanism:CKM_SHA512_RSA_PKCS\n");
	printf("The Signed Message:%s\n",(char*)message);
	
	/* setup signature operation with private key
	 */
	rv = fl->C_SignInit(session, &mechanism, private_key);
	if (CKR_OK != rv)
	{
		fl->C_Logout(session);
		
		return leave("C_SignInit failed...\n");
	}                       
	
	/* sign the message and get back the signature
	 */
	if (CKR_OK != fl->C_Sign(session, message,  strlen((char *)message),
		signature, &signature_length))
	{
		fl->C_Logout(session);
		
		return leave("C_Sign failed...\n");
	}

	printf("Signature:\n");
	for(loop;loop<signature_length;loop++)
	{
		printf ("%x",signature[loop]);
	}
	printf("\n");

	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");
    
	/* close open session
	 */
	if (PKCS_OK != fl->C_CloseSession (session))
		return leave("C_CloseSession failed.\n");
	
	
	/* close PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Finalize(0))
		return leave("C_Finalize failed.\n");
    Finalize();

	return PKCS_OK;
}

int RemoveRSA()
{
	CK_ULONG slot_count = 100;
	CK_SLOT_ID slots[100];
	CK_SESSION_HANDLE session;
	CK_BBOOL         bFalse = FALSE;
	CK_BBOOL         bTrue = TRUE;
	CK_KEY_TYPE      key_type  = CKK_RSA;

	/* setup public key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and public to all
	 * users of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY;
	CK_ULONG vecModulusBits  = 2048;
	CK_BYTE public_exponent[] = { 0x01, 0x00, 0x01 };
	CK_BBOOL b = TRUE;
	CK_BYTE KID = 0;
	CK_CHAR	label_public[] = labelPu;
	CK_CHAR label_private[] = labelPr;
	CK_ATTRIBUTE public_key_template[] = 
	{
		{ CKA_ENCRYPT,			&b,					sizeof (b) },
		{ CKA_CLASS,			&class_public_key,  sizeof (class_public_key) },
		{ CKA_LABEL,			label_public,       sizeof (label_public) },
		{ CKA_KEY_TYPE,			&key_type,          sizeof (key_type) },
		{ CKA_TOKEN,			&bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,			&bFalse,            sizeof (bFalse) },
		{ CKA_MODULUS_BITS,		&vecModulusBits,	sizeof (vecModulusBits) },
		{ CKA_PUBLIC_EXPONENT,	&public_exponent,	sizeof (public_exponent) },
	};
	
	/* setup private key attributes, specific name so we can find it 
	 * later, RSA key type, saved on the UniMate Drive and private to only
	 * the user of the UniMate Drive
	 */
	CK_OBJECT_CLASS class_private_key = CKO_PRIVATE_KEY;
	CK_ATTRIBUTE private_key_template[] = 
	{
		{ CKA_DECRYPT,  &b,					sizeof (b) },
		{ CKA_SIGN,		&b,					sizeof (b) },
		{ CKA_CLASS,    &class_private_key, sizeof (class_private_key) },
		{ CKA_LABEL,    label_private,      sizeof (label_private) },
		{ CKA_KEY_TYPE, &key_type,          sizeof (key_type) },
		{ CKA_TOKEN,    &bTrue,             sizeof (bTrue) },
		{ CKA_PRIVATE,  &bTrue,             sizeof (bTrue) },
		{ CKA_KEY_ID,   &KID,				sizeof (KID) },
	};
	/* setup mechanism to generate RSA key pair
	 */
	CK_MECHANISM mechanism = {0};
	CK_OBJECT_HANDLE public_key;
	CK_OBJECT_HANDLE private_key;
	
	printf("Remove RSA-2048 Keypair Sample:\n");
	
	fl = InitFunctionList();
	if (fl == 0)
		return leave("Can't get function list. \n");
	
	/* Initialize the PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Initialize (0))
		return leave("C_Initialize failed...");                       
	
	/* Get list of slots containing UniMate Drive
	 */
	
	if (PKCS_OK != fl->C_GetSlotList (TRUE, slots, &slot_count))
	{
		return leave("C_GetSlotList failed...");
	}

	/* One or more UniMate Drive must be inserted
	 */
	if (slot_count < 1)
	{
		/* close PKCS #11 library
		 */
		if (PKCS_OK != fl->C_Finalize(0))
			return leave("C_Finalize failed.\n");
		Finalize();
		return leave("No UniMate Drive is available.\n");
	}
	
	printf ("UniMate Drive Found.\n");
	/* open a read/write session on the first UniMate Drive found
	 */
	if (PKCS_OK != fl->C_OpenSession(slots[0], 
		(CKF_SERIAL_SESSION | CKF_RW_SESSION), 0, 0, &session))
		return leave("C_OpenSession failed.\n");
	
	/* login as user so we can use the public and private
	 * keys on the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Login(session, CKU_USER, USER_PIN, 8))
		return leave("C_Login failed.\n");
	
	/* Try to find the two keys using the find_object utility function if exist,
	 * or generate new key pair.
	*/
	private_key = find_object(session, private_key_template, 1);
	public_key = find_object(session,  public_key_template,  1);
	
	if (!(public_key && private_key))
		return leave("Cannot Find Keypair.");

	/* destroy both RSA key objects
	 */

	if (PKCS_OK != fl->C_DestroyObject (session,public_key))
		return leave("C_DestroyObject public Obj failed.\n");

	printf ("Destroy public_key succeed.\n");

	if (PKCS_OK != fl->C_DestroyObject (session,private_key))
		return leave("C_DestroyObject Private Obj failed.\n");

	printf ("Destroy private_key succeed.\n");

	/* logout of the UniMate Drive
	 */
	if (PKCS_OK != fl->C_Logout (session))
		return leave("C_Logout failed.\n");
    
	/* close open session
	 */
	if (PKCS_OK != fl->C_CloseSession (session))
		return leave("C_CloseSession failed.\n");
	
	
	/* close PKCS #11 library
	 */
	if (PKCS_OK != fl->C_Finalize(0))
		return leave("C_Finalize failed.\n");
    Finalize();
	
	return PKCS_OK;
}

int main(int argc, char **argv)
{
	int userSelect;
	while(1) 
	{
		printf("-----------UniMate Drive PKCS#11 Sample-----------\n");
		printf("1: Read SN\n");
		printf("2: Modify Pin\n");
		printf("3: Generate RSA KeyPair(2048 bit)\n");
		printf("4: Export Public Key\n");
		printf("5: Sign\n");
		printf("6: Remove RSA KeyPair\n");
		printf("0: exit\n");
		printf("--------------------------------------------------\n");
		printf("Input Select:");
		scanf("%d", &userSelect);
		printf("\n");
		switch (userSelect)
		{
		case 0:
			printf("***********************Finished***********************\n");
			return 0;

		case 1:
			ReadSN();
			break;

		case 2:
			ModifyPin();
			break;

		case 3:
			generateRSA();
			break;

		case 4:
			exportPubKey();
			break;

		case 5:
			sign();
			break;

		case 6:
			RemoveRSA();
			break;
		}
		printf("\n");
	};
	return 0;
}