blob: d823778f9c68233a6983de3e18feda712a768532 [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"
Jocelyn Bohr764a7d62015-07-30 12:57:09 -07009#include "ExecCommand_fp.h"
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -070010#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//
41LIB_EXPORT void
42ExecuteCommand(
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{
49 // Command local variables
50 TPM_ST tag; // these first three variables are the
51 UINT32 commandSize;
52 TPM_CC commandCode = 0;
53 BYTE *parmBufferStart; // pointer to the first byte of an
54 // optional parameter buffer
55 UINT32 parmBufferSize = 0;// number of bytes in parameter area
56 UINT32 handleNum = 0; // number of handles unmarshaled into
57 // the handles array
58 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 TPM_RC result; // return code for the command
64 TPM_ST resTag; // tag for the response
65 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 UINT32 resParmSize = 0; // the size of the response parameters
70 // These values go in the rpHash.
71 UINT32 resAuthSize = 0; // size of authorization area in the
72//
73 // response
74 INT32 size; // remaining data to be unmarshaled
75 // or remaining space in the marshaling
76 // buffer
77 BYTE *buffer; // pointer into the buffer being used
78 // for marshaling or unmarshaling
Jocelyn Bohr32be4042015-07-29 15:14:01 -070079 INT32 bufferSize; // size of buffer being used for
80 // marshaling or unmarshaling
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -070081 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 g_updateNV = FALSE;
93 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 if(g_inFailureMode)
100 {
101 // Do failure mode processing
102 TpmFailureMode (requestSize, request, responseSize, response);
103 return;
104 }
Vadim Bendebury7878aef2015-08-12 12:57:26 -0700105#ifndef EMBEDDED_MODE
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700106 if(setjmp(g_jumpBuffer) != 0)
107 {
108 // Get here if we got a longjump putting us into failure mode
109 g_inFailureMode = TRUE;
110 result = TPM_RC_FAILURE;
111 goto Fail;
112 }
Vadim Bendebury7878aef2015-08-12 12:57:26 -0700113#endif // EMBEDDED_MODE ^^^ not defined
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700114 // Assume that everything is going to work.
115 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 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 TimeUpdateToCurrent();
129 // Any command through this function will unceremoniously end the
130 // _TPM_Hash_Data/_TPM_Hash_End sequence.
131 if(g_DRTMHandle != TPM_RH_UNASSIGNED)
132 ObjectTerminateEvent();
133 // Get command buffer size and command buffer.
134 size = requestSize;
135 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 result = TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &buffer, &size);
140 if(result != TPM_RC_SUCCESS)
141 goto Cleanup;
142 // Unmarshal the commandSize indicator.
143 result = UINT32_Unmarshal(&commandSize, &buffer, &size);
144 if(result != TPM_RC_SUCCESS)
145 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 if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
154 {
155 result = TPM_RC_COMMAND_SIZE;
156 goto Cleanup;
157 }
158 // Unmarshal the command code.
159 result = TPM_CC_Unmarshal(&commandCode, &buffer, &size);
160 if(result != TPM_RC_SUCCESS)
161 goto Cleanup;
162 // Check to see if the command is implemented.
163 if(!CommandIsImplemented(commandCode))
164 {
165 result = TPM_RC_COMMAND_CODE;
166 goto Cleanup;
167 }
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 if(( !TPMIsStarted() && commandCode != TPM_CC_Startup)
182 || (TPMIsStarted() && commandCode == TPM_CC_Startup))
183 {
184 result = TPM_RC_INITIALIZE;
185 goto Cleanup;
186 }
187 // Start regular command process.
188 // Parse Handle buffer.
189 result = ParseHandleBuffer(commandCode, &buffer, &size, handles, &handleNum);
190 if(result != TPM_RC_SUCCESS)
191 goto Cleanup;
192 // Number of handles retrieved from handle area should be less than
193 // MAX_HANDLE_NUM.
194 pAssert(handleNum <= MAX_HANDLE_NUM);
195 // All handles in the handle area are required to reference TPM-resident
196 // entities.
197 for(i = 0; i < handleNum; i++)
198 {
199 result = EntityGetLoadStatus(&handles[i], commandCode);
200 if(result != TPM_RC_SUCCESS)
201 {
202 if(result == TPM_RC_REFERENCE_H0)
203 result = result + i;
204 else
205 result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]);
206 goto Cleanup;
207 }
208 }
209 // Authorization session handling for the command.
210 if(tag == TPM_ST_SESSIONS)
211 {
212 BYTE *sessionBufferStart;// address of the session area first byte
213 // in the input buffer
214 UINT32 authorizationSize; // number of bytes in the session area
215 // Find out session buffer size.
216 result = UINT32_Unmarshal(&authorizationSize, &buffer, &size);
217 if(result != TPM_RC_SUCCESS)
218 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 if( authorizationSize < 9
225 || authorizationSize > (UINT32) size)
226 {
227 result = TPM_RC_SIZE;
228 goto Cleanup;
229 }
230 // The sessions, if any, follows authorizationSize.
231 sessionBufferStart = buffer;
232 // The parameters follow the session area.
233 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 parmBufferSize = size - authorizationSize;
239 // The actions of ParseSessionBuffer() are described in the introduction.
240 result = ParseSessionBuffer(commandCode,
241 handleNum,
242 handles,
243 sessionBufferStart,
244 authorizationSize,
245 parmBufferStart,
246 parmBufferSize);
247 if(result != TPM_RC_SUCCESS)
248 goto Cleanup;
249 }
250 else
251 {
252 // Whatever remains in the input buffer is used for the parameters of the
253 // command.
254 parmBufferStart = buffer;
255 parmBufferSize = size;
256 // The command has no authorization sessions.
257 // If the command requires authorizations, then CheckAuthNoSession() will
258 // return an error.
259 result = CheckAuthNoSession(commandCode, handleNum, handles,
260 parmBufferStart, parmBufferSize);
261 if(result != TPM_RC_SUCCESS)
262 goto Cleanup;
263 }
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 result = CommandDispatcher(tag,
268 commandCode,
269 (INT32 *) &parmBufferSize,
270 parmBufferStart,
271 handles,
272 &resHandleSize,
273 &resParmSize);
274 if(result != TPM_RC_SUCCESS)
275 goto Cleanup;
276 // Build the session area at the end of the parameter area.
277 BuildResponseSession(tag,
278 commandCode,
279 resHandleSize,
280 resParmSize,
281 &resAuthSize);
282Cleanup:
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 ObjectCleanupEvict();
Vadim Bendebury7878aef2015-08-12 12:57:26 -0700288#ifndef EMBEDDED_MODE
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700289Fail:
Vadim Bendebury7878aef2015-08-12 12:57:26 -0700290#endif // EMBEDDED_MODE ^^^ not defined
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700291 // The response will contain at least a response header.
292 *responseSize = sizeof(TPM_ST) + sizeof(UINT32) + sizeof(TPM_RC);
293 // If the command completed successfully, then build the rest of the response.
294 if(result == TPM_RC_SUCCESS)
295 {
296 // Outgoing tag will be the same as the incoming tag.
297 resTag = tag;
298 // The overall response will include the handles, parameters,
299 // and authorizations.
300 *responseSize += resHandleSize + resParmSize + resAuthSize;
301 // Adding parameter size field.
302 if(tag == TPM_ST_SESSIONS)
303 *responseSize += sizeof(UINT32);
304 if( g_clearOrderly == TRUE
305 && gp.orderlyState != SHUTDOWN_NONE)
306 {
307 gp.orderlyState = SHUTDOWN_NONE;
308 NvWriteReserved(NV_ORDERLY, &gp.orderlyState);
309 g_updateNV = TRUE;
310 }
311 }
312 else
313 {
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 if(result == TPM_RC_BAD_TAG)
318 resTag = TPM_ST_RSP_COMMAND;
319 else
320 // return 2.0 compatible response
321 resTag = TPM_ST_NO_SESSIONS;
322 }
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 if(g_updateNV && !g_inFailureMode)
329 {
330 g_updateNV = FALSE;
Bill Richardson70ac07b2016-09-28 11:17:18 -0700331 if(!NvCommit()) {
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700332 FAIL(FATAL_ERROR_INTERNAL);
Bill Richardson70ac07b2016-09-28 11:17:18 -0700333#ifdef EMBEDDED_MODE
334 // Make sure we pass errors along
335 result = TPM_RC_FAILURE;
336 resTag = TPM_ST_NO_SESSIONS;
337#endif
338 }
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700339 }
340 // Marshal the response header.
341 buffer = MemoryGetResponseBuffer(commandCode);
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700342 bufferSize = 10;
343 TPM_ST_Marshal(&resTag, &buffer, &bufferSize);
344 UINT32_Marshal((UINT32 *)responseSize, &buffer, &bufferSize);
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700345 pAssert(*responseSize <= MAX_RESPONSE_SIZE);
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700346 TPM_RC_Marshal(&result, &buffer, &bufferSize);
Vadim Bendeburyf5cc58b2015-05-31 14:09:19 -0700347 *response = MemoryGetResponseBuffer(commandCode);
348 // Clear unused bit in response buffer.
349 MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize);
350 return;
351}