From b44c0a866aa4ca300527a8f9590e03bdf22eddbe Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 16 Oct 2024 18:04:16 -0400 Subject: [PATCH 1/7] tpm2: Set currentSvn to number derived from library version Set the currentSvn number to a number derived from the library version. Start out with currentSvn '0'. The number would then follow the following numbering scheme relative to possible future libtpms versions: v0.10 : 0x0000 v0.10.1 : 0x0001 v0.10.2 : 0x0002 v0.11 : 0x0010 v0.11.1 : 0x0011 v1.0 : 0x0020 v1.0.1 : 0x0021 Signed-off-by: Stefan Berger --- src/tpm2/VendorInfo.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tpm2/VendorInfo.c b/src/tpm2/VendorInfo.c index 5f416ac1c..df8f2b8ef 100644 --- a/src/tpm2/VendorInfo.c +++ b/src/tpm2/VendorInfo.c @@ -66,6 +66,7 @@ // //** Includes #include "Platform.h" +#include "tpm_library.h" // libtpms added // In this sample platform, these are compile time constants, but are not required to be. #define MANUFACTURER "IBM" @@ -77,10 +78,13 @@ #define FIRMWARE_V2 (0x00120000) #define MAX_SVN 255 -#if SIMULATION // libtpms added +#if SIMULATION // libtpms added static uint32_t currentHash = FIRMWARE_V2; -#endif -static uint16_t currentSvn = 10; +#endif // libtpms added begin +MUST_BE(TPM_LIBRARY_VER_MAJOR == 0); +MUST_BE(TPM_LIBRARY_VER_MICRO <= 15); /* 4 bits fir micro */ // libtpms added end +static uint16_t currentSvn = ((TPM_LIBRARY_VER_MINOR - 10) << 4 | + TPM_LIBRARY_VER_MICRO); // Similar to the Core Library's ByteArrayToUint32, but usable in Platform code. static uint32_t StringToUint32(const char s[4]) // libtpms changed: added const From 2a202158d70a2c78b18bc33bd973e4dc80b7d1bf Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 16 Oct 2024 18:14:50 -0400 Subject: [PATCH 2/7] tpm2: Comment-out MAX_SVN and related function MAX_SVN and its related function are not currently used, so comment them out. Signed-off-by: Stefan Berger --- src/tpm2/VendorInfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tpm2/VendorInfo.c b/src/tpm2/VendorInfo.c index df8f2b8ef..f14b87e7e 100644 --- a/src/tpm2/VendorInfo.c +++ b/src/tpm2/VendorInfo.c @@ -76,7 +76,7 @@ #define VENDOR_STRING_4 "\0\0\0\0" #define FIRMWARE_V1 (0x20240125) #define FIRMWARE_V2 (0x00120000) -#define MAX_SVN 255 +//#define MAX_SVN 255 // libtpms changed #if SIMULATION // libtpms added static uint32_t currentHash = FIRMWARE_V2; @@ -140,11 +140,13 @@ LIB_EXPORT uint16_t _plat__GetTpmFirmwareSvn(void) return currentSvn; } +#if 0 // libtpms added // return the TPM Firmware maximum SVN reported by getCapability. LIB_EXPORT uint16_t _plat__GetTpmFirmwareMaxSvn(void) { return MAX_SVN; } +#endif // libtpms added // Called by the simulator to set the TPM Firmware SVN reported by // getCapability. From 1bf63f09550c6a46440cee6b7be94d869e9aa303 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 16 Oct 2024 21:27:42 -0400 Subject: [PATCH 3/7] tpm2: Create an SVN base secret at first TPM manufacturing time Introduce a per-TPM SVN base secret of 16 bytes that is to be used for the SVN-limited hierarchy to derive its secrets from when the 16bit SVN number is mixed in. Create it at first manufacturing time. Signed-off-by: Stefan Berger --- src/tpm2/Global.h | 4 ++++ src/tpm2/Manufacture.c | 5 ++++- src/tpm2/VendorInfo.c | 14 +++++++++++++- src/tpm2/tpm_to_platform_interface.h | 2 ++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/tpm2/Global.h b/src/tpm2/Global.h index 910b940e3..0ffb08ad2 100644 --- a/src/tpm2/Global.h +++ b/src/tpm2/Global.h @@ -128,6 +128,10 @@ TPM2B_TYPE(PROOF, PROOF_SIZE); // Definition for a Primary Seed value TPM2B_TYPE(SEED, PRIMARY_SEED_SIZE); +// Definition for Svn base secret +TPM2B_TYPE(SVN_BASE_SECRET, 16); +extern TPM2B_SVN_BASE_SECRET g_SvnBaseSecret; + // A CLOCK_NONCE is used to tag the time value in the authorization session and // in the ticket computation so that the ticket expires when there is a time // discontinuity. When the clock stops during normal operation, the nonce is diff --git a/src/tpm2/Manufacture.c b/src/tpm2/Manufacture.c index 486fa0978..c4d455ad2 100644 --- a/src/tpm2/Manufacture.c +++ b/src/tpm2/Manufacture.c @@ -141,7 +141,10 @@ TPM_Manufacture( IsTestStateSet(ENTROPY), IsDrbgTested()); return -1; - } // libtpms added end + } + if (firstTime && _plat__SvnBaseSecretGenerate() < 0) + return -1; + // libtpms added end // default configuration for PCR PCRManufacture(); diff --git a/src/tpm2/VendorInfo.c b/src/tpm2/VendorInfo.c index f14b87e7e..03d30fcb8 100644 --- a/src/tpm2/VendorInfo.c +++ b/src/tpm2/VendorInfo.c @@ -67,6 +67,7 @@ //** Includes #include "Platform.h" #include "tpm_library.h" // libtpms added +#include "Tpm.h" // libtpms added // In this sample platform, these are compile time constants, but are not required to be. #define MANUFACTURER "IBM" @@ -82,10 +83,14 @@ static uint32_t currentHash = FIRMWARE_V2; #endif // libtpms added begin MUST_BE(TPM_LIBRARY_VER_MAJOR == 0); -MUST_BE(TPM_LIBRARY_VER_MICRO <= 15); /* 4 bits fir micro */ // libtpms added end +MUST_BE(TPM_LIBRARY_VER_MICRO <= 15); /* 4 bits for micro */ static uint16_t currentSvn = ((TPM_LIBRARY_VER_MINOR - 10) << 4 | TPM_LIBRARY_VER_MICRO); +/* A TPM-specific SVN base secret that is part of its permanent state */ +TPM2B_SVN_BASE_SECRET g_SvnBaseSecret; // libtpms added end + + // Similar to the Core Library's ByteArrayToUint32, but usable in Platform code. static uint32_t StringToUint32(const char s[4]) // libtpms changed: added const { @@ -218,3 +223,10 @@ LIB_EXPORT uint32_t _plat__GetTpmType() return 1; // just the value the reference code has returned in the past. } +LIB_EXPORT int _plat__SvnBaseSecretGenerate(void) // libtpms added begin +{ + g_SvnBaseSecret.t.size = sizeof(g_SvnBaseSecret.t.buffer); + DRBG_Generate(NULL, g_SvnBaseSecret.t.buffer, g_SvnBaseSecret.t.size); + + return 0; +} // libtpms added end diff --git a/src/tpm2/tpm_to_platform_interface.h b/src/tpm2/tpm_to_platform_interface.h index 481bb917b..6a9378ded 100644 --- a/src/tpm2/tpm_to_platform_interface.h +++ b/src/tpm2/tpm_to_platform_interface.h @@ -439,6 +439,8 @@ LIB_EXPORT int _plat__GetTpmFirmwareSvnSecret( ); #endif // SVN_LIMITED_SUPPORT +LIB_EXPORT int _plat__SvnBaseSecretGenerate(void); // libtpms added + #if FW_LIMITED_SUPPORT //***_plat__GetTpmFirmwareSecret() // Function: Obtain a Firmware Secret bound to the current firmware image. From 828b3dbadbdb12abd4bbabc80c7f16504db3b951 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 17 Oct 2024 09:07:05 -0400 Subject: [PATCH 4/7] tpm2: Use 16-byte SVN base secret to calculate TpmFirmwareSvnSecret Use the TPM's unique 16 byte SVN base secret to deterministically calculate the TpmFirmwareSvnSecret from it by first hashing this 16 byte number and then adding the 16bit SVN to the hash. Signed-off-by: Stefan Berger --- src/tpm2/VendorInfo.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tpm2/VendorInfo.c b/src/tpm2/VendorInfo.c index 03d30fcb8..7f14a5067 100644 --- a/src/tpm2/VendorInfo.c +++ b/src/tpm2/VendorInfo.c @@ -177,6 +177,7 @@ LIB_EXPORT int _plat__GetTpmFirmwareSvnSecret(uint16_t svn, uint8_t* secret_buf, uint16_t* secret_size) { +#if 0 // libtpms added int i; if(svn > currentSvn) @@ -191,6 +192,14 @@ LIB_EXPORT int _plat__GetTpmFirmwareSvnSecret(uint16_t svn, } *secret_size = secret_buf_size; +#endif // libtpms added begin + HASH_STATE state; + UINT64 value = svn; + + CryptHashStart(&state, TPM_ALG_SHA256); + CryptDigestUpdate2B(&state, &g_SvnBaseSecret.b); + CryptDigestUpdateInt(&state, 2, value); + *secret_size = CryptHashEnd(&state, secret_buf_size, secret_buf);// libtpms added end return 0; } From ac3bfdbd722b28236c7767d7e1022aeb496b8269 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 17 Oct 2024 09:54:00 -0400 Subject: [PATCH 5/7] tpm2: Add checks for profile-enabled SVN hierarchy In several locations where #if SVN_LIMITED_SUPPORT is used to deactivate SVN hierarchy related code, add a profile attribute check for whether the svn-limited-hierarchy attribute's flag is set. If it is not set, handle it in the same way is if SVN hierarchy support was disabled. Signed-off-by: Stefan Berger --- src/tpm2/Handle.c | 13 ++++++++++++- src/tpm2/Hierarchy.c | 6 ++++++ src/tpm2/Object_spt.c | 7 ++++++- src/tpm2/RuntimeProfile_fp.h | 7 +++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/tpm2/Handle.c b/src/tpm2/Handle.c index 24ae872f9..95a27fdb5 100644 --- a/src/tpm2/Handle.c +++ b/src/tpm2/Handle.c @@ -119,7 +119,7 @@ NextPermanentHandle(TPM_HANDLE inHandle // IN: the handle to check case TPM_RH_FW_PLATFORM: case TPM_RH_FW_NULL: #endif -#if SVN_LIMITED_SUPPORT +#if 0 //SVN_LIMITED_SUPPORT // libtpms changed case TPM_RH_SVN_OWNER_BASE: case TPM_RH_SVN_ENDORSEMENT_BASE: case TPM_RH_SVN_PLATFORM_BASE: @@ -135,6 +135,17 @@ NextPermanentHandle(TPM_HANDLE inHandle // IN: the handle to check return inHandle; break; +#if SVN_LIMITED_SUPPORT // libtpms added begin + case TPM_RH_SVN_OWNER_BASE: + case TPM_RH_SVN_ENDORSEMENT_BASE: + case TPM_RH_SVN_PLATFORM_BASE: + case TPM_RH_SVN_NULL_BASE: + if(RuntimeProfileHasAttributeFlags(&g_RuntimeProfile, + RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY)) + return inHandle; + + break; +#endif // libtpms added end default: break; } diff --git a/src/tpm2/Hierarchy.c b/src/tpm2/Hierarchy.c index fba2748bd..8f7b2a43e 100644 --- a/src/tpm2/Hierarchy.c +++ b/src/tpm2/Hierarchy.c @@ -308,6 +308,9 @@ static TPM_RC GetAdditionalSecret(const HIERARCHY_MODIFIER* modifier, // I case HM_SVN_LIMITED: { #if SVN_LIMITED_SUPPORT + if(!RuntimeProfileHasAttributeFlags(&g_RuntimeProfile, // libtpms added begin + RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY)) + return TPM_RC_SVN_LIMITED; // libtpms added end if(_plat__GetTpmFirmwareSvnSecret(modifier->min_svn, sizeof(secret_buffer->t.buffer), secret_buffer->t.buffer, @@ -514,6 +517,9 @@ TPM_RC ValidateHierarchy(TPMI_RH_HIERARCHY hierarchy // IN: hierarchy case HM_SVN_LIMITED: { #if SVN_LIMITED_SUPPORT + if(!RuntimeProfileHasAttributeFlags(&g_RuntimeProfile, // libtpms added begin + RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY)) + return TPM_RC_SVN_LIMITED; // libtpms added end // SVN-limited hierarchies are only enabled for SVNs less than or // equal to the current firmware's SVN. if(modifier.min_svn > _plat__GetTpmFirmwareSvn()) diff --git a/src/tpm2/Object_spt.c b/src/tpm2/Object_spt.c index 45a88f2d9..9f1343f61 100644 --- a/src/tpm2/Object_spt.c +++ b/src/tpm2/Object_spt.c @@ -766,7 +766,12 @@ PublicAttributesValidation( } if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, svnLimited)) { -#if SVN_LIMITED_SUPPORT // libtpms added +#if SVN_LIMITED_SUPPORT // libtpms added begin + if(!RuntimeProfileHasAttributeFlags(&g_RuntimeProfile, + RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY)) + { + return TPM_RCS_ATTRIBUTES; + } // libtpms added end if(parentObject != NULL) { // For an ordinary object, svnLimited can only be set if its diff --git a/src/tpm2/RuntimeProfile_fp.h b/src/tpm2/RuntimeProfile_fp.h index 37d6cae9d..d5e11d5db 100644 --- a/src/tpm2/RuntimeProfile_fp.h +++ b/src/tpm2/RuntimeProfile_fp.h @@ -93,5 +93,12 @@ SEED_COMPAT_LEVEL RuntimeProfileGetSeedCompatLevel(void); BOOL RuntimeProfileRequiresAttributeFlags(struct RuntimeProfile *RuntimeProfile, unsigned int attributeFlags); +static inline BOOL +RuntimeProfileHasAttributeFlags(struct RuntimeProfile *RuntimeProfile, + unsigned int attributeFlags) +{ + return RuntimeProfileRequiresAttributeFlags(RuntimeProfile, + attributeFlags); +} #endif /* RUNTIME_PROFILE_H */ From d5368c7c4176182bbda627977b1e113e54207726 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 17 Oct 2024 09:39:35 -0400 Subject: [PATCH 6/7] tpm2: Enable SVN-limited hierarchy: svn-limited-hierarchy (SFL 8) Implement support for a profile attribute svn-limited-hierarchy that must be set for SVN-limited hiearchy support to be enabled. Bump up the StateFormatLevel to 8 and store the SVN base secret starting with StateFormatLevel 8. Signed-off-by: Stefan Berger --- src/tpm2/NVMarshal.c | 17 +++++++++++++++-- src/tpm2/RuntimeAttributes.c | 2 ++ src/tpm2/RuntimeAttributes_fp.h | 3 ++- src/tpm2/RuntimeProfile.c | 11 ++++++++--- src/tpm2/TpmProfile_Common.h | 2 +- tests/tpm2_setprofile.c | 3 ++- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index 122d4dff0..bfbbc4ecb 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -5060,7 +5060,7 @@ USER_NVRAM_Unmarshal(BYTE **buffer, INT32 *size) * - indexOrderlyRAM (NV_INDEX_RAM_DATA) * - NVRAM locations (NV_USER_DYNAMIC) */ -#define PERSISTENT_ALL_VERSION 4 +#define PERSISTENT_ALL_VERSION 5 #define PERSISTENT_ALL_MAGIC 0xab364723 UINT32 PERSISTENT_ALL_Marshal(BYTE **buffer, INT32 *size) @@ -5094,8 +5094,11 @@ PERSISTENT_ALL_Marshal(BYTE **buffer, INT32 *size) case 1: blob_version = 3; break; + case 2 ... 7: + blob_version = 4; + break; default: - blob_version = 4; /* since stateFormatLevel 2 */ + blob_version = 5; /* since stateFormatLevel 8 */ break; } @@ -5112,6 +5115,10 @@ PERSISTENT_ALL_Marshal(BYTE **buffer, INT32 *size) assert(profileJSON); written += String_Marshal(profileJSON, buffer, size); // since v4 } + if (blob_version >= 5) { + written += TPM2B_Marshal(&g_SvnBaseSecret.b, sizeof(g_SvnBaseSecret.t.buffer), + buffer, size); + } written += PACompileConstants_Marshal(buffer, size); written += PERSISTENT_DATA_Marshal(&pd, buffer, size, RuntimeProfile); written += ORDERLY_DATA_Marshal(&od, buffer, size); @@ -5168,6 +5175,12 @@ PERSISTENT_ALL_Unmarshal(BYTE **buffer, INT32 *size) rc = String_Unmarshal(&profileJSON, buffer, size); } } + if (rc == TPM_RC_SUCCESS) { + if (hdr.version >= 5) { + rc = TPM2B_Unmarshal(&g_SvnBaseSecret.b, sizeof(g_SvnBaseSecret.t.buffer), + buffer, size); + } + } if (rc == TPM_RC_SUCCESS) { /* set the profile read from the state */ rc = RuntimeProfileSet(&g_RuntimeProfile, profileJSON, false); diff --git a/src/tpm2/RuntimeAttributes.c b/src/tpm2/RuntimeAttributes.c index e2e5b8ad1..1f19dad58 100644 --- a/src/tpm2/RuntimeAttributes.c +++ b/src/tpm2/RuntimeAttributes.c @@ -80,6 +80,8 @@ static const struct { 7), ATTRIBUTE("no-ecc-key-derivation", RUNTIME_ATTRIBUTE_NO_ECC_KEY_DERIVATION, 7), + ATTRIBUTE("svn-limited-hierarchy", RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY, + 8), }; LIB_EXPORT void diff --git a/src/tpm2/RuntimeAttributes_fp.h b/src/tpm2/RuntimeAttributes_fp.h index b61b090ec..15a8a3669 100644 --- a/src/tpm2/RuntimeAttributes_fp.h +++ b/src/tpm2/RuntimeAttributes_fp.h @@ -42,7 +42,7 @@ #ifndef RUNTIME_ATTRIBUTES_H #define RUNTIME_ATTRIBUTES_H -#define NUM_ENTRIES_ATTRIBUTE_PROPERTIES 10 +#define NUM_ENTRIES_ATTRIBUTE_PROPERTIES 11 #define RUNTIME_ATTRIBUTE_NO_UNPADDED_ENCRYPTION (1 << 0) #define RUNTIME_ATTRIBUTE_NO_SHA1_SIGNING (1 << 1) @@ -52,6 +52,7 @@ #define RUNTIME_ATTRIBUTE_DRBG_CONTINOUS_TEST (1 << 5) #define RUNTIME_ATTRIBUTE_PAIRWISE_CONSISTENCY_TEST (1 << 6) #define RUNTIME_ATTRIBUTE_NO_ECC_KEY_DERIVATION (1 << 7) +#define RUNTIME_ATTRIBUTE_SVN_LIMITED_HIERARCHY (1 << 8) struct RuntimeAttributes { /* */ diff --git a/src/tpm2/RuntimeProfile.c b/src/tpm2/RuntimeProfile.c index 7533d90e4..048501610 100644 --- a/src/tpm2/RuntimeProfile.c +++ b/src/tpm2/RuntimeProfile.c @@ -63,6 +63,9 @@ const char defaultAlgorithmsProfile[] = "ecc-bn,ecc-sm2-p256,symcipher,camellia,camellia-min-size=128,cmac," "ctr,ofb,cbc,cfb,ecb"; +const char defaultAttributesProfile[] = + "svn-limited-hierarchy"; + static const struct RuntimeProfileDesc { const char *name; #define MAX_PROFILE_NAME_LEN 32 @@ -78,7 +81,7 @@ static const struct RuntimeProfileDesc { * This basically locks the name of the profile to the stateFormatLevel. */ unsigned int stateFormatLevel; -#define STATE_FORMAT_LEVEL_CURRENT 7 +#define STATE_FORMAT_LEVEL_CURRENT 8 #define STATE_FORMAT_LEVEL_UNKNOWN 0 /* JSON didn't provide StateFormatLevel; this is only allowed for the 'default' profile or when user passed JSON via SetProfile() */ @@ -105,6 +108,7 @@ static const struct RuntimeProfileDesc { * - drbg-continous-test * - pct * - no-ecc-key-derivation + * 8 : Attribute 'svn-limited-hierarchy' was added */ const char *description; #define DESCRIPTION_MAX_SIZE 250 @@ -118,6 +122,7 @@ static const struct RuntimeProfileDesc { .name = DEFAULT_PROFILE_NAME, .commandsProfile = defaultCommandsProfile, .algorithmsProfile = defaultAlgorithmsProfile, + .attributesProfile = defaultAttributesProfile, .stateFormatLevel = STATE_FORMAT_LEVEL_CURRENT, /* should always be the latest */ .description = "This profile enables all libtpms v0.10-supported commands and " "algorithms. This profile is compatible with libtpms >= v0.10.", @@ -965,8 +970,8 @@ RuntimeProfileGetSeedCompatLevel(void) case 1: /* profile runs on v0.9 */ return SEED_COMPAT_LEVEL_RSA_PRIME_ADJUST_FIX; - case 2 ... 7: /* profile runs on v0.10 */ { - MUST_BE(STATE_FORMAT_LEVEL_CURRENT == 7); // force update when this changes + case 2 ... 8: /* profile runs on v0.10 */ { + MUST_BE(STATE_FORMAT_LEVEL_CURRENT == 8); // force update when this changes return SEED_COMPAT_LEVEL_LAST; } diff --git a/src/tpm2/TpmProfile_Common.h b/src/tpm2/TpmProfile_Common.h index 7a6ba697a..1251b4ffe 100644 --- a/src/tpm2/TpmProfile_Common.h +++ b/src/tpm2/TpmProfile_Common.h @@ -313,7 +313,7 @@ // Defines controlling Firmware- and SVN-limited objects //*********************************************** #define FW_LIMITED_SUPPORT NO // libtpms: NO -#define SVN_LIMITED_SUPPORT NO // libtpms: NO +#define SVN_LIMITED_SUPPORT YES // libtpms: YES (StateFormatLevel 8) //*********************************************** // Defines controlling External NV diff --git a/tests/tpm2_setprofile.c b/tests/tpm2_setprofile.c index 768120f74..3709b847d 100644 --- a/tests/tpm2_setprofile.c +++ b/tests/tpm2_setprofile.c @@ -60,7 +60,7 @@ static const struct { .exp_profile = "{\"ActiveProfile\":{" "\"Name\":\"default-v1\"," - "\"StateFormatLevel\":7," + "\"StateFormatLevel\":8," "\"Commands\":\"0x11f-0x122,0x124-0x12e,0x130-0x140,0x142-0x159," "0x15b-0x15e,0x160-0x165,0x167-0x174,0x176-0x178," "0x17a-0x193,0x197,0x199-0x19c\"," @@ -71,6 +71,7 @@ static const struct { "kdf1-sp800-56a,kdf2,kdf1-sp800-108,ecc,ecc-min-size=192," "ecc-nist,ecc-bn,ecc-sm2-p256,symcipher,camellia," "camellia-min-size=128,cmac,ctr,ofb,cbc,cfb,ecb\"," + "\"Attributes\":\"svn-limited-hierarchy\"," "\"Description\":\"This profile enables all libtpms v0.10-supported " "commands and algorithms. This profile is compatible with " "libtpms >= v0.10.\"" From 54671af0a0b896633cb9e9cee76420fe38746b71 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 17 Oct 2024 11:06:37 -0400 Subject: [PATCH 7/7] tpm2: Implement API call to recreate the SVN base secret Implement TPMLIB_RecreateSvnBaseSecret() to allow the user to recreate the SVN base secret. Trigger the storage of the persistent state. Add a man page. Signed-off-by: Stefan Berger --- include/libtpms/tpm_library.h | 2 ++ include/libtpms/tpm_library.h.in | 2 ++ man/man3/Makefile.am | 1 + man/man3/TPMLIB_RecreateSvnBaseSecret.pod | 37 +++++++++++++++++++++++ man/man3/TPMLIB_SetProfile.pod | 12 ++++++++ src/disabled_interface.c | 6 ++++ src/libtpms.syms | 1 + src/tpm2/VendorInfo.c | 6 ++++ src/tpm2/tpm_to_platform_interface.h | 1 + src/tpm_library.c | 5 +++ src/tpm_library_intern.h | 1 + src/tpm_tpm12_interface.c | 6 ++++ src/tpm_tpm2_interface.c | 8 +++++ 13 files changed, 88 insertions(+) create mode 100644 man/man3/TPMLIB_RecreateSvnBaseSecret.pod diff --git a/include/libtpms/tpm_library.h b/include/libtpms/tpm_library.h index 902ad9343..059b9f9a0 100644 --- a/include/libtpms/tpm_library.h +++ b/include/libtpms/tpm_library.h @@ -175,6 +175,8 @@ TPM_RESULT TPMLIB_SetProfile(const char *profile); TPM_BOOL TPMLIB_WasManufactured(void); +TPM_RESULT TPMLIB_RecreateSvnBaseSecret(void); + #ifdef __cplusplus } #endif diff --git a/include/libtpms/tpm_library.h.in b/include/libtpms/tpm_library.h.in index 5adef4074..a68b13a34 100644 --- a/include/libtpms/tpm_library.h.in +++ b/include/libtpms/tpm_library.h.in @@ -175,6 +175,8 @@ TPM_RESULT TPMLIB_SetProfile(const char *profile); TPM_BOOL TPMLIB_WasManufactured(void); +TPM_RESULT TPMLIB_RecreateSvnBaseSecret(void); + #ifdef __cplusplus } #endif diff --git a/man/man3/Makefile.am b/man/man3/Makefile.am index 8869a6478..2f5ec16f2 100644 --- a/man/man3/Makefile.am +++ b/man/man3/Makefile.am @@ -16,6 +16,7 @@ man3_PODS = \ TPMLIB_GetVersion.pod \ TPMLIB_MainInit.pod \ TPMLIB_Process.pod \ + TPMLIB_RecreateSvnBaseSecret.pod \ TPMLIB_RegisterCallbacks.pod \ TPMLIB_SetBufferSize.pod \ TPMLIB_SetDebugFD.pod \ diff --git a/man/man3/TPMLIB_RecreateSvnBaseSecret.pod b/man/man3/TPMLIB_RecreateSvnBaseSecret.pod new file mode 100644 index 000000000..2986c5797 --- /dev/null +++ b/man/man3/TPMLIB_RecreateSvnBaseSecret.pod @@ -0,0 +1,37 @@ +=head1 NAME + +TPMLIB_RecreateSvnBaseSecret - Recreate a TPM 2's SVN-limited hierarchy base secret + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B + +=head1 DESCRIPTION + +B is used to recreate the internal base SVN +secret that is used for by the SVN-limited hierachy to derive its secret +from by adding the 16bit SVN number to it. Since the SVN base secret is part +of the permanent/persistent state of a TPM 2, this function should be called +after loading the state or before processing the first command. This can for +example be done right after I or as late as just before +I. + +The side effect of recreating the base SVN secret is that previous firmware +SVN secrets cannot be created anymore and objects (keys) associated with the +SVN-limited hierachy cannot be used anymore. + +=head1 SEE ALSO + +B, B(3) + +=cut diff --git a/man/man3/TPMLIB_SetProfile.pod b/man/man3/TPMLIB_SetProfile.pod index 0089e4282..23791422a 100644 --- a/man/man3/TPMLIB_SetProfile.pod +++ b/man/man3/TPMLIB_SetProfile.pod @@ -192,6 +192,10 @@ This I enabled the following profile attributes: =back +=item 8: (since v0.10) + +This I enabled the I attribute. + =back A user may specify the I when using the I profile. @@ -304,6 +308,14 @@ keys =back +=item B: (since v0.10) + +=over 2 + +=item * Enable the SVN-limited hierarchy + +=back + =back =head1 FIPS mode on the host diff --git a/src/disabled_interface.c b/src/disabled_interface.c index 3faaf3291..0571f37b4 100644 --- a/src/disabled_interface.c +++ b/src/disabled_interface.c @@ -110,6 +110,11 @@ static TPM_BOOL Disabled_WasManufactured(void) return FALSE; } +static TPM_RESULT Disabled_RecreateSvnBaseSecret(void) +{ + return TPM_FAIL; +} + const struct tpm_interface DisabledInterface = { .MainInit = Disabled_MainInit, .Terminate = Disabled_Terminate, @@ -128,4 +133,5 @@ const struct tpm_interface DisabledInterface = { .SetState = Disabled_SetState, .GetState = Disabled_GetState, .WasManufactured = Disabled_WasManufactured, + .RecreateSvnBaseSecret = Disabled_RecreateSvnBaseSecret, }; diff --git a/src/libtpms.syms b/src/libtpms.syms index 1f965a87c..e03631a68 100644 --- a/src/libtpms.syms +++ b/src/libtpms.syms @@ -42,6 +42,7 @@ LIBTPMS_0.10.0 { global: TPMLIB_SetProfile; TPMLIB_WasManufactured; + TPMLIB_RecreateSvnBaseSecret; local: *; } LIBTPMS_0.6.0; diff --git a/src/tpm2/VendorInfo.c b/src/tpm2/VendorInfo.c index 7f14a5067..0030369aa 100644 --- a/src/tpm2/VendorInfo.c +++ b/src/tpm2/VendorInfo.c @@ -238,4 +238,10 @@ LIB_EXPORT int _plat__SvnBaseSecretGenerate(void) // libtpms added begin DRBG_Generate(NULL, g_SvnBaseSecret.t.buffer, g_SvnBaseSecret.t.size); return 0; +} + +LIB_EXPORT int _plat__SvnBaseSecretRecreate(void) +{ + // FIXME: Add a check for a profile attribute here to allow this? + return _plat__SvnBaseSecretGenerate(); } // libtpms added end diff --git a/src/tpm2/tpm_to_platform_interface.h b/src/tpm2/tpm_to_platform_interface.h index 6a9378ded..f757e961e 100644 --- a/src/tpm2/tpm_to_platform_interface.h +++ b/src/tpm2/tpm_to_platform_interface.h @@ -440,6 +440,7 @@ LIB_EXPORT int _plat__GetTpmFirmwareSvnSecret( #endif // SVN_LIMITED_SUPPORT LIB_EXPORT int _plat__SvnBaseSecretGenerate(void); // libtpms added +LIB_EXPORT int _plat__SvnBaseSecretRecreate(void); // libtpms added #if FW_LIMITED_SUPPORT //***_plat__GetTpmFirmwareSecret() diff --git a/src/tpm_library.c b/src/tpm_library.c index f48f4fd38..83807c11b 100644 --- a/src/tpm_library.c +++ b/src/tpm_library.c @@ -278,6 +278,11 @@ TPM_BOOL TPMLIB_WasManufactured(void) return tpm_iface[tpmvers_choice]->WasManufactured(); } +TPM_RESULT TPMLIB_RecreateSvnBaseSecret(void) +{ + return tpm_iface[tpmvers_choice]->RecreateSvnBaseSecret(); +} + static struct libtpms_callbacks libtpms_cbs; struct libtpms_callbacks *TPMLIB_GetCallbacks(void) diff --git a/src/tpm_library_intern.h b/src/tpm_library_intern.h index 43b5fac8b..0a2f0516a 100644 --- a/src/tpm_library_intern.h +++ b/src/tpm_library_intern.h @@ -86,6 +86,7 @@ struct tpm_interface { unsigned char **buffer, uint32_t *buflen); TPM_RESULT (*SetProfile)(const char *profile); TPM_BOOL (*WasManufactured)(void); + TPM_RESULT (*RecreateSvnBaseSecret)(void); }; extern const struct tpm_interface DisabledInterface; diff --git a/src/tpm_tpm12_interface.c b/src/tpm_tpm12_interface.c index 32d8a6578..84dc1df36 100644 --- a/src/tpm_tpm12_interface.c +++ b/src/tpm_tpm12_interface.c @@ -520,6 +520,11 @@ static TPM_BOOL TPM12_WasManufactured(void) return FALSE; } +static TPM_RESULT TPM12_RecreateSvnBaseSecret(void) +{ + return TPM_FAIL; +} + const struct tpm_interface TPM12Interface = { .MainInit = TPM12_MainInit, .Terminate = TPM12_Terminate, @@ -539,4 +544,5 @@ const struct tpm_interface TPM12Interface = { .GetState = TPM12_GetState, .SetProfile = TPM12_SetProfile, .WasManufactured = TPM12_WasManufactured, + .RecreateSvnBaseSecret = TPM12_RecreateSvnBaseSecret, }; diff --git a/src/tpm_tpm2_interface.c b/src/tpm_tpm2_interface.c index 7bebbc9e1..aa34b067d 100644 --- a/src/tpm_tpm2_interface.c +++ b/src/tpm_tpm2_interface.c @@ -871,6 +871,13 @@ static TPM_BOOL TPM2_WasManufactured(void) return g_wasManufactured; } +static TPM_RESULT TPM2_RecreateSvnBaseSecret(void) +{ + if (_plat__SvnBaseSecretRecreate() == 0 && NvCommit()) + return TPM_SUCCESS; + return TPM_FAIL; +} + const struct tpm_interface TPM2Interface = { .MainInit = TPM2_MainInit, .Terminate = TPM2_Terminate, @@ -890,4 +897,5 @@ const struct tpm_interface TPM2Interface = { .GetState = TPM2_GetState, .SetProfile = TPM2_SetProfile, .WasManufactured = TPM2_WasManufactured, + .RecreateSvnBaseSecret = TPM2_RecreateSvnBaseSecret, };