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