test(realm): add tests for realm attestation
With this patch, TFTF adds two tests for realm attestation. One tests
the full process of retrieving the attestation token from the host. The
second one triggers a failure by calling RSI_ATTEST_TOKEN_CONTINUE
without calling RSI_ATTEST_TOKEN_INIT first.
Signed-off-by: Juan Pablo Conde <juanpablo.conde@arm.com>
Change-Id: I885402377af1f02ce7e90c80dbe1079fe4c1b178
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index 3e934f1..7005c0d 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -71,7 +71,9 @@
REALM_DIT_CHECK_CMD,
REALM_SME_ID_REGISTERS,
REALM_SME_UNDEF_ABORT,
- REALM_FEAT_DOUBLEFAULT2_TEST
+ REALM_FEAT_DOUBLEFAULT2_TEST,
+ REALM_ATTESTATION,
+ REALM_ATTESTATION_FAULT
};
/*
diff --git a/include/runtime_services/host_realm_managment/realm_def.h b/include/runtime_services/host_realm_managment/realm_def.h
index 5258b87..226034f 100644
--- a/include/runtime_services/host_realm_managment/realm_def.h
+++ b/include/runtime_services/host_realm_managment/realm_def.h
@@ -101,4 +101,6 @@
(((idx) & ~MASK(RMI_MPIDR_AFF0)) << \
(RMI_MPIDR_AFF1_SHIFT - RMI_MPIDR_AFF0_WIDTH)));
+#define REALM_TOKEN_BUF_SIZE GRANULE_SIZE
+
#endif /* REALM_DEF_H */
diff --git a/realm/include/realm_helpers.h b/realm/include/realm_helpers.h
new file mode 100644
index 0000000..11c4423
--- /dev/null
+++ b/realm/include/realm_helpers.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REALM_HELPERS_H
+#define REALM_HELPERS_H
+
+/* Generate 64-bit random number */
+unsigned long long realm_rand64(void);
+
+#endif /* REALM_HELPERS_H */
+
diff --git a/realm/include/realm_rsi.h b/realm/include/realm_rsi.h
index 92a078b..72ee80e 100644
--- a/realm/include/realm_rsi.h
+++ b/realm/include/realm_rsi.h
@@ -127,6 +127,21 @@
*/
#define RSI_IPA_STATE_GET SMC_RSI_FID(8U)
+/*
+ * ret0 == Status / error
+ * ret1 == Token maximum length
+ */
+#define RSI_ATTEST_TOKEN_INIT SMC_RSI_FID(4U)
+
+/*
+ * arg0 == Base of buffer to write the token to
+ * arg1 == Offset within the buffer
+ * arg2 == Size of the buffer
+ * ret0 == Status / error
+ * ret1 == Size of received token hunk
+ */
+#define RSI_ATTEST_TOKEN_CONTINUE SMC_RSI_FID(5U)
+
typedef enum {
RSI_EMPTY = 0U,
RSI_RAM,
@@ -162,6 +177,23 @@
/* This function will call the Host to request IPA of the NS shared buffer */
u_register_t rsi_get_ns_buffer(void);
+/* This function will initialize the attestation context */
+u_register_t rsi_attest_token_init(u_register_t challenge_0,
+ u_register_t challenge_1,
+ u_register_t challenge_2,
+ u_register_t challenge_3,
+ u_register_t challenge_4,
+ u_register_t challenge_5,
+ u_register_t challenge_6,
+ u_register_t challenge_7,
+ u_register_t *out_token_upper_bound);
+
+/* This function will retrieve the (or part of) attestation token */
+u_register_t rsi_attest_token_continue(u_register_t buffer_addr,
+ u_register_t offset,
+ u_register_t buffer_size,
+ u_register_t *bytes_copied);
+
/* This function call Host and request to exit Realm with proper exit code */
void rsi_exit_to_host(enum host_call_cmd exit_code);
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index a2cfc9b..2c1d3a1 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -28,6 +28,8 @@
bool test_realm_sme_read_id_registers(void);
bool test_realm_sme_undef_abort(void);
bool test_realm_sctlr2_ease(void);
+bool test_realm_attestation(void);
+bool test_realm_attestation_fault(void);
#endif /* REALM_TESTS_H */
diff --git a/realm/realm.mk b/realm/realm.mk
index b0536ca..3e66adc 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -26,8 +26,10 @@
$(addprefix realm/, \
aarch64/realm_entrypoint.S \
aarch64/realm_exceptions.S \
+ realm_attestation.c \
realm_exception_report.c \
realm_debug.c \
+ realm_helpers.c \
realm_interrupt.c \
realm_multiple_rec.c \
realm_pauth.c \
diff --git a/realm/realm_attestation.c b/realm/realm_attestation.c
new file mode 100644
index 0000000..e42484e
--- /dev/null
+++ b/realm/realm_attestation.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <realm_rsi.h>
+
+#include <arch_features.h>
+#include <debug.h>
+#include <realm_def.h>
+#include <sync.h>
+#include <realm_helpers.h>
+
+#define CHALLENGE_SIZE 8
+
+static unsigned char attest_token_buffer[REALM_TOKEN_BUF_SIZE]
+ __aligned(GRANULE_SIZE);
+static uint64_t attest_token_offset;
+
+bool test_realm_attestation(void)
+{
+ u_register_t rsi_ret;
+ u_register_t bytes_copied;
+ u_register_t token_upper_bound;
+ u_register_t challenge[CHALLENGE_SIZE];
+
+ for (unsigned int i = 0U; i < CHALLENGE_SIZE; i++) {
+ challenge[i] = realm_rand64();
+ }
+
+ rsi_ret = rsi_attest_token_init(challenge[0],
+ challenge[1],
+ challenge[2],
+ challenge[3],
+ challenge[4],
+ challenge[5],
+ challenge[6],
+ challenge[7],
+ &token_upper_bound);
+
+ if (rsi_ret != RSI_SUCCESS) {
+ realm_printf("RSI_ATTEST_TOKEN_INIT"
+ " returned with code %lu\n", rsi_ret);
+ return false;
+ }
+
+ if (token_upper_bound > REALM_TOKEN_BUF_SIZE) {
+ realm_printf("Attestation token buffer is not large enough"
+ " to hold the token.\n");
+ return false;
+ }
+
+ do {
+ rsi_ret = rsi_attest_token_continue(
+ (u_register_t)attest_token_buffer,
+ attest_token_offset,
+ REALM_TOKEN_BUF_SIZE,
+ &bytes_copied);
+
+ if ((rsi_ret != RSI_SUCCESS) && (rsi_ret != RSI_INCOMPLETE)) {
+ realm_printf("RSI_ATTEST_TOKEN_CONTINUE"
+ " returned with code %lu\n", rsi_ret);
+ return false;
+ }
+
+ attest_token_offset += bytes_copied;
+
+ } while (rsi_ret != RSI_SUCCESS);
+
+ return true;
+}
+
+bool test_realm_attestation_fault(void)
+{
+ u_register_t rsi_ret;
+ u_register_t bytes_copied;
+
+ /*
+ * This RSI call will fail as RSI_ATTEST_TOKEN_INIT has to be invoked
+ * before calling RSI_ATTEST_TOKEN_CONTINUE.
+ */
+ rsi_ret = rsi_attest_token_continue(
+ (u_register_t)attest_token_buffer,
+ attest_token_offset,
+ REALM_TOKEN_BUF_SIZE,
+ &bytes_copied);
+
+ if ((rsi_ret == RSI_SUCCESS) || (rsi_ret == RSI_INCOMPLETE)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/realm/realm_helpers.c b/realm/realm_helpers.c
new file mode 100644
index 0000000..6a3c57d
--- /dev/null
+++ b/realm/realm_helpers.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+/* Generate 64-bit random number */
+unsigned long long realm_rand64(void)
+{
+ return ((unsigned long long)rand() << 32) | rand();
+}
+
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 131f49b..3339b9a 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -368,6 +368,12 @@
case REALM_SME_UNDEF_ABORT:
test_succeed = test_realm_sme_undef_abort();
break;
+ case REALM_ATTESTATION:
+ test_succeed = test_realm_attestation();
+ break;
+ case REALM_ATTESTATION_FAULT:
+ test_succeed = test_realm_attestation_fault();
+ break;
default:
realm_printf("%s() invalid cmd %u\n", __func__, cmd);
break;
diff --git a/realm/realm_rsi.c b/realm/realm_rsi.c
index b2a49d4..db2394c 100644
--- a/realm/realm_rsi.c
+++ b/realm/realm_rsi.c
@@ -87,3 +87,57 @@
}
return res.ret0;
}
+
+/* This function will initialize the attestation context */
+u_register_t rsi_attest_token_init(u_register_t challenge_0,
+ u_register_t challenge_1,
+ u_register_t challenge_2,
+ u_register_t challenge_3,
+ u_register_t challenge_4,
+ u_register_t challenge_5,
+ u_register_t challenge_6,
+ u_register_t challenge_7,
+ u_register_t *out_token_upper_bound)
+{
+ smc_ret_values_ext res = {};
+
+ tftf_smc_no_retval_x8(&(smc_args_ext) {
+ RSI_ATTEST_TOKEN_INIT,
+ challenge_0,
+ challenge_1,
+ challenge_2,
+ challenge_3,
+ challenge_4,
+ challenge_5,
+ challenge_6,
+ challenge_7
+ },
+ &res);
+
+ if (res.ret0 == RSI_SUCCESS) {
+ *out_token_upper_bound = res.ret1;
+ }
+
+ return res.ret0;
+}
+
+/* This function will retrieve the (or part of) attestation token */
+u_register_t rsi_attest_token_continue(u_register_t buffer_addr,
+ u_register_t offset,
+ u_register_t buffer_size,
+ u_register_t *bytes_copied)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args) {
+ RSI_ATTEST_TOKEN_CONTINUE,
+ buffer_addr,
+ offset,
+ buffer_size
+ });
+
+ if ((res.ret0 == RSI_SUCCESS) || (res.ret0 == RSI_INCOMPLETE)) {
+ *bytes_copied = res.ret1;
+ }
+ return res.ret0;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
index 1f4f88d..ce5409c 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
@@ -2591,3 +2591,85 @@
host_destroy_realm(&realm);
return TEST_RESULT_SUCCESS;
}
+
+/*
+ * @Test_Aim@ Create realm with a single REC
+ * Test attestation process for REC
+ */
+test_result_t host_realm_test_attestation(void)
+{
+ bool ret1, ret2;
+ u_register_t rec_flag[] = {RMI_RUNNABLE};
+ struct realm realm;
+ u_register_t feature_flag = 0UL;
+ long sl = RTT_MIN_LEVEL;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (is_feat_52b_on_4k_2_supported() == true) {
+ feature_flag = RMI_FEATURE_REGISTER_0_LPA2;
+ sl = RTT_MIN_LEVEL_LPA2;
+ }
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ feature_flag, sl, rec_flag, 1U)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret1 = host_enter_realm_execute(&realm, REALM_ATTESTATION,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ ERROR("Realm attestation test failed\n");
+ }
+
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret1 || !ret2) {
+ ERROR("%s(): enter=%d destroy=%d\n",
+ __func__, ret1, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Create realm with a single REC
+ * Test attestation fault for REC
+ */
+test_result_t host_realm_test_attestation_fault(void)
+{
+ bool ret1, ret2;
+ u_register_t rec_flag[] = {RMI_RUNNABLE};
+ struct realm realm;
+ u_register_t feature_flag = 0UL;
+ long sl = RTT_MIN_LEVEL;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (is_feat_52b_on_4k_2_supported() == true) {
+ feature_flag = RMI_FEATURE_REGISTER_0_LPA2;
+ sl = RTT_MIN_LEVEL_LPA2;
+ }
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ feature_flag, sl, rec_flag, 1U)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret1 = host_enter_realm_execute(&realm, REALM_ATTESTATION_FAULT,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ ERROR("Realm attestation fault test failed\n");
+ }
+
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret1 || !ret2) {
+ ERROR("%s(): enter=%d destroy=%d\n",
+ __func__, ret1, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 3c0dda4..0d2f7c9 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -126,5 +126,9 @@
function="host_test_non_lpa2_realm_on_lpa2plat" />
<testcase name="Test Realm creation with LPA2 enabled but FEAT_LPA2 absent on platform"
function="host_test_lpa2_realm_on_non_lpa2plat" />
+ <!-- Test cases related to Attestation -->
+ <testcase name="Test realm attestation" function="host_realm_test_attestation" />
+ <testcase name="Test realm attestation fault"
+ function="host_realm_test_attestation_fault" />
</testsuite>
</testsuites>