tpm2: Add SEED_COMPAT_LEVEL to seeds in PERSISTENT_DATA

Add a variable seedCompatLevel to the each seed in the PERSISTENT_DATA
that allows us to track the age of the seed. Whenever a new seed
is created the seedCompatLevel is also written and set to the latest
version. This seedCompatLevel then influences the crypto algorithm that
can be used for deriving keys so that previously derived keys
are now still generated in the same way. When the seed is changed
the old keys are all useless and newly derived keys can then use
the new algorithm.

This patch only sets the variables to the current compatibility
level SEED_COMPAT_LEVEL_ORIGINAL and writes it out as part of the state
file. This makes the state file not downgradeable.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2019-06-09 17:19:33 -04:00 committed by Stefan Berger
parent 63f3354d58
commit eabcd048c4
7 changed files with 152 additions and 3 deletions

View File

@ -499,6 +499,7 @@ noinst_HEADERS += \
tpm2/X509_spt_fp.h \
tpm2/ZGen_2Phase_fp.h \
\
tpm2/BackwardsCompatibility.h \
tpm2/LibtpmsCallbacks.h \
tpm2/NVMarshal.h \
tpm2/StateMarshal.h \

View File

@ -0,0 +1,48 @@
/********************************************************************************/
/* */
/* Backwards compatibility related stuff */
/* Written by Stefan Berger */
/* IBM Thomas J. Watson Research Center */
/* */
/* (c) Copyright IBM Corporation 2017,2018. */
/* */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/********************************************************************************/
#ifndef BACKWARDS_COMPATIBILITY_H
#define BACKWARDS_COMPATIBILITY_H
typedef UINT8 SEED_COMPAT_LEVEL;
enum {
SEED_COMPAT_LEVEL_ORIGINAL = 0, /* original TPM 2 code up to rev155 */
SEED_COMPAT_LEVEL_LAST = SEED_COMPAT_LEVEL_ORIGINAL
};
#endif /* BACKWARDS_COMPATIBILITY_H */

View File

@ -83,6 +83,7 @@ _NORMAL_WARNING_LEVEL_
#undef CONTEXT_SLOT
# define CONTEXT_SLOT UINT8
#endif
#include "BackwardsCompatibility.h" // libtpms added
#include "Capabilities.h"
#include "TpmTypes.h"
#include "CommandAttributes.h"
@ -704,6 +705,10 @@ typedef struct
TPM2B_SEED EPSeed;
TPM2B_SEED SPSeed;
TPM2B_SEED PPSeed;
// SEED_COMPAT_LEVELs related to creation time of seeds
SEED_COMPAT_LEVEL EPSeedCompatLevel; // libtpms added begin
SEED_COMPAT_LEVEL SPSeedCompatLevel;
SEED_COMPAT_LEVEL PPSeedCompatLevel; // libtpms added end
// Note there is a nullSeed in the state_reset memory.
// Hierarchy proofs
TPM2B_PROOF phProof;

View File

