Line | Count | Source (jump to first uncovered line) |
1 | | // This file was extracted from the TCG Published |
2 | | // Trusted Platform Module Library |
3 | | // Part 4: Supporting Routines |
4 | | // Family "2.0" |
5 | | // Level 00 Revision 01.16 |
6 | | // October 30, 2014 |
7 | | |
8 | | #include "InternalRoutines.h" |
9 | | #include "ExecCommand_fp.h" |
10 | | #include "HandleProcess_fp.h" |
11 | | #include "SessionProcess_fp.h" |
12 | | #include "CommandDispatcher_fp.h" |
13 | | // |
14 | | // Uncomment this next #include if doing static command/response buffer sizing |
15 | | // |
16 | | // #include "CommandResponseSizes_fp.h" |
17 | | // |
18 | | // |
19 | | // ExecuteCommand() |
20 | | // |
21 | | // The function performs the following steps. |
22 | | // a) Parses the command header from input buffer. |
23 | | // b) Calls ParseHandleBuffer() to parse the handle area of the command. |
24 | | // c) Validates that each of the handles references a loaded entity. |
25 | | // |
26 | | // d) Calls ParseSessionBuffer() () to: |
27 | | // 1) unmarshal and parse the session area; |
28 | | // 2) check the authorizations; and |
29 | | // 3) when necessary, decrypt a parameter. |
30 | | // e) Calls CommandDispatcher() to: |
31 | | // 1) unmarshal the command parameters from the command buffer; |
32 | | // 2) call the routine that performs the command actions; and |
33 | | // 3) marshal the responses into the response buffer. |
34 | | // f) If any error occurs in any of the steps above create the error response and return. |
35 | | // g) Calls BuildResponseSession() to: |
36 | | // 1) when necessary, encrypt a parameter |
37 | | // 2) build the response authorization sessions |
38 | | // 3) update the audit sessions and nonces |
39 | | // h) Assembles handle, parameter and session buffers for response and return. |
40 | | // |
41 | | LIB_EXPORT void |
42 | | ExecuteCommand( |
43 | | unsigned int requestSize, // IN: command buffer size |
44 | | unsigned char *request, // IN: command buffer |
45 | | unsigned int *responseSize, // OUT: response buffer size |
46 | | unsigned char **response // OUT: response buffer |
47 | | ) |
48 | 888 | { |
49 | | // Command local variables |
50 | 888 | TPM_ST tag; // these first three variables are the |
51 | 888 | UINT32 commandSize; |
52 | 888 | TPM_CC commandCode = 0; |
53 | 888 | BYTE *parmBufferStart; // pointer to the first byte of an |
54 | | // optional parameter buffer |
55 | 888 | UINT32 parmBufferSize = 0;// number of bytes in parameter area |
56 | 888 | UINT32 handleNum = 0; // number of handles unmarshaled into |
57 | | // the handles array |
58 | 888 | TPM_HANDLE handles[MAX_HANDLE_NUM];// array to hold handles in the |
59 | | // command. Only handles in the handle |
60 | | // area are stored here, not handles |
61 | | // passed as parameters. |
62 | | // Response local variables |
63 | 888 | TPM_RC result; // return code for the command |
64 | 888 | TPM_ST resTag; // tag for the response |
65 | 888 | UINT32 resHandleSize = 0; // size of the handle area in the |
66 | | // response. This is needed so that the |
67 | | // handle area can be skipped when |
68 | | // generating the rpHash. |
69 | 888 | UINT32 resParmSize = 0; // the size of the response parameters |
70 | | // These values go in the rpHash. |
71 | 888 | UINT32 resAuthSize = 0; // size of authorization area in the |
72 | | // |
73 | | // response |
74 | 888 | INT32 size; // remaining data to be unmarshaled |
75 | | // or remaining space in the marshaling |
76 | | // buffer |
77 | 888 | BYTE *buffer; // pointer into the buffer being used |
78 | | // for marshaling or unmarshaling |
79 | 888 | INT32 bufferSize; // size of buffer being used for |
80 | | // marshaling or unmarshaling |
81 | 888 | UINT32 i; // local temp |
82 | | // This next function call is used in development to size the command and response |
83 | | // buffers. The values printed are the sizes of the internal structures and |
84 | | // not the sizes of the canonical forms of the command response structures. Also, |
85 | | // the sizes do not include the tag, commandCode, requestSize, or the authorization |
86 | | // fields. |
87 | | //CommandResponseSizes(); |
88 | | // Set flags for NV access state. This should happen before any other |
89 | | // operation that may require a NV write. Note, that this needs to be done |
90 | | // even when in failure mode. Otherwise, g_updateNV would stay SET while in |
91 | | // Failure mode and the NB would be written on each call. |
92 | 888 | g_updateNV = FALSE; |
93 | 888 | g_clearOrderly = FALSE; |
94 | | // As of Sept 25, 2013, the failure mode handling has been incorporated in the |
95 | | // reference code. This implementation requires that the system support |
96 | | // setjmp/longjmp. This code is put here because of the complexity being |
97 | | // added to the platform and simulator code to deal with all the variations |
98 | | // of errors. |
99 | 888 | if(g_inFailureMode) |
100 | 0 | { |
101 | | // Do failure mode processing |
102 | 0 | TpmFailureMode (requestSize, request, responseSize, response); |
103 | 0 | return; |
104 | 0 | } |
105 | 888 | #ifndef EMBEDDED_MODE |
106 | 888 | if(setjmp(g_jumpBuffer) != 0) |
107 | 0 | { |
108 | | // Get here if we got a longjump putting us into failure mode |
109 | 0 | g_inFailureMode = TRUE; |
110 | 0 | result = TPM_RC_FAILURE; |
111 | 0 | goto Fail; |
112 | 0 | } |
113 | 888 | #endif // EMBEDDED_MODE ^^^ not defined |
114 | | // Assume that everything is going to work. |
115 | 888 | result = TPM_RC_SUCCESS; |
116 | | // Query platform to get the NV state. The result state is saved internally |
117 | | // and will be reported by NvIsAvailable(). The reference code requires that |
118 | | // accessibility of NV does not change during the execution of a command. |
119 | | // Specifically, if NV is available when the command execution starts and then |
120 | | // is not available later when it is necessary to write to NV, then the TPM |
121 | | // will go into failure mode. |
122 | 888 | NvCheckState(); |
123 | | // Due to the limitations of the simulation, TPM clock must be explicitly |
124 | | // synchronized with the system clock whenever a command is received. |
125 | | // This function call is not necessary in a hardware TPM. However, taking |
126 | | // a snapshot of the hardware timer at the beginning of the command allows |
127 | | // the time value to be consistent for the duration of the command execution. |
128 | 888 | TimeUpdateToCurrent(); |
129 | | // Any command through this function will unceremoniously end the |
130 | | // _TPM_Hash_Data/_TPM_Hash_End sequence. |
131 | 888 | if(g_DRTMHandle != TPM_RH_UNASSIGNED) |
132 | 0 | ObjectTerminateEvent(); |
133 | | // Get command buffer size and command buffer. |
134 | 888 | size = requestSize; |
135 | 888 | buffer = request; |
136 | | // Parse command header: tag, commandSize and commandCode. |
137 | | // First parse the tag. The unmarshaling routine will validate |
138 | | // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS. |
139 | 888 | result = TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &buffer, &size); |
140 | 888 | if(result != TPM_RC_SUCCESS) |
141 | 5 | goto Cleanup; |
142 | | // Unmarshal the commandSize indicator. |
143 | 883 | result = UINT32_Unmarshal(&commandSize, &buffer, &size); |
144 | 883 | if(result != TPM_RC_SUCCESS) |
145 | 0 | goto Cleanup; |
146 | | // On a TPM that receives bytes on a port, the number of bytes that were |
147 | | // received on that port is requestSize it must be identical to commandSize. |
148 | | // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed |
149 | | // by the implementation. The check against MAX_COMMAND_SIZE may be redundant |
150 | | // as the input processing (the function that receives the command bytes and |
151 | | // places them in the input buffer) would likely have the input truncated when |
152 | | // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize. |
153 | 883 | if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE) |
154 | 13 | { |
155 | 13 | result = TPM_RC_COMMAND_SIZE; |
156 | 13 | goto Cleanup; |
157 | 13 | } |
158 | | // Unmarshal the command code. |
159 | 870 | result = TPM_CC_Unmarshal(&commandCode, &buffer, &size); |
160 | 870 | if(result != TPM_RC_SUCCESS) |
161 | 4 | goto Cleanup; |
162 | | // Check to see if the command is implemented. |
163 | 866 | if(!CommandIsImplemented(commandCode)) |
164 | 0 | { |
165 | 0 | result = TPM_RC_COMMAND_CODE; |
166 | 0 | goto Cleanup; |
167 | 0 | } |
168 | | #if FIELD_UPGRADE_IMPLEMENTED == YES |
169 | | // If the TPM is in FUM, then the only allowed command is |
170 | | // TPM_CC_FieldUpgradeData. |
171 | | if(IsFieldUgradeMode() && (commandCode != TPM_CC_FieldUpgradeData)) |
172 | | { |
173 | | result = TPM_RC_UPGRADE; |
174 | | goto Cleanup; |
175 | | } |
176 | | else |
177 | | #endif |
178 | | // Excepting FUM, the TPM only accepts TPM2_Startup() after |
179 | | // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup() |
180 | | // is no longer allowed. |
181 | 866 | if(( !TPMIsStarted() && commandCode != TPM_CC_Startup) |
182 | 866 | || (TPMIsStarted() && commandCode == TPM_CC_Startup)) |
183 | 0 | { |
184 | 0 | result = TPM_RC_INITIALIZE; |
185 | 0 | goto Cleanup; |
186 | 0 | } |
187 | | // Start regular command process. |
188 | | // Parse Handle buffer. |
189 | 866 | result = ParseHandleBuffer(commandCode, &buffer, &size, handles, &handleNum); |
190 | 866 | if(result != TPM_RC_SUCCESS) |
191 | 18 | goto Cleanup; |
192 | | // Number of handles retrieved from handle area should be less than |
193 | | // MAX_HANDLE_NUM. |
194 | 848 | pAssert(handleNum <= MAX_HANDLE_NUM); |
195 | | // All handles in the handle area are required to reference TPM-resident |
196 | | // entities. |
197 | 1.08k | for(i = 0; i < handleNum; i++) |
198 | 240 | { |
199 | 240 | result = EntityGetLoadStatus(&handles[i], commandCode); |
200 | 240 | if(result != TPM_RC_SUCCESS) |
201 | 1 | { |
202 | 1 | if(result == TPM_RC_REFERENCE_H0) |
203 | 0 | result = result + i; |
204 | 1 | else |
205 | 1 | result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]); |
206 | 1 | goto Cleanup; |
207 | 1 | } |
208 | 240 | } |
209 | | // Authorization session handling for the command. |
210 | 847 | if(tag == TPM_ST_SESSIONS) |
211 | 221 | { |
212 | 221 | BYTE *sessionBufferStart;// address of the session area first byte |
213 | | // in the input buffer |
214 | 221 | UINT32 authorizationSize; // number of bytes in the session area |
215 | | // Find out session buffer size. |
216 | 221 | result = UINT32_Unmarshal(&authorizationSize, &buffer, &size); |
217 | 221 | if(result != TPM_RC_SUCCESS) |
218 | 0 | goto Cleanup; |
219 | | // Perform sanity check on the unmarshaled value. If it is smaller than |
220 | | // the smallest possible session or larger than the remaining size of |
221 | | // the command, then it is an error. NOTE: This check could pass but the |
222 | | // session size could still be wrong. That will be determined after the |
223 | | // sessions are unmarshaled. |
224 | 221 | if( authorizationSize < 9 |
225 | 221 | || authorizationSize > (UINT32) size) |
226 | 0 | { |
227 | 0 | result = TPM_RC_SIZE; |
228 | 0 | goto Cleanup; |
229 | 0 | } |
230 | | // The sessions, if any, follows authorizationSize. |
231 | 221 | sessionBufferStart = buffer; |
232 | | // The parameters follow the session area. |
233 | 221 | parmBufferStart = sessionBufferStart + authorizationSize; |
234 | | // Any data left over after removing the authorization sessions is |
235 | | // parameter data. If the command does not have parameters, then an |
236 | | // error will be returned if the remaining size is not zero. This is |
237 | | // checked later. |
238 | 221 | parmBufferSize = size - authorizationSize; |
239 | | // The actions of ParseSessionBuffer() are described in the introduction. |
240 | 221 | result = ParseSessionBuffer(commandCode, |
241 | 221 | handleNum, |
242 | 221 | handles, |
243 | 221 | sessionBufferStart, |
244 | 221 | authorizationSize, |
245 | 221 | parmBufferStart, |
246 | 221 | parmBufferSize); |
247 | 221 | if(result != TPM_RC_SUCCESS) |
248 | 17 | goto Cleanup; |
249 | 221 | } |
250 | 626 | else |
251 | 626 | { |
252 | | // Whatever remains in the input buffer is used for the parameters of the |
253 | | // command. |
254 | 626 | parmBufferStart = buffer; |
255 | 626 | parmBufferSize = size; |
256 | | // The command has no authorization sessions. |
257 | | // If the command requires authorizations, then CheckAuthNoSession() will |
258 | | // return an error. |
259 | 626 | result = CheckAuthNoSession(commandCode, handleNum, handles, |
260 | 626 | parmBufferStart, parmBufferSize); |
261 | 626 | if(result != TPM_RC_SUCCESS) |
262 | 0 | goto Cleanup; |
263 | 626 | } |
264 | | // CommandDispatcher returns a response handle buffer and a response parameter |
265 | | // buffer if it succeeds. It will also set the parameterSize field in the |
266 | | // buffer if the tag is TPM_RC_SESSIONS. |
267 | 830 | result = CommandDispatcher(tag, |
268 | 830 | commandCode, |
269 | 830 | (INT32 *) &parmBufferSize, |
270 | 830 | parmBufferStart, |
271 | 830 | handles, |
272 | 830 | &resHandleSize, |
273 | 830 | &resParmSize); |
274 | 830 | if(result != TPM_RC_SUCCESS) |
275 | 279 | goto Cleanup; |
276 | | // Build the session area at the end of the parameter area. |
277 | 551 | BuildResponseSession(tag, |
278 | 551 | commandCode, |
279 | 551 | resHandleSize, |
280 | 551 | resParmSize, |
281 | 551 | &resAuthSize); |
282 | 888 | Cleanup: |
283 | | // This implementation loads an "evict" object to a transient object slot in |
284 | | // RAM whenever an "evict" object handle is used in a command so that the |
285 | | // access to any object is the same. These temporary objects need to be |
286 | | // cleared from RAM whether the command succeeds or fails. |
287 | 888 | ObjectCleanupEvict(); |
288 | 888 | #ifndef EMBEDDED_MODE |
289 | 888 | Fail: |
290 | 888 | #endif // EMBEDDED_MODE ^^^ not defined |
291 | | // The response will contain at least a response header. |
292 | 888 | *responseSize = sizeof(TPM_ST) + sizeof(UINT32) + sizeof(TPM_RC); |
293 | | // If the command completed successfully, then build the rest of the response. |
294 | 888 | if(result == TPM_RC_SUCCESS) |
295 | 551 | { |
296 | | // Outgoing tag will be the same as the incoming tag. |
297 | 551 | resTag = tag; |
298 | | // The overall response will include the handles, parameters, |
299 | | // and authorizations. |
300 | 551 | *responseSize += resHandleSize + resParmSize + resAuthSize; |
301 | | // Adding parameter size field. |
302 | 551 | if(tag == TPM_ST_SESSIONS) |
303 | 101 | *responseSize += sizeof(UINT32); |
304 | 551 | if( g_clearOrderly == TRUE |
305 | 551 | && gp.orderlyState != SHUTDOWN_NONE) |
306 | 0 | { |
307 | 0 | gp.orderlyState = SHUTDOWN_NONE; |
308 | 0 | NvWriteReserved(NV_ORDERLY, &gp.orderlyState); |
309 | 0 | g_updateNV = TRUE; |
310 | 0 | } |
311 | 551 | } |
312 | 337 | else |
313 | 337 | { |
314 | | // The command failed. |
315 | | // If this was a failure due to a bad command tag, then need to return |
316 | | // a TPM 1.2 compatible response |
317 | 337 | if(result == TPM_RC_BAD_TAG) |
318 | 5 | resTag = TPM_ST_RSP_COMMAND; |
319 | 332 | else |
320 | | // return 2.0 compatible response |
321 | 332 | resTag = TPM_ST_NO_SESSIONS; |
322 | 337 | } |
323 | | // Try to commit all the writes to NV if any NV write happened during this |
324 | | // command execution. This check should be made for both succeeded and failed |
325 | | // commands, because a failed one may trigger a NV write in DA logic as well. |
326 | | // This is the only place in the command execution path that may call the NV |
327 | | // commit. If the NV commit fails, the TPM should be put in failure mode. |
328 | 888 | if(g_updateNV && !g_inFailureMode) |
329 | 446 | { |
330 | 446 | g_updateNV = FALSE; |
331 | 446 | if(!NvCommit()) { |
332 | 0 | FAIL(FATAL_ERROR_INTERNAL); |
333 | | #ifdef EMBEDDED_MODE |
334 | | // Make sure we pass errors along |
335 | | result = TPM_RC_FAILURE; |
336 | | resTag = TPM_ST_NO_SESSIONS; |
337 | | #endif |
338 | 0 | } |
339 | 446 | } |
340 | | // Marshal the response header. |
341 | 888 | buffer = MemoryGetResponseBuffer(commandCode); |
342 | 888 | bufferSize = 10; |
343 | 888 | TPM_ST_Marshal(&resTag, &buffer, &bufferSize); |
344 | 888 | UINT32_Marshal((UINT32 *)responseSize, &buffer, &bufferSize); |
345 | 888 | pAssert(*responseSize <= MAX_RESPONSE_SIZE); |
346 | 888 | TPM_RC_Marshal(&result, &buffer, &bufferSize); |
347 | 888 | *response = MemoryGetResponseBuffer(commandCode); |
348 | | // Clear unused bit in response buffer. |
349 | 888 | MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize); |
350 | 888 | return; |
351 | 888 | } |