/*
 * <insert one-line description of what the program does>
 * Copyright (c) <2008-2009>, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
	
	File Name:   	TPMInterface.c
	  
	Description:
	  
    OS: Metasys
    SE: SUSE 10.2
		  
	Notes (opt):				
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "TPMCtrl/TPMInterface.h"

int TPM_CreateSpaceForTPM(char *ownerpwd)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_HTPM	 tpmObj;
	TSS_HPOLICY  ownerPolicyObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

    UINT32	ownerpwdlen = strlen(ownerpwd);
    BYTE	*ownerpwdUni;	
	UINT32  i, nIndex;

	ownerpwdUni = malloc(ownerpwdlen * 2);
	memset(ownerpwdUni, 0, ownerpwdlen * 2);
    for(i = 0; i < ownerpwdlen; i ++)
        ownerpwdUni[i * 2] = ownerpwd[i];
    
	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// The context object aggregates only instance of the TPM object
	// we will need the TPM object later to set TPM Owner secret
	tResult = Tspi_Context_GetTpmObject(
		context, 
		&tpmObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Read public portion of Endorsement key on TPM 1.2 this requires Owner authorization
	tResult = Tspi_GetPolicyObject(
		tpmObj, 
		TSS_POLICY_USAGE, 
		&ownerPolicyObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Therefore set TPM Owner secret if this is TPM 1.2
	tResult = Tspi_Policy_SetSecret(
		ownerPolicyObj, 
		TSS_SECRET_MODE_PLAIN, 
		ownerpwdlen * 2, 
		(BYTE *)ownerpwdUni);
 	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	//Create NV Storage space for user data
	nIndex = TDAGENT_USERDATA_INDEX;
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		nIndex, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_DATASIZE, 
		0, 
		TDAGENT_USERDATA_LENGTH);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_PERMISSIONS, 
		0, 
		0x80004000);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_NV_DefineSpace(nvStorageObj, 0, 0);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	//Create NV Storage space for shared secret
	nIndex = TDAGENT_SHAREDSECRET_INDEX;
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		nIndex, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_DATASIZE, 
		0, 
		TDAGENT_SHAREDSECRET_LENGTH);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_PERMISSIONS, 
		0, 
		0x80004000);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_NV_DefineSpace(nvStorageObj, 0, 0);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	//Create NV Storage space for provision packet
	nIndex = TDAGENT_PACKET_INDEX;
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		nIndex, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_DATASIZE, 
		0, 
		TDAGENT_PACKET_LENGTH);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_SetAttribUint32(
		nvStorageObj, 
		TSS_TSPATTRIB_NV_PERMISSIONS, 
		0, 
		0x80004000);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	tResult = Tspi_NV_DefineSpace(nvStorageObj, 0, 0);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	Tspi_Context_Close(context);

	return SUCCESS;
}

int TPM_SaveUserDataToTPM(BYTE *UserData)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(UserData == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_USERDATA_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < TDAGENT_USERDATA_LENGTH)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start writing user data area to NVM
	tResult = Tspi_NV_WriteValue(
		nvStorageObj,
		0,
		TDAGENT_USERDATA_LENGTH,
		UserData);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}

int TPM_ReadUserDataFromTPM(BYTE* UserData)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	BYTE	*pbUserData = NULL;	// pointer to location to hold EK data read from NVM
	UINT32	dwUserDataLen = 0;	// length of the data to read from NVM storage
	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(UserData == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_USERDATA_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < TDAGENT_USERDATA_LENGTH)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start reading user data area from NVM
	dwUserDataLen = TDAGENT_USERDATA_LENGTH;
	tResult = Tspi_NV_ReadValue(
		nvStorageObj,
		0, 
		&dwUserDataLen, 
		&pbUserData);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	memcpy(UserData,pbUserData,TDAGENT_USERDATA_LENGTH);

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}

int TPM_SaveProvisionPacketToTPM(BYTE *Packet,int PacketSize)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(Packet == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_PACKET_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < (UINT32)PacketSize)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start writing provision packet area to NVM
	tResult = Tspi_NV_WriteValue(
		nvStorageObj,
		0,
		PacketSize,
		Packet);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}

int TPM_ReadProvisionPacketFromTPM(BYTE *Packet)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	BYTE	*pbPacketData = NULL;	// pointer to location to provision packet read from NVM
	UINT32	dwPacketDataLen = 0;	// length of the data to read from NVM storage
	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(Packet == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_PACKET_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < TDAGENT_PACKET_LENGTH)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start reading provision packet area from NVM
	dwPacketDataLen = TDAGENT_PACKET_LENGTH;
	tResult = Tspi_NV_ReadValue(
		nvStorageObj,
		0, 
		&dwPacketDataLen, 
		&pbPacketData);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	memcpy(Packet, pbPacketData, TDAGENT_PACKET_LENGTH);

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}

int TPM_SaveSharedSecretToTPM(BYTE *Secret)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(Secret == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	// Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_SHAREDSECRET_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen
		);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < TDAGENT_SHAREDSECRET_LENGTH)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start writing EK area to NVM
	tResult = Tspi_NV_WriteValue(
		nvStorageObj,
		0,
		TDAGENT_SHAREDSECRET_LENGTH,
		Secret);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}


int TPM_ReadSharedSecretFromTPM(BYTE *Secret)
{
	TSS_HCONTEXT context;
	TSS_HNVSTORE nvStorageObj;
	TSS_RESULT	 tResult = TSS_SUCCESS;

	BYTE	*pbSharedSecret = NULL;	// pointer to location to hold shared secret read from NVM
	UINT32	dwSharedSecretLen = 0;	// length of the data to read from NVM storage
	WCHAR	errMsg[MAX_PATH]; // string to hold errmsg.
	UINT32	unDataLen = 0; // length of NVM area present for an Index
	int     i = 0;

	// Check if input parameter is availabe
	if(Secret == NULL)
	{
		return TPMCtrl_ExceptionStatus_ParamError;
	}

	memcpy(errMsg, "", MAX_PATH);

	// Create the context object, the TSP's root object
	Tspi_Context_Create(&context);

	//Connect to the TPM: local system
	Tspi_Context_Connect(context, NULL);

	// Create the NVM storage object
	tResult = Tspi_Context_CreateObject(
		context,
		TSS_OBJECT_TYPE_NV, 
		0, 
		&nvStorageObj);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Select the corresponding index number for NVM storage
	tResult = Tspi_SetAttribUint32(
            nvStorageObj, 
			TSS_TSPATTRIB_NV_INDEX, 
			0, 
			TDAGENT_SHAREDSECRET_INDEX);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	// Get the length of data available at this area.
	tResult = Tspi_GetAttribUint32(
		nvStorageObj,
		TSS_TSPATTRIB_NV_DATASIZE,
		0,
		&unDataLen);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}
	if(unDataLen < TDAGENT_SHAREDSECRET_LENGTH)
	{
		return TPMCtrl_ExceptionStatus_GetAttribUnitFailed;
	}

	// Start reading EK area from NVM
	dwSharedSecretLen = TDAGENT_SHAREDSECRET_LENGTH;
	tResult = Tspi_NV_ReadValue( 
		nvStorageObj,
		0, 
		&dwSharedSecretLen, 
		&pbSharedSecret);
	if(tResult != TSS_SUCCESS) 
	{
		return tResult;
	}

	memcpy(Secret, pbSharedSecret, TDAGENT_SHAREDSECRET_LENGTH);

	// Disconnect to the TPM: local system 
	Tspi_Context_Close(context);

	return SUCCESS;
}



