From 2e6bc955f98468bffd862550b4ebb04d010d070b Mon Sep 17 00:00:00 2001 From: Tomi Fontanilles Date: Mon, 29 Jul 2024 14:15:05 +0300 Subject: [PATCH] secure_storage: introduce the secure storage subsystem Implements RFC https://github.com/zephyrproject-rtos/zephyr/issues/75275. See also the added documentation and the PR (https://github.com/zephyrproject-rtos/zephyr/pull/76222) for more information. Signed-off-by: Tomi Fontanilles --- MAINTAINERS.yml | 16 ++ doc/releases/release-notes-4.0.rst | 4 + doc/services/index.rst | 2 +- doc/services/secure_storage.rst | 119 +++++++++ doc/services/tfm/index.rst | 4 +- doc/zephyr.doxyfile.in | 3 +- modules/mbedtls/CMakeLists.txt | 5 +- modules/mbedtls/configs/config-tls-generic.h | 10 +- samples/index.rst | 1 + samples/psa/index.rst | 10 + samples/psa/its/CMakeLists.txt | 7 + samples/psa/its/README.rst | 67 +++++ samples/psa/its/overlay-entropy_driver.conf | 4 + .../psa/its/overlay-entropy_not_secure.conf | 5 + samples/psa/its/overlay-secure_storage.conf | 10 + samples/psa/its/prj.conf | 4 + samples/psa/its/sample.yaml | 31 +++ samples/psa/its/src/main.c | 128 ++++++++++ samples/psa/persistent_key/CMakeLists.txt | 7 + samples/psa/persistent_key/README.rst | 70 +++++ .../overlay-entropy_driver.conf | 4 + .../overlay-entropy_not_secure.conf | 5 + .../overlay-secure_storage.conf | 10 + samples/psa/persistent_key/prj.conf | 8 + samples/psa/persistent_key/sample.yaml | 31 +++ samples/psa/persistent_key/src/main.c | 123 +++++++++ subsys/CMakeLists.txt | 1 + subsys/Kconfig | 1 + subsys/secure_storage/CMakeLists.txt | 48 ++++ subsys/secure_storage/Kconfig | 102 ++++++++ subsys/secure_storage/Kconfig.its_store | 34 +++ subsys/secure_storage/Kconfig.its_transform | 134 ++++++++++ .../internal/zephyr/secure_storage/common.h | 19 ++ .../internal/zephyr/secure_storage/its.h | 31 +++ .../zephyr/secure_storage/its/common.h | 30 +++ .../zephyr/secure_storage/its/store.h | 52 ++++ .../zephyr/secure_storage/its/transform.h | 62 +++++ .../secure_storage/its/transform/aead_get.h | 45 ++++ .../internal/zephyr/secure_storage/ps.h | 39 +++ subsys/secure_storage/include/psa/error.h | 29 +++ .../include/psa/internal_trusted_storage.h | 126 +++++++++ .../include/psa/protected_storage.h | 241 ++++++++++++++++++ .../include/psa/storage_common.h | 51 ++++ subsys/secure_storage/src/CMakeLists.txt | 6 + subsys/secure_storage/src/its/CMakeLists.txt | 29 +++ .../secure_storage/src/its/implementation.c | 228 +++++++++++++++++ .../secure_storage/src/its/store_settings.c | 112 ++++++++ .../secure_storage/src/its/transform/aead.c | 131 ++++++++++ .../src/its/transform/aead_get.c | 144 +++++++++++ subsys/secure_storage/src/log.c | 6 + .../secure_storage/psa/crypto/CMakeLists.txt | 5 + .../psa/crypto/overlay-secure_storage.conf | 12 + .../subsys/secure_storage/psa/crypto/prj.conf | 4 + .../secure_storage/psa/crypto/src/main.c | 125 +++++++++ .../secure_storage/psa/crypto/testcase.yaml | 14 + .../secure_storage/psa/its/CMakeLists.txt | 11 + .../psa/its/overlay-custom_store.conf | 1 + .../psa/its/overlay-custom_transform.conf | 5 + .../psa/its/overlay-default_store.conf | 2 + .../psa/its/overlay-default_transform.conf | 8 + .../psa/its/overlay-secure_storage.conf | 4 + .../secure_storage/psa/its/overlay-tfm.conf | 2 + tests/subsys/secure_storage/psa/its/prj.conf | 1 + .../secure_storage/psa/its/src/custom_store.c | 73 ++++++ .../psa/its/src/custom_transform.c | 33 +++ .../subsys/secure_storage/psa/its/src/main.c | 134 ++++++++++ .../secure_storage/psa/its/testcase.yaml | 32 +++ 67 files changed, 2845 insertions(+), 10 deletions(-) create mode 100644 doc/services/secure_storage.rst create mode 100644 samples/psa/index.rst create mode 100644 samples/psa/its/CMakeLists.txt create mode 100644 samples/psa/its/README.rst create mode 100644 samples/psa/its/overlay-entropy_driver.conf create mode 100644 samples/psa/its/overlay-entropy_not_secure.conf create mode 100644 samples/psa/its/overlay-secure_storage.conf create mode 100644 samples/psa/its/prj.conf create mode 100644 samples/psa/its/sample.yaml create mode 100644 samples/psa/its/src/main.c create mode 100644 samples/psa/persistent_key/CMakeLists.txt create mode 100644 samples/psa/persistent_key/README.rst create mode 100644 samples/psa/persistent_key/overlay-entropy_driver.conf create mode 100644 samples/psa/persistent_key/overlay-entropy_not_secure.conf create mode 100644 samples/psa/persistent_key/overlay-secure_storage.conf create mode 100644 samples/psa/persistent_key/prj.conf create mode 100644 samples/psa/persistent_key/sample.yaml create mode 100644 samples/psa/persistent_key/src/main.c create mode 100644 subsys/secure_storage/CMakeLists.txt create mode 100644 subsys/secure_storage/Kconfig create mode 100644 subsys/secure_storage/Kconfig.its_store create mode 100644 subsys/secure_storage/Kconfig.its_transform create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/common.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/its.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform/aead_get.h create mode 100644 subsys/secure_storage/include/internal/zephyr/secure_storage/ps.h create mode 100644 subsys/secure_storage/include/psa/error.h create mode 100644 subsys/secure_storage/include/psa/internal_trusted_storage.h create mode 100644 subsys/secure_storage/include/psa/protected_storage.h create mode 100644 subsys/secure_storage/include/psa/storage_common.h create mode 100644 subsys/secure_storage/src/CMakeLists.txt create mode 100644 subsys/secure_storage/src/its/CMakeLists.txt create mode 100644 subsys/secure_storage/src/its/implementation.c create mode 100644 subsys/secure_storage/src/its/store_settings.c create mode 100644 subsys/secure_storage/src/its/transform/aead.c create mode 100644 subsys/secure_storage/src/its/transform/aead_get.c create mode 100644 subsys/secure_storage/src/log.c create mode 100644 tests/subsys/secure_storage/psa/crypto/CMakeLists.txt create mode 100644 tests/subsys/secure_storage/psa/crypto/overlay-secure_storage.conf create mode 100644 tests/subsys/secure_storage/psa/crypto/prj.conf create mode 100644 tests/subsys/secure_storage/psa/crypto/src/main.c create mode 100644 tests/subsys/secure_storage/psa/crypto/testcase.yaml create mode 100644 tests/subsys/secure_storage/psa/its/CMakeLists.txt create mode 100644 tests/subsys/secure_storage/psa/its/overlay-custom_store.conf create mode 100644 tests/subsys/secure_storage/psa/its/overlay-custom_transform.conf create mode 100644 tests/subsys/secure_storage/psa/its/overlay-default_store.conf create mode 100644 tests/subsys/secure_storage/psa/its/overlay-default_transform.conf create mode 100644 tests/subsys/secure_storage/psa/its/overlay-secure_storage.conf create mode 100644 tests/subsys/secure_storage/psa/its/overlay-tfm.conf create mode 100644 tests/subsys/secure_storage/psa/its/prj.conf create mode 100644 tests/subsys/secure_storage/psa/its/src/custom_store.c create mode 100644 tests/subsys/secure_storage/psa/its/src/custom_transform.c create mode 100644 tests/subsys/secure_storage/psa/its/src/main.c create mode 100644 tests/subsys/secure_storage/psa/its/testcase.yaml diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 0e168504467ae8a..8bd9581adf65538 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4115,6 +4115,20 @@ RTIO: tests: - rtio +Secure storage: + status: maintained + maintainers: + - tomi-font + files: + - subsys/secure_storage/ + - samples/psa/ + - doc/services/secure_storage.rst + - tests/subsys/secure_storage/ + labels: + - "area: Secure storage" + tests: + - psa.secure_storage + Storage: status: odd fixes files: @@ -4916,6 +4930,7 @@ West: tests: - benchmark.crypto.mbedtls - crypto.mbedtls + - psa.secure_storage "West project: mcuboot": status: maintained @@ -5089,6 +5104,7 @@ West: - "area: TF-M" tests: - trusted-firmware-m + - psa.secure_storage "West project: tf-m-tests": status: maintained diff --git a/doc/releases/release-notes-4.0.rst b/doc/releases/release-notes-4.0.rst index 8ac2713e701adf3..d70894d9225df09 100644 --- a/doc/releases/release-notes-4.0.rst +++ b/doc/releases/release-notes-4.0.rst @@ -9,6 +9,10 @@ We are pleased to announce the release of Zephyr version 4.0.0. Major enhancements with this release include: +* The introduction of the :ref:`secure storage` subsystem. It allows the use of the + PSA Secure Storage API and of persistent keys in the PSA Crypto API on all board targets. It + is now the standard way to provide device-specific protection to data at rest. ((:github:`76222`)) + An overview of the changes required or recommended when migrating your application from Zephyr v3.7.0 to Zephyr v4.0.0 can be found in the separate :ref:`migration guide`. diff --git a/doc/services/index.rst b/doc/services/index.rst index d900f110a65af4f..d3651b40f6b6390 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -6,7 +6,6 @@ OS Services .. toctree:: :maxdepth: 1 - binary_descriptors/index.rst console.rst crypto/index @@ -29,6 +28,7 @@ OS Services portability/index.rst poweroff.rst profiling/index.rst + secure_storage.rst shell/index.rst serialization/index.rst settings/index.rst diff --git a/doc/services/secure_storage.rst b/doc/services/secure_storage.rst new file mode 100644 index 000000000000000..5f7b90943b6fdcf --- /dev/null +++ b/doc/services/secure_storage.rst @@ -0,0 +1,119 @@ +.. _secure_storage: + +Secure storage +############## + +| The secure storage subsystem provides an implementation of the functions defined in the + `Platform Security Architecture (PSA) Secure Storage API `_. +| It can be enabled on :term:`board targets` + that don't already have an implementation of the API. + +Overview +******** + +The secure storage subsystem makes the PSA Secure Storage API available on all board targets with +non-volatile memory support. +As such, it provides an implementation of the API on those that don't already have one, ensuring +functional support for the API. +Board targets with :ref:`tfm` enabled (ending in ``/ns``), for instance, +cannot enable the subsystem because TF-M already provides an implementation of the API. + +| In addition to providing functional support for the API, depending on + device-specific security features and the configuration, the subsystem + may secure the data stored via the PSA Secure Storage API at rest. +| Keep in mind, however, that it's preferable to use a secure processing environment like TF-M when + possible because it's able to provide more security due to isolation guarantees. + +Limitations +*********** + +The secure storage subsystem's implementation of the PSA Secure Storage API: + +* does not aim at full compliance with the specification. + + | Its foremost goal is functional support for the API on all board targets. + | See below for important ways the implementation deviates from the specification. + +* does not guarantee that the data it stores will be secure at rest in all cases. + + This depends on device-specific security features and the configuration. + +* does not yet provide an implementation of the Protected Storage (PS) API as of this writing. + + Instead, the PS API directly calls into the Internal Trusted Storage (ITS) API + (unless a `custom implementation <#whole-api>`_ of the PS API is provided). + +Below are some ways the implementation deviates from the specification +and an explanation why. This is not an exhaustive list. + +* The data stored in the ITS is by default encrypted and authenticated (Against ``1.`` in + `3.2. Internal Trusted Storage requirements `_.) + + | The specification considers the storage underlying the ITS to be + ``implicitly confidential and protected from replay`` + (`2.4. The Internal Trusted Storage API `_) + because ``most embedded microprocessors (MCU) have on-chip flash storage that can be made + inaccessible except to software running on the MCU`` + (`2.2. Technical Background `_). + | This is not the case on all MCUs. Thus, additional protection is provided to the stored data. + + However, this does not guarantee that the data stored will be secure at rest in all cases, + because this depends on device-specific security features and the configuration. + It requires a random entropy source and especially a secure encryption key provider + (:kconfig:option:`CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER`). + + In addition, the data stored in the ITS is not protected against replay attacks, + because this requires storage that is protected by hardware. + +* The data stored via the PSA Secure Storage API is not protected from direct + read/write by software or debugging. (Against ``2.`` and ``10.`` in + `3.2. Internal Trusted Storage requirements `_.) + + It is only secured at rest. Protecting it at runtime as well + requires specific hardware mechanisms to support this. + +Configuration +************* + +To configure the implementation of the PSA Secure Storage API provided by Zephyr, have a look at the +``CONFIG_SECURE_STORAGE_.*`` Kconfig options. They are defined in the various Kconfig files found +under ``subsys/secure_storage/``. + +Customization +************* + +Custom implementations can also replace those of Zephyr at different levels +if the functionality provided by the existing implementations isn't enough. + +Whole API +========= + +If you already have an implementation of the whole ITS or PS API and want to make use of it, you +can do so by enabling the following Kconfig option and implementing the relevant functions: + +* :kconfig:option:`CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_CUSTOM`, for the ITS API. +* :kconfig:option:`CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_CUSTOM`, for the PS API. + +ITS API +======= + +Zephyr's implementation of the ITS API +(:kconfig:option:`CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR`) +makes use of the ITS transform and store modules, which can be configured and customized separately. +Have a look at the ``CONFIG_SECURE_STORAGE_ITS_(STORE|TRANSFORM)_.*_CUSTOM`` +Kconfig options to see the different customization possibilities. + +It's especially recommended to implement a custom encryption key provider +(:kconfig:option:`CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM`) +that is more secure than the available options, if possible. + +Samples +******* + +* :zephyr:code-sample:`persistent_key` +* :zephyr:code-sample:`psa_its` + +PSA Secure Storage API reference +******************************** + +.. doxygengroup:: psa_secure_storage diff --git a/doc/services/tfm/index.rst b/doc/services/tfm/index.rst index e957ae0d5da91f0..9417648e688613d 100644 --- a/doc/services/tfm/index.rst +++ b/doc/services/tfm/index.rst @@ -1,7 +1,7 @@ .. _tfm: -Trusted Firmware-M -################## +Trusted Firmware-M (TF-M) +######################### .. toctree:: :maxdepth: 1 diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index fa59b29dee60eca..400a59570177f4d 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -977,7 +977,8 @@ INPUT = @ZEPHYR_BASE@/doc/_doxygen/mainpage.md \ @ZEPHYR_BASE@/include/ \ @ZEPHYR_BASE@/lib/libc/minimal/include/ \ @ZEPHYR_BASE@/subsys/testsuite/include/ \ - @ZEPHYR_BASE@/subsys/testsuite/ztest/include/ + @ZEPHYR_BASE@/subsys/testsuite/ztest/include/ \ + @ZEPHYR_BASE@/subsys/secure_storage/include/ \ # This tag can be used to specify the character encoding of the source files # that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index aab4ad5316cf571..c8caa1fd9f65592 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -136,7 +136,7 @@ zephyr_interface_library_named(mbedTLS) zephyr_library_named(mbedTLSCrypto) - if (CONFIG_MBEDTLS_PSA_CRYPTO_C AND NOT CONFIG_BUILD_WITH_TFM) + if (CONFIG_MBEDTLS_PSA_CRYPTO_C) list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_aead.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.c @@ -176,6 +176,9 @@ zephyr_interface_library_named(mbedTLS) zephyr_library_sources(${crypto_source}) + # Custom macro to tell that an mbedTLSCrypto source file is being compiled. + zephyr_library_compile_definitions(BUILDING_MBEDTLS_CRYPTO) + zephyr_library_link_libraries(mbedTLS) zephyr_library_link_libraries_ifdef(CONFIG_BUILD_WITH_TFM tfm_api) diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 404c5e423f97399..20073e64a020ef9 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -453,11 +453,12 @@ #define MBEDTLS_PSA_P256M_DRIVER_ENABLED #endif -#if defined(CONFIG_ARCH_POSIX) && !defined(CONFIG_PICOLIBC) -#define MBEDTLS_PSA_KEY_SLOT_COUNT 64 +#if defined(CONFIG_ARCH_POSIX) +#define MBEDTLS_PSA_KEY_SLOT_COUNT 64 /* for BLE Mesh tests */ +#endif + +#if defined(CONFIG_SECURE_STORAGE) #define MBEDTLS_PSA_CRYPTO_STORAGE_C -#define MBEDTLS_PSA_ITS_FILE_C -#define MBEDTLS_FS_IO #endif #endif /* CONFIG_MBEDTLS_PSA_CRYPTO_C */ @@ -470,7 +471,6 @@ #define MBEDTLS_PSA_CRYPTO_CLIENT #define MBEDTLS_PSA_CRYPTO_CONFIG #define MBEDTLS_PSA_CRYPTO_CONFIG_FILE "config-psa.h" - #endif #if defined(CONFIG_MBEDTLS_TLS_VERSION_1_2) && defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) diff --git a/samples/index.rst b/samples/index.rst index d8f28152c733d46..cc7ba812a3390fa 100644 --- a/samples/index.rst +++ b/samples/index.rst @@ -26,6 +26,7 @@ Samples and Demos cpp/* posix/* kernel/* + psa/* tfm_integration/tfm_integration.rst modules/* fuel_gauge/* diff --git a/samples/psa/index.rst b/samples/psa/index.rst new file mode 100644 index 000000000000000..8d54be639811da6 --- /dev/null +++ b/samples/psa/index.rst @@ -0,0 +1,10 @@ +PSA samples +########### + +The following samples demonstrate various uses of several of the `Platform Security Architecture (PSA) Certified APIs `_. + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/samples/psa/its/CMakeLists.txt b/samples/psa/its/CMakeLists.txt new file mode 100644 index 000000000000000..fbac539c4f0aee0 --- /dev/null +++ b/samples/psa/its/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(psa_its) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/psa/its/README.rst b/samples/psa/its/README.rst new file mode 100644 index 000000000000000..94bff4f47d9f378 --- /dev/null +++ b/samples/psa/its/README.rst @@ -0,0 +1,67 @@ +.. zephyr:code-sample:: psa_its + :name: PSA Internal Trusted Storage API + :relevant-api: psa_secure_storage + + Use the PSA ITS API. + +Overview +******** + +This sample demonstrates usage of the +`PSA Internal Trusted Storage (ITS) API `_, +which is part of the `PSA Secure Storage API `_, +for storing and retrieving persistent data. + +Requirements +************ + +An implementation of the PSA ITS API must be present for this sample to build. +It can be provided by: + +* :ref:`tfm`, for ``*/ns`` :term:`board targets`. +* The :ref:`secure storage subsystem `, for the other board targets. + +Building +******** + +This sample is located in :zephyr_file:`samples/psa/its`. + +Different configurations are defined in the :file:`sample.yaml` file. +You can use them to build the sample, depending on the PSA ITS provider, as follows: + +.. tabs:: + + .. tab:: TF-M + + For board targets with TF-M: + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/its + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.its.tfm + + .. tab:: secure storage subsystem + + For board targets without TF-M. + + If the board target to compile for has an entropy driver (preferable): + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/its + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.its.secure_storage.entropy_driver + + Or, to use an insecure entropy source (only for testing): + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/its + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.its.secure_storage.entropy_not_secure + +To flash it, see :ref:`west-flashing`. diff --git a/samples/psa/its/overlay-entropy_driver.conf b/samples/psa/its/overlay-entropy_driver.conf new file mode 100644 index 000000000000000..b2fea61e044a3c5 --- /dev/null +++ b/samples/psa/its/overlay-entropy_driver.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG=y diff --git a/samples/psa/its/overlay-entropy_not_secure.conf b/samples/psa/its/overlay-entropy_not_secure.conf new file mode 100644 index 000000000000000..2aba3a2c7e27d4a --- /dev/null +++ b/samples/psa/its/overlay-entropy_not_secure.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y +CONFIG_MBEDTLS_ENTROPY_POLL_ZEPHYR=y diff --git a/samples/psa/its/overlay-secure_storage.conf b/samples/psa/its/overlay-secure_storage.conf new file mode 100644 index 000000000000000..3473ae389101ab5 --- /dev/null +++ b/samples/psa/its/overlay-secure_storage.conf @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y + +# The default stack size (1024) is not enough for the PSA Crypto core. +# On top of that, the ITS implementation uses the stack for buffers. +CONFIG_MAIN_STACK_SIZE=3072 + +CONFIG_SECURE_STORAGE=y diff --git a/samples/psa/its/prj.conf b/samples/psa/its/prj.conf new file mode 100644 index 000000000000000..4c214a79a528c88 --- /dev/null +++ b/samples/psa/its/prj.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_LOG_DEFAULT_LEVEL=3 diff --git a/samples/psa/its/sample.yaml b/samples/psa/its/sample.yaml new file mode 100644 index 000000000000000..c4ee3543696a7be --- /dev/null +++ b/samples/psa/its/sample.yaml @@ -0,0 +1,31 @@ +sample: + name: PSA ITS API sample + description: Demonstration of PSA Internal Trusted Storage (ITS) API usage. +common: + tags: + - psa.secure_storage + timeout: 10 + harness: console + harness_config: + type: one_line + regex: + - "Sample finished successfully." +tests: + sample.psa.its.tfm: + filter: CONFIG_BUILD_WITH_TFM + tags: + - trusted-firmware-m + sample.psa.its.secure_storage.entropy_driver: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + and CONFIG_ENTROPY_HAS_DRIVER + extra_args: EXTRA_CONF_FILE=overlay-secure_storage.conf;overlay-entropy_driver.conf + tags: + - drivers.entropy + - settings + sample.psa.its.secure_storage.entropy_not_secure: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + and not CONFIG_ENTROPY_HAS_DRIVER + extra_args: EXTRA_CONF_FILE="overlay-secure_storage.conf;overlay-entropy_not_secure.conf" + tags: + - random + - settings diff --git a/samples/psa/its/src/main.c b/samples/psa/its/src/main.c new file mode 100644 index 000000000000000..47752f056585db3 --- /dev/null +++ b/samples/psa/its/src/main.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +LOG_MODULE_REGISTER(psa_its); + +#define SAMPLE_DATA_UID (psa_storage_uid_t)1 +#define SAMPLE_DATA_FLAGS PSA_STORAGE_FLAG_NONE + +#ifdef CONFIG_SECURE_STORAGE +#define SAMPLE_DATA_SIZE CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE +#else +#define SAMPLE_DATA_SIZE 128 +#endif + +static int write_and_read_data(void) +{ + LOG_INF("Writing to and reading back from ITS..."); + psa_status_t ret; + + /* Data to be written to ITS. */ + uint8_t p_data_write[SAMPLE_DATA_SIZE]; + + for (unsigned int i = 0; i != sizeof(p_data_write); ++i) { + p_data_write[i] = i; + } + + ret = psa_its_set(SAMPLE_DATA_UID, sizeof(p_data_write), p_data_write, SAMPLE_DATA_FLAGS); + if (ret != PSA_SUCCESS) { + LOG_ERR("Writing the data to ITS failed. (%d)", ret); + return -1; + } + + /* Data to be read from ITS. */ + uint8_t p_data_read[SAMPLE_DATA_SIZE]; + + /* Read back the data starting from an offset. */ + const size_t data_offset = SAMPLE_DATA_SIZE / 2; + + /* Number of bytes read. */ + size_t p_data_length = 0; + + ret = psa_its_get(SAMPLE_DATA_UID, data_offset, sizeof(p_data_read), p_data_read, + &p_data_length); + if (ret != PSA_SUCCESS) { + LOG_ERR("Reading back the data from ITS failed. (%d).", ret); + return -1; + } + + if (p_data_length != SAMPLE_DATA_SIZE - data_offset) { + LOG_ERR("Unexpected amount of bytes read back. (%zu != %zu)", + p_data_length, SAMPLE_DATA_SIZE - data_offset); + return -1; + } + + if (memcmp(p_data_write + data_offset, p_data_read, p_data_length)) { + LOG_HEXDUMP_INF(p_data_write + data_offset, p_data_length, "Data written:"); + LOG_HEXDUMP_INF(p_data_read, p_data_length, "Data read back:"); + LOG_ERR("The data read back doesn't match the data written."); + return -1; + } + + LOG_INF("Successfully wrote to ITS and read back what was written."); + return 0; +} + +static int read_info(void) +{ + LOG_INF("Reading the written entry's metadata..."); + psa_status_t ret; + + /* The entry's metadata. */ + struct psa_storage_info_t p_info; + + ret = psa_its_get_info(SAMPLE_DATA_UID, &p_info); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to retrieve the entry's metadata. (%d)", ret); + return -1; + } + + if (p_info.capacity != SAMPLE_DATA_SIZE + || p_info.size != SAMPLE_DATA_SIZE + || p_info.flags != SAMPLE_DATA_FLAGS) { + LOG_ERR("Entry metadata unexpected. (capacity:%zu size:%zu flags:0x%x)", + p_info.capacity, p_info.size, p_info.flags); + return -1; + } + + LOG_INF("Successfully read the entry's metadata."); + return 0; +} + +static int remove_entry(void) +{ + LOG_INF("Removing the entry from ITS..."); + psa_status_t ret; + + ret = psa_its_remove(SAMPLE_DATA_UID); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to remove the entry. (%d)", ret); + return -1; + } + + LOG_INF("Entry removed from ITS."); + return 0; +} + +int main(void) +{ + LOG_INF("PSA ITS sample started."); + + if (write_and_read_data()) { + return -1; + } + + if (read_info()) { + return -1; + } + + if (remove_entry()) { + return -1; + } + + LOG_INF("Sample finished successfully."); + return 0; +} diff --git a/samples/psa/persistent_key/CMakeLists.txt b/samples/psa/persistent_key/CMakeLists.txt new file mode 100644 index 000000000000000..2e9651aa6eef106 --- /dev/null +++ b/samples/psa/persistent_key/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(persistent_key) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/psa/persistent_key/README.rst b/samples/psa/persistent_key/README.rst new file mode 100644 index 000000000000000..bc92cbacb1df4e7 --- /dev/null +++ b/samples/psa/persistent_key/README.rst @@ -0,0 +1,70 @@ +.. zephyr:code-sample:: persistent_key + :name: PSA Crypto persistent key + + Manage and use persistent keys via the PSA Crypto API. + +Overview +******** + +This sample demonstrates usage of persistent keys in the :ref:`PSA Crypto API `. + +Requirements +************ + +In addition to the PSA Crypto API, an implementation of the +`PSA Internal Trusted Storage (ITS) API `_ +(for storage of the persistent keys) must be present for this sample to work. +It can be provided by: + +* :ref:`tfm`, for ``*/ns`` :term:`board targets`. +* The :ref:`secure storage subsystem `, for the other board targets. + +Building +******** + +This sample is located in :zephyr_file:`samples/psa/persistent_key`. + +Different configurations are defined in the :file:`sample.yaml` file. +You can use them to build the sample, depending on the PSA ITS provider, as follows: + +.. tabs:: + + .. tab:: TF-M + + For board targets with TF-M: + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/persistent_key + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.persistent_key.tfm + + .. tab:: secure storage subsystem + + For board targets without TF-M. + + If the board target to compile for has an entropy driver (preferable): + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/persistent_key + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.persistent_key.secure_storage.entropy_driver + + Or, to use an insecure entropy source (only for testing): + + .. zephyr-app-commands:: + :zephyr-app: samples/psa/persistent_key + :tool: west + :goals: build + :board: + :west-args: -T sample.psa.persistent_key.secure_storage.entropy_not_secure + +To flash it, see :ref:`west-flashing`. + +API reference +************* + +`PSA Crypto key management API reference `_ diff --git a/samples/psa/persistent_key/overlay-entropy_driver.conf b/samples/psa/persistent_key/overlay-entropy_driver.conf new file mode 100644 index 000000000000000..b2fea61e044a3c5 --- /dev/null +++ b/samples/psa/persistent_key/overlay-entropy_driver.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG=y diff --git a/samples/psa/persistent_key/overlay-entropy_not_secure.conf b/samples/psa/persistent_key/overlay-entropy_not_secure.conf new file mode 100644 index 000000000000000..2aba3a2c7e27d4a --- /dev/null +++ b/samples/psa/persistent_key/overlay-entropy_not_secure.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y +CONFIG_MBEDTLS_ENTROPY_POLL_ZEPHYR=y diff --git a/samples/psa/persistent_key/overlay-secure_storage.conf b/samples/psa/persistent_key/overlay-secure_storage.conf new file mode 100644 index 000000000000000..3473ae389101ab5 --- /dev/null +++ b/samples/psa/persistent_key/overlay-secure_storage.conf @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y + +# The default stack size (1024) is not enough for the PSA Crypto core. +# On top of that, the ITS implementation uses the stack for buffers. +CONFIG_MAIN_STACK_SIZE=3072 + +CONFIG_SECURE_STORAGE=y diff --git a/samples/psa/persistent_key/prj.conf b/samples/psa/persistent_key/prj.conf new file mode 100644 index 000000000000000..9e78a182bf46e3f --- /dev/null +++ b/samples/psa/persistent_key/prj.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_ASSERT=y + +CONFIG_PSA_WANT_KEY_TYPE_AES=y +CONFIG_PSA_WANT_ALG_CTR=y diff --git a/samples/psa/persistent_key/sample.yaml b/samples/psa/persistent_key/sample.yaml new file mode 100644 index 000000000000000..01cf9f450d1d145 --- /dev/null +++ b/samples/psa/persistent_key/sample.yaml @@ -0,0 +1,31 @@ +sample: + name: PSA Crypto persistent key sample + description: Demonstration of persistent key usage in the PSA Crypto API. +common: + tags: + - psa.secure_storage + timeout: 10 + harness: console + harness_config: + type: one_line + regex: + - "Sample finished successfully." +tests: + sample.psa.persistent_key.tfm: + filter: CONFIG_BUILD_WITH_TFM + tags: + - trusted-firmware-m + sample.psa.persistent_key.secure_storage.entropy_driver: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + and CONFIG_ENTROPY_HAS_DRIVER + extra_args: EXTRA_CONF_FILE=overlay-secure_storage.conf;overlay-entropy_driver.conf + tags: + - drivers.entropy + - settings + sample.psa.persistent_key.secure_storage.entropy_not_secure: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + and not CONFIG_ENTROPY_HAS_DRIVER + extra_args: EXTRA_CONF_FILE="overlay-secure_storage.conf;overlay-entropy_not_secure.conf" + tags: + - random + - settings diff --git a/samples/psa/persistent_key/src/main.c b/samples/psa/persistent_key/src/main.c new file mode 100644 index 000000000000000..c79d8184f94fe06 --- /dev/null +++ b/samples/psa/persistent_key/src/main.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +LOG_MODULE_REGISTER(persistent_key); + +#define SAMPLE_KEY_ID PSA_KEY_ID_USER_MIN +#define SAMPLE_KEY_TYPE PSA_KEY_TYPE_AES +#define SAMPLE_ALG PSA_ALG_CTR +#define SAMPLE_KEY_BITS 256 + +int generate_persistent_key(void) +{ + LOG_INF("Generating a persistent key..."); + psa_status_t ret; + psa_key_id_t key_id; + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_id(&key_attributes, SAMPLE_KEY_ID); + psa_set_key_type(&key_attributes, SAMPLE_KEY_TYPE); + psa_set_key_algorithm(&key_attributes, SAMPLE_ALG); + psa_set_key_bits(&key_attributes, SAMPLE_KEY_BITS); + + ret = psa_generate_key(&key_attributes, &key_id); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to generate the key. (%d)", ret); + return -1; + } + __ASSERT_NO_MSG(key_id == SAMPLE_KEY_ID); + + /* Purge the key from volatile memory. Has the same affect than resetting the device. */ + ret = psa_purge_key(SAMPLE_KEY_ID); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to purge the generated key from volatile memory. (%d).", ret); + return -1; + } + + LOG_INF("Persistent key generated."); + return 0; +} + +int use_persistent_key(void) +{ + LOG_INF("Using the persistent key to encrypt and decrypt some plaintext..."); + psa_status_t ret; + size_t ciphertext_len; + size_t decrypted_text_len; + + static uint8_t plaintext[] = + "Example plaintext to demonstrate basic usage of a persistent key."; + static uint8_t ciphertext[PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(SAMPLE_KEY_TYPE, SAMPLE_ALG, + sizeof(plaintext))]; + static uint8_t decrypted_text[sizeof(plaintext)]; + + ret = psa_cipher_encrypt(SAMPLE_KEY_ID, SAMPLE_ALG, plaintext, sizeof(plaintext), + ciphertext, sizeof(ciphertext), &ciphertext_len); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to encrypt the plaintext. (%d)", ret); + return -1; + } + + ret = psa_cipher_decrypt(SAMPLE_KEY_ID, SAMPLE_ALG, ciphertext, ciphertext_len, + decrypted_text, sizeof(decrypted_text), &decrypted_text_len); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to decrypt the ciphertext. (%d)", ret); + return -1; + } + __ASSERT_NO_MSG(decrypted_text_len == sizeof(plaintext)); + + /* Make sure the decryption gives us the original plaintext back. */ + if (memcmp(plaintext, decrypted_text, sizeof(plaintext))) { + LOG_HEXDUMP_INF(plaintext, sizeof(plaintext), "Plaintext:"); + LOG_HEXDUMP_INF(ciphertext, ciphertext_len, "Ciphertext:"); + LOG_HEXDUMP_INF(decrypted_text, sizeof(decrypted_text), "Decrypted text:"); + LOG_ERR("The decrypted text doesn't match the plaintext."); + return -1; + } + + LOG_INF("Persistent key usage successful."); + return 0; +} + +static int destroy_persistent_key(void) +{ + LOG_INF("Destroying the persistent key..."); + psa_status_t ret; + + ret = psa_destroy_key(SAMPLE_KEY_ID); + if (ret != PSA_SUCCESS) { + LOG_ERR("Failed to destroy the key. (%d)", ret); + return -1; + } + + LOG_INF("Persistent key destroyed."); + return 0; +} + +int main(void) +{ + LOG_INF("Persistent key sample started."); + + /* Ensure there is not already a key with this ID. */ + psa_destroy_key(SAMPLE_KEY_ID); + + if (generate_persistent_key()) { + return -1; + } + + if (use_persistent_key()) { + return -1; + } + + if (destroy_persistent_key()) { + return -1; + } + + LOG_INF("Sample finished successfully."); + return 0; +} diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 58f0cf6ffc3e23d..96148910a92c564 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -50,6 +50,7 @@ add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem) add_subdirectory_ifdef(CONFIG_NET_BUF net) add_subdirectory_ifdef(CONFIG_PROFILING profiling) add_subdirectory_ifdef(CONFIG_RETENTION retention) +add_subdirectory_ifdef(CONFIG_SECURE_STORAGE secure_storage) add_subdirectory_ifdef(CONFIG_SENSING sensing) add_subdirectory_ifdef(CONFIG_SETTINGS settings) add_subdirectory_ifdef(CONFIG_SHELL shell) diff --git a/subsys/Kconfig b/subsys/Kconfig index 59c7fa1721018c3..561d5263422688e 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -38,6 +38,7 @@ source "subsys/random/Kconfig" source "subsys/retention/Kconfig" source "subsys/rtio/Kconfig" source "subsys/sd/Kconfig" +source "subsys/secure_storage/Kconfig" source "subsys/sensing/Kconfig" source "subsys/settings/Kconfig" source "subsys/shell/Kconfig" diff --git a/subsys/secure_storage/CMakeLists.txt b/subsys/secure_storage/CMakeLists.txt new file mode 100644 index 000000000000000..a15c1b24f441dfb --- /dev/null +++ b/subsys/secure_storage/CMakeLists.txt @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) +zephyr_library_include_directories(include/internal) # secure_storage headers +add_subdirectory(src) + +# Make the subsystem's PSA Secure Storage API headers available only when it's enabled. +zephyr_include_directories( + include +) + +# Make the secure_storage headers available to the application only when it's implementing the relevant APIs. +function(make_available header) + if (NOT header STREQUAL "common.h") + make_available(common.h) + endif() + if ((header MATCHES "^its") AND NOT (header STREQUAL "its/common.h")) + make_available(its/common.h) + endif() + configure_file(include/internal/zephyr/secure_storage/${header} + ${CMAKE_BINARY_DIR}/zephyr/include/generated/zephyr/secure_storage/${header} + COPYONLY) +endfunction() + +if (CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_CUSTOM) + make_available(its.h) +endif() + +if (CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_CUSTOM) + make_available(ps.h) +endif() + +if (CONFIG_SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_CUSTOM + OR (CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM + AND CONFIG_SECURE_STORAGE_ITS_TRANSFORM_MODULE)) + make_available(its/transform.h) +endif() + +if (CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM) + make_available(its/store.h) +endif() + +if (CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CUSTOM + OR CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM + OR CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER_CUSTOM) + make_available(its/transform/aead_get.h) +endif() diff --git a/subsys/secure_storage/Kconfig b/subsys/secure_storage/Kconfig new file mode 100644 index 000000000000000..11e78a7dbd2ce88 --- /dev/null +++ b/subsys/secure_storage/Kconfig @@ -0,0 +1,102 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +menuconfig SECURE_STORAGE + bool "Secure storage subsystem" + depends on !BUILD_WITH_TFM + select EXPERIMENTAL + help + The secure storage subsystem provides an implementation of the PSA Secure Storage API + functions on board targets that don't already have one. + It allows making use of the PSA Secure Storage API and persistent keys in the PSA Crypto + API in a standard and portable way. + It is configurable and different implementations can be used to accommodate the varying + capabilities of different devices. + In addition to providing functional support for the PSA Secure Storage API, depending on + the device-specific security features that are available and used, the subsystem may + secure the data stored through it at rest. + This is however highly dependent on the device and configuration in use, and not a + guarantee of the subsystem. + +if SECURE_STORAGE + +module = SECURE_STORAGE +module-str = secure_storage +source "subsys/logging/Kconfig.template.log_config" + +choice SECURE_STORAGE_ITS_IMPLEMENTATION + prompt "Internal Trusted Storage (ITS) API implementation" + +config SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR + bool "Zephyr's ITS implementation" + select SECURE_STORAGE_ITS_TRANSFORM_MODULE + select SECURE_STORAGE_ITS_STORE_MODULE + help + Use Zephyr's implementation of the ITS API. + It calls into the transform and store modules, which + can be configured and have custom implementations. + +config SECURE_STORAGE_ITS_IMPLEMENTATION_CUSTOM + bool "Custom ITS implementation" + help + A custom implementation of the ITS API is present. + Implement the functions declared in . + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_IMPLEMENTATION + +config SECURE_STORAGE_ITS_MAX_DATA_SIZE + int "Maximum data size of an ITS entry in bytes" + default 128 + help + The maximum size, in bytes, that the data of an ITS entry can be. + Increasing this value increases the stack usage when serving PSA ITS API calls. + +menuconfig SECURE_STORAGE_ITS_TRANSFORM_MODULE + bool "ITS transform module" + help + The module that handles the transformation and validation of the + ITS data before it's written to and after it's read from NVM. + Zephyr's ITS implementation calls into it. + +if SECURE_STORAGE_ITS_TRANSFORM_MODULE +rsource "Kconfig.its_transform" +endif + +menuconfig SECURE_STORAGE_ITS_STORE_MODULE + bool "ITS store module" + imply FLASH # for FLASH_HAS_DRIVER_ENABLED + help + The module that handles the storage/retrieval of the ITS data to/from NVM. + Zephyr's ITS implementation calls into it. + +if SECURE_STORAGE_ITS_STORE_MODULE +rsource "Kconfig.its_store" +endif + +choice SECURE_STORAGE_PS_IMPLEMENTATION + prompt "Protected Storage (PS) API implementation" + default SECURE_STORAGE_PS_IMPLEMENTATION_ITS + +config SECURE_STORAGE_PS_IMPLEMENTATION_ITS + bool "PS calls directly into the ITS" + help + The PS API doesn't have an implementation of its own, and directly calls into the ITS API. + This means that the implementation of the PS API will be identical to that of the ITS API. + +config SECURE_STORAGE_PS_IMPLEMENTATION_CUSTOM + bool "Custom PS implementation" + help + A custom implementation of the PS API is present. + Implement the functions declared in . + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_PS_IMPLEMENTATION + +config SECURE_STORAGE_PS_SUPPORTS_SET_EXTENDED + bool "PS API implementation supports psa_ps_create() and psa_ps_set_extended()" + depends on SECURE_STORAGE_PS_IMPLEMENTATION_CUSTOM + help + Whether the psa_ps_create() and psa_ps_set_extended() functions are implemented. + +endif # SECURE_STORAGE diff --git a/subsys/secure_storage/Kconfig.its_store b/subsys/secure_storage/Kconfig.its_store new file mode 100644 index 000000000000000..9e4d9b650205931 --- /dev/null +++ b/subsys/secure_storage/Kconfig.its_store @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +choice SECURE_STORAGE_ITS_STORE_IMPLEMENTATION + prompt "ITS store module implementation" + +config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS + bool "ITS store module implementation using the settings subsystem for storage" + DT_STORAGE_PARTITION := $(dt_nodelabel_path,storage_partition) + depends on FLASH_HAS_DRIVER_ENABLED \ + && $(dt_path_enabled,$(DT_STORAGE_PARTITION)) \ + && $(dt_node_has_compat,$(dt_node_parent,$(DT_STORAGE_PARTITION)),fixed-partitions) + imply FLASH_MAP + imply NVS + select SETTINGS + +config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + bool "No ITS store module implementation" + +config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM + bool "Custom ITS store module implementation" + help + Implement the functions declared in . + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_STORE_IMPLEMENTATION + +if SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS + +config SECURE_STORAGE_ITS_STORE_SETTINGS_PREFIX + string "Subtree in which to store the settings, with a trailing slash. Can be empty." + default "its/" + +endif # SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS diff --git a/subsys/secure_storage/Kconfig.its_transform b/subsys/secure_storage/Kconfig.its_transform new file mode 100644 index 000000000000000..5fcdb2bdb6bc4e5 --- /dev/null +++ b/subsys/secure_storage/Kconfig.its_transform @@ -0,0 +1,134 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +choice SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION + prompt "ITS transform module implementation" + +config SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_AEAD + bool "ITS transform module implementation using AEAD to protect the data" + imply HWINFO # for HWINFO_HAS_DRIVER + +config SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_CUSTOM + bool "Custom ITS transform module implementation" + help + Implement the functions declared in + and set CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD appropriately. + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION + +config SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD + int "Overhead, in bytes, associated with the transformation of an entry's data for storage" + range 0 1000 + # authentication tag (16) + nonce (12) + default 28 if SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_AEAD \ + && SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE = 12 + default -1 + help + This indicates how many more bytes an ITS entry's data will be once it + has been processed by the secure_storage_its_transform_to_store() function. + +if SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_AEAD + +choice SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME + prompt "AEAD ITS transform module scheme" + default SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_AES_GCM + help + The AEAD scheme used to encrypt and authenticate the data. + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_AES_GCM + bool "AES-GCM AEAD scheme" + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_ALG_GCM + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CHACHA20_POLY1305 + bool "ChaCha20-Poly1305 AEAD scheme" + depends on SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE = 12 + select PSA_WANT_KEY_TYPE_CHACHA20 + select PSA_WANT_ALG_CHACHA20_POLY1305 + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CUSTOM + bool "Custom AEAD scheme" + help + Implement the secure_storage_its_transform_aead_get_scheme() function + declared in + and set CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE appropriately. + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME + +choice SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER + prompt "AEAD ITS transform module encryption key provider" + default SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_DEVICE_ID_HASH if HWINFO_HAS_DRIVER + default SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_ENTRY_UID_HASH if !HWINFO_HAS_DRIVER + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_DEVICE_ID_HASH + bool "Hash of the device ID returned by the HW info API (not necessarily secure)" + depends on HWINFO_HAS_DRIVER + select PSA_WANT_ALG_SHA_256 + help + This key provider generates keys by hashing the following: + - the device EUI64 as returned by hwinfo_get_device_eui64() as first choice; + - the device ID as returned by hwinfo_get_device_uuid() as second choice. + In addition to the device ID, it adds the UID of the ITS entry + for which it is generating a key to the data hashed as a salt. + This is not necessarily secure as the device ID may be easily readable + by an attacker, not unique, and/or guessable, depending on the device. + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_ENTRY_UID_HASH + bool "Hash of the ITS entry UID (not secure)" + select PSA_WANT_ALG_SHA_256 + help + This key provider generates keys by hashing the UID of the ITS entry for which it is + generating a key. This is not secure, and only intended for functional support, + because the UIDs are easily guessable and even stored in clear by the store module. + Use a secure key provider if possible. + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM + bool "Custom key provider" + help + Implement the secure_storage_its_transform_aead_get_key() function + declared in . + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE + int "AEAD ITS transform module encryption key size in bytes" + default 32 + +if !SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_NO_INSECURE_KEY_WARNING + bool "Silence the insecure ITS encryption key warnings" + +endif + +choice SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER + prompt "AEAD ITS transform module nonce provider" + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER_DEFAULT + bool "Default nonce provider" + help + The default nonce provider generates a random number for the first nonce with + psa_generate_random(), then increments it for every subsequent nonce. A random + source that doesn't repeat values between reboots is required for this to be secure. + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER_CUSTOM + bool "Custom nonce provider" + help + Implement the secure_storage_its_transform_aead_get_nonce() function + declared in . + The header is made available when this Kconfig option is enabled. + +endchoice # SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER + +config SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE + int "AEAD ITS transform module nonce size in bytes" + range 4 24 + default 12 + help + Make sure to update CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD + appropriately when changing the value of this option. + +endif # SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_AEAD diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/common.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/common.h new file mode 100644 index 000000000000000..6c2c8922395fcc7 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/common.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_COMMON_H +#define SECURE_STORAGE_COMMON_H + +/** @file zephyr/secure_storage/common.h Common definitions of the secure storage subsystem. */ +#include + +/* A size-optimized version of `psa_storage_create_flags_t`. Used for storing the `create_flags`. */ +typedef uint8_t secure_storage_packed_create_flags_t; + +#define SECURE_STORAGE_ALL_CREATE_FLAGS \ + (PSA_STORAGE_FLAG_NONE | \ + PSA_STORAGE_FLAG_WRITE_ONCE | \ + PSA_STORAGE_FLAG_NO_CONFIDENTIALITY | \ + PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION) + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its.h new file mode 100644 index 000000000000000..009bb5e061af75f --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_ITS_H +#define SECURE_STORAGE_ITS_H + +/** @file zephyr/secure_storage/its.h The secure storage ITS implementation. + * + * The functions declared in this header implement the PSA ITS API + * when the secure storage subsystem is enabled. + * They must not be called directly, and this header must not be included other than when + * providing a custom implementation (@kconfig{CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_CUSTOM}). + */ +#include "its/common.h" + +/** @brief See `psa_its_set()`, to which this function is analogous. */ +psa_status_t secure_storage_its_set(secure_storage_its_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags); + +/** @brief See `psa_its_get()`, to which this function is analogous. */ +psa_status_t secure_storage_its_get(secure_storage_its_uid_t uid, size_t data_offset, + size_t data_size, void *p_data, size_t *p_data_length); + +/** @brief See `psa_its_get_info()`, to which this function is analogous. */ +psa_status_t secure_storage_its_get_info(secure_storage_its_uid_t uid, + struct psa_storage_info_t *p_info); + +/** @brief See `psa_its_remove()`, to which this function is analogous. */ +psa_status_t secure_storage_its_remove(secure_storage_its_uid_t uid); + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h new file mode 100644 index 000000000000000..4b73eafcf3d8868 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_ITS_COMMON_H +#define SECURE_STORAGE_ITS_COMMON_H + +/** @file zephyr/secure_storage/its/common.h + * @brief Common definitions of the secure storage subsystem's ITS APIs. + */ +#include "../common.h" +#include +#include + +/** @brief The ID of the caller from which the ITS API call originates. + * This is used to prevent ID collisions between different callers that are not aware + * of each other and so might use the same numerical IDs, e.g. PSA Crypto and PSA ITS. + */ +typedef enum { + SECURE_STORAGE_ITS_CALLER_PSA_ITS, + SECURE_STORAGE_ITS_CALLER_PSA_PS, + SECURE_STORAGE_ITS_CALLER_MBEDTLS, +} secure_storage_its_caller_id_t; + +/** The UID (caller + entry IDs) of an ITS entry. */ +typedef struct { + psa_storage_uid_t uid; + secure_storage_its_caller_id_t caller_id; +} __packed secure_storage_its_uid_t; + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h new file mode 100644 index 000000000000000..fec3448b21589e2 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_ITS_STORE_H +#define SECURE_STORAGE_ITS_STORE_H + +/** @file zephyr/secure_storage/its/store.h The secure storage ITS store module. + * + * The functions declared in this header implement the ITS store module. + * They are meant to be called only by the ITS implementation. + * This header may be included when providing a custom implementation of the + * ITS store module (@kconfig{CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM}). + */ +#include + +/** @brief Writes the data of an ITS entry to the storage medium. + * + * @param uid The entry's UID. + * @param data_length The number of bytes in `data`. + * @param data The data to store. + * + * @retval `PSA_SUCCESS` on success. + * @retval `PSA_ERROR_INSUFFICIENT_STORAGE` if there is insufficient storage space. + * @retval `PSA_ERROR_STORAGE_FAILURE` on any other failure. + */ +psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, + size_t data_length, const void *data); + +/** @brief Retrieves the data of an ITS entry from the storage medium. + * + * @param[in] uid The entry's UID. + * @param[in] data_size The size of `data` in bytes. + * @param[out] data The buffer to which the entry's stored data is written. + * @param[out] data_length On success, the number of bytes written to `data`. + * May be less than `data_size`. + * + * @retval `PSA_SUCCESS` on success. + * @retval `PSA_ERROR_DOES_NOT_EXIST` if no entry with the given UID exists. + * @retval `PSA_ERROR_STORAGE_FAILURE` on any other failure. + */ +psa_status_t secure_storage_its_store_get(secure_storage_its_uid_t uid, size_t data_size, + void *data, size_t *data_length); + +/** @brief Removes an ITS entry from the storage medium. + * + * @param uid The entry's UID. + * + * @return `PSA_SUCCESS` on success, anything else on failure. + */ +psa_status_t secure_storage_its_store_remove(secure_storage_its_uid_t uid); + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform.h new file mode 100644 index 000000000000000..ad8f3e81a3186f0 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_ITS_TRANSFORM_H +#define SECURE_STORAGE_ITS_TRANSFORM_H + +/** @file zephyr/secure_storage/its/transform.h The secure storage ITS transform module. + * + * The functions declared in this header implement the ITS transform module. + * They are meant to be called only by the ITS implementation. + * This header may be included when providing a custom implementation of the + * ITS transform module (@kconfig{CONFIG_SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_CUSTOM}). + */ +#include + +/** The maximum size, in bytes, of an entry's data after it has been transformed for storage. */ +enum { SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE + = CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE + + sizeof(secure_storage_packed_create_flags_t) + + CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD }; + +#define SECURE_STORAGE_ITS_TRANSFORM_DATA_SIZE(stored_data_len) \ + (stored_data_len - (SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE \ + - CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE)) + +/** @brief Transforms the data of an ITS entry for storage. + * + * @param[in] uid The entry's UID. + * @param[in] data_len The number of bytes in `data`. + * @param[in] data The data to transform for storage. + * @param[in] create_flags The entry's create flags. It must contain only valid + * `PSA_STORAGE_FLAG_*` values. It gets stored as part of `stored_data`. + * @param[out] stored_data The buffer to which the transformed data is written. + * @param[out] stored_data_len On success, the number of bytes written to `stored_data`. + * + * @return `PSA_SUCCESS` on success, anything else on failure. + */ +psa_status_t secure_storage_its_transform_to_store( + secure_storage_its_uid_t uid, size_t data_len, const void *data, + secure_storage_packed_create_flags_t create_flags, + uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t *stored_data_len); + +/** @brief Transforms and validates the stored data of an ITS entry for use. + * + * @param[in] uid The entry's UID. + * @param[in] stored_data_len The number of bytes in `stored_data`. + * @param[in] stored_data The stored data to transform for use. + * @param[in] data_size The size of `data` in bytes. + * @param[out] data The buffer to which the transformed data is written. + * @param[out] data_len On success, the number of bytes written to `stored_data`. + * @param[out] create_flags On success, the entry's create flags. + * + * @return `PSA_SUCCESS` on success, anything else on failure. + */ +psa_status_t secure_storage_its_transform_from_store( + secure_storage_its_uid_t uid, size_t stored_data_len, + const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t data_size, void *data, size_t *data_len, + psa_storage_create_flags_t *create_flags); + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform/aead_get.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform/aead_get.h new file mode 100644 index 000000000000000..071c74c029e6257 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/transform/aead_get.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_ITS_TRANSFORM_AEAD_GET_H +#define SECURE_STORAGE_ITS_TRANSFORM_AEAD_GET_H + +/** @file zephyr/secure_storage/its/transform/aead_get.h The AEAD ITS transform module API. + * + * The functions declared in this header allow customization + * of the AEAD implementation of the ITS transform module. + * They are not meant to be called directly other than by the AEAD ITS transform module. + * This header may be included when providing a custom implementation of one + * or more of these functions (@kconfig{CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_*_CUSTOM}). + */ +#include +#include + +/** @brief Returns the key type and algorithm to use for the AEAD operations. + * + * @param[out] key_type The key type to use. + * @param[out] alg The algorithm to use. + */ +void secure_storage_its_transform_aead_get_scheme(psa_key_type_t *key_type, psa_algorithm_t *alg); + +/** @brief Returns the encryption key to use for an ITS entry's AEAD operations. + * + * @param[in] uid The UID of the ITS entry for whom the returned key is used. + * @param[out] key The encryption key. + * + * @return `PSA_SUCCESS` on success, anything else on failure. + */ +psa_status_t secure_storage_its_transform_aead_get_key( + secure_storage_its_uid_t uid, + uint8_t key[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE]); + +/** @brief Generates a nonce for an AEAD operation. + * + * @param[out] nonce The generated nonce. + * + * @return `PSA_SUCCESS` on success, anything else on failure. + */ +psa_status_t secure_storage_its_transform_aead_get_nonce( + uint8_t nonce[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE]); + +#endif diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/ps.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/ps.h new file mode 100644 index 000000000000000..fa5344ded352204 --- /dev/null +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/ps.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SECURE_STORAGE_PS_H +#define SECURE_STORAGE_PS_H + +/** @file zephyr/secure_storage/ps.h The secure storage PS implementation. + * + * The functions declared in this header implement the PSA PS API + * when the secure storage subsystem is enabled. + * They must not be called directly, and this header must not be included other than when + * providing a custom implementation (@kconfig{CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_CUSTOM}). + */ +#include + +/** @brief See `psa_ps_set()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_set(const psa_storage_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags); + +/** @brief See `psa_ps_get()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_get(const psa_storage_uid_t uid, size_t data_offset, + size_t data_length, void *p_data, size_t *p_data_length); + +/** @brief See `psa_ps_get_info()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_get_info(const psa_storage_uid_t uid, + struct psa_storage_info_t *p_info); + +/** @brief See `psa_ps_remove()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_remove(const psa_storage_uid_t uid); + +/** @brief See `psa_ps_create()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_create(psa_storage_uid_t uid, size_t capacity, + psa_storage_create_flags_t create_flags); + +/** @brief See `psa_ps_set_extended()`, to which this function is analogous. */ +psa_status_t secure_storage_ps_set_extended(psa_storage_uid_t uid, size_t data_offset, + size_t data_length, const void *p_data); + +#endif diff --git a/subsys/secure_storage/include/psa/error.h b/subsys/secure_storage/include/psa/error.h new file mode 100644 index 000000000000000..439f4b5e4de512b --- /dev/null +++ b/subsys/secure_storage/include/psa/error.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef PSA_ERROR_H +#define PSA_ERROR_H +/** + * @file psa/error.h Return values of the PSA Secure Storage API. + * @ingroup psa_secure_storage + * @{ + */ +#include + +typedef int32_t psa_status_t; + +#define PSA_SUCCESS ((psa_status_t)0) + +#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132) +#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133) +#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134) +#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135) +#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139) +#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140) +#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142) +#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) +#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) +#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) + +/** @} */ +#endif diff --git a/subsys/secure_storage/include/psa/internal_trusted_storage.h b/subsys/secure_storage/include/psa/internal_trusted_storage.h new file mode 100644 index 000000000000000..a8c3b77c601a00d --- /dev/null +++ b/subsys/secure_storage/include/psa/internal_trusted_storage.h @@ -0,0 +1,126 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef PSA_INTERNAL_TRUSTED_STORAGE_H +#define PSA_INTERNAL_TRUSTED_STORAGE_H + +/** @file psa/internal_trusted_storage.h The PSA Internal Trusted Storage (ITS) API. + * @ingroup psa_secure_storage + * For more information on the ITS, see [The Internal Trusted Storage API](https://arm-software.github.io/psa-api/storage/1.0/overview/architecture.html#the-internal-trusted-storage-api). + */ + +/** @cond INTERNAL_HIDDEN */ +#include "../internal/zephyr/secure_storage/its.h" +#ifdef BUILDING_MBEDTLS_CRYPTO +#define ITS_CALLER_ID SECURE_STORAGE_ITS_CALLER_MBEDTLS +#else +#define ITS_CALLER_ID SECURE_STORAGE_ITS_CALLER_PSA_ITS +#endif +#define ITS_UID (secure_storage_its_uid_t){.uid = uid, .caller_id = ITS_CALLER_ID} +/** @endcond */ + +#include + +#define PSA_ITS_API_VERSION_MAJOR 1 +#define PSA_ITS_API_VERSION_MINOR 0 + +/** + * @brief Creates a new or modifies an existing entry. + * + * Stores data in the internal storage. + * + * @param uid The identifier of the data. Must be nonzero. + * @param data_length The size in bytes of the data in `p_data` to store. + * @param p_data A buffer containing the data to store. + * @param create_flags Flags indicating the properties of the entry. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_NOT_PERMITTED An entry associated with the provided `uid` already + * exists and was created with `PSA_STORAGE_FLAG_WRITE_ONCE`. + * @retval PSA_ERROR_NOT_SUPPORTED One or more of the flags provided in `create_flags` + * are not supported or invalid. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more arguments other than `create_flags` are + * invalid. + * @retval PSA_ERROR_INSUFFICIENT_STORAGE There is insufficient space on the storage medium. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags) +{ + return secure_storage_its_set(ITS_UID, data_length, p_data, create_flags); +} + +/** + * @brief Retrieves data associated with the provided `uid`. + * + * @param[in] uid The identifier of the data. + * @param[in] data_offset The offset, in bytes, from which to start reading the data. + * @param[in] data_size The number of bytes to read. + * @param[out] p_data The buffer where the data will be placed on success. + * Must be at least `data_size` bytes long. + * @param[out] p_data_length On success, the number of bytes placed in `p_data`. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more of the arguments are invalid. This can also + * happen if `data_offset` is larger than the size of the data + * associated with `uid`. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, + size_t data_size, void *p_data, size_t *p_data_length) +{ + return secure_storage_its_get(ITS_UID, data_offset, data_size, p_data, p_data_length); +} + +/** + * @brief Retrieves the metadata of a given entry. + * + * @param[in] uid The identifier of the entry. + * @param[out] p_info A pointer to a `psa_storage_info_t` struct that will + * be populated with the metadata on success. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more of the arguments are invalid. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ + return secure_storage_its_get_info(ITS_UID, p_info); +} + +/** + * @brief Removes the provided `uid` and its associated data. + * + * Deletes all the data associated with the entry from internal storage. + * + * @param uid The identifier of the entry to remove. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_NOT_PERMITTED The entry was created with `PSA_STORAGE_FLAG_WRITE_ONCE`. + * @retval PSA_ERROR_INVALID_ARGUMENT `uid` is invalid. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_its_remove(psa_storage_uid_t uid) +{ + return secure_storage_its_remove(ITS_UID); +} + +#undef ITS_UID +#undef ITS_CALLER_ID + +#endif diff --git a/subsys/secure_storage/include/psa/protected_storage.h b/subsys/secure_storage/include/psa/protected_storage.h new file mode 100644 index 000000000000000..7c20d3097a2ad5d --- /dev/null +++ b/subsys/secure_storage/include/psa/protected_storage.h @@ -0,0 +1,241 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef PSA_PROTECTED_STORAGE_H +#define PSA_PROTECTED_STORAGE_H + +/** @file psa/protected_storage.h The PSA Protected Storage (PS) API. + * @ingroup psa_secure_storage + * For more information on the PS, see [The Protected Storage API](https://arm-software.github.io/psa-api/storage/1.0/overview/architecture.html#the-protected-storage-api). + */ + +/** @cond INTERNAL_HIDDEN */ +#ifdef CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS +#include "../internal/zephyr/secure_storage/its.h" +#define ITS_UID (secure_storage_its_uid_t){.uid = uid, \ + .caller_id = SECURE_STORAGE_ITS_CALLER_PSA_PS} +#else +#include "../internal/zephyr/secure_storage/ps.h" +#endif +/** @endcond */ + +#include + +#define PSA_PS_API_VERSION_MAJOR 1 +#define PSA_PS_API_VERSION_MINOR 0 + +/** + * @brief Creates a new or modifies an existing entry. + * + * @param uid The identifier of the data. Must be nonzero. + * @param data_length The size in bytes of the data in `p_data` to store. + * @param p_data A buffer containing the data to store. + * @param create_flags Flags indicating the properties of the entry. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_NOT_PERMITTED An entry associated with the provided `uid` already + * exists and was created with `PSA_STORAGE_FLAG_WRITE_ONCE`. + * @retval PSA_ERROR_NOT_SUPPORTED One or more of the flags provided in `create_flags` + * are not supported or invalid. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more arguments other than `create_flags` are + * invalid. + * @retval PSA_ERROR_INSUFFICIENT_STORAGE There is insufficient space on the storage medium. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_set(psa_storage_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS + return secure_storage_its_set(ITS_UID, data_length, p_data, create_flags); +#else + return secure_storage_ps_set(uid, data_length, p_data, create_flags); +#endif +} + +/** + * @brief Retrieves data associated with the provided `uid`. + * + * @param[in] uid The identifier of the data. + * @param[in] data_offset The offset, in bytes, from which to start reading the data. + * @param[in] data_size The number of bytes to read. + * @param[out] p_data The buffer where the data will be placed on success. + * Must be at least `data_size` bytes long. + * @param[out] p_data_length On success, the number of bytes placed in `p_data`. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more of the arguments are invalid. This can also + * happen if `data_offset` is larger than the size of the data + * associated with `uid`. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + * @retval PSA_ERROR_INVALID_SIGNATURE The data associated with `uid` failed authentication. + * @retval PSA_ERROR_DATA_CORRUPT The data associated with `uid` is corrupt. + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_get(psa_storage_uid_t uid, size_t data_offset, + size_t data_size, void *p_data, size_t *p_data_length) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS + return secure_storage_its_get(ITS_UID, data_offset, data_size, p_data, p_data_length); +#else + return secure_storage_ps_get(uid, data_offset, data_size, p_data, p_data_length); +#endif +} + +/** + * @brief Retrieves the metadata of a given entry. + * + * @param[in] uid The identifier of the entry. + * @param[out] p_info A pointer to a `psa_storage_info_t` struct that will + * be populated with the metadata on success. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more of the arguments are invalid. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + * @retval PSA_ERROR_INVALID_SIGNATURE The data associated with `uid` failed authentication. + * @retval PSA_ERROR_DATA_CORRUPT The data associated with `uid` is corrupt. + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS + return secure_storage_its_get_info(ITS_UID, p_info); +#else + return secure_storage_ps_get_info(uid, p_info); +#endif +} + +/** + * @brief Removes the provided `uid` and its associated data. + * + * Deletes previously stored data and any associated metadata, including rollback protection data. + * + * @param uid The identifier of the entry to remove. + * + * @return A status indicating the success/failure of the operation + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_NOT_PERMITTED The entry was created with `PSA_STORAGE_FLAG_WRITE_ONCE`. + * @retval PSA_ERROR_INVALID_ARGUMENT `uid` is invalid. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_remove(psa_storage_uid_t uid) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS + return secure_storage_its_remove(ITS_UID); +#else + return secure_storage_ps_remove(uid); +#endif +} + +/** + * @brief Reserves storage for the provided `uid`. + * + * Upon success, the capacity of the storage for `uid` will be `capacity`, and the size will be 0. + * It is only necessary to call this function for data that will be written with the + * @ref psa_ps_set_extended() function. If only the @ref psa_ps_set() function is used, calls to + * this function are redundant. This function cannot be used to replace or resize an existing entry. + * + * @param uid The identifier of the entry to reserve storage for. + * @param capacity The capacity, in bytes, to allocate. + * @param create_flags Flags indicating the properties of the entry. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_NOT_SUPPORTED The implementation doesn't support this function or one + * or more of the flags provided in `create_flags` are not + * supported or invalid. + * @retval PSA_ERROR_INVALID_ARGUMENT `uid` is invalid. + * @retval PSA_ERROR_ALREADY_EXISTS An entry with the provided `uid` already exists. + * @retval PSA_ERROR_INSUFFICIENT_STORAGE There is insufficient space on the storage medium. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_create(psa_storage_uid_t uid, size_t capacity, + psa_storage_create_flags_t create_flags) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_SUPPORTS_SET_EXTENDED + return secure_storage_ps_create(uid, capacity, create_flags); +#else + return PSA_ERROR_NOT_SUPPORTED; +#endif +} + +/** + * @brief Writes part of the data associated with the provided `uid`. + * + * Before calling this function, storage must have been reserved with a call to + * @ref psa_ps_create(). This function can also be used to overwrite data that was + * written with @ref psa_ps_set(). This function can overwrite existing data and/or extend + * it up to the capacity of the entry specified in @ref psa_ps_create(), but cannot create gaps. + * + * @param uid The identifier of the entry to write. + * @param data_offset The offset, in bytes, from which to start writing the data. + * Can be at most the current size of the data. + * @param data_length The size in bytes of the data in `p_data` to write. `data_offset` + * + `data_length` can be at most the capacity of the entry. + * @param p_data A buffer containing the data to write. + * + * @retval PSA_SUCCESS The operation completed successfully. + * @retval PSA_ERROR_GENERIC_ERROR An unspecified internal failure happened. + * @retval PSA_ERROR_NOT_PERMITTED The entry was created with `PSA_STORAGE_FLAG_WRITE_ONCE`. + * @retval PSA_ERROR_NOT_SUPPORTED The implementation doesn't support this function. + * @retval PSA_ERROR_INVALID_ARGUMENT One or more of the arguments are invalid. + * @retval PSA_ERROR_DOES_NOT_EXIST The provided `uid` was not found in the storage. + * @retval PSA_ERROR_STORAGE_FAILURE The physical storage has failed (fatal error). + * @retval PSA_ERROR_INVALID_SIGNATURE The data associated with `uid` failed authentication. + * @retval PSA_ERROR_DATA_CORRUPT The data associated with `uid` is corrupt. + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +psa_status_t psa_ps_set_extended(psa_storage_uid_t uid, size_t data_offset, + size_t data_length, const void *p_data) +{ +#ifdef CONFIG_SECURE_STORAGE_PS_SUPPORTS_SET_EXTENDED + return secure_storage_ps_set_extended(uid, data_offset, data_length, p_data); +#else + return PSA_ERROR_NOT_SUPPORTED; +#endif +} + +/** + * @brief Lists optional features. + * + * @return A bitmask with flags set for the optional features supported by the implementation. + * Currently defined flags are limited to `PSA_STORAGE_SUPPORT_SET_EXTENDED`. + */ +/** @cond INTERNAL_HIDDEN */ +static ALWAYS_INLINE +/** @endcond */ +uint32_t psa_ps_get_support(void) +{ + uint32_t flags = 0; + +#ifdef CONFIG_SECURE_STORAGE_PS_SUPPORTS_SET_EXTENDED + flags |= PSA_STORAGE_SUPPORT_SET_EXTENDED; +#endif + return flags; +} + +#undef ITS_UID + +#endif diff --git a/subsys/secure_storage/include/psa/storage_common.h b/subsys/secure_storage/include/psa/storage_common.h new file mode 100644 index 000000000000000..d5bed2a692e7016 --- /dev/null +++ b/subsys/secure_storage/include/psa/storage_common.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef PSA_STORAGE_COMMON_H +#define PSA_STORAGE_COMMON_H +/** + * @defgroup psa_secure_storage PSA Secure Storage API + * @ingroup os_services + * @details For more information on the PSA Secure Storage API, see the + * [PSA Certified Secure Storage API](https://arm-software.github.io/psa-api/storage/1.0/) + * specification. + */ +/** + * @file psa/storage_common.h + * @ingroup psa_secure_storage + * @brief Common definitions of the PSA Secure Storage API. + * @{ + */ +#include +#include + +/** UID type for identifying entries. */ +typedef uint64_t psa_storage_uid_t; + +/** Flags used when creating an entry. */ +typedef uint32_t psa_storage_create_flags_t; + +/** No flag to pass. */ +#define PSA_STORAGE_FLAG_NONE 0u +/** The data associated with the UID will not be able to be modified or deleted. */ +#define PSA_STORAGE_FLAG_WRITE_ONCE (1u << 0) +/** The data associated with the UID is public, requiring only integrity. */ +#define PSA_STORAGE_FLAG_NO_CONFIDENTIALITY (1u << 1) +/** The data associated with the UID does not require replay protection. */ +#define PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION (1u << 2) + +/** Metadata associated with a specific entry. */ +struct psa_storage_info_t { + /** The allocated capacity of the storage associated with an entry. */ + size_t capacity; + /** The size of an entry's data. */ + size_t size; + /** The flags used when the entry was created. */ + psa_storage_create_flags_t flags; +}; + +/** Flag indicating that @ref psa_ps_create() and @ref psa_ps_set_extended() are supported. */ +#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1u << 0) + +/** @} */ +#endif diff --git a/subsys/secure_storage/src/CMakeLists.txt b/subsys/secure_storage/src/CMakeLists.txt new file mode 100644 index 000000000000000..50def1ab93fa050 --- /dev/null +++ b/subsys/secure_storage/src/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources( + log.c +) +add_subdirectory(its) diff --git a/subsys/secure_storage/src/its/CMakeLists.txt b/subsys/secure_storage/src/its/CMakeLists.txt new file mode 100644 index 000000000000000..b9e2bb877d9c1a8 --- /dev/null +++ b/subsys/secure_storage/src/its/CMakeLists.txt @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR + implementation.c +) + +zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_AEAD + transform/aead.c + transform/aead_get.c +) +if (NOT CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NO_INSECURE_KEY_WARNING) + if (CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_DEVICE_ID_HASH) + message(WARNING " + The PSA ITS encryption key provider in use generates keys by hashing the device ID + retrieved through the HW info API. This is not necessarily secure as the device ID may be + easily readable by an attacker, not unique, and/or guessable, depending on the device. + This means that the data and keys stored via the PSA APIs may not be secure at rest.") + elseif(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_ENTRY_UID_HASH) + message(WARNING " + The PSA ITS encryption key provider in use is not secure. + It's only intended for functional support. + This means that the data and keys stored via the PSA APIs will not be secure at rest. + Use a secure key provider if possible.") + endif() +endif() + +zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS + store_settings.c +) diff --git a/subsys/secure_storage/src/its/implementation.c b/subsys/secure_storage/src/its/implementation.c new file mode 100644 index 000000000000000..2ad937d45d27b3c --- /dev/null +++ b/subsys/secure_storage/src/its/implementation.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL); + +static void log_failed_operation(const char *operation, const char *preposition, psa_status_t ret) +{ + LOG_ERR("Failed to %s data %s storage. (%d)", operation, preposition, ret); +} + +static psa_status_t get_stored_data( + secure_storage_its_uid_t uid, + uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t *stored_data_len) +{ + psa_status_t ret; + + ret = secure_storage_its_store_get(uid, SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE, + stored_data, stored_data_len); + if (ret != PSA_SUCCESS) { + if (ret != PSA_ERROR_DOES_NOT_EXIST) { + log_failed_operation("retrieve", "from", ret); + } + return ret; + } + return PSA_SUCCESS; +} + +static psa_status_t transform_stored_data( + secure_storage_its_uid_t uid, size_t stored_data_len, + const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t data_size, void *data, size_t *data_len, + psa_storage_create_flags_t *create_flags) +{ + psa_status_t ret; + + ret = secure_storage_its_transform_from_store(uid, stored_data_len, stored_data, + data_size, data, data_len, create_flags); + if (ret != PSA_SUCCESS) { + log_failed_operation("transform", "from", ret); + return PSA_ERROR_STORAGE_FAILURE; + } + return PSA_SUCCESS; +} + +static psa_status_t get_entry(secure_storage_its_uid_t uid, size_t data_size, uint8_t *data, + size_t *data_len, psa_storage_create_flags_t *create_flags) +{ + psa_status_t ret; + uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE]; + size_t stored_data_len; + + ret = get_stored_data(uid, stored_data, &stored_data_len); + if (ret != PSA_SUCCESS) { + return ret; + } + + return transform_stored_data(uid, stored_data_len, stored_data, data_size, data, data_len, + create_flags); +} + +static bool keep_stored_entry(secure_storage_its_uid_t uid, size_t data_length, const void *p_data, + psa_storage_create_flags_t create_flags, psa_status_t *ret) +{ + psa_storage_create_flags_t existing_create_flags; + uint8_t existing_data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE]; + size_t existing_data_len; + + *ret = get_entry(uid, sizeof(existing_data), existing_data, &existing_data_len, + &existing_create_flags); + if (*ret != PSA_SUCCESS) { + /* The entry either doesn't exist or is corrupted. */ + /* Allow overwriting corrupted entries to not be stuck with them forever. */ + return false; + } + if (existing_create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) { + *ret = PSA_ERROR_NOT_PERMITTED; + return true; + } + if (existing_data_len == data_length && + existing_create_flags == create_flags && + !memcmp(existing_data, p_data, data_length)) { + LOG_DBG("Not writing entry %u/%llu to storage because its stored data" + " (of length %zu) is identical.", uid.caller_id, uid.uid, data_length); + *ret = PSA_SUCCESS; + return true; + } + return false; +} + +static psa_status_t store_entry(secure_storage_its_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags) +{ + psa_status_t ret; + uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE]; + size_t stored_data_len; + + ret = secure_storage_its_transform_to_store(uid, data_length, p_data, create_flags, + stored_data, &stored_data_len); + if (ret != PSA_SUCCESS) { + log_failed_operation("transform", "for", ret); + return PSA_ERROR_STORAGE_FAILURE; + } + + ret = secure_storage_its_store_set(uid, stored_data_len, stored_data); + if (ret != PSA_SUCCESS) { + log_failed_operation("write", "to", ret); + } + return ret; +} + +psa_status_t secure_storage_its_set(secure_storage_its_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags) +{ + psa_status_t ret; + + if (uid.uid == 0 || (p_data == NULL && data_length != 0)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (create_flags & ~SECURE_STORAGE_ALL_CREATE_FLAGS) { + return PSA_ERROR_NOT_SUPPORTED; + } + if (data_length > CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE) { + LOG_DBG("Passed data length (%zu) exceeds maximum allowed (%u).", + data_length, CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE); + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + + if (keep_stored_entry(uid, data_length, p_data, create_flags, &ret)) { + return ret; + } + + ret = store_entry(uid, data_length, p_data, create_flags); + return ret; +} + +psa_status_t secure_storage_its_get(secure_storage_its_uid_t uid, size_t data_offset, + size_t data_size, void *p_data, size_t *p_data_length) +{ + if (uid.uid == 0 || (p_data == NULL && data_size != 0) || p_data_length == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (data_size == 0) { + *p_data_length = 0; + return PSA_SUCCESS; + } + psa_status_t ret; + uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE]; + size_t stored_data_len; + psa_storage_create_flags_t create_flags; + + ret = get_stored_data(uid, stored_data, &stored_data_len); + if (ret != PSA_SUCCESS) { + return ret; + } + if (data_offset == 0 + && data_size >= SECURE_STORAGE_ITS_TRANSFORM_DATA_SIZE(stored_data_len)) { + /* All the data fits directly in the provided buffer. */ + return transform_stored_data(uid, stored_data_len, stored_data, data_size, p_data, + p_data_length, &create_flags); + } + uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE]; + size_t data_len; + + ret = transform_stored_data(uid, stored_data_len, stored_data, sizeof(data), data, + &data_len, &create_flags); + if (ret == PSA_SUCCESS) { + if (data_offset > data_len) { + LOG_DBG("Passed data offset (%zu) exceeds existing data length (%zu).", + data_offset, data_len); + return PSA_ERROR_INVALID_ARGUMENT; + } + *p_data_length = MIN(data_size, data_len - data_offset); + memcpy(p_data, data + data_offset, *p_data_length); + } + return ret; +} + +psa_status_t secure_storage_its_get_info(secure_storage_its_uid_t uid, + struct psa_storage_info_t *p_info) +{ + psa_status_t ret; + uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE]; + + if (uid.uid == 0 || p_info == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + ret = get_entry(uid, sizeof(data), data, &p_info->size, &p_info->flags); + if (ret == PSA_SUCCESS) { + p_info->capacity = p_info->size; + } + return ret; +} + +psa_status_t secure_storage_its_remove(secure_storage_its_uid_t uid) +{ + psa_status_t ret; + psa_storage_create_flags_t create_flags; + uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE]; + size_t data_len; + + if (uid.uid == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + ret = get_entry(uid, sizeof(data), data, &data_len, &create_flags); + if (ret == PSA_SUCCESS && (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE)) { + return PSA_ERROR_NOT_PERMITTED; + } + /* Allow overwriting corrupted entries as well to not be stuck with them forever. */ + if (ret == PSA_SUCCESS || ret == PSA_ERROR_STORAGE_FAILURE) { + ret = secure_storage_its_store_remove(uid); + if (ret != PSA_SUCCESS) { + log_failed_operation("remove", "from", ret); + return PSA_ERROR_STORAGE_FAILURE; + } + } + return ret; +} diff --git a/subsys/secure_storage/src/its/store_settings.c b/subsys/secure_storage/src/its/store_settings.c new file mode 100644 index 000000000000000..ee0624a59a82e54 --- /dev/null +++ b/subsys/secure_storage/src/its/store_settings.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR +#include +BUILD_ASSERT(SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE <= SETTINGS_MAX_VAL_LEN); +#endif + +LOG_MODULE_DECLARE(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL); + +static int init_settings(void) +{ + const int ret = settings_subsys_init(); + + LOG_DBG("Settings subsystem initialized. (%d)", ret); + return ret; +} +SYS_INIT(init_settings, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +enum { NAME_BUF_SIZE = sizeof(CONFIG_SECURE_STORAGE_ITS_STORE_SETTINGS_PREFIX) - 1 + + 2 * (sizeof(secure_storage_its_uid_t) + 1) }; +BUILD_ASSERT(NAME_BUF_SIZE <= SETTINGS_MAX_NAME_LEN + 1); + +static void make_name(secure_storage_its_uid_t uid, char name[static NAME_BUF_SIZE]) +{ + int ret; + + ret = snprintf(name, NAME_BUF_SIZE, CONFIG_SECURE_STORAGE_ITS_STORE_SETTINGS_PREFIX + "%x/%llx", uid.caller_id, (unsigned long long)uid.uid); + __ASSERT_NO_MSG(ret > 0 && ret < NAME_BUF_SIZE); +} + +psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, + size_t data_length, const void *data) +{ + int ret; + char name[NAME_BUF_SIZE]; + + make_name(uid, name); + ret = settings_save_one(name, data, data_length); + LOG_DBG("Saved setting %s with %zu bytes. (%d)", name, data_length, ret); + + switch (ret) { + case 0: + return PSA_SUCCESS; + case -ENOMEM: + case -ENOSPC: + return PSA_ERROR_INSUFFICIENT_STORAGE; + default: + return PSA_ERROR_STORAGE_FAILURE; + } +} + +struct load_params { + const size_t data_size; + uint8_t *const data; + ssize_t ret; +}; + +static int load_direct_setting(const char *key, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param) +{ + (void)key; + struct load_params *load_params = param; + + load_params->ret = read_cb(cb_arg, load_params->data, MIN(load_params->data_size, len)); + return 0; +} + +psa_status_t secure_storage_its_store_get(secure_storage_its_uid_t uid, size_t data_size, + void *data, size_t *data_length) +{ + char name[NAME_BUF_SIZE]; + struct load_params load_params = {.data_size = data_size, .data = data, .ret = -ENOENT}; + + make_name(uid, name); + + settings_load_subtree_direct(name, load_direct_setting, &load_params); + LOG_DBG("Loaded setting %s for up to %zu bytes. (%zd)", + name, data_size, load_params.ret); + + if (load_params.ret > 0) { + *data_length = load_params.ret; + return PSA_SUCCESS; + } else if (load_params.ret == 0 || load_params.ret == -ENOENT) { + return PSA_ERROR_DOES_NOT_EXIST; + } else { + return PSA_ERROR_STORAGE_FAILURE; + } +} + +psa_status_t secure_storage_its_store_remove(secure_storage_its_uid_t uid) +{ + int ret; + char name[NAME_BUF_SIZE]; + + make_name(uid, name); + ret = settings_delete(name); + if (ret) { + LOG_DBG("Failed to delete setting %s. (%d)", name, ret); + return PSA_ERROR_STORAGE_FAILURE; + } + return PSA_SUCCESS; +} diff --git a/subsys/secure_storage/src/its/transform/aead.c b/subsys/secure_storage/src/its/transform/aead.c new file mode 100644 index 000000000000000..e9f2d57d73abb5a --- /dev/null +++ b/subsys/secure_storage/src/its/transform/aead.c @@ -0,0 +1,131 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include <../library/psa_crypto_driver_wrappers.h> +#include +#include +#include + +static psa_status_t psa_aead_crypt(psa_key_usage_t operation, secure_storage_its_uid_t uid, + const uint8_t nonce + [static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE], + size_t add_data_len, const void *add_data, size_t input_len, + const void *input, size_t output_size, void *output, + size_t *output_len) +{ + psa_status_t ret; + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t key[CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE]; + psa_key_type_t key_type; + psa_algorithm_t alg; + psa_status_t (*aead_crypt)(const psa_key_attributes_t *attributes, const uint8_t *key, + size_t key_size, psa_algorithm_t alg, const uint8_t *nonce, + size_t nonce_length, const uint8_t *add_data, + size_t add_data_len, const uint8_t *input, size_t input_len, + uint8_t *output, size_t output_size, size_t *output_len); + + secure_storage_its_transform_aead_get_scheme(&key_type, &alg); + + psa_set_key_usage_flags(&key_attributes, operation); + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_type(&key_attributes, key_type); + psa_set_key_algorithm(&key_attributes, alg); + psa_set_key_bits(&key_attributes, sizeof(key) * 8); + + /* Avoid calling psa_aead_*crypt() because that would require importing keys into + * PSA Crypto. This gets called from PSA Crypto for storing persistent keys so, + * even if using PSA_KEY_LIFETIME_VOLATILE, it would corrupt the global key store + * which holds all the active keys in the PSA Crypto core. + */ + aead_crypt = (operation == PSA_KEY_USAGE_ENCRYPT) ? + psa_driver_wrapper_aead_encrypt : psa_driver_wrapper_aead_decrypt; + + ret = secure_storage_its_transform_aead_get_key(uid, key); + if (ret != PSA_SUCCESS) { + return ret; + } + + ret = aead_crypt(&key_attributes, key, sizeof(key), alg, nonce, + CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE, add_data, + add_data_len, input, input_len, output, output_size, output_len); + + mbedtls_platform_zeroize(key, sizeof(key)); + return ret; +} + +enum { CIPHERTEXT_MAX_SIZE + = PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE) }; + +BUILD_ASSERT(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD + == CIPHERTEXT_MAX_SIZE - CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE + + CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE); + +BUILD_ASSERT(SECURE_STORAGE_ALL_CREATE_FLAGS + <= (1 << (8 * sizeof(secure_storage_packed_create_flags_t))) - 1); + +struct stored_entry { + secure_storage_packed_create_flags_t create_flags; + uint8_t nonce[CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE]; + uint8_t ciphertext[CIPHERTEXT_MAX_SIZE]; /* Keep last as this is variable in size. */ +} __packed; +BUILD_ASSERT(sizeof(struct stored_entry) == SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE); + +/** @return The length of a `struct stored_entry` whose `ciphertext` is `len` bytes long. */ +#define STORED_ENTRY_LEN(len) (sizeof(struct stored_entry) - CIPHERTEXT_MAX_SIZE + len) + +struct additional_data { + secure_storage_its_uid_t uid; + secure_storage_packed_create_flags_t create_flags; +} __packed; + +psa_status_t secure_storage_its_transform_to_store( + secure_storage_its_uid_t uid, size_t data_len, const void *data, + secure_storage_packed_create_flags_t create_flags, + uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t *stored_data_len) +{ + psa_status_t ret; + struct stored_entry *stored_entry = (struct stored_entry *)stored_data; + const struct additional_data add_data = {.uid = uid, .create_flags = create_flags}; + size_t ciphertext_len; + + stored_entry->create_flags = create_flags; + + ret = secure_storage_its_transform_aead_get_nonce(stored_entry->nonce); + if (ret != PSA_SUCCESS) { + return ret; + } + + ret = psa_aead_crypt(PSA_KEY_USAGE_ENCRYPT, uid, stored_entry->nonce, sizeof(add_data), + &add_data, data_len, data, sizeof(stored_entry->ciphertext), + &stored_entry->ciphertext, &ciphertext_len); + if (ret == PSA_SUCCESS) { + *stored_data_len = STORED_ENTRY_LEN(ciphertext_len); + } + return ret; +} + +psa_status_t secure_storage_its_transform_from_store( + secure_storage_its_uid_t uid, size_t stored_data_len, + const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t data_size, void *data, size_t *data_len, + psa_storage_create_flags_t *create_flags) +{ + if (stored_data_len < STORED_ENTRY_LEN(0)) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t ret; + struct stored_entry *stored_entry = (struct stored_entry *)stored_data; + const struct additional_data add_data = {.uid = uid, + .create_flags = stored_entry->create_flags}; + const size_t ciphertext_len = stored_data_len - STORED_ENTRY_LEN(0); + + ret = psa_aead_crypt(PSA_KEY_USAGE_DECRYPT, uid, stored_entry->nonce, sizeof(add_data), + &add_data, ciphertext_len, stored_entry->ciphertext, data_size, data, + data_len); + if (ret == PSA_SUCCESS) { + *create_flags = stored_entry->create_flags; + } + return ret; +} diff --git a/subsys/secure_storage/src/its/transform/aead_get.c b/subsys/secure_storage/src/its/transform/aead_get.c new file mode 100644 index 000000000000000..07492b47e3f4f1f --- /dev/null +++ b/subsys/secure_storage/src/its/transform/aead_get.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL); + +#ifdef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_AES_GCM +#define PSA_KEY_TYPE PSA_KEY_TYPE_AES +#define PSA_ALG PSA_ALG_GCM +#elif defined(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CHACHA20_POLY1305) +#define PSA_KEY_TYPE PSA_KEY_TYPE_CHACHA20 +#define PSA_ALG PSA_ALG_CHACHA20_POLY1305 +#endif +#ifndef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CUSTOM +void secure_storage_its_transform_aead_get_scheme(psa_key_type_t *key_type, psa_algorithm_t *alg) +{ + *key_type = PSA_KEY_TYPE; + *alg = PSA_ALG; +} +#endif /* !CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_SCHEME_CUSTOM */ + +#ifndef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM + +#define SHA256_OUTPUT_SIZE 32 +BUILD_ASSERT(SHA256_OUTPUT_SIZE == PSA_HASH_LENGTH(PSA_ALG_SHA_256)); +BUILD_ASSERT(SHA256_OUTPUT_SIZE >= CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE); + +static psa_status_t hash_data_into_key( + size_t data_len, const void *data, + uint8_t key[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE]) +{ + size_t hash_len; + +#if CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE == SHA256_OUTPUT_SIZE + /* Save stack usage and avoid unnecessary memory operations.*/ + return psa_hash_compute(PSA_ALG_SHA_256, data, data_len, key, + CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE, &hash_len); +#else + uint8_t hash_output[SHA256_OUTPUT_SIZE]; + const psa_status_t ret = psa_hash_compute(PSA_ALG_SHA_256, data, data_len, hash_output, + sizeof(hash_output), &hash_len); + + if (ret == PSA_SUCCESS) { + memcpy(key, hash_output, CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE); + mbedtls_platform_zeroize(hash_output, sizeof(hash_output)); + } + return ret; +#endif +} + +#ifdef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_DEVICE_ID_HASH + +#define WARNING "Using a potentially insecure PSA ITS encryption key provider." + +psa_status_t secure_storage_its_transform_aead_get_key( + secure_storage_its_uid_t uid, + uint8_t key[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE]) +{ + psa_status_t ret; + ssize_t hwinfo_ret; + struct { + uint8_t device_id[8]; + secure_storage_its_uid_t uid; /* acts as a salt */ + } __packed data; + + hwinfo_ret = hwinfo_get_device_eui64(data.device_id); + if (hwinfo_ret != 0) { + hwinfo_ret = hwinfo_get_device_id(data.device_id, sizeof(data.device_id)); + if (hwinfo_ret <= 0) { + return PSA_ERROR_HARDWARE_FAILURE; + } + if (hwinfo_ret < sizeof(data.device_id)) { + memset(data.device_id + hwinfo_ret, 0, sizeof(data.device_id) - hwinfo_ret); + } + } + data.uid = uid; + ret = hash_data_into_key(sizeof(data), &data, key); + + mbedtls_platform_zeroize(data.device_id, sizeof(data.device_id)); + return ret; +} + +#elif defined(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_ENTRY_UID_HASH) + +#define WARNING "Using an insecure PSA ITS encryption key provider." + +psa_status_t secure_storage_its_transform_aead_get_key( + secure_storage_its_uid_t uid, + uint8_t key[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_SIZE]) +{ + return hash_data_into_key(sizeof(uid), &uid, key); +} + +#endif /* CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER */ + +#ifndef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NO_INSECURE_KEY_WARNING + +static int warn_insecure_key(void) +{ + printk("WARNING: %s\n", WARNING); + LOG_WRN("%s", WARNING); + return 0; +} +SYS_INIT(warn_insecure_key, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +#endif /* !CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NO_INSECURE_KEY_WARNING */ + +#endif /* !CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_KEY_PROVIDER_CUSTOM */ + +#ifdef CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER_DEFAULT + +psa_status_t secure_storage_its_transform_aead_get_nonce( + uint8_t nonce[static CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE]) +{ + psa_status_t ret; + static uint8_t s_nonce[CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_SIZE]; + static bool s_nonce_initialized; + + if (!s_nonce_initialized) { + ret = psa_generate_random(s_nonce, sizeof(s_nonce)); + if (ret != PSA_SUCCESS) { + return ret; + } + s_nonce_initialized = true; + } else { + for (unsigned int i = 0; i != sizeof(s_nonce); ++i) { + ++s_nonce[i]; + if (s_nonce[i] != 0) { + break; + } + } + } + + memcpy(nonce, &s_nonce, sizeof(s_nonce)); + return PSA_SUCCESS; +} +#endif /* CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NONCE_PROVIDER_DEFAULT */ diff --git a/subsys/secure_storage/src/log.c b/subsys/secure_storage/src/log.c new file mode 100644 index 000000000000000..e07be28ee7b6671 --- /dev/null +++ b/subsys/secure_storage/src/log.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +LOG_MODULE_REGISTER(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL); diff --git a/tests/subsys/secure_storage/psa/crypto/CMakeLists.txt b/tests/subsys/secure_storage/psa/crypto/CMakeLists.txt new file mode 100644 index 000000000000000..892a40102de7f24 --- /dev/null +++ b/tests/subsys/secure_storage/psa/crypto/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(app) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/secure_storage/psa/crypto/overlay-secure_storage.conf b/tests/subsys/secure_storage/psa/crypto/overlay-secure_storage.conf new file mode 100644 index 000000000000000..84d933c2332ba2e --- /dev/null +++ b/tests/subsys/secure_storage/psa/crypto/overlay-secure_storage.conf @@ -0,0 +1,12 @@ +CONFIG_ZTEST_STACK_SIZE=3072 +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_MBEDTLS=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y +CONFIG_MBEDTLS_ENTROPY_POLL_ZEPHYR=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y + +CONFIG_SECURE_STORAGE=y +# For testing isolation between the different callers of the ITS. +CONFIG_SECURE_STORAGE_PS_IMPLEMENTATION_ITS=y diff --git a/tests/subsys/secure_storage/psa/crypto/prj.conf b/tests/subsys/secure_storage/psa/crypto/prj.conf new file mode 100644 index 000000000000000..d512b2fd70a8b28 --- /dev/null +++ b/tests/subsys/secure_storage/psa/crypto/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y + +CONFIG_PSA_WANT_KEY_TYPE_AES=y +CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y diff --git a/tests/subsys/secure_storage/psa/crypto/src/main.c b/tests/subsys/secure_storage/psa/crypto/src/main.c new file mode 100644 index 000000000000000..d41fbadc9f372ce --- /dev/null +++ b/tests/subsys/secure_storage/psa/crypto/src/main.c @@ -0,0 +1,125 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +ZTEST_SUITE(secure_storage_psa_crypto, NULL, NULL, NULL, NULL, NULL); + +#define ID PSA_KEY_ID_USER_MIN +#define KEY_TYPE PSA_KEY_TYPE_AES +#define ALG PSA_ALG_CBC_NO_PADDING +#define KEY_BITS 256 + +static void fill_key_attributes(psa_key_attributes_t *key_attributes) +{ + *key_attributes = psa_key_attributes_init(); + psa_set_key_lifetime(key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_usage_flags(key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_id(key_attributes, ID); + psa_set_key_type(key_attributes, KEY_TYPE); + psa_set_key_algorithm(key_attributes, ALG); + psa_set_key_bits(key_attributes, KEY_BITS); +} + +static void fill_data(uint8_t *data, size_t size) +{ + zassert_equal(psa_generate_random(data, size), PSA_SUCCESS); +} + +ZTEST(secure_storage_psa_crypto, test_its_caller_isolation) +{ + psa_status_t ret; + psa_key_attributes_t key_attributes; + psa_key_attributes_t retrieved_key_attributes; + psa_key_id_t key_id; + uint8_t data[32]; + size_t data_length; + uint8_t its_data[sizeof(data)]; + uint8_t ps_data[sizeof(data)]; + + fill_data(its_data, sizeof(its_data)); + fill_data(ps_data, sizeof(ps_data)); + zassert_true(memcmp(its_data, ps_data, sizeof(data))); + ret = psa_its_set(ID, sizeof(its_data), its_data, PSA_STORAGE_FLAG_NONE); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_ps_set(ID, sizeof(ps_data), ps_data, PSA_STORAGE_FLAG_NONE); + zassert_equal(ret, PSA_SUCCESS); + + fill_key_attributes(&key_attributes); + ret = psa_generate_key(&key_attributes, &key_id); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(key_id, ID); + ret = psa_purge_key(ID); + zassert_equal(ret, PSA_SUCCESS); + + ret = psa_its_get(ID, 0, sizeof(data), data, &data_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(data_length, sizeof(data)); + zassert_mem_equal(data, its_data, sizeof(data)); + ret = psa_its_remove(ID); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_its_remove(ID); + zassert_equal(ret, PSA_ERROR_DOES_NOT_EXIST); + + ret = psa_ps_get(ID, 0, sizeof(data), data, &data_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(data_length, sizeof(data)); + zassert_mem_equal(data, ps_data, sizeof(data)); + ret = psa_ps_remove(ID); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_ps_remove(ID); + zassert_equal(ret, PSA_ERROR_DOES_NOT_EXIST); + + ret = psa_get_key_attributes(ID, &retrieved_key_attributes); + zassert_equal(ret, PSA_SUCCESS); + zassert_mem_equal(&retrieved_key_attributes, &key_attributes, sizeof(key_attributes)); + ret = psa_destroy_key(ID); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_get_key_attributes(ID, &retrieved_key_attributes); + zassert_equal(ret, PSA_ERROR_INVALID_HANDLE); +} + +ZTEST(secure_storage_psa_crypto, test_persistent_key_usage) +{ + psa_status_t ret; + psa_key_attributes_t key_attributes; + psa_key_id_t key_id; + uint8_t key_material[KEY_BITS / 8]; + + fill_key_attributes(&key_attributes); + fill_data(key_material, sizeof(key_material)); + ret = psa_import_key(&key_attributes, key_material, sizeof(key_material), &key_id); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(key_id, ID); + ret = psa_purge_key(ID); + zassert_equal(ret, PSA_SUCCESS); + + static uint8_t plaintext[1024]; + static uint8_t ciphertext[PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(KEY_TYPE, ALG, sizeof(plaintext))]; + static uint8_t decrypted_text[sizeof(plaintext)]; + size_t output_length; + + fill_data(plaintext, sizeof(plaintext)); + ret = psa_cipher_encrypt(ID, ALG, plaintext, sizeof(plaintext), + ciphertext, sizeof(ciphertext), &output_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(output_length, sizeof(ciphertext)); + ret = psa_purge_key(ID); + zassert_equal(ret, PSA_SUCCESS); + + ret = psa_cipher_decrypt(ID, ALG, ciphertext, output_length, + decrypted_text, sizeof(decrypted_text), &output_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(output_length, sizeof(plaintext)); + zassert_mem_equal(plaintext, decrypted_text, sizeof(plaintext)); + ret = psa_purge_key(ID); + zassert_equal(ret, PSA_SUCCESS); + + ret = psa_destroy_key(ID); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_destroy_key(ID); + zassert_equal(ret, PSA_ERROR_INVALID_HANDLE); +} diff --git a/tests/subsys/secure_storage/psa/crypto/testcase.yaml b/tests/subsys/secure_storage/psa/crypto/testcase.yaml new file mode 100644 index 000000000000000..1d1878650eccffd --- /dev/null +++ b/tests/subsys/secure_storage/psa/crypto/testcase.yaml @@ -0,0 +1,14 @@ +common: + tags: + - psa.secure_storage +tests: + secure_storage.psa.crypto.secure_storage: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + extra_args: EXTRA_CONF_FILE=overlay-secure_storage.conf + integration_platforms: + - native_sim + - nrf9151dk/nrf9151 + secure_storage.psa.crypto.tfm: + filter: CONFIG_BUILD_WITH_TFM + integration_platforms: + - nrf5340dk/nrf5340/cpuapp/ns diff --git a/tests/subsys/secure_storage/psa/its/CMakeLists.txt b/tests/subsys/secure_storage/psa/its/CMakeLists.txt new file mode 100644 index 000000000000000..5243afeaa852c42 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(app) + +target_sources(app PRIVATE src/main.c) + +zephyr_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_CUSTOM + src/custom_transform.c) + +zephyr_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM + src/custom_store.c) diff --git a/tests/subsys/secure_storage/psa/its/overlay-custom_store.conf b/tests/subsys/secure_storage/psa/its/overlay-custom_store.conf new file mode 100644 index 000000000000000..16d8b2eee381132 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-custom_store.conf @@ -0,0 +1 @@ +CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM=y diff --git a/tests/subsys/secure_storage/psa/its/overlay-custom_transform.conf b/tests/subsys/secure_storage/psa/its/overlay-custom_transform.conf new file mode 100644 index 000000000000000..8a95663d98a7fa5 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-custom_transform.conf @@ -0,0 +1,5 @@ +CONFIG_SECURE_STORAGE_ITS_TRANSFORM_IMPLEMENTATION_CUSTOM=y +CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD=0 + +# SETTINGS_MAX_VAL_LEN (256) - flags (1) +CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE=255 diff --git a/tests/subsys/secure_storage/psa/its/overlay-default_store.conf b/tests/subsys/secure_storage/psa/its/overlay-default_store.conf new file mode 100644 index 000000000000000..584a2d08febb5c9 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-default_store.conf @@ -0,0 +1,2 @@ +# Limit the space available for the maximum entry test to not take too long. +CONFIG_SETTINGS_NVS_SECTOR_COUNT=2 diff --git a/tests/subsys/secure_storage/psa/its/overlay-default_transform.conf b/tests/subsys/secure_storage/psa/its/overlay-default_transform.conf new file mode 100644 index 000000000000000..52751db59b622ee --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-default_transform.conf @@ -0,0 +1,8 @@ +CONFIG_MBEDTLS=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y +CONFIG_MBEDTLS_ENTROPY_POLL_ZEPHYR=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y + +# SETTINGS_MAX_VAL_LEN (256) - flags (1) - CONFIG_SECURE_STORAGE_ITS_TRANSFORM_OUTPUT_OVERHEAD (28) +CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE=227 diff --git a/tests/subsys/secure_storage/psa/its/overlay-secure_storage.conf b/tests/subsys/secure_storage/psa/its/overlay-secure_storage.conf new file mode 100644 index 000000000000000..3ca9fdabcf25eb1 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-secure_storage.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST_STACK_SIZE=3072 +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_SECURE_STORAGE=y diff --git a/tests/subsys/secure_storage/psa/its/overlay-tfm.conf b/tests/subsys/secure_storage/psa/its/overlay-tfm.conf new file mode 100644 index 000000000000000..78762d8afa3ad4f --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/overlay-tfm.conf @@ -0,0 +1,2 @@ +CONFIG_TFM_ITS_MAX_ASSET_SIZE_OVERRIDE=y +CONFIG_TFM_ITS_MAX_ASSET_SIZE=256 diff --git a/tests/subsys/secure_storage/psa/its/prj.conf b/tests/subsys/secure_storage/psa/its/prj.conf new file mode 100644 index 000000000000000..9467c2926896dd7 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/subsys/secure_storage/psa/its/src/custom_store.c b/tests/subsys/secure_storage/psa/its/src/custom_store.c new file mode 100644 index 000000000000000..fa3e97fb7a4a8a8 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/src/custom_store.c @@ -0,0 +1,73 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +static struct { + secure_storage_its_uid_t uid; + size_t data_length; + uint8_t data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE]; +} s_its_entries[100]; + +static int get_existing_entry_index(secure_storage_its_uid_t uid) +{ + __ASSERT_NO_MSG(uid.uid != 0); + + for (unsigned int i = 0; i != ARRAY_SIZE(s_its_entries); ++i) { + if (!memcmp(&uid, &s_its_entries[i].uid, sizeof(uid))) { + return i; + } + } + return -1; +} + +psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, + size_t data_length, const void *data) +{ + __ASSERT_NO_MSG(data_length <= sizeof(s_its_entries[0].data)); + int index = get_existing_entry_index(uid); + + if (index == -1) { + for (unsigned int i = 0; i != ARRAY_SIZE(s_its_entries); ++i) { + if (s_its_entries[i].uid.uid == 0) { + index = i; + break; + } + } + if (index == -1) { + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + s_its_entries[index].uid = uid; + } + + s_its_entries[index].data_length = data_length; + memcpy(s_its_entries[index].data, data, data_length); + return PSA_SUCCESS; +} + +psa_status_t secure_storage_its_store_get(secure_storage_its_uid_t uid, size_t data_size, + void *data, size_t *data_length) +{ + const int index = get_existing_entry_index(uid); + + if (index == -1) { + return PSA_ERROR_DOES_NOT_EXIST; + } + *data_length = MIN(data_size, s_its_entries[index].data_length); + memcpy(data, s_its_entries[index].data, *data_length); + return PSA_SUCCESS; +} + +psa_status_t secure_storage_its_store_remove(secure_storage_its_uid_t uid) +{ + const int index = get_existing_entry_index(uid); + + if (index == -1) { + return PSA_ERROR_DOES_NOT_EXIST; + } + s_its_entries[index].uid.uid = 0; + return PSA_SUCCESS; +} diff --git a/tests/subsys/secure_storage/psa/its/src/custom_transform.c b/tests/subsys/secure_storage/psa/its/src/custom_transform.c new file mode 100644 index 000000000000000..dba5876d6649d9b --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/src/custom_transform.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +psa_status_t secure_storage_its_transform_to_store( + secure_storage_its_uid_t uid, size_t data_len, const void *data, + secure_storage_packed_create_flags_t create_flags, + uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t *stored_data_len) +{ + *stored_data_len = data_len + sizeof(secure_storage_packed_create_flags_t); + __ASSERT_NO_MSG(data_len <= CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE); + __ASSERT_NO_MSG(*stored_data_len <= SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE); + memcpy(stored_data, data, data_len); + *(secure_storage_packed_create_flags_t *)(&stored_data[data_len]) = create_flags; + return PSA_SUCCESS; +} + +psa_status_t secure_storage_its_transform_from_store( + secure_storage_its_uid_t uid, size_t stored_data_len, + const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE], + size_t data_size, void *data, size_t *data_len, + psa_storage_create_flags_t *create_flags) +{ + *data_len = stored_data_len - sizeof(secure_storage_packed_create_flags_t); + __ASSERT_NO_MSG(data_size >= *data_len); + memcpy(data, stored_data, *data_len); + *create_flags = *(secure_storage_packed_create_flags_t *)(&stored_data[*data_len]); + return PSA_SUCCESS; +} diff --git a/tests/subsys/secure_storage/psa/its/src/main.c b/tests/subsys/secure_storage/psa/its/src/main.c new file mode 100644 index 000000000000000..d9bab46ba090d52 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/src/main.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +/* The flash must be erased after this test suite is run for the write-once entry test to pass. */ +ZTEST_SUITE(secure_storage_psa_its, NULL, NULL, NULL, NULL, NULL); + +#ifdef CONFIG_SECURE_STORAGE +#define MAX_DATA_SIZE CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE +#else +#define MAX_DATA_SIZE CONFIG_TFM_ITS_MAX_ASSET_SIZE +#endif + +#define UID (psa_storage_uid_t)1 + +static void fill_data_buffer(uint8_t data[static MAX_DATA_SIZE]) +{ + for (unsigned int i = 0; i != MAX_DATA_SIZE; ++i) { + data[i] = i; + } +} + +ZTEST(secure_storage_psa_its, test_all_sizes) +{ + psa_status_t ret; + uint8_t written_data[MAX_DATA_SIZE]; + struct psa_storage_info_t info; + uint8_t read_data[MAX_DATA_SIZE]; + size_t data_length; + + fill_data_buffer(written_data); + + for (unsigned int i = 0; i <= sizeof(written_data); ++i) { + + ret = psa_its_set(UID, i, written_data, PSA_STORAGE_FLAG_NONE); + zassert_equal(ret, PSA_SUCCESS); + + ret = psa_its_get_info(UID, &info); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(info.flags, PSA_STORAGE_FLAG_NONE); + zassert_equal(info.size, i); + zassert_equal(info.capacity, i); + + ret = psa_its_get(UID, 0, sizeof(read_data), read_data, &data_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(data_length, i); + zassert_mem_equal(read_data, written_data, data_length); + + ret = psa_its_remove(UID); + zassert_equal(ret, PSA_SUCCESS); + ret = psa_its_get_info(UID, &info); + zassert_equal(ret, PSA_ERROR_DOES_NOT_EXIST); + } +} + +ZTEST(secure_storage_psa_its, test_all_offsets) +{ + psa_status_t ret; + uint8_t written_data[MAX_DATA_SIZE]; + uint8_t read_data[MAX_DATA_SIZE]; + size_t data_length; + + fill_data_buffer(written_data); + ret = psa_its_set(UID, sizeof(written_data), written_data, PSA_STORAGE_FLAG_NONE); + zassert_equal(ret, PSA_SUCCESS); + + for (unsigned int i = 0; i <= sizeof(read_data); ++i) { + + ret = psa_its_get(UID, i, sizeof(read_data) - i, read_data, &data_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(data_length, sizeof(read_data) - i); + + zassert_mem_equal(read_data, written_data + i, data_length); + } +} + +ZTEST(secure_storage_psa_its, test_max_num_entries) +{ + psa_status_t ret = PSA_SUCCESS; + unsigned int i; + struct psa_storage_info_t info; + + for (i = 0; ret == PSA_SUCCESS; ++i) { + ret = psa_its_set(UID + i, sizeof(i), &i, PSA_STORAGE_FLAG_NONE); + } + const unsigned int max_num_entries = i - 1; + + zassert_true(max_num_entries > 1); + printk("Successfully wrote %u entries.\n", max_num_entries); + zassert_equal(ret, PSA_ERROR_INSUFFICIENT_STORAGE); + + for (i = 0; i != max_num_entries; ++i) { + unsigned int data; + size_t data_length; + + ret = psa_its_get(UID + i, 0, sizeof(data), &data, &data_length); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(data, i); + } + for (i = 0; i != max_num_entries; ++i) { + ret = psa_its_remove(UID + i); + zassert_equal(ret, PSA_SUCCESS); + } + for (i = 0; i != max_num_entries; ++i) { + ret = psa_its_get_info(UID + i, &info); + zassert_equal(ret, PSA_ERROR_DOES_NOT_EXIST); + } +} + +/* The flash must be erased between runs of this test for it to pass. */ +ZTEST(secure_storage_psa_its, test_write_once_flag) +{ + psa_status_t ret; + /* Use a UID that isn't used in the other tests for the write-once entry. */ + const psa_storage_uid_t uid = ~UID; + const uint8_t data[MAX_DATA_SIZE] = {}; + struct psa_storage_info_t info; + + ret = psa_its_set(uid, sizeof(data), data, PSA_STORAGE_FLAG_WRITE_ONCE); + zassert_equal(ret, PSA_SUCCESS, "%s%d", (ret == PSA_ERROR_NOT_PERMITTED) ? + "Has the flash been erased since this test ran? " : "", ret); + + ret = psa_its_get_info(uid, &info); + zassert_equal(ret, PSA_SUCCESS); + zassert_equal(info.flags, PSA_STORAGE_FLAG_WRITE_ONCE); + + ret = psa_its_set(uid, sizeof(data), data, PSA_STORAGE_FLAG_NONE); + zassert_equal(ret, PSA_ERROR_NOT_PERMITTED); + + ret = psa_its_remove(uid); + zassert_equal(ret, PSA_ERROR_NOT_PERMITTED); +} diff --git a/tests/subsys/secure_storage/psa/its/testcase.yaml b/tests/subsys/secure_storage/psa/its/testcase.yaml new file mode 100644 index 000000000000000..807fdf4bf44cf45 --- /dev/null +++ b/tests/subsys/secure_storage/psa/its/testcase.yaml @@ -0,0 +1,32 @@ +common: + integration_platforms: + - native_sim + platform_exclude: + - qemu_cortex_m0 # settings subsystem initialization fails + timeout: 120 + tags: + - psa.secure_storage +tests: + secure_storage.psa.its.secure_storage: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + extra_args: "EXTRA_CONF_FILE=\ + overlay-secure_storage.conf;overlay-default_transform.conf;overlay-default_store.conf" + integration_platforms: + - nrf5340dk/nrf5340/cpuapp + secure_storage.psa.its.secure_storage.custom.transform: + filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE + extra_args: "EXTRA_CONF_FILE=\ + overlay-secure_storage.conf;overlay-custom_transform.conf;overlay-default_store.conf" + secure_storage.psa.its.secure_storage.custom.store: + filter: CONFIG_SECURE_STORAGE + extra_args: "EXTRA_CONF_FILE=\ + overlay-secure_storage.conf;overlay-default_transform.conf;overlay-custom_store.conf" + secure_storage.psa.its.secure_storage.custom.both: + filter: CONFIG_SECURE_STORAGE + extra_args: "EXTRA_CONF_FILE=\ + overlay-secure_storage.conf;overlay-custom_transform.conf;overlay-custom_store.conf" + secure_storage.psa.its.tfm: + filter: CONFIG_BUILD_WITH_TFM + extra_args: EXTRA_CONF_FILE=overlay-tfm.conf + integration_platforms: + - nrf9151dk/nrf9151/ns