+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*
*
* (C) Copyright 2000-2006
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include "mkimage.h"
#include <bootm.h>
+#include <fdt_region.h>
#include <image.h>
#include <version.h>
*/
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;
}
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) {
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)) {
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;
* @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;
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);
}
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;
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;
}
*
* 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)
*
* @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;
/*
* 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,
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 ret;
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 */
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;
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",
}
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;
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;
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;
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;
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;
* 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;
}
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;
}
}
#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;