1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <string.h>
15 #include "esp_flash_partitions.h"
16 #include "esp_log.h"
17 #include "esp_rom_md5.h"
18 #if CONFIG_IDF_TARGET_ESP32C3
19 #include "esp32c3/rom/spi_flash.h"
20 #elif CONFIG_IDF_TARGET_ESP32S2
21 #include "esp32s2/rom/spi_flash.h"
22 #else
23 #include "esp32/rom/spi_flash.h"
24 #endif
25 
26 static const char *TAG = "flash_parts";
27 
esp_partition_table_verify(const esp_partition_info_t * partition_table,bool log_errors,int * num_partitions)28 esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions)
29 {
30     int md5_found = 0;
31     size_t num_parts;
32     uint32_t chip_size = g_rom_flashchip.chip_size;
33     *num_partitions = 0;
34 
35     for (num_parts = 0; num_parts < ESP_PARTITION_TABLE_MAX_ENTRIES; num_parts++) {
36         const esp_partition_info_t *part = &partition_table[num_parts];
37 
38         if (part->magic == ESP_PARTITION_MAGIC) {
39             const esp_partition_pos_t *pos = &part->pos;
40             if (pos->offset > chip_size || pos->offset + pos->size > chip_size) {
41                 if (log_errors) {
42                     ESP_LOGE(TAG, "partition %d invalid - offset 0x%x size 0x%x exceeds flash chip size 0x%x",
43                              num_parts, pos->offset, pos->size, chip_size);
44                 }
45                 return ESP_ERR_INVALID_SIZE;
46             }
47         } else if (part->magic == ESP_PARTITION_MAGIC_MD5) {
48             if (md5_found) {
49                 if (log_errors) {
50                     ESP_LOGE(TAG, "Only one MD5 checksum is allowed");
51                 }
52                 return ESP_ERR_INVALID_STATE;
53             }
54 
55             struct MD5Context context;
56             unsigned char digest[16];
57             esp_rom_md5_init(&context);
58             esp_rom_md5_update(&context, (unsigned char *) partition_table, num_parts * sizeof(esp_partition_info_t));
59             esp_rom_md5_final(digest, &context);
60 
61             unsigned char *md5sum = ((unsigned char *) part) + 16; // skip the 2B magic number and the 14B fillup bytes
62 
63             if (memcmp(md5sum, digest, sizeof(digest)) != 0) {
64                 if (log_errors) {
65                     ESP_LOGE(TAG, "Incorrect MD5 checksum");
66                 }
67                 return ESP_ERR_INVALID_STATE;
68             }
69             //MD5 checksum matches and we continue with the next interation in
70             //order to detect the end of the partition table
71             md5_found = 1;
72         } else if (part->magic == 0xFFFF
73                    && part->type == PART_TYPE_END
74                    && part->subtype == PART_SUBTYPE_END) {
75             ESP_LOGD(TAG, "partition table verified, %d entries", num_parts);
76             *num_partitions = num_parts - md5_found; //do not count the partition where the MD5 checksum is held
77             return ESP_OK;
78         } else {
79             if (log_errors) {
80                 ESP_LOGE(TAG, "partition %d invalid magic number 0x%x", num_parts, part->magic);
81             }
82             return ESP_ERR_INVALID_STATE;
83         }
84     }
85 
86     if (log_errors) {
87         ESP_LOGE(TAG, "partition table has no terminating entry, not valid");
88     }
89     return ESP_ERR_INVALID_STATE;
90 }
91