1604f23ddSSimon Glass /* 2604f23ddSSimon Glass * Copyright (c) 2013, Google Inc. 3604f23ddSSimon Glass * 4604f23ddSSimon Glass * (C) Copyright 2008 Semihalf 5604f23ddSSimon Glass * 6604f23ddSSimon Glass * (C) Copyright 2000-2006 7604f23ddSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 8604f23ddSSimon Glass * 9*1a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 10604f23ddSSimon Glass */ 11604f23ddSSimon Glass 12604f23ddSSimon Glass #include "mkimage.h" 13604f23ddSSimon Glass #include <image.h> 1456518e71SSimon Glass #include <version.h> 15604f23ddSSimon Glass 16604f23ddSSimon Glass /** 17b7260910SSimon Glass * fit_set_hash_value - set hash value in requested has node 18b7260910SSimon Glass * @fit: pointer to the FIT format image header 19b7260910SSimon Glass * @noffset: hash node offset 20b7260910SSimon Glass * @value: hash value to be set 21b7260910SSimon Glass * @value_len: hash value length 22b7260910SSimon Glass * 23b7260910SSimon Glass * fit_set_hash_value() attempts to set hash value in a node at offset 24b7260910SSimon Glass * given and returns operation status to the caller. 25b7260910SSimon Glass * 26b7260910SSimon Glass * returns 27b7260910SSimon Glass * 0, on success 28b7260910SSimon Glass * -1, on failure 29b7260910SSimon Glass */ 30b7260910SSimon Glass static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 31b7260910SSimon Glass int value_len) 32b7260910SSimon Glass { 33b7260910SSimon Glass int ret; 34b7260910SSimon Glass 35b7260910SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 36b7260910SSimon Glass if (ret) { 37b7260910SSimon Glass printf("Can't set hash '%s' property for '%s' node(%s)\n", 38b7260910SSimon Glass FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 39b7260910SSimon Glass fdt_strerror(ret)); 40b7260910SSimon Glass return -1; 41b7260910SSimon Glass } 42b7260910SSimon Glass 43b7260910SSimon Glass return 0; 44b7260910SSimon Glass } 45b7260910SSimon Glass 46b7260910SSimon Glass /** 4794e5fa46SSimon Glass * fit_image_process_hash - Process a single subnode of the images/ node 4894e5fa46SSimon Glass * 4994e5fa46SSimon Glass * Check each subnode and process accordingly. For hash nodes we generate 5094e5fa46SSimon Glass * a hash of the supplised data and store it in the node. 5194e5fa46SSimon Glass * 5294e5fa46SSimon Glass * @fit: pointer to the FIT format image header 5394e5fa46SSimon Glass * @image_name: name of image being processes (used to display errors) 5494e5fa46SSimon Glass * @noffset: subnode offset 5594e5fa46SSimon Glass * @data: data to process 5694e5fa46SSimon Glass * @size: size of data in bytes 5794e5fa46SSimon Glass * @return 0 if ok, -1 on error 5894e5fa46SSimon Glass */ 5994e5fa46SSimon Glass static int fit_image_process_hash(void *fit, const char *image_name, 6094e5fa46SSimon Glass int noffset, const void *data, size_t size) 6194e5fa46SSimon Glass { 6294e5fa46SSimon Glass uint8_t value[FIT_MAX_HASH_LEN]; 63bbb467dcSSimon Glass const char *node_name; 6494e5fa46SSimon Glass int value_len; 6594e5fa46SSimon Glass char *algo; 6694e5fa46SSimon Glass 67bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6894e5fa46SSimon Glass 6994e5fa46SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo)) { 7094e5fa46SSimon Glass printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 71bbb467dcSSimon Glass node_name, image_name); 7294e5fa46SSimon Glass return -1; 7394e5fa46SSimon Glass } 7494e5fa46SSimon Glass 7594e5fa46SSimon Glass if (calculate_hash(data, size, algo, value, &value_len)) { 7694e5fa46SSimon Glass printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 77bbb467dcSSimon Glass algo, node_name, image_name); 7894e5fa46SSimon Glass return -1; 7994e5fa46SSimon Glass } 8094e5fa46SSimon Glass 81b7260910SSimon Glass if (fit_set_hash_value(fit, noffset, value, value_len)) { 8294e5fa46SSimon Glass printf("Can't set hash value for '%s' hash node in '%s' image node\n", 83bbb467dcSSimon Glass node_name, image_name); 8494e5fa46SSimon Glass return -1; 8594e5fa46SSimon Glass } 8694e5fa46SSimon Glass 8794e5fa46SSimon Glass return 0; 8894e5fa46SSimon Glass } 8994e5fa46SSimon Glass 9094e5fa46SSimon Glass /** 9156518e71SSimon Glass * fit_image_write_sig() - write the signature to a FIT 92604f23ddSSimon Glass * 9356518e71SSimon Glass * This writes the signature and signer data to the FIT. 9456518e71SSimon Glass * 9556518e71SSimon Glass * @fit: pointer to the FIT format image header 9656518e71SSimon Glass * @noffset: hash node offset 9756518e71SSimon Glass * @value: signature value to be set 9856518e71SSimon Glass * @value_len: signature value length 9956518e71SSimon Glass * @comment: Text comment to write (NULL for none) 10056518e71SSimon Glass * 10156518e71SSimon Glass * returns 10256518e71SSimon Glass * 0, on success 10356518e71SSimon Glass * -FDT_ERR_..., on failure 10456518e71SSimon Glass */ 10556518e71SSimon Glass static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 10656518e71SSimon Glass int value_len, const char *comment, const char *region_prop, 10756518e71SSimon Glass int region_proplen) 10856518e71SSimon Glass { 10956518e71SSimon Glass int string_size; 11056518e71SSimon Glass int ret; 11156518e71SSimon Glass 11256518e71SSimon Glass /* 11356518e71SSimon Glass * Get the current string size, before we update the FIT and add 11456518e71SSimon Glass * more 11556518e71SSimon Glass */ 11656518e71SSimon Glass string_size = fdt_size_dt_strings(fit); 11756518e71SSimon Glass 11856518e71SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 11956518e71SSimon Glass if (!ret) { 12056518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-name", 12156518e71SSimon Glass "mkimage"); 12256518e71SSimon Glass } 12356518e71SSimon Glass if (!ret) { 12456518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-version", 12556518e71SSimon Glass PLAIN_VERSION); 12656518e71SSimon Glass } 12756518e71SSimon Glass if (comment && !ret) 12856518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "comment", comment); 12956518e71SSimon Glass if (!ret) 13056518e71SSimon Glass ret = fit_set_timestamp(fit, noffset, time(NULL)); 13156518e71SSimon Glass if (region_prop && !ret) { 13256518e71SSimon Glass uint32_t strdata[2]; 13356518e71SSimon Glass 13456518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-nodes", 13556518e71SSimon Glass region_prop, region_proplen); 13656518e71SSimon Glass strdata[0] = 0; 13756518e71SSimon Glass strdata[1] = cpu_to_fdt32(string_size); 13856518e71SSimon Glass if (!ret) { 13956518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-strings", 14056518e71SSimon Glass strdata, sizeof(strdata)); 14156518e71SSimon Glass } 14256518e71SSimon Glass } 14356518e71SSimon Glass 14456518e71SSimon Glass return ret; 14556518e71SSimon Glass } 14656518e71SSimon Glass 14756518e71SSimon Glass static int fit_image_setup_sig(struct image_sign_info *info, 14856518e71SSimon Glass const char *keydir, void *fit, const char *image_name, 14956518e71SSimon Glass int noffset, const char *require_keys) 15056518e71SSimon Glass { 15156518e71SSimon Glass const char *node_name; 15256518e71SSimon Glass char *algo_name; 15356518e71SSimon Glass 15456518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 15556518e71SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 15656518e71SSimon Glass printf("Can't get algo property for '%s' signature node in '%s' image node\n", 15756518e71SSimon Glass node_name, image_name); 15856518e71SSimon Glass return -1; 15956518e71SSimon Glass } 16056518e71SSimon Glass 16156518e71SSimon Glass memset(info, '\0', sizeof(*info)); 16256518e71SSimon Glass info->keydir = keydir; 16356518e71SSimon Glass info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 16456518e71SSimon Glass info->fit = fit; 16556518e71SSimon Glass info->node_offset = noffset; 16656518e71SSimon Glass info->algo = image_get_sig_algo(algo_name); 16756518e71SSimon Glass info->require_keys = require_keys; 16856518e71SSimon Glass if (!info->algo) { 16956518e71SSimon Glass printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 17056518e71SSimon Glass algo_name, node_name, image_name); 17156518e71SSimon Glass return -1; 17256518e71SSimon Glass } 17356518e71SSimon Glass 17456518e71SSimon Glass return 0; 17556518e71SSimon Glass } 17656518e71SSimon Glass 17756518e71SSimon Glass /** 17856518e71SSimon Glass * fit_image_process_sig- Process a single subnode of the images/ node 17956518e71SSimon Glass * 18056518e71SSimon Glass * Check each subnode and process accordingly. For signature nodes we 18156518e71SSimon Glass * generate a signed hash of the supplised data and store it in the node. 18256518e71SSimon Glass * 18356518e71SSimon Glass * @keydir: Directory containing keys to use for signing 18456518e71SSimon Glass * @keydest: Destination FDT blob to write public keys into 18556518e71SSimon Glass * @fit: pointer to the FIT format image header 18656518e71SSimon Glass * @image_name: name of image being processes (used to display errors) 18756518e71SSimon Glass * @noffset: subnode offset 18856518e71SSimon Glass * @data: data to process 18956518e71SSimon Glass * @size: size of data in bytes 19056518e71SSimon Glass * @comment: Comment to add to signature nodes 19156518e71SSimon Glass * @require_keys: Mark all keys as 'required' 19256518e71SSimon Glass * @return 0 if ok, -1 on error 19356518e71SSimon Glass */ 19456518e71SSimon Glass static int fit_image_process_sig(const char *keydir, void *keydest, 19556518e71SSimon Glass void *fit, const char *image_name, 19656518e71SSimon Glass int noffset, const void *data, size_t size, 19756518e71SSimon Glass const char *comment, int require_keys) 19856518e71SSimon Glass { 19956518e71SSimon Glass struct image_sign_info info; 20056518e71SSimon Glass struct image_region region; 20156518e71SSimon Glass const char *node_name; 20256518e71SSimon Glass uint8_t *value; 20356518e71SSimon Glass uint value_len; 20456518e71SSimon Glass int ret; 20556518e71SSimon Glass 20656518e71SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 20756518e71SSimon Glass require_keys ? "image" : NULL)) 20856518e71SSimon Glass return -1; 20956518e71SSimon Glass 21056518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 21156518e71SSimon Glass region.data = data; 21256518e71SSimon Glass region.size = size; 21356518e71SSimon Glass ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); 21456518e71SSimon Glass if (ret) { 21556518e71SSimon Glass printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 21656518e71SSimon Glass node_name, image_name, ret); 21756518e71SSimon Glass 21856518e71SSimon Glass /* We allow keys to be missing */ 21956518e71SSimon Glass if (ret == -ENOENT) 22056518e71SSimon Glass return 0; 22156518e71SSimon Glass return -1; 22256518e71SSimon Glass } 22356518e71SSimon Glass 22456518e71SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 22556518e71SSimon Glass NULL, 0); 22656518e71SSimon Glass if (ret) { 22756518e71SSimon Glass printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", 22856518e71SSimon Glass node_name, image_name, fdt_strerror(ret)); 22956518e71SSimon Glass return -1; 23056518e71SSimon Glass } 23156518e71SSimon Glass free(value); 23256518e71SSimon Glass 23356518e71SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 23456518e71SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 23556518e71SSimon Glass 23656518e71SSimon Glass /* Write the public key into the supplied FDT file */ 23756518e71SSimon Glass if (keydest && info.algo->add_verify_data(&info, keydest)) { 23856518e71SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 23956518e71SSimon Glass node_name, image_name); 24056518e71SSimon Glass return -1; 24156518e71SSimon Glass } 24256518e71SSimon Glass 24356518e71SSimon Glass return 0; 24456518e71SSimon Glass } 24556518e71SSimon Glass 24656518e71SSimon Glass /** 24756518e71SSimon Glass * fit_image_add_verification_data() - calculate/set verig. data for image node 24856518e71SSimon Glass * 24956518e71SSimon Glass * This adds hash and signature values for an component image node. 250bbb467dcSSimon Glass * 251bbb467dcSSimon Glass * All existing hash subnodes are checked, if algorithm property is set to 252bbb467dcSSimon Glass * one of the supported hash algorithms, hash value is computed and 253bbb467dcSSimon Glass * corresponding hash node property is set, for example: 254604f23ddSSimon Glass * 255604f23ddSSimon Glass * Input component image node structure: 256604f23ddSSimon Glass * 257604f23ddSSimon Glass * o image@1 (at image_noffset) 258604f23ddSSimon Glass * | - data = [binary data] 259604f23ddSSimon Glass * o hash@1 260604f23ddSSimon Glass * |- algo = "sha1" 261604f23ddSSimon Glass * 262604f23ddSSimon Glass * Output component image node structure: 263604f23ddSSimon Glass * 264604f23ddSSimon Glass * o image@1 (at image_noffset) 265604f23ddSSimon Glass * | - data = [binary data] 266604f23ddSSimon Glass * o hash@1 267604f23ddSSimon Glass * |- algo = "sha1" 268604f23ddSSimon Glass * |- value = sha1(data) 269604f23ddSSimon Glass * 270bbb467dcSSimon Glass * For signature details, please see doc/uImage.FIT/signature.txt 271bbb467dcSSimon Glass * 27256518e71SSimon Glass * @keydir Directory containing *.key and *.crt files (or NULL) 27356518e71SSimon Glass * @keydest FDT Blob to write public keys into (NULL if none) 274bbb467dcSSimon Glass * @fit: Pointer to the FIT format image header 275bbb467dcSSimon Glass * @image_noffset: Requested component image node 27656518e71SSimon Glass * @comment: Comment to add to signature nodes 27756518e71SSimon Glass * @require_keys: Mark all keys as 'required' 278bbb467dcSSimon Glass * @return: 0 on success, <0 on failure 279604f23ddSSimon Glass */ 28056518e71SSimon Glass int fit_image_add_verification_data(const char *keydir, void *keydest, 28156518e71SSimon Glass void *fit, int image_noffset, const char *comment, 28256518e71SSimon Glass int require_keys) 283604f23ddSSimon Glass { 284bbb467dcSSimon Glass const char *image_name; 285604f23ddSSimon Glass const void *data; 286604f23ddSSimon Glass size_t size; 287604f23ddSSimon Glass int noffset; 288604f23ddSSimon Glass 289604f23ddSSimon Glass /* Get image data and data length */ 290604f23ddSSimon Glass if (fit_image_get_data(fit, image_noffset, &data, &size)) { 291604f23ddSSimon Glass printf("Can't get image data/size\n"); 292604f23ddSSimon Glass return -1; 293604f23ddSSimon Glass } 294604f23ddSSimon Glass 29594e5fa46SSimon Glass image_name = fit_get_name(fit, image_noffset, NULL); 29694e5fa46SSimon Glass 297604f23ddSSimon Glass /* Process all hash subnodes of the component image node */ 298bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 299bbb467dcSSimon Glass noffset >= 0; 300bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 301bbb467dcSSimon Glass const char *node_name; 302bbb467dcSSimon Glass int ret = 0; 303bbb467dcSSimon Glass 304bbb467dcSSimon Glass /* 305bbb467dcSSimon Glass * Check subnode name, must be equal to "hash" or "signature". 306bbb467dcSSimon Glass * Multiple hash nodes require unique unit node 307bbb467dcSSimon Glass * names, e.g. hash@1, hash@2, signature@1, etc. 308bbb467dcSSimon Glass */ 309bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 310bbb467dcSSimon Glass if (!strncmp(node_name, FIT_HASH_NODENAME, 311bbb467dcSSimon Glass strlen(FIT_HASH_NODENAME))) { 312bbb467dcSSimon Glass ret = fit_image_process_hash(fit, image_name, noffset, 313bbb467dcSSimon Glass data, size); 31456518e71SSimon Glass } else if (IMAGE_ENABLE_SIGN && keydir && 31556518e71SSimon Glass !strncmp(node_name, FIT_SIG_NODENAME, 31656518e71SSimon Glass strlen(FIT_SIG_NODENAME))) { 31756518e71SSimon Glass ret = fit_image_process_sig(keydir, keydest, 31856518e71SSimon Glass fit, image_name, noffset, data, size, 31956518e71SSimon Glass comment, require_keys); 320bbb467dcSSimon Glass } 321bbb467dcSSimon Glass if (ret) 322604f23ddSSimon Glass return -1; 323604f23ddSSimon Glass } 324bbb467dcSSimon Glass 325bbb467dcSSimon Glass return 0; 326bbb467dcSSimon Glass } 327bbb467dcSSimon Glass 3284d098529SSimon Glass struct strlist { 3294d098529SSimon Glass int count; 3304d098529SSimon Glass char **strings; 3314d098529SSimon Glass }; 3324d098529SSimon Glass 3334d098529SSimon Glass static void strlist_init(struct strlist *list) 3344d098529SSimon Glass { 3354d098529SSimon Glass memset(list, '\0', sizeof(*list)); 3364d098529SSimon Glass } 3374d098529SSimon Glass 3384d098529SSimon Glass static void strlist_free(struct strlist *list) 3394d098529SSimon Glass { 3404d098529SSimon Glass int i; 3414d098529SSimon Glass 3424d098529SSimon Glass for (i = 0; i < list->count; i++) 3434d098529SSimon Glass free(list->strings[i]); 3444d098529SSimon Glass free(list->strings); 3454d098529SSimon Glass } 3464d098529SSimon Glass 3474d098529SSimon Glass static int strlist_add(struct strlist *list, const char *str) 3484d098529SSimon Glass { 3494d098529SSimon Glass char *dup; 3504d098529SSimon Glass 3514d098529SSimon Glass dup = strdup(str); 3524d098529SSimon Glass list->strings = realloc(list->strings, 3534d098529SSimon Glass (list->count + 1) * sizeof(char *)); 3544d098529SSimon Glass if (!list || !str) 3554d098529SSimon Glass return -1; 3564d098529SSimon Glass list->strings[list->count++] = dup; 3574d098529SSimon Glass 3584d098529SSimon Glass return 0; 3594d098529SSimon Glass } 3604d098529SSimon Glass 3614d098529SSimon Glass static const char *fit_config_get_image_list(void *fit, int noffset, 3624d098529SSimon Glass int *lenp, int *allow_missingp) 3634d098529SSimon Glass { 3644d098529SSimon Glass static const char default_list[] = FIT_KERNEL_PROP "\0" 3654d098529SSimon Glass FIT_FDT_PROP; 3664d098529SSimon Glass const char *prop; 3674d098529SSimon Glass 3684d098529SSimon Glass /* If there is an "image" property, use that */ 3694d098529SSimon Glass prop = fdt_getprop(fit, noffset, "sign-images", lenp); 3704d098529SSimon Glass if (prop) { 3714d098529SSimon Glass *allow_missingp = 0; 3724d098529SSimon Glass return *lenp ? prop : NULL; 3734d098529SSimon Glass } 3744d098529SSimon Glass 3754d098529SSimon Glass /* Default image list */ 3764d098529SSimon Glass *allow_missingp = 1; 3774d098529SSimon Glass *lenp = sizeof(default_list); 3784d098529SSimon Glass 3794d098529SSimon Glass return default_list; 3804d098529SSimon Glass } 3814d098529SSimon Glass 3824d098529SSimon Glass static int fit_config_get_hash_list(void *fit, int conf_noffset, 3834d098529SSimon Glass int sig_offset, struct strlist *node_inc) 3844d098529SSimon Glass { 3854d098529SSimon Glass int allow_missing; 3864d098529SSimon Glass const char *prop, *iname, *end; 3874d098529SSimon Glass const char *conf_name, *sig_name; 3884d098529SSimon Glass char name[200], path[200]; 3894d098529SSimon Glass int image_count; 3904d098529SSimon Glass int ret, len; 3914d098529SSimon Glass 3924d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 3934d098529SSimon Glass sig_name = fit_get_name(fit, sig_offset, NULL); 3944d098529SSimon Glass 3954d098529SSimon Glass /* 3964d098529SSimon Glass * Build a list of nodes we need to hash. We always need the root 3974d098529SSimon Glass * node and the configuration. 3984d098529SSimon Glass */ 3994d098529SSimon Glass strlist_init(node_inc); 4004d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 4014d098529SSimon Glass if (strlist_add(node_inc, "/") || 4024d098529SSimon Glass strlist_add(node_inc, name)) 4034d098529SSimon Glass goto err_mem; 4044d098529SSimon Glass 4054d098529SSimon Glass /* Get a list of images that we intend to sign */ 4064d098529SSimon Glass prop = fit_config_get_image_list(fit, conf_noffset, &len, 4074d098529SSimon Glass &allow_missing); 4084d098529SSimon Glass if (!prop) 4094d098529SSimon Glass return 0; 4104d098529SSimon Glass 4114d098529SSimon Glass /* Locate the images */ 4124d098529SSimon Glass end = prop + len; 4134d098529SSimon Glass image_count = 0; 4144d098529SSimon Glass for (iname = prop; iname < end; iname += strlen(iname) + 1) { 4154d098529SSimon Glass int noffset; 4164d098529SSimon Glass int image_noffset; 4174d098529SSimon Glass int hash_count; 4184d098529SSimon Glass 4194d098529SSimon Glass image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 4204d098529SSimon Glass iname); 4214d098529SSimon Glass if (image_noffset < 0) { 4224d098529SSimon Glass printf("Failed to find image '%s' in configuration '%s/%s'\n", 4234d098529SSimon Glass iname, conf_name, sig_name); 4244d098529SSimon Glass if (allow_missing) 4254d098529SSimon Glass continue; 4264d098529SSimon Glass 4274d098529SSimon Glass return -ENOENT; 4284d098529SSimon Glass } 4294d098529SSimon Glass 4304d098529SSimon Glass ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 4314d098529SSimon Glass if (ret < 0) 4324d098529SSimon Glass goto err_path; 4334d098529SSimon Glass if (strlist_add(node_inc, path)) 4344d098529SSimon Glass goto err_mem; 4354d098529SSimon Glass 4364d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 4374d098529SSimon Glass conf_name); 4384d098529SSimon Glass 4394d098529SSimon Glass /* Add all this image's hashes */ 4404d098529SSimon Glass hash_count = 0; 4414d098529SSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 4424d098529SSimon Glass noffset >= 0; 4434d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 4444d098529SSimon Glass const char *name = fit_get_name(fit, noffset, NULL); 4454d098529SSimon Glass 4464d098529SSimon Glass if (strncmp(name, FIT_HASH_NODENAME, 4474d098529SSimon Glass strlen(FIT_HASH_NODENAME))) 4484d098529SSimon Glass continue; 4494d098529SSimon Glass ret = fdt_get_path(fit, noffset, path, sizeof(path)); 4504d098529SSimon Glass if (ret < 0) 4514d098529SSimon Glass goto err_path; 4524d098529SSimon Glass if (strlist_add(node_inc, path)) 4534d098529SSimon Glass goto err_mem; 4544d098529SSimon Glass hash_count++; 4554d098529SSimon Glass } 4564d098529SSimon Glass 4574d098529SSimon Glass if (!hash_count) { 4584d098529SSimon Glass printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n", 4594d098529SSimon Glass conf_name, sig_name, iname); 4604d098529SSimon Glass return -ENOMSG; 4614d098529SSimon Glass } 4624d098529SSimon Glass 4634d098529SSimon Glass image_count++; 4644d098529SSimon Glass } 4654d098529SSimon Glass 4664d098529SSimon Glass if (!image_count) { 4674d098529SSimon Glass printf("Failed to find any images for configuration '%s/%s'\n", 4684d098529SSimon Glass conf_name, sig_name); 4694d098529SSimon Glass return -ENOMSG; 4704d098529SSimon Glass } 4714d098529SSimon Glass 4724d098529SSimon Glass return 0; 4734d098529SSimon Glass 4744d098529SSimon Glass err_mem: 4754d098529SSimon Glass printf("Out of memory processing configuration '%s/%s'\n", conf_name, 4764d098529SSimon Glass sig_name); 4774d098529SSimon Glass return -ENOMEM; 4784d098529SSimon Glass 4794d098529SSimon Glass err_path: 4804d098529SSimon Glass printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 4814d098529SSimon Glass iname, conf_name, sig_name, fdt_strerror(ret)); 4824d098529SSimon Glass return -ENOENT; 4834d098529SSimon Glass } 4844d098529SSimon Glass 4854d098529SSimon Glass static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 4864d098529SSimon Glass struct image_region **regionp, int *region_countp, 4874d098529SSimon Glass char **region_propp, int *region_proplen) 4884d098529SSimon Glass { 4894d098529SSimon Glass char * const exc_prop[] = {"data"}; 4904d098529SSimon Glass struct strlist node_inc; 4914d098529SSimon Glass struct image_region *region; 4924d098529SSimon Glass struct fdt_region fdt_regions[100]; 4934d098529SSimon Glass const char *conf_name, *sig_name; 4944d098529SSimon Glass char path[200]; 4954d098529SSimon Glass int count, i; 4964d098529SSimon Glass char *region_prop; 4974d098529SSimon Glass int ret, len; 4984d098529SSimon Glass 4994d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 5004d098529SSimon Glass sig_name = fit_get_name(fit, conf_noffset, NULL); 5014d098529SSimon Glass debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 5024d098529SSimon Glass 5034d098529SSimon Glass /* Get a list of nodes we want to hash */ 5044d098529SSimon Glass ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 5054d098529SSimon Glass if (ret) 5064d098529SSimon Glass return ret; 5074d098529SSimon Glass 5084d098529SSimon Glass /* Get a list of regions to hash */ 5094d098529SSimon Glass count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 5104d098529SSimon Glass exc_prop, ARRAY_SIZE(exc_prop), 5114d098529SSimon Glass fdt_regions, ARRAY_SIZE(fdt_regions), 5124d098529SSimon Glass path, sizeof(path), 1); 5134d098529SSimon Glass if (count < 0) { 5144d098529SSimon Glass printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 5154d098529SSimon Glass sig_name, fdt_strerror(ret)); 5164d098529SSimon Glass return -EIO; 5174d098529SSimon Glass } 5184d098529SSimon Glass if (count == 0) { 5194d098529SSimon Glass printf("No data to hash for configuration '%s/%s': %s\n", 5204d098529SSimon Glass conf_name, sig_name, fdt_strerror(ret)); 5214d098529SSimon Glass return -EINVAL; 5224d098529SSimon Glass } 5234d098529SSimon Glass 5244d098529SSimon Glass /* Build our list of data blocks */ 5254d098529SSimon Glass region = fit_region_make_list(fit, fdt_regions, count, NULL); 5264d098529SSimon Glass if (!region) { 5274d098529SSimon Glass printf("Out of memory hashing configuration '%s/%s'\n", 5284d098529SSimon Glass conf_name, sig_name); 5294d098529SSimon Glass return -ENOMEM; 5304d098529SSimon Glass } 5314d098529SSimon Glass 5324d098529SSimon Glass /* Create a list of all hashed properties */ 5334d098529SSimon Glass debug("Hash nodes:\n"); 5344d098529SSimon Glass for (i = len = 0; i < node_inc.count; i++) { 5354d098529SSimon Glass debug(" %s\n", node_inc.strings[i]); 5364d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1; 5374d098529SSimon Glass } 5384d098529SSimon Glass region_prop = malloc(len); 5394d098529SSimon Glass if (!region_prop) { 5404d098529SSimon Glass printf("Out of memory setting up regions for configuration '%s/%s'\n", 5414d098529SSimon Glass conf_name, sig_name); 5424d098529SSimon Glass return -ENOMEM; 5434d098529SSimon Glass } 5444d098529SSimon Glass for (i = len = 0; i < node_inc.count; 5454d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1, i++) 5464d098529SSimon Glass strcpy(region_prop + len, node_inc.strings[i]); 5474d098529SSimon Glass strlist_free(&node_inc); 5484d098529SSimon Glass 5494d098529SSimon Glass *region_countp = count; 5504d098529SSimon Glass *regionp = region; 5514d098529SSimon Glass *region_propp = region_prop; 5524d098529SSimon Glass *region_proplen = len; 5534d098529SSimon Glass 5544d098529SSimon Glass return 0; 5554d098529SSimon Glass } 5564d098529SSimon Glass 5574d098529SSimon Glass static int fit_config_process_sig(const char *keydir, void *keydest, 5584d098529SSimon Glass void *fit, const char *conf_name, int conf_noffset, 5594d098529SSimon Glass int noffset, const char *comment, int require_keys) 5604d098529SSimon Glass { 5614d098529SSimon Glass struct image_sign_info info; 5624d098529SSimon Glass const char *node_name; 5634d098529SSimon Glass struct image_region *region; 5644d098529SSimon Glass char *region_prop; 5654d098529SSimon Glass int region_proplen; 5664d098529SSimon Glass int region_count; 5674d098529SSimon Glass uint8_t *value; 5684d098529SSimon Glass uint value_len; 5694d098529SSimon Glass int ret; 5704d098529SSimon Glass 5714d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 5724d098529SSimon Glass if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 5734d098529SSimon Glass ®ion_count, ®ion_prop, ®ion_proplen)) 5744d098529SSimon Glass return -1; 5754d098529SSimon Glass 5764d098529SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 5774d098529SSimon Glass require_keys ? "conf" : NULL)) 5784d098529SSimon Glass return -1; 5794d098529SSimon Glass 5804d098529SSimon Glass ret = info.algo->sign(&info, region, region_count, &value, &value_len); 5814d098529SSimon Glass free(region); 5824d098529SSimon Glass if (ret) { 5834d098529SSimon Glass printf("Failed to sign '%s' signature node in '%s' conf node\n", 5844d098529SSimon Glass node_name, conf_name); 5854d098529SSimon Glass 5864d098529SSimon Glass /* We allow keys to be missing */ 5874d098529SSimon Glass if (ret == -ENOENT) 5884d098529SSimon Glass return 0; 5894d098529SSimon Glass return -1; 5904d098529SSimon Glass } 5914d098529SSimon Glass 5924d098529SSimon Glass if (fit_image_write_sig(fit, noffset, value, value_len, comment, 5934d098529SSimon Glass region_prop, region_proplen)) { 5944d098529SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node\n", 5954d098529SSimon Glass node_name, conf_name); 5964d098529SSimon Glass return -1; 5974d098529SSimon Glass } 5984d098529SSimon Glass free(value); 5994d098529SSimon Glass free(region_prop); 6004d098529SSimon Glass 6014d098529SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 6024d098529SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 6034d098529SSimon Glass 6044d098529SSimon Glass /* Write the public key into the supplied FDT file */ 6054d098529SSimon Glass if (keydest && info.algo->add_verify_data(&info, keydest)) { 6064d098529SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 6074d098529SSimon Glass node_name, conf_name); 6084d098529SSimon Glass return -1; 6094d098529SSimon Glass } 6104d098529SSimon Glass 6114d098529SSimon Glass return 0; 6124d098529SSimon Glass } 6134d098529SSimon Glass 6144d098529SSimon Glass static int fit_config_add_verification_data(const char *keydir, void *keydest, 6154d098529SSimon Glass void *fit, int conf_noffset, const char *comment, 6164d098529SSimon Glass int require_keys) 6174d098529SSimon Glass { 6184d098529SSimon Glass const char *conf_name; 6194d098529SSimon Glass int noffset; 6204d098529SSimon Glass 6214d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 6224d098529SSimon Glass 6234d098529SSimon Glass /* Process all hash subnodes of the configuration node */ 6244d098529SSimon Glass for (noffset = fdt_first_subnode(fit, conf_noffset); 6254d098529SSimon Glass noffset >= 0; 6264d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6274d098529SSimon Glass const char *node_name; 6284d098529SSimon Glass int ret = 0; 6294d098529SSimon Glass 6304d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6314d098529SSimon Glass if (!strncmp(node_name, FIT_SIG_NODENAME, 6324d098529SSimon Glass strlen(FIT_SIG_NODENAME))) { 6334d098529SSimon Glass ret = fit_config_process_sig(keydir, keydest, 6344d098529SSimon Glass fit, conf_name, conf_noffset, noffset, comment, 6354d098529SSimon Glass require_keys); 6364d098529SSimon Glass } 6374d098529SSimon Glass if (ret) 6384d098529SSimon Glass return ret; 6394d098529SSimon Glass } 6404d098529SSimon Glass 6414d098529SSimon Glass return 0; 6424d098529SSimon Glass } 6434d098529SSimon Glass 64456518e71SSimon Glass int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 64556518e71SSimon Glass const char *comment, int require_keys) 646bbb467dcSSimon Glass { 6474d098529SSimon Glass int images_noffset, confs_noffset; 648bbb467dcSSimon Glass int noffset; 649bbb467dcSSimon Glass int ret; 650bbb467dcSSimon Glass 651bbb467dcSSimon Glass /* Find images parent node offset */ 652bbb467dcSSimon Glass images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 653bbb467dcSSimon Glass if (images_noffset < 0) { 654bbb467dcSSimon Glass printf("Can't find images parent node '%s' (%s)\n", 655bbb467dcSSimon Glass FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 656bbb467dcSSimon Glass return images_noffset; 657bbb467dcSSimon Glass } 658bbb467dcSSimon Glass 659bbb467dcSSimon Glass /* Process its subnodes, print out component images details */ 660bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, images_noffset); 661bbb467dcSSimon Glass noffset >= 0; 662bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 663bbb467dcSSimon Glass /* 664bbb467dcSSimon Glass * Direct child node of the images parent node, 665bbb467dcSSimon Glass * i.e. component image node. 666bbb467dcSSimon Glass */ 66756518e71SSimon Glass ret = fit_image_add_verification_data(keydir, keydest, 66856518e71SSimon Glass fit, noffset, comment, require_keys); 669bbb467dcSSimon Glass if (ret) 670bbb467dcSSimon Glass return ret; 671604f23ddSSimon Glass } 672604f23ddSSimon Glass 6734d098529SSimon Glass /* If there are no keys, we can't sign configurations */ 6744d098529SSimon Glass if (!IMAGE_ENABLE_SIGN || !keydir) 6754d098529SSimon Glass return 0; 6764d098529SSimon Glass 6774d098529SSimon Glass /* Find configurations parent node offset */ 6784d098529SSimon Glass confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 6794d098529SSimon Glass if (confs_noffset < 0) { 6804d098529SSimon Glass printf("Can't find images parent node '%s' (%s)\n", 6814d098529SSimon Glass FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); 6824d098529SSimon Glass return -ENOENT; 6834d098529SSimon Glass } 6844d098529SSimon Glass 6854d098529SSimon Glass /* Process its subnodes, print out component images details */ 6864d098529SSimon Glass for (noffset = fdt_first_subnode(fit, confs_noffset); 6874d098529SSimon Glass noffset >= 0; 6884d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6894d098529SSimon Glass ret = fit_config_add_verification_data(keydir, keydest, 6904d098529SSimon Glass fit, noffset, comment, 6914d098529SSimon Glass require_keys); 6924d098529SSimon Glass if (ret) 6934d098529SSimon Glass return ret; 6944d098529SSimon Glass } 6954d098529SSimon Glass 696604f23ddSSimon Glass return 0; 697604f23ddSSimon Glass } 698