#include <stdio.h>
#include <string.h>
#include "include/quote.h"
#include "include/trm_helper.h"

int _quote_Main(char* nonce_, int nonce_length, unsigned char* retData){

	TSS_HCONTEXT hContext;
	TSS_HTPM hTPM;
	TSS_HPCRS hPcrComposite;
	TSS_HKEY signKey, hSRK;
	TSS_RESULT result;
	TSS_HPOLICY keyUsagePolicy;
	TSS_HPOLICY srkUsagePolicy;
	TSS_VALIDATION quoteValidationData;
	TSS_HHASH hHash;

	unsigned char digest[DIGEST_SIZE];
	int i,j,c;
	int k=0;

	printf("\n***********Entering _quote_Main_***************\n");

	printf("@Quote@ received nonce (gxgy):");
	for(i=0;i<nonce_length;i++)
		printf("%c",nonce_[i]);
	printf("\n");

	//Create Context
	result = Tspi_Context_Create(&hContext);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ context create error\n");
		goto out_close;
	}
	//Connect Context
	result = Tspi_Context_Connect(hContext, NULL);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ context connect error\n");
		goto out_close;
	}


	//Load SRK By UUID
	result = Tspi_Context_LoadKeyByUUID(hContext,TSS_PS_TYPE_SYSTEM,SRKUUID,&hSRK);
	if (result != TSS_SUCCESS) {
		printf("load key error\n");
		Tspi_Context_CloseObject(hContext, hSRK);
		Tspi_Context_Close(hContext);
		exit(1);
	}

	//Get Policy Object
	result =
	    Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
	if (result != TSS_SUCCESS) {
		printf("get policy object error\n");
		Tspi_Context_CloseObject(hContext, hSRK);
		Tspi_Context_Close(hContext);
		exit(1);
	}

	//Set Secret
	result =
	    Tspi_Policy_SetSecret(srkUsagePolicy,TSS_SECRET_MODE_PLAIN,strlen(SRK_AUTH),SRK_AUTH);
	if (result != TSS_SUCCESS) {
		printf("set secret error\n");
		Tspi_Context_CloseObject(hContext, hSRK);
		Tspi_Context_Close(hContext);
		exit(1);
	}


	//Load the key used to quote
	result = Tspi_Context_GetKeyByUUID(hContext,TSS_PS_TYPE_SYSTEM,signKey_UUID,&signKey);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ sign load key error\n");
		goto out_close;
	}

	result = Tspi_Key_LoadKey(signKey, hSRK);
	if (result != TSS_SUCCESS) {
		printf("Tspi_Key_LoadKey, %x\n", result);
		Tspi_Context_FreeMemory(hContext, NULL);
		Tspi_Context_Close(hContext);
		exit(result);
	}


	//Get policy object
	result=Tspi_GetPolicyObject(signKey, TSS_POLICY_USAGE, &keyUsagePolicy);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ get policy object error\n");
		goto out_close;
	}
	//Set Secret
	result=Tspi_Policy_SetSecret(keyUsagePolicy, TSS_SECRET_MODE_PLAIN, strlen(AIK_AUTH), AIK_AUTH);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ set secret error\n");
		goto out_close;
	}

	//Get TPM Object
	result = Tspi_Context_GetTpmObject(hContext, &hTPM);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ get tpm object error\n");
		goto out_close;
	}

	//Create pcr composite object
	result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, 0, &hPcrComposite);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ create pcr composite error\n");
		goto out_close;
	}

	//Select pcr index to quote
	result = Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, QUOTE_PCR_NUM);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ select pcr index error\n");
		goto out_close;
	}

	//20 byte nonce for quote
	strcat(nonce_,QUOTE_NONCE);
	nonce_[QUOTE_NONCE_LENGTH]='\0';
	printf("@Quote@ Actual nonce for tpm quote: %s\n", nonce_);

	//Call TPM Quote
	quoteValidationData.ulExternalDataLength = QUOTE_NONCE_LENGTH;
	quoteValidationData.rgbExternalData = nonce_;
	result = Tspi_TPM_Quote(hTPM, signKey, hPcrComposite, &quoteValidationData);
	if (result != TSS_SUCCESS){
		printf("@Quote@ tpm quote error\n");
	}
	else printf("Quote success! Quote Info:\n");

	//Validate quote info length
	if (quoteValidationData.ulDataLength!=QUOTE_INFO_LENGTH){
		printf("@Quote@ unexpected tcpa_quote_info length...exiting...\n");
		goto out_close;
	}

	//display quote info
	printf("version:\n");
	for(i=0;i<4;i++)
		printf("%02x ",quoteValidationData.rgbData[i]);
	printf("\n");
	printf("fixed value:\n");
	for(i=4;i<8;i++)
		printf("%c",quoteValidationData.rgbData[i]);
	printf("\n");
	printf("pcr digest:\n");
	for(i=8;i<28;i++)
		printf("%02x ",quoteValidationData.rgbData[i]);
	printf("\n");
	printf("nonce:\n");
	for(i=28;i<quoteValidationData.ulDataLength;i++)
		printf("%c",quoteValidationData.rgbData[i]);
	printf("\n");


	//calculate hash of TCPA_QUOTE_INFO structure
	SHA1(quoteValidationData.rgbData, quoteValidationData.ulDataLength, digest);
	printf("\n@Quote@ digest of tcpa_quote_info:\n");
	for (i=0;i<DIGEST_SIZE;i++)
		printf("%02x ", digest[i]);
	printf("\n");

	//create hash object
	result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_HASH, TSS_HASH_SHA1, &hHash);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ create hash object error\n");
		goto out_close;
	}

	//Set digest as the hash value on hHash
	result = Tspi_Hash_SetHashValue(hHash, DIGEST_SIZE, digest);
	if (result != TSS_SUCCESS) {
		printf("@Quote@ set hash value error\n");
		goto out_close;
	}

	//Populate retData=rgbData||rgbValidationData
	for(i=0;i<quoteValidationData.ulDataLength;i++)
		retData[i]=quoteValidationData.rgbData[i];
	for(j=i;j<quoteValidationData.ulValidationDataLength+quoteValidationData.ulDataLength;j++){
		retData[j]=quoteValidationData.rgbValidationData[k];
		k++;
	}

	printf("\n@Quote@ return data from quote: quote info||signature\n");
	for(i=0;i<quoteValidationData.ulValidationDataLength+quoteValidationData.ulDataLength;i++){
		printf("%x",retData[i]);
	}
	printf("\n");

	Tspi_Context_FreeMemory(hContext, NULL);
	Tspi_Context_CloseObject(hContext, signKey);
	Tspi_Context_Close(hContext);
	printf("***********Leaving _quote_Main_***************\n");
	return j;

out_close:
	Tspi_Context_FreeMemory(hContext, NULL);
	Tspi_Context_CloseObject(hContext, signKey);
	Tspi_Context_Close(hContext);
	printf("\n***********Leaving _quote_Main_***************\n");
	return -1;

}
