xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/tpm/src/subsystem/Time.c (revision 5c591343844d1f9da7da26467c4bf7efc8a7a413)
1*5c591343SA. Cody Schuffelen /* Microsoft Reference Implementation for TPM 2.0
2*5c591343SA. Cody Schuffelen  *
3*5c591343SA. Cody Schuffelen  *  The copyright in this software is being made available under the BSD License,
4*5c591343SA. Cody Schuffelen  *  included below. This software may be subject to other third party and
5*5c591343SA. Cody Schuffelen  *  contributor rights, including patent rights, and no such rights are granted
6*5c591343SA. Cody Schuffelen  *  under this license.
7*5c591343SA. Cody Schuffelen  *
8*5c591343SA. Cody Schuffelen  *  Copyright (c) Microsoft Corporation
9*5c591343SA. Cody Schuffelen  *
10*5c591343SA. Cody Schuffelen  *  All rights reserved.
11*5c591343SA. Cody Schuffelen  *
12*5c591343SA. Cody Schuffelen  *  BSD License
13*5c591343SA. Cody Schuffelen  *
14*5c591343SA. Cody Schuffelen  *  Redistribution and use in source and binary forms, with or without modification,
15*5c591343SA. Cody Schuffelen  *  are permitted provided that the following conditions are met:
16*5c591343SA. Cody Schuffelen  *
17*5c591343SA. Cody Schuffelen  *  Redistributions of source code must retain the above copyright notice, this list
18*5c591343SA. Cody Schuffelen  *  of conditions and the following disclaimer.
19*5c591343SA. Cody Schuffelen  *
20*5c591343SA. Cody Schuffelen  *  Redistributions in binary form must reproduce the above copyright notice, this
21*5c591343SA. Cody Schuffelen  *  list of conditions and the following disclaimer in the documentation and/or
22*5c591343SA. Cody Schuffelen  *  other materials provided with the distribution.
23*5c591343SA. Cody Schuffelen  *
24*5c591343SA. Cody Schuffelen  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25*5c591343SA. Cody Schuffelen  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*5c591343SA. Cody Schuffelen  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27*5c591343SA. Cody Schuffelen  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28*5c591343SA. Cody Schuffelen  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29*5c591343SA. Cody Schuffelen  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30*5c591343SA. Cody Schuffelen  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31*5c591343SA. Cody Schuffelen  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*5c591343SA. Cody Schuffelen  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*5c591343SA. Cody Schuffelen  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*5c591343SA. Cody Schuffelen  */
35*5c591343SA. Cody Schuffelen //** Introduction
36*5c591343SA. Cody Schuffelen // This file contains the functions relating to the TPM's time functions including
37*5c591343SA. Cody Schuffelen // the interface to the implementation-specific time functions.
38*5c591343SA. Cody Schuffelen //
39*5c591343SA. Cody Schuffelen //** Includes
40*5c591343SA. Cody Schuffelen #include "Tpm.h"
41*5c591343SA. Cody Schuffelen #include "PlatformClock.h"
42*5c591343SA. Cody Schuffelen 
43*5c591343SA. Cody Schuffelen //** Functions
44*5c591343SA. Cody Schuffelen 
45*5c591343SA. Cody Schuffelen //*** TimePowerOn()
46*5c591343SA. Cody Schuffelen // This function initialize time info at _TPM_Init().
47*5c591343SA. Cody Schuffelen //
48*5c591343SA. Cody Schuffelen // This function is called at _TPM_Init() so that the TPM time can start counting
49*5c591343SA. Cody Schuffelen // as soon as the TPM comes out of reset and doesn't have to wait until
50*5c591343SA. Cody Schuffelen // TPM2_Startup() in order to begin the new time epoch. This could be significant
51*5c591343SA. Cody Schuffelen // for systems that could get powered up but not run any TPM commands for some
52*5c591343SA. Cody Schuffelen // period of time.
53*5c591343SA. Cody Schuffelen //
54*5c591343SA. Cody Schuffelen void
TimePowerOn(void)55*5c591343SA. Cody Schuffelen TimePowerOn(
56*5c591343SA. Cody Schuffelen     void
57*5c591343SA. Cody Schuffelen     )
58*5c591343SA. Cody Schuffelen {
59*5c591343SA. Cody Schuffelen     g_time = _plat__TimerRead();
60*5c591343SA. Cody Schuffelen }
61*5c591343SA. Cody Schuffelen 
62*5c591343SA. Cody Schuffelen //*** TimeNewEpoch()
63*5c591343SA. Cody Schuffelen // This function does the processing to generate a new time epoch nonce and
64*5c591343SA. Cody Schuffelen // set NV for update. This function is only called when NV is known to be available
65*5c591343SA. Cody Schuffelen // and the clock is running. The epoch is updated to persistent data.
66*5c591343SA. Cody Schuffelen static void
TimeNewEpoch(void)67*5c591343SA. Cody Schuffelen TimeNewEpoch(
68*5c591343SA. Cody Schuffelen     void
69*5c591343SA. Cody Schuffelen     )
70*5c591343SA. Cody Schuffelen {
71*5c591343SA. Cody Schuffelen #if CLOCK_STOPS
72*5c591343SA. Cody Schuffelen     CryptRandomGenerate(sizeof(CLOCK_NONCE), (BYTE *)&g_timeEpoch);
73*5c591343SA. Cody Schuffelen #else
74*5c591343SA. Cody Schuffelen     // if the epoch is kept in NV, update it.
75*5c591343SA. Cody Schuffelen     gp.timeEpoch++;
76*5c591343SA. Cody Schuffelen     NV_SYNC_PERSISTENT(timeEpoch);
77*5c591343SA. Cody Schuffelen #endif
78*5c591343SA. Cody Schuffelen     // Clean out any lingering state
79*5c591343SA. Cody Schuffelen     _plat__TimerWasStopped();
80*5c591343SA. Cody Schuffelen }
81*5c591343SA. Cody Schuffelen 
82*5c591343SA. Cody Schuffelen //*** TimeStartup()
83*5c591343SA. Cody Schuffelen // This function updates the resetCount and restartCount components of
84*5c591343SA. Cody Schuffelen // TPMS_CLOCK_INFO structure at TPM2_Startup().
85*5c591343SA. Cody Schuffelen //
86*5c591343SA. Cody Schuffelen // This function will deal with the deferred creation of a new epoch.
87*5c591343SA. Cody Schuffelen // TimeUpdateToCurrent() will not start a new epoch even if one is due when
88*5c591343SA. Cody Schuffelen // TPM_Startup() has not been run. This is because the state of NV is not known
89*5c591343SA. Cody Schuffelen // until startup completes. When Startup is done, then it will create the epoch
90*5c591343SA. Cody Schuffelen // nonce to complete the initializations by calling this function.
91*5c591343SA. Cody Schuffelen BOOL
TimeStartup(STARTUP_TYPE type)92*5c591343SA. Cody Schuffelen TimeStartup(
93*5c591343SA. Cody Schuffelen     STARTUP_TYPE     type           // IN: start up type
94*5c591343SA. Cody Schuffelen     )
95*5c591343SA. Cody Schuffelen {
96*5c591343SA. Cody Schuffelen     NOT_REFERENCED(type);
97*5c591343SA. Cody Schuffelen     // If the previous cycle is orderly shut down, the value of the safe bit
98*5c591343SA. Cody Schuffelen     // the same as previously saved.  Otherwise, it is not safe.
99*5c591343SA. Cody Schuffelen     if(!NV_IS_ORDERLY)
100*5c591343SA. Cody Schuffelen         go.clockSafe = NO;
101*5c591343SA. Cody Schuffelen     return TRUE;
102*5c591343SA. Cody Schuffelen }
103*5c591343SA. Cody Schuffelen 
104*5c591343SA. Cody Schuffelen //*** TimeClockUpdate()
105*5c591343SA. Cody Schuffelen // This function updates go.clock. If 'newTime' requires an update of NV, then
106*5c591343SA. Cody Schuffelen // NV is checked for availability. If it is not available or is rate limiting, then
107*5c591343SA. Cody Schuffelen // go.clock is not updated and the function returns an error. If 'newTime' would
108*5c591343SA. Cody Schuffelen // not cause an NV write, then go.clock is updated. If an NV write occurs, then
109*5c591343SA. Cody Schuffelen // go.safe is SET.
110*5c591343SA. Cody Schuffelen void
TimeClockUpdate(UINT64 newTime)111*5c591343SA. Cody Schuffelen TimeClockUpdate(
112*5c591343SA. Cody Schuffelen     UINT64           newTime    // IN: New time value in mS.
113*5c591343SA. Cody Schuffelen     )
114*5c591343SA. Cody Schuffelen {
115*5c591343SA. Cody Schuffelen #define CLOCK_UPDATE_MASK  ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1)
116*5c591343SA. Cody Schuffelen 
117*5c591343SA. Cody Schuffelen     // Check to see if the update will cause a need for an nvClock update
118*5c591343SA. Cody Schuffelen     if((newTime | CLOCK_UPDATE_MASK) > (go.clock | CLOCK_UPDATE_MASK))
119*5c591343SA. Cody Schuffelen     {
120*5c591343SA. Cody Schuffelen         pAssert(g_NvStatus == TPM_RC_SUCCESS);
121*5c591343SA. Cody Schuffelen 
122*5c591343SA. Cody Schuffelen         // Going to update the NV time state so SET the safe flag
123*5c591343SA. Cody Schuffelen         go.clockSafe = YES;
124*5c591343SA. Cody Schuffelen 
125*5c591343SA. Cody Schuffelen         // update the time
126*5c591343SA. Cody Schuffelen         go.clock = newTime;
127*5c591343SA. Cody Schuffelen 
128*5c591343SA. Cody Schuffelen         NvWrite(NV_ORDERLY_DATA, sizeof(go), &go);
129*5c591343SA. Cody Schuffelen     }
130*5c591343SA. Cody Schuffelen     else
131*5c591343SA. Cody Schuffelen         // No NV update needed so just update
132*5c591343SA. Cody Schuffelen         go.clock = newTime;
133*5c591343SA. Cody Schuffelen 
134*5c591343SA. Cody Schuffelen }
135*5c591343SA. Cody Schuffelen 
136*5c591343SA. Cody Schuffelen //*** TimeUpdate()
137*5c591343SA. Cody Schuffelen // This function is used to update the time and clock values. If the TPM
138*5c591343SA. Cody Schuffelen // has run TPM2_Startup(), this function is called at the start of each command.
139*5c591343SA. Cody Schuffelen // If the TPM has not run TPM2_Startup(), this is called from TPM2_Startup() to
140*5c591343SA. Cody Schuffelen // get the clock values initialized. It is not called on command entry because, in
141*5c591343SA. Cody Schuffelen // this implementation, the go structure is not read from NV until TPM2_Startup().
142*5c591343SA. Cody Schuffelen // The reason for this is that the initialization code (_TPM_Init()) may run before
143*5c591343SA. Cody Schuffelen // NV is accessible.
144*5c591343SA. Cody Schuffelen void
TimeUpdate(void)145*5c591343SA. Cody Schuffelen TimeUpdate(
146*5c591343SA. Cody Schuffelen     void
147*5c591343SA. Cody Schuffelen     )
148*5c591343SA. Cody Schuffelen {
149*5c591343SA. Cody Schuffelen     UINT64          elapsed;
150*5c591343SA. Cody Schuffelen //
151*5c591343SA. Cody Schuffelen     // Make sure that we consume the current _plat__TimerWasStopped() state.
152*5c591343SA. Cody Schuffelen    if(_plat__TimerWasStopped())
153*5c591343SA. Cody Schuffelen     {
154*5c591343SA. Cody Schuffelen         TimeNewEpoch();
155*5c591343SA. Cody Schuffelen     }
156*5c591343SA. Cody Schuffelen     // Get the difference between this call and the last time we updated the tick
157*5c591343SA. Cody Schuffelen     // timer.
158*5c591343SA. Cody Schuffelen     elapsed = _plat__TimerRead() - g_time;
159*5c591343SA. Cody Schuffelen     // Don't read +
160*5c591343SA. Cody Schuffelen     g_time += elapsed;
161*5c591343SA. Cody Schuffelen 
162*5c591343SA. Cody Schuffelen     // Don't need to check the result because it has to be success because have
163*5c591343SA. Cody Schuffelen     // already checked that NV is available.
164*5c591343SA. Cody Schuffelen     TimeClockUpdate(go.clock + elapsed);
165*5c591343SA. Cody Schuffelen 
166*5c591343SA. Cody Schuffelen     // Call self healing logic for dictionary attack parameters
167*5c591343SA. Cody Schuffelen     DASelfHeal();
168*5c591343SA. Cody Schuffelen }
169*5c591343SA. Cody Schuffelen 
170*5c591343SA. Cody Schuffelen //*** TimeUpdateToCurrent()
171*5c591343SA. Cody Schuffelen // This function updates the 'Time' and 'Clock' in the global
172*5c591343SA. Cody Schuffelen // TPMS_TIME_INFO structure.
173*5c591343SA. Cody Schuffelen //
174*5c591343SA. Cody Schuffelen // In this implementation, 'Time' and 'Clock' are updated at the beginning
175*5c591343SA. Cody Schuffelen // of each command and the values are unchanged for the duration of the
176*5c591343SA. Cody Schuffelen // command.
177*5c591343SA. Cody Schuffelen //
178*5c591343SA. Cody Schuffelen // Because 'Clock' updates may require a write to NV memory, 'Time' and 'Clock'
179*5c591343SA. Cody Schuffelen // are not allowed to advance if NV is not available. When clock is not advancing,
180*5c591343SA. Cody Schuffelen // any function that uses 'Clock' will fail and return TPM_RC_NV_UNAVAILABLE or
181*5c591343SA. Cody Schuffelen // TPM_RC_NV_RATE.
182*5c591343SA. Cody Schuffelen //
183*5c591343SA. Cody Schuffelen // This implementation does not do rate limiting. If the implementation does do
184*5c591343SA. Cody Schuffelen // rate limiting, then the 'Clock' update should not be inhibited even when doing
185*5c591343SA. Cody Schuffelen // rate limiting.
186*5c591343SA. Cody Schuffelen void
TimeUpdateToCurrent(void)187*5c591343SA. Cody Schuffelen TimeUpdateToCurrent(
188*5c591343SA. Cody Schuffelen     void
189*5c591343SA. Cody Schuffelen )
190*5c591343SA. Cody Schuffelen {
191*5c591343SA. Cody Schuffelen     // Can't update time during the dark interval or when rate limiting so don't
192*5c591343SA. Cody Schuffelen     // make any modifications to the internal clock value. Also, defer any clock
193*5c591343SA. Cody Schuffelen     // processing until TPM has run TPM2_Startup()
194*5c591343SA. Cody Schuffelen     if(!NV_IS_AVAILABLE || !TPMIsStarted())
195*5c591343SA. Cody Schuffelen         return;
196*5c591343SA. Cody Schuffelen 
197*5c591343SA. Cody Schuffelen     TimeUpdate();
198*5c591343SA. Cody Schuffelen }
199*5c591343SA. Cody Schuffelen 
200*5c591343SA. Cody Schuffelen 
201*5c591343SA. Cody Schuffelen //*** TimeSetAdjustRate()
202*5c591343SA. Cody Schuffelen // This function is used to perform rate adjustment on 'Time' and 'Clock'.
203*5c591343SA. Cody Schuffelen void
TimeSetAdjustRate(TPM_CLOCK_ADJUST adjust)204*5c591343SA. Cody Schuffelen TimeSetAdjustRate(
205*5c591343SA. Cody Schuffelen     TPM_CLOCK_ADJUST     adjust         // IN: adjust constant
206*5c591343SA. Cody Schuffelen     )
207*5c591343SA. Cody Schuffelen {
208*5c591343SA. Cody Schuffelen     switch(adjust)
209*5c591343SA. Cody Schuffelen     {
210*5c591343SA. Cody Schuffelen         case TPM_CLOCK_COARSE_SLOWER:
211*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(CLOCK_ADJUST_COARSE);
212*5c591343SA. Cody Schuffelen             break;
213*5c591343SA. Cody Schuffelen         case TPM_CLOCK_COARSE_FASTER:
214*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(-CLOCK_ADJUST_COARSE);
215*5c591343SA. Cody Schuffelen             break;
216*5c591343SA. Cody Schuffelen         case TPM_CLOCK_MEDIUM_SLOWER:
217*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(CLOCK_ADJUST_MEDIUM);
218*5c591343SA. Cody Schuffelen             break;
219*5c591343SA. Cody Schuffelen         case TPM_CLOCK_MEDIUM_FASTER:
220*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(-CLOCK_ADJUST_MEDIUM);
221*5c591343SA. Cody Schuffelen             break;
222*5c591343SA. Cody Schuffelen         case TPM_CLOCK_FINE_SLOWER:
223*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(CLOCK_ADJUST_FINE);
224*5c591343SA. Cody Schuffelen             break;
225*5c591343SA. Cody Schuffelen         case TPM_CLOCK_FINE_FASTER:
226*5c591343SA. Cody Schuffelen             _plat__ClockAdjustRate(-CLOCK_ADJUST_FINE);
227*5c591343SA. Cody Schuffelen             break;
228*5c591343SA. Cody Schuffelen         case TPM_CLOCK_NO_CHANGE:
229*5c591343SA. Cody Schuffelen             break;
230*5c591343SA. Cody Schuffelen         default:
231*5c591343SA. Cody Schuffelen             FAIL(FATAL_ERROR_INTERNAL);
232*5c591343SA. Cody Schuffelen             break;
233*5c591343SA. Cody Schuffelen     }
234*5c591343SA. Cody Schuffelen 
235*5c591343SA. Cody Schuffelen     return;
236*5c591343SA. Cody Schuffelen }
237*5c591343SA. Cody Schuffelen 
238*5c591343SA. Cody Schuffelen //*** TimeGetMarshaled()
239*5c591343SA. Cody Schuffelen // This function is used to access TPMS_TIME_INFO in canonical form.
240*5c591343SA. Cody Schuffelen // The function collects the time information and marshals it into 'dataBuffer'
241*5c591343SA. Cody Schuffelen // and returns the marshaled size
242*5c591343SA. Cody Schuffelen UINT16
TimeGetMarshaled(TIME_INFO * dataBuffer)243*5c591343SA. Cody Schuffelen TimeGetMarshaled(
244*5c591343SA. Cody Schuffelen     TIME_INFO       *dataBuffer     // OUT: result buffer
245*5c591343SA. Cody Schuffelen     )
246*5c591343SA. Cody Schuffelen {
247*5c591343SA. Cody Schuffelen     TPMS_TIME_INFO      timeInfo;
248*5c591343SA. Cody Schuffelen 
249*5c591343SA. Cody Schuffelen     // Fill TPMS_TIME_INFO structure
250*5c591343SA. Cody Schuffelen     timeInfo.time = g_time;
251*5c591343SA. Cody Schuffelen     TimeFillInfo(&timeInfo.clockInfo);
252*5c591343SA. Cody Schuffelen 
253*5c591343SA. Cody Schuffelen     // Marshal TPMS_TIME_INFO to canonical form
254*5c591343SA. Cody Schuffelen     return TPMS_TIME_INFO_Marshal(&timeInfo, (BYTE **)&dataBuffer, NULL);
255*5c591343SA. Cody Schuffelen }
256*5c591343SA. Cody Schuffelen 
257*5c591343SA. Cody Schuffelen //*** TimeFillInfo
258*5c591343SA. Cody Schuffelen // This function gathers information to fill in a TPMS_CLOCK_INFO structure.
259*5c591343SA. Cody Schuffelen void
TimeFillInfo(TPMS_CLOCK_INFO * clockInfo)260*5c591343SA. Cody Schuffelen TimeFillInfo(
261*5c591343SA. Cody Schuffelen     TPMS_CLOCK_INFO     *clockInfo
262*5c591343SA. Cody Schuffelen     )
263*5c591343SA. Cody Schuffelen {
264*5c591343SA. Cody Schuffelen     clockInfo->clock = go.clock;
265*5c591343SA. Cody Schuffelen     clockInfo->resetCount = gp.resetCount;
266*5c591343SA. Cody Schuffelen     clockInfo->restartCount = gr.restartCount;
267*5c591343SA. Cody Schuffelen 
268*5c591343SA. Cody Schuffelen     // If NV is not available, clock stopped advancing and the value reported is
269*5c591343SA. Cody Schuffelen     // not "safe".
270*5c591343SA. Cody Schuffelen     if(NV_IS_AVAILABLE)
271*5c591343SA. Cody Schuffelen         clockInfo->safe = go.clockSafe;
272*5c591343SA. Cody Schuffelen     else
273*5c591343SA. Cody Schuffelen         clockInfo->safe = NO;
274*5c591343SA. Cody Schuffelen 
275*5c591343SA. Cody Schuffelen     return;
276*5c591343SA. Cody Schuffelen }