| #include <debug.h> |
| #include <fit.h> |
| #include <malloc.h> |
| #include <platform.h> |
| #include <libfdt.h> |
| #include <blob.h> |
| #include <trace.h> |
| #include "image.h" |
| #include "rsa.h" |
| |
| #define LOCAL_TRACE 0 |
| |
| int sha256_hash(const void *source, int len, u8 *result); |
| int sha512_hash(const void *source, int len, u8 *result); |
| |
| int calculate_hash_multi_region(const struct image_region region[], |
| int region_count, uint8_t *checksum, |
| int hash_len); |
| void mod_exp_65537_mont(uintptr_t *r, const uintptr_t *a, |
| const struct key_prop *pkey); |
| |
| #define DUMP_DATA 0 |
| #define debug(fmt, args...) |
| #define MAX_HASH_NODES 64 |
| #define SHA256_SUM_LEN 32 |
| #define FDT_MAX_DEPTH 32 |
| #define MAX_REGS(x) (20 +x*7) |
| #define IS_NAME_MATCH(x,y) !strncmp((x), (y),strlen(y)) |
| |
| #define SHA512_SUM_LEN 64 |
| #define PADDING_SIZE 19 |
| |
| #define list_each_subnode(fdt, node, parent) \ |
| for (node = fdt_first_subnode(fdt, parent); \ |
| node >= 0; \ |
| node = fdt_next_subnode(fdt, node)) |
| |
| const uint8_t padding_sha256[PADDING_SIZE] = { |
| 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, |
| 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 |
| }; |
| const uint8_t padding_sha512[PADDING_SIZE] = { |
| 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, |
| 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 |
| }; |
| |
| |
| struct hash_algo hash_algos[] = { |
| { |
| "sha256", |
| SHA256_SUM_LEN, |
| RSA2048_BYTES, |
| calculate_hash_multi_region, |
| padding_sha256, |
| }, |
| { |
| "sha512", |
| SHA512_SUM_LEN, |
| RSA4096_BYTES, |
| calculate_hash_multi_region, |
| padding_sha512, |
| }, |
| { |
| "sha256", |
| SHA256_SUM_LEN, |
| RSA4096_BYTES, |
| calculate_hash_multi_region, |
| padding_sha256, |
| }, |
| { |
| "sha512", |
| SHA512_SUM_LEN, |
| RSA2048_BYTES, |
| calculate_hash_multi_region, |
| padding_sha512, |
| } |
| |
| }; |
| |
| struct sig_algo image_sig_algos[] = { |
| { |
| "sha256,rsa2048", |
| &hash_algos[0], |
| rsa_verify, |
| }, |
| { |
| "sha512,rsa4096", |
| &hash_algos[1], |
| rsa_verify, |
| }, |
| { |
| "sha256,rsa4096", |
| &hash_algos[2], |
| rsa_verify, |
| }, |
| { |
| "sha512,rsa2048", |
| &hash_algos[3], |
| rsa_verify, |
| } |
| }; |
| |
| static void dump_data(uint8_t *buff,int len) |
| { |
| uint i=0; |
| |
| for (i=0; i<len; i++) { |
| if ((i%16)==0) |
| LTRACEF("\n"); |
| LTRACEF("0x%02x,",buff[i]); |
| } |
| } |
| |
| int rsa_check_enabled(void) |
| { |
| return CHECK_RSA; |
| } |
| |
| int hash_check_enabled(void) |
| { |
| return CHECK_HASH; |
| } |
| |
| int calculate_hash_multi_region(const struct image_region region[], |
| int region_count, uint8_t *checksum, |
| int hash_len) |
| { |
| |
| int ret = 0; |
| int32_t i,j,k=0; |
| unsigned long inlen=0; |
| unsigned char *input_data; |
| const unsigned char *tmp_data; |
| |
| for (i = 0; i < region_count; i++) |
| inlen+=region[i].size; |
| |
| input_data = malloc(inlen); |
| if (!input_data) { |
| LTRACEF("malloc inlen(%lu bytes) failed\n", inlen); |
| return -1; |
| } |
| |
| for (i = 0; i < region_count; i++) { |
| tmp_data=region[i].data; |
| for (j = 0; j < region[i].size; j++) |
| input_data[k++]=tmp_data[j]; |
| } |
| if (hash_len == SHA256_SUM_LEN) { |
| ret=sha256_hash(input_data, inlen, checksum ); |
| } else if (hash_len == SHA512_SUM_LEN) { |
| ret=sha512_hash(input_data, inlen, checksum ); |
| } else { |
| LTRACEF(" Unsupported hash len\n"); |
| ret = -1; |
| } |
| free(input_data); |
| |
| return ret; |
| } |
| |
| int fdt_getval(const void *blob, int node, const char *prop_name, |
| int default_val) |
| { |
| const uint *tmp; |
| int get_val=0; |
| int len=0; |
| |
| tmp = fdt_getprop(blob, node, prop_name, &len); |
| if ((tmp !=0) && ((unsigned int)len >= sizeof(int))) { |
| get_val = fdt32_to_cpu(tmp[0]); |
| return get_val; |
| } |
| LTRACEF("get %s fail\n",prop_name); |
| |
| return default_val; |
| } |
| |
| static void rsa_verify_raw(const uint8_t *bn_n, uint8_t *bn_out, |
| const uint8_t *bn_in) |
| { |
| mod_exp_65537_mont((uintptr_t *)bn_out, (const uintptr_t *)bn_in, |
| (const struct key_prop *)bn_n); |
| } |
| |
| void get_pubkey_info(struct key_prop *pubkey, const void *blob,int node, |
| int *len) |
| { |
| pubkey->exp_len = sizeof(uint64_t); |
| pubkey->num_bits = fdt_getval(blob, node, BLOB_NBITS_NODE, 0); |
| pubkey->n0inv = *(uint64_t *)fdt_getprop(blob, node, BLOB_N0INV_NODE, NULL); |
| pubkey->rr = fdt_getprop(blob, node, BLOB_RSQU_NODE, NULL); |
| pubkey->modulus = fdt_getprop(blob, node, BLOB_MOD_NODE, NULL); |
| pubkey->public_exponent = fdt_getprop(blob, node, BLOB_EXP_NODE, len); |
| if (!pubkey->public_exponent || (unsigned int)*len < sizeof(uint64_t)) |
| pubkey->public_exponent = NULL; |
| } |
| |
| static void rsa_verify_with_pubkey(struct sig_info *info, |
| uint8_t *sig, uint sig_len, |
| int node, uint8_t *buf) |
| { |
| int i; |
| int length; |
| int rsa_length = info->algo->hash_info->pad_len; |
| struct key_prop prop; |
| const uint8_t *pubk ,*sign_tmp; |
| const void *blob = info->pubkey; |
| uint8_t __attribute__((aligned(8))) key[rsa_length], sign[rsa_length], |
| plain[rsa_length] ,rr[rsa_length]; |
| uint64_t n0inv; |
| |
| if (node < 0) { |
| LTRACEF("%s: Skipping invalid node", __func__); |
| return; |
| } |
| get_pubkey_info(&prop,blob,node,&length); |
| pubk=prop.modulus; |
| sign_tmp=sig; |
| for (i = 0; i < rsa_length; i++) { |
| key[rsa_length -i-1] = pubk[i]; |
| sign[rsa_length - i -1] = sign_tmp[i]; |
| rr[rsa_length - i -1] = *((uint8_t *)prop.rr + i); |
| } |
| |
| #if DUMP_DATA |
| LTRACEF("start to dump public key ===>>>\n"); |
| dump_data(key,rsa_length); |
| LTRACEF("\n end of dump public key <<<===\n"); |
| #endif |
| |
| n0inv=__builtin_bswap64(prop.n0inv); |
| prop.n0inv = n0inv; |
| prop.rr = (const uintptr_t *)rr; |
| prop.modulus = (const uintptr_t *)key; |
| |
| mod_exp_65537_mont((uintptr_t *)plain,(const uintptr_t *)sign,&prop); |
| |
| for (i = 0; i < rsa_length; i++) |
| buf[rsa_length - i -1] = plain[i]; |
| #if DUMP_DATA |
| LTRACEF("\nstart to dump rsa_hash ===>>>\n"); |
| dump_data(buf,rsa_length); |
| LTRACEF("\nend of dump public rsa_hash <<<===\n"); |
| #endif |
| } |
| |
| int rsa_verify(struct sig_info *info, |
| const struct fdt_region region[], int region_count, |
| uint8_t *sig, uint sig_len) |
| { |
| int ret=0,i; |
| int pad_len; |
| const uint8_t *p,*t; |
| uint8_t buf[sig_len]; |
| uint8_t hash[info->algo->hash_info->pad_len]; |
| struct image_region hash_region[region_count]; |
| |
| /* genarte hash region*/ |
| for (i = 0; i < region_count; i++) { |
| hash_region[i].data = info->fit_image + region[i].offset; |
| hash_region[i].size = region[i].size; |
| } |
| |
| |
| if (info->algo->hash_info->hash_len > |
| info->algo->hash_info->pad_len) { |
| LTRACEF("%s: invlaid checksum-algorithm %s for %s\n", |
| __func__, info->algo->hash_info->hash, info->algo->rsa); |
| return -EINVAL; |
| } |
| |
| /* checksum hash*/ |
| ret = info->algo->hash_info->hash_cal(hash_region, region_count, |
| hash,info->algo->hash_info->hash_len); |
| if (ret < 0) { |
| LTRACEF("%s: Error in checksum calculation\n", __func__); |
| return -EINVAL; |
| } |
| |
| #if DUMP_DATA |
| LTRACEF("start to dump calculate_hash ===>>\n"); |
| dump_data(hash,info->algo->hash_info->pad_len); |
| LTRACEF("\n end of dump calculate_hash <<===\n"); |
| #endif |
| |
| if (info->req_offset != -1) { |
| /*rsa calculate hash*/ |
| rsa_verify_with_pubkey(info, sig, sig_len, |
| info->req_offset,&buf[0]); |
| |
| /* compare rsa padding. */ |
| pad_len = info->algo->hash_info->pad_len - |
| info->algo->hash_info->hash_len - PADDING_SIZE; |
| uint8_t padding[pad_len]; |
| memset(padding, 0xff, pad_len); |
| padding[0] = 0x00; |
| padding[1] = 0x01; |
| padding[pad_len -1]=0x00; |
| |
| if (memcmp(padding, buf, pad_len)) { |
| LTRACEF("RSA check padding fail !\n"); |
| return -EINVAL; |
| } |
| |
| p = buf + pad_len; |
| t = &(info->algo->hash_info->hash_padding)[0]; |
| if (memcmp(t, p, PADDING_SIZE)) { |
| LTRACEF("RSA check padding fail !\n"); |
| return -EINVAL; |
| } |
| |
| /* compare calculate hash and rsa hash. */ |
| if (memcmp((uint8_t *)buf + pad_len + PADDING_SIZE, hash, sig_len - pad_len - PADDING_SIZE)) { |
| LTRACEF("RSA check hash fail!\n"); |
| return -EACCES; |
| } |
| |
| if (!ret) |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| int calculate_hash_one_region(const void *data, int data_len, const char *algo, |
| uint8_t *value, int *value_len) |
| { |
| if (strcmp(algo, "sha256") == 0) { |
| sha256_hash((unsigned char *)data, data_len, |
| (unsigned char *)value); |
| *value_len = SHA256_SUM_LEN; |
| } else if (strcmp(algo, "sha512") == 0) { |
| sha512_hash((unsigned char *)data, data_len, |
| (unsigned char *)value); |
| *value_len = SHA512_SUM_LEN; |
| } else { |
| LTRACEF(" Unsupported hash alogrithm\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int fit_get_node_value(const void *fit, int noffset, uint8_t **value, |
| int *value_len) |
| { |
| int len; |
| |
| *value = (uint8_t *)fdt_getprop(fit, noffset, FDT_VAL_NODE, &len); |
| |
| if (*value != NULL) { |
| *value_len = len; |
| return 0; |
| } else { |
| LTRACEF("fit_get_node_value NULL !!\n"); |
| *value_len = 0; |
| } |
| |
| return -1; |
| } |
| |
| int fit_get_hash_algo(const void *fit, int noffset, char **algo) |
| { |
| int len; |
| |
| *algo = (char *)fdt_getprop(fit, noffset, FDT_ALGO_NODE, &len); |
| if (*algo != NULL) |
| return 0; |
| else |
| LTRACEF("fdt_getprop algo NULL !!\n"); |
| |
| return -1; |
| } |
| |
| static int fit_image_check_hash(const void *fit, int noffset, const void *data, |
| uint32_t size) |
| { |
| uint8_t value[SHA512_SUM_LEN]; |
| int value_len; |
| char *algo; |
| uint8_t *image_hash; |
| int image_hash_len; |
| |
| if (fit_get_hash_algo(fit, noffset, &algo)) { |
| LTRACEF("get hash alogrithm fail \n"); |
| return -1; |
| } |
| |
| if (fit_get_node_value(fit, noffset, &image_hash,&image_hash_len)) { |
| LTRACEF("get hash value fail \n"); |
| return -1; |
| } |
| |
| #if DUMP_DATA |
| LTRACEF("\nstart dump img hash %d===>\n",image_hash_len); |
| dump_data(image_hash,image_hash_len); |
| #endif |
| |
| if (calculate_hash_one_region(data, (int)size, algo, value, &value_len)) { |
| LTRACEF("calsulate new hash fail !! \n"); |
| return -1; |
| } |
| |
| #if DUMP_DATA |
| LTRACEF("\nstart dump cal hash %d===>\n",value_len); |
| dump_data(value,value_len); |
| #endif |
| |
| if (value_len != image_hash_len) { |
| LTRACEF("hash length error ! \n"); |
| return -1; |
| } |
| |
| if (memcmp(value, image_hash, value_len) != 0) { |
| LTRACEF("compare hash value fail !! \n"); |
| return -1; |
| } |
| |
| LTRACEF("check integrity success! \n"); |
| return 0; |
| } |
| |
| static int fit_verify_prepare(struct sig_info *sign_info, |
| const void *fit, int noffset, |
| int required_keynode) |
| { |
| char *algo_name; |
| |
| if (fit_get_hash_algo(fit, noffset, &algo_name)) |
| return -1; |
| |
| memset(sign_info, '\0', sizeof(*sign_info)); |
| sign_info->fit_image = (void *)fit; |
| sign_info->algo = image_get_sig_algo(algo_name); |
| sign_info->pubkey = &blob[0]; |
| sign_info->req_offset = required_keynode; |
| LTRACEF("%s\n", algo_name); |
| |
| if (!sign_info->algo) |
| return -1; |
| |
| return 0; |
| } |
| |
| int fit_image_integrity_verify(const void *fit, int image_noffset) |
| { |
| const void *data; |
| int noffset; |
| uint32_t size; |
| |
| /* Get image data and data length */ |
| if (fit_image_get_data(fit, image_noffset, &data, &size)) { |
| LTRACEF("fit_image_get_data fail ! \n"); |
| return -EACCES; |
| } |
| /* Process all hash subnodes of the component image node */ |
| list_each_subnode(fit, noffset, image_noffset) { |
| const char *node_name = fit_get_name(fit, noffset, NULL); |
| if (IS_NAME_MATCH(node_name, FDT_HASH_NODE)) { |
| if (fit_image_check_hash(fit, noffset, data, size)) |
| return -EACCES; |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct sig_algo *image_get_sig_algo(const char *name) |
| { |
| uint i; |
| |
| for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) { |
| if (!strcmp(image_sig_algos[i].rsa, name)) |
| return &image_sig_algos[i]; |
| } |
| |
| return NULL; |
| } |
| |
| static int fit_get_hashed_node_name(const void *fit, int noffset, |
| int conf_noffset, char *nod_name[]) |
| { |
| int prop_len; |
| int i; |
| const char *prop_start, *prop_end, *prop_name; |
| const char *conf_name; |
| char *conf_path; |
| size_t conf_path_len; |
| bool conf_hashed; |
| |
| prop_start = fdt_getprop(fit, noffset, FDT_HASHED_NODE, &prop_len); |
| prop_end = prop_start ? prop_start + prop_len : prop_start; |
| prop_name = prop_start; |
| |
| conf_name = fit_get_name(fit, conf_noffset, NULL); |
| if (conf_name == NULL) |
| return -1; |
| |
| conf_path_len = strlen(FIT_CONFIGS_PATH) + 1 + strlen(conf_name) + 1; |
| conf_path = malloc(conf_path_len); |
| if (conf_path == NULL) |
| return -1; |
| |
| snprintf(conf_path, conf_path_len, "%s/%s", FIT_CONFIGS_PATH, conf_name); |
| |
| i = 0; |
| conf_hashed = false; |
| while (prop_name < prop_end) { |
| if (!conf_hashed && !strncmp(conf_path, prop_name, conf_path_len - 1)) |
| conf_hashed = true; |
| nod_name[i] = (char *)prop_name; |
| prop_name += strlen(prop_name) + 1; |
| i++; |
| } |
| free(conf_path); |
| |
| return conf_hashed ? i : -1; |
| } |
| |
| static int is_recorded_string(const char *string, char *const recorder[], |
| int rec_num) |
| { |
| int i; |
| |
| for (i = 0; i < rec_num; i++) { |
| if (!strcmp(recorder[i], string)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| #define get_base(x) fdt_off_dt_struct(x) |
| |
| int fdt_prop_check(const void *fit, uint offset, char *const invalid_list[], |
| int invalid_num, int default_val) |
| { |
| int def_val = 0; |
| const char *string; |
| const struct fdt_property *property; |
| |
| if (default_val >= 2) |
| def_val = 1; |
| property = fdt_get_property_by_offset(fit, offset, NULL); |
| string = fdt_string(fit, fdt32_to_cpu(property->nameoff)); |
| if (is_recorded_string(string, invalid_list, invalid_num)) |
| def_val = 0; |
| |
| return def_val; |
| } |
| |
| int fdt_check_range(const void *fit, int reg_num, |
| int max_reg_num,uint nextoffset) |
| { |
| if (nextoffset != fdt_size_dt_struct(fit)) |
| return -FDT_ERR_BADLAYOUT; |
| |
| if (reg_num >= max_reg_num) |
| return -FDT_ERR_BADVALUE; |
| |
| return 0; |
| } |
| |
| int fdt_parsing_regions(const void *fit, char *const record_list[], |
| int record_num, char *const property_list[], |
| int property_num, struct fdt_region region[], |
| int max_regions_num) |
| { |
| int stack[FDT_MAX_DEPTH]; |
| char path[200] = { '\0' }; |
| int path_len = sizeof(path); |
| int path_level = -1; |
| char *ppath; |
| int nextoffset = 0; |
| uint previousoffset = 0; |
| uint32_t tag; |
| int region_num = 0; |
| int region_offset = -1; |
| int record = 0; |
| ppath = path; |
| |
| do { |
| const char *node_name = NULL; |
| int node_name_len = 0; |
| int is_region_recorded = 0; |
| uint stopoffset = 0; |
| uint startoffset = 0; |
| |
| startoffset = nextoffset; |
| tag = fdt_next_tag(fit, startoffset, &nextoffset); |
| stopoffset = nextoffset; |
| |
| /* Start of node*/ |
| if (tag == FDT_BEGIN_NODE) { |
| path_level++; |
| if (path_level == FDT_MAX_DEPTH) |
| return -FDT_ERR_BADSTRUCTURE; |
| |
| node_name = fdt_get_name(fit, startoffset, &node_name_len); |
| if (ppath - path + 2 + node_name_len >= path_len) |
| return -FDT_ERR_NOSPACE; |
| if (ppath != path + 1) |
| *ppath++ = '/'; |
| strncpy(ppath, node_name, node_name_len + 1); |
| ppath += node_name_len; |
| stack[path_level] = record; |
| if (record == 1) |
| stopoffset = startoffset; |
| if (is_recorded_string(path, record_list, record_num)) |
| record = 2; |
| else if (record) |
| record--; |
| else |
| stopoffset = startoffset; |
| is_region_recorded = record; |
| } else if (tag == FDT_END_NODE) { |
| /* End of node */ |
| is_region_recorded = record; |
| record = stack[path_level--]; |
| for (; ppath > path;) { |
| if (*--ppath == '/') { |
| *ppath = '\0'; |
| break; |
| } |
| } |
| } else if (tag == FDT_PROP) { |
| /* Property node: contain: name, size, content */ |
| is_region_recorded = fdt_prop_check(fit, startoffset, property_list, |
| property_num, record); |
| stopoffset = startoffset; |
| } else if (tag == FDT_NOP) { |
| /* nop node*/ |
| stopoffset = startoffset; |
| is_region_recorded = record >= 2; |
| } else if (tag == FDT_END) { |
| /* End of fdt */ |
| is_region_recorded = 1; |
| } |
| |
| if (is_region_recorded && region_offset == -1) { |
| if (region_num > 0) { |
| previousoffset = region[region_num - 1].offset + |
| region[region_num - 1].size - get_base(fit); |
| if ((region_num <= max_regions_num) && |
| (startoffset == previousoffset)) |
| region_offset = region[--region_num].offset - get_base(fit); |
| } |
| |
| if (region_offset == -1) |
| region_offset = startoffset; |
| } |
| |
| if (!is_region_recorded && region_offset != -1) { |
| if (region_num < max_regions_num) { |
| region[region_num].offset = get_base(fit) + region_offset; |
| region[region_num].size = stopoffset - region_offset; |
| } |
| region_num++; |
| region_offset = -1; |
| } |
| } while (tag != FDT_END); |
| |
| //end handle |
| if (region_num < max_regions_num) { |
| region[region_num].offset = get_base(fit) + region_offset; |
| region[region_num].size = nextoffset - region_offset; |
| region_num++; |
| } |
| |
| if (fdt_check_range(fit, region_num, max_regions_num, nextoffset)) |
| return 0; |
| |
| return region_num; |
| } |
| |
| static int fit_check_sign(const void *fit, int noffset, int conf_noffset, |
| int required_keynode) |
| { |
| int node_num; |
| int image_sign_len; |
| uint8_t *image_sign; |
| const uint32_t *strings; |
| struct sig_info sign_info; |
| const char *tmp_data = "data" ; |
| char *const exc_prop[] = {(char *const)tmp_data}; |
| char *node_name[MAX_HASH_NODES]; |
| |
| /* get sign info and sign image */ |
| if (fit_verify_prepare(&sign_info, fit, noffset, required_keynode)) |
| return -1; |
| |
| if (fit_get_node_value(fit, noffset, &image_sign, &image_sign_len)) |
| return -1; |
| |
| #if DUMP_DATA |
| LTRACEF("\nstart to dump sign (len=%d) ===>>\n", image_sign_len); |
| dump_data(image_sign, image_sign_len); |
| LTRACEF("\n end of dump sign <<====\n"); |
| #endif |
| |
| /* get node name of fdt image */ |
| node_num = fit_get_hashed_node_name(fit, noffset, conf_noffset, node_name); |
| if (node_num < 0) |
| return -1; |
| |
| /* parsing regions */ |
| struct fdt_region fdt_regions[MAX_REGS(node_num)]; |
| |
| node_num = fdt_parsing_regions(fit, node_name, node_num, |
| exc_prop, ARRAY_SIZE(exc_prop), |
| fdt_regions, (MAX_REGS(node_num) - 1)); |
| if (node_num < 0) |
| return -1; |
| |
| strings = fdt_getprop(fit, noffset, FDT_HASHED_STR, NULL); |
| if (strings) { |
| fdt_regions[node_num].offset = fdt_off_dt_strings(fit) + |
| fdt32_to_cpu(strings[0]); |
| fdt_regions[node_num].size = fdt32_to_cpu(strings[1]); |
| node_num++; |
| } |
| |
| /* signature verify */ |
| if (sign_info.algo->sig_verify(&sign_info, fdt_regions, node_num, |
| image_sign, image_sign_len)) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int fit_verify_configed_sign(const void *fit, int conf_noffset, |
| const void *sig_blob, int sig_offset) |
| { |
| int noffset; |
| int ret = -1; |
| |
| list_each_subnode(fit, noffset, conf_noffset) { |
| const char *node_name = fit_get_name(fit, noffset, NULL); |
| if (IS_NAME_MATCH(node_name,FDT_SIG_NODE)) { |
| ret = fit_check_sign(fit, noffset, conf_noffset, sig_offset); |
| LTRACEF("check sign %s!\n", ret ? "fail" : "pass"); |
| if (ret == 0) |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| int fit_verify_sign(const void *fit, int conf_noffset) |
| { |
| const char *req_node = NULL; |
| int ret; |
| int noffset; |
| int sig_node; |
| const void *sig_blob = &blob[0]; |
| |
| sig_node = fdt_subnode_offset(sig_blob, 0, FDT_SIG_NODE); |
| if (sig_node < 0) { |
| LTRACEF(" No sign node (signature): %s\n",fdt_strerror(sig_node)); |
| return -1; |
| } |
| |
| list_each_subnode(sig_blob, noffset, sig_node) { |
| req_node = fdt_getprop(sig_blob, noffset, BLOB_REQ_NODE, NULL); |
| if ((req_node !=NULL)&&(!strcmp(req_node, "conf"))) { |
| ret = fit_verify_configed_sign(fit, conf_noffset, sig_blob,noffset); |
| if (ret) { |
| LTRACEF("Failed to verify '%s'\n", |
| fit_get_name(sig_blob, noffset, NULL)); |
| } |
| return ret; |
| } |
| } |
| |
| return -1; |
| } |