NuMaker Pelion Device Management example

Fork of mbed-os-example-pelion by cc li

Files at this revision

API Documentation at this revision

Comitter:
ccli8
Date:
Fri Nov 22 11:16:39 2019 +0800
Parent:
3:bda8852d7723
Child:
5:ae686808e015
Commit message:
Update to mbed-os 5.14.2 and related modifications

1. Provide custom entropy source on targets without real TRNG
The targets below don't have real TRNG and cannot annouce TRNG support. A custom entropy source with EADC seeded PRNG is given to remedy it:
- NUMAKER_PFM_NUC47
- NUMAKER_PFM_M487
- NUMAKER_IOT_M487
2. Override mbed_main() for simulating provision process

Changed in this revision

TARGET_NUVOTON/platform_entropy.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
pre-main/mbed_main.cpp Show annotated file Show diff for this revision Revisions of this file
pre-main/provision.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TARGET_NUVOTON/platform_entropy.cpp	Fri Nov 22 11:16:39 2019 +0800
@@ -0,0 +1,363 @@
+/* 
+ * Copyright (c) 2019 Nuvoton Technology Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#if !DEVICE_TRNG && !TARGET_PSA
+ 
+#include "mbed.h"
+#include "mbedtls/config.h"
+
+#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
+
+/* Support entropy source with EADC seeded PRNG on non-PSA targets without TRNG
+ *
+ * Follow the steps below to replace TRNG with EADC seeded PRNG:
+ *
+ * 1. Seed PRNG with EADC band gap
+ * 2. Define MBEDTLS_ENTROPY_HARDWARE_ALT and provide custom mbedtls_hardware_poll(...)
+ *
+ * Reference configuration in mbed_app.json:
+ *
+ * For Pelion/mbedtls:
+ *
+ *  "target.macros_add": [
+ *      "MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", 
+ *      "MBEDTLS_ENTROPY_HARDWARE_ALT"
+ *  ],
+ *
+ * For non-Pelion/mbedtls:
+ *
+ *  "target.macros_add": [
+ *      "MBEDTLS_ENTROPY_HARDWARE_ALT"
+ *  ],
+ *
+ * For both Pelion/non-Pelion (skip when done in targets.json):
+ *
+ *  "target.device_has_remove": ["TRNG"],
+ *
+ * WARNING: If the security level of EADC seeded PRNG cannot meet requirements, replace it with another entropy source.
+ */
+
+#include "crypto-misc.h"
+
+extern "C" {
+    int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen);
+}
+
+/* Support EADC band gap
+ *
+ * Mbed OS defines analog-in HAL for normal purposes, but EADC band gap is not defined.
+ * To avoid EADC code conflict and fit into existent analog-in HAL, we:
+ *
+ * 1. Hijack AnalogIn driver to involve analog-in HAL protection and EADC initialization.
+ *    This needs one dedicated EADC pin EADC_AUX_PINNAME.
+ * 2. Run EADC band gap conversion, with EADC module already initialized via above. This needs
+ *    one dedicated sample module and one dedicated channel.
+ */
+
+#if TARGET_NUC472
+    #define EADC_AUX_PINNAME        A0
+    #define EADC_BANDGAP_SMPLMOD    7
+    #define EADC_BANDGAP_CHN        8
+    #define PRNG_KEYSIZE_ID         PRNG_KEY_SIZE_128
+    #define PRNG_KEYSIZE            16
+#elif TARGET_M480
+    #define EADC_AUX_PINNAME        A0
+    #define EADC_BANDGAP_SMPLMOD    16
+    #define EADC_BANDGAP_CHN        16
+    #define PRNG_KEYSIZE_ID         PRNG_KEY_SIZE_128
+    #define PRNG_KEYSIZE            16
+#else
+    #error("Target not support")
+#endif
+
+class NuBandGap : public mbed::AnalogIn {
+public:
+    NuBandGap();
+    ~NuBandGap();
+
+    /* Generate bitstream based on EADC band gap 
+     *
+     * @returns 1/0 bitstream
+     */
+    uint16_t read_bitstream();
+};
+
+class NuEADCSeedPRNG : private mbed::NonCopyable<NuEADCSeedPRNG>
+{
+public:
+    NuEADCSeedPRNG();
+    ~NuEADCSeedPRNG();
+
+    /* Get random data
+     *
+     * @param output    The pointer to an output array
+     * @param len       The size of output data, to avoid buffer overwrite
+     * @param olen      The length of generated data
+     */
+    int get_bytes(unsigned char *output, size_t len, size_t *olen);
+
+private:
+    NuBandGap band_gap;
+};
+
+int mbedtls_hardware_poll(MBED_UNUSED void *data, unsigned char *output, size_t len, size_t *olen)
+{
+    static NuEADCSeedPRNG eadc_seed_prng;
+
+    return eadc_seed_prng.get_bytes(output, len, olen);
+}
+
+NuBandGap::NuBandGap() : mbed::AnalogIn(EADC_AUX_PINNAME)
+{
+    EADC_T *eadc_base = (EADC_T *) EADC_BASE;
+
+    EADC_ConfigSampleModule(eadc_base, EADC_BANDGAP_SMPLMOD, EADC_SOFTWARE_TRIGGER, EADC_BANDGAP_CHN);
+}
+
+NuBandGap::~NuBandGap()
+{
+}
+
+uint16_t NuBandGap::read_bitstream()
+{
+    uint16_t one_or_zero;
+
+    lock();
+
+    EADC_T *eadc_base = (EADC_T *) EADC_BASE;
+
+    EADC_START_CONV(eadc_base, 1 << EADC_BANDGAP_SMPLMOD);
+    while (EADC_GET_DATA_VALID_FLAG(eadc_base, 1 << EADC_BANDGAP_SMPLMOD) != (1 << EADC_BANDGAP_SMPLMOD));
+    uint16_t conv_res_12 = EADC_GET_CONV_DATA(eadc_base, EADC_BANDGAP_SMPLMOD);
+
+    /* 1 as number of 'one' is odd; 0 otherwise */
+    unsigned i;
+    uint16_t count_one = 0;
+    for (i = 0; i < 12; i ++) {
+        if (conv_res_12 & 1) {
+            count_one ++;
+        }
+        conv_res_12 >>= 1;
+    }
+    one_or_zero = count_one & 1;
+
+    unlock();
+    
+    return one_or_zero;
+}
+
+NuEADCSeedPRNG::NuEADCSeedPRNG()
+{
+    crypto_init();
+    PRNG_ENABLE_INT();
+
+    uint32_t seed = 0;
+    unsigned i = 32;
+
+    /* Get seed from EADC band gap */
+    while (i --) {
+        seed <<= 1;
+        seed |= band_gap.read_bitstream();
+    }
+
+    /* PRNG reload seed */
+    PRNG_Open(PRNG_KEYSIZE_ID, 1, seed);
+}
+
+NuEADCSeedPRNG::~NuEADCSeedPRNG()
+{
+    PRNG_DISABLE_INT();
+    crypto_uninit();
+}
+
+int NuEADCSeedPRNG::get_bytes(unsigned char *output, size_t len, size_t *olen)
+{
+    /* Check argument validity */
+    if (!output && len) {
+        return -1;
+    }
+
+    unsigned char *output_ind = output;
+    size_t rmn = len;
+    uint32_t rand_data[PRNG_KEYSIZE / sizeof(uint32_t)];
+    while (rmn) {
+        crypto_prng_prestart();
+        PRNG_Start();
+        crypto_prng_wait();
+
+        PRNG_Read(rand_data);
+
+        size_t n = (rmn >= PRNG_KEYSIZE) ? PRNG_KEYSIZE : rmn;
+        memcpy(output_ind, rand_data, n);
+        
+        output_ind += n;
+        rmn -= n;
+    }
+
+    if (olen) {
+        *olen = len;
+    }
+
+    return 0;
+}
+
+#else
+
+/* Support entropy source with mbedtls NV seed on non-PSA targets without TRNG
+ *
+ * Follow the steps below to replace TRNG with mbedtls NV seed:
+ *
+ * 1. Define MBEDTLS_ENTROPY_NV_SEED
+ * 2. Define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO/MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and provide custom mbedtls_nv_seed_read(...)/mbedtls_nv_seed_write(...).
+ * 3. Don't define MBEDTLS_PSA_INJECT_ENTROPY. Meet mbedtls_psa_inject_entropy(...) undefined and then provide custom one, which must be compatible with mbedtls_nv_seed_read(...)/mbedtls_nv_seed_write(...) above.
+ * 4. For development, simulating partial provision process, inject entropy seed via mbedtls_psa_inject_entropy(...) pre-main.
+ *
+ * Reference configuration in mbed_app.json:
+ *
+ * For Pelion/mbedtls, don't define MBEDTLS_ENTROPY_NV_SEED because it has defined in:
+ * https://github.com/ARMmbed/mbed-cloud-client/blob/master/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_mbedOS_SW_TRNG.h
+ * 
+ *  "target.macros_add": [
+ *      "MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS_SW_TRNG.h\"", 
+ *      "PAL_USE_HW_TRNG=0",
+ *      "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO=mbedtls_platform_seed_read",
+ *      "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO=mbedtls_platform_seed_write"
+ *  ],
+ *
+ * For non-Pelion/mbedtls:
+ *
+ *  "target.macros_add": [
+ *      "MBEDTLS_ENTROPY_NV_SEED",
+ *      "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO=mbedtls_platform_seed_read",
+ *      "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO=mbedtls_platform_seed_write"
+ *  ],
+ *
+ * For both Pelion/non-Pelion (skip when done in targets.json):
+ *
+ *  "target.device_has_remove": ["TRNG"],
+ *
+ * WARNING: The injection of mbedtls NV seed pre-main is only for development. Run provision process for mass production.
+ */
+
+#include "entropy_poll.h"
+#include "psa/crypto.h"
+#include "KVStore.h"
+#include "TDBStore.h"
+#include "KVMap.h"
+#include "kv_config.h"
+
+extern "C" {
+    psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed, size_t seed_size);
+    int mbedtls_platform_seed_read(unsigned char *buf, size_t buf_len);
+    int mbedtls_platform_seed_write(unsigned char *buf, size_t buf_len);
+}
+
+/* Requirement of seed size
+ *
+ * 1. >= MBEDTLS_ENTROPY_MIN_PLATFORM
+ * 2. >= MBEDTLS_ENTROPY_BLOCK_SIZE
+ * 3. <= MBEDTLS_ENTROPY_MAX_SEED_SIZE
+ */
+#define SEED_SIZE       64
+MBED_STATIC_ASSERT(SEED_SIZE >= MBEDTLS_ENTROPY_MIN_PLATFORM, "Seed size must be larger than or equal to MBEDTLS_ENTROPY_MIN_PLATFORM");
+MBED_STATIC_ASSERT(SEED_SIZE >= MBEDTLS_ENTROPY_BLOCK_SIZE, "Seed size must be larger than or equal to MBEDTLS_ENTROPY_BLOCK_SIZE");
+MBED_STATIC_ASSERT(SEED_SIZE <= MBEDTLS_ENTROPY_MAX_SEED_SIZE, "Seed size must be smaller than or equal to MBEDTLS_ENTROPY_MAX_SEED_SIZE");
+
+/* Seed key name in kvstore */
+#define KV_KEY_SEED         "seed"
+
+/* Inject an initial entropy seed for the random generator into secure storage
+ *
+ * See reference below for its prototype: 
+ * https://github.com/ARMmbed/mbed-os/blob/master/features/mbedtls/mbed-crypto/inc/psa/crypto_extra.h
+ */
+psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed, size_t seed_size)
+{
+    /* Check seed size requirement */
+    if ((( seed_size < MBEDTLS_ENTROPY_MIN_PLATFORM) || (seed_size < MBEDTLS_ENTROPY_BLOCK_SIZE)) ||
+        (seed_size > MBEDTLS_ENTROPY_MAX_SEED_SIZE)) {
+            return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Get kvstore internal storage where seed is injected */
+    KVMap &kv_map = KVMap::get_instance();
+    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
+    if (inner_store == NULL) {
+        return PSA_ERROR_STORAGE_FAILURE;
+    }
+
+    /* Check if seed has injected */
+    KVStore::info_t kv_info;
+    int kv_status = inner_store->get_info(KV_KEY_SEED, &kv_info);
+    if (kv_status == MBED_SUCCESS) {
+        return PSA_ERROR_NOT_PERMITTED;
+    } else if (kv_status == MBED_ERROR_ITEM_NOT_FOUND) {
+        /* No seed injected, inject it below */
+    } else {
+        return PSA_ERROR_STORAGE_FAILURE;
+    }
+
+    /* Inject seed into kvstore internal storage */
+    kv_status = inner_store->set(KV_KEY_SEED, seed, seed_size, 0);
+    if (kv_status == MBED_SUCCESS) {
+        return PSA_SUCCESS;
+    } else {
+        return PSA_ERROR_STORAGE_FAILURE;
+    }
+}
+
+int mbedtls_platform_seed_read(unsigned char *buf, size_t buf_len)
+{
+    /* Get kvstore internal storage where seed is injected */
+    KVMap &kv_map = KVMap::get_instance();
+    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
+    if (inner_store == NULL) {
+        return -1;
+    }
+
+    /* Read seed from kvstore internal storage */
+    size_t actual_size = 0;
+    int kv_status = inner_store->get(KV_KEY_SEED, buf, buf_len, &actual_size, 0);
+    if (kv_status != MBED_SUCCESS || actual_size != buf_len) {
+        return -1;
+    } else {
+        return buf_len;
+    }
+}
+
+int mbedtls_platform_seed_write(unsigned char *buf, size_t buf_len)
+{
+    /* Get kvstore internal storage where seed is injected */
+    KVMap &kv_map = KVMap::get_instance();
+    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
+    if (inner_store == NULL) {
+        return -1;
+    }
+
+    /* Write seed into kvstore internal storage */
+    int kv_status = inner_store->set(KV_KEY_SEED, buf, buf_len, 0);
+    if (kv_status != MBED_SUCCESS) {
+        return -1;
+    } else {
+        return buf_len;
+    }
+}
+
+#endif /* #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) */
+
+#endif /* !DEVICE_TRNG && !TARGET_PSA */
--- a/mbed-os.lib	Fri Nov 22 11:08:23 2019 +0800
+++ b/mbed-os.lib	Fri Nov 22 11:16:39 2019 +0800
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/mbed-os/#b6e5a0a8afa34dec9dae8963778aebce0c82a54b
+https://github.com/ARMmbed/mbed-os/#cf4f12a123c05fcae83fc56d76442015cb8a39e9
--- a/mbed_app.json	Fri Nov 22 11:08:23 2019 +0800
+++ b/mbed_app.json	Fri Nov 22 11:16:39 2019 +0800
@@ -44,7 +44,7 @@
             "storage_filesystem.rbp_internal_size"      : "(2*4*1024)",
             "storage_filesystem.external_base_address"  : "(0x0)",
             "storage_filesystem.external_size"          : "(1024*1024*64)",
-            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\""]
+            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", "MBEDTLS_ENTROPY_HARDWARE_ALT"]
         },
         "NUMAKER_PFM_M487": {
             "target.network-default-interface-type"     : "ETHERNET",
@@ -68,7 +68,7 @@
             "storage_filesystem.rbp_internal_size"      : "(2*4*1024)",
             "storage_filesystem.external_base_address"  : "(0x0)",
             "storage_filesystem.external_size"          : "(1024*1024*64)",
-            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\""]
+            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", "MBEDTLS_ENTROPY_HARDWARE_ALT"]
         },
         "NUMAKER_IOT_M487": {
             "target.network-default-interface-type"     : "WIFI",
@@ -98,7 +98,7 @@
             "esp8266.cts"                               : "A3",
             "esp8266.rst"                               : "PH_3",
             "esp8266.provide-default"                   : true,
-            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", "ESP8266_SEND_TIMEOUT=8000"]
+            "target.macros_add"                         : ["MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", "ESP8266_SEND_TIMEOUT=8000", "MBEDTLS_ENTROPY_HARDWARE_ALT"]
         },
         "NUMAKER_IOT_M263A": {
             "target.network-default-interface-type"     : "WIFI",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pre-main/mbed_main.cpp	Fri Nov 22 11:16:39 2019 +0800
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (c) 2019 Nuvoton Technology Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 "mbed.h"
+
+/* Run pre-main tasks via mbed_main()
+ *
+ * In Mbed OS boot sequence, mbed_main(), designed for user application override, is run
+ * before main(). We use it to run the following tasks:
+ *
+ * 1. Simulate provision process for development
+ * 2. Set up event queue for dispatching host command
+ *
+ * WARNING: For mass production, remove this file.
+ */
+
+/* Check weak reference/definition at the link:
+ * http://www.keil.com/support/man/docs/ARMLINK/armlink_pge1362065917715.htm */
+
+extern "C" {
+    MBED_USED void mbed_main(void);
+    MBED_WEAK void provision(void);
+    MBED_WEAK void pump_host_command(void);
+}
+
+void mbed_main(void)
+{
+    provision();
+    /* Spare memory if event queue is unnecessary */
+    if (pump_host_command) {
+        mbed_event_queue()->call_every(2000, pump_host_command);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pre-main/provision.cpp	Fri Nov 22 11:16:39 2019 +0800
@@ -0,0 +1,152 @@
+/* 
+ * Copyright (c) 2019 Nuvoton Technology Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 "mbed.h"
+#include "mbedtls/config.h"
+#include "entropy_poll.h"
+#include "psa/crypto.h"
+#include "kvstore_global_api.h"
+#include "KVStore.h"
+#include "TDBStore.h"
+#include "KVMap.h"
+#include "kv_config.h"
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+#include <inttypes.h>
+
+/* Simulate provision process for development
+ *
+ * 1. Reset kvstore
+ * 2. Inject entropy seed (if no entropy source)
+ * 3. Initialize user filesystem (if enabled)
+ * 4. Mark the device as provisioned
+ *
+ * WARNING: For mass production, remove this file and run real provision process.
+ */
+
+/* Check weak reference/definition at the link:
+ * http://www.keil.com/support/man/docs/ARMLINK/armlink_pge1362065917715.htm */
+
+extern "C" {
+    MBED_USED void provision(void);
+}
+
+/* Stringize */
+#define STR_EXPAND(tok) #tok
+#define STR(tok) STR_EXPAND(tok)
+
+#define _GET_FILESYSTEM_concat(dev, ...) _get_filesystem_##dev(__VA_ARGS__)
+#define GET_FILESYSTEM(dev, ...) _GET_FILESYSTEM_concat(dev, __VA_ARGS__)
+
+/* Key for the device provisioned */
+#define KV_KEY_PROVISION    "provision"
+
+void provision(void)
+{
+    int kv_reset(const char *kvstore_path);
+    
+    /* Initialize kvstore */
+    int kv_status = kv_init_storage_config();
+    if (kv_status != MBED_SUCCESS) {
+        MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "Initialize kvstore failed", kv_status);
+    }
+
+    /* Get kvstore internal storage */
+    KVMap &kv_map = KVMap::get_instance();
+    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
+    if (inner_store == NULL) {
+        MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "kvstore internal storage failed");
+    }
+
+    /* Check if the device has provisioned */
+    KVStore::info_t kv_info;
+    kv_status = inner_store->get_info(KV_KEY_PROVISION, &kv_info);
+    if (kv_status == MBED_SUCCESS) {
+        do {
+            /* Get KV_KEY_PROVISION key */
+            char buffer[4];
+            size_t actual_size = 0;
+            int kv_status = inner_store->get(KV_KEY_PROVISION, buffer, sizeof(buffer), &actual_size);
+            if (kv_status != MBED_SUCCESS) {
+                printf("Get \'%s\' failed: %d\r\n", KV_KEY_PROVISION, kv_status);
+                break;
+            }
+            /* Check KV_KEY_PROVISION key's value */
+            if (actual_size != 1 || buffer[0] != '1') {
+                printf("\"%s\" not equal \"%s\"\r\n", KV_KEY_PROVISION, "1");
+                break;
+            }
+
+            printf("The device has provisioned. Skip provision process\r\n");
+            return;
+        } while (0);
+    } else if (kv_status == MBED_ERROR_ITEM_NOT_FOUND) {
+        /* Not provisioned yet */
+        printf("The device has not provisioned yet. Try to provision it...\r\n");
+    } else {
+        printf("Get \'%s\' key failed: %d\r\n", KV_KEY_PROVISION, kv_status);
+    }
+
+    /* Provision from here */
+    printf("Provision for development...\r\n");
+    
+    printf("Reset kvstore...\r\n");
+
+    /* Reset kvstore for clean kvstore */
+    kv_status = kv_reset("/" STR(MBED_CONF_STORAGE_DEFAULT_KV) "/");
+    if (kv_status != MBED_SUCCESS) {
+        MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "kv_reset() failed", kv_status);
+    }
+
+    printf("\rReset kvstore...OK\r\n");
+
+#if !DEVICE_TRNG && !TARGET_PSA
+#if !defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
+    /* Inject trivial seed for development */
+
+    printf("Inject NV seed...\r\n");
+
+    psa_status_t psa_status;
+    uint8_t seed[SEED_SIZE] = { 0 };
+
+    /* First inject seed, expect OK or seed has injected by some provision process */
+    psa_status = mbedtls_psa_inject_entropy(seed, sizeof(seed));
+    if (psa_status != PSA_SUCCESS && psa_status != PSA_ERROR_NOT_PERMITTED) {
+        MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "Inject entropy failed", psa_status);
+    }
+
+    /* Second inject seed, expect seed has injected above or by some provision process */
+    psa_status = mbedtls_psa_inject_entropy(seed, sizeof(seed));
+    if (psa_status != PSA_ERROR_NOT_PERMITTED) {
+        MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "Re-jnject entropy expects PSA_ERROR_NOT_PERMITTED", psa_status);
+    }
+
+    printf("\rInject NV seed...OK\r\n");
+#endif  /* !defined(MBEDTLS_ENTROPY_HARDWARE_ALT) */
+#endif  /* #if !DEVICE_TRNG && !TARGET_PSA */
+
+    /* Mark the device as provisioned */
+    kv_status = inner_store->set(KV_KEY_PROVISION, "1", 1, KVStore::WRITE_ONCE_FLAG);
+    if (kv_status != MBED_SUCCESS) {
+        MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNKNOWN), "Mark the device as provisioned failed", kv_status);
+    }
+
+    printf("Provision for development...OK\r\n");
+}