blob: 14e8bd52a657dd3f74e851a52f5a8946f2b95308 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass10a1eca2013-05-07 06:11:54 +00002/*
3 * Copyright (c) 2013, Google Inc.
4 *
5 * (C) Copyright 2008 Semihalf
6 *
7 * (C) Copyright 2000-2006
8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Simon Glass10a1eca2013-05-07 06:11:54 +00009 */
10
11#include "mkimage.h"
Simon Glassa51991d2014-06-12 07:24:53 -060012#include <bootm.h>
Masahiro Yamada6dd10522020-04-16 18:30:18 +090013#include <fdt_region.h>
Simon Glass10a1eca2013-05-07 06:11:54 +000014#include <image.h>
Simon Glassfbabc0f2013-06-13 15:10:01 -070015#include <version.h>
Simon Glass10a1eca2013-05-07 06:11:54 +000016
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +010017#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
Philippe Reynes3e3899c2022-03-28 22:57:02 +020018#include <openssl/pem.h>
19#include <openssl/evp.h>
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +010020#endif
Philippe Reynes3e3899c2022-03-28 22:57:02 +020021
Simon Glass10a1eca2013-05-07 06:11:54 +000022/**
Simon Glass0ce6e3d2013-05-07 06:11:56 +000023 * fit_set_hash_value - set hash value in requested has node
24 * @fit: pointer to the FIT format image header
25 * @noffset: hash node offset
26 * @value: hash value to be set
27 * @value_len: hash value length
28 *
29 * fit_set_hash_value() attempts to set hash value in a node at offset
30 * given and returns operation status to the caller.
31 *
32 * returns
33 * 0, on success
34 * -1, on failure
35 */
36static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
37 int value_len)
38{
39 int ret;
40
41 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
42 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030043 fprintf(stderr, "Can't set hash '%s' property for '%s' node(%s)\n",
44 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
45 fdt_strerror(ret));
Simon Glassec539f72016-07-03 09:40:44 -060046 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
Simon Glass0ce6e3d2013-05-07 06:11:56 +000047 }
48
49 return 0;
50}
51
52/**
Simon Glass25d6e6b2013-05-07 06:11:55 +000053 * fit_image_process_hash - Process a single subnode of the images/ node
54 *
55 * Check each subnode and process accordingly. For hash nodes we generate
Simon Glass6a0efc82021-11-12 12:28:06 -070056 * a hash of the supplied data and store it in the node.
Simon Glass25d6e6b2013-05-07 06:11:55 +000057 *
58 * @fit: pointer to the FIT format image header
Simon Glass6a0efc82021-11-12 12:28:06 -070059 * @image_name: name of image being processed (used to display errors)
Simon Glass25d6e6b2013-05-07 06:11:55 +000060 * @noffset: subnode offset
61 * @data: data to process
62 * @size: size of data in bytes
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010063 * Return: 0 if ok, -1 on error
Simon Glass25d6e6b2013-05-07 06:11:55 +000064 */
65static int fit_image_process_hash(void *fit, const char *image_name,
66 int noffset, const void *data, size_t size)
67{
68 uint8_t value[FIT_MAX_HASH_LEN];
Simon Glassee382652013-05-07 06:12:01 +000069 const char *node_name;
Simon Glass25d6e6b2013-05-07 06:11:55 +000070 int value_len;
Jan Kiszka27beec22022-01-14 10:21:17 +010071 const char *algo;
Simon Glassec539f72016-07-03 09:40:44 -060072 int ret;
Simon Glass25d6e6b2013-05-07 06:11:55 +000073
Simon Glassee382652013-05-07 06:12:01 +000074 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass25d6e6b2013-05-07 06:11:55 +000075
76 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030077 fprintf(stderr,
78 "Can't get hash algo property for '%s' hash node in '%s' image node\n",
79 node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060080 return -ENOENT;
Simon Glass25d6e6b2013-05-07 06:11:55 +000081 }
82
83 if (calculate_hash(data, size, algo, value, &value_len)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030084 fprintf(stderr,
85 "Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
86 algo, node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060087 return -EPROTONOSUPPORT;
Simon Glass25d6e6b2013-05-07 06:11:55 +000088 }
89
Simon Glassec539f72016-07-03 09:40:44 -060090 ret = fit_set_hash_value(fit, noffset, value, value_len);
91 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030092 fprintf(stderr, "Can't set hash value for '%s' hash node in '%s' image node\n",
93 node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060094 return ret;
Simon Glass25d6e6b2013-05-07 06:11:55 +000095 }
96
97 return 0;
98}
99
100/**
Simon Glassfbabc0f2013-06-13 15:10:01 -0700101 * fit_image_write_sig() - write the signature to a FIT
Simon Glass10a1eca2013-05-07 06:11:54 +0000102 *
Simon Glassfbabc0f2013-06-13 15:10:01 -0700103 * This writes the signature and signer data to the FIT.
104 *
105 * @fit: pointer to the FIT format image header
106 * @noffset: hash node offset
107 * @value: signature value to be set
108 * @value_len: signature value length
109 * @comment: Text comment to write (NULL for none)
110 *
111 * returns
112 * 0, on success
113 * -FDT_ERR_..., on failure
114 */
115static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
116 int value_len, const char *comment, const char *region_prop,
Jan Kiszka4043f322022-01-14 10:21:19 +0100117 int region_proplen, const char *cmdname, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700118{
119 int string_size;
120 int ret;
121
122 /*
123 * Get the current string size, before we update the FIT and add
124 * more
125 */
126 string_size = fdt_size_dt_strings(fit);
127
128 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
129 if (!ret) {
130 ret = fdt_setprop_string(fit, noffset, "signer-name",
131 "mkimage");
132 }
133 if (!ret) {
134 ret = fdt_setprop_string(fit, noffset, "signer-version",
135 PLAIN_VERSION);
136 }
137 if (comment && !ret)
138 ret = fdt_setprop_string(fit, noffset, "comment", comment);
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000139 if (!ret) {
140 time_t timestamp = imagetool_get_source_date(cmdname,
141 time(NULL));
Ming Liuf75f1d72021-05-31 09:04:51 +0200142 uint32_t t = cpu_to_uimage(timestamp);
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000143
Ming Liuf75f1d72021-05-31 09:04:51 +0200144 ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
145 sizeof(uint32_t));
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000146 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700147 if (region_prop && !ret) {
148 uint32_t strdata[2];
149
150 ret = fdt_setprop(fit, noffset, "hashed-nodes",
151 region_prop, region_proplen);
Teddy Reed9767bf42018-06-09 11:45:20 -0400152 /* This is a legacy offset, it is unused, and must remain 0. */
Simon Glassfbabc0f2013-06-13 15:10:01 -0700153 strdata[0] = 0;
154 strdata[1] = cpu_to_fdt32(string_size);
155 if (!ret) {
156 ret = fdt_setprop(fit, noffset, "hashed-strings",
157 strdata, sizeof(strdata));
158 }
159 }
Jan Kiszka4043f322022-01-14 10:21:19 +0100160 if (algo_name && !ret)
161 ret = fdt_setprop_string(fit, noffset, "algo", algo_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700162
163 return ret;
164}
165
166static int fit_image_setup_sig(struct image_sign_info *info,
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600167 const char *keydir, const char *keyfile, void *fit,
168 const char *image_name, int noffset, const char *require_keys,
Jan Kiszka4043f322022-01-14 10:21:19 +0100169 const char *engine_id, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700170{
171 const char *node_name;
Philippe Reynes12468352018-11-14 13:51:00 +0100172 const char *padding_name;
Simon Glassfbabc0f2013-06-13 15:10:01 -0700173
174 node_name = fit_get_name(fit, noffset, NULL);
Jan Kiszka4043f322022-01-14 10:21:19 +0100175 if (!algo_name) {
176 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300177 fprintf(stderr,
178 "Can't get algo property for '%s' signature node in '%s' image node\n",
179 node_name, image_name);
Jan Kiszka4043f322022-01-14 10:21:19 +0100180 return -1;
181 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700182 }
183
Philippe Reynes12468352018-11-14 13:51:00 +0100184 padding_name = fdt_getprop(fit, noffset, "padding", NULL);
185
Simon Glassfbabc0f2013-06-13 15:10:01 -0700186 memset(info, '\0', sizeof(*info));
187 info->keydir = keydir;
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600188 info->keyfile = keyfile;
Simon Glassd7aabcc2020-03-18 11:44:06 -0600189 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700190 info->fit = fit;
191 info->node_offset = noffset;
Masahiro Yamadac1f137b2017-10-27 13:25:21 +0900192 info->name = strdup(algo_name);
Andrew Duda6616c822016-11-08 18:53:41 +0000193 info->checksum = image_get_checksum_algo(algo_name);
194 info->crypto = image_get_crypto_algo(algo_name);
Philippe Reynes12468352018-11-14 13:51:00 +0100195 info->padding = image_get_padding_algo(padding_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700196 info->require_keys = require_keys;
George McCollister23d14892017-01-06 13:14:17 -0600197 info->engine_id = engine_id;
Andrew Duda6616c822016-11-08 18:53:41 +0000198 if (!info->checksum || !info->crypto) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300199 fprintf(stderr,
200 "Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
201 algo_name, node_name, image_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700202 return -1;
203 }
204
205 return 0;
206}
207
208/**
209 * fit_image_process_sig- Process a single subnode of the images/ node
210 *
211 * Check each subnode and process accordingly. For signature nodes we
Simon Glass6a0efc82021-11-12 12:28:06 -0700212 * generate a signed hash of the supplied data and store it in the node.
Simon Glassfbabc0f2013-06-13 15:10:01 -0700213 *
214 * @keydir: Directory containing keys to use for signing
Simon Glass6a0efc82021-11-12 12:28:06 -0700215 * @keydest: Destination FDT blob to write public keys into (NULL if none)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700216 * @fit: pointer to the FIT format image header
Simon Glass6a0efc82021-11-12 12:28:06 -0700217 * @image_name: name of image being processed (used to display errors)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700218 * @noffset: subnode offset
219 * @data: data to process
220 * @size: size of data in bytes
221 * @comment: Comment to add to signature nodes
222 * @require_keys: Mark all keys as 'required'
George McCollister23d14892017-01-06 13:14:17 -0600223 * @engine_id: Engine to use for signing
Simon Glass89c3fb62021-11-12 12:28:12 -0700224 * Return: keydest node if @keydest is non-NULL, else 0 if none; -ve error code
225 * on failure
Simon Glassfbabc0f2013-06-13 15:10:01 -0700226 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600227static int fit_image_process_sig(const char *keydir, const char *keyfile,
228 void *keydest, void *fit, const char *image_name,
Simon Glassfbabc0f2013-06-13 15:10:01 -0700229 int noffset, const void *data, size_t size,
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000230 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +0100231 const char *cmdname, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700232{
233 struct image_sign_info info;
234 struct image_region region;
235 const char *node_name;
236 uint8_t *value;
237 uint value_len;
238 int ret;
239
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600240 if (fit_image_setup_sig(&info, keydir, keyfile, fit, image_name,
241 noffset, require_keys ? "image" : NULL,
Jan Kiszka4043f322022-01-14 10:21:19 +0100242 engine_id, algo_name))
Simon Glassfbabc0f2013-06-13 15:10:01 -0700243 return -1;
244
245 node_name = fit_get_name(fit, noffset, NULL);
246 region.data = data;
247 region.size = size;
Andrew Duda6616c822016-11-08 18:53:41 +0000248 ret = info.crypto->sign(&info, &region, 1, &value, &value_len);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700249 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300250 fprintf(stderr, "Failed to sign '%s' signature node in '%s' image node: %d\n",
251 node_name, image_name, ret);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700252
253 /* We allow keys to be missing */
254 if (ret == -ENOENT)
255 return 0;
256 return -1;
257 }
258
259 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +0100260 NULL, 0, cmdname, algo_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700261 if (ret) {
Simon Glass802aa822014-06-02 22:04:53 -0600262 if (ret == -FDT_ERR_NOSPACE)
263 return -ENOSPC;
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300264 fprintf(stderr,
265 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
266 node_name, image_name, fdt_strerror(ret));
Simon Glassfbabc0f2013-06-13 15:10:01 -0700267 return -1;
268 }
269 free(value);
270
271 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glassd7aabcc2020-03-18 11:44:06 -0600272 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700273
mario.six@gdsys.ccdc4053a2016-07-22 08:58:40 +0200274 /*
275 * Write the public key into the supplied FDT file; this might fail
mario.six@gdsys.ccd019e152016-07-19 11:07:06 +0200276 * several times, since we try signing with successively increasing
mario.six@gdsys.ccdc4053a2016-07-22 08:58:40 +0200277 * size values
278 */
Masahiro Yamada01486762017-10-27 15:04:20 +0900279 if (keydest) {
280 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glass94336dc2021-11-12 12:28:11 -0700281 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300282 fprintf(stderr,
283 "Failed to add verification data for '%s' signature node in '%s' image node\n",
284 node_name, image_name);
Masahiro Yamada01486762017-10-27 15:04:20 +0900285 return ret;
286 }
Simon Glass89c3fb62021-11-12 12:28:12 -0700287 /* Return the node that was written to */
288 return ret;
Masahiro Yamada01486762017-10-27 15:04:20 +0900289 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700290
291 return 0;
292}
293
Philippe Reynes3148e422019-12-18 18:25:41 +0100294static int fit_image_read_data(char *filename, unsigned char *data,
295 int expected_size)
296{
297 struct stat sbuf;
298 int fd, ret = -1;
299 ssize_t n;
300
301 /* Open file */
302 fd = open(filename, O_RDONLY | O_BINARY);
303 if (fd < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300304 fprintf(stderr, "Can't open file %s (err=%d => %s)\n",
305 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100306 return -1;
307 }
308
309 /* Compute file size */
310 if (fstat(fd, &sbuf) < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300311 fprintf(stderr, "Can't fstat file %s (err=%d => %s)\n",
312 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100313 goto err;
314 }
315
316 /* Check file size */
317 if (sbuf.st_size != expected_size) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300318 fprintf(stderr, "File %s don't have the expected size (size=%lld, expected=%d)\n",
319 filename, (long long)sbuf.st_size, expected_size);
Philippe Reynes3148e422019-12-18 18:25:41 +0100320 goto err;
321 }
322
323 /* Read data */
324 n = read(fd, data, sbuf.st_size);
325 if (n < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300326 fprintf(stderr, "Can't read file %s (err=%d => %s)\n",
327 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100328 goto err;
329 }
330
331 /* Check that we have read all the file */
332 if (n != sbuf.st_size) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300333 fprintf(stderr, "Can't read all file %s (read %zd bytes, expected %lld)\n",
334 filename, n, (long long)sbuf.st_size);
Philippe Reynes3148e422019-12-18 18:25:41 +0100335 goto err;
336 }
337
338 ret = 0;
339
340err:
341 close(fd);
342 return ret;
343}
344
Hugo Cornelis92814842024-01-08 15:24:30 +0100345static int fit_image_read_key_iv_data(const char *keydir, const char *key_iv_name,
346 unsigned char *key_iv_data, int expected_size)
347{
348 char filename[PATH_MAX];
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100349 int ret;
Hugo Cornelis92814842024-01-08 15:24:30 +0100350
351 ret = snprintf(filename, sizeof(filename), "%s/%s%s",
352 keydir, key_iv_name, ".bin");
353 if (ret >= sizeof(filename)) {
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100354 fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: insufficient buffer space\n");
355 return -1;
Hugo Cornelis92814842024-01-08 15:24:30 +0100356 }
357 if (ret < 0) {
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100358 fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: snprintf error\n");
359 return -1;
Hugo Cornelis92814842024-01-08 15:24:30 +0100360 }
361
362 ret = fit_image_read_data(filename, key_iv_data, expected_size);
363
364 return ret;
365}
366
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100367/**
368 * get_random_data() - fill buffer with random data
369 *
370 * There is no common cryptographically safe function in Linux and BSD.
371 * Hence directly access the /dev/urandom PRNG.
372 *
373 * @data: buffer to fill
374 * @size: buffer size
375 */
376static int get_random_data(void *data, size_t size)
Philippe Reynes64d67c42020-09-17 15:01:46 +0200377{
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100378 int fd;
379 int ret;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200380
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100381 fd = open("/dev/urandom", O_RDONLY);
382 if (fd < 0) {
383 perror("Failed to open /dev/urandom");
384 return -1;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200385 }
386
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100387 while (size) {
388 ssize_t count;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200389
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100390 count = read(fd, data, size);
391 if (count < 0) {
392 if (errno == EINTR) {
393 continue;
394 } else {
395 perror("Failed to read from /dev/urandom");
396 ret = -1;
397 goto out;
398 }
399 }
400 data += count;
401 size -= count;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200402 }
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100403 ret = 0;
404out:
405 close(fd);
Philippe Reynes64d67c42020-09-17 15:01:46 +0200406
Philippe Reynes64d67c42020-09-17 15:01:46 +0200407 return ret;
408}
409
Philippe Reynes3148e422019-12-18 18:25:41 +0100410static int fit_image_setup_cipher(struct image_cipher_info *info,
411 const char *keydir, void *fit,
412 const char *image_name, int image_noffset,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000413 int noffset)
Philippe Reynes3148e422019-12-18 18:25:41 +0100414{
415 char *algo_name;
Philippe Reynes3148e422019-12-18 18:25:41 +0100416 int ret = -1;
417
418 if (fit_image_cipher_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300419 fprintf(stderr, "Can't get algo name for cipher in image '%s'\n",
420 image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100421 goto out;
422 }
423
424 info->keydir = keydir;
425
426 /* Read the key name */
Simon Glassd7aabcc2020-03-18 11:44:06 -0600427 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Philippe Reynes3148e422019-12-18 18:25:41 +0100428 if (!info->keyname) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300429 fprintf(stderr, "Can't get key name for cipher in image '%s'\n",
430 image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100431 goto out;
432 }
433
Philippe Reynes64d67c42020-09-17 15:01:46 +0200434 /*
435 * Read the IV name
436 *
437 * If this property is not provided then mkimage will generate
438 * a random IV and store it in the FIT image
439 */
Philippe Reynes3148e422019-12-18 18:25:41 +0100440 info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL);
Philippe Reynes3148e422019-12-18 18:25:41 +0100441
442 info->fit = fit;
443 info->node_noffset = noffset;
444 info->name = algo_name;
445
446 info->cipher = image_get_cipher_algo(algo_name);
447 if (!info->cipher) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300448 fprintf(stderr, "Can't get algo for cipher '%s'\n", image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100449 goto out;
450 }
451
Philippe Reynes3148e422019-12-18 18:25:41 +0100452 info->key = malloc(info->cipher->key_len);
453 if (!info->key) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300454 fprintf(stderr, "Can't allocate memory for key\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100455 ret = -1;
456 goto out;
457 }
Hugo Cornelis92814842024-01-08 15:24:30 +0100458
459 /* Read the key in the file */
460 ret = fit_image_read_key_iv_data(info->keydir, info->keyname,
461 (unsigned char *)info->key,
462 info->cipher->key_len);
Philippe Reynes3148e422019-12-18 18:25:41 +0100463 if (ret < 0)
464 goto out;
465
Philippe Reynes3148e422019-12-18 18:25:41 +0100466 info->iv = malloc(info->cipher->iv_len);
467 if (!info->iv) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300468 fprintf(stderr, "Can't allocate memory for iv\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100469 ret = -1;
470 goto out;
471 }
Philippe Reynes64d67c42020-09-17 15:01:46 +0200472
473 if (info->ivname) {
474 /* Read the IV in the file */
Hugo Cornelis92814842024-01-08 15:24:30 +0100475 ret = fit_image_read_key_iv_data(info->keydir, info->ivname,
476 (unsigned char *)info->iv,
477 info->cipher->iv_len);
478 if (ret < 0)
479 goto out;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200480 } else {
481 /* Generate an ramdom IV */
482 ret = get_random_data((void *)info->iv, info->cipher->iv_len);
483 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100484
485 out:
486 return ret;
487}
488
489int fit_image_write_cipher(void *fit, int image_noffset, int noffset,
490 const void *data, size_t size,
491 unsigned char *data_ciphered, int data_ciphered_len)
492{
493 int ret = -1;
494
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000495 /* Replace data with ciphered data */
Philippe Reynes3148e422019-12-18 18:25:41 +0100496 ret = fdt_setprop(fit, image_noffset, FIT_DATA_PROP,
497 data_ciphered, data_ciphered_len);
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000498 if (ret == -FDT_ERR_NOSPACE) {
499 ret = -ENOSPC;
500 goto out;
501 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100502 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300503 fprintf(stderr, "Can't replace data with ciphered data (err = %d)\n", ret);
Philippe Reynes3148e422019-12-18 18:25:41 +0100504 goto out;
505 }
506
507 /* add non ciphered data size */
508 ret = fdt_setprop_u32(fit, image_noffset, "data-size-unciphered", size);
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000509 if (ret == -FDT_ERR_NOSPACE) {
510 ret = -ENOSPC;
511 goto out;
512 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100513 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300514 fprintf(stderr, "Can't add unciphered data size (err = %d)\n", ret);
Philippe Reynes3148e422019-12-18 18:25:41 +0100515 goto out;
516 }
517
518 out:
519 return ret;
520}
521
522static int
523fit_image_process_cipher(const char *keydir, void *keydest, void *fit,
524 const char *image_name, int image_noffset,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000525 int node_noffset, const void *data, size_t size,
Philippe Reynes3148e422019-12-18 18:25:41 +0100526 const char *cmdname)
527{
528 struct image_cipher_info info;
529 unsigned char *data_ciphered = NULL;
530 int data_ciphered_len;
531 int ret;
532
533 memset(&info, 0, sizeof(info));
534
535 ret = fit_image_setup_cipher(&info, keydir, fit, image_name,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000536 image_noffset, node_noffset);
Philippe Reynes3148e422019-12-18 18:25:41 +0100537 if (ret)
538 goto out;
539
540 ret = info.cipher->encrypt(&info, data, size,
541 &data_ciphered, &data_ciphered_len);
542 if (ret)
543 goto out;
544
545 /*
546 * Write the public key into the supplied FDT file; this might fail
547 * several times, since we try signing with successively increasing
548 * size values
Philippe Reynes64d67c42020-09-17 15:01:46 +0200549 * And, if needed, write the iv in the FIT file
Philippe Reynes3148e422019-12-18 18:25:41 +0100550 */
Paul HENRYS07019912024-11-25 18:47:15 +0100551 if (keydest || (!keydest && !info.ivname)) {
Philippe Reynes64d67c42020-09-17 15:01:46 +0200552 ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
Philippe Reynes3148e422019-12-18 18:25:41 +0100553 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300554 fprintf(stderr,
555 "Failed to add verification data for cipher '%s' in image '%s'\n",
556 info.keyname, image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100557 goto out;
558 }
559 }
560
561 ret = fit_image_write_cipher(fit, image_noffset, node_noffset,
562 data, size,
563 data_ciphered, data_ciphered_len);
564
565 out:
566 free(data_ciphered);
567 free((void *)info.key);
568 free((void *)info.iv);
569 return ret;
570}
571
572int fit_image_cipher_data(const char *keydir, void *keydest,
573 void *fit, int image_noffset, const char *comment,
574 int require_keys, const char *engine_id,
575 const char *cmdname)
576{
577 const char *image_name;
578 const void *data;
579 size_t size;
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000580 int cipher_node_offset, len;
Philippe Reynes3148e422019-12-18 18:25:41 +0100581
582 /* Get image name */
583 image_name = fit_get_name(fit, image_noffset, NULL);
584 if (!image_name) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300585 fprintf(stderr, "Can't get image name\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100586 return -1;
587 }
588
589 /* Get image data and data length */
Simon Glassd3ca4012025-01-10 17:00:12 -0700590 if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300591 fprintf(stderr, "Can't get image data/size\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100592 return -1;
593 }
594
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000595 /*
596 * Don't cipher ciphered data.
597 *
598 * If the data-size-unciphered property is present the data for this
599 * image is already encrypted. This is important as 'mkimage -F' can be
600 * run multiple times on a FIT image.
601 */
602 if (fdt_getprop(fit, image_noffset, "data-size-unciphered", &len))
603 return 0;
604 if (len != -FDT_ERR_NOTFOUND) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300605 fprintf(stderr, "Failure testing for data-size-unciphered\n");
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000606 return -1;
607 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100608
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000609 /* Process cipher node if present */
610 cipher_node_offset = fdt_subnode_offset(fit, image_noffset,
611 FIT_CIPHER_NODENAME);
612 if (cipher_node_offset == -FDT_ERR_NOTFOUND)
613 return 0;
614 if (cipher_node_offset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300615 fprintf(stderr, "Failure getting cipher node\n");
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000616 return -1;
Philippe Reynes3148e422019-12-18 18:25:41 +0100617 }
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000618 if (!IMAGE_ENABLE_ENCRYPT || !keydir)
619 return 0;
620 return fit_image_process_cipher(keydir, keydest, fit, image_name,
621 image_noffset, cipher_node_offset, data, size, cmdname);
Philippe Reynes3148e422019-12-18 18:25:41 +0100622}
623
Simon Glassfbabc0f2013-06-13 15:10:01 -0700624/**
625 * fit_image_add_verification_data() - calculate/set verig. data for image node
626 *
627 * This adds hash and signature values for an component image node.
Simon Glassee382652013-05-07 06:12:01 +0000628 *
629 * All existing hash subnodes are checked, if algorithm property is set to
630 * one of the supported hash algorithms, hash value is computed and
631 * corresponding hash node property is set, for example:
Simon Glass10a1eca2013-05-07 06:11:54 +0000632 *
633 * Input component image node structure:
634 *
Andre Przywara3234ecd2017-12-04 02:05:10 +0000635 * o image-1 (at image_noffset)
Simon Glass10a1eca2013-05-07 06:11:54 +0000636 * | - data = [binary data]
Andre Przywara3234ecd2017-12-04 02:05:10 +0000637 * o hash-1
Simon Glass10a1eca2013-05-07 06:11:54 +0000638 * |- algo = "sha1"
639 *
640 * Output component image node structure:
641 *
Andre Przywara3234ecd2017-12-04 02:05:10 +0000642 * o image-1 (at image_noffset)
Simon Glass10a1eca2013-05-07 06:11:54 +0000643 * | - data = [binary data]
Andre Przywara3234ecd2017-12-04 02:05:10 +0000644 * o hash-1
Simon Glass10a1eca2013-05-07 06:11:54 +0000645 * |- algo = "sha1"
646 * |- value = sha1(data)
647 *
Simon Glassee382652013-05-07 06:12:01 +0000648 * For signature details, please see doc/uImage.FIT/signature.txt
649 *
Simon Glassfbabc0f2013-06-13 15:10:01 -0700650 * @keydir Directory containing *.key and *.crt files (or NULL)
651 * @keydest FDT Blob to write public keys into (NULL if none)
Simon Glassee382652013-05-07 06:12:01 +0000652 * @fit: Pointer to the FIT format image header
653 * @image_noffset: Requested component image node
Simon Glassfbabc0f2013-06-13 15:10:01 -0700654 * @comment: Comment to add to signature nodes
655 * @require_keys: Mark all keys as 'required'
George McCollister23d14892017-01-06 13:14:17 -0600656 * @engine_id: Engine to use for signing
Simon Glassee382652013-05-07 06:12:01 +0000657 * @return: 0 on success, <0 on failure
Simon Glass10a1eca2013-05-07 06:11:54 +0000658 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600659int fit_image_add_verification_data(const char *keydir, const char *keyfile,
660 void *keydest, void *fit, int image_noffset,
661 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +0100662 const char *cmdname, const char* algo_name)
Simon Glass10a1eca2013-05-07 06:11:54 +0000663{
Simon Glassee382652013-05-07 06:12:01 +0000664 const char *image_name;
Simon Glass10a1eca2013-05-07 06:11:54 +0000665 const void *data;
666 size_t size;
Simon Glass10a1eca2013-05-07 06:11:54 +0000667 int noffset;
Simon Glass10a1eca2013-05-07 06:11:54 +0000668
669 /* Get image data and data length */
Simon Glassd3ca4012025-01-10 17:00:12 -0700670 if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300671 fprintf(stderr, "Can't get image data/size\n");
Simon Glass10a1eca2013-05-07 06:11:54 +0000672 return -1;
673 }
674
Simon Glass25d6e6b2013-05-07 06:11:55 +0000675 image_name = fit_get_name(fit, image_noffset, NULL);
676
Simon Glass10a1eca2013-05-07 06:11:54 +0000677 /* Process all hash subnodes of the component image node */
Simon Glassee382652013-05-07 06:12:01 +0000678 for (noffset = fdt_first_subnode(fit, image_noffset);
679 noffset >= 0;
680 noffset = fdt_next_subnode(fit, noffset)) {
681 const char *node_name;
682 int ret = 0;
683
684 /*
685 * Check subnode name, must be equal to "hash" or "signature".
686 * Multiple hash nodes require unique unit node
Andre Przywara3234ecd2017-12-04 02:05:10 +0000687 * names, e.g. hash-1, hash-2, signature-1, etc.
Simon Glassee382652013-05-07 06:12:01 +0000688 */
689 node_name = fit_get_name(fit, noffset, NULL);
690 if (!strncmp(node_name, FIT_HASH_NODENAME,
691 strlen(FIT_HASH_NODENAME))) {
692 ret = fit_image_process_hash(fit, image_name, noffset,
693 data, size);
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600694 } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) &&
Simon Glassfbabc0f2013-06-13 15:10:01 -0700695 !strncmp(node_name, FIT_SIG_NODENAME,
696 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600697 ret = fit_image_process_sig(keydir, keyfile, keydest,
Simon Glassfbabc0f2013-06-13 15:10:01 -0700698 fit, image_name, noffset, data, size,
Jan Kiszka4043f322022-01-14 10:21:19 +0100699 comment, require_keys, engine_id, cmdname,
700 algo_name);
Simon Glass10a1eca2013-05-07 06:11:54 +0000701 }
Simon Glass89c3fb62021-11-12 12:28:12 -0700702 if (ret < 0)
Simon Glassec539f72016-07-03 09:40:44 -0600703 return ret;
Simon Glassee382652013-05-07 06:12:01 +0000704 }
705
706 return 0;
707}
708
Simon Glass56ab8d62013-06-13 15:10:09 -0700709struct strlist {
710 int count;
711 char **strings;
712};
713
714static void strlist_init(struct strlist *list)
715{
716 memset(list, '\0', sizeof(*list));
717}
718
719static void strlist_free(struct strlist *list)
720{
721 int i;
722
723 for (i = 0; i < list->count; i++)
724 free(list->strings[i]);
725 free(list->strings);
726}
727
728static int strlist_add(struct strlist *list, const char *str)
729{
730 char *dup;
731
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300732 if (!list || !str)
733 return -1;
734
Simon Glass56ab8d62013-06-13 15:10:09 -0700735 dup = strdup(str);
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300736 if(!dup)
737 return -1;
738
Simon Glass56ab8d62013-06-13 15:10:09 -0700739 list->strings = realloc(list->strings,
740 (list->count + 1) * sizeof(char *));
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300741 if (!list->strings) {
742 free(dup);
Simon Glass56ab8d62013-06-13 15:10:09 -0700743 return -1;
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300744 }
745
Simon Glass56ab8d62013-06-13 15:10:09 -0700746 list->strings[list->count++] = dup;
747
748 return 0;
749}
750
Simon Glass6a0efc82021-11-12 12:28:06 -0700751static const char *fit_config_get_image_list(const void *fit, int noffset,
752 int *lenp, int *allow_missingp)
Simon Glass56ab8d62013-06-13 15:10:09 -0700753{
754 static const char default_list[] = FIT_KERNEL_PROP "\0"
Alexander Dahl907ee6a2024-06-20 16:20:59 +0200755 FIT_FDT_PROP "\0" FIT_SCRIPT_PROP;
Simon Glass56ab8d62013-06-13 15:10:09 -0700756 const char *prop;
757
Simon Glass6a0efc82021-11-12 12:28:06 -0700758 /* If there is an "sign-image" property, use that */
Simon Glass56ab8d62013-06-13 15:10:09 -0700759 prop = fdt_getprop(fit, noffset, "sign-images", lenp);
760 if (prop) {
761 *allow_missingp = 0;
762 return *lenp ? prop : NULL;
763 }
764
765 /* Default image list */
766 *allow_missingp = 1;
767 *lenp = sizeof(default_list);
768
769 return default_list;
770}
771
Simon Glass6a0efc82021-11-12 12:28:06 -0700772/**
773 * fit_config_add_hash() - Add a list of nodes to hash for an image
774 *
775 * This adds a list of paths to image nodes (as referred to by a particular
776 * offset) that need to be hashed, to protect a configuration
777 *
778 * @fit: Pointer to the FIT format image header
779 * @image_noffset: Offset of image to process (e.g. /images/kernel-1)
780 * @node_inc: List of nodes to add to
781 * @conf_name Configuration-node name, child of /configurations node (only
782 * used for error messages)
783 * @sig_name Signature-node name (only used for error messages)
784 * @iname: Name of image being processed (e.g. "kernel-1" (only used
785 * for error messages)
786 */
787static int fit_config_add_hash(const void *fit, int image_noffset,
788 struct strlist *node_inc, const char *conf_name,
789 const char *sig_name, const char *iname)
Philippe Reynes856bcc82020-11-24 14:39:47 +0100790{
Simon Glass888c0c52021-11-12 12:28:07 -0700791 char path[200];
Philippe Reynes856bcc82020-11-24 14:39:47 +0100792 int noffset;
793 int hash_count;
794 int ret;
795
796 ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
797 if (ret < 0)
798 goto err_path;
799 if (strlist_add(node_inc, path))
800 goto err_mem;
801
Philippe Reynes856bcc82020-11-24 14:39:47 +0100802 /* Add all this image's hashes */
803 hash_count = 0;
804 for (noffset = fdt_first_subnode(fit, image_noffset);
805 noffset >= 0;
806 noffset = fdt_next_subnode(fit, noffset)) {
807 const char *name = fit_get_name(fit, noffset, NULL);
808
809 if (strncmp(name, FIT_HASH_NODENAME,
810 strlen(FIT_HASH_NODENAME)))
811 continue;
812 ret = fdt_get_path(fit, noffset, path, sizeof(path));
813 if (ret < 0)
814 goto err_path;
815 if (strlist_add(node_inc, path))
816 goto err_mem;
817 hash_count++;
818 }
819
820 if (!hash_count) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300821 fprintf(stderr,
822 "Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
823 conf_name, sig_name, iname);
Philippe Reynes856bcc82020-11-24 14:39:47 +0100824 return -ENOMSG;
825 }
826
827 /* Add this image's cipher node if present */
828 noffset = fdt_subnode_offset(fit, image_noffset,
829 FIT_CIPHER_NODENAME);
830 if (noffset != -FDT_ERR_NOTFOUND) {
831 if (noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300832 fprintf(stderr,
833 "Failed to get cipher node in configuration '%s/%s' image '%s': %s\n",
834 conf_name, sig_name, iname,
835 fdt_strerror(noffset));
Philippe Reynes856bcc82020-11-24 14:39:47 +0100836 return -EIO;
837 }
838 ret = fdt_get_path(fit, noffset, path, sizeof(path));
839 if (ret < 0)
840 goto err_path;
841 if (strlist_add(node_inc, path))
842 goto err_mem;
843 }
844
845 return 0;
846
847err_mem:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300848 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
849 sig_name);
Philippe Reynes856bcc82020-11-24 14:39:47 +0100850 return -ENOMEM;
851
852err_path:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300853 fprintf(stderr, "Failed to get path for image '%s' in configuration '%s/%s': %s\n",
854 iname, conf_name, sig_name, fdt_strerror(ret));
Philippe Reynes856bcc82020-11-24 14:39:47 +0100855 return -ENOENT;
856}
857
Simon Glass6a0efc82021-11-12 12:28:06 -0700858/**
859 * fit_config_get_hash_list() - Get the regions to sign
860 *
861 * This calculates a list of nodes to hash for this particular configuration,
862 * returning it as a string list (struct strlist, not a devicetree string list)
863 *
864 * @fit: Pointer to the FIT format image header
865 * @conf_noffset: Offset of configuration node to sign (child of
866 * /configurations node)
867 * @sig_offset: Offset of signature node containing info about how to sign it
868 * (child of 'signatures' node)
869 * @return 0 if OK, -ENOENT if an image referred to by the configuration cannot
870 * be found, -ENOMSG if ther were no images in the configuration
871 */
872static int fit_config_get_hash_list(const void *fit, int conf_noffset,
Simon Glass56ab8d62013-06-13 15:10:09 -0700873 int sig_offset, struct strlist *node_inc)
874{
875 int allow_missing;
876 const char *prop, *iname, *end;
877 const char *conf_name, *sig_name;
Philippe Reynes856bcc82020-11-24 14:39:47 +0100878 char name[200];
Simon Glass56ab8d62013-06-13 15:10:09 -0700879 int image_count;
880 int ret, len;
881
882 conf_name = fit_get_name(fit, conf_noffset, NULL);
883 sig_name = fit_get_name(fit, sig_offset, NULL);
884
885 /*
886 * Build a list of nodes we need to hash. We always need the root
887 * node and the configuration.
888 */
889 strlist_init(node_inc);
890 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
891 if (strlist_add(node_inc, "/") ||
892 strlist_add(node_inc, name))
893 goto err_mem;
894
895 /* Get a list of images that we intend to sign */
Heiko Schocherfdfd5202014-03-03 12:19:23 +0100896 prop = fit_config_get_image_list(fit, sig_offset, &len,
Simon Glass56ab8d62013-06-13 15:10:09 -0700897 &allow_missing);
898 if (!prop)
899 return 0;
900
901 /* Locate the images */
902 end = prop + len;
903 image_count = 0;
904 for (iname = prop; iname < end; iname += strlen(iname) + 1) {
Simon Glass56ab8d62013-06-13 15:10:09 -0700905 int image_noffset;
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100906 int index, max_index;
Simon Glass56ab8d62013-06-13 15:10:09 -0700907
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100908 max_index = fdt_stringlist_count(fit, conf_noffset, iname);
Simon Glass56ab8d62013-06-13 15:10:09 -0700909
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100910 for (index = 0; index < max_index; index++) {
911 image_noffset = fit_conf_get_prop_node_index(fit, conf_noffset,
912 iname, index);
913
914 if (image_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300915 fprintf(stderr,
916 "Failed to find image '%s' in configuration '%s/%s'\n",
917 iname, conf_name, sig_name);
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100918 if (allow_missing)
919 continue;
Simon Glass56ab8d62013-06-13 15:10:09 -0700920
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100921 return -ENOENT;
922 }
Patrick Oppenlander5964c3f2020-07-30 14:30:47 +1000923
Simon Glass6a0efc82021-11-12 12:28:06 -0700924 ret = fit_config_add_hash(fit, image_noffset, node_inc,
925 conf_name, sig_name, iname);
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100926 if (ret < 0)
927 return ret;
928
929 image_count++;
930 }
Simon Glass56ab8d62013-06-13 15:10:09 -0700931 }
932
933 if (!image_count) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300934 fprintf(stderr, "Failed to find any images for configuration '%s/%s'\n",
935 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -0700936 return -ENOMSG;
937 }
938
939 return 0;
940
941err_mem:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300942 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
943 sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -0700944 return -ENOMEM;
Simon Glass56ab8d62013-06-13 15:10:09 -0700945}
946
Simon Glass6a0efc82021-11-12 12:28:06 -0700947/**
948 * fit_config_get_regions() - Get the regions to sign
949 *
950 * This calculates a list of node to hash for this particular configuration,
951 * then finds which regions of the devicetree they correspond to.
952 *
953 * @fit: Pointer to the FIT format image header
954 * @conf_noffset: Offset of configuration node to sign (child of
955 * /configurations node)
956 * @sig_offset: Offset of signature node containing info about how to sign it
957 * (child of 'signatures' node)
958 * @regionp: Returns list of regions that need to be hashed (allocated; must be
959 * freed by the caller)
960 * @region_count: Returns number of regions
961 * @region_propp: Returns string-list property containing the list of nodes
962 * that correspond to the regions. Each entry is a full path to the node.
963 * This is in devicetree format, i.e. a \0 between each string. This is
964 * allocated and must be freed by the caller.
965 * @region_proplen: Returns length of *@@region_propp in bytes
966 * @return 0 if OK, -ENOMEM if out of memory, -EIO if the regions to hash could
967 * not be found, -EINVAL if no registers were found to hash
968 */
969static int fit_config_get_regions(const void *fit, int conf_noffset,
970 int sig_offset, struct image_region **regionp,
971 int *region_countp, char **region_propp,
972 int *region_proplen)
Simon Glass56ab8d62013-06-13 15:10:09 -0700973{
Sean Anderson016f4d52022-10-20 15:41:10 -0400974 char * const exc_prop[] = {
975 FIT_DATA_PROP,
976 FIT_DATA_SIZE_PROP,
977 FIT_DATA_POSITION_PROP,
978 FIT_DATA_OFFSET_PROP,
979 };
Simon Glass56ab8d62013-06-13 15:10:09 -0700980 struct strlist node_inc;
981 struct image_region *region;
982 struct fdt_region fdt_regions[100];
983 const char *conf_name, *sig_name;
984 char path[200];
985 int count, i;
986 char *region_prop;
987 int ret, len;
988
989 conf_name = fit_get_name(fit, conf_noffset, NULL);
Simon Glass6a0efc82021-11-12 12:28:06 -0700990 sig_name = fit_get_name(fit, sig_offset, NULL);
Simon Glass56ab8d62013-06-13 15:10:09 -0700991 debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
992
993 /* Get a list of nodes we want to hash */
Simon Glass6a0efc82021-11-12 12:28:06 -0700994 ret = fit_config_get_hash_list(fit, conf_noffset, sig_offset,
995 &node_inc);
Simon Glass56ab8d62013-06-13 15:10:09 -0700996 if (ret)
997 return ret;
998
999 /* Get a list of regions to hash */
1000 count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
1001 exc_prop, ARRAY_SIZE(exc_prop),
1002 fdt_regions, ARRAY_SIZE(fdt_regions),
1003 path, sizeof(path), 1);
1004 if (count < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001005 fprintf(stderr, "Failed to hash configuration '%s/%s': %s\n", conf_name,
1006 sig_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001007 return -EIO;
1008 }
1009 if (count == 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001010 fprintf(stderr, "No data to hash for configuration '%s/%s': %s\n",
1011 conf_name, sig_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001012 return -EINVAL;
1013 }
1014
1015 /* Build our list of data blocks */
1016 region = fit_region_make_list(fit, fdt_regions, count, NULL);
1017 if (!region) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001018 fprintf(stderr, "Out of memory hashing configuration '%s/%s'\n",
1019 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001020 return -ENOMEM;
1021 }
1022
1023 /* Create a list of all hashed properties */
1024 debug("Hash nodes:\n");
1025 for (i = len = 0; i < node_inc.count; i++) {
1026 debug(" %s\n", node_inc.strings[i]);
1027 len += strlen(node_inc.strings[i]) + 1;
1028 }
1029 region_prop = malloc(len);
1030 if (!region_prop) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001031 fprintf(stderr, "Out of memory setting up regions for configuration '%s/%s'\n",
1032 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001033 return -ENOMEM;
1034 }
1035 for (i = len = 0; i < node_inc.count;
1036 len += strlen(node_inc.strings[i]) + 1, i++)
1037 strcpy(region_prop + len, node_inc.strings[i]);
1038 strlist_free(&node_inc);
1039
1040 *region_countp = count;
1041 *regionp = region;
1042 *region_propp = region_prop;
1043 *region_proplen = len;
1044
1045 return 0;
1046}
1047
Simon Glass89c3fb62021-11-12 12:28:12 -07001048/**
1049 * fit_config_process_sig - Process a single subnode of the configurations/ node
1050 *
1051 * Generate a signed hash of the supplied data and store it in the node.
1052 *
1053 * @keydir: Directory containing keys to use for signing
1054 * @keydest: Destination FDT blob to write public keys into (NULL if none)
1055 * @fit: pointer to the FIT format image header
1056 * @conf_name name of config being processed (used to display errors)
1057 * @conf_noffset: Offset of configuration node, e.g. '/configurations/conf-1'
1058 * @noffset: subnode offset, e.g. '/configurations/conf-1/sig-1'
1059 * @comment: Comment to add to signature nodes
1060 * @require_keys: Mark all keys as 'required'
1061 * @engine_id: Engine to use for signing
1062 * @cmdname: Command name used when reporting errors
1063 * @return keydest node if @keydest is non-NULL, else 0 if none; -ve error code
1064 * on failure
1065 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001066static int fit_config_process_sig(const char *keydir, const char *keyfile,
Simon Glass6a0efc82021-11-12 12:28:06 -07001067 void *keydest, void *fit, const char *conf_name,
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001068 int conf_noffset, int noffset, const char *comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001069 int require_keys, const char *engine_id, const char *cmdname,
1070 const char *algo_name)
Simon Glass56ab8d62013-06-13 15:10:09 -07001071{
1072 struct image_sign_info info;
1073 const char *node_name;
1074 struct image_region *region;
1075 char *region_prop;
1076 int region_proplen;
1077 int region_count;
1078 uint8_t *value;
1079 uint value_len;
1080 int ret;
1081
1082 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass6a0efc82021-11-12 12:28:06 -07001083 if (fit_config_get_regions(fit, conf_noffset, noffset, &region,
1084 &region_count, &region_prop,
1085 &region_proplen))
Simon Glass56ab8d62013-06-13 15:10:09 -07001086 return -1;
1087
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001088 if (fit_image_setup_sig(&info, keydir, keyfile, fit, conf_name, noffset,
Jan Kiszka4043f322022-01-14 10:21:19 +01001089 require_keys ? "conf" : NULL, engine_id,
1090 algo_name))
Simon Glass56ab8d62013-06-13 15:10:09 -07001091 return -1;
1092
Andrew Duda6616c822016-11-08 18:53:41 +00001093 ret = info.crypto->sign(&info, region, region_count, &value,
1094 &value_len);
Simon Glass56ab8d62013-06-13 15:10:09 -07001095 free(region);
1096 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001097 fprintf(stderr, "Failed to sign '%s' signature node in '%s' conf node\n",
1098 node_name, conf_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001099
1100 /* We allow keys to be missing */
1101 if (ret == -ENOENT)
1102 return 0;
1103 return -1;
1104 }
1105
Simon Glass802aa822014-06-02 22:04:53 -06001106 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001107 region_prop, region_proplen, cmdname,
1108 algo_name);
Simon Glass802aa822014-06-02 22:04:53 -06001109 if (ret) {
1110 if (ret == -FDT_ERR_NOSPACE)
1111 return -ENOSPC;
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001112 fprintf(stderr,
1113 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
1114 node_name, conf_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001115 return -1;
1116 }
1117 free(value);
1118 free(region_prop);
1119
1120 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glassd7aabcc2020-03-18 11:44:06 -06001121 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56ab8d62013-06-13 15:10:09 -07001122
1123 /* Write the public key into the supplied FDT file */
Simon Glass802aa822014-06-02 22:04:53 -06001124 if (keydest) {
Andrew Duda6616c822016-11-08 18:53:41 +00001125 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glass94336dc2021-11-12 12:28:11 -07001126 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001127 fprintf(stderr,
1128 "Failed to add verification data for '%s' signature node in '%s' configuration node\n",
1129 node_name, conf_name);
Simon Glass802aa822014-06-02 22:04:53 -06001130 }
Simon Glass89c3fb62021-11-12 12:28:12 -07001131 return ret;
Simon Glass56ab8d62013-06-13 15:10:09 -07001132 }
1133
1134 return 0;
1135}
1136
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001137static int fit_config_add_verification_data(const char *keydir,
1138 const char *keyfile, void *keydest, void *fit, int conf_noffset,
1139 const char *comment, int require_keys, const char *engine_id,
Simon Glasse4607262021-11-12 12:28:13 -07001140 const char *cmdname, const char *algo_name,
1141 struct image_summary *summary)
Simon Glass56ab8d62013-06-13 15:10:09 -07001142{
1143 const char *conf_name;
1144 int noffset;
1145
1146 conf_name = fit_get_name(fit, conf_noffset, NULL);
1147
1148 /* Process all hash subnodes of the configuration node */
1149 for (noffset = fdt_first_subnode(fit, conf_noffset);
1150 noffset >= 0;
1151 noffset = fdt_next_subnode(fit, noffset)) {
1152 const char *node_name;
1153 int ret = 0;
1154
1155 node_name = fit_get_name(fit, noffset, NULL);
1156 if (!strncmp(node_name, FIT_SIG_NODENAME,
1157 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001158 ret = fit_config_process_sig(keydir, keyfile, keydest,
Simon Glass56ab8d62013-06-13 15:10:09 -07001159 fit, conf_name, conf_noffset, noffset, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001160 require_keys, engine_id, cmdname, algo_name);
Simon Glasse4607262021-11-12 12:28:13 -07001161 if (ret < 0)
1162 return ret;
1163
1164 summary->sig_offset = noffset;
1165 fdt_get_path(fit, noffset, summary->sig_path,
1166 sizeof(summary->sig_path));
1167
1168 if (keydest) {
1169 summary->keydest_offset = ret;
1170 fdt_get_path(keydest, ret,
1171 summary->keydest_path,
1172 sizeof(summary->keydest_path));
1173 }
Simon Glass56ab8d62013-06-13 15:10:09 -07001174 }
Simon Glass56ab8d62013-06-13 15:10:09 -07001175 }
1176
1177 return 0;
1178}
1179
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +01001180#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001181/*
1182 * 0) open file (open)
1183 * 1) read certificate (PEM_read_X509)
1184 * 2) get public key (X509_get_pubkey)
1185 * 3) provide der format (d2i_RSAPublicKey)
1186 */
1187static int read_pub_key(const char *keydir, const void *name,
1188 unsigned char **pubkey, int *pubkey_len)
1189{
1190 char path[1024];
1191 EVP_PKEY *key = NULL;
1192 X509 *cert;
1193 FILE *f;
1194 int ret;
1195
1196 memset(path, 0, 1024);
1197 snprintf(path, sizeof(path), "%s/%s.crt", keydir, (char *)name);
1198
1199 /* Open certificate file */
1200 f = fopen(path, "r");
1201 if (!f) {
1202 fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
1203 path, strerror(errno));
1204 return -EACCES;
1205 }
1206
1207 /* Read the certificate */
1208 cert = NULL;
1209 if (!PEM_read_X509(f, &cert, NULL, NULL)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001210 fprintf(stderr, "Couldn't read certificate");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001211 ret = -EINVAL;
1212 goto err_cert;
1213 }
1214
1215 /* Get the public key from the certificate. */
1216 key = X509_get_pubkey(cert);
1217 if (!key) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001218 fprintf(stderr, "Couldn't read public key\n");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001219 ret = -EINVAL;
1220 goto err_pubkey;
1221 }
1222
1223 /* Get DER form */
1224 ret = i2d_PublicKey(key, pubkey);
1225 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001226 fprintf(stderr, "Couldn't get DER form\n");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001227 ret = -EINVAL;
1228 goto err_pubkey;
1229 }
1230
1231 *pubkey_len = ret;
1232 ret = 0;
1233
1234err_pubkey:
1235 X509_free(cert);
1236err_cert:
1237 fclose(f);
1238 return ret;
1239}
1240
1241int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
1242{
1243 int pre_load_noffset;
1244 const void *algo_name;
1245 const void *key_name;
1246 unsigned char *pubkey = NULL;
1247 int ret, pubkey_len;
1248
1249 if (!keydir || !keydest || !fit)
1250 return 0;
1251
1252 /* Search node pre-load sig */
1253 pre_load_noffset = fdt_path_offset(keydest, IMAGE_PRE_LOAD_PATH);
1254 if (pre_load_noffset < 0) {
1255 ret = 0;
1256 goto out;
1257 }
1258
1259 algo_name = fdt_getprop(keydest, pre_load_noffset, "algo-name", NULL);
1260 key_name = fdt_getprop(keydest, pre_load_noffset, "key-name", NULL);
1261
1262 /* Check that all mandatory properties are present */
1263 if (!algo_name || !key_name) {
1264 if (!algo_name)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001265 fprintf(stderr, "The property algo-name is missing in the node %s\n",
1266 IMAGE_PRE_LOAD_PATH);
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001267 if (!key_name)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001268 fprintf(stderr, "The property key-name is missing in the node %s\n",
1269 IMAGE_PRE_LOAD_PATH);
Mark Kettenisd4ba0b42022-04-26 19:24:38 +02001270 ret = -EINVAL;
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001271 goto out;
1272 }
1273
1274 /* Read public key */
1275 ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
1276 if (ret < 0)
1277 goto out;
1278
1279 /* Add the public key to the device tree */
1280 ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
1281 pubkey, pubkey_len);
1282 if (ret)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001283 fprintf(stderr, "Can't set public-key in node %s (ret = %d)\n",
1284 IMAGE_PRE_LOAD_PATH, ret);
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001285
1286 out:
1287 return ret;
1288}
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +01001289#endif
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001290
Philippe Reynes3148e422019-12-18 18:25:41 +01001291int fit_cipher_data(const char *keydir, void *keydest, void *fit,
1292 const char *comment, int require_keys,
1293 const char *engine_id, const char *cmdname)
1294{
1295 int images_noffset;
1296 int noffset;
1297 int ret;
1298
1299 /* Find images parent node offset */
1300 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1301 if (images_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001302 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1303 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Philippe Reynes3148e422019-12-18 18:25:41 +01001304 return images_noffset;
1305 }
1306
1307 /* Process its subnodes, print out component images details */
1308 for (noffset = fdt_first_subnode(fit, images_noffset);
1309 noffset >= 0;
1310 noffset = fdt_next_subnode(fit, noffset)) {
1311 /*
1312 * Direct child node of the images parent node,
1313 * i.e. component image node.
1314 */
1315 ret = fit_image_cipher_data(keydir, keydest,
1316 fit, noffset, comment,
1317 require_keys, engine_id,
1318 cmdname);
1319 if (ret)
1320 return ret;
1321 }
1322
1323 return 0;
1324}
1325
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001326int fit_add_verification_data(const char *keydir, const char *keyfile,
1327 void *keydest, void *fit, const char *comment,
1328 int require_keys, const char *engine_id,
Simon Glasse4607262021-11-12 12:28:13 -07001329 const char *cmdname, const char *algo_name,
1330 struct image_summary *summary)
Simon Glassee382652013-05-07 06:12:01 +00001331{
Simon Glass56ab8d62013-06-13 15:10:09 -07001332 int images_noffset, confs_noffset;
Simon Glassee382652013-05-07 06:12:01 +00001333 int noffset;
1334 int ret;
1335
1336 /* Find images parent node offset */
1337 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1338 if (images_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001339 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1340 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Simon Glassee382652013-05-07 06:12:01 +00001341 return images_noffset;
1342 }
1343
1344 /* Process its subnodes, print out component images details */
1345 for (noffset = fdt_first_subnode(fit, images_noffset);
1346 noffset >= 0;
1347 noffset = fdt_next_subnode(fit, noffset)) {
1348 /*
1349 * Direct child node of the images parent node,
1350 * i.e. component image node.
1351 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001352 ret = fit_image_add_verification_data(keydir, keyfile, keydest,
Alex Kiernan697fcdc2018-06-20 20:10:52 +00001353 fit, noffset, comment, require_keys, engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +01001354 cmdname, algo_name);
Simon Glass35414072022-12-21 16:08:23 -07001355 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001356 fprintf(stderr, "Can't add verification data for node '%s' (%s)\n",
1357 fdt_get_name(fit, noffset, NULL),
Alexander Kochetkov197ee8b2024-09-16 11:24:45 +03001358 strerror(-ret));
Simon Glassee382652013-05-07 06:12:01 +00001359 return ret;
Simon Glass35414072022-12-21 16:08:23 -07001360 }
Simon Glass10a1eca2013-05-07 06:11:54 +00001361 }
1362
Simon Glass56ab8d62013-06-13 15:10:09 -07001363 /* If there are no keys, we can't sign configurations */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001364 if (!IMAGE_ENABLE_SIGN || !(keydir || keyfile))
Simon Glass56ab8d62013-06-13 15:10:09 -07001365 return 0;
1366
1367 /* Find configurations parent node offset */
1368 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
1369 if (confs_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001370 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1371 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Simon Glass56ab8d62013-06-13 15:10:09 -07001372 return -ENOENT;
1373 }
1374
1375 /* Process its subnodes, print out component images details */
1376 for (noffset = fdt_first_subnode(fit, confs_noffset);
1377 noffset >= 0;
1378 noffset = fdt_next_subnode(fit, noffset)) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001379 ret = fit_config_add_verification_data(keydir, keyfile, keydest,
Simon Glass56ab8d62013-06-13 15:10:09 -07001380 fit, noffset, comment,
George McCollister23d14892017-01-06 13:14:17 -06001381 require_keys,
Jan Kiszka4043f322022-01-14 10:21:19 +01001382 engine_id, cmdname,
Simon Glasse4607262021-11-12 12:28:13 -07001383 algo_name, summary);
Simon Glass56ab8d62013-06-13 15:10:09 -07001384 if (ret)
1385 return ret;
1386 }
1387
Simon Glass10a1eca2013-05-07 06:11:54 +00001388 return 0;
1389}
Heiko Schocherd7b42322014-03-03 12:19:30 +01001390
1391#ifdef CONFIG_FIT_SIGNATURE
Simon Glass05712322020-03-18 11:44:03 -06001392int fit_check_sign(const void *fit, const void *key,
1393 const char *fit_uname_config)
Heiko Schocherd7b42322014-03-03 12:19:30 +01001394{
1395 int cfg_noffset;
1396 int ret;
1397
Simon Glass05712322020-03-18 11:44:03 -06001398 cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
Heiko Schocherd7b42322014-03-03 12:19:30 +01001399 if (!cfg_noffset)
1400 return -1;
1401
Simon Glassa559bb22020-03-18 11:43:56 -06001402 printf("Verifying Hash Integrity for node '%s'... ",
1403 fdt_get_name(fit, cfg_noffset, NULL));
Simon Glassa51991d2014-06-12 07:24:53 -06001404 ret = fit_config_verify(fit, cfg_noffset);
1405 if (ret)
1406 return ret;
Simon Glass05712322020-03-18 11:44:03 -06001407 printf("Verified OK, loading images\n");
Simon Glassa51991d2014-06-12 07:24:53 -06001408 ret = bootm_host_load_images(fit, cfg_noffset);
1409
Heiko Schocherd7b42322014-03-03 12:19:30 +01001410 return ret;
1411}
1412#endif