Boot: Add OTP provisioning functionality to MCUBoot

Add functionality to program hash of ROT public key and HUK to OTP. The
implementation is based on the CryptoCell CMPU and DMPU production
libraries.

If MCUBOOT_IMAGE_NUMBER=1, store the whole 32 byte hash of:
    bl2/ext/mcuboot/root-rsa-<2048|3072>.pem key.

If MCUBOOT_IMAGE_NUMBER=2, separately store
the first 16 bytes of the hash of:
    bl2/ext/mcuboot/root-rsa-<2048|3072>.pem key
and the first 16 bytes of the hash of:
    bl2/ext/mcuboot/root-rsa-<2048|3072>_1.pem key.

OTP provisioning is disabled by default. In order to enable,
add this to CMake command line:
 -DCRYPTO_HW_ACCELERATOR_OTP_STATE=PROVISIONING

Change-Id: Ica589319001f5ed77d853ba45ad8e6d3c266d172
Signed-off-by: Xu Yong <yong.xu@arm.com>
diff --git a/bl2/ext/mcuboot/CMakeLists.txt b/bl2/ext/mcuboot/CMakeLists.txt
index efa64eb..3464c52 100644
--- a/bl2/ext/mcuboot/CMakeLists.txt
+++ b/bl2/ext/mcuboot/CMakeLists.txt
@@ -92,7 +92,7 @@
 set (MBEDCRYPTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbed-crypto/build")
 set (MBEDCRYPTO_INSTALL_DIR ${MBEDCRYPTO_BINARY_DIR}/../install)
 
-if (CRYPTO_HW_ACCELERATOR)
+if (CRYPTO_HW_ACCELERATOR OR CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "PROVISIONING")
 	if(NOT DEFINED CRYPTO_HW_ACCELERATOR_CMAKE_BUILD)
 		message(FATAL_ERROR "CRYPTO_HW_ACCELERATOR_CMAKE_BUILD not defined.")
 	endif()
@@ -151,7 +151,7 @@
 add_dependencies(${PROJECT_NAME} ${MBEDCRYPTO_TARGET_NAME}_install)
 
 #Link crypto accelerator libraries if applicable
-if (CRYPTO_HW_ACCELERATOR)
+if (CRYPTO_HW_ACCELERATOR OR CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "PROVISIONING")
 	if(NOT DEFINED CRYPTO_HW_ACCELERATOR_CMAKE_LINK)
 		message(FATAL_ERROR "CRYPTO_HW_ACCELERATOR_CMAKE_LINK not defined.")
 	endif()
diff --git a/bl2/ext/mcuboot/bl2_main.c b/bl2/ext/mcuboot/bl2_main.c
index 26461c1..f1e289d 100644
--- a/bl2/ext/mcuboot/bl2_main.c
+++ b/bl2/ext/mcuboot/bl2_main.c
@@ -31,9 +31,10 @@
 #if BOOT_LOG_LEVEL > BOOT_LOG_LEVEL_OFF
 #include "uart_stdout.h"
 #endif
-#ifdef CRYPTO_HW_ACCELERATOR
+#if defined(CRYPTO_HW_ACCELERATOR) || \
+    defined(CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING)
 #include "crypto_hw.h"
-#endif /* CRYPTO_HW_ACCELERATOR */
+#endif
 
 /* Avoids the semihosting issue */
 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
@@ -213,6 +214,24 @@
     }
 #endif /* CRYPTO_HW_ACCELERATOR */
 
