#include "test_common.h"
#ifdef WIN32
#include "getopt.h"
#else 
extern char *optarg;
#endif

void usage(void);
CK_RV test_crypto();
int test_gost3411_hmac(CK_SESSION_HANDLE sess);

CK_SLOT_ID SlotId;

CK_SLOT_ID_PTR SlotList = NULL;
CK_ULONG SlotCount = 0;

int main(int argc, char *argv[]) {
   CK_RV rc = 1;
   CK_FLAGS flags = 0;
   unsigned long slot_num = 0;  
   int i;

   // parse the command line parameters
	for (i=1; i<argc; i++) {
		if (strcmp("-api", argv[i]) == 0) {
			i++;
			api_path = argv[i];
		} else if (strcmp("-user_pin", argv[i]) == 0) {
			i++;
			user_pin = argv[i];
		}
	}

   // load the PKCS11 library 
	rc = init(api_path, &funcs, NULL);
   if (rc != CKR_OK) {
      fprintf(stderr, "ERROR calling init, rc = %p.\n", (void *)rc);
      return rc;
   }
	rc = get_slot_list(funcs, 
                    &SlotList, 
                    &SlotCount);
	if (rc != CKR_OK) {
		printf("get_slot_list failed, rc = 0x%x\n", rc );
		return rc;
	}
	rc = find_slot_with_token(funcs, 
                           SlotList, 
                           SlotCount, 
                           &SlotId);
	if (rc != CKR_OK) {
		printf("find_slot_with_token failed, rc = 0x%x\n", rc );
		return rc;
	}
		// test the crypto functions 
//	for (i=0; i<20; i++) {
		rc = test_crypto();
		if (rc != CKR_OK) {
			fprintf(stderr, "ERROR call to lissi failed.\n");
			return rc;
		}
//	}
   return CKR_OK;
}


void usage(void)
{
   fprintf(stderr, "Usage: lissi [-c <slotId>]\n"
      "Default slotID is 0\n"
      "To get a list of slotIDs, call pkcs11_cfg -s\n");
   exit(-1);
}

CK_RV test_crypto() 
{
   CK_RV rc, ret;
   CK_SESSION_HANDLE hSession;
	CK_MECHANISM_INFO minfo;

   // open a R/W cryptoki session, CKR_SERIAL_SESSION is a legacy bit we have to set
   rc = funcs->C_OpenSession(SlotId, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL_PTR,
         NULL_PTR, &hSession);
   if (rc != CKR_OK) {
      fprintf(stderr, "ERROR call to C_OpenSession failed, rc = %p\n", (void *)rc);
      goto out;
   }
  fprintf(stderr, "C_OpenSession success\n");
/*
   // log in as normal user 
   rc = funcs->C_Login(hSession, CKU_USER, user_pin, strlen(user_pin));
   if (rc != CKR_OK) {
      fprintf(stderr, "ERROR call to C_Login failed, rc = %p\n", (void *)rc);
      goto out_close;
   }
  fprintf(stderr, "C_Login success\n");
*/
 
	rc = funcs->C_GetMechanismInfo(SlotId, CKM_GOSTR3411_HMAC, &minfo);
	if (rc != CKR_OK) {
		fprintf(stderr, "\n======== Mechanism CKM_GOSTR3411_HMAC not supported ===========\n");
	} else {
		fprintf(stderr, "\n==================== CKM_GOSTR3411_HMAC test ==================\n");
		rc = test_gost3411_hmac(hSession);
		if (rc != CKR_OK) {
			fprintf(stderr, "ERROR CKM_GOSTR3411_HMAC failed, rc = %p\n", (void *)rc);
		} else {
			fprintf(stderr, "CKM_GOSTR3411_HMAC test passed.\n");
		}
	}
 
//out_close:
   if( (ret = funcs->C_CloseSession(hSession)) != CKR_OK ) {
      fprintf(stderr, "Error: C_CloseSession failed with %p\n", (void *)ret);
	  rc = ret;
   }
   else {
      fprintf(stderr, "C_CloseSession success\n");
   }

out:
   return rc;
}

