// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 3: Commands
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "NV_DefineSpace_fp.h"
//
//
// Error Returns Meaning
//
// TPM_RC_NV_ATTRIBUTES attributes of the index are not consistent
// TPM_RC_NV_DEFINED index already exists
// TPM_RC_HIERARCHY for authorizations using TPM_RH_PLATFORM phEnable_NV is
// clear.
// TPM_RC_NV_SPACE Insufficient space for the index
// TPM_RC_SIZE 'auth->size' or 'publicInfo->authPolicy.size' is larger than the digest
// size of 'publicInfo->nameAlg', or 'publicInfo->dataSize' is not
// consistent with 'publicInfo->attributes'.
//
TPM_RC
TPM2_NV_DefineSpace(
NV_DefineSpace_In *in // IN: input parameter list
)
{
TPM_RC result;
TPMA_NV attributes;
UINT16 nameSize;
nameSize = CryptGetHashDigestSize(in->publicInfo.t.nvPublic.nameAlg);
// Check if NV is available. NvIsAvailable may return TPM_RC_NV_UNAVAILABLE
// TPM_RC_NV_RATE or TPM_RC_SUCCESS.
result = NvIsAvailable();
if(result != TPM_RC_SUCCESS)
return result;
// Input Validation
// If an index is being created by the owner and shEnable is
// clear, then we would not reach this point because ownerAuth
// can't be given when shEnable is CLEAR. However, if phEnable
// is SET but phEnableNV is CLEAR, we have to check here
if(in->authHandle == TPM_RH_PLATFORM && gc.phEnableNV == CLEAR)
return TPM_RC_HIERARCHY + RC_NV_DefineSpace_authHandle;
attributes = in->publicInfo.t.nvPublic.attributes;
//TPMS_NV_PUBLIC validation.
// Counters and bit fields must have a size of 8
if ( (attributes.TPMA_NV_COUNTER == SET || attributes.TPMA_NV_BITS == SET)
&& (in->publicInfo.t.nvPublic.dataSize != 8))
return TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo;
// check that the authPolicy consistent with hash algorithm
if( in->publicInfo.t.nvPublic.authPolicy.t.size != 0
&& in->publicInfo.t.nvPublic.authPolicy.t.size != nameSize)
return TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo;
// make sure that the authValue is not too large
MemoryRemoveTrailingZeros(&in->auth);
if(in->auth.t.size > nameSize)
return TPM_RC_SIZE + RC_NV_DefineSpace_auth;
//TPMA_NV validation.
// Locks may not be SET and written cannot be SET
if( attributes.TPMA_NV_WRITTEN == SET
|| attributes.TPMA_NV_WRITELOCKED == SET
|| attributes.TPMA_NV_READLOCKED == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// There must be a way to read the index
if( attributes.TPMA_NV_OWNERREAD == CLEAR
&& attributes.TPMA_NV_PPREAD == CLEAR
&& attributes.TPMA_NV_AUTHREAD == CLEAR
&& attributes.TPMA_NV_POLICYREAD == CLEAR)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// There must be a way to write the index
if( attributes.TPMA_NV_OWNERWRITE == CLEAR
&& attributes.TPMA_NV_PPWRITE == CLEAR
&& attributes.TPMA_NV_AUTHWRITE == CLEAR
&& attributes.TPMA_NV_POLICYWRITE == CLEAR)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// Make sure that no attribute is used that is not supported by the proper
// command
#if CC_NV_Increment == NO
if( attributes.TPMA_NV_COUNTER == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
#endif
#if CC_NV_SetBits == NO
if( attributes.TPMA_NV_BITS == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
#endif
#if CC_NV_Extend == NO
if( attributes.TPMA_NV_EXTEND == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
#endif
#if CC_NV_UndefineSpaceSpecial == NO
if( attributes.TPMA_NV_POLICY_DELETE == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
#endif
// Can be COUNTER or BITS or EXTEND but not more than one
if( attributes.TPMA_NV_COUNTER == SET
&& attributes.TPMA_NV_BITS == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
if( attributes.TPMA_NV_COUNTER == SET
&& attributes.TPMA_NV_EXTEND == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
if( attributes.TPMA_NV_BITS == SET
&& attributes.TPMA_NV_EXTEND == SET)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// An index with TPMA_NV_CLEAR_STCLEAR can't be a counter and can't have
// TPMA_NV_WRITEDEFINE SET
if( attributes.TPMA_NV_CLEAR_STCLEAR == SET
&& ( attributes.TPMA_NV_COUNTER == SET
|| attributes.TPMA_NV_WRITEDEFINE == SET)
)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// Make sure that the creator of the index can delete the index
if( ( in->publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE == SET
&& in->authHandle == TPM_RH_OWNER
)
|| ( in->publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE == CLEAR
&& in->authHandle == TPM_RH_PLATFORM
)
)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_authHandle;
// If TPMA_NV_POLICY_DELETE is SET, then the index must be defined by
// the platform
if( in->publicInfo.t.nvPublic.attributes.TPMA_NV_POLICY_DELETE == SET
&& TPM_RH_PLATFORM != in->authHandle
)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// If the NV index is used as a PCR, the data size must match the digest
// size
if( in->publicInfo.t.nvPublic.attributes.TPMA_NV_EXTEND == SET
&& in->publicInfo.t.nvPublic.dataSize != nameSize
)
return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
// See if the index is already defined.
if(NvIsUndefinedIndex(in->publicInfo.t.nvPublic.nvIndex))
return TPM_RC_NV_DEFINED;
// Internal Data Update
// define the space. A TPM_RC_NV_SPACE error may be returned at this point
result = NvDefineIndex(&in->publicInfo.t.nvPublic, &in->auth);
if(result != TPM_RC_SUCCESS)
return result;
return TPM_RC_SUCCESS;
}