blob: 698adfb3e1d4db1372778a978bb8d5760ce9f10b [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
20#define IMAGE_PRE_LOAD_PATH "/image/pre-load/sig"
21
Simon Glass604f23d2013-05-07 06:11:54 +000022/**
Simon Glassb7260912013-05-07 06:11:56 +000023 * fit_set_hash_value - set hash value in requested has node
24 * @fit: pointer to the FIT format image header
25 * @noffset: hash node offset
26 * @value: hash value to be set
27 * @value_len: hash value length
28 *
29 * fit_set_hash_value() attempts to set hash value in a node at offset
30 * given and returns operation status to the caller.
31 *
32 * returns
33 * 0, on success
34 * -1, on failure
35 */
36static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
37 int value_len)
38{
39 int ret;
40
41 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
42 if (ret) {
43 printf("Can't set hash '%s' property for '%s' node(%s)\n",
44 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
45 fdt_strerror(ret));
Simon Glass1152a052016-07-03 09:40:44 -060046 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
Simon Glassb7260912013-05-07 06:11:56 +000047 }
48
49 return 0;
50}
51
52/**
Simon Glass94e5fa42013-05-07 06:11:55 +000053 * fit_image_process_hash - Process a single subnode of the images/ node
54 *
55 * Check each subnode and process accordingly. For hash nodes we generate
Simon Glass70e6bcc2021-11-12 12:28:06 -070056 * a hash of the supplied data and store it in the node.
Simon Glass94e5fa42013-05-07 06:11:55 +000057 *
58 * @fit: pointer to the FIT format image header
Simon Glass70e6bcc2021-11-12 12:28:06 -070059 * @image_name: name of image being processed (used to display errors)
Simon Glass94e5fa42013-05-07 06:11:55 +000060 * @noffset: subnode offset
61 * @data: data to process
62 * @size: size of data in bytes
Heinrich Schuchardt185f8122022-01-19 18:05:50 +010063 * Return: 0 if ok, -1 on error
Simon Glass94e5fa42013-05-07 06:11:55 +000064 */
65static int fit_image_process_hash(void *fit, const char *image_name,
66 int noffset, const void *data, size_t size)
67{
68 uint8_t value[FIT_MAX_HASH_LEN];
Simon Glassbbb467d2013-05-07 06:12:01 +000069 const char *node_name;
Simon Glass94e5fa42013-05-07 06:11:55 +000070 int value_len;
Jan Kiszka4550ce92022-01-14 10:21:17 +010071 const char *algo;
Simon Glass1152a052016-07-03 09:40:44 -060072 int ret;
Simon Glass94e5fa42013-05-07 06:11:55 +000073
Simon Glassbbb467d2013-05-07 06:12:01 +000074 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass94e5fa42013-05-07 06:11:55 +000075
76 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
77 printf("Can't get hash algo property for '%s' hash node in '%s' image node\n",
Simon Glassbbb467d2013-05-07 06:12:01 +000078 node_name, image_name);
Simon Glass1152a052016-07-03 09:40:44 -060079 return -ENOENT;
Simon Glass94e5fa42013-05-07 06:11:55 +000080 }
81
82 if (calculate_hash(data, size, algo, value, &value_len)) {
83 printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
Simon Glassbbb467d2013-05-07 06:12:01 +000084 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) {
Simon Glass94e5fa42013-05-07 06:11:55 +000090 printf("Can't set hash value for '%s' hash node in '%s' image node\n",
Simon Glassbbb467d2013-05-07 06:12:01 +000091 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)) {
175 printf("Can't get algo property for '%s' signature node in '%s' image node\n",
176 node_name, image_name);
177 return -1;
178 }
Simon Glass56518e72013-06-13 15:10:01 -0700179 }
180
Philippe Reynes20031562018-11-14 13:51:00 +0100181 padding_name = fdt_getprop(fit, noffset, "padding", NULL);
182
Simon Glass56518e72013-06-13 15:10:01 -0700183 memset(info, '\0', sizeof(*info));
184 info->keydir = keydir;
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600185 info->keyfile = keyfile;
Simon Glass72188f52020-03-18 11:44:06 -0600186 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56518e72013-06-13 15:10:01 -0700187 info->fit = fit;
188 info->node_offset = noffset;
Masahiro Yamada1d88a992017-10-27 13:25:21 +0900189 info->name = strdup(algo_name);
Andrew Duda83dd98e2016-11-08 18:53:41 +0000190 info->checksum = image_get_checksum_algo(algo_name);
191 info->crypto = image_get_crypto_algo(algo_name);
Philippe Reynes20031562018-11-14 13:51:00 +0100192 info->padding = image_get_padding_algo(padding_name);
Simon Glass56518e72013-06-13 15:10:01 -0700193 info->require_keys = require_keys;
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600194 info->engine_id = engine_id;
Andrew Duda83dd98e2016-11-08 18:53:41 +0000195 if (!info->checksum || !info->crypto) {
Simon Glass56518e72013-06-13 15:10:01 -0700196 printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
197 algo_name, node_name, image_name);
198 return -1;
199 }
200
201 return 0;
202}
203
204/**
205 * fit_image_process_sig- Process a single subnode of the images/ node
206 *
207 * Check each subnode and process accordingly. For signature nodes we
Simon Glass70e6bcc2021-11-12 12:28:06 -0700208 * generate a signed hash of the supplied data and store it in the node.
Simon Glass56518e72013-06-13 15:10:01 -0700209 *
210 * @keydir: Directory containing keys to use for signing
Simon Glass70e6bcc2021-11-12 12:28:06 -0700211 * @keydest: Destination FDT blob to write public keys into (NULL if none)
Simon Glass56518e72013-06-13 15:10:01 -0700212 * @fit: pointer to the FIT format image header
Simon Glass70e6bcc2021-11-12 12:28:06 -0700213 * @image_name: name of image being processed (used to display errors)
Simon Glass56518e72013-06-13 15:10:01 -0700214 * @noffset: subnode offset
215 * @data: data to process
216 * @size: size of data in bytes
217 * @comment: Comment to add to signature nodes
218 * @require_keys: Mark all keys as 'required'
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600219 * @engine_id: Engine to use for signing
Simon Glass9737c2d2021-11-12 12:28:12 -0700220 * Return: keydest node if @keydest is non-NULL, else 0 if none; -ve error code
221 * on failure
Simon Glass56518e72013-06-13 15:10:01 -0700222 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600223static int fit_image_process_sig(const char *keydir, const char *keyfile,
224 void *keydest, void *fit, const char *image_name,
Simon Glass56518e72013-06-13 15:10:01 -0700225 int noffset, const void *data, size_t size,
Alex Kiernan795f4522018-06-20 20:10:52 +0000226 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +0100227 const char *cmdname, const char *algo_name)
Simon Glass56518e72013-06-13 15:10:01 -0700228{
229 struct image_sign_info info;
230 struct image_region region;
231 const char *node_name;
232 uint8_t *value;
233 uint value_len;
234 int ret;
235
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600236 if (fit_image_setup_sig(&info, keydir, keyfile, fit, image_name,
237 noffset, require_keys ? "image" : NULL,
Jan Kiszka5902a392022-01-14 10:21:19 +0100238 engine_id, algo_name))
Simon Glass56518e72013-06-13 15:10:01 -0700239 return -1;
240
241 node_name = fit_get_name(fit, noffset, NULL);
242 region.data = data;
243 region.size = size;
Andrew Duda83dd98e2016-11-08 18:53:41 +0000244 ret = info.crypto->sign(&info, &region, 1, &value, &value_len);
Simon Glass56518e72013-06-13 15:10:01 -0700245 if (ret) {
246 printf("Failed to sign '%s' signature node in '%s' image node: %d\n",
247 node_name, image_name, ret);
248
249 /* We allow keys to be missing */
250 if (ret == -ENOENT)
251 return 0;
252 return -1;
253 }
254
255 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +0100256 NULL, 0, cmdname, algo_name);
Simon Glass56518e72013-06-13 15:10:01 -0700257 if (ret) {
Simon Glassa9468112014-06-02 22:04:53 -0600258 if (ret == -FDT_ERR_NOSPACE)
259 return -ENOSPC;
260 printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n",
Simon Glass56518e72013-06-13 15:10:01 -0700261 node_name, image_name, fdt_strerror(ret));
262 return -1;
263 }
264 free(value);
265
266 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glass72188f52020-03-18 11:44:06 -0600267 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass56518e72013-06-13 15:10:01 -0700268
mario.six@gdsys.cc713fb2d2016-07-22 08:58:40 +0200269 /*
270 * Write the public key into the supplied FDT file; this might fail
mario.six@gdsys.ccc236ebd2016-07-19 11:07:06 +0200271 * several times, since we try signing with successively increasing
mario.six@gdsys.cc713fb2d2016-07-22 08:58:40 +0200272 * size values
273 */
Masahiro Yamada6793d012017-10-27 15:04:20 +0900274 if (keydest) {
275 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glassc033dc82021-11-12 12:28:11 -0700276 if (ret < 0) {
Masahiro Yamada6793d012017-10-27 15:04:20 +0900277 printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
278 node_name, image_name);
279 return ret;
280 }
Simon Glass9737c2d2021-11-12 12:28:12 -0700281 /* Return the node that was written to */
282 return ret;
Masahiro Yamada6793d012017-10-27 15:04:20 +0900283 }
Simon Glass56518e72013-06-13 15:10:01 -0700284
285 return 0;
286}
287
Philippe Reynes7298e422019-12-18 18:25:41 +0100288static int fit_image_read_data(char *filename, unsigned char *data,
289 int expected_size)
290{
291 struct stat sbuf;
292 int fd, ret = -1;
293 ssize_t n;
294
295 /* Open file */
296 fd = open(filename, O_RDONLY | O_BINARY);
297 if (fd < 0) {
298 printf("Can't open file %s (err=%d => %s)\n",
299 filename, errno, strerror(errno));
300 return -1;
301 }
302
303 /* Compute file size */
304 if (fstat(fd, &sbuf) < 0) {
305 printf("Can't fstat file %s (err=%d => %s)\n",
306 filename, errno, strerror(errno));
307 goto err;
308 }
309
310 /* Check file size */
311 if (sbuf.st_size != expected_size) {
Heinrich Schuchardt3311eda2020-10-08 20:51:24 +0200312 printf("File %s don't have the expected size (size=%lld, expected=%d)\n",
313 filename, (long long)sbuf.st_size, expected_size);
Philippe Reynes7298e422019-12-18 18:25:41 +0100314 goto err;
315 }
316
317 /* Read data */
318 n = read(fd, data, sbuf.st_size);
319 if (n < 0) {
320 printf("Can't read file %s (err=%d => %s)\n",
321 filename, errno, strerror(errno));
322 goto err;
323 }
324
325 /* Check that we have read all the file */
326 if (n != sbuf.st_size) {
Vagrant Cascadian2c6bcab2021-09-28 10:11:46 -0700327 printf("Can't read all file %s (read %zd bytes, expected %lld)\n",
Heinrich Schuchardt3311eda2020-10-08 20:51:24 +0200328 filename, n, (long long)sbuf.st_size);
Philippe Reynes7298e422019-12-18 18:25:41 +0100329 goto err;
330 }
331
332 ret = 0;
333
334err:
335 close(fd);
336 return ret;
337}
338
Philippe Reynesa6982a62020-09-17 15:01:46 +0200339static int get_random_data(void *data, int size)
340{
341 unsigned char *tmp = data;
342 struct timespec date;
Simon Glass7f0f4e12021-05-13 19:39:20 -0600343 int i, ret;
Philippe Reynesa6982a62020-09-17 15:01:46 +0200344
345 if (!tmp) {
346 printf("%s: pointer data is NULL\n", __func__);
347 ret = -1;
348 goto out;
349 }
350
351 ret = clock_gettime(CLOCK_MONOTONIC, &date);
Simon Glass7f0f4e12021-05-13 19:39:20 -0600352 if (ret) {
353 printf("%s: clock_gettime has failed (%s)\n", __func__,
354 strerror(errno));
Philippe Reynesa6982a62020-09-17 15:01:46 +0200355 goto out;
356 }
357
Philippe Reynescc34f042020-11-13 16:37:46 +0100358 srandom(date.tv_nsec);
Philippe Reynesa6982a62020-09-17 15:01:46 +0200359
360 for (i = 0; i < size; i++) {
Philippe Reynescc34f042020-11-13 16:37:46 +0100361 *tmp = random() & 0xff;
Philippe Reynesa6982a62020-09-17 15:01:46 +0200362 tmp++;
363 }
364
365 out:
366 return ret;
367}
368
Philippe Reynes7298e422019-12-18 18:25:41 +0100369static int fit_image_setup_cipher(struct image_cipher_info *info,
370 const char *keydir, void *fit,
371 const char *image_name, int image_noffset,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000372 int noffset)
Philippe Reynes7298e422019-12-18 18:25:41 +0100373{
374 char *algo_name;
375 char filename[128];
376 int ret = -1;
377
378 if (fit_image_cipher_get_algo(fit, noffset, &algo_name)) {
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000379 printf("Can't get algo name for cipher in image '%s'\n",
380 image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100381 goto out;
382 }
383
384 info->keydir = keydir;
385
386 /* Read the key name */
Simon Glass72188f52020-03-18 11:44:06 -0600387 info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Philippe Reynes7298e422019-12-18 18:25:41 +0100388 if (!info->keyname) {
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000389 printf("Can't get key name for cipher in image '%s'\n",
390 image_name);
Philippe Reynes7298e422019-12-18 18:25:41 +0100391 goto out;
392 }
393
Philippe Reynesa6982a62020-09-17 15:01:46 +0200394 /*
395 * Read the IV name
396 *
397 * If this property is not provided then mkimage will generate
398 * a random IV and store it in the FIT image
399 */
Philippe Reynes7298e422019-12-18 18:25:41 +0100400 info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL);
Philippe Reynes7298e422019-12-18 18:25:41 +0100401
402 info->fit = fit;
403 info->node_noffset = noffset;
404 info->name = algo_name;
405
406 info->cipher = image_get_cipher_algo(algo_name);
407 if (!info->cipher) {
408 printf("Can't get algo for cipher '%s'\n", image_name);
409 goto out;
410 }
411
412 /* Read the key in the file */
413 snprintf(filename, sizeof(filename), "%s/%s%s",
414 info->keydir, info->keyname, ".bin");
415 info->key = malloc(info->cipher->key_len);
416 if (!info->key) {
417 printf("Can't allocate memory for key\n");
418 ret = -1;
419 goto out;
420 }
421 ret = fit_image_read_data(filename, (unsigned char *)info->key,
422 info->cipher->key_len);
423 if (ret < 0)
424 goto out;
425
Philippe Reynes7298e422019-12-18 18:25:41 +0100426 info->iv = malloc(info->cipher->iv_len);
427 if (!info->iv) {
428 printf("Can't allocate memory for iv\n");
429 ret = -1;
430 goto out;
431 }
Philippe Reynesa6982a62020-09-17 15:01:46 +0200432
433 if (info->ivname) {
434 /* Read the IV in the file */
435 snprintf(filename, sizeof(filename), "%s/%s%s",
436 info->keydir, info->ivname, ".bin");
437 ret = fit_image_read_data(filename, (unsigned char *)info->iv,
438 info->cipher->iv_len);
439 } else {
440 /* Generate an ramdom IV */
441 ret = get_random_data((void *)info->iv, info->cipher->iv_len);
442 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100443
444 out:
445 return ret;
446}
447
448int fit_image_write_cipher(void *fit, int image_noffset, int noffset,
449 const void *data, size_t size,
450 unsigned char *data_ciphered, int data_ciphered_len)
451{
452 int ret = -1;
453
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000454 /* Replace data with ciphered data */
Philippe Reynes7298e422019-12-18 18:25:41 +0100455 ret = fdt_setprop(fit, image_noffset, FIT_DATA_PROP,
456 data_ciphered, data_ciphered_len);
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000457 if (ret == -FDT_ERR_NOSPACE) {
458 ret = -ENOSPC;
459 goto out;
460 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100461 if (ret) {
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000462 printf("Can't replace data with ciphered data (err = %d)\n", ret);
Philippe Reynes7298e422019-12-18 18:25:41 +0100463 goto out;
464 }
465
466 /* add non ciphered data size */
467 ret = fdt_setprop_u32(fit, image_noffset, "data-size-unciphered", size);
Patrick Oppenlander04aeebb2020-07-30 14:22:14 +1000468 if (ret == -FDT_ERR_NOSPACE) {
469 ret = -ENOSPC;
470 goto out;
471 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100472 if (ret) {
473 printf("Can't add unciphered data size (err = %d)\n", ret);
474 goto out;
475 }
476
477 out:
478 return ret;
479}
480
481static int
482fit_image_process_cipher(const char *keydir, void *keydest, void *fit,
483 const char *image_name, int image_noffset,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000484 int node_noffset, const void *data, size_t size,
Philippe Reynes7298e422019-12-18 18:25:41 +0100485 const char *cmdname)
486{
487 struct image_cipher_info info;
488 unsigned char *data_ciphered = NULL;
489 int data_ciphered_len;
490 int ret;
491
492 memset(&info, 0, sizeof(info));
493
494 ret = fit_image_setup_cipher(&info, keydir, fit, image_name,
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000495 image_noffset, node_noffset);
Philippe Reynes7298e422019-12-18 18:25:41 +0100496 if (ret)
497 goto out;
498
499 ret = info.cipher->encrypt(&info, data, size,
500 &data_ciphered, &data_ciphered_len);
501 if (ret)
502 goto out;
503
504 /*
505 * Write the public key into the supplied FDT file; this might fail
506 * several times, since we try signing with successively increasing
507 * size values
Philippe Reynesa6982a62020-09-17 15:01:46 +0200508 * And, if needed, write the iv in the FIT file
Philippe Reynes7298e422019-12-18 18:25:41 +0100509 */
510 if (keydest) {
Philippe Reynesa6982a62020-09-17 15:01:46 +0200511 ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
Philippe Reynes7298e422019-12-18 18:25:41 +0100512 if (ret) {
513 printf("Failed to add verification data for cipher '%s' in image '%s'\n",
514 info.keyname, image_name);
515 goto out;
516 }
517 }
518
519 ret = fit_image_write_cipher(fit, image_noffset, node_noffset,
520 data, size,
521 data_ciphered, data_ciphered_len);
522
523 out:
524 free(data_ciphered);
525 free((void *)info.key);
526 free((void *)info.iv);
527 return ret;
528}
529
530int fit_image_cipher_data(const char *keydir, void *keydest,
531 void *fit, int image_noffset, const char *comment,
532 int require_keys, const char *engine_id,
533 const char *cmdname)
534{
535 const char *image_name;
536 const void *data;
537 size_t size;
Patrick Oppenlanderb33e5cc2020-07-30 14:22:15 +1000538 int cipher_node_offset, len;
Philippe Reynes7298e422019-12-18 18:25:41 +0100539
540 /* Get image name */
541 image_name = fit_get_name(fit, image_noffset, NULL);
542 if (!image_name) {
543 printf("Can't get image name\n");
544 return -1;
545 }
546
547 /* Get image data and data length */
548 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
549 printf("Can't get image data/size\n");
550 return -1;
551 }
552
Patrick Oppenlanderb33e5cc2020-07-30 14:22:15 +1000553 /*
554 * Don't cipher ciphered data.
555 *
556 * If the data-size-unciphered property is present the data for this
557 * image is already encrypted. This is important as 'mkimage -F' can be
558 * run multiple times on a FIT image.
559 */
560 if (fdt_getprop(fit, image_noffset, "data-size-unciphered", &len))
561 return 0;
562 if (len != -FDT_ERR_NOTFOUND) {
563 printf("Failure testing for data-size-unciphered\n");
564 return -1;
565 }
Philippe Reynes7298e422019-12-18 18:25:41 +0100566
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000567 /* Process cipher node if present */
568 cipher_node_offset = fdt_subnode_offset(fit, image_noffset,
569 FIT_CIPHER_NODENAME);
570 if (cipher_node_offset == -FDT_ERR_NOTFOUND)
571 return 0;
572 if (cipher_node_offset < 0) {
573 printf("Failure getting cipher node\n");
574 return -1;
Philippe Reynes7298e422019-12-18 18:25:41 +0100575 }
Patrick Oppenlanderc5202662020-07-30 14:22:13 +1000576 if (!IMAGE_ENABLE_ENCRYPT || !keydir)
577 return 0;
578 return fit_image_process_cipher(keydir, keydest, fit, image_name,
579 image_noffset, cipher_node_offset, data, size, cmdname);
Philippe Reynes7298e422019-12-18 18:25:41 +0100580}
581
Simon Glass56518e72013-06-13 15:10:01 -0700582/**
583 * fit_image_add_verification_data() - calculate/set verig. data for image node
584 *
585 * This adds hash and signature values for an component image node.
Simon Glassbbb467d2013-05-07 06:12:01 +0000586 *
587 * All existing hash subnodes are checked, if algorithm property is set to
588 * one of the supported hash algorithms, hash value is computed and
589 * corresponding hash node property is set, for example:
Simon Glass604f23d2013-05-07 06:11:54 +0000590 *
591 * Input component image node structure:
592 *
Andre Przywarab2267e82017-12-04 02:05:10 +0000593 * o image-1 (at image_noffset)
Simon Glass604f23d2013-05-07 06:11:54 +0000594 * | - data = [binary data]
Andre Przywarab2267e82017-12-04 02:05:10 +0000595 * o hash-1
Simon Glass604f23d2013-05-07 06:11:54 +0000596 * |- algo = "sha1"
597 *
598 * Output component image node structure:
599 *
Andre Przywarab2267e82017-12-04 02:05:10 +0000600 * o image-1 (at image_noffset)
Simon Glass604f23d2013-05-07 06:11:54 +0000601 * | - data = [binary data]
Andre Przywarab2267e82017-12-04 02:05:10 +0000602 * o hash-1
Simon Glass604f23d2013-05-07 06:11:54 +0000603 * |- algo = "sha1"
604 * |- value = sha1(data)
605 *
Simon Glassbbb467d2013-05-07 06:12:01 +0000606 * For signature details, please see doc/uImage.FIT/signature.txt
607 *
Simon Glass56518e72013-06-13 15:10:01 -0700608 * @keydir Directory containing *.key and *.crt files (or NULL)
609 * @keydest FDT Blob to write public keys into (NULL if none)
Simon Glassbbb467d2013-05-07 06:12:01 +0000610 * @fit: Pointer to the FIT format image header
611 * @image_noffset: Requested component image node
Simon Glass56518e72013-06-13 15:10:01 -0700612 * @comment: Comment to add to signature nodes
613 * @require_keys: Mark all keys as 'required'
George McCollisterf1ca1fd2017-01-06 13:14:17 -0600614 * @engine_id: Engine to use for signing
Simon Glassbbb467d2013-05-07 06:12:01 +0000615 * @return: 0 on success, <0 on failure
Simon Glass604f23d2013-05-07 06:11:54 +0000616 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600617int fit_image_add_verification_data(const char *keydir, const char *keyfile,
618 void *keydest, void *fit, int image_noffset,
619 const char *comment, int require_keys, const char *engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +0100620 const char *cmdname, const char* algo_name)
Simon Glass604f23d2013-05-07 06:11:54 +0000621{
Simon Glassbbb467d2013-05-07 06:12:01 +0000622 const char *image_name;
Simon Glass604f23d2013-05-07 06:11:54 +0000623 const void *data;
624 size_t size;
Simon Glass604f23d2013-05-07 06:11:54 +0000625 int noffset;
Simon Glass604f23d2013-05-07 06:11:54 +0000626
627 /* Get image data and data length */
628 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
629 printf("Can't get image data/size\n");
630 return -1;
631 }
632
Simon Glass94e5fa42013-05-07 06:11:55 +0000633 image_name = fit_get_name(fit, image_noffset, NULL);
634
Simon Glass604f23d2013-05-07 06:11:54 +0000635 /* Process all hash subnodes of the component image node */
Simon Glassbbb467d2013-05-07 06:12:01 +0000636 for (noffset = fdt_first_subnode(fit, image_noffset);
637 noffset >= 0;
638 noffset = fdt_next_subnode(fit, noffset)) {
639 const char *node_name;
640 int ret = 0;
641
642 /*
643 * Check subnode name, must be equal to "hash" or "signature".
644 * Multiple hash nodes require unique unit node
Andre Przywarab2267e82017-12-04 02:05:10 +0000645 * names, e.g. hash-1, hash-2, signature-1, etc.
Simon Glassbbb467d2013-05-07 06:12:01 +0000646 */
647 node_name = fit_get_name(fit, noffset, NULL);
648 if (!strncmp(node_name, FIT_HASH_NODENAME,
649 strlen(FIT_HASH_NODENAME))) {
650 ret = fit_image_process_hash(fit, image_name, noffset,
651 data, size);
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600652 } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) &&
Simon Glass56518e72013-06-13 15:10:01 -0700653 !strncmp(node_name, FIT_SIG_NODENAME,
654 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -0600655 ret = fit_image_process_sig(keydir, keyfile, keydest,
Simon Glass56518e72013-06-13 15:10:01 -0700656 fit, image_name, noffset, data, size,
Jan Kiszka5902a392022-01-14 10:21:19 +0100657 comment, require_keys, engine_id, cmdname,
658 algo_name);
Simon Glass604f23d2013-05-07 06:11:54 +0000659 }
Simon Glass9737c2d2021-11-12 12:28:12 -0700660 if (ret < 0)
Simon Glass1152a052016-07-03 09:40:44 -0600661 return ret;
Simon Glassbbb467d2013-05-07 06:12:01 +0000662 }
663
664 return 0;
665}
666
Simon Glass4d098522013-06-13 15:10:09 -0700667struct strlist {
668 int count;
669 char **strings;
670};
671
672static void strlist_init(struct strlist *list)
673{
674 memset(list, '\0', sizeof(*list));
675}
676
677static void strlist_free(struct strlist *list)
678{
679 int i;
680
681 for (i = 0; i < list->count; i++)
682 free(list->strings[i]);
683 free(list->strings);
684}
685
686static int strlist_add(struct strlist *list, const char *str)
687{
688 char *dup;
689
690 dup = strdup(str);
691 list->strings = realloc(list->strings,
692 (list->count + 1) * sizeof(char *));
693 if (!list || !str)
694 return -1;
695 list->strings[list->count++] = dup;
696
697 return 0;
698}
699
Simon Glass70e6bcc2021-11-12 12:28:06 -0700700static const char *fit_config_get_image_list(const void *fit, int noffset,
701 int *lenp, int *allow_missingp)
Simon Glass4d098522013-06-13 15:10:09 -0700702{
703 static const char default_list[] = FIT_KERNEL_PROP "\0"
704 FIT_FDT_PROP;
705 const char *prop;
706
Simon Glass70e6bcc2021-11-12 12:28:06 -0700707 /* If there is an "sign-image" property, use that */
Simon Glass4d098522013-06-13 15:10:09 -0700708 prop = fdt_getprop(fit, noffset, "sign-images", lenp);
709 if (prop) {
710 *allow_missingp = 0;
711 return *lenp ? prop : NULL;
712 }
713
714 /* Default image list */
715 *allow_missingp = 1;
716 *lenp = sizeof(default_list);
717
718 return default_list;
719}
720
Simon Glass70e6bcc2021-11-12 12:28:06 -0700721/**
722 * fit_config_add_hash() - Add a list of nodes to hash for an image
723 *
724 * This adds a list of paths to image nodes (as referred to by a particular
725 * offset) that need to be hashed, to protect a configuration
726 *
727 * @fit: Pointer to the FIT format image header
728 * @image_noffset: Offset of image to process (e.g. /images/kernel-1)
729 * @node_inc: List of nodes to add to
730 * @conf_name Configuration-node name, child of /configurations node (only
731 * used for error messages)
732 * @sig_name Signature-node name (only used for error messages)
733 * @iname: Name of image being processed (e.g. "kernel-1" (only used
734 * for error messages)
735 */
736static int fit_config_add_hash(const void *fit, int image_noffset,
737 struct strlist *node_inc, const char *conf_name,
738 const char *sig_name, const char *iname)
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100739{
Simon Glass48422342021-11-12 12:28:07 -0700740 char path[200];
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100741 int noffset;
742 int hash_count;
743 int ret;
744
745 ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
746 if (ret < 0)
747 goto err_path;
748 if (strlist_add(node_inc, path))
749 goto err_mem;
750
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100751 /* Add all this image's hashes */
752 hash_count = 0;
753 for (noffset = fdt_first_subnode(fit, image_noffset);
754 noffset >= 0;
755 noffset = fdt_next_subnode(fit, noffset)) {
756 const char *name = fit_get_name(fit, noffset, NULL);
757
758 if (strncmp(name, FIT_HASH_NODENAME,
759 strlen(FIT_HASH_NODENAME)))
760 continue;
761 ret = fdt_get_path(fit, noffset, path, sizeof(path));
762 if (ret < 0)
763 goto err_path;
764 if (strlist_add(node_inc, path))
765 goto err_mem;
766 hash_count++;
767 }
768
769 if (!hash_count) {
770 printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
771 conf_name, sig_name, iname);
772 return -ENOMSG;
773 }
774
775 /* Add this image's cipher node if present */
776 noffset = fdt_subnode_offset(fit, image_noffset,
777 FIT_CIPHER_NODENAME);
778 if (noffset != -FDT_ERR_NOTFOUND) {
779 if (noffset < 0) {
780 printf("Failed to get cipher node in configuration '%s/%s' image '%s': %s\n",
781 conf_name, sig_name, iname,
782 fdt_strerror(noffset));
783 return -EIO;
784 }
785 ret = fdt_get_path(fit, noffset, path, sizeof(path));
786 if (ret < 0)
787 goto err_path;
788 if (strlist_add(node_inc, path))
789 goto err_mem;
790 }
791
792 return 0;
793
794err_mem:
795 printf("Out of memory processing configuration '%s/%s'\n", conf_name,
796 sig_name);
797 return -ENOMEM;
798
799err_path:
800 printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
801 iname, conf_name, sig_name, fdt_strerror(ret));
802 return -ENOENT;
803}
804
Simon Glass70e6bcc2021-11-12 12:28:06 -0700805/**
806 * fit_config_get_hash_list() - Get the regions to sign
807 *
808 * This calculates a list of nodes to hash for this particular configuration,
809 * returning it as a string list (struct strlist, not a devicetree string list)
810 *
811 * @fit: Pointer to the FIT format image header
812 * @conf_noffset: Offset of configuration node to sign (child of
813 * /configurations node)
814 * @sig_offset: Offset of signature node containing info about how to sign it
815 * (child of 'signatures' node)
816 * @return 0 if OK, -ENOENT if an image referred to by the configuration cannot
817 * be found, -ENOMSG if ther were no images in the configuration
818 */
819static int fit_config_get_hash_list(const void *fit, int conf_noffset,
Simon Glass4d098522013-06-13 15:10:09 -0700820 int sig_offset, struct strlist *node_inc)
821{
822 int allow_missing;
823 const char *prop, *iname, *end;
824 const char *conf_name, *sig_name;
Philippe Reynes5a4116f2020-11-24 14:39:47 +0100825 char name[200];
Simon Glass4d098522013-06-13 15:10:09 -0700826 int image_count;
827 int ret, len;
828
829 conf_name = fit_get_name(fit, conf_noffset, NULL);
830 sig_name = fit_get_name(fit, sig_offset, NULL);
831
832 /*
833 * Build a list of nodes we need to hash. We always need the root
834 * node and the configuration.
835 */
836 strlist_init(node_inc);
837 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
838 if (strlist_add(node_inc, "/") ||
839 strlist_add(node_inc, name))
840 goto err_mem;
841
842 /* Get a list of images that we intend to sign */
Heiko Schocher66b36f82014-03-03 12:19:23 +0100843 prop = fit_config_get_image_list(fit, sig_offset, &len,
Simon Glass4d098522013-06-13 15:10:09 -0700844 &allow_missing);
845 if (!prop)
846 return 0;
847
848 /* Locate the images */
849 end = prop + len;
850 image_count = 0;
851 for (iname = prop; iname < end; iname += strlen(iname) + 1) {
Simon Glass4d098522013-06-13 15:10:09 -0700852 int image_noffset;
Philippe Reynesedfeba72020-11-24 14:39:48 +0100853 int index, max_index;
Simon Glass4d098522013-06-13 15:10:09 -0700854
Philippe Reynesedfeba72020-11-24 14:39:48 +0100855 max_index = fdt_stringlist_count(fit, conf_noffset, iname);
Simon Glass4d098522013-06-13 15:10:09 -0700856
Philippe Reynesedfeba72020-11-24 14:39:48 +0100857 for (index = 0; index < max_index; index++) {
858 image_noffset = fit_conf_get_prop_node_index(fit, conf_noffset,
859 iname, index);
860
861 if (image_noffset < 0) {
862 printf("Failed to find image '%s' in configuration '%s/%s'\n",
863 iname, conf_name, sig_name);
864 if (allow_missing)
865 continue;
866
867 return -ENOENT;
868 }
869
Simon Glass70e6bcc2021-11-12 12:28:06 -0700870 ret = fit_config_add_hash(fit, image_noffset, node_inc,
871 conf_name, sig_name, iname);
Philippe Reynesedfeba72020-11-24 14:39:48 +0100872 if (ret < 0)
873 return ret;
874
875 image_count++;
Simon Glass4d098522013-06-13 15:10:09 -0700876 }
Simon Glass4d098522013-06-13 15:10:09 -0700877 }
878
879 if (!image_count) {
880 printf("Failed to find any images for configuration '%s/%s'\n",
881 conf_name, sig_name);
882 return -ENOMSG;
883 }
884
885 return 0;
886
887err_mem:
888 printf("Out of memory processing configuration '%s/%s'\n", conf_name,
889 sig_name);
890 return -ENOMEM;
Simon Glass4d098522013-06-13 15:10:09 -0700891}
892
Simon Glass70e6bcc2021-11-12 12:28:06 -0700893/**
894 * fit_config_get_regions() - Get the regions to sign
895 *
896 * This calculates a list of node to hash for this particular configuration,
897 * then finds which regions of the devicetree they correspond to.
898 *
899 * @fit: Pointer to the FIT format image header
900 * @conf_noffset: Offset of configuration node to sign (child of
901 * /configurations node)
902 * @sig_offset: Offset of signature node containing info about how to sign it
903 * (child of 'signatures' node)
904 * @regionp: Returns list of regions that need to be hashed (allocated; must be
905 * freed by the caller)
906 * @region_count: Returns number of regions
907 * @region_propp: Returns string-list property containing the list of nodes
908 * that correspond to the regions. Each entry is a full path to the node.
909 * This is in devicetree format, i.e. a \0 between each string. This is
910 * allocated and must be freed by the caller.
911 * @region_proplen: Returns length of *@@region_propp in bytes
912 * @return 0 if OK, -ENOMEM if out of memory, -EIO if the regions to hash could
913 * not be found, -EINVAL if no registers were found to hash
914 */
915static int fit_config_get_regions(const void *fit, int conf_noffset,
916 int sig_offset, struct image_region **regionp,
917 int *region_countp, char **region_propp,
918 int *region_proplen)
Simon Glass4d098522013-06-13 15:10:09 -0700919{
920 char * const exc_prop[] = {"data"};
921 struct strlist node_inc;
922 struct image_region *region;
923 struct fdt_region fdt_regions[100];
924 const char *conf_name, *sig_name;
925 char path[200];
926 int count, i;
927 char *region_prop;
928 int ret, len;
929
930 conf_name = fit_get_name(fit, conf_noffset, NULL);
Simon Glass70e6bcc2021-11-12 12:28:06 -0700931 sig_name = fit_get_name(fit, sig_offset, NULL);
Simon Glass4d098522013-06-13 15:10:09 -0700932 debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
933
934 /* Get a list of nodes we want to hash */
Simon Glass70e6bcc2021-11-12 12:28:06 -0700935 ret = fit_config_get_hash_list(fit, conf_noffset, sig_offset,
936 &node_inc);
Simon Glass4d098522013-06-13 15:10:09 -0700937 if (ret)
938 return ret;
939
940 /* Get a list of regions to hash */
941 count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
942 exc_prop, ARRAY_SIZE(exc_prop),
943 fdt_regions, ARRAY_SIZE(fdt_regions),
944 path, sizeof(path), 1);
945 if (count < 0) {
946 printf("Failed to hash configuration '%s/%s': %s\n", conf_name,
947 sig_name, fdt_strerror(ret));
948 return -EIO;
949 }
950 if (count == 0) {
951 printf("No data to hash for configuration '%s/%s': %s\n",
952 conf_name, sig_name, fdt_strerror(ret));
953 return -EINVAL;
954 }
955
956 /* Build our list of data blocks */
957 region = fit_region_make_list(fit, fdt_regions, count, NULL);
958 if (!region) {
959 printf("Out of memory hashing configuration '%s/%s'\n",
960 conf_name, sig_name);
961 return -ENOMEM;
962 }
963
964 /* Create a list of all hashed properties */
965 debug("Hash nodes:\n");
966 for (i = len = 0; i < node_inc.count; i++) {
967 debug(" %s\n", node_inc.strings[i]);
968 len += strlen(node_inc.strings[i]) + 1;
969 }
970 region_prop = malloc(len);
971 if (!region_prop) {
972 printf("Out of memory setting up regions for configuration '%s/%s'\n",
973 conf_name, sig_name);
974 return -ENOMEM;
975 }
976 for (i = len = 0; i < node_inc.count;
977 len += strlen(node_inc.strings[i]) + 1, i++)
978 strcpy(region_prop + len, node_inc.strings[i]);
979 strlist_free(&node_inc);
980
981 *region_countp = count;
982 *regionp = region;
983 *region_propp = region_prop;
984 *region_proplen = len;
985
986 return 0;
987}
988
Simon Glass9737c2d2021-11-12 12:28:12 -0700989/**
990 * fit_config_process_sig - Process a single subnode of the configurations/ node
991 *
992 * Generate a signed hash of the supplied data and store it in the node.
993 *
994 * @keydir: Directory containing keys to use for signing
995 * @keydest: Destination FDT blob to write public keys into (NULL if none)
996 * @fit: pointer to the FIT format image header
997 * @conf_name name of config being processed (used to display errors)
998 * @conf_noffset: Offset of configuration node, e.g. '/configurations/conf-1'
999 * @noffset: subnode offset, e.g. '/configurations/conf-1/sig-1'
1000 * @comment: Comment to add to signature nodes
1001 * @require_keys: Mark all keys as 'required'
1002 * @engine_id: Engine to use for signing
1003 * @cmdname: Command name used when reporting errors
1004 * @return keydest node if @keydest is non-NULL, else 0 if none; -ve error code
1005 * on failure
1006 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001007static int fit_config_process_sig(const char *keydir, const char *keyfile,
Simon Glass70e6bcc2021-11-12 12:28:06 -07001008 void *keydest, void *fit, const char *conf_name,
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001009 int conf_noffset, int noffset, const char *comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001010 int require_keys, const char *engine_id, const char *cmdname,
1011 const char *algo_name)
Simon Glass4d098522013-06-13 15:10:09 -07001012{
1013 struct image_sign_info info;
1014 const char *node_name;
1015 struct image_region *region;
1016 char *region_prop;
1017 int region_proplen;
1018 int region_count;
1019 uint8_t *value;
1020 uint value_len;
1021 int ret;
1022
1023 node_name = fit_get_name(fit, noffset, NULL);
Simon Glass70e6bcc2021-11-12 12:28:06 -07001024 if (fit_config_get_regions(fit, conf_noffset, noffset, &region,
1025 &region_count, &region_prop,
1026 &region_proplen))
Simon Glass4d098522013-06-13 15:10:09 -07001027 return -1;
1028
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001029 if (fit_image_setup_sig(&info, keydir, keyfile, fit, conf_name, noffset,
Jan Kiszka5902a392022-01-14 10:21:19 +01001030 require_keys ? "conf" : NULL, engine_id,
1031 algo_name))
Simon Glass4d098522013-06-13 15:10:09 -07001032 return -1;
1033
Andrew Duda83dd98e2016-11-08 18:53:41 +00001034 ret = info.crypto->sign(&info, region, region_count, &value,
1035 &value_len);
Simon Glass4d098522013-06-13 15:10:09 -07001036 free(region);
1037 if (ret) {
1038 printf("Failed to sign '%s' signature node in '%s' conf node\n",
1039 node_name, conf_name);
1040
1041 /* We allow keys to be missing */
1042 if (ret == -ENOENT)
1043 return 0;
1044 return -1;
1045 }
1046
Simon Glassa9468112014-06-02 22:04:53 -06001047 ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001048 region_prop, region_proplen, cmdname,
1049 algo_name);
Simon Glassa9468112014-06-02 22:04:53 -06001050 if (ret) {
1051 if (ret == -FDT_ERR_NOSPACE)
1052 return -ENOSPC;
1053 printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n",
1054 node_name, conf_name, fdt_strerror(ret));
Simon Glass4d098522013-06-13 15:10:09 -07001055 return -1;
1056 }
1057 free(value);
1058 free(region_prop);
1059
1060 /* Get keyname again, as FDT has changed and invalidated our pointer */
Simon Glass72188f52020-03-18 11:44:06 -06001061 info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
Simon Glass4d098522013-06-13 15:10:09 -07001062
1063 /* Write the public key into the supplied FDT file */
Simon Glassa9468112014-06-02 22:04:53 -06001064 if (keydest) {
Andrew Duda83dd98e2016-11-08 18:53:41 +00001065 ret = info.crypto->add_verify_data(&info, keydest);
Simon Glassc033dc82021-11-12 12:28:11 -07001066 if (ret < 0) {
Masahiro Yamada76b9cba2017-10-27 15:04:21 +09001067 printf("Failed to add verification data for '%s' signature node in '%s' configuration node\n",
Simon Glassa9468112014-06-02 22:04:53 -06001068 node_name, conf_name);
Simon Glassa9468112014-06-02 22:04:53 -06001069 }
Simon Glass9737c2d2021-11-12 12:28:12 -07001070 return ret;
Simon Glass4d098522013-06-13 15:10:09 -07001071 }
1072
1073 return 0;
1074}
1075
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001076static int fit_config_add_verification_data(const char *keydir,
1077 const char *keyfile, void *keydest, void *fit, int conf_noffset,
1078 const char *comment, int require_keys, const char *engine_id,
Simon Glass2d2384b2021-11-12 12:28:13 -07001079 const char *cmdname, const char *algo_name,
1080 struct image_summary *summary)
Simon Glass4d098522013-06-13 15:10:09 -07001081{
1082 const char *conf_name;
1083 int noffset;
1084
1085 conf_name = fit_get_name(fit, conf_noffset, NULL);
1086
1087 /* Process all hash subnodes of the configuration node */
1088 for (noffset = fdt_first_subnode(fit, conf_noffset);
1089 noffset >= 0;
1090 noffset = fdt_next_subnode(fit, noffset)) {
1091 const char *node_name;
1092 int ret = 0;
1093
1094 node_name = fit_get_name(fit, noffset, NULL);
1095 if (!strncmp(node_name, FIT_SIG_NODENAME,
1096 strlen(FIT_SIG_NODENAME))) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001097 ret = fit_config_process_sig(keydir, keyfile, keydest,
Simon Glass4d098522013-06-13 15:10:09 -07001098 fit, conf_name, conf_noffset, noffset, comment,
Jan Kiszka5902a392022-01-14 10:21:19 +01001099 require_keys, engine_id, cmdname, algo_name);
Simon Glass2d2384b2021-11-12 12:28:13 -07001100 if (ret < 0)
1101 return ret;
1102
1103 summary->sig_offset = noffset;
1104 fdt_get_path(fit, noffset, summary->sig_path,
1105 sizeof(summary->sig_path));
1106
1107 if (keydest) {
1108 summary->keydest_offset = ret;
1109 fdt_get_path(keydest, ret,
1110 summary->keydest_path,
1111 sizeof(summary->keydest_path));
1112 }
Simon Glass4d098522013-06-13 15:10:09 -07001113 }
Simon Glass4d098522013-06-13 15:10:09 -07001114 }
1115
1116 return 0;
1117}
1118
Philippe Reynes6e052d12022-03-28 22:57:02 +02001119/*
1120 * 0) open file (open)
1121 * 1) read certificate (PEM_read_X509)
1122 * 2) get public key (X509_get_pubkey)
1123 * 3) provide der format (d2i_RSAPublicKey)
1124 */
1125static int read_pub_key(const char *keydir, const void *name,
1126 unsigned char **pubkey, int *pubkey_len)
1127{
1128 char path[1024];
1129 EVP_PKEY *key = NULL;
1130 X509 *cert;
1131 FILE *f;
1132 int ret;
1133
1134 memset(path, 0, 1024);
1135 snprintf(path, sizeof(path), "%s/%s.crt", keydir, (char *)name);
1136
1137 /* Open certificate file */
1138 f = fopen(path, "r");
1139 if (!f) {
1140 fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
1141 path, strerror(errno));
1142 return -EACCES;
1143 }
1144
1145 /* Read the certificate */
1146 cert = NULL;
1147 if (!PEM_read_X509(f, &cert, NULL, NULL)) {
1148 printf("Couldn't read certificate");
1149 ret = -EINVAL;
1150 goto err_cert;
1151 }
1152
1153 /* Get the public key from the certificate. */
1154 key = X509_get_pubkey(cert);
1155 if (!key) {
1156 printf("Couldn't read public key\n");
1157 ret = -EINVAL;
1158 goto err_pubkey;
1159 }
1160
1161 /* Get DER form */
1162 ret = i2d_PublicKey(key, pubkey);
1163 if (ret < 0) {
1164 printf("Couldn't get DER form\n");
1165 ret = -EINVAL;
1166 goto err_pubkey;
1167 }
1168
1169 *pubkey_len = ret;
1170 ret = 0;
1171
1172err_pubkey:
1173 X509_free(cert);
1174err_cert:
1175 fclose(f);
1176 return ret;
1177}
1178
1179int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
1180{
1181 int pre_load_noffset;
1182 const void *algo_name;
1183 const void *key_name;
1184 unsigned char *pubkey = NULL;
1185 int ret, pubkey_len;
1186
1187 if (!keydir || !keydest || !fit)
1188 return 0;
1189
1190 /* Search node pre-load sig */
1191 pre_load_noffset = fdt_path_offset(keydest, IMAGE_PRE_LOAD_PATH);
1192 if (pre_load_noffset < 0) {
1193 ret = 0;
1194 goto out;
1195 }
1196
1197 algo_name = fdt_getprop(keydest, pre_load_noffset, "algo-name", NULL);
1198 key_name = fdt_getprop(keydest, pre_load_noffset, "key-name", NULL);
1199
1200 /* Check that all mandatory properties are present */
1201 if (!algo_name || !key_name) {
1202 if (!algo_name)
1203 printf("The property algo-name is missing in the node %s\n",
1204 IMAGE_PRE_LOAD_PATH);
1205 if (!key_name)
1206 printf("The property key-name is missing in the node %s\n",
1207 IMAGE_PRE_LOAD_PATH);
Mark Kettenis61657182022-04-26 19:24:38 +02001208 ret = -EINVAL;
Philippe Reynes6e052d12022-03-28 22:57:02 +02001209 goto out;
1210 }
1211
1212 /* Read public key */
1213 ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
1214 if (ret < 0)
1215 goto out;
1216
1217 /* Add the public key to the device tree */
1218 ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
1219 pubkey, pubkey_len);
1220 if (ret)
1221 printf("Can't set public-key in node %s (ret = %d)\n",
1222 IMAGE_PRE_LOAD_PATH, ret);
1223
1224 out:
1225 return ret;
1226}
1227
Philippe Reynes7298e422019-12-18 18:25:41 +01001228int fit_cipher_data(const char *keydir, void *keydest, void *fit,
1229 const char *comment, int require_keys,
1230 const char *engine_id, const char *cmdname)
1231{
1232 int images_noffset;
1233 int noffset;
1234 int ret;
1235
1236 /* Find images parent node offset */
1237 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1238 if (images_noffset < 0) {
1239 printf("Can't find images parent node '%s' (%s)\n",
1240 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
1241 return images_noffset;
1242 }
1243
1244 /* Process its subnodes, print out component images details */
1245 for (noffset = fdt_first_subnode(fit, images_noffset);
1246 noffset >= 0;
1247 noffset = fdt_next_subnode(fit, noffset)) {
1248 /*
1249 * Direct child node of the images parent node,
1250 * i.e. component image node.
1251 */
1252 ret = fit_image_cipher_data(keydir, keydest,
1253 fit, noffset, comment,
1254 require_keys, engine_id,
1255 cmdname);
1256 if (ret)
1257 return ret;
1258 }
1259
1260 return 0;
1261}
1262
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001263int fit_add_verification_data(const char *keydir, const char *keyfile,
1264 void *keydest, void *fit, const char *comment,
1265 int require_keys, const char *engine_id,
Simon Glass2d2384b2021-11-12 12:28:13 -07001266 const char *cmdname, const char *algo_name,
1267 struct image_summary *summary)
Simon Glassbbb467d2013-05-07 06:12:01 +00001268{
Simon Glass4d098522013-06-13 15:10:09 -07001269 int images_noffset, confs_noffset;
Simon Glassbbb467d2013-05-07 06:12:01 +00001270 int noffset;
1271 int ret;
1272
1273 /* Find images parent node offset */
1274 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1275 if (images_noffset < 0) {
1276 printf("Can't find images parent node '%s' (%s)\n",
1277 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
1278 return images_noffset;
1279 }
1280
1281 /* Process its subnodes, print out component images details */
1282 for (noffset = fdt_first_subnode(fit, images_noffset);
1283 noffset >= 0;
1284 noffset = fdt_next_subnode(fit, noffset)) {
1285 /*
1286 * Direct child node of the images parent node,
1287 * i.e. component image node.
1288 */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001289 ret = fit_image_add_verification_data(keydir, keyfile, keydest,
Alex Kiernan795f4522018-06-20 20:10:52 +00001290 fit, noffset, comment, require_keys, engine_id,
Jan Kiszka5902a392022-01-14 10:21:19 +01001291 cmdname, algo_name);
Simon Glassbbb467d2013-05-07 06:12:01 +00001292 if (ret)
1293 return ret;
Simon Glass604f23d2013-05-07 06:11:54 +00001294 }
1295
Simon Glass4d098522013-06-13 15:10:09 -07001296 /* If there are no keys, we can't sign configurations */
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001297 if (!IMAGE_ENABLE_SIGN || !(keydir || keyfile))
Simon Glass4d098522013-06-13 15:10:09 -07001298 return 0;
1299
1300 /* Find configurations parent node offset */
1301 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
1302 if (confs_noffset < 0) {
1303 printf("Can't find images parent node '%s' (%s)\n",
Heiko Schocher04a710a2014-08-11 11:02:17 +02001304 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Simon Glass4d098522013-06-13 15:10:09 -07001305 return -ENOENT;
1306 }
1307
1308 /* Process its subnodes, print out component images details */
1309 for (noffset = fdt_first_subnode(fit, confs_noffset);
1310 noffset >= 0;
1311 noffset = fdt_next_subnode(fit, noffset)) {
Alexandru Gagniuc36bfcb62021-02-19 12:45:17 -06001312 ret = fit_config_add_verification_data(keydir, keyfile, keydest,
Simon Glass4d098522013-06-13 15:10:09 -07001313 fit, noffset, comment,
George McCollisterf1ca1fd2017-01-06 13:14:17 -06001314 require_keys,
Jan Kiszka5902a392022-01-14 10:21:19 +01001315 engine_id, cmdname,
Simon Glass2d2384b2021-11-12 12:28:13 -07001316 algo_name, summary);
Simon Glass4d098522013-06-13 15:10:09 -07001317 if (ret)
1318 return ret;
1319 }
1320
Simon Glass604f23d2013-05-07 06:11:54 +00001321 return 0;
1322}
Heiko Schocher29a23f92014-03-03 12:19:30 +01001323
1324#ifdef CONFIG_FIT_SIGNATURE
Simon Glassc3aa81e2020-03-18 11:44:03 -06001325int fit_check_sign(const void *fit, const void *key,
1326 const char *fit_uname_config)
Heiko Schocher29a23f92014-03-03 12:19:30 +01001327{
1328 int cfg_noffset;
1329 int ret;
1330
Simon Glassc3aa81e2020-03-18 11:44:03 -06001331 cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
Heiko Schocher29a23f92014-03-03 12:19:30 +01001332 if (!cfg_noffset)
1333 return -1;
1334
Simon Glass382cf622020-03-18 11:43:56 -06001335 printf("Verifying Hash Integrity for node '%s'... ",
1336 fdt_get_name(fit, cfg_noffset, NULL));
Simon Glassce1400f2014-06-12 07:24:53 -06001337 ret = fit_config_verify(fit, cfg_noffset);
1338 if (ret)
1339 return ret;
Simon Glassc3aa81e2020-03-18 11:44:03 -06001340 printf("Verified OK, loading images\n");
Simon Glassce1400f2014-06-12 07:24:53 -06001341 ret = bootm_host_load_images(fit, cfg_noffset);
1342
Heiko Schocher29a23f92014-03-03 12:19:30 +01001343 return ret;
1344}
1345#endif