Home | History | Annotate | Download | only in tpm2
      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 {
     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