4#ifdef USE_OTA_SIGNED_VERIFICATION_MULTI_KEY
12#include <esp_image_format.h>
13#include <esp_partition.h>
14#include <esp_rom_crc.h>
16#include <esp_idf_version.h>
17#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
22#define USE_OTA_SIG_PSA
24#include <psa/crypto.h>
26#include <mbedtls/md.h>
27#include <mbedtls/rsa.h>
28#include <mbedtls/sha256.h>
33static const char *
const TAG =
"ota";
39#define OTA_IDF_SIG_LOG(level, msg) level(TAG, "Signature check: %s", msg)
40#define OTA_IDF_SIG_LOG_BLOCK(level, i, msg) level(TAG, "Signature check: block %zu: %s", static_cast<size_t>(i), msg)
48constexpr uint8_t SIG_BLOCK_MAGIC = 0xE7;
49constexpr uint8_t SIG_BLOCK_VERSION_RSA = 0x02;
50constexpr size_t SIG_BLOCK_SIZE = 1216;
51constexpr size_t SIG_SECTOR_ALIGN = 4096;
52constexpr size_t SIG_BLOCK_MAX_COUNT = 3;
53constexpr size_t RSA_3072_BYTES = 384;
54constexpr size_t SHA256_BYTES = 32;
56constexpr size_t OFFSET_KEY = 36;
57constexpr size_t KEY_REGION_LEN = 776;
58constexpr size_t OFFSET_MODULUS = 36;
59constexpr size_t OFFSET_EXPONENT = 420;
60constexpr size_t OFFSET_SIGNATURE = 812;
61constexpr size_t OFFSET_CRC = 1196;
67using KeyDigest = std::array<uint8_t, SHA256_BYTES>;
68constexpr uint8_t TRUSTED_KEY_DIGESTS[OTA_TRUSTED_KEY_COUNT][SHA256_BYTES] = OTA_TRUSTED_KEY_DIGESTS;
73bool block_is_valid(
const uint8_t *block) {
74 if (block[0] != SIG_BLOCK_MAGIC || block[1] != SIG_BLOCK_VERSION_RSA) {
78 memcpy(&stored_crc, block + OFFSET_CRC,
sizeof(stored_crc));
79 return esp_rom_crc32_le(0, block, OFFSET_CRC) == stored_crc;
82bool key_digest_of(
const uint8_t *block, KeyDigest &out) {
85 return psa_hash_compute(PSA_ALG_SHA_256, block + OFFSET_KEY, KEY_REGION_LEN, out.data(), out.size(), &out_len) ==
87 out_len == out.size();
89 return mbedtls_sha256(block + OFFSET_KEY, KEY_REGION_LEN, out.data(), 0) == 0;
94bool signature_sector_offset(
const esp_partition_t *part,
size_t &out_offset) {
95 esp_partition_pos_t
pos{.offset = part->address, .size = part->size};
96 esp_image_metadata_t meta{};
97 if (esp_image_get_metadata(&
pos, &meta) != ESP_OK) {
102 if (meta.image_len > part->size) {
105 out_offset = (meta.image_len + SIG_SECTOR_ALIGN - 1) & ~(SIG_SECTOR_ALIGN - 1);
106 return out_offset + SIG_BLOCK_SIZE <= part->size;
112bool image_digest(
const esp_partition_t *part,
size_t image_padded_len, uint8_t *out) {
113#ifdef USE_OTA_SIG_PSA
114 psa_hash_operation_t ctx = PSA_HASH_OPERATION_INIT;
115 bool ok = psa_hash_setup(&ctx, PSA_ALG_SHA_256) == PSA_SUCCESS;
117 mbedtls_sha256_context ctx;
118 mbedtls_sha256_init(&ctx);
119 bool ok = mbedtls_sha256_starts(&ctx, 0) == 0;
122 for (
size_t off = 0; ok && off < image_padded_len; off +=
sizeof(buf)) {
123 size_t chunk = std::min(
sizeof(buf), image_padded_len - off);
124 if (esp_partition_read(part, off, buf, chunk) != ESP_OK) {
128#ifdef USE_OTA_SIG_PSA
129 ok = psa_hash_update(&ctx, buf, chunk) == PSA_SUCCESS;
131 ok = mbedtls_sha256_update(&ctx, buf, chunk) == 0;
134#ifdef USE_OTA_SIG_PSA
137 ok = psa_hash_finish(&ctx, out, SHA256_BYTES, &out_len) == PSA_SUCCESS && out_len == SHA256_BYTES;
140 psa_hash_abort(&ctx);
143 ok = mbedtls_sha256_finish(&ctx, out) == 0;
145 mbedtls_sha256_free(&ctx);
155bool rsa_pss_verify(uint8_t *block,
const uint8_t *digest) {
156 std::reverse(block + OFFSET_MODULUS, block + OFFSET_MODULUS + RSA_3072_BYTES);
157 std::reverse(block + OFFSET_SIGNATURE, block + OFFSET_SIGNATURE + RSA_3072_BYTES);
159 memcpy(&exponent_le, block + OFFSET_EXPONENT,
sizeof(exponent_le));
160 uint8_t exponent_be[4] = {
static_cast<uint8_t
>(exponent_le >> 24),
static_cast<uint8_t
>(exponent_le >> 16),
161 static_cast<uint8_t
>(exponent_le >> 8),
static_cast<uint8_t
>(exponent_le)};
163#ifdef USE_OTA_SIG_PSA
164 static_assert(RSA_3072_BYTES ==
RSA_3072_MODULUS_BYTES,
"signature block and DER encoder disagree on modulus size");
166 const size_t der_len =
rsa_der_public_key(block + OFFSET_MODULUS, exponent_be,
sizeof(exponent_be), der,
sizeof(der));
167 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
168 psa_set_key_type(&attr, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
169 psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH);
173 psa_set_key_algorithm(&attr, PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256));
174 mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
175 const bool key_ok = der_len != 0 && psa_import_key(&attr, der, der_len, &key) == PSA_SUCCESS;
177 mbedtls_rsa_context rsa;
178 mbedtls_rsa_init(&rsa);
179 const bool key_ok = mbedtls_rsa_import_raw(&rsa, block + OFFSET_MODULUS, RSA_3072_BYTES,
nullptr, 0,
nullptr, 0,
180 nullptr, 0, exponent_be,
sizeof(exponent_be)) == 0 &&
181 mbedtls_rsa_complete(&rsa) == 0 &&
182 mbedtls_rsa_set_padding(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256) == 0;
184 bool verified =
false;
188 OTA_IDF_SIG_LOG(ESP_LOGE,
"RSA key setup failed");
190#ifdef USE_OTA_SIG_PSA
191 verified = psa_verify_hash(key, PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256), digest, SHA256_BYTES,
192 block + OFFSET_SIGNATURE, RSA_3072_BYTES) == PSA_SUCCESS;
195 mbedtls_rsa_rsassa_pss_verify(&rsa, MBEDTLS_MD_SHA256, SHA256_BYTES, digest, block + OFFSET_SIGNATURE) == 0;
198#ifdef USE_OTA_SIG_PSA
200 psa_destroy_key(key);
203 mbedtls_rsa_free(&rsa);
210bool IDFOTABackend::verify_signed_image_(
const esp_partition_t *incoming) {
214 const uint32_t verify_budget_ms = 15000 + (incoming->size >> 10) * 10;
215 watchdog::WatchdogManager watchdog(verify_budget_ms);
217 size_t incoming_sector;
218 if (!signature_sector_offset(incoming, incoming_sector)) {
219 OTA_IDF_SIG_LOG(ESP_LOGE,
"cannot locate incoming signature sector");
222 uint8_t digest[SHA256_BYTES];
223 if (!image_digest(incoming, incoming_sector, digest)) {
224 OTA_IDF_SIG_LOG(ESP_LOGE,
"cannot hash incoming image");
243 OTA_IDF_SIG_LOG(ESP_LOGE,
"out of memory");
246 bool any_valid_block =
false;
247 for (
size_t i = 0; i < SIG_BLOCK_MAX_COUNT; i++) {
248 size_t off = incoming_sector + i * SIG_BLOCK_SIZE;
249 if (off + SIG_BLOCK_SIZE > incoming->size) {
253 if (esp_partition_read(incoming, off, block.get(), SIG_BLOCK_SIZE) != ESP_OK) {
254 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGE, i,
"unreadable");
257 if (!block_is_valid(block.get())) {
258 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGD, i,
"absent or malformed");
261 any_valid_block =
true;
262 KeyDigest incoming_key;
263 if (!key_digest_of(block.get(), incoming_key)) {
264 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGE, i,
"key hash failed");
267 bool trusted_key =
false;
268 for (
const auto &trusted : TRUSTED_KEY_DIGESTS) {
269 if (memcmp(incoming_key.data(), trusted, SHA256_BYTES) == 0) {
275 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGW, i,
"signed by an untrusted key");
278 if (rsa_pss_verify(block.get(), digest)) {
279 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGD, i,
"verified with a trusted key");
282 OTA_IDF_SIG_LOG_BLOCK(ESP_LOGW, i,
"trusted key failed to verify");
287 if (!any_valid_block) {
288 OTA_IDF_SIG_LOG(ESP_LOGE,
"image has no signature block");
290 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