secure_boot: Checks secure boot efuses

ESP32 V1 and V2 - protection bits.
ESP32xx V2: revoke bits, protection bits

- refactor efuse component
- adds some APIs for esp32 chips as well as for esp32xx chips
This commit is contained in:
KonstantinKondrashov
2021-01-26 04:27:03 +08:00
parent b92c290e56
commit 90f2d3199a
55 changed files with 877 additions and 767 deletions

View File

@@ -4,26 +4,23 @@ if(EXISTS "${COMPONENT_DIR}/${target}")
include(${COMPONENT_DIR}/${target}/sources.cmake)
spaces2list(EFUSE_SOC_SRCS)
set(include_dirs include ${target}/include)
set(private_include private_include ${target}/private_include)
add_prefix(srcs "${target}/" ${EFUSE_SOC_SRCS})
list(APPEND srcs "src/${target}/esp_efuse_api.c"
"src/${target}/esp_efuse_fields.c"
"src/${target}/esp_efuse_utility.c")
if("esp32s2" STREQUAL "${target}")
list(APPEND srcs "src/${target}/esp_efuse_rtc_table.c")
endif()
if("esp32c3" STREQUAL "${target}")
list(APPEND srcs "src/${target}/esp_efuse_rtc_calib.c")
endif()
endif()
list(APPEND srcs "src/esp_efuse_api.c"
"src/esp_efuse_fields.c"
"src/esp_efuse_utility.c")
if("esp32" STREQUAL "${target}")
list(APPEND srcs "src/esp_efuse_api_key_esp32.c")
else()
list(APPEND srcs "src/esp_efuse_api_key_esp32xx.c")
endif()
idf_component_register(SRCS "${srcs}"
PRIV_REQUIRES bootloader_support soc spi_flash
INCLUDE_DIRS "${include_dirs}"
PRIV_INCLUDE_DIRS private_include)
PRIV_INCLUDE_DIRS "${private_include}")
if(target)
set(TOOL_TARGET -t ${target})

View File

@@ -3,8 +3,12 @@
# currently the only SoC supported; to be moved into Kconfig
TARGET := $(IDF_TARGET)
COMPONENT_SRCDIRS := $(TARGET) src src/$(TARGET)
COMPONENT_PRIV_INCLUDEDIRS := private_include
COMPONENT_ADD_INCLUDEDIRS := $(TARGET)/include include
COMPONENT_SRCDIRS := $(TARGET) src
ifdef CONFIG_IDF_TARGET_ESP32
COMPONENT_OBJEXCLUDE := src/esp_efuse_api_key_esp32xx.o
else
COMPONENT_OBJEXCLUDE := src/esp_efuse_api_key_esp32.o
endif
-include $(COMPONENT_PATH)/$(TARGET)/component.mk
COMPONENT_PRIV_INCLUDEDIRS := private_include $(TARGET)/private_include
COMPONENT_ADD_INCLUDEDIRS := include $(TARGET)/include

View File

@@ -1,4 +1,4 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2017-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,54 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of eFuse blocks for ESP32
*/
typedef enum {
EFUSE_BLK0 = 0, /**< Number of eFuse block. Reserved. */
EFUSE_BLK1 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */
EFUSE_BLK_KEY0 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */
EFUSE_BLK_ENCRYPT_FLASH = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */
EFUSE_BLK2 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */
EFUSE_BLK_KEY1 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */
EFUSE_BLK_SECURE_BOOT = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */
EFUSE_BLK3 = 3, /**< Number of eFuse block. Uses for the purpose of the user. */
EFUSE_BLK_KEY2 = 3, /**< Number of eFuse block. Uses for the purpose of the user. */
EFUSE_BLK_KEY_MAX = 4,
EFUSE_BLK_MAX = 4,
} esp_efuse_block_t;
/**
* @brief Type of coding scheme
*/
typedef enum {
EFUSE_CODING_SCHEME_NONE = 0, /**< None */
EFUSE_CODING_SCHEME_3_4 = 1, /**< 3/4 coding */
EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */
} esp_efuse_coding_scheme_t;
#ifdef __cplusplus
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2017-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@@ -1 +1,3 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c")
set(EFUSE_SOC_SRCS "esp_efuse_table.c"
"esp_efuse_fields.c"
"esp_efuse_utility.c")

