1 /*
2  * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <string.h>
7 #include "esp_flash_partitions.h"
8 #include "esp_log.h"
9 #include "esp_rom_md5.h"
10 #include "esp_rom_spiflash.h"
11 
12 static const char *TAG = "flash_parts";
13 
esp_partition_table_verify(const esp_partition_info_t * partition_table,bool log_errors,int * num_partitions)14 esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions)
15 {
16     int md5_found = 0;
17     size_t num_parts;
18     uint32_t chip_size = g_rom_flashchip.chip_size;
19     *num_partitions = 0;
20 
21     for (num_parts = 0; num_parts < ESP_PARTITION_TABLE_MAX_ENTRIES; num_parts++) {
22         const esp_partition_info_t *part = &partition_table[num_parts];
23 
24         if (part->magic == ESP_PARTITION_MAGIC) {
25             const esp_partition_pos_t *pos = &part->pos;
26             if (pos->offset > chip_size || pos->offset + pos->size > chip_size) {
27                 if (log_errors) {
28                     ESP_LOGE(TAG, "partition %d invalid - offset 0x%"PRIx32" size 0x%"PRIx32" exceeds flash chip size 0x%"PRIx32,
29                              num_parts, pos->offset, pos->size, chip_size);
30                 }
31                 return ESP_ERR_INVALID_SIZE;
32             }
33         } else if (part->magic == ESP_PARTITION_MAGIC_MD5) {
34             if (md5_found) {
35                 if (log_errors) {
36                     ESP_LOGE(TAG, "Only one MD5 checksum is allowed");
37                 }
38                 return ESP_ERR_INVALID_STATE;
39             }
40 
41             md5_context_t context;
42             unsigned char digest[16];
43             esp_rom_md5_init(&context);
44             esp_rom_md5_update(&context, (unsigned char *) partition_table, num_parts * sizeof(esp_partition_info_t));
45             esp_rom_md5_final(digest, &context);
46 
47             unsigned char *md5sum = ((unsigned char *) part) + ESP_PARTITION_MD5_OFFSET;
48 
49             if (memcmp(md5sum, digest, sizeof(digest)) != 0) {
50                 if (log_errors) {
51                     ESP_LOGE(TAG, "Incorrect MD5 checksum");
52                 }
53                 return ESP_ERR_INVALID_STATE;
54             }
55             //MD5 checksum matches and we continue with the next interation in
56             //order to detect the end of the partition table
57             md5_found = 1;
58         } else if (part->magic == 0xFFFF
59                    && part->type == PART_TYPE_END
60                    && part->subtype == PART_SUBTYPE_END) {
61             ESP_LOGD(TAG, "partition table verified, %d entries", num_parts);
62             *num_partitions = num_parts - md5_found; //do not count the partition where the MD5 checksum is held
63             return ESP_OK;
64         } else {
65             if (log_errors) {
66                 ESP_LOGE(TAG, "partition %d invalid magic number 0x%x", num_parts, part->magic);
67             }
68             return ESP_ERR_INVALID_STATE;
69         }
70     }
71 
72     if (log_errors) {
73         ESP_LOGE(TAG, "partition table has no terminating entry, not valid");
74     }
75     return ESP_ERR_INVALID_STATE;
76 }
77