Commit 1740aaeb authored by Kevin Townsend's avatar Kevin Townsend Committed by Kumar Gala
Browse files

doc: guides: Add a TF-M guide



This commit adds a high-level overview of Trusted Firmware-M,
describing the basic architecture and integration work with Zephyr.

Co-authored-by: default avatarMarti Bolivar <marti.bolivar@nordicsemi.no>
Signed-off-by: default avatarKevin Townsend <kevin.townsend@linaro.org>
parent 8b8e8f99
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ User and Developer Guides
   portability/index.rst
   porting/index
   test/index
   tfm/index
   west/index
   optimizations/index
   zephyr_cmake_package.rst
+118 −0
Original line number Diff line number Diff line
TF-M Build System
#################

When building a valid ``_ns`` board target, TF-M will be built in the
background, and linked with the Zephyr non-secure application. No knowledge
of TF-M's build system is required in most cases, and the following will
build a TF-M and Zephyr image pair, and run it in qemu with no additional
steps required:

   .. code-block:: bash

     $ west build -p auto -t mps2_an521_ns samples/tfm_integration/psa_crypto/ -t run

The outputs and certain key steps in this build process are described here,
however, since you will need to understand and interact with the outputs, and
deal with signing the secure and non-secure images before deploying them.

Images Created by the TF-M Build
********************************

The TF-M build system creates the following executable files:

* tfm_s - the secure firmware
* tfm_ns - a nonsecure app which is discarded in favor of the Zephyr app
* bl2 - mcuboot, if enabled

For each of these, it creates .bin, .hex, .elf, and .axf files.

The TF-M build system also creates signed variants of tfm_s and tfm_ns, and a
file which combines them:

* tfm_s_signed
* tfm_ns_signed
* tfm_s_ns_signed

For each of these, only .bin files are created.

The Zephyr build system usually signs both tfm_s and the Zephyr ns app itself.
See below for details.

The 'tfm' target contains properties for all these paths.
For example, the following will resolve to ``<path>/tfm_s.hex``:

   .. code-block::

      $<TARGET_PROPERTY:tfm,TFM_S_HEX_FILE>

See the top level CMakeLists.txt file in the tfm module for an overview of all
the properties.

Signing Images
**************

When :kconfig:`CONFIG_TFM_BL2` is set to ``y``, TF-M uses a secure bootloader
(BL2) and firmware images must be signed with a private key. The firmware image
is validated by the bootloader during updates using the corresponding public
key, which is stored inside the secure bootloader firmware image.

By default, ``tfm/bl2/ext/mcuboot/root-rsa-3072.pem`` is used to sign secure
images, and ``tfm/bl2/ext/mcuboot/root-rsa-3072_1.pem`` is used to sign
non-secure images. Theses default .pem keys can (and **should**) be overridden
using the :kconfig:`CONFIG_TFM_KEY_FILE_S` and
:kconfig:`CONFIG_TFM_KEY_FILE_NS` config flags.

To satisfy `PSA Certified Level 1`_ requirements, **You MUST replace
the default .pem file with a new key pair!**

To generate a new public/private key pair, run the following commands:

   .. code-block:: bash

     $ imgtool keygen -k root-rsa-3072_s.pem -t rsa-3072
     $ imgtool keygen -k root-rsa-3072_ns.pem -t rsa-3072

You can then place the new .pem files in an alternate location, such as your
Zephyr application folder, and reference them in the ``prj.conf`` file via the
:kconfig:`CONFIG_TFM_KEY_FILE_S` and :kconfig:`CONFIG_TFM_KEY_FILE_NS` config
flags.

   .. warning::

     Be sure to keep your private key file in a safe, reliable location! If you
     lose this key file, you will be unable to sign any future firmware images,
     and it will no longer be possible to update your devices in the field!

After the built-in signing script has run, it creates a ``tfm_merged.hex``
file that contains all three binaries: bl2, tfm_s, and the zephyr app. This
hex file can then be flashed to your development board or run in QEMU.

