Platform: AN552: Use provisioning bundles

If "-DPLATFORM_DEFAULT_PROVISIONING=OFF" then use provisioning
bundles. A new binary is built that contains the provisioning values
and code. All three of the previous provisionings are moved to the
united provisioning bundle.

The approach is based on RSS's provisioning, but the OTP layout,
provisioning values have changed and it uses flash based OTP.

Change-Id: I68710a3c037f0a17245849ea6b01f4b3ba16945e
Signed-off-by: Bence Balogh <bence.balogh@arm.com>
diff --git a/docs/platform/arm/mps3/an552/README.rst b/docs/platform/arm/mps3/an552/README.rst
index 080f887..d455fc7 100644
--- a/docs/platform/arm/mps3/an552/README.rst
+++ b/docs/platform/arm/mps3/an552/README.rst
@@ -19,6 +19,13 @@
    FVP (FVP_SSE300_MPS3) and Corstone SSE-300 with Ethos-U55 Example Subsystem
    for MPS3 (AN552). For the FVP, at least version 11.16 is required.
 
+.. note::
+
+   Provisioning bundles can be generated with the ``-DPLATFORM_DEFAULT_PROVISIONING=OFF``
+   flag. The provisioning bundle binary will be generated and it's going to contain the
+   provisioning code and provisioning values. The provisioning bundle has to be placed
+   on the ``0x10022000`` address.
+
 To run the example code on AN552
 --------------------------------
 FPGA image is available to download `here <https://developer.arm.com/tools-and-software/development-boards/fpga-prototyping-boards/download-fpga-images>`__
@@ -69,6 +76,11 @@
    Some of the messages above are only visible when ``CMAKE_BUILD_TYPE`` is set
    to ``Debug``.
 
+.. note::
+
+   If ``-DPLATFORM_DEFAULT_PROVISIONING=OFF`` is set then the provisioning bundle has to
+   be placed on the ``0x10022000`` address.
+
 To run the example code on Corstone-300 Ethos-U55 Ecosystem FVP
 ---------------------------------------------------------------
 FVP is available to download `here <https://developer.arm.com/tools-and-software/open-source-software/arm-platforms-software/arm-ecosystem-fvps>`__
@@ -101,6 +113,14 @@
    Some of the messages above are only visible when ``CMAKE_BUILD_TYPE`` is set
    to ``Debug``.
 
+.. note::
+
+   If ``-DPLATFORM_DEFAULT_PROVISIONING=OFF`` is set then the provisioning bundle has to
+   be placed on the ``0x10022000`` address with::
+
+   $ ./FVP_Corstone_SSE-300_Ethos-U55 -a cpu0*="bl2.axf" --data "tfm_s_ns_signed.bin"@0x01000000 --data "encrypted_provisioning_bundle.bin"@0x10022000
+
+
 -------------
 
-*Copyright (c) 2020-2022, Arm Limited. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited. All rights reserved.*
diff --git a/platform/ext/target/arm/mps3/an552/CMakeLists.txt b/platform/ext/target/arm/mps3/an552/CMakeLists.txt
index 5d3f347..febaccf 100644
--- a/platform/ext/target/arm/mps3/an552/CMakeLists.txt
+++ b/platform/ext/target/arm/mps3/an552/CMakeLists.txt
@@ -224,3 +224,7 @@
         ${PLATFORM_DIR}/ext/common/tfm_hal_isolation_v8m.c
         $<$<OR:$<BOOL:${CONFIG_TFM_FLIH_API}>,$<BOOL:${CONFIG_TFM_SLIH_API}>>:${PLATFORM_DIR}/ext/common/tfm_interrupts.c>
 )
+
+if(NOT PLATFORM_DEFAULT_PROVISIONING)
+    add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/provisioning provisioning)
+endif()
diff --git a/platform/ext/target/arm/mps3/an552/partition/region_defs.h b/platform/ext/target/arm/mps3/an552/partition/region_defs.h
index 58a9048..9aac29b 100755
--- a/platform/ext/target/arm/mps3/an552/partition/region_defs.h
+++ b/platform/ext/target/arm/mps3/an552/partition/region_defs.h
@@ -123,12 +123,12 @@
 /* Bootloader regions */
 /* Use ITCM to store Bootloader */
 #define BL2_CODE_START    (ITCM_BASE_S)
