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 * 91a459660SWolfgang 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) { 227a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 228a9468115SSimon Glass return -ENOSPC; 229a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 23056518e71SSimon Glass node_name, image_name, fdt_strerror(ret)); 23156518e71SSimon Glass return -1; 23256518e71SSimon Glass } 23356518e71SSimon Glass free(value); 23456518e71SSimon Glass 23556518e71SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 23656518e71SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 23756518e71SSimon Glass 23856518e71SSimon Glass /* Write the public key into the supplied FDT file */ 23956518e71SSimon Glass if (keydest && info.algo->add_verify_data(&info, keydest)) { 24056518e71SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 24156518e71SSimon Glass node_name, image_name); 24256518e71SSimon Glass return -1; 24356518e71SSimon Glass } 24456518e71SSimon Glass 24556518e71SSimon Glass return 0; 24656518e71SSimon Glass } 24756518e71SSimon Glass 24856518e71SSimon Glass /** 24956518e71SSimon Glass * fit_image_add_verification_data() - calculate/set verig. data for image node 25056518e71SSimon Glass * 25156518e71SSimon Glass * This adds hash and signature values for an component image node. 252bbb467dcSSimon Glass * 253bbb467dcSSimon Glass * All existing hash subnodes are checked, if algorithm property is set to 254bbb467dcSSimon Glass * one of the supported hash algorithms, hash value is computed and 255bbb467dcSSimon Glass * corresponding hash node property is set, for example: 256604f23ddSSimon Glass * 257604f23ddSSimon Glass * Input component image node structure: 258604f23ddSSimon Glass * 259604f23ddSSimon Glass * o image@1 (at image_noffset) 260604f23ddSSimon Glass * | - data = [binary data] 261604f23ddSSimon Glass * o hash@1 262604f23ddSSimon Glass * |- algo = "sha1" 263604f23ddSSimon Glass * 264604f23ddSSimon Glass * Output component image node structure: 265604f23ddSSimon Glass * 266604f23ddSSimon Glass * o image@1 (at image_noffset) 267604f23ddSSimon Glass * | - data = [binary data] 268604f23ddSSimon Glass * o hash@1 269604f23ddSSimon Glass * |- algo = "sha1" 270604f23ddSSimon Glass * |- value = sha1(data) 271604f23ddSSimon Glass * 272bbb467dcSSimon Glass * For signature details, please see doc/uImage.FIT/signature.txt 273bbb467dcSSimon Glass * 27456518e71SSimon Glass * @keydir Directory containing *.key and *.crt files (or NULL) 27556518e71SSimon Glass * @keydest FDT Blob to write public keys into (NULL if none) 276bbb467dcSSimon Glass * @fit: Pointer to the FIT format image header 277bbb467dcSSimon Glass * @image_noffset: Requested component image node 27856518e71SSimon Glass * @comment: Comment to add to signature nodes 27956518e71SSimon Glass * @require_keys: Mark all keys as 'required' 280bbb467dcSSimon Glass * @return: 0 on success, <0 on failure 281604f23ddSSimon Glass */ 28256518e71SSimon Glass int fit_image_add_verification_data(const char *keydir, void *keydest, 28356518e71SSimon Glass void *fit, int image_noffset, const char *comment, 28456518e71SSimon Glass int require_keys) 285604f23ddSSimon Glass { 286bbb467dcSSimon Glass const char *image_name; 287604f23ddSSimon Glass const void *data; 288604f23ddSSimon Glass size_t size; 289604f23ddSSimon Glass int noffset; 290604f23ddSSimon Glass 291604f23ddSSimon Glass /* Get image data and data length */ 292604f23ddSSimon Glass if (fit_image_get_data(fit, image_noffset, &data, &size)) { 293604f23ddSSimon Glass printf("Can't get image data/size\n"); 294604f23ddSSimon Glass return -1; 295604f23ddSSimon Glass } 296604f23ddSSimon Glass 29794e5fa46SSimon Glass image_name = fit_get_name(fit, image_noffset, NULL); 29894e5fa46SSimon Glass 299604f23ddSSimon Glass /* Process all hash subnodes of the component image node */ 300bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 301bbb467dcSSimon Glass noffset >= 0; 302bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 303bbb467dcSSimon Glass const char *node_name; 304bbb467dcSSimon Glass int ret = 0; 305bbb467dcSSimon Glass 306bbb467dcSSimon Glass /* 307bbb467dcSSimon Glass * Check subnode name, must be equal to "hash" or "signature". 308bbb467dcSSimon Glass * Multiple hash nodes require unique unit node 309bbb467dcSSimon Glass * names, e.g. hash@1, hash@2, signature@1, etc. 310bbb467dcSSimon Glass */ 311bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 312bbb467dcSSimon Glass if (!strncmp(node_name, FIT_HASH_NODENAME, 313bbb467dcSSimon Glass strlen(FIT_HASH_NODENAME))) { 314bbb467dcSSimon Glass ret = fit_image_process_hash(fit, image_name, noffset, 315bbb467dcSSimon Glass data, size); 31656518e71SSimon Glass } else if (IMAGE_ENABLE_SIGN && keydir && 31756518e71SSimon Glass !strncmp(node_name, FIT_SIG_NODENAME, 31856518e71SSimon Glass strlen(FIT_SIG_NODENAME))) { 31956518e71SSimon Glass ret = fit_image_process_sig(keydir, keydest, 32056518e71SSimon Glass fit, image_name, noffset, data, size, 32156518e71SSimon Glass comment, require_keys); 322bbb467dcSSimon Glass } 323bbb467dcSSimon Glass if (ret) 324604f23ddSSimon Glass return -1; 325604f23ddSSimon Glass } 326bbb467dcSSimon Glass 327bbb467dcSSimon Glass return 0; 328bbb467dcSSimon Glass } 329bbb467dcSSimon Glass 3304d098529SSimon Glass struct strlist { 3314d098529SSimon Glass int count; 3324d098529SSimon Glass char **strings; 3334d098529SSimon Glass }; 3344d098529SSimon Glass 3354d098529SSimon Glass static void strlist_init(struct strlist *list) 3364d098529SSimon Glass { 3374d098529SSimon Glass memset(list, '\0', sizeof(*list)); 3384d098529SSimon Glass } 3394d098529SSimon Glass 3404d098529SSimon Glass static void strlist_free(struct strlist *list) 3414d098529SSimon Glass { 3424d098529SSimon Glass int i; 3434d098529SSimon Glass 3444d098529SSimon Glass for (i = 0; i < list->count; i++) 3454d098529SSimon Glass free(list->strings[i]); 3464d098529SSimon Glass free(list->strings); 3474d098529SSimon Glass } 3484d098529SSimon Glass 3494d098529SSimon Glass static int strlist_add(struct strlist *list, const char *str) 3504d098529SSimon Glass { 3514d098529SSimon Glass char *dup; 3524d098529SSimon Glass 3534d098529SSimon Glass dup = strdup(str); 3544d098529SSimon Glass list->strings = realloc(list->strings, 3554d098529SSimon Glass (list->count + 1) * sizeof(char *)); 3564d098529SSimon Glass if (!list || !str) 3574d098529SSimon Glass return -1; 3584d098529SSimon Glass list->strings[list->count++] = dup; 3594d098529SSimon Glass 3604d098529SSimon Glass return 0; 3614d098529SSimon Glass } 3624d098529SSimon Glass 3634d098529SSimon Glass static const char *fit_config_get_image_list(void *fit, int noffset, 3644d098529SSimon Glass int *lenp, int *allow_missingp) 3654d098529SSimon Glass { 3664d098529SSimon Glass static const char default_list[] = FIT_KERNEL_PROP "\0" 3674d098529SSimon Glass FIT_FDT_PROP; 3684d098529SSimon Glass const char *prop; 3694d098529SSimon Glass 3704d098529SSimon Glass /* If there is an "image" property, use that */ 3714d098529SSimon Glass prop = fdt_getprop(fit, noffset, "sign-images", lenp); 3724d098529SSimon Glass if (prop) { 3734d098529SSimon Glass *allow_missingp = 0; 3744d098529SSimon Glass return *lenp ? prop : NULL; 3754d098529SSimon Glass } 3764d098529SSimon Glass 3774d098529SSimon Glass /* Default image list */ 3784d098529SSimon Glass *allow_missingp = 1; 3794d098529SSimon Glass *lenp = sizeof(default_list); 3804d098529SSimon Glass 3814d098529SSimon Glass return default_list; 3824d098529SSimon Glass } 3834d098529SSimon Glass 3844d098529SSimon Glass static int fit_config_get_hash_list(void *fit, int conf_noffset, 3854d098529SSimon Glass int sig_offset, struct strlist *node_inc) 3864d098529SSimon Glass { 3874d098529SSimon Glass int allow_missing; 3884d098529SSimon Glass const char *prop, *iname, *end; 3894d098529SSimon Glass const char *conf_name, *sig_name; 3904d098529SSimon Glass char name[200], path[200]; 3914d098529SSimon Glass int image_count; 3924d098529SSimon Glass int ret, len; 3934d098529SSimon Glass 3944d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 3954d098529SSimon Glass sig_name = fit_get_name(fit, sig_offset, NULL); 3964d098529SSimon Glass 3974d098529SSimon Glass /* 3984d098529SSimon Glass * Build a list of nodes we need to hash. We always need the root 3994d098529SSimon Glass * node and the configuration. 4004d098529SSimon Glass */ 4014d098529SSimon Glass strlist_init(node_inc); 4024d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 4034d098529SSimon Glass if (strlist_add(node_inc, "/") || 4044d098529SSimon Glass strlist_add(node_inc, name)) 4054d098529SSimon Glass goto err_mem; 4064d098529SSimon Glass 4074d098529SSimon Glass /* Get a list of images that we intend to sign */ 40866b36f83SHeiko Schocher prop = fit_config_get_image_list(fit, sig_offset, &len, 4094d098529SSimon Glass &allow_missing); 4104d098529SSimon Glass if (!prop) 4114d098529SSimon Glass return 0; 4124d098529SSimon Glass 4134d098529SSimon Glass /* Locate the images */ 4144d098529SSimon Glass end = prop + len; 4154d098529SSimon Glass image_count = 0; 4164d098529SSimon Glass for (iname = prop; iname < end; iname += strlen(iname) + 1) { 4174d098529SSimon Glass int noffset; 4184d098529SSimon Glass int image_noffset; 4194d098529SSimon Glass int hash_count; 4204d098529SSimon Glass 4214d098529SSimon Glass image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 4224d098529SSimon Glass iname); 4234d098529SSimon Glass if (image_noffset < 0) { 4244d098529SSimon Glass printf("Failed to find image '%s' in configuration '%s/%s'\n", 4254d098529SSimon Glass iname, conf_name, sig_name); 4264d098529SSimon Glass if (allow_missing) 4274d098529SSimon Glass continue; 4284d098529SSimon Glass 4294d098529SSimon Glass return -ENOENT; 4304d098529SSimon Glass } 4314d098529SSimon Glass 4324d098529SSimon Glass ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 4334d098529SSimon Glass if (ret < 0) 4344d098529SSimon Glass goto err_path; 4354d098529SSimon Glass if (strlist_add(node_inc, path)) 4364d098529SSimon Glass goto err_mem; 4374d098529SSimon Glass 4384d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 4394d098529SSimon Glass conf_name); 4404d098529SSimon Glass 4414d098529SSimon Glass /* Add all this image's hashes */ 4424d098529SSimon Glass hash_count = 0; 4434d098529SSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 4444d098529SSimon Glass noffset >= 0; 4454d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 4464d098529SSimon Glass const char *name = fit_get_name(fit, noffset, NULL); 4474d098529SSimon Glass 4484d098529SSimon Glass if (strncmp(name, FIT_HASH_NODENAME, 4494d098529SSimon Glass strlen(FIT_HASH_NODENAME))) 4504d098529SSimon Glass continue; 4514d098529SSimon Glass ret = fdt_get_path(fit, noffset, path, sizeof(path)); 4524d098529SSimon Glass if (ret < 0) 4534d098529SSimon Glass goto err_path; 4544d098529SSimon Glass if (strlist_add(node_inc, path)) 4554d098529SSimon Glass goto err_mem; 4564d098529SSimon Glass hash_count++; 4574d098529SSimon Glass } 4584d098529SSimon Glass 4594d098529SSimon Glass if (!hash_count) { 4604d098529SSimon 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", 4614d098529SSimon Glass conf_name, sig_name, iname); 4624d098529SSimon Glass return -ENOMSG; 4634d098529SSimon Glass } 4644d098529SSimon Glass 4654d098529SSimon Glass image_count++; 4664d098529SSimon Glass } 4674d098529SSimon Glass 4684d098529SSimon Glass if (!image_count) { 4694d098529SSimon Glass printf("Failed to find any images for configuration '%s/%s'\n", 4704d098529SSimon Glass conf_name, sig_name); 4714d098529SSimon Glass return -ENOMSG; 4724d098529SSimon Glass } 4734d098529SSimon Glass 4744d098529SSimon Glass return 0; 4754d098529SSimon Glass 4764d098529SSimon Glass err_mem: 4774d098529SSimon Glass printf("Out of memory processing configuration '%s/%s'\n", conf_name, 4784d098529SSimon Glass sig_name); 4794d098529SSimon Glass return -ENOMEM; 4804d098529SSimon Glass 4814d098529SSimon Glass err_path: 4824d098529SSimon Glass printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 4834d098529SSimon Glass iname, conf_name, sig_name, fdt_strerror(ret)); 4844d098529SSimon Glass return -ENOENT; 4854d098529SSimon Glass } 4864d098529SSimon Glass 4874d098529SSimon Glass static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 4884d098529SSimon Glass struct image_region **regionp, int *region_countp, 4894d098529SSimon Glass char **region_propp, int *region_proplen) 4904d098529SSimon Glass { 4914d098529SSimon Glass char * const exc_prop[] = {"data"}; 4924d098529SSimon Glass struct strlist node_inc; 4934d098529SSimon Glass struct image_region *region; 4944d098529SSimon Glass struct fdt_region fdt_regions[100]; 4954d098529SSimon Glass const char *conf_name, *sig_name; 4964d098529SSimon Glass char path[200]; 4974d098529SSimon Glass int count, i; 4984d098529SSimon Glass char *region_prop; 4994d098529SSimon Glass int ret, len; 5004d098529SSimon Glass 5014d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 5024d098529SSimon Glass sig_name = fit_get_name(fit, conf_noffset, NULL); 5034d098529SSimon Glass debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 5044d098529SSimon Glass 5054d098529SSimon Glass /* Get a list of nodes we want to hash */ 5064d098529SSimon Glass ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 5074d098529SSimon Glass if (ret) 5084d098529SSimon Glass return ret; 5094d098529SSimon Glass 5104d098529SSimon Glass /* Get a list of regions to hash */ 5114d098529SSimon Glass count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 5124d098529SSimon Glass exc_prop, ARRAY_SIZE(exc_prop), 5134d098529SSimon Glass fdt_regions, ARRAY_SIZE(fdt_regions), 5144d098529SSimon Glass path, sizeof(path), 1); 5154d098529SSimon Glass if (count < 0) { 5164d098529SSimon Glass printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 5174d098529SSimon Glass sig_name, fdt_strerror(ret)); 5184d098529SSimon Glass return -EIO; 5194d098529SSimon Glass } 5204d098529SSimon Glass if (count == 0) { 5214d098529SSimon Glass printf("No data to hash for configuration '%s/%s': %s\n", 5224d098529SSimon Glass conf_name, sig_name, fdt_strerror(ret)); 5234d098529SSimon Glass return -EINVAL; 5244d098529SSimon Glass } 5254d098529SSimon Glass 5264d098529SSimon Glass /* Build our list of data blocks */ 5274d098529SSimon Glass region = fit_region_make_list(fit, fdt_regions, count, NULL); 5284d098529SSimon Glass if (!region) { 5294d098529SSimon Glass printf("Out of memory hashing configuration '%s/%s'\n", 5304d098529SSimon Glass conf_name, sig_name); 5314d098529SSimon Glass return -ENOMEM; 5324d098529SSimon Glass } 5334d098529SSimon Glass 5344d098529SSimon Glass /* Create a list of all hashed properties */ 5354d098529SSimon Glass debug("Hash nodes:\n"); 5364d098529SSimon Glass for (i = len = 0; i < node_inc.count; i++) { 5374d098529SSimon Glass debug(" %s\n", node_inc.strings[i]); 5384d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1; 5394d098529SSimon Glass } 5404d098529SSimon Glass region_prop = malloc(len); 5414d098529SSimon Glass if (!region_prop) { 5424d098529SSimon Glass printf("Out of memory setting up regions for configuration '%s/%s'\n", 5434d098529SSimon Glass conf_name, sig_name); 5444d098529SSimon Glass return -ENOMEM; 5454d098529SSimon Glass } 5464d098529SSimon Glass for (i = len = 0; i < node_inc.count; 5474d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1, i++) 5484d098529SSimon Glass strcpy(region_prop + len, node_inc.strings[i]); 5494d098529SSimon Glass strlist_free(&node_inc); 5504d098529SSimon Glass 5514d098529SSimon Glass *region_countp = count; 5524d098529SSimon Glass *regionp = region; 5534d098529SSimon Glass *region_propp = region_prop; 5544d098529SSimon Glass *region_proplen = len; 5554d098529SSimon Glass 5564d098529SSimon Glass return 0; 5574d098529SSimon Glass } 5584d098529SSimon Glass 5594d098529SSimon Glass static int fit_config_process_sig(const char *keydir, void *keydest, 5604d098529SSimon Glass void *fit, const char *conf_name, int conf_noffset, 5614d098529SSimon Glass int noffset, const char *comment, int require_keys) 5624d098529SSimon Glass { 5634d098529SSimon Glass struct image_sign_info info; 5644d098529SSimon Glass const char *node_name; 5654d098529SSimon Glass struct image_region *region; 5664d098529SSimon Glass char *region_prop; 5674d098529SSimon Glass int region_proplen; 5684d098529SSimon Glass int region_count; 5694d098529SSimon Glass uint8_t *value; 5704d098529SSimon Glass uint value_len; 5714d098529SSimon Glass int ret; 5724d098529SSimon Glass 5734d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 5744d098529SSimon Glass if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 5754d098529SSimon Glass ®ion_count, ®ion_prop, ®ion_proplen)) 5764d098529SSimon Glass return -1; 5774d098529SSimon Glass 5784d098529SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 5794d098529SSimon Glass require_keys ? "conf" : NULL)) 5804d098529SSimon Glass return -1; 5814d098529SSimon Glass 5824d098529SSimon Glass ret = info.algo->sign(&info, region, region_count, &value, &value_len); 5834d098529SSimon Glass free(region); 5844d098529SSimon Glass if (ret) { 5854d098529SSimon Glass printf("Failed to sign '%s' signature node in '%s' conf node\n", 5864d098529SSimon Glass node_name, conf_name); 5874d098529SSimon Glass 5884d098529SSimon Glass /* We allow keys to be missing */ 5894d098529SSimon Glass if (ret == -ENOENT) 5904d098529SSimon Glass return 0; 5914d098529SSimon Glass return -1; 5924d098529SSimon Glass } 5934d098529SSimon Glass 594a9468115SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 595a9468115SSimon Glass region_prop, region_proplen); 596a9468115SSimon Glass if (ret) { 597a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 598a9468115SSimon Glass return -ENOSPC; 599a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 600a9468115SSimon Glass node_name, conf_name, fdt_strerror(ret)); 6014d098529SSimon Glass return -1; 6024d098529SSimon Glass } 6034d098529SSimon Glass free(value); 6044d098529SSimon Glass free(region_prop); 6054d098529SSimon Glass 6064d098529SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 6074d098529SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 6084d098529SSimon Glass 6094d098529SSimon Glass /* Write the public key into the supplied FDT file */ 610a9468115SSimon Glass if (keydest) { 611a9468115SSimon Glass ret = info.algo->add_verify_data(&info, keydest); 612*597a8b2cSSimon Glass if (ret == -ENOSPC) 613*597a8b2cSSimon Glass return -ENOSPC; 614a9468115SSimon Glass if (ret) { 6154d098529SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 6164d098529SSimon Glass node_name, conf_name); 617a9468115SSimon Glass } 618*597a8b2cSSimon Glass return ret; 6194d098529SSimon Glass } 6204d098529SSimon Glass 6214d098529SSimon Glass return 0; 6224d098529SSimon Glass } 6234d098529SSimon Glass 6244d098529SSimon Glass static int fit_config_add_verification_data(const char *keydir, void *keydest, 6254d098529SSimon Glass void *fit, int conf_noffset, const char *comment, 6264d098529SSimon Glass int require_keys) 6274d098529SSimon Glass { 6284d098529SSimon Glass const char *conf_name; 6294d098529SSimon Glass int noffset; 6304d098529SSimon Glass 6314d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 6324d098529SSimon Glass 6334d098529SSimon Glass /* Process all hash subnodes of the configuration node */ 6344d098529SSimon Glass for (noffset = fdt_first_subnode(fit, conf_noffset); 6354d098529SSimon Glass noffset >= 0; 6364d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6374d098529SSimon Glass const char *node_name; 6384d098529SSimon Glass int ret = 0; 6394d098529SSimon Glass 6404d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6414d098529SSimon Glass if (!strncmp(node_name, FIT_SIG_NODENAME, 6424d098529SSimon Glass strlen(FIT_SIG_NODENAME))) { 6434d098529SSimon Glass ret = fit_config_process_sig(keydir, keydest, 6444d098529SSimon Glass fit, conf_name, conf_noffset, noffset, comment, 6454d098529SSimon Glass require_keys); 6464d098529SSimon Glass } 6474d098529SSimon Glass if (ret) 6484d098529SSimon Glass return ret; 6494d098529SSimon Glass } 6504d098529SSimon Glass 6514d098529SSimon Glass return 0; 6524d098529SSimon Glass } 6534d098529SSimon Glass 65456518e71SSimon Glass int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 65556518e71SSimon Glass const char *comment, int require_keys) 656bbb467dcSSimon Glass { 6574d098529SSimon Glass int images_noffset, confs_noffset; 658bbb467dcSSimon Glass int noffset; 659bbb467dcSSimon Glass int ret; 660bbb467dcSSimon Glass 661bbb467dcSSimon Glass /* Find images parent node offset */ 662bbb467dcSSimon Glass images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 663bbb467dcSSimon Glass if (images_noffset < 0) { 664bbb467dcSSimon Glass printf("Can't find images parent node '%s' (%s)\n", 665bbb467dcSSimon Glass FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 666bbb467dcSSimon Glass return images_noffset; 667bbb467dcSSimon Glass } 668bbb467dcSSimon Glass 669bbb467dcSSimon Glass /* Process its subnodes, print out component images details */ 670bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, images_noffset); 671bbb467dcSSimon Glass noffset >= 0; 672bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 673bbb467dcSSimon Glass /* 674bbb467dcSSimon Glass * Direct child node of the images parent node, 675bbb467dcSSimon Glass * i.e. component image node. 676bbb467dcSSimon Glass */ 67756518e71SSimon Glass ret = fit_image_add_verification_data(keydir, keydest, 67856518e71SSimon Glass fit, noffset, comment, require_keys); 679bbb467dcSSimon Glass if (ret) 680bbb467dcSSimon Glass return ret; 681604f23ddSSimon Glass } 682604f23ddSSimon Glass 6834d098529SSimon Glass /* If there are no keys, we can't sign configurations */ 6844d098529SSimon Glass if (!IMAGE_ENABLE_SIGN || !keydir) 6854d098529SSimon Glass return 0; 6864d098529SSimon Glass 6874d098529SSimon Glass /* Find configurations parent node offset */ 6884d098529SSimon Glass confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 6894d098529SSimon Glass if (confs_noffset < 0) { 6904d098529SSimon Glass printf("Can't find images parent node '%s' (%s)\n", 6914d098529SSimon Glass FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); 6924d098529SSimon Glass return -ENOENT; 6934d098529SSimon Glass } 6944d098529SSimon Glass 6954d098529SSimon Glass /* Process its subnodes, print out component images details */ 6964d098529SSimon Glass for (noffset = fdt_first_subnode(fit, confs_noffset); 6974d098529SSimon Glass noffset >= 0; 6984d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6994d098529SSimon Glass ret = fit_config_add_verification_data(keydir, keydest, 7004d098529SSimon Glass fit, noffset, comment, 7014d098529SSimon Glass require_keys); 7024d098529SSimon Glass if (ret) 7034d098529SSimon Glass return ret; 7044d098529SSimon Glass } 7054d098529SSimon Glass 706604f23ddSSimon Glass return 0; 707604f23ddSSimon Glass } 70829a23f9dSHeiko Schocher 70929a23f9dSHeiko Schocher #ifdef CONFIG_FIT_SIGNATURE 71029a23f9dSHeiko Schocher int fit_check_sign(const void *working_fdt, const void *key) 71129a23f9dSHeiko Schocher { 71229a23f9dSHeiko Schocher int cfg_noffset; 71329a23f9dSHeiko Schocher int ret; 71429a23f9dSHeiko Schocher 71529a23f9dSHeiko Schocher cfg_noffset = fit_conf_get_node(working_fdt, NULL); 71629a23f9dSHeiko Schocher if (!cfg_noffset) 71729a23f9dSHeiko Schocher return -1; 71829a23f9dSHeiko Schocher 71929a23f9dSHeiko Schocher ret = fit_config_verify(working_fdt, cfg_noffset); 72029a23f9dSHeiko Schocher return ret; 72129a23f9dSHeiko Schocher } 72229a23f9dSHeiko Schocher #endif 723