int test_gost3411_hmac(CK_SESSION_HANDLE sess)
{
	int rc = 0;
	CK_BYTE value[256];
	CK_ULONG len;
   	CK_MECHANISM mechanism_desc = 
		{CKM_GOSTR3411_HMAC, NULL, 0};
   	CK_MECHANISM_PTR mechanism = &mechanism_desc;

	CK_OBJECT_HANDLE keyh = CK_INVALID_HANDLE;
	static CK_OBJECT_CLASS oclass = CKO_SECRET_KEY;
	static CK_KEY_TYPE key_type = CKK_GENERIC_SECRET;
	static CK_BBOOL ltrue = CK_TRUE;

	static CK_BYTE keyval1[] = { 
		0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, 
		0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, 
		0x0b,0x0b,0x0b,0x0b,
	};
	static CK_BYTE data1[] = "Hi There";
	static CK_BYTE et1[] = {
		0x34,0x4f,0x17,0xcd,0xa0,0xfa,0x9a,0x56,
		0xdb,0x24,0xed,0x7c,0xf3,0xaa,0xcd,0xe1,
		0xd1,0x26,0xb9,0xe2,0x4e,0xf3,0x92,0xf2,
		0x31,0x77,0x0e,0x3e,0xa8,0x6d,0xde,0x1d,
	};

	static CK_BYTE keyval2[] = { 'J','e','f','e' };
	static CK_BYTE data2[] = "what do ya want for nothing?";
	static CK_BYTE et2[] = {
		0x00,0x61,0x75,0x04,0x8e,0x45,0x72,0xac,
		0x61,0x85,0xfa,0xf5,0xff,0xae,0x49,0x62,
		0x97,0xf9,0x99,0x3f,0xf1,0xab,0xb7,0x05,
		0xce,0x43,0xda,0x09,0x51,0x56,0x8d,0x9a,
	};

	static CK_BYTE keyval3[] = {
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
		0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
	};
	static CK_BYTE data3[] = 
		"Test Using Larger Than Block-Size Key - Hash Key First";
	static CK_BYTE et3[] = {
		0x91,0x77,0xa0,0x5f,0xee,0xca,0xfa,0x5c,
		0xbb,0x14,0x8b,0x17,0x61,0x63,0x70,0xb5,
		0xd5,0x9b,0x23,0x4c,0x56,0x7e,0x26,0x0d,
		0xda,0xe2,0x67,0x2a,0x5f,0xd3,0x45,0xfa,
	};
	// CryptoPro 3411 HASH1 default Param Set
 	static CK_BYTE oid[] = { 
		0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
	};
	static CK_ATTRIBUTE key_template[] = {
		{ CKA_VALUE, NULL_PTR, 0 },
		{ CKA_CLASS, &oclass, sizeof(oclass) },
		{ CKA_KEY_TYPE, &key_type, sizeof(key_type) },
		{ CKA_SIGN, &ltrue, sizeof(ltrue) },
		{ CKA_VERIFY, &ltrue, sizeof(ltrue) }
	};
	
	static CK_BYTE data4[] = {
	    0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
	    0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
	    0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
	    0x67, 0x68, 0x69, 0x6A, 0x68, 0x69, 0x6A, 0x6B,
	    0x69, 0x6A, 0x6B, 0x6C, 0x6A, 0x6B, 0x6C, 0x6D,
	    0x6B, 0x6C, 0x6D, 0x6E, 0x6C, 0x6D, 0x6E, 0x6F,
	    0x6D, 0x6E, 0x6F, 0x70, 0x6E, 0x6F, 0x70, 0x71,
	    0x0A
	};
	static CK_BYTE keyval_32[] = {
	    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	    0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
	    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	    0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
	};
	// For big-endian byte order
	static CK_BYTE et_32[] = {
	    0x52, 0x67, 0xfb, 0xa5, 0xbf, 0x8c, 0x73, 0xaf,
	    0x26, 0x2c, 0xc2, 0xa0, 0x45, 0x61, 0x86, 0x2e,
	    0x28, 0xce, 0xd8, 0xe9, 0x6f, 0x0a, 0x85, 0xf8,
	    0xf8, 0x8b, 0x59, 0x40, 0xb8, 0xf5, 0x4a, 0x56
	};
	// For little-endian byte order
	static CK_BYTE et_32_le[] = {
	    0x6e, 0x18, 0xbf, 0x2e, 0x66, 0x0c, 0x89, 0xb4,
	    0x85, 0xd7, 0x77, 0x25, 0x90, 0x4b, 0x9c, 0x7a,
	    0xbb, 0x85, 0x0e, 0x87, 0x90, 0x09, 0xb5, 0xfa,
	    0xee, 0x9a, 0x41, 0x92, 0xac, 0x81, 0xc8, 0x67
	};
	static CK_BYTE keyval_31[] = {
	    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	    0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
	    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	    0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
	};
	// For big-endian byte order
	static CK_BYTE et_31[] = {
	    0x98, 0x24, 0x2e, 0xd7, 0x01, 0x14, 0xc6, 0x94,
	    0xbf, 0xfd, 0x10, 0x7b, 0x2f, 0x7e, 0xc3, 0xc7,
	    0x87, 0x14, 0x61, 0xaf, 0x7f, 0x39, 0xf4, 0x05,
	    0xe7, 0x2b, 0xfb, 0x63, 0x36, 0x15, 0xf1, 0xce
	};
	// For little-endian byte order
	static CK_BYTE et_31_le[] = {
	    0xd7, 0xee, 0x31, 0x90, 0xa7, 0x8e, 0xd2, 0xd3,
	    0x25, 0xf7, 0x3c, 0xf5, 0xfc, 0xe4, 0x73, 0x54,
	    0x11, 0x34, 0x2f, 0x5c, 0x17, 0x98, 0xc9, 0xea,
	    0x25, 0xb2, 0x8e, 0x90, 0xd3, 0x2c, 0x64, 0x16
	};
	static CK_BYTE keyval_33[] = {
	    0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
	    0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
	    0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
	    0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
	    0x0A
	};
	static CK_BYTE keyval_33_hash[] = {
	    0x10, 0xff, 0xed, 0x16, 0x36, 0x4d, 0xa5, 0x3a,
	    0x07, 0xc9, 0xba, 0x00, 0x0c, 0xb5, 0x55, 0x31,
	    0xab, 0x53, 0xda, 0xf7, 0x1c, 0x1f, 0xfe, 0x31,
	    0xad, 0x48, 0x81, 0xaf, 0xa1, 0x31, 0xae, 0xbe
	};
	// For big-endian byte order
	static CK_BYTE et_33[] = {
	    0x18, 0x8f, 0x6c, 0xc3, 0x3f, 0x19, 0xbe, 0x1b,
	    0x00, 0xa0, 0x67, 0x80, 0x90, 0xdb, 0xb2, 0x2b,
	    0x5a, 0xaa, 0xb3, 0xec, 0x4e, 0x97, 0x5f, 0x6a,
	    0xa5, 0xe5, 0x2b, 0xf3, 0x39, 0x57, 0x72, 0xeb
	};
	// For little-endian byte order
	static CK_BYTE et_33_le[] = {
	    0xe5, 0x60, 0x6b, 0x35, 0x61, 0x72, 0x53, 0x9e,
	    0x69, 0x61, 0x67, 0x3a, 0x85, 0xaa, 0xad, 0xb7,
	    0xe2, 0x99, 0x79, 0x06, 0x6d, 0x22, 0x13, 0x47,
	    0xa4, 0xe0, 0xa6, 0xbe, 0xec, 0x0f, 0xd7, 0xb9
	};
	CK_BYTE *state = NULL;
	CK_ULONG state_len = 0;

	key_template[0].pValue = keyval_32; 
	key_template[0].ulValueLen = sizeof(keyval_32);
	rc = funcs->C_CreateObject(sess, 
		key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE), &keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_CreateObject failed: 0x%x\n", rc);
		goto end;
	}

	mechanism->pParameter = oid;
	mechanism->ulParameterLen = sizeof(oid);
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}

	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_Sign(sess, data4, sizeof(data4), value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Sign failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et_32_le)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -2;
		goto end;
	}
	if (memcmp(value, et_32_le, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -3;
		goto end;
	}
	printf("Sign 32_le OK\n");

	rc = funcs->C_VerifyInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_VerifyInit failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_Verify(sess, data4, sizeof(data4), value, len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Verify failed: 0x%x\n", rc);
		goto end;
	}
	printf("Verify 32_le OK\n");

	rc = funcs->C_DestroyObject(sess, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_DestroyObject failed: 0x%x\n", rc);
		goto end;
	}

	key_template[0].pValue = keyval_31; 
	key_template[0].ulValueLen = sizeof(keyval_31);
	rc = funcs->C_CreateObject(sess, 
		key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE), &keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_CreateObject failed: 0x%x\n", rc);
		goto end;
	}

	// Используется умалчиваемый набор параметров
	mechanism->pParameter = NULL;
	mechanism->ulParameterLen = 0;
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}

	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_Sign(sess, data4, sizeof(data4), value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Sign failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et_31_le)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -4;
		goto end;
	}
	if (memcmp(value, et_31_le, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -5;
		goto end;
	}
	printf("Sign 31_le OK\n");

	rc = funcs->C_VerifyInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_VerifyInit failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_Verify(sess, data4, sizeof(data4), value, len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Verify failed: 0x%x\n", rc);
		goto end;
	}
	printf("Verify 31_le OK\n");

	rc = funcs->C_DestroyObject(sess, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_DestroyObject failed: 0x%x\n", rc);
		goto end;
	}


	key_template[0].pValue = keyval_33_hash; 
	key_template[0].ulValueLen = sizeof(keyval_33_hash);
	rc = funcs->C_CreateObject(sess, 
		key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE), &keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_CreateObject failed: 0x%x\n", rc);
		goto end;
	}

	mechanism->pParameter = 0;
	mechanism->ulParameterLen = 0;
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}

	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_SignUpdate(sess, data4, 7);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignUpdate failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_GetOperationState(sess, NULL, &state_len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_GetOperationState failed: 0x%x\n", rc);
		goto end;
	}
	state = (CK_BYTE *)malloc(state_len);
	rc = funcs->C_GetOperationState(sess, state, &state_len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_GetOperationState failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_SetOperationState(sess, state, state_len,
		CK_INVALID_HANDLE, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SetOperationState failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_SignUpdate(sess, data4+7, sizeof(data4)-7);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignUpdate failed: 0x%x\n", rc);
		goto end;
	}
/*
	rc = funcs->C_GetOperationState(sess, NULL, &state_len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_GetOperationState failed: 0x%x\n", rc);
		goto end;
	}
	state = (CK_BYTE *)malloc(state_len);
	rc = funcs->C_GetOperationState(sess, state, &state_len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_GetOperationState failed: 0x%x\n", rc);
		goto end;
	}
*/
	rc = funcs->C_SignFinal(sess, value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignFinal failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et_33_le)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -6;
		goto end;
	}
	if (memcmp(value, et_33_le, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -7;
		goto end;
	}
	printf("Sign 33_le multipart OK\n");
/*
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}
*/
	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_SetOperationState(sess, state, state_len,
		CK_INVALID_HANDLE, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SetOperationState failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_SignUpdate(sess, data4+7, sizeof(data4)-7);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignUpdate failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_SignFinal(sess, value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignFinal failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et_33_le)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -6;
		goto end;
	}
	if (memcmp(value, et_33_le, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -7;
		goto end;
	}
	printf("Sign 33_le restored multipart OK\n");
	free(state);
	state = NULL;

	rc = funcs->C_VerifyInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_VerifyInit failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_Verify(sess, data4, sizeof(data4), value, len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Verify failed: 0x%x\n", rc);
		goto end;
	}
	printf("Verify 33_le OK\n");



	rc = funcs->C_DestroyObject(sess, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_DestroyObject failed: 0x%x\n", rc);
		goto end;
	}


	key_template[0].pValue = keyval_33; 
	key_template[0].ulValueLen = sizeof(keyval_33);
	rc = funcs->C_CreateObject(sess, 
		key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE), &keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_CreateObject failed: 0x%x\n", rc);
		goto end;
	}

	mechanism->pParameter = 0;
	mechanism->ulParameterLen = 0;
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}

	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_Sign(sess, data4, sizeof(data4), value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Sign failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et_33_le)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -8;
		goto end;
	}
	if (memcmp(value, et_33_le, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -9;
		goto end;
	}

	rc = funcs->C_VerifyInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_VerifyInit failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_Verify(sess, data4, sizeof(data4), value, len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Verify failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_DestroyObject(sess, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_DestroyObject failed: 0x%x\n", rc);
		goto end;
	}

	key_template[0].pValue = keyval1; 
	key_template[0].ulValueLen = sizeof(keyval1);
	rc = funcs->C_CreateObject(sess, 
		key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE), &keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_CreateObject failed: 0x%x\n", rc);
		goto end;
	}

	mechanism->pParameter = 0;
	mechanism->ulParameterLen = 0;
	
	rc = funcs->C_SignInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_SignInit failed: 0x%x\n", rc);
		goto end;
	}

	memset(value,0,sizeof(value));
	len = sizeof(value);
	rc = funcs->C_Sign(sess, data1, strlen(data1), value, &len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Sign failed: 0x%x\n", rc);
		goto end;
	}

	if (len != sizeof(et1)) {
		fprintf(stderr, "Invalid length: %d\n", len);
		rc = -10;
		goto end;
	}
	if (memcmp(value, et1, len) != 0) {
		fprintf(stderr, "Invalid value\n");
		rc = -11;
		goto end;
	}

	rc = funcs->C_VerifyInit(sess, mechanism, keyh);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_VerifyInit failed: 0x%x\n", rc);
		goto end;
	}

	rc = funcs->C_Verify(sess, data1, strlen(data1), value, len);
	if (rc != CKR_OK) {
		fprintf(stderr, "C_Verify failed: 0x%x\n", rc);
		goto end;
	}
	printf("SUCCESS\n");
	rc = CKR_OK;
end:
	if (keyh != CK_INVALID_HANDLE) {
		funcs->C_DestroyObject(sess, keyh);
	}

	return rc;
}



