/* 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 that support command audit. | |
//** Includes | |
#include "Tpm.h" | |
//** Functions | |
//*** CommandAuditPreInstall_Init() | |
// This function initializes the command audit list. This function simulates | |
// the behavior of manufacturing. A function is used instead of a structure | |
// definition because this is easier than figuring out the initialization value | |
// for a bit array. | |
// | |
// This function would not be implemented outside of a manufacturing or | |
// simulation environment. | |
void | |
CommandAuditPreInstall_Init( | |
void | |
) | |
{ | |
// Clear all the audit commands | |
MemorySet(gp.auditCommands, 0x00, sizeof(gp.auditCommands)); | |
// TPM_CC_SetCommandCodeAuditStatus always being audited | |
CommandAuditSet(TPM_CC_SetCommandCodeAuditStatus); | |
// Set initial command audit hash algorithm to be context integrity hash | |
// algorithm | |
gp.auditHashAlg = CONTEXT_INTEGRITY_HASH_ALG; | |
// Set up audit counter to be 0 | |
gp.auditCounter = 0; | |
// Write command audit persistent data to NV | |
NV_SYNC_PERSISTENT(auditCommands); | |
NV_SYNC_PERSISTENT(auditHashAlg); | |
NV_SYNC_PERSISTENT(auditCounter); | |
return; | |
} | |
//*** CommandAuditStartup() | |
// This function clears the command audit digest on a TPM Reset. | |
BOOL | |
CommandAuditStartup( | |
STARTUP_TYPE type // IN: start up type | |
) | |
{ | |
if((type != SU_RESTART) && (type != SU_RESUME)) | |
{ | |
// Reset the digest size to initialize the digest | |
gr.commandAuditDigest.t.size = 0; | |
} | |
return TRUE; | |
} | |
//*** CommandAuditSet() | |
// This function will SET the audit flag for a command. This function | |
// will not SET the audit flag for a command that is not implemented. This | |
// ensures that the audit status is not SET when TPM2_GetCapability() is | |
// used to read the list of audited commands. | |
// | |
// This function is only used by TPM2_SetCommandCodeAuditStatus(). | |
// | |
// The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the | |
// changes to be saved to NV after it is setting and clearing bits. | |
// Return Type: BOOL | |
// TRUE(1) command code audit status was changed | |
// FALSE(0) command code audit status was not changed | |
BOOL | |
CommandAuditSet( | |
TPM_CC commandCode // IN: command code | |
) | |
{ | |
COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode); | |
// Only SET a bit if the corresponding command is implemented | |
if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX) | |
{ | |
// Can't audit shutdown | |
if(commandCode != TPM_CC_Shutdown) | |
{ | |
if(!TEST_BIT(commandIndex, gp.auditCommands)) | |
{ | |
// Set bit | |
SET_BIT(commandIndex, gp.auditCommands); | |
return TRUE; | |
} | |
} | |
} | |
// No change | |
return FALSE; | |
} | |
//*** CommandAuditClear() | |
// This function will CLEAR the audit flag for a command. It will not CLEAR the | |
// audit flag for TPM_CC_SetCommandCodeAuditStatus(). | |
// | |
// This function is only used by TPM2_SetCommandCodeAuditStatus(). | |
// | |
// The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the | |
// changes to be saved to NV after it is setting and clearing bits. | |
// Return Type: BOOL | |
// TRUE(1) command code audit status was changed | |
// FALSE(0) command code audit status was not changed | |
BOOL | |
CommandAuditClear( | |
TPM_CC commandCode // IN: command code | |
) | |
{ | |
COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode); | |
// Do nothing if the command is not implemented | |
if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX) | |
{ | |
// The bit associated with TPM_CC_SetCommandCodeAuditStatus() cannot be | |
// cleared | |
if(commandCode != TPM_CC_SetCommandCodeAuditStatus) | |
{ | |
if(TEST_BIT(commandIndex, gp.auditCommands)) | |
{ | |
// Clear bit | |
CLEAR_BIT(commandIndex, gp.auditCommands); | |
return TRUE; | |
} | |
} | |
} | |
// No change | |
return FALSE; | |
} | |
//*** CommandAuditIsRequired() | |
// This function indicates if the audit flag is SET for a command. | |
// Return Type: BOOL | |
// TRUE(1) command is audited | |
// FALSE(0) command is not audited | |
BOOL | |
CommandAuditIsRequired( | |
COMMAND_INDEX commandIndex // IN: command index | |
) | |
{ | |
// Check the bit map. If the bit is SET, command audit is required | |
return(TEST_BIT(commandIndex, gp.auditCommands)); | |
} | |
//*** CommandAuditCapGetCCList() | |
// This function returns a list of commands that have their audit bit SET. | |
// | |
// The list starts at the input commandCode. | |
// Return Type: TPMI_YES_NO | |
// YES if there are more command code available | |
// NO all the available command code has been returned | |
TPMI_YES_NO | |
CommandAuditCapGetCCList( | |
TPM_CC commandCode, // IN: start command code | |
UINT32 count, // IN: count of returned TPM_CC | |
TPML_CC *commandList // OUT: list of TPM_CC | |
) | |
{ | |
TPMI_YES_NO more = NO; | |
COMMAND_INDEX commandIndex; | |
// Initialize output handle list | |
commandList->count = 0; | |
// The maximum count of command we may return is MAX_CAP_CC | |
if(count > MAX_CAP_CC) count = MAX_CAP_CC; | |
// Find the implemented command that has a command code that is the same or | |
// higher than the input | |
// Collect audit commands | |
for(commandIndex = GetClosestCommandIndex(commandCode); | |
commandIndex != UNIMPLEMENTED_COMMAND_INDEX; | |
commandIndex = GetNextCommandIndex(commandIndex)) | |
{ | |
if(CommandAuditIsRequired(commandIndex)) | |
{ | |
if(commandList->count < count) | |
{ | |
// If we have not filled up the return list, add this command | |
// code to its | |
TPM_CC cc = GET_ATTRIBUTE(s_ccAttr[commandIndex], | |
TPMA_CC, commandIndex); | |
if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) | |
cc += (1 << 29); | |
commandList->commandCodes[commandList->count] = cc; | |
commandList->count++; | |
} | |
else | |
{ | |
// If the return list is full but we still have command | |
// available, report this and stop iterating | |
more = YES; | |
break; | |
} | |
} | |
} | |
return more; | |
} | |
//*** CommandAuditGetDigest | |
// This command is used to create a digest of the commands being audited. The | |
// commands are processed in ascending numeric order with a list of TPM_CC being | |
// added to a hash. This operates as if all the audited command codes were | |
// concatenated and then hashed. | |
void | |
CommandAuditGetDigest( | |
TPM2B_DIGEST *digest // OUT: command digest | |
) | |
{ | |
TPM_CC commandCode; | |
COMMAND_INDEX commandIndex; | |
HASH_STATE hashState; | |
// Start hash | |
digest->t.size = CryptHashStart(&hashState, gp.auditHashAlg); | |
// Add command code | |
for(commandIndex = 0; commandIndex < COMMAND_COUNT; commandIndex++) | |
{ | |
if(CommandAuditIsRequired(commandIndex)) | |
{ | |
commandCode = GetCommandCode(commandIndex); | |
CryptDigestUpdateInt(&hashState, sizeof(commandCode), commandCode); | |
} | |
} | |
// Complete hash | |
CryptHashEnd2B(&hashState, &digest->b); | |
return; | |
} |