#include <stdio.h>
#include <string.h>
#include "include/quote_verify.h"

TSS_RESULT quote_verify(unsigned char* nonce_, int nonce_length, char* gxgy, int gxgyLength, char* fPath, int fsize){
	
	TSS_HCONTEXT hContext;
	TSS_HKEY signKey,verifyKey;
	TSS_RESULT result;
	TSS_HHASH hHash;
	BYTE *prgbPubKey;

	unsigned char digest[DIGEST_SIZE], quoteInfo[QUOTE_INFO_LENGTH], quoteSig[nonce_length-QUOTE_INFO_LENGTH];

	int i,j,k;
	int size;
	FILE *fp;

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

	printf("@quote_verify@ SIGMA nonce: ");
	for(i=0;i<gxgyLength;i++){
		printf("%c",gxgy[i]);
	}
	printf("\n");

	printf("@quote_verify@ Quote info||Quote Signature: %d\n", nonce_length);
	for(i=0;i<nonce_length;i++)
		printf("%02x",nonce_[i]);
	printf("\n");

	//Extract quote info
	for(i=0;i<QUOTE_INFO_LENGTH;i++){
		quoteInfo[i]=nonce_[i];
	}

	//Extract quote signature
	k=0;
	printf("@quote_verify@ QUOTESIG: %d\n", nonce_length-QUOTE_INFO_LENGTH);
	for(j=QUOTE_INFO_LENGTH;j<nonce_length;j++){
		quoteSig[k]=nonce_[j];
		printf("%x",quoteSig[k]);
		k++;
	}
	printf("\n");

	//Display quote info
	printf("@quote_verify@ TCPA_QUOTE_INFO\n");
	printf("@quote_verify@ version: ");
	for(i=0;i<4;i++)
		printf("%02x ",quoteInfo[i]);
	printf("\n");
	printf("@quote_verify@ fixed value: ");
	for(i=4;i<8;i++)
		printf("%c",quoteInfo[i]);
	printf("\n");
	printf("@quote_verify@ pcr digest: ");
	for(i=8;i<28;i++)
		printf("%02x ",quoteInfo[i]);
	printf("\n");
	printf("@quote_verify@ SIGMA nonce || Quote nonce: ");
	for(i=28;i<QUOTE_INFO_LENGTH;i++)
		printf("%c",quoteInfo[i]);
	printf("\n");

	//Read AIK to verify quote signature on quote info
	fp=fopen(fPath,"rb");
        prgbPubKey=malloc(fsize);
	size=fread(prgbPubKey,fsize,1,fp);
        fclose(fp);
        
	//Create Context
	result = Tspi_Context_Create(&hContext);
	if (result != TSS_SUCCESS) {
		printf("@quote_verify@ context create error\n");
		return -1;
	}

	//Connect Context
	result = Tspi_Context_Connect(hContext, NULL);
	if (result != TSS_SUCCESS) {
		printf("@quote_verify@ context connect error\n");
		goto cleanup;
	}

	//calculate hash of TCPA_QUOTE_INFO structure
	SHA1(quoteInfo, QUOTE_INFO_LENGTH, digest);
	printf("@quote_verify@ digest of tcpa_quote_info: ");
	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_verify@ create hash object error\n");
		goto cleanup;
	}

	//Set digest as the hash value on hHash
	result = Tspi_Hash_SetHashValue(hHash, 20, digest);
	if (result != TSS_SUCCESS) {
		printf("@quote_verify@ set hash value error\n");
		goto cleanup;
	}
 
        //Create Object 
        result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_TYPE_IDENTITY, &verifyKey);
        if (result != TSS_SUCCESS) { 
                printf("@quote_verify@ create identity key object error\n");
                goto cleanup;
        } 
         
        //load the public key into verifyKey
        result = Tspi_SetAttribData(verifyKey,TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, size,prgbPubKey);
        if (result != TSS_SUCCESS) { 
                printf("@quote_verify@ set AIK key attribute error\n"); 
                goto cleanup; 
        }
         
        //verify signature on certifcate 
        result = Tspi_Hash_VerifySignature(hHash, verifyKey, nonce_length-QUOTE_INFO_LENGTH, quoteSig);
        if (result != TSS_SUCCESS) { 
                printf("@quote_verify@ invalid Signature! :: %x\n", result);
                goto cleanup; 
        }
        else{
		printf("@quote_verify@ valid signature on quote info...\n");
		//verify if the returned nonce matches with the sent SIGMA nonce (gxgy)
		k=QUOTE_INFO_LENGTH-QUOTE_NONCE_LENGTH;
		for(i=0;i<gxgyLength;i++){
			if(quoteInfo[k]!=gxgy[i]){
				printf("@quote_verify@ gxgy nonce mismatch: %c",quoteInfo[i]);
				goto cleanup;
			}
			k++;
		}
		printf("@quote_verify@ valid gxgy nonce on signed quote info...\n");

		Tspi_Context_FreeMemory(hContext, NULL);
		Tspi_Context_CloseObject(hContext, verifyKey);
		Tspi_Context_Close(hContext);
		printf("*************Leaving quote_verify***************\n");
		return TSS_SUCCESS;
	}

cleanup:
	Tspi_Context_FreeMemory(hContext, NULL);
	Tspi_Context_CloseObject(hContext, verifyKey);
	Tspi_Context_Close(hContext);
	printf("*************Leaving quote_verify***************\n");
	return -1;
}
