/* Microsoft Reference Implementation for TPM 2.0 * * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and * contributor rights, including patent rights, and no such rights are granted * under this license. * * Copyright (c) Microsoft Corporation * * All rights reserved. * * BSD License * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //* Includes and Typedefs #include "Tpm.h" #include "Marshal.h" #if TABLE_DRIVEN_DISPATCH typedef TPM_RC(NoFlagFunction)(void *target, BYTE **buffer, INT32 *size); typedef TPM_RC(FlagFunction)(void *target, BYTE **buffer, INT32 *size, BOOL flag); typedef FlagFunction *UNMARSHAL_t; typedef INT16(MarshalFunction)(void *source, BYTE **buffer, INT32 *size); typedef MarshalFunction *MARSHAL_t; typedef TPM_RC(COMMAND_NO_ARGS)(void); typedef TPM_RC(COMMAND_IN_ARG)(void *in); typedef TPM_RC(COMMAND_OUT_ARG)(void *out); typedef TPM_RC(COMMAND_INOUT_ARG)(void *in, void *out); typedef union COMMAND_t { COMMAND_NO_ARGS *noArgs; COMMAND_IN_ARG *inArg; COMMAND_OUT_ARG *outArg; COMMAND_INOUT_ARG *inOutArg; } COMMAND_t; // This structure is used by ParseHandleBuffer() and CommandDispatcher(). The // parameters in this structure are unique for each command. The parameters are: // command holds the address of the command processing function that is called // by Command Dispatcher // inSize This is the size of the command-dependent input structure. The // input structure holds the unmarshaled handles and command // parameters. If the command takes no arguments (handles or // parameters) then inSize will have a value of 0. // outSize This is the size of the command-dependent output structure. The // output structure holds the results of the command in an unmarshaled // form. When command processing is completed, these values are // marshaled into the output buffer. It is always the case that the // unmarshaled version of an output structure is larger then the // marshaled version. This is because the marshaled version contains // the exact same number of significant bytes but with padding removed. // typesOffsets This parameter points to the list of data types that are to be // marshaled or unmarshaled. The list of types follows the 'offsets' // array. The offsets array is variable sized so the typesOffset filed // is necessary for the handle and command processing to be able to // find the types that are being handled. The 'offsets' array may be // empty. The 'types' structure is described below. // offsets This is an array of offsets of each of the parameters in the // command or response. When processing the command parameters (not // handles) the list contains the offset of the next parameter. For // example, if the first command parameter has a size of 4 and there is // a second command parameter, then the offset would be 4, indicating // that the second parameter starts at 4. If the second parameter has // a size of 8, and there is a third parameter, then the second entry // in offsets is 12 (4 for the first parameter and 8 for the second). // An offset value of 0 in the list indicates the start of the response // parameter list. When CommandDispatcher hits this value, it will stop // unmarshaling the parameters and call 'command'. If a command has no // response parameters and only one command parameter, then offsets can // be an empty list. typedef struct COMMAND_DESCRIPTOR_t { COMMAND_t command; // Address of the command UINT16 inSize; // Maximum size of the input structure UINT16 outSize; // Maximum size of the output structure UINT16 typesOffset; // address of the types field UINT16 offsets[1]; } COMMAND_DESCRIPTOR_t; // The 'types' list is an encoded byte array. The byte value has two parts. The most // significant bit is used when a parameter takes a flag and indicates if the flag // should be SET or not. The remaining 7 bits are an index into an array of // addresses of marshaling and unmarshaling functions. // The array of functions is divided into 6 sections with a value assigned // to denote the start of that section (and the end of the previous section). The // defined offset values for each section are: // 0 unmarshaling for handles that do not take flags // HANDLE_FIRST_FLAG_TYPE unmarshaling for handles that take flags // PARAMETER_FIRST_TYPE unmarshaling for parameters that do not take flags // PARAMETER_FIRST_FLAG_TYPE unmarshaling for parameters that take flags // PARAMETER_LAST_TYPE + 1 marshaling for handles // RESPONSE_PARAMETER_FIRST_TYPE marshaling for parameters // RESPONSE_PARAMETER_LAST_TYPE is the last value in the list of marshaling and // unmarshaling functions. // // The types list is constructed with a byte of 0xff at the end of the command // parameters and with an 0xff at the end of the response parameters. #if COMPRESSED_LISTS # define PAD_LIST 0 #else # define PAD_LIST 1 #endif #define _COMMAND_TABLE_DISPATCH_ #include "CommandDispatchData.h" #define TEST_COMMAND TPM_CC_Startup #define NEW_CC #else #include "Commands.h" #endif //* Marshal/Unmarshal Functions //** ParseHandleBuffer() // This is the table-driven version of the handle buffer unmarshaling code TPM_RC ParseHandleBuffer( COMMAND *command ) { TPM_RC result; #if TABLE_DRIVEN_DISPATCH COMMAND_DESCRIPTOR_t *desc; BYTE *types; BYTE type; BYTE dType; // Make sure that nothing strange has happened pAssert(command->index < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t *)); // Get the address of the descriptor for this command desc = s_CommandDataArray[command->index]; pAssert(desc != NULL); // Get the associated list of unmarshaling data types. types = &((BYTE *)desc)[desc->typesOffset]; // if(s_ccAttr[commandIndex].commandIndex == TEST_COMMAND) // commandIndex = commandIndex; // No handles yet command->handleNum = 0; // Get the first type value for(type = *types++; // check each byte to make sure that we have not hit the start // of the parameters (dType = (type & 0x7F)) < PARAMETER_FIRST_TYPE; // get the next type type = *types++) { #if TABLE_DRIVEN_MARSHAL marshalIndex_t index; index = unmarshalArray[dType] | ((type & 0x80) ? NULL_FLAG : 0); result = Unmarshal(index, &(command->handles[command->handleNum]), &command->parameterBuffer, &command->parameterSize); #else // See if unmarshaling of this handle type requires a flag if(dType < HANDLE_FIRST_FLAG_TYPE) { // Look up the function to do the unmarshaling NoFlagFunction *f = (NoFlagFunction *)unmarshalArray[dType]; // call it result = f(&(command->handles[command->handleNum]), &command->parameterBuffer, &command->parameterSize); } else { // Look up the function FlagFunction *f = unmarshalArray[dType]; // Call it setting the flag to the appropriate value result = f(&(command->handles[command->handleNum]), &command->parameterBuffer, &command->parameterSize, (type & 0x80) != 0); } #endif // Got a handle // We do this first so that the match for the handle offset of the // response code works correctly. command->handleNum += 1; if(result != TPM_RC_SUCCESS) // if the unmarshaling failed, return the response code with the // handle indication set return result + TPM_RC_H + (command->handleNum * TPM_RC_1); } #else BYTE **handleBufferStart = &command->parameterBuffer; INT32 *bufferRemainingSize = &command->parameterSize; TPM_HANDLE *handles = &command->handles[0]; UINT32 *handleCount = &command->handleNum; *handleCount = 0; switch(command->code) { #include "HandleProcess.h" #undef handles default: FAIL(FATAL_ERROR_INTERNAL); break; } #endif return TPM_RC_SUCCESS; } //** CommandDispatcher() // Function to unmarshal the command parameters, call the selected action code, and // marshal the response parameters. TPM_RC CommandDispatcher( COMMAND *command ) { #if !TABLE_DRIVEN_DISPATCH TPM_RC result; BYTE **paramBuffer = &command->parameterBuffer; INT32 *paramBufferSize = &command->parameterSize; BYTE **responseBuffer = &command->responseBuffer; INT32 *respParmSize = &command->parameterSize; INT32 rSize; TPM_HANDLE *handles = &command->handles[0]; // command->handleNum = 0; // The command-specific code knows how // many handles there are. This is for // cataloging the number of response // handles MemoryIoBufferAllocationReset(); // Initialize so that allocation will // work properly switch(GetCommandCode(command->index)) { #include "CommandDispatcher.h" default: FAIL(FATAL_ERROR_INTERNAL); break; } Exit: MemoryIoBufferZero(); return result; #else COMMAND_DESCRIPTOR_t *desc; BYTE *types; BYTE type; UINT16 *offsets; UINT16 offset = 0; UINT32 maxInSize; BYTE *commandIn; INT32 maxOutSize; BYTE *commandOut; COMMAND_t cmd; TPM_HANDLE *handles; UINT32 hasInParameters = 0; BOOL hasOutParameters = FALSE; UINT32 pNum = 0; BYTE dType; // dispatch type TPM_RC result; // // Get the address of the descriptor for this command pAssert(command->index < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t *)); desc = s_CommandDataArray[command->index]; // Get the list of parameter types for this command pAssert(desc != NULL); types = &((BYTE *)desc)[desc->typesOffset]; // Get a pointer to the list of parameter offsets offsets = &desc->offsets[0]; // pointer to handles handles = command->handles; // Get the size required to hold all the unmarshaled parameters for this command maxInSize = desc->inSize; // and the size of the output parameter structure returned by this command maxOutSize = desc->outSize; MemoryIoBufferAllocationReset(); // Get a buffer for the input parameters commandIn = MemoryGetInBuffer(maxInSize); // And the output parameters commandOut = (BYTE *)MemoryGetOutBuffer((UINT32)maxOutSize); // Get the address of the action code dispatch cmd = desc->command; // Copy any handles into the input buffer for(type = *types++; (type & 0x7F) < PARAMETER_FIRST_TYPE; type = *types++) { // 'offset' was initialized to zero so the first unmarshaling will always // be to the start of the data structure *(TPM_HANDLE *)&(commandIn[offset]) = *handles++; // This check is used so that we don't have to add an additional offset // value to the offsets list to correspond to the stop value in the // command parameter list. if(*types != 0xFF) offset = *offsets++; // maxInSize -= sizeof(TPM_HANDLE); hasInParameters++; } // Exit loop with type containing the last value read from types // maxInSize has the amount of space remaining in the command action input // buffer. Make sure that we don't have more data to unmarshal than is going to // fit. // type contains the last value read from types so it is not necessary to // reload it, which is good because *types now points to the next value for(; (dType = (type & 0x7F)) <= PARAMETER_LAST_TYPE; type = *types++) { pNum++; #if TABLE_DRIVEN_MARSHAL { marshalIndex_t index = unmarshalArray[dType]; index |= (type & 0x80) ? NULL_FLAG : 0; result = Unmarshal(index, &commandIn[offset], &command->parameterBuffer, &command->parameterSize); } #else if(dType < PARAMETER_FIRST_FLAG_TYPE) { NoFlagFunction *f = (NoFlagFunction *)unmarshalArray[dType]; result = f(&commandIn[offset], &command->parameterBuffer, &command->parameterSize); } else { FlagFunction *f = unmarshalArray[dType]; result = f(&commandIn[offset], &command->parameterBuffer, &command->parameterSize, (type & 0x80) != 0); } #endif if(result != TPM_RC_SUCCESS) { result += TPM_RC_P + (TPM_RC_1 * pNum); goto Exit; } // This check is used so that we don't have to add an additional offset // value to the offsets list to correspond to the stop value in the // command parameter list. if(*types != 0xFF) offset = *offsets++; hasInParameters++; } // Should have used all the bytes in the input if(command->parameterSize != 0) { result = TPM_RC_SIZE; goto Exit; } // The command parameter unmarshaling stopped when it hit a value that was out // of range for unmarshaling values and left *types pointing to the first // marshaling type. If that type happens to be the STOP value, then there // are no response parameters. So, set the flag to indicate if there are // output parameters. hasOutParameters = *types != 0xFF; // There are four cases for calling, with and without input parameters and with // and without output parameters. if(hasInParameters > 0) { if(hasOutParameters) result = cmd.inOutArg(commandIn, commandOut); else result = cmd.inArg(commandIn); } else { if(hasOutParameters) result = cmd.outArg(commandOut); else result = cmd.noArgs(); } if(result != TPM_RC_SUCCESS) goto Exit; // Offset in the marshaled output structure offset = 0; // Process the return handles, if any command->handleNum = 0; // Could make this a loop to process output handles but there is only ever // one handle in the outputs (for now). type = *types++; if((dType = (type & 0x7F)) < RESPONSE_PARAMETER_FIRST_TYPE) { // The out->handle value was referenced as TPM_HANDLE in the // action code so it has to be properly aligned. command->handles[command->handleNum++] = *((TPM_HANDLE *)&(commandOut[offset])); maxOutSize -= sizeof(UINT32); type = *types++; offset = *offsets++; } // Use the size of the command action output buffer as the maximum for the // number of bytes that can get marshaled. Since the marshaling code has // no pointers to data, all of the data being returned has to be in the // command action output buffer. If we try to marshal more bytes than // could fit into the output buffer, we need to fail. for(;(dType = (type & 0x7F)) <= RESPONSE_PARAMETER_LAST_TYPE && !g_inFailureMode; type = *types++) { #if TABLE_DRIVEN_MARSHAL marshalIndex_t index = marshalArray[dType]; command->parameterSize += Marshal(index, &commandOut[offset], &command->responseBuffer, &maxOutSize); #else const MARSHAL_t f = marshalArray[dType]; command->parameterSize += f(&commandOut[offset], &command->responseBuffer, &maxOutSize); #endif offset = *offsets++; } result = (maxOutSize < 0) ? TPM_RC_FAILURE : TPM_RC_SUCCESS; Exit: MemoryIoBufferZero(); return result; #endif }