blob: 2998804fcd34f708c3f86be7d5f34dc105f33966 [file] [log] [blame]
/* 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 code implements the ACT update code. It does not use a mutex. This code uses
// a platform service (_plat__ACT_UpdateCounter()) that returns 'false' if the update
// is not accepted. If this occurs, then TPM_RC_RETRY should be sent to the caller so
// that they can retry the operation later. The implementation of this is platform
// dependent but the reference uses a simple flag to indicate that an update is
// pending and the only process that can clear that flag is the process that does the
// actual update.
//** Includes
#include "Tpm.h"
#include "ACT_spt_fp.h"
#include "Platform_fp.h"
//** Functions
//*** _ActResume()
// This function does the resume processing for an ACT. It updates the saved count
// and turns signaling back on if necessary.
static void
_ActResume(
UINT32 act, //IN: the act number
ACT_STATE *actData //IN: pointer to the saved ACT data
)
{
// If the act was non-zero, then restore the counter value.
if(actData->remaining > 0)
_plat__ACT_UpdateCounter(act, actData->remaining);
// if the counter was zero and the ACT signaling, enable the signaling.
else if(go.signaledACT & (1 << act))
_plat__ACT_SetSignaled(act, TRUE);
}
//*** ActStartup()
// This function is called by TPM2_Startup() to initialize the ACT counter values.
BOOL
ActStartup(
STARTUP_TYPE type
)
{
// Reset all the ACT hardware
_plat__ACT_Initialize();
// If this not a cold start, copy all the current 'signaled' settings to
// 'preservedSignaled'.
if (g_powerWasLost)
go.preservedSignaled = 0;
else
go.preservedSignaled |= go.signaledACT;
// For TPM_RESET or TPM_RESTART, the ACTs will all be disabled and the output
// de-asserted.
if(type != SU_RESUME)
{
go.signaledACT = 0;
#define CLEAR_ACT_POLICY(N) \
go.ACT_##N.hashAlg = TPM_ALG_NULL; \
go.ACT_##N.authPolicy.b.size = 0;
FOR_EACH_ACT(CLEAR_ACT_POLICY)
}
else
{
// Resume each of the implemented ACT
#define RESUME_ACT(N) _ActResume(0x##N, &go.ACT_##N);
FOR_EACH_ACT(RESUME_ACT)
}
// set no ACT updated since last startup. This is to enable the halving of the
// timeout value
s_ActUpdated = 0;
_plat__ACT_EnableTicks(TRUE);
return TRUE;
}
//*** _ActSaveState()
// Get the counter state and the signaled state for an ACT. If the ACT has not been
// updated since the last time it was saved, then divide the count by 2.
static void
_ActSaveState(
UINT32 act,
P_ACT_STATE actData
)
{
actData->remaining = _plat__ACT_GetRemaining(act);
// If the ACT hasn't been updated since the last startup, then it should be
// be halved.
if((s_ActUpdated & (1 << act)) == 0)
{
// Don't halve if the count is set to max or if halving would make it zero
if((actData->remaining != UINT32_MAX) && (actData->remaining > 1))
actData->remaining /= 2;
}
if(_plat__ACT_GetSignaled(act))
go.signaledACT |= (1 << act);
}
//*** ActGetSignaled()
// This function returns the state of the signaled flag associated with an ACT.
BOOL
ActGetSignaled(
TPM_RH actHandle
)
{
UINT32 act = actHandle - TPM_RH_ACT_0;
//
return _plat__ACT_GetSignaled(act);
}
//***ActShutdown()
// This function saves the current state of the counters
BOOL
ActShutdown(
TPM_SU state //IN: the type of the shutdown.
)
{
// if this is not shutdown state, then the only type of startup is TPM_RESTART
// so the timer values will be cleared. If this is shutdown state, get the current
// countdown and signaled values. Plus, if the counter has not been updated
// since the last restart, divide the time by 2 so that there is no attack on the
// countdown by saving the countdown state early and then not using the TPM.
if(state == TPM_SU_STATE)
{
// This will be populated as each of the ACT is queried
go.signaledACT = 0;
// Get the current count and the signaled state
#define SAVE_ACT_STATE(N) _ActSaveState(0x##N, &go.ACT_##N);
FOR_EACH_ACT(SAVE_ACT_STATE);
}
return TRUE;
}
//*** ActIsImplemented()
// This function determines if an ACT is implemented in both the TPM and the platform
// code.
BOOL
ActIsImplemented(
UINT32 act
)
{
// This switch accounts for the TPM implemented values.
switch(act)
{
FOR_EACH_ACT(CASE_ACT_NUMBER)
// This ensures that the platform implements the values implemented by
// the TPM
return _plat__ACT_GetImplemented(act);
default:
break;
}
return FALSE;
}
//***ActCounterUpdate()
// This function updates the ACT counter. If the counter already has a pending update,
// it returns TPM_RC_RETRY so that the update can be tried again later.
TPM_RC
ActCounterUpdate(
TPM_RH handle, //IN: the handle of the act
UINT32 newValue //IN: the value to set in the ACT
)
{
UINT32 act;
TPM_RC result;
//
act = handle - TPM_RH_ACT_0;
// This should never fail, but...
if(!_plat__ACT_GetImplemented(act))
result = TPM_RC_VALUE;
else
{
// Will need to clear orderly so fail if we are orderly and NV is
// not available
if(NV_IS_ORDERLY)
RETURN_IF_NV_IS_NOT_AVAILABLE;
// if the attempt to update the counter fails, it means that there is an
// update pending so wait until it has occurred and then do an update.
if(!_plat__ACT_UpdateCounter(act, newValue))
result = TPM_RC_RETRY;
else
{
// Indicate that the ACT has been updated since last TPM2_Startup().
s_ActUpdated |= (UINT16)(1 << act);
// Clear the preservedSignaled attribute.
go.preservedSignaled &= ~((UINT16)(1 << act));
// Need to clear the orderly flag
g_clearOrderly = TRUE;
result = TPM_RC_SUCCESS;
}
}
return result;
}
//*** ActGetCapabilityData()
// This function returns the list of ACT data
// Return Type: TPMI_YES_NO
// YES if more ACT data is available
// NO if no more ACT data to
TPMI_YES_NO
ActGetCapabilityData(
TPM_HANDLE actHandle, // IN: the handle for the starting ACT
UINT32 maxCount, // IN: maximum allowed return values
TPML_ACT_DATA *actList // OUT: ACT data list
)
{
// Initialize output property list
actList->count = 0;
// Make sure that the starting handle value is in range (again)
if((actHandle < TPM_RH_ACT_0) || (actHandle > TPM_RH_ACT_F))
return FALSE;
// The maximum count of curves we may return is MAX_ECC_CURVES
if(maxCount > MAX_ACT_DATA)
maxCount = MAX_ACT_DATA;
// Scan the ACT data from the starting ACT
for(; actHandle <= TPM_RH_ACT_F; actHandle++)
{
UINT32 act = actHandle - TPM_RH_ACT_0;
if(actList->count < maxCount)
{
if(ActIsImplemented(act))
{
TPMS_ACT_DATA *actData = &actList->actData[actList->count];
//
memset(&actData->attributes, 0, sizeof(actData->attributes));
actData->handle = actHandle;
actData->timeout = _plat__ACT_GetRemaining(act);
if(_plat__ACT_GetSignaled(act))
SET_ATTRIBUTE(actData->attributes, TPMA_ACT, signaled);
else
CLEAR_ATTRIBUTE(actData->attributes, TPMA_ACT, signaled);
if (go.preservedSignaled & (1 << act))
SET_ATTRIBUTE(actData->attributes, TPMA_ACT, preserveSignaled);
actList->count++;
}
}
else
{
if(_plat__ACT_GetImplemented(act))
return YES;
}
}
// If we get here, either all of the ACT values were put in the list, or the list
// was filled and there are no more ACT values to return
return NO;
}