/* 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. | |
*/ | |
//** Introduction | |
// This file contains the functions for testing various command properties. | |
//** Includes and Defines | |
#include "Tpm.h" | |
#include "CommandCodeAttributes_fp.h" | |
// Set the default value for CC_VEND if not already set | |
#ifndef CC_VEND | |
#define CC_VEND (TPM_CC)(0x20000000) | |
#endif | |
typedef UINT16 ATTRIBUTE_TYPE; | |
// The following file is produced from the command tables in part 3 of the | |
// specification. It defines the attributes for each of the commands. | |
// NOTE: This file is currently produced by an automated process. Files | |
// produced from Part 2 or Part 3 tables through automated processes are not | |
// included in the specification so that their is no ambiguity about the | |
// table containing the information being the normative definition. | |
#define _COMMAND_CODE_ATTRIBUTES_ | |
#include "CommandAttributeData.h" | |
//** Command Attribute Functions | |
//*** NextImplementedIndex() | |
// This function is used when the lists are not compressed. In a compressed list, | |
// only the implemented commands are present. So, a search might find a value | |
// but that value may not be implemented. This function checks to see if the input | |
// commandIndex points to an implemented command and, if not, it searches upwards | |
// until it finds one. When the list is compressed, this function gets defined | |
// as a no-op. | |
// Return Type: COMMAND_INDEX | |
// UNIMPLEMENTED_COMMAND_INDEX command is not implemented | |
// other index of the command | |
#if !COMPRESSED_LISTS | |
static COMMAND_INDEX | |
NextImplementedIndex( | |
COMMAND_INDEX commandIndex | |
) | |
{ | |
for(;commandIndex < COMMAND_COUNT; commandIndex++) | |
{ | |
if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED) | |
return commandIndex; | |
} | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
} | |
#else | |
#define NextImplementedIndex(x) (x) | |
#endif | |
//*** GetClosestCommandIndex() | |
// This function returns the command index for the command with a value that is | |
// equal to or greater than the input value | |
// Return Type: COMMAND_INDEX | |
// UNIMPLEMENTED_COMMAND_INDEX command is not implemented | |
// other index of a command | |
COMMAND_INDEX | |
GetClosestCommandIndex( | |
TPM_CC commandCode // IN: the command code to start at | |
) | |
{ | |
BOOL vendor = (commandCode & CC_VEND) != 0; | |
COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode; | |
// The commandCode is a UINT32 and the search index is UINT16. We are going to | |
// search for a match but need to make sure that the commandCode value is not | |
// out of range. To do this, need to clear the vendor bit of the commandCode | |
// (if set) and compare the result to the 16-bit searchIndex value. If it is | |
// out of range, indicate that the command is not implemented | |
if((commandCode & ~CC_VEND) != searchIndex) | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
// if there is at least one vendor command, the last entry in the array will | |
// have the v bit set. If the input commandCode is larger than the last | |
// vendor-command, then it is out of range. | |
if(vendor) | |
{ | |
#if VENDOR_COMMAND_ARRAY_SIZE > 0 | |
COMMAND_INDEX commandIndex; | |
COMMAND_INDEX min; | |
COMMAND_INDEX max; | |
int diff; | |
#if LIBRARY_COMMAND_ARRAY_SIZE == COMMAND_COUNT | |
#error "Constants are not consistent." | |
#endif | |
// Check to see if the value is equal to or below the minimum | |
// entry. | |
// Note: Put this check first so that the typical case of only one vendor- | |
// specific command doesn't waste any more time. | |
if(GET_ATTRIBUTE(s_ccAttr[LIBRARY_COMMAND_ARRAY_SIZE], TPMA_CC, | |
commandIndex) >= searchIndex) | |
{ | |
// the vendor array is always assumed to be packed so there is | |
// no need to check to see if the command is implemented | |
return LIBRARY_COMMAND_ARRAY_SIZE; | |
} | |
// See if this is out of range on the top | |
if(GET_ATTRIBUTE(s_ccAttr[COMMAND_COUNT - 1], TPMA_CC, commandIndex) | |
< searchIndex) | |
{ | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
} | |
commandIndex = UNIMPLEMENTED_COMMAND_INDEX; // Needs initialization to keep | |
// compiler happy | |
min = LIBRARY_COMMAND_ARRAY_SIZE; // first vendor command | |
max = COMMAND_COUNT - 1; // last vendor command | |
diff = 1; // needs initialization to keep | |
// compiler happy | |
while(min <= max) | |
{ | |
commandIndex = (min + max + 1) / 2; | |
diff = GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex) | |
- searchIndex; | |
if(diff == 0) | |
return commandIndex; | |
if(diff > 0) | |
max = commandIndex - 1; | |
else | |
min = commandIndex + 1; | |
} | |
// didn't find and exact match. commandIndex will be pointing at the last | |
// item tested. If 'diff' is positive, then the last item tested was | |
// larger index of the command code so it is the smallest value | |
// larger than the requested value. | |
if(diff > 0) | |
return commandIndex; | |
// if 'diff' is negative, then the value tested was smaller than | |
// the commandCode index and the next higher value is the correct one. | |
// Note: this will necessarily be in range because of the earlier check | |
// that the index was within range. | |
return commandIndex + 1; | |
#else | |
// If there are no vendor commands so anything with the vendor bit set is out | |
// of range | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
#endif | |
} | |
// Get here if the V-Bit was not set in 'commandCode' | |
if(GET_ATTRIBUTE(s_ccAttr[LIBRARY_COMMAND_ARRAY_SIZE - 1], TPMA_CC, | |
commandIndex) < searchIndex) | |
{ | |
// requested index is out of the range to the top | |
#if VENDOR_COMMAND_ARRAY_SIZE > 0 | |
// If there are vendor commands, then the first vendor command | |
// is the next value greater than the commandCode. | |
// NOTE: we got here if the starting index did not have the V bit but we | |
// reached the end of the array of library commands (non-vendor). Since | |
// there is at least one vendor command, and vendor commands are always | |
// in a compressed list that starts after the library list, the next | |
// index value contains a valid vendor command. | |
return LIBRARY_COMMAND_ARRAY_SIZE; | |
#else | |
// if there are no vendor commands, then this is out of range | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
#endif | |
} | |
// If the request is lower than any value in the array, then return | |
// the lowest value (needs to be an index for an implemented command | |
if(GET_ATTRIBUTE(s_ccAttr[0], TPMA_CC, commandIndex) >= searchIndex) | |
{ | |
return NextImplementedIndex(0); | |
} | |
else | |
{ | |
#if COMPRESSED_LISTS | |
COMMAND_INDEX commandIndex = UNIMPLEMENTED_COMMAND_INDEX; | |
COMMAND_INDEX min = 0; | |
COMMAND_INDEX max = LIBRARY_COMMAND_ARRAY_SIZE - 1; | |
int diff = 1; | |
#if LIBRARY_COMMAND_ARRAY_SIZE == 0 | |
#error "Something is terribly wrong" | |
#endif | |
// The s_ccAttr array contains an extra entry at the end (a zero value). | |
// Don't count this as an array entry. This means that max should start | |
// out pointing to the last valid entry in the array which is - 2 | |
pAssert(max == (sizeof(s_ccAttr) / sizeof(TPMA_CC) | |
- VENDOR_COMMAND_ARRAY_SIZE - 2)); | |
while(min <= max) | |
{ | |
commandIndex = (min + max + 1) / 2; | |
diff = GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, | |
commandIndex) - searchIndex; | |
if(diff == 0) | |
return commandIndex; | |
if(diff > 0) | |
max = commandIndex - 1; | |
else | |
min = commandIndex + 1; | |
} | |
// didn't find and exact match. commandIndex will be pointing at the | |
// last item tested. If diff is positive, then the last item tested was | |
// larger index of the command code so it is the smallest value | |
// larger than the requested value. | |
if(diff > 0) | |
return commandIndex; | |
// if diff is negative, then the value tested was smaller than | |
// the commandCode index and the next higher value is the correct one. | |
// Note: this will necessarily be in range because of the earlier check | |
// that the index was within range. | |
return commandIndex + 1; | |
#else | |
// The list is not compressed so offset into the array by the command | |
// code value of the first entry in the list. Then go find the first | |
// implemented command. | |
return NextImplementedIndex(searchIndex | |
- (COMMAND_INDEX)s_ccAttr[0].commandIndex); | |
#endif | |
} | |
} | |
//*** CommandCodeToComandIndex() | |
// This function returns the index in the various attributes arrays of the | |
// command. | |
// Return Type: COMMAND_INDEX | |
// UNIMPLEMENTED_COMMAND_INDEX command is not implemented | |
// other index of the command | |
COMMAND_INDEX | |
CommandCodeToCommandIndex( | |
TPM_CC commandCode // IN: the command code to look up | |
) | |
{ | |
// Extract the low 16-bits of the command code to get the starting search index | |
COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode; | |
BOOL vendor = (commandCode & CC_VEND) != 0; | |
COMMAND_INDEX commandIndex; | |
#if !COMPRESSED_LISTS | |
if(!vendor) | |
{ | |
commandIndex = searchIndex - (COMMAND_INDEX)s_ccAttr[0].commandIndex; | |
// Check for out of range or unimplemented. | |
// Note, since a COMMAND_INDEX is unsigned, if searchIndex is smaller than | |
// the lowest value of command, it will become a 'negative' number making | |
// it look like a large unsigned number, this will cause it to fail | |
// the unsigned check below. | |
if(commandIndex >= LIBRARY_COMMAND_ARRAY_SIZE | |
|| (s_commandAttributes[commandIndex] & IS_IMPLEMENTED) == 0) | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
return commandIndex; | |
} | |
#endif | |
// Need this code for any vendor code lookup or for compressed lists | |
commandIndex = GetClosestCommandIndex(commandCode); | |
// Look at the returned value from get closest. If it isn't the one that was | |
// requested, then the command is not implemented. | |
if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX) | |
{ | |
if((GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex) | |
!= searchIndex) | |
|| (IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) != vendor) | |
commandIndex = UNIMPLEMENTED_COMMAND_INDEX; | |
} | |
return commandIndex; | |
} | |
//*** GetNextCommandIndex() | |
// This function returns the index of the next implemented command. | |
// Return Type: COMMAND_INDEX | |
// UNIMPLEMENTED_COMMAND_INDEX no more implemented commands | |
// other the index of the next implemented command | |
COMMAND_INDEX | |
GetNextCommandIndex( | |
COMMAND_INDEX commandIndex // IN: the starting index | |
) | |
{ | |
while(++commandIndex < COMMAND_COUNT) | |
{ | |
#if !COMPRESSED_LISTS | |
if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED) | |
#endif | |
return commandIndex; | |
} | |
return UNIMPLEMENTED_COMMAND_INDEX; | |
} | |
//*** GetCommandCode() | |
// This function returns the commandCode associated with the command index | |
TPM_CC | |
GetCommandCode( | |
COMMAND_INDEX commandIndex // IN: the command index | |
) | |
{ | |
TPM_CC commandCode = GET_ATTRIBUTE(s_ccAttr[commandIndex], | |
TPMA_CC, commandIndex); | |
if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) | |
commandCode += CC_VEND; | |
return commandCode; | |
} | |
//*** CommandAuthRole() | |
// | |
// This function returns the authorization role required of a handle. | |
// | |
// Return Type: AUTH_ROLE | |
// AUTH_NONE no authorization is required | |
// AUTH_USER user role authorization is required | |
// AUTH_ADMIN admin role authorization is required | |
// AUTH_DUP duplication role authorization is required | |
AUTH_ROLE | |
CommandAuthRole( | |
COMMAND_INDEX commandIndex, // IN: command index | |
UINT32 handleIndex // IN: handle index (zero based) | |
) | |
{ | |
if(0 == handleIndex) | |
{ | |
// Any authorization role set? | |
COMMAND_ATTRIBUTES properties = s_commandAttributes[commandIndex]; | |
if(properties & HANDLE_1_USER) | |
return AUTH_USER; | |
if(properties & HANDLE_1_ADMIN) | |
return AUTH_ADMIN; | |
if(properties & HANDLE_1_DUP) | |
return AUTH_DUP; | |
} | |
else if(1 == handleIndex) | |
{ | |
if(s_commandAttributes[commandIndex] & HANDLE_2_USER) | |
return AUTH_USER; | |
} | |
return AUTH_NONE; | |
} | |
//*** EncryptSize() | |
// This function returns the size of the decrypt size field. This function returns | |
// 0 if encryption is not allowed | |
// Return Type: int | |
// 0 encryption not allowed | |
// 2 size field is two bytes | |
// 4 size field is four bytes | |
int | |
EncryptSize( | |
COMMAND_INDEX commandIndex // IN: command index | |
) | |
{ | |
return ((s_commandAttributes[commandIndex] & ENCRYPT_2) ? 2 : | |
(s_commandAttributes[commandIndex] & ENCRYPT_4) ? 4 : 0); | |
} | |
//*** DecryptSize() | |
// This function returns the size of the decrypt size field. This function returns | |
// 0 if decryption is not allowed | |
// Return Type: int | |
// 0 encryption not allowed | |
// 2 size field is two bytes | |
// 4 size field is four bytes | |
int | |
DecryptSize( | |
COMMAND_INDEX commandIndex // IN: command index | |
) | |
{ | |
return ((s_commandAttributes[commandIndex] & DECRYPT_2) ? 2 : | |
(s_commandAttributes[commandIndex] & DECRYPT_4) ? 4 : 0); | |
} | |
//*** IsSessionAllowed() | |
// | |
// This function indicates if the command is allowed to have sessions. | |
// | |
// This function must not be called if the command is not known to be implemented. | |
// | |
// Return Type: BOOL | |
// TRUE(1) session is allowed with this command | |
// FALSE(0) session is not allowed with this command | |
BOOL | |
IsSessionAllowed( | |
COMMAND_INDEX commandIndex // IN: the command to be checked | |
) | |
{ | |
return ((s_commandAttributes[commandIndex] & NO_SESSIONS) == 0); | |
} | |
//*** IsHandleInResponse() | |
// This function determines if a command has a handle in the response | |
BOOL | |
IsHandleInResponse( | |
COMMAND_INDEX commandIndex | |
) | |
{ | |
return ((s_commandAttributes[commandIndex] & R_HANDLE) != 0); | |
} | |
//*** IsWriteOperation() | |
// Checks to see if an operation will write to an NV Index and is subject to being | |
// blocked by read-lock | |
BOOL | |
IsWriteOperation( | |
COMMAND_INDEX commandIndex // IN: Command to check | |
) | |
{ | |
#ifdef WRITE_LOCK | |
return ((s_commandAttributes[commandIndex] & WRITE_LOCK) != 0); | |
#else | |
if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) | |
{ | |
switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex)) | |
{ | |
case TPM_CC_NV_Write: | |
#if CC_NV_Increment | |
case TPM_CC_NV_Increment: | |
#endif | |
#if CC_NV_SetBits | |
case TPM_CC_NV_SetBits: | |
#endif | |
#if CC_NV_Extend | |
case TPM_CC_NV_Extend: | |
#endif | |
#if CC_AC_Send | |
case TPM_CC_AC_Send: | |
#endif | |
// NV write lock counts as a write operation for authorization purposes. | |
// We check to see if the NV is write locked before we do the | |
// authorization. If it is locked, we fail the command early. | |
case TPM_CC_NV_WriteLock: | |
return TRUE; | |
default: | |
break; | |
} | |
} | |
return FALSE; | |
#endif | |
} | |
//*** IsReadOperation() | |
// Checks to see if an operation will write to an NV Index and is | |
// subject to being blocked by write-lock. | |
BOOL | |
IsReadOperation( | |
COMMAND_INDEX commandIndex // IN: Command to check | |
) | |
{ | |
#ifdef READ_LOCK | |
return ((s_commandAttributes[commandIndex] & READ_LOCK) != 0); | |
#else | |
if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) | |
{ | |
switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex)) | |
{ | |
case TPM_CC_NV_Read: | |
case TPM_CC_PolicyNV: | |
case TPM_CC_NV_Certify: | |
// NV read lock counts as a read operation for authorization purposes. | |
// We check to see if the NV is read locked before we do the | |
// authorization. If it is locked, we fail the command early. | |
case TPM_CC_NV_ReadLock: | |
return TRUE; | |
default: | |
break; | |
} | |
} | |
return FALSE; | |
#endif | |
} | |
//*** CommandCapGetCCList() | |
// This function returns a list of implemented commands and command attributes | |
// starting from the command in 'commandCode'. | |
// Return Type: TPMI_YES_NO | |
// YES more command attributes are available | |
// NO no more command attributes are available | |
TPMI_YES_NO | |
CommandCapGetCCList( | |
TPM_CC commandCode, // IN: start command code | |
UINT32 count, // IN: maximum count for number of entries in | |
// 'commandList' | |
TPML_CCA *commandList // OUT: list of TPMA_CC | |
) | |
{ | |
TPMI_YES_NO more = NO; | |
COMMAND_INDEX commandIndex; | |
// initialize output handle list count | |
commandList->count = 0; | |
for(commandIndex = GetClosestCommandIndex(commandCode); | |
commandIndex != UNIMPLEMENTED_COMMAND_INDEX; | |
commandIndex = GetNextCommandIndex(commandIndex)) | |
{ | |
#if !COMPRESSED_LISTS | |
// this check isn't needed for compressed lists. | |
if(!(s_commandAttributes[commandIndex] & IS_IMPLEMENTED)) | |
continue; | |
#endif | |
if(commandList->count < count) | |
{ | |
// If the list is not full, add the attributes for this command. | |
commandList->commandAttributes[commandList->count] | |
= s_ccAttr[commandIndex]; | |
commandList->count++; | |
} | |
else | |
{ | |
// If the list is full but there are more commands to report, | |
// indicate this and return. | |
more = YES; | |
break; | |
} | |
} | |
return more; | |
} | |
//*** IsVendorCommand() | |
// Function indicates if a command index references a vendor command. | |
// Return Type: BOOL | |
// TRUE(1) command is a vendor command | |
// FALSE(0) command is not a vendor command | |
BOOL | |
IsVendorCommand( | |
COMMAND_INDEX commandIndex // IN: command index to check | |
) | |
{ | |
return (IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)); | |
} |