mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-04-26 19:00:34 +02:00
[BETA] Add support to Secure Boot in ESP32.
Needs deep testing. Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
|
||||
nvs, data, nvs, 0x9000, 0x6000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
nvs, data, nvs, 0x11000, 0x6000
|
||||
phy_init, data, phy, 0x17000, 0x1000
|
||||
factory, app, factory, 0x20000, 1M
|
||||
part0, 0x40, 0x1, 0x200000, 1M,
|
||||
|
||||
|
230
src/fs/otp.c
230
src/fs/otp.c
@@ -91,6 +91,137 @@ static void otp_lock_page(uint8_t page) {
|
||||
uint8_t _otp_key_1[32] = {0};
|
||||
uint8_t _otp_key_2[32] = {0};
|
||||
|
||||
static const uint8_t esp_secure_boot_digest[32] = {
|
||||
0x0c, 0x1e, 0xce, 0xf3, 0xb4, 0x8f, 0x4a, 0x81,
|
||||
0x45, 0x6c, 0x85, 0x39, 0x15, 0xcc, 0x05, 0x36,
|
||||
0xbe, 0x23, 0x24, 0xee, 0xac, 0x8e, 0x3b, 0xb5,
|
||||
0x77, 0x6f, 0x2d, 0xb9, 0x62, 0x38, 0x75, 0x6a
|
||||
};
|
||||
|
||||
static esp_efuse_purpose_t esp_secure_boot_purpose(uint8_t digest_idx) {
|
||||
switch (digest_idx) {
|
||||
case 0: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0;
|
||||
case 1: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1;
|
||||
case 2: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2;
|
||||
default: return ESP_EFUSE_KEY_PURPOSE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static bool esp_find_secure_boot_block(uint8_t digest_idx, esp_efuse_block_t *out_block) {
|
||||
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
|
||||
return false;
|
||||
}
|
||||
for (esp_efuse_block_t blk = EFUSE_BLK_KEY0; blk < EFUSE_BLK_KEY_MAX; blk++) {
|
||||
if (esp_efuse_get_key_purpose(blk) == purpose) {
|
||||
if (out_block) {
|
||||
*out_block = blk;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static esp_err_t esp_provision_secure_boot_digest(uint8_t digest_idx, esp_efuse_block_t *out_block) {
|
||||
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_efuse_block_t block = EFUSE_BLK_KEY_MAX;
|
||||
if (esp_find_secure_boot_block(digest_idx, &block)) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
if (!key_desc) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t existing[32] = {0};
|
||||
esp_err_t err = esp_efuse_read_field_blob(key_desc, existing, sizeof(existing) * 8);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (memcmp(existing, esp_secure_boot_digest, sizeof(existing)) != 0) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (out_block) {
|
||||
*out_block = block;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
block = esp_efuse_find_unused_key_block();
|
||||
if (block == EFUSE_BLK_KEY_MAX) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_efuse_batch_write_begin();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_efuse_set_key_purpose(block, purpose);
|
||||
if (err == ESP_OK) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
if (!key_desc) {
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
err = esp_efuse_write_field_blob(key_desc, esp_secure_boot_digest, sizeof(esp_secure_boot_digest) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_batch_write_commit();
|
||||
} else {
|
||||
esp_efuse_batch_write_cancel();
|
||||
}
|
||||
|
||||
if (err == ESP_OK && out_block) {
|
||||
*out_block = block;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t esp_disable_debug_interfaces(void) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
#ifdef ESP_EFUSE_SOFT_DIS_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP_EFUSE_HARD_DIS_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP_EFUSE_DIS_USB_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP_EFUSE_DIS_USB_SERIAL_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_SERIAL_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP_EFUSE_DIS_PAD_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t read_key_from_efuse(esp_efuse_block_t block, uint8_t *key, size_t key_len) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
|
||||
@@ -124,6 +255,9 @@ typedef esp_err_t otp_ret_t;
|
||||
#ifndef SECURE_BOOT_BOOTKEY_INDEX
|
||||
#define SECURE_BOOT_BOOTKEY_INDEX 0
|
||||
#endif
|
||||
#ifndef PICO_KEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK
|
||||
#define PICO_KEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK 1
|
||||
#endif
|
||||
|
||||
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
#ifdef PICO_RP2350
|
||||
@@ -151,7 +285,27 @@ bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
}
|
||||
return true;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot check for ESP32-S3
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t preferred = SECURE_BOOT_BOOTKEY_INDEX;
|
||||
if (preferred <= 2 && esp_find_secure_boot_block(preferred, NULL)
|
||||
&& !esp_efuse_get_digest_revoke(preferred)) {
|
||||
if (bootkey) {
|
||||
*bootkey = preferred;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (esp_find_secure_boot_block(idx, NULL) && !esp_efuse_get_digest_revoke(idx)) {
|
||||
if (bootkey) {
|
||||
*bootkey = idx;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -174,7 +328,15 @@ bool otp_is_secure_boot_locked() {
|
||||
}
|
||||
return bootkey_idx != 0xFF;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot lock check for ESP32-S3
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (idx == bootkey_idx) {
|
||||
continue;
|
||||
}
|
||||
if (!esp_efuse_get_digest_revoke(idx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -224,7 +386,69 @@ int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot for ESP32-S3
|
||||
if (bootkey > 2) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (secure_lock && PICO_KEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK) {
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
printf("Secure lock requires SECURE_BOOT_EN already set. Enable secure boot first.\n");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
esp_efuse_block_t key_block = EFUSE_BLK_KEY_MAX;
|
||||
esp_err_t err = esp_provision_secure_boot_digest(bootkey, &key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error provisioning secure boot digest %u [%d]\n", bootkey, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error enabling secure boot [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (secure_lock) {
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (idx == bootkey) {
|
||||
continue;
|
||||
}
|
||||
err = esp_efuse_set_digest_revoke(idx);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error revoking secure boot digest %u [%d]\n", idx, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = esp_efuse_set_key_dis_write(key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error setting secure boot key block read only [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
err = esp_efuse_set_keypurpose_dis_write(key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error setting secure boot key purpose read only [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* // Not sure if it allows future upgrades if ROM download mode is disabled, so leaving it enabled for now
|
||||
err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
printf("Error disabling ROM download mode [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
*/
|
||||
|
||||
err = esp_disable_debug_interfaces();
|
||||
if (err != ESP_OK) {
|
||||
printf("Error disabling JTAG interfaces [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
|
||||
@@ -38,6 +38,7 @@ extern int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
#define OTP_KEY_1 EFUSE_BLK_KEY3
|
||||
#define OTP_KEY_2 EFUSE_BLK_KEY4
|
||||
|
||||
Reference in New Issue
Block a user