.. _PSA Certified Level 1:
  https://www.psacertified.org/security-certification/psa-certified-level-1/

Custom CMake arguments
======================

When building a Zephyr application with TF-M it might be necessary to control
the CMake arguments passed to the TF-M build.

Zephyr TF-M build offers several Kconfig options for controlling the build, but
doesn't cover every CMake argument supported by the TF-M build system.

The ``TFM_CMAKE_OPTIONS`` property on the ``zephyr_property_target`` can be used
to pass custom CMake arguments to the TF-M build system.

To pass the CMake argument ``-DFOO=bar`` to the TF-M build system, place the
following CMake snippet in your CMakeLists.txt file.

   .. code-block:: cmake

     set_property(TARGET zephyr_property_target
                  APPEND PROPERTY TFM_CMAKE_OPTIONS
                  -DFOO=bar
     )

.. note::
   The ``TFM_CMAKE_OPTIONS`` is a list so it is possible to append multiple
   options. Also CMake generator expressions are supported, such as
   ``$<1:-DFOO=bar>``
+12 −0
Original line number Diff line number Diff line
.. _tfm:

Trusted Firmware-M
##################

.. toctree::
   :maxdepth: 1

   overview.rst
   requirements.rst
   build.rst
   integration.rst
+87 −0
Original line number Diff line number Diff line
Trusted Firmware-M Integration
##############################

The Trusted Firmware-M (TF-M) section contains information about the
integration between TF-M and Zephyr RTOS. Use this information to help
understand how to integrate TF-M with Zephyr for Cortex-M platforms and make
use of its secure run-time services in Zephyr applications.

Board Definitions
*****************

TF-M will be built for the secure processing environment along with Zephyr if
the :kconfig:`CONFIG_BUILD_WITH_TFM` flag is set to ``y``.

Generally, this value should never be set at the application level, however,
and all config flags required for TF-M should be set in a board variant with
the ``_ns`` suffix.

This board variant must define an appropriate flash, SRAM and peripheral
configuration that takes into account the initialisation process in the secure
processing environment. :kconfig:`CONFIG_TFM_BOARD` must also be set via
`modules/trusted-firmware-m/Kconfig.tfm <https://github.com/zephyrproject-rtos/zephyr/blob/main/modules/trusted-firmware-m/Kconfig.tfm>`__
to the board name that TF-M expects for this target, so that it knows which
target to build for the secure processing environment.

Example: ``mps2_an521_ns``
==========================

The ``mps2_an521`` target is a dual-core Arm Cortex-M33 evaluation board that,
when using the default board variant, would generate a secure Zephyr binary.

The optional ``mps2_an521_ns`` target, however, sets these additional
kconfig flags that indicate that Zephyr should be built as a
non-secure image, linked with TF-M as an external project, and optionally the
secure bootloader:

* :kconfig:`CONFIG_TRUSTED_EXECUTION_NONSECURE` ``y``
* :kconfig:`CONFIG_ARM_TRUSTZONE_M` ``y``

Comparing the ``mps2_an521.dts`` and ``mps2_an521_ns.dts`` files, we can see
that the ``_ns`` version defines offsets in flash and SRAM memory, which leave
the required space for TF-M and the secure bootloader:

::

    reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		/* The memory regions defined below must match what the TF-M
		 * project has defined for that board - a single image boot is
		 * assumed. Please see the memory layout in:
		 * https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/platform/ext/target/mps2/an521/partition/flash_layout.h
		 */

		code: memory@100000 {
			reg = <0x00100000 DT_SIZE_K(512)>;
		};

		ram: memory@28100000 {
			reg = <0x28100000 DT_SIZE_M(1)>;
		};
	};

This reserves 1 MB of code memory and 1 MB of RAM for secure boot and TF-M,
such that our non-secure Zephyr application code will start at 0x10000, with
RAM at 0x28100000. 512 KB code memory is available for the NS zephyr image,
along with 1 MB of RAM.

This matches the flash memory layout we see in ``flash_layout.h`` in TF-M:

