/*
 * The Initial Developer of the Original Code is Intel Corporation.
 * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation.
 * All Rights Reserved.
 *
 * trousers - An open source TCG Software Stack
 *
 * Author: james.xu@intel.com Rossey.liu@intel.com
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include "trousers/tss.h"
#include "trousers/trousers.h"
#include "trousers_types.h"
#include "spi_utils.h"
#include "capabilities.h"
#include "tsplog.h"
#include "obj.h"

TSS_RESULT
obj_nvstore_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject)
{
	TSS_RESULT result;
	struct tr_nvstore_obj *nvstore = calloc(1, sizeof(struct tr_nvstore_obj));

	if (nvstore == NULL) {
		LogError("malloc of %zd bytes failed.",
				sizeof(struct tr_nvstore_obj));
		return TSPERR(TSS_E_OUTOFMEMORY);
	}

	if ((result = obj_list_add(&nvstore_list, tspContext, 0, nvstore, phObject))) {
		free(nvstore);
		return result;
	}

	return TSS_SUCCESS;
}

TSS_BOOL
obj_is_nvstore(TSS_HOBJECT hObject)
{
	TSS_BOOL answer = FALSE;

	if ((obj_list_get_obj(&nvstore_list, hObject))) {
		answer = TRUE;
		obj_list_put(&nvstore_list);
	}

	return answer;
}

void
nvstore_free(void *data)
{
	struct tr_nvstore_obj *nvstore = (struct tr_nvstore_obj *)data;

	free(nvstore);
}

TSS_RESULT
obj_nvstore_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext)
{
	TSS_RESULT result;

	if ((result = obj_list_remove(&nvstore_list, &nvstore_free, hObject, tspContext)))
		return result;

	return TSS_SUCCESS;
}

TSS_RESULT
obj_nvstore_get_tsp_context(TSS_HNVSTORE hNvstore, TSS_HCONTEXT * tspContext)
{
	struct tsp_object *obj;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	*tspContext = obj->tspContext;

	obj_list_put(&nvstore_list);

	return TSS_SUCCESS;
}

TSS_RESULT
obj_nvstore_set_index(TSS_HNVSTORE hNvstore, UINT32 index)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	nvstore->nvIndex = index;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_get_index(TSS_HNVSTORE hNvstore, UINT32 * index)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	*index = nvstore->nvIndex;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_set_datasize(TSS_HNVSTORE hNvstore, UINT32 datasize)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	nvstore->dataSize= datasize;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_get_datasize(TSS_HNVSTORE hNvstore, UINT32 * datasize)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	*datasize = nvstore->dataSize;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_set_permission(TSS_HNVSTORE hNvstore, UINT32 permission)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	nvstore->permission.attributes= permission;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_get_permission_from_tpm(TSS_HNVSTORE hNvstore, UINT32 * permission)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE] = {0};
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TPM_NV_ATTRIBUTES nv_attributes_value;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result;

	if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
		return result;

	offset = 0;
	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);

	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);
	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);

	offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);

	nv_attributes_value.attributes = Decode_UINT32(nv_data_public
						       + offset + sizeof(TPM_STRUCTURE_TAG));
	*permission = nv_attributes_value.attributes;

	return result;
}

TSS_RESULT
obj_nvstore_get_permission(TSS_HNVSTORE hNvstore, UINT32 * permission)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	*permission = nvstore->permission.attributes;

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_set_policy(TSS_HNVSTORE hNvstore, TSS_HPOLICY hPolicy)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	UINT32 policyType;
	TSS_RESULT result = TSS_SUCCESS;

	if ((result = obj_policy_get_type(hPolicy, &policyType)))
		return result;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	switch (policyType) {
		case TSS_POLICY_USAGE:
			nvstore->policy = hPolicy;
			break;
		default:
			result = TSPERR(TSS_E_BAD_PARAMETER);
	}

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_get_policy(TSS_HNVSTORE hNvstore, UINT32 policyType, TSS_HPOLICY *phPolicy)
{
	struct tsp_object *obj;
	struct tr_nvstore_obj *nvstore;
	TSS_RESULT result=TSS_SUCCESS;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	nvstore = (struct tr_nvstore_obj *)obj->data;

	switch (policyType) {
		case TSS_POLICY_USAGE:
			*phPolicy = nvstore->policy;
			break;
		default:
			result = TSPERR(TSS_E_BAD_PARAMETER);
	}

	obj_list_put(&nvstore_list);

	return result;
}

TSS_RESULT
obj_nvstore_get_datapublic(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE *nv_data_public)
{
	struct tsp_object *obj;
	TSS_HCONTEXT  hContext;
	TSS_HTPM hTpm;
	TSS_RESULT result;
	struct tr_nvstore_obj *nvstore;
	UINT32 uiResultLen;
	BYTE *pResult;
	UINT32 i;
	TPM_BOOL defined_index = FALSE;

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	hContext = obj->tspContext;
	nvstore = (struct tr_nvstore_obj *)obj->data;

	if ((result = obj_tpm_get(hContext, &hTpm)))
		goto out;

	if ((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0,
				 NULL, &uiResultLen, &pResult))) {
		goto out;
	}

	for (i = 0; i < uiResultLen/sizeof(UINT32); i++) {
		if (nvstore->nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) {
			defined_index = TRUE;
			break;
		}
	}

	free_tspi(hContext, pResult);

	if (!defined_index) {
		result = TSPERR(TPM_E_BADINDEX);
		goto out;
	}

	if ((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_INDEX,
					     sizeof(UINT32), (BYTE *)(&(nvstore->nvIndex)),
					     &uiResultLen, &pResult))) {
		LogDebug("get the index capability error");
		goto out;
	}

	if (uiResultLen > *size) {
		free_tspi(hContext, pResult);
		result = TSPERR(TSS_E_INTERNAL_ERROR);
		goto out;
	}
	*size = uiResultLen;
	memcpy(nv_data_public, pResult, uiResultLen);
	free_tspi(hContext, pResult);

out:
	obj_list_put(&nvstore_list);
	return result;
}

TSS_RESULT
obj_nvstore_get_readdigestatrelease(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result;

	if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
		return result;

	*size = sizeof(TPM_COMPOSITE_HASH);
	*data = calloc_tspi(tspContext, *size);
	if (*data == NULL) {
		LogError("malloc of %u bytes failed.", *size);
		result = TSPERR(TSS_E_OUTOFMEMORY);
		return result;
	}

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION);
	memcpy(*data, nv_data_public + offset, sizeof(TPM_COMPOSITE_HASH));

	return result;
}

TSS_RESULT
obj_nvstore_get_readpcrselection(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result;

	if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);

	*size = sizeof(UINT16) + pcrread_sizeOfSelect;
	*data = calloc_tspi(tspContext, *size);
	if (*data == NULL) {
		LogError("malloc of %u bytes failed.", *size);
		result = TSPERR(TSS_E_OUTOFMEMORY);
		return result;
	}

	memcpy(*data, nv_data_public + offset, *size);

	return result;
}

TSS_RESULT
obj_nvstore_get_writedigestatrelease(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
		return result;

	*size = sizeof(TPM_COMPOSITE_HASH);
	*data = calloc_tspi(tspContext, *size);
	if (*data == NULL) {
		LogError("malloc of %u bytes failed.", *size);
		result = TSPERR(TSS_E_OUTOFMEMORY);
		return result;
	}

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);

	Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION);
	memcpy(*data, nv_data_public + offset, sizeof(TPM_COMPOSITE_HASH));

	return result;
}

TSS_RESULT
obj_nvstore_get_writepcrselection(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result;

	if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);
	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);

	*size = sizeof(UINT16) + pcrwrite_sizeOfSelect;
	*data = calloc_tspi(tspContext, *size);
	if (*data == NULL) {
		LogError("malloc of %u bytes failed.", *size);
		result = TSPERR(TSS_E_OUTOFMEMORY);
		return result;
	}

	memcpy(*data, nv_data_public + offset, *size);
	return result;
}

TSS_RESULT
obj_nvstore_get_state_readstclear(TSS_HNVSTORE hNvstore, UINT32 * readstclear)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TPM_BOOL value;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);

	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH)
			+ sizeof(TPM_NV_ATTRIBUTES);

	value = *((TPM_BOOL *)(nv_data_public + offset));

	*readstclear = value;

	return result;
}

TSS_RESULT
obj_nvstore_get_state_writedefine(TSS_HNVSTORE hNvstore, UINT32 * writedefine)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TPM_BOOL value;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);

	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH)
			+ sizeof(TPM_NV_ATTRIBUTES)
			+ sizeof(TPM_BOOL)
			+ sizeof(TPM_BOOL);

	value = *((TPM_BOOL *)(nv_data_public + offset));

	*writedefine = value;

	return result;
}

TSS_RESULT
obj_nvstore_get_state_writestclear(TSS_HNVSTORE hNvstore, UINT32 * writestclear)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TPM_BOOL value;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);

	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH)
			+ sizeof(TPM_NV_ATTRIBUTES)
			+ sizeof(TPM_BOOL);

	value = *((TPM_BOOL *)(nv_data_public + offset));
	*writestclear = value;

	return result;
}

TSS_RESULT
obj_nvstore_get_readlocalityatrelease(TSS_HNVSTORE hNvstore, UINT32 * readlocalityatrelease)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	TPM_LOCALITY_SELECTION locality_value;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect;
	locality_value = *((TPM_LOCALITY_SELECTION *)(nv_data_public + offset));
	*readlocalityatrelease = locality_value;

	return result;
}

TSS_RESULT
obj_nvstore_get_writelocalityatrelease(TSS_HNVSTORE hNvstore, UINT32 * writelocalityatrelease)
{
	BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE];
	UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE;
	UINT32 offset;
	UINT16 pcrread_sizeOfSelect;
	UINT16 pcrwrite_sizeOfSelect;
	TPM_LOCALITY_SELECTION locality_value;
	TSS_RESULT result;

	if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public)))
		return result;

	offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX);
	pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect
			+ sizeof(TPM_LOCALITY_SELECTION)
			+ sizeof(TPM_COMPOSITE_HASH);
	pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset);
	offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect;

	locality_value = *((TPM_LOCALITY_SELECTION *)(nv_data_public + offset));
	*writelocalityatrelease = locality_value;

	return result;
}

TSS_RESULT
obj_nvstore_create_pcrshortinfo(TSS_HNVSTORE hNvstore,
				TSS_HPCRS hPcrComposite,
				UINT32 *size,
				BYTE **data)
{
	struct tsp_object *obj;
	BYTE pdata[MAX_PUBLIC_DATA_SIZE];
	UINT32 dataLen;
	UINT64 offset;
	TSS_HCONTEXT tspContext;
	TSS_RESULT result = TSS_SUCCESS;
	BYTE*  ppbHashData;
	UINT32 i;
	BYTE  digAtRelease[TPM_SHA1_160_HASH_LEN] = { 0, };
	UINT32 tmp_locAtRelease;
	TPM_LOCALITY_SELECTION locAtRelease = TPM_LOC_ZERO | TPM_LOC_ONE
					| TPM_LOC_TWO | TPM_LOC_THREE| TPM_LOC_FOUR;
	BYTE tmp_pcr_select[3] = {0, 0, 0};
	TCPA_PCR_SELECTION pcrSelect = { 3, tmp_pcr_select};

	if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL)
		return TSPERR(TSS_E_INVALID_HANDLE);

	tspContext = obj->tspContext;

	if (hPcrComposite) {
		if ((result = obj_pcrs_get_selection(hPcrComposite, &dataLen, pdata))) {
			LogDebug("get_selection error from hReadPcrComposite");
			goto out;
		}

		/* the index should not >= 24, so the sizeofselect should not be >3*/
		if (dataLen - sizeof(UINT16) > 3) {
			result = TSPERR(TSS_E_BAD_PARAMETER);
			goto out;
		}
		offset = 0;
		Trspi_UnloadBlob_PCR_SELECTION(&offset, pdata, &pcrSelect);

		if (pcrSelect.sizeOfSelect != 0) {
			if ((result = obj_pcrs_get_digest_at_release(hPcrComposite,
								     &dataLen, &ppbHashData))) {
				LogDebug("get_composite error from hReadPcrComposite");
				goto out;
			}
			memcpy(digAtRelease, ppbHashData, dataLen);
			free_tspi(tspContext, ppbHashData);
		} else {
			pcrSelect.sizeOfSelect = 3;
			pcrSelect.pcrSelect = tmp_pcr_select;
		}

		if (pcrSelect.sizeOfSelect < 3) {
			for (i = 0; i < pcrSelect.sizeOfSelect; i++) {
				tmp_pcr_select[i] = pcrSelect.pcrSelect[i];
			}
			pcrSelect.sizeOfSelect = 3;
			pcrSelect.pcrSelect = tmp_pcr_select;
		}

		if ((result = obj_pcrs_get_locality(hPcrComposite, &tmp_locAtRelease)))
			goto out;
		locAtRelease = (TPM_LOCALITY_SELECTION)(tmp_locAtRelease & TSS_LOCALITY_MASK);
	}

	*size = sizeof(UINT16) + 3 + sizeof(TPM_LOCALITY_SELECTION) + TPM_SHA1_160_HASH_LEN;
	*data = calloc_tspi(tspContext, *size);
	if (*data == NULL) {
		LogError("malloc of %u bytes failed.", *size);
		result = TSPERR(TSS_E_OUTOFMEMORY);
		goto out;
	}

	offset = 0;
	Trspi_LoadBlob_PCR_SELECTION(&offset, *data, &pcrSelect);
	Trspi_LoadBlob_BYTE(&offset, locAtRelease, *data);
	Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, *data, digAtRelease);

out:
	obj_list_put(&nvstore_list);
	return result;
}


