| // 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; |
| |
| } |