Merge branch 'feature/flash_encryption_esp32s2' into 'master'

feature/flash_encryption_esp32s2: Enable flash encryption mechanism to esp32s2 chips

Closes IDF-804

See merge request espressif/esp-idf!8109
This commit is contained in:
Angus Gratton
2020-04-25 12:28:21 +08:00
11 changed files with 269 additions and 195 deletions

View File

@@ -601,7 +601,7 @@ menu "Security features"
config SECURE_BOOT_ALLOW_ROM_BASIC config SECURE_BOOT_ALLOW_ROM_BASIC
bool "Leave ROM BASIC Interpreter available on reset" bool "Leave ROM BASIC Interpreter available on reset"
depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT depends on (SECURE_BOOT_INSECURE || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) && IDF_TARGET_ESP32
default N default N
help help
By default, the BASIC ROM Console starts on reset if no valid bootloader is By default, the BASIC ROM Console starts on reset if no valid bootloader is
@@ -664,7 +664,7 @@ menu "Security features"
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC config SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
bool "Leave UART bootloader decryption enabled" bool "Leave UART bootloader decryption enabled"
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT && IDF_TARGET_ESP32
default N default N
help help
If not set (default), the bootloader will permanently disable UART bootloader decryption access on If not set (default), the bootloader will permanently disable UART bootloader decryption access on

View File

@@ -6,17 +6,13 @@ set(srcs
"src/bootloader_random.c" "src/bootloader_random.c"
"src/bootloader_utility.c" "src/bootloader_utility.c"
"src/esp_image_format.c" "src/esp_image_format.c"
"src/flash_encrypt.c"
"src/flash_partitions.c" "src/flash_partitions.c"
"src/flash_qio_mode.c" "src/flash_qio_mode.c"
"src/bootloader_flash_config_${IDF_TARGET}.c" "src/bootloader_flash_config_${IDF_TARGET}.c"
"src/bootloader_efuse_${IDF_TARGET}.c" "src/bootloader_efuse_${IDF_TARGET}.c"
) )
if(IDF_TARGET STREQUAL "esp32")
# Not supported on ESP32S2 yet
list(APPEND srcs "src/flash_encrypt.c")
endif()
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD)
set(include_dirs "include" "include_bootloader") set(include_dirs "include" "include_bootloader")
set(priv_requires micro-ecc spi_flash efuse) set(priv_requires micro-ecc spi_flash efuse)

View File

