feat(partition_table): Support primary subtypes partitions

This commit is contained in:
Konstantin Kondrashov
2024-10-14 20:45:24 +03:00
parent 7d179ccd3e
commit 8c4f576f99
12 changed files with 264 additions and 79 deletions

View File

@@ -43,7 +43,7 @@ static const char *TAG = "flash_encrypt";
/* Static functions for stages of flash encryption */
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(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
static size_t get_flash_encrypt_cnt_value(void);
@@ -262,12 +262,12 @@ esp_err_t esp_flash_encrypt_contents(void)
esp_flash_encryption_enable_key_mgr();
#endif
err = encrypt_bootloader();
err = encrypt_bootloader(); // PART_SUBTYPE_BOOTLOADER_PRIMARY
if (err != ESP_OK) {
return err;
}
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
err = encrypt_and_load_partition_table(ESP_PRIMARY_PARTITION_TABLE_OFFSET, partition_table, &num_partitions); // PART_SUBTYPE_PARTITION_TABLE_PRIMARY
if (err != ESP_OK) {
return err;
}
@@ -277,6 +277,14 @@ esp_err_t esp_flash_encrypt_contents(void)
/* Go through each partition and encrypt if necessary */
for (int i = 0; i < num_partitions; i++) {
if ((partition_table[i].type == PART_TYPE_BOOTLOADER && partition_table[i].subtype == PART_SUBTYPE_BOOTLOADER_PRIMARY)
|| (partition_table[i].type == PART_TYPE_PARTITION_TABLE && partition_table[i].subtype == PART_SUBTYPE_PARTITION_TABLE_PRIMARY)) {
/* Skip encryption of PRIMARY partitions for bootloader and partition table.
* PRIMARY partitions have already been encrypted above.
* We allow to encrypt partitions that are not PRIMARY.
*/
continue;
}
err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) {
return err;
@@ -337,13 +345,13 @@ static esp_err_t encrypt_bootloader(void)
#if CONFIG_SECURE_BOOT_V2_ENABLED
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
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);
if (image_length > ESP_BOOTLOADER_SIZE) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PRIMARY_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_PRIMARY_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
@@ -368,33 +376,37 @@ static esp_err_t encrypt_bootloader(void)
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 read_and_verify_partition_table(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err;
/* Check for plaintext partition table */
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
err = bootloader_flash_read(offset, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data");
ESP_LOGE(TAG, "Failed to read partition table data at 0x%" PRIx32, offset);
return err;
}
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
} else {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
return ESP_ERR_INVALID_STATE;
err = esp_partition_table_verify(partition_table, false, num_partitions);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext or empty?");
}
/* Valid partition table loaded */
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return ESP_OK;
return err;
}
static esp_err_t encrypt_and_load_partition_table(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err = read_and_verify_partition_table(offset, partition_table, num_partitions);
if (err != ESP_OK) {
return err;
}
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
err = esp_flash_encrypt_region(offset, FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return err;
}
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
{
@@ -402,19 +414,26 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
uint32_t size = partition->pos.size;
if (partition->type == PART_TYPE_APP) {
/* check if the partition holds a valid unencrypted app */
if (partition->type == PART_TYPE_APP || partition->type == PART_TYPE_BOOTLOADER) {
/* check if the partition holds a valid unencrypted app/bootloader */
esp_image_metadata_t image_data = {};
err = esp_image_verify(ESP_IMAGE_VERIFY,
&partition->pos,
&image_data);
if (partition->type == PART_TYPE_BOOTLOADER) {
esp_image_bootloader_offset_set(partition->pos.offset);
}
err = esp_image_verify(ESP_IMAGE_VERIFY, &partition->pos, &image_data);
should_encrypt = (err == ESP_OK);
#ifdef CONFIG_SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART
if (should_encrypt) {
if (partition->type == PART_TYPE_APP && should_encrypt) {
// Encrypt only the app image instead of encrypting the whole partition
size = image_data.image_len;
}
#endif
} else if (partition->type == PART_TYPE_PARTITION_TABLE) {
/* check if the partition holds a valid unencrypted partition table */
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
err = read_and_verify_partition_table(partition->pos.offset, partition_table, &num_partitions);
should_encrypt = (err == ESP_OK && num_partitions != 0);
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */