Esempio n. 1
0
static int fit_image_setup_verify(struct image_sign_info *info,
		const void *fit, int noffset, int required_keynode,
		char **err_msgp)
{
	char *algo_name;

	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
		*err_msgp = "Can't get hash algo property";
		return -1;
	}
	memset(info, '\0', sizeof(*info));
	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
	info->fit = (void *)fit;
	info->node_offset = noffset;
	info->algo = image_get_sig_algo(algo_name);
	info->fdt_blob = gd_fdt_blob();
	info->required_keynode = required_keynode;
	printf("%s:%s", algo_name, info->keyname);

	if (!info->algo) {
		*err_msgp = "Unknown signature algorithm";
		return -1;
	}

	return 0;
}
Esempio n. 2
0
/**
 * fit_image_verify - verify data intergity
 * @fit: pointer to the FIT format image header
 * @image_noffset: component image node offset
 *
 * fit_image_verify() goes over component image hash nodes,
 * re-calculates each data hash and compares with the value stored in hash
 * node.
 *
 * returns:
 *     1, if all hashes are valid
 *     0, otherwise (or on error)
 */
int fit_image_verify(const void *fit, int image_noffset)
{
	const void	*data;
	size_t		size;
	int		noffset = 0;
	char		*err_msg = "";
	int verify_all = 1;
	int ret;

	/* Get image data and data length */
	if (fit_image_get_data(fit, image_noffset, &data, &size)) {
		err_msg = "Can't get image data/size";
		goto error;
	}

	/* Verify all required signatures */
	if (IMAGE_ENABLE_VERIFY &&
	    fit_image_verify_required_sigs(fit, image_noffset, data, size,
					   gd_fdt_blob(), &verify_all)) {
		err_msg = "Unable to verify required signature";
		goto error;
	}

	/* Process all hash subnodes of the component image node */
	for (noffset = fdt_first_subnode(fit, image_noffset);
	     noffset >= 0;
	     noffset = fdt_next_subnode(fit, noffset)) {
		const char *name = fit_get_name(fit, noffset, NULL);

		/*
		 * Check subnode name, must be equal to "hash".
		 * Multiple hash nodes require unique unit node
		 * names, e.g. hash@1, hash@2, etc.
		 */
		if (!strncmp(name, FIT_HASH_NODENAME,
			     strlen(FIT_HASH_NODENAME))) {
			if (fit_image_check_hash(fit, noffset, data, size,
						 &err_msg))
				goto error;
			puts("+ ");
		} else if (IMAGE_ENABLE_VERIFY && verify_all &&
				!strncmp(name, FIT_SIG_NODENAME,
					strlen(FIT_SIG_NODENAME))) {
			ret = fit_image_check_sig(fit, noffset, data,
							size, -1, &err_msg);
			if (ret)
				puts("- ");
			else
				puts("+ ");
		}
	}

	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
		err_msg = "Corrupted or truncated tree";
		goto error;
	}

	return 1;

error:
	printf(" error!\n%s for '%s' hash node in '%s' image node\n",
	       err_msg, fit_get_name(fit, noffset, NULL),
	       fit_get_name(fit, image_noffset, NULL));
	return 0;
}
Esempio n. 3
0
int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr,
		   const char **fit_unamep, const char **fit_uname_configp,
		   int arch, int image_type, int bootstage_id,
		   enum fit_load_op load_op, ulong *datap, ulong *lenp)
{
	int cfg_noffset, noffset;
	const char *fit_uname;
	const char *fit_uname_config;
	const void *fit;
	const void *buf;
	size_t size;
	int type_ok, os_ok;
	ulong load, data, len;
	int ret;

