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 } 334 // Marshal the response header. 335 buffer = MemoryGetResponseBuffer(commandCode); 336 bufferSize = 10; 337 TPM_ST_Marshal(&resTag, &buffer, &bufferSize); 338 UINT32_Marshal((UINT32 *)responseSize, &buffer, &bufferSize); 339 pAssert(*responseSize <= MAX_RESPONSE_SIZE); 340 TPM_RC_Marshal(&result, &buffer, &bufferSize); 341 *response = MemoryGetResponseBuffer(commandCode); 342 // Clear unused bit in response buffer. 343 MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize); 344 return; 345 } 346