• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ExecuteCommand(unsigned int requestSize,unsigned char * request,unsigned int * responseSize,unsigned char ** response)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 {
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
79    INT32                      bufferSize;          // size of buffer being used for
80                                                    // marshaling or unmarshaling
81    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    }
105 #ifndef EMBEDDED_MODE
106    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    }
113 #endif  // EMBEDDED_MODE   ^^^ not defined
114    // 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);
282 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    ObjectCleanupEvict();
288 #ifndef EMBEDDED_MODE
289 Fail:
290 #endif  // EMBEDDED_MODE  ^^^ not defined
291    // 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;
331          if(!NvCommit()) {
332               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 	 }
339      }
340      // Marshal the response header.
341      buffer = MemoryGetResponseBuffer(commandCode);
342      bufferSize = 10;
343      TPM_ST_Marshal(&resTag, &buffer, &bufferSize);
344      UINT32_Marshal((UINT32 *)responseSize, &buffer, &bufferSize);
345      pAssert(*responseSize <= MAX_RESPONSE_SIZE);
346      TPM_RC_Marshal(&result, &buffer, &bufferSize);
347      *response = MemoryGetResponseBuffer(commandCode);
348      // Clear unused bit in response buffer.
349      MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize);
350      return;
351 }
352