Test: Add ITS secure and non-secure tests
This patch adds the ITS secure and non-secure tests. It also modifies
and adds the necessary CMake files to integrate the tests into the
regression tests.
Change-Id: Id5393f6da9867f1f1278d01ed080406e974122e4
Signed-off-by: Tudor Cretu <tudor.cretu@arm.com>
diff --git a/test/CMakeLists.inc b/test/CMakeLists.inc
index 2edfbc1..37d3730 100644
--- a/test/CMakeLists.inc
+++ b/test/CMakeLists.inc
@@ -37,6 +37,7 @@
include(${CMAKE_CURRENT_LIST_DIR}/suites/core/CMakeLists.inc)
include(${CMAKE_CURRENT_LIST_DIR}/suites/invert/CMakeLists.inc)
include(${CMAKE_CURRENT_LIST_DIR}/suites/sst/CMakeLists.inc)
+include(${CMAKE_CURRENT_LIST_DIR}/suites/its/CMakeLists.inc)
include(${CMAKE_CURRENT_LIST_DIR}/suites/crypto/CMakeLists.inc)
include(${CMAKE_CURRENT_LIST_DIR}/suites/attestation/CMakeLists.inc)
include(${CMAKE_CURRENT_LIST_DIR}/suites/qcbor/CMakeLists.inc)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 982aa39..71caf7f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -76,6 +76,7 @@
endif()
set(ENABLE_SECURE_STORAGE_SERVICE_TESTS TRUE)
+set(ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS TRUE)
set(ENABLE_AUDIT_LOGGING_SERVICE_TESTS TRUE)
set(ENABLE_CRYPTO_SERVICE_TESTS TRUE)
set(ENABLE_INVERT_SERVICE_TESTS TRUE)
diff --git a/test/framework/non_secure_suites.c b/test/framework/non_secure_suites.c
index b32d227..2772bc1 100644
--- a/test/framework/non_secure_suites.c
+++ b/test/framework/non_secure_suites.c
@@ -11,6 +11,7 @@
/* Service specific includes */
#include "test/suites/sst/non_secure/sst_ns_tests.h"
+#include "test/suites/its/non_secure/its_ns_tests.h"
#include "test/suites/audit/non_secure/audit_ns_tests.h"
#include "test/suites/crypto/non_secure/crypto_ns_tests.h"
#include "test/suites/attestation/non_secure/attestation_ns_tests.h"
@@ -25,6 +26,9 @@
{®ister_testsuite_ns_psa_ps_interface, 0, 0, 0},
+ /* Non-secure ITS test cases */
+ {®ister_testsuite_ns_psa_its_interface, 0, 0, 0},
+
/* Non-secure Crypto test cases */
{®ister_testsuite_ns_crypto_interface, 0, 0, 0},
diff --git a/test/framework/secure_suites.c b/test/framework/secure_suites.c
index 5042e11..cde8f42 100644
--- a/test/framework/secure_suites.c
+++ b/test/framework/secure_suites.c
@@ -11,6 +11,7 @@
/* Service specific includes */
#include "test/suites/sst/secure/sst_tests.h"
+#include "test/suites/its/secure/its_s_tests.h"
#include "test/suites/audit/secure/audit_s_tests.h"
#include "test/suites/attestation/secure/attestation_s_tests.h"
#include "test/suites/invert/secure/invert_s_tests.h"
@@ -28,6 +29,10 @@
{®ister_testsuite_s_rollback_protection, 0, 0, 0},
#endif
+ /* Secure ITS test cases */
+ {®ister_testsuite_s_psa_its_interface, 0, 0, 0},
+ {®ister_testsuite_s_psa_its_reliability, 0, 0, 0},
+
/* Crypto test cases */
{®ister_testsuite_s_crypto_interface, 0, 0, 0},
diff --git a/test/suites/its/CMakeLists.inc b/test/suites/its/CMakeLists.inc
new file mode 100644
index 0000000..8b30f07
--- /dev/null
+++ b/test/suites/its/CMakeLists.inc
@@ -0,0 +1,48 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Definitions to compile the "internal trusted storage test" module.
+#This file assumes it will be included from a project specific cmakefile, and
+#will not create a library or executable.
+#Inputs:
+# TFM_ROOT_DIR - root directory of the TF-M repo.
+#
+#Outputs:
+# Will modify include directories to make the source compile.
+# ALL_SRC_C: C source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+# ALL_SRC_CXX: C++ source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+# ALL_SRC_ASM: assembly source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+# Include directories will be modified by using the include_directories() commands as needed.
+
+#Get the current directory where this file is located.
+set(ITS_TEST_DIR ${CMAKE_CURRENT_LIST_DIR})
+if(NOT DEFINED TFM_ROOT_DIR)
+ message(FATAL_ERROR "Please set TFM_ROOT_DIR before including this file.")
+endif()
+
+if (NOT DEFINED ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS)
+ message(FATAL_ERROR "Incomplete build configuration: ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS is undefined. ")
+elseif (ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS)
+ list(APPEND ALL_SRC_C_NS "${ITS_TEST_DIR}/non_secure/psa_its_ns_interface_testsuite.c"
+ "${ITS_TEST_DIR}/its_tests_common.c")
+
+ list(APPEND ALL_SRC_C_S "${ITS_TEST_DIR}/secure/psa_its_s_interface_testsuite.c"
+ "${ITS_TEST_DIR}/secure/psa_its_s_reliability_testsuite.c"
+ "${ITS_TEST_DIR}/its_tests_common.c")
+
+ if (NOT ITS_RAM_FS AND NOT (REFERENCE_PLATFORM OR ${TARGET_PLATFORM} STREQUAL "AN524"))
+ # Show flash warning message only when the RAM FS is not in use or the tests are compiled to
+ # be executed in the reference plaforms (AN519 and AN521) & AN524. The reference platforms and AN524
+ # use RAM memory to emulated a flash device as they do not have one.
+ set_property(SOURCE ${ALL_SRC_C_S} APPEND PROPERTY COMPILE_DEFINITIONS ITS_SHOW_FLASH_WARNING)
+ set_property(SOURCE ${ALL_SRC_C_NS} APPEND PROPERTY COMPILE_DEFINITIONS ITS_SHOW_FLASH_WARNING)
+ endif()
+
+ #Setting include directories
+ embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
+ embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)
+endif()
diff --git a/test/suites/its/its_tests_common.c b/test/suites/its/its_tests_common.c
new file mode 100644
index 0000000..d3066a8
--- /dev/null
+++ b/test/suites/its/its_tests_common.c
@@ -0,0 +1,947 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "its_tests_common.h"
+#include "psa/internal_trusted_storage.h"
+#if DOMAIN_NS == 1
+#include <string.h>
+#else
+#include "tfm_memory_utils.h"
+#endif
+
+void tfm_its_test_common_001(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = 0;
+ const uint8_t write_data[] = {0};
+
+ /* Set with no data and no flags and a valid UID */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail with valid UID");
+ return;
+ }
+
+ /* Attempt to set a second time */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail the second time with valid UID");
+ return;
+ }
+
+ /* Set with an invalid UID */
+ status = psa_its_set(INVALID_UID, data_len, write_data, flags);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Set should not succeed with an invalid UID");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_002(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const uint8_t write_data[] = WRITE_DATA;
+
+ /* Set with no flags */
+ status = psa_its_set(WRITE_ONCE_UID, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail with no flags");
+ return;
+ }
+
+ /* Set with valid flag: PSA_STORAGE_FLAG_WRITE_ONCE (with previously created
+ * UID)
+ * Note: Once created, WRITE_ONCE_UID cannot be deleted. It is reused across
+ * multiple tests.
+ */
+ status = psa_its_set(WRITE_ONCE_UID, WRITE_ONCE_DATA_SIZE, WRITE_ONCE_DATA,
+ PSA_STORAGE_FLAG_WRITE_ONCE);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail with valid flags (and existing UID)");
+ return;
+ }
+
+ /* Set with invalid flags */
+ status = psa_its_set(uid, data_len, write_data, INVALID_FLAG);
+ if (status != PSA_ERROR_NOT_SUPPORTED) {
+ TEST_FAIL("Set should not succeed with invalid flags");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_003(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_3;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = 0;
+
+ /* Set with NULL data pointer */
+ status = psa_its_set(uid, data_len, NULL, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should succeed with NULL data pointer and zero length");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_004(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = WRITE_ONCE_UID;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t write_len = WRITE_DATA_SIZE;
+ const size_t read_len = WRITE_ONCE_DATA_SIZE;
+ const size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = WRITE_ONCE_READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ /* Set a write once UID a second time */
+ status = psa_its_set(uid, write_len, write_data, flags);
+ if (status != PSA_ERROR_NOT_PERMITTED) {
+ TEST_FAIL("Set should not rewrite a write once UID");
+ return;
+ }
+
+ /* Get write once data */
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that write once data has not changed */
+ comp_result = memcmp(read_data, WRITE_ONCE_RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, WRITE_ONCE_RESULT_DATA,
+ sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Write once data should not have changed");
+ return;
+ }
+
+ /* Check that write once data length has not changed */
+ if (read_data_length != read_len) {
+ TEST_FAIL("Write once data length should not have changed");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_005(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ size_t data_len = WRITE_DATA_SIZE;
+ size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ const uint8_t *p_read_data = read_data;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get the entire data */
+ status = psa_its_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the data is correct, including no illegal pre- or post-data */
+ comp_result = memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to result data");
+ return;
+ }
+
+ /* Check that the length of data is correct */
+ if (read_data_length != data_len) {
+ TEST_FAIL("Read data length should be equal to requested data length");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Reset read data */
+ memcpy(read_data, READ_DATA, sizeof(read_data));
+#else
+ tfm_memcpy(read_data, READ_DATA, sizeof(read_data));
+#endif
+
+ /* Read from offset 2 to 2 bytes before end of the data */
+ offset = 2;
+ data_len -= offset + 2;
+
+ status = psa_its_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the correct data was read */
+ comp_result = memcmp(p_read_data, "____", HALF_PADDING_SIZE);
+#else
+ comp_result = tfm_memcmp(p_read_data, "____", HALF_PADDING_SIZE);
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data contains illegal pre-data");
+ return;
+ }
+
+ p_read_data += HALF_PADDING_SIZE;
+
+#if DOMAIN_NS == 1U
+ comp_result = memcmp(p_read_data, write_data + offset, data_len);
+#else
+ comp_result = tfm_memcmp(p_read_data, write_data + offset, data_len);
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data incorrect");
+ return;
+ }
+
+ p_read_data += data_len;
+
+#if DOMAIN_NS == 1U
+ comp_result = memcmp(p_read_data, "____", HALF_PADDING_SIZE);
+#else
+ comp_result = tfm_memcmp(p_read_data, "____", HALF_PADDING_SIZE);
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data contains illegal post-data");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_006(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_3;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t write_len = WRITE_DATA_SIZE;
+ const size_t read_len = 0;
+ size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 1;
+ int comp_result;
+
+ status = psa_its_set(uid, write_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get zero data from zero offset */
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail with zero data len");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is unchanged */
+ comp_result = memcmp(read_data, READ_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, READ_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to original read data");
+ return;
+ }
+
+ /* Check that the read data length is zero */
+ if (read_data_length != 0) {
+ TEST_FAIL("Read data length should be equal to zero");
+ return;
+ }
+
+ offset = 5;
+ read_data_length = 1;
+
+ /* Get zero data from non-zero offset */
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is unchanged */
+ comp_result = memcmp(read_data, READ_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, READ_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to original read data");
+ return;
+ }
+
+ /* Check that the read data length is zero */
+ if (read_data_length != 0) {
+ TEST_FAIL("Read data length should be equal to zero");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_007(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ const size_t data_len = 1;
+ const size_t offset = 0;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ /* Get with UID that has not yet been set */
+ status = psa_its_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ TEST_FAIL("Get succeeded with non-existant UID");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is unchanged */
+ comp_result = memcmp(read_data, READ_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, READ_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data not equal to original read data");
+ return;
+ }
+
+ /* Get with invalid UID */
+ status = psa_its_get(INVALID_UID, offset, data_len,
+ read_data + HALF_PADDING_SIZE, &read_data_length);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get succeeded with invalid UID");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is unchanged */
+ comp_result = memcmp(read_data, READ_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, READ_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data not equal to original read data");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_008(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t write_len = WRITE_DATA_SIZE;
+ size_t read_len;
+ size_t offset;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ status = psa_its_set(uid, write_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get with offset greater than UID's length */
+ read_len = 1;
+ offset = write_len + 1;
+
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get should not succeed with offset too large");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is unchanged */
+ comp_result = memcmp(read_data, READ_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, READ_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to original read data");
+ return;
+ }
+
+ /* Get with data length greater than UID's length */
+ read_len = write_len + 1;
+ offset = 0;
+
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should succeed with data length larger than UID's "
+ "length");
+ return;
+ }
+
+ if (read_data_length != write_len) {
+ TEST_FAIL("Read data length should be equal to UID's length");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is changed */
+ comp_result = memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to newly read data");
+ return;
+ }
+
+ /* Get with offset + data length greater than UID's length, but individually
+ * valid
+ */
+#if DOMAIN_NS == 1U
+ /* Reset read_data to original READ_DATA */
+ memcpy(read_data, READ_DATA, sizeof(read_data));
+#else
+ tfm_memcpy(read_data, READ_DATA, sizeof(read_data));
+#endif
+ read_len = write_len;
+ offset = 1;
+
+ status = psa_its_get(uid, offset, read_len,
+ read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should succeed with offset + data length too large, "
+ "but individually valid");
+ return;
+ }
+
+ if (read_data_length != write_len - offset) {
+ TEST_FAIL("Read data length should be equal to the UID's remaining "
+ "size starting from offset");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that the read data is changed */
+ comp_result = memcmp(read_data, OFFSET_RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, OFFSET_RESULT_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read data should be equal to newly read data starting at "
+ "offset");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_009(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_3;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ size_t read_data_length = 0;
+
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get with NULL data pointer */
+ status = psa_its_get(uid, offset, 0, NULL, &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should succeed with NULL data pointer and zero length");
+ return;
+ }
+
+ /* Check that the read data length is unchanged */
+ if (read_data_length != 0) {
+ TEST_FAIL("Read data length should be 0 with NULL data pointer and "
+ "zero length");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_010(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = WRITE_ONCE_UID;
+ struct psa_storage_info_t info = {0};
+
+ /* Get info for write once UID */
+ status = psa_its_get_info(uid, &info);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get info should not fail for write once UID");
+ return;
+ }
+
+ /* Check that the info struct contains the correct values */
+ if (info.size != WRITE_ONCE_DATA_SIZE) {
+ TEST_FAIL("Size incorrect for write once UID");
+ return;
+ }
+
+ if (info.capacity != WRITE_ONCE_DATA_SIZE) {
+ TEST_FAIL("Capacity incorrect for write once UID");
+ return;
+ }
+
+ if (info.flags != PSA_STORAGE_FLAG_WRITE_ONCE) {
+ TEST_FAIL("Flags incorrect for write once UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_011(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ struct psa_storage_info_t info = {0};
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const uint8_t write_data[] = WRITE_DATA;
+
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get info for valid UID */
+ status = psa_its_get_info(uid, &info);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get info should not fail with valid UID");
+ return;
+ }
+
+ /* Check that the info struct contains the correct values */
+ if (info.size != data_len) {
+ TEST_FAIL("Size incorrect for valid UID");
+ return;
+ }
+
+ if (info.capacity != data_len) {
+ TEST_FAIL("Capacity incorrect for valid UID");
+ return;
+ }
+
+ if (info.flags != flags) {
+ TEST_FAIL("Flags incorrect for valid UID");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_012(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ struct psa_storage_info_t info = {0};
+
+ /* Get info with UID that has not yet been set */
+ status = psa_its_get_info(uid, &info);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ TEST_FAIL("Get info should not succeed with unset UID");
+ return;
+ }
+
+ /* Check that the info struct has not been modified */
+ if (info.size != 0) {
+ TEST_FAIL("Size should not have changed");
+ return;
+ }
+
+ /* Get info with invalid UID */
+ status = psa_its_get_info(INVALID_UID, &info);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get info should not succeed with invalid UID");
+ return;
+ }
+
+ /* Check that the info struct has not been modified */
+ if (info.size != 0) {
+ TEST_FAIL("Size should not have changed");
+ return;
+ }
+
+ if (info.capacity != 0) {
+ TEST_FAIL("Capacity should not have changed");
+ return;
+ }
+
+ if (info.flags != PSA_STORAGE_FLAG_NONE) {
+ TEST_FAIL("Flags should not have changed");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_013(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ struct psa_storage_info_t info = {0};
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Call remove with valid ID */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ /* Check that get info fails for removed UID */
+ status = psa_its_get_info(uid, &info);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ TEST_FAIL("Get info should not succeed with removed UID");
+ return;
+ }
+
+ /* Check that get fails for removed UID */
+ status = psa_its_get(uid, offset, data_len, read_data, &read_data_length);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ TEST_FAIL("Get should not succeed with removed UID");
+ return;
+ }
+
+ /* Check that remove fails for removed UID */
+ status = psa_its_remove(uid);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ TEST_FAIL("Remove should not succeed with removed UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_014(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = WRITE_ONCE_UID;
+
+ /* Call remove with write once UID */
+ status = psa_its_remove(uid);
+ if (status != PSA_ERROR_NOT_PERMITTED) {
+ TEST_FAIL("Remove should not succeed with write once UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_015(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = INVALID_UID;
+
+ /* Call remove with an invalid UID */
+ status = psa_its_remove(uid);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Remove should not succeed with invalid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_016(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid_1 = TEST_UID_2;
+ const psa_storage_uid_t uid_2 = TEST_UID_3;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len_2 = WRITE_DATA_SIZE;
+ const size_t offset = 0;
+ const uint8_t write_data_1[] = "UID 1 DATA";
+ const uint8_t write_data_2[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ /* Set UID 1 */
+ status = psa_its_set(uid_1, sizeof(write_data_1), write_data_1, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail for UID 1");
+ return;
+ }
+
+ /* Set UID 2 */
+ status = psa_its_set(uid_2, data_len_2, write_data_2, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail for UID 2");
+ return;
+ }
+
+ /* Remove UID 1. This should cause UID 2 to be compacted to the beginning of
+ * the block.
+ */
+ status = psa_its_remove(uid_1);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail for UID 1");
+ return;
+ }
+
+ /* If the compact worked as expected, the test should be able to read back
+ * the data from UID 2 correctly.
+ */
+ status = psa_its_get(uid_2, offset, data_len_2,
+ read_data + HALF_PADDING_SIZE, &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail for UID 2");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ comp_result = memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read buffer has incorrect data");
+ return;
+ }
+
+ if (read_data_length != WRITE_DATA_SIZE) {
+ TEST_FAIL("Read data length should be equal to result data length");
+ return;
+ }
+
+ /* Remove UID 2 to clean up storage for the next test */
+ status = psa_its_remove(uid_2);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail for UID 2");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_017(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ size_t offset = 0;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ /* Set the entire data into UID */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get the data from UID one byte at a time */
+ for (offset = 0; offset < data_len; ++offset) {
+ status = psa_its_get(uid, offset, 1,
+ (read_data + HALF_PADDING_SIZE + offset),
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail for partial read");
+ return;
+ }
+ }
+
+#if DOMAIN_NS == 1U
+ comp_result = memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#else
+ comp_result = tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read buffer has incorrect data");
+ return;
+ }
+
+ /* Remove UID to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+void tfm_its_test_common_018(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t offset = 0;
+ const uint8_t write_data_1[] = "ONE";
+ const uint8_t write_data_2[] = "TWO";
+ const uint8_t write_data_3[] = "THREE";
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+ int comp_result;
+
+ /* Set write data 1 into UID */
+ status = psa_its_set(uid, sizeof(write_data_1), write_data_1, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("First set should not fail");
+ return;
+ }
+
+ /* Set write data 2 into UID */
+ status = psa_its_set(uid, sizeof(write_data_2), write_data_2, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Second set should not fail");
+ return;
+ }
+
+ /* Set write data 3 into UID */
+ status = psa_its_set(uid, sizeof(write_data_3), write_data_3, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Third set should not fail");
+ return;
+ }
+
+ status = psa_its_get(uid, offset, sizeof(write_data_3), read_data,
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+#if DOMAIN_NS == 1U
+ /* Check that get returns the last data to be set */
+ comp_result = memcmp(read_data, write_data_3, sizeof(write_data_3));
+#else
+ comp_result = tfm_memcmp(read_data, write_data_3, sizeof(write_data_3));
+#endif
+ if (comp_result != 0) {
+ TEST_FAIL("Read buffer has incorrect data");
+ return;
+ }
+
+ if (read_data_length != sizeof(write_data_3)) {
+ TEST_FAIL("Read data length should be equal to result data length");
+ return;
+ }
+
+ /* Remove UID to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
diff --git a/test/suites/its/its_tests_common.h b/test/suites/its/its_tests_common.h
new file mode 100644
index 0000000..f9dbc7d
--- /dev/null
+++ b/test/suites/its/its_tests_common.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ITS_TESTS_COMMON_H__
+#define __ITS_TESTS_COMMON_H__
+
+#include "test/framework/test_framework_helpers.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Test UIDs */
+#define WRITE_ONCE_UID 1U /* Cannot be modified or deleted once created */
+#define TEST_UID_1 2U
+#define TEST_UID_2 3U
+#define TEST_UID_3 4U
+
+/* Invalid values */
+#define INVALID_UID 0U
+#define INVALID_DATA_LEN UINT32_MAX
+#define INVALID_OFFSET UINT32_MAX
+#define INVALID_FLAG (1U << 31)
+
+/* Write once data */
+#define WRITE_ONCE_DATA "THE_FIVE_BOXING_WIZARDS_JUMP_QUICKLY"
+#define WRITE_ONCE_DATA_SIZE (sizeof(WRITE_ONCE_DATA) - 1)
+#define WRITE_ONCE_READ_DATA "############################################"
+#define WRITE_ONCE_RESULT_DATA ("####" WRITE_ONCE_DATA "####")
+
+#define WRITE_DATA "THEQUICKBROWNFOXJUMPSOVERALAZYDOG"
+#define WRITE_DATA_SIZE (sizeof(WRITE_DATA) - 1)
+#define READ_DATA "_________________________________________"
+#define RESULT_DATA ("____" WRITE_DATA "____")
+#define OFFSET_READ_DATA "HEQUICKBROWNFOXJUMPSOVERALAZYDOG"
+#define OFFSET_RESULT_DATA ("____" OFFSET_READ_DATA "_____")
+
+/**
+ * Several tests use a buffer to read back data from an asset. This buffer is
+ * larger than the size of the asset data by PADDING_SIZE bytes. This allows
+ * us to ensure that only the expected data is read back and that it is read
+ * back correctly.
+ *
+ * For example if the buffer and asset are as follows:
+ * Buffer - "XXXXXXXXXXXX", Asset data - "AAAA"
+ *
+ * Then a correct and successful read would give this result: "XXXXAAAAXXXX"
+ * (Assuming a PADDING_SIZE of 8)
+ */
+#define BUFFER_SIZE 24
+#define PADDING_SIZE 8
+#define HALF_PADDING_SIZE 4
+#define BUFFER_PLUS_PADDING_SIZE (BUFFER_SIZE + PADDING_SIZE)
+#define BUFFER_PLUS_HALF_PADDING_SIZE (BUFFER_SIZE + HALF_PADDING_SIZE)
+
+/**
+ * \brief Tests set function with:
+ * - Valid UID, no data, no flags
+ * - Invalid UID, no data, no flags
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_001(struct test_result_t *ret);
+
+/**
+ * \brief Tests set function with:
+ * - Zero create flags
+ * - Valid create flags (with previously created UID)
+ * - Invalid create flags
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_002(struct test_result_t *ret);
+
+/**
+ * \brief Tests set function with:
+ * - NULL data pointer and zero data length
+ *
+ * \param[out] ret Test result
+ *
+ * \note A request with a null data pointer and data length not equal to zero is
+ * treated as a secure violation. TF-M framework will reject such requests
+ * and not return to the caller so this case is not tested here.
+ *
+ */
+void tfm_its_test_common_003(struct test_result_t *ret);
+
+/**
+ * \brief Tests set function with:
+ * - Write once UID that has already been created
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_004(struct test_result_t *ret);
+
+/**
+ * \brief Tests get function with:
+ * - Valid data, zero offset
+ * - Valid data, non-zero offset
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_005(struct test_result_t *ret);
+
+/**
+ * \brief Tests get function with:
+ * - Zero data length, zero offset
+ * - Zero data length, non-zero offset
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_006(struct test_result_t *ret);
+
+/**
+ * \brief Tests get function with:
+ * - Unset UID
+ * - Invalid UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_007(struct test_result_t *ret);
+
+/**
+ * \brief Tests get function with:
+ * - Offset greater than UID length
+ * - Data length greater than UID length
+ * - Data length + offset greater than UID length
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_008(struct test_result_t *ret);
+
+/**
+ * \brief Tests get function with:
+ * - NULL data pointer and zero data length
+ *
+ * \param[out] ret Test result
+ *
+ * \note A request with a null data pointer and data length not equal to zero is
+ * treated as a secure violation. TF-M framework will reject such requests
+ * and not return to the caller so this case is not tested here.
+ *
+ */
+void tfm_its_test_common_009(struct test_result_t *ret);
+
+/**
+ * \brief Tests get info function with:
+ * - Write once UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_010(struct test_result_t *ret);
+
+/**
+ * \brief Tests get info function with:
+ * - Valid UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_011(struct test_result_t *ret);
+
+/**
+ * \brief Tests get info function with:
+ * - Unset UID
+ * - Invalid UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_012(struct test_result_t *ret);
+
+/**
+ * \brief Tests remove function with:
+ * - Valid UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_013(struct test_result_t *ret);
+
+/**
+ * \brief Tests remove function with:
+ * - Write once UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_014(struct test_result_t *ret);
+
+/**
+ * \brief Tests remove function with:
+ * - Invalid UID
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_015(struct test_result_t *ret);
+
+/**
+ * \brief Tests data block compact feature.
+ * Set UID 1 to locate it at the beginning of the block. Then set UID 2
+ * to be located after UID 1 and remove UID 1. UID 2 will be compacted to
+ * the beginning of the block. This test verifies that the compaction
+ * works correctly by reading back UID 2.
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_016(struct test_result_t *ret);
+
+/**
+ * \brief Tests set and multiple partial gets.
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_017(struct test_result_t *ret);
+
+/**
+ * \brief Tests multiple sets to the same UID.
+ *
+ * \param[out] ret Test result
+ */
+void tfm_its_test_common_018(struct test_result_t *ret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ITS_TESTS_COMMON_H__ */
diff --git a/test/suites/its/non_secure/its_ns_tests.h b/test/suites/its/non_secure/its_ns_tests.h
new file mode 100644
index 0000000..534dd17
--- /dev/null
+++ b/test/suites/its/non_secure/its_ns_tests.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ITS_NS_TESTS_H__
+#define __ITS_NS_TESTS_H__
+
+#include "test/framework/test_framework.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Register testsuite for the PSA internal trusted storage NS interface
+ * tests.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_ns_psa_its_interface(struct test_suite_t *p_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ITS_NS_TESTS_H__ */
diff --git a/test/suites/its/non_secure/psa_its_ns_interface_testsuite.c b/test/suites/its/non_secure/psa_its_ns_interface_testsuite.c
new file mode 100644
index 0000000..34e02be
--- /dev/null
+++ b/test/suites/its/non_secure/psa_its_ns_interface_testsuite.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "its_ns_tests.h"
+#include "test/framework/test_framework_helpers.h"
+#include "../its_tests_common.h"
+
+static struct test_t psa_its_ns_tests[] = {
+ {&tfm_its_test_common_001, "TFM_ITS_TEST_1001",
+ "Set interface"},
+ {&tfm_its_test_common_002, "TFM_ITS_TEST_1002",
+ "Set interface with create flags"},
+ {&tfm_its_test_common_003, "TFM_ITS_TEST_1003",
+ "Set interface with NULL data pointer"},
+ {&tfm_its_test_common_004, "TFM_ITS_TEST_1004",
+ "Set interface with write once UID"},
+ {&tfm_its_test_common_005, "TFM_ITS_TEST_1005",
+ "Get interface with valid data"},
+ {&tfm_its_test_common_006, "TFM_ITS_TEST_1006",
+ "Get interface with zero data length"},
+ {&tfm_its_test_common_007, "TFM_ITS_TEST_1007",
+ "Get interface with invalid UIDs"},
+ {&tfm_its_test_common_008, "TFM_ITS_TEST_1008",
+ "Get interface with invalid data lengths and offsets"},
+ {&tfm_its_test_common_009, "TFM_ITS_TEST_1009",
+ "Get interface with NULL data pointer"},
+ {&tfm_its_test_common_010, "TFM_ITS_TEST_1010",
+ "Get info interface with write once UID"},
+ {&tfm_its_test_common_011, "TFM_ITS_TEST_1011",
+ "Get info interface with valid UID"},
+ {&tfm_its_test_common_012, "TFM_ITS_TEST_1012",
+ "Get info interface with invalid UIDs"},
+ {&tfm_its_test_common_013, "TFM_ITS_TEST_1013",
+ "Remove interface with valid UID"},
+ {&tfm_its_test_common_014, "TFM_ITS_TEST_1014",
+ "Remove interface with write once UID"},
+ {&tfm_its_test_common_015, "TFM_ITS_TEST_1015",
+ "Remove interface with invalid UID"},
+ {&tfm_its_test_common_016, "TFM_ITS_TEST_1016",
+ "Block compaction after remove"},
+ {&tfm_its_test_common_017, "TFM_ITS_TEST_1017",
+ "Multiple partial gets"},
+ {&tfm_its_test_common_018, "TFM_ITS_TEST_1018",
+ "Multiple sets to same UID from same thread"},
+};
+
+void register_testsuite_ns_psa_its_interface(struct test_suite_t *p_test_suite)
+{
+ uint32_t list_size;
+
+ list_size = (sizeof(psa_its_ns_tests) / sizeof(psa_its_ns_tests[0]));
+
+ set_testsuite("PSA internal trusted storage NS interface tests "
+ "(TFM_ITS_TEST_1XXX)",
+ psa_its_ns_tests, list_size, p_test_suite);
+
+#ifdef ITS_SHOW_FLASH_WARNING
+ TEST_LOG("\r\n**WARNING** The ITS regression tests reduce the life of the "
+ "flash memory as they write/erase multiple times the memory. \r\n"
+ "Please, set the ITS_RAM_FS flag to use RAM instead of flash."
+ "\r\n\r\n");
+#endif
+}
diff --git a/test/suites/its/secure/its_s_tests.h b/test/suites/its/secure/its_s_tests.h
new file mode 100644
index 0000000..42d739f
--- /dev/null
+++ b/test/suites/its/secure/its_s_tests.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ITS_S_TESTS_H__
+#define __ITS_S_TESTS_H__
+
+#include "test/framework/test_framework.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Register testsuite for the PSA internal trusted storage S interface
+ * tests.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_s_psa_its_interface(struct test_suite_t *p_test_suite);
+
+/**
+ * \brief Register testsuite for the ITS reliability tests.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_s_psa_its_reliability(struct test_suite_t
+ *p_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ITS_S_TESTS_H__ */
diff --git a/test/suites/its/secure/psa_its_s_interface_testsuite.c b/test/suites/its/secure/psa_its_s_interface_testsuite.c
new file mode 100644
index 0000000..b31cc59
--- /dev/null
+++ b/test/suites/its/secure/psa_its_s_interface_testsuite.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "its_s_tests.h"
+#include "psa/internal_trusted_storage.h"
+#include "test/framework/test_framework_helpers.h"
+#include "../its_tests_common.h"
+#include "tfm_memory_utils.h"
+
+/* List of tests */
+static void tfm_its_test_2019(struct test_result_t *ret);
+static void tfm_its_test_2020(struct test_result_t *ret);
+static void tfm_its_test_2021(struct test_result_t *ret);
+
+static struct test_t psa_its_s_tests[] = {
+ {&tfm_its_test_common_001, "TFM_ITS_TEST_2001",
+ "Set interface"},
+ {&tfm_its_test_common_002, "TFM_ITS_TEST_2002",
+ "Set interface with create flags"},
+ {&tfm_its_test_common_003, "TFM_ITS_TEST_2003",
+ "Set interface with NULL data pointer"},
+ {&tfm_its_test_common_004, "TFM_ITS_TEST_2004",
+ "Set interface with write once UID"},
+ {&tfm_its_test_common_005, "TFM_ITS_TEST_2005",
+ "Get interface with valid data"},
+ {&tfm_its_test_common_006, "TFM_ITS_TEST_2006",
+ "Get interface with zero data length"},
+ {&tfm_its_test_common_007, "TFM_ITS_TEST_2007",
+ "Get interface with invalid UIDs"},
+ {&tfm_its_test_common_008, "TFM_ITS_TEST_2008",
+ "Get interface with data lengths and offsets greater than UID length"},
+ {&tfm_its_test_common_009, "TFM_ITS_TEST_2009",
+ "Get interface with NULL data pointer"},
+ {&tfm_its_test_common_010, "TFM_ITS_TEST_2010",
+ "Get info interface with write once UID"},
+ {&tfm_its_test_common_011, "TFM_ITS_TEST_2011",
+ "Get info interface with valid UID"},
+ {&tfm_its_test_common_012, "TFM_ITS_TEST_2012",
+ "Get info interface with invalid UIDs"},
+ {&tfm_its_test_common_013, "TFM_ITS_TEST_2013",
+ "Remove interface with valid UID"},
+ {&tfm_its_test_common_014, "TFM_ITS_TEST_2014",
+ "Remove interface with write once UID"},
+ {&tfm_its_test_common_015, "TFM_ITS_TEST_2015",
+ "Remove interface with invalid UID"},
+ {&tfm_its_test_common_016, "TFM_ITS_TEST_2016",
+ "Block compaction after remove"},
+ {&tfm_its_test_common_017, "TFM_ITS_TEST_2017",
+ "Multiple partial gets"},
+ {&tfm_its_test_common_018, "TFM_ITS_TEST_2018",
+ "Multiple sets to same UID from same thread"},
+ {&tfm_its_test_2019, "TFM_ITS_TEST_2019",
+ "Set interface with invalid data length"},
+ {&tfm_its_test_2020, "TFM_ITS_TEST_2020",
+ "Get interface with invalid data lengths and offsets"},
+ {&tfm_its_test_2021, "TFM_ITS_TEST_2021",
+ "Get info interface with NULL info pointer"},
+};
+
+void register_testsuite_s_psa_its_interface(struct test_suite_t *p_test_suite)
+{
+ uint32_t list_size;
+
+ list_size = (sizeof(psa_its_s_tests) / sizeof(psa_its_s_tests[0]));
+
+ set_testsuite("PSA internal trusted storage S interface tests "
+ "(TFM_ITS_TEST_2XXX)",
+ psa_its_s_tests, list_size, p_test_suite);
+
+#ifdef ITS_SHOW_FLASH_WARNING
+ TEST_LOG("\r\n**WARNING** The ITS regression tests reduce the life of the "
+ "flash memory as they write/erase multiple times the memory. \r\n"
+ "Please, set the ITS_RAM_FS flag to use RAM instead of flash."
+ "\r\n\r\n");
+#endif
+}
+
+/**
+ * \brief Tests set function with:
+ * - Data length longer than maximum permitted
+ *
+ * \param[out] ret Test result
+ */
+static void tfm_its_test_2019(struct test_result_t *ret)
+{
+#ifndef TFM_PSA_API
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_1;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = INVALID_DATA_LEN;
+ const uint8_t write_data[] = WRITE_DATA;
+
+ /* A parameter with a buffer pointer where its data length is longer than
+ * maximum permitted, it is treated as a secure violation.
+ * TF-M framework rejects the request with a proper error code.
+ * The ITS secure PSA implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+
+ /* Set with data length longer than the maximum supported */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Set should not succeed with invalid data length");
+ return;
+ }
+
+#endif
+ ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - Invalid data len and offset
+ * - NULL read data length pointer
+ *
+ * \param[out] ret Test result
+ */
+static void tfm_its_test_2020(struct test_result_t *ret)
+{
+#ifndef TFM_PSA_API
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_2;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t write_len = WRITE_DATA_SIZE;
+ size_t read_len;
+ size_t offset;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+
+ status = psa_its_set(uid, write_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* Get with data length and offset set to invalid values */
+ read_len = INVALID_DATA_LEN;
+ offset = INVALID_OFFSET;
+
+ /* A parameter with a buffer pointer where its data length is longer than
+ * maximum permitted, it is treated as a secure violation.
+ * TF-M framework rejects the request with a proper error code.
+ * The ITS secure PSA implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ &read_data_length);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get should not succeed with invalid arguments");
+ return;
+ }
+
+ /* Check that the read data is unchanged */
+ if (tfm_memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+ TEST_FAIL("Read data should be equal to original read data");
+ return;
+ }
+
+ read_len = 1;
+ offset = 0;
+
+ status = psa_its_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE,
+ NULL);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get should not succeed with invalid arguments");
+ return;
+ }
+
+ /* Check that the read data is unchanged */
+ if (tfm_memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+ TEST_FAIL("Read data should be equal to original read data");
+ return;
+ }
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+#endif
+ ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with:
+ * - NULL info pointer
+ *
+ * \param[out] ret Test result
+ */
+static void tfm_its_test_2021(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID_3;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const uint8_t write_data[] = WRITE_DATA;
+
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail");
+ return;
+ }
+
+ /* A parameter with a null pointer is treated as a secure violation.
+ * TF-M framework rejects the request with a proper error code.
+ * The secure PSA ITS implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+
+ /* Get info with NULL info pointer */
+#ifndef TFM_PSA_API
+ status = psa_its_get_info(uid, NULL);
+ if (status != PSA_ERROR_INVALID_ARGUMENT) {
+ TEST_FAIL("Get info should not succeed with NULL info pointer");
+ return;
+ }
+#endif
+
+ /* Call remove to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
diff --git a/test/suites/its/secure/psa_its_s_reliability_testsuite.c b/test/suites/its/secure/psa_its_s_reliability_testsuite.c
new file mode 100644
index 0000000..c562c6d
--- /dev/null
+++ b/test/suites/its/secure/psa_its_s_reliability_testsuite.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "its_s_tests.h"
+#include "psa/internal_trusted_storage.h"
+#include "test/framework/test_framework_helpers.h"
+#include "tfm_memory_utils.h"
+
+/* Test UIDs */
+#define TEST_UID 2UL /* UID 1 cannot be used as it references a write once
+ * asset, created in psa_its_s_interface_testsuite.c
+ */
+
+/* Test suite defines */
+#define LOOP_ITERATIONS_001 15U
+#define LOOP_ITERATIONS_002 15U
+
+/* Write data */
+#define WRITE_DATA "THEQUICKBROWNFOXJUMPSOVERALAZYDOG"
+#define WRITE_DATA_SIZE (sizeof(WRITE_DATA) - 1)
+#define READ_DATA "_________________________________________"
+#define RESULT_DATA ("____" WRITE_DATA "____")
+
+/* Size of ____ from RESULT_DATA */
+#define HALF_PADDING_SIZE 4
+
+/* Define test suite for ITS reliability tests */
+/* List of tests */
+static void tfm_its_test_3001(struct test_result_t *ret);
+static void tfm_its_test_3002(struct test_result_t *ret);
+
+static struct test_t reliability_tests[] = {
+ {&tfm_its_test_3001, "TFM_ITS_TEST_3001",
+ "repetitive sets and gets in/from an asset", {0} },
+ {&tfm_its_test_3002, "TFM_ITS_TEST_3002",
+ "repetitive sets, gets and removes", {0} },
+};
+
+void register_testsuite_s_psa_its_reliability(struct test_suite_t *p_test_suite)
+{
+ uint32_t list_size = (sizeof(reliability_tests) /
+ sizeof(reliability_tests[0]));
+
+ set_testsuite("ITS reliability tests (TFM_ITS_TEST_3XXX)",
+ reliability_tests, list_size, p_test_suite);
+}
+
+/**
+ * \brief Tests repetitive sets and gets in/from an asset.
+ *
+ * \param[out] ret Test result
+ */
+static void tfm_its_test_3001(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const size_t offset = 0;
+ uint32_t itr;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+
+ for (itr = 0; itr < LOOP_ITERATIONS_001; itr++) {
+ TEST_LOG(" > Iteration %d of %d\r", itr + 1, LOOP_ITERATIONS_001);
+
+ /* Set a data in the asset */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail with valid UID");
+ return;
+ }
+
+ /* Get data from the asset */
+ status = psa_its_get(uid, offset, data_len, (read_data +
+ HALF_PADDING_SIZE),
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+ /* Check that the data has not changed */
+ if (tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+ TEST_FAIL("The data should not have changed");
+ return;
+ }
+
+ /* Set the original data into read buffer */
+ tfm_memcpy(read_data, READ_DATA, sizeof(read_data));
+ }
+
+ TEST_LOG("\n");
+
+ /* Remove the asset to clean up storage for the next test */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests repetitive sets, gets and removes.
+ *
+ * \param[out] ret Test result
+ */
+static void tfm_its_test_3002(struct test_result_t *ret)
+{
+ psa_status_t status;
+ const psa_storage_uid_t uid = TEST_UID;
+ const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
+ const size_t data_len = WRITE_DATA_SIZE;
+ const size_t offset = 0;
+ uint32_t itr;
+ const uint8_t write_data[] = WRITE_DATA;
+ uint8_t read_data[] = READ_DATA;
+ size_t read_data_length = 0;
+
+ for (itr = 0; itr < LOOP_ITERATIONS_002; itr++) {
+ TEST_LOG(" > Iteration %d of %d\r", itr + 1, LOOP_ITERATIONS_002);
+
+ /* Set a data in the asset */
+ status = psa_its_set(uid, data_len, write_data, flags);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Set should not fail with valid UID");
+ return;
+ }
+
+ /* Get data from the asset */
+ status = psa_its_get(uid, offset, data_len, (read_data +
+ HALF_PADDING_SIZE),
+ &read_data_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Get should not fail");
+ return;
+ }
+
+ /* Check that the data has not changed */
+ if (tfm_memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+ TEST_FAIL("The data should not have changed");
+ return;
+ }
+
+ /* Remove the asset from the secure storage */
+ status = psa_its_remove(uid);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Remove should not fail with valid UID");
+ return;
+ }
+
+ /* Set the original data into read buffer */
+ tfm_memcpy(read_data, READ_DATA, sizeof(read_data));
+ }
+
+ TEST_LOG("\n");
+
+ ret->val = TEST_PASSED;
+}