@@ -242,44 +242,140 @@ static bool isValidBootloader(const uint8_t* data, size_t len) {
242242 uint8_t segmentCount = data[1 ];
243243 if (segmentCount > 16 ) return false ;
244244
245- // Use ESP-IDF image verification for more thorough validation
246- esp_image_metadata_t metadata;
247- esp_image_load_mode_t mode = ESP_IMAGE_VERIFY;
248-
249- // Create a simple data structure for verification
250- // Note: esp_image_verify expects data in flash, so we do basic checks here
251- // The full verification will be done after buffering is complete
252-
253245 return true ;
254246}
255247
256- // Verify complete buffered bootloader using ESP-IDF validation
248+ // Verify complete buffered bootloader using ESP-IDF validation approach
249+ // This matches the key validation steps from esp_image_verify() in ESP-IDF
257250static bool verifyBootloaderImage (const uint8_t * buffer, size_t len) {
258- // Basic magic byte check
259- if (len < 32 || buffer[0 ] != 0xE9 ) {
251+ // ESP32 image header structure (based on esp_image_format.h)
252+ // Offset 0: magic (0xE9)
253+ // Offset 1: segment_count
254+ // Offset 2: spi_mode
255+ // Offset 3: spi_speed (4 bits) + spi_size (4 bits)
256+ // Offset 4-7: entry_addr (uint32_t)
257+ // Offset 8: wp_pin
258+ // Offset 9-11: spi_pin_drv[3]
259+ // Offset 12-13: chip_id (uint16_t, little-endian)
260+ // Offset 14: min_chip_rev
261+ // Offset 15-22: reserved[8]
262+ // Offset 23: hash_appended
263+
264+ const size_t MIN_IMAGE_HEADER_SIZE = 24 ;
265+
266+ // 1. Validate minimum size for header
267+ if (len < MIN_IMAGE_HEADER_SIZE) {
268+ DEBUG_PRINTLN (F (" Bootloader too small - invalid header" ));
269+ return false ;
270+ }
271+
272+ // 2. Magic byte check (matches esp_image_verify step 1)
273+ if (buffer[0 ] != 0xE9 ) {
260274 DEBUG_PRINTLN (F (" Invalid bootloader magic byte" ));
261275 return false ;
262276 }
263277
264- // Check segment count
278+ // 3. Segment count validation (matches esp_image_verify step 2)
265279 uint8_t segmentCount = buffer[1 ];
266- if (segmentCount > 16 ) {
267- DEBUG_PRINTLN (F (" Invalid segment count" ));
280+ if (segmentCount == 0 || segmentCount > 16 ) {
281+ DEBUG_PRINTF_P (PSTR (" Invalid segment count: %d\n " ), segmentCount);
282+ return false ;
283+ }
284+
285+ // 4. SPI mode validation (basic sanity check)
286+ uint8_t spiMode = buffer[2 ];
287+ if (spiMode > 3 ) { // Valid modes are 0-3 (QIO, QOUT, DIO, DOUT)
288+ DEBUG_PRINTF_P (PSTR (" Invalid SPI mode: %d\n " ), spiMode);
268289 return false ;
269290 }
270291
271- // Verify chip ID matches (basic check - the image header contains chip ID at offset 12)
272- if (len >= 16 ) {
273- uint16_t chipId = (buffer[13 ] << 8 ) | buffer[12 ];
274- // ESP32 chip IDs: 0x0000 (ESP32), 0x0002 (ESP32-S2), 0x0005 (ESP32-C3), 0x0009 (ESP32-S3), etc.
275- // For now, we just check it's not obviously wrong
292+ // 5. Chip ID validation (matches esp_image_verify step 3)
293+ uint16_t chipId = buffer[12 ] | (buffer[13 ] << 8 ); // Little-endian
294+
295+ // Known ESP32 chip IDs from ESP-IDF:
296+ // 0x0000 = ESP32
297+ // 0x0002 = ESP32-S2
298+ // 0x0005 = ESP32-C3
299+ // 0x0009 = ESP32-S3
300+ // 0x000C = ESP32-C2
301+ // 0x000D = ESP32-C6
302+ // 0x0010 = ESP32-H2
303+
304+ #if defined(CONFIG_IDF_TARGET_ESP32)
305+ if (chipId != 0x0000 ) {
306+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32 (0x0000), got 0x%04X\n " ), chipId);
307+ return false ;
308+ }
309+ #elif defined(CONFIG_IDF_TARGET_ESP32S2)
310+ if (chipId != 0x0002 ) {
311+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-S2 (0x0002), got 0x%04X\n " ), chipId);
312+ return false ;
313+ }
314+ #elif defined(CONFIG_IDF_TARGET_ESP32C3)
315+ if (chipId != 0x0005 ) {
316+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-C3 (0x0005), got 0x%04X\n " ), chipId);
317+ return false ;
318+ }
319+ #elif defined(CONFIG_IDF_TARGET_ESP32S3)
320+ if (chipId != 0x0009 ) {
321+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-S3 (0x0009), got 0x%04X\n " ), chipId);
322+ return false ;
323+ }
324+ #elif defined(CONFIG_IDF_TARGET_ESP32C2)
325+ if (chipId != 0x000C ) {
326+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-C2 (0x000C), got 0x%04X\n " ), chipId);
327+ return false ;
328+ }
329+ #elif defined(CONFIG_IDF_TARGET_ESP32C6)
330+ if (chipId != 0x000D ) {
331+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-C6 (0x000D), got 0x%04X\n " ), chipId);
332+ return false ;
333+ }
334+ #elif defined(CONFIG_IDF_TARGET_ESP32H2)
335+ if (chipId != 0x0010 ) {
336+ DEBUG_PRINTF_P (PSTR (" Chip ID mismatch - expected ESP32-H2 (0x0010), got 0x%04X\n " ), chipId);
337+ return false ;
338+ }
339+ #else
340+ // Generic validation - chip ID should be valid
276341 if (chipId > 0x00FF ) {
277- DEBUG_PRINTLN ( F (" Invalid chip ID in bootloader " ) );
342+ DEBUG_PRINTF_P ( PSTR (" Invalid chip ID: 0x%04X \n " ), chipId );
278343 return false ;
279344 }
345+ #endif
346+
347+ // 6. Entry point validation (should be in valid memory range)
348+ uint32_t entryAddr = buffer[4 ] | (buffer[5 ] << 8 ) | (buffer[6 ] << 16 ) | (buffer[7 ] << 24 );
349+ // ESP32 bootloader entry points are typically in IRAM range (0x40000000 - 0x40400000)
350+ // or ROM range (0x40000000 and above)
351+ if (entryAddr < 0x40000000 || entryAddr > 0x50000000 ) {
352+ DEBUG_PRINTF_P (PSTR (" Invalid entry address: 0x%08X\n " ), entryAddr);
353+ return false ;
354+ }
355+
356+ // 7. Basic segment structure validation
357+ // Each segment has a header: load_addr (4 bytes) + data_len (4 bytes)
358+ size_t offset = MIN_IMAGE_HEADER_SIZE;
359+ for (uint8_t i = 0 ; i < segmentCount && offset + 8 <= len; i++) {
360+ uint32_t segmentSize = buffer[offset + 4 ] | (buffer[offset + 5 ] << 8 ) |
361+ (buffer[offset + 6 ] << 16 ) | (buffer[offset + 7 ] << 24 );
362+
363+ // Segment size sanity check (shouldn't be > 32KB for bootloader segments)
364+ if (segmentSize > 0x8000 ) {
365+ DEBUG_PRINTF_P (PSTR (" Segment %d too large: %d bytes\n " ), i, segmentSize);
366+ return false ;
367+ }
368+
369+ offset += 8 + segmentSize; // Skip segment header and data
370+ }
371+
372+ // 8. Verify total size is reasonable
373+ if (len > 0x8000 ) { // Bootloader shouldn't exceed 32KB
374+ DEBUG_PRINTF_P (PSTR (" Bootloader too large: %d bytes\n " ), len);
375+ return false ;
280376 }
281377
282- DEBUG_PRINTLN (F (" Bootloader validation passed" ));
378+ DEBUG_PRINTLN (F (" Bootloader validation passed - matches esp_image_verify checks " ));
283379 return true ;
284380}
285381#endif
0 commit comments