mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-11 21:10:05 +01:00
Flash encryption: Support enabling flash encryption in bootloader, app support
* App access functions are all flash encryption-aware * Documentation for flash encryption * Partition read/write is flash aware * New encrypted write function
This commit is contained in:
@@ -34,20 +34,6 @@ extern "C"
|
||||
#define RTC_DATA_LOW 0x50000000
|
||||
#define RTC_DATA_HIGH 0x50002000
|
||||
|
||||
#define PART_TYPE_APP 0x00
|
||||
#define PART_SUBTYPE_FACTORY 0x00
|
||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||
#define PART_SUBTYPE_OTA_MASK 0x0f
|
||||
#define PART_SUBTYPE_TEST 0x20
|
||||
|
||||
#define PART_TYPE_DATA 0x01
|
||||
#define PART_SUBTYPE_DATA_OTA 0x00
|
||||
#define PART_SUBTYPE_DATA_RF 0x01
|
||||
#define PART_SUBTYPE_DATA_WIFI 0x02
|
||||
|
||||
#define PART_TYPE_END 0xff
|
||||
#define PART_SUBTYPE_END 0xff
|
||||
|
||||
#define SPI_ERROR_LOG "spi flash error"
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
#include "bootloader_config.h"
|
||||
@@ -225,7 +226,9 @@ static bool ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
void bootloader_main()
|
||||
{
|
||||
ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOTLOADER_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)
|
||||
esp_err_t err;
|
||||
#endif
|
||||
esp_image_header_t fhdr;
|
||||
bootloader_state_t bs;
|
||||
SpiFlashOpResult spiRet1,spiRet2;
|
||||
@@ -240,7 +243,7 @@ void bootloader_main()
|
||||
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
|
||||
SPIUnlock();
|
||||
|
||||
if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) {
|
||||
if(esp_image_load_header(0x1000, true, &fhdr) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||
return;
|
||||
}
|
||||
@@ -319,12 +322,11 @@ void bootloader_main()
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
/* Generate secure digest from this bootloader to protect future
|
||||
modifications */
|
||||
esp_err_t err = esp_secure_boot_permanently_enable();
|
||||
ESP_LOGI(TAG, "Checking secure boot...");
|
||||
err = esp_secure_boot_permanently_enable();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
|
||||
/* Allow booting to continue, as the failure is probably
|
||||
@@ -333,15 +335,28 @@ void bootloader_main()
|
||||
}
|
||||
#endif
|
||||
|
||||
if(fhdr.encrypt_flag == 0x01) {
|
||||
/* encrypt flash */
|
||||
if (false == flash_encrypt(&bs)) {
|
||||
ESP_LOGE(TAG, "flash encrypt failed");
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
|
||||
/* encrypt flash */
|
||||
ESP_LOGI(TAG, "Checking flash encryption...");
|
||||
bool flash_encryption_enabled = esp_flash_encryption_enabled();
|
||||
err = esp_flash_encrypt_check_and_update();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
|
||||
/* Flash encryption was just enabled for the first time,
|
||||
so issue a system reset to ensure flash encryption
|
||||
cache resets properly */
|
||||
ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
|
||||
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// copy loaded segments to RAM, set up caches for mapped segments, and start application
|
||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
||||
unpack_load_app(&load_part_pos);
|
||||
}
|
||||
|
||||
@@ -353,7 +368,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
uint32_t image_length;
|
||||
|
||||
/* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
|
||||
err = esp_image_basic_verify(partition->offset, &image_length);
|
||||
err = esp_image_basic_verify(partition->offset, true, &image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
||||
return;
|
||||
@@ -371,7 +386,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_image_load_header(partition->offset, &image_header) != ESP_OK) {
|
||||
if (esp_image_load_header(partition->offset, true, &image_header) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset);
|
||||
return;
|
||||
}
|
||||
@@ -397,8 +412,8 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
esp_image_segment_header_t segment_header;
|
||||
uint32_t data_offs;
|
||||
if(esp_image_load_segment_header(segment, partition->offset,
|
||||
&image_header, &segment_header,
|
||||
&data_offs) != ESP_OK) {
|
||||
&image_header, true,
|
||||
&segment_header, &data_offs) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load segment header #%d", segment);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// Copyright 2015-2016 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 <string.h>
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_config.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
static const char* TAG = "flash_encrypt";
|
||||
|
||||
/**
|
||||
* @function : bitcount
|
||||
* @description: calculate bit 1 in flash_crypt_cnt
|
||||
* if it's even number, need encrypt flash data, and burn efuse
|
||||
*
|
||||
* @inputs: n flash_crypt_cnt
|
||||
* @return: number of 1 in flash_crypt_cnt
|
||||
*
|
||||
*/
|
||||
int bitcount(int n){
|
||||
int count = 0;
|
||||
while (n > 0) {
|
||||
count += n & 1;
|
||||
n >>= 1;
|
||||
}
|
||||
return count;
|
||||
|
||||
}
|
||||
/**
|
||||
* @function : flash_encrypt_write
|
||||
* @description: write encrypted data in flash
|
||||
*
|
||||
* @inputs: pos address in flash
|
||||
* len size of data need encrypt
|
||||
* @return: return true, if the write flash success
|
||||
*
|
||||
*/
|
||||
bool flash_encrypt_write(uint32_t pos, uint32_t len)
|
||||
{
|
||||
SpiFlashOpResult spiRet;
|
||||
uint32_t buf[1024];
|
||||
int i = 0;
|
||||
Cache_Read_Disable(0);
|
||||
for (i = 0;i<((len-1)/0x1000 + 1);i++) {
|
||||
spiRet = SPIRead(pos, buf, SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
spiRet = SPIEraseSector(pos/SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
spiRet = SPI_Encrypt_Write(pos, buf, SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
pos += SPI_SEC_SIZE;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @function : flash_encrypt
|
||||
* @description: encrypt 2nd boot ,partition table ,factory bin <20><>test bin (if use)<29><>ota bin
|
||||
* <20><>OTA info sector.
|
||||
*
|
||||
* @inputs: bs bootloader state structure used to save the data
|
||||
*
|
||||
* @return: return true, if the encrypt flash success
|
||||
*
|
||||
*/
|
||||
bool flash_encrypt(bootloader_state_t *bs)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t image_len = 0;
|
||||
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
|
||||
uint8_t count = bitcount(flash_crypt_cnt);
|
||||
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
|
||||
|
||||
if ((count % 2) == 0) {
|
||||
/* encrypt iv and abstract */
|
||||
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt iv and abstract error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt bootloader image */
|
||||
err = esp_image_basic_verify(0x1000, &image_len);
|
||||
if(err == ESP_OK && image_len != 0) {
|
||||
if (false == flash_encrypt_write(0x1000, image_len)) {
|
||||
ESP_LOGE(TAG, "encrypt 2nd boot error");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "2nd boot len error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt partition table */
|
||||
if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt partition table error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt write factory bin */
|
||||
if(bs->factory.offset != 0 && bs->factory.size != 0) {
|
||||
ESP_LOGD(TAG, "have factory bin");
|
||||
if (false == flash_encrypt_write(bs->factory.offset, bs->factory.size)) {
|
||||
ESP_LOGE(TAG, "encrypt factory bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write test bin */
|
||||
if(bs->test.offset != 0 && bs->test.size != 0) {
|
||||
ESP_LOGD(TAG, "have test bin");
|
||||
if (false == flash_encrypt_write(bs->test.offset, bs->test.size)) {
|
||||
ESP_LOGE(TAG, "encrypt test bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write ota bin */
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) {
|
||||
ESP_LOGD(TAG, "have ota[%d] bin",i);
|
||||
if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) {
|
||||
ESP_LOGE(TAG, "encrypt ota bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write ota info bin */
|
||||
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt ota info error");
|
||||
return false;
|
||||
}
|
||||
|
||||
REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||
ESP_LOGW(TAG, "burn flash_crypt_cnt");
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "flash already encrypted.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user