View File

@@ -1 +1,4 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c")
set(EFUSE_SOC_SRCS "esp_efuse_table.c"
"esp_efuse_fields.c"
"esp_efuse_rtc_calib.c"
"esp_efuse_utility.c")

View File

@@ -13,7 +13,7 @@
// limitations under the License.
#include <stdbool.h>
#include "esp32s2/esp_efuse_rtc_table.h"
#include "esp_efuse_rtc_table.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_log.h"

View File

@@ -1 +1,4 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c")
set(EFUSE_SOC_SRCS "esp_efuse_table.c"
"esp_efuse_fields.c"
"esp_efuse_rtc_table.c"
"esp_efuse_utility.c")

View File

@@ -1 +1,3 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c")
set(EFUSE_SOC_SRCS "esp_efuse_table.c"
"esp_efuse_fields.c"
"esp_efuse_utility.c")

View File

@@ -1,44 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of eFuse blocks for ESP32
*/
typedef enum {
EFUSE_BLK0 = 0, /**< Number of eFuse block. Reserved. */
EFUSE_BLK1 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */
EFUSE_BLK2 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */
EFUSE_BLK3 = 3, /**< Number of eFuse block. Uses for the purpose of the user. */
EFUSE_BLK_MAX
} esp_efuse_block_t;
/**
* @brief Type of coding scheme
*/
typedef enum {
EFUSE_CODING_SCHEME_NONE = 0, /**< None */
EFUSE_CODING_SCHEME_3_4 = 1, /**< 3/4 coding */
EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */
} esp_efuse_coding_scheme_t;
#ifdef __cplusplus
}
#endif

View File

