blob: ca4950312f9b35daa95f7ec104c01f0c570e7163 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass604f23d2013-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 Glass604f23d2013-05-07 06:11:54 +00009 */
10
11#include "mkimage.h"
Simon Glassce1400f2014-06-12 07:24:53 -060012#include <bootm.h>
Masahiro Yamada64045a62020-04-16 18:30:18 +090013#include <fdt_region.h>
Simon Glass604f23d2013-05-07 06:11:54 +000014#include <image.h>
Simon Glass56518e72013-06-13 15:10:01 -070015#include <version.h>
Simon Glass604f23d2013-05-07 06:11:54 +000016
Philippe Reynes6e052d12022-03-28 22:57:02 +020017#include <openssl/pem.h>
18#include <openssl/evp.h>
19
Simon Glass604f23d2013-05-07 06:11:54 +000020/**
Simon Glassb7260912013-05-07 06:11:56 +000021 * fit_set_hash_value - set hash value in requested has node
22 * @fit: pointer to the FIT format image header
23 * @noffset: hash node offset
24 * @value: hash value to be set
25 * @value_len: hash value length
26 *
27 * fit_set_hash_value() attempts to set hash value in a node at offset
28 * given and returns operation status to the caller.
29 *
30 * returns
31 * 0, on success
32 * -1, on failure
33 */
34static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
35 int value_len)
36{
37 int ret;
38
39 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
40 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +030041 fprintf(stderr, "Can't set hash '%s' property for '%s' node(%s)\n",
42 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
43 fdt_strerror(ret));
Simon Glass1152a052016-07-03 09:40:44 -060044 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
Simon Glassb7260912013-05-07 06:11:56 +000045 }
46
47 return 0;
48}
49
50/**
Simon Glass94e5fa42013-05-07 06:11:55 +000051 * fit_image_process_hash - Process a single subnode of the images/ node
52 *
53 * Check each subnode and process accordingly. For hash nodes we generate
Simon Glass70e6bcc2021-11-12 12:28:06 -070054 * a hash of the supplied data and store it in the node.
Simon Glass94e5fa42013-05-07 06:11:55 +000055 *
56 * @fit: pointer to the FIT format image header
Simon Glass70e6bcc2021-11-12 12:28:06 -070057 * @image_name: name of image being processed (used to display errors)
Simon Glass94e5fa42013-05-07 06:11:55 +000058 * @noffset: subnode offset
59 * @data: data to process
60 * @size: size of data in bytes
Heinrich Schuchardt185f8122022-01-19 18:05:50 +010061 * Return: 0 if ok, -1 on error
Simon Glass94e5fa42013-05-07 06:11:55 +000062 */
63static int fit_image_process_hash(void *fit, const char *image_name,
64 int noffset, const void *data, size_t size)
65{
66 uint8_t value[FIT_MAX_HASH_LEN];
Simon Glassbbb467d2013-05-07 06:12:01 +000067 const char *node_name;
Simon Glass94e5fa42013-05-07 06:11:55 +000068 int value_len;
Jan Kiszka4550ce92022-01-14 10:21:17 +010069 const char *algo;
Simon Glass1152a052016-07-03 09:40:44 -060070 int ret;
Simon Glass94e5fa42013-05-07 06:11:55 +000071
Simon Glassbbb467d2013-05-07 06:12:01 +000072 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass94e5fa42013-05-07 06:11:55 +000073
74 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +030075 fprintf(stderr,
76 "Can't get hash algo property for '%s' hash node in '%s' image node\n",
77 node_name, image_name);
Simon Glass1152a052016-07-03 09:40:44 -060078 return -ENOENT;
Simon Glass94e5fa42013-05-07 06:11:55 +000079 }
80
81 if (calculate_hash(data, size, algo, value, &value_len)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +030082 fprintf(stderr,
83 "Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
84 algo, node_name, image_name);
Simon Glass1152a052016-07-03 09:40:44 -060085 return -EPROTONOSUPPORT;
Simon Glass94e5fa42013-05-07 06:11:55 +000086 }
87
Simon Glass1152a052016-07-03 09:40:44 -060088 ret = fit_set_hash_value(fit, noffset, value, value_len);
89 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +030090 fprintf(stderr, "Can't set hash value for '%s' hash node in '%s' image node\n",
91 node_name, image_name);
Simon Glass1152a052016-07-03 09:40:44 -060092 return ret;
Simon Glass94e5fa42013-05-07 06:11:55 +000093 }
94
95 return 0;
96}
97
98/**
Simon Glass56518e72013-06-13 15:10:01 -070099 * fit_image_write_sig() - write the signature to a FIT
Simon Glass604f23d2013-05-07 06:11:54 +0000100 *
Simon Glass56518e72013-06-13 15:10:01 -0700101 * This writes the signature and signer data to the FIT.
102 *
103 * @fit: pointer to the FIT format image header
104 * @noffset: hash node offset
105 * @value: signature value to be set
106 * @value_len: signature value length
107 * @comment: Text comment to write (NULL for none)
108 *
109 * returns
110 * 0, on success
111 * -FDT_ERR_..., on failure
112 */
113static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
114 int value_len, const char *comment, const char *region_prop,
Jan Kiszka5902a392022-01-14 10:21:19 +0100115 int region_proplen, const char *cmdname, const char *algo_name)
Simon Glass56518e72013-06-13 15:10:01 -0700116{
117 int string_size;
118 int ret;
119
120 /*
121 * Get the current string size, before we update the FIT and add
122 * more
123 */
124 string_size = fdt_size_dt_strings(fit);
125
126 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
127 if (!ret) {
128 ret = fdt_setprop_string(fit, noffset, "signer-name",
129 "mkimage");
130 }
131 if (!ret) {
132 ret = fdt_setprop_string(fit, noffset, "signer-version",
133 PLAIN_VERSION);
134 }
135 if (comment && !ret)
136 ret = fdt_setprop_string(fit, noffset, "comment", comment);
Alex Kiernan795f4522018-06-20 20:10:52 +0000137 if (!ret) {
138 time_t timestamp = imagetool_get_source_date(cmdname,
139 time(NULL));
Ming Liu7c397992021-05-31 09:04:51 +0200140 uint32_t t = cpu_to_uimage(timestamp);
Alex Kiernan795f4522018-06-20 20:10:52 +0000141
Ming Liu7c397992021-05-31 09:04:51 +0200142 ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
143 sizeof(uint32_t));
Alex Kiernan795f4522018-06-20 20:10:52 +0000144 }
Simon Glass56518e72013-06-13 15:10:01 -0700145 if (region_prop && !ret) {
146 uint32_t strdata[2];
147
148 ret = fdt_setprop(fit, noffset, "hashed-nodes",
149 region_prop, region_proplen);
Teddy Reed7346c1e2018-06-09 11:45:20 -0400150 /* This is a legacy offset, it is unused, and must remain 0. */
Simon Glass56518e72013-06-13 15:10:01 -0700151 strdata[0] = 0;
152 strdata[1] = cpu_to_fdt32(string_size);
153 if (!ret) {
154 ret = fdt_setprop(fit, noffset, "hashed-strings",
155 strdata, sizeof(strdata));
156 }
157 }
Jan Kiszka5902a392022-01-14 10:21:19 +0100158 if (algo_name && !ret)
159 ret = fdt_setprop_string(fit, noffset, "algo", algo_name);
Simon Glass56518e72013-06-13 15:10:01 -0700160
161 return ret;
162}
163
164static int fit_image_setup_sig(struct image_sign_info *info,
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600165 const char *keydir, const char *keyfile, void *fit,
166 const char *image_name, int noffset, const char *require_keys,
Jan Kiszka5902a392022-01-14 10:21:19 +0100167 const char *engine_id, const char *algo_name)
Simon Glass56518e72013-06-13 15:10:01 -0700168{
169 const char *node_name;
Philippe Reynes20031562018-11-14 13:51:00 +0100170 const char *padding_name;
Simon Glass56518e72013-06-13 15:10:01 -0700171
172 node_name = fit_get_name(fit, noffset, NULL);
Jan Kiszka5902a392022-01-14 10:21:19 +0100173 if (!algo_name) {
174 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300175 fprintf(stderr,
176 "Can't get algo property for '%s' signature node in '%s' image node\n",
177 node_name, image_name);
Jan Kiszka5902a392022-01-14 10:21:19 +0100178 return -1;
179 }
Simon Glass56518e72013-06-13 15:10:01 -0700180 }
181
Philippe Reynes20031562018-11-14 13:51:00 +0100182 padding_name = fdt_getprop(fit, noffset, "padding", NULL);
183
Simon Glass56518e72013-06-13 15:10:01 -0700184 memset(info, '\0', sizeof(*info));
185 info->keydir = keydir;
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600186 info->keyfile = keyfile;
Simon Glass72188f52020-03-18 11:44:06 -0600187 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56518e72013-06-13 15:10:01 -0700188 info->fit = fit;
189 info->node_offset = noffset;
Masahiro Yamada1d88a992017-10-27 13:25:21 +0900190 info->name = strdup(algo_name);
Andrew Duda83dd98e2016-11-08 18:53:41 +0000191 info->checksum = image_get_checksum_algo(algo_name);
192 info->crypto = image_get_crypto_algo(algo_name);
Philippe Reynes20031562018-11-14 13:51:00 +0100193 info->padding = image_get_padding_algo(padding_name);
Simon Glass56518e72013-06-13 15:10:01 -0700194 info->require_keys = require_keys;
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600195 info->engine_id = engine_id;
Andrew Duda83dd98e2016-11-08 18:53:41 +0000196 if (!info->checksum || !info->crypto) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300197 fprintf(stderr,
198 "Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
199 algo_name, node_name, image_name);
Simon Glass56518e72013-06-13 15:10:01 -0700200 return -1;
201 }
202
203 return 0;
204}
205
206/**
207 * fit_image_process_sig- Process a single subnode of the images/ node
208 *
209 * Check each subnode and process accordingly. For signature nodes we
Simon Glass70e6bcc2021-11-12 12:28:06 -0700210 * generate a signed hash of the supplied data and store it in the node.
Simon Glass56518e72013-06-13 15:10:01 -0700211 *
212 * @keydir: Directory containing keys to use for signing
Simon Glass70e6bcc2021-11-12 12:28:06 -0700213 * @keydest: Destination FDT blob to write public keys into (NULL if none)
Simon Glass56518e72013-06-13 15:10:01 -0700214 * @fit: pointer to the FIT format image header
Simon Glass70e6bcc2021-11-12 12:28:06 -0700215 * @image_name: name of image being processed (used to display errors)
Simon Glass56518e72013-06-13 15:10:01 -0700216 * @noffset: subnode offset
217 * @data: data to process
218 * @size: size of data in bytes
219 * @comment: Comment to add to signature nodes
220 * @require_keys: Mark all keys as 'required'
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600221 * @engine_id: Engine to use for signing
Simon Glass9737c2d2021-11-12 12:28:12 -0700222 * Return: keydest node if @keydest is non-NULL, else 0 if none; -ve error code
223 * on failure
Simon Glass56518e72013-06-13 15:10:01 -0700224 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600225static int fit_image_process_sig(const char *keydir, const char *keyfile,
226 void *keydest, void *fit, const char *image_name,
Simon Glass56518e72013-06-13 15:10:01 -0700227 int noffset, const void *data, size_t size,
Alex Kiernan795f4522018-06-20 20:10:52 +0000228 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +0100229 const char *cmdname, const char *algo_name)
Simon Glass56518e72013-06-13 15:10:01 -0700230{
231 struct image_sign_info info;
232 struct image_region region;
233 const char *node_name;
234 uint8_t *value;
235 uint value_len;
236 int ret;
237
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600238 if (fit_image_setup_sig(&info, keydir, keyfile, fit, image_name,
239 noffset, require_keys ? "image" : NULL,
Jan Kiszka5902a392022-01-14 10:21:19 +0100240 engine_id, algo_name))
Simon Glass56518e72013-06-13 15:10:01 -0700241 return -1;
242
243 node_name = fit_get_name(fit, noffset, NULL);
244 region.data = data;
245 region.size = size;
Andrew Duda83dd98e2016-11-08 18:53:41 +0000246 ret = info.crypto->sign(&info, &region, 1, &value, &value_len);
Simon Glass56518e72013-06-13 15:10:01 -0700247 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300248 fprintf(stderr, "Failed to sign '%s' signature node in '%s' image node: %d\n",
249 node_name, image_name, ret);
Simon Glass56518e72013-06-13 15:10:01 -0700250
251 /* We allow keys to be missing */
252 if (ret == -ENOENT)
253 return 0;
254 return -1;
255 }
256
257 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +0100258 NULL, 0, cmdname, algo_name);
Simon Glass56518e72013-06-13 15:10:01 -0700259 if (ret) {
Simon Glassa9468112014-06-02 22:04:53 -0600260 if (ret == -FDT_ERR_NOSPACE)
261 return -ENOSPC;
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300262 fprintf(stderr,
263 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
264 node_name, image_name, fdt_strerror(ret));
Simon Glass56518e72013-06-13 15:10:01 -0700265 return -1;
266 }
267 free(value);
268
269 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glass72188f52020-03-18 11:44:06 -0600270 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56518e72013-06-13 15:10:01 -0700271
mario.six@gdsys.cc713fb2d2016-07-22 08:58:40 +0200272 /*
273 * Write the public key into the supplied FDT file; this might fail
mario.six@gdsys.ccc236ebd2016-07-19 11:07:06 +0200274 * several times, since we try signing with successively increasing
mario.six@gdsys.cc713fb2d2016-07-22 08:58:40 +0200275 * size values
276 */
Masahiro Yamada6793d012017-10-27 15:04:20 +0900277 if (keydest) {
278 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glassc033dc82021-11-12 12:28:11 -0700279 if (ret < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300280 fprintf(stderr,
281 "Failed to add verification data for '%s' signature node in '%s' image node\n",
282 node_name, image_name);
Masahiro Yamada6793d012017-10-27 15:04:20 +0900283 return ret;
284 }
Simon Glass9737c2d2021-11-12 12:28:12 -0700285 /* Return the node that was written to */
286 return ret;
Masahiro Yamada6793d012017-10-27 15:04:20 +0900287 }
Simon Glass56518e72013-06-13 15:10:01 -0700288
289 return 0;
290}
291
Philippe Reynes7298e422019-12-18 18:25:41 +0100292static int fit_image_read_data(char *filename, unsigned char *data,
293 int expected_size)
294{
295 struct stat sbuf;
296 int fd, ret = -1;
297 ssize_t n;
298
299 /* Open file */
300 fd = open(filename, O_RDONLY | O_BINARY);
301 if (fd < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300302 fprintf(stderr, "Can't open file %s (err=%d => %s)\n",
303 filename, errno, strerror(errno));
Philippe Reynes7298e422019-12-18 18:25:41 +0100304 return -1;
305 }
306
307 /* Compute file size */
308 if (fstat(fd, &sbuf) < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300309 fprintf(stderr, "Can't fstat file %s (err=%d => %s)\n",
310 filename, errno, strerror(errno));
Philippe Reynes7298e422019-12-18 18:25:41 +0100311 goto err;
312 }
313
314 /* Check file size */
315 if (sbuf.st_size != expected_size) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300316 fprintf(stderr, "File %s don't have the expected size (size=%lld, expected=%d)\n",
317 filename, (long long)sbuf.st_size, expected_size);
Philippe Reynes7298e422019-12-18 18:25:41 +0100318 goto err;
319 }
320
321 /* Read data */
322 n = read(fd, data, sbuf.st_size);
323 if (n < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300324 fprintf(stderr, "Can't read file %s (err=%d => %s)\n",
325 filename, errno, strerror(errno));
Philippe Reynes7298e422019-12-18 18:25:41 +0100326 goto err;
327 }
328
329 /* Check that we have read all the file */
330 if (n != sbuf.st_size) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300331 fprintf(stderr, "Can't read all file %s (read %zd bytes, expected %lld)\n",
332 filename, n, (long long)sbuf.st_size);
Philippe Reynes7298e422019-12-18 18:25:41 +0100333 goto err;
334 }
335
336 ret = 0;
337
338err:
339 close(fd);
340 return ret;
341}
342
Philippe Reynesa6982a62020-09-17 15:01:46 +0200343static int get_random_data(void *data, int size)
344{
345 unsigned char *tmp = data;
346 struct timespec date;
Simon Glass7f0f4e12021-05-13 19:39:20 -0600347 int i, ret;
Philippe Reynesa6982a62020-09-17 15:01:46 +0200348
349 if (!tmp) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300350 fprintf(stderr, "%s: pointer data is NULL\n", __func__);
Philippe Reynesa6982a62020-09-17 15:01:46 +0200351 ret = -1;
352 goto out;
353 }
354
355 ret = clock_gettime(CLOCK_MONOTONIC, &date);
Simon Glass7f0f4e12021-05-13 19:39:20 -0600356 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300357 fprintf(stderr, "%s: clock_gettime has failed (%s)\n", __func__,
358 strerror(errno));
Philippe Reynesa6982a62020-09-17 15:01:46 +0200359 goto out;
360 }
361
Philippe Reynescc34f042020-11-13 16:37:46 +0100362 srandom(date.tv_nsec);
Philippe Reynesa6982a62020-09-17 15:01:46 +0200363
364 for (i = 0; i < size; i++) {
Philippe Reynescc34f042020-11-13 16:37:46 +0100365 *tmp = random() & 0xff;
Philippe Reynesa6982a62020-09-17 15:01:46 +0200366 tmp++;
367 }
368
369 out:
370 return ret;
371}
372
Philippe Reynes7298e422019-12-18 18:25:41 +0100373static int fit_image_setup_cipher(struct image_cipher_info *info,
374 const char *keydir, void *fit,
375 const char *image_name, int image_noffset,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000376 int noffset)
Philippe Reynes7298e422019-12-18 18:25:41 +0100377{
378 char *algo_name;
379 char filename[128];
380 int ret = -1;
381
382 if (fit_image_cipher_get_algo(fit, noffset, &algo_name)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300383 fprintf(stderr, "Can't get algo name for cipher in image '%s'\n",
384 image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100385 goto out;
386 }
387
388 info->keydir = keydir;
389
390 /* Read the key name */
Simon Glass72188f52020-03-18 11:44:06 -0600391 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Philippe Reynes7298e422019-12-18 18:25:41 +0100392 if (!info->keyname) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300393 fprintf(stderr, "Can't get key name for cipher in image '%s'\n",
394 image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100395 goto out;
396 }
397
Philippe Reynesa6982a62020-09-17 15:01:46 +0200398 /*
399 * Read the IV name
400 *
401 * If this property is not provided then mkimage will generate
402 * a random IV and store it in the FIT image
403 */
Philippe Reynes7298e422019-12-18 18:25:41 +0100404 info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL);
Philippe Reynes7298e422019-12-18 18:25:41 +0100405
406 info->fit = fit;
407 info->node_noffset = noffset;
408 info->name = algo_name;
409
410 info->cipher = image_get_cipher_algo(algo_name);
411 if (!info->cipher) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300412 fprintf(stderr, "Can't get algo for cipher '%s'\n", image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100413 goto out;
414 }
415
416 /* Read the key in the file */
417 snprintf(filename, sizeof(filename), "%s/%s%s",
418 info->keydir, info->keyname, ".bin");
419 info->key = malloc(info->cipher->key_len);
420 if (!info->key) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300421 fprintf(stderr, "Can't allocate memory for key\n");
Philippe Reynes7298e422019-12-18 18:25:41 +0100422 ret = -1;
423 goto out;
424 }
425 ret = fit_image_read_data(filename, (unsigned char *)info->key,
426 info->cipher->key_len);
427 if (ret < 0)
428 goto out;
429
Philippe Reynes7298e422019-12-18 18:25:41 +0100430 info->iv = malloc(info->cipher->iv_len);
431 if (!info->iv) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300432 fprintf(stderr, "Can't allocate memory for iv\n");
Philippe Reynes7298e422019-12-18 18:25:41 +0100433 ret = -1;
434 goto out;
435 }
Philippe Reynesa6982a62020-09-17 15:01:46 +0200436
437 if (info->ivname) {
438 /* Read the IV in the file */
439 snprintf(filename, sizeof(filename), "%s/%s%s",
440 info->keydir, info->ivname, ".bin");
441 ret = fit_image_read_data(filename, (unsigned char *)info->iv,
442 info->cipher->iv_len);
443 } else {
444 /* Generate an ramdom IV */
445 ret = get_random_data((void *)info->iv, info->cipher->iv_len);
446 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100447
448 out:
449 return ret;
450}
451
452int fit_image_write_cipher(void *fit, int image_noffset, int noffset,
453 const void *data, size_t size,
454 unsigned char *data_ciphered, int data_ciphered_len)
455{
456 int ret = -1;
457
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000458 /* Replace data with ciphered data */
Philippe Reynes7298e422019-12-18 18:25:41 +0100459 ret = fdt_setprop(fit, image_noffset, FIT_DATA_PROP,
460 data_ciphered, data_ciphered_len);
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000461 if (ret == -FDT_ERR_NOSPACE) {
462 ret = -ENOSPC;
463 goto out;
464 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100465 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300466 fprintf(stderr, "Can't replace data with ciphered data (err = %d)\n", ret);
Philippe Reynes7298e422019-12-18 18:25:41 +0100467 goto out;
468 }
469
470 /* add non ciphered data size */
471 ret = fdt_setprop_u32(fit, image_noffset, "data-size-unciphered", size);
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000472 if (ret == -FDT_ERR_NOSPACE) {
473 ret = -ENOSPC;
474 goto out;
475 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100476 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300477 fprintf(stderr, "Can't add unciphered data size (err = %d)\n", ret);
Philippe Reynes7298e422019-12-18 18:25:41 +0100478 goto out;
479 }
480
481 out:
482 return ret;
483}
484
485static int
486fit_image_process_cipher(const char *keydir, void *keydest, void *fit,
487 const char *image_name, int image_noffset,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000488 int node_noffset, const void *data, size_t size,
Philippe Reynes7298e422019-12-18 18:25:41 +0100489 const char *cmdname)
490{
491 struct image_cipher_info info;
492 unsigned char *data_ciphered = NULL;
493 int data_ciphered_len;
494 int ret;
495
496 memset(&info, 0, sizeof(info));
497
498 ret = fit_image_setup_cipher(&info, keydir, fit, image_name,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000499 image_noffset, node_noffset);
Philippe Reynes7298e422019-12-18 18:25:41 +0100500 if (ret)
501 goto out;
502
503 ret = info.cipher->encrypt(&info, data, size,
504 &data_ciphered, &data_ciphered_len);
505 if (ret)
506 goto out;
507
508 /*
509 * Write the public key into the supplied FDT file; this might fail
510 * several times, since we try signing with successively increasing
511 * size values
Philippe Reynesa6982a62020-09-17 15:01:46 +0200512 * And, if needed, write the iv in the FIT file
Philippe Reynes7298e422019-12-18 18:25:41 +0100513 */
514 if (keydest) {
Philippe Reynesa6982a62020-09-17 15:01:46 +0200515 ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
Philippe Reynes7298e422019-12-18 18:25:41 +0100516 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300517 fprintf(stderr,
518 "Failed to add verification data for cipher '%s' in image '%s'\n",
519 info.keyname, image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100520 goto out;
521 }
522 }
523
524 ret = fit_image_write_cipher(fit, image_noffset, node_noffset,
525 data, size,
526 data_ciphered, data_ciphered_len);
527
528 out:
529 free(data_ciphered);
530 free((void *)info.key);
531 free((void *)info.iv);
532 return ret;
533}
534
535int fit_image_cipher_data(const char *keydir, void *keydest,
536 void *fit, int image_noffset, const char *comment,
537 int require_keys, const char *engine_id,
538 const char *cmdname)
539{
540 const char *image_name;
541 const void *data;
542 size_t size;
Patrick Oppenlanderb33e5cc2020-07-30 14:22:15 +1000543 int cipher_node_offset, len;
Philippe Reynes7298e422019-12-18 18:25:41 +0100544
545 /* Get image name */
546 image_name = fit_get_name(fit, image_noffset, NULL);
547 if (!image_name) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300548 fprintf(stderr, "Can't get image name\n");
Philippe Reynes7298e422019-12-18 18:25:41 +0100549 return -1;
550 }
551
552 /* Get image data and data length */
553 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300554 fprintf(stderr, "Can't get image data/size\n");
Philippe Reynes7298e422019-12-18 18:25:41 +0100555 return -1;
556 }
557
Patrick Oppenlanderb33e5cc2020-07-30 14:22:15 +1000558 /*
559 * Don't cipher ciphered data.
560 *
561 * If the data-size-unciphered property is present the data for this
562 * image is already encrypted. This is important as 'mkimage -F' can be
563 * run multiple times on a FIT image.
564 */
565 if (fdt_getprop(fit, image_noffset, "data-size-unciphered", &len))
566 return 0;
567 if (len != -FDT_ERR_NOTFOUND) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300568 fprintf(stderr, "Failure testing for data-size-unciphered\n");
Patrick Oppenlanderb33e5cc2020-07-30 14:22:15 +1000569 return -1;
570 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100571
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000572 /* Process cipher node if present */
573 cipher_node_offset = fdt_subnode_offset(fit, image_noffset,
574 FIT_CIPHER_NODENAME);
575 if (cipher_node_offset == -FDT_ERR_NOTFOUND)
576 return 0;
577 if (cipher_node_offset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300578 fprintf(stderr, "Failure getting cipher node\n");
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000579 return -1;
Philippe Reynes7298e422019-12-18 18:25:41 +0100580 }
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000581 if (!IMAGE_ENABLE_ENCRYPT || !keydir)
582 return 0;
583 return fit_image_process_cipher(keydir, keydest, fit, image_name,
584 image_noffset, cipher_node_offset, data, size, cmdname);
Philippe Reynes7298e422019-12-18 18:25:41 +0100585}
586
Simon Glass56518e72013-06-13 15:10:01 -0700587/**
588 * fit_image_add_verification_data() - calculate/set verig. data for image node
589 *
590 * This adds hash and signature values for an component image node.
Simon Glassbbb467d2013-05-07 06:12:01 +0000591 *
592 * All existing hash subnodes are checked, if algorithm property is set to
593 * one of the supported hash algorithms, hash value is computed and
594 * corresponding hash node property is set, for example:
Simon Glass604f23d2013-05-07 06:11:54 +0000595 *
596 * Input component image node structure:
597 *
Andre Przywarab2267e82017-12-04 02:05:10 +0000598 * o image-1 (at image_noffset)
Simon Glass604f23d2013-05-07 06:11:54 +0000599 * | - data = [binary data]
Andre Przywarab2267e82017-12-04 02:05:10 +0000600 * o hash-1
Simon Glass604f23d2013-05-07 06:11:54 +0000601 * |- algo = "sha1"
602 *
603 * Output component image node structure:
604 *
Andre Przywarab2267e82017-12-04 02:05:10 +0000605 * o image-1 (at image_noffset)
Simon Glass604f23d2013-05-07 06:11:54 +0000606 * | - data = [binary data]
Andre Przywarab2267e82017-12-04 02:05:10 +0000607 * o hash-1
Simon Glass604f23d2013-05-07 06:11:54 +0000608 * |- algo = "sha1"
609 * |- value = sha1(data)
610 *
Simon Glassbbb467d2013-05-07 06:12:01 +0000611 * For signature details, please see doc/uImage.FIT/signature.txt
612 *
Simon Glass56518e72013-06-13 15:10:01 -0700613 * @keydir Directory containing *.key and *.crt files (or NULL)
614 * @keydest FDT Blob to write public keys into (NULL if none)
Simon Glassbbb467d2013-05-07 06:12:01 +0000615 * @fit: Pointer to the FIT format image header
616 * @image_noffset: Requested component image node
Simon Glass56518e72013-06-13 15:10:01 -0700617 * @comment: Comment to add to signature nodes
618 * @require_keys: Mark all keys as 'required'
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600619 * @engine_id: Engine to use for signing
Simon Glassbbb467d2013-05-07 06:12:01 +0000620 * @return: 0 on success, <0 on failure
Simon Glass604f23d2013-05-07 06:11:54 +0000621 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600622int fit_image_add_verification_data(const char *keydir, const char *keyfile,
623 void *keydest, void *fit, int image_noffset,
624 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +0100625 const char *cmdname, const char* algo_name)
Simon Glass604f23d2013-05-07 06:11:54 +0000626{
Simon Glassbbb467d2013-05-07 06:12:01 +0000627 const char *image_name;
Simon Glass604f23d2013-05-07 06:11:54 +0000628 const void *data;
629 size_t size;
Simon Glass604f23d2013-05-07 06:11:54 +0000630 int noffset;
Simon Glass604f23d2013-05-07 06:11:54 +0000631
632 /* Get image data and data length */
633 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300634 fprintf(stderr, "Can't get image data/size\n");
Simon Glass604f23d2013-05-07 06:11:54 +0000635 return -1;
636 }
637
Simon Glass94e5fa42013-05-07 06:11:55 +0000638 image_name = fit_get_name(fit, image_noffset, NULL);
639
Simon Glass604f23d2013-05-07 06:11:54 +0000640 /* Process all hash subnodes of the component image node */
Simon Glassbbb467d2013-05-07 06:12:01 +0000641 for (noffset = fdt_first_subnode(fit, image_noffset);
642 noffset >= 0;
643 noffset = fdt_next_subnode(fit, noffset)) {
644 const char *node_name;
645 int ret = 0;
646
647 /*
648 * Check subnode name, must be equal to "hash" or "signature".
649 * Multiple hash nodes require unique unit node
Andre Przywarab2267e82017-12-04 02:05:10 +0000650 * names, e.g. hash-1, hash-2, signature-1, etc.
Simon Glassbbb467d2013-05-07 06:12:01 +0000651 */
652 node_name = fit_get_name(fit, noffset, NULL);
653 if (!strncmp(node_name, FIT_HASH_NODENAME,
654 strlen(FIT_HASH_NODENAME))) {
655 ret = fit_image_process_hash(fit, image_name, noffset,
656 data, size);
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600657 } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) &&
Simon Glass56518e72013-06-13 15:10:01 -0700658 !strncmp(node_name, FIT_SIG_NODENAME,
659 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600660 ret = fit_image_process_sig(keydir, keyfile, keydest,
Simon Glass56518e72013-06-13 15:10:01 -0700661 fit, image_name, noffset, data, size,
Jan Kiszka5902a392022-01-14 10:21:19 +0100662 comment, require_keys, engine_id, cmdname,
663 algo_name);
Simon Glass604f23d2013-05-07 06:11:54 +0000664 }
Simon Glass9737c2d2021-11-12 12:28:12 -0700665 if (ret < 0)
Simon Glass1152a052016-07-03 09:40:44 -0600666 return ret;
Simon Glassbbb467d2013-05-07 06:12:01 +0000667 }
668
669 return 0;
670}
671
Simon Glass4d098522013-06-13 15:10:09 -0700672struct strlist {
673 int count;
674 char **strings;
675};
676
677static void strlist_init(struct strlist *list)
678{
679 memset(list, '\0', sizeof(*list));
680}
681
682static void strlist_free(struct strlist *list)
683{
684 int i;
685
686 for (i = 0; i < list->count; i++)
687 free(list->strings[i]);
688 free(list->strings);
689}
690
691static int strlist_add(struct strlist *list, const char *str)
692{
693 char *dup;
694
695 dup = strdup(str);
696 list->strings = realloc(list->strings,
697 (list->count + 1) * sizeof(char *));
698 if (!list || !str)
699 return -1;
700 list->strings[list->count++] = dup;
701
702 return 0;
703}
704
Simon Glass70e6bcc2021-11-12 12:28:06 -0700705static const char *fit_config_get_image_list(const void *fit, int noffset,
706 int *lenp, int *allow_missingp)
Simon Glass4d098522013-06-13 15:10:09 -0700707{
708 static const char default_list[] = FIT_KERNEL_PROP "\0"
709 FIT_FDT_PROP;
710 const char *prop;
711
Simon Glass70e6bcc2021-11-12 12:28:06 -0700712 /* If there is an "sign-image" property, use that */
Simon Glass4d098522013-06-13 15:10:09 -0700713 prop = fdt_getprop(fit, noffset, "sign-images", lenp);
714 if (prop) {
715 *allow_missingp = 0;
716 return *lenp ? prop : NULL;
717 }
718
719 /* Default image list */
720 *allow_missingp = 1;
721 *lenp = sizeof(default_list);
722
723 return default_list;
724}
725
Simon Glass70e6bcc2021-11-12 12:28:06 -0700726/**
727 * fit_config_add_hash() - Add a list of nodes to hash for an image
728 *
729 * This adds a list of paths to image nodes (as referred to by a particular
730 * offset) that need to be hashed, to protect a configuration
731 *
732 * @fit: Pointer to the FIT format image header
733 * @image_noffset: Offset of image to process (e.g. /images/kernel-1)
734 * @node_inc: List of nodes to add to
735 * @conf_name Configuration-node name, child of /configurations node (only
736 * used for error messages)
737 * @sig_name Signature-node name (only used for error messages)
738 * @iname: Name of image being processed (e.g. "kernel-1" (only used
739 * for error messages)
740 */
741static int fit_config_add_hash(const void *fit, int image_noffset,
742 struct strlist *node_inc, const char *conf_name,
743 const char *sig_name, const char *iname)
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100744{
Simon Glass48422342021-11-12 12:28:07 -0700745 char path[200];
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100746 int noffset;
747 int hash_count;
748 int ret;
749
750 ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
751 if (ret < 0)
752 goto err_path;
753 if (strlist_add(node_inc, path))
754 goto err_mem;
755
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100756 /* Add all this image's hashes */
757 hash_count = 0;
758 for (noffset = fdt_first_subnode(fit, image_noffset);
759 noffset >= 0;
760 noffset = fdt_next_subnode(fit, noffset)) {
761 const char *name = fit_get_name(fit, noffset, NULL);
762
763 if (strncmp(name, FIT_HASH_NODENAME,
764 strlen(FIT_HASH_NODENAME)))
765 continue;
766 ret = fdt_get_path(fit, noffset, path, sizeof(path));
767 if (ret < 0)
768 goto err_path;
769 if (strlist_add(node_inc, path))
770 goto err_mem;
771 hash_count++;
772 }
773
774 if (!hash_count) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300775 fprintf(stderr,
776 "Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
777 conf_name, sig_name, iname);
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100778 return -ENOMSG;
779 }
780
781 /* Add this image's cipher node if present */
782 noffset = fdt_subnode_offset(fit, image_noffset,
783 FIT_CIPHER_NODENAME);
784 if (noffset != -FDT_ERR_NOTFOUND) {
785 if (noffset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300786 fprintf(stderr,
787 "Failed to get cipher node in configuration '%s/%s' image '%s': %s\n",
788 conf_name, sig_name, iname,
789 fdt_strerror(noffset));
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100790 return -EIO;
791 }
792 ret = fdt_get_path(fit, noffset, path, sizeof(path));
793 if (ret < 0)
794 goto err_path;
795 if (strlist_add(node_inc, path))
796 goto err_mem;
797 }
798
799 return 0;
800
801err_mem:
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300802 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
803 sig_name);
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100804 return -ENOMEM;
805
806err_path:
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300807 fprintf(stderr, "Failed to get path for image '%s' in configuration '%s/%s': %s\n",
808 iname, conf_name, sig_name, fdt_strerror(ret));
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100809 return -ENOENT;
810}
811
Simon Glass70e6bcc2021-11-12 12:28:06 -0700812/**
813 * fit_config_get_hash_list() - Get the regions to sign
814 *
815 * This calculates a list of nodes to hash for this particular configuration,
816 * returning it as a string list (struct strlist, not a devicetree string list)
817 *
818 * @fit: Pointer to the FIT format image header
819 * @conf_noffset: Offset of configuration node to sign (child of
820 * /configurations node)
821 * @sig_offset: Offset of signature node containing info about how to sign it
822 * (child of 'signatures' node)
823 * @return 0 if OK, -ENOENT if an image referred to by the configuration cannot
824 * be found, -ENOMSG if ther were no images in the configuration
825 */
826static int fit_config_get_hash_list(const void *fit, int conf_noffset,
Simon Glass4d098522013-06-13 15:10:09 -0700827 int sig_offset, struct strlist *node_inc)
828{
829 int allow_missing;
830 const char *prop, *iname, *end;
831 const char *conf_name, *sig_name;
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100832 char name[200];
Simon Glass4d098522013-06-13 15:10:09 -0700833 int image_count;
834 int ret, len;
835
836 conf_name = fit_get_name(fit, conf_noffset, NULL);
837 sig_name = fit_get_name(fit, sig_offset, NULL);
838
839 /*
840 * Build a list of nodes we need to hash. We always need the root
841 * node and the configuration.
842 */
843 strlist_init(node_inc);
844 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
845 if (strlist_add(node_inc, "/") ||
846 strlist_add(node_inc, name))
847 goto err_mem;
848
849 /* Get a list of images that we intend to sign */
Heiko Schocher66b36f82014-03-03 12:19:23 +0100850 prop = fit_config_get_image_list(fit, sig_offset, &len,
Simon Glass4d098522013-06-13 15:10:09 -0700851 &allow_missing);
852 if (!prop)
853 return 0;
854
855 /* Locate the images */
856 end = prop + len;
857 image_count = 0;
858 for (iname = prop; iname < end; iname += strlen(iname) + 1) {
Simon Glass4d098522013-06-13 15:10:09 -0700859 int image_noffset;
Philippe Reynesedfeba72020-11-24 14:39:48 +0100860 int index, max_index;
Simon Glass4d098522013-06-13 15:10:09 -0700861
Philippe Reynesedfeba72020-11-24 14:39:48 +0100862 max_index = fdt_stringlist_count(fit, conf_noffset, iname);
Simon Glass4d098522013-06-13 15:10:09 -0700863
Philippe Reynesedfeba72020-11-24 14:39:48 +0100864 for (index = 0; index < max_index; index++) {
865 image_noffset = fit_conf_get_prop_node_index(fit, conf_noffset,
866 iname, index);
867
868 if (image_noffset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300869 fprintf(stderr,
870 "Failed to find image '%s' in configuration '%s/%s'\n",
871 iname, conf_name, sig_name);
Philippe Reynesedfeba72020-11-24 14:39:48 +0100872 if (allow_missing)
873 continue;
874
875 return -ENOENT;
876 }
877
Simon Glass70e6bcc2021-11-12 12:28:06 -0700878 ret = fit_config_add_hash(fit, image_noffset, node_inc,
879 conf_name, sig_name, iname);
Philippe Reynesedfeba72020-11-24 14:39:48 +0100880 if (ret < 0)
881 return ret;
882
883 image_count++;
Simon Glass4d098522013-06-13 15:10:09 -0700884 }
Simon Glass4d098522013-06-13 15:10:09 -0700885 }
886
887 if (!image_count) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300888 fprintf(stderr, "Failed to find any images for configuration '%s/%s'\n",
889 conf_name, sig_name);
Simon Glass4d098522013-06-13 15:10:09 -0700890 return -ENOMSG;
891 }
892
893 return 0;
894
895err_mem:
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300896 fprintf(stderr, "Out of memory processing configuration '%s/%s'\n", conf_name,
897 sig_name);
Simon Glass4d098522013-06-13 15:10:09 -0700898 return -ENOMEM;
Simon Glass4d098522013-06-13 15:10:09 -0700899}
900
Simon Glass70e6bcc2021-11-12 12:28:06 -0700901/**
902 * fit_config_get_regions() - Get the regions to sign
903 *
904 * This calculates a list of node to hash for this particular configuration,
905 * then finds which regions of the devicetree they correspond to.
906 *
907 * @fit: Pointer to the FIT format image header
908 * @conf_noffset: Offset of configuration node to sign (child of
909 * /configurations node)
910 * @sig_offset: Offset of signature node containing info about how to sign it
911 * (child of 'signatures' node)
912 * @regionp: Returns list of regions that need to be hashed (allocated; must be
913 * freed by the caller)
914 * @region_count: Returns number of regions
915 * @region_propp: Returns string-list property containing the list of nodes
916 * that correspond to the regions. Each entry is a full path to the node.
917 * This is in devicetree format, i.e. a \0 between each string. This is
918 * allocated and must be freed by the caller.
919 * @region_proplen: Returns length of *@@region_propp in bytes
920 * @return 0 if OK, -ENOMEM if out of memory, -EIO if the regions to hash could
921 * not be found, -EINVAL if no registers were found to hash
922 */
923static int fit_config_get_regions(const void *fit, int conf_noffset,
924 int sig_offset, struct image_region **regionp,
925 int *region_countp, char **region_propp,
926 int *region_proplen)
Simon Glass4d098522013-06-13 15:10:09 -0700927{
Sean Anderson0abe3322022-10-20 15:41:10 -0400928 char * const exc_prop[] = {
929 FIT_DATA_PROP,
930 FIT_DATA_SIZE_PROP,
931 FIT_DATA_POSITION_PROP,
932 FIT_DATA_OFFSET_PROP,
933 };
Simon Glass4d098522013-06-13 15:10:09 -0700934 struct strlist node_inc;
935 struct image_region *region;
936 struct fdt_region fdt_regions[100];
937 const char *conf_name, *sig_name;
938 char path[200];
939 int count, i;
940 char *region_prop;
941 int ret, len;
942
943 conf_name = fit_get_name(fit, conf_noffset, NULL);
Simon Glass70e6bcc2021-11-12 12:28:06 -0700944 sig_name = fit_get_name(fit, sig_offset, NULL);
Simon Glass4d098522013-06-13 15:10:09 -0700945 debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
946
947 /* Get a list of nodes we want to hash */
Simon Glass70e6bcc2021-11-12 12:28:06 -0700948 ret = fit_config_get_hash_list(fit, conf_noffset, sig_offset,
949 &node_inc);
Simon Glass4d098522013-06-13 15:10:09 -0700950 if (ret)
951 return ret;
952
953 /* Get a list of regions to hash */
954 count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
955 exc_prop, ARRAY_SIZE(exc_prop),
956 fdt_regions, ARRAY_SIZE(fdt_regions),
957 path, sizeof(path), 1);
958 if (count < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300959 fprintf(stderr, "Failed to hash configuration '%s/%s': %s\n", conf_name,
960 sig_name, fdt_strerror(ret));
Simon Glass4d098522013-06-13 15:10:09 -0700961 return -EIO;
962 }
963 if (count == 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300964 fprintf(stderr, "No data to hash for configuration '%s/%s': %s\n",
965 conf_name, sig_name, fdt_strerror(ret));
Simon Glass4d098522013-06-13 15:10:09 -0700966 return -EINVAL;
967 }
968
969 /* Build our list of data blocks */
970 region = fit_region_make_list(fit, fdt_regions, count, NULL);
971 if (!region) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300972 fprintf(stderr, "Out of memory hashing configuration '%s/%s'\n",
973 conf_name, sig_name);
Simon Glass4d098522013-06-13 15:10:09 -0700974 return -ENOMEM;
975 }
976
977 /* Create a list of all hashed properties */
978 debug("Hash nodes:\n");
979 for (i = len = 0; i < node_inc.count; i++) {
980 debug(" %s\n", node_inc.strings[i]);
981 len += strlen(node_inc.strings[i]) + 1;
982 }
983 region_prop = malloc(len);
984 if (!region_prop) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +0300985 fprintf(stderr, "Out of memory setting up regions for configuration '%s/%s'\n",
986 conf_name, sig_name);
Simon Glass4d098522013-06-13 15:10:09 -0700987 return -ENOMEM;
988 }
989 for (i = len = 0; i < node_inc.count;
990 len += strlen(node_inc.strings[i]) + 1, i++)
991 strcpy(region_prop + len, node_inc.strings[i]);
992 strlist_free(&node_inc);
993
994 *region_countp = count;
995 *regionp = region;
996 *region_propp = region_prop;
997 *region_proplen = len;
998
999 return 0;
1000}
1001
Simon Glass9737c2d2021-11-12 12:28:12 -07001002/**
1003 * fit_config_process_sig - Process a single subnode of the configurations/ node
1004 *
1005 * Generate a signed hash of the supplied data and store it in the node.
1006 *
1007 * @keydir: Directory containing keys to use for signing
1008 * @keydest: Destination FDT blob to write public keys into (NULL if none)
1009 * @fit: pointer to the FIT format image header
1010 * @conf_name name of config being processed (used to display errors)
1011 * @conf_noffset: Offset of configuration node, e.g. '/configurations/conf-1'
1012 * @noffset: subnode offset, e.g. '/configurations/conf-1/sig-1'
1013 * @comment: Comment to add to signature nodes
1014 * @require_keys: Mark all keys as 'required'
1015 * @engine_id: Engine to use for signing
1016 * @cmdname: Command name used when reporting errors
1017 * @return keydest node if @keydest is non-NULL, else 0 if none; -ve error code
1018 * on failure
1019 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001020static int fit_config_process_sig(const char *keydir, const char *keyfile,
Simon Glass70e6bcc2021-11-12 12:28:06 -07001021 void *keydest, void *fit, const char *conf_name,
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001022 int conf_noffset, int noffset, const char *comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001023 int require_keys, const char *engine_id, const char *cmdname,
1024 const char *algo_name)
Simon Glass4d098522013-06-13 15:10:09 -07001025{
1026 struct image_sign_info info;
1027 const char *node_name;
1028 struct image_region *region;
1029 char *region_prop;
1030 int region_proplen;
1031 int region_count;
1032 uint8_t *value;
1033 uint value_len;
1034 int ret;
1035
1036 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass70e6bcc2021-11-12 12:28:06 -07001037 if (fit_config_get_regions(fit, conf_noffset, noffset, &region,
1038 &region_count, &region_prop,
1039 &region_proplen))
Simon Glass4d098522013-06-13 15:10:09 -07001040 return -1;
1041
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001042 if (fit_image_setup_sig(&info, keydir, keyfile, fit, conf_name, noffset,
Jan Kiszka5902a392022-01-14 10:21:19 +01001043 require_keys ? "conf" : NULL, engine_id,
1044 algo_name))
Simon Glass4d098522013-06-13 15:10:09 -07001045 return -1;
1046
Andrew Duda83dd98e2016-11-08 18:53:41 +00001047 ret = info.crypto->sign(&info, region, region_count, &value,
1048 &value_len);
Simon Glass4d098522013-06-13 15:10:09 -07001049 free(region);
1050 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001051 fprintf(stderr, "Failed to sign '%s' signature node in '%s' conf node\n",
1052 node_name, conf_name);
Simon Glass4d098522013-06-13 15:10:09 -07001053
1054 /* We allow keys to be missing */
1055 if (ret == -ENOENT)
1056 return 0;
1057 return -1;
1058 }
1059
Simon Glassa9468112014-06-02 22:04:53 -06001060 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001061 region_prop, region_proplen, cmdname,
1062 algo_name);
Simon Glassa9468112014-06-02 22:04:53 -06001063 if (ret) {
1064 if (ret == -FDT_ERR_NOSPACE)
1065 return -ENOSPC;
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001066 fprintf(stderr,
1067 "Can't write signature for '%s' signature node in '%s' conf node: %s\n",
1068 node_name, conf_name, fdt_strerror(ret));
Simon Glass4d098522013-06-13 15:10:09 -07001069 return -1;
1070 }
1071 free(value);
1072 free(region_prop);
1073
1074 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glass72188f52020-03-18 11:44:06 -06001075 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass4d098522013-06-13 15:10:09 -07001076
1077 /* Write the public key into the supplied FDT file */
Simon Glassa9468112014-06-02 22:04:53 -06001078 if (keydest) {
Andrew Duda83dd98e2016-11-08 18:53:41 +00001079 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glassc033dc82021-11-12 12:28:11 -07001080 if (ret < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001081 fprintf(stderr,
1082 "Failed to add verification data for '%s' signature node in '%s' configuration node\n",
1083 node_name, conf_name);
Simon Glassa9468112014-06-02 22:04:53 -06001084 }
Simon Glass9737c2d2021-11-12 12:28:12 -07001085 return ret;
Simon Glass4d098522013-06-13 15:10:09 -07001086 }
1087
1088 return 0;
1089}
1090
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001091static int fit_config_add_verification_data(const char *keydir,
1092 const char *keyfile, void *keydest, void *fit, int conf_noffset,
1093 const char *comment, int require_keys, const char *engine_id,
Simon Glass2d2384b2021-11-12 12:28:13 -07001094 const char *cmdname, const char *algo_name,
1095 struct image_summary *summary)
Simon Glass4d098522013-06-13 15:10:09 -07001096{
1097 const char *conf_name;
1098 int noffset;
1099
1100 conf_name = fit_get_name(fit, conf_noffset, NULL);
1101
1102 /* Process all hash subnodes of the configuration node */
1103 for (noffset = fdt_first_subnode(fit, conf_noffset);
1104 noffset >= 0;
1105 noffset = fdt_next_subnode(fit, noffset)) {
1106 const char *node_name;
1107 int ret = 0;
1108
1109 node_name = fit_get_name(fit, noffset, NULL);
1110 if (!strncmp(node_name, FIT_SIG_NODENAME,
1111 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001112 ret = fit_config_process_sig(keydir, keyfile, keydest,
Simon Glass4d098522013-06-13 15:10:09 -07001113 fit, conf_name, conf_noffset, noffset, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001114 require_keys, engine_id, cmdname, algo_name);
Simon Glass2d2384b2021-11-12 12:28:13 -07001115 if (ret < 0)
1116 return ret;
1117
1118 summary->sig_offset = noffset;
1119 fdt_get_path(fit, noffset, summary->sig_path,
1120 sizeof(summary->sig_path));
1121
1122 if (keydest) {
1123 summary->keydest_offset = ret;
1124 fdt_get_path(keydest, ret,
1125 summary->keydest_path,
1126 sizeof(summary->keydest_path));
1127 }
Simon Glass4d098522013-06-13 15:10:09 -07001128 }
Simon Glass4d098522013-06-13 15:10:09 -07001129 }
1130
1131 return 0;
1132}
1133
Philippe Reynes6e052d12022-03-28 22:57:02 +02001134/*
1135 * 0) open file (open)
1136 * 1) read certificate (PEM_read_X509)
1137 * 2) get public key (X509_get_pubkey)
1138 * 3) provide der format (d2i_RSAPublicKey)
1139 */
1140static int read_pub_key(const char *keydir, const void *name,
1141 unsigned char **pubkey, int *pubkey_len)
1142{
1143 char path[1024];
1144 EVP_PKEY *key = NULL;
1145 X509 *cert;
1146 FILE *f;
1147 int ret;
1148
1149 memset(path, 0, 1024);
1150 snprintf(path, sizeof(path), "%s/%s.crt", keydir, (char *)name);
1151
1152 /* Open certificate file */
1153 f = fopen(path, "r");
1154 if (!f) {
1155 fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
1156 path, strerror(errno));
1157 return -EACCES;
1158 }
1159
1160 /* Read the certificate */
1161 cert = NULL;
1162 if (!PEM_read_X509(f, &cert, NULL, NULL)) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001163 fprintf(stderr, "Couldn't read certificate");
Philippe Reynes6e052d12022-03-28 22:57:02 +02001164 ret = -EINVAL;
1165 goto err_cert;
1166 }
1167
1168 /* Get the public key from the certificate. */
1169 key = X509_get_pubkey(cert);
1170 if (!key) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001171 fprintf(stderr, "Couldn't read public key\n");
Philippe Reynes6e052d12022-03-28 22:57:02 +02001172 ret = -EINVAL;
1173 goto err_pubkey;
1174 }
1175
1176 /* Get DER form */
1177 ret = i2d_PublicKey(key, pubkey);
1178 if (ret < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001179 fprintf(stderr, "Couldn't get DER form\n");
Philippe Reynes6e052d12022-03-28 22:57:02 +02001180 ret = -EINVAL;
1181 goto err_pubkey;
1182 }
1183
1184 *pubkey_len = ret;
1185 ret = 0;
1186
1187err_pubkey:
1188 X509_free(cert);
1189err_cert:
1190 fclose(f);
1191 return ret;
1192}
1193
1194int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
1195{
1196 int pre_load_noffset;
1197 const void *algo_name;
1198 const void *key_name;
1199 unsigned char *pubkey = NULL;
1200 int ret, pubkey_len;
1201
1202 if (!keydir || !keydest || !fit)
1203 return 0;
1204
1205 /* Search node pre-load sig */
1206 pre_load_noffset = fdt_path_offset(keydest, IMAGE_PRE_LOAD_PATH);
1207 if (pre_load_noffset < 0) {
1208 ret = 0;
1209 goto out;
1210 }
1211
1212 algo_name = fdt_getprop(keydest, pre_load_noffset, "algo-name", NULL);
1213 key_name = fdt_getprop(keydest, pre_load_noffset, "key-name", NULL);
1214
1215 /* Check that all mandatory properties are present */
1216 if (!algo_name || !key_name) {
1217 if (!algo_name)
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001218 fprintf(stderr, "The property algo-name is missing in the node %s\n",
1219 IMAGE_PRE_LOAD_PATH);
Philippe Reynes6e052d12022-03-28 22:57:02 +02001220 if (!key_name)
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001221 fprintf(stderr, "The property key-name is missing in the node %s\n",
1222 IMAGE_PRE_LOAD_PATH);
Mark Kettenis61657182022-04-26 19:24:38 +02001223 ret = -EINVAL;
Philippe Reynes6e052d12022-03-28 22:57:02 +02001224 goto out;
1225 }
1226
1227 /* Read public key */
1228 ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
1229 if (ret < 0)
1230 goto out;
1231
1232 /* Add the public key to the device tree */
1233 ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
1234 pubkey, pubkey_len);
1235 if (ret)
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001236 fprintf(stderr, "Can't set public-key in node %s (ret = %d)\n",
1237 IMAGE_PRE_LOAD_PATH, ret);
Philippe Reynes6e052d12022-03-28 22:57:02 +02001238
1239 out:
1240 return ret;
1241}
1242
Philippe Reynes7298e422019-12-18 18:25:41 +01001243int fit_cipher_data(const char *keydir, void *keydest, void *fit,
1244 const char *comment, int require_keys,
1245 const char *engine_id, const char *cmdname)
1246{
1247 int images_noffset;
1248 int noffset;
1249 int ret;
1250
1251 /* Find images parent node offset */
1252 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1253 if (images_noffset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001254 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1255 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Philippe Reynes7298e422019-12-18 18:25:41 +01001256 return images_noffset;
1257 }
1258
1259 /* Process its subnodes, print out component images details */
1260 for (noffset = fdt_first_subnode(fit, images_noffset);
1261 noffset >= 0;
1262 noffset = fdt_next_subnode(fit, noffset)) {
1263 /*
1264 * Direct child node of the images parent node,
1265 * i.e. component image node.
1266 */
1267 ret = fit_image_cipher_data(keydir, keydest,
1268 fit, noffset, comment,
1269 require_keys, engine_id,
1270 cmdname);
1271 if (ret)
1272 return ret;
1273 }
1274
1275 return 0;
1276}
1277
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001278int fit_add_verification_data(const char *keydir, const char *keyfile,
1279 void *keydest, void *fit, const char *comment,
1280 int require_keys, const char *engine_id,
Simon Glass2d2384b2021-11-12 12:28:13 -07001281 const char *cmdname, const char *algo_name,
1282 struct image_summary *summary)
Simon Glassbbb467d2013-05-07 06:12:01 +00001283{
Simon Glass4d098522013-06-13 15:10:09 -07001284 int images_noffset, confs_noffset;
Simon Glassbbb467d2013-05-07 06:12:01 +00001285 int noffset;
1286 int ret;
1287
1288 /* Find images parent node offset */
1289 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1290 if (images_noffset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001291 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1292 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Simon Glassbbb467d2013-05-07 06:12:01 +00001293 return images_noffset;
1294 }
1295
1296 /* Process its subnodes, print out component images details */
1297 for (noffset = fdt_first_subnode(fit, images_noffset);
1298 noffset >= 0;
1299 noffset = fdt_next_subnode(fit, noffset)) {
1300 /*
1301 * Direct child node of the images parent node,
1302 * i.e. component image node.
1303 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001304 ret = fit_image_add_verification_data(keydir, keyfile, keydest,
Alex Kiernan795f4522018-06-20 20:10:52 +00001305 fit, noffset, comment, require_keys, engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +01001306 cmdname, algo_name);
Simon Glass90cfae22022-12-21 16:08:23 -07001307 if (ret) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001308 fprintf(stderr, "Can't add verification data for node '%s' (%s)\n",
1309 fdt_get_name(fit, noffset, NULL),
1310 fdt_strerror(ret));
Simon Glassbbb467d2013-05-07 06:12:01 +00001311 return ret;
Simon Glass90cfae22022-12-21 16:08:23 -07001312 }
Simon Glass604f23d2013-05-07 06:11:54 +00001313 }
1314
Simon Glass4d098522013-06-13 15:10:09 -07001315 /* If there are no keys, we can't sign configurations */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001316 if (!IMAGE_ENABLE_SIGN || !(keydir || keyfile))
Simon Glass4d098522013-06-13 15:10:09 -07001317 return 0;
1318
1319 /* Find configurations parent node offset */
1320 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
1321 if (confs_noffset < 0) {
Oleksandr Suvorov8d8851e2023-08-17 18:36:10 +03001322 fprintf(stderr, "Can't find images parent node '%s' (%s)\n",
1323 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Simon Glass4d098522013-06-13 15:10:09 -07001324 return -ENOENT;
1325 }
1326
1327 /* Process its subnodes, print out component images details */
1328 for (noffset = fdt_first_subnode(fit, confs_noffset);
1329 noffset >= 0;
1330 noffset = fdt_next_subnode(fit, noffset)) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001331 ret = fit_config_add_verification_data(keydir, keyfile, keydest,
Simon Glass4d098522013-06-13 15:10:09 -07001332 fit, noffset, comment,
George McCollisterf1ca1fd2017-01-06 13:14:17 -06001333 require_keys,
Jan Kiszka5902a392022-01-14 10:21:19 +01001334 engine_id, cmdname,
Simon Glass2d2384b2021-11-12 12:28:13 -07001335 algo_name, summary);
Simon Glass4d098522013-06-13 15:10:09 -07001336 if (ret)
1337 return ret;
1338 }
1339
Simon Glass604f23d2013-05-07 06:11:54 +00001340 return 0;
1341}
Heiko Schocher29a23f92014-03-03 12:19:30 +01001342
1343#ifdef CONFIG_FIT_SIGNATURE
Simon Glassc3aa81e2020-03-18 11:44:03 -06001344int fit_check_sign(const void *fit, const void *key,
1345 const char *fit_uname_config)
Heiko Schocher29a23f92014-03-03 12:19:30 +01001346{
1347 int cfg_noffset;
1348 int ret;
1349
Simon Glassc3aa81e2020-03-18 11:44:03 -06001350 cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
Heiko Schocher29a23f92014-03-03 12:19:30 +01001351 if (!cfg_noffset)
1352 return -1;
1353
Simon Glass382cf622020-03-18 11:43:56 -06001354 printf("Verifying Hash Integrity for node '%s'... ",
1355 fdt_get_name(fit, cfg_noffset, NULL));
Simon Glassce1400f2014-06-12 07:24:53 -06001356 ret = fit_config_verify(fit, cfg_noffset);
1357 if (ret)
1358 return ret;
Simon Glassc3aa81e2020-03-18 11:44:03 -06001359 printf("Verified OK, loading images\n");
Simon Glassce1400f2014-06-12 07:24:53 -06001360 ret = bootm_host_load_images(fit, cfg_noffset);
1361
Heiko Schocher29a23f92014-03-03 12:19:30 +01001362 return ret;
1363}
1364#endif