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;
+}