diff options
author | Raef Coles <raef.coles@arm.com> | 2021-06-18 08:53:43 +0100 |
---|---|---|
committer | Raef Coles <raef.coles@arm.com> | 2021-10-07 09:10:40 +0100 |
commit | aefbe08fb68dc0c8c4e37e44abf703dc44ee16c5 (patch) | |
tree | c43f6604049d32bba8fbb52374623940e1db3de2 /platform/ext | |
parent | 148b947b24e59e2a4535102df4e4b387ad03da6b (diff) | |
download | trusted-firmware-m-aefbe08fb68dc0c8c4e37e44abf703dc44ee16c5.tar.gz |
Platform: Add provisioning api and implementation
Provision data and secrets to OTP memory, where they can later be
retrieved. Used for all data that should be changed on a per-device /
per-implementation basis. Add a cmake option to replace with
platform-specific implementation. Update provisioning documentation.
Change-Id: I0f2e85e93c12bd47b9f68490672d0fc0695e1612
Signed-off-by: Raef Coles <raef.coles@arm.com>
Diffstat (limited to 'platform/ext')
-rw-r--r-- | platform/ext/common/provisioning.c | 293 | ||||
-rw-r--r-- | platform/ext/index.rst | 2 | ||||
-rw-r--r-- | platform/ext/otp_provisioning.rst | 88 | ||||
-rw-r--r-- | platform/ext/platform_provisioning.rst | 89 |
4 files changed, 383 insertions, 89 deletions
diff --git a/platform/ext/common/provisioning.c b/platform/ext/common/provisioning.c new file mode 100644 index 0000000000..9aa70045a7 --- /dev/null +++ b/platform/ext/common/provisioning.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "tfm_plat_provisioning.h" + +#include "cmsis_compiler.h" +#include "tfm_plat_otp.h" +#include "tfm_attest_hal.h" +#include "psa/crypto.h" +#include "tfm_spm_log.h" +#include "tfm_memory_utils.h" + +#include <string.h> + +#define ASSEMBLY_AND_TEST_PROV_DATA_MAGIC 0xC0DEFEED +#define PSA_ROT_PROV_DATA_MAGIC 0xBEEFFEED + +__PACKED_STRUCT tfm_assembly_and_test_provisioning_data_t { + uint32_t magic; + uint8_t huk[32]; +}; + +__PACKED_STRUCT tfm_psa_rot_provisioning_data_t { + uint32_t magic; + uint8_t iak[32]; + uint32_t iak_len; + uint32_t iak_type; + uint8_t iak_id[32]; + + uint8_t boot_seed[32]; + uint8_t implementation_id[32]; + uint8_t hw_version[18]; + uint8_t verification_service_url[32]; + uint8_t profile_definition[32]; + + uint8_t entropy_seed[64]; +}; + +#ifdef TFM_DUMMY_PROVISIONING +static const struct tfm_assembly_and_test_provisioning_data_t assembly_and_test_prov_data = { + ASSEMBLY_AND_TEST_PROV_DATA_MAGIC, + /* HUK */ + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + }, +}; + +static const struct tfm_psa_rot_provisioning_data_t psa_rot_prov_data = { + PSA_ROT_PROV_DATA_MAGIC, + /* IAK */ + { + 0xA9, 0xB4, 0x54, 0xB2, 0x6D, 0x6F, 0x90, 0xA4, + 0xEA, 0x31, 0x19, 0x35, 0x64, 0xCB, 0xA9, 0x1F, + 0xEC, 0x6F, 0x9A, 0x00, 0x2A, 0x7D, 0xC0, 0x50, + 0x4B, 0x92, 0xA1, 0x93, 0x71, 0x34, 0x58, 0x5F + }, + /* IAK len */ + 32, +#ifdef SYMMETRIC_INITIAL_ATTESTATION + /* IAK type */ + PSA_ALG_HMAC(PSA_ALG_SHA_256), +#else + /* IAK type */ + PSA_ECC_FAMILY_SECP_R1, +#endif /* SYMMETRIC_INITIAL_ATTESTATION */ + /* IAK id */ + "kid@trustedfirmware.example", + /* boot seed */ + { + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + }, + /* implementation id */ + { + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + }, + /* hw version */ + "0604565272829100", + /* verification_service_url */ + "www.trustedfirmware.org", + /* attestation_profile_definition */ + "PSA_IOT_PROFILE_1", + /* Entropy seed */ + { + 0x12, 0x13, 0x23, 0x34, 0x0a, 0x05, 0x89, 0x78, + 0xa3, 0x66, 0x8c, 0x0d, 0x97, 0x55, 0x53, 0xca, + 0xb5, 0x76, 0x18, 0x62, 0x29, 0xc6, 0xb6, 0x79, + 0x75, 0xc8, 0x5a, 0x8d, 0x9e, 0x11, 0x8f, 0x85, + 0xde, 0xc4, 0x5f, 0x66, 0x21, 0x52, 0xf9, 0x39, + 0xd9, 0x77, 0x93, 0x28, 0xb0, 0x5e, 0x02, 0xfa, + 0x58, 0xb4, 0x16, 0xc8, 0x0f, 0x38, 0x91, 0xbb, + 0x28, 0x17, 0xcd, 0x8a, 0xc9, 0x53, 0x72, 0x66, + }, +}; +#else +static struct tfm_assembly_and_test_provisioning_data_t assembly_and_test_prov_data; +static struct tfm_psa_rot_provisioning_data_t psa_rot_prov_data; +#endif /* TFM_DUMMY_PROVISIONING */ + +void tfm_plat_provisioning_check_for_dummy_keys(void) +{ + uint64_t iak_start; + + tfm_plat_otp_read(PLAT_OTP_ID_IAK, sizeof(iak_start), (uint8_t*)&iak_start); + + if(iak_start == 0xA4906F6DB254B4A9) { + SPMLOG_ERRMSG("[WRN]\033[1;31m "); + SPMLOG_ERRMSG("This device was provisioned with dummy keys. "); + SPMLOG_ERRMSG("This device is \033[1;1mNOT SECURE"); + SPMLOG_ERRMSG("\033[0m\r\n"); + } + + tfm_memset(&iak_start, 0, sizeof(iak_start)); +} + +int tfm_plat_provisioning_is_required(void) +{ + enum tfm_plat_err_t err; + enum plat_otp_lcs_t lcs; + + err = tfm_plat_otp_read(PLAT_OTP_ID_LCS, sizeof(lcs), (uint8_t*)&lcs); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + return lcs == PLAT_OTP_LCS_ASSEMBLY_AND_TEST + || lcs == PLAT_OTP_LCS_PSA_ROT_PROVISIONING; +} + +enum tfm_plat_err_t provision_assembly_and_test(void) +{ + enum tfm_plat_err_t err; + uint32_t new_lcs; + + err = tfm_plat_otp_write(PLAT_OTP_ID_HUK, sizeof(assembly_and_test_prov_data.huk), + assembly_and_test_prov_data.huk); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + new_lcs = PLAT_OTP_LCS_PSA_ROT_PROVISIONING; + err = tfm_plat_otp_write(PLAT_OTP_ID_LCS, sizeof(new_lcs), + (uint8_t*)&new_lcs); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + return err; +} + +enum tfm_plat_err_t provision_psa_rot(void) +{ + enum tfm_plat_err_t err; + uint32_t new_lcs; + + err = tfm_plat_otp_write(PLAT_OTP_ID_IAK, + sizeof(psa_rot_prov_data.iak), + psa_rot_prov_data.iak); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_IAK_LEN, + sizeof(psa_rot_prov_data.iak_len), + (uint8_t*)&psa_rot_prov_data.iak_len); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_IAK_TYPE, + sizeof(psa_rot_prov_data.iak_type), + (uint8_t*)&psa_rot_prov_data.iak_type); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + +#ifdef ATTEST_INCLUDE_COSE_KEY_ID + err = tfm_plat_otp_write(PLAT_OTP_ID_IAK_ID, + sizeof(psa_rot_prov_data.iak_id), + psa_rot_prov_data.iak_id); + if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) { + return err; + } +#endif /* ATTEST_INCLUDE_COSE_KEY_ID */ + + err = tfm_plat_otp_write(PLAT_OTP_ID_BOOT_SEED, + sizeof(psa_rot_prov_data.boot_seed), + psa_rot_prov_data.boot_seed); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_IMPLEMENTATION_ID, + sizeof(psa_rot_prov_data.implementation_id), + psa_rot_prov_data.implementation_id); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_HW_VERSION, + sizeof(psa_rot_prov_data.hw_version), + psa_rot_prov_data.hw_version); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_VERIFICATION_SERVICE_URL, + sizeof(psa_rot_prov_data.verification_service_url), + psa_rot_prov_data.verification_service_url); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + err = tfm_plat_otp_write(PLAT_OTP_ID_PROFILE_DEFINITION, + sizeof(psa_rot_prov_data.profile_definition), + psa_rot_prov_data.profile_definition); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + err = tfm_plat_otp_write(PLAT_OTP_ID_ENTROPY_SEED, + sizeof(psa_rot_prov_data.entropy_seed), + psa_rot_prov_data.entropy_seed); + if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) { + return err; + } + + new_lcs = PLAT_OTP_LCS_SECURED; + err = tfm_plat_otp_write(PLAT_OTP_ID_LCS, + sizeof(new_lcs), + (uint8_t*)&new_lcs); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + return err; +} + +enum tfm_plat_err_t tfm_plat_provisioning_perform(void) +{ + enum tfm_plat_err_t err; + enum plat_otp_lcs_t lcs; + + err = tfm_plat_otp_read(PLAT_OTP_ID_LCS, sizeof(lcs), (uint8_t*)&lcs); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + + SPMLOG_INFMSG("[INF] Beginning TF-M provisioning\r\n"); + +#ifdef TFM_DUMMY_PROVISIONING + SPMLOG_ERRMSG("[WRN]\033[1;31m "); + SPMLOG_ERRMSG("TFM_DUMMY_PROVISIONING is not suitable for production! "); + SPMLOG_ERRMSG("This device is \033[1;1mNOT SECURE"); + SPMLOG_ERRMSG("\033[0m\r\n"); +#endif /* TFM_DUMMY_PROVISIONING */ + + if (lcs == PLAT_OTP_LCS_ASSEMBLY_AND_TEST) { + if (assembly_and_test_prov_data.magic != ASSEMBLY_AND_TEST_PROV_DATA_MAGIC) { + SPMLOG_ERRMSG("No valid ASSEMBLY_AND_TEST provisioning data found\r\n"); + return TFM_PLAT_ERR_INVALID_INPUT; + } + + err = provision_assembly_and_test(); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + } + + err = tfm_plat_otp_read(PLAT_OTP_ID_LCS, sizeof(lcs), (uint8_t*)&lcs); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + if (lcs == PLAT_OTP_LCS_PSA_ROT_PROVISIONING) { + if (psa_rot_prov_data.magic != PSA_ROT_PROV_DATA_MAGIC) { + SPMLOG_ERRMSG("No valid PSA_ROT provisioning data found\r\n"); + return TFM_PLAT_ERR_INVALID_INPUT; + } + + err = provision_psa_rot(); + if (err != TFM_PLAT_ERR_SUCCESS) { + return err; + } + } + + return TFM_PLAT_ERR_SUCCESS; +} diff --git a/platform/ext/index.rst b/platform/ext/index.rst index 36e3af98f7..2e0633c94e 100644 --- a/platform/ext/index.rst +++ b/platform/ext/index.rst @@ -9,6 +9,7 @@ Supported Platforms readme /platform/ext/platform_introduction.rst /platform/ext/platform_deprecation.rst + /platform/ext/platform_provisioning.rst .. toctree:: :maxdepth: 1 @@ -16,7 +17,6 @@ Supported Platforms :glob: target/arm/** - otp_provisioning.rst .. toctree:: :maxdepth: 1 diff --git a/platform/ext/otp_provisioning.rst b/platform/ext/otp_provisioning.rst deleted file mode 100644 index c29e1a8067..0000000000 --- a/platform/ext/otp_provisioning.rst +++ /dev/null @@ -1,88 +0,0 @@ -############################ -Musca-B1/S1 OTP Provisioning -############################ - -This document assumes that the user has set up the build environment, is -capable of compiling the TF-M project, and is in possession of at least one -Musca-S1 board, or a Musca-B1 board that has not been provisioned before. - -.. Note:: - During provisioning, the 'MCUBOOT_IMAGE_NUMBER' configuration's value - determines which Root of Trust public key's hash will be stored. Whichever - one is stored, it can only be checked against successfully in the matching - way later. This means that a board provisioned with a build in which - 'MCUBOOT_IMAGE_NUMBER=1' can only be used with 'MCUBOOT_IMAGE_NUMBER=1', - as long as the OTP is enabled. Same goes with 'MCUBOOT_IMAGE_NUMBER=2'. - -********************************* -Provisioning on Musca HW variants -********************************* -Even though most of the process is identical between the boards, there is -a difference between them because of the underlying hardware. -While the B1 has actual OTP memory, the S1 only has volatile registers in its -place. Because a power cyclce wipes that area, the S1 merely imitates OTP -memory by copying provisioned data to its non-volatile MRAM. - -Once the provisioning process is done, the CryptoCell-312 enters the Secure -Enabled lifecycle, which it recognizes by the contents of the OTP. -Debug and board reprogramming through USB is locked down in this state. -This lock can be forced open, but only with DAPLink firmware v34 or above. - -Because the S1 "OTP" content is stored in the MRAM, it can be provisioned only -once with the normal provisioning flow. However, a workaround to re-provision -the board does exist. To achieve this, one needs to wipe the key area in the -MRAM with the debugger in advance. The address and size of said area can be -found at 'platform/ext/target/musca_s1/partition/flash_layout.h' as -'TF-M key area'. - -For further information on the DAPLink firmware and update process, please -refer to the `Musca-B1 Technical Reference Manual -<https://developer.arm.com/docs/101312/0000>`__ or the `Musca-S1 Technical -Reference Manual <https://developer.arm.com/docs/101835/0000>`__. - -Provisioning steps -================== -1. Build TF-M with -DCRYPTO_HW_ACCELERATOR_OTP_STATE=PROVISIONING given on -the CMake command line. - -2. Load the tfm.hex file to the board and open the serial output. -Once you see something like the following snippet: - -.. code-block:: bash - - ... - First cycle: Attestation key is provisioned successfully - First cycle: HUK is provisioned successfully - Please reset the board to program ROTPK - ... - -3. Reset the board once by pressing the nSRST button and wait until you see -something like this: - -:: - - ... - Second cycle: ROTPK is provisioned successfully - Provisioning finished, reset the board to get secure enabled lifecycle - ... - -4. Reset the board once more. -If the provisioning process was succesful, you should see an output like: - -:: - - ... - Board is in invalid lifecycle for provisioning: 5 - ... - -Using the provisioned data -========================== -1. Build TF-M with -DCRYPTO_HW_ACCELERATOR_OTP_STATE=ENABLED given -on the CMake command line. - -2. Load the tfm.hex file to -the board. - --------------- - -*Copyright (c) 2020, Arm Limited. All rights reserved.*
\ No newline at end of file diff --git a/platform/ext/platform_provisioning.rst b/platform/ext/platform_provisioning.rst new file mode 100644 index 0000000000..52d96aa13b --- /dev/null +++ b/platform/ext/platform_provisioning.rst @@ -0,0 +1,89 @@ +##################### +Platform Provisioning +##################### + +TF-M stores any data that should be provisioned at the factory in OTP memory. +The default is that this OTP memory is actually implemented using on-chip flash, +the same that is used to implement the ITS service. + +If the lifecycle state is in the ``TFM_SLC_ASSEMBLY_AND_TEST`` [1]_ state (which +is the default for non-provisioned boards), then TF-M will attempt to provision +the: +- HUK +instead of booting. It will read the data from the +``assembly_and_test_prov_data`` struct, and will then provision it to OTP. The +lifecycle state will then transition to ``TFM_SLC_PSA_ROT_PROVISIONING`` [1]_. + +If the lifecycle state is in the ``TFM_SLC_PSA_ROT_PROVISIONING`` [1]_ state, +then TF-M will attempt to provision the: + +- IAK +- boot seed +- implementation id +- hw version +- bl2 ROTPKs (of which there are up to 4) +- entropy seed + +Once all of these have been loaded from the ``psa_rot_prov_data`` struct and +provisioned to OTP, the LCS will transition to ``TFM_SLC_SECURED`` [1]_. Note +that this provisioning step will be run immediately after the +``TFM_SLC_ASSEMBLY_AND_TEST`` [1]_ provisioning stage if the lifecycle +transition completed successfully. + +Provisioning development hardware +================================= + +If ``TFM_DUMMY_PROVISIONING`` is enabled in the cmake config (as it is by +default), a set of dummy keys / data will be provisioned. The dummy IAK matches +the IAK tested by the TF-M tests, and the dummy bl2 ROTPKs match the dummy bl2 +keys used by default. ``TFM_DUMMY_PROVISIONING`` _MUST_ not be used in +production hardware, as the keys are insecure. + +Provisioning production hardware +================================ + +For provisioning of real hardware, firstly ``TFM_DUMMY_PROVISIONING`` must be +disabled. Then it is required to inject the keys into RAM so they populate the +``assembly_and_test_prov_data`` and ``psa_rot_prov_data`` structs, at the +beginning of the TF-M boot. These structs each require a magic value to be set +to be accepted by the provisioning code, which is detailed in +``platform/ext/common/provisioning.c``. Two suggestions for how to do this are: + +- Attach a debugger, and inject the values into RAM. +- Flash an image that contains the required data. Care must be taken with this + approach that the keys are not left in RAM after provisioning, so a different + image (without provisioning data embedded) must be flashed afterwards, without + erasing the OTP flash area. + +************************************************ +Provisioning on CryptoCell-312 enabled platforms +************************************************ + +On boards that have a CC312 accelerator, and that have the default flash-backed +OTP disabled by setting ``PLATFORM_DEFAULT_OTP=OFF`` in cmake, the CC312 OTP +will be used as a backing for the OTP HAL. + +Due to the CC312 requiring a power-cycle to transition LCS, you will be prompted +to manually power-cycle the board between provisioning stages. + +Boards with real OTP memory cannot be reprovisioned - care should be taken that +the data being provisioned is the desired data. + +***************************** +Platform-specific OTP backing +***************************** + +If a platform has a medium that is suitable for storing data with OTP semantics +(Where a bit cannot transition from a 1 to a 0), such as physical OTP memory, +then it can provide a backing for the OTP HAL by implementing the methods +described in ``tfm_plat_otp.h``. + +-------------- + +.. [1] For the definitions of these lifecycle states, please refer to the + Platform Security Model + https://developer.arm.com/documentation/den0128/0100/ + +-------------- + +*Copyright (c) 2020-2021, Arm Limited. All rights reserved.* |