Trusted storage
The trusted storage library enables its users to provide integrity, confidentiality and authenticity of stored data using Authenticated Encryption with Associated Data (AEAD) algorithms or cryptographic hash, without the use of TF-M Platform Root of Trust (PRoT). The library implements the PSA Certified Secure Storage API.
Overview
The following subsections give an overview of the library architecture, its interfaces, choices and backends.
Architecture
The trusted storage library is designed and implemented in a modular way, which allows and simplifies customization. This is realized by using backends for the different tasks performed within the trusted storage.
The library provides users two choices that are interfacing backends: TRUSTED_STORAGE_BACKEND
and TRUSTED_STORAGE_STORAGE_BACKEND
.
The backends are also modular, allowing customization of what crypto implementation and the key nonce are provided.
The following image gives an overview of the default architecture of the trusted storage library.
External storage is not supported by the trusted storage library by default. To add support for external storage, implement a custom storage backend.
Interfaces
The trusted storage library provides two storage interfaces for use with device-protected storage:
PSA internal trusted storage, designed to store critical data that must be placed inside internal non-volatile memory. The size of the storage available by the internal trusted storage API is expected to be limited, and therefore should be used for small, security-critical values. Examples of assets that require this kind of storage are replay protection values for external storage and keys for use by components of the PSA Root of Trust.
PSA protected storage, designed to store all other critical data that do not need to be stored inside internal non-volatile memory.
The two interfaces provide a consistent way for applications to access the storage types, through PSA Internal Trusted Storage API and PSA Protected Storage API.
Choices and backends
The trusted storage library comes with two choices:
TRUSTED_STORAGE_BACKEND
that defines a backend for handling of encryption, authentication or other means of validation of the stored data. It is responsible for what is happening with the data before and after they are read from or written to non-volatile storage.TRUSTED_STORAGE_STORAGE_BACKEND
that defines a backend that handles how the data are written to non-volatile storage.
In other words, TRUSTED_STORAGE_BACKEND
is responsible for modifying the assets before they are forwarded to the TRUSTED_STORAGE_STORAGE_BACKEND
, which again handles storing of data in the non-volatile storage.
The following backends are used in the trusted storage library:
TRUSTED_STORAGE_BACKEND_AEAD
Uses an AEAD scheme to provide integrity, confidentiality and authenticity. The trusted storage library provides the
TRUSTED_STORAGE_BACKEND_AEAD
backend, but it has support for adding other secure implementation backends to provide various levels of trust, depending on the device security features.Uses a separate backend to perform the AEAD operation, set by the Kconfig option
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_CRYPTO
. The nonce and the key for the AEAD operation are provided by separate backends, allowing a custom implementation.For the key, the default choice is to use the
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_KEY_DERIVE_FROM_HUK
Kconfig option. With this option, a Hardware unique key and the UID are used to derive an AEAD key.TRUSTED_STORAGE_STORAGE_BACKEND_SETTINGS
Stores the given assets by using Zephyr’s settings subsystem. The backend requires that Zephyr’s settings subsystem is enabled for use (Kconfig option
CONFIG_SETTINGS
has to be set).The trusted storage library provides the
TRUSTED_STORAGE_STORAGE_BACKEND_SETTINGS
as a storage backend, but it has support for adding other memory types for storage.
Requirements
Before using the trusted storage library with its default settings and options, make sure to meet the following requirements:
The hardware unique key (HUK) library and sample are enabled and ready for use to derive an AEAD key.
Zephyr’s settings subsystem has to be enabled for use by setting the Kconfig option
CONFIG_SETTINGS
.The settings subsystem uses the Non-Volatile Storage (NVS) file system by default. This file system has to be mounted to a mount point at application startup. For more information about this, see File Systems.
Configuration
Set the Kconfig option CONFIG_TRUSTED_STORAGE
to enable the trusted storage library.
Use the Kconfig option CONFIG_TRUSTED_STORAGE_BACKEND
to define the backend that handles encryption and authentication.
If this Kconfig option is set, the configuration defaults to the only currently available option CONFIG_TRUSTED_STORAGE_BACKEND_AEAD
to use an AEAD scheme for encryption and authentication of stored data.
Use the Kconfig option CONFIG_TRUSTED_STORAGE_STORAGE_BACKEND
to define the backend that handles how the data are written to and from the non-volatile storage.
If this Kconfig option is set, the configuration defaults to the CONFIG_TRUSTED_STORAGE_STORAGE_BACKEND_SETTINGS
option to use Zephyr’s settings subsystem.
Alternatively, you can use a custom storage backend by setting the Kconfig option CONFIG_TRUSTED_STORAGE_STORAGE_BACKEND_CUSTOM
.
The following options are used to configure the AEAD backend and its behavior:
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_MAX_DATA_SIZE
Defines the maximum data storage size for the AEAD backend (256 as default value).
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_CRYPTO
Selects what implementation is used to perform the AEAD cryptographic operations. This option defaults to
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_CRYPTO_PSA_CHACHAPOLY
using the ChaCha20Poly1305 AEAD scheme via PSA APIs.CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_NONCE
Selects what implementation provides AEAD nonce. You can choose one of the following values when this configuration option is set:
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_NONCE_PSA_SEED_COUNTER
- Selects the PSA Crypto for nonce initial random seed and a counter incrementing nonce for each AEAD encryption. This is the default option for the AEAD nonce.CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_NONCE_CUSTOM
- Selects a custom implementation for AEAD nonce provider.
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_KEY
Selects what implementation provides the AEAD keys. You can choose one of the following values when this configuration option is set:
CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_KEY_DERIVE_FROM_HUK
- Selects HUK to derive a key based on the UID file. This is the default selection for the AEAD key provider, and also the only really secure option.CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_KEY_HASH_UID
- Selects the use of SHA-256 of the UID file as the key. This option is not as secure as when using HUKs for key derivation as it will only provide integrity of the data. Use this option only when HUK is not possible to use.CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_KEY_CUSTOM
- Selects a custom implementation for the AEAD key provider.
Usage
The trusted storage library can only be used on a build using a board target with CMSE disabled (/cpuapp
).
When you build for /cpuapp
, you build the firmware for the application core without CMSE and thus no TF-M.
The library can be used directly on such a build to store important assets.
However, for cryptographic keys we suggest to use the PSA functions for key management.
These APIs will internally use this library to store persistent keys.
Dependencies
This library has dependencies to following libraries:
API documentation
Protected storage
include/protected_storage.h
subsys/secure_storage/src/protected_storage/backend_interface.c
- group protected_storage
Defines
-
PSA_PS_API_VERSION_MAJOR
PSA_PS_API_VERSION version.
Major and minor PSA_PS_API_VERSION numbers
-
PSA_PS_API_VERSION_MINOR
Functions
-
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)
Create a new, or modify an existing, uid/value pair.
Stores data in the protected storage.
- Parameters:
uid – [in] The identifier for the data
data_length – [in] The size in bytes of the data in
p_data
p_data – [in] A buffer containing the data
create_flags – [in] The flags that the data will be stored with
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_NOT_PERMITTED – The operation failed because the provided
uid
value was already created with PSA_STORAGE_FLAG_WRITE_ONCEPSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided pointers(
p_data
) is invalid, for example isNULL
or references memory the caller cannot accessPSA_ERROR_NOT_SUPPORTED – The operation failed because one or more of the flags provided in
create_flags
is not supported or is not validPSA_ERROR_INSUFFICIENT_STORAGE – The operation failed because there was insufficient space on the storage medium
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_GENERIC_ERROR – The operation failed because of an unspecified internal failure
- Returns:
A status indicating the success/failure of the operation
-
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)
Retrieve data associated with a provided uid.
Retrieves up to
data_size
bytes of the data associated withuid
, starting atdata_offset
bytes from the beginning of the data. Upon successful completion, the data will be placed in thep_data
buffer, which must be at leastdata_size
bytes in size. The length of the data returned will be inp_data_length
. Ifdata_size
is 0, the contents ofp_data_length
will be set to zero.- Parameters:
uid – [in] The uid value
data_offset – [in] The starting offset of the data requested
data_size – [in] The amount of data requested
p_data – [out] On success, the buffer where the data will be placed
p_data_length – [out] On success, this will contain size of the data placed in
p_data
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided arguments (
p_data
,p_data_length
) is invalid, for example isNULL
or references memory the caller cannot access. In addition, this can also happen ifdata_offset
is larger than the size of the data associated withuid
PSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided
uid
value was not found in the storagePSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_GENERIC_ERROR – The operation failed because of an unspecified internal failure
PSA_ERROR_DATA_CORRUPT – The operation failed because the data associated with the UID was corrupt
PSA_ERROR_INVALID_SIGNATURE – The operation failed because the data associated with the UID failed authentication
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info)
Retrieve the metadata about the provided uid.
Retrieves the metadata stored for a given
uid
- Parameters:
uid – [in] The
uid
valuep_info – [out] A pointer to the
psa_storage_info_t
struct that will be populated with the metadata
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided pointers(
p_info
) is invalid, for example isNULL
or references memory the caller cannot accessPSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided uid value was not found in the storage
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_GENERIC_ERROR – The operation failed because of an unspecified internal failure
PSA_ERROR_DATA_CORRUPT – The operation failed because the data associated with the UID was corrupt
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_ps_remove(psa_storage_uid_t uid)
Remove the provided uid and its associated data from the storage.
Removes previously stored data and any associated metadata, including rollback protection data.
- Parameters:
uid – [in] The
uid
value
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags and so on)
PSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided uid value was not found in the storage
PSA_ERROR_NOT_PERMITTED – The operation failed because the provided uid value was created with PSA_STORAGE_FLAG_WRITE_ONCE
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_GENERIC_ERROR – The operation failed because of an unspecified internal failure
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_ps_create(psa_storage_uid_t uid, size_t capacity, psa_storage_create_flags_t create_flags)
Reserves storage for the specified uid.
Upon success, the capacity of the storage will be capacity, and the size will be 0. It is only necessary to call this function for assets that will be written with the psa_ps_set_extended function. If only the psa_ps_set function is needed, calls to this function are redundant.
- Parameters:
uid – [in] The
uid
valuecapacity – [in] The capacity to be allocated in bytes
create_flags – [in] Flags indicating properties of storage
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_INSUFFICIENT_STORAGE – The operation failed because the capacity is bigger than the current available space
PSA_ERROR_NOT_SUPPORTED – The operation failed because the function is not implemented or one or more create_flags are not supported.
PSA_ERROR_INVALID_ARGUMENT – The operation failed because uid was 0 or create_flags specified flags that are not defined in the API.
PSA_ERROR_GENERIC_ERROR – The operation failed due to an unspecified error
PSA_ERROR_ALREADY_EXISTS – Storage for the specified uid already exists
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_ps_set_extended(psa_storage_uid_t uid, size_t data_offset, size_t data_length, const void *p_data)
Sets partial data into an asset.
Before calling this function, the storage must have been reserved with a call to psa_ps_create. It can also be used to overwrite data in an asset that was created with a call to psa_ps_set. Calling this function with data_length = 0 is permitted, which will make no change to the stored data.This function can overwrite existing data and/or extend it up to the capacity for the uid specified in psa_ps_create, but cannot create gaps.
That is, it has preconditions:
data_offset <= size
data_offset + data_length <= capacity and postconditions:
size = max(size, data_offset + data_length)
capacity unchanged.
- Parameters:
uid – [in] The
uid
valuedata_offset – [in] Offset within the asset to start the write
data_length – [in] The size in bytes of the data in p_data to write
p_data – [in] Pointer to a buffer which contains the data to write
- Return values:
PSA_SUCCESS – The asset exists, the input parameters are correct and the data is correctly written in the physical storage.
PSA_ERROR_STORAGE_FAILURE – The data was not written correctly in the physical storage
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one or more of the preconditions listed above regarding data_offset, size, or data_length was violated.
PSA_ERROR_DOES_NOT_EXIST – The specified uid was not found
PSA_ERROR_NOT_SUPPORTED – The implementation of the API does not support this function
PSA_ERROR_GENERIC_ERROR – The operation failed due to an unspecified error
PSA_ERROR_DATA_CORRUPT – The operation failed because the existing data has been corrupted.
PSA_ERROR_INVALID_SIGNATURE – The operation failed because the existing data failed authentication (MAC check failed).
PSA_ERROR_NOT_PERMITTED – The operation failed because it was attempted on an asset which was written with the flag PSA_STORAGE_FLAG_WRITE_ONCE
- Returns:
A status indicating the success/failure of the operation
-
uint32_t psa_ps_get_support(void)
Lists optional features.
- Returns:
A bitmask with flags set for all of the optional features supported by the implementation. Currently defined flags are limited to PSA_STORAGE_SUPPORT_SET_EXTENDED
-
PSA_PS_API_VERSION_MAJOR
Internal trusted storage
include/internal_trusted_storage.h
subsys/secure_storage/src/internal_trusted_storage/backend_interface.c
- group internal_trusted_storage
This file describes the PSA Internal Trusted Storage API
Functions
-
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)
Create a new, or modify an existing, uid/value pair.
Stores data in the internal storage.
- Parameters:
uid – [in] The identifier for the data
data_length – [in] The size in bytes of the data in
p_data
p_data – [in] A buffer containing the data
create_flags – [in] The flags that the data will be stored with
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_NOT_PERMITTED – The operation failed because the provided
uid
value was already created with PSA_STORAGE_FLAG_WRITE_ONCEPSA_ERROR_NOT_SUPPORTED – The operation failed because one or more of the flags provided in
create_flags
is not supported or is not validPSA_ERROR_INSUFFICIENT_STORAGE – The operation failed because there was insufficient space on the storage medium
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided pointers(
p_data
) is invalid, for example isNULL
or references memory the caller cannot access
- Returns:
A status indicating the success/failure of the operation
-
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)
Retrieve data associated with a provided UID.
Retrieves up to
data_size
bytes of the data associated withuid
, starting atdata_offset
bytes from the beginning of the data. Upon successful completion, the data will be placed in thep_data
buffer, which must be at leastdata_size
bytes in size. The length of the data returned will be inp_data_length
. Ifdata_size
is 0, the contents ofp_data_length
will be set to zero.- Parameters:
uid – [in] The uid value
data_offset – [in] The starting offset of the data requested
data_size – [in] The amount of data requested
p_data – [out] On success, the buffer where the data will be placed
p_data_length – [out] On success, this will contain size of the data placed in
p_data
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided
uid
value was not found in the storagePSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided arguments (
p_data
,p_data_length
) is invalid, for example isNULL
or references memory the caller cannot access. In addition, this can also happen ifdata_offset
is larger than the size of the data associated withuid
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info)
Retrieve the metadata about the provided uid.
Retrieves the metadata stored for a given
uid
as apsa_storage_info_t
structure.- Parameters:
uid – [in] The
uid
valuep_info – [out] A pointer to the
psa_storage_info_t
struct that will be populated with the metadata
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided uid value was not found in the storage
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one of the provided pointers(
p_info
) is invalid, for example isNULL
or references memory the caller cannot access
- Returns:
A status indicating the success/failure of the operation
-
psa_status_t psa_its_remove(psa_storage_uid_t uid)
Remove the provided uid and its associated data from the storage.
Deletes the data from internal storage.
- Parameters:
uid – [in] The
uid
value
- Return values:
PSA_SUCCESS – The operation completed successfully
PSA_ERROR_INVALID_ARGUMENT – The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags and so on)
PSA_ERROR_DOES_NOT_EXIST – The operation failed because the provided uid value was not found in the storage
PSA_ERROR_NOT_PERMITTED – The operation failed because the provided uid value was created with PSA_STORAGE_FLAG_WRITE_ONCE
PSA_ERROR_STORAGE_FAILURE – The operation failed because the physical storage has failed (Fatal error)
- Returns:
A status indicating the success/failure of the operation
-
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)