static int pfm_flash_get_firmware_images_v1()

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;
}