4#ifdef USE_OTA_SIGNED_VERIFICATION_MULTI_KEY
13#include <esp_image_format.h>
14#include <esp_partition.h>
15#include <esp_rom_crc.h>
17#include <esp_idf_version.h>
18#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
23#define USE_OTA_SIG_PSA
25#include <psa/crypto.h>
27#include <mbedtls/md.h>
28#include <mbedtls/rsa.h>
29#include <mbedtls/sha256.h>
34static const char *
const TAG =
"ota.idf";
40#define OTA_IDF_SIG_LOG(level, msg) level(TAG, "Signature check: %s", msg)
41#define OTA_IDF_SIG_LOG_BLOCK(level, i, msg) level(TAG, "Signature check: block %zu: %s", static_cast<size_t>(i), msg)
49constexpr uint8_t SIG_BLOCK_MAGIC = 0xE7;
50constexpr uint8_t SIG_BLOCK_VERSION_RSA = 0x02;
51constexpr size_t SIG_BLOCK_SIZE = 1216;
52constexpr size_t SIG_SECTOR_ALIGN = 4096;
53constexpr size_t SIG_BLOCK_MAX_COUNT = 3;
54constexpr size_t RSA_3072_BYTES = 384;
55constexpr size_t SHA256_BYTES = 32;
57constexpr size_t OFFSET_KEY = 36;
58constexpr size_t KEY_REGION_LEN = 776;
59constexpr size_t OFFSET_MODULUS = 36;
60constexpr size_t OFFSET_EXPONENT = 420;
61constexpr size_t OFFSET_SIGNATURE = 812;
62constexpr size_t OFFSET_CRC = 1196;
68using KeyDigest = std::array<uint8_t, SHA256_BYTES>;
69constexpr uint8_t TRUSTED_KEY_DIGESTS[OTA_TRUSTED_KEY_COUNT][SHA256_BYTES] = OTA_TRUSTED_KEY_DIGESTS;
74bool block_is_valid(
const uint8_t *block) {
75 if (block[0] != SIG_BLOCK_MAGIC || block[1] != SIG_BLOCK_VERSION_RSA) {
79 memcpy(&stored_crc, block + OFFSET_CRC,
sizeof(stored_crc));
80 return esp_rom_crc32_le(0, block, OFFSET_CRC) == stored_crc;
83bool key_digest_of(
const uint8_t *block, KeyDigest &out) {
86 return psa_hash_compute(PSA_ALG_SHA_256, block + OFFSET_KEY, KEY_REGION_LEN, out.data(), out.size(), &out_len) ==
88 out_len == out.size();
90 return mbedtls_sha256(block + OFFSET_KEY, KEY_REGION_LEN, out.data(), 0) == 0;
95bool signature_sector_offset(
const esp_partition_t *part,
size_t &out_offset) {
96 esp_partition_pos_t
pos{.offset = part->address, .size = part->size};
97 esp_image_metadata_t meta{};
98 if (esp_image_get_metadata(&
pos, &meta) != ESP_OK) {
103 if (meta.image_len > part->size) {
106 out_offset = (meta.image_len + SIG_SECTOR_ALIGN - 1) & ~(SIG_SECTOR_ALIGN - 1);
107 return out_offset + SIG_BLOCK_SIZE <= part->size;
113bool image_digest(
const esp_partition_t *part,
size_t image_padded_len, uint8_t *out) {
114#ifdef USE_OTA_SIG_PSA
115 psa_hash_operation_t ctx = PSA_HASH_OPERATION_INIT;
116 bool ok = psa_hash_setup(&ctx, PSA_ALG_SHA_256) == PSA_SUCCESS;
118 mbedtls_sha256_context ctx;
119 mbedtls_sha256_init(&ctx);
120 bool ok = mbedtls_sha256_starts(&ctx, 0) == 0;
123 for (
size_t off = 0; ok && off < image_padded_len; off +=
sizeof(buf)) {
124 size_t chunk = std::min(
sizeof(buf), image_padded_len - off);
125 if (esp_partition_read(part, off, buf, chunk) != ESP_OK) {
129#ifdef USE_OTA_SIG_PSA
130 ok = psa_hash_update(&ctx, buf, chunk) == PSA_SUCCESS;
132 ok = mbedtls_sha256_update(&ctx, buf, chunk) == 0;
135#ifdef USE_OTA_SIG_PSA
138 ok = psa_hash_finish(&ctx, out, SHA256_BYTES, &out_len) == PSA_SUCCESS && out_len == SHA256_BYTES;
141 psa_hash_abort(&ctx);
144 ok = mbedtls_sha256_finish(&ctx, out) == 0;
146 mbedtls_sha256_free(&ctx);
156bool rsa_pss_verify(uint8_t *block,
const uint8_t *digest) {
157 std::reverse(block + OFFSET_MODULUS, block + OFFSET_MODULUS + RSA_3072_BYTES);
158 std::reverse(block + OFFSET_SIGNATURE, block + OFFSET_SIGNATURE + RSA_3072_BYTES);
160 memcpy(&exponent_le, block + OFFSET_EXPONENT,
sizeof(exponent_le));
161 uint8_t exponent_be[4] = {
static_cast<uint8_t
>(exponent_le >> 24),
static_cast<uint8_t
>(exponent_le >> 16),
162 static_cast<uint8_t
>(exponent_le >> 8),
static_cast<uint8_t
>(exponent_le)};
164#ifdef USE_OTA_SIG_PSA
165 static_assert(RSA_3072_BYTES ==
RSA_3072_MODULUS_BYTES,
"signature block and DER encoder disagree on modulus size");
167 const size_t der_len =
rsa_der_public_key(block + OFFSET_MODULUS, exponent_be,
sizeof(exponent_be), der,
sizeof(der));
168 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
169 psa_set_key_type(&attr, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
170 psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH);
174 psa_set_key_algorithm(&attr, PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256));
175 mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
176 const bool key_ok = der_len != 0 && psa_import_key(&attr, der, der_len, &key) == PSA_SUCCESS;
178 mbedtls_rsa_context rsa;
179 mbedtls_rsa_init(&rsa);
180 const bool key_ok = mbedtls_rsa_import_raw(&rsa, block + OFFSET_MODULUS, RSA_3072_BYTES,
nullptr, 0,
nullptr, 0,
181 nullptr, 0, exponent_be,
sizeof(exponent_be)) == 0 &&
182 mbedtls_rsa_complete(&rsa) == 0 &&
183 mbedtls_rsa_set_padding(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256) == 0;
185 bool verified =
false;
189 OTA_IDF_SIG_LOG(ESP_LOGE,
"RSA key setup failed");
191#ifdef USE_OTA_SIG_PSA
192 verified = psa_verify_hash(key, PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256), digest, SHA256_BYTES,
193 block + OFFSET_SIGNATURE, RSA_3072_BYTES) == PSA_SUCCESS;
196 mbedtls_rsa_rsassa_pss_verify(&rsa, MBEDTLS_MD_SHA256, SHA256_BYTES, digest, block + OFFSET_SIGNATURE) == 0;
199#ifdef USE_OTA_SIG_PSA
201 psa_destroy_key(key);
204 mbedtls_rsa_free(&rsa);
211bool IDFOTABackend::verify_signed_image_(
const esp_partition_t *incoming) {
215 const uint32_t verify_budget_ms = 15000 + (incoming->size >> 10) * 10;
216 watchdog::WatchdogManager watchdog(verify_budget_ms);
218 size_t incoming_sector;
219 if (!signature_sector_offset(incoming, incoming_sector)) {
220 OTA_IDF_SIG_LOG(ESP_LOGE,
"cannot locate incoming signature sector");
223 uint8_t digest[SHA256_BYTES];
224 if (!image_digest(incoming, incoming_sector, digest)) {
225 OTA_IDF_SIG_LOG(ESP_LOGE,
"cannot hash incoming image");
240 std::unique_ptr<uint8_t[]> block(
new (std::nothrow) uint8_t[SIG_BLOCK_SIZE]);
242 OTA_IDF_SIG_LOG(ESP_LOGE,
"out of memory");
245 bool any_valid_block =
false;
246 for (
size_t i = 0; i < SIG_BLOCK_MAX_COUNT; i++) {
247 size_t off = incoming_sector + i * SIG_BLOCK_SIZE;
248 if (off + SIG_BLOCK_SIZE > incoming->size) {
252 if (esp_partition_read(incoming, off, block.get(), SIG_BLOCK_SIZE) != ESP_OK) {
253 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGE, i,
"unreadable");
256 if (!block_is_valid(block.get())) {
257 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGD, i,
"absent or malformed");
260 any_valid_block =
true;
261 KeyDigest incoming_key;
262 if (!key_digest_of(block.get(), incoming_key)) {
263 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGE, i,
"key hash failed");
266 bool trusted_key =
false;
267 for (
const auto &trusted : TRUSTED_KEY_DIGESTS) {
268 if (memcmp(incoming_key.data(), trusted, SHA256_BYTES) == 0) {
274 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGW, i,
"signed by an untrusted key");
277 if (rsa_pss_verify(block.get(), digest)) {
278 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGD, i,
"verified with a trusted key");
281 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGW, i,
"trusted key failed to verify");
286 if (!any_valid_block) {
287 OTA_IDF_SIG_LOG(ESP_LOGE,
"image has no signature block");
289 OTA_IDF_SIG_LOG(ESP_LOGE,
"no trusted key produced a valid signature");
constexpr size_t RSA_3072_MODULUS_BYTES
size_t rsa_der_public_key(const uint8_t *modulus_be, const uint8_t *exponent_be, size_t exponent_len, uint8_t *out, size_t out_len)
Wrap a raw RSA-3072 modulus and exponent as a DER RSAPublicKey.
constexpr size_t RSA_DER_PUBKEY_MAX