+/* This is a workaround to program the TF-M related cryptographic keys
+ * to CC312 OTP memory. This functionality is independent from secure boot,
+ * this is usually done in the factory floor during chip manufacturing.
+ */
+#ifdef CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING
+    BOOT_LOG_INF("OTP provisioning started.");
+    rc = crypto_hw_accelerator_otp_provisioning();
+    if (rc) {
+        BOOT_LOG_ERR("OTP provisioning FAILED: 0x%X", rc);
+        while (1);
+    } else {
+        BOOT_LOG_INF("OTP provisioning succeeded. TF-M won't be loaded.");
+
+        /* We don't need to boot - the only aim is provisioning. */
+        while (1);
+    }
+#endif /* CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING */
+
     BOOT_LOG_INF("Bootloader chainload address offset: 0x%x",
                  rsp.br_image_off);
     flash_area_warn_on_open();
diff --git a/bl2/ext/mcuboot/include/config-boot.h b/bl2/ext/mcuboot/include/config-boot.h
index 6b0c040..71667eb 100644
--- a/bl2/ext/mcuboot/include/config-boot.h
+++ b/bl2/ext/mcuboot/include/config-boot.h
@@ -64,6 +64,12 @@
 /* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
 #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
 
+#ifdef CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_AES_C
+#define MBEDTLS_CCM_C
+#endif /* CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING */
+
 #ifdef CRYPTO_HW_ACCELERATOR
 #include "mbedtls_accelerator_config.h"
 #endif
diff --git a/platform/ext/common/cc312/BuildCC312.cmake b/platform/ext/common/cc312/BuildCC312.cmake
index 38c66cf..9bb963e 100644
--- a/platform/ext/common/cc312/BuildCC312.cmake
+++ b/platform/ext/common/cc312/BuildCC312.cmake
@@ -54,8 +54,24 @@
 	endif()
 endif()
 
+if (CRYPTO_HW_ACCELERATOR)
+	list(APPEND ALL_SRC_C "${PLATFORM_DIR}/common/cc312/cc312.c")
+	string(APPEND MBEDCRYPTO_C_FLAGS " -DUSE_MBEDTLS_CRYPTOCELL")
+	string(APPEND MBEDCRYPTO_C_FLAGS " -DCRYPTO_HW_ACCELERATOR")
 
-list(APPEND ALL_SRC_C "${PLATFORM_DIR}/common/cc312/cc312.c")
+	string(APPEND CC312_C_FLAGS " -DUSE_MBEDTLS_CRYPTOCELL")
+	string(APPEND CC312_C_FLAGS " -DCRYPTO_HW_ACCELERATOR")
+endif()
+
+if (CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "PROVISIONING")
+	list(APPEND ALL_SRC_C_BL2 "${PLATFORM_DIR}/common/cc312/cc312_provisioning.c")
+	string(APPEND MBEDCRYPTO_C_FLAGS " -DCRYPTO_HW_ACCELERATOR_OTP_PROVISIONING")
+	string(APPEND CC312_C_FLAGS " -DCRYPTO_HW_ACCELERATOR_OTP_PROVISIONING")
+elseif (CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "ENABLED")
+	string(APPEND MBEDCRYPTO_C_FLAGS " -DCRYPTO_HW_ACCELERATOR_OTP_ENABLED")
+	string(APPEND CC312_C_FLAGS " -DCRYPTO_HW_ACCELERATOR_OTP_ENABLED")
+endif()
+
 
 embedded_include_directories(PATH "${PLATFORM_DIR}/common/cc312/" ABSOLUTE)
 
@@ -64,18 +80,12 @@
 string(APPEND CC312_C_FLAGS   " -I ${CC312_INSTALL_DIR}/include")
 
 string(APPEND MBEDCRYPTO_C_FLAGS " -I ${PLATFORM_DIR}/common/cc312")
-string(APPEND MBEDTLS_C_FLAGS " -DUSE_MBEDTLS_CRYPTOCELL")
-string(APPEND MBEDCRYPTO_C_FLAGS " -DCRYPTO_HW_ACCELERATOR")
-
 string(APPEND MBEDCRYPTO_C_FLAGS " -DMBEDTLS_ECDH_LEGACY_CONTEXT")
 
 string(APPEND CC312_C_FLAGS " -DMBEDTLS_CONFIG_FILE=\'\\\\\\\"${MBEDTLS_CONFIG_FILE}\\\\\\\"\'")
 string(APPEND CC312_C_FLAGS " -I ${MBEDTLS_CONFIG_PATH}")
 string(APPEND CC312_C_FLAGS " -I ${PLATFORM_DIR}/common/cc312")
 