::

    * 0x0000_0000 BL2 - MCUBoot (0.5 MB)
    * 0x0008_0000 Secure image     primary slot (0.5 MB)
    * 0x0010_0000 Non-secure image primary slot (0.5 MB)
    * 0x0018_0000 Secure image     secondary slot (0.5 MB)
    * 0x0020_0000 Non-secure image secondary slot (0.5 MB)
    * 0x0028_0000 Scratch area (0.5 MB)
    * 0x0030_0000 Protected Storage Area (20 KB)
    * 0x0030_5000 Internal Trusted Storage Area (16 KB)
    * 0x0030_9000 NV counters area (4 KB)
    * 0x0030_A000 Unused (984 KB)

``mps2/an521`` will be passed in to Tf-M as the board target, specified via
:kconfig:`CONFIG_TFM_BOARD`.
+272 −0
Original line number Diff line number Diff line
Trusted Firmware-M Overview
###########################

`Trusted Firmware-M (TF-M) <https://tf-m-user-guide.trustedfirmware.org/>`__
is a reference implementation of the Platform Security Architecture (PSA)
`IoT Security Framework <https://www.psacertified.org/what-is-psa-certified/>`__.
It defines and implements an architecture and a set of software components
that aim to address some of the main security concerns in IoT products.

Zephyr RTOS has been PSA Certified since Zephyr 2.0.0 with TF-M 1.0, and
is currently integrated with TF-M 1.3.0.

What Does TF-M Offer?
*********************

Through a set of secure services and by design, TF-M provides:

* Isolation of secure and non-secure resources
* Embedded-appropriate crypto
* Management of device secrets (keys, etc.)
* Firmware verification (and encryption)
* Protected off-chip data storage and retrieval
* Proof of device identity (device attestation)
* Audit logging

Build System Integration
************************

When using TF-M with a supported platform, TF-M will be automatically built and
link in the background as part of the standard Zephyr build process. This
build process makes a number of assumptions about how TF-M is being used, and
has certain implications about what the Zephyr application image can and can
not do:

* The secure processing environment (secure boot and TF-M) starts first
* Resource allocation for Zephyr relies on choices made in the secure image.

Architecture Overview
*********************

A TF-M application will, generally, have the following three parts, from most
to least trusted, left-to-right, with code execution happening in the same
order (secure boot > secure image > ns image).

While the secure bootloader is optional, it is enabled by default, and secure
boot is an important part of providing a secure solution:

::

    +-------------------------------------+           +--------------+
    | Secure Processing Environment (SPE) |           |     NSPE     |
    | +----------++---------------------+ |           | +----------+ |
    | |          ||                     | |           | |          | |
    | | bl2.bin  ||  tfm_s_signed.bin   | |           | |zephyr.bin| |
    | |          ||                     | | <- PSA -> | |          | |
    | |  Secure  || Trusted Firmware-M  | |    APIs   | |  Zephyr  | |
    | |   Boot   ||   (Secure Image)    | |           | |(NS Image)| |
    | |          ||                     | |           | |          | |
    | +----------++---------------------+ |           | +----------+ |
    +-------------------------------------+           +--------------+

Communication between the (Zephyr) Non-Secure Processing Environment (NSPE) and
the (TF-M) Secure Processing Environment image happens based on a set of PSA
APIs, and normally makes use of an IPC mechanism that is included as part of
the TF-M build, and implemented in Zephyr
(see :zephyr_file:`modules/trusted-firmware-m/interface`).

Root of Trust (RoT) Architecture
================================

TF-M is based upon a **Root of Trust (RoT)** architecture. This allows for
hierarchies of trust from most, to less, to least trusted, providing a sound
foundation upon which to build or access trusted services and resources.

The benefit of this approach is that less trusted components are prevented from
accessing or compromising more critical parts of the system, and error
conditions in less trusted environments won't corrupt more trusted, isolated
resources.

The following RoT hierarchy is defined for TF-M, from most to least trusted:

