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 * 9604f23ddSSimon Glass * See file CREDITS for list of people who contributed to this 10604f23ddSSimon Glass * project. 11604f23ddSSimon Glass * 12604f23ddSSimon Glass * This program is free software; you can redistribute it and/or 13604f23ddSSimon Glass * modify it under the terms of the GNU General Public License as 14604f23ddSSimon Glass * published by the Free Software Foundation; either version 2 of 15604f23ddSSimon Glass * the License, or (at your option) any later version. 16604f23ddSSimon Glass * 17604f23ddSSimon Glass * This program is distributed in the hope that it will be useful, 18604f23ddSSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 19604f23ddSSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20604f23ddSSimon Glass * GNU General Public License for more details. 21604f23ddSSimon Glass * 22604f23ddSSimon Glass * You should have received a copy of the GNU General Public License 23604f23ddSSimon Glass * along with this program; if not, write to the Free Software 24604f23ddSSimon Glass * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 25604f23ddSSimon Glass * MA 02111-1307 USA 26604f23ddSSimon Glass */ 27604f23ddSSimon Glass 28604f23ddSSimon Glass #include "mkimage.h" 29604f23ddSSimon Glass #include <image.h> 3056518e71SSimon Glass #include <version.h> 31604f23ddSSimon Glass 32604f23ddSSimon Glass /** 33b7260910SSimon Glass * fit_set_hash_value - set hash value in requested has node 34b7260910SSimon Glass * @fit: pointer to the FIT format image header 35b7260910SSimon Glass * @noffset: hash node offset 36b7260910SSimon Glass * @value: hash value to be set 37b7260910SSimon Glass * @value_len: hash value length 38b7260910SSimon Glass * 39b7260910SSimon Glass * fit_set_hash_value() attempts to set hash value in a node at offset 40b7260910SSimon Glass * given and returns operation status to the caller. 41b7260910SSimon Glass * 42b7260910SSimon Glass * returns 43b7260910SSimon Glass * 0, on success 44b7260910SSimon Glass * -1, on failure 45b7260910SSimon Glass */ 46b7260910SSimon Glass static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 47b7260910SSimon Glass int value_len) 48b7260910SSimon Glass { 49b7260910SSimon Glass int ret; 50b7260910SSimon Glass 51b7260910SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 52b7260910SSimon Glass if (ret) { 53b7260910SSimon Glass printf("Can't set hash '%s' property for '%s' node(%s)\n", 54b7260910SSimon Glass FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 55b7260910SSimon Glass fdt_strerror(ret)); 56b7260910SSimon Glass return -1; 57b7260910SSimon Glass } 58b7260910SSimon Glass 59b7260910SSimon Glass return 0; 60b7260910SSimon Glass } 61b7260910SSimon Glass 62b7260910SSimon Glass /** 6394e5fa46SSimon Glass * fit_image_process_hash - Process a single subnode of the images/ node 6494e5fa46SSimon Glass * 6594e5fa46SSimon Glass * Check each subnode and process accordingly. For hash nodes we generate 6694e5fa46SSimon Glass * a hash of the supplised data and store it in the node. 6794e5fa46SSimon Glass * 6894e5fa46SSimon Glass * @fit: pointer to the FIT format image header 6994e5fa46SSimon Glass * @image_name: name of image being processes (used to display errors) 7094e5fa46SSimon Glass * @noffset: subnode offset 7194e5fa46SSimon Glass * @data: data to process 7294e5fa46SSimon Glass * @size: size of data in bytes 7394e5fa46SSimon Glass * @return 0 if ok, -1 on error 7494e5fa46SSimon Glass */ 7594e5fa46SSimon Glass static int fit_image_process_hash(void *fit, const char *image_name, 7694e5fa46SSimon Glass int noffset, const void *data, size_t size) 7794e5fa46SSimon Glass { 7894e5fa46SSimon Glass uint8_t value[FIT_MAX_HASH_LEN]; 79bbb467dcSSimon Glass const char *node_name; 8094e5fa46SSimon Glass int value_len; 8194e5fa46SSimon Glass char *algo; 8294e5fa46SSimon Glass 83bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 8494e5fa46SSimon Glass 8594e5fa46SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo)) { 8694e5fa46SSimon Glass printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 87bbb467dcSSimon Glass node_name, image_name); 8894e5fa46SSimon Glass return -1; 8994e5fa46SSimon Glass } 9094e5fa46SSimon Glass 9194e5fa46SSimon Glass if (calculate_hash(data, size, algo, value, &value_len)) { 9294e5fa46SSimon Glass printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 93bbb467dcSSimon Glass algo, node_name, image_name); 9494e5fa46SSimon Glass return -1; 9594e5fa46SSimon Glass } 9694e5fa46SSimon Glass 97b7260910SSimon Glass if (fit_set_hash_value(fit, noffset, value, value_len)) { 9894e5fa46SSimon Glass printf("Can't set hash value for '%s' hash node in '%s' image node\n", 99bbb467dcSSimon Glass node_name, image_name); 10094e5fa46SSimon Glass return -1; 10194e5fa46SSimon Glass } 10294e5fa46SSimon Glass 10394e5fa46SSimon Glass return 0; 10494e5fa46SSimon Glass } 10594e5fa46SSimon Glass 10694e5fa46SSimon Glass /** 10756518e71SSimon Glass * fit_image_write_sig() - write the signature to a FIT 108604f23ddSSimon Glass * 10956518e71SSimon Glass * This writes the signature and signer data to the FIT. 11056518e71SSimon Glass * 11156518e71SSimon Glass * @fit: pointer to the FIT format image header 11256518e71SSimon Glass * @noffset: hash node offset 11356518e71SSimon Glass * @value: signature value to be set 11456518e71SSimon Glass * @value_len: signature value length 11556518e71SSimon Glass * @comment: Text comment to write (NULL for none) 11656518e71SSimon Glass * 11756518e71SSimon Glass * returns 11856518e71SSimon Glass * 0, on success 11956518e71SSimon Glass * -FDT_ERR_..., on failure 12056518e71SSimon Glass */ 12156518e71SSimon Glass static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 12256518e71SSimon Glass int value_len, const char *comment, const char *region_prop, 12356518e71SSimon Glass int region_proplen) 12456518e71SSimon Glass { 12556518e71SSimon Glass int string_size; 12656518e71SSimon Glass int ret; 12756518e71SSimon Glass 12856518e71SSimon Glass /* 12956518e71SSimon Glass * Get the current string size, before we update the FIT and add 13056518e71SSimon Glass * more 13156518e71SSimon Glass */ 13256518e71SSimon Glass string_size = fdt_size_dt_strings(fit); 13356518e71SSimon Glass 13456518e71SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 13556518e71SSimon Glass if (!ret) { 13656518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-name", 13756518e71SSimon Glass "mkimage"); 13856518e71SSimon Glass } 13956518e71SSimon Glass if (!ret) { 14056518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-version", 14156518e71SSimon Glass PLAIN_VERSION); 14256518e71SSimon Glass } 14356518e71SSimon Glass if (comment && !ret) 14456518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "comment", comment); 14556518e71SSimon Glass if (!ret) 14656518e71SSimon Glass ret = fit_set_timestamp(fit, noffset, time(NULL)); 14756518e71SSimon Glass if (region_prop && !ret) { 14856518e71SSimon Glass uint32_t strdata[2]; 14956518e71SSimon Glass 15056518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-nodes", 15156518e71SSimon Glass region_prop, region_proplen); 15256518e71SSimon Glass strdata[0] = 0; 15356518e71SSimon Glass strdata[1] = cpu_to_fdt32(string_size); 15456518e71SSimon Glass if (!ret) { 15556518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-strings", 15656518e71SSimon Glass strdata, sizeof(strdata)); 15756518e71SSimon Glass } 15856518e71SSimon Glass } 15956518e71SSimon Glass 16056518e71SSimon Glass return ret; 16156518e71SSimon Glass } 16256518e71SSimon Glass 16356518e71SSimon Glass static int fit_image_setup_sig(struct image_sign_info *info, 16456518e71SSimon Glass const char *keydir, void *fit, const char *image_name, 16556518e71SSimon Glass int noffset, const char *require_keys) 16656518e71SSimon Glass { 16756518e71SSimon Glass const char *node_name; 16856518e71SSimon Glass char *algo_name; 16956518e71SSimon Glass 17056518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 17156518e71SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 17256518e71SSimon Glass printf("Can't get algo property for '%s' signature node in '%s' image node\n", 17356518e71SSimon Glass node_name, image_name); 17456518e71SSimon Glass return -1; 17556518e71SSimon Glass } 17656518e71SSimon Glass 17756518e71SSimon Glass memset(info, '\0', sizeof(*info)); 17856518e71SSimon Glass info->keydir = keydir; 17956518e71SSimon Glass info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 18056518e71SSimon Glass info->fit = fit; 18156518e71SSimon Glass info->node_offset = noffset; 18256518e71SSimon Glass info->algo = image_get_sig_algo(algo_name); 18356518e71SSimon Glass info->require_keys = require_keys; 18456518e71SSimon Glass if (!info->algo) { 18556518e71SSimon Glass printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 18656518e71SSimon Glass algo_name, node_name, image_name); 18756518e71SSimon Glass return -1; 18856518e71SSimon Glass } 18956518e71SSimon Glass 19056518e71SSimon Glass return 0; 19156518e71SSimon Glass } 19256518e71SSimon Glass 19356518e71SSimon Glass /** 19456518e71SSimon Glass * fit_image_process_sig- Process a single subnode of the images/ node 19556518e71SSimon Glass * 19656518e71SSimon Glass * Check each subnode and process accordingly. For signature nodes we 19756518e71SSimon Glass * generate a signed hash of the supplised data and store it in the node. 19856518e71SSimon Glass * 19956518e71SSimon Glass * @keydir: Directory containing keys to use for signing 20056518e71SSimon Glass * @keydest: Destination FDT blob to write public keys into 20156518e71SSimon Glass * @fit: pointer to the FIT format image header 20256518e71SSimon Glass * @image_name: name of image being processes (used to display errors) 20356518e71SSimon Glass * @noffset: subnode offset 20456518e71SSimon Glass * @data: data to process 20556518e71SSimon Glass * @size: size of data in bytes 20656518e71SSimon Glass * @comment: Comment to add to signature nodes 20756518e71SSimon Glass * @require_keys: Mark all keys as 'required' 20856518e71SSimon Glass * @return 0 if ok, -1 on error 20956518e71SSimon Glass */ 21056518e71SSimon Glass static int fit_image_process_sig(const char *keydir, void *keydest, 21156518e71SSimon Glass void *fit, const char *image_name, 21256518e71SSimon Glass int noffset, const void *data, size_t size, 21356518e71SSimon Glass const char *comment, int require_keys) 21456518e71SSimon Glass { 21556518e71SSimon Glass struct image_sign_info info; 21656518e71SSimon Glass struct image_region region; 21756518e71SSimon Glass const char *node_name; 21856518e71SSimon Glass uint8_t *value; 21956518e71SSimon Glass uint value_len; 22056518e71SSimon Glass int ret; 22156518e71SSimon Glass 22256518e71SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 22356518e71SSimon Glass require_keys ? "image" : NULL)) 22456518e71SSimon Glass return -1; 22556518e71SSimon Glass 22656518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 22756518e71SSimon Glass region.data = data; 22856518e71SSimon Glass region.size = size; 22956518e71SSimon Glass ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); 23056518e71SSimon Glass if (ret) { 23156518e71SSimon Glass printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 23256518e71SSimon Glass node_name, image_name, ret); 23356518e71SSimon Glass 23456518e71SSimon Glass /* We allow keys to be missing */ 23556518e71SSimon Glass if (ret == -ENOENT) 23656518e71SSimon Glass return 0; 23756518e71SSimon Glass return -1; 23856518e71SSimon Glass } 23956518e71SSimon Glass 24056518e71SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 24156518e71SSimon Glass NULL, 0); 24256518e71SSimon Glass if (ret) { 24356518e71SSimon Glass printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", 24456518e71SSimon Glass node_name, image_name, fdt_strerror(ret)); 24556518e71SSimon Glass return -1; 24656518e71SSimon Glass } 24756518e71SSimon Glass free(value); 24856518e71SSimon Glass 24956518e71SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 25056518e71SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 25156518e71SSimon Glass 25256518e71SSimon Glass /* Write the public key into the supplied FDT file */ 25356518e71SSimon Glass if (keydest && info.algo->add_verify_data(&info, keydest)) { 25456518e71SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 25556518e71SSimon Glass node_name, image_name); 25656518e71SSimon Glass return -1; 25756518e71SSimon Glass } 25856518e71SSimon Glass 25956518e71SSimon Glass return 0; 26056518e71SSimon Glass } 26156518e71SSimon Glass 26256518e71SSimon Glass /** 26356518e71SSimon Glass * fit_image_add_verification_data() - calculate/set verig. data for image node 26456518e71SSimon Glass * 26556518e71SSimon Glass * This adds hash and signature values for an component image node. 266bbb467dcSSimon Glass * 267bbb467dcSSimon Glass * All existing hash subnodes are checked, if algorithm property is set to 268bbb467dcSSimon Glass * one of the supported hash algorithms, hash value is computed and 269bbb467dcSSimon Glass * corresponding hash node property is set, for example: 270604f23ddSSimon Glass * 271604f23ddSSimon Glass * Input component image node structure: 272604f23ddSSimon Glass * 273604f23ddSSimon Glass * o image@1 (at image_noffset) 274604f23ddSSimon Glass * | - data = [binary data] 275604f23ddSSimon Glass * o hash@1 276604f23ddSSimon Glass * |- algo = "sha1" 277604f23ddSSimon Glass * 278604f23ddSSimon Glass * Output component image node structure: 279604f23ddSSimon Glass * 280604f23ddSSimon Glass * o image@1 (at image_noffset) 281604f23ddSSimon Glass * | - data = [binary data] 282604f23ddSSimon Glass * o hash@1 283604f23ddSSimon Glass * |- algo = "sha1" 284604f23ddSSimon Glass * |- value = sha1(data) 285604f23ddSSimon Glass * 286bbb467dcSSimon Glass * For signature details, please see doc/uImage.FIT/signature.txt 287bbb467dcSSimon Glass * 28856518e71SSimon Glass * @keydir Directory containing *.key and *.crt files (or NULL) 28956518e71SSimon Glass * @keydest FDT Blob to write public keys into (NULL if none) 290bbb467dcSSimon Glass * @fit: Pointer to the FIT format image header 291bbb467dcSSimon Glass * @image_noffset: Requested component image node 29256518e71SSimon Glass * @comment: Comment to add to signature nodes 29356518e71SSimon Glass * @require_keys: Mark all keys as 'required' 294bbb467dcSSimon Glass * @return: 0 on success, <0 on failure 295604f23ddSSimon Glass */ 29656518e71SSimon Glass int fit_image_add_verification_data(const char *keydir, void *keydest, 29756518e71SSimon Glass void *fit, int image_noffset, const char *comment, 29856518e71SSimon Glass int require_keys) 299604f23ddSSimon Glass { 300bbb467dcSSimon Glass const char *image_name; 301604f23ddSSimon Glass const void *data; 302604f23ddSSimon Glass size_t size; 303604f23ddSSimon Glass int noffset; 304604f23ddSSimon Glass 305604f23ddSSimon Glass /* Get image data and data length */ 306604f23ddSSimon Glass if (fit_image_get_data(fit, image_noffset, &data, &size)) { 307604f23ddSSimon Glass printf("Can't get image data/size\n"); 308604f23ddSSimon Glass return -1; 309604f23ddSSimon Glass } 310604f23ddSSimon Glass 31194e5fa46SSimon Glass image_name = fit_get_name(fit, image_noffset, NULL); 31294e5fa46SSimon Glass 313604f23ddSSimon Glass /* Process all hash subnodes of the component image node */ 314bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 315bbb467dcSSimon Glass noffset >= 0; 316bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 317bbb467dcSSimon Glass const char *node_name; 318bbb467dcSSimon Glass int ret = 0; 319bbb467dcSSimon Glass 320bbb467dcSSimon Glass /* 321bbb467dcSSimon Glass * Check subnode name, must be equal to "hash" or "signature". 322bbb467dcSSimon Glass * Multiple hash nodes require unique unit node 323bbb467dcSSimon Glass * names, e.g. hash@1, hash@2, signature@1, etc. 324bbb467dcSSimon Glass */ 325bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 326bbb467dcSSimon Glass if (!strncmp(node_name, FIT_HASH_NODENAME, 327bbb467dcSSimon Glass strlen(FIT_HASH_NODENAME))) { 328bbb467dcSSimon Glass ret = fit_image_process_hash(fit, image_name, noffset, 329bbb467dcSSimon Glass data, size); 33056518e71SSimon Glass } else if (IMAGE_ENABLE_SIGN && keydir && 33156518e71SSimon Glass !strncmp(node_name, FIT_SIG_NODENAME, 33256518e71SSimon Glass strlen(FIT_SIG_NODENAME))) { 33356518e71SSimon Glass ret = fit_image_process_sig(keydir, keydest, 33456518e71SSimon Glass fit, image_name, noffset, data, size, 33556518e71SSimon Glass comment, require_keys); 336bbb467dcSSimon Glass } 337bbb467dcSSimon Glass if (ret) 338604f23ddSSimon Glass return -1; 339604f23ddSSimon Glass } 340bbb467dcSSimon Glass 341bbb467dcSSimon Glass return 0; 342bbb467dcSSimon Glass } 343bbb467dcSSimon Glass 344*4d098529SSimon Glass struct strlist { 345*4d098529SSimon Glass int count; 346*4d098529SSimon Glass char **strings; 347*4d098529SSimon Glass }; 348*4d098529SSimon Glass 349*4d098529SSimon Glass static void strlist_init(struct strlist *list) 350*4d098529SSimon Glass { 351*4d098529SSimon Glass memset(list, '\0', sizeof(*list)); 352*4d098529SSimon Glass } 353*4d098529SSimon Glass 354*4d098529SSimon Glass static void strlist_free(struct strlist *list) 355*4d098529SSimon Glass { 356*4d098529SSimon Glass int i; 357*4d098529SSimon Glass 358*4d098529SSimon Glass for (i = 0; i < list->count; i++) 359*4d098529SSimon Glass free(list->strings[i]); 360*4d098529SSimon Glass free(list->strings); 361*4d098529SSimon Glass } 362*4d098529SSimon Glass 363*4d098529SSimon Glass static int strlist_add(struct strlist *list, const char *str) 364*4d098529SSimon Glass { 365*4d098529SSimon Glass char *dup; 366*4d098529SSimon Glass 367*4d098529SSimon Glass dup = strdup(str); 368*4d098529SSimon Glass list->strings = realloc(list->strings, 369*4d098529SSimon Glass (list->count + 1) * sizeof(char *)); 370*4d098529SSimon Glass if (!list || !str) 371*4d098529SSimon Glass return -1; 372*4d098529SSimon Glass list->strings[list->count++] = dup; 373*4d098529SSimon Glass 374*4d098529SSimon Glass return 0; 375*4d098529SSimon Glass } 376*4d098529SSimon Glass 377*4d098529SSimon Glass static const char *fit_config_get_image_list(void *fit, int noffset, 378*4d098529SSimon Glass int *lenp, int *allow_missingp) 379*4d098529SSimon Glass { 380*4d098529SSimon Glass static const char default_list[] = FIT_KERNEL_PROP "\0" 381*4d098529SSimon Glass FIT_FDT_PROP; 382*4d098529SSimon Glass const char *prop; 383*4d098529SSimon Glass 384*4d098529SSimon Glass /* If there is an "image" property, use that */ 385*4d098529SSimon Glass prop = fdt_getprop(fit, noffset, "sign-images", lenp); 386*4d098529SSimon Glass if (prop) { 387*4d098529SSimon Glass *allow_missingp = 0; 388*4d098529SSimon Glass return *lenp ? prop : NULL; 389*4d098529SSimon Glass } 390*4d098529SSimon Glass 391*4d098529SSimon Glass /* Default image list */ 392*4d098529SSimon Glass *allow_missingp = 1; 393*4d098529SSimon Glass *lenp = sizeof(default_list); 394*4d098529SSimon Glass 395*4d098529SSimon Glass return default_list; 396*4d098529SSimon Glass } 397*4d098529SSimon Glass 398*4d098529SSimon Glass static int fit_config_get_hash_list(void *fit, int conf_noffset, 399*4d098529SSimon Glass int sig_offset, struct strlist *node_inc) 400*4d098529SSimon Glass { 401*4d098529SSimon Glass int allow_missing; 402*4d098529SSimon Glass const char *prop, *iname, *end; 403*4d098529SSimon Glass const char *conf_name, *sig_name; 404*4d098529SSimon Glass char name[200], path[200]; 405*4d098529SSimon Glass int image_count; 406*4d098529SSimon Glass int ret, len; 407*4d098529SSimon Glass 408*4d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 409*4d098529SSimon Glass sig_name = fit_get_name(fit, sig_offset, NULL); 410*4d098529SSimon Glass 411*4d098529SSimon Glass /* 412*4d098529SSimon Glass * Build a list of nodes we need to hash. We always need the root 413*4d098529SSimon Glass * node and the configuration. 414*4d098529SSimon Glass */ 415*4d098529SSimon Glass strlist_init(node_inc); 416*4d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 417*4d098529SSimon Glass if (strlist_add(node_inc, "/") || 418*4d098529SSimon Glass strlist_add(node_inc, name)) 419*4d098529SSimon Glass goto err_mem; 420*4d098529SSimon Glass 421*4d098529SSimon Glass /* Get a list of images that we intend to sign */ 422*4d098529SSimon Glass prop = fit_config_get_image_list(fit, conf_noffset, &len, 423*4d098529SSimon Glass &allow_missing); 424*4d098529SSimon Glass if (!prop) 425*4d098529SSimon Glass return 0; 426*4d098529SSimon Glass 427*4d098529SSimon Glass /* Locate the images */ 428*4d098529SSimon Glass end = prop + len; 429*4d098529SSimon Glass image_count = 0; 430*4d098529SSimon Glass for (iname = prop; iname < end; iname += strlen(iname) + 1) { 431*4d098529SSimon Glass int noffset; 432*4d098529SSimon Glass int image_noffset; 433*4d098529SSimon Glass int hash_count; 434*4d098529SSimon Glass 435*4d098529SSimon Glass image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 436*4d098529SSimon Glass iname); 437*4d098529SSimon Glass if (image_noffset < 0) { 438*4d098529SSimon Glass printf("Failed to find image '%s' in configuration '%s/%s'\n", 439*4d098529SSimon Glass iname, conf_name, sig_name); 440*4d098529SSimon Glass if (allow_missing) 441*4d098529SSimon Glass continue; 442*4d098529SSimon Glass 443*4d098529SSimon Glass return -ENOENT; 444*4d098529SSimon Glass } 445*4d098529SSimon Glass 446*4d098529SSimon Glass ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 447*4d098529SSimon Glass if (ret < 0) 448*4d098529SSimon Glass goto err_path; 449*4d098529SSimon Glass if (strlist_add(node_inc, path)) 450*4d098529SSimon Glass goto err_mem; 451*4d098529SSimon Glass 452*4d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 453*4d098529SSimon Glass conf_name); 454*4d098529SSimon Glass 455*4d098529SSimon Glass /* Add all this image's hashes */ 456*4d098529SSimon Glass hash_count = 0; 457*4d098529SSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 458*4d098529SSimon Glass noffset >= 0; 459*4d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 460*4d098529SSimon Glass const char *name = fit_get_name(fit, noffset, NULL); 461*4d098529SSimon Glass 462*4d098529SSimon Glass if (strncmp(name, FIT_HASH_NODENAME, 463*4d098529SSimon Glass strlen(FIT_HASH_NODENAME))) 464*4d098529SSimon Glass continue; 465*4d098529SSimon Glass ret = fdt_get_path(fit, noffset, path, sizeof(path)); 466*4d098529SSimon Glass if (ret < 0) 467*4d098529SSimon Glass goto err_path; 468*4d098529SSimon Glass if (strlist_add(node_inc, path)) 469*4d098529SSimon Glass goto err_mem; 470*4d098529SSimon Glass hash_count++; 471*4d098529SSimon Glass } 472*4d098529SSimon Glass 473*4d098529SSimon Glass if (!hash_count) { 474*4d098529SSimon 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", 475*4d098529SSimon Glass conf_name, sig_name, iname); 476*4d098529SSimon Glass return -ENOMSG; 477*4d098529SSimon Glass } 478*4d098529SSimon Glass 479*4d098529SSimon Glass image_count++; 480*4d098529SSimon Glass } 481*4d098529SSimon Glass 482*4d098529SSimon Glass if (!image_count) { 483*4d098529SSimon Glass printf("Failed to find any images for configuration '%s/%s'\n", 484*4d098529SSimon Glass conf_name, sig_name); 485*4d098529SSimon Glass return -ENOMSG; 486*4d098529SSimon Glass } 487*4d098529SSimon Glass 488*4d098529SSimon Glass return 0; 489*4d098529SSimon Glass 490*4d098529SSimon Glass err_mem: 491*4d098529SSimon Glass printf("Out of memory processing configuration '%s/%s'\n", conf_name, 492*4d098529SSimon Glass sig_name); 493*4d098529SSimon Glass return -ENOMEM; 494*4d098529SSimon Glass 495*4d098529SSimon Glass err_path: 496*4d098529SSimon Glass printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 497*4d098529SSimon Glass iname, conf_name, sig_name, fdt_strerror(ret)); 498*4d098529SSimon Glass return -ENOENT; 499*4d098529SSimon Glass } 500*4d098529SSimon Glass 501*4d098529SSimon Glass static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 502*4d098529SSimon Glass struct image_region **regionp, int *region_countp, 503*4d098529SSimon Glass char **region_propp, int *region_proplen) 504*4d098529SSimon Glass { 505*4d098529SSimon Glass char * const exc_prop[] = {"data"}; 506*4d098529SSimon Glass struct strlist node_inc; 507*4d098529SSimon Glass struct image_region *region; 508*4d098529SSimon Glass struct fdt_region fdt_regions[100]; 509*4d098529SSimon Glass const char *conf_name, *sig_name; 510*4d098529SSimon Glass char path[200]; 511*4d098529SSimon Glass int count, i; 512*4d098529SSimon Glass char *region_prop; 513*4d098529SSimon Glass int ret, len; 514*4d098529SSimon Glass 515*4d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 516*4d098529SSimon Glass sig_name = fit_get_name(fit, conf_noffset, NULL); 517*4d098529SSimon Glass debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 518*4d098529SSimon Glass 519*4d098529SSimon Glass /* Get a list of nodes we want to hash */ 520*4d098529SSimon Glass ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 521*4d098529SSimon Glass if (ret) 522*4d098529SSimon Glass return ret; 523*4d098529SSimon Glass 524*4d098529SSimon Glass /* Get a list of regions to hash */ 525*4d098529SSimon Glass count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 526*4d098529SSimon Glass exc_prop, ARRAY_SIZE(exc_prop), 527*4d098529SSimon Glass fdt_regions, ARRAY_SIZE(fdt_regions), 528*4d098529SSimon Glass path, sizeof(path), 1); 529*4d098529SSimon Glass if (count < 0) { 530*4d098529SSimon Glass printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 531*4d098529SSimon Glass sig_name, fdt_strerror(ret)); 532*4d098529SSimon Glass return -EIO; 533*4d098529SSimon Glass } 534*4d098529SSimon Glass if (count == 0) { 535*4d098529SSimon Glass printf("No data to hash for configuration '%s/%s': %s\n", 536*4d098529SSimon Glass conf_name, sig_name, fdt_strerror(ret)); 537*4d098529SSimon Glass return -EINVAL; 538*4d098529SSimon Glass } 539*4d098529SSimon Glass 540*4d098529SSimon Glass /* Build our list of data blocks */ 541*4d098529SSimon Glass region = fit_region_make_list(fit, fdt_regions, count, NULL); 542*4d098529SSimon Glass if (!region) { 543*4d098529SSimon Glass printf("Out of memory hashing configuration '%s/%s'\n", 544*4d098529SSimon Glass conf_name, sig_name); 545*4d098529SSimon Glass return -ENOMEM; 546*4d098529SSimon Glass } 547*4d098529SSimon Glass 548*4d098529SSimon Glass /* Create a list of all hashed properties */ 549*4d098529SSimon Glass debug("Hash nodes:\n"); 550*4d098529SSimon Glass for (i = len = 0; i < node_inc.count; i++) { 551*4d098529SSimon Glass debug(" %s\n", node_inc.strings[i]); 552*4d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1; 553*4d098529SSimon Glass } 554*4d098529SSimon Glass region_prop = malloc(len); 555*4d098529SSimon Glass if (!region_prop) { 556*4d098529SSimon Glass printf("Out of memory setting up regions for configuration '%s/%s'\n", 557*4d098529SSimon Glass conf_name, sig_name); 558*4d098529SSimon Glass return -ENOMEM; 559*4d098529SSimon Glass } 560*4d098529SSimon Glass for (i = len = 0; i < node_inc.count; 561*4d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1, i++) 562*4d098529SSimon Glass strcpy(region_prop + len, node_inc.strings[i]); 563*4d098529SSimon Glass strlist_free(&node_inc); 564*4d098529SSimon Glass 565*4d098529SSimon Glass *region_countp = count; 566*4d098529SSimon Glass *regionp = region; 567*4d098529SSimon Glass *region_propp = region_prop; 568*4d098529SSimon Glass *region_proplen = len; 569*4d098529SSimon Glass 570*4d098529SSimon Glass return 0; 571*4d098529SSimon Glass } 572*4d098529SSimon Glass 573*4d098529SSimon Glass static int fit_config_process_sig(const char *keydir, void *keydest, 574*4d098529SSimon Glass void *fit, const char *conf_name, int conf_noffset, 575*4d098529SSimon Glass int noffset, const char *comment, int require_keys) 576*4d098529SSimon Glass { 577*4d098529SSimon Glass struct image_sign_info info; 578*4d098529SSimon Glass const char *node_name; 579*4d098529SSimon Glass struct image_region *region; 580*4d098529SSimon Glass char *region_prop; 581*4d098529SSimon Glass int region_proplen; 582*4d098529SSimon Glass int region_count; 583*4d098529SSimon Glass uint8_t *value; 584*4d098529SSimon Glass uint value_len; 585*4d098529SSimon Glass int ret; 586*4d098529SSimon Glass 587*4d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 588*4d098529SSimon Glass if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 589*4d098529SSimon Glass ®ion_count, ®ion_prop, ®ion_proplen)) 590*4d098529SSimon Glass return -1; 591*4d098529SSimon Glass 592*4d098529SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 593*4d098529SSimon Glass require_keys ? "conf" : NULL)) 594*4d098529SSimon Glass return -1; 595*4d098529SSimon Glass 596*4d098529SSimon Glass ret = info.algo->sign(&info, region, region_count, &value, &value_len); 597*4d098529SSimon Glass free(region); 598*4d098529SSimon Glass if (ret) { 599*4d098529SSimon Glass printf("Failed to sign '%s' signature node in '%s' conf node\n", 600*4d098529SSimon Glass node_name, conf_name); 601*4d098529SSimon Glass 602*4d098529SSimon Glass /* We allow keys to be missing */ 603*4d098529SSimon Glass if (ret == -ENOENT) 604*4d098529SSimon Glass return 0; 605*4d098529SSimon Glass return -1; 606*4d098529SSimon Glass } 607*4d098529SSimon Glass 608*4d098529SSimon Glass if (fit_image_write_sig(fit, noffset, value, value_len, comment, 609*4d098529SSimon Glass region_prop, region_proplen)) { 610*4d098529SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node\n", 611*4d098529SSimon Glass node_name, conf_name); 612*4d098529SSimon Glass return -1; 613*4d098529SSimon Glass } 614*4d098529SSimon Glass free(value); 615*4d098529SSimon Glass free(region_prop); 616*4d098529SSimon Glass 617*4d098529SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 618*4d098529SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 619*4d098529SSimon Glass 620*4d098529SSimon Glass /* Write the public key into the supplied FDT file */ 621*4d098529SSimon Glass if (keydest && info.algo->add_verify_data(&info, keydest)) { 622*4d098529SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 623*4d098529SSimon Glass node_name, conf_name); 624*4d098529SSimon Glass return -1; 625*4d098529SSimon Glass } 626*4d098529SSimon Glass 627*4d098529SSimon Glass return 0; 628*4d098529SSimon Glass } 629*4d098529SSimon Glass 630*4d098529SSimon Glass static int fit_config_add_verification_data(const char *keydir, void *keydest, 631*4d098529SSimon Glass void *fit, int conf_noffset, const char *comment, 632*4d098529SSimon Glass int require_keys) 633*4d098529SSimon Glass { 634*4d098529SSimon Glass const char *conf_name; 635*4d098529SSimon Glass int noffset; 636*4d098529SSimon Glass 637*4d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 638*4d098529SSimon Glass 639*4d098529SSimon Glass /* Process all hash subnodes of the configuration node */ 640*4d098529SSimon Glass for (noffset = fdt_first_subnode(fit, conf_noffset); 641*4d098529SSimon Glass noffset >= 0; 642*4d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 643*4d098529SSimon Glass const char *node_name; 644*4d098529SSimon Glass int ret = 0; 645*4d098529SSimon Glass 646*4d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 647*4d098529SSimon Glass if (!strncmp(node_name, FIT_SIG_NODENAME, 648*4d098529SSimon Glass strlen(FIT_SIG_NODENAME))) { 649*4d098529SSimon Glass ret = fit_config_process_sig(keydir, keydest, 650*4d098529SSimon Glass fit, conf_name, conf_noffset, noffset, comment, 651*4d098529SSimon Glass require_keys); 652*4d098529SSimon Glass } 653*4d098529SSimon Glass if (ret) 654*4d098529SSimon Glass return ret; 655*4d098529SSimon Glass } 656*4d098529SSimon Glass 657*4d098529SSimon Glass return 0; 658*4d098529SSimon Glass } 659*4d098529SSimon Glass 66056518e71SSimon Glass int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 66156518e71SSimon Glass const char *comment, int require_keys) 662bbb467dcSSimon Glass { 663*4d098529SSimon Glass int images_noffset, confs_noffset; 664bbb467dcSSimon Glass int noffset; 665bbb467dcSSimon Glass int ret; 666bbb467dcSSimon Glass 667bbb467dcSSimon Glass /* Find images parent node offset */ 668bbb467dcSSimon Glass images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 669bbb467dcSSimon Glass if (images_noffset < 0) { 670bbb467dcSSimon Glass printf("Can't find images parent node '%s' (%s)\n", 671bbb467dcSSimon Glass FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 672bbb467dcSSimon Glass return images_noffset; 673bbb467dcSSimon Glass } 674bbb467dcSSimon Glass 675bbb467dcSSimon Glass /* Process its subnodes, print out component images details */ 676bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, images_noffset); 677bbb467dcSSimon Glass noffset >= 0; 678bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 679bbb467dcSSimon Glass /* 680bbb467dcSSimon Glass * Direct child node of the images parent node, 681bbb467dcSSimon Glass * i.e. component image node. 682bbb467dcSSimon Glass */ 68356518e71SSimon Glass ret = fit_image_add_verification_data(keydir, keydest, 68456518e71SSimon Glass fit, noffset, comment, require_keys); 685bbb467dcSSimon Glass if (ret) 686bbb467dcSSimon Glass return ret; 687604f23ddSSimon Glass } 688604f23ddSSimon Glass 689*4d098529SSimon Glass /* If there are no keys, we can't sign configurations */ 690*4d098529SSimon Glass if (!IMAGE_ENABLE_SIGN || !keydir) 691*4d098529SSimon Glass return 0; 692*4d098529SSimon Glass 693*4d098529SSimon Glass /* Find configurations parent node offset */ 694*4d098529SSimon Glass confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 695*4d098529SSimon Glass if (confs_noffset < 0) { 696*4d098529SSimon Glass printf("Can't find images parent node '%s' (%s)\n", 697*4d098529SSimon Glass FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); 698*4d098529SSimon Glass return -ENOENT; 699*4d098529SSimon Glass } 700*4d098529SSimon Glass 701*4d098529SSimon Glass /* Process its subnodes, print out component images details */ 702*4d098529SSimon Glass for (noffset = fdt_first_subnode(fit, confs_noffset); 703*4d098529SSimon Glass noffset >= 0; 704*4d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 705*4d098529SSimon Glass ret = fit_config_add_verification_data(keydir, keydest, 706*4d098529SSimon Glass fit, noffset, comment, 707*4d098529SSimon Glass require_keys); 708*4d098529SSimon Glass if (ret) 709*4d098529SSimon Glass return ret; 710*4d098529SSimon Glass } 711*4d098529SSimon Glass 712604f23ddSSimon Glass return 0; 713604f23ddSSimon Glass } 714