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_DefineSpace_fp.h"
10 //
11 //
12 //     Error Returns                 Meaning
13 //
14 //     TPM_RC_NV_ATTRIBUTES          attributes of the index are not consistent
15 //     TPM_RC_NV_DEFINED             index already exists
16 //     TPM_RC_HIERARCHY              for authorizations using TPM_RH_PLATFORM phEnable_NV is
17 //                                   clear.
18 //     TPM_RC_NV_SPACE               Insufficient space for the index
19 //     TPM_RC_SIZE                   'auth->size' or 'publicInfo->authPolicy.size' is larger than the digest
20 //                                   size of 'publicInfo->nameAlg', or 'publicInfo->dataSize' is not
21 //                                   consistent with 'publicInfo->attributes'.
22 //
23 TPM_RC
TPM2_NV_DefineSpace(NV_DefineSpace_In * in)24 TPM2_NV_DefineSpace(
25    NV_DefineSpace_In   *in                  // IN: input parameter list
26    )
27 {
28    TPM_RC          result;
29    TPMA_NV         attributes;
30    UINT16          nameSize;
31 
32    nameSize = CryptGetHashDigestSize(in->publicInfo.t.nvPublic.nameAlg);
33 
34    // Check if NV is available. NvIsAvailable may return TPM_RC_NV_UNAVAILABLE
35    // TPM_RC_NV_RATE or TPM_RC_SUCCESS.
36    result = NvIsAvailable();
37    if(result != TPM_RC_SUCCESS)
38        return result;
39 
40 // Input Validation
41    // If an index is being created by the owner and shEnable is
42    // clear, then we would not reach this point because ownerAuth
43    // can't be given when shEnable is CLEAR. However, if phEnable
44    // is SET but phEnableNV is CLEAR, we have to check here
45    if(in->authHandle == TPM_RH_PLATFORM && gc.phEnableNV == CLEAR)
46        return TPM_RC_HIERARCHY + RC_NV_DefineSpace_authHandle;
47 
48    attributes = in->publicInfo.t.nvPublic.attributes;
49 
50    //TPMS_NV_PUBLIC validation.
51    // Counters and bit fields must have a size of 8
52    if (   (attributes.TPMA_NV_COUNTER == SET || attributes.TPMA_NV_BITS == SET)
53        && (in->publicInfo.t.nvPublic.dataSize != 8))
54        return TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo;
55 
56    // check that the authPolicy consistent with hash algorithm
57    if(   in->publicInfo.t.nvPublic.authPolicy.t.size != 0
58       && in->publicInfo.t.nvPublic.authPolicy.t.size != nameSize)
59        return TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo;
60 
61    // make sure that the authValue is not too large
62    MemoryRemoveTrailingZeros(&in->auth);
63    if(in->auth.t.size > nameSize)
64        return TPM_RC_SIZE + RC_NV_DefineSpace_auth;
65 
66    //TPMA_NV validation.
67    // Locks may not be SET and written cannot be SET
68    if(   attributes.TPMA_NV_WRITTEN == SET
69       || attributes.TPMA_NV_WRITELOCKED == SET
70       || attributes.TPMA_NV_READLOCKED == SET)
71        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
72 
73    // There must be a way to read the index
74    if(   attributes.TPMA_NV_OWNERREAD == CLEAR
75       && attributes.TPMA_NV_PPREAD == CLEAR
76       && attributes.TPMA_NV_AUTHREAD == CLEAR
77       && attributes.TPMA_NV_POLICYREAD == CLEAR)
78        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
79 
80    // There must be a way to write the index
81    if(   attributes.TPMA_NV_OWNERWRITE == CLEAR
82       && attributes.TPMA_NV_PPWRITE == CLEAR
83       && attributes.TPMA_NV_AUTHWRITE == CLEAR
84       && attributes.TPMA_NV_POLICYWRITE == CLEAR)
85        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
86 
87    // Make sure that no attribute is used that is not supported by the proper
88    // command
89 #if CC_NV_Increment == NO
90    if( attributes.TPMA_NV_COUNTER == SET)
91        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
92 #endif
93 #if CC_NV_SetBits == NO
94       if( attributes.TPMA_NV_BITS == SET)
95           return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
96 #endif
97 #if CC_NV_Extend == NO
98      if( attributes.TPMA_NV_EXTEND == SET)
99          return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
100 #endif
101 #if CC_NV_UndefineSpaceSpecial == NO
102     if( attributes.TPMA_NV_POLICY_DELETE == SET)
103         return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
104 #endif
105 
106    // Can be COUNTER or BITS or EXTEND but not more than one
107    if( attributes.TPMA_NV_COUNTER == SET
108       && attributes.TPMA_NV_BITS == SET)
109        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
110    if(   attributes.TPMA_NV_COUNTER == SET
111       && attributes.TPMA_NV_EXTEND == SET)
112        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
113    if(   attributes.TPMA_NV_BITS == SET
114       && attributes.TPMA_NV_EXTEND == SET)
115        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
116 
117    // An index with TPMA_NV_CLEAR_STCLEAR can't be a counter and can't have
118    // TPMA_NV_WRITEDEFINE SET
119    if(     attributes.TPMA_NV_CLEAR_STCLEAR == SET
120        && (    attributes.TPMA_NV_COUNTER == SET
121             || attributes.TPMA_NV_WRITEDEFINE == SET)
122       )
123        return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
124 
125    // Make sure that the creator of the index can delete the index
126    if( (    in->publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE == SET
127           && in->authHandle == TPM_RH_OWNER
128          )
129       || (   in->publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE == CLEAR
130           && in->authHandle == TPM_RH_PLATFORM
131          )
132      )
133          return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_authHandle;
134 
135   // If TPMA_NV_POLICY_DELETE is SET, then the index must be defined by
136   // the platform
137   if(    in->publicInfo.t.nvPublic.attributes.TPMA_NV_POLICY_DELETE == SET
138      && TPM_RH_PLATFORM != in->authHandle
139     )
140       return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
141 
142   // If the NV index is used as a PCR, the data size must match the digest
143   // size
144   if(   in->publicInfo.t.nvPublic.attributes.TPMA_NV_EXTEND == SET
145      && in->publicInfo.t.nvPublic.dataSize != nameSize
146     )
147       return TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo;
148 
149   // See if the index is already defined.
150   if(NvIsUndefinedIndex(in->publicInfo.t.nvPublic.nvIndex))
151       return TPM_RC_NV_DEFINED;
152 
153 // Internal Data Update
154    // define the space. A TPM_RC_NV_SPACE error may be returned at this point
155    result = NvDefineIndex(&in->publicInfo.t.nvPublic, &in->auth);
156    if(result != TPM_RC_SUCCESS)
157        return result;
158 
159   return TPM_RC_SUCCESS;
160 
161 }
162