@@ -25,66 +25,100 @@
#include "esp32s2/rom/secure_boot.h" #include "esp32s2/rom/secure_boot.h"
#include "esp32s2/rom/cache.h" #include "esp32s2/rom/cache.h"
#include "esp32s2/rom/efuse.h" #include "esp32s2/rom/efuse.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/wdt_hal.h"
static const char *TAG = "flash_encrypt"; static const char *TAG = "flash_encrypt";
/* Static functions for stages of flash encryption */ /* Static functions for stages of flash encryption */
static esp_err_t initialise_flash_encryption(void); static esp_err_t initialise_flash_encryption(void);
static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis); static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
static esp_err_t encrypt_bootloader(void); static esp_err_t encrypt_bootloader(void);
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions); static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition); static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void) esp_err_t esp_flash_encrypt_check_and_update(void)
{ {
// TODO: not clear why this is read from DATA1 and written to PGM_DATA2 uint8_t flash_crypt_wr_dis = 0;
uint32_t cnt = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_SPI_BOOT_CRYPT_CNT); uint32_t flash_crypt_cnt = 0;
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", cnt);
bool flash_crypt_wr_dis = false; // TODO: check if CRYPT_CNT is write disabled esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, 3);
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &flash_crypt_wr_dis, 1);
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_cnt);
ESP_LOGV(TAG, "EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_wr_dis);
_Static_assert(EFUSE_SPI_BOOT_CRYPT_CNT == 0x7, "assuming CRYPT_CNT is only 3 bits wide"); _Static_assert(EFUSE_SPI_BOOT_CRYPT_CNT == 0x7, "assuming CRYPT_CNT is only 3 bits wide");
if (cnt == 1 || cnt == 3 || cnt == 7) { if (__builtin_parity(flash_crypt_cnt) == 1) {
/* Flash is already encrypted */ /* Flash is already encrypted */
int left; int left = (flash_crypt_cnt == 1) ? 1 : 0;
if (cnt == 7 /* || disabled */) { if (flash_crypt_wr_dis) {
left = 0; left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
} else if (cnt == 3) {
left = 1;
} else {
left = 2;
} }
ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left); ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
return ESP_OK; return ESP_OK;
} } else {
else {
#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
/* Flash is not encrypted, so encrypt it! */ /* Flash is not encrypted, so encrypt it! */
return encrypt_flash_contents(cnt, flash_crypt_wr_dis); return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis);
#else
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
"is set, refusing to boot.");
return ESP_ERR_INVALID_STATE;
#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
} }
} }
static esp_err_t initialise_flash_encryption(void) static bool s_key_dis_read(ets_efuse_block_t block)
{ {
/* Before first flash encryption pass, need to initialise key & crypto config */ unsigned key_num = block - ETS_EFUSE_BLOCK_KEY0;
return REG_GET_FIELD(EFUSE_RD_REPEAT_DATA0_REG, EFUSE_RD_DIS) & (EFUSE_RD_DIS_KEY0 << key_num);
}
/* Find out if a key is already set */ static bool s_key_dis_write(ets_efuse_block_t block)
bool has_aes128 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL); {
bool has_aes256_1 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, NULL); unsigned key_num = block - ETS_EFUSE_BLOCK_KEY0;
bool has_aes256_2 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, NULL); return REG_GET_FIELD(EFUSE_RD_WR_DIS_REG, EFUSE_WR_DIS) & (EFUSE_WR_DIS_KEY0 << key_num);
}
static esp_err_t check_and_generate_encryption_keys(void)
{
esp_err_t err = ESP_ERR_INVALID_STATE;
ets_efuse_block_t aes_128_key_block;
ets_efuse_block_t aes_256_key_block_1;
ets_efuse_block_t aes_256_key_block_2;
bool has_aes128 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, &aes_128_key_block);
bool has_aes256_1 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, &aes_256_key_block_1);
bool has_aes256_2 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, &aes_256_key_block_2);
bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2); bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2);
bool dis_write = false;
bool dis_read = false;
// If there are keys set, they must be write and read protected!
if(has_key && has_aes128) {
dis_write = s_key_dis_write(aes_128_key_block);
dis_read = s_key_dis_read(aes_128_key_block);
} else if (has_key && has_aes256_1 && has_aes256_2) {
dis_write = s_key_dis_write(aes_256_key_block_1) && s_key_dis_write(aes_256_key_block_2);
dis_read = s_key_dis_read(aes_256_key_block_1) && s_key_dis_read(aes_256_key_block_2);
}
if (!has_key && (has_aes256_1 || has_aes256_2)) { if (!has_key && (has_aes256_1 || has_aes256_2)) {
ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set."); ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
if (has_key) { if(has_key && (!dis_read || !dis_write)) {
ESP_LOGI(TAG, "Using pre-existing key in efuse"); ESP_LOGE(TAG, "Invalid key state, a key was set but not read and write protected.");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGE(TAG, "TODO: Check key is read & write protected"); // TODO if(!has_key && !dis_write && !dis_read) {
} else {
ESP_LOGI(TAG, "Generating new flash encryption key..."); ESP_LOGI(TAG, "Generating new flash encryption key...");
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256 #ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256
const unsigned BLOCKS_NEEDED = 2; const unsigned BLOCKS_NEEDED = 2;
@@ -102,26 +136,87 @@ static esp_err_t initialise_flash_encryption(void)
} }
for(ets_efuse_purpose_t purpose = PURPOSE_START; purpose <= PURPOSE_END; purpose++) { for(ets_efuse_purpose_t purpose = PURPOSE_START; purpose <= PURPOSE_END; purpose++) {
uint32_t buf[8]; uint32_t buf[8] = {0};
bootloader_fill_random(buf, sizeof(buf)); bootloader_fill_random(buf, sizeof(buf));
ets_efuse_block_t block = ets_efuse_find_unused_key_block(); ets_efuse_block_t block = ets_efuse_find_unused_key_block();
ESP_LOGD(TAG, "Writing ETS_EFUSE_BLOCK_KEY%d with purpose %d", ESP_LOGD(TAG, "Writing ETS_EFUSE_BLOCK_KEY%d with purpose %d",
block - ETS_EFUSE_BLOCK_KEY0, purpose); block - ETS_EFUSE_BLOCK_KEY0, purpose);
bootloader_debug_buffer(buf, sizeof(buf), "Key content");
/* Note: everything else in this function is deferred as a batch write, but we write the
key (and write protect it) immediately as it's too fiddly to manage unused key blocks, etc.
in bootloader size footprint otherwise. */
int r = ets_efuse_write_key(block, purpose, buf, sizeof(buf)); int r = ets_efuse_write_key(block, purpose, buf, sizeof(buf));
bzero(buf, sizeof(buf));
if (r != 0) { if (r != 0) {
ESP_LOGE(TAG, "Failed to write efuse block %d with purpose %d. Can't continue."); ESP_LOGE(TAG, "Failed to write efuse block %d with purpose %d. Can't continue.",
block, purpose);
return ESP_FAIL; return ESP_FAIL;
} }
}
/* assuming numbering of esp_efuse_block_t matches ets_efuse_block_t */
_Static_assert((int)EFUSE_BLK_KEY0 == (int)ETS_EFUSE_BLOCK_KEY0, "esp_efuse_block_t doesn't match ets_efuse_block_t");
_Static_assert((int)EFUSE_BLK_KEY1 == (int)ETS_EFUSE_BLOCK_KEY1, "esp_efuse_block_t doesn't match ets_efuse_block_t");
_Static_assert((int)EFUSE_BLK_KEY2 == (int)ETS_EFUSE_BLOCK_KEY2, "esp_efuse_block_t doesn't match ets_efuse_block_t");
_Static_assert((int)EFUSE_BLK_KEY3 == (int)ETS_EFUSE_BLOCK_KEY3, "esp_efuse_block_t doesn't match ets_efuse_block_t");
_Static_assert((int)EFUSE_BLK_KEY4 == (int)ETS_EFUSE_BLOCK_KEY4, "esp_efuse_block_t doesn't match ets_efuse_block_t");
_Static_assert((int)EFUSE_BLK_KEY5 == (int)ETS_EFUSE_BLOCK_KEY5, "esp_efuse_block_t doesn't match ets_efuse_block_t");
// protect this block against reading after key is set (writing is done by ets_efuse_write_key)
err = esp_efuse_set_read_protect(block);
if(err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set read protect to efuse block %d. Can't continue.", block);
return err;
}
}
ESP_LOGD(TAG, "Key generation complete"); ESP_LOGD(TAG, "Key generation complete");
return ESP_OK;
} else {
ESP_LOGI(TAG, "Using pre-existing key in efuse");
return ESP_OK;
}
}
static esp_err_t initialise_flash_encryption(void)
{
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_encryption_keys();
if(key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
} }
ESP_LOGE(TAG, "TODO: burn remaining security protection bits"); // TODO #ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
const uint8_t dis_manual_encrypt = 1;
esp_efuse_write_field_blob(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT, &dis_manual_encrypt, 1);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
#endif
return ESP_OK; #ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
ESP_LOGI(TAG, "Disable UART bootloader cache...");
const uint8_t dis_download_caches = 1;
esp_efuse_write_field_blob(ESP_EFUSE_DIS_DOWNLOAD_DCACHE, &dis_download_caches, 1);
esp_efuse_write_field_blob(ESP_EFUSE_DIS_DOWNLOAD_ICACHE, &dis_download_caches, 1);
#else
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
const uint8_t dis_jtag = 1;
esp_efuse_write_field_blob(ESP_EFUSE_HARD_DIS_JTAG, &dis_jtag, 1);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
const uint8_t dis_boot_remap = 1;
esp_efuse_write_field_blob(ESP_EFUSE_DIS_BOOT_REMAP, &dis_boot_remap, 1);
esp_err_t err = esp_efuse_batch_write_commit();
return err;
} }
/* Encrypt all flash data that should be encrypted */ /* Encrypt all flash data that should be encrypted */
@@ -134,7 +229,7 @@ static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_
/* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the /* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the
device can't re-encrypt itself. */ device can't re-encrypt itself. */
if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) { if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) {
ESP_LOGE(TAG, "Cannot re-encrypt data (SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis); ESP_LOGE(TAG, "Cannot re-encrypt data SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis);
return ESP_FAIL; return ESP_FAIL;
} }
@@ -156,10 +251,7 @@ static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_
return err; return err;
} }
/* Now iterate the just-loaded partition table, looking for entries to encrypt /* Now iterate the just-loaded partition table, looking for entries to encrypt */
*/
/* Go through each partition and encrypt if necessary */
for (int i = 0; i < num_partitions; i++) { for (int i = 0; i < num_partitions; i++) {
err = encrypt_partition(i, &partition_table[i]); err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) { if (err != ESP_OK) {
@@ -172,13 +264,17 @@ static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_
/* Set least significant 0-bit in spi_boot_crypt_cnt */ /* Set least significant 0-bit in spi_boot_crypt_cnt */
int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7); int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7);
/* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */ /* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */
uint32_t new_spi_boot_crypt_cnt = spi_boot_crypt_cnt + (1 << (ffs_inv - 1)); uint32_t new_spi_boot_crypt_cnt = (1 << (ffs_inv - 1));
ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt); ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt + spi_boot_crypt_cnt);
ets_efuse_clear_program_registers(); esp_efuse_write_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &new_spi_boot_crypt_cnt, 3);
REG_SET_FIELD(EFUSE_PGM_DATA2_REG, EFUSE_SPI_BOOT_CRYPT_CNT, new_spi_boot_crypt_cnt);
ets_efuse_program(ETS_EFUSE_BLOCK0);
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
//Secure SPI boot cnt after its update if needed.
const uint32_t spi_boot_cnt_wr_dis = 1;
ESP_LOGI(TAG, "Write protecting SPI_CRYPT_CNT eFuse");
esp_efuse_write_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &spi_boot_cnt_wr_dis, 1);
#endif
ESP_LOGI(TAG, "Flash encryption completed"); ESP_LOGI(TAG, "Flash encryption completed");
return ESP_OK; return ESP_OK;
@@ -191,21 +287,30 @@ static esp_err_t encrypt_bootloader(void)
/* Check for plaintext bootloader (verification will fail if it's already encrypted) */ /* Check for plaintext bootloader (verification will fail if it's already encrypted) */
if (esp_image_verify_bootloader(&image_length) == ESP_OK) { if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
ESP_LOGD(TAG, "bootloader is plaintext. Encrypting..."); ESP_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
// Account for the signature sector after the bootloader
image_length = (image_length + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE - 1);
image_length += FLASH_SECTOR_SIZE;
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_SIZE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length); err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err); ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err; return err;
} }
if (esp_secure_boot_enabled()) { ESP_LOGI(TAG, "bootloader encrypted successfully");
// TODO: anything different for secure boot? return err;
}
} }
else { else {
ESP_LOGW(TAG, "no valid bootloader was found"); ESP_LOGW(TAG, "no valid bootloader was found");
return ESP_ERR_NOT_FOUND;
} }
return ESP_OK;
} }
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions) static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
@@ -232,6 +337,7 @@ static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partitio
} }
/* Valid partition table loded */ /* Valid partition table loded */
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return ESP_OK; return ESP_OK;
} }
@@ -280,7 +386,13 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
return ESP_FAIL; return ESP_FAIL;
} }
wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) { for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_feed(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
uint32_t sec_start = i + src_addr; uint32_t sec_start = i + src_addr;
err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false); err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false);
if (err != ESP_OK) { if (err != ESP_OK) {

View File

@@ -20,6 +20,14 @@
#include "esp_flash_encrypt.h" #include "esp_flash_encrypt.h"
#include "esp_secure_boot.h" #include "esp_secure_boot.h"
#if CONFIG_IDF_TARGET_ESP32
#define CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
#elif CONFIG_IDF_TARGET_ESP32S2
#define CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
#endif
#ifndef BOOTLOADER_BUILD #ifndef BOOTLOADER_BUILD
static const char *TAG = "flash_encrypt"; static const char *TAG = "flash_encrypt";
@@ -34,7 +42,7 @@ void esp_flash_encryption_init_checks()
#ifdef CONFIG_SECURE_BOOT #ifdef CONFIG_SECURE_BOOT
if (esp_secure_boot_enabled() && esp_flash_encryption_enabled()) { if (esp_secure_boot_enabled() && esp_flash_encryption_enabled()) {
uint8_t flash_crypt_cnt_wr_dis = 0; uint8_t flash_crypt_cnt_wr_dis = 0;
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1); esp_efuse_read_field_blob(CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1);
if (!flash_crypt_cnt_wr_dis) { if (!flash_crypt_cnt_wr_dis) {
ESP_EARLY_LOGE(TAG, "Flash encryption & Secure Boot together requires FLASH_CRYPT_CNT efuse to be write protected. Fixing now..."); ESP_EARLY_LOGE(TAG, "Flash encryption & Secure Boot together requires FLASH_CRYPT_CNT efuse to be write protected. Fixing now...");
esp_flash_write_protect_crypt_cnt(); esp_flash_write_protect_crypt_cnt();
@@ -62,22 +70,35 @@ void esp_flash_encryption_init_checks()
void esp_flash_write_protect_crypt_cnt(void) void esp_flash_write_protect_crypt_cnt(void)
{ {
uint8_t flash_crypt_cnt_wr_dis = 0; uint8_t flash_crypt_cnt_wr_dis = 0;
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1);
esp_efuse_read_field_blob(CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1);
if (!flash_crypt_cnt_wr_dis) { if (!flash_crypt_cnt_wr_dis) {
esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, 1); esp_efuse_write_field_cnt(WR_DIS_CRYPT_CNT, 1);
} }
} }
esp_flash_enc_mode_t esp_get_flash_encryption_mode(void) esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
{ {
uint8_t efuse_flash_crypt_cnt_wr_protected = 0; uint8_t efuse_flash_crypt_cnt_wr_protected = 0;
#if CONFIG_IDF_TARGET_ESP32
uint8_t dis_dl_enc = 0, dis_dl_dec = 0, dis_dl_cache = 0; uint8_t dis_dl_enc = 0, dis_dl_dec = 0, dis_dl_cache = 0;
#elif CONFIG_IDF_TARGET_ESP32S2
uint8_t dis_dl_enc = 0;
uint8_t dis_dl_icache = 0;
uint8_t dis_dl_dcache = 0;
#endif
esp_flash_enc_mode_t mode = ESP_FLASH_ENC_MODE_DEVELOPMENT; esp_flash_enc_mode_t mode = ESP_FLASH_ENC_MODE_DEVELOPMENT;
if (esp_flash_encryption_enabled()) { if (esp_flash_encryption_enabled()) {
/* Check if FLASH CRYPT CNT is write protected */ /* Check if FLASH CRYPT CNT is write protected */
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &efuse_flash_crypt_cnt_wr_protected, 1); esp_efuse_read_field_blob(WR_DIS_CRYPT_CNT, &efuse_flash_crypt_cnt_wr_protected, 1);
if (efuse_flash_crypt_cnt_wr_protected) { if (efuse_flash_crypt_cnt_wr_protected) {
#if CONFIG_IDF_TARGET_ESP32
esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_CACHE, &dis_dl_cache, 1); esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_CACHE, &dis_dl_cache, 1);
esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_ENCRYPT, &dis_dl_enc, 1); esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_ENCRYPT, &dis_dl_enc, 1);
esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_DECRYPT, &dis_dl_dec, 1); esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_DECRYPT, &dis_dl_dec, 1);
@@ -85,6 +106,15 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
if ( dis_dl_cache && dis_dl_enc && dis_dl_dec ) { if ( dis_dl_cache && dis_dl_enc && dis_dl_dec ) {
mode = ESP_FLASH_ENC_MODE_RELEASE; mode = ESP_FLASH_ENC_MODE_RELEASE;
} }
#elif CONFIG_IDF_TARGET_ESP32S2
esp_efuse_read_field_blob(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT, &dis_dl_enc, 1);
esp_efuse_read_field_blob(ESP_EFUSE_DIS_DOWNLOAD_ICACHE, &dis_dl_icache, 1);
esp_efuse_read_field_blob(ESP_EFUSE_DIS_DOWNLOAD_DCACHE, &dis_dl_dcache, 1);
if (dis_dl_enc && dis_dl_icache && dis_dl_dcache) {
mode = ESP_FLASH_ENC_MODE_RELEASE;
}
#endif
} }
} else { } else {
mode = ESP_FLASH_ENC_MODE_DISABLED; mode = ESP_FLASH_ENC_MODE_DISABLED;

View File

@@ -167,6 +167,14 @@ extern "C" {
#define EFUSE_RD_DIS_V 0x7F #define EFUSE_RD_DIS_V 0x7F
#define EFUSE_RD_DIS_S 0 #define EFUSE_RD_DIS_S 0
#define EFUSE_RD_DIS_KEY0 (1<<0)
#define EFUSE_RD_DIS_KEY1 (1<<1)
#define EFUSE_RD_DIS_KEY2 (1<<2)
#define EFUSE_RD_DIS_KEY3 (1<<3)
#define EFUSE_RD_DIS_KEY4 (1<<4)
#define EFUSE_RD_DIS_KEY5 (1<<5)
#define EFUSE_RD_DIS_SYS_DATA_PART2 (1<<6)
#define EFUSE_PGM_DATA2_REG (DR_REG_EFUSE_BASE + 0x008) #define EFUSE_PGM_DATA2_REG (DR_REG_EFUSE_BASE + 0x008)
/* EFUSE_KEY_PURPOSE_1 : R/W ;bitpos:[31:28] ;default: 4'h0 ; */ /* EFUSE_KEY_PURPOSE_1 : R/W ;bitpos:[31:28] ;default: 4'h0 ; */
/*description: Purpose of Key1. Refer to Table KEY_PURPOSE Values.*/ /*description: Purpose of Key1. Refer to Table KEY_PURPOSE Values.*/
@@ -466,6 +474,36 @@ extern "C" {
#define EFUSE_WR_DIS_V 0xFFFFFFFF #define EFUSE_WR_DIS_V 0xFFFFFFFF
#define EFUSE_WR_DIS_S 0 #define EFUSE_WR_DIS_S 0
#define EFUSE_WR_DIS_RD_DIS (1<<0)
#define EFUSE_WR_DIS_DIS_RTC_RAM_BOOT (1<<1)
#define EFUSE_WR_DIS_GROUP_1 (1<<2)
#define EFUSE_WR_DIS_GROUP_2 (1<<3)
#define EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT (1<<4)
#define EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0 (1<<5)
#define EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1 (1<<6)
#define EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2 (1<<7)
#define EFUSE_WR_DIS_KEY0_PURPOSE (1<<8)
#define EFUSE_WR_DIS_KEY1_PURPOSE (1<<9)
#define EFUSE_WR_DIS_KEY2_PURPOSE (1<<10)
#define EFUSE_WR_DIS_KEY3_PURPOSE (1<<11)
#define EFUSE_WR_DIS_KEY4_PURPOSE (1<<12)
#define EFUSE_WR_DIS_KEY5_PURPOSE (1<<13)
#define EFUSE_WR_DIS_SECURE_BOOT_EN (1<<15)
#define EFUSE_WR_DIS_SECURE_BOOT_AGGRESSIVE_REVOKE (1<<16)
#define EFUSE_WR_DIS_GROUP_3 (1<<18)
#define EFUSE_WR_DIS_BLK1 (1<<20)
#define EFUSE_WR_DIS_SYS_DATA_PART1 (1<<21)
#define EFUSE_WR_DIS_USER_DATA (1<<22)
#define EFUSE_WR_DIS_KEY0 (1<<23)
#define EFUSE_WR_DIS_KEY1 (1<<24)
#define EFUSE_WR_DIS_KEY2 (1<<25)
#define EFUSE_WR_DIS_KEY3 (1<<26)
#define EFUSE_WR_DIS_KEY4 (1<<27)
#define EFUSE_WR_DIS_KEY5 (1<<28)
#define EFUSE_WR_DIS_SYS_DATA_PART2 (1<<29)
#define EFUSE_WR_DIS_USB_EXCHG_PINS (1<<30)
#define EFUSE_RD_REPEAT_DATA0_REG (DR_REG_EFUSE_BASE + 0x030) #define EFUSE_RD_REPEAT_DATA0_REG (DR_REG_EFUSE_BASE + 0x030)
/* EFUSE_VDD_SPI_DREFH : RO ;bitpos:[31:30] ;default: 2'h0 ; */ /* EFUSE_VDD_SPI_DREFH : RO ;bitpos:[31:30] ;default: 2'h0 ; */
/*description: The value of VDD_SPI_DREFH.*/ /*description: The value of VDD_SPI_DREFH.*/

View File

@@ -15,6 +15,7 @@ else()
"cache_utils.c" "cache_utils.c"
"flash_mmap.c" "flash_mmap.c"
"flash_ops.c" "flash_ops.c"
"${IDF_TARGET}/flash_ops_${IDF_TARGET}.c"
) )
set(srcs set(srcs
"partition.c") "partition.c")

View File

@@ -36,6 +36,10 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a
{ {
const uint8_t *ssrc = (const uint8_t *)src; const uint8_t *ssrc = (const uint8_t *)src;
esp_rom_spiflash_result_t rc; esp_rom_spiflash_result_t rc;
assert((dest_addr % 16) == 0);
assert((size % 16) == 0);
rc = esp_rom_spiflash_unlock(); rc = esp_rom_spiflash_unlock();
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
return rc; return rc;

View File

@@ -22,12 +22,21 @@
#include "esp32s2/rom/cache.h" #include "esp32s2/rom/cache.h"
#include "hal/spi_flash_hal.h" #include "hal/spi_flash_hal.h"
#include "esp_flash.h" #include "esp_flash.h"
#include "esp_log.h"
static const char *TAG = "spiflash_s2";
#define SPICACHE SPIMEM0
#define SPIFLASH SPIMEM1
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size) esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size)
{ {
const spi_flash_guard_funcs_t *ops = spi_flash_guard_get(); const spi_flash_guard_funcs_t *ops = spi_flash_guard_get();
esp_rom_spiflash_result_t rc; esp_rom_spiflash_result_t rc;
assert((dest_addr % 16) == 0);
assert((size % 16) == 0);
if (!esp_ptr_internal(src)) { if (!esp_ptr_internal(src)) {
uint8_t block[128]; // Need to buffer in RAM as we write uint8_t block[128]; // Need to buffer in RAM as we write
while (size > 0) { while (size > 0) {
@@ -48,10 +57,13 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a
return ESP_ROM_SPIFLASH_RESULT_OK; return ESP_ROM_SPIFLASH_RESULT_OK;
} }
else { // Already in internal memory else { // Already in internal memory
rc = esp_rom_spiflash_unlock(); ESP_LOGV(TAG, "calling SPI_Encrypt_Write addr 0x%x src %p size 0x%x", dest_addr, src, size);
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
return rc; #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
} /* The ROM function SPI_Encrypt_Write assumes ADDR_BITLEN is already set but new
implementation doesn't automatically set this to a usable value */
SPIFLASH.user1.usr_addr_bitlen = 23;
#endif
if (ops && ops->start) { if (ops && ops->start) {
ops->start(); ops->start();
@@ -64,8 +76,6 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a
} }
} }
#define SPICACHE SPIMEM0
#define SPIFLASH SPIMEM1
#define FLASH_WRAP_CMD 0x77 #define FLASH_WRAP_CMD 0x77
esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode) esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode)
{ {

View File

@@ -45,6 +45,7 @@
#include "esp_flash.h" #include "esp_flash.h"
#include "esp_attr.h" #include "esp_attr.h"
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size);
/* bytes erased by SPIEraseBlock() ROM function */ /* bytes erased by SPIEraseBlock() ROM function */
#define BLOCK_ERASE_SIZE 65536 #define BLOCK_ERASE_SIZE 65536
@@ -434,58 +435,6 @@ out:
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL #endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
static IRAM_ATTR esp_err_t spi_flash_write_encrypted_in_rows(size_t dest_addr, const uint8_t *src, size_t size)
{
assert((dest_addr % 16) == 0);
assert((size % 16) == 0);
/* esp_rom_spiflash_write_encrypted encrypts data in RAM as it writes,
so copy to a temporary buffer - 32 bytes at a time.
Each call to esp_rom_spiflash_write_encrypted takes a 32 byte "row" of
data to encrypt, and each row is two 16 byte AES blocks
that share a key (as derived from flash address).
*/
esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
WORD_ALIGNED_ATTR uint8_t encrypt_buf[32];
uint32_t row_size;
for (size_t i = 0; i < size; i += row_size) {
uint32_t row_addr = dest_addr + i;
if (i == 0 && (row_addr % 32) != 0) {
/* writing to second block of a 32 byte row */
row_size = 16;
row_addr -= 16;
/* copy to second block in buffer */
memcpy(encrypt_buf + 16, src + i, 16);
/* decrypt the first block from flash, will reencrypt to same bytes */
spi_flash_read_encrypted(row_addr, encrypt_buf, 16);
} else if (size - i == 16) {
/* 16 bytes left, is first block of a 32 byte row */
row_size = 16;
/* copy to first block in buffer */
memcpy(encrypt_buf, src + i, 16);
/* decrypt the second block from flash, will reencrypt to same bytes */
spi_flash_read_encrypted(row_addr + 16, encrypt_buf + 16, 16);
} else {
/* Writing a full 32 byte row (2 blocks) */
row_size = 32;
memcpy(encrypt_buf, src + i, 32);
}
spi_flash_guard_start();
rc = esp_rom_spiflash_write_encrypted(row_addr, (uint32_t *)encrypt_buf, 32);
spi_flash_guard_end();
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
break;
}
}
bzero(encrypt_buf, sizeof(encrypt_buf));
return spi_flash_translate_rc(rc);
}
esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size) esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@@ -505,7 +454,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src,
} }
#ifndef CONFIG_SPI_FLASH_VERIFY_WRITE #ifndef CONFIG_SPI_FLASH_VERIFY_WRITE
err = spi_flash_write_encrypted_in_rows(dest_addr, (const uint8_t*)src, size); err = spi_flash_write_encrypted_chip(dest_addr, src, size);
COUNTER_ADD_BYTES(write, size); COUNTER_ADD_BYTES(write, size);
spi_flash_guard_start(); spi_flash_guard_start();
spi_flash_check_and_flush_cache(dest_addr, size); spi_flash_check_and_flush_cache(dest_addr, size);
@@ -535,7 +484,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src,
} }
#endif #endif
err = spi_flash_write_encrypted_in_rows(dest_addr + i, src + i, read_len); err = spi_flash_write_encrypted_chip(dest_addr + i, src + i, read_len);
if (err != ESP_OK) { if (err != ESP_OK) {
break; break;
} }
@@ -795,78 +744,6 @@ void spi_flash_dump_counters(void)
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
#if CONFIG_IDF_TARGET_ESP32S2
#define SPICACHE SPIMEM0
#define SPIFLASH SPIMEM1
#define FLASH_WRAP_CMD 0x77
esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode)
{
uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
uint32_t reg_bkp_usr = SPIFLASH.user.val;
SPIFLASH.user.fwrite_dio = 0;
SPIFLASH.user.fwrite_dual = 0;
SPIFLASH.user.fwrite_qio = 1;
SPIFLASH.user.fwrite_quad = 0;
SPIFLASH.ctrl.fcmd_dual = 0;
SPIFLASH.ctrl.fcmd_quad = 0;
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 1;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD;
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.addr = 0;
SPIFLASH.user.usr_miso = 0;
SPIFLASH.user.usr_mosi = 1;
SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
SPIFLASH.cmd.usr = 1;
while(SPIFLASH.cmd.usr != 0)
{ }
SPIFLASH.ctrl.val = reg_bkp_ctrl;
SPIFLASH.user.val = reg_bkp_usr;
return ESP_OK;
}
esp_err_t spi_flash_enable_wrap(uint32_t wrap_size)
{
switch(wrap_size) {
case 8:
return spi_flash_wrap_set(FLASH_WRAP_MODE_8B);
case 16:
return spi_flash_wrap_set(FLASH_WRAP_MODE_16B);
case 32:
return spi_flash_wrap_set(FLASH_WRAP_MODE_32B);
case 64:
return spi_flash_wrap_set(FLASH_WRAP_MODE_64B);
default:
return ESP_FAIL;
}
}
void spi_flash_disable_wrap(void)
{
spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
}
bool spi_flash_support_wrap_size(uint32_t wrap_size)
{
if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO) || !REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FASTRD_MODE)){
return ESP_FAIL;
}
switch(wrap_size) {
case 0:
case 8:
case 16:
case 32:
case 64:
return true;
default:
return false;
}
}
#endif
#if defined(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) && defined(CONFIG_IDF_TARGET_ESP32S2) #if defined(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) && defined(CONFIG_IDF_TARGET_ESP32S2)
// TODO esp32s2: Remove once ESP32S2 has new SPI Flash API support // TODO esp32s2: Remove once ESP32S2 has new SPI Flash API support
esp_flash_t *esp_flash_default_chip = NULL; esp_flash_t *esp_flash_default_chip = NULL;

