Test: Add PSA PS NS interface test suite

Adds a test suite for the PSA Protected Storage non-secure API.

Change-Id: I3d7d8cd3f54f0e62b1fc763728698ab353f7f011
Signed-off-by: Jamie Fox <jamie.fox@arm.com>
diff --git a/test/framework/non_secure_suites.c b/test/framework/non_secure_suites.c
index 35890d9..9c1489d 100644
--- a/test/framework/non_secure_suites.c
+++ b/test/framework/non_secure_suites.c
@@ -36,7 +36,9 @@
 #ifdef SERVICES_TEST_NS
     /* List test cases which compliant with level 1 isolation */
 
-#ifndef PSA_PROTECTED_STORAGE
+#ifdef PSA_PROTECTED_STORAGE
+    {&register_testsuite_ns_psa_ps_interface, 0, 0, 0},
+#else /* PSA_PROTECTED_STORAGE */
     /* Non-secure SST test cases */
     {&register_testsuite_ns_sst_interface, 0, 0, 0},
 
@@ -49,7 +51,7 @@
 #endif /* TFM_PARTITION_TEST_SST */
 
 #endif /* TFM_NS_CLIENT_IDENTIFICATION */
-#endif /* !PSA_PROTECTED_STORAGE */
+#endif /* PSA_PROTECTED_STORAGE */
 
     /* Non-secure Audit Logging test cases */
     {&register_testsuite_ns_audit_interface, 0, 0, 0},
diff --git a/test/suites/sst/CMakeLists.inc b/test/suites/sst/CMakeLists.inc
index dcd5e32..e35895d 100644
--- a/test/suites/sst/CMakeLists.inc
+++ b/test/suites/sst/CMakeLists.inc
@@ -27,13 +27,23 @@
 if (NOT DEFINED ENABLE_SECURE_STORAGE_SERVICE_TESTS)
 	message(FATAL_ERROR "Incomplete build configuration: ENABLE_SECURE_STORAGE_SERVICE_TESTS is undefined. ")
 elseif (ENABLE_SECURE_STORAGE_SERVICE_TESTS)
+	list(APPEND ALL_SRC_C_NS "${SECURE_STORAGE_TEST_DIR}/non_secure/ns_test_helpers.c")
+
 	if (NOT DEFINED PSA_PROTECTED_STORAGE)
 		message(FATAL_ERROR "Incomplete build configuration: PSA_PROTECTED_STORAGE is undefined.")
 
 	elseif (PSA_PROTECTED_STORAGE)
+		list(APPEND ALL_SRC_C_NS "${SECURE_STORAGE_TEST_DIR}/non_secure/psa_ps_ns_interface_testsuite.c")
+
 		set_property(SOURCE ${ALL_SRC_C_S} APPEND PROPERTY COMPILE_DEFINITIONS PSA_PROTECTED_STORAGE)
 		set_property(SOURCE ${ALL_SRC_C_NS} APPEND PROPERTY COMPILE_DEFINITIONS PSA_PROTECTED_STORAGE)
 
+		if (NOT DEFINED TFM_NS_CLIENT_IDENTIFICATION)
+			message(FATAL_ERROR "Incomplete build configuration: TFM_NS_CLIENT_IDENTIFICATION is undefined.")
+		elseif (TFM_NS_CLIENT_IDENTIFICATION)
+			set_property(SOURCE ${ALL_SRC_C_NS} APPEND PROPERTY COMPILE_DEFINITIONS TFM_NS_CLIENT_IDENTIFICATION)
+		endif()
+
 	else()
 		list(APPEND ALL_SRC_C_S "${SECURE_STORAGE_TEST_DIR}/secure/sst_sec_interface_testsuite.c"
 				"${SECURE_STORAGE_TEST_DIR}/secure/sst_reliability_testsuite.c"
@@ -43,10 +53,7 @@
 						"${SECURE_STORAGE_TEST_DIR}/secure/nv_counters/test_sst_nv_counters.c")
 		endif()
 
