From a9f62d265c9a36f1b39f974628c9f11fa3bac6f3 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 1 Oct 2025 17:58:05 -0400 Subject: [PATCH] tpm2: Increase MAX_NV_INDEX_SIZE (StateFormatLevel 9) In order to be able to write certificates signed with an ML-DSA key into an NVRAM index, the size must be increased. Therefore, increase the size of MAX_NV_INDEX_SIZE to 10kb starting ats StateFormatLevel 9. Replace many occurrenced of MAX_NV_INDEX_SIZE with a function get_MAX_NV_INDEX_SIZE_by_SFL() to get the maximum allowed index size given the StateFormatLevel of the current profile. This allows to create bigger indices with default-v2 profile and only smaller ones with any older profile. Signed-off-by: Stefan Berger --- src/tpm2/NVMarshal.c | 4 ++-- src/tpm2/NV_spt.c | 2 +- src/tpm2/PropertyCap.c | 2 +- src/tpm2/RuntimeProfile.c | 28 +++++++++++++++++++++++++--- src/tpm2/RuntimeProfile_fp.h | 2 ++ src/tpm2/TpmProfile_Misc.h | 2 +- src/tpm2/Unmarshal.c | 4 ++-- tests/tpm2_setprofile.c | 2 +- 8 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index 1356c2597..d717aa59a 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -3901,7 +3901,7 @@ static const struct _entry { { COMPILE_CONSTANT(NUM_AUTHVALUE_PCR_GROUP, EQ) }, { COMPILE_CONSTANT(MAX_CONTEXT_SIZE, LE) }, /* old: 2474 */ { COMPILE_CONSTANT(MAX_DIGEST_BUFFER, EQ) }, - { COMPILE_CONSTANT(MAX_NV_INDEX_SIZE, EQ) }, + { COMPILE_CONSTANT(2048, EQ) }, /* was MAX_NV_INDEX_SIZE (2048) up to SFL 8 */ { COMPILE_CONSTANT(MAX_NV_BUFFER_SIZE, EQ) }, { COMPILE_CONSTANT(MAX_CAP_BUFFER, EQ) }, { COMPILE_CONSTANT(NV_MEMORY_SIZE, LE) }, @@ -4955,7 +4955,7 @@ USER_NVRAM_Unmarshal(BYTE **buffer, INT32 *size) /* * datasize cannot exceed MAX_NV_INDEX_SIZE (2048 bytes) */ - if (datasize > MAX_NV_INDEX_SIZE) { + if (datasize > get_MAX_NV_INDEX_SIZE_by_SFL(g_RuntimeProfile.stateFormatLevel)) { TPMLIB_LogTPM2Error("datasize for NV_INDEX too " "large: %u\n", datasize); rc = TPM_RC_SIZE; diff --git a/src/tpm2/NV_spt.c b/src/tpm2/NV_spt.c index ab217a49c..8ded78d26 100644 --- a/src/tpm2/NV_spt.c +++ b/src/tpm2/NV_spt.c @@ -407,7 +407,7 @@ TPM_RC NvDefineSpace(TPMI_RH_PROVISION authHandle, { case TPM_NT_ORDINARY: // Can't exceed the allowed size for the implementation - if(publicInfo->dataSize > MAX_NV_INDEX_SIZE) + if(publicInfo->dataSize > get_MAX_NV_INDEX_SIZE_by_SFL(g_RuntimeProfile.stateFormatLevel)) // libtpms changed return TPM_RCS_SIZE + blamePublic; break; case TPM_NT_EXTEND: diff --git a/src/tpm2/PropertyCap.c b/src/tpm2/PropertyCap.c index ffc89d622..5fe23b587 100644 --- a/src/tpm2/PropertyCap.c +++ b/src/tpm2/PropertyCap.c @@ -196,7 +196,7 @@ static BOOL TPMPropertyIsDefined(TPM_PT property, // IN: property break; case TPM_PT_NV_INDEX_MAX: // maximum size of an NV index data area - *value = MAX_NV_INDEX_SIZE; + *value = get_MAX_NV_INDEX_SIZE_by_SFL(g_RuntimeProfile.stateFormatLevel); // libtpms changed break; case TPM_PT_MEMORY: // a TPMA_MEMORY indicating the memory management method for the TPM diff --git a/src/tpm2/RuntimeProfile.c b/src/tpm2/RuntimeProfile.c index f72eae1e5..b919d2843 100644 --- a/src/tpm2/RuntimeProfile.c +++ b/src/tpm2/RuntimeProfile.c @@ -78,7 +78,7 @@ static const struct RuntimeProfileDesc { * This basically locks the name of the profile to the stateFormatLevel. */ unsigned int stateFormatLevel; -#define STATE_FORMAT_LEVEL_CURRENT 8 +#define STATE_FORMAT_LEVEL_CURRENT 9 #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() */ @@ -106,6 +106,7 @@ static const struct RuntimeProfileDesc { * - pct * - no-ecc-key-derivation * 8 : Enabled 4096-bit RSA support + * 9 : MAX_NV_INDEX_SIZE was increased to 10kb */ const char *description; #define DESCRIPTION_MAX_SIZE 250 @@ -990,8 +991,8 @@ RuntimeProfileGetSeedCompatLevel(void) case 1: /* profile runs on v0.9 */ return SEED_COMPAT_LEVEL_RSA_PRIME_ADJUST_FIX; - case 2 ... 8: /* profile runs on v0.10 */ { - MUST_BE(STATE_FORMAT_LEVEL_CURRENT == 8); // force update when this changes + case 2 ... 9: /* profile runs on v0.10 */ { + MUST_BE(STATE_FORMAT_LEVEL_CURRENT == 9); // force update when this changes return SEED_COMPAT_LEVEL_LAST; } @@ -1007,3 +1008,24 @@ RuntimeProfileRequiresAttributeFlags(struct RuntimeProfile *RuntimeProfile, return RuntimeAttributeCheckRequired(&RuntimeProfile->RuntimeAttributes, attributeFlags); } + +LIB_EXPORT unsigned int +get_MAX_NV_INDEX_SIZE_by_SFL(unsigned int stateFormatLevel) +{ + unsigned int size; + + switch (stateFormatLevel) { + case 0 ... 8: + size = 2048; + break; + case 9: + MUST_BE(STATE_FORMAT_LEVEL_CURRENT == 9); // force update when this changes + size = MAX_NV_INDEX_SIZE; + break; + + default: + FAIL(FATAL_ERROR_INTERNAL); + } + pAssert(size <= MAX_NV_INDEX_SIZE); + return size; +} diff --git a/src/tpm2/RuntimeProfile_fp.h b/src/tpm2/RuntimeProfile_fp.h index ae3ac28ca..372340e98 100644 --- a/src/tpm2/RuntimeProfile_fp.h +++ b/src/tpm2/RuntimeProfile_fp.h @@ -96,4 +96,6 @@ BOOL RuntimeProfileRequiresAttributeFlags(struct RuntimeProfile *RuntimeProfile, unsigned int attributeFlags); +unsigned int get_MAX_NV_INDEX_SIZE_by_SFL(unsigned int sfl); + #endif /* RUNTIME_PROFILE_H */ diff --git a/src/tpm2/TpmProfile_Misc.h b/src/tpm2/TpmProfile_Misc.h index 9696a9e88..09ffc05c8 100644 --- a/src/tpm2/TpmProfile_Misc.h +++ b/src/tpm2/TpmProfile_Misc.h @@ -87,7 +87,7 @@ //#define MAX_CONTEXT_SIZE 2168 #define MAX_CONTEXT_SIZE 2680 /* libtpms: changed for RSA-3072 */ #define MAX_DIGEST_BUFFER 1024 -#define MAX_NV_INDEX_SIZE 2048 +#define MAX_NV_INDEX_SIZE (10 * 1024) /* libtpms: changed; SFL 9 use get_MAX_NV_INDEX_SIZE_by_SFL() */ #define MAX_NV_BUFFER_SIZE 1024 #define MAX_CAP_BUFFER 1024 /* libtmps: 65 OBJECTs in USER NVRAM expanded by 704 bytes due to size diff --git a/src/tpm2/Unmarshal.c b/src/tpm2/Unmarshal.c index f33973264..7d65f7072 100644 --- a/src/tpm2/Unmarshal.c +++ b/src/tpm2/Unmarshal.c @@ -4762,7 +4762,7 @@ TPMS_NV_PUBLIC_Unmarshal(TPMS_NV_PUBLIC *target, BYTE **buffer, INT32 *size) rc = UINT16_Unmarshal(&target->dataSize, buffer, size); } if (rc == TPM_RC_SUCCESS) { - if (target->dataSize > MAX_NV_INDEX_SIZE) { + if (target->dataSize > get_MAX_NV_INDEX_SIZE_by_SFL(g_RuntimeProfile.stateFormatLevel)) { rc = TPM_RC_SIZE; target->dataSize = 0; // libtpms added } @@ -4842,7 +4842,7 @@ TPMS_NV_PUBLIC_EXP_ATTR_Unmarshal(TPMS_NV_PUBLIC_EXP_ATTR *target, BYTE **buffer rc = UINT16_Unmarshal(&target->dataSize, buffer, size); } if (rc == TPM_RC_SUCCESS) { - if (target->dataSize > MAX_NV_INDEX_SIZE) { + if (target->dataSize > get_MAX_NV_INDEX_SIZE_by_SFL(g_RuntimeProfile.stateFormatLevel)) { rc = TPM_RC_SIZE; } } diff --git a/tests/tpm2_setprofile.c b/tests/tpm2_setprofile.c index 27ba00b72..756fcc142 100644 --- a/tests/tpm2_setprofile.c +++ b/tests/tpm2_setprofile.c @@ -60,7 +60,7 @@ static const struct { .exp_profile = "{\"ActiveProfile\":{" "\"Name\":\"default-v2\"," - "\"StateFormatLevel\":8," + "\"StateFormatLevel\":9," "\"Commands\":\"0x11f-0x122,0x124-0x12e,0x130-0x140,0x142-0x159," "0x15b-0x15e,0x160-0x165,0x167-0x174,0x176-0x178," "0x17a-0x193,0x197,0x199-0x19c\","