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 }