278 lines
13 KiB
ReStructuredText
278 lines
13 KiB
ReStructuredText
======================================
|
|
Internal Trusted Storage (ITS) Service
|
|
======================================
|
|
|
|
:Author: Jamie Fox
|
|
:Organization: Arm Limited
|
|
:Contact: Jamie Fox <jamie.fox@arm.com>
|
|
:Status: Accepted
|
|
|
|
PSA Internal Trusted Storage
|
|
============================
|
|
PSA Internal Trusted Storage (ITS) is a PSA RoT Service for storing the most
|
|
security-critical device data (e.g. cryptographic keys) in internal storage,
|
|
which is trusted to provide data confidentiality and authenticity. This
|
|
contrasts with PSA Protected Storage, which is an Application RoT service that
|
|
allows larger data sets to be stored securely in external flash, with the option
|
|
for encryption, authentication and rollback protection to protect the
|
|
data-at-rest.
|
|
|
|
Current TF-M Secure Storage
|
|
===========================
|
|
Currently, the TF-M Secure Storage service implements PSA Protected Storage
|
|
version 1.0-beta2. There is not yet an implementation of PSA Internal Trusted
|
|
Storage in TF-M.
|
|
|
|
New TF-M service
|
|
================
|
|
The proposal is to implement the *PSA Internal Trusted Storage API* with the
|
|
*TF-M Internal Trusted Storage service*. It can be abbreviated to *TF-M ITS
|
|
service* in general and to ``its`` in code. This name has the advantage of
|
|
making clear the correspondence between the service and the API it implements.
|
|
|
|
If this name is adopted, then it may make sense to rename the *Secure Storage
|
|
service* to the *Protected Storage service* in the future to match. Then "secure
|
|
storage" could refer to the two services as a collective.
|
|
|
|
The TF-M ITS service will implement PSA ITS version 1.0. It will be provided by
|
|
a separate partition to Protected Storage, for a couple of reasons:
|
|
|
|
- To permit isolation between the services.
|
|
|
|
- ITS is a PSA RoT Service, while Protected Storage is an Application RoT
|
|
Service.
|
|
|
|
- To avoid circular dependencies.
|
|
|
|
- The PSA Firmware Framework does not permit circular dependencies between
|
|
partitions, which would occur if Protected Storage and ITS were provided by
|
|
the same partition. Protected Storage depends on Crypto, which in turn
|
|
depends on ITS.
|
|
|
|
The existing SST filesystem will be reused to provide the backend of the
|
|
service, with the flash layer modified to direct storage to internal flash,
|
|
rather than external.
|
|
|
|
Compared to Protected Storage, encryption, authentication and rollback
|
|
protection are not required, so the SST encrypted object layer and the crypto
|
|
and NV counter interfaces are not required. The rollback protection feature of
|
|
the object table is also not required.
|
|
|
|
Code structure
|
|
==============
|
|
The code structure of the service will be as follows:
|
|
|
|
``interface/``
|
|
|
|
- ``include/psa/internal_trusted_storage.h`` - PSA ITS API
|
|
- ``src/tfm_its_api.c`` - PSA ITS API implementation for NSPE
|
|
|
|
``secure_fw/ns_callable/tfm_veneers.c`` - ITS veneers (auto-generated from
|
|
manifest)
|
|
|
|
``secure_fw/partitions/internal_trusted_storage/``
|
|
|
|
- ``tfm_internal_trusted_storage.yaml`` - Partition manifest
|
|
- ``tfm_its_secure_api.c`` - PSA ITS API implementation for SPE
|
|
- ``tfm_its_req_mngr.c`` - Uniform secure functions and IPC request handlers
|
|
- ``tfm_internal_trusted_storage.h`` - TF-M ITS API (with client_id parameter)
|
|
- ``tfm_internal_trusted_storage.c`` - TF-M ITS implementation, using the
|
|
flash_fs as a backend
|
|
- ``flash_fs/`` - Filesystem
|
|
- ``flash/`` - Flash interface
|
|
|
|
``test/suites/its/``
|
|
|
|
- ``non_secure/psa_its_ns_interface_testsuite.c`` - Non-secure interface tests
|
|
- ``secure/psa_its_s_interface_testsuite.c`` - Secure interface tests
|
|
|
|
TF-M ITS implementation
|
|
-----------------------
|
|
The following APIs will be exposed by ``tfm_internal_trusted_storage.h``::
|
|
|
|
psa_status_t tfm_its_init(void);
|
|
|
|
psa_status_t tfm_its_set(int32_t client_id,
|
|
psa_storage_uid_t uid,
|
|
size_t data_length,
|
|
const void *p_data,
|
|
psa_storage_create_flags_t create_flags);
|
|
|
|
psa_status_t tfm_its_get(int32_t client_id,
|
|
psa_storage_uid_t uid,
|
|
size_t data_offset,
|
|
size_t data_size,
|
|
void *p_data,
|
|
size_t *p_data_length);
|
|
|
|
psa_status_t tfm_its_get_info(int32_t client_id,
|
|
psa_storage_uid_t uid,
|
|
struct psa_storage_info_t *p_info);
|
|
|
|
psa_status_t tfm_its_remove(int32_t client_id,
|
|
psa_storage_uid_t uid);
|
|
|
|
That is, the TF-M ITS APIs will have the same prototypes as the PSA ITS APIs,
|
|
but with the addition of a ``client_id`` parameter, which will be passed from
|
|
the ITS request manager. A ``tfm_its_init`` function will also be present, which
|
|
will be called at initialisation time and not exposed through a veneer or SID.
|
|
|
|
The implementation in ``tfm_internal_trusted_storage.c`` must validate the
|
|
parameters (excepting memory references, which are validated by the SPM),
|
|
translate the UID and client ID into a file ID and then make appropriate calls
|
|
to the filesystem layer. It must also take care ensure that any PSA Storage
|
|
flags associated with the UID are honoured.
|
|
|
|
Filesystem
|
|
----------
|
|
The ITS filesystem will be copied and modified from the SST filesystem. The
|
|
modifications required will be to rename symbols from ``sst`` to ``its`` and to
|
|
update the implementation to be aligned with the latest version of the PSA
|
|
Storage spec (which consists mainly of moving to the ``psa_status_t`` error type
|
|
and using common error codes from ``psa/error.h``).
|
|
|
|
The filesystem will also be modified to align the size of each file stored to
|
|
the alignment requirement exposed by the flash interface, by adding appropriate
|
|
padding.
|
|
|
|
The filesystem code will be de-duplicated again once the ITS service is
|
|
implemented (see below).
|
|
|
|
Flash layer
|
|
-----------
|
|
The flash layer will be copied from SST, and modified to direct writes to the
|
|
internal flash device. It too needs to be updated to use ``psa_status_t`` error
|
|
types.
|
|
|
|
Platform layer
|
|
--------------
|
|
The TF-M platform layer must be be updated to distinguish between the external
|
|
flash device used for Protected Storage and internal flash device used for ITS.
|
|
A flash region for the relevant storage service needs to be allocated in each.
|
|
|
|
On test platforms these may just be two distinct regions of the same flash
|
|
device, but in general they will separate devices with their own drivers.
|
|
|
|
Detailed design considerations
|
|
==============================
|
|
|
|
Mapping UID onto file ID
|
|
------------------------
|
|
The ITS APIs identify assets with 64-bit UIDs, to which the ITS service must
|
|
append the 32-bit client ID of the calling partition for access control. The
|
|
existing filesystem uses 32-bit file IDs to identify files, so some mapping
|
|
would be required to convert between the identifiers.
|
|
|
|
SST uses the object table to do the mapping from client ID, UID pairs to file
|
|
IDs, which means making an extra filesystem read/write for each get/set
|
|
operation. This mapping has minimal overhead for SST though, because object
|
|
table lookups are already required for rollback protection.
|
|
|
|
For ITS, no rollback protection feature is required, so there are two options:
|
|
|
|
- Keep a simplified version of the SST object table that just maps from
|
|
(client ID, UID) to file ID
|
|
|
|
- Modify the filesystem to take (at least) 96-bit file IDs, in the form of a
|
|
fixed-length char buffer.
|
|
|
|
The advantage of the former is that it would require no extra modification to
|
|
the existing filesystem code, and the existing SST object table could be cut
|
|
down for ITS. However, it would mean that every ITS request would invoke twice
|
|
the number of filesystem operations, increasing latency and flash wear. The code
|
|
size of the ITS partition would be increased, as would RAM usage as the table
|
|
would need to be read into RAM.
|
|
|
|
The latter option would make the filesystem slightly more complex: the size of a
|
|
metadata entry would be increased by 64-bits and the 96-bit fids would need to
|
|
be copied and compared with ``memcpy`` and ``memcmp`` calls. On the other hand,
|
|
mapping onto file IDs would incur only the cost of copying the UID and client ID
|
|
values into the file ID buffer.
|
|
|
|
A third, even more general, solution would be to use arbitrary-length
|
|
null-terminated strings as the file IDs. This is the standard solution in
|
|
full-featured filesystems, but we do not currently require this level of
|
|
complexity in secure storage.
|
|
|
|
With this in mind, the proposed option is the second.
|
|
|
|
Storing create flags
|
|
--------------------
|
|
The ITS APIs provide a 32-bit ``create_flags`` parameter, which contains bit
|
|
flags that determine the properties of the stored data. Only one flag is
|
|
currently defined for ITS: ``PSA_STORAGE_FLAG_WRITE_ONCE``, which prevents a UID
|
|
from being modified or deleted after it is set for the first time.
|
|
|
|
There are two places that these flags could be stored: in the file data or as
|
|
part of the file metadata.
|
|
|
|
For the first option, the ITS implementation would need to copy to the flags
|
|
into the buffer containing the data, and adjust the size accordingly, for each
|
|
set operation, and the reverse for each get. Every get_info operation would need
|
|
to read some of the file data, rather than just the metadata, implying a second
|
|
flash read. A potential downside is that many of the cryptographic assets stored
|
|
in ITS will be aligned to power-of-two sizes; adding an extra 32-bits would
|
|
misalign the size, which may reduce flash performance or necessitate adding
|
|
padding to align to the flash page size.
|
|
|
|
To implement the second option, a 32-bit ``flag`` field would be added to the
|
|
filesystem's metadata structure, whose interpretation is defined by the user.
|
|
This field would clearly be catered towards the PSA Storage APIs, even if
|
|
nominally generic, and alternative filesystems may not have any such field.
|
|
However, it is a more intuitive solution and would simplify both flash alignment
|
|
and get_info operations.
|
|
|
|
Overall, it seems more beneficial to store the flags in the metadata, so this is
|
|
the proposed solution.
|
|
|
|
Code sharing between Protected Storage and ITS
|
|
----------------------------------------------
|
|
To de-duplicate the filesystem code used by both Protected Storage and ITS, it
|
|
is proposed that Protected Storage calls ITS APIs as its backend filesystem.
|
|
|
|
Protected Storage essentially becomes an encryption, authentication and rollback
|
|
protection layer on top of ITS. It makes IPC requests or secure function calls
|
|
to the ITS service to do filesystem operations on its behalf.
|
|
|
|
This has a couple of advantages:
|
|
|
|
- It shrinks Protected Storage's stack size, because the filesystem and flash
|
|
layer stack is only in ITS.
|
|
|
|
- It automatically solves the problem of ensuring mutual exclusion in the
|
|
filesystem and flash layers when Protected Storage and ITS are called
|
|
concurrently. The second request to ITS will just be made to wait by the SPM.
|
|
|
|
The disadvantage of this approach is that it will increase the latency of
|
|
Protected Storage requests, due to the extra overhead associated with making a
|
|
second IPC request or secure function call. It also limits Protected Storage to
|
|
using only the ITS APIs, unless extra veneers are added solely for Protected
|
|
Storage to use. This, for example, prevents Protected Storage from doing partial
|
|
writes to file without reading and re-writing the whole file.
|
|
|
|
ITS will need to be modified to direct calls from Protected Storage to a
|
|
different flash device. It can use the client ID to detect when the caller is
|
|
Protected Storage, and pass down the identity of the flash device to use to the
|
|
flash layer, which then calls the appropriate driver.
|
|
|
|
An open question is what to do if Protected Storage itself wants to store
|
|
something in internal storage in the future (e.g. rollback counters, hash
|
|
tree/table or top hash). A couple of possible solutions would be:
|
|
|
|
- Divide up the UIDs, so certain UIDs from Protected Storage refer to assets in
|
|
internal storage, and others to ones in external storage.
|
|
|
|
- Use the ``type`` field of ``psa_call`` in IPC model and extra veneers in
|
|
library model to distinguish between internal and external storage requests.
|
|
|
|
The other option for code sharing would be for Protected Storage and ITS to
|
|
directly share filesystem code, which would be placed in a shared code region.
|
|
With this approach, mutual exclusion to the flash device would need to be
|
|
implemented separately, as would some way of isolating static memory belonging
|
|
to each partition but not the code. Because of these complications, this option
|
|
has not been considered further at this time.
|
|
|
|
--------------
|
|
|
|
*Copyright (c) 2019, Arm Limited. All rights reserved.*
|