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" 13ce1400f6SSimon Glass #include <bootm.h> 14604f23ddSSimon Glass #include <image.h> 1556518e71SSimon Glass #include <version.h> 16604f23ddSSimon Glass 17604f23ddSSimon Glass /** 18b7260910SSimon Glass * fit_set_hash_value - set hash value in requested has node 19b7260910SSimon Glass * @fit: pointer to the FIT format image header 20b7260910SSimon Glass * @noffset: hash node offset 21b7260910SSimon Glass * @value: hash value to be set 22b7260910SSimon Glass * @value_len: hash value length 23b7260910SSimon Glass * 24b7260910SSimon Glass * fit_set_hash_value() attempts to set hash value in a node at offset 25b7260910SSimon Glass * given and returns operation status to the caller. 26b7260910SSimon Glass * 27b7260910SSimon Glass * returns 28b7260910SSimon Glass * 0, on success 29b7260910SSimon Glass * -1, on failure 30b7260910SSimon Glass */ 31b7260910SSimon Glass static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 32b7260910SSimon Glass int value_len) 33b7260910SSimon Glass { 34b7260910SSimon Glass int ret; 35b7260910SSimon Glass 36b7260910SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 37b7260910SSimon Glass if (ret) { 38b7260910SSimon Glass printf("Can't set hash '%s' property for '%s' node(%s)\n", 39b7260910SSimon Glass FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 40b7260910SSimon Glass fdt_strerror(ret)); 411152a05eSSimon Glass return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; 42b7260910SSimon Glass } 43b7260910SSimon Glass 44b7260910SSimon Glass return 0; 45b7260910SSimon Glass } 46b7260910SSimon Glass 47b7260910SSimon Glass /** 4894e5fa46SSimon Glass * fit_image_process_hash - Process a single subnode of the images/ node 4994e5fa46SSimon Glass * 5094e5fa46SSimon Glass * Check each subnode and process accordingly. For hash nodes we generate 5194e5fa46SSimon Glass * a hash of the supplised data and store it in the node. 5294e5fa46SSimon Glass * 5394e5fa46SSimon Glass * @fit: pointer to the FIT format image header 5494e5fa46SSimon Glass * @image_name: name of image being processes (used to display errors) 5594e5fa46SSimon Glass * @noffset: subnode offset 5694e5fa46SSimon Glass * @data: data to process 5794e5fa46SSimon Glass * @size: size of data in bytes 5894e5fa46SSimon Glass * @return 0 if ok, -1 on error 5994e5fa46SSimon Glass */ 6094e5fa46SSimon Glass static int fit_image_process_hash(void *fit, const char *image_name, 6194e5fa46SSimon Glass int noffset, const void *data, size_t size) 6294e5fa46SSimon Glass { 6394e5fa46SSimon Glass uint8_t value[FIT_MAX_HASH_LEN]; 64bbb467dcSSimon Glass const char *node_name; 6594e5fa46SSimon Glass int value_len; 6694e5fa46SSimon Glass char *algo; 671152a05eSSimon Glass int ret; 6894e5fa46SSimon Glass 69bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 7094e5fa46SSimon Glass 7194e5fa46SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo)) { 7294e5fa46SSimon Glass printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 73bbb467dcSSimon Glass node_name, image_name); 741152a05eSSimon Glass return -ENOENT; 7594e5fa46SSimon Glass } 7694e5fa46SSimon Glass 7794e5fa46SSimon Glass if (calculate_hash(data, size, algo, value, &value_len)) { 7894e5fa46SSimon Glass printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 79bbb467dcSSimon Glass algo, node_name, image_name); 801152a05eSSimon Glass return -EPROTONOSUPPORT; 8194e5fa46SSimon Glass } 8294e5fa46SSimon Glass 831152a05eSSimon Glass ret = fit_set_hash_value(fit, noffset, value, value_len); 841152a05eSSimon Glass if (ret) { 8594e5fa46SSimon Glass printf("Can't set hash value for '%s' hash node in '%s' image node\n", 86bbb467dcSSimon Glass node_name, image_name); 871152a05eSSimon Glass return ret; 8894e5fa46SSimon Glass } 8994e5fa46SSimon Glass 9094e5fa46SSimon Glass return 0; 9194e5fa46SSimon Glass } 9294e5fa46SSimon Glass 9394e5fa46SSimon Glass /** 9456518e71SSimon Glass * fit_image_write_sig() - write the signature to a FIT 95604f23ddSSimon Glass * 9656518e71SSimon Glass * This writes the signature and signer data to the FIT. 9756518e71SSimon Glass * 9856518e71SSimon Glass * @fit: pointer to the FIT format image header 9956518e71SSimon Glass * @noffset: hash node offset 10056518e71SSimon Glass * @value: signature value to be set 10156518e71SSimon Glass * @value_len: signature value length 10256518e71SSimon Glass * @comment: Text comment to write (NULL for none) 10356518e71SSimon Glass * 10456518e71SSimon Glass * returns 10556518e71SSimon Glass * 0, on success 10656518e71SSimon Glass * -FDT_ERR_..., on failure 10756518e71SSimon Glass */ 10856518e71SSimon Glass static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 10956518e71SSimon Glass int value_len, const char *comment, const char *region_prop, 11056518e71SSimon Glass int region_proplen) 11156518e71SSimon Glass { 11256518e71SSimon Glass int string_size; 11356518e71SSimon Glass int ret; 11456518e71SSimon Glass 11556518e71SSimon Glass /* 11656518e71SSimon Glass * Get the current string size, before we update the FIT and add 11756518e71SSimon Glass * more 11856518e71SSimon Glass */ 11956518e71SSimon Glass string_size = fdt_size_dt_strings(fit); 12056518e71SSimon Glass 12156518e71SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 12256518e71SSimon Glass if (!ret) { 12356518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-name", 12456518e71SSimon Glass "mkimage"); 12556518e71SSimon Glass } 12656518e71SSimon Glass if (!ret) { 12756518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-version", 12856518e71SSimon Glass PLAIN_VERSION); 12956518e71SSimon Glass } 13056518e71SSimon Glass if (comment && !ret) 13156518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "comment", comment); 13256518e71SSimon Glass if (!ret) 13356518e71SSimon Glass ret = fit_set_timestamp(fit, noffset, time(NULL)); 13456518e71SSimon Glass if (region_prop && !ret) { 13556518e71SSimon Glass uint32_t strdata[2]; 13656518e71SSimon Glass 13756518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-nodes", 13856518e71SSimon Glass region_prop, region_proplen); 13956518e71SSimon Glass strdata[0] = 0; 14056518e71SSimon Glass strdata[1] = cpu_to_fdt32(string_size); 14156518e71SSimon Glass if (!ret) { 14256518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-strings", 14356518e71SSimon Glass strdata, sizeof(strdata)); 14456518e71SSimon Glass } 14556518e71SSimon Glass } 14656518e71SSimon Glass 14756518e71SSimon Glass return ret; 14856518e71SSimon Glass } 14956518e71SSimon Glass 15056518e71SSimon Glass static int fit_image_setup_sig(struct image_sign_info *info, 15156518e71SSimon Glass const char *keydir, void *fit, const char *image_name, 15256518e71SSimon Glass int noffset, const char *require_keys) 15356518e71SSimon Glass { 15456518e71SSimon Glass const char *node_name; 15556518e71SSimon Glass char *algo_name; 15656518e71SSimon Glass 15756518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 15856518e71SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 15956518e71SSimon Glass printf("Can't get algo property for '%s' signature node in '%s' image node\n", 16056518e71SSimon Glass node_name, image_name); 16156518e71SSimon Glass return -1; 16256518e71SSimon Glass } 16356518e71SSimon Glass 16456518e71SSimon Glass memset(info, '\0', sizeof(*info)); 16556518e71SSimon Glass info->keydir = keydir; 16656518e71SSimon Glass info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 16756518e71SSimon Glass info->fit = fit; 16856518e71SSimon Glass info->node_offset = noffset; 169*83dd98e0SAndrew Duda info->name = algo_name; 170*83dd98e0SAndrew Duda info->checksum = image_get_checksum_algo(algo_name); 171*83dd98e0SAndrew Duda info->crypto = image_get_crypto_algo(algo_name); 17256518e71SSimon Glass info->require_keys = require_keys; 173*83dd98e0SAndrew Duda if (!info->checksum || !info->crypto) { 17456518e71SSimon Glass printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 17556518e71SSimon Glass algo_name, node_name, image_name); 17656518e71SSimon Glass return -1; 17756518e71SSimon Glass } 17856518e71SSimon Glass 17956518e71SSimon Glass return 0; 18056518e71SSimon Glass } 18156518e71SSimon Glass 18256518e71SSimon Glass /** 18356518e71SSimon Glass * fit_image_process_sig- Process a single subnode of the images/ node 18456518e71SSimon Glass * 18556518e71SSimon Glass * Check each subnode and process accordingly. For signature nodes we 18656518e71SSimon Glass * generate a signed hash of the supplised data and store it in the node. 18756518e71SSimon Glass * 18856518e71SSimon Glass * @keydir: Directory containing keys to use for signing 18956518e71SSimon Glass * @keydest: Destination FDT blob to write public keys into 19056518e71SSimon Glass * @fit: pointer to the FIT format image header 19156518e71SSimon Glass * @image_name: name of image being processes (used to display errors) 19256518e71SSimon Glass * @noffset: subnode offset 19356518e71SSimon Glass * @data: data to process 19456518e71SSimon Glass * @size: size of data in bytes 19556518e71SSimon Glass * @comment: Comment to add to signature nodes 19656518e71SSimon Glass * @require_keys: Mark all keys as 'required' 19756518e71SSimon Glass * @return 0 if ok, -1 on error 19856518e71SSimon Glass */ 19956518e71SSimon Glass static int fit_image_process_sig(const char *keydir, void *keydest, 20056518e71SSimon Glass void *fit, const char *image_name, 20156518e71SSimon Glass int noffset, const void *data, size_t size, 20256518e71SSimon Glass const char *comment, int require_keys) 20356518e71SSimon Glass { 20456518e71SSimon Glass struct image_sign_info info; 20556518e71SSimon Glass struct image_region region; 20656518e71SSimon Glass const char *node_name; 20756518e71SSimon Glass uint8_t *value; 20856518e71SSimon Glass uint value_len; 20956518e71SSimon Glass int ret; 21056518e71SSimon Glass 21156518e71SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 21256518e71SSimon Glass require_keys ? "image" : NULL)) 21356518e71SSimon Glass return -1; 21456518e71SSimon Glass 21556518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 21656518e71SSimon Glass region.data = data; 21756518e71SSimon Glass region.size = size; 218*83dd98e0SAndrew Duda ret = info.crypto->sign(&info, ®ion, 1, &value, &value_len); 21956518e71SSimon Glass if (ret) { 22056518e71SSimon Glass printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 22156518e71SSimon Glass node_name, image_name, ret); 22256518e71SSimon Glass 22356518e71SSimon Glass /* We allow keys to be missing */ 22456518e71SSimon Glass if (ret == -ENOENT) 22556518e71SSimon Glass return 0; 22656518e71SSimon Glass return -1; 22756518e71SSimon Glass } 22856518e71SSimon Glass 22956518e71SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 23056518e71SSimon Glass NULL, 0); 23156518e71SSimon Glass if (ret) { 232a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 233a9468115SSimon Glass return -ENOSPC; 234a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 23556518e71SSimon Glass node_name, image_name, fdt_strerror(ret)); 23656518e71SSimon Glass return -1; 23756518e71SSimon Glass } 23856518e71SSimon Glass free(value); 23956518e71SSimon Glass 24056518e71SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 24156518e71SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 24256518e71SSimon Glass 243713fb2dcSmario.six@gdsys.cc if (keydest) 244*83dd98e0SAndrew Duda ret = info.crypto->add_verify_data(&info, keydest); 245713fb2dcSmario.six@gdsys.cc else 246713fb2dcSmario.six@gdsys.cc return -1; 247c236ebd2Smario.six@gdsys.cc 248713fb2dcSmario.six@gdsys.cc /* 249713fb2dcSmario.six@gdsys.cc * Write the public key into the supplied FDT file; this might fail 250c236ebd2Smario.six@gdsys.cc * several times, since we try signing with successively increasing 251713fb2dcSmario.six@gdsys.cc * size values 252713fb2dcSmario.six@gdsys.cc */ 253c236ebd2Smario.six@gdsys.cc if (keydest && ret) 254c236ebd2Smario.six@gdsys.cc return ret; 25556518e71SSimon Glass 25656518e71SSimon Glass return 0; 25756518e71SSimon Glass } 25856518e71SSimon Glass 25956518e71SSimon Glass /** 26056518e71SSimon Glass * fit_image_add_verification_data() - calculate/set verig. data for image node 26156518e71SSimon Glass * 26256518e71SSimon Glass * This adds hash and signature values for an component image node. 263bbb467dcSSimon Glass * 264bbb467dcSSimon Glass * All existing hash subnodes are checked, if algorithm property is set to 265bbb467dcSSimon Glass * one of the supported hash algorithms, hash value is computed and 266bbb467dcSSimon Glass * corresponding hash node property is set, for example: 267604f23ddSSimon Glass * 268604f23ddSSimon Glass * Input component image node structure: 269604f23ddSSimon Glass * 270604f23ddSSimon Glass * o image@1 (at image_noffset) 271604f23ddSSimon Glass * | - data = [binary data] 272604f23ddSSimon Glass * o hash@1 273604f23ddSSimon Glass * |- algo = "sha1" 274604f23ddSSimon Glass * 275604f23ddSSimon Glass * Output component image node structure: 276604f23ddSSimon Glass * 277604f23ddSSimon Glass * o image@1 (at image_noffset) 278604f23ddSSimon Glass * | - data = [binary data] 279604f23ddSSimon Glass * o hash@1 280604f23ddSSimon Glass * |- algo = "sha1" 281604f23ddSSimon Glass * |- value = sha1(data) 282604f23ddSSimon Glass * 283bbb467dcSSimon Glass * For signature details, please see doc/uImage.FIT/signature.txt 284bbb467dcSSimon Glass * 28556518e71SSimon Glass * @keydir Directory containing *.key and *.crt files (or NULL) 28656518e71SSimon Glass * @keydest FDT Blob to write public keys into (NULL if none) 287bbb467dcSSimon Glass * @fit: Pointer to the FIT format image header 288bbb467dcSSimon Glass * @image_noffset: Requested component image node 28956518e71SSimon Glass * @comment: Comment to add to signature nodes 29056518e71SSimon Glass * @require_keys: Mark all keys as 'required' 291bbb467dcSSimon Glass * @return: 0 on success, <0 on failure 292604f23ddSSimon Glass */ 29356518e71SSimon Glass int fit_image_add_verification_data(const char *keydir, void *keydest, 29456518e71SSimon Glass void *fit, int image_noffset, const char *comment, 29556518e71SSimon Glass int require_keys) 296604f23ddSSimon Glass { 297bbb467dcSSimon Glass const char *image_name; 298604f23ddSSimon Glass const void *data; 299604f23ddSSimon Glass size_t size; 300604f23ddSSimon Glass int noffset; 301604f23ddSSimon Glass 302604f23ddSSimon Glass /* Get image data and data length */ 303604f23ddSSimon Glass if (fit_image_get_data(fit, image_noffset, &data, &size)) { 304604f23ddSSimon Glass printf("Can't get image data/size\n"); 305604f23ddSSimon Glass return -1; 306604f23ddSSimon Glass } 307604f23ddSSimon Glass 30894e5fa46SSimon Glass image_name = fit_get_name(fit, image_noffset, NULL); 30994e5fa46SSimon Glass 310604f23ddSSimon Glass /* Process all hash subnodes of the component image node */ 311bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 312bbb467dcSSimon Glass noffset >= 0; 313bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 314bbb467dcSSimon Glass const char *node_name; 315bbb467dcSSimon Glass int ret = 0; 316bbb467dcSSimon Glass 317bbb467dcSSimon Glass /* 318bbb467dcSSimon Glass * Check subnode name, must be equal to "hash" or "signature". 319bbb467dcSSimon Glass * Multiple hash nodes require unique unit node 320bbb467dcSSimon Glass * names, e.g. hash@1, hash@2, signature@1, etc. 321bbb467dcSSimon Glass */ 322bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 323bbb467dcSSimon Glass if (!strncmp(node_name, FIT_HASH_NODENAME, 324bbb467dcSSimon Glass strlen(FIT_HASH_NODENAME))) { 325bbb467dcSSimon Glass ret = fit_image_process_hash(fit, image_name, noffset, 326bbb467dcSSimon Glass data, size); 32756518e71SSimon Glass } else if (IMAGE_ENABLE_SIGN && keydir && 32856518e71SSimon Glass !strncmp(node_name, FIT_SIG_NODENAME, 32956518e71SSimon Glass strlen(FIT_SIG_NODENAME))) { 33056518e71SSimon Glass ret = fit_image_process_sig(keydir, keydest, 33156518e71SSimon Glass fit, image_name, noffset, data, size, 33256518e71SSimon Glass comment, require_keys); 333bbb467dcSSimon Glass } 334bbb467dcSSimon Glass if (ret) 3351152a05eSSimon Glass return ret; 336604f23ddSSimon Glass } 337bbb467dcSSimon Glass 338bbb467dcSSimon Glass return 0; 339bbb467dcSSimon Glass } 340bbb467dcSSimon Glass 3414d098529SSimon Glass struct strlist { 3424d098529SSimon Glass int count; 3434d098529SSimon Glass char **strings; 3444d098529SSimon Glass }; 3454d098529SSimon Glass 3464d098529SSimon Glass static void strlist_init(struct strlist *list) 3474d098529SSimon Glass { 3484d098529SSimon Glass memset(list, '\0', sizeof(*list)); 3494d098529SSimon Glass } 3504d098529SSimon Glass 3514d098529SSimon Glass static void strlist_free(struct strlist *list) 3524d098529SSimon Glass { 3534d098529SSimon Glass int i; 3544d098529SSimon Glass 3554d098529SSimon Glass for (i = 0; i < list->count; i++) 3564d098529SSimon Glass free(list->strings[i]); 3574d098529SSimon Glass free(list->strings); 3584d098529SSimon Glass } 3594d098529SSimon Glass 3604d098529SSimon Glass static int strlist_add(struct strlist *list, const char *str) 3614d098529SSimon Glass { 3624d098529SSimon Glass char *dup; 3634d098529SSimon Glass 3644d098529SSimon Glass dup = strdup(str); 3654d098529SSimon Glass list->strings = realloc(list->strings, 3664d098529SSimon Glass (list->count + 1) * sizeof(char *)); 3674d098529SSimon Glass if (!list || !str) 3684d098529SSimon Glass return -1; 3694d098529SSimon Glass list->strings[list->count++] = dup; 3704d098529SSimon Glass 3714d098529SSimon Glass return 0; 3724d098529SSimon Glass } 3734d098529SSimon Glass 3744d098529SSimon Glass static const char *fit_config_get_image_list(void *fit, int noffset, 3754d098529SSimon Glass int *lenp, int *allow_missingp) 3764d098529SSimon Glass { 3774d098529SSimon Glass static const char default_list[] = FIT_KERNEL_PROP "\0" 3784d098529SSimon Glass FIT_FDT_PROP; 3794d098529SSimon Glass const char *prop; 3804d098529SSimon Glass 3814d098529SSimon Glass /* If there is an "image" property, use that */ 3824d098529SSimon Glass prop = fdt_getprop(fit, noffset, "sign-images", lenp); 3834d098529SSimon Glass if (prop) { 3844d098529SSimon Glass *allow_missingp = 0; 3854d098529SSimon Glass return *lenp ? prop : NULL; 3864d098529SSimon Glass } 3874d098529SSimon Glass 3884d098529SSimon Glass /* Default image list */ 3894d098529SSimon Glass *allow_missingp = 1; 3904d098529SSimon Glass *lenp = sizeof(default_list); 3914d098529SSimon Glass 3924d098529SSimon Glass return default_list; 3934d098529SSimon Glass } 3944d098529SSimon Glass 3954d098529SSimon Glass static int fit_config_get_hash_list(void *fit, int conf_noffset, 3964d098529SSimon Glass int sig_offset, struct strlist *node_inc) 3974d098529SSimon Glass { 3984d098529SSimon Glass int allow_missing; 3994d098529SSimon Glass const char *prop, *iname, *end; 4004d098529SSimon Glass const char *conf_name, *sig_name; 4014d098529SSimon Glass char name[200], path[200]; 4024d098529SSimon Glass int image_count; 4034d098529SSimon Glass int ret, len; 4044d098529SSimon Glass 4054d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 4064d098529SSimon Glass sig_name = fit_get_name(fit, sig_offset, NULL); 4074d098529SSimon Glass 4084d098529SSimon Glass /* 4094d098529SSimon Glass * Build a list of nodes we need to hash. We always need the root 4104d098529SSimon Glass * node and the configuration. 4114d098529SSimon Glass */ 4124d098529SSimon Glass strlist_init(node_inc); 4134d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 4144d098529SSimon Glass if (strlist_add(node_inc, "/") || 4154d098529SSimon Glass strlist_add(node_inc, name)) 4164d098529SSimon Glass goto err_mem; 4174d098529SSimon Glass 4184d098529SSimon Glass /* Get a list of images that we intend to sign */ 41966b36f83SHeiko Schocher prop = fit_config_get_image_list(fit, sig_offset, &len, 4204d098529SSimon Glass &allow_missing); 4214d098529SSimon Glass if (!prop) 4224d098529SSimon Glass return 0; 4234d098529SSimon Glass 4244d098529SSimon Glass /* Locate the images */ 4254d098529SSimon Glass end = prop + len; 4264d098529SSimon Glass image_count = 0; 4274d098529SSimon Glass for (iname = prop; iname < end; iname += strlen(iname) + 1) { 4284d098529SSimon Glass int noffset; 4294d098529SSimon Glass int image_noffset; 4304d098529SSimon Glass int hash_count; 4314d098529SSimon Glass 4324d098529SSimon Glass image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 4334d098529SSimon Glass iname); 4344d098529SSimon Glass if (image_noffset < 0) { 4354d098529SSimon Glass printf("Failed to find image '%s' in configuration '%s/%s'\n", 4364d098529SSimon Glass iname, conf_name, sig_name); 4374d098529SSimon Glass if (allow_missing) 4384d098529SSimon Glass continue; 4394d098529SSimon Glass 4404d098529SSimon Glass return -ENOENT; 4414d098529SSimon Glass } 4424d098529SSimon Glass 4434d098529SSimon Glass ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 4444d098529SSimon Glass if (ret < 0) 4454d098529SSimon Glass goto err_path; 4464d098529SSimon Glass if (strlist_add(node_inc, path)) 4474d098529SSimon Glass goto err_mem; 4484d098529SSimon Glass 4494d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 4504d098529SSimon Glass conf_name); 4514d098529SSimon Glass 4524d098529SSimon Glass /* Add all this image's hashes */ 4534d098529SSimon Glass hash_count = 0; 4544d098529SSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 4554d098529SSimon Glass noffset >= 0; 4564d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 4574d098529SSimon Glass const char *name = fit_get_name(fit, noffset, NULL); 4584d098529SSimon Glass 4594d098529SSimon Glass if (strncmp(name, FIT_HASH_NODENAME, 4604d098529SSimon Glass strlen(FIT_HASH_NODENAME))) 4614d098529SSimon Glass continue; 4624d098529SSimon Glass ret = fdt_get_path(fit, noffset, path, sizeof(path)); 4634d098529SSimon Glass if (ret < 0) 4644d098529SSimon Glass goto err_path; 4654d098529SSimon Glass if (strlist_add(node_inc, path)) 4664d098529SSimon Glass goto err_mem; 4674d098529SSimon Glass hash_count++; 4684d098529SSimon Glass } 4694d098529SSimon Glass 4704d098529SSimon Glass if (!hash_count) { 4714d098529SSimon 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", 4724d098529SSimon Glass conf_name, sig_name, iname); 4734d098529SSimon Glass return -ENOMSG; 4744d098529SSimon Glass } 4754d098529SSimon Glass 4764d098529SSimon Glass image_count++; 4774d098529SSimon Glass } 4784d098529SSimon Glass 4794d098529SSimon Glass if (!image_count) { 4804d098529SSimon Glass printf("Failed to find any images for configuration '%s/%s'\n", 4814d098529SSimon Glass conf_name, sig_name); 4824d098529SSimon Glass return -ENOMSG; 4834d098529SSimon Glass } 4844d098529SSimon Glass 4854d098529SSimon Glass return 0; 4864d098529SSimon Glass 4874d098529SSimon Glass err_mem: 4884d098529SSimon Glass printf("Out of memory processing configuration '%s/%s'\n", conf_name, 4894d098529SSimon Glass sig_name); 4904d098529SSimon Glass return -ENOMEM; 4914d098529SSimon Glass 4924d098529SSimon Glass err_path: 4934d098529SSimon Glass printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 4944d098529SSimon Glass iname, conf_name, sig_name, fdt_strerror(ret)); 4954d098529SSimon Glass return -ENOENT; 4964d098529SSimon Glass } 4974d098529SSimon Glass 4984d098529SSimon Glass static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 4994d098529SSimon Glass struct image_region **regionp, int *region_countp, 5004d098529SSimon Glass char **region_propp, int *region_proplen) 5014d098529SSimon Glass { 5024d098529SSimon Glass char * const exc_prop[] = {"data"}; 5034d098529SSimon Glass struct strlist node_inc; 5044d098529SSimon Glass struct image_region *region; 5054d098529SSimon Glass struct fdt_region fdt_regions[100]; 5064d098529SSimon Glass const char *conf_name, *sig_name; 5074d098529SSimon Glass char path[200]; 5084d098529SSimon Glass int count, i; 5094d098529SSimon Glass char *region_prop; 5104d098529SSimon Glass int ret, len; 5114d098529SSimon Glass 5124d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 5134d098529SSimon Glass sig_name = fit_get_name(fit, conf_noffset, NULL); 5144d098529SSimon Glass debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 5154d098529SSimon Glass 5164d098529SSimon Glass /* Get a list of nodes we want to hash */ 5174d098529SSimon Glass ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 5184d098529SSimon Glass if (ret) 5194d098529SSimon Glass return ret; 5204d098529SSimon Glass 5214d098529SSimon Glass /* Get a list of regions to hash */ 5224d098529SSimon Glass count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 5234d098529SSimon Glass exc_prop, ARRAY_SIZE(exc_prop), 5244d098529SSimon Glass fdt_regions, ARRAY_SIZE(fdt_regions), 5254d098529SSimon Glass path, sizeof(path), 1); 5264d098529SSimon Glass if (count < 0) { 5274d098529SSimon Glass printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 5284d098529SSimon Glass sig_name, fdt_strerror(ret)); 5294d098529SSimon Glass return -EIO; 5304d098529SSimon Glass } 5314d098529SSimon Glass if (count == 0) { 5324d098529SSimon Glass printf("No data to hash for configuration '%s/%s': %s\n", 5334d098529SSimon Glass conf_name, sig_name, fdt_strerror(ret)); 5344d098529SSimon Glass return -EINVAL; 5354d098529SSimon Glass } 5364d098529SSimon Glass 5374d098529SSimon Glass /* Build our list of data blocks */ 5384d098529SSimon Glass region = fit_region_make_list(fit, fdt_regions, count, NULL); 5394d098529SSimon Glass if (!region) { 5404d098529SSimon Glass printf("Out of memory hashing configuration '%s/%s'\n", 5414d098529SSimon Glass conf_name, sig_name); 5424d098529SSimon Glass return -ENOMEM; 5434d098529SSimon Glass } 5444d098529SSimon Glass 5454d098529SSimon Glass /* Create a list of all hashed properties */ 5464d098529SSimon Glass debug("Hash nodes:\n"); 5474d098529SSimon Glass for (i = len = 0; i < node_inc.count; i++) { 5484d098529SSimon Glass debug(" %s\n", node_inc.strings[i]); 5494d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1; 5504d098529SSimon Glass } 5514d098529SSimon Glass region_prop = malloc(len); 5524d098529SSimon Glass if (!region_prop) { 5534d098529SSimon Glass printf("Out of memory setting up regions for configuration '%s/%s'\n", 5544d098529SSimon Glass conf_name, sig_name); 5554d098529SSimon Glass return -ENOMEM; 5564d098529SSimon Glass } 5574d098529SSimon Glass for (i = len = 0; i < node_inc.count; 5584d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1, i++) 5594d098529SSimon Glass strcpy(region_prop + len, node_inc.strings[i]); 5604d098529SSimon Glass strlist_free(&node_inc); 5614d098529SSimon Glass 5624d098529SSimon Glass *region_countp = count; 5634d098529SSimon Glass *regionp = region; 5644d098529SSimon Glass *region_propp = region_prop; 5654d098529SSimon Glass *region_proplen = len; 5664d098529SSimon Glass 5674d098529SSimon Glass return 0; 5684d098529SSimon Glass } 5694d098529SSimon Glass 5704d098529SSimon Glass static int fit_config_process_sig(const char *keydir, void *keydest, 5714d098529SSimon Glass void *fit, const char *conf_name, int conf_noffset, 5724d098529SSimon Glass int noffset, const char *comment, int require_keys) 5734d098529SSimon Glass { 5744d098529SSimon Glass struct image_sign_info info; 5754d098529SSimon Glass const char *node_name; 5764d098529SSimon Glass struct image_region *region; 5774d098529SSimon Glass char *region_prop; 5784d098529SSimon Glass int region_proplen; 5794d098529SSimon Glass int region_count; 5804d098529SSimon Glass uint8_t *value; 5814d098529SSimon Glass uint value_len; 5824d098529SSimon Glass int ret; 5834d098529SSimon Glass 5844d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 5854d098529SSimon Glass if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 5864d098529SSimon Glass ®ion_count, ®ion_prop, ®ion_proplen)) 5874d098529SSimon Glass return -1; 5884d098529SSimon Glass 5894d098529SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 5904d098529SSimon Glass require_keys ? "conf" : NULL)) 5914d098529SSimon Glass return -1; 5924d098529SSimon Glass 593*83dd98e0SAndrew Duda ret = info.crypto->sign(&info, region, region_count, &value, 5940c1d74fdSAndrew Duda &value_len); 5954d098529SSimon Glass free(region); 5964d098529SSimon Glass if (ret) { 5974d098529SSimon Glass printf("Failed to sign '%s' signature node in '%s' conf node\n", 5984d098529SSimon Glass node_name, conf_name); 5994d098529SSimon Glass 6004d098529SSimon Glass /* We allow keys to be missing */ 6014d098529SSimon Glass if (ret == -ENOENT) 6024d098529SSimon Glass return 0; 6034d098529SSimon Glass return -1; 6044d098529SSimon Glass } 6054d098529SSimon Glass 606a9468115SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 607a9468115SSimon Glass region_prop, region_proplen); 608a9468115SSimon Glass if (ret) { 609a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 610a9468115SSimon Glass return -ENOSPC; 611a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 612a9468115SSimon Glass node_name, conf_name, fdt_strerror(ret)); 6134d098529SSimon Glass return -1; 6144d098529SSimon Glass } 6154d098529SSimon Glass free(value); 6164d098529SSimon Glass free(region_prop); 6174d098529SSimon Glass 6184d098529SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 6194d098529SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 6204d098529SSimon Glass 6214d098529SSimon Glass /* Write the public key into the supplied FDT file */ 622a9468115SSimon Glass if (keydest) { 623*83dd98e0SAndrew Duda ret = info.crypto->add_verify_data(&info, keydest); 624597a8b2cSSimon Glass if (ret == -ENOSPC) 625597a8b2cSSimon Glass return -ENOSPC; 626a9468115SSimon Glass if (ret) { 6274d098529SSimon Glass printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 6284d098529SSimon Glass node_name, conf_name); 629a9468115SSimon Glass } 630597a8b2cSSimon Glass return ret; 6314d098529SSimon Glass } 6324d098529SSimon Glass 6334d098529SSimon Glass return 0; 6344d098529SSimon Glass } 6354d098529SSimon Glass 6364d098529SSimon Glass static int fit_config_add_verification_data(const char *keydir, void *keydest, 6374d098529SSimon Glass void *fit, int conf_noffset, const char *comment, 6384d098529SSimon Glass int require_keys) 6394d098529SSimon Glass { 6404d098529SSimon Glass const char *conf_name; 6414d098529SSimon Glass int noffset; 6424d098529SSimon Glass 6434d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 6444d098529SSimon Glass 6454d098529SSimon Glass /* Process all hash subnodes of the configuration node */ 6464d098529SSimon Glass for (noffset = fdt_first_subnode(fit, conf_noffset); 6474d098529SSimon Glass noffset >= 0; 6484d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6494d098529SSimon Glass const char *node_name; 6504d098529SSimon Glass int ret = 0; 6514d098529SSimon Glass 6524d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6534d098529SSimon Glass if (!strncmp(node_name, FIT_SIG_NODENAME, 6544d098529SSimon Glass strlen(FIT_SIG_NODENAME))) { 6554d098529SSimon Glass ret = fit_config_process_sig(keydir, keydest, 6564d098529SSimon Glass fit, conf_name, conf_noffset, noffset, comment, 6574d098529SSimon Glass require_keys); 6584d098529SSimon Glass } 6594d098529SSimon Glass if (ret) 6604d098529SSimon Glass return ret; 6614d098529SSimon Glass } 6624d098529SSimon Glass 6634d098529SSimon Glass return 0; 6644d098529SSimon Glass } 6654d098529SSimon Glass 66656518e71SSimon Glass int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 66756518e71SSimon Glass const char *comment, int require_keys) 668bbb467dcSSimon Glass { 6694d098529SSimon Glass int images_noffset, confs_noffset; 670bbb467dcSSimon Glass int noffset; 671bbb467dcSSimon Glass int ret; 672bbb467dcSSimon Glass 673bbb467dcSSimon Glass /* Find images parent node offset */ 674bbb467dcSSimon Glass images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 675bbb467dcSSimon Glass if (images_noffset < 0) { 676bbb467dcSSimon Glass printf("Can't find images parent node '%s' (%s)\n", 677bbb467dcSSimon Glass FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 678bbb467dcSSimon Glass return images_noffset; 679bbb467dcSSimon Glass } 680bbb467dcSSimon Glass 681bbb467dcSSimon Glass /* Process its subnodes, print out component images details */ 682bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, images_noffset); 683bbb467dcSSimon Glass noffset >= 0; 684bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 685bbb467dcSSimon Glass /* 686bbb467dcSSimon Glass * Direct child node of the images parent node, 687bbb467dcSSimon Glass * i.e. component image node. 688bbb467dcSSimon Glass */ 68956518e71SSimon Glass ret = fit_image_add_verification_data(keydir, keydest, 69056518e71SSimon Glass fit, noffset, comment, require_keys); 691bbb467dcSSimon Glass if (ret) 692bbb467dcSSimon Glass return ret; 693604f23ddSSimon Glass } 694604f23ddSSimon Glass 6954d098529SSimon Glass /* If there are no keys, we can't sign configurations */ 6964d098529SSimon Glass if (!IMAGE_ENABLE_SIGN || !keydir) 6974d098529SSimon Glass return 0; 6984d098529SSimon Glass 6994d098529SSimon Glass /* Find configurations parent node offset */ 7004d098529SSimon Glass confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 7014d098529SSimon Glass if (confs_noffset < 0) { 7024d098529SSimon Glass printf("Can't find images parent node '%s' (%s)\n", 70304a710a5SHeiko Schocher FIT_CONFS_PATH, fdt_strerror(confs_noffset)); 7044d098529SSimon Glass return -ENOENT; 7054d098529SSimon Glass } 7064d098529SSimon Glass 7074d098529SSimon Glass /* Process its subnodes, print out component images details */ 7084d098529SSimon Glass for (noffset = fdt_first_subnode(fit, confs_noffset); 7094d098529SSimon Glass noffset >= 0; 7104d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 7114d098529SSimon Glass ret = fit_config_add_verification_data(keydir, keydest, 7124d098529SSimon Glass fit, noffset, comment, 7134d098529SSimon Glass require_keys); 7144d098529SSimon Glass if (ret) 7154d098529SSimon Glass return ret; 7164d098529SSimon Glass } 7174d098529SSimon Glass 718604f23ddSSimon Glass return 0; 719604f23ddSSimon Glass } 72029a23f9dSHeiko Schocher 72129a23f9dSHeiko Schocher #ifdef CONFIG_FIT_SIGNATURE 722ce1400f6SSimon Glass int fit_check_sign(const void *fit, const void *key) 72329a23f9dSHeiko Schocher { 72429a23f9dSHeiko Schocher int cfg_noffset; 72529a23f9dSHeiko Schocher int ret; 72629a23f9dSHeiko Schocher 727ce1400f6SSimon Glass cfg_noffset = fit_conf_get_node(fit, NULL); 72829a23f9dSHeiko Schocher if (!cfg_noffset) 72929a23f9dSHeiko Schocher return -1; 73029a23f9dSHeiko Schocher 731ce1400f6SSimon Glass printf("Verifying Hash Integrity ... "); 732ce1400f6SSimon Glass ret = fit_config_verify(fit, cfg_noffset); 733ce1400f6SSimon Glass if (ret) 734ce1400f6SSimon Glass return ret; 735ce1400f6SSimon Glass ret = bootm_host_load_images(fit, cfg_noffset); 736ce1400f6SSimon Glass 73729a23f9dSHeiko Schocher return ret; 73829a23f9dSHeiko Schocher } 73929a23f9dSHeiko Schocher #endif 740