diff --git a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt new file mode 100644 index 00000000000..ec34b3ccb74 --- /dev/null +++ b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Building TFM requires Cmake 3.15. +cmake_minimum_required(VERSION 3.15) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(protected_storage) + +target_sources(app PRIVATE src/main.c) + +target_include_directories(app PRIVATE + ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/trusted-firmware-m/interface/include +) diff --git a/samples/tfm_integration/psa_protected_storage/README.rst b/samples/tfm_integration/psa_protected_storage/README.rst new file mode 100644 index 00000000000..b32ebc02cdd --- /dev/null +++ b/samples/tfm_integration/psa_protected_storage/README.rst @@ -0,0 +1,71 @@ +.. psa_protected_storage: + +PSA Protected Storage +##################### + +Overview +******** + +This sample demonstrates how the Protected Storage (PS) API can be used for storing data. + +Protected storage provides a key/value storage interface where data is (by default) encrypted, with +optional authentication and rollback protection. The default crypto algorithm is ``AES-128-GCM``. +The encryption key is derived from the Hardware Unique Key (HUK), which is often set via device +fuses, etc. + +Using the PS API, this sample stores data to non-volatile storage. The sample shows how data can +be stored to and read from UIDs, and how overwrite protection can be enabled using flags. + +TF-M includes a maximum number of PS records, set via ``PS_NUM_ASSETS`` (default 10 as of +TF-M 1.3), and a maximum record size, set via ``PS_MAX_ASSET_SIZE`` (default of 2048 as of +TF-M 1.3.0). These defaults may be different depending on the platform being used, the current +value will be printed by the build system during the TF-M compilation step. + +More information about Protected Storage can be found in the Platform Security Architecture (PSA) +Secure Storage API: https://developer.arm.com/architectures/architecture-security-features/platform-security + +This sample is available for platforms that are supported in the trusted-firmware-m repo: +https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/ +See sample.yaml for a list of supported platforms. + +Building and Running +******************** + +On Target +========= + +Refer to :ref:`tfm_psa_level_1` for detailed instructions. + +Note that the board needs to be completely erased before programming the sample, as the flash area +used might contain data from before. The board must also be erased between each time the sample is +run as the overwrite protection will not be removed with a power reset. + +On QEMU +======== + +Refer to :ref:`tfm_ipc` for detailed instructions. +Following is an example based on ``west build`` + + .. code-block:: bash + + $ west build samples/tfm_integration/psa_protected_storage/ -p -b mps2_an521_nonsecure -t run + +Sample Output +============= + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v2.5.0-2791-g5585355dde0c *** + TF-M Protected Storage sample started. PSA Protected Storage API Version 1.0 + Writing data to UID1: The quick brown fox jumps over the lazy dog + Info on data stored in UID1: + - Size: 16 + - Capacity: 0x42 + - Flags: 0x 0 + Read and compare data stored in UID1 + Data stored in UID1: The quick brown fox jumps over the lazy dog + Overwriting data stored in UID1 with: Lorem ipsum dolor sit amet + Writing data to UID2 with overwrite protection: The quick brown fox jumps over the lazy dog + Attempting to write 'The quick brown fox jumps over the lazy dog' to UID2 + Got expected error (PSA_ERROR_NOT_PERMITTED) when writing to protected UID + Removing UID1 diff --git a/samples/tfm_integration/psa_protected_storage/prj.conf b/samples/tfm_integration/psa_protected_storage/prj.conf new file mode 100644 index 00000000000..811b3048d10 --- /dev/null +++ b/samples/tfm_integration/psa_protected_storage/prj.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BUILD_WITH_TFM=y diff --git a/samples/tfm_integration/psa_protected_storage/sample.yaml b/samples/tfm_integration/psa_protected_storage/sample.yaml new file mode 100644 index 00000000000..f5d8a51f5a2 --- /dev/null +++ b/samples/tfm_integration/psa_protected_storage/sample.yaml @@ -0,0 +1,25 @@ +sample: + description: Protected Storage API sample + name: PSA Protected Storage +common: + tags: psa + platform_allow: mps2_an521_nonsecure v2m_musca_s1_nonsecure + nrf5340dk_nrf5340_cpuappns nrf9160dk_nrf9160ns bl5340_dvk_cpuappns + harness: console + harness_config: + type: multi_line + regex: + - "Protected Storage sample started" + - "PSA Protected Storage API Version [0-9]*.[0-9]*" + - "Writing data to UID1: .*" + - "Info on data stored in UID1:" + - "- Size: [0-9]*" + - "- Capacity: 0x[0-9a-f]*" + - "- Flags: 0x[0-9-a-f]*" + - "Got expected error \\(PSA_ERROR_NOT_PERMITTED\\) when writing to protected UID" + - "Removing UID1" + +tests: + sample.tfm.protected_storage: + extra_args: "CONFIG_TEST=y" + tags: tfm ci_build diff --git a/samples/tfm_integration/psa_protected_storage/src/main.c b/samples/tfm_integration/psa_protected_storage/src/main.c new file mode 100644 index 00000000000..303bfbb4abb --- /dev/null +++ b/samples/tfm_integration/psa_protected_storage/src/main.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define TEST_STRING_1 "The quick brown fox jumps over the lazy dog" +#define TEST_STRING_2 "Lorem ipsum dolor sit amet" + +void main(void) +{ + psa_status_t status = 0; + + printk("Protected Storage sample started.\n"); + printk("PSA Protected Storage API Version %d.%d\n", + PSA_PS_API_VERSION_MAJOR, PSA_PS_API_VERSION_MINOR); + + printk("Writing data to UID1: %s\n", TEST_STRING_1); + psa_storage_uid_t uid1 = 1; + psa_storage_create_flags_t uid1_flag = PSA_STORAGE_FLAG_NONE; + + status = psa_ps_set(uid1, sizeof(TEST_STRING_1), TEST_STRING_1, uid1_flag); + if (status != PSA_SUCCESS) { + printk("Failed to store data! (%d)\n", status); + return; + } + + /* Get info on UID1 */ + struct psa_storage_info_t uid1_info; + + status = psa_ps_get_info(uid1, &uid1_info); + if (status != PSA_SUCCESS) { + printk("Failed to get info! (%d)\n", status); + return; + } + printk("Info on data stored in UID1:\n"); + printk("- Size: %d\n", uid1_info.size); + printk("- Capacity: 0x%2x\n", uid1_info.capacity); + printk("- Flags: 0x%2x\n", uid1_info.flags); + + printk("Read and compare data stored in UID1\n"); + size_t bytes_read; + char stored_data[sizeof(TEST_STRING_1)]; + + status = psa_ps_get(uid1, 0, sizeof(TEST_STRING_1), &stored_data, &bytes_read); + if (status != PSA_SUCCESS) { + printk("Failed to get data stored in UID1! (%d)\n", status); + return; + } + printk("Data stored in UID1: %s\n", stored_data); + + printk("Overwriting data stored in UID1: %s\n", TEST_STRING_2); + status = psa_ps_set(uid1, sizeof(TEST_STRING_2), TEST_STRING_2, uid1_flag); + if (status != PSA_SUCCESS) { + printk("Failed to overwrite UID1! (%d)\n", status); + return; + } + + printk("Writing data to UID2 with overwrite protection: %s\n", TEST_STRING_1); + psa_storage_uid_t uid2 = 2; + psa_storage_create_flags_t uid2_flag = PSA_STORAGE_FLAG_WRITE_ONCE; + + status = psa_ps_set(uid2, sizeof(TEST_STRING_1), TEST_STRING_1, uid2_flag); + if (status != PSA_SUCCESS) { + printk("Failed to set write once flag! (%d)\n", status); + return; + } + + printk("Attempting to write '%s' to UID2\n", TEST_STRING_2); + status = psa_ps_set(uid2, sizeof(TEST_STRING_2), TEST_STRING_2, uid2_flag); + if (status != PSA_ERROR_NOT_PERMITTED) { + printk("Got unexpected status when overwriting! (%d)\n", status); + return; + } + printk("Got expected error (PSA_ERROR_NOT_PERMITTED) when writing to protected UID\n"); + + printk("Removing UID1\n"); + status = psa_ps_remove(uid1); + if (status != PSA_SUCCESS) { + printk("Failed to remove UID1! (%d)\n", status); + return; + } +}