samples: tfm: Add PSA Protected Storage sample

Add sample showing PSA Protected Storage API usage

Signed-off-by: Andreas Vibeto <andreas.vibeto@nordicsemi.no>
This commit is contained in:
Andreas Vibeto 2021-05-12 16:21:19 +02:00 committed by Ioannis Glaropoulos
parent 9143f4fd8c
commit 75dccbbbc7
5 changed files with 210 additions and 0 deletions

View File

@ -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
)

View File

@ -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

View File

@ -0,0 +1,7 @@
#
# Copyright (c) 2021 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_BUILD_WITH_TFM=y

View File

@ -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

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <sys/printk.h>
#include <psa/storage_common.h>
#include <psa/protected_storage.h>
#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;
}
}