-#define BL2_CODE_SIZE     (ITCM_SIZE)
+#define BL2_CODE_SIZE     (0x00020000)      /* 128 kB */
 #define BL2_CODE_LIMIT    (BL2_CODE_START + BL2_CODE_SIZE - 1)
 
 /* Bootloader uses same memory as for secure image */
 #define BL2_DATA_START    (S_DATA_START)
-#define BL2_DATA_SIZE     (S_DATA_SIZE)
+#define BL2_DATA_SIZE     (0x00010000)  /* 64 kB */
 #define BL2_DATA_LIMIT    (BL2_DATA_START + BL2_DATA_SIZE - 1)
 #endif /* BL2 */
 
@@ -141,4 +141,17 @@
 #define BOOT_TFM_SHARED_DATA_LIMIT (BOOT_TFM_SHARED_DATA_BASE + \
                                     BOOT_TFM_SHARED_DATA_SIZE - 1)
 
+#define PROVISIONING_BUNDLE_CODE_START (BL2_CODE_START + BL2_CODE_SIZE)
+#define PROVISIONING_BUNDLE_CODE_SIZE  (0x2000)
+/* The max size of the values(keys, seeds) that are going to be provisioned
+ * into the OTP. */
+#define PROVISIONING_BUNDLE_VALUES_START (BL2_DATA_START + BL2_DATA_SIZE)
+#define PROVISIONING_BUNDLE_VALUES_SIZE (0x400)
+#define PROVISIONING_BUNDLE_DATA_START (PROVISIONING_BUNDLE_VALUES_START + \
+                                        PROVISIONING_BUNDLE_VALUES_SIZE)
+#define PROVISIONING_BUNDLE_DATA_SIZE (0x400)
+
+#define PROVISIONING_BUNDLE_START (PROVISIONING_BUNDLE_CODE_START + \
+                                      PROVISIONING_BUNDLE_CODE_SIZE)
+
 #endif /* __REGION_DEFS_H__ */
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/CMakeLists.txt b/platform/ext/target/arm/mps3/an552/provisioning/CMakeLists.txt
new file mode 100644
index 0000000..fe20e69
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/CMakeLists.txt
@@ -0,0 +1,103 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+
+find_package(Python3)
+
+add_executable(provisioning_bundle)
+
+set_target_properties(provisioning_bundle
+    PROPERTIES
+        SUFFIX ".axf"
+)
+
+target_add_scatter_file(provisioning_bundle
+    $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/provisioning_bundle.sct>
+    $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/provisioning_bundle.ld>
+)
+
+target_link_options(provisioning_bundle
+    PRIVATE
+        $<$<C_COMPILER_ID:GNU>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/provisioning_bundle.map>
+        $<$<C_COMPILER_ID:ARMClang>:--map>
+        $<$<C_COMPILER_ID:IAR>:--map\;${CMAKE_BINARY_DIR}/bin/provisioning_bundle.map>
+)
+
+target_link_options(provisioning_bundle
+    PRIVATE
+        --entry=do_provision
+)
+
+target_sources(provisioning_bundle
+    PRIVATE
+        ./provisioning_code.c
+        $<$<BOOL:${TFM_DUMMY_PROVISIONING}>:./dummy_provisioning_data.c>
+)
+
+target_include_directories(provisioning_bundle
+    PRIVATE
+        .
+)
+
+target_link_libraries(provisioning_bundle
+    platform_s
+    psa_interface
+)
+
+target_compile_definitions(provisioning_bundle
+    PRIVATE
+        $<$<BOOL:${PLATFORM_DEFAULT_CRYPTO_KEYS}>:PLATFORM_DEFAULT_CRYPTO_KEYS>
+        $<$<BOOL:${PLATFORM_DEFAULT_OTP}>:PLATFORM_DEFAULT_OTP>
+        $<$<BOOL:${SYMMETRIC_INITIAL_ATTESTATION}>:SYMMETRIC_INITIAL_ATTESTATION>
+        $<$<BOOL:${TFM_DUMMY_PROVISIONING}>:TFM_DUMMY_PROVISIONING>
+        $<$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>:PLATFORM_DEFAULT_NV_COUNTERS>
+        $<$<BOOL:${PLATFORM_DEFAULT_OTP_WRITEABLE}>:OTP_WRITEABLE>
+)
+
+add_custom_target(encrypted_provisioning_bundle
+    ALL
+    SOURCES encrypted_provisioning_bundle.bin
+)
+
+add_custom_command(OUTPUT encrypted_provisioning_bundle.bin
+    DEPENDS $<TARGET_FILE_DIR:provisioning_bundle>/provisioning_bundle.axf
+    DEPENDS provisioning_bundle
+    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/create_provisioning_bundle.py
+    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:provisioning_bundle>/provisioning_bundle.axf
+                    --dump-section CODE=provisioning_code.bin
+    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:provisioning_bundle>/provisioning_bundle.axf
+                    --dump-section RO_DATA=provisioning_rodata.bin
+    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:provisioning_bundle>/provisioning_bundle.axf
+                    --dump-section RW_DATA=provisioning_rwdata.bin
+    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:provisioning_bundle>/provisioning_bundle.axf
+                    --dump-section VALUES=provisioning_values.bin
+    COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/create_provisioning_bundle.py
+                    --provisioning_code provisioning_code.bin
+                    --provisioning_rwdata provisioning_rwdata.bin
+                    --provisioning_rodata provisioning_rodata.bin
+                    --provisioning_values provisioning_values.bin
+                    --bundle_output_file encrypted_provisioning_bundle.bin
+                    --magic "0xC0DEFEED"
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/encrypted_provisioning_bundle.bin ${CMAKE_BINARY_DIR}/bin/encrypted_provisioning_bundle.bin
+)
+
+
+
+target_sources(platform_s
+    PRIVATE
+        ./runtime_stub_provisioning.c
+)
+
+target_sources(platform_bl2
+    PRIVATE
+        ./bl2_provisioning.c
+)
+
+target_include_directories(platform_bl2
+    INTERFACE
+        .
+)
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/bl2_provisioning.c b/platform/ext/target/arm/mps3/an552/provisioning/bl2_provisioning.c
new file mode 100644
index 0000000..d1bf141
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/bl2_provisioning.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_plat_provisioning.h"
+#include "tfm_plat_otp.h"
+#include "tfm_attest_hal.h"
+#include "region_defs.h"
+#include "bootutil/bootutil_log.h"
+#include "string.h"
+#include "provisioning_bundle.h"
+
+static const volatile struct provisioning_bundle *encrypted_bundle =
+(const struct provisioning_bundle *)PROVISIONING_BUNDLE_START;
+
+static enum tfm_plat_err_t provision_assembly_and_test(void);
+
+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("[WRN]\033[1;31m ");
+        BOOT_LOG_WRN("This device was provisioned with dummy keys. ");
+        BOOT_LOG_WRN("This device is \033[1;1mNOT SECURE");
+        BOOT_LOG_WRN("\033[0m\r\n");
+    }
+
+    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 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("[INF] Beginning provisioning\r\n");
+#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) {
+
+        BOOT_LOG_INF("[INF] Waiting for CM provisioning bundle\r\n");
+        while (encrypted_bundle->magic != BUNDLE_MAGIC ||
+               encrypted_bundle->magic2 != BUNDLE_MAGIC) {
+        }
+
+        err = provision_assembly_and_test();
+        if (err != TFM_PLAT_ERR_SUCCESS) {
+            return err;
+        }
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+static enum tfm_plat_err_t provision_assembly_and_test(void)
+{
+    enum tfm_plat_err_t err;
+
+    /* TODO replace this with decrypt and auth */
+    memcpy((void*)PROVISIONING_BUNDLE_CODE_START,
+           (void *)encrypted_bundle->code,
+           PROVISIONING_BUNDLE_CODE_SIZE);
+    memcpy((void*)PROVISIONING_BUNDLE_DATA_START,
+           (void *)&encrypted_bundle->data,
+           PROVISIONING_BUNDLE_DATA_SIZE);
+    memcpy((void*)PROVISIONING_BUNDLE_VALUES_START,
+           (void *)&encrypted_bundle->values,
+           PROVISIONING_BUNDLE_VALUES_SIZE);
+
+    BOOT_LOG_INF("[INF] Running provisioning bundle\r\n");
+    err = ((enum tfm_plat_err_t (*)(void))(PROVISIONING_BUNDLE_CODE_START | 0b1))();
+
+    memset((void *)PROVISIONING_BUNDLE_CODE_START, 0,
+           PROVISIONING_BUNDLE_CODE_SIZE);
+    memset((void *)PROVISIONING_BUNDLE_DATA_START, 0,
+           PROVISIONING_BUNDLE_DATA_SIZE);
+    memset((void *)PROVISIONING_BUNDLE_VALUES_START, 0,
+           PROVISIONING_BUNDLE_VALUES_SIZE);
+
+    return err;
+}
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/create_provisioning_bundle.py b/platform/ext/target/arm/mps3/an552/provisioning/create_provisioning_bundle.py
new file mode 100755
index 0000000..c84b589
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/create_provisioning_bundle.py
@@ -0,0 +1,85 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+import argparse
+import struct
+import secrets
+
+def struct_pack(objects, pad_to=0):
+    defstring = "<"
+    for obj in objects:
+        defstring += str(len(obj)) + "s"
+
+    size = struct.calcsize(defstring)
+    if size < pad_to:
+        defstring += str(pad_to - size) + "x"
+    elif size > pad_to and pad_to != 0:
+        print("Error padding struct of size {} to {}".format(size, pad_to))
+        exit(1);
+
+    return (bytes(struct.pack(defstring, *objects)))
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--provisioning_code", help="the input provisioning code", required=True)
+parser.add_argument("--provisioning_rwdata", help="the input provisioning rwdata", required=False)
+parser.add_argument("--provisioning_rodata", help="the input provisioning rodata", required=False)
+parser.add_argument("--provisioning_values", help="the input provisioning values", required=True)
+parser.add_argument("--magic", help="the magic constant to insert at the start and end", required=True)
+parser.add_argument("--bl1_2_padded_hash_input_file", help="the hash of the final bl1_2 image", required=False)
+parser.add_argument("--bl1_2_input_file", help="the final bl1_2 image", required=False)
+parser.add_argument("--bundle_output_file", help="bundle output file", required=False)
+args = parser.parse_args()
+
+with open(args.provisioning_code, "rb") as in_file:
+    code = in_file.read()
+
+if args.provisioning_rwdata:
+    with open(args.provisioning_rwdata, "rb") as in_file:
+        rwdata = in_file.read()
+else:
+    rwdata = bytes(0)
+
+if args.provisioning_rodata:
+    with open(args.provisioning_rodata, "rb") as in_file:
+        rodata = in_file.read()
+else:
+    rodata = bytes(0)
+
+with open(args.provisioning_values, "rb") as in_file:
+    values = in_file.read()
+
+if args.bl1_2_padded_hash_input_file:
+    with open(args.bl1_2_padded_hash_input_file, "rb") as in_file:
+        bl1_2_padded_hash = in_file.read()
+else:
+    bl1_2_padded_hash = bytes(0)
+
+if args.bl1_2_input_file:
+    with open(args.bl1_2_input_file, "rb") as in_file:
+        bl1_2 = in_file.read()
+else:
+    bl1_2 = bytes(0)
+
+patch_bundle = struct_pack([
+    bl1_2_padded_hash,
+    bl1_2,
+])
+
+code = struct_pack([code], pad_to=0x2000)
+values = struct_pack([patch_bundle, values[len(patch_bundle):]], pad_to=0x400)
+data = struct_pack([values, rwdata, rodata], pad_to=0x800)
+
+bundle = struct_pack([
+    int(args.magic, 16).to_bytes(4, 'little'),
+    code,
+    data,
+    bytes(16), # Replace with GCM TAG
+    int(args.magic, 16).to_bytes(4, 'little'),
+])
+
+with open(args.bundle_output_file, "wb") as out_file:
+    out_file.write(bundle)
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/dummy_provisioning_data.c b/platform/ext/target/arm/mps3/an552/provisioning/dummy_provisioning_data.c
new file mode 100644
index 0000000..91ccf2a
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/dummy_provisioning_data.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "provisioning_bundle.h"
+#include "psa/crypto.h"
+#include "config_tfm.h"
+
+const struct provisioning_data_t data = {
+    .bl2_assembly_and_test_prov_data = {
+#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,
+            },
+#if (MCUBOOT_IMAGE_NUMBER > 2)
+            /* bl2 rotpk 2 */
+            {
+                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,
+            },
+#endif /* MCUBOOT_IMAGE_NUMBER > 2 */
+#if (MCUBOOT_IMAGE_NUMBER > 3)
+            /* bl2 rotpk 3 */
+            {
+                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,
+            },
+#endif /* MCUBOOT_IMAGE_NUMBER > 3 */
+#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,
+            },
+#if (MCUBOOT_IMAGE_NUMBER > 2)
+            /* bl2 rotpk 2 */
+            {
+                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,
+            },
+#endif /* MCUBOOT_IMAGE_NUMBER > 2 */
+#if (MCUBOOT_IMAGE_NUMBER > 3)
+            /* bl2 rotpk 3 */
+            {
+                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,
+            },
+#endif /* MCUBOOT_IMAGE_NUMBER > 3 */
+#else
+#error "No public key available for given signing algorithm."
+#endif /* MCUBOOT_SIGN_RSA_LEN */
+
+#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
+            {
+                0xf4, 0x0c, 0x8f, 0xbf, 0x12, 0xdb, 0x78, 0x2a,
+                0xfd, 0xf4, 0x75, 0x96, 0x6a, 0x06, 0x82, 0x36,
+                0xe0, 0x32, 0xab, 0x80, 0xd1, 0xb7, 0xf1, 0xbc,
+                0x9f, 0xe7, 0xd8, 0x7a, 0x88, 0xcb, 0x26, 0xd0,
+            },
+#endif /* PLATFORM_PSA_ADAC_SECURE_DEBUG */
+    },
+    .assembly_and_test_prov_data = {
+        /* 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,
+        },
+    },
+    .psa_rot_prov_data = {
+            /* 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 */
+#if ATTEST_INCLUDE_COSE_KEY_ID
+            /* IAK id */
+            "kid@trustedfirmware.example",
+#endif /* ATTEST_INCLUDE_COSE_KEY_ID */
+            /* 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,
+            },
+            /* certification reference */
+            "0604565272829-10010",
+            /* verification_service_url */
+            "www.trustedfirmware.org",
+            /* attestation_profile_definition */
+#if ATTEST_TOKEN_PROFILE_PSA_IOT_1
+            "PSA_IOT_PROFILE_1",
+#elif ATTEST_TOKEN_PROFILE_PSA_2_0_0
+            "http://arm.com/psa/2.0.0",
+#elif ATTEST_TOKEN_PROFILE_ARM_CCA
+            "http://arm.com/CCA-SSD/1.0.0",
+#else
+#ifdef TFM_PARTITION_INITIAL_ATTESTATION
+#error "Attestation token profile is incorrect"
+#else
+            "UNDEFINED",
+#endif /* TFM_PARTITION_INITIAL_ATTESTATION */
+#endif
+            /* 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,
+            },
+    }
+};
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.h b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.h
new file mode 100644
index 0000000..4a7edb1
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __PROVISIONING_BUNDLE_H__
+#define __PROVISIONING_BUNDLE_H__
+
+#include "stdint.h"
+#include "region_defs.h"
+#include "cmsis_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BUNDLE_MAGIC 0xC0DEFEED
+
+__PACKED_STRUCT tfm_assembly_and_test_provisioning_data_t {
+    uint8_t huk[32];
+};
+
+__PACKED_STRUCT tfm_psa_rot_provisioning_data_t {
+    uint8_t iak[32];
+    uint32_t iak_len;
+    uint32_t iak_type;
+#if ATTEST_INCLUDE_COSE_KEY_ID
+    uint8_t iak_id[32];
+#endif /* ATTEST_INCLUDE_COSE_KEY_ID */
+
+    uint8_t boot_seed[32];
+    uint8_t implementation_id[32];
+    uint8_t cert_ref[32];
+    uint8_t verification_service_url[32];
+    uint8_t profile_definition[32];
+
+    uint8_t entropy_seed[64];
+};
+
+__PACKED_STRUCT bl2_assembly_and_test_provisioning_data_t {
+    uint8_t bl2_rotpk_0[32];
+    uint8_t bl2_rotpk_1[32];
+#if (MCUBOOT_IMAGE_NUMBER > 2)
+    uint8_t bl2_rotpk_2[32];
+#endif
+#if (MCUBOOT_IMAGE_NUMBER > 3)
+    uint8_t bl2_rotpk_3[32];
+#endif
+
+#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
+    uint8_t secure_debug_pk[32];
+#endif /* PLATFORM_PSA_ADAC_SECURE_DEBUG */
+};
+
+__PACKED_STRUCT provisioning_data_t {
+    const struct bl2_assembly_and_test_provisioning_data_t bl2_assembly_and_test_prov_data;
+    const struct tfm_assembly_and_test_provisioning_data_t assembly_and_test_prov_data;
+    const struct tfm_psa_rot_provisioning_data_t psa_rot_prov_data;
+};
+
+struct __attribute__((__packed__)) provisioning_bundle {
+    /* This section is authenticated */
+    uint32_t magic;
+    /* This section is encrypted */
+    uint8_t code[PROVISIONING_BUNDLE_CODE_SIZE];
+    union __attribute__((__packed__)) {
+        const struct provisioning_data_t values;
+        const uint8_t _pad[PROVISIONING_BUNDLE_VALUES_SIZE];
+    };
+    uint8_t data[PROVISIONING_BUNDLE_DATA_SIZE];
+    /* This section is metadata */
+    uint8_t tag[16];
+    uint32_t magic2;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PROVISIONING_BUNDLE_H__ */
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.ld b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.ld
new file mode 100644
index 0000000..0400f51
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.ld
@@ -0,0 +1,65 @@
+;/*
+; * Copyright (c) 2021-2023 Arm Limited. All rights reserved.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; *
+; *     http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 gcc_arm.ld
+; */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+MEMORY
+{
+    CODE (rx) : ORIGIN = PROVISIONING_BUNDLE_CODE_START, LENGTH = PROVISIONING_BUNDLE_CODE_SIZE
+    DATA (rw) : ORIGIN = PROVISIONING_BUNDLE_DATA_START, LENGTH = PROVISIONING_BUNDLE_DATA_SIZE
+    VALUES (r) : ORIGIN = PROVISIONING_BUNDLE_VALUES_START, LENGTH = PROVISIONING_BUNDLE_VALUES_SIZE
+}
+
+/* Library configurations */
+GROUP(libgcc.a libc.a libm.a libnosys.a)
+
+ENTRY(do_provisioning)
+
+SECTIONS
+{
+    CODE :
+    {
+        *provisioning_code.o(DO_PROVISION)
+        *(.text*)
+    } > CODE
+
+    RW_DATA :
+    {
+        *(COMMON .data*)
+    } > DATA
+
+    RO_DATA :
+    {
+        *(EXCLUDE_FILE (*provisioning_data.o) .rodata*)
+    } > DATA
+
+    BSS_DATA :
+    {
+        *(.bss*)
+    } > DATA
+
+    VALUES :
+    {
+        *_provisioning_data.o(.rodata.data)
+    } > VALUES
+
+}
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.sct b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.sct
new file mode 100644
index 0000000..6a09f14
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_bundle.sct
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2023 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "region_defs.h"
+
+LR_VALUES PROVISIONING_BUNDLE_VALUES_START {
+    VALUES PROVISIONING_BUNDLE_VALUES_START PROVISIONING_BUNDLE_VALUES_SIZE {
+        *provisioning_data.o (+RO)
+    }
+}
+
+LR_DATA PROVISIONING_BUNDLE_DATA_START {
+    RW_DATA PROVISIONING_BUNDLE_DATA_START PROVISIONING_BUNDLE_DATA_SIZE{
+        * (+RW)
+    }
+    RO_DATA +0 {
+        * (+RO-DATA)
+    }
+    BSS_DATA +0 {
+        * (+ZI)
+    }
+}
+
+LR_CODE PROVISIONING_BUNDLE_CODE_START {
+    CODE PROVISIONING_BUNDLE_CODE_START PROVISIONING_BUNDLE_CODE_SIZE {
+        * (DO_PROVISION +First)
+        * (+RO-CODE)
+    }
+}
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/provisioning_code.c b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_code.c
new file mode 100644
index 0000000..7d0592f
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/provisioning_code.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_plat_otp.h"
+#include "provisioning_bundle.h"
+
+/* This is a stub to make the linker happy */
+void __Vectors(){}
+
+
+extern const struct provisioning_data_t data;
+
+enum tfm_plat_err_t __attribute__((section("DO_PROVISION"))) do_provision(void) {
+    enum tfm_plat_err_t err;
+    uint32_t new_lcs;
+    err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_0,
+                             sizeof(data.bl2_assembly_and_test_prov_data.bl2_rotpk_0),
+                             data.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(data.bl2_assembly_and_test_prov_data.bl2_rotpk_1),
+                             data.bl2_assembly_and_test_prov_data.bl2_rotpk_1);
+    if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+        return err;
+    }
+#if (MCUBOOT_IMAGE_NUMBER > 2)
+    err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_2,
+                             sizeof(data.bl2_assembly_and_test_prov_data.bl2_rotpk_2),
+                             data.bl2_assembly_and_test_prov_data.bl2_rotpk_2);
+    if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+        return err;
+    }
+#endif /* MCUBOOT_IMAGE_NUMBER > 2 */
+#if (MCUBOOT_IMAGE_NUMBER > 3)
+    err = tfm_plat_otp_write(PLAT_OTP_ID_BL2_ROTPK_3,
+                             sizeof(data.bl2_assembly_and_test_prov_data.bl2_rotpk_3),
+                             data.bl2_assembly_and_test_prov_data.bl2_rotpk_3);
+    if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+        return err;
+    }
+#endif /* MCUBOOT_IMAGE_NUMBER > 3 */
+
+#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
+    err = tfm_plat_otp_write(PLAT_OTP_ID_SECURE_DEBUG_PK,
+                             sizeof(data.bl2_assembly_and_test_prov_data.secure_debug_pk),
+                             data.bl2_assembly_and_test_prov_data.secure_debug_pk);
+    if (err != TFM_PLAT_ERR_SUCCESS && err != TFM_PLAT_ERR_UNSUPPORTED) {
+        return err;
+    }
+#endif /* PLATFORM_PSA_ADAC_SECURE_DEBUG */
+
+    err = tfm_plat_otp_write(PLAT_OTP_ID_HUK, sizeof(data.assembly_and_test_prov_data.huk),
+                             data.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;
+    }
+
+    err = tfm_plat_otp_write(PLAT_OTP_ID_IAK,
+                             sizeof(data.psa_rot_prov_data.iak),
+                             data.psa_rot_prov_data.iak);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+    err = tfm_plat_otp_write(PLAT_OTP_ID_IAK_LEN,
+                             sizeof(data.psa_rot_prov_data.iak_len),
+                             (uint8_t*)&data.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(data.psa_rot_prov_data.iak_type),
+                             (uint8_t*)&data.psa_rot_prov_data.iak_type);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+#if ATTEST_INCLUDE_COSE_KEY_ID
+    err = tfm_plat_otp_write(PLAT_OTP_ID_IAK_ID,
+                             sizeof(data.psa_rot_prov_data.iak_id),
+                             data.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(data.psa_rot_prov_data.boot_seed),
+                             data.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(data.psa_rot_prov_data.implementation_id),
+                             data.psa_rot_prov_data.implementation_id);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+    err = tfm_plat_otp_write(PLAT_OTP_ID_CERT_REF,
+                             sizeof(data.psa_rot_prov_data.cert_ref),
+                             data.psa_rot_prov_data.cert_ref);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+    err = tfm_plat_otp_write(PLAT_OTP_ID_VERIFICATION_SERVICE_URL,
+                             sizeof(data.psa_rot_prov_data.verification_service_url),
+                             data.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(data.psa_rot_prov_data.profile_definition),
+                             data.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(data.psa_rot_prov_data.entropy_seed),
+                             data.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;
+}
diff --git a/platform/ext/target/arm/mps3/an552/provisioning/runtime_stub_provisioning.c b/platform/ext/target/arm/mps3/an552/provisioning/runtime_stub_provisioning.c
new file mode 100644
index 0000000..d353a9b
--- /dev/null
+++ b/platform/ext/target/arm/mps3/an552/provisioning/runtime_stub_provisioning.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_plat_provisioning.h"
+
+void tfm_plat_provisioning_check_for_dummy_keys(void)
+{
+}
+
+int tfm_plat_provisioning_is_required(void)
+{
+    return 0;
+}
+
+enum tfm_plat_err_t tfm_plat_provisioning_perform(void)
+{
+    return TFM_PLAT_ERR_SUCCESS;
+}