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>
diff --git a/bl2/CMakeLists.txt b/bl2/CMakeLists.txt
index 049d1e5..c5626d7 100644
--- a/bl2/CMakeLists.txt
+++ b/bl2/CMakeLists.txt
@@ -14,6 +14,7 @@
$<$<BOOL:${DEFAULT_MCUBOOT_SECURITY_COUNTERS}>:src/security_cnt.c>
$<$<BOOL:${DEFAULT_MCUBOOT_FLASH_MAP}>:src/default_flash_map.c>
$<$<BOOL:${MCUBOOT_DATA_SHARING}>:src/shared_data.c>
+ $<$<BOOL:${PLATFORM_DEFAULT_PROVISIONING}>:src/provisioning.c>
)
add_subdirectory(ext/mcuboot)
diff --git a/bl2/ext/mcuboot/bl2_main.c b/bl2/ext/mcuboot/bl2_main.c
index 9876239..1674e13 100644
--- a/bl2/ext/mcuboot/bl2_main.c
+++ b/bl2/ext/mcuboot/bl2_main.c
@@ -29,6 +29,8 @@
#include "flash_map_backend/flash_map_backend.h"
#include "boot_hal.h"
#include "uart_stdout.h"
+#include "tfm_plat_otp.h"
+#include "tfm_plat_provisioning.h"
/* Avoids the semihosting issue */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
@@ -85,6 +87,7 @@
{
struct boot_rsp rsp;
fih_int fih_rc = FIH_FAILURE;
+ enum tfm_plat_err_t plat_err;
/* Initialise the mbedtls static memory allocator so that mbedtls allocates
* memory from the provided static buffer instead of from the heap.
@@ -103,6 +106,22 @@
BOOT_LOG_INF("Starting bootloader");
+ plat_err = tfm_plat_otp_init();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ BOOT_LOG_ERR("OTP system initialization failed");
+ FIH_PANIC;
+ }
+
+ if (tfm_plat_provisioning_is_required()) {
+ plat_err = tfm_plat_provisioning_perform();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ BOOT_LOG_ERR("Provisioning failed");
+ FIH_PANIC;
+ }
+ } else {
+ tfm_plat_provisioning_check_for_dummy_keys();
+ }
+
FIH_CALL(boot_nv_security_counter_init, fih_rc);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BOOT_LOG_ERR("Error while initializing the security counter");
diff --git a/bl2/src/provisioning.c b/bl2/src/provisioning.c
new file mode 100644
index 0000000..4121e8d
--- /dev/null
+++ b/bl2/src/provisioning.c
@@ -0,0 +1,214 @@
+/*
+ * 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 "bootutil/bootutil_log.h"
+
+#include <string.h>
+
+#define ASSEMBLY_AND_TEST_PROV_DATA_MAGIC 0xC0DEFEED
+
+__PACKED_STRUCT bl2_assembly_and_test_provisioning_data_t {
+ uint32_t magic;
+ uint8_t bl2_rotpk_0[32];
+ uint8_t bl2_rotpk_1[32];
+ uint8_t bl2_rotpk_2[32];
+
+#ifdef BL1
+ uint8_t bl1_rotpk_0[32];
+#endif /* BL1 */
+};
+
+#ifdef TFM_DUMMY_PROVISIONING
+static const struct bl2_assembly_and_test_provisioning_data_t bl2_assembly_and_test_prov_data = {
+ ASSEMBLY_AND_TEST_PROV_DATA_MAGIC,
+#if (MCUBOOT_SIGN_RSA_LEN == 2048)
+ /* bl2 rotpk 0 */
+ {
+ 0xfc, 0x57, 0x01, 0xdc, 0x61, 0x35, 0xe1, 0x32,
+ 0x38, 0x47, 0xbd, 0xc4, 0x0f, 0x04, 0xd2, 0xe5,
+ 0xbe, 0xe5, 0x83, 0x3b, 0x23, 0xc2, 0x9f, 0x93,
+ 0x59, 0x3d, 0x00, 0x01, 0x8c, 0xfa, 0x99, 0x94,
+ },
+ /* bl2 rotpk 1 */
+ {
+ 0xe1, 0x80, 0x15, 0x99, 0x3d, 0x6d, 0x27, 0x60,
+ 0xb4, 0x99, 0x27, 0x4b, 0xae, 0xf2, 0x64, 0xb8,
+ 0x3a, 0xf2, 0x29, 0xe9, 0xa7, 0x85, 0xf3, 0xd5,
+ 0xbf, 0x00, 0xb9, 0xd3, 0x2c, 0x1f, 0x03, 0x96,
+ },
+ /* bl2 rotpk 2 */
+ {
+ 0xe1, 0x80, 0x15, 0x99, 0x3d, 0x6d, 0x27, 0x60,
+ 0xb4, 0x99, 0x27, 0x4b, 0xae, 0xf2, 0x64, 0xb8,
+ 0x3a, 0xf2, 0x29, 0xe9, 0xa7, 0x85, 0xf3, 0xd5,
+ 0xbf, 0x00, 0xb9, 0xd3, 0x2c, 0x1f, 0x03, 0x96,
+ },
+ /* bl1 rotpk 0 */
+ {
+ 0xfc, 0x57, 0x01, 0xdc, 0x61, 0x35, 0xe1, 0x32,
+ 0x38, 0x47, 0xbd, 0xc4, 0x0f, 0x04, 0xd2, 0xe5,
+ 0xbe, 0xe5, 0x83, 0x3b, 0x23, 0xc2, 0x9f, 0x93,
+ 0x59, 0x3d, 0x00, 0x01, 0x8c, 0xfa, 0x99, 0x94,
+ },
+#elif (MCUBOOT_SIGN_RSA_LEN == 3072)
+ /* bl2 rotpk 0 */
+ {
+ 0xbf, 0xe6, 0xd8, 0x6f, 0x88, 0x26, 0xf4, 0xff,
+ 0x97, 0xfb, 0x96, 0xc4, 0xe6, 0xfb, 0xc4, 0x99,
+ 0x3e, 0x46, 0x19, 0xfc, 0x56, 0x5d, 0xa2, 0x6a,
+ 0xdf, 0x34, 0xc3, 0x29, 0x48, 0x9a, 0xdc, 0x38,
+ },
+ /* bl2 rotpk 1 */
+ {
+ 0xb3, 0x60, 0xca, 0xf5, 0xc9, 0x8c, 0x6b, 0x94,
+ 0x2a, 0x48, 0x82, 0xfa, 0x9d, 0x48, 0x23, 0xef,
+ 0xb1, 0x66, 0xa9, 0xef, 0x6a, 0x6e, 0x4a, 0xa3,
+ 0x7c, 0x19, 0x19, 0xed, 0x1f, 0xcc, 0xc0, 0x49,
+ },
+ /* bl2 rotpk 2 */
+ {
+ 0xb3, 0x60, 0xca, 0xf5, 0xc9, 0x8c, 0x6b, 0x94,
+ 0x2a, 0x48, 0x82, 0xfa, 0x9d, 0x48, 0x23, 0xef,
+ 0xb1, 0x66, 0xa9, 0xef, 0x6a, 0x6e, 0x4a, 0xa3,
+ 0x7c, 0x19, 0x19, 0xed, 0x1f, 0xcc, 0xc0, 0x49,
+ },
+#else
+#error "No public key available for given signing algorithm."
+#endif /* MCUBOOT_SIGN_RSA_LEN */
+#ifdef BL1
+#if (MCUBOOT_SIGN_RSA_LEN == 2048)
+ /* bl2 rotpk 0 */
+ {
+ 0xfc, 0x57, 0x01, 0xdc, 0x61, 0x35, 0xe1, 0x32,
+ 0x38, 0x47, 0xbd, 0xc4, 0x0f, 0x04, 0xd2, 0xe5,
+ 0xbe, 0xe5, 0x83, 0x3b, 0x23, 0xc2, 0x9f, 0x93,
+ 0x59, 0x3d, 0x00, 0x01, 0x8c, 0xfa, 0x99, 0x94,
+ },
+#elif (MCUBOOT_SIGN_RSA_LEN == 3072)
+ /* bl1 rotpk 0 */
+ {
+ 0xbf, 0xe6, 0xd8, 0x6f, 0x88, 0x26, 0xf4, 0xff,
+ 0x97, 0xfb, 0x96, 0xc4, 0xe6, 0xfb, 0xc4, 0x99,
+ 0x3e, 0x46, 0x19, 0xfc, 0x56, 0x5d, 0xa2, 0x6a,
+ 0xdf, 0x34, 0xc3, 0x29, 0x48, 0x9a, 0xdc, 0x38,
+ },
+#else
+#error "No public key available for given signing algorithm."
+#endif /* MCUBOOT_SIGN_RSA_LEN */
+#endif /* BL1 */
+};
+#else
+static const struct bl2_assembly_and_test_provisioning_data_t bl2_assembly_and_test_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) {
+ BOOT_LOG_WRN("%s%s%s%s",
+ "\033[1;31m"
+ "This device was provisioned with dummy keys. ",
+ "This device is \033[1;1mNOT SECURE",
+ "\033[0m");
+ }
+
+ 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;
+
+ err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_0,
+ sizeof(bl2_assembly_and_test_prov_data.bl2_rotpk_0),
+ bl2_assembly_and_test_prov_data.bl2_rotpk_0);
+ if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+ return err;
+ }
+ err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_1,
+ sizeof(bl2_assembly_and_test_prov_data.bl2_rotpk_1),
+ bl2_assembly_and_test_prov_data.bl2_rotpk_1);
+ if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+ return err;
+ }
+
+ err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_2,
+ sizeof(bl2_assembly_and_test_prov_data.bl2_rotpk_2),
+ bl2_assembly_and_test_prov_data.bl2_rotpk_2);
+ if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+ return err;
+ }
+
+#ifdef BL1
+ err = tfm_plat_otp_write(PLAT_OTP_ID_BL1_ROTPK_0,
+ sizeof(bl2_assembly_and_test_prov_data.bl1_rotpk_0),
+ bl2_assembly_and_test_prov_data.bl1_rotpk_0);
+ if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+ return err;
+ }
+#endif /* BL1 */
+
+ 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;
+ }
+
+ BOOT_LOG_INF("Beginning BL2 provisioning");
+
+#ifdef TFM_DUMMY_PROVISIONING
+ BOOT_LOG_WRN("%s%s%s%s",
+ "\033[1;31m",
+ "TFM_DUMMY_PROVISIONING is not suitable for production! ",
+ "This device is \033[1;1mNOT SECURE",
+ "\033[0m");
+#endif /* TFM_DUMMY_PROVISIONING */
+
+ if (lcs == PLAT_OTP_LCS_ASSEMBLY_AND_TEST) {
+ if (bl2_assembly_and_test_prov_data.magic != ASSEMBLY_AND_TEST_PROV_DATA_MAGIC) {
+ BOOT_LOG_ERR("No valid ASSEMBLY_AND_TEST provisioning data found");
+ return TFM_PLAT_ERR_INVALID_INPUT;
+ }
+
+ err = provision_assembly_and_test();
+ if (err != TFM_PLAT_ERR_SUCCESS) {
+ return err;
+ }
+ }
+
+ return TFM_PLAT_ERR_SUCCESS;
+}
diff --git a/config/config_default.cmake b/config/config_default.cmake
index add2414..841e377 100644
--- a/config/config_default.cmake
+++ b/config/config_default.cmake
@@ -70,6 +70,9 @@
set(PLATFORM_DEFAULT_UART_STDOUT TRUE CACHE BOOL "Use default uart stdout implementation.")
set(PLATFORM_DUMMY_NV_SEED TRUE CACHE BOOL "Use dummy NV seed implementation. Should not be used in production.")
set(PLATFORM_DEFAULT_OTP ON CACHE BOOL "Use trusted on-chip flash to implement OTP memory")
+set(PLATFORM_DEFAULT_PROVISIONING ON CACHE BOOL "Use default provisioning implementation")
+
+set(TFM_DUMMY_PROVISIONING ON CACHE BOOL "Provision with dummy values. NOT to be used in production")
############################ Partitions ########################################
diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt
index e66893f..469341f 100755
--- a/platform/CMakeLists.txt
+++ b/platform/CMakeLists.txt
@@ -53,6 +53,7 @@
$<$<AND:$<NOT:$<BOOL:${ATTEST_TEST_GET_PUBLIC_KEY}>>,$<NOT:$<BOOL:${SYMMETRIC_INITIAL_ATTESTATION}>>,$<BOOL:${PLATFORM_DUMMY_IAK}>,$<BOOL:${TEST_S_ATTESTATION}>>:ext/common/template/tfm_initial_attest_pub_key.c>
$<$<BOOL:${PLATFORM_DEFAULT_OTP}>:ext/common/template/flash_otp_nv_counters_backend.c>
$<$<BOOL:${PLATFORM_DEFAULT_OTP}>:ext/common/template/otp_flash.c>
+ $<$<BOOL:${PLATFORM_DEFAULT_PROVISIONING}>:ext/common/provisioning.c>
)
target_link_libraries(platform_s
@@ -63,6 +64,7 @@
psa_interface
tfm_secure_api
tfm_arch
+ tfm_partition_defs
)
target_compile_definitions(platform_s
@@ -74,6 +76,8 @@
$<$<OR:$<VERSION_GREATER:${TFM_ISOLATION_LEVEL},1>,$<STREQUAL:"${TEST_PSA_API}","IPC">>:CONFIG_TFM_ENABLE_MEMORY_PROTECT>
$<$<AND:$<BOOL:${TFM_PXN_ENABLE}>,$<STREQUAL:${CMAKE_SYSTEM_ARCHITECTURE},armv8.1-m.main>>:TFM_PXN_ENABLE>
$<$<BOOL:${PLATFORM_DEFAULT_OTP}>:PLATFORM_DEFAULT_OTP>
+ $<$<BOOL:${TFM_DUMMY_PROVISIONING}>:TFM_DUMMY_PROVISIONING>
+ $<$<BOOL:${ATTEST_INCLUDE_COSE_KEY_ID}>:ATTEST_INCLUDE_COSE_KEY_ID>
)
#========================= Platform Non-Secure ================================#
@@ -148,6 +152,8 @@
MCUBOOT_FIH_PROFILE_${MCUBOOT_FIH_PROFILE}
$<$<BOOL:${PLATFORM_DEFAULT_OTP}>:PLATFORM_DEFAULT_OTP>
$<$<BOOL:${OTP_NV_COUNTERS_RAM_EMULATION}>:OTP_NV_COUNTERS_RAM_EMULATION>
+ $<$<BOOL:${TFM_DUMMY_PROVISIONING}>:TFM_DUMMY_PROVISIONING>
+ $<$<BOOL:${ATTEST_INCLUDE_COSE_KEY_ID}>:ATTEST_INCLUDE_COSE_KEY_ID>
)
endif()
diff --git a/platform/ext/common/provisioning.c b/platform/ext/common/provisioning.c
new file mode 100644
index 0000000..9aa7004
--- /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 36e3af9..2e0633c 100644
--- a/platform/ext/index.rst
+++ b/platform/ext/index.rst
@@ -9,6 +9,7 @@
readme
/platform/ext/platform_introduction.rst
/platform/ext/platform_deprecation.rst
+ /platform/ext/platform_provisioning.rst
.. toctree::
:maxdepth: 1
@@ -16,7 +17,6 @@
: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 c29e1a8..0000000
--- 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 0000000..52d96aa
--- /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.*
diff --git a/platform/include/tfm_plat_provisioning.h b/platform/include/tfm_plat_provisioning.h
new file mode 100644
index 0000000..2f3b169
--- /dev/null
+++ b/platform/include/tfm_plat_provisioning.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PLAT_PROVISIONING_H__
+#define __TFM_PLAT_PROVISIONING_H__
+
+#include "tfm_plat_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Check the contents of OTP memory for the
+ * presence of keys provisioned by
+ * TFM_DUMMY_PROVISIONING
+ *
+ * \note This function should print a warning to
+ * the UART, or otherwise notify the device
+ * user, if dummy keys are detected.
+ */
+void tfm_plat_provisioning_check_for_dummy_keys(void);
+
+/**
+ * \brief Check if a provisioning operation is
+ * required.
+ *
+ * \retval 1 A provisioning operation is required.
+ * \retval 0 A provisioning operation is not
+ * required.
+ */
+int tfm_plat_provisioning_is_required(void);
+
+/**
+ * \brief Performs a provisioning operation.
+ *
+ * \retval TFM_PLAT_ERR_SUCCESS The provisioning operation completed
+ * successfully.
+ * \retval TFM_PLAT_ERR_INVALID_INPUT The provisioning data that was input to
+ * the device is invalid
+ * \retval TFM_PLAT_ERR_SYSTEM_ERR An unspecified error occurred.
+ */
+enum tfm_plat_err_t tfm_plat_provisioning_perform(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_PLAT_PROVISIONING_H__ */
diff --git a/secure_fw/spm/cmsis_func/main.c b/secure_fw/spm/cmsis_func/main.c
index c889748..d8dadbc 100644
--- a/secure_fw/spm/cmsis_func/main.c
+++ b/secure_fw/spm/cmsis_func/main.c
@@ -18,6 +18,8 @@
#include "tfm_spm_hal.h"
#include "tfm_spm_log.h"
#include "tfm_version.h"
+#include "tfm_plat_otp.h"
+#include "tfm_plat_provisioning.h"
/*
* Avoids the semihosting issue
@@ -94,6 +96,21 @@
FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
}
+ plat_err = tfm_plat_otp_init();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+ }
+
+ /* Perform provisioning. */
+ if (tfm_plat_provisioning_is_required()) {
+ plat_err = tfm_plat_provisioning_perform();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+ }
+ } else {
+ tfm_plat_provisioning_check_for_dummy_keys();
+ }
+
/* Configures architecture */
tfm_arch_config_extensions();
diff --git a/secure_fw/spm/cmsis_psa/main.c b/secure_fw/spm/cmsis_psa/main.c
index 30cae8b..b8e4ccc 100644
--- a/secure_fw/spm/cmsis_psa/main.c
+++ b/secure_fw/spm/cmsis_psa/main.c
@@ -16,6 +16,8 @@
#include "tfm_spm_hal.h"
#include "tfm_spm_log.h"
#include "tfm_version.h"
+#include "tfm_plat_otp.h"
+#include "tfm_plat_provisioning.h"
/*
* Avoids the semihosting issue
@@ -95,6 +97,21 @@
FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
}
+ plat_err = tfm_plat_otp_init();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+ }
+
+ /* Perform provisioning. */
+ if (tfm_plat_provisioning_is_required()) {
+ plat_err = tfm_plat_provisioning_perform();
+ if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+ }
+ } else {
+ tfm_plat_provisioning_check_for_dummy_keys();
+ }
+
/* Configures architecture */
tfm_arch_config_extensions();