View File

@@ -2,6 +2,5 @@
# CMakeLists in this exact order for cmake to work correctly # CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# Flash encryption not currently supported for ESP32-S2
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(flash_encryption) project(flash_encryption)

View File

@@ -23,6 +23,13 @@ static void example_read_write_flash(void);
static const char* TAG = "example"; static const char* TAG = "example";
#if CONFIG_IDF_TARGET_ESP32
#define TARGET_CRYPT_CNT_EFUSE ESP_EFUSE_FLASH_CRYPT_CNT
#define TARGET_CRYPT_CNT_WIDTH 7
#elif CONFIG_IDF_TARGET_ESP32S2
#define TARGET_CRYPT_CNT_EFUSE ESP_EFUSE_SPI_BOOT_CRYPT_CNT
#define TARGET_CRYPT_CNT_WIDTH 3
#endif
void app_main(void) void app_main(void)
{ {
@@ -54,7 +61,7 @@ static void example_print_chip_info(void)
static void example_print_flash_encryption_status(void) static void example_print_flash_encryption_status(void)
{ {
uint32_t flash_crypt_cnt = 0; uint32_t flash_crypt_cnt = 0;
esp_efuse_read_field_blob(ESP_EFUSE_FLASH_CRYPT_CNT, &flash_crypt_cnt, 7); esp_efuse_read_field_blob(TARGET_CRYPT_CNT_EFUSE, &flash_crypt_cnt, TARGET_CRYPT_CNT_WIDTH);
printf("FLASH_CRYPT_CNT eFuse value is %d\n", flash_crypt_cnt); printf("FLASH_CRYPT_CNT eFuse value is %d\n", flash_crypt_cnt);
esp_flash_enc_mode_t mode = esp_get_flash_encryption_mode(); esp_flash_enc_mode_t mode = esp_get_flash_encryption_mode();