feat(neg-boot): tftf invalid rotpk test

Test to improve code coverage in scenario with corrupt rotpk in fip certificate

Change-Id: I995ab6d9f1488fda44e10ae9ef70c9056d780a89
Signed-off-by: Thaddeus Gonzalez-Serna <Thaddeus.Gonzalez-Serna@arm.com>
diff --git a/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.c b/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.c
new file mode 100644
index 0000000..e45a0b0
--- /dev/null
+++ b/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "neg_scenario_test_infra.h"
+
+/*
+ Temporary variables to speed up the authentication parameters search. These
+ variables are assigned once during the integrity check and used any time an
+ authentication parameter is requested, so we do not have to parse the image
+ again
+ */
+
+
+int get_pubKey_from_cert(void *cert, size_t cert_len, void **returnPtr) {
+
+	int ret;
+	size_t len;
+	unsigned char *p, *end, *crt_end, *pk_end;
+	mbedtls_asn1_buf pk;
+
+	/*
+	 * The unique ASN.1 DER encoding of [0] EXPLICIT INTEGER { v3(2} }.
+	 */
+	const char v3[] = {
+		/* The outer CONTEXT SPECIFIC 0 tag */
+		MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0,
+		/* The number bytes used to encode the inner INTEGER */
+		3,
+		/* The tag of the inner INTEGER */
+		MBEDTLS_ASN1_INTEGER,
+		/* The number of bytes needed to represent 2 */
+		1,
+		/* The actual value 2 */
+		2,
+	};
+
+	p = (unsigned char *)cert;
+	len = cert_len;
+	crt_end = p + len;
+	end = crt_end;
+
+	/*
+	 * Certificate  ::=  SEQUENCE  {
+	 *      tbsCertificate       TBSCertificate,
+	 *      signatureAlgorithm   AlgorithmIdentifier,
+	 *      signatureValue       BIT STRING  }
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if ((ret != 0) || ((p + len) != end))
+		return -1;
+
+	/*
+	 * TBSCertificate  ::=  SEQUENCE  {
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	end = p + len;
+
+	/*
+	 * Version  ::=  [0] EXPLICIT INTEGER {  v1(0), v2(1), v3(2)  }
+	 * -- only v3 accepted
+	 */
+	if (((end - p) <= (ptrdiff_t)sizeof(v3)) ||
+	    (memcmp(p, v3, sizeof(v3)) != 0)) {
+		return -1;
+	}
+	p += sizeof(v3);
+
+	/*
+	 * CertificateSerialNumber  ::=  INTEGER
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
+	if (ret != 0)
+		return -1;
+
+	p += len;
+
+	/*
+	 * signature            AlgorithmIdentifier
+	 */
+
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	p += len;
+
+	/*
+	 * issuer               Name
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	p += len;
+
+	/*
+	 * Validity ::= SEQUENCE {
+	 *      notBefore      Time,
+	 *      notAfter       Time }
+	 *
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	p += len;
+
+	/*
+	 * subject              Name
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	p += len;
+
+	/*
+	 * SubjectPublicKeyInfo
+	 */
+	pk.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0)
+		return -1;
+
+	pk_end = p + len;
+	pk.len = pk_end - pk.p;
+
+	*returnPtr = p;
+
+	return 0;
+}
diff --git a/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.h b/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.h
new file mode 100644
index 0000000..428f86b
--- /dev/null
+++ b/tftf/tests/neg_scenario_tests/neg_scenario_test_infra.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+#include <firmware_image_package.h>
+
+/*
+    cert:
+    cert_len:
+    returnPtr: ptr to pubKey in cert
+
+    return 0 upon success, -1 on fail
+*/
+int get_pubKey_from_cert(void *cert, size_t cert_len, void **returnPtr);
diff --git a/tftf/tests/neg_scenario_tests/test_invalid_rotpk.c b/tftf/tests/neg_scenario_tests/test_invalid_rotpk.c
new file mode 100644
index 0000000..9f465a0
--- /dev/null
+++ b/tftf/tests/neg_scenario_tests/test_invalid_rotpk.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <uuid.h>
+#include <io_storage.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <smccc.h>
+#include <status.h>
+#include <tftf_lib.h>
+#include <uuid_utils.h>
+#include "neg_scenario_test_infra.h"
+
+#define CRYPTO_SUPPORT 1
+
+static fip_toc_entry_t *
+find_fiptoc_entry_t(const int fip_base, const uuid_t *uuid)
+{
+	fip_toc_entry_t *current_file =
+		(fip_toc_entry_t *) (fip_base + sizeof(fip_toc_header_t));
+
+	while (!is_uuid_null(&(current_file->uuid))) {
+		if (uuid_equal(&(current_file->uuid), uuid)){
+			return current_file;
+		}
+
+		current_file += 1;
+	};
+
+	return NULL;
+}
+
+test_result_t test_invalid_rotpk(void)
+{
+	smc_args args = { SMC_PSCI_SYSTEM_RESET };
+	smc_ret_values ret = (smc_ret_values){0};
+	const uuid_t trusted_cert = UUID_TRUSTED_KEY_CERT;
+
+	uintptr_t handle;
+	fip_toc_entry_t * cert;
+	size_t exp_len, len;
+	int address, rc;
+	void * paramOut = NULL;
+
+	if(tftf_is_rebooted() ){
+		/* ROTPK is tampered with and upon reboot tfa should not reach this point */
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Locate Trusted Key certificate memory address by using UUID */
+	cert = find_fiptoc_entry_t(PLAT_ARM_FIP_BASE, &trusted_cert);
+	if (cert == NULL){
+		return TEST_RESULT_FAIL;
+	}
+
+	address = (uintptr_t)cert->offset_address;
+	exp_len = cert->size;
+	if (exp_len == 0U){
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Runtime-sized buffer on stack */
+	uint8_t cert_buffer[exp_len];
+
+	/* Open NVM and Read certicate */
+	plat_get_nvm_handle(&handle);
+	if(handle < 0) {
+		return TEST_RESULT_FAIL;
+	}
+
+	rc = io_seek(handle, IO_SEEK_SET, address);
+	if (rc < 0){
+		return TEST_RESULT_FAIL;
+	}
+
+	rc = io_read(handle, (uintptr_t) &cert_buffer, exp_len, &len);
+	if (rc < 0 || len != exp_len){
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Parse certifacte to retrieve public key */
+	rc = get_pubKey_from_cert(&cert_buffer, len, &paramOut);
+	if ( rc != 0){
+		return TEST_RESULT_FAIL;
+	}
+
+	/*
+	* Corrupt part of the certificate in storage.
+	* Simple overwrite: just clobber the first 32 bytes so parsing/verification fails.
+	*/
+	{
+		uint8_t junk[32] = {0};
+
+		rc = io_seek(handle, IO_SEEK_SET, address);
+		if (rc < 0){
+			return TEST_RESULT_FAIL;
+		}
+
+		rc = io_write(handle, (uintptr_t)junk, sizeof(junk), &len);
+		if (rc < 0 || len != sizeof(junk)){
+			return TEST_RESULT_FAIL;
+		}
+	}
+
+	/* Reboot */
+	tftf_notify_reboot();
+	ret = tftf_smc(&args);
+
+	/* The PSCI SYSTEM_RESET call is not supposed to return */
+	tftf_testcase_printf("System didn't reboot properly (%d)\n",
+						(unsigned int)ret.ret0);
+
+	/* If this point is reached, reboot failed to trigger*/
+	return TEST_RESULT_FAIL;
+}
diff --git a/tftf/tests/tests-corrupt-rotpk.mk b/tftf/tests/tests-corrupt-rotpk.mk
new file mode 100644
index 0000000..bf25158
--- /dev/null
+++ b/tftf/tests/tests-corrupt-rotpk.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	$(addprefix tftf/tests/neg_scenario_tests/,	\
+					test_invalid_rotpk.c \
+					neg_scenario_test_infra.c \
+)
+
+include lib/ext_mbedtls/mbedtls.mk
+
+
diff --git a/tftf/tests/tests-corrupt-rotpk.xml b/tftf/tests/tests-corrupt-rotpk.xml
new file mode 100644
index 0000000..354752b
--- /dev/null
+++ b/tftf/tests/tests-corrupt-rotpk.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2025, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+  <testsuite name="neg scenario test-rotpk" description="Stress test for when ROTPK in fip cert is corrupted" >
+    <testcase name="invalid rotpk" function="test_invalid_rotpk" />
+  </testsuite>
+
+</testsuites>
+