183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2604f23ddSSimon Glass /* 3604f23ddSSimon Glass * Copyright (c) 2013, Google Inc. 4604f23ddSSimon Glass * 5604f23ddSSimon Glass * (C) Copyright 2008 Semihalf 6604f23ddSSimon Glass * 7604f23ddSSimon Glass * (C) Copyright 2000-2006 8604f23ddSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9604f23ddSSimon Glass */ 10604f23ddSSimon Glass 11604f23ddSSimon Glass #include "mkimage.h" 12ce1400f6SSimon Glass #include <bootm.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)); 401152a05eSSimon Glass return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; 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; 661152a05eSSimon Glass int ret; 6794e5fa46SSimon Glass 68bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6994e5fa46SSimon Glass 7094e5fa46SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo)) { 7194e5fa46SSimon Glass printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 72bbb467dcSSimon Glass node_name, image_name); 731152a05eSSimon Glass return -ENOENT; 7494e5fa46SSimon Glass } 7594e5fa46SSimon Glass 7694e5fa46SSimon Glass if (calculate_hash(data, size, algo, value, &value_len)) { 7794e5fa46SSimon Glass printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 78bbb467dcSSimon Glass algo, node_name, image_name); 791152a05eSSimon Glass return -EPROTONOSUPPORT; 8094e5fa46SSimon Glass } 8194e5fa46SSimon Glass 821152a05eSSimon Glass ret = fit_set_hash_value(fit, noffset, value, value_len); 831152a05eSSimon Glass if (ret) { 8494e5fa46SSimon Glass printf("Can't set hash value for '%s' hash node in '%s' image node\n", 85bbb467dcSSimon Glass node_name, image_name); 861152a05eSSimon Glass return ret; 8794e5fa46SSimon Glass } 8894e5fa46SSimon Glass 8994e5fa46SSimon Glass return 0; 9094e5fa46SSimon Glass } 9194e5fa46SSimon Glass 9294e5fa46SSimon Glass /** 9356518e71SSimon Glass * fit_image_write_sig() - write the signature to a FIT 94604f23ddSSimon Glass * 9556518e71SSimon Glass * This writes the signature and signer data to the FIT. 9656518e71SSimon Glass * 9756518e71SSimon Glass * @fit: pointer to the FIT format image header 9856518e71SSimon Glass * @noffset: hash node offset 9956518e71SSimon Glass * @value: signature value to be set 10056518e71SSimon Glass * @value_len: signature value length 10156518e71SSimon Glass * @comment: Text comment to write (NULL for none) 10256518e71SSimon Glass * 10356518e71SSimon Glass * returns 10456518e71SSimon Glass * 0, on success 10556518e71SSimon Glass * -FDT_ERR_..., on failure 10656518e71SSimon Glass */ 10756518e71SSimon Glass static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 10856518e71SSimon Glass int value_len, const char *comment, const char *region_prop, 109*795f452eSAlex Kiernan int region_proplen, const char *cmdname) 11056518e71SSimon Glass { 11156518e71SSimon Glass int string_size; 11256518e71SSimon Glass int ret; 11356518e71SSimon Glass 11456518e71SSimon Glass /* 11556518e71SSimon Glass * Get the current string size, before we update the FIT and add 11656518e71SSimon Glass * more 11756518e71SSimon Glass */ 11856518e71SSimon Glass string_size = fdt_size_dt_strings(fit); 11956518e71SSimon Glass 12056518e71SSimon Glass ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 12156518e71SSimon Glass if (!ret) { 12256518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-name", 12356518e71SSimon Glass "mkimage"); 12456518e71SSimon Glass } 12556518e71SSimon Glass if (!ret) { 12656518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "signer-version", 12756518e71SSimon Glass PLAIN_VERSION); 12856518e71SSimon Glass } 12956518e71SSimon Glass if (comment && !ret) 13056518e71SSimon Glass ret = fdt_setprop_string(fit, noffset, "comment", comment); 131*795f452eSAlex Kiernan if (!ret) { 132*795f452eSAlex Kiernan time_t timestamp = imagetool_get_source_date(cmdname, 133*795f452eSAlex Kiernan time(NULL)); 134*795f452eSAlex Kiernan 135*795f452eSAlex Kiernan ret = fit_set_timestamp(fit, noffset, timestamp); 136*795f452eSAlex Kiernan } 13756518e71SSimon Glass if (region_prop && !ret) { 13856518e71SSimon Glass uint32_t strdata[2]; 13956518e71SSimon Glass 14056518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-nodes", 14156518e71SSimon Glass region_prop, region_proplen); 1427346c1e1STeddy Reed /* This is a legacy offset, it is unused, and must remain 0. */ 14356518e71SSimon Glass strdata[0] = 0; 14456518e71SSimon Glass strdata[1] = cpu_to_fdt32(string_size); 14556518e71SSimon Glass if (!ret) { 14656518e71SSimon Glass ret = fdt_setprop(fit, noffset, "hashed-strings", 14756518e71SSimon Glass strdata, sizeof(strdata)); 14856518e71SSimon Glass } 14956518e71SSimon Glass } 15056518e71SSimon Glass 15156518e71SSimon Glass return ret; 15256518e71SSimon Glass } 15356518e71SSimon Glass 15456518e71SSimon Glass static int fit_image_setup_sig(struct image_sign_info *info, 15556518e71SSimon Glass const char *keydir, void *fit, const char *image_name, 156f1ca1fdeSGeorge McCollister int noffset, const char *require_keys, const char *engine_id) 15756518e71SSimon Glass { 15856518e71SSimon Glass const char *node_name; 15956518e71SSimon Glass char *algo_name; 16056518e71SSimon Glass 16156518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 16256518e71SSimon Glass if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 16356518e71SSimon Glass printf("Can't get algo property for '%s' signature node in '%s' image node\n", 16456518e71SSimon Glass node_name, image_name); 16556518e71SSimon Glass return -1; 16656518e71SSimon Glass } 16756518e71SSimon Glass 16856518e71SSimon Glass memset(info, '\0', sizeof(*info)); 16956518e71SSimon Glass info->keydir = keydir; 17056518e71SSimon Glass info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 17156518e71SSimon Glass info->fit = fit; 17256518e71SSimon Glass info->node_offset = noffset; 1731d88a99dSMasahiro Yamada info->name = strdup(algo_name); 17483dd98e0SAndrew Duda info->checksum = image_get_checksum_algo(algo_name); 17583dd98e0SAndrew Duda info->crypto = image_get_crypto_algo(algo_name); 17656518e71SSimon Glass info->require_keys = require_keys; 177f1ca1fdeSGeorge McCollister info->engine_id = engine_id; 17883dd98e0SAndrew Duda if (!info->checksum || !info->crypto) { 17956518e71SSimon Glass printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 18056518e71SSimon Glass algo_name, node_name, image_name); 18156518e71SSimon Glass return -1; 18256518e71SSimon Glass } 18356518e71SSimon Glass 18456518e71SSimon Glass return 0; 18556518e71SSimon Glass } 18656518e71SSimon Glass 18756518e71SSimon Glass /** 18856518e71SSimon Glass * fit_image_process_sig- Process a single subnode of the images/ node 18956518e71SSimon Glass * 19056518e71SSimon Glass * Check each subnode and process accordingly. For signature nodes we 19156518e71SSimon Glass * generate a signed hash of the supplised data and store it in the node. 19256518e71SSimon Glass * 19356518e71SSimon Glass * @keydir: Directory containing keys to use for signing 19456518e71SSimon Glass * @keydest: Destination FDT blob to write public keys into 19556518e71SSimon Glass * @fit: pointer to the FIT format image header 19656518e71SSimon Glass * @image_name: name of image being processes (used to display errors) 19756518e71SSimon Glass * @noffset: subnode offset 19856518e71SSimon Glass * @data: data to process 19956518e71SSimon Glass * @size: size of data in bytes 20056518e71SSimon Glass * @comment: Comment to add to signature nodes 20156518e71SSimon Glass * @require_keys: Mark all keys as 'required' 202f1ca1fdeSGeorge McCollister * @engine_id: Engine to use for signing 20356518e71SSimon Glass * @return 0 if ok, -1 on error 20456518e71SSimon Glass */ 20556518e71SSimon Glass static int fit_image_process_sig(const char *keydir, void *keydest, 20656518e71SSimon Glass void *fit, const char *image_name, 20756518e71SSimon Glass int noffset, const void *data, size_t size, 208*795f452eSAlex Kiernan const char *comment, int require_keys, const char *engine_id, 209*795f452eSAlex Kiernan const char *cmdname) 21056518e71SSimon Glass { 21156518e71SSimon Glass struct image_sign_info info; 21256518e71SSimon Glass struct image_region region; 21356518e71SSimon Glass const char *node_name; 21456518e71SSimon Glass uint8_t *value; 21556518e71SSimon Glass uint value_len; 21656518e71SSimon Glass int ret; 21756518e71SSimon Glass 21856518e71SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 219f1ca1fdeSGeorge McCollister require_keys ? "image" : NULL, engine_id)) 22056518e71SSimon Glass return -1; 22156518e71SSimon Glass 22256518e71SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 22356518e71SSimon Glass region.data = data; 22456518e71SSimon Glass region.size = size; 22583dd98e0SAndrew Duda ret = info.crypto->sign(&info, ®ion, 1, &value, &value_len); 22656518e71SSimon Glass if (ret) { 22756518e71SSimon Glass printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 22856518e71SSimon Glass node_name, image_name, ret); 22956518e71SSimon Glass 23056518e71SSimon Glass /* We allow keys to be missing */ 23156518e71SSimon Glass if (ret == -ENOENT) 23256518e71SSimon Glass return 0; 23356518e71SSimon Glass return -1; 23456518e71SSimon Glass } 23556518e71SSimon Glass 23656518e71SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 237*795f452eSAlex Kiernan NULL, 0, cmdname); 23856518e71SSimon Glass if (ret) { 239a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 240a9468115SSimon Glass return -ENOSPC; 241a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 24256518e71SSimon Glass node_name, image_name, fdt_strerror(ret)); 24356518e71SSimon Glass return -1; 24456518e71SSimon Glass } 24556518e71SSimon Glass free(value); 24656518e71SSimon Glass 24756518e71SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 24856518e71SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 24956518e71SSimon Glass 250713fb2dcSmario.six@gdsys.cc /* 251713fb2dcSmario.six@gdsys.cc * Write the public key into the supplied FDT file; this might fail 252c236ebd2Smario.six@gdsys.cc * several times, since we try signing with successively increasing 253713fb2dcSmario.six@gdsys.cc * size values 254713fb2dcSmario.six@gdsys.cc */ 2556793d017SMasahiro Yamada if (keydest) { 2566793d017SMasahiro Yamada ret = info.crypto->add_verify_data(&info, keydest); 2576793d017SMasahiro Yamada if (ret) { 2586793d017SMasahiro Yamada printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 2596793d017SMasahiro Yamada node_name, image_name); 260c236ebd2Smario.six@gdsys.cc return ret; 2616793d017SMasahiro Yamada } 2626793d017SMasahiro Yamada } 26356518e71SSimon Glass 26456518e71SSimon Glass return 0; 26556518e71SSimon Glass } 26656518e71SSimon Glass 26756518e71SSimon Glass /** 26856518e71SSimon Glass * fit_image_add_verification_data() - calculate/set verig. data for image node 26956518e71SSimon Glass * 27056518e71SSimon Glass * This adds hash and signature values for an component image node. 271bbb467dcSSimon Glass * 272bbb467dcSSimon Glass * All existing hash subnodes are checked, if algorithm property is set to 273bbb467dcSSimon Glass * one of the supported hash algorithms, hash value is computed and 274bbb467dcSSimon Glass * corresponding hash node property is set, for example: 275604f23ddSSimon Glass * 276604f23ddSSimon Glass * Input component image node structure: 277604f23ddSSimon Glass * 278b2267e8aSAndre Przywara * o image-1 (at image_noffset) 279604f23ddSSimon Glass * | - data = [binary data] 280b2267e8aSAndre Przywara * o hash-1 281604f23ddSSimon Glass * |- algo = "sha1" 282604f23ddSSimon Glass * 283604f23ddSSimon Glass * Output component image node structure: 284604f23ddSSimon Glass * 285b2267e8aSAndre Przywara * o image-1 (at image_noffset) 286604f23ddSSimon Glass * | - data = [binary data] 287b2267e8aSAndre Przywara * o hash-1 288604f23ddSSimon Glass * |- algo = "sha1" 289604f23ddSSimon Glass * |- value = sha1(data) 290604f23ddSSimon Glass * 291bbb467dcSSimon Glass * For signature details, please see doc/uImage.FIT/signature.txt 292bbb467dcSSimon Glass * 29356518e71SSimon Glass * @keydir Directory containing *.key and *.crt files (or NULL) 29456518e71SSimon Glass * @keydest FDT Blob to write public keys into (NULL if none) 295bbb467dcSSimon Glass * @fit: Pointer to the FIT format image header 296bbb467dcSSimon Glass * @image_noffset: Requested component image node 29756518e71SSimon Glass * @comment: Comment to add to signature nodes 29856518e71SSimon Glass * @require_keys: Mark all keys as 'required' 299f1ca1fdeSGeorge McCollister * @engine_id: Engine to use for signing 300bbb467dcSSimon Glass * @return: 0 on success, <0 on failure 301604f23ddSSimon Glass */ 30256518e71SSimon Glass int fit_image_add_verification_data(const char *keydir, void *keydest, 30356518e71SSimon Glass void *fit, int image_noffset, const char *comment, 304*795f452eSAlex Kiernan int require_keys, const char *engine_id, const char *cmdname) 305604f23ddSSimon Glass { 306bbb467dcSSimon Glass const char *image_name; 307604f23ddSSimon Glass const void *data; 308604f23ddSSimon Glass size_t size; 309604f23ddSSimon Glass int noffset; 310604f23ddSSimon Glass 311604f23ddSSimon Glass /* Get image data and data length */ 312604f23ddSSimon Glass if (fit_image_get_data(fit, image_noffset, &data, &size)) { 313604f23ddSSimon Glass printf("Can't get image data/size\n"); 314604f23ddSSimon Glass return -1; 315604f23ddSSimon Glass } 316604f23ddSSimon Glass 31794e5fa46SSimon Glass image_name = fit_get_name(fit, image_noffset, NULL); 31894e5fa46SSimon Glass 319604f23ddSSimon Glass /* Process all hash subnodes of the component image node */ 320bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 321bbb467dcSSimon Glass noffset >= 0; 322bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 323bbb467dcSSimon Glass const char *node_name; 324bbb467dcSSimon Glass int ret = 0; 325bbb467dcSSimon Glass 326bbb467dcSSimon Glass /* 327bbb467dcSSimon Glass * Check subnode name, must be equal to "hash" or "signature". 328bbb467dcSSimon Glass * Multiple hash nodes require unique unit node 329b2267e8aSAndre Przywara * names, e.g. hash-1, hash-2, signature-1, etc. 330bbb467dcSSimon Glass */ 331bbb467dcSSimon Glass node_name = fit_get_name(fit, noffset, NULL); 332bbb467dcSSimon Glass if (!strncmp(node_name, FIT_HASH_NODENAME, 333bbb467dcSSimon Glass strlen(FIT_HASH_NODENAME))) { 334bbb467dcSSimon Glass ret = fit_image_process_hash(fit, image_name, noffset, 335bbb467dcSSimon Glass data, size); 33656518e71SSimon Glass } else if (IMAGE_ENABLE_SIGN && keydir && 33756518e71SSimon Glass !strncmp(node_name, FIT_SIG_NODENAME, 33856518e71SSimon Glass strlen(FIT_SIG_NODENAME))) { 33956518e71SSimon Glass ret = fit_image_process_sig(keydir, keydest, 34056518e71SSimon Glass fit, image_name, noffset, data, size, 341*795f452eSAlex Kiernan comment, require_keys, engine_id, cmdname); 342bbb467dcSSimon Glass } 343bbb467dcSSimon Glass if (ret) 3441152a05eSSimon Glass return ret; 345604f23ddSSimon Glass } 346bbb467dcSSimon Glass 347bbb467dcSSimon Glass return 0; 348bbb467dcSSimon Glass } 349bbb467dcSSimon Glass 3504d098529SSimon Glass struct strlist { 3514d098529SSimon Glass int count; 3524d098529SSimon Glass char **strings; 3534d098529SSimon Glass }; 3544d098529SSimon Glass 3554d098529SSimon Glass static void strlist_init(struct strlist *list) 3564d098529SSimon Glass { 3574d098529SSimon Glass memset(list, '\0', sizeof(*list)); 3584d098529SSimon Glass } 3594d098529SSimon Glass 3604d098529SSimon Glass static void strlist_free(struct strlist *list) 3614d098529SSimon Glass { 3624d098529SSimon Glass int i; 3634d098529SSimon Glass 3644d098529SSimon Glass for (i = 0; i < list->count; i++) 3654d098529SSimon Glass free(list->strings[i]); 3664d098529SSimon Glass free(list->strings); 3674d098529SSimon Glass } 3684d098529SSimon Glass 3694d098529SSimon Glass static int strlist_add(struct strlist *list, const char *str) 3704d098529SSimon Glass { 3714d098529SSimon Glass char *dup; 3724d098529SSimon Glass 3734d098529SSimon Glass dup = strdup(str); 3744d098529SSimon Glass list->strings = realloc(list->strings, 3754d098529SSimon Glass (list->count + 1) * sizeof(char *)); 3764d098529SSimon Glass if (!list || !str) 3774d098529SSimon Glass return -1; 3784d098529SSimon Glass list->strings[list->count++] = dup; 3794d098529SSimon Glass 3804d098529SSimon Glass return 0; 3814d098529SSimon Glass } 3824d098529SSimon Glass 3834d098529SSimon Glass static const char *fit_config_get_image_list(void *fit, int noffset, 3844d098529SSimon Glass int *lenp, int *allow_missingp) 3854d098529SSimon Glass { 3864d098529SSimon Glass static const char default_list[] = FIT_KERNEL_PROP "\0" 3874d098529SSimon Glass FIT_FDT_PROP; 3884d098529SSimon Glass const char *prop; 3894d098529SSimon Glass 3904d098529SSimon Glass /* If there is an "image" property, use that */ 3914d098529SSimon Glass prop = fdt_getprop(fit, noffset, "sign-images", lenp); 3924d098529SSimon Glass if (prop) { 3934d098529SSimon Glass *allow_missingp = 0; 3944d098529SSimon Glass return *lenp ? prop : NULL; 3954d098529SSimon Glass } 3964d098529SSimon Glass 3974d098529SSimon Glass /* Default image list */ 3984d098529SSimon Glass *allow_missingp = 1; 3994d098529SSimon Glass *lenp = sizeof(default_list); 4004d098529SSimon Glass 4014d098529SSimon Glass return default_list; 4024d098529SSimon Glass } 4034d098529SSimon Glass 4044d098529SSimon Glass static int fit_config_get_hash_list(void *fit, int conf_noffset, 4054d098529SSimon Glass int sig_offset, struct strlist *node_inc) 4064d098529SSimon Glass { 4074d098529SSimon Glass int allow_missing; 4084d098529SSimon Glass const char *prop, *iname, *end; 4094d098529SSimon Glass const char *conf_name, *sig_name; 4104d098529SSimon Glass char name[200], path[200]; 4114d098529SSimon Glass int image_count; 4124d098529SSimon Glass int ret, len; 4134d098529SSimon Glass 4144d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 4154d098529SSimon Glass sig_name = fit_get_name(fit, sig_offset, NULL); 4164d098529SSimon Glass 4174d098529SSimon Glass /* 4184d098529SSimon Glass * Build a list of nodes we need to hash. We always need the root 4194d098529SSimon Glass * node and the configuration. 4204d098529SSimon Glass */ 4214d098529SSimon Glass strlist_init(node_inc); 4224d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 4234d098529SSimon Glass if (strlist_add(node_inc, "/") || 4244d098529SSimon Glass strlist_add(node_inc, name)) 4254d098529SSimon Glass goto err_mem; 4264d098529SSimon Glass 4274d098529SSimon Glass /* Get a list of images that we intend to sign */ 42866b36f83SHeiko Schocher prop = fit_config_get_image_list(fit, sig_offset, &len, 4294d098529SSimon Glass &allow_missing); 4304d098529SSimon Glass if (!prop) 4314d098529SSimon Glass return 0; 4324d098529SSimon Glass 4334d098529SSimon Glass /* Locate the images */ 4344d098529SSimon Glass end = prop + len; 4354d098529SSimon Glass image_count = 0; 4364d098529SSimon Glass for (iname = prop; iname < end; iname += strlen(iname) + 1) { 4374d098529SSimon Glass int noffset; 4384d098529SSimon Glass int image_noffset; 4394d098529SSimon Glass int hash_count; 4404d098529SSimon Glass 4414d098529SSimon Glass image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 4424d098529SSimon Glass iname); 4434d098529SSimon Glass if (image_noffset < 0) { 4444d098529SSimon Glass printf("Failed to find image '%s' in configuration '%s/%s'\n", 4454d098529SSimon Glass iname, conf_name, sig_name); 4464d098529SSimon Glass if (allow_missing) 4474d098529SSimon Glass continue; 4484d098529SSimon Glass 4494d098529SSimon Glass return -ENOENT; 4504d098529SSimon Glass } 4514d098529SSimon Glass 4524d098529SSimon Glass ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 4534d098529SSimon Glass if (ret < 0) 4544d098529SSimon Glass goto err_path; 4554d098529SSimon Glass if (strlist_add(node_inc, path)) 4564d098529SSimon Glass goto err_mem; 4574d098529SSimon Glass 4584d098529SSimon Glass snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 4594d098529SSimon Glass conf_name); 4604d098529SSimon Glass 4614d098529SSimon Glass /* Add all this image's hashes */ 4624d098529SSimon Glass hash_count = 0; 4634d098529SSimon Glass for (noffset = fdt_first_subnode(fit, image_noffset); 4644d098529SSimon Glass noffset >= 0; 4654d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 4664d098529SSimon Glass const char *name = fit_get_name(fit, noffset, NULL); 4674d098529SSimon Glass 4684d098529SSimon Glass if (strncmp(name, FIT_HASH_NODENAME, 4694d098529SSimon Glass strlen(FIT_HASH_NODENAME))) 4704d098529SSimon Glass continue; 4714d098529SSimon Glass ret = fdt_get_path(fit, noffset, path, sizeof(path)); 4724d098529SSimon Glass if (ret < 0) 4734d098529SSimon Glass goto err_path; 4744d098529SSimon Glass if (strlist_add(node_inc, path)) 4754d098529SSimon Glass goto err_mem; 4764d098529SSimon Glass hash_count++; 4774d098529SSimon Glass } 4784d098529SSimon Glass 4794d098529SSimon Glass if (!hash_count) { 4804d098529SSimon 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", 4814d098529SSimon Glass conf_name, sig_name, iname); 4824d098529SSimon Glass return -ENOMSG; 4834d098529SSimon Glass } 4844d098529SSimon Glass 4854d098529SSimon Glass image_count++; 4864d098529SSimon Glass } 4874d098529SSimon Glass 4884d098529SSimon Glass if (!image_count) { 4894d098529SSimon Glass printf("Failed to find any images for configuration '%s/%s'\n", 4904d098529SSimon Glass conf_name, sig_name); 4914d098529SSimon Glass return -ENOMSG; 4924d098529SSimon Glass } 4934d098529SSimon Glass 4944d098529SSimon Glass return 0; 4954d098529SSimon Glass 4964d098529SSimon Glass err_mem: 4974d098529SSimon Glass printf("Out of memory processing configuration '%s/%s'\n", conf_name, 4984d098529SSimon Glass sig_name); 4994d098529SSimon Glass return -ENOMEM; 5004d098529SSimon Glass 5014d098529SSimon Glass err_path: 5024d098529SSimon Glass printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 5034d098529SSimon Glass iname, conf_name, sig_name, fdt_strerror(ret)); 5044d098529SSimon Glass return -ENOENT; 5054d098529SSimon Glass } 5064d098529SSimon Glass 5074d098529SSimon Glass static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 5084d098529SSimon Glass struct image_region **regionp, int *region_countp, 5094d098529SSimon Glass char **region_propp, int *region_proplen) 5104d098529SSimon Glass { 5114d098529SSimon Glass char * const exc_prop[] = {"data"}; 5124d098529SSimon Glass struct strlist node_inc; 5134d098529SSimon Glass struct image_region *region; 5144d098529SSimon Glass struct fdt_region fdt_regions[100]; 5154d098529SSimon Glass const char *conf_name, *sig_name; 5164d098529SSimon Glass char path[200]; 5174d098529SSimon Glass int count, i; 5184d098529SSimon Glass char *region_prop; 5194d098529SSimon Glass int ret, len; 5204d098529SSimon Glass 5214d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 52216067e6bSMasahiro Yamada sig_name = fit_get_name(fit, noffset, NULL); 5234d098529SSimon Glass debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 5244d098529SSimon Glass 5254d098529SSimon Glass /* Get a list of nodes we want to hash */ 5264d098529SSimon Glass ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 5274d098529SSimon Glass if (ret) 5284d098529SSimon Glass return ret; 5294d098529SSimon Glass 5304d098529SSimon Glass /* Get a list of regions to hash */ 5314d098529SSimon Glass count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 5324d098529SSimon Glass exc_prop, ARRAY_SIZE(exc_prop), 5334d098529SSimon Glass fdt_regions, ARRAY_SIZE(fdt_regions), 5344d098529SSimon Glass path, sizeof(path), 1); 5354d098529SSimon Glass if (count < 0) { 5364d098529SSimon Glass printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 5374d098529SSimon Glass sig_name, fdt_strerror(ret)); 5384d098529SSimon Glass return -EIO; 5394d098529SSimon Glass } 5404d098529SSimon Glass if (count == 0) { 5414d098529SSimon Glass printf("No data to hash for configuration '%s/%s': %s\n", 5424d098529SSimon Glass conf_name, sig_name, fdt_strerror(ret)); 5434d098529SSimon Glass return -EINVAL; 5444d098529SSimon Glass } 5454d098529SSimon Glass 5464d098529SSimon Glass /* Build our list of data blocks */ 5474d098529SSimon Glass region = fit_region_make_list(fit, fdt_regions, count, NULL); 5484d098529SSimon Glass if (!region) { 5494d098529SSimon Glass printf("Out of memory hashing configuration '%s/%s'\n", 5504d098529SSimon Glass conf_name, sig_name); 5514d098529SSimon Glass return -ENOMEM; 5524d098529SSimon Glass } 5534d098529SSimon Glass 5544d098529SSimon Glass /* Create a list of all hashed properties */ 5554d098529SSimon Glass debug("Hash nodes:\n"); 5564d098529SSimon Glass for (i = len = 0; i < node_inc.count; i++) { 5574d098529SSimon Glass debug(" %s\n", node_inc.strings[i]); 5584d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1; 5594d098529SSimon Glass } 5604d098529SSimon Glass region_prop = malloc(len); 5614d098529SSimon Glass if (!region_prop) { 5624d098529SSimon Glass printf("Out of memory setting up regions for configuration '%s/%s'\n", 5634d098529SSimon Glass conf_name, sig_name); 5644d098529SSimon Glass return -ENOMEM; 5654d098529SSimon Glass } 5664d098529SSimon Glass for (i = len = 0; i < node_inc.count; 5674d098529SSimon Glass len += strlen(node_inc.strings[i]) + 1, i++) 5684d098529SSimon Glass strcpy(region_prop + len, node_inc.strings[i]); 5694d098529SSimon Glass strlist_free(&node_inc); 5704d098529SSimon Glass 5714d098529SSimon Glass *region_countp = count; 5724d098529SSimon Glass *regionp = region; 5734d098529SSimon Glass *region_propp = region_prop; 5744d098529SSimon Glass *region_proplen = len; 5754d098529SSimon Glass 5764d098529SSimon Glass return 0; 5774d098529SSimon Glass } 5784d098529SSimon Glass 5794d098529SSimon Glass static int fit_config_process_sig(const char *keydir, void *keydest, 5804d098529SSimon Glass void *fit, const char *conf_name, int conf_noffset, 581f1ca1fdeSGeorge McCollister int noffset, const char *comment, int require_keys, 582*795f452eSAlex Kiernan const char *engine_id, const char *cmdname) 5834d098529SSimon Glass { 5844d098529SSimon Glass struct image_sign_info info; 5854d098529SSimon Glass const char *node_name; 5864d098529SSimon Glass struct image_region *region; 5874d098529SSimon Glass char *region_prop; 5884d098529SSimon Glass int region_proplen; 5894d098529SSimon Glass int region_count; 5904d098529SSimon Glass uint8_t *value; 5914d098529SSimon Glass uint value_len; 5924d098529SSimon Glass int ret; 5934d098529SSimon Glass 5944d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 5954d098529SSimon Glass if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 5964d098529SSimon Glass ®ion_count, ®ion_prop, ®ion_proplen)) 5974d098529SSimon Glass return -1; 5984d098529SSimon Glass 5994d098529SSimon Glass if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 600f1ca1fdeSGeorge McCollister require_keys ? "conf" : NULL, engine_id)) 6014d098529SSimon Glass return -1; 6024d098529SSimon Glass 60383dd98e0SAndrew Duda ret = info.crypto->sign(&info, region, region_count, &value, 6040c1d74fdSAndrew Duda &value_len); 6054d098529SSimon Glass free(region); 6064d098529SSimon Glass if (ret) { 6074d098529SSimon Glass printf("Failed to sign '%s' signature node in '%s' conf node\n", 6084d098529SSimon Glass node_name, conf_name); 6094d098529SSimon Glass 6104d098529SSimon Glass /* We allow keys to be missing */ 6114d098529SSimon Glass if (ret == -ENOENT) 6124d098529SSimon Glass return 0; 6134d098529SSimon Glass return -1; 6144d098529SSimon Glass } 6154d098529SSimon Glass 616a9468115SSimon Glass ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 617*795f452eSAlex Kiernan region_prop, region_proplen, cmdname); 618a9468115SSimon Glass if (ret) { 619a9468115SSimon Glass if (ret == -FDT_ERR_NOSPACE) 620a9468115SSimon Glass return -ENOSPC; 621a9468115SSimon Glass printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n", 622a9468115SSimon Glass node_name, conf_name, fdt_strerror(ret)); 6234d098529SSimon Glass return -1; 6244d098529SSimon Glass } 6254d098529SSimon Glass free(value); 6264d098529SSimon Glass free(region_prop); 6274d098529SSimon Glass 6284d098529SSimon Glass /* Get keyname again, as FDT has changed and invalidated our pointer */ 6294d098529SSimon Glass info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 6304d098529SSimon Glass 6314d098529SSimon Glass /* Write the public key into the supplied FDT file */ 632a9468115SSimon Glass if (keydest) { 63383dd98e0SAndrew Duda ret = info.crypto->add_verify_data(&info, keydest); 634a9468115SSimon Glass if (ret) { 63576b9cbabSMasahiro Yamada printf("Failed to add verification data for '%s' signature node in '%s' configuration node\n", 6364d098529SSimon Glass node_name, conf_name); 637a9468115SSimon Glass } 638597a8b2cSSimon Glass return ret; 6394d098529SSimon Glass } 6404d098529SSimon Glass 6414d098529SSimon Glass return 0; 6424d098529SSimon Glass } 6434d098529SSimon Glass 6444d098529SSimon Glass static int fit_config_add_verification_data(const char *keydir, void *keydest, 6454d098529SSimon Glass void *fit, int conf_noffset, const char *comment, 646*795f452eSAlex Kiernan int require_keys, const char *engine_id, const char *cmdname) 6474d098529SSimon Glass { 6484d098529SSimon Glass const char *conf_name; 6494d098529SSimon Glass int noffset; 6504d098529SSimon Glass 6514d098529SSimon Glass conf_name = fit_get_name(fit, conf_noffset, NULL); 6524d098529SSimon Glass 6534d098529SSimon Glass /* Process all hash subnodes of the configuration node */ 6544d098529SSimon Glass for (noffset = fdt_first_subnode(fit, conf_noffset); 6554d098529SSimon Glass noffset >= 0; 6564d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 6574d098529SSimon Glass const char *node_name; 6584d098529SSimon Glass int ret = 0; 6594d098529SSimon Glass 6604d098529SSimon Glass node_name = fit_get_name(fit, noffset, NULL); 6614d098529SSimon Glass if (!strncmp(node_name, FIT_SIG_NODENAME, 6624d098529SSimon Glass strlen(FIT_SIG_NODENAME))) { 6634d098529SSimon Glass ret = fit_config_process_sig(keydir, keydest, 6644d098529SSimon Glass fit, conf_name, conf_noffset, noffset, comment, 665*795f452eSAlex Kiernan require_keys, engine_id, cmdname); 6664d098529SSimon Glass } 6674d098529SSimon Glass if (ret) 6684d098529SSimon Glass return ret; 6694d098529SSimon Glass } 6704d098529SSimon Glass 6714d098529SSimon Glass return 0; 6724d098529SSimon Glass } 6734d098529SSimon Glass 67456518e71SSimon Glass int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 675f1ca1fdeSGeorge McCollister const char *comment, int require_keys, 676*795f452eSAlex Kiernan const char *engine_id, const char *cmdname) 677bbb467dcSSimon Glass { 6784d098529SSimon Glass int images_noffset, confs_noffset; 679bbb467dcSSimon Glass int noffset; 680bbb467dcSSimon Glass int ret; 681bbb467dcSSimon Glass 682bbb467dcSSimon Glass /* Find images parent node offset */ 683bbb467dcSSimon Glass images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 684bbb467dcSSimon Glass if (images_noffset < 0) { 685bbb467dcSSimon Glass printf("Can't find images parent node '%s' (%s)\n", 686bbb467dcSSimon Glass FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 687bbb467dcSSimon Glass return images_noffset; 688bbb467dcSSimon Glass } 689bbb467dcSSimon Glass 690bbb467dcSSimon Glass /* Process its subnodes, print out component images details */ 691bbb467dcSSimon Glass for (noffset = fdt_first_subnode(fit, images_noffset); 692bbb467dcSSimon Glass noffset >= 0; 693bbb467dcSSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 694bbb467dcSSimon Glass /* 695bbb467dcSSimon Glass * Direct child node of the images parent node, 696bbb467dcSSimon Glass * i.e. component image node. 697bbb467dcSSimon Glass */ 69856518e71SSimon Glass ret = fit_image_add_verification_data(keydir, keydest, 699*795f452eSAlex Kiernan fit, noffset, comment, require_keys, engine_id, 700*795f452eSAlex Kiernan cmdname); 701bbb467dcSSimon Glass if (ret) 702bbb467dcSSimon Glass return ret; 703604f23ddSSimon Glass } 704604f23ddSSimon Glass 7054d098529SSimon Glass /* If there are no keys, we can't sign configurations */ 7064d098529SSimon Glass if (!IMAGE_ENABLE_SIGN || !keydir) 7074d098529SSimon Glass return 0; 7084d098529SSimon Glass 7094d098529SSimon Glass /* Find configurations parent node offset */ 7104d098529SSimon Glass confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 7114d098529SSimon Glass if (confs_noffset < 0) { 7124d098529SSimon Glass printf("Can't find images parent node '%s' (%s)\n", 71304a710a5SHeiko Schocher FIT_CONFS_PATH, fdt_strerror(confs_noffset)); 7144d098529SSimon Glass return -ENOENT; 7154d098529SSimon Glass } 7164d098529SSimon Glass 7174d098529SSimon Glass /* Process its subnodes, print out component images details */ 7184d098529SSimon Glass for (noffset = fdt_first_subnode(fit, confs_noffset); 7194d098529SSimon Glass noffset >= 0; 7204d098529SSimon Glass noffset = fdt_next_subnode(fit, noffset)) { 7214d098529SSimon Glass ret = fit_config_add_verification_data(keydir, keydest, 7224d098529SSimon Glass fit, noffset, comment, 723f1ca1fdeSGeorge McCollister require_keys, 724*795f452eSAlex Kiernan engine_id, cmdname); 7254d098529SSimon Glass if (ret) 7264d098529SSimon Glass return ret; 7274d098529SSimon Glass } 7284d098529SSimon Glass 729604f23ddSSimon Glass return 0; 730604f23ddSSimon Glass } 73129a23f9dSHeiko Schocher 73229a23f9dSHeiko Schocher #ifdef CONFIG_FIT_SIGNATURE 733ce1400f6SSimon Glass int fit_check_sign(const void *fit, const void *key) 73429a23f9dSHeiko Schocher { 73529a23f9dSHeiko Schocher int cfg_noffset; 73629a23f9dSHeiko Schocher int ret; 73729a23f9dSHeiko Schocher 738ce1400f6SSimon Glass cfg_noffset = fit_conf_get_node(fit, NULL); 73929a23f9dSHeiko Schocher if (!cfg_noffset) 74029a23f9dSHeiko Schocher return -1; 74129a23f9dSHeiko Schocher 742ce1400f6SSimon Glass printf("Verifying Hash Integrity ... "); 743ce1400f6SSimon Glass ret = fit_config_verify(fit, cfg_noffset); 744ce1400f6SSimon Glass if (ret) 745ce1400f6SSimon Glass return ret; 746ce1400f6SSimon Glass ret = bootm_host_load_images(fit, cfg_noffset); 747ce1400f6SSimon Glass 74829a23f9dSHeiko Schocher return ret; 74929a23f9dSHeiko Schocher } 75029a23f9dSHeiko Schocher #endif 751