mirror of
https://github.com/stefanberger/libtpms
synced 2025-12-30 18:31:53 +00:00
tpm2: Switch to UINT16 for CONTEXT_SLOT and 64k context gap
This patch addresses issue #209. The context gap for libtpms is currently only 0xff due to the CONTEXT_SLOT being a UINT8. To extend this to 0xffff, we need to define the CONTEXT_SLOT as UINT16 and introduce a global variable s_ContextArrayMask that takes on two valid values, 0xff for simulating the CONTEXT_SLOT when it was UINT8 and 0xffff for usage with the new CONTEXT_SLOT of type UINT16. All occurrences of casts to CONTEXT_SLOT are replaced with a macro CONTEXT_SLOT_MASKED that applies this mask to a value instead of using the cast. We also use it for some calculations to avoid spilling over from 1 byte into 2 bytes for example. The cast with the new code is the same as applying the mask 0xffff, and using the 0xff mask we can simulate the old CONTEXT_SLOT (1 byte), which we need for seamlessly resuming old state. We switch from the 0xff mask to the 0xffff mask when the TPM is reset. There's one place where the s_ContextArrayMask is initialized to 0xff, and this is when we resume 'old' STATE_RESET_DATA. The places where it is intialized to 0xffff are in TPM_Manufacture() and TPM_SessionStartup(SU_CLEAR), both of which are not called after resuming state. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
parent
31925c8e33
commit
db1fd5948b
6
CHANGES
6
CHANGES
@ -1,5 +1,11 @@
|
||||
CHANGES - changes for libtpms
|
||||
|
||||
version 0.9.0:
|
||||
- NOTE: Downgrade to previous versions is not possible. See below.
|
||||
- The size of the context gap has been adjusted to 0xffff from 0xff.
|
||||
As a consequence of this the volatile state's format (STATE_RESET_DATA)
|
||||
has changed and cannot be downgraded.
|
||||
|
||||
version 0.8.0
|
||||
- NOTE: Downgrade to previous versions is not possible. See below.
|
||||
- Update to TPM 2 code release 159
|
||||
|
||||
@ -996,6 +996,28 @@ typedef struct state_reset_data
|
||||
} STATE_RESET_DATA;
|
||||
EXTERN STATE_RESET_DATA gr;
|
||||
|
||||
// libtpms added begin
|
||||
/* The s_ContextSlotMask masks CONTEXT_SLOT values; this variable can have
|
||||
* only two valid values, 0xff or 0xffff. The former is used to simulate
|
||||
* a CONTEXT_SLOT defined as UINT8, the latter is used for the CONTEXT_SLOT
|
||||
* when it is a UINT16. The original TPM 2 code uses a cast to CONTEXT_SLOT
|
||||
* to truncate larger values and has been modified to use CONTEXT_SLOT_MASKED
|
||||
* to achieve the same effect with the above two values.
|
||||
*
|
||||
* Using CONTEXT_SLOT_MASKED we make sure that when we write values into
|
||||
* gr.contextArray that these values are properly masked/truncated so that
|
||||
* when we read values from gr.contextArray that we don't have to mask
|
||||
* them again.
|
||||
*
|
||||
* s_ContextSlotMask may only be initialized to 0xff when resuming an older
|
||||
* state from the time when CONTEXT_SLOT was UINT8, otherwise it must be set
|
||||
* to 0xffff. We set it to 0xffff in SessionStartup(SU_CLEAR) and to be
|
||||
* able to save the TPM state really early (and restore it) also in
|
||||
* TPM_Manufacture().
|
||||
*/
|
||||
EXTERN CONTEXT_SLOT s_ContextSlotMask;
|
||||
#define CONTEXT_SLOT_MASKED(val) ((CONTEXT_SLOT)(val) & s_ContextSlotMask) // libtpms added end
|
||||
|
||||
/* 5.9.12 NV Layout */
|
||||
/* The NV data organization is */
|
||||
/* a) a PERSISTENT_DATA structure */
|
||||
|
||||
@ -86,6 +86,9 @@ TPM_Manufacture(
|
||||
)
|
||||
{
|
||||
TPM_SU orderlyShutdown;
|
||||
|
||||
// Initialize the context slot mask for UINT16
|
||||
s_ContextSlotMask = 0xffff; // libtpms added
|
||||
#if RUNTIME_SIZE_CHECKS
|
||||
// Call the function to verify the sizes of values that result from different
|
||||
// compile options.
|
||||
|
||||
@ -1262,7 +1262,7 @@ skip_future_versions:
|
||||
}
|
||||
|
||||
#define STATE_RESET_DATA_MAGIC 0x01102332
|
||||
#define STATE_RESET_DATA_VERSION 3
|
||||
#define STATE_RESET_DATA_VERSION 4
|
||||
|
||||
static TPM_RC
|
||||
STATE_RESET_DATA_Unmarshal(STATE_RESET_DATA *data, BYTE **buffer, INT32 *size)
|
||||
@ -1295,15 +1295,38 @@ STATE_RESET_DATA_Unmarshal(STATE_RESET_DATA *data, BYTE **buffer, INT32 *size)
|
||||
rc = UINT16_Unmarshal(&array_size, buffer, size);
|
||||
}
|
||||
if (rc == TPM_RC_SUCCESS &&
|
||||
array_size != sizeof(data->contextArray)) {
|
||||
array_size != ARRAY_SIZE(data->contextArray)) {
|
||||
TPMLIB_LogTPM2Error("STATE_RESET_DATA: Bad array size for contextArray; "
|
||||
"expected %zu, got %u\n",
|
||||
sizeof(data->contextArray), array_size);
|
||||
ARRAY_SIZE(data->contextArray), array_size);
|
||||
rc = TPM_RC_BAD_PARAMETER;
|
||||
}
|
||||
if (rc == TPM_RC_SUCCESS) {
|
||||
rc = Array_Unmarshal((BYTE *)&data->contextArray, array_size,
|
||||
buffer, size);
|
||||
size_t i;
|
||||
if (hdr.version <= 3) {
|
||||
/* version <= 3 was writing an array of UINT8 */
|
||||
UINT8 element;
|
||||
for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
|
||||
rc = UINT8_Unmarshal(&element, buffer, size);
|
||||
data->contextArray[i] = element;
|
||||
}
|
||||
s_ContextSlotMask = 0xff;
|
||||
} else {
|
||||
/* version 4 and later an array of UINT16 */
|
||||
for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
|
||||
rc = UINT16_Unmarshal(&data->contextArray[i], buffer, size);
|
||||
}
|
||||
if (rc == TPM_RC_SUCCESS) {
|
||||
rc = UINT16_Unmarshal(&s_ContextSlotMask, buffer, size);
|
||||
}
|
||||
if (rc == TPM_RC_SUCCESS) {
|
||||
if (s_ContextSlotMask != 0xffff && s_ContextSlotMask != 0x00ff) {
|
||||
TPMLIB_LogTPM2Error("STATE_RESET_DATA: s_ContextSlotMask has bad value: 0x%04x\n",
|
||||
s_ContextSlotMask);
|
||||
rc = TPM_RC_BAD_PARAMETER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc == TPM_RC_SUCCESS) {
|
||||
rc = UINT64_Unmarshal(&data->contextCounter, buffer, size);
|
||||
@ -1385,19 +1408,21 @@ STATE_RESET_DATA_Marshal(STATE_RESET_DATA *data, BYTE **buffer, INT32 *size)
|
||||
BOOL has_block;
|
||||
UINT16 array_size;
|
||||
BLOCK_SKIP_INIT;
|
||||
size_t i;
|
||||
|
||||
written = NV_HEADER_Marshal(buffer, size,
|
||||
STATE_RESET_DATA_VERSION,
|
||||
STATE_RESET_DATA_MAGIC, 3);
|
||||
STATE_RESET_DATA_MAGIC, 4);
|
||||
written += TPM2B_PROOF_Marshal(&data->nullProof, buffer, size);
|
||||
written += TPM2B_Marshal(&data->nullSeed.b, buffer, size);
|
||||
written += UINT32_Marshal(&data->clearCount, buffer, size);
|
||||
written += UINT64_Marshal(&data->objectContextID, buffer, size);
|
||||
|
||||
array_size = sizeof(data->contextArray);
|
||||
array_size = ARRAY_SIZE(data->contextArray);
|
||||
written += UINT16_Marshal(&array_size, buffer, size);
|
||||
written += Array_Marshal((BYTE *)&data->contextArray, array_size,
|
||||
buffer, size);
|
||||
for (i = 0; i < array_size; i++)
|
||||
written += UINT16_Marshal(&data->contextArray[i], buffer, size);
|
||||
written += UINT16_Marshal(&s_ContextSlotMask, buffer, size);
|
||||
|
||||
written += UINT64_Marshal(&data->contextCounter, buffer, size);
|
||||
written += TPM2B_DIGEST_Marshal(&data->commandAuditDigest,
|
||||
|
||||
@ -185,7 +185,10 @@ TPMPropertyIsDefined(
|
||||
case TPM_PT_CONTEXT_GAP_MAX:
|
||||
// maximum allowed difference (unsigned) between the contextID
|
||||
// values of two saved session contexts
|
||||
#if 0
|
||||
*value = ((UINT32)1 << (sizeof(CONTEXT_SLOT) * 8)) - 1;
|
||||
#endif
|
||||
*value = s_ContextSlotMask; // libtpms added; the mask is either 0xff (old state) or 0xffff
|
||||
break;
|
||||
case TPM_PT_NV_COUNTERS_MAX:
|
||||
// maximum number of NV indexes that are allowed to have the
|
||||
|
||||
@ -73,11 +73,12 @@ ContextIdSetOldest(
|
||||
{
|
||||
CONTEXT_SLOT lowBits;
|
||||
CONTEXT_SLOT entry;
|
||||
CONTEXT_SLOT smallest = ((CONTEXT_SLOT)~0);
|
||||
CONTEXT_SLOT smallest = CONTEXT_SLOT_MASKED(~0); // libtpms changed
|
||||
UINT32 i;
|
||||
pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added
|
||||
// Set oldestSaveContext to a value indicating none assigned
|
||||
s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
|
||||
lowBits = (CONTEXT_SLOT)gr.contextCounter;
|
||||
lowBits = CONTEXT_SLOT_MASKED(gr.contextCounter); // libtpms changed
|
||||
for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
|
||||
{
|
||||
entry = gr.contextArray[i];
|
||||
@ -87,9 +88,9 @@ ContextIdSetOldest(
|
||||
// Use a less than or equal in case the oldest
|
||||
// is brand new (= lowBits-1) and equal to our initial
|
||||
// value for smallest.
|
||||
if(((CONTEXT_SLOT)(entry - lowBits)) <= smallest)
|
||||
if(CONTEXT_SLOT_MASKED(entry - lowBits) <= smallest) // libtpms changed
|
||||
{
|
||||
smallest = (entry - lowBits);
|
||||
smallest = CONTEXT_SLOT_MASKED(entry - lowBits); // libtpms changed
|
||||
s_oldestSavedSession = i;
|
||||
}
|
||||
}
|
||||
@ -140,6 +141,9 @@ SessionStartup(
|
||||
gr.contextCounter = MAX_LOADED_SESSIONS + 1;
|
||||
// Initialize oldest saved session
|
||||
s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
|
||||
|
||||
// Initialize the context slot mask for UINT16
|
||||
s_ContextSlotMask = 0xffff; // libtpms added
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@ -199,14 +203,16 @@ SequenceNumberForSavedContextIsValid(
|
||||
// structure to be validated
|
||||
)
|
||||
{
|
||||
#define MAX_CONTEXT_GAP ((UINT64)((CONTEXT_SLOT) ~0) + 1)
|
||||
#define MAX_CONTEXT_GAP ((UINT64)(CONTEXT_SLOT_MASKED(~0) + 1)) /* libtpms changed */
|
||||
pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added
|
||||
|
||||
TPM_HANDLE handle = context->savedHandle & HR_HANDLE_MASK;
|
||||
if(// Handle must be with the range of active sessions
|
||||
handle >= MAX_ACTIVE_SESSIONS
|
||||
// the array entry must be for a saved context
|
||||
|| gr.contextArray[handle] <= MAX_LOADED_SESSIONS
|
||||
// the array entry must agree with the sequence number
|
||||
|| gr.contextArray[handle] != (CONTEXT_SLOT)context->sequence
|
||||
|| gr.contextArray[handle] != CONTEXT_SLOT_MASKED(context->sequence) // libtpms changed
|
||||
// the provided sequence number has to be less than the current counter
|
||||
|| context->sequence > gr.contextCounter
|
||||
// but not so much that it could not be a valid sequence number
|
||||
@ -287,7 +293,7 @@ ContextIdSessionCreate(
|
||||
// saved context. If the value to be assigned would make the same as an
|
||||
// existing context, then we can't use it because of the ambiguity it would
|
||||
// create.
|
||||
if((CONTEXT_SLOT)gr.contextCounter
|
||||
if(CONTEXT_SLOT_MASKED(gr.contextCounter) // libtpms changed
|
||||
== gr.contextArray[s_oldestSavedSession])
|
||||
return TPM_RC_CONTEXT_GAP;
|
||||
}
|
||||
@ -298,7 +304,7 @@ ContextIdSessionCreate(
|
||||
{
|
||||
// indicate that the session associated with this handle
|
||||
// references a loaded session
|
||||
gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex + 1);
|
||||
gr.contextArray[*handle] = CONTEXT_SLOT_MASKED(sessionIndex + 1); // libtpms changed
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -446,12 +452,13 @@ SessionContextSave(
|
||||
UINT32 contextIndex;
|
||||
CONTEXT_SLOT slotIndex;
|
||||
pAssert(SessionIsLoaded(handle));
|
||||
pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added
|
||||
// check to see if the gap is already maxed out
|
||||
// Need to have a saved session
|
||||
if(s_oldestSavedSession < MAX_ACTIVE_SESSIONS
|
||||
// if the oldest saved session has the same value as the low bits
|
||||
// of the contextCounter, then the GAP is maxed out.
|
||||
&& gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter)
|
||||
&& gr.contextArray[s_oldestSavedSession] == CONTEXT_SLOT_MASKED(gr.contextCounter)) // libtpms changed
|
||||
return TPM_RC_CONTEXT_GAP;
|
||||
// if the caller wants the context counter, set it
|
||||
if(contextID != NULL)
|
||||
@ -463,7 +470,7 @@ SessionContextSave(
|
||||
// contextID value.
|
||||
slotIndex = gr.contextArray[contextIndex] - 1;
|
||||
// Set the contextID for the contextArray
|
||||
gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter;
|
||||
gr.contextArray[contextIndex] = CONTEXT_SLOT_MASKED(gr.contextCounter); // libtpms changed
|
||||
// Increment the counter
|
||||
gr.contextCounter++;
|
||||
// In the unlikely event that the 64-bit context counter rolls over...
|
||||
@ -476,7 +483,7 @@ SessionContextSave(
|
||||
}
|
||||
// if the low-order bits wrapped, need to advance the value to skip over
|
||||
// the values used to indicate that a session is loaded
|
||||
if(((CONTEXT_SLOT)gr.contextCounter) == 0)
|
||||
if(CONTEXT_SLOT_MASKED(gr.contextCounter) == 0) // libtpms changed
|
||||
gr.contextCounter += MAX_LOADED_SESSIONS + 1;
|
||||
// If no other sessions are saved, this is now the oldest.
|
||||
if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS)
|
||||
@ -504,6 +511,7 @@ SessionContextLoad(
|
||||
{
|
||||
UINT32 contextIndex;
|
||||
CONTEXT_SLOT slotIndex;
|
||||
pAssert(s_ContextSlotMask == 0xff || s_ContextSlotMask == 0xffff); // libtpms added
|
||||
pAssert(HandleGetType(*handle) == TPM_HT_POLICY_SESSION
|
||||
|| HandleGetType(*handle) == TPM_HT_HMAC_SESSION);
|
||||
// Don't bother looking if no openings
|
||||
@ -525,7 +533,7 @@ SessionContextLoad(
|
||||
// context that we can safely load is the oldest one.
|
||||
if(s_oldestSavedSession < MAX_ACTIVE_SESSIONS
|
||||
&& s_freeSessionSlots == 1
|
||||
&& (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession]
|
||||
&& CONTEXT_SLOT_MASKED(gr.contextCounter) == gr.contextArray[s_oldestSavedSession] // libtpms changed
|
||||
&& contextIndex != s_oldestSavedSession)
|
||||
return TPM_RC_CONTEXT_GAP;
|
||||
pAssert(contextIndex < MAX_ACTIVE_SESSIONS);
|
||||
|
||||
@ -219,7 +219,7 @@
|
||||
#define MAX_ACTIVE_SESSIONS 64
|
||||
#endif
|
||||
#ifndef CONTEXT_SLOT
|
||||
#define CONTEXT_SLOT UINT8 /* libtpms: use 'old' type */
|
||||
#define CONTEXT_SLOT UINT16 /* libtpms: changed from UINT8 in v0.9.0 */
|
||||
#endif
|
||||
#ifndef MAX_LOADED_SESSIONS
|
||||
#define MAX_LOADED_SESSIONS 3
|
||||
|
||||
Loading…
Reference in New Issue
Block a user