|
51 | 51 | #ifdef WOLFBOOT_HASH_SHA3_384 |
52 | 52 | #include <wolfssl/wolfcrypt/sha3.h> |
53 | 53 | #endif |
| 54 | +#ifdef WOLFBOOT_ELF |
| 55 | +#include "elf.h" |
| 56 | +#endif |
54 | 57 |
|
55 | 58 | /* Globals */ |
56 | 59 | static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE]; |
@@ -770,6 +773,39 @@ static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset) |
770 | 773 | #endif |
771 | 774 | return (uint8_t *)(img->fw_base + offset); |
772 | 775 | } |
| 776 | +/** |
| 777 | + * @brief Get a block of data to be hashed from a specific memory address. |
| 778 | + * |
| 779 | + * This function retrieves a block of data to be hashed from a specific memory address. |
| 780 | + * It behaves similarly to get_sha_block but takes a direct pointer instead of an offset. |
| 781 | + * |
| 782 | + * @param img The image to retrieve the data from. |
| 783 | + * @param addr The memory address to read the data from. |
| 784 | + * @return A pointer to the data block. |
| 785 | + */ |
| 786 | +static uint8_t *get_sha_block_ptr(struct wolfBoot_image *img, const uint8_t *addr) |
| 787 | +{ |
| 788 | + uint32_t offset; |
| 789 | + |
| 790 | + /* Calculate offset from base address */ |
| 791 | + if ((uintptr_t)addr < (uintptr_t)img->fw_base) { |
| 792 | + return NULL; |
| 793 | + } |
| 794 | + |
| 795 | + offset = (uint32_t)((uintptr_t)addr - (uintptr_t)img->fw_base); |
| 796 | + |
| 797 | + if (offset > img->fw_size) { |
| 798 | + return NULL; |
| 799 | + } |
| 800 | + |
| 801 | +#ifdef EXT_FLASH |
| 802 | + if (PART_IS_EXT(img)) { |
| 803 | + ext_flash_check_read((uintptr_t)addr, ext_hash_block, WOLFBOOT_SHA_BLOCK_SIZE); |
| 804 | + return ext_hash_block; |
| 805 | + } else |
| 806 | +#endif |
| 807 | + return (uint8_t *)addr; |
| 808 | +} |
773 | 809 |
|
774 | 810 | #ifdef EXT_FLASH |
775 | 811 | static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; |
@@ -1061,6 +1097,147 @@ static void key_sha3_384(uint8_t key_slot, uint8_t *hash) |
1061 | 1097 | #endif /* WOLFBOOT_NO_SIGN */ |
1062 | 1098 | #endif /* SHA3-384 */ |
1063 | 1099 |
|
| 1100 | + |
| 1101 | +#ifdef WOLFBOOT_ELF |
| 1102 | +/** |
| 1103 | + * @brief Compute the scattered hash by hashing PT_LOAD segments at their XIP |
| 1104 | + * addresses. Note: This function assumes that the destination addresses for elf |
| 1105 | + * loading have the same access patterns as the memory represented by img. |
| 1106 | + * (e.g. if BOOT partition is external, then reads/writes to the load address |
| 1107 | + * will use ext_flash_read/ext_flash_write. |
| 1108 | + * |
| 1109 | + * @param img Pointer to the wolfBoot image |
| 1110 | + * @param hash Buffer to store the computed hash (must be at least |
| 1111 | + * WOLFBOOT_SHA_DIGEST_SIZE bytes) |
| 1112 | + * @return 0 on success, negative value on error |
| 1113 | + */ |
| 1114 | +static int wolfBoot_compute_scattered_hash(struct wolfBoot_image *img, uint8_t *hash) |
| 1115 | +{ |
| 1116 | + uint8_t elf_header_buf[sizeof(elf64_header)]; |
| 1117 | + uint8_t program_header_buf[sizeof(elf64_program_header)]; |
| 1118 | + elf32_header* h32; |
| 1119 | + elf64_header* h64; |
| 1120 | + uint16_t entry_count, entry_size; |
| 1121 | + uint32_t ph_offset; |
| 1122 | + int is_elf32, is_le, i; |
| 1123 | +#if defined(WOLFBOOT_HASH_SHA256) |
| 1124 | + wc_Sha256 sha256_ctx; |
| 1125 | +#elif defined(WOLFBOOT_HASH_SHA384) |
| 1126 | + wc_Sha384 sha384_ctx; |
| 1127 | +#elif defined(WOLFBOOT_HASH_SHA3_384) |
| 1128 | + wc_Sha3 sha3_384_ctx; |
| 1129 | +#endif |
| 1130 | + |
| 1131 | +#ifdef EXT_FLASH |
| 1132 | + if (PART_IS_EXT(img)) { |
| 1133 | + /* Read ELF header from external flash */ |
| 1134 | + ext_flash_check_read((uintptr_t)(img->fw_base), elf_header_buf, sizeof(elf64_header)); |
| 1135 | + } else |
| 1136 | +#endif |
| 1137 | + { |
| 1138 | + memcpy(elf_header_buf, (void*)(img->fw_base), sizeof(elf64_header)); |
| 1139 | + } |
| 1140 | + |
| 1141 | + h32 = (elf32_header*)elf_header_buf; |
| 1142 | + h64 = (elf64_header*)elf_header_buf; |
| 1143 | + |
| 1144 | + /* Verify ELF header */ |
| 1145 | + if (memcmp(h32->ident, ELF_IDENT_STR, 4) != 0) { |
| 1146 | + return -1; /* not valid header identifier */ |
| 1147 | + } |
| 1148 | + |
| 1149 | + /* Load class and endianess */ |
| 1150 | + is_elf32 = (h32->ident[4] == ELF_CLASS_32); |
| 1151 | + is_le = (h32->ident[5] == ELF_ENDIAN_LITTLE); |
| 1152 | + (void)is_le; |
| 1153 | + |
| 1154 | + /* Initialize hash context */ |
| 1155 | +#if defined(WOLFBOOT_HASH_SHA256) |
| 1156 | + wc_InitSha256(&sha256_ctx); |
| 1157 | +#elif defined(WOLFBOOT_HASH_SHA384) |
| 1158 | + wc_InitSha384(&sha384_ctx); |
| 1159 | +#elif defined(WOLFBOOT_HASH_SHA3_384) |
| 1160 | + wc_Sha3_384_Init(&sha3_384_ctx, NULL, INVALID_DEVID); |
| 1161 | +#endif |
| 1162 | + |
| 1163 | + /* Get program headers info */ |
| 1164 | + ph_offset = is_elf32 ? GET32(h32->ph_offset) : GET32(h64->ph_offset); |
| 1165 | + entry_size = is_elf32 ? GET16(h32->ph_entry_size) : GET16(h64->ph_entry_size); |
| 1166 | + entry_count = is_elf32 ? GET16(h32->ph_entry_count) : GET16(h64->ph_entry_count); |
| 1167 | + |
| 1168 | + /* Hash each loadable segment directly from its physical address */ |
| 1169 | + for (i = 0; i < entry_count; i++) { |
| 1170 | + elf32_program_header* phdr32; |
| 1171 | + elf64_program_header* phdr64; |
| 1172 | + uint32_t type; |
| 1173 | + uintptr_t paddr; |
| 1174 | + uintptr_t file_size; |
| 1175 | + |
| 1176 | + /* Read program header into buffer */ |
| 1177 | +#ifdef EXT_FLASH |
| 1178 | + if (PART_IS_EXT(img)) { |
| 1179 | + ext_flash_check_read((uintptr_t)(img->fw_base) + ph_offset + (i * entry_size), |
| 1180 | + program_header_buf, entry_size); |
| 1181 | + } else |
| 1182 | +#endif |
| 1183 | + { |
| 1184 | + memcpy(program_header_buf, |
| 1185 | + (uint8_t*)(img->fw_base) + ph_offset + (i * entry_size), |
| 1186 | + entry_size); |
| 1187 | + } |
| 1188 | + |
| 1189 | + |
| 1190 | + phdr32 = (elf32_program_header*)program_header_buf; |
| 1191 | + phdr64 = (elf64_program_header*)program_header_buf; |
| 1192 | + type = (is_elf32 ? GET32(phdr32->type) : GET32(phdr64->type)); |
| 1193 | + paddr = (is_elf32 ? GET32(phdr32->paddr) : GET64(phdr64->paddr)); |
| 1194 | + file_size = (is_elf32 ? GET32(phdr32->file_size) : GET64(phdr64->file_size)); |
| 1195 | + |
| 1196 | + /* Only hash PT_LOAD segments with non-zero size */ |
| 1197 | + if (type == ELF_PT_LOAD && file_size > 0) { |
| 1198 | +#ifdef DEBUG_ELF |
| 1199 | + wolfBoot_printf("Hashing segment at %p (%d bytes)\r\n", (void*)paddr, (uint32_t)file_size); |
| 1200 | +#endif |
| 1201 | + /* Hash the segment data from physical address in blocks */ |
| 1202 | + uint32_t pos = 0; |
| 1203 | + while (pos < file_size) { |
| 1204 | + uint8_t *block; |
| 1205 | + uint32_t blksz = WOLFBOOT_SHA_BLOCK_SIZE; |
| 1206 | + |
| 1207 | + if (pos + blksz > file_size) { |
| 1208 | + blksz = file_size - pos; |
| 1209 | + } |
| 1210 | + |
| 1211 | + block = get_sha_block_ptr(img, (const uint8_t *)(paddr + pos)); |
| 1212 | + if (block == NULL) { |
| 1213 | + return -1; |
| 1214 | + } |
| 1215 | + |
| 1216 | +#if defined(WOLFBOOT_HASH_SHA256) |
| 1217 | + wc_Sha256Update(&sha256_ctx, block, blksz); |
| 1218 | +#elif defined(WOLFBOOT_HASH_SHA384) |
| 1219 | + wc_Sha384Update(&sha384_ctx, block, blksz); |
| 1220 | +#elif defined(WOLFBOOT_HASH_SHA3_384) |
| 1221 | + wc_Sha3_384_Update(&sha3_384_ctx, block, blksz); |
| 1222 | +#endif |
| 1223 | + pos += blksz; |
| 1224 | + } |
| 1225 | + } |
| 1226 | + } |
| 1227 | + |
| 1228 | + /* Finalize hash */ |
| 1229 | +#if defined(WOLFBOOT_HASH_SHA256) |
| 1230 | + wc_Sha256Final(&sha256_ctx, hash); |
| 1231 | +#elif defined(WOLFBOOT_HASH_SHA384) |
| 1232 | + wc_Sha384Final(&sha384_ctx, hash); |
| 1233 | +#elif defined(WOLFBOOT_HASH_SHA3_384) |
| 1234 | + wc_Sha3_384_Final(&sha3_384_ctx, hash); |
| 1235 | +#endif |
| 1236 | + |
| 1237 | + return 0; |
| 1238 | +} |
| 1239 | +#endif /* WOLFBOOT_ELF */ |
| 1240 | + |
1064 | 1241 | /** |
1065 | 1242 | * @brief Convert a 32-bit integer from little-endian to native byte order. |
1066 | 1243 | * |
|
0 commit comments