/********************************************************************************/ /* */ /* Non-Volatile Storage */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* */ /* Licenses and Notices */ /* */ /* 1. Copyright Licenses: */ /* */ /* - Trusted Computing Group (TCG) grants to the user of the source code in */ /* this specification (the "Source Code") a worldwide, irrevocable, */ /* nonexclusive, royalty free, copyright license to reproduce, create */ /* derivative works, distribute, display and perform the Source Code and */ /* derivative works thereof, and to grant others the rights granted herein. */ /* */ /* - The TCG grants to the user of the other parts of the specification */ /* (other than the Source Code) the rights to reproduce, distribute, */ /* display, and perform the specification solely for the purpose of */ /* developing products based on such documents. */ /* */ /* 2. Source Code Distribution Conditions: */ /* */ /* - Redistributions of Source Code must retain the above copyright licenses, */ /* this list of conditions and the following disclaimers. */ /* */ /* - Redistributions in binary form must reproduce the above copyright */ /* licenses, this list of conditions and the following disclaimers in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* 3. Disclaimers: */ /* */ /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ /* information on specification licensing rights available through TCG */ /* membership agreements. */ /* */ /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ /* */ /* - Without limitation, TCG and its members and licensors disclaim all */ /* liability, including liability for infringement of any proprietary */ /* rights, relating to use of information in this specification and to the */ /* implementation of this specification, and TCG disclaims all liability for */ /* cost of procurement of substitute goods or services, lost profits, loss */ /* of use, loss of data or any incidental, consequential, direct, indirect, */ /* or special damages, whether under contract, tort, warranty or otherwise, */ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ /* (c) Copyright IBM Corp. and others, 2016 - 2024 */ /* */ /********************************************************************************/ #include "Tpm.h" #include "NV_DefineSpace_fp.h" extern int verbose; #if CC_NV_DefineSpace // Conditional expansion of this file TPM_RC TPM2_NV_DefineSpace( NV_DefineSpace_In *in // IN: input parameter list ) { TPMA_NV attributes = in->publicInfo.nvPublic.attributes; UINT16 nameSize; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_DefineSpace: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_DefineSpace: nvIndex %08x attributes %08x\n", in->publicInfo.nvPublic.nvIndex, in->publicInfo.nvPublic.attributes); fclose(f); } nameSize = CryptHashGetDigestSize(in->publicInfo.nvPublic.nameAlg); // Input Validation // Checks not specific to type // If the UndefineSpaceSpecial command is not implemented, then can't have // an index that can only be deleted with policy #if CC_NV_UndefineSpaceSpecial == NO if(IS_ATTRIBUTE(attributes, TPMA_NV, POLICY_DELETE)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; #endif // check that the authPolicy consistent with hash algorithm if(in->publicInfo.nvPublic.authPolicy.t.size != 0 && in->publicInfo.nvPublic.authPolicy.t.size != nameSize) return TPM_RCS_SIZE + RC_NV_DefineSpace_publicInfo; // make sure that the authValue is not too large if(MemoryRemoveTrailingZeros(&in->auth) > CryptHashGetDigestSize(in->publicInfo.nvPublic.nameAlg)) return TPM_RCS_SIZE + RC_NV_DefineSpace_auth; // 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_RCS_HIERARCHY + RC_NV_DefineSpace_authHandle; // Attribute checks // Eliminate the unsupported types switch(GET_TPM_NT(attributes)) { #if CC_NV_Increment == YES case TPM_NT_COUNTER: #endif #if CC_NV_SetBits == YES case TPM_NT_BITS: #endif #if CC_NV_Extend == YES case TPM_NT_EXTEND: #endif #if CC_PolicySecret == YES && defined TPM_NT_PIN_PASS case TPM_NT_PIN_PASS: case TPM_NT_PIN_FAIL: #endif case TPM_NT_ORDINARY: break; default: return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; break; } // Check that the sizes are OK based on the type switch(GET_TPM_NT(attributes)) { case TPM_NT_ORDINARY: // Can't exceed the allowed size for the implementation if(in->publicInfo.nvPublic.dataSize > MAX_NV_INDEX_SIZE) return TPM_RCS_SIZE + RC_NV_DefineSpace_publicInfo; break; case TPM_NT_EXTEND: if(in->publicInfo.nvPublic.dataSize != nameSize) return TPM_RCS_SIZE + RC_NV_DefineSpace_publicInfo; break; default: // Everything else needs a size of 8 if(in->publicInfo.nvPublic.dataSize != 8) return TPM_RCS_SIZE + RC_NV_DefineSpace_publicInfo; break; } // Handle other specifics switch(GET_TPM_NT(attributes)) { case TPM_NT_COUNTER: // Counter can't have TPMA_NV_CLEAR_STCLEAR SET (don't clear counters) if(IS_ATTRIBUTE(attributes, TPMA_NV, CLEAR_STCLEAR)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; break; #ifdef TPM_NT_PIN_FAIL case TPM_NT_PIN_FAIL: // NV_NO_DA must be SET and AUTHWRITE must be CLEAR // NOTE: As with a PIN_PASS index, the authValue of the index is not // available until the index is written. If AUTHWRITE is the only way to // write then index, it could never be written. Rather than go through // all of the other possible ways to write the Index, it is simply // prohibited to write the index with the authValue. Other checks // below will insure that there seems to be a way to write the index // (i.e., with platform authorization , owner authorization, // or with policyAuth.) // It is not allowed to create a PIN Index that can't be modified. if(!IS_ATTRIBUTE(attributes, TPMA_NV, NO_DA)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; #endif #ifdef TPM_NT_PIN_PASS case TPM_NT_PIN_PASS: // AUTHWRITE must be CLEAR (see note above to TPM_NT_PIN_FAIL) if(IS_ATTRIBUTE(attributes, TPMA_NV, AUTHWRITE) || IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK) || IS_ATTRIBUTE(attributes, TPMA_NV, WRITEDEFINE)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; #endif // this comes before break because PIN_FAIL falls through break; default: break; } // Locks may not be SET and written cannot be SET if(IS_ATTRIBUTE(attributes, TPMA_NV, WRITTEN) || IS_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED) || IS_ATTRIBUTE(attributes, TPMA_NV, READLOCKED)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; // There must be a way to read the index. if(!IS_ATTRIBUTE(attributes, TPMA_NV, OWNERREAD) && !IS_ATTRIBUTE(attributes, TPMA_NV, PPREAD) && !IS_ATTRIBUTE(attributes, TPMA_NV, AUTHREAD) && !IS_ATTRIBUTE(attributes, TPMA_NV, POLICYREAD)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; // There must be a way to write the index if(!IS_ATTRIBUTE(attributes, TPMA_NV, OWNERWRITE) && !IS_ATTRIBUTE(attributes, TPMA_NV, PPWRITE) && !IS_ATTRIBUTE(attributes, TPMA_NV, AUTHWRITE) && !IS_ATTRIBUTE(attributes, TPMA_NV, POLICYWRITE)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; // An index with TPMA_NV_CLEAR_STCLEAR can't have TPMA_NV_WRITEDEFINE SET if(IS_ATTRIBUTE(attributes, TPMA_NV, CLEAR_STCLEAR) && IS_ATTRIBUTE(attributes, TPMA_NV, WRITEDEFINE)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; // Make sure that the creator of the index can delete the index if((IS_ATTRIBUTE(attributes, TPMA_NV, PLATFORMCREATE) && in->authHandle == TPM_RH_OWNER) || (!IS_ATTRIBUTE(attributes, TPMA_NV, PLATFORMCREATE) && in->authHandle == TPM_RH_PLATFORM)) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_authHandle; // If TPMA_NV_POLICY_DELETE is SET, then the index must be defined by // the platform if(IS_ATTRIBUTE(attributes, TPMA_NV, POLICY_DELETE) && TPM_RH_PLATFORM != in->authHandle) return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace_publicInfo; // Make sure that the TPMA_NV_WRITEALL is not set if the index size is larger // than the allowed NV buffer size. if(in->publicInfo.nvPublic.dataSize > MAX_NV_BUFFER_SIZE && IS_ATTRIBUTE(attributes, TPMA_NV, WRITEALL)) return TPM_RCS_SIZE + RC_NV_DefineSpace_publicInfo; // And finally, see if the index is already defined. if(NvIndexIsDefined(in->publicInfo.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 return NvDefineIndex(&in->publicInfo.nvPublic, &in->auth); } #endif // CC_NV_DefineSpace #include "Tpm.h" #include "NV_UndefineSpace_fp.h" #if CC_NV_UndefineSpace // Conditional expansion of this file TPM_RC TPM2_NV_UndefineSpace( NV_UndefineSpace_In *in // IN: input parameter list ) { NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_UndefineSpace: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_UndefineSpace: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // This command can't be used to delete an index with TPMA_NV_POLICY_DELETE SET if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, POLICY_DELETE)) return TPM_RCS_ATTRIBUTES + RC_NV_UndefineSpace_nvIndex; // The owner may only delete an index that was defined with ownerAuth. The // platform may delete an index that was created with either authorization. if(in->authHandle == TPM_RH_OWNER && IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE)) return TPM_RC_NV_AUTHORIZATION; // Internal Data Update // Call implementation dependent internal routine to delete NV index return NvDeleteIndex(nvIndex, locator); } #endif // CC_NV_UndefineSpace #include "Tpm.h" #include "NV_UndefineSpaceSpecial_fp.h" #include "SessionProcess_fp.h" #if CC_NV_UndefineSpaceSpecial // Conditional expansion of this file TPM_RC TPM2_NV_UndefineSpaceSpecial( NV_UndefineSpaceSpecial_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_UndefineSpaceSpecial: nvIndex %08x\n", in->nvIndex); fprintf(f, "TPM2_NV_UndefineSpaceSpecial: platform %08x\n", in->platform ); fclose(f); } // Input Validation // This operation only applies when the TPMA_NV_POLICY_DELETE attribute is SET if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, POLICY_DELETE)) return TPM_RCS_ATTRIBUTES + RC_NV_UndefineSpaceSpecial_nvIndex; // Internal Data Update // Call implementation dependent internal routine to delete NV index result = NvDeleteIndex(nvIndex, locator); // If we just removed the index providing the authorization, make sure that the // authorization session computation is modified so that it doesn't try to // access the authValue of the just deleted index if(result == TPM_RC_SUCCESS) SessionRemoveAssociationToHandle(in->nvIndex); return result; } #endif // CC_NV_UndefineSpaceSpecial #include "Tpm.h" #include "NV_ReadPublic_fp.h" #if CC_NV_ReadPublic // Conditional expansion of this file TPM_RC TPM2_NV_ReadPublic( NV_ReadPublic_In *in, // IN: input parameter list NV_ReadPublic_Out *out // OUT: output parameter list ) { if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_ReadPublic: nvIndex %08x\n", in->nvIndex); fclose(f); } NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, NULL); // Command Output // Copy index public data to output out->nvPublic.nvPublic = nvIndex->publicArea; // Compute NV name NvGetIndexName(nvIndex, &out->nvName); return TPM_RC_SUCCESS; } #endif // CC_NV_ReadPublic #include "Tpm.h" #include "NV_Write_fp.h" #if CC_NV_Write // Conditional expansion of this file TPM_RC TPM2_NV_Write( NV_Write_In *in // IN: input parameter list ) { NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, NULL); TPMA_NV attributes = nvIndex->publicArea.attributes; TPM_RC result; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_Write: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_Write: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvWriteAccessChecks(in->authHandle, in->nvIndex, attributes); if(result != TPM_RC_SUCCESS) return result; // Bits index, extend index or counter index may not be updated by // TPM2_NV_Write if(IsNvCounterIndex(attributes) || IsNvBitsIndex(attributes) || IsNvExtendIndex(attributes)) return TPM_RC_ATTRIBUTES; // Make sure that the offset is not too large if(in->offset > nvIndex->publicArea.dataSize) return TPM_RCS_VALUE + RC_NV_Write_offset; // Make sure that the selection is within the range of the Index if(in->data.t.size > (nvIndex->publicArea.dataSize - in->offset)) return TPM_RC_NV_RANGE; // If this index requires a full sized write, make sure that input range is // full sized. // Note: if the requested size is the same as the Index data size, then offset // will have to be zero. Otherwise, the range check above would have failed. if(IS_ATTRIBUTE(attributes, TPMA_NV, WRITEALL) && in->data.t.size < nvIndex->publicArea.dataSize) return TPM_RC_NV_RANGE; // Internal Data Update // Perform the write. This called routine will SET the TPMA_NV_WRITTEN // attribute if it has not already been SET. If NV isn't available, an error // will be returned. return NvWriteIndexData(nvIndex, in->offset, in->data.t.size, in->data.t.buffer); } #endif // CC_NV_Write #include "Tpm.h" #include "NV_Increment_fp.h" #if CC_NV_Increment // Conditional expansion of this file TPM_RC TPM2_NV_Increment( NV_Increment_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); UINT64 countValue; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_Increment: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_Increment: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvWriteAccessChecks(in->authHandle, in->nvIndex, nvIndex->publicArea.attributes); if(result != TPM_RC_SUCCESS) return result; // Make sure that this is a counter if(!IsNvCounterIndex(nvIndex->publicArea.attributes)) return TPM_RCS_ATTRIBUTES + RC_NV_Increment_nvIndex; // Internal Data Update // If counter index is not been written, initialize it if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN)) countValue = NvReadMaxCount(); else // Read NV data in native format for TPM CPU. countValue = NvGetUINT64Data(nvIndex, locator); // Do the increment countValue++; // Write NV data back. A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may // be returned at this point. If necessary, this function will set the // TPMA_NV_WRITTEN attribute result = NvWriteUINT64Data(nvIndex, countValue); if(result == TPM_RC_SUCCESS) { // If a counter just rolled over, then force the NV update. // Note, if this is an orderly counter, then the write-back needs to be // forced, for other counters, the write-back will happen anyway if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY) && (countValue & MAX_ORDERLY_COUNT) == 0 ) { // Need to force an NV update of orderly data SET_NV_UPDATE(UT_ORDERLY); } } return result; } #endif // CC_NV_Increment #include "Tpm.h" #include "NV_Extend_fp.h" #if CC_NV_Extend // Conditional expansion of this file TPM_RC TPM2_NV_Extend( NV_Extend_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); TPM2B_DIGEST oldDigest; TPM2B_DIGEST newDigest; HASH_STATE hashState; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_Extend: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_Extend: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvWriteAccessChecks(in->authHandle, in->nvIndex, nvIndex->publicArea.attributes); if(result != TPM_RC_SUCCESS) return result; // Make sure that this is an extend index if(!IsNvExtendIndex(nvIndex->publicArea.attributes)) return TPM_RCS_ATTRIBUTES + RC_NV_Extend_nvIndex; // Internal Data Update // Perform the write. oldDigest.t.size = CryptHashGetDigestSize(nvIndex->publicArea.nameAlg); pAssert(oldDigest.t.size <= sizeof(oldDigest.t.buffer)); if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN)) { NvGetIndexData(nvIndex, locator, 0, oldDigest.t.size, oldDigest.t.buffer); } else { MemorySet(oldDigest.t.buffer, 0, oldDigest.t.size); } // Start hash newDigest.t.size = CryptHashStart(&hashState, nvIndex->publicArea.nameAlg); // Adding old digest CryptDigestUpdate2B(&hashState, &oldDigest.b); // Adding new data CryptDigestUpdate2B(&hashState, &in->data.b); // Complete hash CryptHashEnd2B(&hashState, &newDigest.b); // Write extended hash back. // Note, this routine will SET the TPMA_NV_WRITTEN attribute if necessary return NvWriteIndexData(nvIndex, 0, newDigest.t.size, newDigest.t.buffer); } #endif // CC_NV_Extend #include "Tpm.h" #include "NV_SetBits_fp.h" #if CC_NV_SetBits // Conditional expansion of this file TPM_RC TPM2_NV_SetBits( NV_SetBits_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); UINT64 oldValue; UINT64 newValue; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_SetBits: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_SetBits: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvWriteAccessChecks(in->authHandle, in->nvIndex, nvIndex->publicArea.attributes); if(result != TPM_RC_SUCCESS) return result; // Make sure that this is a bit field if(!IsNvBitsIndex(nvIndex->publicArea.attributes)) return TPM_RCS_ATTRIBUTES + RC_NV_SetBits_nvIndex; // If index is not been written, initialize it if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN)) oldValue = 0; else // Read index data oldValue = NvGetUINT64Data(nvIndex, locator); // Figure out what the new value is going to be newValue = oldValue | in->bits; // Internal Data Update return NvWriteUINT64Data(nvIndex, newValue); } #endif // CC_NV_SetBits #include "Tpm.h" #include "NV_WriteLock_fp.h" #if CC_NV_WriteLock // Conditional expansion of this file TPM_RC TPM2_NV_WriteLock( NV_WriteLock_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); TPMA_NV nvAttributes = nvIndex->publicArea.attributes; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_WriteLock: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_WriteLock: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation: // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvWriteAccessChecks(in->authHandle, in->nvIndex, nvAttributes); if(result != TPM_RC_SUCCESS) { if(result == TPM_RC_NV_AUTHORIZATION) return result; // If write access failed because the index is already locked, then it is // no error. return TPM_RC_SUCCESS; } // if neither TPMA_NV_WRITEDEFINE nor TPMA_NV_WRITE_STCLEAR is set, the index // can not be write-locked if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITEDEFINE) && !IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITE_STCLEAR)) return TPM_RCS_ATTRIBUTES + RC_NV_WriteLock_nvIndex; // Internal Data Update // Set the WRITELOCK attribute. // Note: if TPMA_NV_WRITELOCKED were already SET, then the write access check // above would have failed and this code isn't executed. SET_ATTRIBUTE(nvAttributes, TPMA_NV, WRITELOCKED); // Write index info back return NvWriteIndexAttributes(nvIndex->publicArea.nvIndex, locator, nvAttributes); } #endif // CC_NV_WriteLock #include "Tpm.h" #include "NV_GlobalWriteLock_fp.h" #if CC_NV_GlobalWriteLock // Conditional expansion of this file TPM_RC TPM2_NV_GlobalWriteLock( NV_GlobalWriteLock_In *in // IN: input parameter list ) { if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_GlobalWriteLock: authHandle %08x\n", in->authHandle); fclose(f); } // Input parameter (the authorization handle) is not reference in command action. NOT_REFERENCED(in); // Internal Data Update // Implementation dependent method of setting the global lock return NvSetGlobalLock(); } #endif // CC_NV_GlobalWriteLock #include "Tpm.h" #include "NV_Read_fp.h" #if CC_NV_Read // Conditional expansion of this file /* TPM_RC_NV_AUTHORIZATION the authorization was valid but the authorizing entity (authHandle) is not allowed to read from the Index referenced by nvIndex */ /* TPM_RC_NV_LOCKED the Index referenced by nvIndex is read locked */ /* TPM_RC_NV_RANGE read range defined by size and offset is outside the range of the Index referenced by nvIndex */ /* TPM_RC_NV_UNINITIALIZED the Index referenced by nvIndex has not been initialized (written) */ /* TPM_RC_VALUE the read size is larger than the MAX_NV_BUFFER_SIZE */ TPM_RC TPM2_NV_Read( NV_Read_In *in, // IN: input parameter list NV_Read_Out *out // OUT: output parameter list ) { NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); TPM_RC result; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_Read: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_Read: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Common read access checks. NvReadAccessChecks() may return // TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED result = NvReadAccessChecks(in->authHandle, in->nvIndex, nvIndex->publicArea.attributes); if(result != TPM_RC_SUCCESS) return result; // Make sure the data will fit the return buffer if(in->size > MAX_NV_BUFFER_SIZE) return TPM_RCS_VALUE + RC_NV_Read_size; // Verify that the offset is not too large if(in->offset > nvIndex->publicArea.dataSize) return TPM_RCS_VALUE + RC_NV_Read_offset; // Make sure that the selection is within the range of the Index if(in->size > (nvIndex->publicArea.dataSize - in->offset)) return TPM_RC_NV_RANGE; // Command Output // Set the return size out->data.t.size = in->size; // Perform the read NvGetIndexData(nvIndex, locator, in->offset, in->size, out->data.t.buffer); return TPM_RC_SUCCESS; } #endif // CC_NV_Read #include "Tpm.h" #include "NV_ReadLock_fp.h" #if CC_NV_ReadLock // Conditional expansion of this file TPM_RC TPM2_NV_ReadLock( NV_ReadLock_In *in // IN: input parameter list ) { TPM_RC result; NV_REF locator; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_ReadLock: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_ReadLock: nvIndex %08x\n", in->nvIndex); fclose(f); } // The referenced index has been checked multiple times before this is called // so it must be present and will be loaded into cache NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); TPMA_NV nvAttributes = nvIndex->publicArea.attributes; // Input Validation // Common read access checks. NvReadAccessChecks() may return // TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED result = NvReadAccessChecks(in->authHandle, in->nvIndex, nvAttributes); if(result == TPM_RC_NV_AUTHORIZATION) return TPM_RC_NV_AUTHORIZATION; // Index is already locked for write else if(result == TPM_RC_NV_LOCKED) return TPM_RC_SUCCESS; // If NvReadAccessChecks return TPM_RC_NV_UNINITALIZED, then continue. // It is not an error to read lock an uninitialized Index. // if TPMA_NV_READ_STCLEAR is not set, the index can not be read-locked if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, READ_STCLEAR)) return TPM_RCS_ATTRIBUTES + RC_NV_ReadLock_nvIndex; // Internal Data Update // Set the READLOCK attribute SET_ATTRIBUTE(nvAttributes, TPMA_NV, READLOCKED); // Write NV info back return NvWriteIndexAttributes(nvIndex->publicArea.nvIndex, locator, nvAttributes); } #endif // CC_NV_ReadLock #include "Tpm.h" #include "NV_ChangeAuth_fp.h" #if CC_NV_ChangeAuth // Conditional expansion of this file TPM_RC TPM2_NV_ChangeAuth( NV_ChangeAuth_In *in // IN: input parameter list ) { NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_ChangeAuth: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation // Remove trailing zeros and make sure that the result is not larger than the // digest of the nameAlg. if(MemoryRemoveTrailingZeros(&in->newAuth) > CryptHashGetDigestSize(nvIndex->publicArea.nameAlg)) return TPM_RCS_SIZE + RC_NV_ChangeAuth_newAuth; // Internal Data Update // Change authValue return NvWriteIndexAuth(locator, &in->newAuth); } #endif // CC_NV_ChangeAuth #include "Tpm.h" #include "Attest_spt_fp.h" #include "NV_Certify_fp.h" #if CC_NV_Certify // Conditional expansion of this file TPM_RC TPM2_NV_Certify( NV_Certify_In *in, // IN: input parameter list NV_Certify_Out *out // OUT: output parameter list ) { TPM_RC result; NV_REF locator; NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); TPMS_ATTEST certifyInfo; OBJECT *signObject = HandleToObject(in->signHandle); if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_Certify: signHandle %08x\n", in->signHandle); fprintf(f, "TPM2_NV_Certify: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_Certify: nvIndex %08x\n", in->nvIndex); fclose(f); } // Input Validation if(!IsSigningObject(signObject)) return TPM_RCS_KEY + RC_NV_Certify_signHandle; if(!CryptSelectSignScheme(signObject, &in->inScheme)) return TPM_RCS_SCHEME + RC_NV_Certify_inScheme; // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION // or TPM_RC_NV_LOCKED result = NvReadAccessChecks(in->authHandle, in->nvIndex, nvIndex->publicArea.attributes); if(result != TPM_RC_SUCCESS) return result; // make sure that the selection is within the range of the Index (cast to avoid // any wrap issues with addition) if((UINT32)in->size + (UINT32)in->offset > (UINT32)nvIndex->publicArea.dataSize) return TPM_RC_NV_RANGE; // Make sure the data will fit the return buffer // NOTE: This check may be modified if the output buffer will not hold the // maximum sized NV buffer as part of the certified data. The difference in // size could be substantial if the signature scheme was produced a large // signature (e.g., RSA 4096). if(in->size > MAX_NV_BUFFER_SIZE) return TPM_RCS_VALUE + RC_NV_Certify_size; // Command Output // Fill in attest information common fields FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, &certifyInfo); // Get the name of the index NvGetIndexName(nvIndex, &certifyInfo.attested.nv.indexName); // See if this is old format or new format if ((in->size != 0) || (in->offset != 0)) { // NV certify specific fields // Attestation type certifyInfo.type = TPM_ST_ATTEST_NV; // Set the return size certifyInfo.attested.nv.nvContents.t.size = in->size; // Set the offset certifyInfo.attested.nv.offset = in->offset; // Perform the read NvGetIndexData(nvIndex, locator, in->offset, in->size, certifyInfo.attested.nv.nvContents.t.buffer); } else { HASH_STATE hashState; // This is to sign a digest of the data certifyInfo.type = TPM_ST_ATTEST_NV_DIGEST; // Initialize the hash before calling the function to add the Index data to // the hash. certifyInfo.attested.nvDigest.nvDigest.t.size = CryptHashStart(&hashState, in->inScheme.details.any.hashAlg); NvHashIndexData(&hashState, nvIndex, locator, 0, nvIndex->publicArea.dataSize); CryptHashEnd2B(&hashState, &certifyInfo.attested.nvDigest.nvDigest.b); } // Sign attestation structure. A NULL signature will be returned if // signObject is NULL. return SignAttestInfo(signObject, &in->inScheme, &certifyInfo, &in->qualifyingData, &out->certifyInfo, &out->signature); } #endif // CC_NV_Certify #include "Tpm.h" #include "NV_ReadPublic2_fp.h" #if CC_NV_ReadPublic2 // Conditional expansion of this file /*(See part 3 specification) // Read the public information of a NV index */ TPM_RC TPM2_NV_ReadPublic2(NV_ReadPublic2_In* in, // IN: input parameter list NV_ReadPublic2_Out* out // OUT: output parameter list ) { TPM_RC result; NV_INDEX* nvIndex; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_ReadPublic2: nvIndex %08x\n", in->nvIndex); fclose(f); } nvIndex = NvGetIndexInfo(in->nvIndex, NULL); // Command Output // The reference code stores its NV indices in the legacy form, because // it doesn't support any extended attributes. // Translate the legacy form to the general form. result = NvPublic2FromNvPublic(&nvIndex->publicArea, &out->nvPublic.nvPublic2); if(result != TPM_RC_SUCCESS) { return RcSafeAddToResult(result, RC_NV_ReadPublic2_nvIndex); } // Compute NV name NvGetIndexName(nvIndex, &out->nvName); return TPM_RC_SUCCESS; } #endif // CC_NV_ReadPublic2 #include "Tpm.h" #include "NV_DefineSpace2_fp.h" #if CC_NV_DefineSpace2 // Conditional expansion of this file /*(See part 3 specification) // Define a NV index space */ // Return Type: TPM_RC // TPM_RC_HIERARCHY for authorizations using TPM_RH_PLATFORM // phEnable_NV is clear preventing access to NV // data in the platform hierarchy. // TPM_RC_ATTRIBUTES attributes of the index are not consistent // TPM_RC_NV_DEFINED index already exists // 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' // (this includes the case when the index is // larger than a MAX_NV_BUFFER_SIZE but the // TPMA_NV_WRITEALL attribute is SET) TPM_RC TPM2_NV_DefineSpace2(NV_DefineSpace2_In* in // IN: input parameter list ) { TPM_RC result; TPMS_NV_PUBLIC legacyPublic; if (verbose) { FILE *f = fopen("trace.txt", "a"); fprintf(f, "TPM2_NV_DefineSpace2: authHandle %08x\n", in->authHandle); fprintf(f, "TPM2_NV_DefineSpace2: nvIndex %08x\n", in->publicInfo.nvPublic2.nvPublic2.nvIndex.nvIndex); fclose(f); } // Input Validation // Validate the handle type and the (handle-type-specific) attributes. switch(in->publicInfo.nvPublic2.handleType) { case TPM_HT_NV_INDEX: break; # if EXTERNAL_NV case TPM_HT_EXTERNAL_NV: // The reference implementation may let you define an "external" NV // index, but it doesn't currently support setting any of the extended // bits for customizing the behavior of external NV. if((TPMA_NV_EXP_TO_UINT64( in->publicInfo.nvPublic2.nvPublic2.externalNV.attributes) & 0xffffffff00000000) != 0) { return TPM_RCS_ATTRIBUTES + RC_NV_DefineSpace2_publicInfo; } break; # endif default: return TPM_RCS_HANDLE + RC_NV_DefineSpace2_publicInfo; } result = NvPublicFromNvPublic2(&in->publicInfo.nvPublic2, &legacyPublic); if(result != TPM_RC_SUCCESS) { return RcSafeAddToResult(result, RC_NV_DefineSpace2_publicInfo); } return NvDefineSpace(in->authHandle, &in->auth, &legacyPublic, RC_NV_DefineSpace2_authHandle, RC_NV_DefineSpace2_auth, RC_NV_DefineSpace2_publicInfo); } #endif // CC_NV_DefineSpace