/*
* 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
*
* Kent Yoder - updates for new authsession mechanism
* (C) International Business Machines Corp. 2007
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "trousers/tss.h"
#include "trousers/trousers.h"
#include "trousers_types.h"
#include "trousers_types.h"
#include "spi_utils.h"
#include "capabilities.h"
#include "tsplog.h"
#include "obj.h"
#include "authsess.h"
TSS_RESULT
Tspi_NV_DefineSpace(TSS_HNVSTORE hNvstore, /* in */
TSS_HPCRS hReadPcrComposite, /* in, may be NULL */
TSS_HPCRS hWritePcrComposite) /* in, may be NULL*/
{
TSS_HCONTEXT tspContext;
TSS_HTPM hTpm;
TSS_RESULT result;
UINT32 uiResultLen;
BYTE *pResult;
UINT32 i;
TPM_BOOL defined_index = FALSE;
NV_DATA_PUBLIC nv_data_public;
TSS_BOOL need_authdata = FALSE;
TCPA_DIGEST digest;
BYTE *pReadPCR;
UINT32 pReadPCR_len;
BYTE *pWritePCR;
UINT32 pWritePCR_len;
UINT64 NVPublic_DataSize;
BYTE NVPublicData[MAX_PUBLIC_DATA_SIZE];
Trspi_HashCtx hashCtx;
struct authsess *xsap = NULL;
if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
return result;
__tspi_memset(&nv_data_public, 0, sizeof(NV_DATA_PUBLIC));
if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex)))
return result;
if ((result = obj_nvstore_get_datasize(hNvstore, &nv_data_public.dataSize)))
return result;
if ((result = obj_nvstore_get_permission(hNvstore, &nv_data_public.permission.attributes)))
return result;
if ((result = obj_tpm_get(tspContext, &hTpm)))
return result;
if((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0,
NULL, &uiResultLen, &pResult)))
return result;
for (i = 0; i < uiResultLen/sizeof(UINT32); i++) {
if (nv_data_public.nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) {
defined_index = TRUE;
break;
}
}
free_tspi(tspContext, pResult);
if (defined_index) {
result = TSPERR(TSS_E_NV_AREA_EXIST);
return result;
}
need_authdata = (nv_data_public.permission.attributes
& (TPM_NV_PER_AUTHREAD |TPM_NV_PER_AUTHWRITE)) ? TRUE : FALSE;
nv_data_public.tag = TPM_TAG_NV_DATA_PUBLIC;
if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, hReadPcrComposite,
&pReadPCR_len, &pReadPCR)))
return result;
if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, hWritePcrComposite,
&pWritePCR_len, &pWritePCR))) {
free_tspi(tspContext, pReadPCR);
return result;
}
NVPublic_DataSize = 0;
Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_DATA_PUBLIC, NVPublicData);
Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.nvIndex, NVPublicData);
Trspi_LoadBlob(&NVPublic_DataSize, pReadPCR_len, NVPublicData, pReadPCR);
Trspi_LoadBlob(&NVPublic_DataSize, pWritePCR_len, NVPublicData, pWritePCR);
Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_ATTRIBUTES, NVPublicData);
Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.permission.attributes, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bReadSTClear, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteSTClear, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteDefine, NVPublicData);
Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.dataSize, NVPublicData);
free_tspi(tspContext, pReadPCR);
free_tspi(tspContext, pWritePCR);
if ((result = authsess_xsap_init(tspContext, hTpm, hNvstore, need_authdata,
TPM_ORD_NV_DefineSpace, TPM_ET_OWNER, &xsap))) {
if (result == TSPERR(TSS_E_TSP_AUTHREQUIRED))
result = TSS_ERROR_CODE(TSS_E_BAD_PARAMETER);
return result;
}
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace);
result |= Trspi_HashUpdate(&hashCtx, NVPublic_DataSize, NVPublicData);
result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto error;
if ((result = authsess_xsap_hmac(xsap, &digest)))
goto error;
if ((result = TCS_API(tspContext)->NV_DefineOrReleaseSpace(tspContext, NVPublic_DataSize,
NVPublicData, xsap->encAuthUse,
xsap->pAuth)))
goto error;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto error;
result = authsess_xsap_verify(xsap, &digest);
error:
authsess_free(xsap);
return result;
}
TSS_RESULT
Tspi_NV_ReleaseSpace(TSS_HNVSTORE hNvstore) /* in */
{
TSS_HCONTEXT tspContext;
TSS_HTPM hTpm;
TSS_RESULT result;
UINT32 uiResultLen;
BYTE *pResult;
UINT32 i;
TPM_BOOL defined_index = FALSE;
NV_DATA_PUBLIC nv_data_public;
TCPA_DIGEST digest;
BYTE *pPCR;
UINT32 pPCR_len;
UINT64 NVPublic_DataSize;
BYTE NVPublicData[MAX_PUBLIC_DATA_SIZE];
Trspi_HashCtx hashCtx;
struct authsess *xsap = NULL;
__tspi_memset(&nv_data_public, 0, sizeof(NV_DATA_PUBLIC));
if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
return result;
if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex)))
return result;
if ((result = obj_nvstore_get_datasize(hNvstore, &nv_data_public.dataSize)))
return result;
if ((result = obj_nvstore_get_permission(hNvstore, &nv_data_public.permission.attributes)))
return result;
if ((result = obj_tpm_get(tspContext, &hTpm)))
return result;
if((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0,
NULL, &uiResultLen, &pResult)))
return result;
for (i = 0; i < uiResultLen/sizeof(UINT32); i++) {
if (nv_data_public.nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) {
defined_index = TRUE;
break;
}
}
free_tspi(tspContext, pResult);
if (!defined_index) {
result = TSPERR(TSS_E_NV_AREA_NOT_EXIST);
return result;
}
nv_data_public.tag = TPM_TAG_NV_DATA_PUBLIC;
if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, NULL_HPCRS, &pPCR_len, &pPCR)))
return result;
NVPublic_DataSize = 0;
Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_DATA_PUBLIC, NVPublicData);
Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.nvIndex, NVPublicData);
/* load the read pcr short info */
Trspi_LoadBlob(&NVPublic_DataSize, pPCR_len, NVPublicData, pPCR);
/* load the write pcr short info */
Trspi_LoadBlob(&NVPublic_DataSize, pPCR_len, NVPublicData, pPCR);
Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_ATTRIBUTES, NVPublicData);
Trspi_LoadBlob_UINT32(&NVPublic_DataSize,
nv_data_public.permission.attributes, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bReadSTClear, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteSTClear, NVPublicData);
Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteDefine, NVPublicData);
/*Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.dataSize, NVPublicData);*/
Trspi_LoadBlob_UINT32(&NVPublic_DataSize, 0, NVPublicData);
free_tspi(tspContext, pPCR);
if ((result = authsess_xsap_init(tspContext, hTpm, hNvstore, TSS_AUTH_POLICY_NOT_REQUIRED,
TPM_ORD_NV_DefineSpace, TPM_ET_OWNER, &xsap)))
return result;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace);
result |= Trspi_HashUpdate(&hashCtx, NVPublic_DataSize, NVPublicData);
result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto error;
if ((result = authsess_xsap_hmac(xsap, &digest)))
goto error;
if ((result = TCS_API(tspContext)->NV_DefineOrReleaseSpace(tspContext, NVPublic_DataSize,
NVPublicData, xsap->encAuthUse,
xsap->pAuth)))
goto error;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto error;
result = authsess_xsap_verify(xsap, &digest);
error:
authsess_free(xsap);
return result;
}
TSS_RESULT
Tspi_NV_WriteValue(TSS_HNVSTORE hNvstore, /* in */
UINT32 offset, /* in */
UINT32 ulDataLength, /* in */
BYTE* rgbDataToWrite) /* in */
{
TSS_HCONTEXT tspContext;
TSS_HTPM hTpm;
TSS_RESULT result;
NV_DATA_PUBLIC nv_data_public;
UINT32 need_authdata = 0;
UINT32 authwrite =0;
TSS_HPOLICY hPolicy;
TPM_AUTH auth;
TCPA_DIGEST digest;
Trspi_HashCtx hashCtx;
if ((ulDataLength != 0) && (rgbDataToWrite == NULL))
return TSPERR(TSS_E_BAD_PARAMETER);
if((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
return result;
if ((result = obj_tpm_get(tspContext, &hTpm)))
return result;
if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex)))
return result;
if ((result = obj_nvstore_get_policy(hNvstore, TSS_POLICY_USAGE, &hPolicy)))
return result;
if (hPolicy) {
if ((result = obj_nvstore_get_permission_from_tpm(hNvstore,
&nv_data_public.permission.attributes)))
return result;
need_authdata = nv_data_public.permission.attributes
& (TPM_NV_PER_AUTHWRITE | TPM_NV_PER_OWNERWRITE);
authwrite = nv_data_public.permission.attributes & TPM_NV_PER_AUTHWRITE;
if (need_authdata) {
if (!authwrite) {
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValue);
result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex);
result |= Trspi_Hash_UINT32(&hashCtx, offset);
result |= Trspi_Hash_UINT32(&hashCtx, ulDataLength);
result |= Trspi_HashUpdate(&hashCtx, ulDataLength, rgbDataToWrite);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = secret_PerformAuth_OIAP(hNvstore,
TPM_ORD_NV_WriteValue,
hPolicy, FALSE, &digest,
&auth)))
return result;
if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength,
rgbDataToWrite, &auth)))
return result;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, result);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValue);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = obj_policy_validate_auth_oiap(hPolicy,
&digest, &auth)))
return result;
} else {
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValueAuth);
result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex);
result |= Trspi_Hash_UINT32(&hashCtx, offset);
result |= Trspi_Hash_UINT32(&hashCtx, ulDataLength);
result |= Trspi_HashUpdate(&hashCtx, ulDataLength, rgbDataToWrite);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = secret_PerformAuth_OIAP(hNvstore,
TPM_ORD_NV_WriteValueAuth,
hPolicy, FALSE, &digest,
&auth)))
return result;
if ((result = TCS_API(tspContext)->NV_WriteValueAuth(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength,
rgbDataToWrite, &auth)))
return result;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, result);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValueAuth);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = obj_policy_validate_auth_oiap(hPolicy,
&digest, &auth)))
return result;
}
} else {
if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength,
rgbDataToWrite, NULL)))
return result;
}
} else {
LogDebug("no policy, so noauthentication");
if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext, nv_data_public.nvIndex,
offset, ulDataLength,
rgbDataToWrite, NULL)))
return result;
}
return result;
}
TSS_RESULT
Tspi_NV_ReadValue(TSS_HNVSTORE hNvstore, /* in */
UINT32 offset, /* in */
UINT32* ulDataLength, /* in, out */
BYTE** rgbDataRead) /* out */
{
TSS_HCONTEXT tspContext;
TSS_HTPM hTpm;
TSS_RESULT result;
NV_DATA_PUBLIC nv_data_public;
UINT32 need_authdata = 0;
UINT32 authread =0;
TSS_HPOLICY hPolicy;
TPM_AUTH auth;
TCPA_DIGEST digest;
Trspi_HashCtx hashCtx;
if (ulDataLength == NULL || rgbDataRead == NULL)
return TSPERR(TSS_E_BAD_PARAMETER);
if((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext)))
return result;
if ((result = obj_tpm_get(tspContext, &hTpm)))
return result;
if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex)))
return result;
if ((result = obj_nvstore_get_policy(hNvstore, TSS_POLICY_USAGE, &hPolicy)))
return result;
if (hPolicy) {/*if the policy secret is set*/
if ((result = obj_nvstore_get_permission_from_tpm(hNvstore,
&nv_data_public.permission.attributes)))
return result;
need_authdata = nv_data_public.permission.attributes
& (TPM_NV_PER_AUTHREAD | TPM_NV_PER_OWNERREAD);
authread = nv_data_public.permission.attributes & TPM_NV_PER_AUTHREAD;
if (need_authdata) {
if (!authread) {
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValue);
result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex);
result |= Trspi_Hash_UINT32(&hashCtx, offset);
result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = secret_PerformAuth_OIAP(hNvstore,
TPM_ORD_NV_ReadValue,
hPolicy, FALSE, &digest,
&auth)))
return result;
if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength,
&auth, rgbDataRead)))
return result;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValue);
result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength);
result |= Trspi_HashUpdate(&hashCtx, *ulDataLength, *rgbDataRead);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = obj_policy_validate_auth_oiap(hPolicy,
&digest, &auth)))
return result;
} else {
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValueAuth);
result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex);
result |= Trspi_Hash_UINT32(&hashCtx, offset);
result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = secret_PerformAuth_OIAP(hNvstore,
TPM_ORD_NV_ReadValueAuth,
hPolicy, FALSE, &digest,
&auth)))
return result;
if ((result = TCS_API(tspContext)->NV_ReadValueAuth(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength,
&auth, rgbDataRead)))
return result;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValueAuth);
result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength);
result |= Trspi_HashUpdate(&hashCtx, *ulDataLength, *rgbDataRead);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = obj_policy_validate_auth_oiap(hPolicy,
&digest, &auth)))
return result;
}
} else {
if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext,
nv_data_public.nvIndex,
offset, ulDataLength, NULL,
rgbDataRead)))
return result;
}
} else {
if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext, nv_data_public.nvIndex,
offset, ulDataLength, NULL,
rgbDataRead)))
return result;
}
return result;
}