/* 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; }