secure_boot: Secure Boot V2 verify app signature on update (without Secure boot)

- ESP32 ECO3, ESP32-S2/C3/S3
This commit is contained in:
KonstantinKondrashov
2021-03-05 22:22:29 +08:00
committed by bot
parent 9de1591660
commit 95564b4687
30 changed files with 934 additions and 960 deletions

View File

@@ -19,7 +19,6 @@
#include "esp_log.h"
#include "esp32/rom/cache.h"
#include "esp_rom_crc.h"
#include "soc/efuse_periph.h"
#include "soc/rtc_periph.h"
@@ -223,16 +222,12 @@ esp_err_t esp_secure_boot_permanently_enable(void)
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "secure_boot_v2";
#define SIG_BLOCK_MAGIC_BYTE 0xe7
#define CRC_SIGN_BLOCK_LEN 1196
#define SIG_BLOCK_PADDING 4096
#define DIGEST_LEN 32
static esp_err_t validate_signature_block(const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)sig_block, CRC_SIGN_BLOCK_LEN);
if (sig_block->block[0].magic_byte == SIG_BLOCK_MAGIC_BYTE && sig_block->block[0].block_crc == crc && !memcmp(digest, sig_block->block[0].image_digest, DIGEST_LEN)) {
if (sig_block->block[0].magic_byte == ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
&& sig_block->block[0].block_crc == crc
&& !memcmp(digest, sig_block->block[0].image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "valid signature block found");
return ESP_OK;
}
@@ -243,7 +238,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
{
esp_err_t ret = ESP_FAIL;
uint8_t image_digest[DIGEST_LEN] = {0};
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
if (ret != ESP_OK) {
@@ -266,7 +261,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
}
/* Verifying Signature block */
uint8_t verified_digest[DIGEST_LEN] = {0};
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
@@ -318,7 +313,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
return ret;
}
uint8_t boot_pub_key_digest[DIGEST_LEN];
uint8_t boot_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
@@ -350,7 +345,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
}
ESP_LOGI(TAG, "Burning public key hash to efuse.");
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (DIGEST_LEN * 8));
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (ESP_SECURE_BOOT_DIGEST_LEN * 8));
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Writing public key hash to efuse failed.");
return ret;
@@ -366,7 +361,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
efuse_blk2_digest[5] = efuse_blk2_r5;
efuse_blk2_digest[6] = efuse_blk2_r6;
efuse_blk2_digest[7] = efuse_blk2_r7;
memcpy(boot_pub_key_digest, efuse_blk2_digest, DIGEST_LEN);
memcpy(boot_pub_key_digest, efuse_blk2_digest, ESP_SECURE_BOOT_DIGEST_LEN);
ESP_LOGW(TAG, "Using pre-loaded secure boot v2 public key digest in EFUSE block 2");
}
@@ -380,7 +375,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
efuse_key_write_protected = true;
}
uint8_t app_pub_key_digest[DIGEST_LEN];
uint8_t app_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, app_pub_key_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Application signature block is invalid.");
@@ -388,7 +383,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
}
/* Confirming if the public key in the bootloader's signature block matches with the one in the application's signature block */
if (memcmp(boot_pub_key_digest, app_pub_key_digest, DIGEST_LEN) != 0) {
if (memcmp(boot_pub_key_digest, app_pub_key_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0) {
ESP_LOGE(TAG, "Application not signed with a valid private key.");
return ESP_FAIL;
}

View File

@@ -1,184 +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 "sdkconfig.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_log.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_spi_flash.h"
#include "esp_fault.h"
#include "esp32/rom/sha.h"
#include "uECC_verify_antifault.h"
#include <sys/param.h>
#include <string.h>
static const char *TAG = "secure_boot";
#define DIGEST_LEN 32
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
#define SIGNATURE_VERIFICATION_KEYLEN 64
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[DIGEST_LEN];
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* ignored in this function */
const esp_secure_boot_sig_block_t *sigblock;
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
if (err != ESP_OK) {
return err;
}
// Map the signature block
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
if(!sigblock) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
return ESP_FAIL;
}
// Verify the signature
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
// Unmap
bootloader_munmap(sigblock);
return err;
}
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
{
uint8_t verified_digest[DIGEST_LEN] = { 0 };
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
}
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
{
ptrdiff_t keylen;
keylen = signature_verification_key_end - signature_verification_key_start;
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
return ESP_FAIL;
}
if (sig_block->version != 0) {
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
return ESP_FAIL;
}
ESP_LOGD(TAG, "Verifying secure boot signature");
bool is_valid;
is_valid = uECC_verify_antifault(signature_verification_key_start,
image_digest,
DIGEST_LEN,
sig_block->signature,
uECC_secp256r1(),
verified_digest);
ESP_LOGD(TAG, "Verification result %d", is_valid);
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[DIGEST_LEN] = {0};
uint8_t verified_digest[DIGEST_LEN] = {0}; // ignored in this function
const uint8_t *data;
/* Padding to round off the input to the nearest 4k boundary */
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
data = bootloader_mmap(src_addr, padded_length + sizeof(ets_secure_boot_signature_t));
if (data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, padded_length);
return ESP_FAIL;
}
/* Calculate digest of main image */
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
bootloader_munmap(data);
return err;
}
const ets_secure_boot_signature_t *sig_block = (const ets_secure_boot_signature_t *)(data + padded_length);
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
}
bootloader_munmap(data);
return err;
}
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
{
secure_boot_v2_status_t r;
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, sig_block_trusted_digest[DIGEST_LEN] = {0};
memcpy(efuse_trusted_digest, (uint8_t *)EFUSE_BLK2_RDATA0_REG, DIGEST_LEN); /* EFUSE_BLK2_RDATA0_REG - Stores the Secure Boot Public Key Digest */
if (!ets_use_secure_boot_v2()) {
ESP_LOGI(TAG, "Secure Boot eFuse bit(ABS_DONE_1) not yet programmed.");
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
sig_block_sha = bootloader_sha256_start();
bootloader_sha256_data(sig_block_sha, &sig_block->block[0].key, sizeof(sig_block->block[0].key));
bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_trusted_digest);
#if CONFIG_SECURE_BOOT_V2_ENABLED
if (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
/* Most likely explanation for this is that BLK2 is empty, and we're going to burn it
after we verify that the signature is valid. However, if BLK2 is not empty then we need to
fail here.
*/
bool all_zeroes = true;
for (int i = 0; i < DIGEST_LEN; i++) {
all_zeroes = all_zeroes && (efuse_trusted_digest[i] == 0);
}
if (!all_zeroes) {
ESP_LOGE(TAG, "Different public key digest burned to eFuse BLK2");
return ESP_ERR_INVALID_STATE;
}
}
ESP_FAULT_ASSERT(!ets_use_secure_boot_v2());
#endif
memcpy(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN);
}
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
r = ets_secure_boot_verify_signature(sig_block, image_digest, efuse_trusted_digest, verified_digest);
if (r != SBV2_SUCCESS) {
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
}
return (r == SBV2_SUCCESS) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}
#endif