@@ -23,15 +23,7 @@ extern "C" {
#include "esp_log.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/esp_efuse.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/esp_efuse.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/esp_efuse.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/esp_efuse.h"
#endif
#include_next "esp_efuse.h"
#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */
#define ESP_OK_EFUSE_CNT (ESP_ERR_EFUSE + 0x01) /*!< OK the required number of bits is set. */
@@ -496,48 +488,14 @@ esp_err_t esp_efuse_batch_write_cancel(void);
*/
esp_err_t esp_efuse_batch_write_commit(void);
#ifndef CONFIG_IDF_TARGET_ESP32
/**
* @brief Type of key purpose
* @brief Checks that the given block is empty.
*
* @return
* - True: The block is empty.
* - False: The block is not empty or was an error.
*/
typedef enum {
ESP_EFUSE_KEY_PURPOSE_USER = 0,
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 = 2,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7,
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11,
ESP_EFUSE_KEY_PURPOSE_MAX,
} esp_efuse_purpose_t;
/**
* @brief Returns a pointer to a key purpose for an efuse key block.
*
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
*
* To get the value of this field use esp_efuse_read_field_blob() or esp_efuse_get_key_purpose().
*
* @return Pointer: If Successful returns a pointer to the corresponding efuse field otherwise NULL.
*/
const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block);
/**
* @brief Returns a pointer to a key block.
*
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
*
* @return Pointer: If Successful returns a pointer to the corresponding efuse field otherwise NULL.
*/
const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block);
bool esp_efuse_block_is_empty(esp_efuse_block_t block);
/**
* @brief Returns a read protection for the key block.
@@ -585,6 +543,62 @@ bool esp_efuse_get_key_dis_write(esp_efuse_block_t block);
*/
esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block);
/**
* @brief Returns true if the key block is unused, false otherwise.
*
* An unused key block is all zero content, not read or write protected,
* and has purpose 0 (ESP_EFUSE_KEY_PURPOSE_USER)
*
* @param block key block to check.
*
* @return
* - True if key block is unused,
* - False if key block is used or the specified block index is not a key block.
*/
bool esp_efuse_key_block_unused(esp_efuse_block_t block);
#ifndef CONFIG_IDF_TARGET_ESP32
/**
* @brief Type of key purpose
*/
typedef enum {
ESP_EFUSE_KEY_PURPOSE_USER = 0,
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 = 2,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3,
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6,
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7,
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11,
ESP_EFUSE_KEY_PURPOSE_MAX,
} esp_efuse_purpose_t;
/**
* @brief Returns a pointer to a key purpose for an efuse key block.
*
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
*
* To get the value of this field use esp_efuse_read_field_blob() or esp_efuse_get_key_purpose().
*
* @return Pointer: If Successful returns a pointer to the corresponding efuse field otherwise NULL.
*/
const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block);
/**
* @brief Returns a pointer to a key block.
*
* @param[in] block A key block in the range EFUSE_BLK_KEY0..EFUSE_BLK_KEY_MAX
*
* @return Pointer: If Successful returns a pointer to the corresponding efuse field otherwise NULL.
*/
const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block);
/**
* @brief Returns the current purpose set for an efuse key block.
*
@@ -660,20 +674,6 @@ esp_efuse_block_t esp_efuse_find_unused_key_block(void);
*/
unsigned esp_efuse_count_unused_key_blocks(void);
/**
* @brief Returns true if the key block is unused, false otherwise.
*
* An unused key block is all zero content, not read or write protected,
* and has purpose 0 (ESP_EFUSE_KEY_PURPOSE_USER)
*
* @param block key block to check.
*
* @return
* - True if key block is unused,
* - False if key block is used or the specified block index is not a key block.
*/
bool esp_efuse_key_block_unused(esp_efuse_block_t block);
/**
* @brief Returns the status of the Secure Boot public key digest revocation bit.
*

View File

@@ -23,15 +23,7 @@ extern "C" {
#include "esp_err.h"
#include "esp_efuse.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/esp_efuse_utility.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/esp_efuse_utility.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/esp_efuse_utility.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/esp_efuse_utility.h"
#endif
#include_next "esp_efuse_utility.h"
/**
* @brief Structure range address by blocks

View File

@@ -1,69 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK2, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK3, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK2, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK3, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE ||
coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) {
scheme = EFUSE_CODING_SCHEME_3_4;
} else {
scheme = EFUSE_CODING_SCHEME_REPEAT;
}
}
ESP_EARLY_LOGD(TAG, "coding scheme %d", scheme);
return scheme;
}

View File

@@ -1,83 +0,0 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART1, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_USER_DATA, 1);
} else if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
scheme = EFUSE_CODING_SCHEME_RS;
}
ESP_LOGD(TAG, "coding scheme %d", scheme);
return scheme;
}

View File

@@ -1,83 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART1, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_USER_DATA, 1);
} else if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
scheme = EFUSE_CODING_SCHEME_RS;
}
ESP_EARLY_LOGD(TAG, "coding scheme %d", scheme);
return scheme;
}

View File

@@ -1,83 +0,0 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART1, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_USER_DATA, 1);
} else if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK4) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY0, 1);
} else if (blk == EFUSE_BLK5) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY1, 1);
} else if (blk == EFUSE_BLK6) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY2, 1);
} else if (blk == EFUSE_BLK7) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY3, 1);
} else if (blk == EFUSE_BLK8) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY4, 1);
} else if (blk == EFUSE_BLK9) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_KEY5, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
scheme = EFUSE_CODING_SCHEME_RS;
}
ESP_EARLY_LOGD(TAG, "coding scheme %d", scheme);
return scheme;
}

View File

@@ -282,307 +282,3 @@ esp_err_t esp_efuse_batch_write_commit(void)
}
return ESP_OK;
}
#ifndef CONFIG_IDF_TARGET_ESP32
/**
* @brief Keys and their attributes are packed into a structure
*/
typedef struct {
const esp_efuse_desc_t** key; /**< Key */
const esp_efuse_desc_t** keypurpose; /**< Key purpose */
const esp_efuse_desc_t** key_rd_dis; /**< Read protection of a key */
const esp_efuse_desc_t** key_wr_dis; /**< Write protection of a key*/
const esp_efuse_desc_t** keypurpose_wr_dis; /**< Write protection of a key purpose*/
} esp_efuse_keys_t;
typedef struct {
const esp_efuse_desc_t** revoke;
const esp_efuse_desc_t** revoke_wr_dis;
} esp_efuse_revokes_t;
const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
{ESP_EFUSE_KEY0, ESP_EFUSE_KEY_PURPOSE_0, ESP_EFUSE_RD_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0_PURPOSE},
{ESP_EFUSE_KEY1, ESP_EFUSE_KEY_PURPOSE_1, ESP_EFUSE_RD_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1_PURPOSE},
{ESP_EFUSE_KEY2, ESP_EFUSE_KEY_PURPOSE_2, ESP_EFUSE_RD_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2_PURPOSE},
{ESP_EFUSE_KEY3, ESP_EFUSE_KEY_PURPOSE_3, ESP_EFUSE_RD_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3_PURPOSE},
{ESP_EFUSE_KEY4, ESP_EFUSE_KEY_PURPOSE_4, ESP_EFUSE_RD_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4_PURPOSE},
{ESP_EFUSE_KEY5, ESP_EFUSE_KEY_PURPOSE_5, ESP_EFUSE_RD_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5_PURPOSE},
#if 0
{ESP_EFUSE_KEY6, ESP_EFUSE_KEY_PURPOSE_6, ESP_EFUSE_RD_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6_PURPOSE},
#endif
};
const esp_efuse_revokes_t s_revoke_table[] = {
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0},
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1},
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2},
};
#define ESP_EFUSE_CHK(ret) \
do \
{ \
if( ( err = (ret) ) != ESP_OK ) \
goto err_exit; \
} while( 0 )
const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block)
{
switch(block) {
case EFUSE_BLK_KEY0:
return ESP_EFUSE_KEY_PURPOSE_0;
case EFUSE_BLK_KEY1:
return ESP_EFUSE_KEY_PURPOSE_1;
case EFUSE_BLK_KEY2:
return ESP_EFUSE_KEY_PURPOSE_2;
case EFUSE_BLK_KEY3:
return ESP_EFUSE_KEY_PURPOSE_3;
case EFUSE_BLK_KEY4:
return ESP_EFUSE_KEY_PURPOSE_4;
case EFUSE_BLK_KEY5:
return ESP_EFUSE_KEY_PURPOSE_5;
default:
return NULL;
}
}
const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return NULL;
}
unsigned idx = block - EFUSE_BLK_KEY0;
return s_table[idx].key;
}
bool esp_efuse_get_key_dis_read(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_rd_dis);
}
esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1);
}
bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_wr_dis);
}
esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1);
}
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_EFUSE_KEY_PURPOSE_MAX;
}
unsigned idx = block - EFUSE_BLK_KEY0;
uint8_t value = 0;
esp_err_t err = esp_efuse_read_field_blob(s_table[idx].keypurpose, &value, s_table[idx].keypurpose[0]->bit_count);
if (err != ESP_OK) {
return ESP_EFUSE_KEY_PURPOSE_MAX;
}
return value;
}
esp_err_t esp_efuse_set_key_purpose(esp_efuse_block_t block, esp_efuse_purpose_t purpose)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_write_field_blob(s_table[idx].keypurpose, &purpose, s_table[idx].keypurpose[0]->bit_count);
}
bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].keypurpose_wr_dis);
}
esp_err_t esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].keypurpose_wr_dis, &one, 1);
}
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block)
{
esp_efuse_block_t dummy;
if (block == NULL) {
block = &dummy;
}
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_get_key_purpose(b) == purpose) {
*block = b;
return true;
}
}
return false;
}
esp_efuse_block_t esp_efuse_find_unused_key_block(void)
{
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_key_block_unused(b)) {
return b;
}
}
return EFUSE_BLK_KEY_MAX; // nothing
}
unsigned esp_efuse_count_unused_key_blocks(void)
{
unsigned r = 0;
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_key_block_unused(b)) {
r++;
}
}
return r;
}
bool esp_efuse_key_block_unused(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return false; // Not a key block
}
if (esp_efuse_get_key_purpose(block) != ESP_EFUSE_KEY_PURPOSE_USER ||
esp_efuse_get_keypurpose_dis_write(block) ||
esp_efuse_get_key_dis_read(block) ||
esp_efuse_get_key_dis_write(block)) {
return false; // Block in use!
}
for (int i = 0; i < 8; ++i) {
if (esp_efuse_read_reg(block, i) != 0) {
return false; // Block in use!
}
}
return true; // Unused
}
bool esp_efuse_get_digest_revoke(unsigned num_digest)
{
assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke);
}
esp_err_t esp_efuse_set_digest_revoke(unsigned num_digest)
{
if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
return ESP_ERR_INVALID_ARG;
}
return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke);
}
bool esp_efuse_get_write_protect_of_digest_revoke(unsigned num_digest)
{
assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
}
esp_err_t esp_efuse_set_write_protect_of_digest_revoke(unsigned num_digest)
{
if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
return ESP_ERR_INVALID_ARG;
}
return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
}
esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpose, const void *key, size_t key_size_bytes)
{
esp_err_t err = ESP_OK;
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX || key_size_bytes > 32 || purpose >= ESP_EFUSE_KEY_PURPOSE_MAX) {
return ESP_ERR_INVALID_ARG;
}
esp_efuse_batch_write_begin();
if (!esp_efuse_key_block_unused(block)) {
err = ESP_ERR_INVALID_STATE;
} else {
unsigned idx = block - EFUSE_BLK_KEY0;
ESP_EFUSE_CHK(esp_efuse_write_field_blob(s_table[idx].key, key, key_size_bytes * 8));
ESP_EFUSE_CHK(esp_efuse_set_key_dis_write(block));
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
ESP_EFUSE_CHK(esp_efuse_set_key_dis_read(block));
}
ESP_EFUSE_CHK(esp_efuse_set_key_purpose(block, purpose));
ESP_EFUSE_CHK(esp_efuse_set_keypurpose_dis_write(block));
return esp_efuse_batch_write_commit();
}
err_exit:
esp_efuse_batch_write_cancel();
return err;
}
esp_err_t esp_efuse_write_keys(esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
{
esp_err_t err = ESP_OK;
if (number_of_keys == 0 || number_of_keys > (EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0) || keys == NULL || purposes == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_efuse_purpose_t purpose = 0;
esp_efuse_block_t block = EFUSE_BLK_KEY0;
esp_efuse_batch_write_begin();
unsigned unused_keys = esp_efuse_count_unused_key_blocks();
if (number_of_keys > unused_keys) {
ESP_LOGE(TAG, "Not enough unused key blocks available. Required %d, was %d", number_of_keys, unused_keys);
err = ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS;
} else {
for (int i_key = 0; (block < EFUSE_BLK_KEY_MAX) && (i_key < number_of_keys); block++) {
if (esp_efuse_key_block_unused(block)) {
purpose = purposes[i_key];
ESP_LOGI(TAG, "Writing EFUSE_BLK_KEY%d with purpose %d", block - EFUSE_BLK_KEY0, purpose);
ESP_EFUSE_CHK(esp_efuse_write_key(block, purpose, keys[i_key], 32));
i_key++;
}
}
return esp_efuse_batch_write_commit();
err_exit:
ESP_LOGE(TAG, "Failed to write EFUSE_BLK_KEY%d with purpose %d. Can't continue.", block - EFUSE_BLK_KEY0, purpose);
}
esp_efuse_batch_write_cancel();
return err;
}
#endif // not CONFIG_IDF_TARGET_ESP32

View File

@@ -0,0 +1,148 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
static __attribute__((unused)) const char *TAG = "efuse";
/**
* @brief Keys and their attributes are packed into a structure
*/
typedef struct {
const esp_efuse_desc_t** key_rd_dis; /**< Read protection of a key */
const esp_efuse_desc_t** key_wr_dis; /**< Write protection of a key*/
} esp_efuse_keys_t;
const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
{ESP_EFUSE_RD_DIS_BLK1, ESP_EFUSE_WR_DIS_BLK1},
{ESP_EFUSE_RD_DIS_BLK2, ESP_EFUSE_WR_DIS_BLK2},
{ESP_EFUSE_RD_DIS_BLK3, ESP_EFUSE_WR_DIS_BLK3},
};
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX) {
return ESP_ERR_NOT_SUPPORTED;
}
unsigned idx = blk - EFUSE_BLK1;
return esp_efuse_write_field_cnt(s_table[idx].key_wr_dis, 1);
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX) {
return ESP_ERR_NOT_SUPPORTED;
}
unsigned idx = blk - EFUSE_BLK1;
return esp_efuse_write_field_cnt(s_table[idx].key_rd_dis, 1);
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE ||
coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) {
scheme = EFUSE_CODING_SCHEME_3_4;
} else {
scheme = EFUSE_CODING_SCHEME_REPEAT;
}
}
return scheme;
}
bool esp_efuse_block_is_empty(esp_efuse_block_t block)
{
unsigned blk_len_bit = 256;
uint32_t key[8];
if (esp_efuse_get_coding_scheme(block) == EFUSE_CODING_SCHEME_3_4) {
blk_len_bit = 192;
}
esp_err_t err = esp_efuse_read_block(block, &key, 0, blk_len_bit);
if (err != ESP_OK) {
return false;
}
unsigned zeros = 0;
for (unsigned i = 0; i < blk_len_bit / 32; ++i) {
if (key[i] == 0) {
++zeros;
}
}
if (zeros == blk_len_bit / 32) {
return true;
}
return false;
}
bool esp_efuse_get_key_dis_read(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_rd_dis);
}
esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1);
}
bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_wr_dis);
}
esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1);
}
bool esp_efuse_key_block_unused(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return false; // Not a key block
}
if (esp_efuse_get_key_dis_read(block) || esp_efuse_get_key_dis_write(block) ||
!esp_efuse_block_is_empty(block)) {
return false; // Block in use!
}
return true; // Unused
}

View File

@@ -0,0 +1,371 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
//
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
/**
* @brief Keys and their attributes are packed into a structure
*/
typedef struct {
const esp_efuse_desc_t** key; /**< Key */
const esp_efuse_desc_t** keypurpose; /**< Key purpose */
const esp_efuse_desc_t** key_rd_dis; /**< Read protection of a key */
const esp_efuse_desc_t** key_wr_dis; /**< Write protection of a key*/
const esp_efuse_desc_t** keypurpose_wr_dis; /**< Write protection of a key purpose*/
} esp_efuse_keys_t;
typedef struct {
const esp_efuse_desc_t** revoke;
const esp_efuse_desc_t** revoke_wr_dis;
} esp_efuse_revokes_t;
const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
{ESP_EFUSE_KEY0, ESP_EFUSE_KEY_PURPOSE_0, ESP_EFUSE_RD_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0_PURPOSE},
{ESP_EFUSE_KEY1, ESP_EFUSE_KEY_PURPOSE_1, ESP_EFUSE_RD_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1_PURPOSE},
{ESP_EFUSE_KEY2, ESP_EFUSE_KEY_PURPOSE_2, ESP_EFUSE_RD_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2_PURPOSE},
{ESP_EFUSE_KEY3, ESP_EFUSE_KEY_PURPOSE_3, ESP_EFUSE_RD_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3_PURPOSE},
{ESP_EFUSE_KEY4, ESP_EFUSE_KEY_PURPOSE_4, ESP_EFUSE_RD_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4_PURPOSE},
{ESP_EFUSE_KEY5, ESP_EFUSE_KEY_PURPOSE_5, ESP_EFUSE_RD_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5_PURPOSE},
#if 0
{ESP_EFUSE_KEY6, ESP_EFUSE_KEY_PURPOSE_6, ESP_EFUSE_RD_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6_PURPOSE},
#endif
};
const esp_efuse_revokes_t s_revoke_table[] = {
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0},
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1},
{ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2},
};
#define ESP_EFUSE_CHK(ret) \
do \
{ \
if( ( err = (ret) ) != ESP_OK ) \
goto err_exit; \
} while( 0 )
bool esp_efuse_block_is_empty(esp_efuse_block_t block)
{
const unsigned blk_len_bit = 256;
uint32_t key[8];
esp_err_t err = esp_efuse_read_block(block, &key, 0, blk_len_bit);
if (err != ESP_OK) {
return false;
}
unsigned zeros = 0;
for (unsigned i = 0; i < blk_len_bit / 32; ++i) {
if (key[i] == 0) {
++zeros;
}
}
if (zeros == blk_len_bit / 32) {
return true;
}
return false;
}
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART1, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_USER_DATA, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART2, 1);
} else if (blk >= EFUSE_BLK_KEY0 && blk < EFUSE_BLK_KEY_MAX) {
unsigned idx = blk - EFUSE_BLK_KEY0;
return esp_efuse_write_field_cnt(s_table[idx].key_wr_dis, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk >= EFUSE_BLK_KEY0 && blk < EFUSE_BLK_KEY_MAX) {
unsigned idx = blk - EFUSE_BLK_KEY0;
return esp_efuse_write_field_cnt(s_table[idx].key_rd_dis, 1);
} else if (blk == EFUSE_BLK10) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_SYS_DATA_PART2, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
scheme = EFUSE_CODING_SCHEME_RS;
}
return scheme;
}
const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return NULL;
}
unsigned idx = block - EFUSE_BLK_KEY0;
return s_table[idx].keypurpose;
}
const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return NULL;
}
unsigned idx = block - EFUSE_BLK_KEY0;
return s_table[idx].key;
}
bool esp_efuse_get_key_dis_read(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_rd_dis);
}
esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1);
}
bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].key_wr_dis);
}
esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1);
}
esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_EFUSE_KEY_PURPOSE_MAX;
}
unsigned idx = block - EFUSE_BLK_KEY0;
uint8_t value = 0;
esp_err_t err = esp_efuse_read_field_blob(s_table[idx].keypurpose, &value, s_table[idx].keypurpose[0]->bit_count);
if (err != ESP_OK) {
return ESP_EFUSE_KEY_PURPOSE_MAX;
}
return value;
}
esp_err_t esp_efuse_set_key_purpose(esp_efuse_block_t block, esp_efuse_purpose_t purpose)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_write_field_blob(s_table[idx].keypurpose, &purpose, s_table[idx].keypurpose[0]->bit_count);
}
bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block)
{
assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
unsigned idx = block - EFUSE_BLK_KEY0;
return esp_efuse_read_field_bit(s_table[idx].keypurpose_wr_dis);
}
esp_err_t esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
unsigned idx = block - EFUSE_BLK_KEY0;
const uint8_t one = 1;
return esp_efuse_write_field_blob(s_table[idx].keypurpose_wr_dis, &one, 1);
}
bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block)
{
esp_efuse_block_t dummy;
if (block == NULL) {
block = &dummy;
}
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_get_key_purpose(b) == purpose) {
*block = b;
return true;
}
}
return false;
}
esp_efuse_block_t esp_efuse_find_unused_key_block(void)
{
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_key_block_unused(b)) {
return b;
}
}
return EFUSE_BLK_KEY_MAX; // nothing
}
unsigned esp_efuse_count_unused_key_blocks(void)
{
unsigned r = 0;
for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
if (esp_efuse_key_block_unused(b)) {
r++;
}
}
return r;
}
bool esp_efuse_key_block_unused(esp_efuse_block_t block)
{
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
return false; // Not a key block
}
if (esp_efuse_get_key_purpose(block) != ESP_EFUSE_KEY_PURPOSE_USER ||
esp_efuse_get_keypurpose_dis_write(block) ||
esp_efuse_get_key_dis_read(block) ||
esp_efuse_get_key_dis_write(block)) {
return false; // Block in use!
}
if (!esp_efuse_block_is_empty(block)) {
return false; // Block in use!
}
return true; // Unused
}
bool esp_efuse_get_digest_revoke(unsigned num_digest)
{
assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke);
}
esp_err_t esp_efuse_set_digest_revoke(unsigned num_digest)
{
if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
return ESP_ERR_INVALID_ARG;
}
return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke);
}
bool esp_efuse_get_write_protect_of_digest_revoke(unsigned num_digest)
{
assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
}
esp_err_t esp_efuse_set_write_protect_of_digest_revoke(unsigned num_digest)
{
if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
return ESP_ERR_INVALID_ARG;
}
return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
}
esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpose, const void *key, size_t key_size_bytes)
{
esp_err_t err = ESP_OK;
if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX || key_size_bytes > 32 || purpose >= ESP_EFUSE_KEY_PURPOSE_MAX) {
return ESP_ERR_INVALID_ARG;
}
esp_efuse_batch_write_begin();
if (!esp_efuse_key_block_unused(block)) {
err = ESP_ERR_INVALID_STATE;
} else {
unsigned idx = block - EFUSE_BLK_KEY0;
ESP_EFUSE_CHK(esp_efuse_write_field_blob(s_table[idx].key, key, key_size_bytes * 8));
ESP_EFUSE_CHK(esp_efuse_set_key_dis_write(block));
if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
ESP_EFUSE_CHK(esp_efuse_set_key_dis_read(block));
}
ESP_EFUSE_CHK(esp_efuse_set_key_purpose(block, purpose));
ESP_EFUSE_CHK(esp_efuse_set_keypurpose_dis_write(block));
return esp_efuse_batch_write_commit();
}
err_exit:
esp_efuse_batch_write_cancel();
return err;
}
esp_err_t esp_efuse_write_keys(esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
{
esp_err_t err = ESP_OK;
if (number_of_keys == 0 || number_of_keys > (EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0) || keys == NULL || purposes == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_efuse_purpose_t purpose = 0;
esp_efuse_block_t block = EFUSE_BLK_KEY0;
esp_efuse_batch_write_begin();
unsigned unused_keys = esp_efuse_count_unused_key_blocks();
if (number_of_keys > unused_keys) {
ESP_LOGE(TAG, "Not enough unused key blocks available. Required %d, was %d", number_of_keys, unused_keys);
err = ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS;
} else {
for (int i_key = 0; (block < EFUSE_BLK_KEY_MAX) && (i_key < number_of_keys); block++) {
if (esp_efuse_key_block_unused(block)) {
purpose = purposes[i_key];
ESP_LOGI(TAG, "Writing EFUSE_BLK_KEY%d with purpose %d", block - EFUSE_BLK_KEY0, purpose);
ESP_EFUSE_CHK(esp_efuse_write_key(block, purpose, keys[i_key], 32));
i_key++;
}
}
return esp_efuse_batch_write_commit();
err_exit:
ESP_LOGE(TAG, "Failed to write EFUSE_BLK_KEY%d with purpose %d. Can't continue.", block - EFUSE_BLK_KEY0, purpose);
}
esp_efuse_batch_write_cancel();
return err;
}

View File

@@ -1,5 +1,6 @@
idf_build_get_property(target IDF_TARGET)
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "." "include"
PRIV_INCLUDE_DIRS "../private_include"
PRIV_INCLUDE_DIRS "." "include" "../private_include" ../${target}/private_include
PRIV_REQUIRES cmock test_utils efuse bootloader_support
)