summaryrefslogtreecommitdiffstats
path: root/src/tpm2/Time.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm2/Time.c')
-rw-r--r--src/tpm2/Time.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/src/tpm2/Time.c b/src/tpm2/Time.c
new file mode 100644
index 0000000..9ff1bb5
--- /dev/null
+++ b/src/tpm2/Time.c
@@ -0,0 +1,273 @@
+/********************************************************************************/
+/* */
+/* Functions relating to the TPM's time functions */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: Time.c 1519 2019-11-15 20:43:51Z kgoldman $ */
+/* */
+/* Licenses and Notices */
+/* */
+/* 1. Copyright Licenses: */
+/* */
+/* - Trusted Computing Group (TCG) grants to the user of the source code in */
+/* this specification (the "Source Code") a worldwide, irrevocable, */
+/* nonexclusive, royalty free, copyright license to reproduce, create */
+/* derivative works, distribute, display and perform the Source Code and */
+/* derivative works thereof, and to grant others the rights granted herein. */
+/* */
+/* - The TCG grants to the user of the other parts of the specification */
+/* (other than the Source Code) the rights to reproduce, distribute, */
+/* display, and perform the specification solely for the purpose of */
+/* developing products based on such documents. */
+/* */
+/* 2. Source Code Distribution Conditions: */
+/* */
+/* - Redistributions of Source Code must retain the above copyright licenses, */
+/* this list of conditions and the following disclaimers. */
+/* */
+/* - Redistributions in binary form must reproduce the above copyright */
+/* licenses, this list of conditions and the following disclaimers in the */
+/* documentation and/or other materials provided with the distribution. */
+/* */
+/* 3. Disclaimers: */
+/* */
+/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
+/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
+/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
+/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
+/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
+/* information on specification licensing rights available through TCG */
+/* membership agreements. */
+/* */
+/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
+/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
+/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
+/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
+/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
+/* */
+/* - Without limitation, TCG and its members and licensors disclaim all */
+/* liability, including liability for infringement of any proprietary */
+/* rights, relating to use of information in this specification and to the */
+/* implementation of this specification, and TCG disclaims all liability for */
+/* cost of procurement of substitute goods or services, lost profits, loss */
+/* of use, loss of data or any incidental, consequential, direct, indirect, */
+/* or special damages, whether under contract, tort, warranty or otherwise, */
+/* arising in any way out of use or reliance upon this specification or any */
+/* information herein. */
+/* */
+/* (c) Copyright IBM Corp. and others, 2016 - 2019 */
+/* */
+/********************************************************************************/
+
+/* 8.10.1 Introduction */
+/* This file contains the functions relating to the TPM's time functions including the interface to
+ the implementation-specific time functions. */
+/* 8.10.2 Includes */
+#include "Tpm.h"
+#include "PlatformClock.h"
+/* 8.10.3 Functions */
+/* 8.10.3.1 TimePowerOn() */
+/* This function initialize time info at _TPM_Init(). */
+/* This function is called at _TPM_Init() so that the TPM time can start counting as soon as the TPM
+ comes out of reset and doesn't have to wait until TPM2_Startup() in order to begin the new time
+ epoch. This could be significant for systems that could get powered up but not run any TPM
+ commands for some period of time. */
+void
+TimePowerOn(
+ void
+ )
+{
+ g_time = _plat__TimerRead();
+}
+/* 8.10.3.2 TimeNewEpoch() */
+/* This function does the processing to generate a new time epoch nonce and set NV for update. This
+ function is only called when NV is known to be available and the clock is running. The epoch is
+ updated to persistent data. */
+static void
+TimeNewEpoch(
+ void
+ )
+{
+#if CLOCK_STOPS
+ CryptRandomGenerate(sizeof(CLOCK_NONCE), (BYTE *)&g_timeEpoch);
+#else
+ // if the epoch is kept in NV, update it.
+ gp.timeEpoch++;
+ NV_SYNC_PERSISTENT(timeEpoch);
+#endif
+ // Clean out any lingering state
+ _plat__TimerWasStopped();
+}
+/* 8.10.3.3 TimeStartup() */
+/* This function updates the resetCount and restartCount components of TPMS_CLOCK_INFO structure at
+ TPM2_Startup(). */
+/* This function will deal with the deferred creation of a new epoch. TimeUpdateToCurrent() will not
+ start a new epoch even if one is due when TPM_Startup() has not been run. This is because the
+ state of NV is not known until startup completes. When Startup is done, then it will create the
+ epoch nonce to complete the initializations by calling this function. */
+BOOL
+TimeStartup(
+ STARTUP_TYPE type // IN: start up type
+ )
+{
+ NOT_REFERENCED(type);
+ // If the previous cycle is orderly shut down, the value of the safe bit
+ // the same as previously saved. Otherwise, it is not safe.
+ if(!NV_IS_ORDERLY)
+ go.clockSafe = NO;
+ return TRUE;
+}
+/* 8.10.3.4 TimeClockUpdate() */
+/* This function updates go.clock. If newTime requires an update of NV, then NV is checked for
+ availability. If it is not available or is rate limiting, then go.clock is not updated and the
+ function returns an error. If newTime would not cause an NV write, then go.clock is updated. If
+ an NV write occurs, then go.safe is SET. */
+void
+TimeClockUpdate(
+ UINT64 newTime // IN: New time value in mS.
+ )
+{
+#define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1)
+ // Check to see if the update will cause a need for an nvClock update
+ if((newTime | CLOCK_UPDATE_MASK) > (go.clock | CLOCK_UPDATE_MASK))
+ {
+ pAssert(g_NvStatus == TPM_RC_SUCCESS);
+ // Going to update the NV time state so SET the safe flag
+ go.clockSafe = YES;
+ // update the time
+ go.clock = newTime;
+
+ /* libtpms: Changing the clock alone does not cause the permanent
+ * state to be written to storage, there must be other
+ * reasons as well.
+ */
+ UPDATE_TYPE old_g_updateNV = g_updateNV; // libtpms added
+
+ NvWrite(NV_ORDERLY_DATA, sizeof(go), &go);
+
+ g_updateNV = old_g_updateNV; // libtpms added
+ }
+ else
+ // No NV update needed so just update
+ go.clock = newTime;
+}
+/* 8.10.3.5 TimeUpdate() */
+/* This function is used to update the time and clock values. If the TPM has run TPM2_Startup(),
+ this function is called at the start of each command. If the TPM has not run TPM2_Startup(), this
+ is called from TPM2_Startup() to get the clock values initialized. It is not called on command
+ entry because, in this implementation, the go structure is not read from NV until
+ TPM2_Startup(). The reason for this is that the initialization code (_TPM_Init()) may run before
+ NV is accessible. */
+void
+TimeUpdate(
+ void
+ )
+{
+ UINT64 elapsed;
+ //
+ // Make sure that we consume the current _plat__TimerWasStopped() state.
+ if(_plat__TimerWasStopped())
+ {
+ TimeNewEpoch();
+ }
+ // Get the difference between this call and the last time we updated the tick
+ // timer.
+ elapsed = _plat__TimerRead() - g_time;
+ // Don't read +
+ g_time += elapsed;
+ // Don't need to check the result because it has to be success because have
+ // already checked that NV is available.
+ TimeClockUpdate(go.clock + elapsed);
+ // Call self healing logic for dictionary attack parameters
+ DASelfHeal();
+}
+/* 8.10.3.6 TimeUpdateToCurrent() */
+/* This function updates the Time and Clock in the global TPMS_TIME_INFO structure. */
+/* In this implementation, Time and Clock are updated at the beginning of each command and the
+ values are unchanged for the duration of the command. */
+/* Because Clock updates may require a write to NV memory, Time and Clock are not allowed to advance
+ if NV is not available. When clock is not advancing, any function that uses Clock will fail and
+ return TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE. */
+/* This implementation does not do rate limiting. If the implementation does do rate limiting, then
+ the Clock update should not be inhibited even when doing rate limiting. */
+void
+TimeUpdateToCurrent(
+ void
+ )
+{
+ // Can't update time during the dark interval or when rate limiting so don't
+ // make any modifications to the internal clock value. Also, defer any clock
+ // processing until TPM has run TPM2_Startup()
+ if(!NV_IS_AVAILABLE || !TPMIsStarted())
+ return;
+ TimeUpdate();
+}
+/* 8.10.3.7 TimeSetAdjustRate() */
+/* This function is used to perform rate adjustment on Time and Clock. */
+void
+TimeSetAdjustRate(
+ TPM_CLOCK_ADJUST adjust // IN: adjust constant
+ )
+{
+ switch(adjust)
+ {
+ case TPM_CLOCK_COARSE_SLOWER:
+ _plat__ClockAdjustRate(CLOCK_ADJUST_COARSE);
+ break;
+ case TPM_CLOCK_COARSE_FASTER:
+ _plat__ClockAdjustRate(-CLOCK_ADJUST_COARSE);
+ break;
+ case TPM_CLOCK_MEDIUM_SLOWER:
+ _plat__ClockAdjustRate(CLOCK_ADJUST_MEDIUM);
+ break;
+ case TPM_CLOCK_MEDIUM_FASTER:
+ _plat__ClockAdjustRate(-CLOCK_ADJUST_MEDIUM);
+ break;
+ case TPM_CLOCK_FINE_SLOWER:
+ _plat__ClockAdjustRate(CLOCK_ADJUST_FINE);
+ break;
+ case TPM_CLOCK_FINE_FASTER:
+ _plat__ClockAdjustRate(-CLOCK_ADJUST_FINE);
+ break;
+ case TPM_CLOCK_NO_CHANGE:
+ break;
+ default:
+ FAIL(FATAL_ERROR_INTERNAL);
+ break;
+ }
+ return;
+}
+/* 8.10.3.8 TimeGetMarshaled() */
+/* This function is used to access TPMS_TIME_INFO in canonical form. The function collects the time
+ information and marshals it into dataBuffer and returns the marshaled size */
+/* Return Value Meaning */
+UINT16
+TimeGetMarshaled(
+ TIME_INFO *dataBuffer // OUT: result buffer
+ )
+{
+ TPMS_TIME_INFO timeInfo;
+ // Fill TPMS_TIME_INFO structure
+ timeInfo.time = g_time;
+ TimeFillInfo(&timeInfo.clockInfo);
+ // Marshal TPMS_TIME_INFO to canonical form
+ return TPMS_TIME_INFO_Marshal(&timeInfo, (BYTE **)&dataBuffer, NULL);
+}
+/* 8.10.3.9 TimeFillInfo */
+/* This function gathers information to fill in a TPMS_CLOCK_INFO structure. */
+void
+TimeFillInfo(
+ TPMS_CLOCK_INFO *clockInfo
+ )
+{
+ clockInfo->clock = go.clock;
+ clockInfo->resetCount = gp.resetCount;
+ clockInfo->restartCount = gr.restartCount;
+ // If NV is not available, clock stopped advancing and the value reported is
+ // not "safe".
+ if(NV_IS_AVAILABLE)
+ clockInfo->safe = go.clockSafe;
+ else
+ clockInfo->safe = NO;
+ return;
+}