-string(APPEND CC312_C_FLAGS " -DUSE_MBEDTLS_CRYPTOCELL")
-string(APPEND CC312_C_FLAGS " -DCRYPTO_HW_ACCELERATOR")
-
 if (MBEDCRYPTO_DEBUG)
 	if (${COMPILER} STREQUAL "GNUARM")
 		list(APPEND ALL_SRC_C "${PLATFORM_DIR}/common/cc312/cc312_log.c")
diff --git a/platform/ext/common/cc312/LinkCC312Provisioning.cmake b/platform/ext/common/cc312/LinkCC312Provisioning.cmake
new file mode 100644
index 0000000..8f3baa3
--- /dev/null
+++ b/platform/ext/common/cc312/LinkCC312Provisioning.cmake
@@ -0,0 +1,22 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#When included, this file will add a target to link the CC312 libraries. It will
+#also add the dependency between the project and the CC312 build target.
+cmake_minimum_required(VERSION 3.7)
+
+add_dependencies(${PROJECT_NAME} ${CC312_TARGET_NAME})
+
+get_target_property(TARGET_TYPE ${PROJECT_NAME} TYPE)
+
+if (TARGET_TYPE STREQUAL "EXECUTABLE")
+	target_link_libraries(${PROJECT_NAME} "${CC312_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX_C}libcmpu${CMAKE_STATIC_LIBRARY_SUFFIX_C}")
+	target_link_libraries(${PROJECT_NAME} "${CC312_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX_C}libdmpu${CMAKE_STATIC_LIBRARY_SUFFIX_C}")
+	target_link_libraries(${PROJECT_NAME} "${MBEDCRYPTO_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX_C}mbedcrypto${CMAKE_STATIC_LIBRARY_SUFFIX_C}")
+else()
+	message(FATAL_ERROR "Unknown target type ${TARGET_TYPE}")
+endif()
diff --git a/platform/ext/common/cc312/cc312_provisioning.c b/platform/ext/common/cc312/cc312_provisioning.c
new file mode 100644
index 0000000..24cf8a8
--- /dev/null
+++ b/platform/ext/common/cc312/cc312_provisioning.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "crypto_hw.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include "cc_hal_plat.h"
+#include "cc_prod.h"
+#include "cc_cmpu.h"
+#include "cc_dmpu.h"
+#include "cc_pal_types.h"
+#include "dx_reg_base_host.h"
+#include "mbedtls_cc_mng_int.h"
+
+extern uint8_t rotpk_hash_0[];
+extern uint8_t rotpk_hash_1[];
+
+/* Workspace for provisioning internal use */
+#define PROVISIONING_MEM_BUF_LEN  \
+        (CMPU_WORKSPACE_MINIMUM_SIZE > DMPU_WORKSPACE_MINIMUM_SIZE) ? \
+         CMPU_WORKSPACE_MINIMUM_SIZE : DMPU_WORKSPACE_MINIMUM_SIZE
+__attribute__((aligned(CC_32BIT_WORD_SIZE)))
+static uint8_t provisioning_mem_buf[PROVISIONING_MEM_BUF_LEN];
+
+static int cc312_cmpu_provision(void)
+{
+    int rc;
+    uint8_t *pWorkspaceBuf = provisioning_mem_buf;
+    static const uint32_t DCU_DEFAULT_LOCK[PROD_DCU_LOCK_WORD_SIZE];
+    static CCCmpuData_t cmpuData;
+
+    /* Populate cmpuData with data */
+#if (MCUBOOT_IMAGE_NUMBER == 1)
+    /* HBK won't be provisioned */
+    cmpuData.uniqueDataType = CMPU_UNIQUE_IS_USER_DATA;
+#elif (MCUBOOT_IMAGE_NUMBER == 2)
+    cmpuData.uniqueDataType = CMPU_UNIQUE_IS_HBK0;
+    memcpy(cmpuData.uniqueBuff.hbk0, rotpk_hash_0, 16);
+#else
+#error "MCUBOOT_IMAGE_NUMBER is not defined or has invalid value"
+#endif
+
+    cmpuData.kpicvDataType = ASSET_NO_KEY;
+    cmpuData.kceicvDataType = ASSET_NO_KEY;
+    cmpuData.icvMinVersion = 0;
+    cmpuData.icvConfigWord = 0;
+
+    memcpy(cmpuData.icvDcuDefaultLock, DCU_DEFAULT_LOCK,
+           sizeof(DCU_DEFAULT_LOCK));
+
+    rc = CCProd_Cmpu(DX_BASE_CC, &cmpuData, (unsigned long)pWorkspaceBuf,
+                     CMPU_WORKSPACE_MINIMUM_SIZE);
+
+    return rc;
+}
+
+static int cc312_dmpu_provision(void)
+{
+    int rc;
+    uint8_t *pWorkspaceBuf = provisioning_mem_buf;
+    static const uint32_t DCU_DEFAULT_LOCK[PROD_DCU_LOCK_WORD_SIZE];
+    static CCDmpuData_t dmpuData;
+
+    /* Populate dmpuData with data */
+#if (MCUBOOT_IMAGE_NUMBER == 1)
+    dmpuData.hbkType = DMPU_HBK_TYPE_HBK;
+    memcpy(dmpuData.hbkBuff.hbk, rotpk_hash_0, 32);
+#elif (MCUBOOT_IMAGE_NUMBER == 2)
+    dmpuData.hbkType = DMPU_HBK_TYPE_HBK1;
+    memcpy(dmpuData.hbkBuff.hbk1, rotpk_hash_1, 16);
+#else
+#error "MCUBOOT_IMAGE_NUMBER is not defined or has invalid value"
+#endif
+
+    dmpuData.kcpDataType = ASSET_NO_KEY;
+    dmpuData.kceDataType = ASSET_NO_KEY;
+    dmpuData.oemMinVersion = 0;
+
+    memcpy(dmpuData.oemDcuDefaultLock, DCU_DEFAULT_LOCK,
+           sizeof(DCU_DEFAULT_LOCK));
+
+    rc = CCProd_Dmpu(DX_BASE_CC, &dmpuData, (unsigned long)pWorkspaceBuf,
+                     DMPU_WORKSPACE_MINIMUM_SIZE);
+    return rc;
+}
+
+int crypto_hw_accelerator_otp_provisioning(void)
+{
+    int rc;
+    uint32_t lcs;
+
+    gCcRegBase = DX_BASE_CC;
+
+    if (CCProd_Init() != CC_OK) {
+        return -1;
+    }
+
+    rc = mbedtls_mng_lcsGet(&lcs);
+    if (rc) {
+        return rc;
+    }
+
+    if (lcs == CC_MNG_LCS_CM) {
+        rc = cc312_cmpu_provision();
+        if (rc) {
+            return rc;
+        }
+        printf("First cycle: HUK is provisioned successfully\r\n");
+        printf("Please reset the board to program ROTPK\r\n");
+    } else if (lcs == CC_MNG_LCS_DM) {
+        rc = cc312_dmpu_provision();
+        if (rc) {
+            return rc;
+        }
+        printf("Second cycle: ROTPK is provisioned successfully\r\n");
+        printf("Provisioning finished, reset the board to get secure"
+               " enabled lifecycle\r\n");
+    } else {
+        printf("Board is in invalid lifecycle for provisioning: %u\r\n", lcs);
+    }
+
+    return 0;
+}
diff --git a/platform/ext/common/cc312/crypto_hw.h b/platform/ext/common/cc312/crypto_hw.h
index f0675dd..b5baa8b 100644
--- a/platform/ext/common/cc312/crypto_hw.h
+++ b/platform/ext/common/cc312/crypto_hw.h
@@ -33,6 +33,17 @@
  */
 int crypto_hw_accelerator_finish(void);
 