-		list(APPEND ALL_SRC_C_NS
-				"${SECURE_STORAGE_TEST_DIR}/non_secure/ns_test_helpers.c"
-				"${SECURE_STORAGE_TEST_DIR}/non_secure/sst_ns_interface_testsuite.c"
-		)
+		list(APPEND ALL_SRC_C_NS "${SECURE_STORAGE_TEST_DIR}/non_secure/sst_ns_interface_testsuite.c")
 
 		if (NOT DEFINED TFM_NS_CLIENT_IDENTIFICATION)
 			message(FATAL_ERROR "Incomplete build configuration: TFM_NS_CLIENT_IDENTIFICATION is undefined.")
diff --git a/test/suites/sst/non_secure/psa_ps_ns_interface_testsuite.c b/test/suites/sst/non_secure/psa_ps_ns_interface_testsuite.c
new file mode 100644
index 0000000..da26901
--- /dev/null
+++ b/test/suites/sst/non_secure/psa_ps_ns_interface_testsuite.c
@@ -0,0 +1,1662 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "sst_ns_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ns_test_helpers.h"
+#include "psa_protected_storage.h"
+#include "test/framework/test_framework_helpers.h"
+
+/* 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)
+#define INVALID_THREAD_NAME      "Thread_INVALID"
+
+/* Memory bounds to check */
+#define ROM_ADDR_LOCATION        ((void *)0x00100000)
+#define DEV_ADDR_LOCATION        ((void *)0x40000000)
+#define SECURE_ADDR_LOCATION     ((void *)0x30000000)
+#define NON_EXIST_ADDR_LOCATION  ((void *)0xEFFFFFFF)
+
+/* 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 "____")
+
+/* List of tests */
+static void tfm_sst_test_1001(struct test_result_t *ret);
+static void tfm_sst_test_1002(struct test_result_t *ret);
+static void tfm_sst_test_1003(struct test_result_t *ret);
+static void tfm_sst_test_1004(struct test_result_t *ret);
+static void tfm_sst_test_1005(struct test_result_t *ret);
+static void tfm_sst_test_1006(struct test_result_t *ret);
+static void tfm_sst_test_1007(struct test_result_t *ret);
+static void tfm_sst_test_1008(struct test_result_t *ret);
+static void tfm_sst_test_1009(struct test_result_t *ret);
+static void tfm_sst_test_1010(struct test_result_t *ret);
+static void tfm_sst_test_1011(struct test_result_t *ret);
+static void tfm_sst_test_1012(struct test_result_t *ret);
+static void tfm_sst_test_1013(struct test_result_t *ret);
+static void tfm_sst_test_1014(struct test_result_t *ret);
+static void tfm_sst_test_1015(struct test_result_t *ret);
+static void tfm_sst_test_1016(struct test_result_t *ret);
+static void tfm_sst_test_1017(struct test_result_t *ret);
+#ifdef TFM_NS_CLIENT_IDENTIFICATION
+static void tfm_sst_test_1018(struct test_result_t *ret);
+static void tfm_sst_test_1019(struct test_result_t *ret);
+static void tfm_sst_test_1020(struct test_result_t *ret);
+static void tfm_sst_test_1021(struct test_result_t *ret);
+static void tfm_sst_test_1022(struct test_result_t *ret);
+#endif /* TFM_NS_CLIENT_IDENTIFICATION */
+static void tfm_sst_test_1023(struct test_result_t *ret);
+static void tfm_sst_test_1024(struct test_result_t *ret);
+static void tfm_sst_test_1025(struct test_result_t *ret);
+static void tfm_sst_test_1026(struct test_result_t *ret);
+
+static struct test_t psa_ps_ns_tests[] = {
+    {&tfm_sst_test_1001, "TFM_SST_TEST_1001",
+     "Set interface"},
+    {&tfm_sst_test_1002, "TFM_SST_TEST_1002",
+     "Set interface with create flags"},
+    {&tfm_sst_test_1003, "TFM_SST_TEST_1003",
+     "Set interface with NULL data pointer"},
+    {&tfm_sst_test_1004, "TFM_SST_TEST_1004",
+     "Set interface with invalid data length"},
+    {&tfm_sst_test_1005, "TFM_SST_TEST_1005",
+     "Set interface with write once UID"},
+    {&tfm_sst_test_1006, "TFM_SST_TEST_1006",
+     "Get interface with valid data"},
+    {&tfm_sst_test_1007, "TFM_SST_TEST_1007",
+     "Get interface with zero data length"},
+    {&tfm_sst_test_1008, "TFM_SST_TEST_1008",
+     "Get interface with invalid UIDs"},
+    {&tfm_sst_test_1009, "TFM_SST_TEST_1009",
+     "Get interface with invalid data lengths and offsets"},
+    {&tfm_sst_test_1010, "TFM_SST_TEST_1010",
+     "Get interface with NULL data pointer"},
+    {&tfm_sst_test_1011, "TFM_SST_TEST_1011",
+     "Get info interface with write once UID"},
+    {&tfm_sst_test_1012, "TFM_SST_TEST_1012",
+     "Get info interface with valid UID"},
+    {&tfm_sst_test_1013, "TFM_SST_TEST_1013",
+     "Get info interface with invalid UIDs"},
+    {&tfm_sst_test_1014, "TFM_SST_TEST_1014",
+     "Get info interface with NULL info pointer"},
+    {&tfm_sst_test_1015, "TFM_SST_TEST_1015",
+     "Remove interface with valid UID"},
+    {&tfm_sst_test_1016, "TFM_SST_TEST_1016",
+     "Remove interface with write once UID"},
+    {&tfm_sst_test_1017, "TFM_SST_TEST_1017",
+     "Remove interface with invalid UID"},
+#ifdef TFM_NS_CLIENT_IDENTIFICATION
+    {&tfm_sst_test_1018, "TFM_SST_TEST_1018",
+     "Get interface with invalid thread name"},
+    {&tfm_sst_test_1019, "TFM_SST_TEST_1019",
+     "Get info interface with invalid thread name"},
+    {&tfm_sst_test_1020, "TFM_SST_TEST_1020",
+     "Remove interface with invalid thread name"},
+    {&tfm_sst_test_1021, "TFM_SST_TEST_1021",
+     "Attempt to access UID belonging to another thread"},
+    {&tfm_sst_test_1022, "TFM_SST_TEST_1022",
+     "Set UID alternately from two threads"},
+#endif /* TFM_NS_CLIENT_IDENTIFICATION */
+    {&tfm_sst_test_1023, "TFM_SST_TEST_1023",
+     "Block compaction after remove"},
+    {&tfm_sst_test_1024, "TFM_SST_TEST_1024",
+     "Multiple partial gets"},
+    {&tfm_sst_test_1025, "TFM_SST_TEST_1025",
+     "Multiple sets to same UID from same thread"},
+    {&tfm_sst_test_1026, "TFM_SST_TEST_1026",
+     "Get support interface"},
+};
+
+void register_testsuite_ns_psa_ps_interface(struct test_suite_t *p_test_suite)
+{
+    uint32_t list_size;
+
+    list_size = (sizeof(psa_ps_ns_tests) / sizeof(psa_ps_ns_tests[0]));
+
+    set_testsuite(
+                 "PSA protected storage NS interface tests (TFM_SST_TEST_1XXX)",
+                  psa_ps_ns_tests, list_size, p_test_suite);
+
+#ifdef SST_SHOW_FLASH_WARNING
+    TEST_LOG("\r\n**WARNING** The SST regression tests reduce the life of the "
+             "flash memory as they write/erase multiple times the memory. \r\n"
+             "Please, set the SST_RAM_FS flag to use RAM instead of flash."
+             "\r\n\r\n");
+#endif
+}
+
+/**
+ * \brief Tests set function with:
+ * - Valid UID, no data, no flags
+ * - Invalid UID, no data, no flags
+ */
+TFM_SST_NS_TEST(1001, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = 0;
+    const uint8_t write_data[] = {0};
+
+    /* Set with no data and no flags and a valid UID */
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid UID");
+        return;
+    }
+
+    /* Attempt to set a second time */
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail the second time with valid UID");
+        return;
+    }
+
+    /* Set with an invalid UID */
+    status = psa_ps_set(INVALID_UID, data_len, write_data, flags);
+    if (status != PSA_PS_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_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests set function with:
+ * - Zero create flags
+ * - Valid create flags (with previously created UID)
+ * - Invalid create flags
+ */
+TFM_SST_NS_TEST(1002, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    /* Set with no flags */
+    status = psa_ps_set(WRITE_ONCE_UID, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with no flags");
+        return;
+    }
+
+    /* Set with valid flag: PSA_PS_FLAG_WRITE_ONCE (with previously created UID)
+     * Note: Once created, WRITE_ONCE_UID cannot be deleted. It is reused across
+     * multiple tests.
+     */
+    status = psa_ps_set(WRITE_ONCE_UID, WRITE_ONCE_DATA_SIZE, WRITE_ONCE_DATA,
+                        PSA_PS_FLAG_WRITE_ONCE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid flags (and existing UID)");
+        return;
+    }
+
+    /* Set with invalid flags */
+    status = psa_ps_set(uid, data_len, write_data, INVALID_FLAG);
+    if (status != PSA_PS_ERROR_FLAGS_NOT_SUPPORTED) {
+        TEST_FAIL("Set should not succeed with invalid flags");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests set function with:
+ * - NULL data pointer
+ */
+TFM_SST_NS_TEST(1003, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = 1;
+
+    /* Set with NULL data pointer */
+    status = psa_ps_set(uid, data_len, NULL, flags);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Set should not succeed with NULL data pointer");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests set function with:
+ * - Data length longer than maximum permitted
+ */
+TFM_SST_NS_TEST(1004, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = INVALID_DATA_LEN;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    /* Set with data length longer than the maximum supported */
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Set should not succeed with invalid data length");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests set function with:
+ * - Write once UID that has already been created
+ */
+TFM_SST_NS_TEST(1005, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = WRITE_ONCE_UID;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t write_len = WRITE_DATA_SIZE;
+    const uint32_t read_len = WRITE_ONCE_DATA_SIZE;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = WRITE_ONCE_READ_DATA;
+
+    /* Set a write once UID a second time */
+    status = psa_ps_set(uid, write_len, write_data, flags);
+    if (status != PSA_PS_ERROR_WRITE_ONCE) {
+        TEST_FAIL("Set should not rewrite a write once UID");
+        return;
+    }
+
+    /* Get write once data */
+    status = psa_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail");
+        return;
+    }
+
+    /* Check that write once data has not changed */
+    if (memcmp(read_data, WRITE_ONCE_RESULT_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Write once data should not have changed");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - Valid data, zero offset
+ * - Valid data, non-zero offset
+ */
+TFM_SST_NS_TEST(1006, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    uint32_t data_len = WRITE_DATA_SIZE;
+    uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+    const uint8_t *p_read_data = read_data;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get the entire data */
+    status = psa_ps_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail");
+        return;
+    }
+
+    /* Check that the data is correct, including no illegal pre- or post-data */
+    if (memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should be equal to result data");
+        return;
+    }
+
+    /* Reset read data */
+    memcpy(read_data, READ_DATA, sizeof(read_data));
+
+    /* Read from offset 2 to 2 bytes before end of the data */
+    offset = 2;
+    data_len -= offset + 2;
+
+    status = psa_ps_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail");
+        return;
+    }
+
+    /* Check that the correct data was read */
+    if (memcmp(p_read_data, "____", HALF_PADDING_SIZE) != 0) {
+        TEST_FAIL("Read data contains illegal pre-data");
+        return;
+    }
+
+    p_read_data += HALF_PADDING_SIZE;
+
+    if (memcmp(p_read_data, write_data + offset, data_len) != 0) {
+        TEST_FAIL("Read data incorrect");
+        return;
+    }
+
+    p_read_data += data_len;
+
+    if (memcmp(p_read_data, "____", HALF_PADDING_SIZE) != 0) {
+        TEST_FAIL("Read data contains illegal post-data");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - Zero data length, zero offset
+ * - Zero data length, non-zero offset
+ */
+TFM_SST_NS_TEST(1007, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t write_len = WRITE_DATA_SIZE;
+    const uint32_t read_len = 0;
+    uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_set(uid, write_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get zero data from zero offset */
+    status = psa_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail with zero data len");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should be equal to original read data");
+        return;
+    }
+
+    offset = 5;
+
+    /* Get zero data from non-zero offset */
+    status = psa_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (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_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - Unset UID
+ * - Invalid UID
+ */
+TFM_SST_NS_TEST(1008, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const uint32_t data_len = 1;
+    const uint32_t offset = 0;
+    uint8_t read_data[] = READ_DATA;
+
+    /* Get with UID that has not yet been set */
+    status = psa_ps_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get succeeded with non-existant UID");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data not equal to original read data");
+        return;
+    }
+
+    /* Get with invalid UID */
+    status = psa_ps_get(INVALID_UID, offset, data_len,
+                        read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Get succeeded with invalid UID");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data not equal to original read data");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - Offset greater than UID length
+ * - Data length greater than UID length
+ * - Data length + offset greater than UID length
+ * - Invalid data len and offset
+ */
+TFM_SST_NS_TEST(1009, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t write_len = WRITE_DATA_SIZE;
+    uint32_t read_len;
+    uint32_t offset;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_set(uid, write_len, write_data, flags);
+    if (status != PSA_PS_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_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_OFFSET_INVALID) {
+        TEST_FAIL("Get should not succeed with offset too large");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 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_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_INCORRECT_SIZE) {
+        TEST_FAIL("Get should not succeed with data length too large");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should be equal to original read data");
+        return;
+    }
+
+    /* Get with offset + data length greater than UID's length, but individually
+     * valid
+     */
+    read_len = write_len;
+    offset = 1;
+
+    status = psa_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_INCORRECT_SIZE) {
+        TEST_FAIL("Get should not succeed with offset + data length too large");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should be equal to original read data");
+        return;
+    }
+
+    /* Get with data length and offset set to invalid values */
+    read_len = INVALID_DATA_LEN;
+    offset = INVALID_OFFSET;
+
+    status = psa_ps_get(uid, offset, read_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Get should not succeed with invalid arguments");
+        return;
+    }
+
+    /* Check that the read data is unchanged */
+    if (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_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with:
+ * - NULL data pointer
+ */
+TFM_SST_NS_TEST(1010, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get with NULL data pointer */
+    status = psa_ps_get(uid, offset, data_len, NULL);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Get should not succeed with NULL data pointer");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with:
+ * - Write once UID
+ */
+TFM_SST_NS_TEST(1011, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = WRITE_ONCE_UID;
+    struct psa_ps_info_t info = {0};
+
+    /* Get info for write once UID */
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_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.flags != PSA_PS_FLAG_WRITE_ONCE) {
+        TEST_FAIL("Flags incorrect for write once UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with:
+ * - Valid UID
+ */
+TFM_SST_NS_TEST(1012, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    struct psa_ps_info_t info = {0};
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get info for valid UID */
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_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.flags != flags) {
+        TEST_FAIL("Flags incorrect for valid UID");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with:
+ * - Unset UID
+ * - Invalid UID
+ */
+TFM_SST_NS_TEST(1013, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    struct psa_ps_info_t info = {0};
+
+    /* Get info with UID that has not yet been set */
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        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;
+    }
+
+    if (info.flags != 0) {
+        TEST_FAIL("Flags should not have changed");
+        return;
+    }
+
+    /* Get info with invalid UID */
+    status = psa_ps_get_info(INVALID_UID, &info);
+    if (status != PSA_PS_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.flags != 0) {
+        TEST_FAIL("Flags should not have changed");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with:
+ * - NULL info pointer
+ */
+TFM_SST_NS_TEST(1014, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get info with NULL info pointer */
+    status = psa_ps_get_info(uid, NULL);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Get info should not succeed with NULL info pointer");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests remove function with:
+ * - Valid UID
+ */
+TFM_SST_NS_TEST(1015, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    struct psa_ps_info_t info = {0};
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Call remove with valid ID */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    /* Check that get info fails for removed UID */
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get info should not succeed with removed UID");
+        return;
+    }
+
+    /* Check that get fails for removed UID */
+    status = psa_ps_get(uid, offset, data_len, read_data);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get should not succeed with removed UID");
+        return;
+    }
+
+    /* Check that remove fails for removed UID */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Remove should not succeed with removed UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests remove function with:
+ * - Write once UID
+ */
+TFM_SST_NS_TEST(1016, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = WRITE_ONCE_UID;
+
+    /* Call remove with write once UID */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_ERROR_WRITE_ONCE) {
+        TEST_FAIL("Remove should not succeed with write once UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests remove function with:
+ * - Invalid UID
+ */
+TFM_SST_NS_TEST(1017, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = INVALID_UID;
+
+    /* Call remove with an invalid UID */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_ERROR_INVALID_ARGUMENT) {
+        TEST_FAIL("Remove should not succeed with invalid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+#ifdef TFM_NS_CLIENT_IDENTIFICATION
+/**
+ * \brief Sets UID with a valid thread name.
+ */
+static void tfm_sst_test_1018_task_1(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Calls get with an invalid thread name.
+ */
+static void tfm_sst_test_1018_task_2(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint32_t offset = 0;
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_get(uid, offset, data_len, read_data);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get should not succeed with invalid thread name");
+        return;
+    }
+
+    /* Check that read data has not been modified */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should not have changed");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Removes UID with a valid thread name to clean up storage.
+ */
+static void tfm_sst_test_1018_task_3(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get function with an invalid thread name.
+ */
+static void tfm_sst_test_1018(struct test_result_t *ret)
+{
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1018_task_1);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test(INVALID_THREAD_NAME, ret, tfm_sst_test_1018_task_2);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1018_task_3);
+}
+
+/**
+ * \brief Sets UID with a valid thread name.
+ */
+static void tfm_sst_test_1019_task_1(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Calls get info with an invalid thread name.
+ */
+static void tfm_sst_test_1019_task_2(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    struct psa_ps_info_t info = {0};
+
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get info should not succeed with invalid thread name");
+        return;
+    }
+
+    /* Check that info has not been modified */
+    if (info.size != 0 || info.flags != 0) {
+        TEST_FAIL("Info should not have changed");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Removes UID with a valid thread name to clean up storage.
+ */
+static void tfm_sst_test_1019_task_3(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get info function with an invalid thread name.
+ */
+static void tfm_sst_test_1019(struct test_result_t *ret)
+{
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1019_task_1);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test(INVALID_THREAD_NAME, ret, tfm_sst_test_1019_task_2);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1019_task_3);
+}
+
+/**
+ * \brief Sets UID with a valid thread name.
+ */
+static void tfm_sst_test_1020_task_1(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint8_t write_data[] = WRITE_DATA;
+
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Calls remove with an invalid thread name.
+ */
+static void tfm_sst_test_1020_task_2(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Remove should not succeed with invalid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Removes UID with a valid thread name to clean up storage.
+ */
+static void tfm_sst_test_1020_task_3(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid thread name");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests remove function with an invalid thread name.
+ */
+static void tfm_sst_test_1020(struct test_result_t *ret)
+{
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1020_task_1);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test(INVALID_THREAD_NAME, ret, tfm_sst_test_1020_task_2);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1020_task_3);
+}
+
+/**
+ * \brief Sets UID with first thread.
+ */
+static void tfm_sst_test_1021_task_1(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint8_t write_data[] = "Thread A data";
+
+    status = psa_ps_set(uid, sizeof(write_data), write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Attempts to access same UID from second thread.
+ */
+static void tfm_sst_test_1021_task_2(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    struct psa_ps_info_t info = {0};
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+
+    /* Attempt to access the other thread's UID */
+    status = psa_ps_get(uid, offset, data_len, read_data);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get should not find another thread's UID");
+        return;
+    }
+
+    /* Check that read data has not been modified */
+    if (memcmp(read_data, READ_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should not have changed");
+        return;
+    }
+
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Get info should not find another thread's UID");
+        return;
+    }
+
+    /* Check that info has not been modified */
+    if (info.size != 0 || info.flags != 0) {
+        TEST_FAIL("Info should not have changed");
+        return;
+    }
+
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_ERROR_UID_NOT_FOUND) {
+        TEST_FAIL("Remove should not find another thread's UID");
+        return;
+    }
+
+    /* Create the same UID, but belonging to this thread */
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail with valid UID");
+        return;
+    }
+
+    status = psa_ps_get(uid, offset, data_len, read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail with valid UID");
+        return;
+    }
+
+    /* Check that the data read belongs to this thread, not the other one */
+    if (memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read data should be equal to result data");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Checks that first thread's UID has not been modified.
+ */
+static void tfm_sst_test_1021_task_3(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_3;
+    struct psa_ps_info_t info = {0};
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = "Thread A data";
+    uint8_t read_data[] = READ_DATA;
+    const uint32_t data_len = sizeof(write_data);
+
+    /* Check that first thread can still get info for UID */
+    status = psa_ps_get_info(uid, &info);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get info should not fail with valid UID");
+        return;
+    }
+
+    /* Check that first thread's UID info has not been modified */
+    if (info.size != data_len || info.flags != flags) {
+        TEST_FAIL("Info should be equal to original info");
+        return;
+    }
+
+    /* Check that first thread can still get UID */
+    status = psa_ps_get(uid, offset, data_len, read_data);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail with valid UID");
+        return;
+    }
+
+    /* Check that first thread's UID data has not been modified */
+    if (memcmp(read_data, write_data, data_len) != 0) {
+        TEST_FAIL("Read data should be equal to original write data");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail with valid UID");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests attempting to access UID belonging to another thread.
+ */
+static void tfm_sst_test_1021(struct test_result_t *ret)
+{
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1021_task_1);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_B", ret, tfm_sst_test_1021_task_2);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1021_task_3);
+}
+
+/**
+ * \brief Sets TEST_UID_1 from Thread_A.
+ */
+static void tfm_sst_test_1022_task_1(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint8_t write_data[] = "A";
+
+    status = psa_ps_set(uid, sizeof(write_data), write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should succeed for Thread_A");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Sets TEST_UID_1 from Thread_B.
+ */
+static void tfm_sst_test_1022_task_2(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint8_t write_data[] = "B";
+
+    status = psa_ps_set(uid, sizeof(write_data), write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should succeed for Thread_B");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Sets TEST_UID_1 again from Thread_A.
+ */
+static void tfm_sst_test_1022_task_3(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint8_t write_data[] = "HELLO";
+
+    status = psa_ps_set(uid, sizeof(write_data), write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Second set should succeed for Thread_A");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Sets TEST_UID_1 again from Thread_B.
+ */
+static void tfm_sst_test_1022_task_4(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint8_t write_data[] = "WORLD_1234";
+
+    status = psa_ps_set(uid, sizeof(write_data), write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Second set should succeed for Thread_B");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Gets TEST_UID_1 from Thread_A.
+ */
+static void tfm_sst_test_1022_task_5(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = "HELLO";
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_get(uid, offset, sizeof(write_data), read_data);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should succeed for Thread_A");
+        return;
+    }
+
+    /* Check that UID contains Thread_A's data */
+    if (memcmp(read_data, write_data, sizeof(write_data)) != 0) {
+        TEST_FAIL("Read data incorrect for Thread_A");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Gets TEST_UID_1 from Thread_B.
+ */
+static void tfm_sst_test_1022_task_6(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const uint32_t offset = 0;
+    const uint8_t write_data[] = "WORLD_1234";
+    uint8_t read_data[] = READ_DATA;
+
+    status = psa_ps_get(uid, offset, sizeof(write_data), read_data);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should succeed for Thread_B");
+        return;
+    }
+
+    /* Check that UID contains Thread_B's data */
+    if (memcmp(read_data, write_data, sizeof(write_data)) != 0) {
+        TEST_FAIL("Read data incorrect for Thread_B");
+        return;
+    }
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should work form Thread_B");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Calls removes from Thread_B to clean up storage for the next test.
+ */
+static void tfm_sst_test_1022_task_7(struct test_result_t *ret)
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_1;
+
+    /* Call remove to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should work form Thread_B");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests writing data to a UID alternately from two threads before
+ *        read-back.
+ */
+static void tfm_sst_test_1022(struct test_result_t *ret)
+{
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1022_task_1);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_B", ret, tfm_sst_test_1022_task_2);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1022_task_3);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_B", ret, tfm_sst_test_1022_task_4);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1022_task_5);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_B", ret, tfm_sst_test_1022_task_6);
+    if (ret->val != TEST_PASSED) {
+        return;
+    }
+
+    tfm_sst_run_test("Thread_A", ret, tfm_sst_test_1022_task_7);
+}
+#endif /* TFM_NS_CLIENT_IDENTIFICATION */
+
+/**
+ * \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.
+ */
+TFM_SST_NS_TEST(1023, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid_1 = TEST_UID_2;
+    const psa_ps_uid_t uid_2 = TEST_UID_3;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len_2 = WRITE_DATA_SIZE;
+    const uint32_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;
+
+    /* Set UID 1 */
+    status = psa_ps_set(uid_1, sizeof(write_data_1), write_data_1, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail for UID 1");
+        return;
+    }
+
+    /* Set UID 2 */
+    status = psa_ps_set(uid_2, data_len_2, write_data_2, flags);
+    if (status != PSA_PS_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_ps_remove(uid_1);
+    if (status != PSA_PS_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_ps_get(uid_2, offset, data_len_2,
+                        read_data + HALF_PADDING_SIZE);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail for UID 2");
+        return;
+    }
+
+    if (memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read buffer has incorrect data");
+        return;
+    }
+
+    /* Remove UID 2 to clean up storage for the next test */
+    status = psa_ps_remove(uid_2);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail for UID 2");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests set and multiple partial gets.
+ */
+TFM_SST_NS_TEST(1024, "Thread_A")
+{
+    psa_ps_status_t status;
+    uint32_t i;
+    const psa_ps_uid_t uid = TEST_UID_1;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_t data_len = WRITE_DATA_SIZE;
+    uint32_t offset = 0;
+    const uint8_t write_data[] = WRITE_DATA;
+    uint8_t read_data[] = READ_DATA;
+
+    /* Set the entire data into UID */
+    status = psa_ps_set(uid, data_len, write_data, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Set should not fail");
+        return;
+    }
+
+    /* Get the data from UID one byte at a time */
+    for (i = 0; i < data_len; ++i) {
+        status = psa_ps_get(uid, offset, 1,
+                            (read_data + HALF_PADDING_SIZE + i));
+        if (status != PSA_PS_SUCCESS) {
+            TEST_FAIL("Get should not fail for partial read");
+            return;
+        }
+
+        ++offset;
+    }
+
+    if (memcmp(read_data, RESULT_DATA, sizeof(read_data)) != 0) {
+        TEST_FAIL("Read buffer has incorrect data");
+        return;
+    }
+
+    /* Remove UID to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests multiple sets to the same UID.
+ */
+TFM_SST_NS_TEST(1025, "Thread_A")
+{
+    psa_ps_status_t status;
+    const psa_ps_uid_t uid = TEST_UID_2;
+    const psa_ps_create_flags_t flags = PSA_PS_FLAG_NONE;
+    const uint32_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;
+
+    /* Set write data 1 into UID */
+    status = psa_ps_set(uid, sizeof(write_data_1), write_data_1, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("First set should not fail");
+        return;
+    }
+
+    /* Set write data 2 into UID */
+    status = psa_ps_set(uid, sizeof(write_data_2), write_data_2, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Second set should not fail");
+        return;
+    }
+
+    /* Set write data 3 into UID */
+    status = psa_ps_set(uid, sizeof(write_data_3), write_data_3, flags);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Third set should not fail");
+        return;
+    }
+
+    status = psa_ps_get(uid, offset, sizeof(write_data_3), read_data);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Get should not fail");
+        return;
+    }
+
+    /* Check that get returns the last data to be set */
+    if (memcmp(read_data, write_data_3, sizeof(write_data_3)) != 0) {
+        TEST_FAIL("Read buffer has incorrect data");
+        return;
+    }
+
+    /* Remove UID to clean up storage for the next test */
+    status = psa_ps_remove(uid);
+    if (status != PSA_PS_SUCCESS) {
+        TEST_FAIL("Remove should not fail");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Tests get support function.
+ */
+TFM_SST_NS_TEST(1026, "Thread_A")
+{
+    uint32_t support_flags;
+
+    support_flags = psa_ps_get_support();
+    if (support_flags != 0) {
+        TEST_FAIL("Support flags should be 0");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
diff --git a/test/suites/sst/non_secure/sst_ns_tests.h b/test/suites/sst/non_secure/sst_ns_tests.h
index f7aa299..b742fc9 100644
--- a/test/suites/sst/non_secure/sst_ns_tests.h
+++ b/test/suites/sst/non_secure/sst_ns_tests.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -15,6 +15,13 @@
 #endif
 
 /**
+ * \brief Register testsuite for the PSA protected storage NS interface tests.
+ *
+ * \param[in] p_test_suite  The test suite to be executed.
+ */
+void register_testsuite_ns_psa_ps_interface(struct test_suite_t *p_test_suite);
+
+/**
  * \brief Register testsuite for the SST tests.
  *
  * \param[in] p_test_suite  The test suite to be executed.