• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Microsoft Reference Implementation for TPM 2.0
2  *
3  *  The copyright in this software is being made available under the BSD License,
4  *  included below. This software may be subject to other third party and
5  *  contributor rights, including patent rights, and no such rights are granted
6  *  under this license.
7  *
8  *  Copyright (c) Microsoft Corporation
9  *
10  *  All rights reserved.
11  *
12  *  BSD License
13  *
14  *  Redistribution and use in source and binary forms, with or without modification,
15  *  are permitted provided that the following conditions are met:
16  *
17  *  Redistributions of source code must retain the above copyright notice, this list
18  *  of conditions and the following disclaimer.
19  *
20  *  Redistributions in binary form must reproduce the above copyright notice, this
21  *  list of conditions and the following disclaimer in the documentation and/or
22  *  other materials provided with the distribution.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 //** Introduction
36 // This file contains the functions and data definitions relating to the
37 // dictionary attack logic.
38 
39 //** Includes and Data Definitions
40 #define DA_C
41 #include "Tpm.h"
42 
43 //** Functions
44 
45 //*** DAPreInstall_Init()
46 // This function initializes the DA parameters to their manufacturer-default
47 // values. The default values are determined by a platform-specific specification.
48 //
49 // This function should not be called outside of a manufacturing or simulation
50 // environment.
51 //
52 // The DA parameters will be restored to these initial values by TPM2_Clear().
53 void
DAPreInstall_Init(void)54 DAPreInstall_Init(
55     void
56     )
57 {
58     gp.failedTries = 0;
59     gp.maxTries = 3;
60     gp.recoveryTime = 1000;         // in seconds (~16.67 minutes)
61     gp.lockoutRecovery = 1000;      // in seconds
62     gp.lockOutAuthEnabled = TRUE;   // Use of lockoutAuth is enabled
63 
64     // Record persistent DA parameter changes to NV
65     NV_SYNC_PERSISTENT(failedTries);
66     NV_SYNC_PERSISTENT(maxTries);
67     NV_SYNC_PERSISTENT(recoveryTime);
68     NV_SYNC_PERSISTENT(lockoutRecovery);
69     NV_SYNC_PERSISTENT(lockOutAuthEnabled);
70 
71     return;
72 }
73 
74 
75 //*** DAStartup()
76 // This function is called  by TPM2_Startup() to initialize the DA parameters.
77 // In the case of Startup(CLEAR), use of lockoutAuth will be enabled if the
78 // lockout recovery time is 0. Otherwise, lockoutAuth will not be enabled until
79 // the TPM has been continuously powered for the lockoutRecovery time.
80 //
81 // This function requires that NV be available and not rate limiting.
82 BOOL
DAStartup(STARTUP_TYPE type)83 DAStartup(
84     STARTUP_TYPE     type           // IN: startup type
85     )
86 {
87     NOT_REFERENCED(type);
88 #if !ACCUMULATE_SELF_HEAL_TIMER
89     _plat__TimerWasReset();
90     s_selfHealTimer = 0;
91     s_lockoutTimer = 0;
92 #else
93     if(_plat__TimerWasReset())
94     {
95         if(!NV_IS_ORDERLY)
96         {
97             // If shutdown was not orderly, then don't really know if go.time has
98             // any useful value so reset the timer to 0. This is what the tick
99             // was reset to
100             s_selfHealTimer = 0;
101             s_lockoutTimer = 0;
102         }
103         else
104         {
105             // If we know how much time was accumulated at the last orderly shutdown
106             // subtract that from the saved timer values so that they effectively
107             // have the accumulated values
108             s_selfHealTimer -= go.time;
109             s_lockoutTimer -= go.time;
110         }
111     }
112 #endif
113 
114     // For any Startup(), if lockoutRecovery is 0, enable use of lockoutAuth.
115     if(gp.lockoutRecovery == 0)
116     {
117         gp.lockOutAuthEnabled = TRUE;
118         // Record the changes to NV
119         NV_SYNC_PERSISTENT(lockOutAuthEnabled);
120     }
121 
122     // If DA has not been disabled and the previous shutdown is not orderly
123     // failedTries is not already at its maximum then increment 'failedTries'
124     if(gp.recoveryTime != 0
125        && gp.failedTries < gp.maxTries
126        && !IS_ORDERLY(g_prevOrderlyState))
127     {
128 #if USE_DA_USED
129         gp.failedTries += g_daUsed;
130         g_daUsed = FALSE;
131 #else
132         gp.failedTries++;
133 #endif
134         // Record the change to NV
135         NV_SYNC_PERSISTENT(failedTries);
136     }
137     // Before Startup, the TPM will not do clock updates. At startup, need to
138     // do a time update which will do the DA update.
139     TimeUpdate();
140 
141     return TRUE;
142 }
143 
144 //*** DARegisterFailure()
145 // This function is called when an authorization failure occurs on an entity
146 // that is subject to dictionary-attack protection. When a DA failure is
147 // triggered, register the failure by resetting the relevant self-healing
148 // timer to the current time.
149 void
DARegisterFailure(TPM_HANDLE handle)150 DARegisterFailure(
151     TPM_HANDLE       handle         // IN: handle for failure
152     )
153 {
154     // Reset the timer associated with lockout if the handle is the lockoutAuth.
155     if(handle == TPM_RH_LOCKOUT)
156         s_lockoutTimer = g_time;
157     else
158         s_selfHealTimer = g_time;
159     return;
160 }
161 
162 //*** DASelfHeal()
163 // This function is called to check if sufficient time has passed to allow
164 // decrement of failedTries or to re-enable use of lockoutAuth.
165 //
166 // This function should be called when the time interval is updated.
167 void
DASelfHeal(void)168 DASelfHeal(
169     void
170     )
171 {
172     // Regular authorization self healing logic
173     // If no failed authorization tries, do nothing.  Otherwise, try to
174     // decrease failedTries
175     if(gp.failedTries != 0)
176     {
177         // if recovery time is 0, DA logic has been disabled.  Clear failed tries
178         // immediately
179         if(gp.recoveryTime == 0)
180         {
181             gp.failedTries = 0;
182             // Update NV record
183             NV_SYNC_PERSISTENT(failedTries);
184         }
185         else
186         {
187             UINT64          decreaseCount;
188 #if 0 // Errata eliminates this code
189             // In the unlikely event that failedTries should become larger than
190             // maxTries
191             if(gp.failedTries > gp.maxTries)
192                 gp.failedTries = gp.maxTries;
193 #endif
194             // How much can failedTries be decreased
195 
196             // Cast s_selfHealTimer to an int in case it became negative at
197             // startup
198             decreaseCount = ((g_time - (INT64)s_selfHealTimer) / 1000)
199                 / gp.recoveryTime;
200 
201             if(gp.failedTries <= (UINT32)decreaseCount)
202                 // should not set failedTries below zero
203                 gp.failedTries = 0;
204             else
205                 gp.failedTries -= (UINT32)decreaseCount;
206 
207             // the cast prevents overflow of the product
208             s_selfHealTimer += (decreaseCount * (UINT64)gp.recoveryTime) * 1000;
209             if(decreaseCount != 0)
210                 // If there was a change to the failedTries, record the changes
211                 // to NV
212                 NV_SYNC_PERSISTENT(failedTries);
213         }
214     }
215 
216     // LockoutAuth self healing logic
217     // If lockoutAuth is enabled, do nothing.  Otherwise, try to see if we
218     // may enable it
219     if(!gp.lockOutAuthEnabled)
220     {
221         // if lockout authorization recovery time is 0, a reboot is required to
222         // re-enable use of lockout authorization.  Self-healing would not
223         // apply in this case.
224         if(gp.lockoutRecovery != 0)
225         {
226             if(((g_time - (INT64)s_lockoutTimer) / 1000) >= gp.lockoutRecovery)
227             {
228                 gp.lockOutAuthEnabled = TRUE;
229                 // Record the changes to NV
230                 NV_SYNC_PERSISTENT(lockOutAuthEnabled);
231             }
232         }
233     }
234     return;
235 }