	fit = map_sysmem(addr, 0);
	fit_uname = fit_unamep ? *fit_unamep : NULL;
	fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
	printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);

	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
	if (!fit_check_format(fit)) {
		printf("Bad FIT %s image format!\n", prop_name);
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
		return -ENOEXEC;
	}
	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK);
	if (fit_uname) {
		/* get ramdisk component image node offset */
		bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME);
		noffset = fit_image_get_node(fit, fit_uname);
	} else {
		/*
		 * no image node unit name, try to get config
		 * node first. If config unit node name is NULL
		 * fit_conf_get_node() will try to find default config node
		 */
		bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME);
		if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) {
			cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob());
		} else {
			cfg_noffset = fit_conf_get_node(fit,
							fit_uname_config);
		}
		if (cfg_noffset < 0) {
			puts("Could not find configuration node\n");
			bootstage_error(bootstage_id +
					BOOTSTAGE_SUB_NO_UNIT_NAME);
			return -ENOENT;
		}
		fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
		printf("   Using '%s' configuration\n", fit_uname_config);
		if (image_type == IH_TYPE_KERNEL) {
			/* Remember (and possibly verify) this config */
			images->fit_uname_cfg = fit_uname_config;
			if (IMAGE_ENABLE_VERIFY && images->verify) {
				puts("   Verifying Hash Integrity ... ");
				if (!fit_config_verify(fit, cfg_noffset)) {
					puts("Bad Data Hash\n");
					bootstage_error(bootstage_id +
						BOOTSTAGE_SUB_HASH);
					return -EACCES;
				}
				puts("OK\n");
			}
			bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG);
		}

		noffset = fit_conf_get_prop_node(fit, cfg_noffset,
						 prop_name);
		fit_uname = fit_get_name(fit, noffset, NULL);
	}
	if (noffset < 0) {
		puts("Could not find subimage node\n");
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE);
		return -ENOENT;
	}

	printf("   Trying '%s' %s subimage\n", fit_uname, prop_name);

	ret = fit_image_select(fit, noffset, images->verify);
	if (ret) {
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH);
		return ret;
	}

	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
	if (!fit_image_check_target_arch(fit, noffset)) {
		puts("Unsupported Architecture\n");
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
		return -ENOEXEC;
	}

	if (image_type == IH_TYPE_FLATDT &&
	    !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) {
		puts("FDT image is compressed");
		return -EPROTONOSUPPORT;
	}

	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
	type_ok = fit_image_check_type(fit, noffset, image_type) ||
		(image_type == IH_TYPE_KERNEL &&
			fit_image_check_type(fit, noffset,
					     IH_TYPE_KERNEL_NOLOAD));
	os_ok = image_type == IH_TYPE_FLATDT ||
		fit_image_check_os(fit, noffset, IH_OS_LINUX);
	if (!type_ok || !os_ok) {
		printf("No Linux %s %s Image\n", genimg_get_arch_name(arch),
		       genimg_get_type_name(image_type));
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
		return -EIO;
	}

	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);

	/* get image data address and length */
	if (fit_image_get_data(fit, noffset, &buf, &size)) {
		printf("Could not find %s subimage data!\n", prop_name);
		bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA);
		return -ENOENT;
	}
	len = (ulong)size;

	/* verify that image data is a proper FDT blob */
	if (image_type == IH_TYPE_FLATDT && fdt_check_header((char *)buf)) {
		puts("Subimage data is not a FDT");
		return -ENOEXEC;
	}

	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK);

	/*
	 * Work-around for eldk-4.2 which gives this warning if we try to
	 * case in the unmap_sysmem() call:
	 * warning: initialization discards qualifiers from pointer target type
	 */
	{
		void *vbuf = (void *)buf;

		data = map_to_sysmem(vbuf);
	}

	if (load_op == FIT_LOAD_IGNORED) {
		/* Don't load */
	} else if (fit_image_get_load(fit, noffset, &load)) {
		if (load_op == FIT_LOAD_REQUIRED) {
			printf("Can't get %s subimage load address!\n",
			       prop_name);
			bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD);
			return -EBADF;
		}
	} else {
		ulong image_start, image_end;
		ulong load_end;
		void *dst;

		/*
		 * move image data to the load address,
		 * make sure we don't overwrite initial image
		 */
		image_start = addr;
		image_end = addr + fit_get_size(fit);

		load_end = load + len;
		if (image_type != IH_TYPE_KERNEL &&
		    load < image_end && load_end > image_start) {
			printf("Error: %s overwritten\n", prop_name);
			return -EXDEV;
		}

		printf("   Loading %s from 0x%08lx to 0x%08lx\n",
		       prop_name, data, load);

		dst = map_sysmem(load, len);
		memmove(dst, buf, len);
		data = load;
	}
	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);

	*datap = data;
	*lenp = len;
	if (fit_unamep)
		*fit_unamep = (char *)fit_uname;
	if (fit_uname_configp)
		*fit_uname_configp = (char *)fit_uname_config;

	return noffset;
}
Esempio n. 4
0
int fit_config_verify(const void *fit, int conf_noffset)
{
	return fit_config_verify_required_sigs(fit, conf_noffset,
					       gd_fdt_blob());
}
Esempio n. 5
0
int fit_config_check_sig(const void *fit, int noffset, int required_keynode,
			 char **err_msgp)
{
	char * const exc_prop[] = {"data"};
	const char *prop, *end, *name;
	struct image_sign_info info;
	const uint32_t *strings;
	uint8_t *fit_value;
	int fit_value_len;
	int max_regions;
	int i, prop_len;
	char path[200];
	int count;

	debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
	      fit_get_name(fit, noffset, NULL),
	      fit_get_name(gd_fdt_blob(), required_keynode, NULL));
	*err_msgp = NULL;
	if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
				   err_msgp))
		return -1;

	if (fit_image_hash_get_value(fit, noffset, &fit_value,
				     &fit_value_len)) {
		*err_msgp = "Can't get hash value property";
		return -1;
	}

	/* Count the number of strings in the property */
	prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
	end = prop ? prop + prop_len : prop;
	for (name = prop, count = 0; name < end; name++)
		if (!*name)
			count++;
	if (!count) {
		*err_msgp = "Can't get hashed-nodes property";
		return -1;
	}

	/* Add a sanity check here since we are using the stack */
	if (count > IMAGE_MAX_HASHED_NODES) {
		*err_msgp = "Number of hashed nodes exceeds maximum";
		return -1;
	}

	/* Create a list of node names from those strings */
	char *node_inc[count];

	debug("Hash nodes (%d):\n", count);
	for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
		debug("   '%s'\n", name);
		node_inc[i] = (char *)name;
	}

	/*
	 * Each node can generate one region for each sub-node. Allow for
	 * 7 sub-nodes (hash@1, signature@1, etc.) and some extra.
	 */
	max_regions = 20 + count * 7;
	struct fdt_region fdt_regions[max_regions];

	/* Get a list of regions to hash */
	count = fdt_find_regions(fit, node_inc, count,
			exc_prop, ARRAY_SIZE(exc_prop),
			fdt_regions, max_regions - 1,
			path, sizeof(path), 0);
	if (count < 0) {
		*err_msgp = "Failed to hash configuration";
		return -1;
	}
	if (count == 0) {
		*err_msgp = "No data to hash";
		return -1;
	}
	if (count >= max_regions - 1) {
		*err_msgp = "Too many hash regions";
		return -1;
	}

	/* Add the strings */
	strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
	if (strings) {
		fdt_regions[count].offset = fdt_off_dt_strings(fit) +
				fdt32_to_cpu(strings[0]);
		fdt_regions[count].size = fdt32_to_cpu(strings[1]);
		count++;
	}

	/* Allocate the region list on the stack */
	struct image_region region[count];

	fit_region_make_list(fit, fdt_regions, count, region);
	if (info.algo->verify(&info, region, count, fit_value,
			      fit_value_len)) {
		*err_msgp = "Verification failed";
		return -1;
	}

	return 0;
}