+/**
+ * \brief Write the crypto keys to One-Time-Programmable memory
+ *
+ * The following keys will be provisioned:
+ *  - Hardware Unique Key (HUK)
+ *  - Hash of ROTPK
+ *
+ * \return 0 on success, non-zero otherwise
+ */
+int crypto_hw_accelerator_otp_provisioning(void);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/platform/ext/musca_b1.cmake b/platform/ext/musca_b1.cmake
index b3dd021..8f9633c 100644
--- a/platform/ext/musca_b1.cmake
+++ b/platform/ext/musca_b1.cmake
@@ -218,6 +218,29 @@
     set (CRYPTO_HW_ACCELERATOR OFF)
 endif()
 
+if (NOT DEFINED CRYPTO_HW_ACCELERATOR_OTP_STATE)
+    set (CRYPTO_HW_ACCELERATOR_OTP_STATE "DISABLED")
+endif()
+
+if (CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "PROVISIONING")
+    set(CRYPTO_HW_ACCELERATOR OFF)
+    set(CRYPTO_HW_ACCELERATOR_CMAKE_BUILD "${PLATFORM_DIR}/common/cc312/BuildCC312.cmake" PARENT_SCOPE)
+    set(CRYPTO_HW_ACCELERATOR_CMAKE_LINK "${PLATFORM_DIR}/common/cc312/LinkCC312Provisioning.cmake" PARENT_SCOPE)
+
+    get_filename_component(CC312_SOURCE_DIR "${PLATFORM_DIR}/../../lib/ext/cryptocell-312-runtime" ABSOLUTE)
+    add_definitions("-DCRYPTO_HW_ACCELERATOR_OTP_PROVISIONING")
+
+    add_definitions("-DCC_IOT")
+    embedded_include_directories(PATH "${CC312_SOURCE_DIR}/shared/hw/include/musca_b1" ABSOLUTE)
+elseif (CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "ENABLED")
+    set(CRYPTO_HW_ACCELERATOR ON)
+
+    add_definitions("-DCRYPTO_HW_ACCELERATOR_OTP_ENABLED")
+elseif(CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "DISABLED")
+else()
+    message(FATAL_ERROR "CRYPTO_HW_ACCELERATOR_OTP_STATE invalid. expected (DISABLED|PROVISIONING|ENABLED)")
+endif()
+
 #Enable CryptoCell-312 HW accelerator
 if (CRYPTO_HW_ACCELERATOR)
     set(CRYPTO_HW_ACCELERATOR_CMAKE_BUILD "${PLATFORM_DIR}/common/cc312/BuildCC312.cmake" PARENT_SCOPE)
@@ -228,7 +251,11 @@
     add_definitions("-DCRYPTO_HW_ACCELERATOR_CC312")
 
     add_definitions("-DCC_IOT")
+    #The CC312 uses GNU make as a build system so does not use the cmake flag
+    #system. As such any flags that need to be set for both CC312 and TF-M
+    #require setting multiple times.
     string(APPEND CC312_C_FLAGS " -I ${CC312_SOURCE_DIR}/shared/hw/include/musca_b1")
+    embedded_include_directories(PATH "${CC312_SOURCE_DIR}/shared/hw/include/musca_b1" ABSOLUTE)
     embedded_include_directories(PATH "${CMAKE_CURRENT_BINARY_DIR}/services/crypto/cryptocell/install/include" ABSOLUTE)
     embedded_include_directories(PATH "${PLATFORM_DIR}/common/cc312/" ABSOLUTE)
 endif()