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 }