File extra-self-tests.patch of Package pcr-oracle

From 1601cfe8d1dd9e8ed30efa7a234e668ee96ab855 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Tue, 23 Sep 2025 14:46:40 +0800
Subject: [PATCH 1/3] Extra checks for TPM self-test

Do a few more checks besides the TPM SelfTest command
- Check the TPM properties: PropertyStartupClear and PropertyPermanent
- Check the tagged policies associated with the following permanent
  handles: TPM2_RH_LOCKOUT, TPM2_RH_OWNER, and TPM2_RH_ENDORSEMENT

Signed-off-by: Gary Lin <glin@suse.com>
---
 src/tpm.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 191 insertions(+), 1 deletion(-)

diff --git a/src/tpm.c b/src/tpm.c
index 84b5dbe..fdfffc8 100644
--- a/src/tpm.c
+++ b/src/tpm.c
@@ -85,14 +85,204 @@ tss_esys_context(void)
 	return esys_ctx;
 }
 
+static bool
+tpm_get_tpm_property(TPM2_PT property, uint32_t *value)
+{
+	ESYS_CONTEXT *esys_ctx = tss_esys_context();
+	TPMS_CAPABILITY_DATA *cap_data = NULL;
+	TPMI_YES_NO more_data;
+	TPML_TAGGED_TPM_PROPERTY *props = NULL;
+	TSS2_RC rc;
+	bool okay = false;
+
+	if (value == NULL)
+		return false;
+
+	rc = Esys_GetCapability(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE,
+			ESYS_TR_NONE, TPM2_CAP_TPM_PROPERTIES, property,
+			1, &more_data, &cap_data);
+	if (rc != TSS2_RC_SUCCESS)
+		return tss_check_error(rc, "Esys_GetCapability (TPM_PROPERTIES) failed");
+
+	if (cap_data == NULL) {
+		error("Empty CAP data (TPM_PROPERTIES)\n");
+		return false;
+	}
+
+	if (cap_data->capability != TPM2_CAP_TPM_PROPERTIES) {
+		error("Wrong CAP data (TPM_PROPERTIES)\n");
+		goto out;
+	}
+
+	props = &cap_data->data.tpmProperties;
+	if (props->count != 1) {
+		error("Got more than 1 property\n");
+		goto out;
+	}
+
+	if (props->tpmProperty[0].property != property) {
+		error("Property not match\n");
+		goto out;
+	}
+
+	*value = props->tpmProperty[0].value;
+
+	okay = true;
+out:
+	if (cap_data)
+		free(cap_data);
+
+	return okay;
+}
+
+#ifdef TPM2_CAP_AUTH_POLICIES
+static bool
+tpm_get_auth_policies(TPM2_HANDLE hierarchy, TPMS_CAPABILITY_DATA **cap_data)
+{
+	ESYS_CONTEXT *esys_ctx = tss_esys_context();
+	TPMI_YES_NO more_data;
+	TSS2_RC rc;
+
+	rc = Esys_GetCapability(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE,
+			ESYS_TR_NONE, TPM2_CAP_AUTH_POLICIES, hierarchy,
+			TPM2_MAX_TAGGED_POLICIES, &more_data, cap_data);
+	if (rc != TSS2_RC_SUCCESS)
+		return tss_check_error(rc, "Esys_GetCapability (AUTH_POLICIES) failed");
+
+	if (*cap_data == NULL) {
+		error("Empty CAP data (AUTH_POLICIES)\n");
+		return false;
+	}
+
+	if ((*cap_data)->capability != TPM2_CAP_AUTH_POLICIES) {
+		error("Wrong CAP data (AUTH_POLICIES)\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+tpm_check_auth_policies(TPM2_HANDLE hierarchy)
+{
+	TPMS_CAPABILITY_DATA *cap_data = NULL;
+	TPML_TAGGED_POLICY *policies = NULL;
+	uint32_t i;
+	bool okay = false;
+
+	if (!tpm_get_auth_policies(hierarchy, &cap_data))
+		goto out;
+
+	policies = &cap_data->data.authPolicies;
+	for (i = 0; i < policies->count; i++) {
+		if (policies->policies[i].policyHash.hashAlg != TPM2_ALG_NULL) {
+			error("Tagged policy NON-NULL Hash Algorithm\n");
+			goto out;
+		}
+	}
+
+	okay = true;
+out:
+	if (cap_data)
+		free(cap_data);
+
+	return okay;
+}
+#endif
+
+static bool
+tpm_check_capabilities(void)
+{
+	uint32_t prop_startup, prop_permanent;
+
+	/* Check PropertyStartupClear (TPM2_PT_STARTUP_CLEAR) */
+	if (!tpm_get_tpm_property(TPM2_PT_STARTUP_CLEAR, &prop_startup)) {
+		error("Failed to get PropertyStartupClear\n");
+		return false;
+	}
+
+	if ((prop_startup & TPMA_STARTUP_CLEAR_SHENABLE) == 0) {
+		error("Storage hierarchy not enabled\n");
+		return false;
+	}
+
+	if ((prop_startup & TPMA_STARTUP_CLEAR_EHENABLE) == 0) {
+		error("Endorsement hierarchy not enabled\n");
+		return false;
+	}
+
+	/* Check PropertyPermanent (TPM2_PT_PERMANENT) */
+	if (!tpm_get_tpm_property(TPM2_PT_PERMANENT, &prop_permanent)) {
+		error("Failed to get PropertyPermanent\n");
+		return false;
+	}
+
+	if ((prop_permanent & TPMA_PERMANENT_OWNERAUTHSET) != 0) {
+		error("TPM2 Owner Authorization set\n");
+		return false;
+	}
+
+	if ((prop_permanent & TPMA_PERMANENT_ENDORSEMENTAUTHSET) != 0) {
+		error("TPM2 Endorsement Authorization set\n");
+		return false;
+	}
+
+	if ((prop_permanent & TPMA_PERMANENT_LOCKOUTAUTHSET) != 0) {
+		error("TPM2 Lockout Authorization set\n");
+		return false;
+	}
+
+	if ((prop_permanent & TPMA_PERMANENT_INLOCKOUT) != 0) {
+		error("TPM2 in lockout\n");
+		return false;
+	}
+
+#ifdef TPM2_CAP_AUTH_POLICIES
+	/*
+	 * Ensure that there is no authorization policy associated with the
+	 * following hierarchies: TPM2_RH_LOCKOUT, TPM2_RH_OWNER, and
+	 * TPM2_RH_ENDORSEMENT
+	 *
+	 * Some older TPM may not support TPM2_CAP_AUTH_POLICIES, so the
+	 * following checks are optional.
+	 */
+	if (!tpm_check_auth_policies(TPM2_RH_LOCKOUT)) {
+		warning("Error from LockOut handle\n");
+		goto skip_auth_policies;
+	}
+
+	if (!tpm_check_auth_policies(TPM2_RH_OWNER)) {
+		warning("Error from Owner handle\n");
+		goto skip_auth_policies;
+	}
+
+	if (!tpm_check_auth_policies(TPM2_RH_ENDORSEMENT)) {
+		warning("Error from Endorsement handle\n");
+		goto skip_auth_policies;
+	}
+
+skip_auth_policies:
+#endif
+
+	return true;
+}
+
 bool
 tpm_selftest(bool fulltest)
 {
 	ESYS_CONTEXT *esys_ctx = tss_esys_context();
 	TSS2_RC rc;
 
+	/* TPM self test */
 	rc = Esys_SelfTest(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, fulltest);
-	return tss_check_error(rc, "TPM self test failed");
+	if (rc != TSS2_RC_SUCCESS)
+		return tss_check_error(rc, "TPM self test failed");
+
+	/* Capability check */
+	if(!tpm_check_capabilities())
+		return false;
+
+	return true;
 }
 
 bool
-- 
2.51.0


From 3fb4199db23d1e6d20b6eb073ede0c535c94a3e3 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 26 Sep 2025 15:27:25 +0800
Subject: [PATCH 2/3] Add SRK template test to self-test

Add the RSA and ECC SRK template test to self-test.

Signed-off-by: Gary Lin <glin@suse.com>
---
 src/pcr-policy.c |  4 ++--
 src/tpm.c        | 34 ++++++++++++++++++++++++++++++++++
 src/tpm.h        |  3 +++
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index e5d1bc9..3c08775 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -62,7 +62,7 @@ struct target_platform {
 					const stored_key_t *public_key_file);
 };
 
-static TPM2B_PUBLIC RSA_SRK_template = {
+TPM2B_PUBLIC RSA_SRK_template = {
 	.size = sizeof(TPMT_PUBLIC),
 	.publicArea = {
 		.type = TPM2_ALG_RSA,
@@ -88,7 +88,7 @@ static TPM2B_PUBLIC RSA_SRK_template = {
 	}
 };
 
-static TPM2B_PUBLIC ECC_SRK_template = {
+TPM2B_PUBLIC ECC_SRK_template = {
 	.size = sizeof(TPMT_PUBLIC),
 	.publicArea = {
 		.type = TPM2_ALG_ECC,
diff --git a/src/tpm.c b/src/tpm.c
index fdfffc8..b9047dc 100644
--- a/src/tpm.c
+++ b/src/tpm.c
@@ -267,6 +267,36 @@ skip_auth_policies:
 	return true;
 }
 
+static bool
+tpm_check_srk(void)
+{
+	ESYS_CONTEXT *esys_ctx = tss_esys_context();
+	TPMT_PUBLIC_PARMS parms = {0};
+	TSS2_RC rc;
+
+	/* Test RSA SRK */
+	parms.type = TPM2_ALG_RSA;
+	memcpy(&parms.parameters, &RSA_SRK_template.publicArea.parameters,
+	       sizeof(TPMU_PUBLIC_PARMS));
+
+	rc = Esys_TestParms(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parms);
+	if (rc != TSS2_RC_SUCCESS)
+		return tss_check_error(rc, "RSA SRK test failed");
+
+	memset(&parms, 0, sizeof(TPMT_PUBLIC_PARMS));
+
+	/* Test ECC SRK */
+	parms.type = TPM2_ALG_ECC;
+	memcpy(&parms.parameters, &ECC_SRK_template.publicArea.parameters,
+	       sizeof(TPMU_PUBLIC_PARMS));
+
+	rc = Esys_TestParms(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parms);
+	if (rc != TSS2_RC_SUCCESS)
+		return tss_check_error(rc, "ECC SRK test failed");
+
+	return true;
+}
+
 bool
 tpm_selftest(bool fulltest)
 {
@@ -282,6 +312,10 @@ tpm_selftest(bool fulltest)
 	if(!tpm_check_capabilities())
 		return false;
 
+	/* SRK template test */
+	if (!tpm_check_srk())
+		return false;
+
 	return true;
 }
 
diff --git a/src/tpm.h b/src/tpm.h
index 50ae203..8a5ef2d 100644
--- a/src/tpm.h
+++ b/src/tpm.h
@@ -28,6 +28,9 @@
 extern uint32_t		esys_tr_rh_null;
 extern uint32_t		esys_tr_rh_owner;
 
+extern TPM2B_PUBLIC	RSA_SRK_template;
+extern TPM2B_PUBLIC	ECC_SRK_template;
+
 extern ESYS_CONTEXT *	tss_esys_context(void);
 extern void		tss_print_error(int rc, const char *msg);
 
-- 
2.51.0


From b7aadd51b1ca8b1957580f6a527c4b3b30e30ec7 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 26 Sep 2025 15:30:00 +0800
Subject: [PATCH 3/3] Fix a typo in tpm_rsa_bits_test()

Fix a typo in the error message of tpm_rsa_bits_test()

Signed-off-by: Gary Lin <glin@suse.com>
---
 src/tpm.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/tpm.c b/src/tpm.c
index b9047dc..2b52ef0 100644
--- a/src/tpm.c
+++ b/src/tpm.c
@@ -343,9 +343,8 @@ tpm_rsa_bits_test(unsigned int rsa_bits)
 			ESYS_TR_NONE, &rsa_parms);
 	if (rc == TSS2_RC_SUCCESS)
 		okay = true;
-	else if (rc != (TPM2_RC_VALUE | TPM2_RC_P | TPM2_RC_1)) {
-		tss_check_error(rc, "Esys_CreatePrimary failed");
-	}
+	else if (rc != (TPM2_RC_VALUE | TPM2_RC_P | TPM2_RC_1))
+		tss_check_error(rc, "Esys_TestParms failed");
 
 	return okay;
 }
-- 
2.51.0

openSUSE Build Service is sponsored by