1 // This file was extracted from the TCG Published
2 // Trusted Platform Module Library
3 // Part 3: Commands
4 // Family "2.0"
5 // Level 00 Revision 01.16
6 // October 30, 2014
7 
8 #include "InternalRoutines.h"
9 #include "NV_Extend_fp.h"
10 #include "NV_spt_fp.h"
11 //
12 //
13 //     Error Returns               Meaning
14 //
15 //     TPM_RC_ATTRIBUTES           the TPMA_NV_EXTEND attribute is not SET in the Index referenced
16 //                                 by nvIndex
17 //     TPM_RC_NV_AUTHORIZATION     the authorization was valid but the authorizing entity (authHandle) is
18 //                                 not allowed to write to the Index referenced by nvIndex
19 //     TPM_RC_NV_LOCKED            the Index referenced by nvIndex is locked for writing
20 //
21 TPM_RC
TPM2_NV_Extend(NV_Extend_In * in)22 TPM2_NV_Extend(
23    NV_Extend_In      *in            // IN: input parameter list
24    )
25 {
26    TPM_RC                  result;
27    NV_INDEX                nvIndex;
28 
29    TPM2B_DIGEST            oldDigest;
30    TPM2B_DIGEST            newDigest;
31    HASH_STATE              hashState;
32 
33 // Input Validation
34 
35    // Common access checks, NvWriteAccessCheck() may return TPM_RC_NV_AUTHORIZATION
36    // or TPM_RC_NV_LOCKED
37    result = NvWriteAccessChecks(in->authHandle, in->nvIndex);
38    if(result != TPM_RC_SUCCESS)
39        return result;
40 
41    // Get NV index info
42    NvGetIndexInfo(in->nvIndex, &nvIndex);
43 
44    // Make sure that this is an extend index
45    if(nvIndex.publicArea.attributes.TPMA_NV_EXTEND != SET)
46        return TPM_RC_ATTRIBUTES + RC_NV_Extend_nvIndex;
47 
48    // If the Index is not-orderly, or if this is the first write, NV will
49    // need to be updated.
50    if(   nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == CLEAR
51       || nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == CLEAR)
52    {
53        // Check if NV is available. NvIsAvailable may return TPM_RC_NV_UNAVAILABLE
54        // TPM_RC_NV_RATE or TPM_RC_SUCCESS.
55        result = NvIsAvailable();
56        if(result != TPM_RC_SUCCESS)
57            return result;
58    }
59 
60 // Internal Data Update
61 
62    // Perform the write.
63    oldDigest.t.size = CryptGetHashDigestSize(nvIndex.publicArea.nameAlg);
64    pAssert(oldDigest.t.size <= sizeof(oldDigest.t.buffer));
65    if(nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
66    {
67        NvGetIndexData(in->nvIndex, &nvIndex, 0,
68                       oldDigest.t.size, oldDigest.t.buffer);
69    }
70    else
71    {
72        MemorySet(oldDigest.t.buffer, 0, oldDigest.t.size);
73    }
74    // Start hash
75    newDigest.t.size = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState);
76 
77    // Adding old digest
78    CryptUpdateDigest2B(&hashState, &oldDigest.b);
79 
80    // Adding new data
81    CryptUpdateDigest2B(&hashState, &in->data.b);
82 
83    // Complete hash
84    CryptCompleteHash2B(&hashState, &newDigest.b);
85 
86    // Write extended hash back.
87    // Note, this routine will SET the TPMA_NV_WRITTEN attribute if necessary
88    return NvWriteIndexData(in->nvIndex, &nvIndex, 0,
89                            newDigest.t.size, newDigest.t.buffer);
90 }
91