* PSA Root of Trust (**PRoT**), which consists of:

  * PSA Immutable Root of Trust: secure boot
  * PSA Updateable Root of Trust: most trusted secure services
* Application Root of Trust (**ARoT**): isolated secure services

The **PSA Immutable Root of Trust** is the most trusted piece of code in the
system, to which subsequent Roots of Trust are anchored. In TF-M, this is the
secure boot image, which verifies that the secure and non-secure images are
valid, have not been tampered with, and come from a reliable source. The
secure bootloader also verifies new images during the firmware update process,
thanks to the public signing key(s) built into it. As the name implies,
this image is **immutable**.

The **PSA Updateable Root of Trust** implements the most trusted secure
services and components in TF-M, such as the Secure Partition Manager (SPM),
and shared secure services like PSA Crypto, Internal Trusted Storage (ITS),
etc. Services in the PSA Updateable Root of Trust have access to other
resources in the same Root of Trust.

The **Application Root of Trust** is a reduced-privilege area in the secure
processing environment which, depending on the isolation level chosen when
building TF-M, has limited access to the PRoT, or even other ARoT services at
the highest isolation levels. Some standard services exist in the ARoT, such as
Protected Storage (PS), and generally custom secure services that you implement
should be placed in the ARoT, unless a compelling reason is present to place
them in the PRoT.

These divisions are distinct from the **untrusted code**, which runs in the
non-secure environment, and has the least privilege in the system. This is the
Zephyr application image in this case.

Isolation Levels
----------------

At present, there are three distinct **isolation levels** defined in TF-M,
with increasingly rigid boundaries between regions. The isolation level used
will depend on your security requirements, and the system resources available
to you.

* **Isolation Level 1** is the lowest isolation level, and the only major
  boundary is between the secure and non-secure processing environment,
  usually by means of Arm TrustZone on Armv8-M processors. There is no
  distinction here between the PSA Updateable Root of Trust (PRoT) and the
  Application Root of Trust (ARoT). They execute at the same privilege level.
  This isolation level will lead to the smallest combined application images.
* **Isolation Level 2** builds upon level one by introducing a distinction
  between the PSA Updateable Root of Trust and the Application Root of Trust,
  where ARoT services have limited access to PRoT services, and can only
  communicate with them through public APIs exposed by the PRoT services.
  ARoT services, however, are not strictly isolated from one another.
* **Isolation Level 3** is the highest isolation level, and builds upon level
  2 by isolating ARoT services from each other, so that each ARoT is
  essentially silo'ed from other services. This provides the highest level of
  isolation, but also comes at the cost of additional overhead and code
  duplication between services.

The current isolation level can be checked via
:kconfig:`CONFIG_TFM_ISOLATION_LEVEL`.

Secure Boot
===========

The default secure bootloader in TF-M is based on
`MCUBoot <https://www.mcuboot.com/>`__, and is referred to as ``BL2`` in TF-M
(for the second-stage bootloader, potentially after a HW-based bootloader on
the secure MCU, etc.).

All images in TF-M are hashed and signed, with the hash and signature verified
by MCUBoot during the firmware update process.

Some key features of MCUBooot as used in TF-M are:

* Public signing key(s) are baked into the bootloader
* S and NS images can be signed using different keys
* Firmware images can optionally be encyrpted
* Client software is responsible for writing a new image to the secondary slot
* By default, uses static flash layout of two identically-sized memory regions
* Optional security counter for rollback protection

When dealing with (optionally) encrypted images:

* Only the payload is encrypted (header, TLVs are plain text)
* Hashing and signing are applied over the un-encrypted data
* Uses ``AES-CTR-128`` or ``AES-CTR-256`` for encryption
* Encryption key randomized every encryption cycle (via ``imgtool``)
* The ``AES-CTR`` key is included in the image and can be encrypted using:

  * ``RSA-OAEP``
  * ``AES-KW`` (128 or 256 bits depending on the ``AES-CTR`` key length)
  * ``ECIES-P256``
  * ``ECIES-X25519``

Key config properties to control secure boot in Zephyr are:

