X-Git-Url: https://git.librecmc.org/?p=oweals%2Fu-boot.git;a=blobdiff_plain;f=tools%2Fimage-host.c;h=9a83b7f6755f89c6b202897d7487fcdbe687a891;hp=0eff720b62178972aa92290aea457590c8c42b56;hb=35c2683f46bdea96f1dfce404aee4369a824b68e;hpb=d6694aff569a0838a9d0ef352128f5aa309d73ff diff --git a/tools/image-host.c b/tools/image-host.c index 0eff720b62..9a83b7f675 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2013, Google Inc. * @@ -5,12 +6,11 @@ * * (C) Copyright 2000-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ */ #include "mkimage.h" #include +#include #include #include @@ -38,7 +38,7 @@ static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, printf("Can't set hash '%s' property for '%s' node(%s)\n", FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), fdt_strerror(ret)); - return -1; + return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; } return 0; @@ -64,25 +64,27 @@ static int fit_image_process_hash(void *fit, const char *image_name, const char *node_name; int value_len; char *algo; + int ret; node_name = fit_get_name(fit, noffset, NULL); if (fit_image_hash_get_algo(fit, noffset, &algo)) { printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", node_name, image_name); - return -1; + return -ENOENT; } if (calculate_hash(data, size, algo, value, &value_len)) { printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", algo, node_name, image_name); - return -1; + return -EPROTONOSUPPORT; } - if (fit_set_hash_value(fit, noffset, value, value_len)) { + ret = fit_set_hash_value(fit, noffset, value, value_len); + if (ret) { printf("Can't set hash value for '%s' hash node in '%s' image node\n", node_name, image_name); - return -1; + return ret; } return 0; @@ -105,7 +107,7 @@ static int fit_image_process_hash(void *fit, const char *image_name, */ static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, int value_len, const char *comment, const char *region_prop, - int region_proplen) + int region_proplen, const char *cmdname) { int string_size; int ret; @@ -127,13 +129,18 @@ static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, } if (comment && !ret) ret = fdt_setprop_string(fit, noffset, "comment", comment); - if (!ret) - ret = fit_set_timestamp(fit, noffset, time(NULL)); + if (!ret) { + time_t timestamp = imagetool_get_source_date(cmdname, + time(NULL)); + + ret = fit_set_timestamp(fit, noffset, timestamp); + } if (region_prop && !ret) { uint32_t strdata[2]; ret = fdt_setprop(fit, noffset, "hashed-nodes", region_prop, region_proplen); + /* This is a legacy offset, it is unused, and must remain 0. */ strdata[0] = 0; strdata[1] = cpu_to_fdt32(string_size); if (!ret) { @@ -147,10 +154,11 @@ static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, static int fit_image_setup_sig(struct image_sign_info *info, const char *keydir, void *fit, const char *image_name, - int noffset, const char *require_keys) + int noffset, const char *require_keys, const char *engine_id) { const char *node_name; char *algo_name; + const char *padding_name; node_name = fit_get_name(fit, noffset, NULL); if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { @@ -159,14 +167,20 @@ static int fit_image_setup_sig(struct image_sign_info *info, return -1; } + padding_name = fdt_getprop(fit, noffset, "padding", NULL); + memset(info, '\0', sizeof(*info)); info->keydir = keydir; - info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); info->fit = fit; info->node_offset = noffset; - info->algo = image_get_sig_algo(algo_name); + info->name = strdup(algo_name); + info->checksum = image_get_checksum_algo(algo_name); + info->crypto = image_get_crypto_algo(algo_name); + info->padding = image_get_padding_algo(padding_name); info->require_keys = require_keys; - if (!info->algo) { + info->engine_id = engine_id; + if (!info->checksum || !info->crypto) { printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", algo_name, node_name, image_name); return -1; @@ -190,12 +204,14 @@ static int fit_image_setup_sig(struct image_sign_info *info, * @size: size of data in bytes * @comment: Comment to add to signature nodes * @require_keys: Mark all keys as 'required' + * @engine_id: Engine to use for signing * @return 0 if ok, -1 on error */ static int fit_image_process_sig(const char *keydir, void *keydest, void *fit, const char *image_name, int noffset, const void *data, size_t size, - const char *comment, int require_keys) + const char *comment, int require_keys, const char *engine_id, + const char *cmdname) { struct image_sign_info info; struct image_region region; @@ -205,13 +221,13 @@ static int fit_image_process_sig(const char *keydir, void *keydest, int ret; if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, - require_keys ? "image" : NULL)) + require_keys ? "image" : NULL, engine_id)) return -1; node_name = fit_get_name(fit, noffset, NULL); region.data = data; region.size = size; - ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); + ret = info.crypto->sign(&info, ®ion, 1, &value, &value_len); if (ret) { printf("Failed to sign '%s' signature node in '%s' image node: %d\n", node_name, image_name, ret); @@ -223,7 +239,7 @@ static int fit_image_process_sig(const char *keydir, void *keydest, } ret = fit_image_write_sig(fit, noffset, value, value_len, comment, - NULL, 0); + NULL, 0, cmdname); if (ret) { if (ret == -FDT_ERR_NOSPACE) return -ENOSPC; @@ -234,15 +250,278 @@ static int fit_image_process_sig(const char *keydir, void *keydest, free(value); /* Get keyname again, as FDT has changed and invalidated our pointer */ - info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); - /* Write the public key into the supplied FDT file */ - if (keydest && info.algo->add_verify_data(&info, keydest)) { - printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + /* + * Write the public key into the supplied FDT file; this might fail + * several times, since we try signing with successively increasing + * size values + */ + if (keydest) { + ret = info.crypto->add_verify_data(&info, keydest); + if (ret) { + printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + node_name, image_name); + return ret; + } + } + + return 0; +} + +static int fit_image_read_data(char *filename, unsigned char *data, + int expected_size) +{ + struct stat sbuf; + int fd, ret = -1; + ssize_t n; + + /* Open file */ + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + printf("Can't open file %s (err=%d => %s)\n", + filename, errno, strerror(errno)); + return -1; + } + + /* Compute file size */ + if (fstat(fd, &sbuf) < 0) { + printf("Can't fstat file %s (err=%d => %s)\n", + filename, errno, strerror(errno)); + goto err; + } + + /* Check file size */ + if (sbuf.st_size != expected_size) { + printf("File %s don't have the expected size (size=%ld, expected=%d)\n", + filename, sbuf.st_size, expected_size); + goto err; + } + + /* Read data */ + n = read(fd, data, sbuf.st_size); + if (n < 0) { + printf("Can't read file %s (err=%d => %s)\n", + filename, errno, strerror(errno)); + goto err; + } + + /* Check that we have read all the file */ + if (n != sbuf.st_size) { + printf("Can't read all file %s (read %zd bytes, expexted %ld)\n", + filename, n, sbuf.st_size); + goto err; + } + + ret = 0; + +err: + close(fd); + return ret; +} + +static int fit_image_setup_cipher(struct image_cipher_info *info, + const char *keydir, void *fit, + const char *image_name, int image_noffset, + const char *node_name, int noffset) +{ + char *algo_name; + char filename[128]; + int ret = -1; + + if (fit_image_cipher_get_algo(fit, noffset, &algo_name)) { + printf("Can't get algo name for cipher '%s' in image '%s'\n", node_name, image_name); + goto out; + } + + info->keydir = keydir; + + /* Read the key name */ + info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); + if (!info->keyname) { + printf("Can't get key name for cipher '%s' in image '%s'\n", + node_name, image_name); + goto out; + } + + /* Read the IV name */ + info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL); + if (!info->ivname) { + printf("Can't get iv name for cipher '%s' in image '%s'\n", + node_name, image_name); + goto out; + } + + info->fit = fit; + info->node_noffset = noffset; + info->name = algo_name; + + info->cipher = image_get_cipher_algo(algo_name); + if (!info->cipher) { + printf("Can't get algo for cipher '%s'\n", image_name); + goto out; + } + + /* Read the key in the file */ + snprintf(filename, sizeof(filename), "%s/%s%s", + info->keydir, info->keyname, ".bin"); + info->key = malloc(info->cipher->key_len); + if (!info->key) { + printf("Can't allocate memory for key\n"); + ret = -1; + goto out; + } + ret = fit_image_read_data(filename, (unsigned char *)info->key, + info->cipher->key_len); + if (ret < 0) + goto out; + + /* Read the IV in the file */ + snprintf(filename, sizeof(filename), "%s/%s%s", + info->keydir, info->ivname, ".bin"); + info->iv = malloc(info->cipher->iv_len); + if (!info->iv) { + printf("Can't allocate memory for iv\n"); + ret = -1; + goto out; + } + ret = fit_image_read_data(filename, (unsigned char *)info->iv, + info->cipher->iv_len); + + out: + return ret; +} + +int fit_image_write_cipher(void *fit, int image_noffset, int noffset, + const void *data, size_t size, + unsigned char *data_ciphered, int data_ciphered_len) +{ + int ret = -1; + + /* Remove unciphered data */ + ret = fdt_delprop(fit, image_noffset, FIT_DATA_PROP); + if (ret) { + printf("Can't remove data (err = %d)\n", ret); + goto out; + } + + /* Add ciphered data */ + ret = fdt_setprop(fit, image_noffset, FIT_DATA_PROP, + data_ciphered, data_ciphered_len); + if (ret) { + printf("Can't add ciphered data (err = %d)\n", ret); + goto out; + } + + /* add non ciphered data size */ + ret = fdt_setprop_u32(fit, image_noffset, "data-size-unciphered", size); + if (ret) { + printf("Can't add unciphered data size (err = %d)\n", ret); + goto out; + } + + out: + return ret; +} + +static int +fit_image_process_cipher(const char *keydir, void *keydest, void *fit, + const char *image_name, int image_noffset, + const char *node_name, int node_noffset, + const void *data, size_t size, + const char *cmdname) +{ + struct image_cipher_info info; + unsigned char *data_ciphered = NULL; + int data_ciphered_len; + int ret; + + memset(&info, 0, sizeof(info)); + + ret = fit_image_setup_cipher(&info, keydir, fit, image_name, + image_noffset, node_name, node_noffset); + if (ret) + goto out; + + ret = info.cipher->encrypt(&info, data, size, + &data_ciphered, &data_ciphered_len); + if (ret) + goto out; + + /* + * Write the public key into the supplied FDT file; this might fail + * several times, since we try signing with successively increasing + * size values + */ + if (keydest) { + ret = info.cipher->add_cipher_data(&info, keydest); + if (ret) { + printf("Failed to add verification data for cipher '%s' in image '%s'\n", + info.keyname, image_name); + goto out; + } + } + + ret = fit_image_write_cipher(fit, image_noffset, node_noffset, + data, size, + data_ciphered, data_ciphered_len); + + out: + free(data_ciphered); + free((void *)info.key); + free((void *)info.iv); + return ret; +} + +int fit_image_cipher_data(const char *keydir, void *keydest, + void *fit, int image_noffset, const char *comment, + int require_keys, const char *engine_id, + const char *cmdname) +{ + const char *image_name; + const void *data; + size_t size; + int node_noffset; + + /* Get image name */ + image_name = fit_get_name(fit, image_noffset, NULL); + if (!image_name) { + printf("Can't get image name\n"); return -1; } + /* Get image data and data length */ + if (fit_image_get_data(fit, image_noffset, &data, &size)) { + printf("Can't get image data/size\n"); + return -1; + } + + /* Process all hash subnodes of the component image node */ + for (node_noffset = fdt_first_subnode(fit, image_noffset); + node_noffset >= 0; + node_noffset = fdt_next_subnode(fit, node_noffset)) { + const char *node_name; + int ret = 0; + + node_name = fit_get_name(fit, node_noffset, NULL); + if (!node_name) { + printf("Can't get node name\n"); + return -1; + } + + if (IMAGE_ENABLE_ENCRYPT && keydir && + !strncmp(node_name, FIT_CIPHER_NODENAME, + strlen(FIT_CIPHER_NODENAME))) + ret = fit_image_process_cipher(keydir, keydest, + fit, image_name, + image_noffset, + node_name, node_noffset, + data, size, cmdname); + if (ret) + return ret; + } + return 0; } @@ -257,16 +536,16 @@ static int fit_image_process_sig(const char *keydir, void *keydest, * * Input component image node structure: * - * o image@1 (at image_noffset) + * o image-1 (at image_noffset) * | - data = [binary data] - * o hash@1 + * o hash-1 * |- algo = "sha1" * * Output component image node structure: * - * o image@1 (at image_noffset) + * o image-1 (at image_noffset) * | - data = [binary data] - * o hash@1 + * o hash-1 * |- algo = "sha1" * |- value = sha1(data) * @@ -278,11 +557,12 @@ static int fit_image_process_sig(const char *keydir, void *keydest, * @image_noffset: Requested component image node * @comment: Comment to add to signature nodes * @require_keys: Mark all keys as 'required' + * @engine_id: Engine to use for signing * @return: 0 on success, <0 on failure */ int fit_image_add_verification_data(const char *keydir, void *keydest, void *fit, int image_noffset, const char *comment, - int require_keys) + int require_keys, const char *engine_id, const char *cmdname) { const char *image_name; const void *data; @@ -307,7 +587,7 @@ int fit_image_add_verification_data(const char *keydir, void *keydest, /* * Check subnode name, must be equal to "hash" or "signature". * Multiple hash nodes require unique unit node - * names, e.g. hash@1, hash@2, signature@1, etc. + * names, e.g. hash-1, hash-2, signature-1, etc. */ node_name = fit_get_name(fit, noffset, NULL); if (!strncmp(node_name, FIT_HASH_NODENAME, @@ -319,10 +599,10 @@ int fit_image_add_verification_data(const char *keydir, void *keydest, strlen(FIT_SIG_NODENAME))) { ret = fit_image_process_sig(keydir, keydest, fit, image_name, noffset, data, size, - comment, require_keys); + comment, require_keys, engine_id, cmdname); } if (ret) - return -1; + return ret; } return 0; @@ -500,7 +780,7 @@ static int fit_config_get_data(void *fit, int conf_noffset, int noffset, int ret, len; conf_name = fit_get_name(fit, conf_noffset, NULL); - sig_name = fit_get_name(fit, conf_noffset, NULL); + sig_name = fit_get_name(fit, noffset, NULL); debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); /* Get a list of nodes we want to hash */ @@ -559,7 +839,8 @@ static int fit_config_get_data(void *fit, int conf_noffset, int noffset, static int fit_config_process_sig(const char *keydir, void *keydest, void *fit, const char *conf_name, int conf_noffset, - int noffset, const char *comment, int require_keys) + int noffset, const char *comment, int require_keys, + const char *engine_id, const char *cmdname) { struct image_sign_info info; const char *node_name; @@ -577,10 +858,11 @@ static int fit_config_process_sig(const char *keydir, void *keydest, return -1; if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, - require_keys ? "conf" : NULL)) + require_keys ? "conf" : NULL, engine_id)) return -1; - ret = info.algo->sign(&info, region, region_count, &value, &value_len); + ret = info.crypto->sign(&info, region, region_count, &value, + &value_len); free(region); if (ret) { printf("Failed to sign '%s' signature node in '%s' conf node\n", @@ -593,7 +875,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest, } ret = fit_image_write_sig(fit, noffset, value, value_len, comment, - region_prop, region_proplen); + region_prop, region_proplen, cmdname); if (ret) { if (ret == -FDT_ERR_NOSPACE) return -ENOSPC; @@ -605,15 +887,13 @@ static int fit_config_process_sig(const char *keydir, void *keydest, free(region_prop); /* Get keyname again, as FDT has changed and invalidated our pointer */ - info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL); /* Write the public key into the supplied FDT file */ if (keydest) { - ret = info.algo->add_verify_data(&info, keydest); - if (ret == -ENOSPC) - return -ENOSPC; + ret = info.crypto->add_verify_data(&info, keydest); if (ret) { - printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + printf("Failed to add verification data for '%s' signature node in '%s' configuration node\n", node_name, conf_name); } return ret; @@ -624,7 +904,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest, static int fit_config_add_verification_data(const char *keydir, void *keydest, void *fit, int conf_noffset, const char *comment, - int require_keys) + int require_keys, const char *engine_id, const char *cmdname) { const char *conf_name; int noffset; @@ -643,7 +923,7 @@ static int fit_config_add_verification_data(const char *keydir, void *keydest, strlen(FIT_SIG_NODENAME))) { ret = fit_config_process_sig(keydir, keydest, fit, conf_name, conf_noffset, noffset, comment, - require_keys); + require_keys, engine_id, cmdname); } if (ret) return ret; @@ -652,8 +932,44 @@ static int fit_config_add_verification_data(const char *keydir, void *keydest, return 0; } +int fit_cipher_data(const char *keydir, void *keydest, void *fit, + const char *comment, int require_keys, + const char *engine_id, const char *cmdname) +{ + int images_noffset; + int noffset; + int ret; + + /* Find images parent node offset */ + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images_noffset < 0) { + printf("Can't find images parent node '%s' (%s)\n", + FIT_IMAGES_PATH, fdt_strerror(images_noffset)); + return images_noffset; + } + + /* Process its subnodes, print out component images details */ + for (noffset = fdt_first_subnode(fit, images_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + /* + * Direct child node of the images parent node, + * i.e. component image node. + */ + ret = fit_image_cipher_data(keydir, keydest, + fit, noffset, comment, + require_keys, engine_id, + cmdname); + if (ret) + return ret; + } + + return 0; +} + int fit_add_verification_data(const char *keydir, void *keydest, void *fit, - const char *comment, int require_keys) + const char *comment, int require_keys, + const char *engine_id, const char *cmdname) { int images_noffset, confs_noffset; int noffset; @@ -676,7 +992,8 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit, * i.e. component image node. */ ret = fit_image_add_verification_data(keydir, keydest, - fit, noffset, comment, require_keys); + fit, noffset, comment, require_keys, engine_id, + cmdname); if (ret) return ret; } @@ -689,7 +1006,7 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit, confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); if (confs_noffset < 0) { printf("Can't find images parent node '%s' (%s)\n", - FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); + FIT_CONFS_PATH, fdt_strerror(confs_noffset)); return -ENOENT; } @@ -699,7 +1016,8 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit, noffset = fdt_next_subnode(fit, noffset)) { ret = fit_config_add_verification_data(keydir, keydest, fit, noffset, comment, - require_keys); + require_keys, + engine_id, cmdname); if (ret) return ret; } @@ -708,19 +1026,22 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit, } #ifdef CONFIG_FIT_SIGNATURE -int fit_check_sign(const void *fit, const void *key) +int fit_check_sign(const void *fit, const void *key, + const char *fit_uname_config) { int cfg_noffset; int ret; - cfg_noffset = fit_conf_get_node(fit, NULL); + cfg_noffset = fit_conf_get_node(fit, fit_uname_config); if (!cfg_noffset) return -1; - printf("Verifying Hash Integrity ... "); + printf("Verifying Hash Integrity for node '%s'... ", + fdt_get_name(fit, cfg_noffset, NULL)); ret = fit_config_verify(fit, cfg_noffset); if (ret) return ret; + printf("Verified OK, loading images\n"); ret = bootm_host_load_images(fit, cfg_noffset); return ret;