diff --git a/cmsis/device/rtos/mbed_lib.json b/cmsis/device/rtos/mbed_lib.json index 231ee3c0755..b707834e66b 100644 --- a/cmsis/device/rtos/mbed_lib.json +++ b/cmsis/device/rtos/mbed_lib.json @@ -4,7 +4,7 @@ "present": 1, "main-thread-stack-size": { "help": "The size of the main thread's stack", - "value": 4096 + "value": 16384 }, "timer-thread-stack-size": { "help": "The size of the timer thread's stack", diff --git a/storage/blockdevice/CMakeLists.txt b/storage/blockdevice/CMakeLists.txt index 8b77f0fbc05..3a8a12bee28 100644 --- a/storage/blockdevice/CMakeLists.txt +++ b/storage/blockdevice/CMakeLists.txt @@ -38,6 +38,9 @@ if("SPIF" IN_LIST MBED_TARGET_LABELS) add_subdirectory(COMPONENT_SPIF) endif() +if("SECUREF" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(COMPONENT_SECUREF) +endif() target_include_directories(mbed-storage-blockdevice INTERFACE diff --git a/storage/blockdevice/COMPONENT_SECUREF/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/CMakeLists.txt new file mode 100644 index 00000000000..c7288188bf6 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +target_sources(mbed-storage-securef + INTERFACE + source/SecureFBlockDevice.cpp + PRIVATE + platform/plat_secure_flash.cpp + spi_nor_flash/spi_nor.c +) + +target_include_directories(mbed-storage-securef + INTERFACE + include + include/SECUREF + PRIVATE + platform/include/ + spi_nor_flash/ +) +add_subdirectory(JEDEC_security_HAL) diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/CMakeLists.txt new file mode 100644 index 00000000000..f4bf0c4c952 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/CMakeLists.txt @@ -0,0 +1,27 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.15) + +cmake_policy(SET CMP0079 NEW) + +add_library(jedec_security_hal STATIC) + +target_sources(jedec_security_hal + PRIVATE + JEDEC_security_HAL/jedec_security_hal.c + JEDEC_security_HAL/queue.c +) + +target_include_directories(jedec_security_hal + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/JEDEC_security_HAL + ${CMAKE_CURRENT_SOURCE_DIR}/JEDEC_security_HAL/include + ${CMAKE_CURRENT_SOURCE_DIR}/vendor_impl +) + +add_subdirectory(vendor_impl) \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/CMakeLists.txt new file mode 100644 index 00000000000..52611c3dd71 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/CMakeLists.txt @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.15) + +cmake_policy(SET CMP0079 NEW) + +add_library(jedec_security_hal STATIC) + +target_sources(jedec_security_hal + PRIVATE + jedec_security_hal.c + queue.c +) + +target_include_directories(jedec_security_hal + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include +) \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/crypto_wrapper.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/crypto_wrapper.h new file mode 100644 index 00000000000..753d077fc90 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/crypto_wrapper.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _CRYPTO_WRAPPER_H_ +#define _CRYPTO_WRAPPER_H_ + +#include +#include "include/crypto_defs.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef int (*init_t)(void); +typedef int (*deinit_t)(void); +typedef int (*algorithm_support_t)(int alg); +typedef int (*crypto_func_t)(crypto_indicator_t *indicator); +typedef int (*key_derive_t)(crypto_indicator_t *indicator, uint32_t *output_key_id); +typedef int (*generate_random_t)(uint8_t *odata, uint32_t odata_len); +typedef int (*ecdh_gen_key_pair_t)(crypto_indicator_t *indicator); +typedef int (*ecdh_gen_shared_secret_t)(crypto_indicator_t *indicator); + +typedef int (*open_key_t)(uint32_t key_id); +typedef int (*close_key_t)(uint32_t key_id); +typedef int (*destroy_key_t)(uint32_t key_id); +typedef int (*export_public_key_t)(uint32_t key_id, uint8_t *key_buf, uint32_t buf_size, uint32_t *actual_size); +typedef int (*export_key_t)(uint32_t key_id, uint8_t *key_buf, uint32_t buf_size, uint32_t *actual_size); +typedef int (*import_key_t)(uint32_t *key_id, uint8_t *key_buf, uint32_t buf_size, KeyLifeTime lifetime); + + +typedef struct { + init_t init; + deinit_t deinit; + algorithm_support_t algorithm_support; + crypto_func_t crypto_func; + key_derive_t key_derive; + generate_random_t generate_random; + ecdh_gen_key_pair_t ecdh_gen_key_pair; + ecdh_gen_shared_secret_t ecdh_gen_shared_secret; + + open_key_t open_key; + close_key_t close_key; + destroy_key_t destroy_key; + export_public_key_t export_public_key; + export_key_t export_key; + import_key_t import_key; + +} crypto_wrapper_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _CRYPTO_WRAPPER_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/crypto_defs.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/crypto_defs.h new file mode 100644 index 00000000000..96d5627c0d4 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/crypto_defs.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _CRYPTO_DEFS_H_ +#define _CRYPTO_DEFS_H_ + +#include +#include "error.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * \brief Cryptographic service error code + * + */ + +#define JEDEC_ERROR_NOTHING -0x1001 +#define JEDEC_ERROR_AEAD_ENC -0x1002 +#define JEDEC_ERROR_AEAD_DEC -0x1003 +#define JEDEC_ERROR_CIPHER_ENC -0x1004 +#define JEDEC_ERROR_CIPHER_DEC -0x1005 +#define JEDEC_ERROR_AEAD -0x1006 +#define JEDEC_ERROR_HMAC -0x1007 +#define JEDEC_ERROR_KDF -0x1008 +#define JEDEC_ERROR_MAC_COMPUTE -0x1009 +#define JEDEC_ERROR_MAC_VERIFY -0x100A +#define JEDEC_ERROR_GENERATE_RANDOM -0x100B +#define JEDEC_ERROR_OPEN_KEY -0x100C +#define JEDEC_ERROR_CLOSE_KEY -0x100D +#define JEDEC_ERROR_EXPORT_KEY -0x100E +#define JEDEC_ERROR_IMPORT_KEY -0x100F +#define JEDEC_ERROR_DESTROY_KEY -0x1010 +#define JEDEC_ERROR_INVALID_PARAM -0x1011 +#define JEDEC_ERROR_NOT_SUPPORT -0x1012 +#define JEDEC_ERROR_GENERATE_KEY -0x1013 +#define JEDEC_ERROR_KEY_ID_CONFLICT -0x1014 +#define JEDEC_ERROR_KEY_ID_NOT_FOUND -0x1015 +#define JEDEC_ERROR_KEY_OPERATION -0x1016 +#define JEDEC_ERROR_RANDOM_GEN -0x1017 +#define JEDEC_ERROR_MAC -0x1018 +#define JEDEC_ERROR_CRYPTO -0x1019 + +#define MAX_CIPHER_DATA_SIZE 1024 + +#define INVALID_KEY_ID 0 /*!< Invalid key id */ +#define RESVD_KEY_ID 0xFFFFFFFF /*!< Reserved key id */ + +#define ALG_TYPE(ALG) (ALG & 0xFFFFFFF0) + +/* \brief Supported cipher types and modes + * + */ +typedef enum { + ALG_NONE = 0x00, // 0x00 + + ALG_AES_CCM = 0x10, // 0x10 + ALG_AES_CCM_128, // 0x11 + ALG_AES_CCM_192, // 0x12 + ALG_AES_CCM_256, // 0x13 + ALG_AES_GCM = 0x20, // 0x20 + ALG_AES_GCM_128, // 0x21 + ALG_AES_GCM_192, // 0x22 + ALG_AES_GCM_256, // 0x23 + ALG_AES_ECB = 0x30, // 0x30 + ALG_AES_ECB_128, // 0x31 + ALG_AES_ECB_192, // 0x32 + ALG_AES_ECB_256, // 0x33 + ALG_AES_CBC = 0x40, // 0x40 + ALG_AES_CBC_128, // 0x41 + ALG_AES_CBC_192, // 0x42 + ALG_AES_CBC_256, // 0x43 + ALG_AES_OFB = 0x50, // 0x50 + ALG_AES_OFB_128, // 0x51 + ALG_AES_OFB_192, // 0x52 + ALG_AES_OFB_256, // 0x53 + ALG_AES_CTR = 0x60, // 0x60 + ALG_AES_CTR_128, // 0x61 + ALG_AES_CTR_192, // 0x62 + ALG_AES_CTR_256, // 0x63 + + ALG_ECDSA = 0x70, // 0x70 + ALG_ECDSA_SECP192R1, // 0x71 + ALG_ECDSA_SECP224R1, // 0x72 + ALG_ECDSA_SECP256R1, // 0x73 + ALG_ECDSA_SECP384R1, // 0x74 + ALG_ECDSA_SECP521R1, // 0x75 + ALG_ECDSA_BP256R1, // 0x76 + ALG_ECDSA_BP384R1, // 0x77 + ALG_ECDSA_BP512R1, // 0x78 + ALG_ECDSA_CURVE25519, // 0x79 + ALG_ECDSA_SECP192K1, // 0x7A + ALG_ECDSA_SECP224K1, // 0x7B + ALG_ECDSA_SECP256K1, // 0x7C + ALG_ECDSA_CURVE448, // 0x7D + + ALG_ECDH = 0x80, // 0x80 + ALG_ECDH_SECP192R1, // 0x81 + ALG_ECDH_SECP224R1, // 0x82 + ALG_ECDH_SECP256R1, // 0x83 + ALG_ECDH_SECP384R1, // 0x84 + ALG_ECDH_SECP521R1, // 0x85 + ALG_ECDH_BP256R1, // 0x86 + ALG_ECDH_BP384R1, // 0x87 + ALG_ECDH_BP512R1, // 0x88 + ALG_ECDH_CURVE25519, // 0x89 + ALG_ECDH_SECP192K1, // 0x8A + ALG_ECDH_SECP224K1, // 0x8B + ALG_ECDH_SECP256K1, // 0x8C + + ALG_HMAC = 0x90, // 0x90 + ALG_HMAC_SHA_1, // 0x91 + ALG_HMAC_SHA_224, // 0x92 + ALG_HMAC_SHA_256, // 0x93 + ALG_HMAC_SHA_384, // 0x94 + ALG_HMAC_SHA_512, // 0x95 + + ALG_HKDF = 0xA0, // 0xA0 + ALG_HKDF_SHA_1, // 0xA1 + ALG_HKDF_SHA_224, // 0xA2 + ALG_HKDF_SHA_256, // 0xA3 + ALG_HKDF_SHA_384, // 0xA4 + ALG_HKDF_SHA_512, // 0xA5 +} CryptoAlgorithm; + +/** + * \brief Supported cryptographic operation properties + * + */ +typedef enum { + PROP_NO_SECURITY_OPERATION , /*!< No security operation. */ + + PROP_AUTHEN_TAG_DECRYPT_DATA , /*!< Authenticate tag and decrypt data */ + PROP_AUTHEN_TAG , /*!< Authenticate tag only */ + PROP_DECRYPT_DATA , /*!< Decrypt data only */ + + PROP_ENCRYPT_TAG_DATA , /*!< Encrypt data and generate authenticate tag */ + PROP_ENCRYPT_TAG , /*!< Generate authenticate tag only */ + PROP_ENCRYPT_DATA , /*!< Encrypt data only */ + + PROP_HMAC_COMPUTE , /*!< Compute Hash-based MAC */ + PROP_HMAC_VERIFY , /*!< Verify Hash-based MAC */ + + PROP_HKDF , /*!< HKDF Extract-Expand */ + PROP_HKDF_EXTRACT , /*!< HKDF Extract */ + PROP_HKDF_EXPAND , /*!< HKDF Expand */ + + PROP_SIGNATURE_SIGN , /*!< Generate signature */ + PROP_SIGNATURE_VERIFY , /*!< Verify signature */ + + PROP_GEN_KEY_PAIR , /*!< Generate key pair */ + PROP_GEN_SHARED_SECRET , /*!< Compute shared secret */ +} CryptoOpProperty; + +typedef enum { + RAW_PUB_KEY, + UNCOMPRESSED_PUB_KEY, + COMPRESSED_PUB_KEY +} EcdhPubKeyType; + +typedef enum { + KEY_LIFETIME_VOLATILE, + KEY_LIFETIME_PERSISTENT, +} KeyLifeTime; +/** + * \brief Cryptographic operation indicator + * + */ +typedef struct { + union { + /** + * \struct aead + * + * \brief Structure containing AES-CCM/AES-GCM operation parameters. + */ + struct { + uint32_t key_id; + uint32_t key_len; + uint8_t *iv; + uint32_t iv_len; + uint8_t *add; + uint32_t add_len; + uint8_t *plain_text; + uint8_t *cipher_text; + uint32_t text_len; + uint8_t *tag; + uint32_t tag_len; + } aead; + /** + * \struct hkdf + * + * \brief Structure containing HKDF operation parameters. + */ + struct { + uint32_t ikm_id; /*!< input key material id */ + uint32_t ikm_len; + uint8_t *salt; /*!< optional salt value (a non-secret random value) */ + uint32_t salt_len; + uint32_t prk_id; + uint8_t *prk; /*!< pseudo random key (of HashLen octets) */ + uint32_t prk_len; + uint8_t *info; /*!< optional context and application specific information */ + uint32_t info_len; + uint32_t okm_id; + uint8_t *okm; /*!< output keying material (of okm_len octets) */ + uint32_t okm_len; /*!< length of output keying material in octets */ + } hkdf; + /** + * \struct cipher + * + * \brief Structure containing AES CBC/ECB operation parameters. + */ + struct { + uint32_t key_id; + uint8_t *iv; + uint32_t iv_len; + uint8_t *plain_text; + uint8_t *cipher_text; + uint32_t text_len; + } enc_cipher; + /** + * \struct ecdh + * + * \brief Structure containing ECDH operation parameters. + */ + struct { + EcdhPubKeyType pub_key_type; + uint8_t *pub_key; + uint32_t pub_key_id; + uint32_t pub_key_len; + uint32_t pri_key_id; + uint32_t pri_key_len; + uint8_t *secret; + uint32_t secret_id; + uint32_t secret_len; + } ecdh; + /** + * \struct hmac + * + * \brief Structure containing HMAC operation parameters. + */ + struct { + uint8_t *key; + uint32_t key_id; + uint32_t key_len; + uint8_t *idata; + uint32_t idata_len; + uint8_t *mac; + uint32_t mac_id; + uint32_t mac_len; + } hmac; + }; + struct { + uint8_t import_req; + int flag; + KeyLifeTime lifetime; + int type; + } key_attr; + uint8_t buf[MAX_CIPHER_DATA_SIZE]; + /** + * \brief Crypto algorithm type. + */ + CryptoAlgorithm algorithm; + /** + * \brief Crypto operation property. + */ + CryptoOpProperty property; +} crypto_indicator_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _CRYPTO_DEFS_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/error.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/error.h new file mode 100644 index 00000000000..a4b2768a881 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/error.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +typedef int32_t jedec_error_t; + +#define JEDEC_ERROR_NONE 0 +#define JEDEC_ERROR_SESSION -0x0001 +#define JEDEC_ERROR_INV_ARGS -0x0002 +#define JEDEC_ERROR_AUTH_FAIL -0x0003 +#define JEDEC_ERROR_COMM_FAIL -0x0004 +#define JEDEC_ERROR_INVALID_ADDR -0x0005 +#define JEDEC_ERROR_MAX_SESSIONS_REACHED -0x0006 +#define JEDEC_ERROR_CMD_NOT_SUPPORTED_ON_DEVICE -0x000a +#define JEDEC_ERROR_INIT_FAIL -0x000b +#define JEDEC_ERROR_NOT_PERMITTED -0x000c +#define JEDEC_ERROR_DEVICE_BUSY -0x0011 +#define JEDEC_ERROR_CMD_PACKET -0x0012 +#define JEDEC_ERROR_INSUFFICIENT_MEMORY -0x0013 +#define JEDEC_ERROR_GENERIC -0x0014 + +#ifdef __cplusplus +} +#endif + +#endif /* _ERROR_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/jedec_defs.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/jedec_defs.h new file mode 100644 index 00000000000..fcfbd7ddc8e --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/include/jedec_defs.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _JEDEC_DEFS_H_ +#define _JEDEC_DEFS_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/* secure read is supported */ +#define SECURE_READ +/* fixme: These macro could be defined in jedec_config.cmake file */ +#define PACKET_MAX_LEN 0x400 +#define MAX_RANDOM_SIZE 0x20 +#define MAX_REGION_NUM 0x10 + +/* Persistent key ids */ +/* fixme: 0X55AA55 is just a example key id */ +#define SECUREFLASH_AUTHEN_KEY_ID 0x55AA55 /*!< Authentication key id for secure init/uninit */ +/** + * \brief Region access restriction + * + */ +typedef enum { + NONE_PROC, /*!< no access restriction */ + WR_PROC, /*!< write protection */ + RD_PROC, /*!< read protection */ + RW_PROC, /*!< read&write protection */ + RD_ONLY, /*!< readonly, write is not allowed */ +} access_restr_t; + +/** + * \brief Region protection type + * + */ +typedef enum { + LOCK, /*!< need unlock before read/write */ + CONTINUOUS, /*!< need sign each read/write command */ +} proc_type_t; + +/** + * \brief region attributes + * + */ +typedef struct secure_region_attributes { + uint32_t address; /*!< region start address */ + uint32_t length; /*!< region size */ + uint32_t root_key_id; /*!< region root key id */ + uint8_t auth_algo; /*!< region authentication algorithm */ + uint8_t encr_algo; /*!< region encryption algorithm */ + uint8_t access_restr; /*!< region access restriction */ + uint8_t prot_type; /*!< region protection type */ +} secure_region_attributes_t; + +/** + * \brief region link list node + * + */ +typedef struct region_ll_node{ + secure_region_attributes_t attributes; /*!< region attributes */ + uint32_t session_key_id; /*!< region session key id */ + struct region_ll_node *next; /*!< pointer to next node */ +} region_ll_node_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _JEDEC_DEFS_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.c new file mode 100644 index 00000000000..0bd79d3fdaa --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include +#include +#include "jedec_security_hal.h" +#include "include/error.h" + +static jedec_ctx_t ctx = {}; + +jedec_error_t jedec_set_vendor(vendor_security_op_t *vendor, + crypto_wrapper_t *crypto_wrapper, + void *vendor_ctx) +{ + ctx.vendor_security_op = vendor; + ctx.crypto_wrapper = crypto_wrapper, + ctx.vendor_ctx = vendor_ctx; +} + +jedec_error_t jedec_secure_init(uint32_t auth_key_id) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + uint8_t random[MAX_RANDOM_SIZE]; + + if (ctx.is_initialized) { + return JEDEC_ERROR_NONE; + } + /* Check whether auth_key_id is valid */ + if (auth_key_id == INVALID_KEY_ID || ctx.vendor_security_op == NULL || + ctx.crypto_wrapper == NULL || ctx.vendor_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + err = ctx.crypto_wrapper->open_key(auth_key_id); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_KEY_OPERATION; + } + queue_clear(&ctx.q); + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_RANDOM_GEN; + } + err = ctx.vendor_security_op->pre_secure_init(ctx.vendor_ctx, + random, MAX_RANDOM_SIZE, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->secure_init_packet(ctx.vendor_ctx, auth_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + NULL, + 0, + indicator.hmac.mac, + indicator.hmac.mac_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->post_secure_init(ctx.vendor_ctx, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + ctx.is_initialized = true; + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_uninit(uint32_t auth_key_id) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + uint8_t random[MAX_RANDOM_SIZE]; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NONE; + } + if (auth_key_id == INVALID_KEY_ID) { + return JEDEC_ERROR_INV_ARGS; + } + queue_clear(&ctx.q); + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_RANDOM_GEN; + } + err = ctx.vendor_security_op->pre_secure_uninit(ctx.vendor_ctx, + random, MAX_RANDOM_SIZE, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->secure_uninit_packet(ctx.vendor_ctx, + auth_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + NULL, 0, + indicator.hmac.mac, + indicator.hmac.mac_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + queue_clear(&ctx.q); + err = ctx.vendor_security_op->post_secure_uninit(ctx.vendor_ctx, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + /* Close root_key_id */ + err = ctx.crypto_wrapper->close_key(auth_key_id); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_KEY_OPERATION; + } + ctx.is_initialized = false; + memset(&ctx, 0x00, sizeof (jedec_ctx_t)); + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_create_session(uint32_t root_key_id, bool verify, uint32_t *session_key_id) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + uint8_t random[MAX_RANDOM_SIZE]; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + queue_clear(&ctx.q); + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_RANDOM_GEN; + } + err = ctx.vendor_security_op->pre_create_session(ctx.vendor_ctx, + random, MAX_RANDOM_SIZE, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->create_session_packet(ctx.vendor_ctx, + root_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + NULL, 0, + NULL, 0); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* derive session key from root key */ + err = ctx.crypto_wrapper->key_derive(&indicator, session_key_id); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->post_create_session(ctx.vendor_ctx, + root_key_id, + *session_key_id, + random, MAX_RANDOM_SIZE, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_terminate_session(uint32_t session_key_id) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + uint8_t random[MAX_RANDOM_SIZE]; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + queue_clear(&ctx.q); + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_RANDOM_GEN; + } + err = ctx.vendor_security_op->pre_terminate_session(ctx.vendor_ctx, + random, MAX_RANDOM_SIZE, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->terminate_session_packet(ctx.vendor_ctx, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + NULL, 0, + indicator.hmac.mac, + indicator.hmac.mac_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->post_terminate_session(ctx.vendor_ctx, + session_key_id, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + /* Destroy companion crypto system session keys */ + err = ctx.crypto_wrapper->destroy_key(session_key_id); + if (err != JEDEC_ERROR_NONE) { + return err; + } + return JEDEC_ERROR_NONE; +} + + +jedec_error_t jedec_secure_program(uint32_t addr, const uint8_t *data, uint32_t len, + uint32_t session_key_id, uint32_t *bytes_programmed) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + queue_clear(&ctx.q); + err = ctx.vendor_security_op->pre_secure_program(ctx.vendor_ctx, addr, + session_key_id, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.vendor_security_op->secure_program_packet(ctx.vendor_ctx, + addr, data, len, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + indicator.aead.cipher_text, + indicator.aead.text_len, + indicator.aead.tag, + indicator.aead.tag_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Get secure program response from secure Flash */ + err = ctx.vendor_security_op->post_secure_program(ctx.vendor_ctx, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from secure Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Parse response from secure Flash */ + err = ctx.vendor_security_op->parse_secure_program_response(ctx.vendor_ctx, + &indicator, + bytes_programmed); + if (err != JEDEC_ERROR_NONE) { + return err; + } + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_erase(uint32_t addr, uint32_t len, uint32_t session_key_id) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + queue_clear(&ctx.q); + err = ctx.vendor_security_op->pre_secure_erase(ctx.vendor_ctx, addr, len, + session_key_id, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.vendor_security_op->secure_erase_packet(ctx.vendor_ctx, + addr, len, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + indicator.aead.cipher_text, + indicator.aead.text_len, + indicator.aead.tag, + indicator.aead.tag_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Get secure program response from secure Flash */ + err = ctx.vendor_security_op->post_secure_erase(ctx.vendor_ctx, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from secure Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Parse response from secure Flash */ + err = ctx.vendor_security_op->parse_secure_erase_response(ctx.vendor_ctx, &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_read(uint32_t addr, uint8_t *data, uint32_t len, + uint32_t session_key_id, uint32_t *bytes_read) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + queue_clear(&ctx.q); + err = ctx.vendor_security_op->pre_secure_read(ctx.vendor_ctx, addr, + session_key_id, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.vendor_security_op->secure_read_packet(ctx.vendor_ctx, + addr, len, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + indicator.aead.cipher_text, + indicator.aead.text_len, + indicator.aead.tag, + indicator.aead.tag_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Get secure program response from secure Flash */ + err = ctx.vendor_security_op->post_secure_read(ctx.vendor_ctx, + session_key_id, + ctx.packet, &ctx.packet_len, + &indicator, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from secure Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Parse response from secure Flash */ + err = ctx.vendor_security_op->parse_secure_read_response(ctx.vendor_ctx, + &indicator, + data, len, + bytes_read); + if (err != JEDEC_ERROR_NONE) { + return err; + } + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_copy(uint32_t src_addr, uint32_t dst_addr, uint32_t len, + uint32_t session_key_id) +{ + //TODO + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_get_regions_info(region_ll_node_t *region_descr_p, + uint32_t session_key_id, int8_t region_index) +{ + jedec_error_t err = JEDEC_ERROR_NONE; + crypto_indicator_t indicator = {}; + bool session_key_valid_flag; + uint16_t region_index_start, region_index_end; + uint8_t random[MAX_RANDOM_SIZE]; + + if (!ctx.is_initialized) { + return JEDEC_ERROR_NOT_PERMITTED; + } + region_ll_node_t *node_ptr = region_descr_p; + region_ll_node_t *next_node_ptr = region_descr_p; + memset(&indicator, 0x00, sizeof(indicator)); + queue_clear(&ctx.q); + err = ctx.vendor_security_op->pre_secure_get_regions_info(ctx.vendor_ctx, + session_key_id, + &session_key_valid_flag, + &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + if (session_key_valid_flag) { + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + } + if (region_index < 0) { + region_index_start = 0; + region_index_end = MAX_REGION_NUM - 1; + } else if (region_index < MAX_REGION_NUM) { + region_index_start = region_index; + region_index_end = region_index; + } else { + return JEDEC_ERROR_INV_ARGS; + } + for (uint16_t index = region_index_start; index <= region_index_end; index++) { + if (session_key_valid_flag) { + err = ctx.crypto_wrapper->generate_random(random, MAX_RANDOM_SIZE); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->secure_get_regions_info_packet(ctx.vendor_ctx, + session_key_id, + index, + random, MAX_RANDOM_SIZE, + ctx.packet, &ctx.packet_len, + &indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.crypto_wrapper->crypto_func(&indicator); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, + ctx.packet_len, + NULL, + 0, + indicator.hmac.mac, + indicator.hmac.mac_len); + if (err != JEDEC_ERROR_NONE) { + return err; + } + queue_clear(&ctx.q); + err = ctx.vendor_security_op->post_secure_get_regions_info(ctx.vendor_ctx, node_ptr, &ctx.q); + if (err != JEDEC_ERROR_NONE) { + return err; + } + /* Verify response from secure Flash */ + if (queue_verify(ctx.crypto_wrapper, &ctx.q) == false) { + return JEDEC_ERROR_AUTH_FAIL; + } + } else { + err = ctx.vendor_security_op->secure_get_regions_info_packet(ctx.vendor_ctx, + 0, + index, + NULL, 0, + ctx.packet, &ctx.packet_len, + NULL); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->packet_send(ctx.vendor_ctx, + ctx.packet, ctx.packet_len, + NULL, 0, + NULL, 0); + if (err != JEDEC_ERROR_NONE) { + return err; + } + err = ctx.vendor_security_op->post_secure_get_regions_info(ctx.vendor_ctx, node_ptr, NULL); + if (err != JEDEC_ERROR_NONE) { + return err; + } + } + next_node_ptr = node_ptr + 1; + node_ptr->next = next_node_ptr; + node_ptr = next_node_ptr; + next_node_ptr->next = NULL; + } + return JEDEC_ERROR_NONE; +} + +jedec_error_t jedec_secure_manage_region(region_ll_node_t *head) +{ + //TODO + return JEDEC_ERROR_NONE; +} diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.h new file mode 100644 index 00000000000..813ce140c90 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/jedec_security_hal.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _JEDEC_SECURITY_HAL_H_ +#define _JEDEC_SECURITY_HAL_H_ + +#include +#include +#include "vendor_security_impl.h" +#include "crypto_wrapper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + bool is_initialized; /*!< Secure Flash state:Initialized or uninitialized */ + void *vendor_ctx; /*!< Vendor context */ + vendor_security_op_t *vendor_security_op; /*!< Vendor specific security operations */ + crypto_wrapper_t *crypto_wrapper; /*!< Crypto wrapper functions */ + uint8_t packet[PACKET_MAX_LEN]; /*!< Buffer holding command packet */ + uint32_t packet_len; /*!< Command packet length */ + uint8_t verify; /*!< Verification indication of responses from secure Flash */ + jqueue_t q; /*!< Response queue */ +} jedec_ctx_t; + +/** + * \brief Bind JEDEC context with vendor specific implementation. + * + * \param[in] vendor Vendor specific implementation + * \param[in] vendor_ctx Vendor specific context + * + */ +jedec_error_t jedec_set_vendor(vendor_security_op_t *vendor, + crypto_wrapper_t *crypto_wrapper, + void *vendor_ctx); + +/** + * \brief Set verify flag of packets returned in the queue. + * + * \param[in] verify Verify indication + * + */ +jedec_error_t jedec_set_verify(uint8_t verify); + +/** + * \brief Move the secure Flash's status to initialized status. + * + * \param[in] auth_key_id Input authenticatoin key id for secure initialization + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + */ +jedec_error_t jedec_secure_init(uint32_t auth_key_id); +/** + * \brief Security uninitialization of secure Flash. + * + * \param[in] auth_key_id Input authentication key id for secure uninitialization + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + */ +jedec_error_t jedec_secure_uninit(uint32_t auth_key_id); +/** + * \brief Establish a cryptographic session with secure Flash. + * + * \param[in] root_key_id Preshared root key ID + * \param[in] verify Indicate whether subsequent flash responses + * within session should be verified + * \param[out] session_key_id Generated session key ID + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + * JEDEC_ERROR_MAX_SESSIONS_REACHED - no more sessions may be created + */ +jedec_error_t jedec_create_session(uint32_t root_key_id, bool verify, uint32_t *session_key_id); +/** + * \brief Terminate a cryptographic session with secure Flash. + * + * \param[in] session_key_id Corresponding session key ID + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_COMM_FAIL - communication error + */ +jedec_error_t jedec_terminate_session(uint32_t session_key_id); +/** + * \brief Program data to secure Flash. + * + * \param[in] secureflash Secure Flash to access + * \param[in] addr Target address in secure Flash + * \param[in] data Data to be programmed to secure Flash + * \param[in] len Number of bytes requested to be programmed + * \param[in] session_key_id Session key ID + * \param[out] bytes_programmed Number of bytes that have been programmed + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + * JEDEC_ERROR_INVALID_ADDR -address is outside addressable flash address space + */ +jedec_error_t jedec_secure_program(uint32_t addr, const uint8_t *data, uint32_t len, + uint32_t session_key_id, uint32_t *bytes_programmed); +/** + * \brief Erase a sector/block specified by a base address of secure Flash. + * + * \param[in] secureflash Secure Flash to access + * \param[in] addr Address from which to start erase + * \param[in] len Number of bytes requested to be programmed + * \param[in] session_key_id Session key ID + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + */ +jedec_error_t jedec_secure_erase(uint32_t addr, uint32_t len, uint32_t session_key_id); +/** + * \brief Read protected data from secure Flash. + * + * \param[in] secureflash Secure Flash to access + * \param[in] addr Target (starting) address in secure Flash + * \param[in] data Data read from secure Flash + * \param[in] len Number of bytes requested to be read + * \param[in] session_key_id Session key ID + * \param[out] bytes_read Number of bytes that have been read + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + * JEDEC_ERROR_INVALID_ADDR -address is outside addressable flash address space + * JEDEC_ERROR_CMD_NOT_SUPPORTED_ON_DEVICE -command not supported by vendor's flash + */ +jedec_error_t jedec_secure_read(uint32_t addr, uint8_t *data, uint32_t len, + uint32_t session_key_id, uint32_t *bytes_read); +/** + * \brief Copy data from secure Flash one location to another. + * + * \param[in] secureflash Secure Flash to access + * \param[in] src_addr Source address in secure Flash + * \param[in] dst_addr Destination address in secure Flash + * \param[in] len Number of bytes to copy + * \param[in] session_key_id Session key ID + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + * JEDEC_ERROR_INVALID_ADDR -address is outside addressable flash address space + * JEDEC_ERROR_CMD_NOT_SUPPORTED_ON_DEVICE -command not supported by vendor's flash + */ +jedec_error_t jedec_secure_copy(uint32_t src_addr, uint32_t dst_addr, uint32_t len, + uint32_t session_key_id); +/** + * \brief Obtain current secure configuration parameters of secure Flash. + * + * \param[in] secureflash Secure Flash to access + * \param[in/out] region_descr_p Pointer to secure region configuration linked list. + * \param[in] session_key_id Session key ID + * \param[in] region_idx Region index + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + */ +jedec_error_t jedec_secure_get_regions_info(region_ll_node_t *region_descr_p, + uint32_t session_key_id, int8_t region_idx); +/** + * \brief Configure secure Flash regions. + * + * \param[in] secureflash Secure Flash to access + * \param[in] head Pointer to the header of secure regions' + * configuration parameters link list + * + * \return JEDEC_ERROR_NONE - success + * JEDEC_ERROR_SESSION - no session has been established + * JEDEC_ERROR_INV_ARGS - invalid input arguments + * JEDEC_ERROR_AUTH_FAIL - authentication failure + * JEDEC_ERROR_COMM_FAIL - communication error + * JEDEC_ERROR_CMD_NOT_SUPPORTED_ON_DEVICE - command not supported by vendor's flash + */ +jedec_error_t jedec_secure_manage_region(region_ll_node_t *head); + +#ifdef __cplusplus +} +#endif + +#endif /* _JEDEC_SECURITY_HAL_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.c new file mode 100644 index 00000000000..a04ea1f50f4 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include "queue.h" + +void queue_clear(jqueue_t *q) +{ + q->list.head.next = &q->list.head; + q->list.head.prev = &q->list.head; + memset(q->buf, 0x00, sizeof(q->buf)); + q->offset = 0; +} + +bool queue_is_empty(jqueue_t *q) +{ + if ((q->list.head.next == NULL) || + (q->list.head.next == &(q->list.head))) { + return 1; + } else { + return 0; + } +} + +void queue_add(jqueue_t *q, resp_param_t *item) +{ + if ((q->offset + sizeof(jresp_t)) > BUF_SIZE) { + return; + } + jresp_t *r = (jresp_t *)&q->buf[q->offset]; + q->offset += sizeof(jresp_t); + r->node.next = NULL; + r->node.prev = NULL; + + r->param.alg = item->alg; + r->param.property = item->property; + switch (ALG_TYPE(item->alg)) { + case ALG_HMAC: + r->param.hmac.flag = item->hmac.flag; + r->param.hmac.key_id = item->hmac.key_id; + r->param.hmac.key_len = item->hmac.key_len; + //input data + if (((q->offset + item->hmac.idata_len) <= BUF_SIZE) && + (item->hmac.idata != NULL) && (item->hmac.idata_len > 0)) { + memcpy(&q->buf[q->offset], item->hmac.idata, item->hmac.idata_len); + r->param.hmac.idata = &q->buf[q->offset]; + r->param.hmac.idata_len = item->hmac.idata_len; + q->offset += item->hmac.idata_len; + } + //mac + if (((q->offset + item->hmac.mac_len) <= BUF_SIZE) && + (item->hmac.mac != NULL) && (item->hmac.mac_len > 0)) { + memcpy(&q->buf[q->offset], item->hmac.mac, item->hmac.mac_len); + r->param.hmac.mac = &q->buf[q->offset]; + r->param.hmac.mac_len = item->hmac.mac_len; + q->offset += item->hmac.mac_len; + } + break; + case ALG_AES_GCM: + r->param.aead.key_id = item->aead.key_id; + //iv + if (((q->offset + item->aead.iv_len) <= BUF_SIZE) && + (item->aead.iv != NULL) && (item->aead.iv_len > 0)) { + memcpy(&q->buf[q->offset], item->aead.iv, item->aead.iv_len); + r->param.aead.iv = &q->buf[q->offset]; + r->param.aead.iv_len = item->aead.iv_len; + q->offset += item->aead.iv_len; + } + //aad + if (((q->offset + item->aead.aad_len) <= BUF_SIZE) && + (item->aead.aad != NULL) && (item->aead.aad_len > 0)) { + memcpy(&q->buf[q->offset], item->aead.aad, item->aead.aad_len); + r->param.aead.aad = &q->buf[q->offset]; + r->param.aead.aad_len = item->aead.aad_len; + q->offset += item->aead.aad_len; + } + //packet + if (((q->offset + item->aead.ciphertext_len) <= BUF_SIZE) && + (item->aead.ciphertext != NULL) && (item->aead.ciphertext_len > 0)) { + memcpy(&q->buf[q->offset], item->aead.ciphertext, item->aead.ciphertext_len); + r->param.aead.ciphertext = &q->buf[q->offset]; + r->param.aead.ciphertext_len = item->aead.ciphertext_len; + q->offset += item->aead.ciphertext_len; + } + //tag + if (((q->offset + item->aead.tag_len) <= BUF_SIZE) && + (item->aead.tag != NULL) && (item->aead.tag_len > 0)) { + memcpy(&q->buf[q->offset], item->aead.tag, item->aead.tag_len); + r->param.aead.tag = &q->buf[q->offset]; + r->param.aead.tag_len = item->aead.tag_len; + q->offset += item->aead.tag_len; + } + //plaintext + if (((q->offset + item->aead.plaintext_len) <= BUF_SIZE) && + (item->aead.plaintext != NULL) && (item->aead.plaintext_len > 0)) { + memcpy(&q->buf[q->offset], item->aead.plaintext, item->aead.plaintext_len); + r->param.aead.plaintext = &q->buf[q->offset]; + r->param.aead.plaintext_len = item->aead.plaintext_len; + q->offset += item->aead.plaintext_len; + } + break; + default: + break; + } + r->node.prev = q->list.head.prev; + r->node.next = &(q->list.head); + r->node.next->prev = &r->node; + r->node.prev->next = &r->node; +} + +void queue_get(jqueue_t *q, resp_param_t *item) +{ + jresp_t *r = (jresp_t *)q->list.head.next; + if (queue_is_empty(q)) { + return; + } + switch (ALG_TYPE(r->param.alg)) { + case ALG_HMAC: + memcpy (item, &r->param, sizeof (resp_param_t)); + q->offset -= r->param.hmac.idata_len; + q->offset -= r->param.hmac.mac_len; + q->offset -= sizeof(jresp_t); + break; + case ALG_AES_GCM: + memcpy (item, &r->param, sizeof (resp_param_t)); + q->offset -= r->param.aead.iv_len; + q->offset -= r->param.aead.aad_len; + q->offset -= r->param.aead.ciphertext_len; + q->offset -= r->param.aead.tag_len; + q->offset -= sizeof(jresp_t); + break; + default: + break; + } + r->node.prev->next = r->node.next; + r->node.next->prev = r->node.prev; + r->node.prev = NULL; + r->node.next = NULL; +} + +/** + * \brief Verify secure Flash responses stored in queque. + * + * \param[in] crypto_wrapper Pointer of crypto wrapper + * \param[in] queue Queue of secure Flash responses + * + * \return true if crypto verification success, + * or false if crypto verification fail + */ +bool queue_verify(crypto_wrapper_t *crypto_wrapper, jqueue_t *queue) +{ + resp_param_t response; + crypto_indicator_t indicator = {}; + + while (!queue_is_empty(queue)) { + queue_get(queue, &response); + indicator.algorithm = response.alg; + indicator.property = response.property; + switch (ALG_TYPE(response.alg)) { + case ALG_HMAC: + if ((response.hmac.key_id != 0) && + (response.hmac.idata != NULL) && (response.hmac.idata_len > 0) || + (response.hmac.mac == NULL) && (response.hmac.mac_len > 0)) { + indicator.key_attr.flag = response.hmac.flag; + indicator.hmac.key_id = response.hmac.key_id; + indicator.hmac.key_len = response.hmac.key_len; + indicator.hmac.idata = response.hmac.idata; + indicator.hmac.idata_len = response.hmac.idata_len; + indicator.hmac.mac = response.hmac.mac; + indicator.hmac.mac_len = response.hmac.mac_len; + if (crypto_wrapper->crypto_func(&indicator) != JEDEC_ERROR_NONE) { + return false; + } + } + break; + case ALG_AES_GCM: + if ((response.aead.key_id != 0) && + (response.aead.iv != NULL) && (response.aead.iv_len > 0) && + (response.aead.aad != NULL) && (response.aead.aad_len > 0) && + (response.aead.ciphertext != NULL) && (response.aead.ciphertext_len > 0) && + (response.aead.tag != NULL) && (response.aead.tag_len > 0)) { + indicator.property = PROP_AUTHEN_TAG; + indicator.aead.key_id = response.aead.key_id; + indicator.aead.iv = response.aead.iv; + indicator.aead.iv_len = response.aead.iv_len; + indicator.aead.add = response.aead.aad; + indicator.aead.add_len = response.aead.aad_len; + indicator.aead.cipher_text = response.aead.ciphertext; + indicator.aead.text_len = response.aead.ciphertext_len; + indicator.aead.tag = response.aead.tag; + indicator.aead.tag_len = response.aead.tag_len; + if (crypto_wrapper->crypto_func(&indicator) != JEDEC_ERROR_NONE) { + return false; + } + } + break; + case ALG_NONE: + break; + default: + return false; + } + } + return true; +} diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.h new file mode 100644 index 00000000000..9914db6e870 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/queue.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _QUEUE_H_ +#define _QUEUE_H_ +#include +#include +#include "crypto_wrapper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define BUF_SIZE (4*1024) + +typedef struct jnode { + struct jnode *next; + struct jnode *prev; +} jnode_t; + +typedef struct { + jnode_t head; +} jlist_t; + +typedef struct { + uint8_t buf[BUF_SIZE]; + uint16_t offset; + jlist_t list; +} jqueue_t; + +/** Response cipher type */ +enum cipher_type { + HMAC, + AEAD, + ENC_CIPHER, +}; + +typedef struct { + CryptoAlgorithm alg; + CryptoOpProperty property; + union { + struct { + uint32_t key_id; + uint8_t key_len; + uint8_t *idata; + uint16_t idata_len; + uint8_t *mac; + uint16_t mac_len; + uint8_t flag; + } hmac; + struct { + uint32_t key_id; + uint8_t *iv; + uint16_t iv_len; + uint8_t *aad; + uint16_t aad_len; + uint8_t *tag; + uint16_t tag_len; + uint8_t *ciphertext; + uint16_t ciphertext_len; + uint8_t *plaintext; + uint16_t plaintext_len; + uint8_t flag; + } aead; + struct { + uint32_t key_id; + uint8_t *iv; + uint16_t iv_len; + uint8_t *ciphertext; + uint16_t ciphertext_len; + uint8_t *plaintext; + uint16_t plaintext_len; + uint8_t flag; + } enc_cipher; + }; +} resp_param_t; + +typedef struct { + jnode_t node; + resp_param_t param; +} jresp_t; + +/** + * \brief Clear queue. + * + * \param[in] q Pointer to the queue + * + * \return NULL + */ +void queue_clear(jqueue_t *q); +/** + * \brief Check whether queue is empty. + * + * \param[in] q Pointer to the queue + * + * \return 1 if empty, otherwise 0 + */ +bool queue_is_empty(jqueue_t *q); +/** + * \brief Add a response item to the queue. + * + * \param[in] q Pointer to the queue + * \param[in] item Response item + * \return NULL + */ +void queue_add(jqueue_t *q, resp_param_t *item); +/** + * \brief Get a response item from the queue. + * + * \param[in] q Pointer to the queue + * \param[in] item Response item + * \return NULL + */ +void queue_get(jqueue_t *q, resp_param_t *item); + +/** + * \brief Verify secure Flash responses stored in queque. + * + * \param[in] crypto_wrapper Pointer of crypto wrapper + * \param[in] queue Queue of secure Flash responses + * + * \return true if crypto verification success, + * or false if crypto verification fail + */ +bool queue_verify(crypto_wrapper_t *crypto_wrapper, jqueue_t *queue); + +#ifdef __cplusplus +} +#endif + +#endif /* _QUEUE_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/vendor_security_impl.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/vendor_security_impl.h new file mode 100644 index 00000000000..8365cab97c0 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/JEDEC_security_HAL/vendor_security_impl.h @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _VENDOR_IMPL_H_ +#define _VENDOR_IMPL_H_ + +#include +#include +#include "include/jedec_defs.h" +#include "queue.h" +#include "crypto_wrapper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * \brief vendor specific security operations + * + */ +typedef struct { + /** + * \brief Vendor id. + */ + uint8_t vendor_id; + /** + * \brief Pre create session. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] nonce Host input nonce + * \param[in] nonce_len Host nonce length + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_create_session)(void *vendor_ctx, uint8_t *nonce, + uint32_t nonce_len, jqueue_t *resp_queue); + /** + * \brief Pack create session packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] root_key_id Associated root key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*create_session_packet)(void *vendor_ctx, uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post create session. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] root_key_id Associated root key id + * \param[in] session_key_id created session key id + * \param[in] nonce Nonce + * \param[in] nonce_len Nonce length + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_create_session)(void *vendor_ctx, uint32_t root_key_id, + uint32_t session_key_id, + uint8_t *nonce, uint32_t nonce_len, + jqueue_t *resp_queue); +#if defined(SESSION_CONFIRMATION) + int32_t (*pre_confirm_session)(); + int32_t (*confirm_session_packet)(); + int32_t (*post_confirm_session)(); +#endif + /** + * \brief Pre terminate session. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] nonce Host input nonce + * \param[in] nonce_len Host nonce length + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_terminate_session)(void *vendor_ctx, uint8_t *nonce, + uint32_t nonce_len, jqueue_t *resp_queue); + /** + * \brief Pack terminate session packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*terminate_session_packet)(void *vendor_ctx, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post terminate session. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_terminate_session)(void *vendor_ctx, + uint32_t session_key_id, + jqueue_t *resp_queue); + /** + * \brief Pre secure init. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] nonce Host input nonce + * \param[in] nonce_len Host nonce length + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_init)(void *vendor_ctx, uint8_t *nonce, + uint32_t nonce_len, jqueue_t *resp_queue); + /** + * \brief Pack secure init packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] root_key_id Associated root key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_init_packet)(void *vendor_ctx, uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post secure init. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_init)(void *vendor_ctx, jqueue_t *resp_queue); + /** + * \brief Pre secure uninit. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] nonce Host input nonce + * \param[in] nonce_len Host nonce length + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_uninit)(void *vendor_ctx, uint8_t *nonce, + uint32_t nonce_len, jqueue_t *resp_queue); + /** + * \brief Pack secure uninit packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] root_key_id Associated root key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_uninit_packet)(void *vendor_ctx, uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post secure uninit. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_uninit)(void *vendor_ctx, jqueue_t *resp_queue); + /** + * \brief Pre secure program. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Destination address + * \param[in] session_key_id Associated session key id + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_program)(void *vendor_ctx, uint32_t addr, + uint32_t session_key_id, jqueue_t *resp_queue); + /** + * \brief Pack secure program packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Destination address + * \param[in] data Pointer to source data + * \param[in] len Data length + * \param[in] session_key_id Associated session key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_program_packet)(void *vendor_ctx, uint32_t addr, + const uint8_t *data, uint32_t len, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post secure program. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[in] resp_queue Pointer to response queue holding responses from flash + * \param[in] resp_packet_buffer Buffer to hold secure program response from flash + * \param[out] resp_packet_buffer_size Actual secure program response size + * \param[out] indicator Indicator holding crypto algorithm parameters + * (if secure program response also needs crypto operations) + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_program)(void *vendor_ctx, jqueue_t *resp_queue, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator); + /** + * \brief Parse secure program response. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] indicator Indicator holding crypto algorithm parameters + * \param[out] bytes_programmed Actual programmed bytes + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*parse_secure_program_response)(void *vendor_ctx, + crypto_indicator_t *indicator, + uint32_t *bytes_programmed); + /** + * \brief Pre secure erase. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Destination address + * \param[in] len Erase size + * \param[in] session_key_id Associated session key id + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_erase)(void *vendor_ctx, uint32_t addr, uint32_t len, + uint32_t session_key_id, jqueue_t *resp_queue); + /** + * \brief Pack secure erase packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Destination address + * \param[in] len Erase size + * \param[in] session_key_id Associated session key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_erase_packet)(void *vendor_ctx, uint32_t addr, uint32_t len, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post secure erase. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[in] resp_queue Pointer to response queue holding responses from flash + * \param[in] resp_packet_buffer Buffer to hold secure erase response from flash + * \param[out] resp_packet_buffer_size Actual secure erase response size + * \param[out] indicator Indicator holding crypto algorithm parameters + * (if secure erase response also needs crypto operations) + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_erase)(void *vendor_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue); + /** + * \brief Parse secure erase response. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*parse_secure_erase_response)(void *vendor_ctx, + crypto_indicator_t *indicator); +#if defined(SECURE_COPY) + int32_t (*pre_secure_copy)(); + int32_t (*secure_copy_packet)(); + int32_t (*post_secure_copy)(); + int32_t (*parse_secure_copy_response)(); +#endif +#if defined(SECURE_READ) + /** + * \brief Pre secure read. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Target address + * \param[in] session_key_id Associated session key id + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_read)(void *vendor_ctx, uint32_t addr, + uint32_t session_key_id, jqueue_t *resp_queue); + /** + * \brief Pack secure read packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] addr Target address + * \param[in] len Data length + * \param[in] session_key_id Associated session key id + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_read_packet)(void *vendor_ctx, uint32_t addr, + uint32_t len, uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post secure read. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[in] resp_queue Pointer to response queue holding responses from flash + * \param[in] resp_packet_buffer Buffer to hold secure read response from flash + * \param[out] resp_packet_buffer_size Actual secure read response size + * \param[out] indicator Indicator holding crypto algorithm parameters + * (if secure read response also needs crypto operations) + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_read)(void *vendor_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue); + /** + * \brief Parse secure read response. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] indicator Indicator holding crypto algorithm parameters + * \param[out] data Buffer to hold read data + * \param[in] data_len Read data length + * \param[out] bytes_read Actual read bytes + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*parse_secure_read_response)(void *vendor_ctx, + crypto_indicator_t *indicator, + uint8_t *data, uint32_t data_len, + uint32_t *bytes_read); +#endif + /** + * \brief Pre get regions' information in security. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[out] session_key_valid_flag Session key valid flag + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*pre_secure_get_regions_info)(void *vendor_ctx, + uint32_t session_key_id, + bool *session_key_valid_flag, + jqueue_t *resp_queue); + /** + * \brief Pack get regions' information in security packet. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] session_key_id Associated session key id + * \param[in] region_index Region index + * \param[in] nonce Nonce + * \param[in] nonce_len Nonce length + * \param[in] packet Pointer to packet + * \param[in] packet_len Actual packet length + * \param[out] indicator Indicator holding crypto algorithm parameters + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*secure_get_regions_info_packet)(void *vendor_ctx, + uint32_t session_key_id, + int8_t region_index, + uint8_t *nonce, uint32_t nonce_len, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator); + /** + * \brief Post get regions' information in security. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] region_descr_p Pointer to the link list holding region description + * \param[out] resp_queue Pointer to response queue holding responses from flash + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*post_secure_get_regions_info)(void *vendor_ctx, + region_ll_node_t *region_descr_p, + jqueue_t *resp_queue); +#if defined(SECURE_REGION_MANAGE) + int32_t (*pre_secure_manage_region)(void *vendor_ctx); + int32_t (*secure_manage_region_packet)(void *vendor_ctx); + int32_t (*post_secure_manage_region)(void *vendor_ctx); +#endif + /** + * \brief Send security command packet to secure flash. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in/out] packet_out Pointer to command packet + * \param[in] packet_len Current packet length without cipher and mac + * \param[in] cipher_text Pointer to cipher text + * \param[in] cipher_text_len Cipher text length + * \param[in] mac Pointer to mac + * \param[in] mac_len Mac length + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*packet_send)(void *vendor_ctx, + uint8_t *packet_out, uint16_t packet_len, + uint8_t *cipher_text, uint16_t cipher_text_len, + uint8_t *mac, uint16_t mac_len); + /** + * \brief Receive security command response packet from secure flash. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] packet_in Pointer to response packet + * \param[in] packet_len Response packet length + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*packet_receive)(void *vendor_ctx, + uint8_t *packet_in, uint16_t packet_len); +} vendor_security_op_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_IMPL_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/README.md b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/README.md new file mode 100644 index 00000000000..a76ef05f86d --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/README.md @@ -0,0 +1,92 @@ +Getting started +================== + +JEDEC have published the [JESD261 standard](https://www.jedec.org/standards-documents/docs/jesd261), titled Serial NOR Security +Hardware Abstraction Layer(HAL). This standard defines a software layer to provide +a uniform interface for cryptographic operations on compliant Secure Flash devices. + +JESD261 HAL enables manufacturer-neutral communication with secure Flash devices. +Security features introduced in JESD261 include session-based communication, secure program +and erase operations, as well as partitioning of the Flash device into protected regions, +that are available through an application interface. JESD261 defines rules for implementing +this application interface to simplify the use and evaluation of these common security features +accross secure Flash vendors. + +************** +## Design concept + +JEDEC security HAL module could be compiled for use within different OSes and software platforms. +In this design, this module consits of JEDEC security HAL API layer and vendor specific implementation layer. + +JEDEC security HAL API layer implements the interfaces defined in JEDEC JESD261 standard. +And calls the pre-binding specific sub-steps implemented in vendor specific implementation layer. +Besides, the JEDEC security HAL API layer calls crypto services via vendor specific crypto wrapper functions. +Currently, mbedtls library and TF-M PSA crypto services are both supported. + +Vendor specific implementations layer provides specific sub-steps implementaion required by +JEDEC security HAL API layer. In addition, this layer also includes the specific implementation +of secure Flash provisioning which should be performed before deployment. + +Code structure +-------------- +```bash +TG424_3/ +├─JEDEC_security_HAL --------------------------------> JEDEC security HAL API layer +│ │ crypto_wrapper.h ------------------------------> Header file for crypto wrapper functions +│ │ jedec_security_hal.c ---------------------------> JEDEC security HAL API implementation +│ │ jedec_security_hal.h ---------------------------> Header file for JEDEC security HAL API layer +│ │ queue.c ----------------------------------------> Queue operations implementation +│ │ queue.h ----------------------------------------> Queue operations definition +│ │ vendor_security_impl.h --------------------------> Header file for vendor specific implementation of security HAL sub-steps +│ │ +│ └─include +│ +└─vendor_impl -----------------------------------------> Flash vendors specific implementation + │ vendor_provisioning_impl.h -------------------> Header file for vendor specific secure flash provisioning operations + │ vendor_secureflash.h --------------------------> Vendor secure flash definitions + │ vendor_secureflash_defs.h ----------------------> Vendor secure flash informations + │ + ├─macronix + │ ├─armorflash_mx75 -----------------------------> The specific implementations for Macronix MX75 ArmorFlash + │ │ + │ └─armorflash_mx78 -----------------------------> The specific implementations for Macronix MX78 ArmorFlash + │ │ libmx78_armor_lib.a --------------------> Binary library of MX78 ArmorFlash driver + │ │ mx78_armor.c ---------------------------> The specific implementations of JEDEC secuiry HAL sub-steps for Macronix MX78 ArmorFlash + │ │ mx78_armor.h + │ │ mx78_armor_lib.h + │ │ secureflash_layout.h -------------------> The specific parameters and secure region layout of MX78 ArmorFlash + │ │ + │ ├─crypto_wrapper ---------------------------> The specific crypto wrapper functions for Macronix MX78 ArmorFlash + │ │ crypto_wrapper_mbedtls.c -----------> The specific crypto wrapper functions based on mbedtls library + │ │ crypto_wrapper_psa.c --------------> The specific crypto wrapper functions based on Trusted Firmware-M crypto service + │ │ + │ └─provisioning ----------------------------> The specific provisioning implementation for Macronix MX78 ArmorFlash + │ libmx78_armor_provision_lib.a ------> Binary library of MX78 ArmorFlash provisioning driver + │ mx78_armor_provision.h + │ + └─vendor_template --------------------------------> Reserved vendor specific implementation for other secure Flash vendors reference +``` +******** +## Examples + +This JEDEC security HAL implementation has been integrated and tested with following OSes and software platforms. + +- [Arm Mbed OS](https://www.arm.com/products/development-tools/embedded-and-software/mbed-os) + +For Arm Mbed OS, JEDEC security HAL is integrated in the COMPONENT_SECUREF. The source code is available on [github](https://github.com/macronix/). + +``` +git clone -b macronix_secureflash_TG424_3 --recursive https://github.com/macronix/mbed-os +``` + + + +- [Arm Trusted Firmware-M](https://tf-m-user-guide.trustedfirmware.org/index.html) + +For Arm Trusted Firmware-M, JEDEC security HAL is integrated in the ETSS partition which provides solution for supporting secure Flash in Arm Trusted Firmware-M framework. The source code is available on [github](https://github.com/macronix/). + +``` +git clone -b macronix_secureflash_TG424_3 --recursive https://github.com/macronix/tf-m-extras +``` + + diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/CMakeLists.txt new file mode 100644 index 00000000000..b3af1ca5bca --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/CMakeLists.txt @@ -0,0 +1,12 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.15) + +cmake_policy(SET CMP0079 NEW) + +add_subdirectory(${SECUREFLASH_TYPE}) \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx75/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx75/CMakeLists.txt new file mode 100644 index 00000000000..efe2adcc990 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx75/CMakeLists.txt @@ -0,0 +1 @@ +Reserved for Macronix MX75 ArmorFlash. diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/CMakeLists.txt b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/CMakeLists.txt new file mode 100644 index 00000000000..0788c2963bb --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/CMakeLists.txt @@ -0,0 +1,85 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +#------------------------------------------------------------------------------- +cmake_minimum_required(VERSION 3.15) + +cmake_policy(SET CMP0079 NEW) + +if (CRYPTO_MBEDTLS AND CRYPTO_PSA) + Message(FATAL_ERROR "CRYPTO_MBEDTLS and CRYPTO_PSA both enabled!") +endif() +if (NOT CRYPTO_MBEDTLS AND NOT CRYPTO_PSA) + Message(FATAL_ERROR "CRYPTO_MBEDTLS and CRYPTO_PSA both disabled!") +endif() +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libmx78_armor_lib.a) + Message(FATAL_ERROR "libmx78_armor_lib.a should be download and put under current directory") +else() + add_library(mx78_armor_lib STATIC IMPORTED) + set_target_properties(mx78_armor_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmx78_armor_lib.a) + set_target_properties(mx78_armor_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +add_library(mx78_armor STATIC) +target_include_directories(mx78_armor + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../include +) + +target_compile_definitions(mx78_armor + PRIVATE + $<$:SECUREFLASH_PROVISION> + ETSS_PROV_DEVELOPER_MODE=${ETSS_PROV_DEVELOPER_MODE} + $<$:MULTI_CLIENT_ISOLATION> + $<$:SECUREFLASH_DEBUG> + $<$:MX78_ARMOR_TEST_MODE> + $<$:CRYPTO_MBEDTLS> + $<$:CRYPTO_PSA> +) + +target_sources(mx78_armor + PRIVATE + mx78_armor.c + $<$:${CMAKE_CURRENT_SOURCE_DIR}/crypto_wrapper/crypto_wrapper_psa.c> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/crypto_wrapper/crypto_wrapper_mbedtls.c> +) + +target_link_libraries(mx78_armor + PRIVATE + psa_interface + platform_s + tfm_sprt + secureflash_platform + spi_nor_driver + mx78_armor_lib + INTERFACE + platform_common_interface +) + +target_link_libraries(jedec_security_hal + PRIVATE + mx78_armor +) +if(SECUREFLASH_PROVISION) +target_include_directories(mx78_armor + PRIVATE + provisioning +) + + +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/provisioning/libmx78_armor_provision_lib.a) + Message(FATAL_ERROR "libmx78_armor_provision_lib.a should be download and put under provisioning directory") +else() + add_library(mx78_armor_provision_lib STATIC IMPORTED) + set_target_properties(mx78_armor_provision_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/provisioning/libmx78_armor_provision_lib.a) + set_target_properties(mx78_armor_provision_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/provisioning) +endif() + +target_link_libraries(mx78_armor + PRIVATE + mx78_armor_provision_lib +) +endif() diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_mbedtls.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_mbedtls.c new file mode 100644 index 00000000000..749f71d21aa --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_mbedtls.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ + +#ifdef CRYPTO_MBEDTLS + +#include +#include +#include +#include +#include +#include "../../../JEDEC_security_HAL/crypto_wrapper.h" +#include "mbedtls/entropy.h" +#include "mbedtls/gcm.h" +#include "mbedtls/ccm.h" +#include "mbedtls/aes.h" +#include "mbedtls/md.h" +#include "mbedtls/hkdf.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ctr_drbg.h" +#include "../../../spi_nor_flash/spi_nor.h" + +#define KEY_SIZE ((256 / 8) * 2 + 1) +#define KEY_MAX_NUM 0x20 +#define KEY_UNUSED 0 +#define KEY_USED 1 + +#define KEY_HANDLE_NOT_LOADED 0 +#define MAC_SIZE 0x20 +#define TAG_LENGTH 0x10 + +#define MAX_ROOT_KEY_NUM 0x10 +#define MAX_SESSION_KEY_NUM 0x10 +#define MAC_KEY_SIZE 0x20 +#define ENC_KEY_SIZE 0x10 + +#define KEY_ID_LEN 4 + +typedef struct { + uint8_t value[KEY_SIZE]; + uint32_t id; + uint8_t used:1, + len:7; +} key_manager_t; + +typedef struct { + uint32_t enc_key_id; + uint32_t mac_key_id; +} session_key_id_t; + +static session_key_id_t session_key_id_slot[MAX_SESSION_KEY_NUM] = {}; +static key_manager_t key_manager[KEY_MAX_NUM] = {}; + +/** + * \brief Find an empty session key slot. + * + * \param[out] slot_index Returned empty slot index + * + * \return true if an empty session key slot was found, + * or false there's no empty session key slot + */ +static bool find_empty_session_key_id_slot(uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_SESSION_KEY_NUM; i++) { + if ((session_key_id_slot[i].enc_key_id == KEY_HANDLE_NOT_LOADED) && + (session_key_id_slot[i].mac_key_id == KEY_HANDLE_NOT_LOADED)) { + *slot_index = i; + return true; + } + } + return false; +} + +/** + * \brief Find the session key slot index corresponding to session key id. + * \param[in] session_key_id Input session key id + * \param[out] slot_index Returned empty slot index + * + * \return true if corresponding session key slot was found, + * or false there's no matching session key slot + */ +static bool find_session_key_id_slot(uint32_t session_key_id, uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_SESSION_KEY_NUM; i++) { + if ((uint32_t)&session_key_id_slot[i] == session_key_id) { + *slot_index = i; + return true; + } + } + return false; +} + +static int mbedtls_if_init() +{ + memset(key_manager, 0x00, sizeof(key_manager)); + memset(session_key_id_slot, 0x00, sizeof(session_key_id_slot)); + return JEDEC_ERROR_NONE; +} + +static int mbedtls_if_deinit() +{ + memset(key_manager, 0x00, sizeof(key_manager)); + memset(session_key_id_slot, 0x00, sizeof(session_key_id_slot)); + return JEDEC_ERROR_NONE; +} + +static int mbedtls_if_generate_random(uint8_t *odata, uint32_t odata_len) +{ + int32_t status = JEDEC_ERROR_NONE; + mbedtls_entropy_context entropy_ctx; + mbedtls_ctr_drbg_context ctr_drbg_ctx; + + mbedtls_entropy_init(&entropy_ctx); + mbedtls_ctr_drbg_init(&ctr_drbg_ctx); + + if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, NULL, 0)) { + status = JEDEC_ERROR_GENERATE_RANDOM; + goto generate_random_exit_point; + } + + if (0 != mbedtls_ctr_drbg_random(&ctr_drbg_ctx, odata, odata_len)) { + status = JEDEC_ERROR_GENERATE_RANDOM; + goto generate_random_exit_point; + } + +generate_random_exit_point: + mbedtls_entropy_free(&entropy_ctx); + mbedtls_ctr_drbg_free(&ctr_drbg_ctx); + + return status; +} + +static int simple_import_key(uint32_t *key_id, const uint8_t *key, uint8_t key_len) +{ + int32_t status = JEDEC_ERROR_NONE; + + if (0 == *key_id) { + uint8_t i = 0; + do { + status = mbedtls_if_generate_random((uint8_t *)key_id, KEY_ID_LEN); + if (JEDEC_ERROR_NONE != status) { + return status; + } + for (i = 0; i < KEY_MAX_NUM; i++) { + if (KEY_USED == key_manager[i].used && *key_id == key_manager[i].id) { + break; + } + } + }while (KEY_MAX_NUM != i); + } + for (uint8_t i = 0; i < KEY_MAX_NUM; i++) { + if (KEY_USED == key_manager[i].used && *key_id == key_manager[i].id) { + if (!memcmp(key, key_manager[i].value, key_manager[i].len)) { + return JEDEC_ERROR_NONE; + } + return JEDEC_ERROR_KEY_ID_CONFLICT; + } + if (KEY_UNUSED == key_manager[i].used) { + memcpy(key_manager[i].value, key, key_len); + key_manager[i].id = *key_id; + key_manager[i].len = key_len; + key_manager[i].used = KEY_USED; + return JEDEC_ERROR_NONE; + } + } + return JEDEC_ERROR_INSUFFICIENT_MEMORY; +} + +static int simple_export_key(uint32_t key_id, const uint8_t *key, uint8_t key_len, uint8_t *actual_key_len) +{ + for (uint8_t i = 0; i < KEY_MAX_NUM; i++) { + if (KEY_USED == key_manager[i].used && key_id == key_manager[i].id) { + if (key_len < key_manager[i].len) { + return JEDEC_ERROR_EXPORT_KEY; + } + memcpy(key, key_manager[i].value, key_manager[i].len); + *actual_key_len = key_manager[i].len; + return JEDEC_ERROR_NONE; + } + } + return JEDEC_ERROR_EXPORT_KEY; +} + +static int simple_destroy_key(uint32_t key_id) +{ + uint32_t index, target_key_id; + + if (true == find_session_key_id_slot(key_id, &index)) { + target_key_id = session_key_id_slot[index].mac_key_id; + + for (uint8_t i = 0; i < KEY_MAX_NUM; i++) { + if (target_key_id == key_manager[i].id) { + memset(&key_manager[i], 0x00, sizeof(key_manager_t)); + break; + } + } + target_key_id = session_key_id_slot[index].enc_key_id; + + for (uint8_t i = 0; i < KEY_MAX_NUM; i++) { + if (target_key_id == key_manager[i].id) { + memset(&key_manager[i], 0x00, sizeof(key_manager_t)); + break; + } + } + memset(&session_key_id_slot[index], 0x00, sizeof(session_key_id_t)); + return JEDEC_ERROR_NONE; + } + for (uint8_t i = 0; i < KEY_MAX_NUM; i++) { + if (key_id == key_manager[i].id) { + memset(&key_manager[i], 0x00, sizeof(key_manager_t)); + return JEDEC_ERROR_NONE; + } + } + return JEDEC_ERROR_KEY_ID_NOT_FOUND; +} + +static int simple_open_key(uint32_t key_id) +{ + (void)key_id; + return JEDEC_ERROR_NONE; +} + +static int simple_close_key(uint32_t key_id) +{ + (void)key_id; + return JEDEC_ERROR_NONE; +} + +static int mbedtls_if_aes_gcm(crypto_indicator_t *indicator) +{ + int32_t status = JEDEC_ERROR_NONE, mbedl_status, index; + mbedtls_gcm_context ctx = {}; + uint8_t key[16]; + uint8_t actual_key_len = 0; + + mbedtls_gcm_init(&ctx); + + /* export key from session key slot or key manager */ + bool ret = find_session_key_id_slot(indicator->aead.key_id, &index); + if (true == ret) { + status = simple_export_key(session_key_id_slot[index].enc_key_id, key, indicator->aead.key_len, &actual_key_len); + if (JEDEC_ERROR_NONE != status) { + goto aes_gcm_exit_point; + } + } else { + status = simple_export_key(indicator->aead.key_id, key, indicator->aead.key_len, &actual_key_len); + if (JEDEC_ERROR_NONE != status) { + goto aes_gcm_exit_point; + } + } + + if (0 != mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, indicator->aead.key_len * 8)) { + status = JEDEC_ERROR_AEAD; + goto aes_gcm_exit_point; + } + switch (indicator->property) { + case PROP_AUTHEN_TAG_DECRYPT_DATA: + case PROP_AUTHEN_TAG: + mbedl_status = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_DECRYPT, + indicator->aead.text_len, + indicator->aead.iv, indicator->aead.iv_len, + indicator->aead.add, indicator->aead.add_len, + indicator->aead.cipher_text, indicator->aead.plain_text, + indicator->aead.tag_len, indicator->aead.tag); + if (0 != mbedl_status) { + status = JEDEC_ERROR_AEAD; + goto aes_gcm_exit_point; + } + break; + case PROP_ENCRYPT_TAG_DATA: + case PROP_ENCRYPT_TAG: + mbedl_status = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT, + indicator->aead.text_len, + indicator->aead.iv, indicator->aead.iv_len, + indicator->aead.add, indicator->aead.add_len, + indicator->aead.plain_text, indicator->aead.cipher_text, + indicator->aead.tag_len, indicator->aead.tag); + if (0 != mbedl_status) { + status = JEDEC_ERROR_AEAD; + goto aes_gcm_exit_point; + } + break; + default: + status = JEDEC_ERROR_AEAD; + goto aes_gcm_exit_point; + } +aes_gcm_exit_point: + mbedtls_gcm_free(&ctx); + return status; +} + +static mbedtls_md_type_t sha_select_md_type(CryptoAlgorithm alg) +{ + switch (alg) { + case ALG_HKDF_SHA_1: + case ALG_HMAC_SHA_1: + return MBEDTLS_MD_SHA1; + case ALG_HKDF_SHA_224: + case ALG_HMAC_SHA_224: + return MBEDTLS_MD_SHA224; + case ALG_HKDF_SHA_256: + case ALG_HMAC_SHA_256: + return MBEDTLS_MD_SHA256; + case ALG_HKDF_SHA_384: + case ALG_HMAC_SHA_384: + return MBEDTLS_MD_SHA384; + case ALG_HKDF_SHA_512: + case ALG_HMAC_SHA_512: + return MBEDTLS_MD_SHA512; + default: + return MBEDTLS_MD_NONE; + } + return MBEDTLS_MD_NONE; +} + +static mbedtls_ecp_group_id ecdh_select_grp(CryptoAlgorithm alg) +{ + switch (alg) { + case ALG_ECDH_SECP192R1: + return MBEDTLS_ECP_DP_SECP192R1; + case ALG_ECDH_SECP224R1: + return MBEDTLS_ECP_DP_SECP224R1; + case ALG_ECDH_SECP256R1: + return MBEDTLS_ECP_DP_SECP256R1; + case ALG_ECDH_SECP384R1: + return MBEDTLS_ECP_DP_SECP384R1; + // case ALG_ECDH_SECP521R1: + // return MBEDTLS_ECP_DP_SECP521R1; + case ALG_ECDH_BP256R1: + return MBEDTLS_ECP_DP_BP256R1; + case ALG_ECDH_BP384R1: + return MBEDTLS_ECP_DP_BP384R1; + // case ALG_ECDH_BP512R1: + // return MBEDTLS_ECP_DP_BP512R1; + case ALG_ECDH_CURVE25519: + return MBEDTLS_ECP_DP_CURVE25519; + case ALG_ECDH_SECP192K1: + return MBEDTLS_ECP_DP_SECP192K1; + case ALG_ECDH_SECP224K1: + return MBEDTLS_ECP_DP_SECP224K1; + case ALG_ECDH_SECP256K1: + return MBEDTLS_ECP_DP_SECP256K1; + default: + return MBEDTLS_ECP_DP_NONE; + } + return MBEDTLS_ECP_DP_NONE; +} + +static int mbedtls_if_ecdh_gen_key_pair(crypto_indicator_t *indicator) +{ + /* The procedure refer to the Mbedtls's test suite (test_suite_ecdh.c) */ + int32_t status = JEDEC_ERROR_NONE; + size_t olen; + uint8_t pri_key[(256/8)+1] = {}, pub_key[(512/8)+1] ={}; + mbedtls_ecp_group_id ecp_grp_id; + mbedtls_mpi host_pri; + mbedtls_ecp_group grp; + mbedtls_ecp_point host_pub; + mbedtls_entropy_context entropy_ctx; + mbedtls_ctr_drbg_context ctr_drbg_ctx; + + /* Init. data struct */ + mbedtls_mpi_init(&host_pri); + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&host_pub); + mbedtls_entropy_init(&entropy_ctx); + mbedtls_ctr_drbg_init(&ctr_drbg_ctx); + /* Update random seed use custom string(pers) */ + mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, NULL, 0); + ecp_grp_id = ecdh_select_grp(indicator->algorithm); + if (ecp_grp_id == MBEDTLS_ECP_DP_NONE) { + status = JEDEC_ERROR_NOT_SUPPORT; + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + mbedtls_ecp_group_load(&grp, ecp_grp_id); + /* Generate an ECDH key pair on an elliptic curve, private key in host_pri and public key in host_pub */ + mbedtls_ecdh_gen_public(&grp, &host_pri, &host_pub, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); + /* Derived public key */ + switch (indicator->ecdh.pub_key_type) { + case RAW_PUB_KEY: + mbedtls_ecp_point_write_binary(&grp, &host_pub, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, + pub_key, indicator->ecdh.pub_key_len + 1); + memmove(pub_key, &pub_key[1], olen - 1); + if(indicator->ecdh.pub_key_len != (olen - 1)) { + status = JEDEC_ERROR_INV_ARGS; + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + break; + case UNCOMPRESSED_PUB_KEY: + mbedtls_ecp_point_write_binary(&grp, &host_pub, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, + pub_key, indicator->ecdh.pub_key_len); + if(indicator->ecdh.pub_key_len != olen) { + status = JEDEC_ERROR_INV_ARGS; + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + break; + case COMPRESSED_PUB_KEY: + mbedtls_ecp_point_write_binary(&grp, &host_pub, MBEDTLS_ECP_PF_COMPRESSED, &olen, + pub_key, indicator->ecdh.pub_key_len); + if(indicator->ecdh.pub_key_len != olen) { + status = JEDEC_ERROR_INV_ARGS; + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + break; + default: + status = JEDEC_ERROR_NOT_SUPPORT; + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + memcpy(indicator->ecdh.pub_key, pub_key, indicator->ecdh.pub_key_len); + indicator->ecdh.pri_key_len = mbedtls_mpi_size(&host_pri); + + /* Derived private key */ + mbedtls_mpi_write_binary(&host_pri, pri_key, mbedtls_mpi_size(&host_pri)); + status = simple_import_key(&indicator->ecdh.pub_key_id, indicator->ecdh.pub_key, indicator->ecdh.pub_key_len); + if (status != JEDEC_ERROR_NONE) { + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + status = simple_import_key(&indicator->ecdh.pri_key_id, pri_key, indicator->ecdh.pri_key_len); + if (status != JEDEC_ERROR_NONE) { + goto mbedtls_if_ecdh_gen_key_pair_exit_point; + } + memset(pri_key, 0x00, sizeof(pri_key)); +mbedtls_if_ecdh_gen_key_pair_exit_point: + mbedtls_mpi_free(&host_pri); + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&host_pub); + mbedtls_entropy_free(&entropy_ctx); + mbedtls_ctr_drbg_free(&ctr_drbg_ctx); + return status; +} + +static int32_t mbedlts_if_ecdh_gen_shared_secret(crypto_indicator_t *indicator) +{ + int32_t status = JEDEC_ERROR_NONE; + const char *pers = "mbedtls_ecdh"; + mbedtls_mpi host_secret; + mbedtls_mpi host_pri; + mbedtls_ecp_group grp; + mbedtls_ecp_point dev_pub; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ecp_group_id ecp_grp_id; + uint8_t host_pri_key[256 / 8 +1] = {}; + uint8_t secret[256 / 8] = {}; + uint8_t actual_key_len; + uint8_t pub_key_half_len, ofs = 0; + + if (NULL == indicator->ecdh.secret && !indicator->key_attr.import_req) { + return JEDEC_ERROR_INVALID_PARAM; + } + /* Init. data struct */ + mbedtls_mpi_init(&host_secret); + mbedtls_mpi_init(&host_pri); + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&dev_pub); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + /* Update random seed use custom string(pers) */ + // mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const uint8_t *)pers, strlen(pers)); + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + ecp_grp_id = ecdh_select_grp(indicator->algorithm); + if (ecp_grp_id == MBEDTLS_ECP_DP_NONE) { + return JEDEC_ERROR_NOT_SUPPORT; + } + mbedtls_ecp_group_load(&grp, ecp_grp_id); + status = simple_export_key(indicator->ecdh.pri_key_id, host_pri_key, sizeof(host_pri_key), &actual_key_len); + if (JEDEC_ERROR_NONE != status) { + return status; + } + switch (indicator->ecdh.pub_key_type) { + case RAW_PUB_KEY: + pub_key_half_len = indicator->ecdh.pub_key_len / 2; + ofs = 0; + break; + case UNCOMPRESSED_PUB_KEY: + pub_key_half_len = (indicator->ecdh.pub_key_len - 1) / 2; + ofs = 1; + break; + default: + return JEDEC_ERROR_NOT_SUPPORT; + } + /* Import device public key to dev_pub */ + mbedtls_mpi_read_binary(&dev_pub.X, indicator->ecdh.pub_key + ofs, pub_key_half_len); + mbedtls_mpi_read_binary(&dev_pub.Y, indicator->ecdh.pub_key + ofs + pub_key_half_len, pub_key_half_len); + mbedtls_mpi_lset(&dev_pub.Z, 1); + + /* Import host private key to host_pri */ + mbedtls_mpi_read_binary(&host_pri, host_pri_key, indicator->ecdh.pri_key_len); + + /* Compute the shared secret */ + mbedtls_ecdh_compute_shared(&grp, &host_secret, &dev_pub, &host_pri, mbedtls_ctr_drbg_random, &ctr_drbg); + + /* Derived shared secret */ + mbedtls_mpi_write_binary(&host_secret, secret, mbedtls_mpi_size(&host_secret)); + indicator->ecdh.secret_len = mbedtls_mpi_size(&host_secret); + + if (indicator->key_attr.import_req) { + status = simple_import_key(&indicator->ecdh.secret_id, secret, indicator->ecdh.secret_len); + if (status != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_GENERATE_KEY; + } + memset(secret, 0x00, indicator->ecdh.secret_len); + } else { + memcpy(indicator->ecdh.secret, secret, indicator->ecdh.secret_len); + } + + mbedtls_mpi_free(&host_pri); + mbedtls_mpi_free(&host_secret); + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&dev_pub); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + + return status; +} + +static int mbedtls_if_hmac_compute(crypto_indicator_t *indicator, mbedtls_md_info_t *md, uint8_t *key) +{ + int32_t status = JEDEC_ERROR_NONE; + uint8_t mac[256 / 8] = {}; + + if (0 != mbedtls_md_hmac(md, key, indicator->hmac.key_len, indicator->hmac.idata, indicator->hmac.idata_len, mac)) { + return JEDEC_ERROR_HMAC; + } + if (indicator->key_attr.import_req) { + status = simple_import_key(&indicator->hmac.mac_id, mac, indicator->hmac.key_len); + if (JEDEC_ERROR_NONE != status) { + return status; + } + memset (mac, 0x00, indicator->hmac.mac_len); + } else { + memcpy(indicator->hmac.mac, mac, indicator->hmac.mac_len); + } + return status; +} + +static int mbedtls_if_hmac_verify(crypto_indicator_t *indicator, mbedtls_md_info_t *md, uint8_t *key) +{ + uint8_t mac[256 / 8] = {}; + + if (0 != mbedtls_md_hmac(md, + key, + indicator->hmac.key_len, + indicator->hmac.idata, + indicator->hmac.idata_len, + mac)) { + return JEDEC_ERROR_HMAC; + } + if (memcmp(mac, indicator->hmac.mac, indicator->hmac.mac_len)) { + return JEDEC_ERROR_HMAC; + } + return JEDEC_ERROR_NONE; +} + +static int mbedtls_if_hmac(crypto_indicator_t *indicator) +{ + int32_t status = JEDEC_ERROR_NONE; + mbedtls_md_type_t md_type = MBEDTLS_MD_NONE; + mbedtls_md_info_t *md = NULL; + uint8_t key[256 / 8], actual_key_len = 0; + + if ((0 == indicator->hmac.key_id && NULL == indicator->hmac.key) || + NULL == indicator->hmac.idata || 0 == indicator->hmac.idata_len) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (PROP_HMAC_VERIFY == indicator->property && NULL == indicator->hmac.mac) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (NULL == indicator->hmac.mac && 0 == indicator->key_attr.import_req) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (ALG_HMAC != ALG_TYPE(indicator->algorithm)) { + return JEDEC_ERROR_NOT_SUPPORT; + } + md_type = sha_select_md_type(indicator->algorithm); + if (MBEDTLS_MD_NONE == md_type) { + return JEDEC_ERROR_NOT_SUPPORT; + } + md = mbedtls_md_info_from_type(md_type); + if (NULL == md) { + return JEDEC_ERROR_NOT_SUPPORT; + } + if (indicator->hmac.mac_len != mbedtls_md_get_size(md)) { + return JEDEC_ERROR_INVALID_PARAM; + } + /* If hmac.key is NULL, then export key from session key slot or key manager */ + if (NULL == indicator->hmac.key) { + int index; + bool ret = find_session_key_id_slot(indicator->hmac.key_id, & index); + if (true == ret) { + status = simple_export_key(session_key_id_slot[index].mac_key_id, key, indicator->hmac.key_len, &actual_key_len); + if (JEDEC_ERROR_NONE != status) { + return status; + } + } else { + status = simple_export_key(indicator->hmac.key_id, key, indicator->hmac.key_len, &actual_key_len); + if (JEDEC_ERROR_NONE != status) { + return status; + } + } + } else { + memcpy(key , indicator->hmac.key, indicator->hmac.key_len); + } + + switch (indicator->property) { + case PROP_HMAC_COMPUTE: + status = mbedtls_if_hmac_compute(indicator, md, key); + break; + case PROP_HMAC_VERIFY: + status = mbedtls_if_hmac_verify(indicator, md, key); + break; + default: + return JEDEC_ERROR_INVALID_PARAM; + } + return status; +} + +static int mbedtls_if_mx78_kdf(crypto_indicator_t *indicator) +{ + int status = JEDEC_ERROR_NONE, index = 0; + uint8_t actual_key_len = 0, prk[256 / 8], okm[256 / 8]; + mbedtls_md_type_t md_type = MBEDTLS_MD_NONE; + mbedtls_md_info_t *md = NULL; + + if (true != find_empty_session_key_id_slot(&index)) { + return JEDEC_ERROR_INVALID_PARAM; + } + md_type = sha_select_md_type(indicator->algorithm); + if (MBEDTLS_MD_NONE == md_type) { + return JEDEC_ERROR_NOT_SUPPORT; + } + md = mbedtls_md_info_from_type(md_type); + if (NULL == md) { + return JEDEC_ERROR_NOT_SUPPORT; + } + if (indicator->hkdf.prk_len != mbedtls_md_get_size(md)) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (NULL == indicator->hkdf.prk) { + status = simple_export_key(indicator->hkdf.prk_id, prk, indicator->hkdf.prk_len, &actual_key_len); + if (status != JEDEC_ERROR_NONE) { + return status; + } + } else { + memcpy(prk, indicator->hkdf.prk, indicator->hkdf.prk_len); + } + if (0 != mbedtls_md_hmac(md, prk, indicator->hkdf.prk_len, indicator->hkdf.info, indicator->hkdf.info_len, okm)) { + return JEDEC_ERROR_KDF; + } + /* import mac and enc key */ + status = simple_import_key(&session_key_id_slot[index].mac_key_id, okm, MAC_KEY_SIZE); + if (JEDEC_ERROR_NONE != status) { + return status; + } + status = simple_import_key(&session_key_id_slot[index].enc_key_id, okm, ENC_KEY_SIZE); + if (JEDEC_ERROR_NONE != status) { + return status; + } + memset(okm, 0x00, mbedtls_md_get_size(md)); + memset(prk, 0x00, mbedtls_md_get_size(md)); + indicator->hkdf.okm_id = (uint32_t)&session_key_id_slot[index]; + return status; + +} + +const static crypto_func_t CRYPTO_FUNC[] = { + 0, //ALG_NONE 0 + 0, //ALG_AES_CCM 1 + mbedtls_if_aes_gcm, //ALG_AES_GCM 2 + 0, //ALG_AES_ECB 3 + 0, //ALG_AES_CBC 4 + 0, //ALG_AES_OFB 5 + 0, //ALG_AES_CTR 6 + 0, //ALG_ECDSA 7 + 0, //ALG_ECDH 8 + mbedtls_if_hmac, //ALG_HMAC 9 + mbedtls_if_mx78_kdf, //ALG_HKDF 10 +}; + +static int mbedtls_if_algorithm_support(int alg, int index) +{ + if (ALG_NONE == alg) { + return JEDEC_ERROR_NOTHING; + } + if ((sizeof(CRYPTO_FUNC)/sizeof(crypto_func_t)) <= index || 0 == CRYPTO_FUNC[index]) { + return JEDEC_ERROR_NOT_SUPPORT; + } + return JEDEC_ERROR_NONE; +} + +static int mbedtls_if_crypto_func(crypto_indicator_t *indicator) +{ + int status = JEDEC_ERROR_NONE, index = ALG_TYPE(indicator->algorithm) >> 4; + + status = mbedtls_if_algorithm_support(indicator->algorithm, index); + if (JEDEC_ERROR_NOTHING == status) { + return JEDEC_ERROR_NONE; + } + if (JEDEC_ERROR_NONE != status) { + return status; + } + return CRYPTO_FUNC[index](indicator); +} + +static int mbedtls_if_key_derive(crypto_indicator_t *indicator, uint32_t *output_key_id) +{ + int32_t status = JEDEC_ERROR_NONE, index = ALG_TYPE(indicator->algorithm) >> 4; + + status = mbedtls_if_algorithm_support(indicator->algorithm, index); + if (JEDEC_ERROR_NOTHING == status) { + return JEDEC_ERROR_NONE; + } + if (JEDEC_ERROR_NONE != status) { + return status; + } + status = CRYPTO_FUNC[index](indicator); + if (JEDEC_ERROR_NONE != status) { + return JEDEC_ERROR_KDF; + } + switch (ALG_TYPE(indicator->algorithm)) { + case ALG_HKDF: + *output_key_id = indicator->hkdf.okm_id; + break; + case ALG_HMAC: + *output_key_id = indicator->hmac.mac_id; + break; + default: + return JEDEC_ERROR_NOT_SUPPORT; + } + return JEDEC_ERROR_NONE; + +} + +const crypto_wrapper_t mx78_armor_crypto_wrapper = { + .init = mbedtls_if_init, + .deinit = mbedtls_if_deinit, + .algorithm_support = mbedtls_if_algorithm_support, + .crypto_func = mbedtls_if_crypto_func, + .key_derive = mbedtls_if_key_derive, + .generate_random = mbedtls_if_generate_random, + .ecdh_gen_key_pair = mbedtls_if_ecdh_gen_key_pair, + .ecdh_gen_shared_secret = mbedlts_if_ecdh_gen_shared_secret, + .open_key = simple_open_key, + .close_key = simple_close_key, + .destroy_key = simple_destroy_key, + .export_key = simple_export_key, + .import_key = simple_import_key +}; +#endif /* CRYPTO_MBEDTLS */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_psa.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_psa.c new file mode 100644 index 00000000000..6d2bed4e041 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/crypto_wrapper/crypto_wrapper_psa.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ + +#ifdef CRYPTO_PSA + +#include +#include +#include +#include "../../../../JEDEC_security_HAL/crypto_wrapper.h" +#include "psa/crypto.h" + +#define KEY_HANDLE_NOT_LOADED (0) +#define MAC_SIZE (0x20) +#define TAG_LENGTH (0x10) + +#define MAX_ROOT_KEY_NUM (0x10) +#define MAX_SESSION_KEY_NUM (0x10) +#define MAC_KEY_SIZE (0x20) +#define ENC_KEY_SIZE (0x10) + + +typedef struct { + uint32_t session_enc_key_id; + uint32_t session_mac_key_id; +} session_key_id_t; + + +typedef struct { + uint32_t root_key_id; + uint32_t root_key_handle; +} root_key_handle_t; + +static session_key_id_t session_key_id_slot[MAX_SESSION_KEY_NUM] = {KEY_HANDLE_NOT_LOADED}; +static root_key_handle_t root_key_slot[MAX_ROOT_KEY_NUM] = {KEY_HANDLE_NOT_LOADED}; + +/** + * \brief Find an empty session key slot. + * + * \param[out] slot_index Returned empty slot index + * + * \return true if an empty session key slot was found, + * or false there's no empty session key slot + */ +static bool find_empty_session_key_id_slot(uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_SESSION_KEY_NUM; i++) { + if ((session_key_id_slot[i].session_enc_key_id == KEY_HANDLE_NOT_LOADED) && + (session_key_id_slot[i].session_mac_key_id == KEY_HANDLE_NOT_LOADED)) { + *slot_index = i; + return true; + } + } + return false; +} + +/** + * \brief Find the session key slot index corresponding to session key id. + * \param[in] session_key_id Input session key id + * \param[out] slot_index Returned empty slot index + * + * \return true if corresponding session key slot was found, + * or false there's no matching session key slot + */ +static bool find_session_key_id_slot(uint32_t session_key_id, uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_SESSION_KEY_NUM; i++) { + if ((uint32_t)&session_key_id_slot[i] == session_key_id) { + *slot_index = i; + return true; + } + } + return false; +} + +/** + * \brief Find an empty root key slot. + * + * \param[out] slot_index Returned empty slot index + * + * \return true if an empty root key slot was found, + * or false there's no empty root key slot + */ +static bool find_empty_root_key_id_slot(uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_ROOT_KEY_NUM; i++) { + if ((root_key_slot[i].root_key_handle == KEY_HANDLE_NOT_LOADED) && + (root_key_slot[i].root_key_id == KEY_HANDLE_NOT_LOADED)) { + *slot_index = i; + return true; + } + } + return false; +} + +/** + * \brief Find the root key slot index corresponding to root key id. + * \param[in] root_key_id Input root key id + * \param[out] slot_index Returned empty slot index + * + * \return true if corresponding session key slot was found, + * or false there's no matching session key slot + */ +static bool find_root_key_id_slot(uint32_t root_key_id, uint32_t *slot_index) +{ + for (uint32_t i = 0; i < MAX_ROOT_KEY_NUM; i++) { + if (root_key_slot[i].root_key_id == root_key_id) { + *slot_index = i; + return true; + } + } + return false; +} + +static int crypto_wrapper_init(void) +{ + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_deinit(void) +{ + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_mx78_kdf(crypto_indicator_t *indicator) +{ + psa_status_t status; + uint8_t mac[MAC_SIZE]; + size_t mac_length; + uint32_t vol_root_key_id; + uint32_t index; + /* session_key_id ==> { + * session_enc_key_id, + * session_mac_key_id + * } + */ + if (true == find_empty_session_key_id_slot(&index)) { + indicator->hkdf.okm_id = (uint32_t)&session_key_id_slot[index]; + } else { + return JEDEC_ERROR_INVALID_PARAM; + } + /* Open root key to tf-m crypto key slot */ + status = psa_open_key(indicator->hkdf.prk_id, &vol_root_key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_OPEN_KEY; + } + /* Multi-part mac compute */ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + status = psa_mac_sign_setup(&operation, + vol_root_key_id, + PSA_ALG_HMAC(PSA_ALG_SHA_256)); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_update(&operation, + indicator->hkdf.info, + indicator->hkdf.info_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_sign_finish(&operation, mac, MAC_SIZE, &mac_length); + if ((status != PSA_SUCCESS) || + (mac_length != MAC_SIZE)) { + return JEDEC_ERROR_HMAC; + } + /* import volatile hmac key */ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(MAC_KEY_SIZE)); + status = psa_import_key(&attributes, + mac, MAC_KEY_SIZE, + &(session_key_id_slot[index].session_mac_key_id)); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_IMPORT_KEY; + } + /* import volatile aes-gcm key */ + memset(&attributes, 0x00, sizeof(attributes)); + psa_set_key_usage_flags(&attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, + PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, TAG_LENGTH)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(ENC_KEY_SIZE)); + status = psa_import_key(&attributes, + mac, ENC_KEY_SIZE, + &(session_key_id_slot[index].session_enc_key_id)); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_IMPORT_KEY; + } + /* Close root key handle from tf-m crypto key slot */ + status = psa_close_key(vol_root_key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_CLOSE_KEY; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_ecdh_gen_key_pair(crypto_indicator_t *indicator) +{ + psa_status_t status; + uint16_t key_bits; + size_t exported_length = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + /* Generate an ECC key pair */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&attributes, PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, 0x00)); + switch (indicator->algorithm) { + case ALG_ECDH_SECP192R1: + case ALG_ECDH_SECP224R1: + case ALG_ECDH_SECP256R1: + case ALG_ECDH_SECP384R1: + psa_set_key_type(&attributes, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + break; + case ALG_ECDH_BP256R1: + case ALG_ECDH_BP384R1: + psa_set_key_type(&attributes, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1)); + break; + case ALG_ECDH_SECP192K1:; + case ALG_ECDH_SECP256K1: + psa_set_key_type(&attributes, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_K1)); + break; + default: + return JEDEC_ERROR_NOT_SUPPORT; + } + key_bits = 8 * indicator->ecdh.pri_key_len; + psa_set_key_bits(&attributes, key_bits); + status = psa_generate_key(&attributes, &indicator->ecdh.pri_key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_GENERATE_KEY; + } + indicator->ecdh.pub_key_id = indicator->ecdh.pri_key_id; + status = psa_export_public_key(indicator->ecdh.pub_key_id, + indicator->ecdh.pub_key, + indicator->ecdh.pub_key_len, + &exported_length); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_EXPORT_KEY; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_ecdh_gen_shared_secret(crypto_indicator_t *indicator) +{ + psa_status_t status; + uint32_t actual_size; + status = psa_raw_key_agreement(PSA_ALG_ECDH, + indicator->ecdh.pri_key_id, + indicator->ecdh.pub_key, + indicator->ecdh.pub_key_len, + indicator->ecdh.secret, + indicator->ecdh.secret_len, + &actual_size); + if (status) { + return JEDEC_ERROR_GENERATE_KEY; + } + return JEDEC_ERROR_NONE; +} + +/** + * \brief Open root key corresponding to root_key_id. + * \param[in] root_key_id Input root key id + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_open_key(uint32_t root_key_id) +{ + psa_status_t status; + uint32_t key_handle; + uint32_t index; + + status = psa_open_key(root_key_id, &key_handle); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_OPEN_KEY; + } + if (find_empty_root_key_id_slot(&index) == true) { + root_key_slot[index].root_key_id = root_key_id; + root_key_slot[index].root_key_handle = key_handle; + } else { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + return JEDEC_ERROR_NONE; +} + +/** + * \brief Close root key corresponding to root_key_id. + * \param[in] root_key_id Input root key id + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_close_key(uint32_t root_key_id) +{ + psa_status_t status; + uint32_t index; + + if (find_root_key_id_slot(root_key_id, &index) == true) { + status = psa_close_key(root_key_slot[index].root_key_handle); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_CLOSE_KEY; + } + root_key_slot[index].root_key_handle = KEY_HANDLE_NOT_LOADED; + root_key_slot[index].root_key_id = KEY_HANDLE_NOT_LOADED; + } else { + return JEDEC_ERROR_INVALID_PARAM; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_export_public_key(uint32_t key_id, uint8_t *key_buf, + uint32_t buf_size, uint32_t *actual_size) +{ + psa_status_t status; + status = psa_export_public_key(key_id, key_buf, buf_size, + actual_size); + if (status != PSA_SUCCESS) { + return status; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_export_key(uint32_t key_id, uint8_t *key_buf, + uint32_t buf_size, uint32_t *actual_size) +{ + psa_status_t status; + status = psa_export_key(key_id, key_buf, buf_size, + actual_size); + if (status != PSA_SUCCESS) { + return status; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_import_key(uint32_t *key_id, uint8_t *key_buf, + uint32_t key_size, KeyLifeTime lifetime) +{ + psa_status_t status; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(key_size)); + if (lifetime == KEY_LIFETIME_VOLATILE) { + *key_id = PSA_KEY_ID_NULL; + } else { + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&attributes, *key_id); + } + status = psa_import_key(&attributes, key_buf, key_size, key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_IMPORT_KEY; + } + return JEDEC_ERROR_NONE; +} +/** + * \brief Destroy session key corresponding to session_key_id. + * \param[in] session_key_id Input session key id + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_destroy_key(uint32_t key_id) +{ + psa_status_t status; + uint32_t index; + + if (find_session_key_id_slot(key_id, &index) == true) { + /* Destroy session's encryption key */ + status = psa_destroy_key(session_key_id_slot[index].session_enc_key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_DESTROY_KEY; + } + session_key_id_slot[index].session_enc_key_id = KEY_HANDLE_NOT_LOADED; + /* Destroy session's hmac key */ + status = psa_destroy_key(session_key_id_slot[index].session_mac_key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_DESTROY_KEY; + } + session_key_id_slot[index].session_mac_key_id = KEY_HANDLE_NOT_LOADED; + } else { + status = psa_destroy_key(key_id); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_DESTROY_KEY; + } + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_aes_ccm(crypto_indicator_t *indicator) +{ + /* TODO */ + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_aes_ecb(crypto_indicator_t *indicator) +{ + /* TODO */ + return JEDEC_ERROR_NONE; +} + + +/** + * \brief Implement AEAD encryption with input session_key_id. + * \param[in] session_key_id Input session key id + * \param[in] indicator AEAD encryption parameters + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_aead_enc(uint32_t session_key_id, crypto_indicator_t *indicator) +{ + psa_status_t status; + size_t out_len; + + if (sizeof(indicator->buf) < + PSA_AEAD_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, + PSA_ALG_GCM, + indicator->aead.text_len)) { + return JEDEC_ERROR_INVALID_PARAM; + } + session_key_id_t *session_key_id_ptr = (session_key_id_t *)session_key_id; + status = psa_aead_encrypt((psa_key_id_t)session_key_id_ptr->session_enc_key_id, + PSA_ALG_GCM, + indicator->aead.iv, indicator->aead.iv_len, + indicator->aead.add, indicator->aead.add_len, + indicator->aead.plain_text, indicator->aead.text_len, + indicator->buf, sizeof(indicator->buf), &out_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_AEAD_ENC; + } + /* Authentication tag is appended to the encrypted data */ + /* NOTE:The indicator->aead.cipher_text has been set to point to send packet previously, + here just copy the actual mac and ciphertext to send packet */ + indicator->aead.text_len = out_len - + PSA_AEAD_TAG_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_GCM); + memcpy(indicator->aead.cipher_text, indicator->buf, indicator->aead.text_len); + indicator->aead.tag_len = PSA_AEAD_TAG_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_GCM); + memcpy(indicator->aead.tag, + indicator->buf + indicator->aead.text_len, + indicator->aead.tag_len); + return JEDEC_ERROR_NONE; +} + +/** + * \brief Implement AEAD decryption with input session_key_id. + * \param[in] session_key_id Input session key id + * \param[in] indicator AEAD decryption parameters + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_aead_dec(uint32_t session_key_id, crypto_indicator_t *indicator) +{ + psa_status_t status; + size_t out_len; + + session_key_id_t *session_key_id_ptr = (session_key_id_t *)session_key_id; + memcpy(indicator->buf, indicator->aead.cipher_text, indicator->aead.text_len); + memcpy(indicator->buf + indicator->aead.text_len, + indicator->aead.tag, indicator->aead.tag_len); + status = psa_aead_decrypt((psa_key_id_t)session_key_id_ptr->session_enc_key_id, + PSA_ALG_GCM, + indicator->aead.iv, indicator->aead.iv_len, + indicator->aead.add, indicator->aead.add_len, + indicator->buf, + indicator->aead.text_len + indicator->aead.tag_len, + indicator->aead.plain_text, + indicator->aead.text_len, &out_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_AEAD_DEC; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_aes_gcm(crypto_indicator_t *indicator) +{ + psa_status_t status; + size_t out_len; + + switch (indicator->property) { + case PROP_AUTHEN_TAG_DECRYPT_DATA: + case PROP_AUTHEN_TAG: + return crypto_wrapper_aead_dec(indicator->aead.key_id, indicator); + break; + case PROP_ENCRYPT_TAG_DATA: + case PROP_ENCRYPT_TAG: + return crypto_wrapper_aead_enc(indicator->aead.key_id, indicator); + break; + default: + return JEDEC_ERROR_AEAD; + } +} + + +/** + * \brief Compute MAC with input session key. + * \param[in] session_key_id Input session key id + * \param[in] indicator MAC operation parameters + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_mac_compute(uint32_t key_id, crypto_indicator_t *indicator) +{ + psa_status_t status; + size_t actual_mac_size; + uint32_t index; + + /* No need for computing mac */ + if ((indicator->hmac.idata == NULL) && (indicator->hmac.idata_len == 0)) { + return JEDEC_ERROR_NONE; + } + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + + if (find_session_key_id_slot(key_id, &index) == true) { + session_key_id_t *session_key_id_ptr = key_id; + status = psa_mac_sign_setup(&operation, + session_key_id_ptr->session_mac_key_id, + PSA_ALG_HMAC(PSA_ALG_SHA_256)); + } else { + status = psa_mac_sign_setup(&operation, + key_id, + PSA_ALG_HMAC(PSA_ALG_SHA_256)); + } + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_update(&operation, + indicator->hmac.idata, + indicator->hmac.idata_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_sign_finish(&operation, + indicator->hmac.mac, + indicator->hmac.mac_len, + &actual_mac_size); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + return JEDEC_ERROR_NONE; +} + +/** + * \brief Implement MAC verify with input session key. + * \param[in] session_key_id Input session key id + * \param[in] indicator MAC verify parameters + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_mac_verify(uint32_t key_id, crypto_indicator_t *indicator) +{ + psa_status_t status; + uint32_t index; + + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + if (find_session_key_id_slot(key_id, &index) == true) { + session_key_id_t *session_key_id_ptr = key_id; + status = psa_mac_verify_setup(&operation, + session_key_id_ptr->session_mac_key_id, + PSA_ALG_HMAC(PSA_ALG_SHA_256)); + } else { + status = psa_mac_verify_setup(&operation, + key_id, + PSA_ALG_HMAC(PSA_ALG_SHA_256)); + } + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_update(&operation, + indicator->hmac.idata, + indicator->hmac.idata_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + status = psa_mac_verify_finish(&operation, + indicator->hmac.mac, + indicator->hmac.mac_len); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_HMAC; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_hmac(crypto_indicator_t *indicator) +{ + if ((0 == indicator->hmac.key_id && NULL == indicator->hmac.key) || + NULL == indicator->hmac.idata || 0 == indicator->hmac.idata_len) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (PROP_HMAC_VERIFY == indicator->property && NULL == indicator->hmac.mac) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (NULL == indicator->hmac.mac && 0 == indicator->key_attr.import_req) { + return JEDEC_ERROR_INVALID_PARAM; + } + if (ALG_HMAC != ALG_TYPE(indicator->algorithm)) { + return JEDEC_ERROR_NOT_SUPPORT; + } + switch (indicator->property) { + case PROP_HMAC_COMPUTE: + return crypto_wrapper_mac_compute(indicator->hmac.key_id, indicator); + break; + case PROP_HMAC_VERIFY: + return crypto_wrapper_mac_verify(indicator->hmac.key_id, indicator); + break; + default: + return JEDEC_ERROR_INVALID_PARAM; + } +} +/** + * \brief Generate random number. + * \param[out] output Output buffer for generated random number + * \param[in] output_size Number of bytes to generate and output + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_generate_random(uint8_t *output, uint32_t output_size) +{ + psa_status_t status; + + status = psa_generate_random(output, output_size); + if (status != PSA_SUCCESS) { + return JEDEC_ERROR_GENERATE_RANDOM; + } + return JEDEC_ERROR_NONE; +} + +const static crypto_func_t CRYPTO_FUNC[] = { + 0, //ALG_NONE 0 + crypto_wrapper_aes_ccm, //ALG_AES_CCM 1 + crypto_wrapper_aes_gcm, //ALG_AES_GCM 2 + crypto_wrapper_aes_ecb, //ALG_AES_ECB 3 + 0, //ALG_AES_CBC 4 + 0, //ALG_AES_OFB 5 + 0, //ALG_AES_CTR 6 + 0, //ALG_ECDSA 7 + 0, //ALG_ECDH 8 + crypto_wrapper_hmac, //ALG_HMAC 9 + crypto_wrapper_mx78_kdf, //ALG_HKDF 10 +}; + +static int crypto_wrapper_algorithm_support(int alg, int index) +{ + if (ALG_NONE == alg) { + return JEDEC_ERROR_NOTHING; + } + if ((sizeof(CRYPTO_FUNC)/sizeof(crypto_func_t)) <= index || 0 == CRYPTO_FUNC[index]) { + return JEDEC_ERROR_NOT_SUPPORT; + } + return JEDEC_ERROR_NONE; +} + +static int crypto_wrapper_crypto_func(crypto_indicator_t *indicator) +{ + int32_t status = JEDEC_ERROR_NONE, index = ALG_TYPE(indicator->algorithm) >> 4; + + status = crypto_wrapper_algorithm_support(indicator->algorithm, index); + if (JEDEC_ERROR_NOTHING == status) { + return JEDEC_ERROR_NONE; + } + if (JEDEC_ERROR_NONE != status) { + return status; + } + return CRYPTO_FUNC[index](indicator); +} + +/** + * \brief Generate session key from root key. + * \param[in] crypto_indicator KDF parameters + * \param[out] session_key_id Returned session key id + * + * \return JEDEC_ERROR_NONE if success, + * or JEDEC_ERROR_XX if fail + */ +static int crypto_wrapper_kdf(crypto_indicator_t *indicator, + uint32_t *output_key_id) +{ + int32_t status = JEDEC_ERROR_NONE, index = ALG_TYPE(indicator->algorithm) >> 4; + + status = crypto_wrapper_algorithm_support(indicator->algorithm, index); + if (JEDEC_ERROR_NOTHING == status) { + return JEDEC_ERROR_NONE; + } + if (JEDEC_ERROR_NONE != status) { + return status; + } + status = CRYPTO_FUNC[index](indicator); + if (JEDEC_ERROR_NONE != status) { + return JEDEC_ERROR_KDF; + } + switch (ALG_TYPE(indicator->algorithm)) { + case ALG_HKDF: + *output_key_id = indicator->hkdf.okm_id; + break; + case ALG_HMAC: + *output_key_id = indicator->hmac.mac_id; + break; + default: + return JEDEC_ERROR_NOT_SUPPORT; + } + return JEDEC_ERROR_NONE; +} + +crypto_wrapper_t mx78_armor_crypto_wrapper = { + .init = crypto_wrapper_init, + .deinit = crypto_wrapper_deinit, + .algorithm_support = crypto_wrapper_algorithm_support, + .crypto_func = crypto_wrapper_crypto_func, + .key_derive = crypto_wrapper_kdf, + .generate_random = crypto_wrapper_generate_random, + .ecdh_gen_key_pair = crypto_wrapper_ecdh_gen_key_pair, + .ecdh_gen_shared_secret = crypto_wrapper_ecdh_gen_shared_secret, + .open_key = crypto_wrapper_open_key, + .close_key = crypto_wrapper_close_key, + .destroy_key = crypto_wrapper_destroy_key, + .export_public_key = crypto_wrapper_export_public_key, + .export_key = crypto_wrapper_export_key, + .import_key = crypto_wrapper_import_key, + +}; +#endif /* CRYPTO_PSA */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/libmx78_armor_lib.a b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/libmx78_armor_lib.a new file mode 100644 index 00000000000..a8fc7034318 Binary files /dev/null and b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/libmx78_armor_lib.a differ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.c new file mode 100644 index 00000000000..657e7f0d3f5 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.c @@ -0,0 +1,1603 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include "../../../JEDEC_security_HAL/include/error.h" +#include "../../vendor_provisioning_impl.h" +#include "mx78_armor.h" +#include "mx78_armor_lib.h" +#include "provisioning/mx78_armor_provision.h" +#include "spi_nor.h" +#include "../../vendor_secureflash_defs.h" +#include "plat_secure_flash.h" +#include "secureflash_layout.h" + +#define ARMOR_MC_SIZE 0x04 +#define DEFAULT_SECURITY_PROFILE_ID 0 + +#define CFG_READ_SIZE_DEFAULT 0x20 +#define HEALTH_TEST_TYPE_CNT 0x05 +#define TMP_BUFFER_SIZE 0x20 + +#ifdef SECUREFLASH_PROVISION +uint8_t PROVISIONING_BLOB[] = { + /* Major Header */ + 'S', 'F', 'P', 'I', // DWORD 0: [31:00] magic, "SFPI" + 0x01, 0x01, 0x3c, 0x00, // DWORD 1: [03:00] minor_version, [07:04] major_version, [15:08] sub header number, [31:16] total size + 0xc2, 0x29, 0x17, 0x00, // DWORD 2: [23:00] ID, [31:24] provision_disable_indicator + + /* Sub Header, ID: 0x03, APP_INFO */ + 0x03, 0x04, 0x30, 0x80, // DWORD 0: [07:00] ID, [15:08] num, [30:16] app_info size, [31] save:1, not save: 0 + /* APP_INFO, Table */ + 0xFE, 0xFF, 0xFF, 0xFF, // DWORD 1: [31:00] application id (-2/0xfffffffe) + 0x55, 0xAA, 0x55, 0x00, // DWORD 2: [31:00] key id (app0) + 0x00, 0xFF, 0xFF, 0xFF, // DWORD 3: [07:00] zone id, [31:08] reserved (app0) + 0xFD, 0xFF, 0xFF, 0xFF, // DWORD 1: [31:00] application id (-3/0xfffffffd) + 0x55, 0xAA, 0x55, 0x04, // DWORD 5: [31:00] key id (app1) + 0x01, 0xFF, 0xFF, 0xFF, // DWORD 6: [07:00] zone id, [31:08] reserved (app1) + 0xBA, 0x0B, 0x00, 0x00, // DWORD 1: [31:00] application id (3002/0x00000bba) + 0x55, 0xAA, 0x55, 0x0B, // DWORD 8: [31:00] key id (app2) + 0x02, 0xFF, 0xFF, 0xFF, // DWORD 9: [07:00] zone id, [31:08] reserved (app2) + 0xBE, 0x0B, 0x00, 0x00, // DWORD 10: [31:00] application id (3006/0x00000bbe) + 0x55, 0xAA, 0x55, 0x0F, // DWORD 11: [31:00] key id (app3) + 0x03, 0xFF, 0xFF, 0xFF, // DWORD 12: [07:00] zone id, [31:08] reserved (app3) + }; +#endif /* SECUREFLASH_PROVISION */ + +mx78_armor_context g_mx78_armor_ctx; +static mx78_armor_security_operation_t operation[CONC_OPER_NUM] = {}; + +/** + * \brief Allocate an operation context. + * + * \param[in] type ArmorFlash operation type + * \param[out] op_ctx Pointer to allocated operation context + * \return true or false + */ +static bool mx78_armor_operation_alloc(mx78_armor_operation_type_t type, + mx78_armor_security_operation_t **op_ctx) +{ + for (uint8_t i = 0; i < CONC_OPER_NUM; i++) { + if (operation[i].in_use == OPER_NOT_IN_USE) { + operation[i].in_use = OPER_IN_USE; + operation[i].type = type; + *op_ctx = &operation[i]; + return true; + } + } + *op_ctx = NULL; + return false; +} + +/** + * \brief Release an operation context. + * + * \param[in] op_ctx Pointer to the operation context + * \return NULL + */ +static void mx78_armor_operation_release(mx78_armor_security_operation_t *op_ctx) +{ + op_ctx->in_use = OPER_NOT_IN_USE; + memset(op_ctx, 0x00, sizeof(mx78_armor_security_operation_t)); +} + +/** + * \brief Look up an operation context. + * \param[in] type ArmorFlash operation type + * \param[out] op_ctx Pointer to the matched operation context + * \return NULL + */ +static void mx78_armor_operation_lookup(mx78_armor_operation_type_t type, + mx78_armor_security_operation_t **op_ctx) +{ + for (uint8_t i = 0; i < CONC_OPER_NUM; i++) { + if ((operation[i].in_use == OPER_IN_USE) && + (operation[i].type == type)) { + *op_ctx = &operation[i]; + return; + } + } + *op_ctx = NULL; +} + +static int32_t mx78_armor_packet_send(mx78_armor_context *mx78_armor_ctx, + uint8_t *outdata, uint32_t outdata_len, + uint8_t *cipher_text, uint32_t cipher_text_len, + uint8_t *mac, uint32_t mac_len) +{ + int32_t status; + uint32_t tx_packet_size; + uint32_t outdata_actual_len = outdata_len; + + if ((mac != NULL) && (mac_len > 0)) { + memcpy(outdata + outdata_len, mac, mac_len); + outdata_actual_len += mac_len; + } + if ((cipher_text != NULL) && (cipher_text_len > 0)) { + memcpy(outdata + outdata_actual_len, cipher_text, cipher_text_len); + outdata_actual_len += cipher_text_len; + } + status = __packet_assemble(mx78_armor_ctx, PACKET_OUT, + outdata, outdata_actual_len, + mx78_armor_ctx->scratchpad, &tx_packet_size); + if (status != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_CMD_PACKET; + } + if (spi_write(mx78_armor_ctx->scratchpad, tx_packet_size)) { + return JEDEC_ERROR_COMM_FAIL; + } + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_packet_receive(mx78_armor_context *mx78_armor_ctx, + uint8_t *indata, uint32_t indata_len) +{ + int32_t status; + uint8_t rx_buffer[PACKET_MAX_LEN]; + uint32_t tx_packet_size, rx_packet_size; + + rx_packet_size = indata_len; + status = __packet_assemble(mx78_armor_ctx, PACKET_IN, NULL, 0, + mx78_armor_ctx->scratchpad, &tx_packet_size); + if (status != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_CMD_PACKET; + } + if (spi_read(mx78_armor_ctx->scratchpad, tx_packet_size, rx_buffer, rx_packet_size)) { + return JEDEC_ERROR_COMM_FAIL; + } + memcpy(indata, rx_buffer, indata_len); + return JEDEC_ERROR_NONE; +} + +/** + * \brief Exchange nonce with ArmorFlash. + * + * \param[in] mx78_armor_ctx MX78 ArmorFlash context + * \param[in] nonce_in Input nonce from host + * \param[in] nonce_in_len Input nonce length + * \param[out] nonce_out Buffer for holding output nonce from ArmorFlash + * \param[in] buf_size Buffer size + * \param[out] actual_nonce_size Actual size of output nonce from ArmorFlash + * + * \return JEDEC_ERROR_NONE if successful, + * JEDEC_ERROR_XX if failed + */ +static int32_t _armor_generate_nonce(mx78_armor_context *mx78_armor_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + uint8_t *nonce_out, uint32_t buf_size, + uint32_t *actual_nonce_size) +{ + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + uint8_t nonce_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(GENERATE_NONCE, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + nonce_len = __get_nonce_size(oper_ctx); + oper_ctx->out_size = nonce_len; + if (nonce_in_len > nonce_len) { + nonce_in_len = nonce_len; + } + status = __prepare_write_packet(oper_ctx, + nonce_in, nonce_in_len, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_generate_nonce_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, + rw_packet, wr_packet_len, + NULL, 0, NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto _armor_generate_nonce_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_generate_nonce_exit_point; + } + status = __parse_read_packet(oper_ctx, + nonce_out, buf_size, + NULL, 0, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_generate_nonce_exit_point; + } + *actual_nonce_size = nonce_len; +_armor_generate_nonce_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +/** + * \brief Read current ArmorFlash sessions status. + * + * \param[in] mx78_armor_ctx MX78 ArmorFlash context + * \param[out] session_status Buffer to store session status + * \param[in] status_size Size of status in byte + * \return JEDEC_ERROR_NONE if successful, + * JEDEC_ERROR_XX if failed + */ +static int32_t _armor_check_sessions_status(mx78_armor_context *mx78_armor_ctx, + uint8_t *session_status, + uint32_t status_size) +{ + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(READ_SESSION_STATUS, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->out_size = status_size; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_check_sessions_status_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, + rw_packet, wr_packet_len, + NULL, 0, NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto _armor_check_sessions_status_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + memset(rw_packet, 0x00, sizeof(rw_packet)); + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_check_sessions_status_exit_point; + } + status = __parse_read_packet(oper_ctx, + session_status, status_size, + NULL, 0, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_check_sessions_status_exit_point; + } +_armor_check_sessions_status_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +/** + * \brief Confirm session key. + * + * \param[in] mx78_armor_ctx MX78 ArmorFlash context + * \param[in] session_key_id Session key id + * \param[out] resp_queue Response queue + * + * \return JEDEC_ERROR_NONE if successful, + * JEDEC_ERROR_XX if failed + */ +static int32_t _armor_confirm_session(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + jqueue_t *resp_queue) +{ + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + uint8_t mac[MAC_SIZE]; + uint8_t resp_buf[MAX_RESP_SIZE]; + uint32_t actual_resp_len; + int32_t status; + resp_param_t response = {}; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(CONFIRM_SESSION, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->crypto_key_id = session_key_id; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_confirm_session_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, + rw_packet, wr_packet_len, + NULL, 0, + NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto _armor_confirm_session_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_confirm_session_exit_point; + } + status = __parse_read_packet(oper_ctx, + NULL, 0, + mac, MAC_SIZE, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_confirm_session_exit_point; + } + /* Pack response packet */ + (void)__pack_response(oper_ctx, resp_buf, sizeof(resp_buf), &actual_resp_len); + /* Add response packet and mac to queue */ + response.alg = ALG_HMAC_SHA_256; + response.property = PROP_HMAC_VERIFY; + response.hmac.key_id = session_key_id; + response.hmac.key_len = 32; + response.hmac.idata = resp_buf; + response.hmac.idata_len = (uint16_t)actual_resp_len; + response.hmac.mac = mac; + response.hmac.mac_len = MAC_SIZE; + queue_add(resp_queue, &response); +_armor_confirm_session_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_health_test(mx78_armor_context *mx78_armor_ctx) +{ + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(HEALTH_TEST, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + for (uint8_t i = 0; i < HEALTH_TEST_TYPE_CNT; i++) { + oper_ctx->addr = i; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_health_test_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, rw_packet, wr_packet_len, + NULL, 0, NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto armor_health_test_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_health_test_exit_point; + } + status = __parse_read_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_health_test_exit_point; + } + } +armor_health_test_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_configure_security_profile(mx78_armor_context *mx78_armor_ctx) +{ + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(CFG_SECURITY_PROFILE, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->id.profile = DEFAULT_SECURITY_PROFILE_ID; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_configure_security_profile_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, + rw_packet, wr_packet_len, + NULL, 0, + NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto armor_configure_security_profile_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_configure_security_profile_exit_point; + } + status = __parse_read_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_configure_security_profile_exit_point; + } +armor_configure_security_profile_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_read_mc(mx78_armor_context *mx78_armor_ctx, + uint8_t mc_id, uint8_t *mc, + uint32_t mc_buf_size, uint32_t *mc_size) +{ + (void)mc_buf_size; + uint8_t rw_packet[PACKET_MAX_LEN]; + uint32_t wr_packet_len, rd_packet_len; + int32_t status = JEDEC_ERROR_NONE; + uint8_t mc_buf[ARMOR_MC_SIZE]; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(MC_READ, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->id.mc = mc_id; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + rw_packet, &wr_packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_mc_rd_exit_point; + } + status = mx78_armor_packet_send(mx78_armor_ctx, + rw_packet, wr_packet_len, + NULL, 0, + NULL, 0); + if (status != JEDEC_ERROR_NONE) { + goto armor_mc_rd_exit_point; + } + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_mc_rd_exit_point; + } + status = __parse_read_packet(oper_ctx, + mc_buf, ARMOR_MC_SIZE, + NULL, 0, + rw_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto armor_mc_rd_exit_point; + } + *mc_size = ARMOR_MC_SIZE; + memcpy(mc, mc_buf, ARMOR_MC_SIZE); +armor_mc_rd_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +/** + * \brief Pre-processing of creating session. + * + * \param[in] mx78_armor_ctx MX78 ArmorFlash context + * \param[in] nonce_in Input nonce + * \param[in] nonce_in_len Input nonce length + * \param[out] resp_queue Response queue + * + * \return JEDEC_ERROR_NONE if successful, + * JEDEC_ERROR_XX if failed + */ +static int32_t mx78_armor_pre_create_session(mx78_armor_context *mx78_armor_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + (void)resp_queue; + int32_t status; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + uint8_t session_status = SESSION_STATUS_ABUNDANT; + + /* check whether session has been exhausted */ + status = _armor_check_sessions_status(mx78_armor_ctx, &session_status, sizeof(session_status)); + if (status != JEDEC_ERROR_NONE) { + return status; + } + if (session_status == SESSION_STATUS_EXHAUST) { + return JEDEC_ERROR_MAX_SESSIONS_REACHED; + } + /*exchange nonce with secure flash*/ + status = _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); + if (status != JEDEC_ERROR_NONE) { + return status; + } + return status; +} + +static int32_t mx78_armor_create_session_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + uint32_t rd_packet_len; + int32_t status; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(CREATE_SESSION, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->crypto_key_id = root_key_id; + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + return status; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + /* get kdf info */ + __get_kdf_msg(root_key_id, mc, ARMOR_MC_SIZE, indicator); + /* prepare create session cmd packet*/ + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_create_session_exit_point; + } + return status; + +_armor_create_session_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_post_create_session(mx78_armor_context *mx78_armor_ctx, + uint32_t root_key_id, + uint32_t session_key_id, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + int32_t status; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + uint8_t rd_packet[PACKET_MAX_LEN]; + uint32_t rd_packet_len; + mx78_armor_security_operation_t *oper_ctx; + + mx78_armor_operation_lookup(CREATE_SESSION, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_create_session_exit_point; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_create_session_exit_point; + } + status = __parse_read_packet(oper_ctx, + NULL, 0, + NULL, 0, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_create_session_exit_point; + } + /*exchange nonce with secure flash*/ + status = _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_create_session_exit_point; + } + status = _armor_confirm_session(mx78_armor_ctx, session_key_id, resp_queue); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_create_session_exit_point; + } +_armor_post_create_session_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_pre_terminate_session(mx78_armor_context *mx78_armor_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + (void)resp_queue; + int32_t status; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + + /*exchange nonce with secure flash*/ + status = _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); + if (status != JEDEC_ERROR_NONE) { + return status; + } + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_terminate_session_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + (void)mx78_armor_ctx; + (void)indicator; + uint32_t rd_packet_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(TERMINATE_SESSION, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->crypto_key_id = session_key_id; + /* prepare create session cmd packet*/ + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_terminate_session_exit_point; + } + return status; + +_armor_terminate_session_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_post_terminate_session(mx78_armor_context *mx78_armor_ctx, + jqueue_t *resp_queue) +{ + (void)resp_queue; + int32_t status; + uint32_t rd_packet_len; + mx78_armor_security_operation_t *oper_ctx; + + mx78_armor_operation_lookup(TERMINATE_SESSION, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_terminate_session_exit_point; + } + + status = mx78_armor_packet_receive(mx78_armor_ctx, mx78_armor_ctx->scratchpad, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_terminate_session_exit_point; + } + status = __parse_read_packet(oper_ctx, + NULL, 0, + NULL, 0, + mx78_armor_ctx->scratchpad, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_terminate_session_exit_point; + } +_armor_post_terminate_session_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + + +static int32_t mx78_armor_pre_secure_init(mx78_armor_context *mx78_armor_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + (void)resp_queue; + int32_t status; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + + status = mx78_armor_health_test(mx78_armor_ctx); + if (status) { + return JEDEC_ERROR_INIT_FAIL; + } + status = mx78_armor_configure_security_profile(mx78_armor_ctx); + if (status != JEDEC_ERROR_NONE) { + return status; + } + /*exchange nonce with secure flash*/ + return _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); +} + +static int32_t mx78_armor_secure_init_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + (void)mx78_armor_ctx; + (void)root_key_id; + (void)indicator; + uint32_t rd_packet_len; + int32_t status; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(SECURE_INIT, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->crypto_key_id = root_key_id; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_init_packet_exit_point; + } + return status; + +_armor_secure_init_packet_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_post_secure_init(mx78_armor_context *mx78_armor_ctx, + jqueue_t *resp_queue) +{ + (void)resp_queue; + int32_t status; + uint32_t rd_packet_len; + uint8_t init_resp_buf[TMP_BUFFER_SIZE]; + mx78_armor_security_operation_t *oper_ctx; + + mx78_armor_operation_lookup(SECURE_INIT, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_secure_init_exit_point; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, mx78_armor_ctx->scratchpad, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_init_exit_point; + } + status = __parse_read_packet(oper_ctx, + init_resp_buf, oper_ctx->out_size, + NULL, 0, + mx78_armor_ctx->scratchpad, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_init_exit_point; + } +_armor_post_secure_init_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_pre_secure_uninit(mx78_armor_context *mx78_armor_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + (void)resp_queue; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + + /*exchange nonce with secure flash*/ + return _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); +} + +static int32_t mx78_armor_secure_uninit_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + (void)mx78_armor_ctx; + (void)root_key_id; + (void)packet; + (void)packet_len; + (void)indicator; + *packet_len = 0; + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_post_secure_uninit(mx78_armor_context *mx78_armor_ctx, + jqueue_t *resp_queue) +{ + (void)mx78_armor_ctx; + (void)resp_queue; + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_pre_secure_program(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, uint32_t session_key_id, + jqueue_t *resp_queue) +{ + (void)mx78_armor_ctx; + (void)addr; + (void)session_key_id; + (void)resp_queue; + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_secure_program_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, const uint8_t *data, + uint32_t len, uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + int32_t status; + uint32_t rd_packet_len; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(SECURITY_WRITE, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->addr = addr; + oper_ctx->in_data = data; + oper_ctx->in_size = len; + oper_ctx->crypto_key_id = session_key_id; + + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_program_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_program_exit_point; + } + /* get aead info */ + indicator->algorithm = ALG_AES_GCM_256; + indicator->property = PROP_ENCRYPT_TAG_DATA; + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + /* Prepare secure program packet without tag and ciphertext*/ + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, + &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_program_exit_point; + } + /* Make the pointers point to the packet buffer in advance */ + indicator->aead.key_id = session_key_id; + indicator->aead.key_len = 16; + indicator->aead.tag = &packet[*packet_len]; + indicator->aead.cipher_text = &packet[*packet_len + indicator->aead.tag_len]; + return status; + +_armor_secure_program_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + + +static int32_t mx78_armor_post_secure_program(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + (void)session_key_id; + (void)resp_queue; + (void)resp_packet_buffer_size; + uint8_t rd_packet[PACKET_MAX_LEN]; + uint32_t rd_packet_len; + int32_t status; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx; + + mx78_armor_operation_lookup(SECURITY_WRITE, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + indicator->property = PROP_AUTHEN_TAG_DECRYPT_DATA; + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_secure_program_exit_point; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_program_exit_point; + } + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_program_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_program_exit_point; + } + /* get aead info */ + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + /* Allocate buffer for AEAD information */ + indicator->aead.cipher_text = resp_packet_buffer; + indicator->aead.tag = resp_packet_buffer + indicator->aead.text_len; + indicator->aead.plain_text = resp_packet_buffer + indicator->aead.text_len + indicator->aead.tag_len; + status = __parse_read_packet(oper_ctx, + indicator->aead.cipher_text, indicator->aead.text_len, + indicator->aead.tag, (uint8_t)indicator->aead.tag_len, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_program_exit_point; + } +_armor_post_secure_program_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_parse_secure_program_response(mx78_armor_context *mx78_armor_ctx, + crypto_indicator_t *indicator, + uint32_t *bytes_programmed) +{ + (void)mx78_armor_ctx; + + if (__parse_secure_program_response(indicator->aead.plain_text, + (uint16_t)indicator->aead.text_len, + bytes_programmed) == JEDEC_ERROR_NONE) { + return JEDEC_ERROR_NONE; + } else { + return JEDEC_ERROR_COMM_FAIL; + } +} + + +static int32_t mx78_armor_pre_secure_read(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, uint32_t session_key_id, + jqueue_t *resp_queue) +{ + (void)mx78_armor_ctx; + (void)addr; + (void)session_key_id; + (void)resp_queue; + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_secure_read_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, uint32_t len, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + int32_t status; + uint32_t rd_packet_len; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx; + + if (!mx78_armor_operation_alloc(SECURITY_READ, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->addr = addr; + oper_ctx->out_size = len; + oper_ctx->crypto_key_id = session_key_id; + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_read_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_read_exit_point; + } + /* get aead info */ + indicator->algorithm = ALG_AES_GCM_256; + indicator->property = PROP_ENCRYPT_TAG_DATA; + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + /* Prepare secure read packet without tag and ciphertext*/ + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_read_exit_point; + } + /* Make the pointers point to the packet buffer in advance */ + indicator->aead.key_id = session_key_id; + indicator->aead.key_len = 16; + indicator->aead.tag = &packet[*packet_len]; + indicator->aead.cipher_text = &packet[*packet_len + indicator->aead.tag_len]; + return status; + +_armor_secure_read_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_post_secure_read(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + (void)resp_queue; + (void)resp_packet_buffer_size; + uint8_t rd_packet[PACKET_MAX_LEN]; + uint32_t rd_packet_len; + int32_t status; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx = NULL; + + mx78_armor_operation_lookup(SECURITY_READ, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + return JEDEC_ERROR_DEVICE_BUSY; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_read_exit_point; + } + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_read_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_read_exit_point; + } + indicator->algorithm = ALG_AES_GCM_256; + indicator->property = PROP_AUTHEN_TAG_DECRYPT_DATA; + /* get aead info */ + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + /* Allocate buffer for AEAD information */ + indicator->aead.key_id = session_key_id; + indicator->aead.key_len = 16; + indicator->aead.cipher_text = resp_packet_buffer; + indicator->aead.tag = resp_packet_buffer + indicator->aead.text_len; + indicator->aead.plain_text = resp_packet_buffer + indicator->aead.text_len + indicator->aead.tag_len; + + status = __parse_read_packet(oper_ctx, + indicator->aead.cipher_text, indicator->aead.text_len, + indicator->aead.tag, (uint8_t)indicator->aead.tag_len, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_read_exit_point; + } +_armor_post_secure_read_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_parse_secure_read_response(mx78_armor_context *mx78_armor_ctx, + crypto_indicator_t *indicator, + uint8_t *data, uint32_t data_len, + uint32_t *bytes_read) +{ + (void)mx78_armor_ctx; + + if (__parse_secure_read_response(indicator->aead.plain_text, + (uint16_t)indicator->aead.text_len, + data, data_len, bytes_read) == JEDEC_ERROR_NONE) { + return JEDEC_ERROR_NONE; + } else { + return JEDEC_ERROR_COMM_FAIL; + } +} + + +static int32_t mx78_armor_pre_secure_erase(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, uint32_t len, + uint32_t session_key_id, + jqueue_t *resp_queue) +{ + (void)resp_queue; + (void)mx78_armor_ctx; + (void)session_key_id; + uint32_t secure_erase_size; + + secure_erase_size = __secure_erase_min_size(); + if (secure_erase_size == 0) { + return JEDEC_ERROR_INV_ARGS; + } + if (((addr % secure_erase_size) != 0) || (((addr + len) % secure_erase_size) != 0)) { + return JEDEC_ERROR_INV_ARGS; + } + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_secure_erase_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t addr, uint32_t len, + uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + int32_t status; + uint32_t rd_packet_len; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx = NULL; + + if (!mx78_armor_operation_alloc(SECURITY_ERASE, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + oper_ctx->addr = addr; + oper_ctx->in_size = len; + oper_ctx->crypto_key_id = session_key_id; + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_erase_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_erase_exit_point; + } + indicator->algorithm = ALG_AES_GCM_256; + indicator->property = PROP_ENCRYPT_TAG_DATA; + /* get aead info */ + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_secure_erase_exit_point; + } + indicator->aead.key_id = session_key_id; + indicator->aead.key_len = 16; + indicator->aead.tag = &packet[*packet_len]; + indicator->aead.cipher_text = &packet[*packet_len + indicator->aead.tag_len]; + return status; + +_armor_secure_erase_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_post_secure_erase(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + (void)session_key_id; + (void)resp_queue; + (void)resp_packet_buffer_size; + uint8_t rd_packet[PACKET_MAX_LEN]; + uint32_t rd_packet_len; + int32_t status; + uint8_t mc[ARMOR_MC_SIZE]; + uint32_t actual_mc_size; + mx78_armor_security_operation_t *oper_ctx = NULL; + + mx78_armor_operation_lookup(SECURITY_ERASE, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + indicator->property = PROP_AUTHEN_TAG_DECRYPT_DATA; + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_secure_erase_exit_point; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_erase_exit_point; + } + /* get linked monotonic counter id */ + status = __get_linked_mc_id(oper_ctx); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_erase_exit_point; + } + status = mx78_armor_read_mc(mx78_armor_ctx, oper_ctx->id.mc, mc, + ARMOR_MC_SIZE, &actual_mc_size); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_erase_exit_point; + } + /* get aead info */ + if (__get_aead_msg(oper_ctx, indicator) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_INV_ARGS; + } + /* Allocate buffer for AEAD information */ + indicator->aead.cipher_text = resp_packet_buffer; + indicator->aead.tag = resp_packet_buffer + indicator->aead.text_len; + indicator->aead.plain_text = resp_packet_buffer + indicator->aead.text_len + indicator->aead.tag_len; + status = __parse_read_packet(oper_ctx, + indicator->aead.cipher_text, indicator->aead.text_len, + indicator->aead.tag, (uint8_t)indicator->aead.tag_len, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_secure_erase_exit_point; + } +_armor_post_secure_erase_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t mx78_armor_parse_secure_erase_response(mx78_armor_context *mx78_armor_ctx, + crypto_indicator_t *indicator) +{ + (void)mx78_armor_ctx; + + if (__parse_secure_erase_response(indicator->aead.plain_text, + indicator->aead.text_len) == JEDEC_ERROR_NONE) { + return JEDEC_ERROR_NONE; + } else { + return JEDEC_ERROR_COMM_FAIL; + } +} + +static int32_t mx78_armor_pre_get_region_info(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, + bool *session_key_valid_flag, + jqueue_t *resp_queue) +{ + (void)mx78_armor_ctx; + (void)resp_queue; + + __mx78_armor_check_session_key_id_validity(session_key_id, session_key_valid_flag); + return JEDEC_ERROR_NONE; +} + +static int32_t mx78_armor_get_region_info_packet(mx78_armor_context *mx78_armor_ctx, + uint32_t session_key_id, int8_t region_index, + uint8_t *nonce_in, uint32_t nonce_in_len, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + (void)indicator; + int32_t status; + uint32_t rd_packet_len; + uint8_t nonce_out[MAX_NONCE_SIZE]; + uint32_t actual_nonce_size; + mx78_armor_security_operation_t *oper_ctx = NULL; + + if (!mx78_armor_operation_alloc(SECURITY_GET_REGION_CONFIG, &oper_ctx)) { + return JEDEC_ERROR_INSUFFICIENT_MEMORY; + } + if (session_key_id == INVALID_SESSION_KEY_ID) { + oper_ctx->crypto_key_id = 0; + } else { + oper_ctx->crypto_key_id = session_key_id; + /*exchange nonce with secure flash*/ + status = _armor_generate_nonce(mx78_armor_ctx, nonce_in, nonce_in_len, + nonce_out, MAX_NONCE_SIZE, &actual_nonce_size); + if (status != JEDEC_ERROR_NONE) { + return status; + } + } + oper_ctx->id.region = region_index; + oper_ctx->out_size = CFG_SIZE_PER_REGION; + status = __prepare_write_packet(oper_ctx, + NULL, 0, + NULL, 0, + packet, packet_len, &rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_get_region_config_exit_point; + } +_armor_get_region_config_exit_point: + return status; +} + + +static int32_t mx78_armor_post_get_region_info(mx78_armor_context *mx78_armor_ctx, + region_ll_node_t *region_descr_p, + jqueue_t *resp_queue) +{ + uint8_t rd_packet[PACKET_MAX_LEN]; + uint32_t rd_packet_len; + uint8_t cfg[CFG_READ_SIZE_DEFAULT]; + uint8_t mac[MAC_SIZE]; + uint8_t resp_buf[MAX_RESP_SIZE]; + uint32_t actual_resp_len; + resp_param_t response; + int32_t status; + mx78_armor_security_operation_t *oper_ctx = NULL; + + mx78_armor_operation_lookup(SECURITY_GET_REGION_CONFIG, &oper_ctx); + if (oper_ctx == NULL) { + return JEDEC_ERROR_INV_ARGS; + } + __get_read_packet_size(oper_ctx, &rd_packet_len); + status = spi_nor_polling_for_out_ready(); + if (status) { + goto _armor_post_get_region_config_exit_point; + } + status = mx78_armor_packet_receive(mx78_armor_ctx, rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_get_region_config_exit_point; + } + oper_ctx->out_data = cfg; + if (oper_ctx->crypto_key_id != 0) { + status = __parse_read_packet(oper_ctx, + cfg, CFG_SIZE_PER_REGION, + mac, MAC_SIZE, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_get_region_config_exit_point; + } + /* Pack response packet */ + (void)__pack_response(oper_ctx, resp_buf, sizeof(resp_buf), &actual_resp_len); + /* Add response packet and mac to queue */ + response.alg = ALG_HMAC_SHA_256; + response.hmac.idata = resp_buf; + response.hmac.idata_len = (uint16_t)actual_resp_len; + response.hmac.mac = mac; + response.hmac.mac_len = MAC_SIZE; + queue_add(resp_queue, &response); + } else { + status = __parse_read_packet(oper_ctx, + cfg, CFG_SIZE_PER_REGION, + NULL, 0, + rd_packet, rd_packet_len); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_get_region_config_exit_point; + } + } + /* Return region's attributes */ + status = __parse_region_config(oper_ctx, region_descr_p); + if (status != JEDEC_ERROR_NONE) { + goto _armor_post_get_region_config_exit_point; + } +_armor_post_get_region_config_exit_point: + mx78_armor_operation_release(oper_ctx); + return status; +} + +static int32_t _check_major_header(uint8_t *provision_data_blob, + provision_major_header_t **major_header) +{ + *major_header = (provision_major_header_t *)provision_data_blob; + + SF_DBG_PR("major_header-magic: %c%c%c%c\r\n", + (*major_header)->magic[0],(*major_header)->magic[1], + (*major_header)->magic[2],(*major_header)->magic[3]); + SF_DBG_PR("major_header-major-version: %X\r\n", + (*major_header)->major_version); + SF_DBG_PR("major_header-minor-version: %X\r\n", + (*major_header)->minor_version); + SF_DBG_PR("major_header-total size: %X\r\n", + (*major_header)->total_size); + SF_DBG_PR("major_header-sub_header num: %X\r\n", + (*major_header)->sub_header_num); + if (memcmp((*major_header)->magic, "SFPI", 4) != 0) { + SF_ERR_PR("Check magic \"SFPI\" failed\r\n"); + return -1; + } + if (memcmp((*major_header)->id, macronix_mx78_info.id, macronix_mx78_info.id_len) != 0) { + return -1; + } + return 0; +} +#ifdef SECUREFLASH_PROVISION +static int32_t mx78_armor_provision_perform_and_verify(mx78_armor_context *mx78_armor_ctx, + uint8_t *provision_data, + uint32_t data_length) +{ + int32_t status; + provision_major_header_t *major_header = NULL; + uint8_t provision_data_buf[PROVISION_INFO_SIZE] = {}; + uint8_t vfy_provision_data_buf[PROVISION_INFO_SIZE] = {}; + uint32_t data_store_size = 0; + + if (provision_data == NULL) { + provision_data = PROVISIONING_BLOB; + data_length = sizeof(PROVISIONING_BLOB); + } + memcpy(provision_data_buf, provision_data, SFPI_MAJOR_HEADER_SIZE); + /* check major header */ + if (_check_major_header(provision_data_buf, &major_header) != 0) { + return JEDEC_ERROR_PROVISION; + } + status = mx78_armor_configure_security_profile(mx78_armor_ctx); + if (status != JEDEC_ERROR_NONE) { + return status; + } + status = mx78_armor_provision_perform(mx78_armor_ctx, provision_data, data_length, + provision_data_buf, &data_store_size); + if (status != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_PROVISION; + } + status = plat_store_secure_flash_provision_info(provision_data_buf, data_store_size); + if (status != 0) { + return JEDEC_ERROR_PROVISION; + } + status = plat_get_secure_flash_provision_info(vfy_provision_data_buf, data_store_size); + if (status != 0) { + return JEDEC_ERROR_PROVISION; + } + /* Read back provision data stored by above code line, and check whether + provision data has been stored successfully */ + if (memcmp(vfy_provision_data_buf, provision_data_buf, data_store_size) != 0) { + return JEDEC_ERROR_PROVISION; + } + return status; +} +#endif /* SECUREFLASH_PROVISION */ +static int32_t mx78_armor_provision_item_get_data(mx78_armor_context *mx78_armor_ctx, + provision_item_type_e item_type, + uint8_t *item_data_buf, + uint32_t item_data_buf_size, + uint8_t *item_data_num, + uint32_t *item_data_act_size) +{ + (void)mx78_armor_ctx; + int32_t status; + uint8_t provision_data_buf[PROVISION_INFO_SIZE] = {}; + uint32_t act_size = 0; + uint8_t i; + provision_major_header_t *major_header = NULL; + provision_sub_item_header_t *sub_header = NULL; + /* Get the major header of provisioning info*/ + status = plat_get_secure_flash_provision_info(provision_data_buf, SFPI_MAJOR_HEADER_SIZE); + if (0 != status) { + return JEDEC_ERROR_PROVISION; + } + major_header = provision_data_buf; + /* Check major header magic */ + if (memcmp(major_header->magic, "SFPI", 4) != 0) { + SF_ERR_PR("Provision info header magic check failed\r\n"); + return JEDEC_ERROR_GET_PROVISION_INFO; + } + act_size = major_header->total_size + sizeof(major_header->magic); + if (act_size > PROVISION_INFO_SIZE) { + return JEDEC_ERROR_INV_ARGS; + } + status = plat_get_secure_flash_provision_info(provision_data_buf, act_size); + if (JEDEC_ERROR_NONE != status) { + return JEDEC_ERROR_GET_PROVISION_INFO; + } + sub_header = provision_data_buf + SFPI_MAJOR_HEADER_SIZE; + switch (item_type) { + case ITEM_APP_INFO: + for (i = 0; i < major_header->sub_header_num; i++) { + if (sub_header->id == SUB_ID_APP_INFO) { + if (item_data_buf_size < sub_header->size) { + return JEDEC_ERROR_PROVISION; + } + *item_data_num = sub_header->num; + memcpy(item_data_buf, (uint8_t *)sub_header + SFPI_SUB_HEADER_SIZE, sub_header->size); + if (__parse_app_info(item_data_buf, sub_header->size, sub_header->num) != JEDEC_ERROR_NONE) { + return JEDEC_ERROR_GET_PROVISION_INFO; + } + *item_data_act_size = sub_header->size; + return JEDEC_ERROR_NONE; + } + /* Move to next sub-item header */ + sub_header = (uint8_t *)sub_header + SFPI_SUB_HEADER_SIZE + sub_header->size; + } + break; + /*TODO*/ + default: + break; + } + return JEDEC_ERROR_GET_PROVISION_INFO; +} + +flash_profile_t macronix_armor_mx78_profile = { + .security_feature.security_storage = SECURE_FLASH_SECURITY_STORAGE_CAP, + .architecture.regions_min_secure_erase_size = SECURE_FLASH_SECTOR_SIZE, + .architecture.secure_program_size = SECURE_FLASH_PROGRAM_SIZE, + .architecture.secure_read_size = SECURE_FLASH_READ_SIZE, + .architecture.secure_zone_number = SECURE_FLASH_ZONE_NUM, + .architecture.secure_zone_size = SECURE_FLASH_ZONE_SIZE, + .architecture.secure_zone_total_size = SECURE_FLASH_SIZE +}; + +vendor_security_op_t macronix_armor_mx78 = { + .vendor_id = 0x03, + .pre_create_session = mx78_armor_pre_create_session, + .create_session_packet = mx78_armor_create_session_packet, + .post_create_session = mx78_armor_post_create_session, +#if defined(SESSION_CONFIRMATION) + .pre_confirm_session = null, + .confirm_session_packet = null, + .post_confirm_session = null, +#endif + .pre_terminate_session = mx78_armor_pre_terminate_session, + .terminate_session_packet = mx78_armor_terminate_session_packet, + .post_terminate_session = mx78_armor_post_terminate_session, + .pre_secure_init = mx78_armor_pre_secure_init, + .secure_init_packet = mx78_armor_secure_init_packet, + .post_secure_init = mx78_armor_post_secure_init, + .pre_secure_uninit = mx78_armor_pre_secure_uninit, + .secure_uninit_packet = mx78_armor_secure_uninit_packet, + .post_secure_uninit = mx78_armor_post_secure_uninit, + .pre_secure_program = mx78_armor_pre_secure_program, + .secure_program_packet = mx78_armor_secure_program_packet, + .post_secure_program = mx78_armor_post_secure_program, + .parse_secure_program_response = mx78_armor_parse_secure_program_response, + .pre_secure_erase = mx78_armor_pre_secure_erase, + .secure_erase_packet = mx78_armor_secure_erase_packet, + .post_secure_erase = mx78_armor_post_secure_erase, + .parse_secure_erase_response = mx78_armor_parse_secure_erase_response, +#if defined(SECURE_COPY) + .pre_secure_copy = null, + .secure_copy_packet = null,//TODO:return not supported + .post_secure_copy = null, +#endif +#if defined(SECURE_READ) + .pre_secure_read = mx78_armor_pre_secure_read, + .secure_read_packet = mx78_armor_secure_read_packet, + .post_secure_read = mx78_armor_post_secure_read, + .parse_secure_read_response = mx78_armor_parse_secure_read_response, +#endif + .pre_secure_get_regions_info = mx78_armor_pre_get_region_info, + .secure_get_regions_info_packet = mx78_armor_get_region_info_packet, + .post_secure_get_regions_info = mx78_armor_post_get_region_info, +#if defined(SECURE_REGION_MANAGE) + .pre_secure_manage_region = null, + .secure_manage_region_packet = null, + .post_secure_manage_region = null, +#endif + .packet_send = mx78_armor_packet_send, + .packet_receive = mx78_armor_packet_receive, +}; + +vendor_provisioning_op_t macronix_armor_mx78_provisioning = { +#ifdef SECUREFLASH_PROVISION + .perform_and_verify = mx78_armor_provision_perform_and_verify, +#endif /* SECUREFLASH_PROVISION */ + .provision_item_get_data = mx78_armor_provision_item_get_data +}; + +extern crypto_wrapper_t mx78_armor_crypto_wrapper; + +const secure_flash_info_t macronix_mx78_info = { + "mx78u64xx", + {0xc2, 0x29, 0x17}, + 3, + .flash_profile = ¯onix_armor_mx78_profile, + .vendor_security_op = ¯onix_armor_mx78, + .vendor_provisioning_op = ¯onix_armor_mx78_provisioning, + .crypto_wrapper = &mx78_armor_crypto_wrapper, + &g_mx78_armor_ctx +}; diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.h new file mode 100644 index 00000000000..52a2caf428e --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _MX78_ARMOR_H_ +#define _MX78_ARMOR_H_ + +#include +#include "../../../JEDEC_security_HAL/vendor_security_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SF_WARN_PR +#define SF_DBG_PR +#define SF_DBG0_PR +#define SF_INFO_PR +#define SF_ERR_PR +#define SF_TMP_PR + +#define SESSION_STATUS_EXHAUST 0x00 +#define SESSION_STATUS_ABUNDANT 0x01 +#define SESSION_STATUS_EMPTY 0x02 +#define MAX_NONCE_SIZE 0x10 +#define MAC_SIZE 0x20 +#define MAX_RESP_SIZE 0x150 +#define SCRATCHPAD_SIZE 0x150 +/* Extended configure registers number */ +#define EX_CR_NUM 0x06 +/* The max number of concurrent operations */ +#define CONC_OPER_NUM 0x04 +/* Data region configure size */ +#define CFG_SIZE_PER_REGION 0x04 +#define INVALID_SESSION_KEY_ID (0) +/** + * MX78 ArmorFlash supported security operations definition + * + */ +typedef enum { + SECURITY_READ, /*!< Security read */ + SECURITY_WRITE, /*!< Security program */ + SECURITY_ERASE, /*!< Security erase */ + MC_INCREASEMENT, /*!< Increase Monotonic counter */ + MC_READ, /*!< Read Monotonic counter */ + GENERATE_NONCE, /*!< Generate nonce for cryptographic operations */ + READ_SESSION_STATUS, /*!< Read sessions status */ + CREATE_SESSION, /*!< Create new sessions */ + CONFIRM_SESSION, /*!< Session confirmation */ + TERMINATE_SESSION, /*!< Session termination */ + GEN_PRIV_KEY, /*!< Generate private key */ + GEN_PUB_KEY, /*!< Generate public key */ + EXPORT_PUB_KEY, /*!< Export public key */ + SYNC_HOST_PUB_KEY, /*!< Synchronize host public key */ + SYNC_SALT, /*!< Synchronize salt */ + GEN_ROOT_KEY, /*!< Generate root key */ + SECURITY_GET_REGION_CONFIG, + GET_CFG, /*!< Read configuration information */ + SET_CFG, + CFG_SECURITY_PROFILE,/*!< Configure security profile */ + SECURE_INIT, + SECURE_UNINIT, + HEALTH_TEST, + LOCK_DOWN /*!< Lock down */ +} mx78_armor_operation_type_t; + +enum { + OPER_NOT_IN_USE = 0, + OPER_IN_USE = 1, +}; + +#define PACKET_OUT 0 +#define PACKET_IN 1 + +typedef enum { + ITEM_DATA_CFG, + ITEM_MC_CFG, + ITEM_KEY_CFG, + ITEM_LKD_CFG, + ITEM_TOTAL_CFG, + ITEM_MC, + ITEM_KEY, + ITEM_EXTRA, +} mx78_armor_security_item_t; + +/** + * \struct mx78_armor_security_operation_t + * + * \brief The structure holding MX78 ArmorFlash security operations' context. + */ +typedef struct { + uint32_t in_use; + mx78_armor_operation_type_t type; /*!< Security operation type */ + uint8_t *in_data; /*!< Pointer to current security operation input data */ + uint32_t in_size; /*!< Input data size in bytes */ + uint8_t *out_data; /*!< Pointer to current security operation output data */ + uint32_t out_size; /*!< Output data size in bytes */ + uint32_t addr; /*!< The access address of current security operation */ + union { + uint8_t mc; /*!< Current security operation linked monotonic counter id */ + uint8_t profile; /*!< Current security operation linked security profile id */ + uint8_t region; /*!< Current security operation linked region id */ + uint32_t root_key; /*!< Current security operation linked root key id */ + } id; + uint32_t crypto_key_id; /*!< Current security operation linked crypto service key id */ +} mx78_armor_security_operation_t; + + +typedef struct { + uint8_t status_register; + uint8_t configure_register; + uint8_t configure_register_extend[EX_CR_NUM];//cr2 + uint8_t secure_register; +} registers_t; + + +typedef struct { + const char *name; + registers_t regs; + uint8_t scratchpad[SCRATCHPAD_SIZE]; +} mx78_armor_context; + +#ifdef __cplusplus +} +#endif + +#endif /* _MX78_ARMOR_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor_lib.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor_lib.h new file mode 100644 index 00000000000..53955fa448d --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/mx78_armor_lib.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _MX78_ARMOR_LIB_H_ +#define _MX78_ARMOR_LIB_H_ + +#include +#include +#include "../../../JEDEC_security_HAL/crypto_wrapper.h" +#include "../../../JEDEC_security_HAL/include/jedec_defs.h" +#include "mx78_armor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Check whether input session_key_id is valid. + * + * \param[in] session_key_id Input session_key_id + * \param[out] session_key_valid_flag Session key validity flag + * \return NULL + */ +void __mx78_armor_check_session_key_id_validity(uint32_t session_key_id, + bool *session_key_valid_flag); +/** + * \brief Get security item's access address and size. + * + * \param[in] item Security item type + * \param[out] addr Pointer to address + * \param[out] size Pointer to size + * \return JEDEC_ERROR_NONE on success, otherwise JEDEC_ERROR_XX + */ +int32_t __get_target_addr_and_size(mx78_armor_security_item_t item, + uint32_t *addr, uint32_t *size); +/** + * \brief Get the minimum size of secure erase operation. + * + * \return The minimum size of secure erase operation. + */ +uint32_t __secure_erase_min_size(void); +/** + * \brief Get security operation's Nonce size. + * + * \param[in] params Security operation parameters + * + * \return Size of the nonce + */ +uint8_t __get_nonce_size(mx78_armor_security_operation_t *oper_ctx); +/** + * \brief Get security operation's linked monotonic counter id. + * + * \param[in] params Security operation parameters + * + * \return Monotonic counter id + */ +int32_t __get_linked_mc_id(mx78_armor_security_operation_t *oper_ctx); + +/** + * \brief Get security operation's to-be-received packet size. + * + * \param[in] params Security operation parameters + * \param[out] rd_packet_len The size of to-be-received packet from secure Flash + * \return NULL + */ +void __get_read_packet_size(mx78_armor_security_operation_t *oper_ctx, + uint32_t *rd_packet_len); + +/** + * \brief Get the messages needed by AEAD cryptographic algorithm. + * + * \param[in] params Security operation parameters + * \param[out] indicator The cryptographic indicator of AEAD cryptographic algorithm + * + * \return JEDEC_ERROR_XX + */ +int32_t __get_aead_msg(mx78_armor_security_operation_t *oper_ctx, + crypto_indicator_t *indicator); +/** + * \brief Get the messages needed by key derivation function. + * + * \param[in] root_key_id The id of kdf's input root key + * \param[in] mc Pointer to the monotonic counter involved in key derivation + * \param[in] mc_size The size of monotonic counter + * \param[out] indicator The cryptographic indicator of key derivation operation + * \return JEDEC_ERROR_XX + */ +int32_t __get_kdf_msg(uint32_t root_key_id, + uint8_t *mc, uint32_t mc_size, + crypto_indicator_t *indicator); +/** + * \brief Prepare write packet to be sent to secure Flash. + * + * \param[in] params Structure containing security operation's parameters + * \param[in] buf Buffer containing ciphertext data + * \param[in] buf_size The size of ciphertext data i bytes + * \param[in] mac Buffer containing authentication code + * \param[in] mac_size The size of authentication code + * \param[out] wr_packet Pointer to write packet + * \param[out] wr_packet_len The size of write packet in bytes + * \param[out] rd_packet_len The size of read packet in bytes + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __prepare_write_packet(mx78_armor_security_operation_t *oper_ctx, + uint8_t *buf, uint32_t buf_size, + uint8_t *mac, uint8_t mac_size, + uint8_t *wr_packet, uint32_t *wr_packet_len, + uint32_t *rd_packet_len); + +/** + * \brief Pack the command packet to secure Flash. + * + * \param[in] ctx Secure flash context + * \param[in] type Command packet type + * \param[in] data Buffer holding command data + * \param[in] data_size The buffer size + * \param[out] tx_buffer Buffer to hold command packet + * \param[out] tx_buffer_len The actual command packet size in byte + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + +int32_t __packet_assemble(mx78_armor_context *ctx, uint8_t type, + uint8_t *data, uint32_t data_size, + uint8_t *tx_buffer, uint32_t *tx_buffer_len); +/** + * \brief Pack the to-be-authenticated response from secure Flash. + * + * \param[in] params Security operation's parameters + * \param[in] resp_buf Buffer to hold the response + * \param[in] resp_buf_size The size of resp_buf + * \param[out] actual_resp_len The actual packed response size in byte + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __pack_response(mx78_armor_security_operation_t *oper_ctx, + uint8_t *resp_buf, uint32_t resp_buf_size, + uint32_t *actual_resp_len); +/** + * \brief Parse secure Flash security configuration. + * + * \param[in] data_buf Buffer holding secure Flash security configuration + * \param[in] data_size The size of secure Flash security configuration + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_security_configuration(uint8_t *data_buf, uint32_t data_size); +/** + * \brief Parse read packet received from secure Flash. + * + * \param[in] params Structure containing security operation's parameters + * \param[out] buf Buffer to hold data parsed from read packet + * \param[in] buf_size The size of data buf + * \param[out] mac_buf Buffer to hold mac + * \param[in] mac_size The size of mac + * \param[in] rd_packet Pointer to read packet + * \param[in] rd_packet_len The size of read packet in bytes + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_read_packet(mx78_armor_security_operation_t *oper_ctx, + uint8_t *buf, uint32_t buf_size, + uint8_t *mac_buf, uint8_t mac_size, + uint8_t *rd_packet, uint32_t rd_packet_len); +/** + * \brief Parse region security description based on region configure. + * + * \param[in] oper_ctx Security operation's context + * \param[out] region_descr_p Pointer to region description link list node + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_region_config(mx78_armor_security_operation_t *oper_ctx, + region_ll_node_t *region_descr_p); +/** + * \brief Parse secure program response from secure Flash. + * + * \param[in] response_buffer Buffer containing response + * \param[in] response_buffer_size The size of response buffer + * \param[out] bytes_programmed The size of programmed data in byte + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_secure_program_response(uint8_t *response_buffer, + uint16_t response_buffer_size, + uint32_t *bytes_programmed); +/** + * \brief Parse secure erase response from secure Flash. + * + * \param[in] response_buffer Buffer containing response + * \param[in] response_buffer_size The size of response buffer + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_secure_erase_response(uint8_t *response_buffer, + uint32_t response_buffer_size); +/** + * \brief Parse secure read response from secure Flash. + * + * \param[in] response_buffer Buffer holding response + * \param[in] response_buffer_size The size of response buffer + * \param[out] data Buffer to hold data + * \param[out] data_len Buffer length + * \param[out] bytes_read The actual size of read data in byte + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_secure_read_response(uint8_t *response_buffer, + uint16_t response_buffer_size, + uint8_t *data, uint32_t data_len, + uint32_t *bytes_read); +/** + * \brief Parse app info. + * + * \param[in] app_data Buffer holding app data + * \param[in] info_size The size of app data + * \param[in] app_data_num App data item number + * + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ +int32_t __parse_app_info(uint8_t *app_data, uint32_t info_size, uint8_t app_data_num); + +#ifdef __cplusplus +} +#endif + +#endif /* _MX78_ARMOR_LIB_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/libmx78_armor_provision_lib.a b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/libmx78_armor_provision_lib.a new file mode 100644 index 00000000000..b7bb5f02f11 Binary files /dev/null and b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/libmx78_armor_provision_lib.a differ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/mx78_armor_provision.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/mx78_armor_provision.h new file mode 100644 index 00000000000..6c55efd3812 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/provisioning/mx78_armor_provision.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _MX78_ARMOR_PROVISION_H +#define _MX78_ARMOR_PROVISION_H + +#include +#include +#include "../mx78_armor.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * \file mx78_armor_provision.h + * + * \brief This file describes the structures of mx78 series secure Flash + * provisioning data template + */ + +#define PROVISION_INFO_SIZE 0x80 +/**The template structure of provisioning data blob +----------------------------------------------------------- +| Magic | +----------------------------------------------------------- +|Sub header num |Sub header size | Version | +----------------------------------------------------------- +|Provision_disable | ID2 |ID1 |ID0 | +| Reserved | Total size | +----------------------------------------------------------- +| Sub header 1:application info | /// app_info id; app_info num; each app_info size; app_info storage flag +----------------------------------------------------------- +| Detailed application info | /// app_info id; +| description | [app_id0, zone_id0, root_key_id0];[app_id1, zone_id1, root_key_id1] +----------------------------------------------------------- +| Sub header 2:key derivation info | /// key_info id; key_info num; each key_info size; key_info storage flag +----------------------------------------------------------- +| Detailed key derivation info | /// key_info id; key exchange type: 00:send key directly to the other party +| description | 01:DH +----------------------------------------------------------- +| Sub header 3:counter info | +----------------------------------------------------------- +| Detailed counter info | /// counter_info id; +| description | [counter_id0, counter_init_value0];[counter_id1, counter_init_value1] +----------------------------------------------------------- +| Sub header 4:configure info | /// configure_info id; configure_info num; each configure_info size; configure_info storage flag +----------------------------------------------------------- +| Detailed configure info | /// configure_info id; +| description | +----------------------------------------------------------- +| Sub header 5:lock info | /// lock_info id; lock_info num; each lock_info size; lock_info storage flag +----------------------------------------------------------- +| Detailed lock info | /// lock_info id; +| description | +----------------------------------------------------------- +As it doesn't need to store the whole provisioning data, the size of +provisioning data to be stored in memory is less than received provisioning data +blob's size. +The template structure of provisioning data in memory is similar to above +provisioning data blob's structure. + +The template structure of provisioning data stored in memory +----------------------------------------------------------- +| Magic | +----------------------------------------------------------- +|Sub header stored num |Sub header size | Version | +----------------------------------------------------------- +|Provision_disable | ID2 |ID1 |ID0 | +| Reserved | Total stored size | +----------------------------------------------------------- +| Sub header 1:application info | /// app_info id; app_info num; each app_info size; app_info storage flag +----------------------------------------------------------- +| Detailed application info | /// app_info id; +| description | [app_id0, zone_id0, root_key_id0];[app_id1, zone_id1, root_key_id1] +----------------------------------------------------------- +| Sub header 2:key derivation info | /// key_info id; key_info num; each key_info size; key_info storage flag +----------------------------------------------------------- +| Detailed key derivation info | /// key_info id; key exchange type: 00:send key directly to the other party +| description | 01:DH +----------------------------------------------------------- +| Sub header 3:lock info | /// lock_info id; lock_info num; each lock_info size; lock_info storage flag +----------------------------------------------------------- +| Detailed lock info | /// lock_info id; +| description | lock_type:counter/datazone/key/... +----------------------------------------------------------- +*/ + +#define ARMOR_APP_INFO_MAX_NUM 16 +#define ARMOR_LKD_INFO_MAX_NUM 8 +#define KEY_INFO_MAX_NUM 16 +#define MC_INFO_MAX_NUM 16 +#define MC_MAX_SIZE 4 +#define CFG_INFO_MAX_NUM 0x60 + +/** + * Sub items' header id of ArmorFlash provisioning information. + */ +typedef enum { + SUB_ID_DATA_CONFIG_INFO = 0, + SUB_ID_KEY_CONFIG_INFO = 1, + SUB_ID_CNT_CONFIG_INFO = 2, + SUB_ID_APP_INFO = 3, + SUB_ID_KEY_INFO = 4, + SUB_ID_MC_INFO = 5, + SUB_ID_LOCK_INFO = 6, + SUB_ID_MAX_NUMBER, +} SubHeaderId; + + +/** + * \struct provision_sub_item_header_t + * + * \brief Structure holding each sub item's header of ArmorFlash provisioning + * information. + */ +typedef struct { + uint32_t id: 8, /*!< Sub item's header id */ + num: 8, /*!< Sub item's number */ + size: 15, /*!< Sub item's size */ + store: 1; /*!< Sub item's storage flag */ +} provision_sub_item_header_t; + + +/** + * \struct provision_major_header_t + * + * \brief Structure holding the major header of ArmorFlash provisioning + * information. + */ +typedef struct { + uint8_t magic[4]; /*!< The magic bytes of this + provisioning information */ + uint32_t minor_version: 4, /*!< The version of this provisioning information */ + major_version: 4, + sub_header_num: 8, /*!< The number of this provisioning + information's sub headers */ + total_size: 16; /*!< The total size of this + provisioning information */ + uint8_t id[4]; /*!< The secure Flash id */ +} provision_major_header_t; + +#define SFPI_MAJOR_HEADER_SIZE (sizeof(provision_major_header_t)) +#define SFPI_SUB_HEADER_SIZE (sizeof(provision_sub_item_header_t)) + +/** + * \struct mx_app_data_t + * + * \brief Structure to store a certain application item's + * provisioning information. + */ +typedef struct { + uint32_t app_id; /*!< Application id */ + uint32_t key_id; /*!< Application binded crypto key id */ + uint32_t zone_id:8, /*!< Application binded security zone id */ + mc_id:8, /*!< Application binded monotonic counter id */ + reserved:16; +} mx_app_data_t; +/** + * \struct mx_app_info_t + * + * \brief Structure holding provisioning information for applications. + */ +typedef struct { + provision_sub_item_header_t header; + mx_app_data_t app_data[ARMOR_APP_INFO_MAX_NUM]; /*!< Buffer holding + application items' + provisioning + information */ +} mx_app_info_t; + +/** provision for lock_info + * + * DWORD 0: [07:00] ID, [31:08] reserved + * DWORD 1: [07:00] config_regs, [15:08] ind_key_lock, + * [23:16] ind_key_dis, [31:24] reserved + * DWORD 2: [15:00] datazone lock(bitwise), [31:16] provision (bitwise) + **/ + +/** + * \struct lock_info_t + * + * \brief Structure holding provisioning information for + * ArmorFlash's lock down configuration. + */ +typedef struct { + provision_sub_item_header_t header; + uint8_t lock_data[ARMOR_LKD_INFO_MAX_NUM]; /*!< Buffer holding lock + down information */ +} lock_info_t; + +/** provision for key_info + * + * DWORD 0: [07:00] ID, [15:08] key number, [31:16] Reserved + * key 0 + * DWORD 1: [31:00] key id + * DWORD 2: [31:00] key derive message + * DWORD 3: [07:00] key derive params suite, [23:08] key length (in bytes), + * [31:24] key inject type + * key 1 ~ (key number -1) + **/ +/** + * \struct key_data_t + * + * \brief Structure holding provisioning information used to derive a + * certain root key of ArmorFlash. + */ +typedef struct { + uint32_t key_id; /*!< Root key id */ + uint32_t derive_message; /*!< Specific information for root key + derivation */ + uint32_t key_derive_suite: 8, /*!< Key derivation cipher algorithm */ + key_exchange_type: 4, /*!< Key exchange type: DH or directly share to the other party */ + key_len: 8, /*!< Derived root key length in bytes */ + zone_id: 8, /*!< Corresponding */ + inject_type: 4; /*!< The mode of synchronizing ArmorFlash's + root key */ +} key_data_t; +/** + * \struct key_info_t + * + * \brief Structure holding provisioning information for ArmorFlash root keys + * derivation. + */ +typedef struct { + provision_sub_item_header_t header; + key_data_t key_data[KEY_INFO_MAX_NUM]; /*!< Buffer holding root keys' + provisioning information */ +} key_info_t; + +/** provision for mc_info + * + * DWORD 0: [07:00] ID, [15:08] mc number, [31:16] reserved + * mc 0 + * DWORD 1: [31:00] mc value + * mc 1 ~ (mc number -1) + **/ +typedef struct { + uint8_t value[MC_MAX_SIZE]; // power of two, '0' is not supported +} mc_data_t; +/** + * \struct mc_info_t + * + * \brief Structure holding ArmorFlash monotonic counters' provisioning + * information. + */ +typedef struct { + provision_sub_item_header_t header; + mc_data_t mc_data[MC_INFO_MAX_NUM]; /*!< Buffer holding monotonic counters' + provisioning information */ +} mc_info_t; + + +/** + * \struct config_info_t + * + * \brief Structure holding provisioning information used to configure ArmorFlash. + */ +typedef struct { + provision_sub_item_header_t header; + uint8_t config_data[CFG_INFO_MAX_NUM]; /*!< Buffer holding ArmorFlash + configuration' provisioning + information */ +} config_info_t; + +int32_t mx78_armor_provision_perform(mx78_armor_context *mx78_armor_ctx, + uint8_t *provision_data_blob, + uint32_t data_size, + uint8_t *provision_data_buf, + uint32_t *data_store_size); +#ifdef __cplusplus +} +#endif + +#endif /* _MX78_ARMOR_PROVISION_H */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/secureflash_layout.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/secureflash_layout.h new file mode 100644 index 00000000000..b74b3f50ebb --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/macronix/armorflash_mx78/secureflash_layout.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _SECUREFLASH_LAYOUT_H_ +#define _SECUREFLASH_LAYOUT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \brief Secure Flash name string. */ +#define SECURE_FLASH_NAME "mx78x64" +#define SECURE_FLASH_SECURITY_STORAGE_CAP (1) +#define SECURE_FLASH_SECTOR_SIZE (0x1000) /*!< The size of secure Flash's sector */ +#define SECURE_FLASH_ERASED_VALUE (0xFF) /*!< The erase value of secure Flash */ +#define SECURE_FLASH_PROGRAM_UNIT (0x01) /*!< The program unit of secure Flash */ +#define SECURE_FLASH_READ_UNIT (0x01) /*!< The read unit of secure Flash */ +#define SECURE_FLASH_PROGRAM_SIZE (0x100) /*!< The max data size of each secure program packet */ +#define SECURE_FLASH_READ_SIZE (0x100) /*!< The max data size of each secure read packet */ +#define SECURE_FLASH_SIZE (0x800000) +#define SECURE_FLASH_ZONE_SIZE (0x80000) +#define SECURE_FLASH_ZONE_NUM (SECURE_FLASH_SIZE / SECURE_FLASH_ZONE_SIZE) + +#define SECURE_FLASH_MAX_PUF_SIZE (0x20) +#define SECURE_FLASH_MAX_TRNG_SIZE (0x20) +#define SECURE_FLASH_MAX_MC_SIZE (4) +/** \brief If multi-client(or multi-application) isolation is defined, + * the number of clients, + * and the layout of secure Flash memory region should be defined. + * Here takes four applications for example. + */ +#if defined(MULTI_CLIENT_ISOLATION) /*!< Enable multi-client isolation */ +/* multi-client secure flash layout*/ +/* Negative client id stands for clients from nspe; + * Positive client id stands for clients from spe */ +#define SECURE_FLASH_CLIENT_NUM (3) +#define SECURE_FLASH_CLIENT0_ID (-2) /*!< Client id 0:0xfffffffe */ +#define SECURE_FLASH_CLIENT0_AREA_START_ADDR (0) /*!< Start address of security memory region allocated for Client id 0 */ +#define SECURE_FLASH_CLIENT0_AREA_SIZE (SECURE_FLASH_ZONE_SIZE) /*!< The size of security memory region allocated for Client id 0 */ +#define SECURE_FLASH_CLIENT0_SECTORS_PER_BLOCK (4) +#if (SECURE_FLASH_CLIENT_NUM > 1) +#define SECURE_FLASH_CLIENT1_ID (-3) /*!< Client id 1:0xfffffffd */ +#define SECURE_FLASH_CLIENT1_AREA_START_ADDR (SECURE_FLASH_CLIENT0_AREA_START_ADDR + SECURE_FLASH_CLIENT0_AREA_SIZE) /*!< Start address of security memory region allocated for Client id 1 */ +#define SECURE_FLASH_CLIENT1_AREA_SIZE (SECURE_FLASH_ZONE_SIZE) /*!< The size of security memory region allocated for Client id 1 */ +#define SECURE_FLASH_CLIENT1_SECTORS_PER_BLOCK (4) +#endif +#if (SECURE_FLASH_CLIENT_NUM > 2) +#define SECURE_FLASH_CLIENT2_ID (3002) /*!< Client id 2:0xbba */ +#define SECURE_FLASH_CLIENT2_AREA_START_ADDR (SECURE_FLASH_CLIENT1_AREA_START_ADDR + SECURE_FLASH_CLIENT1_AREA_SIZE) /*!< Start address of security memory region allocated for Client id 2 */ +#define SECURE_FLASH_CLIENT2_AREA_SIZE (SECURE_FLASH_ZONE_SIZE) /*!< The size of security memory region allocated for Client id 2 */ +#define SECURE_FLASH_CLIENT2_SECTORS_PER_BLOCK (4) +#endif +#if (SECURE_FLASH_CLIENT_NUM > 3) +#define SECURE_FLASH_CLIENT3_ID (3006) /*!< Client id 3:0xbbe */ +#define SECURE_FLASH_CLIENT3_AREA_START_ADDR (SECURE_FLASH_CLIENT2_AREA_START_ADDR + SECURE_FLASH_CLIENT2_AREA_SIZE) /*!< Start address of security memory region allocated for Client id 3 */ +#define SECURE_FLASH_CLIENT3_AREA_SIZE (SECURE_FLASH_ZONE_SIZE) /*!< The size of security memory region allocated for Client id 3 */ +#define SECURE_FLASH_CLIENT3_SECTORS_PER_BLOCK (4) +#endif +#endif +/* Multi client isolation disabled */ +#define SECURE_FLASH_START_ADDR (0) /*!< Start address of secure Flash's security memory region */ +#define SECURE_FLASH_DEFAULT_CLIENT_AREA_SIZE (SECURE_FLASH_ZONE_SIZE *2) /*!< Default client area size equals secure zone size */ +#define SECURE_FLASH_SECTORS_PER_BLOCK (4) /*!< The number of sectors of per secure Flash block */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SECUREFLASH_LAYOUT_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_provisioning_impl.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_provisioning_impl.h new file mode 100644 index 00000000000..e10b25645b2 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_provisioning_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ + +#ifndef _VENDOR_PROVISIONING_IMPL_H_ +#define _VENDOR_PROVISIONING_IMPL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* secure Flash provisioning error definition */ +#define JEDEC_ERROR_PROVISION -0x2001 +#define JEDEC_ERROR_GET_PROVISION_INFO -0x2002 +#define JEDEC_ERROR_PROVISION_EXCHANGE_KEY -0x2003 +#define JEDEC_ERROR_PROVISION_SYNC_SALT -0x2004 +#define JEDEC_ERROR_PROVISION_GEN_ROOT_KEY -0x2005 + +typedef enum { + ITEM_APP_INFO, + ITEM_LKD_INFO, + LAST_ITEM_TYPE +}provision_item_type_e; + +/** + * \brief vendor specific provisioning operations + * + */ +typedef struct { + /** + * \brief Perform secure Flash provisioning and verify. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] provision_data Input provisioning data blob + * \param[in] data_length The size of input provisioning data blob in bytes + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*perform_and_verify)(void *vendor_ctx, + uint8_t *provision_data, + uint32_t data_length); + /** + * \brief Get secure Flash provisioning item data. + * + * \param[in] vendor_ctx The vendor specific secure Flash context + * \param[in] item_type Provisioning item type + * \param[in] provision_data_buf Buffer to store provisioning item data + * \param[in] provision_data_size Buffer size + * \param[out] item_data_num The number of item entries + * \param[out] provision_data_act_size Actual size of provisioning item data + * \return JEDEC_ERROR_NONE if successful, + * or a specific JEDEC_ERROR_XX error code + */ + int32_t (*provision_item_get_data)(void *vendor_ctx, + provision_item_type_e item_type, + uint8_t *provision_data_buf, + uint32_t provision_data_size, + uint8_t *item_data_num, + uint32_t *provision_data_act_size); +} vendor_provisioning_op_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_PROVISIONING_IMPL_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash.h new file mode 100644 index 00000000000..ae053d35800 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _VENDOR_SECUREFLASH_H_ +#define _VENDOR_SECUREFLASH_H_ + +#include "vendor_secureflash_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const secure_flash_info_t macronix_mx78_info; + +const secure_flash_info_t *flash_info[] = { + ¯onix_mx78_info, + /* Add secure flash info here */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_SECUREFLASH_H_ */ \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash_defs.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash_defs.h new file mode 100644 index 00000000000..dde3e784358 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_secureflash_defs.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _VENDOR_SECUREFLASH_DEFS_H +#define _VENDOR_SECUREFLASH_DEFS_H + +#include "../JEDEC_security_HAL/jedec_security_hal.h" +#include "vendor_provisioning_impl.h" +#include "secureflash_layout.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SECURE_FLASH_MAX_ID_LEN 6 + +/*! + * \struct security_feature_t + * + * \brief Structure to store the security features of secure Flash. + */ +typedef struct { + uint32_t security_storage: 1, /*!< Support security storage of data */ + rpmc: 1, /*!< Support replay protection monotonic counter */ + uid: 1, /*!< Support unique id */ + rng: 1, /*!< Support random number generator */ + puf: 1, /*!< Support physical unclonable function */ + reserved: 27; /*!< Reserved */ +} security_feature_t; + +/*! + * \struct cipher_suite_t + * + * \brief Structure to store the cipher suites of secure Flash. + */ +typedef struct { + uint32_t key_exchange_alg: 8, /*!< Key exchange algorithm */ + key_derive_alg: 8, /*!< Key derivation algorithm */ + encryption_alg: 8, /*!< Encryption algorithm */ + signature_alg:8; /*!< Signature algorithm */ +} cipher_suite_t; + +/*! + * \struct key_size_t + * + * \brief Structure to store secure Flash various keys' size. + */ +typedef struct { + uint32_t session_key_size: 16, + private_key_size: 16; + uint32_t public_key_size: 16, + preshare_key_size: 16; + uint32_t salt_key_size: 16, + root_key_size: 16; + uint32_t rpmc_root_key_size: 16, + rpmc_hmac_key_size: 16; +} key_size_t; + +/*! + * \struct architecture_t + * + * \brief Structure to store secure Flash architecture. + */ +typedef struct { + uint8_t erase_value; + uint32_t secure_read_size; /*!< Security read size in bytes */ + uint32_t secure_program_size; /*!< Security program size in bytes */ + uint32_t secure_erase_size[4]; /*!< Security erase size in bytes */ + uint32_t regions_min_secure_erase_size; /*!< Minimum security erase size in bytes */ + uint32_t sector_size; + uint32_t secure_zone_number; /*!< Secure data zone number */ + uint32_t secure_zone_size; /*!< Individual data zone size */ + uint32_t secure_zone_total_size; /*!< Whole data zones size */ +} architecture_t; + +/*! + * \struct flash_profile_t + * + * \brief Structure to store secure Flash profile. + */ +typedef struct { + security_feature_t security_feature; /*!< Secure Flash security features */ + cipher_suite_t cipher_suite; /*!< Secure Flash cipher suites */ + key_size_t key_size; /*!< Secure Flash keys size */ + architecture_t architecture; /*!< Secure Flash architecture */ +} flash_profile_t; + + + /*! + * \struct secure_flash_info_t + * + * \brief Structure to store secure Flash specific information. + */ +typedef struct { + char *name; /*! Secure Flash name */ + uint8_t id[SECURE_FLASH_MAX_ID_LEN]; /*! Secure Flash ID */ + uint8_t id_len; /*! Secure Flash ID length */ + flash_profile_t *flash_profile; + vendor_security_op_t *vendor_security_op; /*! Vendor specific security operations */ + vendor_provisioning_op_t *vendor_provisioning_op; /*! Vendor specific secure Flash provisioning operations */ + crypto_wrapper_t *crypto_wrapper; /*! Vendor specific crypto wrapper functions */ + void *vendor_ctx; /*! Vendor specific context */ +} secure_flash_info_t; + +extern const secure_flash_info_t macronix_mx78_info; + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_SECUREFLASH_DEFS_H */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.c new file mode 100644 index 00000000000..202ae8742d1 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 "vendor.h" +#include "../../vendor_secureflash_defs.h" + +extern crypto_wrapper_t vendor_crypto_wrapper; + +static int32_t vendor_secureflash_pre_create_session(vendor_secureflash_context *secureflash_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_create_session_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_create_session(vendor_secureflash_context *secureflash_ctx, + uint32_t root_key_id, + uint32_t *session_key_id, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +#if defined(SESSION_CONFIRMATION) +static int32_t vendor_secureflash_pre_confirm_session() +{ + //TODO + return 0; +} +static int32_t vendor_secureflash_confirm_session_packet() +{ + //TODO + return 0; +} +static int32_t vendor_secureflash_post_confirm_session() +{ + //TODO + return 0; +} +#endif + +static int32_t vendor_secureflash_pre_terminate_session(vendor_secureflash_context *secureflash_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_terminate_session_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, + uint8_t *packet,uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_terminate_session(vendor_secureflash_context *secureflash_ctx, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_pre_secure_init(vendor_secureflash_context *secureflash_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_init_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_init(vendor_secureflash_context *secureflash_ctx, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_pre_secure_uninit(vendor_secureflash_context *secureflash_ctx, + uint8_t *nonce_in, uint32_t nonce_in_len, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_uninit_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t root_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_uninit(vendor_secureflash_context *secureflash_ctx, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_pre_secure_program(vendor_secureflash_context *secureflash_ctx, uint32_t addr, + uint32_t session_key_id, jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_program_packet(vendor_secureflash_context *secureflash_ctx, uint32_t addr, + const uint8_t *data, uint32_t len, uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_program(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_parse_secure_program_response(vendor_secureflash_context *secureflash_ctx, + crypto_indicator_t *indicator, + uint32_t *bytes_programmed) +{ + //TODO + return 0; +} + +#if defined(SECURE_READ) +static int32_t vendor_secureflash_pre_secure_read(vendor_secureflash_context *secureflash_ctx, uint32_t addr, + uint32_t session_key_id, jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_read_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t addr, uint32_t len, uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_read(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_parse_secure_read_response(vendor_secureflash_context *secureflash_ctx, + crypto_indicator_t *indicator, + uint8_t *data, uint32_t data_len, + uint32_t *bytes_read) +{ + //TODO + return 0; +} +#endif + +static int32_t vendor_secureflash_pre_secure_erase(vendor_secureflash_context *secureflash_ctx, + uint32_t addr, uint32_t len, uint32_t session_key_id, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_erase_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t addr, uint32_t len, uint32_t session_key_id, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_erase(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, + uint8_t *resp_packet_buffer, + uint32_t *resp_packet_buffer_size, + crypto_indicator_t *indicator, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_parse_secure_erase_response(vendor_secureflash_context *secureflash_ctx, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +#if defined(SECURE_COPY) +static int32_t vendor_secureflash_pre_secure_copy() +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_copy_packet() +{ + //TODO + return 0; +} +static int32_t vendor_secureflash_post_secure_copy() +{ + //TODO + return 0; +} +#endif + +static int32_t vendor_secureflash_pre_get_region_info(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, bool *session_key_valid_flag, + jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_get_region_info_packet(vendor_secureflash_context *secureflash_ctx, + uint32_t session_key_id, int8_t region_index, + uint8_t *nonce_in, uint32_t nonce_in_len, + uint8_t *packet, uint32_t *packet_len, + crypto_indicator_t *indicator) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_get_region_info(vendor_secureflash_context *secureflash_ctx, + region_ll_node_t *region_descr_p, jqueue_t *resp_queue) +{ + //TODO + return 0; +} + +#if defined(SECURE_REGION_MANAGE) +static int32_t vendor_secureflash_pre_secure_manage_region() +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_secure_manage_region_packet() +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_post_secure_manage_region() +{ + //TODO + return 0; +} +#endif + +static int32_t vendor_secureflash_packet_send(vendor_secureflash_context *secureflash_ctx, + uint8_t *outdata, uint32_t outdata_len, + uint8_t *cipher_text, uint32_t cipher_text_len, + uint8_t *mac, uint32_t mac_len) +{ + //TODO + return 0; +} + +static int32_t vendor_secureflash_packet_receive(vendor_secureflash_context *secureflash_ctx, + uint8_t *indata, uint32_t indata_len) +{ + //TODO + return 0; +} + + +vendor_security_op_t vendor_secureflash = { + .vendor_id = VENOR_ID, + .pre_create_session = vendor_secureflash_pre_create_session, + .create_session_packet = vendor_secureflash_create_session_packet, + .post_create_session = vendor_secureflash_post_create_session, +#if defined(SESSION_CONFIRMATION) + .pre_confirm_session = vendor_secureflash_pre_confirm_session, + .confirm_session_packet = vendor_secureflash_confirm_session_packet, + .post_confirm_session = vendor_secureflash_post_confirm_session, +#endif + .pre_terminate_session = vendor_secureflash_pre_terminate_session, + .terminate_session_packet = vendor_secureflash_terminate_session_packet, + .post_terminate_session = vendor_secureflash_post_terminate_session, + .pre_secure_init = vendor_secureflash_pre_secure_init, + .secure_init_packet = vendor_secureflash_secure_init_packet, + .post_secure_init = vendor_secureflash_post_secure_init, + .pre_secure_uninit = vendor_secureflash_pre_secure_uninit, + .secure_uninit_packet = vendor_secureflash_secure_uninit_packet, + .post_secure_uninit = vendor_secureflash_post_secure_uninit, + + .pre_secure_program = vendor_secureflash_pre_secure_program, + .secure_program_packet = vendor_secureflash_secure_program_packet, + .post_secure_program = vendor_secureflash_post_secure_program, + .parse_secure_program_response = vendor_secureflash_parse_secure_program_response, + + .pre_secure_erase = vendor_secureflash_pre_secure_erase, + .secure_erase_packet = vendor_secureflash_secure_erase_packet, + .post_secure_erase = vendor_secureflash_post_secure_erase, + .parse_secure_erase_response = vendor_secureflash_parse_secure_erase_response, +#if defined(SECURE_COPY) + .pre_secure_copy = vendor_secureflash_pre_secure_copy, + .secure_copy_packet = vendor_secureflash_secure_copy_packet, + .post_secure_copy = vendor_secureflash_post_secure_copy, +#endif +#if defined(SECURE_READ) + .pre_secure_read = vendor_secureflash_pre_secure_read, + .secure_read_packet = vendor_secureflash_secure_read_packet, + .post_secure_read = vendor_secureflash_post_secure_read, + .parse_secure_read_response = vendor_secureflash_parse_secure_read_response, +#endif + .pre_secure_get_regions_info = vendor_secureflash_pre_get_region_info, + .secure_get_regions_info_packet = vendor_secureflash_get_region_info_packet, + .post_secure_get_regions_info = vendor_secureflash_post_get_region_info, +#if defined(SECURE_REGION_MANAGE) + .pre_secure_manage_region = vendor_secureflash_pre_secure_manage_region, + .secure_manage_region_packet = vendor_secureflash_secure_manage_region_packet, + .post_secure_manage_region = vendor_secureflash_post_secure_manage_region, +#endif + .packet_send = vendor_secureflash_packet_send, + .packet_receive = vendor_secureflash_packet_receive, +}; + +const secure_flash_info_t vendor_secure_flash_info = { + .id = {0xff, 0xff, 0xff}, + .id_len = 3, + .vendor_security_op = &vendor_secureflash, + .crypto_wrapper = &vendor_crypto_wrapper, +}; diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.h b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.h new file mode 100644 index 00000000000..370a1afd98a --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _VENDOR_H_ +#define _VENDOR_H_ + +#include "../../../JEDEC_security_HAL/vendor_security_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Define your macros here + * + */ +#define VENOR_ID 0xFF + +/** + * Secure Flash supported security operations definition + * + */ +typedef enum { + SECURITY_READ, /*!< Security read */ + SECURITY_WRITE, /*!< Security program */ + SECURITY_ERASE, /*!< Security erase */ + MC_INCREASEMENT, /*!< Increase monotonic counter */ + MC_READ, /*!< Read monotonic counter */ + GENERATE_NONCE, /*!< Generate random number */ + CREATE_SESSION, /*!< Session creation */ + CONFIRM_SESSION, /*!< Session confirmation */ + TERMINATE_SESSION, /*!< Session termination */ + GEN_ROOT_KEY, /*!< Generate root key */ + SECURITY_GET_REGION_CONFIG, /*!< Get region configure in security */ + CFG_SECURITY_PROFILE, /*!< Set secure Flash security profile */ + SECURE_INIT, /*!< Initialize in security */ + SECURE_UNINIT, /*!< Unitialize in security */ + LOCK_DOWN /*!< Lock down */ + /* Add secure Flash operations here */ + //TODO +} vendor_secureflash_operation_type_t; + +/** + * \struct vendor_secureflash_security_operation_t + * + * \brief The structure holding secure Flash security operations' context. + */ +typedef struct { +//TODO +} vendor_secureflash_security_operation_t; + + +/** + * \struct secureflash_registers_t + * + * \brief The structure holding secure Flash registers' value. + */ +typedef struct { +//TODO +} secureflash_registers_t; + + +typedef struct { + const char *name; + //TODO + /* Add vendor context members here */ +} vendor_secureflash_context; + +extern vendor_security_op_t vendor_secureflash; + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_H_ */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor_crypto_wrapper/vendor_crypto_wrapper.c b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor_crypto_wrapper/vendor_crypto_wrapper.c new file mode 100644 index 00000000000..2c5c46b896b --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/TG424_3/vendor_impl/vendor_template/vendor_crypto_wrapper/vendor_crypto_wrapper.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include "../../../JEDEC_security_HAL/crypto_wrapper.h" + +#define KEY_HANDLE_NOT_LOADED (0) +#define MAC_SIZE +#define TAG_LENGTH +#define MAX_ROOT_KEY_NUM +#define MAX_SESSION_KEY_NUM +#define MAC_KEY_SIZE +#define ENC_KEY_SIZE + + +typedef struct { + //TODO +}session_key_id_t; + + +static int crypto_wrapper_init(void) +{ + //TODO +} + +static int crypto_wrapper_deinit(void) +{ + //TODO +} + +static int crypto_wrapper_algorithm_support(int alg, int index) +{ + //TODO +} + +static int crypto_wrapper_crypto_func(crypto_indicator_t *indicator) +{ + //TODO +} +static int crypto_wrapper_kdf(crypto_indicator_t *indicator, + uint32_t *output_key_id) +{ + //TODO +} + +static int crypto_wrapper_generate_random(uint8_t *output, uint32_t output_size) +{ + //TODO +} + +static int crypto_wrapper_ecdh_gen_key_pair(crypto_indicator_t *indicator) +{ + //TODO +} + +static int crypto_wrapper_ecdh_gen_shared_secret(crypto_indicator_t *indicator) +{ + //TODO +} + +static int crypto_wrapper_open_key(uint32_t root_key_id) +{ + //TODO +} + +static int crypto_wrapper_close_key(uint32_t root_key_id) +{ + //TODO +} +static int crypto_wrapper_destroy_key(uint32_t key_id) +{ + //TODO +} + +static int crypto_wrapper_export_public_key(uint32_t key_id, uint8_t *key_buf, + uint32_t buf_size, uint32_t *actual_size) +{ + //TODO +} + +static int crypto_wrapper_export_key(uint32_t key_id, uint8_t *key_buf, + uint32_t buf_size, uint32_t *actual_size) +{ + //TODO +} + +static int crypto_wrapper_import_key(uint32_t *key_id, uint8_t *key_buf, + uint32_t key_size, KeyLifeTime lifetime) +{ + //TODO +} + +crypto_wrapper_t vendor_crypto_wrapper = { + .init = crypto_wrapper_init, + .deinit = crypto_wrapper_deinit, + .algorithm_support = crypto_wrapper_algorithm_support, + .crypto_func = crypto_wrapper_crypto_func, + .key_derive = crypto_wrapper_kdf, + .generate_random = crypto_wrapper_generate_random, + .ecdh_gen_key_pair = crypto_wrapper_ecdh_gen_key_pair, + .ecdh_gen_shared_secret = crypto_wrapper_ecdh_gen_shared_secret, + .open_key = crypto_wrapper_open_key, + .close_key = crypto_wrapper_close_key, + .destroy_key = crypto_wrapper_destroy_key, + .export_public_key = crypto_wrapper_export_public_key, + .export_key = crypto_wrapper_export_key, + .import_key = crypto_wrapper_import_key, +}; diff --git a/storage/blockdevice/COMPONENT_SECUREF/include/SECUREF/SecureFBlockDevice.h b/storage/blockdevice/COMPONENT_SECUREF/include/SECUREF/SecureFBlockDevice.h new file mode 100644 index 00000000000..c476cfa3605 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/include/SECUREF/SecureFBlockDevice.h @@ -0,0 +1,312 @@ +/* mbed Microcontroller Library + * Copyright (c) 2023 ARM Limited + * 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. + */ +#ifndef MBED_SECUREFLASH_BLOCK_DEVICE_H +#define MBED_SECUREFLASH_BLOCK_DEVICE_H + +#include "platform/SingletonPtr.h" +#include "drivers/SPI.h" +#include "drivers/DigitalOut.h" +#include "blockdevice/internal/SFDP.h" +#include "blockdevice/BlockDevice.h" + +#include "../../TG424_3/vendor_impl/vendor_secureflash_defs.h" + +#ifndef MBED_CONF_SECUREF_DRIVER_SPI_MOSI +#define MBED_CONF_SECUREF_DRIVER_SPI_MOSI NC +#endif +#ifndef MBED_CONF_SECUREF_DRIVER_SPI_MISO +#define MBED_CONF_SECUREF_DRIVER_SPI_MISO NC +#endif +#ifndef MBED_CONF_SECUREF_DRIVER_SPI_CLK +#define MBED_CONF_SECUREF_DRIVER_SPI_CLK NC +#endif +#ifndef MBED_CONF_SECUREF_DRIVER_SPI_CS +#define MBED_CONF_SECUREF_DRIVER_SPI_CS NC +#endif +#ifndef MBED_CONF_SECUREF_DRIVER_SPI_FREQ +#define MBED_CONF_SECUREF_DRIVER_SPI_FREQ 40000000 +#endif + +#define APP_INFO_MAX_NUM (0x10) + +/** Enum spif standard error codes + * + * @enum spif_bd_error + */ +enum securef_bd_error { + SECUREF_BD_ERROR_OK = 0, /*!< no error */ + SECUREF_BD_ERROR_DEVICE_ERROR = mbed::BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */ + SECUREF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */ + SECUREF_BD_ERROR_READY_FAILED = -4003, /* Wait for Memory Ready failed */ + SECUREF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */ + SECUREF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */ + SECUREF_BD_ERROR_DEVICE_UNSUPPORT = -4006, /* Device id match failed */ + SECUREF_BD_ERROR_PROVISION_FLASH = -4007, /* Provision secure flash failed */ + SECUREF_BD_ERROR_GET_PROVISION = -4007, /* Get the information of provision failed */ + SECUREF_BD_ERROR_ILLEGAL_ACCESS = -4008, /* Operation illegal */ + SECUREF_BD_ERROR_CREATE_SESSION = -4009, /* Create sessopm failed */ + SECUREF_BD_ERROR_TERMINATE_SESSION = -4010, /* Terminate sessopm failed */ + SECUREF_BD_ERROR_SECURE_READ = -4011, /* Secure read failed */ + SECUREF_BD_ERROR_SECURE_PROGRAM = -4012, /* Secure program failed */ + SECUREF_BD_ERROR_SECURE_ERASE = -4013, /* Secure erase failed */ + SECUREF_BD_ERROR_INVALID_PGM_PARAMS = -4014, /* Program command invalid arguments */ + SECUREF_BD_ERROR_INVALID_READ_PARAMS = -4015, /* Read command invalid arguments */ +}; + +/** + * app_data_t + * + * Structure to store the pre-provisioned application & secure zone binding information. + */ +typedef struct { + int32_t app_id; /*!< The id of applications */ + uint32_t key_id; /*!< The id of crypto root keys */ + uint32_t zone_id:8, /*!< The id of security zone id */ + mc_id:8, /*!< The id of monotonic counter */ + reserved:16; +} app_data_t; + +/** + * app_info_t + * + * Structure to store the pre-provisioned application information. + */ +typedef struct { + uint8_t id; /*!< The id of app info */ + uint8_t num; /*!< The number of app_data items */ + app_data_t app_data[APP_INFO_MAX_NUM]; /*!< The detailed app_data */ +} app_info_t; + +/** + * session_info_t + * + * Structure to store secure Flash session information. + */ +typedef struct{ + uint32_t key_id; /*!< Root key id */ + uint32_t session_key_id; /*!< Session key id */ + uint32_t session_id; /*!< Session id */ +} session_info_t; + +/** + * secureflash_t + * + * Structure indicating secure Flash API layer informations + */ +typedef struct { + uint32_t _init_ref_count; /*!< The initialization count of secure Flash */ + bool _is_initialized; /*!< Secure Flash initialization status */ + app_info_t app_info; /*!< The pre-provisioned application information of secure Flash */ + secure_flash_info_t flash_info; /*!< The specific secure Flash information */ +} secureflash_t; + +class SecureFBlockDevice : public mbed::BlockDevice { +public: + /** Creates a SecureFBlockDevice on a SPI bus specified by pins + * + * @param mosi SPI master out, slave in pin + * @param miso SPI master in, slave out pin + * @param sclk SPI clock pin + * @param csel SPI chip select pin + * @param freq Clock speed of the SPI bus (defaults to 40MHz) + * + * + */ + SecureFBlockDevice(PinName mosi = MBED_CONF_SECUREF_DRIVER_SPI_MOSI, + PinName miso = MBED_CONF_SECUREF_DRIVER_SPI_MISO, + PinName sclk = MBED_CONF_SECUREF_DRIVER_SPI_CLK, + PinName csel = MBED_CONF_SECUREF_DRIVER_SPI_CS, + int freq = MBED_CONF_SECUREF_DRIVER_SPI_FREQ); + + /** Initialize a block device + * + * @return SPIF_BD_ERROR_OK(0) - success + * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out + * SPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return SPIF_BD_ERROR_OK(0) - success + */ + virtual int deinit(); + + /** Desctruct SPIFBlockDevice + */ + ~SecureFBlockDevice() + { + deinit(); + } + + /** Read blocks from a block device + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return SPIF_BD_ERROR_OK(0) - success + * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + */ + virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size); + + /** Program blocks to a block device + * + * @note The blocks must have been erased prior to being programmed + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return SPIF_BD_ERROR_OK(0) - success + * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out + * SPIF_BD_ERROR_WREN_FAILED - Write Enable failed + */ + virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size); + + /** Erase blocks on a block device + * + * @note The state of an erased block is undefined until it has been programmed + * + * @param addr Address of block to begin erasing + * @param size Size to erase in bytes, must be a multiple of erase block size + * @return SPIF_BD_ERROR_OK(0) - success + * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out + * SPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size + */ + virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + + virtual int secure_read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id); + virtual int secure_program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id); + virtual int secure_erase(mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id); + virtual bd_size_t secure_zone_number() const; + virtual bd_size_t secure_zone_size() const; + + virtual mbed::bd_size_t get_read_size() const; + + /** Get the size of a programable block + * + * @return Size of a programable block in bytes + * @note Must be a multiple of the read size + */ + virtual mbed::bd_size_t get_program_size() const; + + /** Get the size of an erasable block + * + * @return Size of an erasable block in bytes + * @note Must be a multiple of the program size + */ + virtual mbed::bd_size_t get_erase_size() const; + + /** Get the size of minimal erasable sector size of given address + * + * @param addr Any address within block queried for erase sector size (can be any address within flash size offset) + * @return Size of minimal erase sector size, in given address region, in bytes + * @note Must be a multiple of the program size + */ + virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr) const; + + /** Get the value of storage byte after it was erased + * + * If get_erase_value returns a non-negative byte value, the underlying + * storage is set to that value when erased, and storage containing + * that value can be programmed without another erase. + * + * @return The value of storage when erased, or -1 if you can't + * rely on the value of erased storage + */ + virtual int get_erase_value() const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual mbed::bd_size_t size() const; + + /** Get the BlockDevice class type. + * + * @return A string representation of the BlockDevice class type. + */ + virtual const char *get_type() const; + +private: + /********************************/ + /* Calls to SPI Driver APIs */ + /********************************/ + + // Send set_frequency command to Driver + securef_bd_error _spi_set_frequency(int freq); + /********************************/ + + // Soft Reset Flash Memory + int _reset_flash_mem(); + + // Configure Write Enable in Status Register + int _set_write_enable(); + + // Wait on status register until write not-in-progress + bool _is_mem_ready(); + + // Query vendor ID and handle special behavior that isn't covered by SFDP data + int _handle_vendor_quirks(); + + // Probe secure flash + int _probe(); + + // Find the flash_info + int _find_flash_info(uint8_t *id); + + // Get the information of provision + int _secureflash_get_app_info(); + + // SPI protocol read + static int _spi_read(uint8_t *tx_buf, uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_len); + + // SPI protocol program + static int _spi_write(uint8_t *tx_buf, uint32_t tx_len); + + app_data_t *_query_app_info(mbed::bd_addr_t addr, int app_id); + +private: + // Master side hardware + static mbed::SPI *_spi; + + PinName _mosi; + PinName _miso; + PinName _sclk; + PinName _csel; + int _freq; + + // Mutex is used to protect Flash device for some SPI Driver commands that must be done sequentially with no other commands in between + // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready + static SingletonPtr _mutex; + + // Bus configuration + uint32_t _init_ref_count; + bool _is_initialized; + + // Struct for secure flash information + secureflash_t _secureflash; +}; + +#endif /* MBED_SECUREFLASH_BLOCK_DEVICE_H */ diff --git a/storage/blockdevice/COMPONENT_SECUREF/mbed_lib.json b/storage/blockdevice/COMPONENT_SECUREF/mbed_lib.json new file mode 100644 index 00000000000..a71093dbd20 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/mbed_lib.json @@ -0,0 +1,93 @@ +{ + "name": "securef-driver", + "config": { + "param1": { + "help": "Enable mbedtls based crypto wrapper", + "macro_name": "CRYPTO_MBEDTLS", + "value": 1 + }, + "param2": { + "help": "Enable provisioning flow", + "macro_name": "SECUREFLASH_PROVISION", + "value": 1 + }, + "param3": { + "help": "Enable test mode", + "macro_name": "MX78_ARMOR_TEST_MODE", + "value": 1 + }, + "SPI_MOSI": "SPI_MOSI", + "SPI_MISO": "SPI_MISO", + "SPI_CLK": "SPI_SCK", + "SPI_CS": "SPI_CS", + "SPI_FREQ": "40000000", + "debug": { + "help": "Enable debug logs. [0/1]", + "options" : [0, 1], + "value": 1 + } + }, + "target_overrides": { + "HANI_IOT": { + "SPI_MOSI": "P0_26", + "SPI_MISO": "P1_3", + "SPI_CLK": "P1_2", + "SPI_CS": "P0_20" + }, + "LPC54114": { + "SPI_MOSI": "P0_20", + "SPI_MISO": "P0_18", + "SPI_CLK": "P0_19", + "SPI_CS": "P1_2" + }, + "NRF52840_DK": { + "SPI_MOSI": "p20", + "SPI_MISO": "p21", + "SPI_CLK": "p19", + "SPI_CS": "p17" + }, + "HEXIWEAR": { + "SPI_MOSI": "PTD6", + "SPI_MISO": "PTD7", + "SPI_CLK": "PTD5", + "SPI_CS": "PTD4" + }, + "WIO_EMW3166": { + "SPI_MOSI": "PB_15", + "SPI_MISO": "PB_14", + "SPI_CLK": "PB_13", + "SPI_CS": "PA_10" + }, + "ADV_WISE_1570": { + "SPI_MOSI": "PA_7", + "SPI_MISO": "PA_6", + "SPI_CLK": "PA_5", + "SPI_CS": "PB_12", + "SPI_FREQ": "20000000" + }, + "UHURU_RAVEN": { + "SPI_MOSI": "PE_14", + "SPI_MISO": "PE_13", + "SPI_CLK": "PE_12", + "SPI_CS": "PE_11" + }, + "MTS_DRAGONFLY_F411RE": { + "SPI_MOSI": "SPI3_MOSI", + "SPI_MISO": "SPI3_MISO", + "SPI_CLK": "SPI3_SCK", + "SPI_CS": "SPI_CS1" + }, + "MTS_DRAGONFLY_F413RH": { + "SPI_MOSI": "SPI3_MOSI", + "SPI_MISO": "SPI3_MISO", + "SPI_CLK": "SPI3_SCK", + "SPI_CS": "SPI_CS1" + }, + "NUCLEO_L4R5ZI_P": { + "SPI_MOSI": "PA_7", + "SPI_MISO": "PA_6", + "SPI_CLK": "PA_1", + "SPI_CS": "PA_5" + } + } +} diff --git a/storage/blockdevice/COMPONENT_SECUREF/platform/include/plat_secure_flash.h b/storage/blockdevice/COMPONENT_SECUREF/platform/include/plat_secure_flash.h new file mode 100644 index 00000000000..7bd6d4c6a15 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/platform/include/plat_secure_flash.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _PLATFORM_IMPL_H_ +#define _PLATFORM_IMPL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t plat_store_secure_flash_provision_info(uint8_t *buffer, int size); +int32_t plat_get_secure_flash_provision_info(uint8_t *buffer, uint32_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _PLATFORM_IMPL_H_ */ \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/platform/plat_secure_flash.cpp b/storage/blockdevice/COMPONENT_SECUREF/platform/plat_secure_flash.cpp new file mode 100644 index 00000000000..40ef6b61cdd --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/platform/plat_secure_flash.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include "../include/plat_secure_flash.h" +#include "FlashIAPBlockDevice.h" + +#define PROVISION_INFO_SIZE 0x1000 + +static inline uint32_t align_up(uint32_t val, uint32_t size) +{ + return (((val - 1) / size) + 1) * size; +} + +int32_t plat_store_secure_flash_provision_info(uint8_t *buffer, int size) +{ +#if COMPONENT_FLASHIAP +#if (MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE == 0) && (MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS == 0xFFFFFFFF) + int status; + uint32_t actual_size = 0; + uint32_t bottom_addr, provision_start_addr, last_addr, erase_addr, program_addr; + + mbed::FlashIAP flash; + status = flash.init(); + if (0 != status) { + return -1; + } + //Find the start of first sector after text area + bottom_addr = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR)); + last_addr = flash.get_flash_start() + flash.get_flash_size(); + status = flash.deinit(); + if (0 != status) { + return -1; + } + FlashIAPBlockDevice iap_bd(bottom_addr, last_addr - bottom_addr); +#else + FlashIAPBlockDevice iap_bd; +#endif + provision_start_addr = last_addr - 1; + while (actual_size < PROVISION_INFO_SIZE) { + provision_start_addr -= flash.get_sector_size(provision_start_addr); + actual_size += flash.get_sector_size(provision_start_addr); + } + if ((provision_start_addr + 1) < bottom_addr) { + return -1; + } + provision_start_addr = provision_start_addr - bottom_addr + 1; + + status = iap_bd.init(); + if (0 != status) { + printf("Error : iap init failed.\r\n"); + return -1; + } + erase_addr = provision_start_addr; + while (erase_addr < (last_addr - bottom_addr)) { + status = iap_bd.erase(erase_addr, iap_bd.get_erase_size(erase_addr)); + if (0 != status) { + printf("Error : iap erase failed.\r\n"); + iap_bd.deinit(); + return -1; + } + erase_addr += iap_bd.get_erase_size(erase_addr); + } + program_addr = provision_start_addr; + while (size > 0) { + status = iap_bd.program(&buffer[program_addr - provision_start_addr], program_addr, iap_bd.get_program_size()); + if (0 != status) { + printf("Error : iap program failed.\r\n"); + iap_bd.deinit(); + return -1; + } + program_addr += iap_bd.get_program_size(); + size -= iap_bd.get_program_size(); + } + status = iap_bd.deinit(); + if (0 != status) { + printf("Error : iap deinit failed.\r\n"); + } + return 0; +#endif +} + +int32_t plat_get_secure_flash_provision_info(uint8_t *buffer, uint32_t size) +{ +#if COMPONENT_FLASHIAP +#if (MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE == 0) && (MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS == 0xFFFFFFFF) + int status; + uint32_t actual_size = 0; + uint32_t bottom_addr, provision_start_addr, last_addr, read_addr; + + mbed::FlashIAP flash; + status = flash.init(); + if (0 != status) { + return -1; + } + + //Find the start of first sector after text area + bottom_addr = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR)); + last_addr = flash.get_flash_start() + flash.get_flash_size(); + status = flash.deinit(); + if (0 != status) { + return -1; + } + FlashIAPBlockDevice iap_bd(bottom_addr, last_addr - bottom_addr); +#else + FlashIAPBlockDevice iap_bd; +#endif + + provision_start_addr = last_addr - 1; + while (actual_size < PROVISION_INFO_SIZE) { + provision_start_addr -= flash.get_sector_size(provision_start_addr); + actual_size += flash.get_sector_size(provision_start_addr); + } + if ((provision_start_addr + 1) < bottom_addr) { + return -1; + } + provision_start_addr = provision_start_addr - bottom_addr + 1; + + status = iap_bd.init(); + if (0 != status) { + printf("Error : iap init failed.\r\n"); + return -1; + } + + read_addr = provision_start_addr; + while (size > 0) { + status = iap_bd.read(&buffer[read_addr - provision_start_addr], read_addr, iap_bd.get_read_size()); + if (0 != status) { + printf("Error : iap read failed.\r\n"); + iap_bd.deinit(); + return -1; + } + read_addr += iap_bd.get_read_size(); + size -= iap_bd.get_read_size(); + } + + status = iap_bd.deinit(); + if (0 != status) { + printf("Error : iap deinit failed.\r\n"); + return -1; + } + return 0; +#endif +} \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/source/SecureFBlockDevice.cpp b/storage/blockdevice/COMPONENT_SECUREF/source/SecureFBlockDevice.cpp new file mode 100644 index 00000000000..89311e5f4e8 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/source/SecureFBlockDevice.cpp @@ -0,0 +1,540 @@ +/* mbed Microcontroller Library + * Copyright (c) 2023 ARM Limited + * 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 "SecureFBlockDevice.h" +#include "rtos/ThisThread.h" +#include "mbed_critical.h" + +#include +#include + +#include "mbed_trace.h" + +#include "../spi_nor_flash/spi_nor.h" +#include "../TG424_3/JEDEC_security_HAL/include/error.h" +#include "../TG424_3/JEDEC_security_HAL/include/jedec_defs.h" +#include "../TG424_3/JEDEC_security_HAL/jedec_security_hal.h" +#include "../TG424_3/vendor_impl/vendor_secureflash.h" + +#define TRACE_GROUP "SECUREF" +using namespace std::chrono; +using namespace mbed; + +// Status Register Bits +#define SPIF_STATUS_BIT_WIP 0x1 //Write In Progress +#define SPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch + +mbed::SPI *SecureFBlockDevice::_spi; +// Mutex is used for some SPI Driver commands that must be done sequentially with no other commands in between +// e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready +SingletonPtr SecureFBlockDevice::_mutex; + +//************************** +// SECUREF Block Device APIs +//************************** +SecureFBlockDevice::SecureFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq) + : + _mosi(mosi), _miso(miso), _sclk(sclk), _csel(csel), _freq(freq), + _is_initialized(false) +{} + +int SecureFBlockDevice::init() +{ + int status = SECUREF_BD_ERROR_OK; + + _mutex->lock(); + + if (!_is_initialized) { + _init_ref_count = 0; + } + + _init_ref_count++; + + if (_init_ref_count != 1) { + goto exit_point; + } + memset(&_secureflash, 0x00, sizeof (secureflash_t)); + + _spi = new (std::nothrow) mbed::SPI(_mosi, _miso, _sclk, _csel, use_gpio_ssel); + if (0 == _spi) { + tr_error("Allocation of mbed::SPI failed"); + goto exit_point; + } + if (SECUREF_BD_ERROR_OK != _spi_set_frequency(_freq)) { + tr_error("SPI Set Frequency Failed"); + goto exit_point; + } + if (0 != spi_nor_init(_spi_read, _spi_write)) { + status = SECUREF_BD_ERROR_DEVICE_ERROR; + goto exit_point; + } + // Soft Reset + if (0 != _reset_flash_mem()) { + tr_error("init - Unable to initialize flash memory, tests failed"); + status = SECUREF_BD_ERROR_DEVICE_ERROR; + goto exit_point; + } else { + tr_debug("Initialize flash memory OK"); + } + // Synchronize Device + if (0 != spi_nor_polling_for_wr_ready()) { + tr_error("init - spi_nor_polling_for_wr_ready Failed"); + status = SECUREF_BD_ERROR_READY_FAILED; + goto exit_point; + } + tr_debug("Probe secure flash"); + status = _probe(); + if (SECUREF_BD_ERROR_OK != status) { + goto exit_point; + } +#ifdef SECUREFLASH_PROVISION + tr_debug("Provision the secure flash"); + status = _secureflash.flash_info.vendor_provisioning_op->perform_and_verify(_secureflash.flash_info.vendor_ctx, + NULL, 0); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_PROVISION_FLASH; + goto exit_point; + } +#endif /* SECUREFLASH_PROVISION */ + tr_debug("Get the applicaition information"); + status = _secureflash_get_app_info(); + if (SECUREF_BD_ERROR_OK != status) { + goto exit_point; + } + tr_debug("Jedect secure init"); + status = jedec_secure_init(SECUREFLASH_AUTHEN_KEY_ID); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_DEVICE_ERROR; + goto exit_point; + } + _is_initialized = true; + tr_debug("Init successful"); +exit_point: + if (false == _is_initialized && 0 != _spi) { + delete _spi; + } + _mutex->unlock(); + return status; +} + +int SecureFBlockDevice::_probe() +{ + uint8_t vendor_device_ids[4]; + uint32_t data_length = 3; + + // Read Manufacturer ID (1byte), and Device ID (2bytes) + if (0 != spi_nor_read_id(vendor_device_ids, data_length)) { + tr_error("Read Vendor ID Failed"); + return SECUREF_BD_ERROR_DEVICE_ERROR; + } + + tr_debug("Vendor device ID = 0x%x 0x%x 0x%x", vendor_device_ids[0], vendor_device_ids[1], vendor_device_ids[2]); + + if (0 != _find_flash_info(vendor_device_ids)) { + return SECUREF_BD_ERROR_DEVICE_UNSUPPORT; + } + return SECUREF_BD_ERROR_OK; +} + +int SecureFBlockDevice::_find_flash_info(uint8_t *id) +{ + for (uint8_t i = 0; i < sizeof(flash_info); i++) { + if (!memcmp(id, flash_info[i]->id, flash_info[i]->id_len)) { + jedec_set_vendor(flash_info[i]->vendor_security_op, + flash_info[i]->crypto_wrapper, + flash_info[i]->vendor_ctx); + flash_info[i]->crypto_wrapper->init(); + memcpy(&_secureflash.flash_info, flash_info[i], sizeof(secure_flash_info_t)); + return 0; + } + } + return -1; +} + +int SecureFBlockDevice::_secureflash_get_app_info() +{ + int status = JEDEC_ERROR_NONE; + uint32_t actual_size; + vendor_provisioning_op_t *provision_op = _secureflash.flash_info.vendor_provisioning_op; + + status = provision_op->provision_item_get_data(_secureflash.flash_info.vendor_ctx, + ITEM_APP_INFO, + (uint8_t *)_secureflash.app_info.app_data, + sizeof(_secureflash.app_info.app_data), + &_secureflash.app_info.num, + &actual_size); + if (JEDEC_ERROR_NONE != status) { + return SECUREF_BD_ERROR_GET_PROVISION; + } + return SECUREF_BD_ERROR_OK; +} + +int SecureFBlockDevice::deinit() +{ + securef_bd_error status = SECUREF_BD_ERROR_OK; + + _mutex->lock(); + if (!_is_initialized) { + _init_ref_count = 0; + goto exit_point; + } + _init_ref_count--; + + if (_init_ref_count) { + goto exit_point; + } + _is_initialized = false; + +exit_point: + if (false == _is_initialized && 0 != _spi) { + delete _spi; + } + _mutex->unlock(); + return status; +} + +int SecureFBlockDevice::_spi_read(uint8_t *tx_buf, uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_len) +{ + _spi->select(); + + // Write/Read Data + for (uint32_t i = 0; i < tx_len; i++) { + _spi->write(tx_buf[i]); + } + for (uint32_t i = 0; i < rx_len; i++) { + rx_buf[i] = _spi->write(0); + } + + _spi->deselect(); + return 0; +} + +int SecureFBlockDevice::_spi_write(uint8_t *tx_buf, uint32_t tx_len) +{ + _spi->select(); + + // Write Data + for (uint32_t i = 0; i < tx_len; i++) { + _spi->write(tx_buf[i]); + } + + _spi->deselect(); + return 0; +} + +int SecureFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) +{ + return 0; +} + +int SecureFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) +{ + return 0; +} + +int SecureFBlockDevice::erase(bd_addr_t addr, bd_size_t size) +{ + return 0; +} + +app_data_t *SecureFBlockDevice::_query_app_info(mbed::bd_addr_t addr, int app_id) +{ + uint8_t zone_id = (uint8_t)(addr / SecureFBlockDevice::secure_zone_size()); + + for (int i = 0; i < _secureflash.app_info.num; i++) { + if ((_secureflash.app_info.app_data[i].app_id == app_id) && + (_secureflash.app_info.app_data[i].zone_id == zone_id)) { + return &(_secureflash.app_info.app_data[i]); + } + } + return NULL; +} + +int SecureFBlockDevice::secure_read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) +{ + int status = SECUREF_BD_ERROR_OK; + app_data_t *app_data; + uint32_t session_key_id, actual_read_size, offset, chunk, read_size = get_read_size(); + + if (!_is_initialized) { + return BD_ERROR_DEVICE_ERROR; + } + if (((uint32_t)(addr + size)) > SecureFBlockDevice::size()) { + return SECUREF_BD_ERROR_INVALID_PGM_PARAMS; + } + _mutex->lock(); + app_data = _query_app_info(addr, app_id); + if (NULL == app_data) { + status = SECUREF_BD_ERROR_ILLEGAL_ACCESS; + goto secure_read_exit_point; + } + status = jedec_create_session(app_data->key_id, 0, &session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_CREATE_SESSION; + goto secure_read_exit_point; + } + while (size > 0) { + offset = addr % read_size; + chunk = (offset + size < read_size) ? size : (read_size - offset); + status = jedec_secure_read(addr, (uint8_t *)buffer, chunk, session_key_id, &actual_read_size); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_SECURE_READ; + goto secure_read_exit_point; + } + size -= chunk; + addr += chunk; + buffer += chunk; + } + status = jedec_terminate_session(session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_TERMINATE_SESSION; + goto secure_read_exit_point; + } +secure_read_exit_point: + _mutex->unlock(); + return status; +} +int SecureFBlockDevice::secure_program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) +{ + int status = SECUREF_BD_ERROR_OK; + uint32_t session_key_id; + app_data_t *app_data; + uint32_t actual_program_size, chunk, offset, pgm_size = get_program_size(); + + if (!_is_initialized) { + return BD_ERROR_DEVICE_ERROR; + } + + if (((uint32_t)(addr + size)) > SecureFBlockDevice::size()) { + return SECUREF_BD_ERROR_INVALID_PGM_PARAMS; + } + _mutex->lock(); + app_data = _query_app_info(addr, app_id); + if (NULL == app_data) { + status = SECUREF_BD_ERROR_ILLEGAL_ACCESS; + goto secure_program_exit_point; + } + status = jedec_create_session(app_data->key_id, 0, &session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_CREATE_SESSION; + goto secure_program_exit_point; + } + while (size > 0) { + offset = addr % pgm_size; + chunk = (offset + size < pgm_size) ? size : (pgm_size - offset); + status = jedec_secure_program(addr, (uint8_t *)buffer, chunk, session_key_id, &actual_program_size); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_SECURE_PROGRAM; + goto secure_program_exit_point; + } + size -= chunk; + addr += chunk; + buffer += chunk; + } + status = jedec_terminate_session(session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_TERMINATE_SESSION; + goto secure_program_exit_point; + } +secure_program_exit_point: + _mutex->unlock(); + return status; +} + +int SecureFBlockDevice::secure_erase(mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) +{ + int status = SECUREF_BD_ERROR_OK; + app_data_t *app_data; + uint32_t session_key_id, ers_size = get_erase_size(); + + if (!_is_initialized) { + return BD_ERROR_DEVICE_ERROR; + } + if (((uint32_t)(addr + size)) > SecureFBlockDevice::size()) { + return SECUREF_BD_ERROR_INVALID_ERASE_PARAMS; + } + if ((addr % ers_size) || (size % ers_size)) { + return SECUREF_BD_ERROR_INVALID_ERASE_PARAMS; + } + _mutex->lock(); + app_data = _query_app_info(addr, app_id); + if (NULL == app_data) { + status = SECUREF_BD_ERROR_ILLEGAL_ACCESS; + goto secure_erase_exit_point; + } + status = jedec_create_session(app_data->key_id, 0, &session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_CREATE_SESSION; + goto secure_erase_exit_point; + } + while (size > 0) { + status = jedec_secure_erase((uint32_t)addr, ers_size, session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_SECURE_ERASE; + goto secure_erase_exit_point; + } + size -= ers_size; + addr += ers_size; + } + status = jedec_terminate_session(session_key_id); + if (JEDEC_ERROR_NONE != status) { + status = SECUREF_BD_ERROR_TERMINATE_SESSION; + goto secure_erase_exit_point; + } +secure_erase_exit_point: + _mutex->unlock(); + return status; +} + +bd_size_t SecureFBlockDevice::get_read_size() const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.secure_read_size; +} + +bd_size_t SecureFBlockDevice::get_program_size() const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.secure_program_size; +} + +bd_size_t SecureFBlockDevice::get_erase_size() const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.regions_min_secure_erase_size; +} + +// Find minimal erase size supported by the region to which the address belongs to +bd_size_t SecureFBlockDevice::get_erase_size(bd_addr_t addr) const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.regions_min_secure_erase_size; +} +bd_size_t SecureFBlockDevice::secure_zone_number() const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.secure_zone_number; +} + +bd_size_t SecureFBlockDevice::secure_zone_size() const +{ + if (!_is_initialized) { + return 0; + } + return _secureflash.flash_info.flash_profile->architecture.secure_zone_size; +} + +bd_size_t SecureFBlockDevice::size() const +{ + if (!_is_initialized) { + return 0; + } + + return _secureflash.flash_info.flash_profile->architecture.secure_zone_total_size; +} + +int SecureFBlockDevice::get_erase_value() const +{ + return 0xFF; +} + +const char *SecureFBlockDevice::get_type() const +{ + return "SECUREF"; +} + +/***************************************************/ +/*********** SPI Driver API Functions **************/ +/***************************************************/ +securef_bd_error SecureFBlockDevice::_spi_set_frequency(int freq) +{ + _spi->frequency(freq); + return SECUREF_BD_ERROR_OK; +} + +/*********************************************************/ +/********** SFDP Parsing and Detection Functions *********/ +/*********************************************************/ +int SecureFBlockDevice::_reset_flash_mem() +{ + // Perform Soft Reset of the Device prior to initialization + int status = 0; + uint8_t status_value[2] = {0}; + tr_info("_reset_flash_mem:"); + // Read the Status Register from device + if (0 == spi_nor_read_sr(status_value, 1)) { + // store received values in status_value + tr_debug("Reading Status Register Success: value = 0x%x", (int)status_value[0]); + } else { + tr_error("Reading Status Register failed"); + status = -1; + } + + if (0 == status) { + // Send Reset Enable + if (0 == spi_nor_reset_enable()) { + // store received values in status_value + tr_debug("Sending RSTEN Success"); + } else { + tr_error("Sending RSTEN failed"); + status = -1; + } + + if (0 == status) { + // Send Reset + if (0 == spi_nor_reset()) { + // store received values in status_value + tr_debug("Sending RST Success"); + } else { + tr_error("Sending RST failed"); + status = -1; + } + if (0 != spi_nor_polling_for_wr_ready()) { + tr_error("Device not ready, write failed"); + status = -1; + } + } + } + + return status; +} + +int SecureFBlockDevice::_handle_vendor_quirks() +{ + uint8_t vendor_device_ids[4]; + size_t data_length = 3; + + // Read Manufacturer ID (1byte), and Device ID (2bytes) + if (0 != spi_nor_read_id(vendor_device_ids, data_length)) { + tr_error("Read Vendor ID Failed"); + return -1; + } + + tr_debug("Vendor device ID = 0x%x 0x%x 0x%x", vendor_device_ids[0], vendor_device_ids[1], vendor_device_ids[2]); + + return 0; +} \ No newline at end of file diff --git a/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.c b/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.c new file mode 100644 index 00000000000..6e5cf63c9a5 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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 +#include +#include "spi_nor.h" + +#define STD_INST_PP 0x02 +#define STD_INST_READ 0x03 +#define STD_INST_ERASE_SECTOR 0x20 +#define STD_INST_RDSCUR 0x2B +#define STD_INST_RDCR 0x15 +#define STD_INST_RDCR2 0x71 +#define STD_INST_RDSR 0x05 +#define STD_INST_RDID 0x9F + +#define STD_INST_RSTEN 0x66 +#define STD_INST_RST 0x99 +#define STD_INST_RSTQPI 0xF5 + +#define STD_INST_WREN 0x06 +#define STD_INST_FREAD 0x0B +#define STD_INST_ENSO 0xB1 +#define STD_INST_EXSO 0xC1 + +/* status register definition */ +#define SR_WIP 0x01 +#define SR_WEL 0x02 +#define SR_QE 0x40 /* Quad-IO enable bit */ +#define SR_BP0 0x04 /* Block protect 0 */ +#define SR_BP1 0x08 /* Block protect 1 */ +#define SR_BP2 0x10 /* Block protect 2 */ +#define SR_BP3 0x20 /* Block protect 3 */ +#define SR_BP_BIT_OFFSET 2 /* Offset to Block protect 0 */ +#define SR_BP_BIT_MASK (SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0) +#define SR_SRWD 0x80 /* SR write protect */ + +#define SCUR_ORDY 0x10 /* Security packet output ready bit */ + +#define SUCCESS 0 +#define FAILURE -1 +#define BUFFER_SIZE 0x132 +#define MAX_POLLING_TIMES 1000 + +static spi_nor_t spi_nor = {}; + +static void wait_for_us(uint32_t microsec) +{ + //TODO +} + +static void wait_for_ms(uint32_t millisec) +{ + //TODO +} + +static void cmd_packing(nor_cmd_packet_t *cmd_packet) +{ + uint32_t send_packet_size = 0; + + cmd_packet->cmd_buffer.tx_buf[0] = cmd_packet->cmd; + send_packet_size++; + if (cmd_packet->addr_len > 0) { + memcpy(&cmd_packet->cmd_buffer.tx_buf[send_packet_size], cmd_packet->addr, cmd_packet->addr_len); + send_packet_size += cmd_packet->addr_len; + } + if (cmd_packet->dummy_len > 0) { + memset(&cmd_packet->cmd_buffer.tx_buf[send_packet_size], 0xFF, cmd_packet->dummy_len); + send_packet_size += cmd_packet->dummy_len; + } + if (cmd_packet->data != NULL) { + memcpy(&cmd_packet->cmd_buffer.tx_buf[send_packet_size], cmd_packet->data, cmd_packet->data_len); + send_packet_size += cmd_packet->data_len; + } + cmd_packet->cmd_buffer.tx_len = send_packet_size; +} + +int32_t spi_read(uint8_t *tx_buf, uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_len) +{ + spi_nor.read(tx_buf, tx_len, rx_buf, rx_len); + return 0; +} + +int32_t spi_write(uint8_t *tx_buf, uint32_t tx_len) +{ + spi_nor.write(tx_buf, tx_len); + return 0; +} + +int32_t spi_nor_reset_enable(void) +{ + spi_nor.cmd_packet.cmd = STD_INST_RSTEN; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.write(spi_nor.cmd_packet.cmd_buffer.tx_buf, spi_nor.cmd_packet.cmd_buffer.tx_len); +} + +int32_t spi_nor_reset(void) +{ + spi_nor.cmd_packet.cmd = STD_INST_RST; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.write(spi_nor.cmd_packet.cmd_buffer.tx_buf, spi_nor.cmd_packet.cmd_buffer.tx_len); + +} + +int32_t spi_nor_write_enable(void) +{ + spi_nor.cmd_packet.cmd = STD_INST_WREN; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.write(spi_nor.cmd_packet.cmd_buffer.tx_buf, spi_nor.cmd_packet.cmd_buffer.tx_len); +} + +int32_t spi_nor_write_disable(void) +{ + //TODO + return 0; +} + +int32_t spi_nor_read(uint8_t *buffer, uint32_t addr, uint32_t size) +{ + //TODO + return 0; +} + +int32_t spi_nor_program(uint8_t *buffer, uint32_t addr, uint32_t size) +{ + //TODO + return 0; +} + +int32_t spi_nor_erase(uint32_t addr, uint32_t size) +{ + //TODO + return 0; +} + +int32_t spi_nor_read_id(uint8_t *id, uint32_t size) +{ + spi_nor.cmd_packet.cmd = STD_INST_RDID; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.read(spi_nor.cmd_packet.cmd_buffer.tx_buf, + spi_nor.cmd_packet.cmd_buffer.tx_len, + id, size); +} + +int32_t spi_nor_read_sr(uint8_t *sr, uint32_t size) +{ + spi_nor.cmd_packet.cmd = STD_INST_RDSR; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.read(spi_nor.cmd_packet.cmd_buffer.tx_buf, + spi_nor.cmd_packet.cmd_buffer.tx_len, + sr, size); +} + +int32_t spi_nor_read_cr(uint8_t *cr, uint32_t size) +{ + spi_nor.cmd_packet.cmd = STD_INST_RDCR; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.read(spi_nor.cmd_packet.cmd_buffer.tx_buf, + spi_nor.cmd_packet.cmd_buffer.tx_len, + cr, size); +} + +int32_t spi_nor_read_cr2(uint8_t *cr, uint32_t size) +{ + //TODO + return 0; +} + +int32_t spi_nor_read_scur(uint8_t *scur, uint32_t size) +{ + spi_nor.cmd_packet.cmd = STD_INST_RDSCUR; + spi_nor.cmd_packet.addr_len = 0; + spi_nor.cmd_packet.dummy_len = 0; + spi_nor.cmd_packet.data = NULL; + cmd_packing(&spi_nor.cmd_packet); + return spi_nor.read(spi_nor.cmd_packet.cmd_buffer.tx_buf, + spi_nor.cmd_packet.cmd_buffer.tx_len, + scur, size); +} + +int32_t spi_nor_enter_secured_OTP(void) +{ + //TODO + return 0; +} + +int32_t spi_nor_exit_secured_OTP(void) +{ + //TODO + return 0; +} + +int32_t spi_nor_software_reset(void) +{ + if (spi_nor_reset_enable() != SUCCESS) { + return -1; + } + if (spi_nor_reset() != SUCCESS) { + return -1; + } + wait_for_ms(1);//stm32l562 hal driver not support us delay + return 0; +} + +int32_t spi_nor_polling_for_wr_ready(void) +{ + uint32_t cnt = 0; + uint8_t status_reg; + /* Polling for secure Flash ready for program */ + do { + cnt++; + if (spi_nor_read_sr(&status_reg, 1) != SUCCESS) { + return -1; + } + wait_for_ms(1); + } while ((status_reg & SR_WIP) && (cnt < MAX_POLLING_TIMES)); + + if (cnt >= MAX_POLLING_TIMES) { + return -1; + } + return 0; +} +int32_t spi_nor_polling_for_out_ready(void) +{ + uint32_t cnt = 0; + uint8_t status_reg, scur_reg; + + /* Polling for secure Flash ready for program */ + do { + cnt++; + if (spi_nor_read_scur(&scur_reg, 1) != SUCCESS) { + return -1; + } + if (spi_nor_read_sr(&status_reg, 1) != SUCCESS) { + return -1; + } + wait_for_ms(1); + } while (((status_reg & SR_WIP) || !(scur_reg & SCUR_ORDY)) && (cnt < MAX_POLLING_TIMES)); + + if (cnt >= MAX_POLLING_TIMES) { + return -1; + } + return 0; +} + +int32_t spi_nor_init(spi_read_t spi_read, spi_write_t spi_write) +{ + if (spi_read == NULL || spi_write == NULL) { + printf("ERROR: spi_ctx == NULL(%08X, %08X)\r\n", spi_read, spi_write); + } + spi_nor.read = spi_read; + spi_nor.write = spi_write; + + return 0; +} diff --git a/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.h b/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.h new file mode 100644 index 00000000000..64fe54147a5 --- /dev/null +++ b/storage/blockdevice/COMPONENT_SECUREF/spi_nor_flash/spi_nor.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2022-2023 Macronix International Co. LTD. All rights reserved. + * 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. + */ +#ifndef _SPI_NOR_H_ +#define _SPI_NOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define MAX_ADDR_LEN 4 +#define MAX_ID_LEN 6 +#define BUFFER_SIZE 0x132 + +typedef int (*spi_read_t)(uint8_t *tx_buf, uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_len); +typedef int (*spi_write_t)(uint8_t *tx_buf, uint32_t tx_len); + +struct nor_cmd_packet { + uint8_t cmd; + uint8_t addr[MAX_ADDR_LEN]; + uint8_t addr_len; + uint8_t dummy_len; + uint8_t *data; + uint32_t data_len; + struct { + uint8_t tx_buf[BUFFER_SIZE]; + uint32_t tx_len; + uint8_t rx_buf[BUFFER_SIZE]; + uint32_t rx_len; + } cmd_buffer; +}; + +struct spi_nor { + uint8_t id[MAX_ID_LEN]; + uint8_t read_dummy_cycle; + struct nor_cmd_packet cmd_packet; + spi_read_t read; + spi_write_t write; +}; + +typedef struct nor_cmd_packet nor_cmd_packet_t; +typedef struct spi_nor spi_nor_t; + +int32_t spi_read(uint8_t *tx_buf, uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_len); +int32_t spi_write(uint8_t *tx_buf, uint32_t tx_len); + +int32_t spi_nor_init(spi_read_t spi_read, spi_write_t spi_write); +/** + * \brief Enable software reset. + * + * \return: 0 on success, -1 if not + */ +int32_t spi_nor_reset_enable(void); +/** + * \brief Perform a software reset. + * + * \return: 0 on success, -1 if not + */ +int32_t spi_nor_reset(void); +/** + * \brief Set write enable latch. + * + * \return: 0 on success, -1 if not + */ +int32_t spi_nor_write_enable(void); +/** + * \brief Send write disable instruction to the chip. + * + * \return: 0 on success, -1 if not + */ +int32_t spi_nor_write_disable(void); +/** + * \brief Read data from flash. + * \param[in] buffer pointer to destination buffer + * \param[in] addr Address to read from + * \param[in] size Number of bytes to read + * \return: number of bytes read successfully, -1 otherwise + */ +int32_t spi_nor_read(uint8_t *buffer, uint32_t addr, uint32_t size); +/** + * \brief Write data to flash. + * \param[in] buffer Pointer to source buffer + * \param[in] addr Address to write to + * \param[in] size Number of bytes to write + * \return: number of bytes written successfully, -1 otherwise + */ +int32_t spi_nor_program(uint8_t *buffer, uint32_t addr, uint32_t size); +/** + * \brief Erase an address range on the nor chip. + * \param[in] addr Address to erase + * \param[in] size Erase size + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_erase(uint32_t addr, uint32_t size); +/** + * \brief Read the JEDEC ID. + * \param[in] id Pointer to buffer where the value of JEDEC ID will be written + * \param[in] size ID size + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_read_id(uint8_t *id, uint32_t size); +/** + * \brief Read the status register. + * \param[in] sr Pointer to buffer where the value of status register will be written + * \param[in] size SR size + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_read_sr(uint8_t *sr, uint32_t size); +/** + * \brief Read the configuration register. + * \param[in] cr Pointer to buffer where the value of configuration register will be written + * \param[in] size CR size + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_read_cr(uint8_t *cr, uint32_t size); +/** + * \brief Read the security register. + * \param[in] scur Pointer to buffer where the value of security register will be written + * \param[in] size SCUR size + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_read_scur(uint8_t *scur, uint32_t size); +/** + * \brief Enter secured OTP. + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_enter_secured_OTP(void); +/** + * \brief Exit secured OTP. + * \return: 0 on success, -1 otherwise + */ +int32_t spi_nor_exit_secured_OTP(void); +/** + * \brief Polling for nor flash ready for program. + * + * \return: 0 if flash is ready for program, -1 otherwise + */ +int32_t spi_nor_polling_for_wr_ready(void); +/** + * \brief Polling for nor flash ready for read. + * + * \return: 0 if flash is ready for read, -1 otherwise + */ +int32_t spi_nor_polling_for_out_ready(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _SPI_NOR_H_ */ diff --git a/storage/blockdevice/include/blockdevice/BlockDevice.h b/storage/blockdevice/include/blockdevice/BlockDevice.h index 688728e1a44..b026ea05129 100644 --- a/storage/blockdevice/include/blockdevice/BlockDevice.h +++ b/storage/blockdevice/include/blockdevice/BlockDevice.h @@ -139,6 +139,27 @@ class BlockDevice { return 0; } + virtual int secure_read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) + { + return -1; + } + virtual int secure_program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) + { + return -1; + } + virtual int secure_erase(mbed::bd_addr_t addr, mbed::bd_size_t size, int app_id) + { + return -1; + } + virtual bd_size_t secure_zone_number() const + { + return 0; + } + virtual bd_size_t secure_zone_size() const + { + return 0; + } + /** Get the size of a readable block * * @return Size of a readable block in bytes diff --git a/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/CMakeLists.txt b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/CMakeLists.txt index 29a242abb95..10301137edd 100644 --- a/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/CMakeLists.txt +++ b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/CMakeLists.txt @@ -38,6 +38,10 @@ if("SPIF" IN_LIST MBED_TARGET_LABELS) list(APPEND mbed_blockdevice_libs mbed-storage-spif) endif() +if("SECUREF" IN_LIST MBED_TARGET_LABELS) + list(APPEND mbed_blockdevice_libs mbed-storage-securef) +endif() + mbed_greentea_add_test( TEST_NAME ${TEST_TARGET} diff --git a/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/main.cpp b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/main.cpp index 11b3e11d447..b15c527a743 100644 --- a/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/main.cpp +++ b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/main.cpp @@ -28,6 +28,7 @@ #include "BufferedBlockDevice.h" #include "BlockDevice.h" #include +#include "mx78_armor2_provision_example.h" #if COMPONENT_SPIF #include "SPIFBlockDevice.h" @@ -57,6 +58,10 @@ #include "SPINANDBlockDevice.h" #endif +#if COMPONENT_SECUREF +#include "SecureFBlockDevice.h" +#endif + // Debug available #ifndef MODE_DEBUG #define MODE_DEBUG 0 @@ -97,10 +102,11 @@ enum bd_type { flashiap, ospif, spinand, + securef, default_bd }; -uint8_t bd_arr[6] = {0}; +uint8_t bd_arr[default_bd] = {0}; static uint8_t test_iteration = 0; @@ -238,6 +244,19 @@ static BlockDevice *get_bd_instance(uint8_t bd_type) #endif return &default_bd; +#endif + break; + } + case securef: { +#if COMPONENT_SECUREF + static SecureFBlockDevice default_bd( + MBED_CONF_SECUREF_DRIVER_SPI_MOSI, + MBED_CONF_SECUREF_DRIVER_SPI_MISO, + MBED_CONF_SECUREF_DRIVER_SPI_CLK, + MBED_CONF_SECUREF_DRIVER_SPI_CS, + MBED_CONF_SECUREF_DRIVER_SPI_FREQ + ); + return &default_bd; #endif break; } @@ -273,16 +292,43 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si write_block[i_ind] = 0xff & rand(); } // Write, sync, and read the block - DEBUG_PRINTF("test %0*llx:%llu...\n", addrwidth, block, curr_block_size); + DEBUG_PRINTF("test %llx:%llu...\n", addrwidth, block); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = block / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone %llx , SKIP!!!\n", block, access_zone_id); + _mutex->unlock(); + return; + } + err = block_device->secure_erase(block, curr_block_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); - err = block_device->erase(block, curr_block_size); - TEST_ASSERT_EQUAL(0, err); + err = block_device->secure_program(write_block, block, block_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); - err = block_device->program(write_block, block, block_size); - TEST_ASSERT_EQUAL(0, err); + err = block_device->secure_read(read_block, block, block_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { - err = block_device->read(read_block, block, block_size); - TEST_ASSERT_EQUAL(0, err); + err = block_device->erase(block, curr_block_size); + TEST_ASSERT_EQUAL(0, err); + + err = block_device->program(write_block, block, block_size); + TEST_ASSERT_EQUAL(0, err); + + err = block_device->read(read_block, block, block_size); + TEST_ASSERT_EQUAL(0, err); + } // Check that the data was unmodified srand(seed); @@ -406,6 +452,7 @@ void test_multi_threads() utest_printf("\nTest Multi Threaded Erase/Program/Read Starts..\n"); TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found."); + TEST_SKIP_UNLESS_MESSAGE(strcmp(block_device->get_type(), "SECUREF"), "Secure Flash currently does not support this type of test."); for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) { static const char *prefixes[] = {"", "k", "M", "G"}; @@ -575,44 +622,94 @@ void test_erase_functionality() uint8_t *out_data_buf = new (std::nothrow) uint8_t[data_buf_size]; TEST_SKIP_UNLESS_MESSAGE(out_data_buf != NULL, "Not enough memory for test"); - // First must Erase given memory region - utest_printf("erasing given memory region\n"); - int err = block_device->erase(start_address, data_buf_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; - // Write random data to selected region to make sure data is not accidentally set to "erased" value. - // With this pre-write, the test case will fail even if block_device->erase() is broken. - for (bd_size_t i = 0; i < data_buf_size; i++) { - data_buf[i] = (uint8_t) rand(); - } + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + // First must Erase given memory region + utest_printf("erasing given memory region\n"); + int err = block_device->secure_erase(start_address, data_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); - utest_printf("writing given memory region\n"); - err = block_device->program((const void *)data_buf, start_address, data_buf_size); - TEST_ASSERT_EQUAL(0, err); + // Write random data to selected region to make sure data is not accidentally set to "erased" value. + // With this pre-write, the test case will fail even if block_device->erase() is broken. + for (bd_size_t i = 0; i < data_buf_size; i++) { + data_buf[i] = (uint8_t) rand(); + } - // Read written memory region to verify it contains information - memset(out_data_buf, 0, data_buf_size); - utest_printf("reading written memory region\n"); - err = block_device->read((void *)out_data_buf, start_address, data_buf_size); - TEST_ASSERT_EQUAL(0, err); + utest_printf("writing given memory region\n"); + err = block_device->secure_program((const void *)data_buf, start_address, data_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); - // Verify erased memory region - utest_printf("verifying written memory region\n"); - for (bd_size_t i = 0; i < data_buf_size; i++) { - TEST_ASSERT_EQUAL(out_data_buf[i], data_buf[i]); - } + // Read written memory region to verify it contains information + memset(out_data_buf, 0, data_buf_size); + utest_printf("reading written memory region\n"); + err = block_device->secure_read((void *)out_data_buf, start_address, data_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); - // Erase given memory region - utest_printf("erasing written memory region\n"); - err = block_device->erase(start_address, data_buf_size); - TEST_ASSERT_EQUAL(0, err); + // Verify erased memory region + utest_printf("verifying written memory region\n"); + for (bd_size_t i = 0; i < data_buf_size; i++) { + TEST_ASSERT_EQUAL(out_data_buf[i], data_buf[i]); + } - // Read erased memory region - utest_printf("reading erased memory region\n"); - memset(out_data_buf, 0, data_buf_size); - err = block_device->read((void *)out_data_buf, start_address, data_buf_size); - TEST_ASSERT_EQUAL(0, err); + // Erase given memory region + utest_printf("erasing written memory region\n"); + err = block_device->secure_erase(start_address, data_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + // Read erased memory region + utest_printf("reading erased memory region\n"); + memset(out_data_buf, 0, data_buf_size); + err = block_device->secure_read((void *)out_data_buf, start_address, data_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + // First must Erase given memory region + utest_printf("erasing given memory region\n"); + int err = block_device->erase(start_address, data_buf_size); + TEST_ASSERT_EQUAL(0, err); + + // Write random data to selected region to make sure data is not accidentally set to "erased" value. + // With this pre-write, the test case will fail even if block_device->erase() is broken. + for (bd_size_t i = 0; i < data_buf_size; i++) { + data_buf[i] = (uint8_t) rand(); + } + + utest_printf("writing given memory region\n"); + err = block_device->program((const void *)data_buf, start_address, data_buf_size); + TEST_ASSERT_EQUAL(0, err); + + // Read written memory region to verify it contains information + memset(out_data_buf, 0, data_buf_size); + utest_printf("reading written memory region\n"); + err = block_device->read((void *)out_data_buf, start_address, data_buf_size); + TEST_ASSERT_EQUAL(0, err); + + // Verify erased memory region + utest_printf("verifying written memory region\n"); + for (bd_size_t i = 0; i < data_buf_size; i++) { + TEST_ASSERT_EQUAL(out_data_buf[i], data_buf[i]); + } + + // Erase given memory region + utest_printf("erasing written memory region\n"); + err = block_device->erase(start_address, data_buf_size); + TEST_ASSERT_EQUAL(0, err); + + // Read erased memory region + utest_printf("reading erased memory region\n"); + memset(out_data_buf, 0, data_buf_size); + err = block_device->read((void *)out_data_buf, start_address, data_buf_size); + TEST_ASSERT_EQUAL(0, err); + } // Verify erased memory region utest_printf("verifying erased memory region\n"); for (bd_size_t i = 0; i < data_buf_size; i++) { @@ -637,6 +734,7 @@ void test_contiguous_erase_write_read() // 3. Return step 2 for whole erase region // Test parameters + int err = 0; bd_size_t program_size = block_device->get_program_size(); TEST_ASSERT(program_size > 0); utest_printf("program_size=%" PRId64 "\n", program_size); @@ -679,8 +777,27 @@ void test_contiguous_erase_write_read() // Must Erase the whole region first utest_printf("erasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address, contiguous_erase_size); - int err = block_device->erase(start_address, contiguous_erase_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", start_address, access_zone_id); + } + err = block_device->secure_erase(start_address, contiguous_erase_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + int err = block_device->erase(start_address, contiguous_erase_size); + TEST_ASSERT_EQUAL(0, err); + } // Pre-fill the to-be-erased region. By pre-filling the region, // we can be sure the test will not pass if the erase doesn't work. @@ -694,14 +811,54 @@ void test_contiguous_erase_write_read() } DEBUG_PRINTF("pre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "", start_address + offset, write_read_buf_size); - err = block_device->program((const void *)write_read_buf, start_address + offset, write_read_buf_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", start_address, access_zone_id); + continue; + } + DEBUG_PRINTF("Test secure_program in zone %d\n", valid_zone_id); + err = block_device->secure_program((const void *)write_read_buf, start_address + offset, write_read_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + err = block_device->program((const void *)write_read_buf, start_address + offset, write_read_buf_size); + TEST_ASSERT_EQUAL(0, err); + } } // Erase the whole region again utest_printf("erasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address, contiguous_erase_size); - err = block_device->erase(start_address, contiguous_erase_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", start_address, access_zone_id); + } + err = block_device->secure_erase(start_address, contiguous_erase_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + err = block_device->erase(start_address, contiguous_erase_size); + TEST_ASSERT_EQUAL(0, err); + } // Loop through all write/read regions int region = 0; @@ -718,13 +875,55 @@ void test_contiguous_erase_write_read() } // Write test data - err = block_device->program((const void *)write_read_buf, start_address, write_read_buf_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", start_address, access_zone_id); + continue; + } + DEBUG_PRINTF("Test secure_program in zone %d\n", valid_zone_id); + err = block_device->secure_program((const void *)write_read_buf, start_address, write_read_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + err = block_device->program((const void *)write_read_buf, start_address, write_read_buf_size); + TEST_ASSERT_EQUAL(0, err); + } // Read test data memset(write_read_buf, 0, (size_t)write_read_buf_size); - err = block_device->read(write_read_buf, start_address, write_read_buf_size); - TEST_ASSERT_EQUAL(0, err); + if (!strcmp(block_device->get_type(), "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = start_address / block_device->secure_zone_size(); + int n; + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", start_address, access_zone_id); + continue; + } + DEBUG_PRINTF("Test secure_read in zone %d\n", valid_zone_id); + err = block_device->secure_read(write_read_buf, start_address, write_read_buf_size, valid_app_id); + TEST_ASSERT_EQUAL(0, err); + } else { + err = block_device->read(write_read_buf, start_address, write_read_buf_size); + TEST_ASSERT_EQUAL(0, err); + } // Verify read data srand(seed); @@ -746,6 +945,7 @@ void test_program_read_small_data_sizes() utest_printf("\nTest program-read small data sizes, from 1 to 7 bytes..\n"); TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found."); + TEST_SKIP_UNLESS_MESSAGE(strcmp(block_device->get_type(), "SECUREF"), "Secure Flash currently does not support this type of test."); bd_size_t program_size = block_device->get_program_size(); bd_size_t read_size = block_device->get_read_size(); @@ -803,6 +1003,7 @@ void test_unaligned_erase_blocks() TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found."); TEST_SKIP_UNLESS_MESSAGE(block_device->get_erase_value() != -1, "block device has no erase functionality."); + TEST_SKIP_UNLESS_MESSAGE(strcmp(block_device->get_type(), "SECUREF"), "Secure Flash currently does not support this type of test."); bd_addr_t addr = 0; bd_size_t sector_erase_size = block_device->get_erase_size(addr); @@ -856,6 +1057,7 @@ void test_deinit_bd() void test_write_deinit_init() { TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found."); + const char *bd_type = block_device->get_type(); // Determine start_address & stop_address bd_addr_t addr = sectors_addr[rand() % num_of_sectors]; bd_size_t erase_size = block_device->get_erase_size(addr); @@ -871,17 +1073,46 @@ void test_write_deinit_init() prog[j] = (uint8_t)'0' + i + j; } - int err; - err = block_device->erase(addr, erase_size); - TEST_ASSERT_EQUAL(err, 0); - err = block_device->program(prog, addr, prog_size); - TEST_ASSERT_EQUAL(err, 0); - err = block_device->deinit(); - TEST_ASSERT_EQUAL(0, err); - err = block_device->init(); - TEST_ASSERT_EQUAL(0, err); - err = block_device->read(buf, addr, prog_size); - TEST_ASSERT_EQUAL(0, memcmp(prog, buf, prog_size)); + int err, n; + if (!strcmp(bd_type, "SECUREF")) { + uint32_t valid_app_id, valid_zone_id; + bd_size_t access_zone_id = addr / block_device->secure_zone_size(); + + for (n = 0; n < AVAILABLE_PAIR_NUM; n++) { + if (access_zone_id == app_zone_available_pair[n].secure_zone_id) { + valid_app_id = app_zone_available_pair[n].app_id; + valid_zone_id = app_zone_available_pair[n].secure_zone_id; + break; + } + } + if (AVAILABLE_PAIR_NUM == n) { + utest_printf("Address %llx is not in the avaliable zone(%llu), SKIP!!!\n", addr, access_zone_id); + continue; + } + err = block_device->secure_erase(addr, erase_size, valid_app_id); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->secure_program(prog, addr, prog_size, valid_app_id); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->deinit(); + TEST_ASSERT_EQUAL(0, err); + err = block_device->init(); + TEST_ASSERT_EQUAL(0, err); + // err = block_device->secure_read(buf, addr, prog_size, app_id); + err = block_device->secure_read(buf, addr, prog_size, valid_app_id); + TEST_ASSERT_EQUAL(0, memcmp(prog, buf, prog_size)); + + } else { + err = block_device->erase(addr, erase_size); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->program(prog, addr, prog_size); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->deinit(); + TEST_ASSERT_EQUAL(0, err); + err = block_device->init(); + TEST_ASSERT_EQUAL(0, err); + err = block_device->read(buf, addr, prog_size); + TEST_ASSERT_EQUAL(0, memcmp(prog, buf, prog_size)); + } } free(prog); free(buf); @@ -911,6 +1142,8 @@ void test_get_type_functionality() TEST_ASSERT_EQUAL(0, strcmp(bd_type, "FLASHIAP")); #elif COMPONENT_SPINAND TEST_ASSERT_EQUAL(0, strcmp(bd_type, "SPINAND")); +#elif COMPONENT_SECUREF + TEST_ASSERT_EQUAL(0, strcmp(bd_type, "SECUREF")); #endif } @@ -975,11 +1208,14 @@ int get_bd_count() #if COMPONENT_SPINAND bd_arr[count++] = spinand; //6 #endif +#if COMPONENT_SECUREF + bd_arr[count++] = securef; //7 +#endif return count; } -static const char *prefix[] = {"SPIF ", "QSPIF ", "DATAFLASH ", "SD ", "FLASHIAP ", "OSPIF ", "SPINAND ", "DEFAULT "}; +static const char *prefix[] = {"SPIF ", "QSPIF ", "DATAFLASH ", "SD ", "FLASHIAP ", "OSPIF ", "SPINAND ", "SECUREF ", "DEFAULT "}; int main() { diff --git a/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/mx78_armor2_provision_example.h b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/mx78_armor2_provision_example.h new file mode 100644 index 00000000000..afc8e72b6a0 --- /dev/null +++ b/storage/blockdevice/tests/TESTS/blockdevice/general_block_device/mx78_armor2_provision_example.h @@ -0,0 +1,18 @@ +#ifndef MBED_MX78_ARMOR2_PROVISION_EXAMPLE_H +#define MBED_MX78_ARMOR2_PROVISION_EXAMPLE_H +#include + +#define AVAILABLE_PAIR_NUM 4 +typedef struct { + uint32_t app_id; + uint32_t secure_zone_id; +} app_zone_pair_t; + +const app_zone_pair_t app_zone_available_pair[AVAILABLE_PAIR_NUM] = { + {0xFFFFFFFE, 0x00}, + {0xFFFFFFFD, 0x01}, + {0x00000BBA, 0x02}, + {0x00000BBE, 0x03}, +}; + +#endif /* MBED_MX78_ARMOR2_PROVISION_EXAMPLE_H */ \ No newline at end of file diff --git a/targets/targets.json b/targets/targets.json index 49de7cd93f3..041dbcd885b 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4571,6 +4571,9 @@ ], "detect_code": [ "0781" + ], + "components_add": [ + "SECUREF" ] }, "MCU_STM32L4R9xI": {