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 relating to the TPM's time functions including
37 // the interface to the implementation-specific time functions.
38 //
39 //** Includes
40 #include "Tpm.h"
41 #include "PlatformClock.h"
42
43 //** Functions
44
45 //*** TimePowerOn()
46 // This function initialize time info at _TPM_Init().
47 //
48 // This function is called at _TPM_Init() so that the TPM time can start counting
49 // as soon as the TPM comes out of reset and doesn't have to wait until
50 // TPM2_Startup() in order to begin the new time epoch. This could be significant
51 // for systems that could get powered up but not run any TPM commands for some
52 // period of time.
53 //
54 void
TimePowerOn(void)55 TimePowerOn(
56 void
57 )
58 {
59 g_time = _plat__TimerRead();
60 }
61
62 //*** TimeNewEpoch()
63 // This function does the processing to generate a new time epoch nonce and
64 // set NV for update. This function is only called when NV is known to be available
65 // and the clock is running. The epoch is updated to persistent data.
66 static void
TimeNewEpoch(void)67 TimeNewEpoch(
68 void
69 )
70 {
71 #if CLOCK_STOPS
72 CryptRandomGenerate(sizeof(CLOCK_NONCE), (BYTE *)&g_timeEpoch);
73 #else
74 // if the epoch is kept in NV, update it.
75 gp.timeEpoch++;
76 NV_SYNC_PERSISTENT(timeEpoch);
77 #endif
78 // Clean out any lingering state
79 _plat__TimerWasStopped();
80 }
81
82 //*** TimeStartup()
83 // This function updates the resetCount and restartCount components of
84 // TPMS_CLOCK_INFO structure at TPM2_Startup().
85 //
86 // This function will deal with the deferred creation of a new epoch.
87 // TimeUpdateToCurrent() will not start a new epoch even if one is due when
88 // TPM_Startup() has not been run. This is because the state of NV is not known
89 // until startup completes. When Startup is done, then it will create the epoch
90 // nonce to complete the initializations by calling this function.
91 BOOL
TimeStartup(STARTUP_TYPE type)92 TimeStartup(
93 STARTUP_TYPE type // IN: start up type
94 )
95 {
96 NOT_REFERENCED(type);
97 // If the previous cycle is orderly shut down, the value of the safe bit
98 // the same as previously saved. Otherwise, it is not safe.
99 if(!NV_IS_ORDERLY)
100 go.clockSafe = NO;
101 return TRUE;
102 }
103
104 //*** TimeClockUpdate()
105 // This function updates go.clock. If 'newTime' requires an update of NV, then
106 // NV is checked for availability. If it is not available or is rate limiting, then
107 // go.clock is not updated and the function returns an error. If 'newTime' would
108 // not cause an NV write, then go.clock is updated. If an NV write occurs, then
109 // go.safe is SET.
110 void
TimeClockUpdate(UINT64 newTime)111 TimeClockUpdate(
112 UINT64 newTime // IN: New time value in mS.
113 )
114 {
115 #define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1)
116
117 // Check to see if the update will cause a need for an nvClock update
118 if((newTime | CLOCK_UPDATE_MASK) > (go.clock | CLOCK_UPDATE_MASK))
119 {
120 pAssert(g_NvStatus == TPM_RC_SUCCESS);
121
122 // Going to update the NV time state so SET the safe flag
123 go.clockSafe = YES;
124
125 // update the time
126 go.clock = newTime;
127
128 NvWrite(NV_ORDERLY_DATA, sizeof(go), &go);
129 }
130 else
131 // No NV update needed so just update
132 go.clock = newTime;
133
134 }
135
136 //*** TimeUpdate()
137 // This function is used to update the time and clock values. If the TPM
138 // has run TPM2_Startup(), this function is called at the start of each command.
139 // If the TPM has not run TPM2_Startup(), this is called from TPM2_Startup() to
140 // get the clock values initialized. It is not called on command entry because, in
141 // this implementation, the go structure is not read from NV until TPM2_Startup().
142 // The reason for this is that the initialization code (_TPM_Init()) may run before
143 // NV is accessible.
144 void
TimeUpdate(void)145 TimeUpdate(
146 void
147 )
148 {
149 UINT64 elapsed;
150 //
151 // Make sure that we consume the current _plat__TimerWasStopped() state.
152 if(_plat__TimerWasStopped())
153 {
154 TimeNewEpoch();
155 }
156 // Get the difference between this call and the last time we updated the tick
157 // timer.
158 elapsed = _plat__TimerRead() - g_time;
159 // Don't read +
160 g_time += elapsed;
161
162 // Don't need to check the result because it has to be success because have
163 // already checked that NV is available.
164 TimeClockUpdate(go.clock + elapsed);
165
166 // Call self healing logic for dictionary attack parameters
167 DASelfHeal();
168 }
169
170 //*** TimeUpdateToCurrent()
171 // This function updates the 'Time' and 'Clock' in the global
172 // TPMS_TIME_INFO structure.
173 //
174 // In this implementation, 'Time' and 'Clock' are updated at the beginning
175 // of each command and the values are unchanged for the duration of the
176 // command.
177 //
178 // Because 'Clock' updates may require a write to NV memory, 'Time' and 'Clock'
179 // are not allowed to advance if NV is not available. When clock is not advancing,
180 // any function that uses 'Clock' will fail and return TPM_RC_NV_UNAVAILABLE or
181 // TPM_RC_NV_RATE.
182 //
183 // This implementation does not do rate limiting. If the implementation does do
184 // rate limiting, then the 'Clock' update should not be inhibited even when doing
185 // rate limiting.
186 void
TimeUpdateToCurrent(void)187 TimeUpdateToCurrent(
188 void
189 )
190 {
191 // Can't update time during the dark interval or when rate limiting so don't
192 // make any modifications to the internal clock value. Also, defer any clock
193 // processing until TPM has run TPM2_Startup()
194 if(!NV_IS_AVAILABLE || !TPMIsStarted())
195 return;
196
197 TimeUpdate();
198 }
199
200
201 //*** TimeSetAdjustRate()
202 // This function is used to perform rate adjustment on 'Time' and 'Clock'.
203 void
TimeSetAdjustRate(TPM_CLOCK_ADJUST adjust)204 TimeSetAdjustRate(
205 TPM_CLOCK_ADJUST adjust // IN: adjust constant
206 )
207 {
208 switch(adjust)
209 {
210 case TPM_CLOCK_COARSE_SLOWER:
211 _plat__ClockAdjustRate(CLOCK_ADJUST_COARSE);
212 break;
213 case TPM_CLOCK_COARSE_FASTER:
214 _plat__ClockAdjustRate(-CLOCK_ADJUST_COARSE);
215 break;
216 case TPM_CLOCK_MEDIUM_SLOWER:
217 _plat__ClockAdjustRate(CLOCK_ADJUST_MEDIUM);
218 break;
219 case TPM_CLOCK_MEDIUM_FASTER:
220 _plat__ClockAdjustRate(-CLOCK_ADJUST_MEDIUM);
221 break;
222 case TPM_CLOCK_FINE_SLOWER:
223 _plat__ClockAdjustRate(CLOCK_ADJUST_FINE);
224 break;
225 case TPM_CLOCK_FINE_FASTER:
226 _plat__ClockAdjustRate(-CLOCK_ADJUST_FINE);
227 break;
228 case TPM_CLOCK_NO_CHANGE:
229 break;
230 default:
231 FAIL(FATAL_ERROR_INTERNAL);
232 break;
233 }
234
235 return;
236 }
237
238 //*** TimeGetMarshaled()
239 // This function is used to access TPMS_TIME_INFO in canonical form.
240 // The function collects the time information and marshals it into 'dataBuffer'
241 // and returns the marshaled size
242 UINT16
TimeGetMarshaled(TIME_INFO * dataBuffer)243 TimeGetMarshaled(
244 TIME_INFO *dataBuffer // OUT: result buffer
245 )
246 {
247 TPMS_TIME_INFO timeInfo;
248
249 // Fill TPMS_TIME_INFO structure
250 timeInfo.time = g_time;
251 TimeFillInfo(&timeInfo.clockInfo);
252
253 // Marshal TPMS_TIME_INFO to canonical form
254 return TPMS_TIME_INFO_Marshal(&timeInfo, (BYTE **)&dataBuffer, NULL);
255 }
256
257 //*** TimeFillInfo
258 // This function gathers information to fill in a TPMS_CLOCK_INFO structure.
259 void
TimeFillInfo(TPMS_CLOCK_INFO * clockInfo)260 TimeFillInfo(
261 TPMS_CLOCK_INFO *clockInfo
262 )
263 {
264 clockInfo->clock = go.clock;
265 clockInfo->resetCount = gp.resetCount;
266 clockInfo->restartCount = gr.restartCount;
267
268 // If NV is not available, clock stopped advancing and the value reported is
269 // not "safe".
270 if(NV_IS_AVAILABLE)
271 clockInfo->safe = go.clockSafe;
272 else
273 clockInfo->safe = NO;
274
275 return;
276 }