@ -86,6 +86,9 @@ HierarchyPreInstall_Init(
#endif
CryptRandomGenerate(gp.SPSeed.t.size, gp.SPSeed.t.buffer);
CryptRandomGenerate(gp.PPSeed.t.size, gp.PPSeed.t.buffer);
gp.EPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added begin
gp.SPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST;
gp.PPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added end
// Initialize owner, endorsement and lockout authorization
gp.ownerAuth.t.size = 0;
gp.endorsementAuth.t.size = 0;
@ -109,6 +112,9 @@ HierarchyPreInstall_Init(
NV_SYNC_PERSISTENT(EPSeed);
NV_SYNC_PERSISTENT(SPSeed);
NV_SYNC_PERSISTENT(PPSeed);
NV_SYNC_PERSISTENT(EPSeedCompatLevel); // libtpms added begin
NV_SYNC_PERSISTENT(SPSeedCompatLevel);
NV_SYNC_PERSISTENT(PPSeedCompatLevel); // libtpms added end
NV_SYNC_PERSISTENT(ownerAuth);
NV_SYNC_PERSISTENT(endorsementAuth);
NV_SYNC_PERSISTENT(lockoutAuth);
@ -207,6 +213,31 @@ HierarchyGetPrimarySeed(
}
return seed;
}
// libtpms added begin
SEED_COMPAT_LEVEL
HierarchyGetPrimarySeedCompatLevel(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
)
{
switch(hierarchy)
{
case TPM_RH_PLATFORM:
return gp.PPSeedCompatLevel;
break;
case TPM_RH_OWNER:
return gp.SPSeedCompatLevel;
break;
case TPM_RH_ENDORSEMENT:
return gp.EPSeedCompatLevel;
break;
case TPM_RH_NULL:
return SEED_COMPAT_LEVEL_LAST;
default:
FAIL(FATAL_ERROR_INTERNAL);
break;
}
}
// libtpms added end
/* 8.3.3.5 HierarchyIsEnabled() */
/* This function checks to see if a hierarchy is enabled. */
/* NOTE: The TPM_RH_NULL hierarchy is always enabled. */

View File

@ -294,6 +294,7 @@ TPM2_ChangePPS(
// Internal Data Update
// Reset platform hierarchy seed from RNG
CryptRandomGenerate(sizeof(gp.PPSeed.t.buffer), gp.PPSeed.t.buffer);
gp.PPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added
// Create a new phProof value from RNG to prevent the saved platform
// hierarchy contexts being loaded
CryptRandomGenerate(sizeof(gp.phProof.t.buffer), gp.phProof.t.buffer);
@ -306,6 +307,7 @@ TPM2_ChangePPS(
NvFlushHierarchy(TPM_RH_PLATFORM);
// Save hierarchy changes to NV
NV_SYNC_PERSISTENT(PPSeed);
NV_SYNC_PERSISTENT(PPSeedCompatLevel); // libtpms added
NV_SYNC_PERSISTENT(phProof);
// Re-initialize PCR policies
#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
@ -338,6 +340,7 @@ TPM2_ChangeEPS(
// Internal Data Update
// Reset endorsement hierarchy seed from RNG
CryptRandomGenerate(sizeof(gp.EPSeed.t.buffer), gp.EPSeed.t.buffer);
gp.EPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added
// Create new ehProof value from RNG
CryptRandomGenerate(sizeof(gp.ehProof.t.buffer), gp.ehProof.t.buffer);
// Enable endorsement hierarchy
@ -355,6 +358,7 @@ TPM2_ChangeEPS(
NvFlushHierarchy(TPM_RH_ENDORSEMENT);
// Save hierarchy changes to NV
NV_SYNC_PERSISTENT(EPSeed);
NV_SYNC_PERSISTENT(EPSeedCompatLevel); // libtpms added
NV_SYNC_PERSISTENT(ehProof);
NV_SYNC_PERSISTENT(endorsementAuth);
NV_SYNC_PERSISTENT(endorsementAlg);
@ -385,6 +389,7 @@ TPM2_Clear(
// Internal Data Update
// Reset storage hierarchy seed from RNG
CryptRandomGenerate(sizeof(gp.SPSeed.t.buffer), gp.SPSeed.t.buffer);
gp.SPSeedCompatLevel = SEED_COMPAT_LEVEL_LAST; // libtpms added
// Create new shProof and ehProof value from RNG
CryptRandomGenerate(sizeof(gp.shProof.t.buffer), gp.shProof.t.buffer);
CryptRandomGenerate(sizeof(gp.ehProof.t.buffer), gp.ehProof.t.buffer);

View File

@ -78,6 +78,12 @@ TPM2B_SEED *
HierarchyGetPrimarySeed(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
);
// libtpms added begin
SEED_COMPAT_LEVEL
HierarchyGetPrimarySeedCompatLevel(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
);
// libtpms added end
BOOL
HierarchyIsEnabled(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy

View File

@ -241,6 +241,29 @@ BOOL_Unmarshal(BOOL *boolean, BYTE **buffer, INT32 *size)
return rc;
}
static UINT16
SEED_COMPAT_LEVEL_Marshal(SEED_COMPAT_LEVEL *source,
BYTE **buffer, INT32 *size)
{
return UINT8_Marshal((UINT8 *)source, buffer, size);
}
static TPM_RC
SEED_COMPAT_LEVEL_Unmarshal(SEED_COMPAT_LEVEL *source,
BYTE **buffer, INT32 *size,
const char *name)
{
TPM_RC rc;
rc = UINT8_Unmarshal((UINT8 *)source, buffer, size);
if (rc == TPM_RC_SUCCESS && *source > SEED_COMPAT_LEVEL_LAST) {
TPMLIB_LogTPM2Error("%s compatLevel '%u' higher than supported '%u'\n",
name, *source, SEED_COMPAT_LEVEL_LAST);
rc = TPM_RC_BAD_VERSION;
}
return rc;
}
static int
TPM2B_Cmp(const TPM2B *t1, const TPM2B *t2)
{
@ -3689,7 +3712,7 @@ skip_future_versions:
}
#define PERSISTENT_DATA_MAGIC 0x12213443
#define PERSISTENT_DATA_VERSION 3
#define PERSISTENT_DATA_VERSION 4
static UINT16
PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size)
@ -3702,7 +3725,7 @@ PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size)
written = NV_HEADER_Marshal(buffer, size,
PERSISTENT_DATA_VERSION,
PERSISTENT_DATA_MAGIC, 1);
PERSISTENT_DATA_MAGIC, 4);
written += BOOL_Marshal(&data->disableClear, buffer, size);
written += TPM_ALG_ID_Marshal(&data->ownerAlg, buffer, size);
written += TPM_ALG_ID_Marshal(&data->endorsementAlg, buffer, size);
@ -3774,9 +3797,18 @@ PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size)
/* there's a 'shadow' pcrAllocated as well */
written += TPML_PCR_SELECTION_Marshal(&gp.pcrAllocated, buffer, size);
written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
written += SEED_COMPAT_LEVEL_Marshal(&data->EPSeedCompatLevel,
buffer, size);
written += SEED_COMPAT_LEVEL_Marshal(&data->SPSeedCompatLevel,
buffer, size);
written += SEED_COMPAT_LEVEL_Marshal(&data->PPSeedCompatLevel,
buffer, size);
written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
/* future versions append below this line */
BLOCK_SKIP_WRITE_POP(size);
BLOCK_SKIP_WRITE_POP(size);
BLOCK_SKIP_WRITE_POP(size);
@ -3962,6 +3994,11 @@ skip_num_policy_pcr_group:
#endif
}
/* default values before conditional block */
data->EPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
data->SPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
data->PPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
/* version 2 starts having indicator for next versions that we can skip;
this allows us to downgrade state */
if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
@ -3969,8 +4006,24 @@ skip_num_policy_pcr_group:
"Volatile State", "version 3 or later");
rc = TPML_PCR_SELECTION_Unmarshal(&shadow.pcrAllocated, buffer, size);
BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 4, buffer, size,
"PERSISTENT DATA", "version 4 or later");
if (rc == TPM_RC_SUCCESS) {
rc = SEED_COMPAT_LEVEL_Unmarshal(&data->EPSeedCompatLevel,
buffer, size, "EPSeed");
}
if (rc == TPM_RC_SUCCESS) {
rc = SEED_COMPAT_LEVEL_Unmarshal(&data->SPSeedCompatLevel,
buffer, size, "SPSeed");
}
if (rc == TPM_RC_SUCCESS) {
rc = SEED_COMPAT_LEVEL_Unmarshal(&data->PPSeedCompatLevel,
buffer, size, "PPSeed");
}
BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
"PERSISTENT DATA", "version 5 or later");
/* future versions nest-append here */
}