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