diff --git a/CHANGES b/CHANGES index 5403b425..3247f26b 100644 --- a/CHANGES +++ b/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 diff --git a/src/tpm2/Global.h b/src/tpm2/Global.h index 007b0a02..84a0d13e 100644 --- a/src/tpm2/Global.h +++ b/src/tpm2/Global.h @@ -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 */ diff --git a/src/tpm2/Manufacture.c b/src/tpm2/Manufacture.c index 19b480d9..032bc763 100644 --- a/src/tpm2/Manufacture.c +++ b/src/tpm2/Manufacture.c @@ -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. diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index a0299de1..12be70a4 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -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, diff --git a/src/tpm2/PropertyCap.c b/src/tpm2/PropertyCap.c index 5c933187..db7d679c 100644 --- a/src/tpm2/PropertyCap.c +++ b/src/tpm2/PropertyCap.c @@ -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 diff --git a/src/tpm2/Session.c b/src/tpm2/Session.c index b36ac234..991a1460 100644 --- a/src/tpm2/Session.c +++ b/src/tpm2/Session.c @@ -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); diff --git a/src/tpm2/TpmProfile.h b/src/tpm2/TpmProfile.h index e406bceb..e5764c9d 100644 --- a/src/tpm2/TpmProfile.h +++ b/src/tpm2/TpmProfile.h @@ -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