in core/manifest/pfm/pfm_flash.c [1315:1447]
static int pfm_flash_get_firmware_images_v1 (const struct pfm_flash *pfm, const char *version,
struct pfm_image_list *img_list)
{
struct pfm_firmware_header fw_header;
struct pfm_image_header img_header;
struct pfm_key_manifest_header key_section;
struct pfm_public_key_header key_header;
struct rsa_public_key key;
struct pfm_image_signature *images;
struct flash_region *region_list = NULL;
uint32_t next_addr;
uint32_t key_addr;
int status;
int i;
int j;
int matched;
status = pfm_flash_find_version_entry_v1 (&pfm->base_flash, version, &fw_header, &next_addr,
&key_addr);
if (status != 0) {
return status;
}
images = platform_calloc (fw_header.img_count, sizeof (struct pfm_image_signature));
if (images == NULL) {
return PFM_NO_MEMORY;
}
img_list->images_hash = NULL;
img_list->images_sig = images;
img_list->count = fw_header.img_count;
next_addr += sizeof (struct pfm_firmware_header) + fw_header.version_length +
(sizeof (struct pfm_flash_region) * fw_header.rw_count);
if ((fw_header.version_length % 4) != 0) {
next_addr += 4 - (fw_header.version_length % 4);
}
for (i = 0; i < fw_header.img_count; i++) {
status = pfm->base_flash.flash->read (pfm->base_flash.flash, next_addr,
(uint8_t*) &img_header, sizeof (img_header));
if (status != 0) {
goto error;
}
if (img_header.sig_length > sizeof (images[i].signature)) {
status = PFM_FW_IMAGE_UNSUPPORTED;
goto error;
}
region_list = platform_calloc (img_header.region_count, sizeof (struct flash_region));
if (region_list == NULL) {
status = PFM_NO_MEMORY;
goto error;
}
images[i].regions = region_list;
images[i].count = img_header.region_count;
images[i].always_validate = !!(img_header.flags & PFM_IMAGE_MUST_VALIDATE);
images[i].sig_length = img_header.sig_length;
images[i].key.mod_length = (0xffU << 24) | img_header.key_id;
next_addr += sizeof (struct pfm_image_header);
status = pfm->base_flash.flash->read (pfm->base_flash.flash, next_addr, images[i].signature,
img_header.sig_length);
if (status != 0) {
goto error;
}
next_addr += img_header.sig_length;
status = pfm_flash_read_multiple_regions_v1 (&pfm->base_flash, img_header.region_count,
region_list, &next_addr);
if (status != 0) {
goto error;
}
}
status = pfm->base_flash.flash->read (pfm->base_flash.flash, key_addr, (uint8_t*) &key_section,
sizeof (key_section));
if (status != 0) {
goto error;
}
i = 0;
matched = 0;
next_addr = key_addr + sizeof (struct pfm_key_manifest_header);
while ((i < key_section.key_count) && (matched < fw_header.img_count)) {
status = pfm->base_flash.flash->read (pfm->base_flash.flash, next_addr,
(uint8_t*) &key_header, sizeof (key_header));
if (status != 0) {
goto error;
}
if (key_header.key_length > sizeof (key.modulus)) {
status = PFM_KEY_UNSUPPORTED;
goto error;
}
next_addr += sizeof (struct pfm_public_key_header);
status = pfm->base_flash.flash->read (pfm->base_flash.flash, next_addr, key.modulus,
key_header.key_length);
if (status != 0) {
goto error;
}
key.exponent = key_header.key_exponent;
key.mod_length = key_header.key_length;
for (j = 0; j < fw_header.img_count; j++) {
if (((images[j].key.mod_length >> 24) & 0xff) == 0xff) {
if ((images[j].key.mod_length & 0xff) == key_header.id) {
images[j].key = key;
matched++;
}
}
}
i++;
next_addr += key_header.key_length;
}
if (matched < fw_header.img_count) {
status = PFM_UNKNOWN_KEY_ID;
goto error;
}
return 0;
error:
pfm_flash_free_firmware_images (&pfm->base, img_list);
return status;
}