Implementation of COMPONENT_SECUREF with TG424_3 for secure flash

pull/15436/head
alvinzhou 2023-07-13 11:01:25 +08:00
parent 13f43cce52
commit 61cfe5c4a7
45 changed files with 9025 additions and 67 deletions

View File

@ -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",

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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
)

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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_ */

View File

@ -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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#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;
}

View File

@ -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 <stdint.h>
#include <stddef.h>
#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_ */

View File

@ -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 <stddef.h>
#include <string.h>
#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;
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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_ */

View File

@ -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 <stdint.h>
#include <stddef.h>
#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_ */

View File

@ -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
```

View File

@ -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})

View File

@ -0,0 +1 @@
Reserved for Macronix MX75 ArmorFlash.

View File

@ -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
$<$<BOOL:${SECUREFLASH_PROVISION}>:SECUREFLASH_PROVISION>
ETSS_PROV_DEVELOPER_MODE=${ETSS_PROV_DEVELOPER_MODE}
$<$<BOOL:${MULTI_CLIENT_ISOLATION}>:MULTI_CLIENT_ISOLATION>
$<$<BOOL:${SECUREFLASH_DEBUG}>:SECUREFLASH_DEBUG>
$<$<BOOL:${MX78_ARMOR_TEST_MODE}>:MX78_ARMOR_TEST_MODE>
$<$<BOOL:${CRYPTO_MBEDTLS}>:CRYPTO_MBEDTLS>
$<$<BOOL:${CRYPTO_PSA}>:CRYPTO_PSA>
)
target_sources(mx78_armor
PRIVATE
mx78_armor.c
$<$<BOOL:${CRYPTO_PSA}>:${CMAKE_CURRENT_SOURCE_DIR}/crypto_wrapper/crypto_wrapper_psa.c>
$<$<BOOL:${CRYPTO_MBEDTLS}>:${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()

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#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 */

View File

@ -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 <stdbool.h>
#include <string.h>
#include <stddef.h>
#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 */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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_ */

View File

@ -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 <stddef.h>
#include <stdint.h>
#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 */

View File

@ -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_ */

View File

@ -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 <stdint.h>
#include <stddef.h>
#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_ */

View File

@ -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[] = {
&macronix_mx78_info,
/* Add secure flash info here */
};
#ifdef __cplusplus
}
#endif
#endif /* _VENDOR_SECUREFLASH_H_ */

View File

@ -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 */

View File

@ -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,
};

View File

@ -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_ */

View File

@ -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 <stdbool.h>
#include <string.h>
#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,
};

View File

@ -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<PlatformMutex> _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 */

View File

@ -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"
}
}
}

View File

@ -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_ */

View File

@ -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 <stdio.h>
#include <stdint.h>
#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
}

View File

@ -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 <string.h>
#include <inttypes.h>
#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<PlatformMutex> 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;
}

View File

@ -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 <stddef.h>
#include <string.h>
#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;
}

View File

@ -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 <stdint.h>
#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_ */

View File

@ -139,6 +139,27 @@ public:
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

View File

@ -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}

View File

@ -28,6 +28,7 @@
#include "BufferedBlockDevice.h"
#include "BlockDevice.h"
#include <algorithm>
#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;
err = block_device->erase(block, curr_block_size);
TEST_ASSERT_EQUAL(0, err);
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->program(write_block, block, 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->read(read_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->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);
// 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->secure_program((const void *)data_buf, start_address, data_buf_size, valid_app_id);
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->secure_read((void *)out_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]);
}
// 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);
}
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()
{

View File

@ -0,0 +1,18 @@
#ifndef MBED_MX78_ARMOR2_PROVISION_EXAMPLE_H
#define MBED_MX78_ARMOR2_PROVISION_EXAMPLE_H
#include <stdint.h>
#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 */

View File

@ -4571,6 +4571,9 @@
],
"detect_code": [
"0781"
],
"components_add": [
"SECUREF"
]
},
"MCU_STM32L4R9xI": {