tpm2: ACT: Extend TPM2_Getcapability with TPM_CAP_ACT

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2019-11-26 16:11:21 -05:00 committed by Stefan Berger
parent 213271eed8
commit 1f4c70cd3c
4 changed files with 668 additions and 2 deletions

View File

@ -182,6 +182,7 @@ libtpms_tpm2_la_CFLAGS += -DTPM_POSIX
libtpms_tpm2_la_CFLAGS += -DTPM_LIBTPMS_CALLBACKS
libtpms_tpm2_la_SOURCES = \
tpm2/ACT_spt.c \
tpm2/ACTCommands.c \
tpm2/AlgorithmCap.c \
tpm2/AlgorithmTests.c \
@ -238,6 +239,7 @@ libtpms_tpm2_la_SOURCES = \
tpm2/ObjectCommands.c \
tpm2/Object_spt.c \
tpm2/PCR.c \
tpm2/PlatformACT.c \
tpm2/PlatformData.c \
tpm2/Policy_spt.c \
tpm2/Power.c \

303
src/tpm2/ACT_spt.c Normal file
View File

@ -0,0 +1,303 @@
/********************************************************************************/
/* */
/* ACT Command Support */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: Object_spt.c 1490 2019-07-26 21:13:22Z 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 */
/* */
/********************************************************************************/
/* 7.8 ACT Support (ACT_spt.c) */
/* 7.8.1 Introduction */
/* This code implements the ACT update code. It does not use a mutex. This code uses a platform
service (_plat__ACT_UpdateCounter()) that returns false if the update is not accepted. If this
occurs, then TPM_RC_RETRY should be sent to the caller so that they can retry the operation
later. The implementation of this is platform dependent but the reference uses a simple flag to
indicate that an update is pending and the only process that can clear that flag is the process
that does the actual update. */
/* 7.8.2 Includes */
#include "Tpm.h"
#include "ACT_spt_fp.h"
#include "Platform_fp.h"
#include "PlatformACT_fp.h" /* added kgold */
/* 7.8.3 Functions */
/* 7.8.3.1 _ActResume() */
/* This function does the resume processing for an ACT. It updates the saved count and turns
signaling back on if necessary. */
#ifndef __ACT_DISABLED // libtpms added
static void
_ActResume(
UINT32 act, //IN: the act number
ACT_STATE *actData //IN: pointer to the saved ACT data
)
{
// If the act was non-zero, then restore the counter value.
if(actData->remaining > 0)
_plat__ACT_UpdateCounter(act, actData->remaining);
// if the counter was zero and the ACT signaling, enable the signaling.
else if(go.signaledACT & (1 << act))
_plat__ACT_SetSignaled(act, TRUE);
}
#endif // libtpms added
/* 7.8.3.2 ActStartup() */
/* This function is called by TPM2_Startup() to initialize the ACT counter values. */
BOOL
ActStartup(
STARTUP_TYPE type
)
{
// Reset all the ACT hardware
_plat__ACT_Initialize();
// For TPM_RESET or TPM_RESTART, the ACTs will all be disabled and the output
// de-asserted.
if(type != SU_RESUME)
{
#ifndef __ACT_DISABLED // libtpms added
go.signaledACT = 0;
#endif // libtpms added
#define CLEAR_ACT_POLICY(N) \
go.ACT_##N.hashAlg = TPM_ALG_NULL; \
go.ACT_##N.authPolicy.b.size = 0;
FOR_EACH_ACT(CLEAR_ACT_POLICY)
}
else
{
// Resume each of the implemented ACT
#define RESUME_ACT(N) _ActResume(0x##N, &go.ACT_##N);
FOR_EACH_ACT(RESUME_ACT)
}
s_ActUpdated = 0;
_plat__ACT_EnableTicks(TRUE);
return TRUE;
}
/* 7.8.3.3 _ActSaveState() */
/* Get the counter state and the signaled state for an ACT. If the ACT has not been updated since
the last time it was saved, then divide the count by 2. */
#ifndef __ACT_DISABLED // libtpms added
static void
_ActSaveState(
UINT32 act,
P_ACT_STATE actData
)
{
actData->remaining = _plat__ACT_GetRemaining(act);
// If the ACT hasn't been updated since the last startup, then it should be
// be halved.
if((s_ActUpdated & (1 << act)) == 0)
{
// Don't halve if the count is set to max or if halving would make it zero
if((actData->remaining != UINT32_MAX) && (actData->remaining > 1))
actData->remaining /= 2;
}
if(_plat__ACT_GetSignaled(act))
go.signaledACT |= (1 << act);
}
/* 7.8.3.4 ActGetSignaled() */
/* This function returns the state of the signaled flag associated with an ACT. */
BOOL
ActGetSignaled(
TPM_RH actHandle
)
{
UINT32 act = actHandle - TPM_RH_ACT_0;
//
return _plat__ACT_GetSignaled(act);
}
#endif // libtpms added
/* 7.8.3.5 ActShutdown() */
/* This function saves the current state of the counters */
BOOL
ActShutdown(
TPM_SU state //IN: the type of the shutdown.
)
{
// if this is not shutdown state, then the only type of startup is TPM_RESTART
// so the timer values will be cleared. If this is shutdown state, get the current
// countdown and signaled values. Plus, if the counter has not been updated
// since the last restart, divide the time by 2 so that there is no attack on the
// countdown by saving the countdown state early and then not using the TPM.
if(state == TPM_SU_STATE)
{
// This will be populated as each of the ACT is queried
#ifndef __ACT_DISABLED // libtpms added
go.signaledACT = 0;
#endif // libtpms added
// Get the current count and the signaled state
#define SAVE_ACT_STATE(N) _ActSaveState(0x##N, &go.ACT_##N);
FOR_EACH_ACT(SAVE_ACT_STATE);
}
return TRUE;
}
/* 7.8.3.6 ActIsImplemented() */
/* This function determines if an ACT is implemented in both the TPM and the platform code. */
BOOL
ActIsImplemented(
UINT32 act
)
{
#define CASE_ACT_
// This switch accounts for the TPM implemente values.
switch(act)
{
#ifndef __ACT_DISABLED // libtpms added
FOR_EACH_ACT(CASE_ACT_NUMBER)
// This ensures that the platorm implementes the values implemented by
// the TPM
return _plat__ACT_GetImplemented(act);
#endif // libtpms added
default:
break;
}
return FALSE;
}
/* 7.8.3.7 ActCounterUpdate() */
/* This function updates the ACT counter. If the counter already has a pending update, it returns
TPM_RC_RETRY so that the update can be tried again later. */
#if CC_ACT_SetTimeout // libtpms added
TPM_RC
ActCounterUpdate(
TPM_RH handle, //IN: the handle of the act
UINT32 newValue //IN: the value to set in the ACT
)
{
UINT32 act;
TPM_RC result;
//
act = handle - TPM_RH_ACT_0;
// This should never fail, but...
if(!_plat__ACT_GetImplemented(act))
result = TPM_RC_VALUE;
else
{
// Will need to clear orderly so fail if we are orderly and NV is not available
if(NV_IS_ORDERLY)
RETURN_IF_NV_IS_NOT_AVAILABLE;
// if the attempt to update the counter fails, it means that there is an
// update pending so wait until it has occurred and then do an update.
if(!_plat__ACT_UpdateCounter(act, newValue))
result = TPM_RC_RETRY;
else
{
// Indicate that the ACT has been updated since last TPM2_Startup().
s_ActUpdated |= (UINT16)(1 << act);
// Need to clear the orderly flag
g_clearOrderly = TRUE;
result = TPM_RC_SUCCESS;
}
}
return result;
}
#endif // libtpms added
/* 7.8.3.8 ActGetCapabilityData() */
/* This function returns the list of ACT data */
/* Return Value Meaning */
/* YES if more ACT data is available */
/* NO if no more ACT data to */
TPMI_YES_NO
ActGetCapabilityData(
TPM_HANDLE actHandle, // IN: the handle for the starting ACT
UINT32 maxCount, // IN: maximum allowed return values
TPML_ACT_DATA *actList // OUT: ACT data list
)
{
// Initialize output property list
actList->count = 0;
// Make sure that the starting handle value is in range (again)
if((actHandle < TPM_RH_ACT_0) || (actHandle > TPM_RH_ACT_F))
return FALSE;
// The maximum count of curves we may return is MAX_ECC_CURVES
if(maxCount > MAX_ACT_DATA)
maxCount = MAX_ACT_DATA;
// Scan the ACT data from the starting ACT
for(; actHandle <= TPM_RH_ACT_F; actHandle++)
{
UINT32 act = actHandle - TPM_RH_ACT_0;
if(actList->count < maxCount)
{
if(ActIsImplemented(act))
{
TPMS_ACT_DATA *actData = &actList->actData[actList->count];
//
memset(&actData->attributes, 0, sizeof(actData->attributes));
actData->handle = actHandle;
actData->timeout = _plat__ACT_GetRemaining(act);
/* actData->attributes.signaled = _plat__ACT_GetSignaled(act); kgold */
if (_plat__ACT_GetSignaled(act)) {
SET_ATTRIBUTE(actData->attributes, TPMA_ACT, signaled);
}
actList->count++;
}
}
else
{
if(_plat__ACT_GetImplemented(act))
return YES;
}
}
// If we get here, either all of the ACT values were put in the list, or the list
// was filled and there are no more ACT values to return
return NO;
}

