/* 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 and data definitions relating to the | |
// dictionary attack logic. | |
//** Includes and Data Definitions | |
#define DA_C | |
#include "Tpm.h" | |
//** Functions | |
//*** DAPreInstall_Init() | |
// This function initializes the DA parameters to their manufacturer-default | |
// values. The default values are determined by a platform-specific specification. | |
// | |
// This function should not be called outside of a manufacturing or simulation | |
// environment. | |
// | |
// The DA parameters will be restored to these initial values by TPM2_Clear(). | |
void | |
DAPreInstall_Init( | |
void | |
) | |
{ | |
gp.failedTries = 0; | |
gp.maxTries = 3; | |
gp.recoveryTime = 1000; // in seconds (~16.67 minutes) | |
gp.lockoutRecovery = 1000; // in seconds | |
gp.lockOutAuthEnabled = TRUE; // Use of lockoutAuth is enabled | |
// Record persistent DA parameter changes to NV | |
NV_SYNC_PERSISTENT(failedTries); | |
NV_SYNC_PERSISTENT(maxTries); | |
NV_SYNC_PERSISTENT(recoveryTime); | |
NV_SYNC_PERSISTENT(lockoutRecovery); | |
NV_SYNC_PERSISTENT(lockOutAuthEnabled); | |
return; | |
} | |
//*** DAStartup() | |
// This function is called by TPM2_Startup() to initialize the DA parameters. | |
// In the case of Startup(CLEAR), use of lockoutAuth will be enabled if the | |
// lockout recovery time is 0. Otherwise, lockoutAuth will not be enabled until | |
// the TPM has been continuously powered for the lockoutRecovery time. | |
// | |
// This function requires that NV be available and not rate limiting. | |
BOOL | |
DAStartup( | |
STARTUP_TYPE type // IN: startup type | |
) | |
{ | |
NOT_REFERENCED(type); | |
#if !ACCUMULATE_SELF_HEAL_TIMER | |
_plat__TimerWasReset(); | |
s_selfHealTimer = 0; | |
s_lockoutTimer = 0; | |
#else | |
if(_plat__TimerWasReset()) | |
{ | |
if(!NV_IS_ORDERLY) | |
{ | |
// If shutdown was not orderly, then don't really know if go.time has | |
// any useful value so reset the timer to 0. This is what the tick | |
// was reset to | |
s_selfHealTimer = 0; | |
s_lockoutTimer = 0; | |
} | |
else | |
{ | |
// If we know how much time was accumulated at the last orderly shutdown | |
// subtract that from the saved timer values so that they effectively | |
// have the accumulated values | |
s_selfHealTimer -= go.time; | |
s_lockoutTimer -= go.time; | |
} | |
} | |
#endif | |
// For any Startup(), if lockoutRecovery is 0, enable use of lockoutAuth. | |
if(gp.lockoutRecovery == 0) | |
{ | |
gp.lockOutAuthEnabled = TRUE; | |
// Record the changes to NV | |
NV_SYNC_PERSISTENT(lockOutAuthEnabled); | |
} | |
// If DA has not been disabled and the previous shutdown is not orderly | |
// failedTries is not already at its maximum then increment 'failedTries' | |
if(gp.recoveryTime != 0 | |
&& gp.failedTries < gp.maxTries | |
&& !IS_ORDERLY(g_prevOrderlyState)) | |
{ | |
#if USE_DA_USED | |
gp.failedTries += g_daUsed; | |
g_daUsed = FALSE; | |
#else | |
gp.failedTries++; | |
#endif | |
// Record the change to NV | |
NV_SYNC_PERSISTENT(failedTries); | |
} | |
// Before Startup, the TPM will not do clock updates. At startup, need to | |
// do a time update which will do the DA update. | |
TimeUpdate(); | |
return TRUE; | |
} | |
//*** DARegisterFailure() | |
// This function is called when an authorization failure occurs on an entity | |
// that is subject to dictionary-attack protection. When a DA failure is | |
// triggered, register the failure by resetting the relevant self-healing | |
// timer to the current time. | |
void | |
DARegisterFailure( | |
TPM_HANDLE handle // IN: handle for failure | |
) | |
{ | |
// Reset the timer associated with lockout if the handle is the lockoutAuth. | |
if(handle == TPM_RH_LOCKOUT) | |
s_lockoutTimer = g_time; | |
else | |
s_selfHealTimer = g_time; | |
return; | |
} | |
//*** DASelfHeal() | |
// This function is called to check if sufficient time has passed to allow | |
// decrement of failedTries or to re-enable use of lockoutAuth. | |
// | |
// This function should be called when the time interval is updated. | |
void | |
DASelfHeal( | |
void | |
) | |
{ | |
// Regular authorization self healing logic | |
// If no failed authorization tries, do nothing. Otherwise, try to | |
// decrease failedTries | |
if(gp.failedTries != 0) | |
{ | |
// if recovery time is 0, DA logic has been disabled. Clear failed tries | |
// immediately | |
if(gp.recoveryTime == 0) | |
{ | |
gp.failedTries = 0; | |
// Update NV record | |
NV_SYNC_PERSISTENT(failedTries); | |
} | |
else | |
{ | |
UINT64 decreaseCount; | |
#if 0 // Errata eliminates this code | |
// In the unlikely event that failedTries should become larger than | |
// maxTries | |
if(gp.failedTries > gp.maxTries) | |
gp.failedTries = gp.maxTries; | |
#endif | |
// How much can failedTries be decreased | |
// Cast s_selfHealTimer to an int in case it became negative at | |
// startup | |
decreaseCount = ((g_time - (INT64)s_selfHealTimer) / 1000) | |
/ gp.recoveryTime; | |
if(gp.failedTries <= (UINT32)decreaseCount) | |
// should not set failedTries below zero | |
gp.failedTries = 0; | |
else | |
gp.failedTries -= (UINT32)decreaseCount; | |
// the cast prevents overflow of the product | |
s_selfHealTimer += (decreaseCount * (UINT64)gp.recoveryTime) * 1000; | |
if(decreaseCount != 0) | |
// If there was a change to the failedTries, record the changes | |
// to NV | |
NV_SYNC_PERSISTENT(failedTries); | |
} | |
} | |
// LockoutAuth self healing logic | |
// If lockoutAuth is enabled, do nothing. Otherwise, try to see if we | |
// may enable it | |
if(!gp.lockOutAuthEnabled) | |
{ | |
// if lockout authorization recovery time is 0, a reboot is required to | |
// re-enable use of lockout authorization. Self-healing would not | |
// apply in this case. | |
if(gp.lockoutRecovery != 0) | |
{ | |
if(((g_time - (INT64)s_lockoutTimer) / 1000) >= gp.lockoutRecovery) | |
{ | |
gp.lockOutAuthEnabled = TRUE; | |
// Record the changes to NV | |
NV_SYNC_PERSISTENT(lockOutAuthEnabled); | |
} | |
} | |
} | |
return; | |
} |