Backport upstream fixes

Resolves: RHEL-164795

Signed-off-by: Štěpán Horáček <shoracek@redhat.com>
This commit is contained in:
Štěpán Horáček 2026-04-16 00:06:41 +02:00
parent 34275d24df
commit 9983900131
21 changed files with 1554 additions and 1 deletions

View File

@ -0,0 +1,24 @@
From baf581709a6a84983df5c212ad727c18dfee0992 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Fri, 29 May 2026 22:52:33 +0200
Subject: [PATCH] Add missing include
---
lib/tpm2_capability.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/tpm2_capability.c b/lib/tpm2_capability.c
index 3bccaeca..3871aaa6 100644
--- a/lib/tpm2_capability.c
+++ b/lib/tpm2_capability.c
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
#include "log.h"
#include "tool_rc.h"
--
2.54.0

View File

@ -0,0 +1,93 @@
From 31349de663413c28c3c4fa1f8966ead8a47d6133 Mon Sep 17 00:00:00 2001
From: Juergen Repp <juergen_repp@web.de>
Date: Wed, 22 Oct 2025 12:57:18 +0200
Subject: [PATCH 01/20] tpm2_makecredential: Fix usage of name parameter.
The man page for tpm2_makecredential states that the -name parameter
can be a file. However, a hex string of the name is expected. Similar
to the procedure used with tpm2_certifycreation, a file with the name
or a hex string can now be passed.
Fixes: #3274
Signed-off-by: Juergen Repp <juergen_repp@web.de>
---
man/tpm2_makecredential.1.md | 5 +++--
test/integration/tests/makecredential.sh | 5 +++++
tools/tpm2_makecredential.c | 12 ++++++++----
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/man/tpm2_makecredential.1.md b/man/tpm2_makecredential.1.md
index e10d4a92..18896690 100644
--- a/man/tpm2_makecredential.1.md
+++ b/man/tpm2_makecredential.1.md
@@ -55,9 +55,10 @@ TCTI option.
The secret which will be protected by the key derived from the random seed. It can be specified as a file or passed from stdin.
- * **-n**, **\--name**=_FILE_:
+ * **-n**, **\--name**=_FILE\_OR\_HEX_:
- The name of the key for which certificate is to be created.
+ The name of the key for which certificate is to be created. Can either be
+ a path or hex string.
* **-o**, **\--credential-blob**=_FILE_:
diff --git a/test/integration/tests/makecredential.sh b/test/integration/tests/makecredential.sh
index 783422bf..1a26962a 100644
--- a/test/integration/tests/makecredential.sh
+++ b/test/integration/tests/makecredential.sh
@@ -14,6 +14,7 @@ output_ek_pub=ek_pub.out
output_ak_pub=ak_pub.out
output_ak_pub_name=ak_name_pub.out
output_mkcredential=mkcredential.out
+output_mkcredential2=mkcredentiali2.out
cleanup() {
rm -f $output_ek_pub $output_ak_pub $output_ak_pub_name \
@@ -45,6 +46,10 @@ Loadkeyname=`cat $output_ak_pub_name | xxd -p -c $file_size`
tpm2 makecredential -Q -u $output_ek_pub -s $file_input_data -n $Loadkeyname \
-o $output_mkcredential
+# Check usage of name file instead of hex string
+tpm2 makecredential -Q -u $output_ek_pub -s $file_input_data -n $output_ak_pub_name \
+-o $output_mkcredential2
+
# use no tpm backend
tpm2 makecredential -T none -Q -u $output_ek_pub -s $file_input_data \
-n $Loadkeyname -o $output_mkcredential
diff --git a/tools/tpm2_makecredential.c b/tools/tpm2_makecredential.c
index 5bd5b484..1f7b558c 100644
--- a/tools/tpm2_makecredential.c
+++ b/tools/tpm2_makecredential.c
@@ -203,6 +203,7 @@ static tool_rc make_credential_and_save(ESYS_CONTEXT *ectx) {
static bool on_option(char key, char *value) {
+ tool_rc rc;
switch (key) {
case 'u':
if (ctx.flags.e) {
@@ -226,12 +227,15 @@ static bool on_option(char key, char *value) {
break;
case 'n':
ctx.object_name.size = BUFFER_SIZE(TPM2B_NAME, name);
- int q;
- if ((q = tpm2_util_hex_to_byte_structure(value, &ctx.object_name.size,
- ctx.object_name.name)) != 0) {
- LOG_ERR("FAILED: %d", q);
+ rc = tpm2_util_bin_from_hex_or_file(value,
+ &ctx.object_name.size, ctx.object_name.name) ?
+ tool_rc_success : tool_rc_general_error;
+
+ if (rc != tool_rc_success) {
+ LOG_ERR("Could not load name data");
return false;
}
+
ctx.flags.n = 1;
break;
case 'o':
--
2.54.0

View File

@ -0,0 +1,51 @@
From 2509caebf3500bf747bb11bbfe097fda275ed416 Mon Sep 17 00:00:00 2001
From: Dimitrios Siganos <dimitris@siganos.org>
Date: Sun, 9 Nov 2025 11:41:34 +0000
Subject: [PATCH 02/20] tpm2_checkquote: Fix indentation in
parse_marshaled_selection_data
Signed-off-by: Dimitrios Siganos <dimitris@siganos.org>
---
tools/misc/tpm2_checkquote.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
index fb4d5868..8abf75e6 100644
--- a/tools/misc/tpm2_checkquote.c
+++ b/tools/misc/tpm2_checkquote.c
@@ -373,19 +373,19 @@ static bool parse_marshaled_selection_data(FILE *pcr_input,
return false;
}
- for (i = 0; i < pcrs->count; i++) {
- rc = Tss2_MU_TPML_DIGEST_Unmarshal(buffer, size, &offset,
- &pcrs->pcr_values[i]);
- if (rc) {
- LOG_ERR("Failed unmarshal PCR digest list.");
- goto error;
- }
- }
- return true;
-
- error:
- free(buffer);
- return false;
+ for (i = 0; i < pcrs->count; i++) {
+ rc = Tss2_MU_TPML_DIGEST_Unmarshal(buffer, size, &offset,
+ &pcrs->pcr_values[i]);
+ if (rc) {
+ LOG_ERR("Failed unmarshal PCR digest list.");
+ goto error;
+ }
+ }
+ return true;
+
+error:
+ free(buffer);
+ return false;
}
static bool pcrs_from_file(const char *pcr_file_path,
--
2.54.0

View File

@ -0,0 +1,30 @@
From 5c20a472e856b10301a4c5c0c02dc49b594f6c3f Mon Sep 17 00:00:00 2001
From: Dimitrios Siganos <dimitris@siganos.org>
Date: Sun, 9 Nov 2025 11:50:52 +0000
Subject: [PATCH 03/20] tpm2_checkquote: Fix missing error checking
The return of malloc was not checked
Signed-off-by: Dimitrios Siganos <dimitris@siganos.org>
---
tools/misc/tpm2_checkquote.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
index 8abf75e6..abd09619 100644
--- a/tools/misc/tpm2_checkquote.c
+++ b/tools/misc/tpm2_checkquote.c
@@ -350,6 +350,10 @@ static bool parse_marshaled_selection_data(FILE *pcr_input,
UINT32 count;
buffer = malloc(fsize);
+ if (!buffer) {
+ LOG_ERR("OOM");
+ return false;
+ }
if (!file_read_bytes_from_file(pcr_input, buffer, &size, ctx.pcr_file_path)) {
LOG_ERR("Failed to read PCR selection from file");
--
2.54.0

View File

@ -0,0 +1,47 @@
From 62846ee6a0c79d0098bcd5bece2af5955c4e3646 Mon Sep 17 00:00:00 2001
From: Dimitrios Siganos <dimitris@siganos.org>
Date: Sun, 9 Nov 2025 11:53:21 +0000
Subject: [PATCH 04/20] tpm2_checkquote: Fix memory leaks, malloced buffer not
always freed
A buffer allocated with malloc was not freed in all possible paths,
not even in the success path.
Signed-off-by: Dimitrios Siganos <dimitris@siganos.org>
---
tools/misc/tpm2_checkquote.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
index abd09619..0c0427da 100644
--- a/tools/misc/tpm2_checkquote.c
+++ b/tools/misc/tpm2_checkquote.c
@@ -357,7 +357,7 @@ static bool parse_marshaled_selection_data(FILE *pcr_input,
if (!file_read_bytes_from_file(pcr_input, buffer, &size, ctx.pcr_file_path)) {
LOG_ERR("Failed to read PCR selection from file");
- return false;
+ goto error;
}
rc = Tss2_MU_TPML_PCR_SELECTION_Unmarshal(buffer, size, &offset, pcr_select);
@@ -374,7 +374,7 @@ static bool parse_marshaled_selection_data(FILE *pcr_input,
if (pcrs->count > ARRAY_LEN(pcrs->pcr_values)) {
LOG_ERR("Malformed PCR file, pcr count cannot be greater than %zu, got: %" PRIu64 " ",
ARRAY_LEN(pcrs->pcr_values), le64toh((UINT64)pcrs->count));
- return false;
+ goto error;
}
for (i = 0; i < pcrs->count; i++) {
@@ -385,6 +385,7 @@ static bool parse_marshaled_selection_data(FILE *pcr_input,
goto error;
}
}
+ free(buffer);
return true;
error:
--
2.54.0

View File

@ -0,0 +1,226 @@
From 0c563fee6c9b4cecd347420581019b62feeb51c2 Mon Sep 17 00:00:00 2001
From: Juergen Repp <juergen_repp@web.de>
Date: Wed, 14 Jan 2026 08:34:13 +0100
Subject: [PATCH 06/20] tpm2_create: Fix creation of ctx file if
TPM2_CreateLoaded is not available.
If the TPM2 command CreateLoaded is not available the creation of a ctx
file with tpm2_create was not possible. Now a TPM2_Create and TPM2_Load is
used to create a ctx file if CreateLoaded is not available.
Signed-off-by: Juergen Repp <juergen_repp@web.de>
---
lib/tpm2.c | 67 +++++++++++++++++++++++++++++++++----------
lib/tpm2.h | 4 ++-
lib/tpm2_capability.c | 37 ++++++++++++++++++++++++
tools/tpm2_create.c | 14 ++-------
4 files changed, 94 insertions(+), 28 deletions(-)
diff --git a/lib/tpm2.c b/lib/tpm2.c
index 27f101e9..2f8991f2 100644
--- a/lib/tpm2.c
+++ b/lib/tpm2.c
@@ -1425,15 +1425,32 @@ tpm2_create_skip_esapi_call:
tool_rc tpm2_create_loaded(ESYS_CONTEXT *esys_context,
tpm2_loaded_object *parent_obj,
const TPM2B_SENSITIVE_CREATE *in_sensitive,
- const TPM2B_TEMPLATE *in_public, ESYS_TR *object_handle,
+ const TPM2B_PUBLIC *in_public, ESYS_TR *object_handle,
TPM2B_PRIVATE **out_private, TPM2B_PUBLIC **out_public,
TPM2B_DIGEST *cp_hash, TPM2B_DIGEST *rp_hash,
TPMI_ALG_HASH parameter_hash_algorithm, ESYS_TR shandle2,
ESYS_TR shandle3) {
-
+ TPM2B_TEMPLATE template = { .size = 0 };
+
TSS2_SYS_CONTEXT *sys_context = NULL;
+ bool create_loaded_exists;
tool_rc rc = tool_rc_success;
- if (cp_hash->size || rp_hash->size) {
+ size_t offset = 0;
+
+ tool_rc tmp_rc = tpm2_mu_tpmt_public_marshal(
+ &in_public->publicArea, &template.buffer[0],
+ sizeof(TPMT_PUBLIC), &offset);
+ if (tmp_rc != tool_rc_success) {
+ return tmp_rc;
+ }
+
+ template.size = offset;
+
+ rc = tpm2_check_cc(esys_context, TPM2_CC_CreateLoaded, &create_loaded_exists);
+ if (rc != tool_rc_success) {
+ return rc;
+ }
+ if ((cp_hash->size || rp_hash->size) && create_loaded_exists) {
rc = tpm2_getsapicontext(esys_context, &sys_context);
if(rc != tool_rc_success) {
@@ -1442,9 +1459,9 @@ tool_rc tpm2_create_loaded(ESYS_CONTEXT *esys_context,
}
}
- if (cp_hash->size) {
+ if (cp_hash->size && create_loaded_exists) {
TSS2_RC rval = Tss2_Sys_CreateLoaded_Prepare(sys_context,
- parent_obj->handle, in_sensitive, in_public);
+ parent_obj->handle, in_sensitive, &template);
if (rval != TPM2_RC_SUCCESS) {
LOG_PERR(Tss2_Sys_CreateLoaded_Prepare, rval);
return tool_rc_general_error;
@@ -1480,19 +1497,39 @@ tpm2_createloaded_free_name1:
return rc;
}
- TSS2_RC rval = Esys_CreateLoaded(esys_context, parent_obj->tr_handle,
- shandle1, shandle2, shandle3, in_sensitive, in_public,
+ if (create_loaded_exists) {
+ TSS2_RC rval = Esys_CreateLoaded(esys_context, parent_obj->tr_handle,
+ shandle1, shandle2, shandle3, in_sensitive, &template,
object_handle, out_private, out_public);
- if (rval != TSS2_RC_SUCCESS) {
- LOG_PERR(Esys_CreateLoaded, rval);
- return tool_rc_from_tpm(rval);
- }
+ if (rval != TSS2_RC_SUCCESS) {
+ LOG_PERR(Esys_CreateLoaded, rval);
+ return tool_rc_from_tpm(rval);
+ }
- if (rp_hash->size) {
- rc = tpm2_sapi_getrphash(sys_context, rval, rp_hash,
- parameter_hash_algorithm);
+ if (rp_hash->size) {
+ rc = tpm2_sapi_getrphash(sys_context, rval, rp_hash,
+ parameter_hash_algorithm);
+ }
+ } else {
+ TPML_PCR_SELECTION creationPCR = {
+ .count = 0,
+ };
+
+ TSS2_RC rval = Esys_Create(esys_context, parent_obj->tr_handle,
+ shandle1, shandle2, shandle3, in_sensitive, in_public,
+ NULL, &creationPCR, out_private, out_public, NULL, NULL, NULL);
+ if (rval != TSS2_RC_SUCCESS) {
+ LOG_PERR(Esys_CreateLoaded, rval);
+ return tool_rc_from_tpm(rval);
+ }
+ rval = Esys_Load(esys_context, parent_obj->tr_handle,
+ shandle1, shandle2, shandle3, *out_private,
+ *out_public, object_handle);
+ if (rval != TPM2_RC_SUCCESS) {
+ LOG_PERR(Esys_Load, rval);
+ return tool_rc_from_tpm(rval);
+ }
}
-
tpm2_createloaded_skip_esapi_call:
return rc;
}
diff --git a/lib/tpm2.h b/lib/tpm2.h
index ed5f246d..8809ca3e 100644
--- a/lib/tpm2.h
+++ b/lib/tpm2.h
@@ -62,6 +62,8 @@ tool_rc tpm2_sess_get_noncetpm(ESYS_CONTEXT *esys_context,
tool_rc tpm2_policy_restart(ESYS_CONTEXT *esys_context, ESYS_TR session_handle,
ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3);
+tool_rc tpm2_check_cc(ESYS_CONTEXT *ectx, uint32_t cc, bool *exists);
+
tool_rc tpm2_get_capability(ESYS_CONTEXT *esys_context, ESYS_TR shandle1,
ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability,
UINT32 property, UINT32 property_count, TPMI_YES_NO *more_data,
@@ -199,7 +201,7 @@ tool_rc tpm2_create(ESYS_CONTEXT *esys_context, tpm2_loaded_object *parent_obj,
tool_rc tpm2_create_loaded(ESYS_CONTEXT *esys_context,
tpm2_loaded_object *parent_obj,
const TPM2B_SENSITIVE_CREATE *in_sensitive,
- const TPM2B_TEMPLATE *in_public, ESYS_TR *object_handle,
+ const TPM2B_PUBLIC *in_public, ESYS_TR *object_handle,
TPM2B_PRIVATE **out_private, TPM2B_PUBLIC **out_public,
TPM2B_DIGEST *cp_hash, TPM2B_DIGEST *rp_hash,
TPMI_ALG_HASH parameter_hash_algorithm, ESYS_TR shandle2,
diff --git a/lib/tpm2_capability.c b/lib/tpm2_capability.c
index 95c332d0..3bccaeca 100644
--- a/lib/tpm2_capability.c
+++ b/lib/tpm2_capability.c
@@ -5,6 +5,7 @@
#include <string.h>
#include "log.h"
+#include "tool_rc.h"
#include "tpm2.h"
#include "tpm2_capability.h"
@@ -26,6 +27,42 @@
more_data = false; \
}
+
+tool_rc tpm2_check_cc(ESYS_CONTEXT *ectx, uint32_t cc, bool *exists) {
+ TPMI_YES_NO more_data = TPM2_NO;
+ TPMS_CAPABILITY_DATA *cap = NULL;
+ uint32_t count = 1;
+
+
+ TSS2_RC rc = Esys_GetCapability(
+ ectx,
+ ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
+ TPM2_CAP_COMMANDS,
+ cc,
+ count,
+ &more_data,
+ &cap
+ );
+
+ if (rc != TSS2_RC_SUCCESS) {
+ LOG_ERR("Esys_GetCapability(TPM2_CAP_COMMANDS, property=0x%08" PRIX32 " failed: 0x%x",
+ cc, rc);
+ return tool_rc_general_error;
+ }
+
+ const TPML_CCA *cmds = &cap->data.command;
+
+ if (cmds->count == 1 && (cmds->commandAttributes[0] & 0xffff) == cc) {
+ Esys_Free(cap);
+ *exists = true;
+ return tool_rc_success;
+ }
+
+ Esys_Free(cap);
+ *exists = false;
+ return tool_rc_success;
+}
+
tool_rc tpm2_capability_get(ESYS_CONTEXT *ectx, TPM2_CAP capability,
UINT32 property, UINT32 count, TPMS_CAPABILITY_DATA **capability_data) {
diff --git a/tools/tpm2_create.c b/tools/tpm2_create.c
index 1c75c384..9e1757d7 100644
--- a/tools/tpm2_create.c
+++ b/tools/tpm2_create.c
@@ -118,19 +118,9 @@ static tool_rc create(ESYS_CONTEXT *ectx) {
/* TPM2_CC_CreateLoaded */
if (ctx.is_createloaded) {
- size_t offset = 0;
- TPM2B_TEMPLATE template = { .size = 0 };
- tool_rc tmp_rc = tpm2_mu_tpmt_public_marshal(
- &ctx.object.in_public.publicArea, &template.buffer[0],
- sizeof(TPMT_PUBLIC), &offset);
- if (tmp_rc != tool_rc_success) {
- return tmp_rc;
- }
-
- template.size = offset;
-
+ tool_rc tmp_rc;
tmp_rc = tpm2_create_loaded(ectx, &ctx.parent.object,
- &ctx.object.sensitive, &template, &ctx.object.object_handle,
+ &ctx.object.sensitive, &ctx.object.in_public, &ctx.object.object_handle,
&ctx.object.out_private, &ctx.object.out_public, &ctx.cp_hash,
&ctx.rp_hash, ctx.parameter_hash_algorithm,
ctx.aux_session_handle[0], ctx.aux_session_handle[1]);
--
2.54.0

View File

@ -0,0 +1,66 @@
From b543b618d8937d8d8ef351935ad6d132171699a1 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Tue, 3 Feb 2026 18:43:01 +0900
Subject: [PATCH 07/20] fix(checkquote): fix off-by-one in PCR digest list
handling
parse_selection_data_from_selection_string() now updates
TPML_DIGEST.count correctly and rolls over to a new list only after
8 digests, resolving failures with 8+ PCRs in the -f/-l path.
Fixes: #3542
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/misc/tpm2_checkquote.c | 30 ++++++++++++------------------
1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
index 0c0427da..4c820208 100644
--- a/tools/misc/tpm2_checkquote.c
+++ b/tools/misc/tpm2_checkquote.c
@@ -260,29 +260,23 @@ static bool parse_selection_data_from_selection_string(FILE *pcr_input,
/*
* Read the digest at a selected PCR index.
*/
- pcrs->pcr_values[digest_list_count].digests[pcrs->pcr_values[
- digest_list_count].count].size = read_size;
- read_count = fread(pcrs->pcr_values[digest_list_count].digests[
- pcrs->pcr_values[digest_list_count].count].buffer,
+ if (pcrs->pcr_values[digest_list_count].count == 8) {
+ ++digest_list_count;
+ if (digest_list_count >= TPM2_MAX_PCRS) {
+ LOG_ERR("Maximum count for allowed digest lists reached.");
+ return false;
+ }
+ }
+ UINT32 digest_index = pcrs->pcr_values[digest_list_count].count;
+ pcrs->pcr_values[digest_list_count].digests[digest_index].size = read_size;
+ read_count = fread(
+ pcrs->pcr_values[digest_list_count].digests[digest_index].buffer,
read_size, 1, pcr_input);
if (read_count != 1) {
LOG_ERR("Failed to read PCR digests from file");
return false;
}
- /*
- * Ensure we don't overrun the allowed digest count in a
- * TPML_DIGEST.
- */
- if (pcrs->pcr_values[digest_list_count].count == 7) {
- digest_list_count++;
- } else {
- /*
- * Ensure we populate the digest in a new list if we
- * exhausted the digest count in the current TPML_DIGEST
- * instance.
- */
- pcrs->pcr_values[digest_list_count].count++;
- }
+ pcrs->pcr_values[digest_list_count].count++;
}
}
}
--
2.54.0

View File

@ -0,0 +1,54 @@
From ca2d039f073bf3544a0ba3915c586769d724a0a3 Mon Sep 17 00:00:00 2001
From: Juergen Repp <juergen_repp@web.de>
Date: Tue, 3 Feb 2026 16:18:46 +0100
Subject: [PATCH 08/20] tpm2_checkquote: Add size checks for PCR
desearialization
When a binary blob in the PCR file written in the form 'serialized'
is used the size fields are not checked after reading the file.
These field are no checked and an error is produced if the max values
are exceeded.
Signed-off-by: Juergen Repp <juergen_repp@web.de>
---
tools/misc/tpm2_checkquote.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
index 4c820208..4f8ae74b 100644
--- a/tools/misc/tpm2_checkquote.c
+++ b/tools/misc/tpm2_checkquote.c
@@ -299,6 +299,10 @@ static bool parse_selection_data_from_file(FILE *pcr_input,
return false;
}
pcr_select->count = le32toh(pcr_select->count);
+ if (pcr_select->count > TPM2_NUM_PCR_BANKS) {
+ LOG_ERR("Failed to read PCR selection from file");
+ return false;
+ }
for (i = 0; i < pcr_select->count; i++) {
pcr_select->pcrSelections[i].hash = le16toh(pcr_select->pcrSelections[i].hash);
}
@@ -325,9 +329,19 @@ static bool parse_selection_data_from_file(FILE *pcr_input,
}
// Convert TPML_DIGEST from little endian to host endian.
pcrs->pcr_values[j].count = le32toh( pcrs->pcr_values[j].count);
+ if (pcrs->pcr_values[j].count > ARRAY_LEN(pcrs->pcr_values[j].digests)) {
+ LOG_ERR("Malformed PCR file, TPML_DIGEST count cannot be greater than %" PRIu64,
+ ARRAY_LEN(pcrs->pcr_values[j].digests));
+ return false;
+ }
for (i = 0; i < pcrs->pcr_values[j].count; i++) {
pcrs->pcr_values[j].digests[i].size =
le16toh(pcrs->pcr_values[j].digests[i].size);
+ if (pcrs->pcr_values[j].digests[i].size > sizeof(TPMU_HA)) {
+ LOG_ERR("Malformed PCR file, TPML_DIGEST count cannot be greater than %" PRIu64,
+ sizeof(TPMU_HA));
+ return false;
+ }
}
}
--
2.54.0

View File

@ -0,0 +1,44 @@
From 5abee441971dcc8e98077748058704d71edcf0e1 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 15 Feb 2026 04:39:57 +0900
Subject: [PATCH 09/20] fix(tpm2_send): validate command_size before computing
data_size
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/tpm2_send.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/tools/tpm2_send.c b/tools/tpm2_send.c
index 94936a0a..27f6dca1 100644
--- a/tools/tpm2_send.c
+++ b/tools/tpm2_send.c
@@ -47,15 +47,19 @@ static int read_command_from_file(FILE *f, tpm2_command_header **c,
tpm2_command_header *header = tpm2_command_header_from_bytes(buffer);
UINT32 command_size = tpm2_command_header_get_size(header, true);
- UINT32 data_size = tpm2_command_header_get_size(header, false);
-
- if (command_size > TPM2_MAX_SIZE || command_size < data_size) {
- LOG_ERR("Command buffer %"PRIu32" bytes cannot be smaller then the "
- "encapsulated data %"PRIu32" bytes, and can not be bigger than"
- " the maximum buffer size", command_size, data_size);
+ if (command_size < TPM2_COMMAND_HEADER_SIZE) {
+ LOG_ERR("Command buffer size %"PRIu32" is smaller than command header "
+ "size %zu", command_size, TPM2_COMMAND_HEADER_SIZE);
+ return -1;
+ }
+ if (command_size > TPM2_MAX_SIZE) {
+ LOG_ERR("Command buffer size %"PRIu32" exceeds maximum buffer size %u",
+ command_size, TPM2_MAX_SIZE);
return -1;
}
+ UINT32 data_size = tpm2_command_header_get_size(header, false);
+
tpm2_command_header *command = (tpm2_command_header *) malloc(command_size);
if (!command) {
LOG_ERR("oom");
--
2.54.0

View File

@ -0,0 +1,27 @@
From 07eaf78eb14c818a10ee5a835b76e81ccfd2ad2f Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 15 Feb 2026 05:59:27 +0900
Subject: [PATCH 10/20] fix(tpm2_send): avoid unintended stdio closing in
close_file()
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/tpm2_send.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/tpm2_send.c b/tools/tpm2_send.c
index 27f6dca1..18b3a733 100644
--- a/tools/tpm2_send.c
+++ b/tools/tpm2_send.c
@@ -111,7 +111,7 @@ static FILE *open_file(const char *path, const char *mode) {
static void close_file(FILE *f) {
- if (f && (f != stdin || f != stdout)) {
+ if (f && f != stdin && f != stdout) {
fclose(f);
}
}
--
2.54.0

View File

@ -0,0 +1,27 @@
From 0c0035e606862ba0a37daab890162ae3de07b975 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 15 Feb 2026 13:04:10 +0900
Subject: [PATCH 11/20] fix(tpm2_util): fix error message in
tpm2_pem_encoded_key_to_fingerprint
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
lib/tpm2_util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
index 31204b56..d9ca57e7 100644
--- a/lib/tpm2_util.c
+++ b/lib/tpm2_util.c
@@ -1069,7 +1069,7 @@ bool tpm2_pem_encoded_key_to_fingerprint(const char *pem_encoded_key,
rc = tpm2_base64_encode(buffer, buffer_length, base64);
if(!rc){
- LOG_ERR("%s", "tpm2_base64_decode");
+ LOG_ERR("%s", "tpm2_base64_encode");
return false;
}
strcpy(fingerprint, "SHA256:");
--
2.54.0

View File

@ -0,0 +1,70 @@
From 8e4b970a8c1523c6af7c35e662a3ad41a5d31e3c Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 15 Feb 2026 08:05:58 +0900
Subject: [PATCH 12/20] fix(tpm2_util)!: modify tpm2_safe_read_from_stdin to
read entire line
Fixes #3551.
The tpm2_safe_read_from_stdin function is used exclusively in
tools/fapi/tss2_template.c to read file paths from stdin. The current
implementation however uses the "%s" template in sscanf, which cannot
properly handle file paths containing whitespaces.
This commit modifies the function's behavior to read the entire line.
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
lib/tpm2_util.c | 25 +++++++------------------
1 file changed, 7 insertions(+), 18 deletions(-)
diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
index d9ca57e7..a5facec7 100644
--- a/lib/tpm2_util.c
+++ b/lib/tpm2_util.c
@@ -3,6 +3,7 @@
#include <ctype.h>
#include <dlfcn.h>
#include <inttypes.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -1000,28 +1001,16 @@ out:
}
bool tpm2_safe_read_from_stdin(int length, char *data) {
- int rc;
- char *buf = malloc(length);
- char *read_data = malloc(length);
-
- if (buf == fgets(buf, length, stdin)) {
- rc = sscanf(buf, "%s", read_data);
- if (rc != 1) {
- free(buf);
- free(read_data);
- return false;
- }
- }
- else {
- free(buf);
- free(read_data);
+ /* Read line from stdin; at most length-1 bytes + null-termination */
+ if (!fgets(data, length, stdin)) {
return false;
}
- strcpy(data, read_data);
- free(buf);
- free(read_data);
+ /* Delete newline character */
+ size_t end = strcspn(data, "\r\n");
+ data[end] = '\0';
+
return true;
}
--
2.54.0

View File

@ -0,0 +1,286 @@
From 35274ee8e236b379081e02b13c8c610170250463 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Tue, 17 Feb 2026 23:36:49 +0900
Subject: [PATCH 13/20] fix(tools): out-of-bounds write with too many auxiliary
sessions
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/tpm2_activatecredential.c | 9 ++++-----
tools/tpm2_certify.c | 9 ++++-----
tools/tpm2_certifycreation.c | 9 ++++-----
tools/tpm2_changeauth.c | 7 +++----
tools/tpm2_changeeps.c | 9 ++++-----
tools/tpm2_changepps.c | 9 ++++-----
tools/tpm2_create.c | 9 ++++-----
tools/tpm2_getrandom.c | 9 ++++-----
tools/tpm2_nvdefine.c | 8 ++++----
tools/tpm2_nvextend.c | 8 ++++----
tools/tpm2_nvread.c | 9 ++++-----
tools/tpm2_nvsetbits.c | 9 ++++-----
12 files changed, 47 insertions(+), 57 deletions(-)
diff --git a/tools/tpm2_activatecredential.c b/tools/tpm2_activatecredential.c
index eee8a210..a1cf65fa 100644
--- a/tools/tpm2_activatecredential.c
+++ b/tools/tpm2_activatecredential.c
@@ -292,13 +292,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
}
diff --git a/tools/tpm2_certify.c b/tools/tpm2_certify.c
index 38dd626b..7d5146b0 100644
--- a/tools/tpm2_certify.c
+++ b/tools/tpm2_certify.c
@@ -315,13 +315,12 @@ static bool on_option(char key, char *value) {
}
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
}
diff --git a/tools/tpm2_certifycreation.c b/tools/tpm2_certifycreation.c
index c301aad5..c5070d10 100644
--- a/tools/tpm2_certifycreation.c
+++ b/tools/tpm2_certifycreation.c
@@ -358,13 +358,12 @@ static bool on_option(char key, char *value) {
ctx.policy_qualifier_data = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
/* no default */
}
diff --git a/tools/tpm2_changeauth.c b/tools/tpm2_changeauth.c
index 4b65ea9e..014b71b5 100644
--- a/tools/tpm2_changeauth.c
+++ b/tools/tpm2_changeauth.c
@@ -309,13 +309,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
LOG_ERR("Specify a max of 3 sessions");
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
/*no default */
}
diff --git a/tools/tpm2_changeeps.c b/tools/tpm2_changeeps.c
index c3d6f6df..8c95915f 100644
--- a/tools/tpm2_changeeps.c
+++ b/tools/tpm2_changeeps.c
@@ -164,13 +164,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
}
diff --git a/tools/tpm2_changepps.c b/tools/tpm2_changepps.c
index 343dfc9b..fa331cd8 100644
--- a/tools/tpm2_changepps.c
+++ b/tools/tpm2_changepps.c
@@ -164,13 +164,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
}
diff --git a/tools/tpm2_create.c b/tools/tpm2_create.c
index 9e1757d7..2aea7ffc 100644
--- a/tools/tpm2_create.c
+++ b/tools/tpm2_create.c
@@ -515,13 +515,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
case 'f':
ctx.format = tpm2_convert_pubkey_fmt_from_optarg(value);
diff --git a/tools/tpm2_getrandom.c b/tools/tpm2_getrandom.c
index f4b064d9..a6775a60 100644
--- a/tools/tpm2_getrandom.c
+++ b/tools/tpm2_getrandom.c
@@ -289,13 +289,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
/* no default */
}
diff --git a/tools/tpm2_nvdefine.c b/tools/tpm2_nvdefine.c
index 7f193e83..650eb205 100644
--- a/tools/tpm2_nvdefine.c
+++ b/tools/tpm2_nvdefine.c
@@ -428,12 +428,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
case 'g':
ctx.halg = tpm2_alg_util_from_optarg(value,
diff --git a/tools/tpm2_nvextend.c b/tools/tpm2_nvextend.c
index 44fb1e81..84d94fe6 100644
--- a/tools/tpm2_nvextend.c
+++ b/tools/tpm2_nvextend.c
@@ -224,12 +224,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
case 'n':
ctx.precalc_nvname.size = BUFFER_SIZE(TPM2B_NAME, name);
diff --git a/tools/tpm2_nvread.c b/tools/tpm2_nvread.c
index 8f9c61cc..ea7d389f 100644
--- a/tools/tpm2_nvread.c
+++ b/tools/tpm2_nvread.c
@@ -321,13 +321,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
/* no default */
}
diff --git a/tools/tpm2_nvsetbits.c b/tools/tpm2_nvsetbits.c
index feb4d938..89ff1ccd 100644
--- a/tools/tpm2_nvsetbits.c
+++ b/tools/tpm2_nvsetbits.c
@@ -237,13 +237,12 @@ static bool on_option(char key, char *value) {
ctx.rp_hash_path = value;
break;
case 'S':
- ctx.aux_session_path[ctx.aux_session_cnt] = value;
- if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
- ctx.aux_session_cnt++;
- } else {
- LOG_ERR("Specify a max of 3 sessions");
+ if (ctx.aux_session_cnt >= MAX_AUX_SESSIONS) {
+ LOG_ERR("Specify a max of %u auxiliary sessions", MAX_AUX_SESSIONS);
return false;
}
+ ctx.aux_session_path[ctx.aux_session_cnt] = value;
+ ++ctx.aux_session_cnt;
break;
case 'n':
ctx.precalc_nvname.size = BUFFER_SIZE(TPM2B_NAME, name);
--
2.54.0

View File

@ -0,0 +1,123 @@
From d154f8bf3688269fbe9bcfcf2f02a9f1fd513bdf Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Wed, 18 Feb 2026 23:38:43 +0900
Subject: [PATCH 14/20] fix(tpm2_alg_util): avoid mutating input scheme in
handle_scheme_sign
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
lib/tpm2_alg_util.c | 52 ++++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 24 deletions(-)
diff --git a/lib/tpm2_alg_util.c b/lib/tpm2_alg_util.c
index 580f41cb..f66ec7bb 100644
--- a/lib/tpm2_alg_util.c
+++ b/lib/tpm2_alg_util.c
@@ -153,9 +153,9 @@ static alg_parser_rc handle_sym_common(const char *ext, TPMT_SYM_DEF_OBJECT *s)
* You cannot change all the variables in this, as they are dependent
* on names in that routine; this is for simplicity.
*/
-#define do_scheme_halg(scheme, advance, alg) \
+#define DO_SCHEME_HALG(scheme_, advance, alg) \
do { \
- scheme += advance; \
+ scheme_ += advance; \
s->scheme.scheme = alg; \
do_scheme_hash_alg = true; \
found = true; \
@@ -175,16 +175,18 @@ static alg_parser_rc handle_scheme_sign(const char *scheme,
return alg_parser_rc_error;
}
+ char *buf_ptr = buf;
+
// Get the scheme and symetric details
TPMS_ASYM_PARMS *s = &public->publicArea.parameters.asymDetail;
- if (!strcmp(scheme, "null")) {
+ if (!strcmp(buf_ptr, "null")) {
public->publicArea.parameters.asymDetail.scheme.scheme = TPM2_ALG_NULL;
return alg_parser_rc_continue;
}
char *halg = NULL;
- char *split = strchr(scheme, '-');
+ char *split = strchr(buf_ptr, '-');
if (split) {
*split = '\0';
halg = split + 1;
@@ -194,49 +196,51 @@ static alg_parser_rc handle_scheme_sign(const char *scheme,
bool do_scheme_hash_alg = false;
if (public->publicArea.type == TPM2_ALG_ECC) {
- if (!strncmp(scheme, "ecdsa", 5)) {
- do_scheme_halg(scheme, 5, TPM2_ALG_ECDSA);
- } else if (!strncmp(scheme, "ecdh", 4)) {
- do_scheme_halg(scheme, 4, TPM2_ALG_ECDH);
- } else if (!strncmp(scheme, "ecschnorr", 9)) {
- do_scheme_halg(scheme, 9, TPM2_ALG_ECSCHNORR);
- } else if (!strncmp(scheme, "ecdaa", 5)) {
- do_scheme_halg(scheme, 5, TPM2_ALG_ECDAA);
+ if (!strncmp(buf_ptr, "ecdsa", 5)) {
+ DO_SCHEME_HALG(buf_ptr, 5, TPM2_ALG_ECDSA);
+ } else if (!strncmp(buf_ptr, "ecdh", 4)) {
+ DO_SCHEME_HALG(buf_ptr, 4, TPM2_ALG_ECDH);
+ } else if (!strncmp(buf_ptr, "ecschnorr", 9)) {
+ DO_SCHEME_HALG(buf_ptr, 9, TPM2_ALG_ECSCHNORR);
+ } else if (!strncmp(buf_ptr, "ecdaa", 5)) {
+ DO_SCHEME_HALG(buf_ptr, 5, TPM2_ALG_ECDAA);
/*
* ECDAA has both a commit-counter value and hashing algorithm.
* The default commit-counter value is set to zero to use the first
* commit-id.
*/
- if (scheme[0] == '\0') {
- scheme = "0";
+ const char *count_str = buf_ptr;
+ if (buf_ptr[0] == '\0') {
+ count_str = "0";
}
TPMS_SIG_SCHEME_ECDAA *e = &s->scheme.details.ecdaa;
- bool res = tpm2_util_string_to_uint16(scheme, &e->count);
+ bool res = tpm2_util_string_to_uint16(count_str, &e->count);
if (!res) {
return alg_parser_rc_error;
}
- } else if (!strcmp("null", scheme)) {
+ } else if (!strcmp(buf_ptr, "null")) {
s->scheme.scheme = TPM2_ALG_NULL;
+ found = true;
}
} else {
- if (!strcmp(scheme, "rsaes")) {
+ if (!strcmp(buf_ptr, "rsaes")) {
/*
* rsaes has no hash alg or details, so it MUST
* match exactly, notice strcmp and NOT strNcmp!
*/
s->scheme.scheme = TPM2_ALG_RSAES;
found = true;
- } else if (!strcmp("null", scheme)) {
+ } else if (!strcmp(buf_ptr, "null")) {
s->scheme.scheme = TPM2_ALG_NULL;
found = true;
- } else if (!strncmp("rsapss", scheme, 6)) {
- do_scheme_halg(scheme, 6, TPM2_ALG_RSAPSS);
- } else if (!strncmp("rsassa", scheme, 6)) {
- do_scheme_halg(scheme, 6, TPM2_ALG_RSASSA);
- } else if (!strncmp(scheme, "oaep", 4)) {
- do_scheme_halg(scheme, 4, TPM2_ALG_OAEP);
+ } else if (!strncmp(buf_ptr, "rsapss", 6)) {
+ DO_SCHEME_HALG(buf_ptr, 6, TPM2_ALG_RSAPSS);
+ } else if (!strncmp(buf_ptr, "rsassa", 6)) {
+ DO_SCHEME_HALG(buf_ptr, 6, TPM2_ALG_RSASSA);
+ } else if (!strncmp(buf_ptr, "oaep", 4)) {
+ DO_SCHEME_HALG(buf_ptr, 4, TPM2_ALG_OAEP);
}
}
--
2.54.0

View File

@ -0,0 +1,56 @@
From 3f0538eecd0f53fc4f9a09bad73418f0f058519a Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 1 Mar 2026 03:41:03 +0900
Subject: [PATCH 15/20] fix(tools): add missing null checks after malloc
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/tpm2_getekcertificate.c | 9 +++++++++
tools/tpm2_verifysignature.c | 4 ++++
2 files changed, 13 insertions(+)
diff --git a/tools/tpm2_getekcertificate.c b/tools/tpm2_getekcertificate.c
index b8fa5647..b824d59c 100644
--- a/tools/tpm2_getekcertificate.c
+++ b/tools/tpm2_getekcertificate.c
@@ -381,6 +381,11 @@ static bool retrieve_web_endorsement_certificate(char *b64h) {
* rsa_cert_buffer for either RSA EK cert or ECC EK cert.
*/
ctx.rsa_cert_buffer = malloc(CURL_MAX_WRITE_SIZE);
+ if (!ctx.rsa_cert_buffer) {
+ LOG_ERR("oom");
+ ret = false;
+ goto out_easy_cleanup;
+ }
rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)ctx.rsa_cert_buffer);
if (rc != CURLE_OK) {
LOG_ERR("curl_easy_setopt for CURLOPT_WRITEDATA failed: %s",
@@ -666,6 +671,10 @@ static tool_rc process_input(ESYS_CONTEXT *ectx) {
if (ctx.ek_path) {
ctx.out_public = malloc(sizeof(*ctx.out_public));
+ if (!ctx.out_public) {
+ LOG_ERR("oom");
+ return tool_rc_general_error;
+ }
ctx.out_public->size = 0;
bool res = files_load_public(ctx.ek_path, ctx.out_public);
if (!res) {
diff --git a/tools/tpm2_verifysignature.c b/tools/tpm2_verifysignature.c
index e09dd48c..55e78263 100644
--- a/tools/tpm2_verifysignature.c
+++ b/tools/tpm2_verifysignature.c
@@ -193,6 +193,10 @@ static bool on_option(char key, char *value) {
break;
case 'd': {
ctx.msg_hash = malloc(sizeof(TPM2B_DIGEST));
+ if (!ctx.msg_hash) {
+ LOG_ERR("oom");
+ return false;
+ }
ctx.msg_hash->size = sizeof(ctx.msg_hash->buffer);
if (!files_load_bytes_from_path(value, ctx.msg_hash->buffer,
&ctx.msg_hash->size)) {
--
2.54.0

View File

@ -0,0 +1,45 @@
From 11874a7231fb8a6dae77f63aaec62fd733a3ef53 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Sun, 1 Mar 2026 02:47:49 +0900
Subject: [PATCH 16/20] fix(tpm2_util): fix buffer overflow in string
validation checks
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
lib/tpm2_util.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
index a5facec7..e1f4ff91 100644
--- a/lib/tpm2_util.c
+++ b/lib/tpm2_util.c
@@ -1017,22 +1017,20 @@ bool tpm2_safe_read_from_stdin(int length, char *data) {
bool tpm2_pem_encoded_key_to_fingerprint(const char *pem_encoded_key,
char *fingerprint) {
- bool is_pemkey_len_valid = strlen(pem_encoded_key) > 1024 ? false : true;
- if (!is_pemkey_len_valid) {
+ if (strlen(pem_encoded_key) >= 1024) {
return false;
}
char str[1024] = "";
- strcpy(str, pem_encoded_key);
+ strncpy(str, pem_encoded_key, 1023);
+ str[1023] = '\0';
/* walk through other tokens */
char base64[1024] = "";
char *token = strtok(str, "\n");
while ( token != NULL ) {
if (!strstr(token, "-----")) {
- bool is_base64_overrun = (strlen(base64) + strlen(token)) > 1024 ?
- true : false;
- if (is_base64_overrun) {
+ if ((strlen(base64) + strlen(token)) >= 1024) {
return false;
}
strcat(base64, token);
--
2.54.0

View File

@ -0,0 +1,30 @@
From 5d9dc0a5abb716f6c30c8fa6c47f31fabf8ae5f7 Mon Sep 17 00:00:00 2001
From: Andreas Fuchs <andreas.fuchs@infineon.com>
Date: Tue, 10 Feb 2026 09:20:05 +0100
Subject: [PATCH 17/20] Allocate the right amount of memory for auth_policy
For some reason we did a malloc(UINT16_MAX+...) which is way to much for a policy.
Signed-off-by: Andreas Fuchs <andreas.fuchs@infineon.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---
tools/tpm2_setprimarypolicy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/tpm2_setprimarypolicy.c b/tools/tpm2_setprimarypolicy.c
index 459d3d03..c30323f4 100644
--- a/tools/tpm2_setprimarypolicy.c
+++ b/tools/tpm2_setprimarypolicy.c
@@ -123,7 +123,7 @@ static tool_rc process_setprimarypolicy_input(ESYS_CONTEXT *ectx,
*/
if (ctx.policy_path) {
- *auth_policy = malloc(UINT16_MAX + sizeof(uint16_t));
+ *auth_policy = malloc(sizeof(**auth_policy));
if (!*auth_policy) {
LOG_ERR("oom");
return tool_rc_general_error;
--
2.54.0

View File

@ -0,0 +1,37 @@
From f1083844194a8ce1467d6fcf2481ab3092a1c936 Mon Sep 17 00:00:00 2001
From: Juergen Repp <juergen_repp@web.de>
Date: Sun, 8 Mar 2026 15:59:20 +0100
Subject: [PATCH 18/20] tpm2_util: add some checks to
tpm2_safe_read_from_stdin.
* Prevent garbage in stdin buffer.
* Add check whether input is empty.
Signed-off-by: Juergen Repp <juergen_repp@web.de>
---
lib/tpm2_util.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
index e1f4ff91..a09166d9 100644
--- a/lib/tpm2_util.c
+++ b/lib/tpm2_util.c
@@ -1011,6 +1011,15 @@ bool tpm2_safe_read_from_stdin(int length, char *data) {
size_t end = strcspn(data, "\r\n");
data[end] = '\0';
+ /* clear fget buffer */
+ if (strlen(data) == (size_t)length - 1) {
+ int c;
+ while ((c = getchar()) != '\n' && c != EOF);
+ }
+ /* Return false if input is empty */
+ if (data[0] == '\0') {
+ return false;
+ }
return true;
}
--
2.54.0

View File

@ -0,0 +1,41 @@
From 887387a7fb12c570f813aa8ed1de22367fe60a5a Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Fri, 6 Mar 2026 23:45:56 +0900
Subject: [PATCH 19/20] fix(tpm2_loadexternal): check return value of
RAND_bytes
RAND_bytes() can fail with return code 0 or -1 when the OpenSSL CSPRNG has
not been sufficiently seeded.
If RAND_bytes() fails, seed->buffer is left uninitialised. This seed value
is stored in ctx.priv.sensitiveArea.seedValue and used in the consistency
checks by TPM.
Check the return value and return tool_rc_general_error on failure so that
the operation is aborted rather than proceeding with a bad seed.
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
tools/tpm2_loadexternal.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/tpm2_loadexternal.c b/tools/tpm2_loadexternal.c
index 2cd4411f..1aa37ff0 100644
--- a/tools/tpm2_loadexternal.c
+++ b/tools/tpm2_loadexternal.c
@@ -267,7 +267,11 @@ static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
TPM2B_DIGEST *seed = &priv.sensitiveArea.seedValue;
seed->size = tpm2_alg_util_get_hash_size(pub.publicArea.nameAlg);
if (seed->size != 0) {
- RAND_bytes(seed->buffer, seed->size);
+ int tmp_rc = RAND_bytes(seed->buffer, seed->size);
+ if (tmp_rc != 1) {
+ LOG_ERR("Failed to generate random seed value");
+ return tool_rc_general_error;
+ }
}
tpm2_openssl_load_rc load_status = tpm2_openssl_load_private(
--
2.54.0

View File

@ -0,0 +1,151 @@
From 92139de454e5aecfb11bf9ccba5a5bd2e8052cc6 Mon Sep 17 00:00:00 2001
From: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
Date: Fri, 27 Mar 2026 19:15:29 +0900
Subject: [PATCH 20/20] fix(tpm2_identity_util)!: add buffer size check
hmac_outer_integrity() concatenates two caller-supplied buffers into a
fixed-size stack buffer of TPM2_MAX_DIGEST_BUFFER (1024) bytes using
memcpy without checking their combined size.
This commit adds a buffer size check before memcpy to prevent potential
oob.
To propagate errors to the caller, the return type of hmac_outer_integrity()
and tpm2_identity_util_calculate_outer_integrity() from void to bool.
The latter change breaks compatibility with the public API.
Signed-off-by: Takuma IMAMURA <209989118+hyperfinitism@users.noreply.github.com>
---
lib/tpm2_identity_util.c | 15 ++++++++++++---
lib/tpm2_identity_util.h | 2 +-
tools/tpm2_duplicate.c | 5 ++++-
tools/tpm2_import.c | 5 ++++-
tools/tpm2_makecredential.c | 7 +++++--
5 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
index 781b34c9..759d0cd6 100644
--- a/lib/tpm2_identity_util.c
+++ b/lib/tpm2_identity_util.c
@@ -268,11 +268,18 @@ out:
return result;
}
-static void hmac_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+static bool hmac_outer_integrity(TPMI_ALG_HASH parent_name_alg,
uint8_t *buffer1, uint16_t buffer1_size, uint8_t *buffer2,
uint16_t buffer2_size, uint8_t *hmac_key,
TPM2B_DIGEST *outer_integrity_hmac) {
+ if ((size_t)buffer1_size + buffer2_size > TPM2_MAX_DIGEST_BUFFER) {
+ LOG_ERR("Necessary buffer size (%u) exceeds TPM2_MAX_DIGEST_BUFFER (%zu)",
+ (unsigned)(buffer1_size + buffer2_size),
+ (size_t)TPM2_MAX_DIGEST_BUFFER);
+ return false;
+ }
+
uint8_t to_hmac_buffer[TPM2_MAX_DIGEST_BUFFER];
memcpy(to_hmac_buffer, buffer1, buffer1_size);
memcpy(to_hmac_buffer + buffer1_size, buffer2, buffer2_size);
@@ -284,6 +291,7 @@ static void hmac_outer_integrity(TPMI_ALG_HASH parent_name_alg,
to_hmac_buffer, buffer1_size + buffer2_size,
outer_integrity_hmac->buffer, &size);
outer_integrity_hmac->size = size;
+ return true;
}
bool tpm2_identity_util_calculate_inner_integrity(TPMI_ALG_HASH name_alg,
@@ -359,7 +367,7 @@ bool tpm2_identity_util_calculate_inner_integrity(TPMI_ALG_HASH name_alg,
encrypted_inner_integrity);
}
-void tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+bool tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
TPM2B_NAME *pubname, TPM2B_MAX_BUFFER *marshalled_sensitive,
TPM2B_MAX_BUFFER *protection_hmac_key,
TPM2B_MAX_BUFFER *protection_enc_key, TPMT_SYM_DEF_OBJECT *sym_alg,
@@ -373,7 +381,8 @@ void tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
marshalled_sensitive->buffer, marshalled_sensitive->size,
NULL, 0, encrypted_duplicate_sensitive);
//Calculate outerHMAC
- hmac_outer_integrity(parent_name_alg, encrypted_duplicate_sensitive->buffer,
+ return hmac_outer_integrity(parent_name_alg,
+ encrypted_duplicate_sensitive->buffer,
encrypted_duplicate_sensitive->size, pubname->name, pubname->size,
protection_hmac_key->buffer, outer_hmac);
}
diff --git a/lib/tpm2_identity_util.h b/lib/tpm2_identity_util.h
index c298a62f..31ba6e6e 100644
--- a/lib/tpm2_identity_util.h
+++ b/lib/tpm2_identity_util.h
@@ -95,7 +95,7 @@ bool tpm2_identity_util_calculate_inner_integrity(TPMI_ALG_HASH name_alg,
* @param outer_hmac
* The outer HMAC structure to populate.
*/
-void tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+bool tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
TPM2B_NAME *pubname, TPM2B_MAX_BUFFER *marshalled_sensitive,
TPM2B_MAX_BUFFER *protection_hmac_key,
TPM2B_MAX_BUFFER *protection_enc_key, TPMT_SYM_DEF_OBJECT *sym_alg,
diff --git a/tools/tpm2_duplicate.c b/tools/tpm2_duplicate.c
index b64e8fcb..88a70f95 100644
--- a/tools/tpm2_duplicate.c
+++ b/tools/tpm2_duplicate.c
@@ -315,10 +315,13 @@ static tool_rc tpm2_create_duplicate(
*/
TPM2B_DIGEST outer_hmac = TPM2B_EMPTY_INIT;
TPM2B_MAX_BUFFER encrypted_duplicate_sensitive = TPM2B_EMPTY_INIT;
- tpm2_identity_util_calculate_outer_integrity(parent_pub->publicArea.nameAlg,
+ bool outer_res = tpm2_identity_util_calculate_outer_integrity(parent_pub->publicArea.nameAlg,
&pubname, &marshalled_sensitive, &hmac_key, &enc_key,
&parent_pub->publicArea.parameters.rsaDetail.symmetric,
&encrypted_duplicate_sensitive, &outer_hmac);
+ if (!outer_res) {
+ return tool_rc_general_error;
+ }
/*
* Build the private data structure for writing out
diff --git a/tools/tpm2_import.c b/tools/tpm2_import.c
index 3a8c5c34..b7b1687e 100644
--- a/tools/tpm2_import.c
+++ b/tools/tpm2_import.c
@@ -155,10 +155,13 @@ static tool_rc key_import(ESYS_CONTEXT *ectx, TPM2B_PUBLIC *parent_pub,
TPM2B_DIGEST outer_hmac = TPM2B_EMPTY_INIT;
TPM2B_MAX_BUFFER encrypted_duplicate_sensitive = TPM2B_EMPTY_INIT;
- tpm2_identity_util_calculate_outer_integrity(parent_pub->publicArea.nameAlg,
+ bool outer_res = tpm2_identity_util_calculate_outer_integrity(parent_pub->publicArea.nameAlg,
&pubname, &encrypted_inner_integrity, &hmac_key, &enc_key,
&parent_pub->publicArea.parameters.rsaDetail.symmetric,
&encrypted_duplicate_sensitive, &outer_hmac);
+ if (!outer_res) {
+ return tool_rc_general_error;
+ }
TPM2B_PRIVATE private = TPM2B_EMPTY_INIT;
res = create_import_key_private_data(&private, parent_pub->publicArea.nameAlg,
diff --git a/tools/tpm2_makecredential.c b/tools/tpm2_makecredential.c
index 2a3d137a..dc1cb5e8 100644
--- a/tools/tpm2_makecredential.c
+++ b/tools/tpm2_makecredential.c
@@ -137,10 +137,13 @@ static tool_rc make_external_credential_and_save(void) {
*/
TPM2B_DIGEST outer_hmac = TPM2B_EMPTY_INIT;
TPM2B_MAX_BUFFER encrypted_sensitive = TPM2B_EMPTY_INIT;
- tpm2_identity_util_calculate_outer_integrity(name_alg, &ctx.object_name,
- &marshalled_inner_integrity, &hmac_key, &enc_key,
+ bool outer_res = tpm2_identity_util_calculate_outer_integrity(name_alg,
+ &ctx.object_name, &marshalled_inner_integrity, &hmac_key, &enc_key,
&ctx.public.publicArea.parameters.rsaDetail.symmetric,
&encrypted_sensitive, &outer_hmac);
+ if (!outer_res) {
+ return tool_rc_general_error;
+ }
/*
* Package up the info to save
--
2.54.0

View File

@ -2,7 +2,7 @@
Name: tpm2-tools
Version: 5.2
Release: 7%{?candidate:.%{candidate}}%{?dist}
Release: 8%{?candidate:.%{candidate}}%{?dist}
Summary: A bunch of TPM testing toolS build upon tpm2-tss
License: BSD
@ -59,6 +59,27 @@ Patch402: 0001-tpm2_eventlog-Fix-parsing-on-big-endian-systems.patch
Patch403: 0001-tpm2_quote-checkquote-Fix-usage-of-little-endian-ser.patch
Patch404: add_pregenerated_doc_2.patch
Patch501: 0001-tpm2_makecredential-Fix-usage-of-name-parameter.patch
Patch502: 0002-tpm2_checkquote-Fix-indentation-in-parse_marshaled_s.patch
Patch503: 0003-tpm2_checkquote-Fix-missing-error-checking.patch
Patch504: 0004-tpm2_checkquote-Fix-memory-leaks-malloced-buffer-not.patch
Patch506: 0006-tpm2_create-Fix-creation-of-ctx-file-if-TPM2_CreateL.patch
Patch507: 0007-fix-checkquote-fix-off-by-one-in-PCR-digest-list-han.patch
Patch508: 0008-tpm2_checkquote-Add-size-checks-for-PCR-desearializa.patch
Patch509: 0009-fix-tpm2_send-validate-command_size-before-computing.patch
Patch510: 0010-fix-tpm2_send-avoid-unintended-stdio-closing-in-clos.patch
Patch511: 0011-fix-tpm2_util-fix-error-message-in-tpm2_pem_encoded_.patch
Patch512: 0012-fix-tpm2_util-modify-tpm2_safe_read_from_stdin-to-re.patch
Patch513: 0013-fix-tools-out-of-bounds-write-with-too-many-auxiliar.patch
Patch514: 0014-fix-tpm2_alg_util-avoid-mutating-input-scheme-in-han.patch
Patch515: 0015-fix-tools-add-missing-null-checks-after-malloc.patch
Patch516: 0016-fix-tpm2_util-fix-buffer-overflow-in-string-validati.patch
Patch517: 0017-Allocate-the-right-amount-of-memory-for-auth_policy.patch
Patch518: 0018-tpm2_util-add-some-checks-to-tpm2_safe_read_from_std.patch
Patch519: 0019-fix-tpm2_loadexternal-check-return-value-of-RAND_byt.patch
Patch520: 0020-fix-tpm2_identity_util-add-buffer-size-check.patch
Patch521: 0001-Add-missing-include.patch
BuildRequires: git
BuildRequires: make
BuildRequires: gcc-c++
@ -110,6 +131,10 @@ touch man/man1/*
%{_mandir}/man1/tss2_*.1.gz
%changelog
* Wed Apr 15 2026 Štěpán Horáček <shoracek@redhat.com> - 5.2-8
- Backport upstream fixes.
Resolves: RHEL-164795
* Thu Sep 18 2025 Štěpán Horáček <shoracek@redhat.com> - 5.2-7
- Fix endianity issues.
Resolves: RHEL-79885