View File

@ -3,7 +3,7 @@
/* Capability Commands */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: CapabilityCommands.c 1490 2019-07-26 21:13:22Z kgoldman $ */
/* $Id: CapabilityCommands.c 1519 2019-11-15 20:43:51Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
@ -55,7 +55,7 @@
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016 - 2018 */
/* (c) Copyright IBM Corp. and others, 2016 - 2019 */
/* */
/********************************************************************************/
@ -180,6 +180,14 @@ TPM2_GetCapability(
in->propertyCount,
&data->authPolicies);
break;
case TPM_CAP_ACT:
if(((TPM_RH)in->property < TPM_RH_ACT_0)
|| ((TPM_RH)in->property > TPM_RH_ACT_F))
return TPM_RCS_VALUE + RC_GetCapability_property;
out->moreData = ActGetCapabilityData((TPM_HANDLE)in->property,
in->propertyCount,
&data->actData);
break;
case TPM_CAP_VENDOR_PROPERTY:
// vendor property is not implemented
default:

353
src/tpm2/PlatformACT.c Normal file
View File

@ -0,0 +1,353 @@
/********************************************************************************/
/* */
/* Platform Authenticated Countdown Timer */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: PlatformACT.c 1529 2019-11-21 23:29:01Z 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, 2019 */
/* */
/********************************************************************************/
/* C.16 PlatformACT.c */
/* C.16.1. Includes */
#include "Platform.h"
#include "PlatformACT_fp.h"
/* C.16.2. Functions */
/* C.16.2.1. ActSignal() */
/* Function called when there is an ACT event to signal or unsignal */
#ifndef __ACT_DISABLED // libtpms added
static void
ActSignal(
P_ACT_DATA actData,
int on
)
{
if(actData == NULL)
return;
// If this is to turn a signal on, don't do anything if it is already on. If this
// is to turn the signal off, do it anyway because this might be for
// initialization.
if(on && (actData->signaled == TRUE))
return;
actData->signaled = (uint8_t)on;
// If there is an action, then replace the "Do something" with the correct action.
// It should test 'on' to see if it is turning the signal on or off.
switch(actData->number)
{
#if RH_ACT_0
case 0: // Do something
return;
#endif
#if RH_ACT_1
case 1: // Do something
return;
#endif
#if RH_ACT_2
case 2: // Do something
return;
#endif
#if RH_ACT_3
case 3: // Do something
return;
#endif
#if RH_ACT_4
case 4: // Do something
return;
#endif
#if RH_ACT_5
case 5: // Do something
return;
#endif
#if RH_ACT_6
case 6: // Do something
return;
#endif
#if RH_ACT_7
case 7: // Do something
return;
#endif
#if RH_ACT_8
case 8: // Do something
return;
#endif
#if RH_ACT_9
case 9: // Do something
return;
#endif
#if RH_ACT_A
case 0xA: // Do something
return;
#endif
#if RH_ACT_B
case 0xB:
// Do something
return;
#endif
#if RH_ACT_C
case 0xC: // Do something
return;
#endif
#if RH_ACT_D
case 0xD: // Do something
return;
#endif
#if RH_ACT_E
case 0xE: // Do something
return;
#endif
#if RH_ACT_F
case 0xF: // Do something
return;
#endif
default:
return;
}
}
#endif // libtpms added
/* C.16.2.2. ActGetDataPointer() */
static P_ACT_DATA
ActGetDataPointer(
uint32_t act
)
{
#define RETURN_ACT_POINTER(N) if(0x##N == act) return &ACT_##N;
FOR_EACH_ACT(RETURN_ACT_POINTER)
return (P_ACT_DATA)NULL;
}
/* C.16.2.3. _plat__ACT_GetImplemented() */
/* This function tests to see if an ACT is implemented. It is a belt and suspenders function because
the TPM should not be calling to to manipulate an ACT that is not implemented. However, this
could help the simulator code which doesn't necessarily know if an ACT is implemented or not. */
LIB_EXPORT int
_plat__ACT_GetImplemented(
uint32_t act
)
{
return (ActGetDataPointer(act) != NULL);
}
/* C.16.2.4. _plat__ACT_GetRemaining() */
/* This function returns the remaining time. If an update is pending, newValue is
returned. Otherwise, the current counter value is returned. Note that since the timers keep
running, the returned value can get stale immediately. The actual count value will be no greater
than the returned value. */
LIB_EXPORT uint32_t
_plat__ACT_GetRemaining(
uint32_t act //IN: the ACT selector
)
{
P_ACT_DATA actData = ActGetDataPointer(act);
uint32_t remain;
//
if(actData == NULL)
return 0;
remain = actData->remaining;
if(actData->pending)
remain = actData->newValue;
return remain;
}
/* C.16.2.5. _plat__ACT_GetSignaled() */
LIB_EXPORT int
_plat__ACT_GetSignaled(
uint32_t act //IN: number of ACT to check
)
{
P_ACT_DATA actData = ActGetDataPointer(act);
//
if(actData == NULL)
return 0;
return (int)actData->signaled;
}
/* C.16.2.6. _plat__ACT_SetSignaled() */
#ifndef __ACT_DISABLED // libtpms added
LIB_EXPORT void
_plat__ACT_SetSignaled(
uint32_t act,
int on
)
{
ActSignal(ActGetDataPointer(act), on);
}
/* C.16.2.7. _plat__ACT_GetPending() */
LIB_EXPORT int
_plat__ACT_GetPending(
uint32_t act //IN: number of ACT to check
)
{
P_ACT_DATA actData = ActGetDataPointer(act);
//
if(actData == NULL)
return 0;
return (int)actData->pending;
}
/* C.16.2.8. _plat__ACT_UpdateCounter() */
/* This function is used to write the newValue for the counter. If an update is pending, then no
update occurs and the function returns FALSE. If setSignaled is TRUE, then the ACT signaled state
is SET and if newValue is 0, nothing is posted. */
LIB_EXPORT int
_plat__ACT_UpdateCounter(
uint32_t act, // IN: ACT to update
uint32_t newValue // IN: the value to post
)
{
P_ACT_DATA actData = ActGetDataPointer(act);
//
if(actData == NULL)
// actData doesn't exist but pretend update is pending rather than indicate
// that a retry is necessary.
return TRUE;
// if an update is pending then return FALSE so that there will be a retry
if(actData->pending != 0)
return FALSE;
actData->newValue = newValue;
actData->pending = TRUE;
return TRUE;
}
#endif // libtpms added
/* C.16.2.9. _plat__ACT_EnableTicks() */
/* This enables and disables the processing of the once-per-second ticks. This should be turned off
(enable = FALSE) by _TPM_Init() and turned on (enable = TRUE) by TPM2_Startup() after all the
initializations have completed. */
LIB_EXPORT void
_plat__ACT_EnableTicks(
int enable
)
{
actTicksAllowed = enable;
}
/* C.16.2.10. ActDecrement() */
/* If newValue is non-zero it is copied to remaining and then newValue is set to zero. Then
remaining is decremented by one if it is not already zero. If the value is decremented to zero,
then the associated event is signaled. If setting remaining causes it to be greater than 1, then
the signal associated with the ACT is turned off. */
#ifndef __ACT_DISABLED // libtpms added
static void
ActDecrement(
P_ACT_DATA actData
)
{
// Check to see if there is an update pending
if(actData->pending)
{
// If this update will cause the count to go from non-zero to zero, set
// the newValue to 1 so that it will timeout when decremented below.
if((actData->newValue == 0) && (actData->remaining != 0))
actData->newValue = 1;
actData->remaining = actData->newValue;
// Update processed
actData->pending = 0;
}
// no update so countdown if the count is non-zero but not max
if((actData->remaining != 0) && (actData->remaining != UINT32_MAX))
{
// If this countdown causes the count to go to zero, then turn the signal for
// the ACT on.
if((actData->remaining -= 1) == 0)
ActSignal(actData, TRUE);
}
// If the current value of the counter is non-zero, then the signal should be
// off.
if(actData->signaled && (actData->remaining > 0))
ActSignal(actData, FALSE);
}
/* C.16.2.11. _plat__ACT_Tick() */
/* This processes the once-per-second clock tick from the hardware. This is set up for the simulator to use the control interface to send ticks to the TPM. These ticks do not have to be on a per second basis. They can be as slow or as fast as desired so that the simulation can be tested. */
LIB_EXPORT void
_plat__ACT_Tick(
void
)
{
// Ticks processing is turned off at certain times just to make sure that nothing
// strange is happening before pointers and things are
if(actTicksAllowed)
{
// Handle the update for each counter.
#define DECREMENT_COUNT(N) ActDecrement(&ACT_##N);
FOR_EACH_ACT(DECREMENT_COUNT)
}
}
/* C.16.2.12. ActZero() */
/* This function initializes a single ACT */
static void
ActZero(
uint32_t act,
P_ACT_DATA actData
)
{
actData->remaining = 0;
actData->newValue = 0;
actData->pending = 0;
actData->number = (uint8_t)act;
ActSignal(actData, FALSE);
}
#endif // libtpms added
/* C.16.2.13. _plat__ACT_Initialize() */
/* This function initializes the ACT hardware and data structures */
LIB_EXPORT int
_plat__ACT_Initialize(
void
)
{
actTicksAllowed = 0;
#define ZERO_ACT(N) ActZero(0x##N, &ACT_##N);
FOR_EACH_ACT(ZERO_ACT)
return TRUE;
}