blob: a9b8690276386aa21983612c6a306b7897a0af26 [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
Paul HENRYSee5925a2025-02-24 22:20:50 +010022#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
23#include <openssl/rsa.h>
24#include <openssl/err.h>
25#endif
26
Simon Glass10a1eca2013-05-07 06:11:54 +000027/**
Simon Glass0ce6e3d2013-05-07 06:11:56 +000028 * fit_set_hash_value - set hash value in requested has node
29 * @fit: pointer to the FIT format image header
30 * @noffset: hash node offset
31 * @value: hash value to be set
32 * @value_len: hash value length
33 *
34 * fit_set_hash_value() attempts to set hash value in a node at offset
35 * given and returns operation status to the caller.
36 *
37 * returns
38 * 0, on success
39 * -1, on failure
40 */
41static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
42 int value_len)
43{
44 int ret;
45
46 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
47 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030048 fprintf(stderr, "Can't set hash '%s' property for '%s' node(%s)\n",
49 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
50 fdt_strerror(ret));
Simon Glassec539f72016-07-03 09:40:44 -060051 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
Simon Glass0ce6e3d2013-05-07 06:11:56 +000052 }
53
54 return 0;
55}
56
57/**
Simon Glass25d6e6b2013-05-07 06:11:55 +000058 * fit_image_process_hash - Process a single subnode of the images/ node
59 *
60 * Check each subnode and process accordingly. For hash nodes we generate
Simon Glass6a0efc82021-11-12 12:28:06 -070061 * a hash of the supplied data and store it in the node.
Simon Glass25d6e6b2013-05-07 06:11:55 +000062 *
63 * @fit: pointer to the FIT format image header
Simon Glass6a0efc82021-11-12 12:28:06 -070064 * @image_name: name of image being processed (used to display errors)
Simon Glass25d6e6b2013-05-07 06:11:55 +000065 * @noffset: subnode offset
66 * @data: data to process
67 * @size: size of data in bytes
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010068 * Return: 0 if ok, -1 on error
Simon Glass25d6e6b2013-05-07 06:11:55 +000069 */
70static int fit_image_process_hash(void *fit, const char *image_name,
71 int noffset, const void *data, size_t size)
72{
73 uint8_t value[FIT_MAX_HASH_LEN];
Simon Glassee382652013-05-07 06:12:01 +000074 const char *node_name;
Simon Glass25d6e6b2013-05-07 06:11:55 +000075 int value_len;
Jan Kiszka27beec22022-01-14 10:21:17 +010076 const char *algo;
Simon Glassec539f72016-07-03 09:40:44 -060077 int ret;
Simon Glass25d6e6b2013-05-07 06:11:55 +000078
Simon Glassee382652013-05-07 06:12:01 +000079 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass25d6e6b2013-05-07 06:11:55 +000080
81 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030082 fprintf(stderr,
83 "Can't get hash algo property for '%s' hash node in '%s' image node\n",
84 node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060085 return -ENOENT;
Simon Glass25d6e6b2013-05-07 06:11:55 +000086 }
87
88 if (calculate_hash(data, size, algo, value, &value_len)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030089 fprintf(stderr,
90 "Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
91 algo, node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060092 return -EPROTONOSUPPORT;
Simon Glass25d6e6b2013-05-07 06:11:55 +000093 }
94
Simon Glassec539f72016-07-03 09:40:44 -060095 ret = fit_set_hash_value(fit, noffset, value, value_len);
96 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +030097 fprintf(stderr, "Can't set hash value for '%s' hash node in '%s' image node\n",
98 node_name, image_name);
Simon Glassec539f72016-07-03 09:40:44 -060099 return ret;
Simon Glass25d6e6b2013-05-07 06:11:55 +0000100 }
101
102 return 0;
103}
104
105/**
Simon Glassfbabc0f2013-06-13 15:10:01 -0700106 * fit_image_write_sig() - write the signature to a FIT
Simon Glass10a1eca2013-05-07 06:11:54 +0000107 *
Simon Glassfbabc0f2013-06-13 15:10:01 -0700108 * This writes the signature and signer data to the FIT.
109 *
110 * @fit: pointer to the FIT format image header
111 * @noffset: hash node offset
112 * @value: signature value to be set
113 * @value_len: signature value length
114 * @comment: Text comment to write (NULL for none)
115 *
116 * returns
117 * 0, on success
118 * -FDT_ERR_..., on failure
119 */
120static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
121 int value_len, const char *comment, const char *region_prop,
Jan Kiszka4043f322022-01-14 10:21:19 +0100122 int region_proplen, const char *cmdname, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700123{
124 int string_size;
125 int ret;
126
127 /*
128 * Get the current string size, before we update the FIT and add
129 * more
130 */
131 string_size = fdt_size_dt_strings(fit);
132
133 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
134 if (!ret) {
135 ret = fdt_setprop_string(fit, noffset, "signer-name",
136 "mkimage");
137 }
138 if (!ret) {
139 ret = fdt_setprop_string(fit, noffset, "signer-version",
140 PLAIN_VERSION);
141 }
142 if (comment && !ret)
143 ret = fdt_setprop_string(fit, noffset, "comment", comment);
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000144 if (!ret) {
145 time_t timestamp = imagetool_get_source_date(cmdname,
146 time(NULL));
Ming Liuf75f1d72021-05-31 09:04:51 +0200147 uint32_t t = cpu_to_uimage(timestamp);
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000148
Ming Liuf75f1d72021-05-31 09:04:51 +0200149 ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
150 sizeof(uint32_t));
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000151 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700152 if (region_prop && !ret) {
153 uint32_t strdata[2];
154
155 ret = fdt_setprop(fit, noffset, "hashed-nodes",
156 region_prop, region_proplen);
Teddy Reed9767bf42018-06-09 11:45:20 -0400157 /* This is a legacy offset, it is unused, and must remain 0. */
Simon Glassfbabc0f2013-06-13 15:10:01 -0700158 strdata[0] = 0;
159 strdata[1] = cpu_to_fdt32(string_size);
160 if (!ret) {
161 ret = fdt_setprop(fit, noffset, "hashed-strings",
162 strdata, sizeof(strdata));
163 }
164 }
Jan Kiszka4043f322022-01-14 10:21:19 +0100165 if (algo_name && !ret)
166 ret = fdt_setprop_string(fit, noffset, "algo", algo_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700167
168 return ret;
169}
170
171static int fit_image_setup_sig(struct image_sign_info *info,
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600172 const char *keydir, const char *keyfile, void *fit,
173 const char *image_name, int noffset, const char *require_keys,
Jan Kiszka4043f322022-01-14 10:21:19 +0100174 const char *engine_id, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700175{
176 const char *node_name;
Philippe Reynes12468352018-11-14 13:51:00 +0100177 const char *padding_name;
Simon Glassfbabc0f2013-06-13 15:10:01 -0700178
179 node_name = fit_get_name(fit, noffset, NULL);
Jan Kiszka4043f322022-01-14 10:21:19 +0100180 if (!algo_name) {
181 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300182 fprintf(stderr,
183 "Can't get algo property for '%s' signature node in '%s' image node\n",
184 node_name, image_name);
Jan Kiszka4043f322022-01-14 10:21:19 +0100185 return -1;
186 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700187 }
188
Philippe Reynes12468352018-11-14 13:51:00 +0100189 padding_name = fdt_getprop(fit, noffset, "padding", NULL);
190
Simon Glassfbabc0f2013-06-13 15:10:01 -0700191 memset(info, '\0', sizeof(*info));
192 info->keydir = keydir;
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600193 info->keyfile = keyfile;
Simon Glassd7aabcc2020-03-18 11:44:06 -0600194 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700195 info->fit = fit;
196 info->node_offset = noffset;
Masahiro Yamadac1f137b2017-10-27 13:25:21 +0900197 info->name = strdup(algo_name);
Andrew Duda6616c822016-11-08 18:53:41 +0000198 info->checksum = image_get_checksum_algo(algo_name);
199 info->crypto = image_get_crypto_algo(algo_name);
Philippe Reynes12468352018-11-14 13:51:00 +0100200 info->padding = image_get_padding_algo(padding_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700201 info->require_keys = require_keys;
George McCollister23d14892017-01-06 13:14:17 -0600202 info->engine_id = engine_id;
Andrew Duda6616c822016-11-08 18:53:41 +0000203 if (!info->checksum || !info->crypto) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300204 fprintf(stderr,
205 "Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
206 algo_name, node_name, image_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700207 return -1;
208 }
209
210 return 0;
211}
212
213/**
214 * fit_image_process_sig- Process a single subnode of the images/ node
215 *
216 * Check each subnode and process accordingly. For signature nodes we
Simon Glass6a0efc82021-11-12 12:28:06 -0700217 * generate a signed hash of the supplied data and store it in the node.
Simon Glassfbabc0f2013-06-13 15:10:01 -0700218 *
219 * @keydir: Directory containing keys to use for signing
Simon Glass6a0efc82021-11-12 12:28:06 -0700220 * @keydest: Destination FDT blob to write public keys into (NULL if none)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700221 * @fit: pointer to the FIT format image header
Simon Glass6a0efc82021-11-12 12:28:06 -0700222 * @image_name: name of image being processed (used to display errors)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700223 * @noffset: subnode offset
224 * @data: data to process
225 * @size: size of data in bytes
226 * @comment: Comment to add to signature nodes
227 * @require_keys: Mark all keys as 'required'
George McCollister23d14892017-01-06 13:14:17 -0600228 * @engine_id: Engine to use for signing
Simon Glass89c3fb62021-11-12 12:28:12 -0700229 * Return: keydest node if @keydest is non-NULL, else 0 if none; -ve error code
230 * on failure
Simon Glassfbabc0f2013-06-13 15:10:01 -0700231 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600232static int fit_image_process_sig(const char *keydir, const char *keyfile,
233 void *keydest, void *fit, const char *image_name,
Simon Glassfbabc0f2013-06-13 15:10:01 -0700234 int noffset, const void *data, size_t size,
Alex Kiernan697fcdc2018-06-20 20:10:52 +0000235 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +0100236 const char *cmdname, const char *algo_name)
Simon Glassfbabc0f2013-06-13 15:10:01 -0700237{
238 struct image_sign_info info;
239 struct image_region region;
240 const char *node_name;
241 uint8_t *value;
242 uint value_len;
243 int ret;
244
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600245 if (fit_image_setup_sig(&info, keydir, keyfile, fit, image_name,
246 noffset, require_keys ? "image" : NULL,
Jan Kiszka4043f322022-01-14 10:21:19 +0100247 engine_id, algo_name))
Simon Glassfbabc0f2013-06-13 15:10:01 -0700248 return -1;
249
250 node_name = fit_get_name(fit, noffset, NULL);
251 region.data = data;
252 region.size = size;
Andrew Duda6616c822016-11-08 18:53:41 +0000253 ret = info.crypto->sign(&info, &region, 1, &value, &value_len);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700254 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300255 fprintf(stderr, "Failed to sign '%s' signature node in '%s' image node: %d\n",
256 node_name, image_name, ret);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700257
258 /* We allow keys to be missing */
259 if (ret == -ENOENT)
260 return 0;
261 return -1;
262 }
263
264 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +0100265 NULL, 0, cmdname, algo_name);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700266 if (ret) {
Simon Glass802aa822014-06-02 22:04:53 -0600267 if (ret == -FDT_ERR_NOSPACE)
268 return -ENOSPC;
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300269 fprintf(stderr,
270 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
271 node_name, image_name, fdt_strerror(ret));
Simon Glassfbabc0f2013-06-13 15:10:01 -0700272 return -1;
273 }
274 free(value);
275
276 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glassd7aabcc2020-03-18 11:44:06 -0600277 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glassfbabc0f2013-06-13 15:10:01 -0700278
mario.six@gdsys.ccdc4053a2016-07-22 08:58:40 +0200279 /*
280 * Write the public key into the supplied FDT file; this might fail
mario.six@gdsys.ccd019e152016-07-19 11:07:06 +0200281 * several times, since we try signing with successively increasing
mario.six@gdsys.ccdc4053a2016-07-22 08:58:40 +0200282 * size values
283 */
Masahiro Yamada01486762017-10-27 15:04:20 +0900284 if (keydest) {
285 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glass94336dc2021-11-12 12:28:11 -0700286 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300287 fprintf(stderr,
288 "Failed to add verification data for '%s' signature node in '%s' image node\n",
289 node_name, image_name);
Masahiro Yamada01486762017-10-27 15:04:20 +0900290 return ret;
291 }
Simon Glass89c3fb62021-11-12 12:28:12 -0700292 /* Return the node that was written to */
293 return ret;
Masahiro Yamada01486762017-10-27 15:04:20 +0900294 }
Simon Glassfbabc0f2013-06-13 15:10:01 -0700295
296 return 0;
297}
298
Philippe Reynes3148e422019-12-18 18:25:41 +0100299static int fit_image_read_data(char *filename, unsigned char *data,
300 int expected_size)
301{
302 struct stat sbuf;
303 int fd, ret = -1;
304 ssize_t n;
305
306 /* Open file */
307 fd = open(filename, O_RDONLY | O_BINARY);
308 if (fd < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300309 fprintf(stderr, "Can't open file %s (err=%d => %s)\n",
310 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100311 return -1;
312 }
313
314 /* Compute file size */
315 if (fstat(fd, &sbuf) < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300316 fprintf(stderr, "Can't fstat file %s (err=%d => %s)\n",
317 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100318 goto err;
319 }
320
321 /* Check file size */
322 if (sbuf.st_size != expected_size) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300323 fprintf(stderr, "File %s don't have the expected size (size=%lld, expected=%d)\n",
324 filename, (long long)sbuf.st_size, expected_size);
Philippe Reynes3148e422019-12-18 18:25:41 +0100325 goto err;
326 }
327
328 /* Read data */
329 n = read(fd, data, sbuf.st_size);
330 if (n < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300331 fprintf(stderr, "Can't read file %s (err=%d => %s)\n",
332 filename, errno, strerror(errno));
Philippe Reynes3148e422019-12-18 18:25:41 +0100333 goto err;
334 }
335
336 /* Check that we have read all the file */
337 if (n != sbuf.st_size) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300338 fprintf(stderr, "Can't read all file %s (read %zd bytes, expected %lld)\n",
339 filename, n, (long long)sbuf.st_size);
Philippe Reynes3148e422019-12-18 18:25:41 +0100340 goto err;
341 }
342
343 ret = 0;
344
345err:
346 close(fd);
347 return ret;
348}
349
Hugo Cornelis92814842024-01-08 15:24:30 +0100350static int fit_image_read_key_iv_data(const char *keydir, const char *key_iv_name,
351 unsigned char *key_iv_data, int expected_size)
352{
353 char filename[PATH_MAX];
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100354 int ret;
Hugo Cornelis92814842024-01-08 15:24:30 +0100355
356 ret = snprintf(filename, sizeof(filename), "%s/%s%s",
357 keydir, key_iv_name, ".bin");
358 if (ret >= sizeof(filename)) {
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100359 fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: insufficient buffer space\n");
360 return -1;
Hugo Cornelis92814842024-01-08 15:24:30 +0100361 }
362 if (ret < 0) {
Hugo Cornelis23b571e2024-03-21 12:22:22 +0100363 fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: snprintf error\n");
364 return -1;
Hugo Cornelis92814842024-01-08 15:24:30 +0100365 }
366
367 ret = fit_image_read_data(filename, key_iv_data, expected_size);
368
369 return ret;
370}
371
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100372/**
373 * get_random_data() - fill buffer with random data
374 *
375 * There is no common cryptographically safe function in Linux and BSD.
376 * Hence directly access the /dev/urandom PRNG.
377 *
378 * @data: buffer to fill
379 * @size: buffer size
380 */
381static int get_random_data(void *data, size_t size)
Philippe Reynes64d67c42020-09-17 15:01:46 +0200382{
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100383 int fd;
384 int ret;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200385
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100386 fd = open("/dev/urandom", O_RDONLY);
387 if (fd < 0) {
388 perror("Failed to open /dev/urandom");
389 return -1;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200390 }
391
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100392 while (size) {
393 ssize_t count;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200394
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100395 count = read(fd, data, size);
396 if (count < 0) {
397 if (errno == EINTR) {
398 continue;
399 } else {
400 perror("Failed to read from /dev/urandom");
401 ret = -1;
402 goto out;
403 }
404 }
405 data += count;
406 size -= count;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200407 }
Heinrich Schuchardta7747502025-02-11 14:55:22 +0100408 ret = 0;
409out:
410 close(fd);
Philippe Reynes64d67c42020-09-17 15:01:46 +0200411
Philippe Reynes64d67c42020-09-17 15:01:46 +0200412 return ret;
413}
414
Philippe Reynes3148e422019-12-18 18:25:41 +0100415static int fit_image_setup_cipher(struct image_cipher_info *info,
416 const char *keydir, void *fit,
417 const char *image_name, int image_noffset,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000418 int noffset)
Philippe Reynes3148e422019-12-18 18:25:41 +0100419{
420 char *algo_name;
Philippe Reynes3148e422019-12-18 18:25:41 +0100421 int ret = -1;
422
423 if (fit_image_cipher_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300424 fprintf(stderr, "Can't get algo name for cipher in image '%s'\n",
425 image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100426 goto out;
427 }
428
429 info->keydir = keydir;
430
431 /* Read the key name */
Simon Glassd7aabcc2020-03-18 11:44:06 -0600432 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Philippe Reynes3148e422019-12-18 18:25:41 +0100433 if (!info->keyname) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300434 fprintf(stderr, "Can't get key name for cipher in image '%s'\n",
435 image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100436 goto out;
437 }
438
Philippe Reynes64d67c42020-09-17 15:01:46 +0200439 /*
440 * Read the IV name
441 *
442 * If this property is not provided then mkimage will generate
443 * a random IV and store it in the FIT image
444 */
Philippe Reynes3148e422019-12-18 18:25:41 +0100445 info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL);
Philippe Reynes3148e422019-12-18 18:25:41 +0100446
447 info->fit = fit;
448 info->node_noffset = noffset;
449 info->name = algo_name;
450
451 info->cipher = image_get_cipher_algo(algo_name);
452 if (!info->cipher) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300453 fprintf(stderr, "Can't get algo for cipher '%s'\n", image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100454 goto out;
455 }
456
Philippe Reynes3148e422019-12-18 18:25:41 +0100457 info->key = malloc(info->cipher->key_len);
458 if (!info->key) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300459 fprintf(stderr, "Can't allocate memory for key\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100460 ret = -1;
461 goto out;
462 }
Hugo Cornelis92814842024-01-08 15:24:30 +0100463
464 /* Read the key in the file */
465 ret = fit_image_read_key_iv_data(info->keydir, info->keyname,
466 (unsigned char *)info->key,
467 info->cipher->key_len);
Philippe Reynes3148e422019-12-18 18:25:41 +0100468 if (ret < 0)
469 goto out;
470
Philippe Reynes3148e422019-12-18 18:25:41 +0100471 info->iv = malloc(info->cipher->iv_len);
472 if (!info->iv) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300473 fprintf(stderr, "Can't allocate memory for iv\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100474 ret = -1;
475 goto out;
476 }
Philippe Reynes64d67c42020-09-17 15:01:46 +0200477
478 if (info->ivname) {
479 /* Read the IV in the file */
Hugo Cornelis92814842024-01-08 15:24:30 +0100480 ret = fit_image_read_key_iv_data(info->keydir, info->ivname,
481 (unsigned char *)info->iv,
482 info->cipher->iv_len);
483 if (ret < 0)
484 goto out;
Philippe Reynes64d67c42020-09-17 15:01:46 +0200485 } else {
486 /* Generate an ramdom IV */
487 ret = get_random_data((void *)info->iv, info->cipher->iv_len);
488 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100489
490 out:
491 return ret;
492}
493
494int fit_image_write_cipher(void *fit, int image_noffset, int noffset,
495 const void *data, size_t size,
496 unsigned char *data_ciphered, int data_ciphered_len)
497{
498 int ret = -1;
499
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000500 /* Replace data with ciphered data */
Philippe Reynes3148e422019-12-18 18:25:41 +0100501 ret = fdt_setprop(fit, image_noffset, FIT_DATA_PROP,
502 data_ciphered, data_ciphered_len);
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000503 if (ret == -FDT_ERR_NOSPACE) {
504 ret = -ENOSPC;
505 goto out;
506 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100507 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300508 fprintf(stderr, "Can't replace data with ciphered data (err = %d)\n", ret);
Philippe Reynes3148e422019-12-18 18:25:41 +0100509 goto out;
510 }
511
512 /* add non ciphered data size */
513 ret = fdt_setprop_u32(fit, image_noffset, "data-size-unciphered", size);
Patrick Oppenlanderbe472112020-07-30 14:22:14 +1000514 if (ret == -FDT_ERR_NOSPACE) {
515 ret = -ENOSPC;
516 goto out;
517 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100518 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300519 fprintf(stderr, "Can't add unciphered data size (err = %d)\n", ret);
Philippe Reynes3148e422019-12-18 18:25:41 +0100520 goto out;
521 }
522
523 out:
524 return ret;
525}
526
527static int
528fit_image_process_cipher(const char *keydir, void *keydest, void *fit,
529 const char *image_name, int image_noffset,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000530 int node_noffset, const void *data, size_t size,
Philippe Reynes3148e422019-12-18 18:25:41 +0100531 const char *cmdname)
532{
533 struct image_cipher_info info;
534 unsigned char *data_ciphered = NULL;
535 int data_ciphered_len;
536 int ret;
537
538 memset(&info, 0, sizeof(info));
539
540 ret = fit_image_setup_cipher(&info, keydir, fit, image_name,
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000541 image_noffset, node_noffset);
Philippe Reynes3148e422019-12-18 18:25:41 +0100542 if (ret)
543 goto out;
544
545 ret = info.cipher->encrypt(&info, data, size,
546 &data_ciphered, &data_ciphered_len);
547 if (ret)
548 goto out;
549
550 /*
551 * Write the public key into the supplied FDT file; this might fail
552 * several times, since we try signing with successively increasing
553 * size values
Philippe Reynes64d67c42020-09-17 15:01:46 +0200554 * And, if needed, write the iv in the FIT file
Philippe Reynes3148e422019-12-18 18:25:41 +0100555 */
Paul HENRYS07019912024-11-25 18:47:15 +0100556 if (keydest || (!keydest && !info.ivname)) {
Philippe Reynes64d67c42020-09-17 15:01:46 +0200557 ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
Philippe Reynes3148e422019-12-18 18:25:41 +0100558 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300559 fprintf(stderr,
560 "Failed to add verification data for cipher '%s' in image '%s'\n",
561 info.keyname, image_name);
Philippe Reynes3148e422019-12-18 18:25:41 +0100562 goto out;
563 }
564 }
565
566 ret = fit_image_write_cipher(fit, image_noffset, node_noffset,
567 data, size,
568 data_ciphered, data_ciphered_len);
569
570 out:
571 free(data_ciphered);
572 free((void *)info.key);
573 free((void *)info.iv);
574 return ret;
575}
576
577int fit_image_cipher_data(const char *keydir, void *keydest,
578 void *fit, int image_noffset, const char *comment,
579 int require_keys, const char *engine_id,
580 const char *cmdname)
581{
582 const char *image_name;
583 const void *data;
584 size_t size;
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000585 int cipher_node_offset, len;
Philippe Reynes3148e422019-12-18 18:25:41 +0100586
587 /* Get image name */
588 image_name = fit_get_name(fit, image_noffset, NULL);
589 if (!image_name) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300590 fprintf(stderr, "Can't get image name\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100591 return -1;
592 }
593
594 /* Get image data and data length */
Simon Glassd3ca4012025-01-10 17:00:12 -0700595 if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300596 fprintf(stderr, "Can't get image data/size\n");
Philippe Reynes3148e422019-12-18 18:25:41 +0100597 return -1;
598 }
599
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000600 /*
601 * Don't cipher ciphered data.
602 *
603 * If the data-size-unciphered property is present the data for this
604 * image is already encrypted. This is important as 'mkimage -F' can be
605 * run multiple times on a FIT image.
606 */
607 if (fdt_getprop(fit, image_noffset, "data-size-unciphered", &len))
608 return 0;
609 if (len != -FDT_ERR_NOTFOUND) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300610 fprintf(stderr, "Failure testing for data-size-unciphered\n");
Patrick Oppenlandera4fafb32020-07-30 14:22:15 +1000611 return -1;
612 }
Philippe Reynes3148e422019-12-18 18:25:41 +0100613
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000614 /* Process cipher node if present */
615 cipher_node_offset = fdt_subnode_offset(fit, image_noffset,
616 FIT_CIPHER_NODENAME);
617 if (cipher_node_offset == -FDT_ERR_NOTFOUND)
618 return 0;
619 if (cipher_node_offset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300620 fprintf(stderr, "Failure getting cipher node\n");
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000621 return -1;
Philippe Reynes3148e422019-12-18 18:25:41 +0100622 }
Patrick Oppenlanderd586fc32020-07-30 14:22:13 +1000623 if (!IMAGE_ENABLE_ENCRYPT || !keydir)
624 return 0;
625 return fit_image_process_cipher(keydir, keydest, fit, image_name,
626 image_noffset, cipher_node_offset, data, size, cmdname);
Philippe Reynes3148e422019-12-18 18:25:41 +0100627}
628
Simon Glassfbabc0f2013-06-13 15:10:01 -0700629/**
630 * fit_image_add_verification_data() - calculate/set verig. data for image node
631 *
632 * This adds hash and signature values for an component image node.
Simon Glassee382652013-05-07 06:12:01 +0000633 *
634 * All existing hash subnodes are checked, if algorithm property is set to
635 * one of the supported hash algorithms, hash value is computed and
636 * corresponding hash node property is set, for example:
Simon Glass10a1eca2013-05-07 06:11:54 +0000637 *
638 * Input component image node structure:
639 *
Andre Przywara3234ecd2017-12-04 02:05:10 +0000640 * o image-1 (at image_noffset)
Simon Glass10a1eca2013-05-07 06:11:54 +0000641 * | - data = [binary data]
Andre Przywara3234ecd2017-12-04 02:05:10 +0000642 * o hash-1
Simon Glass10a1eca2013-05-07 06:11:54 +0000643 * |- algo = "sha1"
644 *
645 * Output component image node structure:
646 *
Andre Przywara3234ecd2017-12-04 02:05:10 +0000647 * o image-1 (at image_noffset)
Simon Glass10a1eca2013-05-07 06:11:54 +0000648 * | - data = [binary data]
Andre Przywara3234ecd2017-12-04 02:05:10 +0000649 * o hash-1
Simon Glass10a1eca2013-05-07 06:11:54 +0000650 * |- algo = "sha1"
651 * |- value = sha1(data)
652 *
Simon Glassee382652013-05-07 06:12:01 +0000653 * For signature details, please see doc/uImage.FIT/signature.txt
654 *
Simon Glassfbabc0f2013-06-13 15:10:01 -0700655 * @keydir Directory containing *.key and *.crt files (or NULL)
656 * @keydest FDT Blob to write public keys into (NULL if none)
Simon Glassee382652013-05-07 06:12:01 +0000657 * @fit: Pointer to the FIT format image header
658 * @image_noffset: Requested component image node
Simon Glassfbabc0f2013-06-13 15:10:01 -0700659 * @comment: Comment to add to signature nodes
660 * @require_keys: Mark all keys as 'required'
George McCollister23d14892017-01-06 13:14:17 -0600661 * @engine_id: Engine to use for signing
Simon Glassee382652013-05-07 06:12:01 +0000662 * @return: 0 on success, <0 on failure
Simon Glass10a1eca2013-05-07 06:11:54 +0000663 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600664int fit_image_add_verification_data(const char *keydir, const char *keyfile,
665 void *keydest, void *fit, int image_noffset,
666 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +0100667 const char *cmdname, const char* algo_name)
Simon Glass10a1eca2013-05-07 06:11:54 +0000668{
Simon Glassee382652013-05-07 06:12:01 +0000669 const char *image_name;
Simon Glass10a1eca2013-05-07 06:11:54 +0000670 const void *data;
671 size_t size;
Simon Glass10a1eca2013-05-07 06:11:54 +0000672 int noffset;
Simon Glass10a1eca2013-05-07 06:11:54 +0000673
674 /* Get image data and data length */
Simon Glassd3ca4012025-01-10 17:00:12 -0700675 if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300676 fprintf(stderr, "Can't get image data/size\n");
Simon Glass10a1eca2013-05-07 06:11:54 +0000677 return -1;
678 }
679
Simon Glass25d6e6b2013-05-07 06:11:55 +0000680 image_name = fit_get_name(fit, image_noffset, NULL);
681
Simon Glass10a1eca2013-05-07 06:11:54 +0000682 /* Process all hash subnodes of the component image node */
Simon Glassee382652013-05-07 06:12:01 +0000683 for (noffset = fdt_first_subnode(fit, image_noffset);
684 noffset >= 0;
685 noffset = fdt_next_subnode(fit, noffset)) {
686 const char *node_name;
687 int ret = 0;
688
689 /*
690 * Check subnode name, must be equal to "hash" or "signature".
691 * Multiple hash nodes require unique unit node
Andre Przywara3234ecd2017-12-04 02:05:10 +0000692 * names, e.g. hash-1, hash-2, signature-1, etc.
Simon Glassee382652013-05-07 06:12:01 +0000693 */
694 node_name = fit_get_name(fit, noffset, NULL);
695 if (!strncmp(node_name, FIT_HASH_NODENAME,
696 strlen(FIT_HASH_NODENAME))) {
697 ret = fit_image_process_hash(fit, image_name, noffset,
698 data, size);
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600699 } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) &&
Simon Glassfbabc0f2013-06-13 15:10:01 -0700700 !strncmp(node_name, FIT_SIG_NODENAME,
701 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -0600702 ret = fit_image_process_sig(keydir, keyfile, keydest,
Simon Glassfbabc0f2013-06-13 15:10:01 -0700703 fit, image_name, noffset, data, size,
Jan Kiszka4043f322022-01-14 10:21:19 +0100704 comment, require_keys, engine_id, cmdname,
705 algo_name);
Simon Glass10a1eca2013-05-07 06:11:54 +0000706 }
Simon Glass89c3fb62021-11-12 12:28:12 -0700707 if (ret < 0)
Simon Glassec539f72016-07-03 09:40:44 -0600708 return ret;
Simon Glassee382652013-05-07 06:12:01 +0000709 }
710
711 return 0;
712}
713
Simon Glass56ab8d62013-06-13 15:10:09 -0700714struct strlist {
715 int count;
716 char **strings;
717};
718
719static void strlist_init(struct strlist *list)
720{
721 memset(list, '\0', sizeof(*list));
722}
723
724static void strlist_free(struct strlist *list)
725{
726 int i;
727
728 for (i = 0; i < list->count; i++)
729 free(list->strings[i]);
730 free(list->strings);
731}
732
733static int strlist_add(struct strlist *list, const char *str)
734{
735 char *dup;
736
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300737 if (!list || !str)
738 return -1;
739
Simon Glass56ab8d62013-06-13 15:10:09 -0700740 dup = strdup(str);
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300741 if(!dup)
742 return -1;
743
Simon Glass56ab8d62013-06-13 15:10:09 -0700744 list->strings = realloc(list->strings,
745 (list->count + 1) * sizeof(char *));
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300746 if (!list->strings) {
747 free(dup);
Simon Glass56ab8d62013-06-13 15:10:09 -0700748 return -1;
Anton Moryakov35edf1a2025-01-30 16:42:43 +0300749 }
750
Simon Glass56ab8d62013-06-13 15:10:09 -0700751 list->strings[list->count++] = dup;
752
753 return 0;
754}
755
Simon Glass6a0efc82021-11-12 12:28:06 -0700756static const char *fit_config_get_image_list(const void *fit, int noffset,
757 int *lenp, int *allow_missingp)
Simon Glass56ab8d62013-06-13 15:10:09 -0700758{
759 static const char default_list[] = FIT_KERNEL_PROP "\0"
Alexander Dahl907ee6a2024-06-20 16:20:59 +0200760 FIT_FDT_PROP "\0" FIT_SCRIPT_PROP;
Simon Glass56ab8d62013-06-13 15:10:09 -0700761 const char *prop;
762
Simon Glass6a0efc82021-11-12 12:28:06 -0700763 /* If there is an "sign-image" property, use that */
Simon Glass56ab8d62013-06-13 15:10:09 -0700764 prop = fdt_getprop(fit, noffset, "sign-images", lenp);
765 if (prop) {
766 *allow_missingp = 0;
767 return *lenp ? prop : NULL;
768 }
769
770 /* Default image list */
771 *allow_missingp = 1;
772 *lenp = sizeof(default_list);
773
774 return default_list;
775}
776
Simon Glass6a0efc82021-11-12 12:28:06 -0700777/**
778 * fit_config_add_hash() - Add a list of nodes to hash for an image
779 *
780 * This adds a list of paths to image nodes (as referred to by a particular
781 * offset) that need to be hashed, to protect a configuration
782 *
783 * @fit: Pointer to the FIT format image header
784 * @image_noffset: Offset of image to process (e.g. /images/kernel-1)
785 * @node_inc: List of nodes to add to
786 * @conf_name Configuration-node name, child of /configurations node (only
787 * used for error messages)
788 * @sig_name Signature-node name (only used for error messages)
789 * @iname: Name of image being processed (e.g. "kernel-1" (only used
790 * for error messages)
791 */
792static int fit_config_add_hash(const void *fit, int image_noffset,
793 struct strlist *node_inc, const char *conf_name,
794 const char *sig_name, const char *iname)
Philippe Reynes856bcc82020-11-24 14:39:47 +0100795{
Simon Glass888c0c52021-11-12 12:28:07 -0700796 char path[200];
Philippe Reynes856bcc82020-11-24 14:39:47 +0100797 int noffset;
798 int hash_count;
799 int ret;
800
801 ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
802 if (ret < 0)
803 goto err_path;
804 if (strlist_add(node_inc, path))
805 goto err_mem;
806
Philippe Reynes856bcc82020-11-24 14:39:47 +0100807 /* Add all this image's hashes */
808 hash_count = 0;
809 for (noffset = fdt_first_subnode(fit, image_noffset);
810 noffset >= 0;
811 noffset = fdt_next_subnode(fit, noffset)) {
812 const char *name = fit_get_name(fit, noffset, NULL);
813
814 if (strncmp(name, FIT_HASH_NODENAME,
815 strlen(FIT_HASH_NODENAME)))
816 continue;
817 ret = fdt_get_path(fit, noffset, path, sizeof(path));
818 if (ret < 0)
819 goto err_path;
820 if (strlist_add(node_inc, path))
821 goto err_mem;
822 hash_count++;
823 }
824
825 if (!hash_count) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300826 fprintf(stderr,
827 "Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
828 conf_name, sig_name, iname);
Philippe Reynes856bcc82020-11-24 14:39:47 +0100829 return -ENOMSG;
830 }
831
832 /* Add this image's cipher node if present */
833 noffset = fdt_subnode_offset(fit, image_noffset,
834 FIT_CIPHER_NODENAME);
835 if (noffset != -FDT_ERR_NOTFOUND) {
836 if (noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300837 fprintf(stderr,
838 "Failed to get cipher node in configuration '%s/%s' image '%s': %s\n",
839 conf_name, sig_name, iname,
840 fdt_strerror(noffset));
Philippe Reynes856bcc82020-11-24 14:39:47 +0100841 return -EIO;
842 }
843 ret = fdt_get_path(fit, noffset, path, sizeof(path));
844 if (ret < 0)
845 goto err_path;
846 if (strlist_add(node_inc, path))
847 goto err_mem;
848 }
849
850 return 0;
851
852err_mem:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300853 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
854 sig_name);
Philippe Reynes856bcc82020-11-24 14:39:47 +0100855 return -ENOMEM;
856
857err_path:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300858 fprintf(stderr, "Failed to get path for image '%s' in configuration '%s/%s': %s\n",
859 iname, conf_name, sig_name, fdt_strerror(ret));
Philippe Reynes856bcc82020-11-24 14:39:47 +0100860 return -ENOENT;
861}
862
Simon Glass6a0efc82021-11-12 12:28:06 -0700863/**
864 * fit_config_get_hash_list() - Get the regions to sign
865 *
866 * This calculates a list of nodes to hash for this particular configuration,
867 * returning it as a string list (struct strlist, not a devicetree string list)
868 *
869 * @fit: Pointer to the FIT format image header
870 * @conf_noffset: Offset of configuration node to sign (child of
871 * /configurations node)
872 * @sig_offset: Offset of signature node containing info about how to sign it
873 * (child of 'signatures' node)
874 * @return 0 if OK, -ENOENT if an image referred to by the configuration cannot
875 * be found, -ENOMSG if ther were no images in the configuration
876 */
877static int fit_config_get_hash_list(const void *fit, int conf_noffset,
Simon Glass56ab8d62013-06-13 15:10:09 -0700878 int sig_offset, struct strlist *node_inc)
879{
880 int allow_missing;
881 const char *prop, *iname, *end;
882 const char *conf_name, *sig_name;
Philippe Reynes856bcc82020-11-24 14:39:47 +0100883 char name[200];
Simon Glass56ab8d62013-06-13 15:10:09 -0700884 int image_count;
885 int ret, len;
886
887 conf_name = fit_get_name(fit, conf_noffset, NULL);
888 sig_name = fit_get_name(fit, sig_offset, NULL);
889
890 /*
891 * Build a list of nodes we need to hash. We always need the root
892 * node and the configuration.
893 */
894 strlist_init(node_inc);
895 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
896 if (strlist_add(node_inc, "/") ||
897 strlist_add(node_inc, name))
898 goto err_mem;
899
900 /* Get a list of images that we intend to sign */
Heiko Schocherfdfd5202014-03-03 12:19:23 +0100901 prop = fit_config_get_image_list(fit, sig_offset, &len,
Simon Glass56ab8d62013-06-13 15:10:09 -0700902 &allow_missing);
903 if (!prop)
904 return 0;
905
906 /* Locate the images */
907 end = prop + len;
908 image_count = 0;
909 for (iname = prop; iname < end; iname += strlen(iname) + 1) {
Simon Glass56ab8d62013-06-13 15:10:09 -0700910 int image_noffset;
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100911 int index, max_index;
Simon Glass56ab8d62013-06-13 15:10:09 -0700912
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100913 max_index = fdt_stringlist_count(fit, conf_noffset, iname);
Simon Glass56ab8d62013-06-13 15:10:09 -0700914
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100915 for (index = 0; index < max_index; index++) {
916 image_noffset = fit_conf_get_prop_node_index(fit, conf_noffset,
917 iname, index);
918
919 if (image_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300920 fprintf(stderr,
921 "Failed to find image '%s' in configuration '%s/%s'\n",
922 iname, conf_name, sig_name);
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100923 if (allow_missing)
924 continue;
Simon Glass56ab8d62013-06-13 15:10:09 -0700925
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100926 return -ENOENT;
927 }
Patrick Oppenlander5964c3f2020-07-30 14:30:47 +1000928
Simon Glass6a0efc82021-11-12 12:28:06 -0700929 ret = fit_config_add_hash(fit, image_noffset, node_inc,
930 conf_name, sig_name, iname);
Philippe Reynes1f7d9a22020-11-24 14:39:48 +0100931 if (ret < 0)
932 return ret;
933
934 image_count++;
935 }
Simon Glass56ab8d62013-06-13 15:10:09 -0700936 }
937
938 if (!image_count) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300939 fprintf(stderr, "Failed to find any images for configuration '%s/%s'\n",
940 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -0700941 return -ENOMSG;
942 }
943
944 return 0;
945
946err_mem:
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +0300947 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
948 sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -0700949 return -ENOMEM;
Simon Glass56ab8d62013-06-13 15:10:09 -0700950}
951
Simon Glass6a0efc82021-11-12 12:28:06 -0700952/**
953 * fit_config_get_regions() - Get the regions to sign
954 *
955 * This calculates a list of node to hash for this particular configuration,
956 * then finds which regions of the devicetree they correspond to.
957 *
958 * @fit: Pointer to the FIT format image header
959 * @conf_noffset: Offset of configuration node to sign (child of
960 * /configurations node)
961 * @sig_offset: Offset of signature node containing info about how to sign it
962 * (child of 'signatures' node)
963 * @regionp: Returns list of regions that need to be hashed (allocated; must be
964 * freed by the caller)
965 * @region_count: Returns number of regions
966 * @region_propp: Returns string-list property containing the list of nodes
967 * that correspond to the regions. Each entry is a full path to the node.
968 * This is in devicetree format, i.e. a \0 between each string. This is
969 * allocated and must be freed by the caller.
970 * @region_proplen: Returns length of *@@region_propp in bytes
971 * @return 0 if OK, -ENOMEM if out of memory, -EIO if the regions to hash could
972 * not be found, -EINVAL if no registers were found to hash
973 */
974static int fit_config_get_regions(const void *fit, int conf_noffset,
975 int sig_offset, struct image_region **regionp,
976 int *region_countp, char **region_propp,
977 int *region_proplen)
Simon Glass56ab8d62013-06-13 15:10:09 -0700978{
Sean Anderson016f4d52022-10-20 15:41:10 -0400979 char * const exc_prop[] = {
980 FIT_DATA_PROP,
981 FIT_DATA_SIZE_PROP,
982 FIT_DATA_POSITION_PROP,
983 FIT_DATA_OFFSET_PROP,
984 };
Simon Glass56ab8d62013-06-13 15:10:09 -0700985 struct strlist node_inc;
986 struct image_region *region;
987 struct fdt_region fdt_regions[100];
988 const char *conf_name, *sig_name;
989 char path[200];
990 int count, i;
991 char *region_prop;
992 int ret, len;
993
994 conf_name = fit_get_name(fit, conf_noffset, NULL);
Simon Glass6a0efc82021-11-12 12:28:06 -0700995 sig_name = fit_get_name(fit, sig_offset, NULL);
Simon Glass56ab8d62013-06-13 15:10:09 -0700996 debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
997
998 /* Get a list of nodes we want to hash */
Simon Glass6a0efc82021-11-12 12:28:06 -0700999 ret = fit_config_get_hash_list(fit, conf_noffset, sig_offset,
1000 &node_inc);
Simon Glass56ab8d62013-06-13 15:10:09 -07001001 if (ret)
1002 return ret;
1003
1004 /* Get a list of regions to hash */
1005 count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
1006 exc_prop, ARRAY_SIZE(exc_prop),
1007 fdt_regions, ARRAY_SIZE(fdt_regions),
1008 path, sizeof(path), 1);
1009 if (count < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001010 fprintf(stderr, "Failed to hash configuration '%s/%s': %s\n", conf_name,
1011 sig_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001012 return -EIO;
1013 }
1014 if (count == 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001015 fprintf(stderr, "No data to hash for configuration '%s/%s': %s\n",
1016 conf_name, sig_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001017 return -EINVAL;
1018 }
1019
1020 /* Build our list of data blocks */
1021 region = fit_region_make_list(fit, fdt_regions, count, NULL);
1022 if (!region) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001023 fprintf(stderr, "Out of memory hashing configuration '%s/%s'\n",
1024 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001025 return -ENOMEM;
1026 }
1027
1028 /* Create a list of all hashed properties */
1029 debug("Hash nodes:\n");
1030 for (i = len = 0; i < node_inc.count; i++) {
1031 debug(" %s\n", node_inc.strings[i]);
1032 len += strlen(node_inc.strings[i]) + 1;
1033 }
1034 region_prop = malloc(len);
1035 if (!region_prop) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001036 fprintf(stderr, "Out of memory setting up regions for configuration '%s/%s'\n",
1037 conf_name, sig_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001038 return -ENOMEM;
1039 }
1040 for (i = len = 0; i < node_inc.count;
1041 len += strlen(node_inc.strings[i]) + 1, i++)
1042 strcpy(region_prop + len, node_inc.strings[i]);
1043 strlist_free(&node_inc);
1044
1045 *region_countp = count;
1046 *regionp = region;
1047 *region_propp = region_prop;
1048 *region_proplen = len;
1049
1050 return 0;
1051}
1052
Simon Glass89c3fb62021-11-12 12:28:12 -07001053/**
1054 * fit_config_process_sig - Process a single subnode of the configurations/ node
1055 *
1056 * Generate a signed hash of the supplied data and store it in the node.
1057 *
1058 * @keydir: Directory containing keys to use for signing
1059 * @keydest: Destination FDT blob to write public keys into (NULL if none)
1060 * @fit: pointer to the FIT format image header
1061 * @conf_name name of config being processed (used to display errors)
1062 * @conf_noffset: Offset of configuration node, e.g. '/configurations/conf-1'
1063 * @noffset: subnode offset, e.g. '/configurations/conf-1/sig-1'
1064 * @comment: Comment to add to signature nodes
1065 * @require_keys: Mark all keys as 'required'
1066 * @engine_id: Engine to use for signing
1067 * @cmdname: Command name used when reporting errors
1068 * @return keydest node if @keydest is non-NULL, else 0 if none; -ve error code
1069 * on failure
1070 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001071static int fit_config_process_sig(const char *keydir, const char *keyfile,
Simon Glass6a0efc82021-11-12 12:28:06 -07001072 void *keydest, void *fit, const char *conf_name,
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001073 int conf_noffset, int noffset, const char *comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001074 int require_keys, const char *engine_id, const char *cmdname,
1075 const char *algo_name)
Simon Glass56ab8d62013-06-13 15:10:09 -07001076{
1077 struct image_sign_info info;
1078 const char *node_name;
1079 struct image_region *region;
1080 char *region_prop;
1081 int region_proplen;
1082 int region_count;
1083 uint8_t *value;
1084 uint value_len;
1085 int ret;
1086
1087 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass6a0efc82021-11-12 12:28:06 -07001088 if (fit_config_get_regions(fit, conf_noffset, noffset, &region,
1089 &region_count, &region_prop,
1090 &region_proplen))
Simon Glass56ab8d62013-06-13 15:10:09 -07001091 return -1;
1092
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001093 if (fit_image_setup_sig(&info, keydir, keyfile, fit, conf_name, noffset,
Jan Kiszka4043f322022-01-14 10:21:19 +01001094 require_keys ? "conf" : NULL, engine_id,
1095 algo_name))
Simon Glass56ab8d62013-06-13 15:10:09 -07001096 return -1;
1097
Andrew Duda6616c822016-11-08 18:53:41 +00001098 ret = info.crypto->sign(&info, region, region_count, &value,
1099 &value_len);
Simon Glass56ab8d62013-06-13 15:10:09 -07001100 free(region);
1101 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001102 fprintf(stderr, "Failed to sign '%s' signature node in '%s' conf node\n",
1103 node_name, conf_name);
Simon Glass56ab8d62013-06-13 15:10:09 -07001104
1105 /* We allow keys to be missing */
1106 if (ret == -ENOENT)
1107 return 0;
1108 return -1;
1109 }
1110
Simon Glass802aa822014-06-02 22:04:53 -06001111 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001112 region_prop, region_proplen, cmdname,
1113 algo_name);
Simon Glass802aa822014-06-02 22:04:53 -06001114 if (ret) {
1115 if (ret == -FDT_ERR_NOSPACE)
1116 return -ENOSPC;
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001117 fprintf(stderr,
1118 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
1119 node_name, conf_name, fdt_strerror(ret));
Simon Glass56ab8d62013-06-13 15:10:09 -07001120 return -1;
1121 }
1122 free(value);
1123 free(region_prop);
1124
1125 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glassd7aabcc2020-03-18 11:44:06 -06001126 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56ab8d62013-06-13 15:10:09 -07001127
1128 /* Write the public key into the supplied FDT file */
Simon Glass802aa822014-06-02 22:04:53 -06001129 if (keydest) {
Andrew Duda6616c822016-11-08 18:53:41 +00001130 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glass94336dc2021-11-12 12:28:11 -07001131 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001132 fprintf(stderr,
1133 "Failed to add verification data for '%s' signature node in '%s' configuration node\n",
1134 node_name, conf_name);
Simon Glass802aa822014-06-02 22:04:53 -06001135 }
Simon Glass89c3fb62021-11-12 12:28:12 -07001136 return ret;
Simon Glass56ab8d62013-06-13 15:10:09 -07001137 }
1138
1139 return 0;
1140}
1141
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001142static int fit_config_add_verification_data(const char *keydir,
1143 const char *keyfile, void *keydest, void *fit, int conf_noffset,
1144 const char *comment, int require_keys, const char *engine_id,
Simon Glasse4607262021-11-12 12:28:13 -07001145 const char *cmdname, const char *algo_name,
1146 struct image_summary *summary)
Simon Glass56ab8d62013-06-13 15:10:09 -07001147{
1148 const char *conf_name;
1149 int noffset;
1150
1151 conf_name = fit_get_name(fit, conf_noffset, NULL);
1152
1153 /* Process all hash subnodes of the configuration node */
1154 for (noffset = fdt_first_subnode(fit, conf_noffset);
1155 noffset >= 0;
1156 noffset = fdt_next_subnode(fit, noffset)) {
1157 const char *node_name;
1158 int ret = 0;
1159
1160 node_name = fit_get_name(fit, noffset, NULL);
1161 if (!strncmp(node_name, FIT_SIG_NODENAME,
1162 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001163 ret = fit_config_process_sig(keydir, keyfile, keydest,
Simon Glass56ab8d62013-06-13 15:10:09 -07001164 fit, conf_name, conf_noffset, noffset, comment,
Jan Kiszka4043f322022-01-14 10:21:19 +01001165 require_keys, engine_id, cmdname, algo_name);
Simon Glasse4607262021-11-12 12:28:13 -07001166 if (ret < 0)
1167 return ret;
1168
1169 summary->sig_offset = noffset;
1170 fdt_get_path(fit, noffset, summary->sig_path,
1171 sizeof(summary->sig_path));
1172
1173 if (keydest) {
1174 summary->keydest_offset = ret;
1175 fdt_get_path(keydest, ret,
1176 summary->keydest_path,
1177 sizeof(summary->keydest_path));
1178 }
Simon Glass56ab8d62013-06-13 15:10:09 -07001179 }
Simon Glass56ab8d62013-06-13 15:10:09 -07001180 }
1181
1182 return 0;
1183}
1184
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +01001185#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001186/*
1187 * 0) open file (open)
1188 * 1) read certificate (PEM_read_X509)
1189 * 2) get public key (X509_get_pubkey)
1190 * 3) provide der format (d2i_RSAPublicKey)
1191 */
1192static int read_pub_key(const char *keydir, const void *name,
1193 unsigned char **pubkey, int *pubkey_len)
1194{
1195 char path[1024];
1196 EVP_PKEY *key = NULL;
1197 X509 *cert;
1198 FILE *f;
1199 int ret;
1200
1201 memset(path, 0, 1024);
1202 snprintf(path, sizeof(path), "%s/%s.crt", keydir, (char *)name);
1203
1204 /* Open certificate file */
1205 f = fopen(path, "r");
1206 if (!f) {
1207 fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
1208 path, strerror(errno));
1209 return -EACCES;
1210 }
1211
1212 /* Read the certificate */
1213 cert = NULL;
1214 if (!PEM_read_X509(f, &cert, NULL, NULL)) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001215 fprintf(stderr, "Couldn't read certificate");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001216 ret = -EINVAL;
1217 goto err_cert;
1218 }
1219
1220 /* Get the public key from the certificate. */
1221 key = X509_get_pubkey(cert);
1222 if (!key) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001223 fprintf(stderr, "Couldn't read public key\n");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001224 ret = -EINVAL;
1225 goto err_pubkey;
1226 }
1227
1228 /* Get DER form */
1229 ret = i2d_PublicKey(key, pubkey);
1230 if (ret < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001231 fprintf(stderr, "Couldn't get DER form\n");
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001232 ret = -EINVAL;
1233 goto err_pubkey;
1234 }
1235
1236 *pubkey_len = ret;
1237 ret = 0;
1238
1239err_pubkey:
1240 X509_free(cert);
1241err_cert:
1242 fclose(f);
1243 return ret;
1244}
1245
1246int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
1247{
1248 int pre_load_noffset;
1249 const void *algo_name;
1250 const void *key_name;
1251 unsigned char *pubkey = NULL;
1252 int ret, pubkey_len;
1253
1254 if (!keydir || !keydest || !fit)
1255 return 0;
1256
1257 /* Search node pre-load sig */
1258 pre_load_noffset = fdt_path_offset(keydest, IMAGE_PRE_LOAD_PATH);
1259 if (pre_load_noffset < 0) {
1260 ret = 0;
1261 goto out;
1262 }
1263
1264 algo_name = fdt_getprop(keydest, pre_load_noffset, "algo-name", NULL);
1265 key_name = fdt_getprop(keydest, pre_load_noffset, "key-name", NULL);
1266
1267 /* Check that all mandatory properties are present */
1268 if (!algo_name || !key_name) {
1269 if (!algo_name)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001270 fprintf(stderr, "The property algo-name is missing in the node %s\n",
1271 IMAGE_PRE_LOAD_PATH);
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001272 if (!key_name)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001273 fprintf(stderr, "The property key-name is missing in the node %s\n",
1274 IMAGE_PRE_LOAD_PATH);
Mark Kettenisd4ba0b42022-04-26 19:24:38 +02001275 ret = -EINVAL;
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001276 goto out;
1277 }
1278
1279 /* Read public key */
1280 ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
1281 if (ret < 0)
1282 goto out;
1283
1284 /* Add the public key to the device tree */
1285 ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
1286 pubkey, pubkey_len);
1287 if (ret)
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001288 fprintf(stderr, "Can't set public-key in node %s (ret = %d)\n",
1289 IMAGE_PRE_LOAD_PATH, ret);
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001290
1291 out:
1292 return ret;
1293}
Paul-Erwan Riodcfb6332023-12-21 08:26:11 +01001294#endif
Philippe Reynes3e3899c2022-03-28 22:57:02 +02001295
Philippe Reynes3148e422019-12-18 18:25:41 +01001296int fit_cipher_data(const char *keydir, void *keydest, void *fit,
1297 const char *comment, int require_keys,
1298 const char *engine_id, const char *cmdname)
1299{
1300 int images_noffset;
1301 int noffset;
1302 int ret;
1303
1304 /* Find images parent node offset */
1305 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1306 if (images_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001307 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1308 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Philippe Reynes3148e422019-12-18 18:25:41 +01001309 return images_noffset;
1310 }
1311
1312 /* Process its subnodes, print out component images details */
1313 for (noffset = fdt_first_subnode(fit, images_noffset);
1314 noffset >= 0;
1315 noffset = fdt_next_subnode(fit, noffset)) {
1316 /*
1317 * Direct child node of the images parent node,
1318 * i.e. component image node.
1319 */
1320 ret = fit_image_cipher_data(keydir, keydest,
1321 fit, noffset, comment,
1322 require_keys, engine_id,
1323 cmdname);
1324 if (ret)
1325 return ret;
1326 }
1327
1328 return 0;
1329}
1330
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001331int fit_add_verification_data(const char *keydir, const char *keyfile,
1332 void *keydest, void *fit, const char *comment,
1333 int require_keys, const char *engine_id,
Simon Glasse4607262021-11-12 12:28:13 -07001334 const char *cmdname, const char *algo_name,
1335 struct image_summary *summary)
Simon Glassee382652013-05-07 06:12:01 +00001336{
Simon Glass56ab8d62013-06-13 15:10:09 -07001337 int images_noffset, confs_noffset;
Simon Glassee382652013-05-07 06:12:01 +00001338 int noffset;
1339 int ret;
1340
1341 /* Find images parent node offset */
1342 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1343 if (images_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001344 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1345 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Simon Glassee382652013-05-07 06:12:01 +00001346 return images_noffset;
1347 }
1348
1349 /* Process its subnodes, print out component images details */
1350 for (noffset = fdt_first_subnode(fit, images_noffset);
1351 noffset >= 0;
1352 noffset = fdt_next_subnode(fit, noffset)) {
1353 /*
1354 * Direct child node of the images parent node,
1355 * i.e. component image node.
1356 */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001357 ret = fit_image_add_verification_data(keydir, keyfile, keydest,
Alex Kiernan697fcdc2018-06-20 20:10:52 +00001358 fit, noffset, comment, require_keys, engine_id,
Jan Kiszka4043f322022-01-14 10:21:19 +01001359 cmdname, algo_name);
Simon Glass35414072022-12-21 16:08:23 -07001360 if (ret) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001361 fprintf(stderr, "Can't add verification data for node '%s' (%s)\n",
1362 fdt_get_name(fit, noffset, NULL),
Alexander Kochetkov197ee8b2024-09-16 11:24:45 +03001363 strerror(-ret));
Simon Glassee382652013-05-07 06:12:01 +00001364 return ret;
Simon Glass35414072022-12-21 16:08:23 -07001365 }
Simon Glass10a1eca2013-05-07 06:11:54 +00001366 }
1367
Simon Glass56ab8d62013-06-13 15:10:09 -07001368 /* If there are no keys, we can't sign configurations */
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001369 if (!IMAGE_ENABLE_SIGN || !(keydir || keyfile))
Simon Glass56ab8d62013-06-13 15:10:09 -07001370 return 0;
1371
1372 /* Find configurations parent node offset */
1373 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
1374 if (confs_noffset < 0) {
Oleksandr Suvorov9ed732d2023-08-17 18:36:10 +03001375 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1376 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Simon Glass56ab8d62013-06-13 15:10:09 -07001377 return -ENOENT;
1378 }
1379
1380 /* Process its subnodes, print out component images details */
1381 for (noffset = fdt_first_subnode(fit, confs_noffset);
1382 noffset >= 0;
1383 noffset = fdt_next_subnode(fit, noffset)) {
Alexandru Gagniuc8fcea122021-02-19 12:45:17 -06001384 ret = fit_config_add_verification_data(keydir, keyfile, keydest,
Simon Glass56ab8d62013-06-13 15:10:09 -07001385 fit, noffset, comment,
George McCollister23d14892017-01-06 13:14:17 -06001386 require_keys,
Jan Kiszka4043f322022-01-14 10:21:19 +01001387 engine_id, cmdname,
Simon Glasse4607262021-11-12 12:28:13 -07001388 algo_name, summary);
Simon Glass56ab8d62013-06-13 15:10:09 -07001389 if (ret)
1390 return ret;
1391 }
1392
Simon Glass10a1eca2013-05-07 06:11:54 +00001393 return 0;
1394}
Heiko Schocherd7b42322014-03-03 12:19:30 +01001395
1396#ifdef CONFIG_FIT_SIGNATURE
Simon Glass05712322020-03-18 11:44:03 -06001397int fit_check_sign(const void *fit, const void *key,
1398 const char *fit_uname_config)
Heiko Schocherd7b42322014-03-03 12:19:30 +01001399{
1400 int cfg_noffset;
1401 int ret;
1402
Simon Glass05712322020-03-18 11:44:03 -06001403 cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
Heiko Schocherd7b42322014-03-03 12:19:30 +01001404 if (!cfg_noffset)
1405 return -1;
1406
Simon Glassa559bb22020-03-18 11:43:56 -06001407 printf("Verifying Hash Integrity for node '%s'... ",
1408 fdt_get_name(fit, cfg_noffset, NULL));
Simon Glassa51991d2014-06-12 07:24:53 -06001409 ret = fit_config_verify(fit, cfg_noffset);
1410 if (ret)
1411 return ret;
Simon Glass05712322020-03-18 11:44:03 -06001412 printf("Verified OK, loading images\n");
Simon Glassa51991d2014-06-12 07:24:53 -06001413 ret = bootm_host_load_images(fit, cfg_noffset);
1414
Heiko Schocherd7b42322014-03-03 12:19:30 +01001415 return ret;
1416}
1417#endif
Paul HENRYSee5925a2025-02-24 22:20:50 +01001418
1419#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
1420/**
1421 * rsa_verify_openssl() - Verify a signature against some data with openssl API
1422 *
1423 * Verify a RSA PKCS1.5/PSS signature against an expected hash.
1424 *
1425 * @info: Specifies the key and algorithms
1426 * @region: Pointer to the input data
1427 * @region_count: Number of region
1428 * @sig: Signature
1429 * @sig_len: Number of bytes in the signature
1430 * Return: 0 if verified, -ve on error
1431 */
1432int rsa_verify_openssl(struct image_sign_info *info,
1433 const struct image_region region[], int region_count,
1434 uint8_t *sig, uint sig_len)
1435{
1436 EVP_PKEY *pkey = NULL;
1437 EVP_PKEY_CTX *ckey = NULL;
1438 EVP_MD_CTX *ctx = NULL;
1439 int pad;
1440 int size;
1441 int i;
1442 int ret = 0;
1443
1444 if (!info) {
1445 fprintf(stderr, "No info provided\n");
1446 ret = -EINVAL;
1447 goto out;
1448 }
1449
1450 if (!info->key) {
1451 fprintf(stderr, "No key provided\n");
1452 ret = -EINVAL;
1453 goto out;
1454 }
1455
1456 if (!info->checksum) {
1457 fprintf(stderr, "No checksum information\n");
1458 ret = -EINVAL;
1459 goto out;
1460 }
1461
1462 if (!info->padding) {
1463 fprintf(stderr, "No padding information\n");
1464 ret = -EINVAL;
1465 goto out;
1466 }
1467
1468 if (region_count < 1) {
1469 fprintf(stderr, "Invalid value for region_count: %d\n", region_count);
1470 ret = -EINVAL;
1471 goto out;
1472 }
1473
1474 pkey = (EVP_PKEY *)info->key;
1475
1476 ckey = EVP_PKEY_CTX_new(pkey, NULL);
1477 if (!ckey) {
1478 ret = -ENOMEM;
1479 fprintf(stderr, "EVK key context setup failed: %s\n",
1480 ERR_error_string(ERR_get_error(), NULL));
1481 goto out;
1482 }
1483
1484 size = EVP_PKEY_size(pkey);
1485 if (size > sig_len) {
1486 fprintf(stderr, "Invalid signature size (%d bytes)\n",
1487 size);
1488 ret = -EINVAL;
1489 goto out;
1490 }
1491
1492 ctx = EVP_MD_CTX_new();
1493 if (!ctx) {
1494 ret = -ENOMEM;
1495 fprintf(stderr, "EVP context creation failed: %s\n",
1496 ERR_error_string(ERR_get_error(), NULL));
1497 goto out;
1498 }
1499 EVP_MD_CTX_init(ctx);
1500
1501 if (EVP_DigestVerifyInit(ctx, &ckey,
1502 EVP_get_digestbyname(info->checksum->name),
1503 NULL, pkey) <= 0) {
1504 ret = -EINVAL;
1505 fprintf(stderr, "Verifier setup failed: %s\n",
1506 ERR_error_string(ERR_get_error(), NULL));
1507 goto out;
1508 }
1509
1510 if (!strcmp(info->padding->name, "pkcs-1.5")) {
1511 pad = RSA_PKCS1_PADDING;
1512 } else if (!strcmp(info->padding->name, "pss")) {
1513 pad = RSA_PKCS1_PSS_PADDING;
1514 } else {
1515 ret = -ENOMSG;
1516 fprintf(stderr, "Unsupported padding: %s\n",
1517 info->padding->name);
1518 goto out;
1519 }
1520
1521 if (EVP_PKEY_CTX_set_rsa_padding(ckey, pad) <= 0) {
1522 ret = -EINVAL;
1523 fprintf(stderr, "padding setup has failed: %s\n",
1524 ERR_error_string(ERR_get_error(), NULL));
1525 goto out;
1526 }
1527
1528 for (i=0 ; i < region_count ; ++i) {
1529 if (EVP_DigestVerifyUpdate(ctx, region[i].data,
1530 region[i].size) <= 0) {
1531 ret = -EINVAL;
1532 fprintf(stderr, "Hashing data failed: %s\n",
1533 ERR_error_string(ERR_get_error(), NULL));
1534 goto out;
1535 }
1536 }
1537
1538 if (EVP_DigestVerifyFinal(ctx, sig, sig_len) <= 0) {
1539 ret = -EINVAL;
1540 fprintf(stderr, "Verifying digest failed: %s\n",
1541 ERR_error_string(ERR_get_error(), NULL));
1542 goto out;
1543 }
1544out:
1545 if (ctx)
1546 EVP_MD_CTX_free(ctx);
1547
1548 if (ret)
1549 fprintf(stderr, "Failed to verify signature\n");
1550
1551 return ret;
1552}
1553#endif