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; }
/** * 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; }
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; }
int fit_config_verify(const void *fit, int conf_noffset) { return fit_config_verify_required_sigs(fit, conf_noffset, gd_fdt_blob()); }
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; }