* :kconfig:`CONFIG_TFM_BL2` toggles the bootloader (default = ``y``).
* :kconfig:`CONFIG_TFM_KEY_FILE_S` overrides the secure signing key.
* :kconfig:`CONFIG_TFM_KEY_FILE_NS` overrides the non-secure signing key.

Secure Processing Environment
=============================

Once the secure bootloader has finished executing, a TF-M based secure image
will begin execution in the **secure processing environment**. This is where
our device will be initially configured, and any secure services will be
initialised.

Note that the starting state of our device is controlled by the secure firmware,
meaning that when the non-secure Zephyr application starts, peripherals may
not be in the HW-default reset state. In case of doubts, be sure to consult
the board support packages in TF-M, available in the ``platform/ext/target/``
folder of the TF-M module (which is in ``modules/tee/tfm/trusted-firmware-m/``
within a default Zephyr west workspace.)

Secure Services
---------------

As of TF-M 1.3.0, the following secure services are available:

* Audit Logging (Audit)
* Crypto (Crypto)
* Firmware Update (FWU)
* Initial Attestation (IAS)
* Secure Storage, which has two parts:

  * Internal Trusted Storage (ITS)
  * Protected Storage (PS)

A template also exists for creating your own custom services.

For full details on these services, and their exposed APIs, please consult the
`TF-M Documentation <https://tf-m-user-guide.trustedfirmware.org/>`__.

Key Management and Derivation
-----------------------------

Key and secret management is a critical part of any secure device. You need to
ensure that key material is available to regions that require it, but not to
anything else, and that it is stored securely in a way that makes it difficult
to tamper with or maliciously access.

The **Internal Trusted Storage** service in TF-M is used by the **PSA Crypto**
service (which itself makes use of mbedtls) to store keys, and ensure that
private keys are only ever accessible to the secure processing environment.
Crypto operations that make use of key material, such as when signing payloads
or when decrypting sensitive data, all take place via key handles. At no point
should the key material ever be exposed to the NS environment.

One exception is that private keys can be provisioned into the secure
processing environment as a one-way operation, such as during a factory
provisioning process, but even this should be avoided where possible, and a
request should be made to the SPE (via the PSA Crypto service) to generate a
new private key itself, and the public key for that can be requested during
provisioning and logged in the factory. This ensures the private key
material is never exposed, or even known during the provisioning phase.

TF-M also makes extensive use of the **Hardware Unique Key (HUK)**, which
every TF-M device must provide. This device-unique key is used by the
**Protected Storage** service, for example, to encrypt information stored in
external memory. For example, this ensures that the contents of flash memory
can't be decrypted if they are removed and placed on a new device, since each
device has its own unique HUK used while encrypting the memory contents
the first time.

HUKs provide an additional advantage for developers, in that they can be used
to derive new keys, and the **derived keys** don't need to be stored since
they can be regenerated from the HUK at startup, using an additional salt/seed
value (depending on the key derivation algorithm used). This removes the
storage issue and a frequent attack vector. The HUK itself it usually highly
protected in secure devices, and inaccessible directly by users.

``TFM_CRYPTO_ALG_HUK_DERIVATION`` identifies the default key derivation
algorithm used if a software implementation is used. The current default
algorithm is ``HKDF`` (RFC 5869) with a SHA-256 hash. Other hardware
implementations may be available on some platforms.

Non-Secure Processing Environment
=================================

Zephyr is used for the NSPE, using a board that is supported by TF-M where the
:kconfig:`CONFIG_BUILD_WITH_TFM` flag has been enabled.

Generally, you simply need to select the ``*_ns`` variant of a valid target
(for example ``mps2_an521_ns``), which will configure your Zephyr application
to run in the NSPE, correctly build and link it with the TF-M secure images,
sign the secure and non-secure images, and merge the three binaries into a
single ``tfm_merged.hex`` file. The :ref:`west flash <west-flashing>` command
will flash ``tfm_merged.hex`` by default in this configuration.

At present, Zephyr can not be configured to be used as the secure processing
environment.
Loading