blob: 2f851ebb28c2832cb823c4c4cbb33beb0584a2a4 [file] [log] [blame]
Philippe Reynesd28484e2022-03-28 22:56:59 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2021 Philippe Reynes <philippe.reynes@softathome.com>
4 */
5
Paul HENRYSa8c92342025-02-24 22:20:52 +01006#ifdef USE_HOSTCC
7#include "mkimage.h"
8#else
Philippe Reynesd28484e2022-03-28 22:56:59 +02009#include <asm/global_data.h>
Tom Riniee8ed542025-05-14 16:46:00 -060010#include <env.h>
Philippe Reynesd28484e2022-03-28 22:56:59 +020011#include <mapmem.h>
Paul HENRYSa8c92342025-02-24 22:20:52 +010012DECLARE_GLOBAL_DATA_PTR;
13#endif /* !USE_HOSTCC*/
Philippe Reynesd28484e2022-03-28 22:56:59 +020014
Paul HENRYSa8c92342025-02-24 22:20:52 +010015#include <image.h>
Philippe Reynesd28484e2022-03-28 22:56:59 +020016#include <u-boot/sha256.h>
17
Paul HENRYSa8c92342025-02-24 22:20:52 +010018#ifdef USE_HOSTCC
19/* Define compat stuff for use in tools. */
20typedef uint8_t u8;
21typedef uint16_t u16;
22typedef uint32_t u32;
23#endif
24
Philippe Reynesd28484e2022-03-28 22:56:59 +020025/*
26 * Offset of the image
27 *
28 * This value is used to skip the header before really launching the image
29 */
30ulong image_load_offset;
31
Paul HENRYSa8c92342025-02-24 22:20:52 +010032#ifdef USE_HOSTCC
33/* Host tools use these implementations to setup information related to the
34 * pre-load signatures
35 */
36static struct image_sig_info *host_info;
37
38#define log_info(fmt, args...) printf(fmt, ##args)
39#define log_err(fmt, args...) printf(fmt, ##args)
40
41void image_pre_load_sig_set_info(struct image_sig_info *info)
42{
43 host_info = info;
44}
45
46/*
47 * This function sets a pointer to information for the signature check.
48 * It expects that host_info has been initially provision by the host
49 * application.
50 *
51 * return:
52 * < 0 => an error has occurred
53 * 0 => OK
54 */
55static int image_pre_load_sig_setup(struct image_sig_info *info)
56{
57 if (!info) {
58 log_err("ERROR: info is NULL\n");
59 return -EINVAL;
60 }
61
62 if (!host_info) {
63 log_err("ERROR: host_info is NULL\n");
64 log_err("ERROR: Set it with image_pre_load_sig_set_info()\n");
65 return -EINVAL;
66 }
67
68 memcpy(info, host_info, sizeof(struct image_sig_info));
69
70 return 0;
71}
72#else
Philippe Reynesd28484e2022-03-28 22:56:59 +020073/*
74 * This function gathers information about the signature check
75 * that could be done before launching the image.
76 *
77 * return:
78 * < 0 => an error has occurred
79 * 0 => OK
80 * 1 => no setup
81 */
82static int image_pre_load_sig_setup(struct image_sig_info *info)
83{
84 const void *algo_name, *padding_name, *key, *mandatory;
85 const u32 *sig_size;
86 int key_len;
87 int node, ret = 0;
Steven Lawrance591da922022-09-14 20:57:28 +020088 char *sig_info_path = NULL;
Philippe Reynesd28484e2022-03-28 22:56:59 +020089
90 if (!info) {
91 log_err("ERROR: info is NULL for image pre-load sig check\n");
92 ret = -EINVAL;
93 goto out;
94 }
95
96 memset(info, 0, sizeof(*info));
97
Steven Lawrance591da922022-09-14 20:57:28 +020098 sig_info_path = env_get("pre_load_sig_info_path");
99 if (!sig_info_path)
100 sig_info_path = IMAGE_PRE_LOAD_PATH;
101
102 node = fdt_path_offset(gd_fdt_blob(), sig_info_path);
Philippe Reynesd28484e2022-03-28 22:56:59 +0200103 if (node < 0) {
104 log_info("INFO: no info for image pre-load sig check\n");
105 ret = 1;
106 goto out;
107 }
108
109 algo_name = fdt_getprop(gd_fdt_blob(), node,
110 IMAGE_PRE_LOAD_PROP_ALGO_NAME, NULL);
111 if (!algo_name) {
112 printf("ERROR: no algo_name for image pre-load sig check\n");
113 ret = -EINVAL;
114 goto out;
115 }
116
117 padding_name = fdt_getprop(gd_fdt_blob(), node,
118 IMAGE_PRE_LOAD_PROP_PADDING_NAME, NULL);
119 if (!padding_name) {
120 log_info("INFO: no padding_name provided, so using pkcs-1.5\n");
121 padding_name = "pkcs-1.5";
122 }
123
124 sig_size = fdt_getprop(gd_fdt_blob(), node,
125 IMAGE_PRE_LOAD_PROP_SIG_SIZE, NULL);
126 if (!sig_size) {
127 log_err("ERROR: no signature-size for image pre-load sig check\n");
128 ret = -EINVAL;
129 goto out;
130 }
131
132 key = fdt_getprop(gd_fdt_blob(), node,
133 IMAGE_PRE_LOAD_PROP_PUBLIC_KEY, &key_len);
134 if (!key) {
135 log_err("ERROR: no key for image pre-load sig check\n");
136 ret = -EINVAL;
137 goto out;
138 }
139
140 info->algo_name = (char *)algo_name;
141 info->padding_name = (char *)padding_name;
142 info->key = (uint8_t *)key;
143 info->key_len = key_len;
144 info->sig_size = fdt32_to_cpu(*sig_size);
145
146 mandatory = fdt_getprop(gd_fdt_blob(), node,
147 IMAGE_PRE_LOAD_PROP_MANDATORY, NULL);
148 if (mandatory && !strcmp((char *)mandatory, "yes"))
149 info->mandatory = 1;
150
151 /* Compute signature information */
152 info->sig_info.name = info->algo_name;
153 info->sig_info.padding = image_get_padding_algo(info->padding_name);
154 info->sig_info.checksum = image_get_checksum_algo(info->sig_info.name);
155 info->sig_info.crypto = image_get_crypto_algo(info->sig_info.name);
156 info->sig_info.key = info->key;
157 info->sig_info.keylen = info->key_len;
158
159 out:
160 return ret;
161}
Paul HENRYSa8c92342025-02-24 22:20:52 +0100162#endif /* !USE_HOSTCC */
Philippe Reynesd28484e2022-03-28 22:56:59 +0200163
164static int image_pre_load_sig_get_magic(ulong addr, u32 *magic)
165{
166 struct sig_header_s *sig_header;
167 int ret = 0;
168
169 sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
170 if (!sig_header) {
171 log_err("ERROR: can't map first header\n");
172 ret = -EFAULT;
173 goto out;
174 }
175
176 *magic = fdt32_to_cpu(sig_header->magic);
177
178 unmap_sysmem(sig_header);
179
180 out:
181 return ret;
182}
183
184static int image_pre_load_sig_get_header_size(ulong addr, u32 *header_size)
185{
186 struct sig_header_s *sig_header;
187 int ret = 0;
188
189 sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
190 if (!sig_header) {
191 log_err("ERROR: can't map first header\n");
192 ret = -EFAULT;
193 goto out;
194 }
195
196 *header_size = fdt32_to_cpu(sig_header->header_size);
197
198 unmap_sysmem(sig_header);
199
200 out:
201 return ret;
202}
203
204/*
205 * return:
206 * < 0 => no magic and magic mandatory (or error when reading magic)
207 * 0 => magic found
208 * 1 => magic NOT found
209 */
210static int image_pre_load_sig_check_magic(struct image_sig_info *info, ulong addr)
211{
212 u32 magic;
213 int ret = 1;
214
215 ret = image_pre_load_sig_get_magic(addr, &magic);
216 if (ret < 0)
217 goto out;
218
219 if (magic != IMAGE_PRE_LOAD_SIG_MAGIC) {
220 if (info->mandatory) {
221 log_err("ERROR: signature is mandatory\n");
222 ret = -EINVAL;
223 goto out;
224 }
225 ret = 1;
226 goto out;
227 }
228
229 ret = 0; /* magic found */
230
231 out:
232 return ret;
233}
234
235static int image_pre_load_sig_check_header_sig(struct image_sig_info *info, ulong addr)
236{
237 void *header;
238 struct image_region reg;
239 u32 sig_len;
240 u8 *sig;
241 int ret = 0;
242
243 /* Only map header of the header and its signature */
244 header = (void *)map_sysmem(addr, SIG_HEADER_LEN + info->sig_size);
245 if (!header) {
246 log_err("ERROR: can't map header\n");
247 ret = -EFAULT;
248 goto out;
249 }
250
251 reg.data = header;
252 reg.size = SIG_HEADER_LEN;
253
254 sig = (uint8_t *)header + SIG_HEADER_LEN;
255 sig_len = info->sig_size;
256
257 ret = info->sig_info.crypto->verify(&info->sig_info, &reg, 1, sig, sig_len);
258 if (ret) {
259 log_err("ERROR: header signature check has failed (err=%d)\n", ret);
260 ret = -EINVAL;
261 goto out_unmap;
262 }
263
264 out_unmap:
265 unmap_sysmem(header);
266
267 out:
268 return ret;
269}
270
271static int image_pre_load_sig_check_img_sig_sha256(struct image_sig_info *info, ulong addr)
272{
273 struct sig_header_s *sig_header;
274 u32 header_size, offset_img_sig;
275 void *header;
276 u8 sha256_img_sig[SHA256_SUM_LEN];
277 int ret = 0;
278
279 sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
280 if (!sig_header) {
281 log_err("ERROR: can't map first header\n");
282 ret = -EFAULT;
283 goto out;
284 }
285
286 header_size = fdt32_to_cpu(sig_header->header_size);
287 offset_img_sig = fdt32_to_cpu(sig_header->offset_img_sig);
288
289 header = (void *)map_sysmem(addr, header_size);
290 if (!header) {
291 log_err("ERROR: can't map header\n");
292 ret = -EFAULT;
293 goto out_sig_header;
294 }
295
296 sha256_csum_wd(header + offset_img_sig, info->sig_size,
297 sha256_img_sig, CHUNKSZ_SHA256);
298
299 ret = memcmp(sig_header->sha256_img_sig, sha256_img_sig, SHA256_SUM_LEN);
300 if (ret) {
301 log_err("ERROR: sha256 of image signature is invalid\n");
302 ret = -EFAULT;
303 goto out_header;
304 }
305
306 out_header:
307 unmap_sysmem(header);
308 out_sig_header:
309 unmap_sysmem(sig_header);
310 out:
311 return ret;
312}
313
314static int image_pre_load_sig_check_img_sig(struct image_sig_info *info, ulong addr)
315{
316 struct sig_header_s *sig_header;
317 u32 header_size, image_size, offset_img_sig;
318 void *image;
319 struct image_region reg;
320 u32 sig_len;
321 u8 *sig;
322 int ret = 0;
323
324 sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
325 if (!sig_header) {
326 log_err("ERROR: can't map first header\n");
327 ret = -EFAULT;
328 goto out;
329 }
330
331 header_size = fdt32_to_cpu(sig_header->header_size);
332 image_size = fdt32_to_cpu(sig_header->image_size);
333 offset_img_sig = fdt32_to_cpu(sig_header->offset_img_sig);
334
335 unmap_sysmem(sig_header);
336
337 image = (void *)map_sysmem(addr, header_size + image_size);
338 if (!image) {
339 log_err("ERROR: can't map full image\n");
340 ret = -EFAULT;
341 goto out;
342 }
343
344 reg.data = image + header_size;
345 reg.size = image_size;
346
347 sig = (uint8_t *)image + offset_img_sig;
348 sig_len = info->sig_size;
349
350 ret = info->sig_info.crypto->verify(&info->sig_info, &reg, 1, sig, sig_len);
351 if (ret) {
352 log_err("ERROR: signature check has failed (err=%d)\n", ret);
353 ret = -EINVAL;
354 goto out_unmap_image;
355 }
356
357 log_info("INFO: signature check has succeed\n");
358
359 out_unmap_image:
360 unmap_sysmem(image);
361
362 out:
363 return ret;
364}
365
366int image_pre_load_sig(ulong addr)
367{
368 struct image_sig_info info;
369 int ret;
370
371 ret = image_pre_load_sig_setup(&info);
372 if (ret < 0)
373 goto out;
374 if (ret > 0) {
375 ret = 0;
376 goto out;
377 }
378
379 ret = image_pre_load_sig_check_magic(&info, addr);
380 if (ret < 0)
381 goto out;
382 if (ret > 0) {
383 ret = 0;
384 goto out;
385 }
386
387 /* Check the signature of the signature header */
388 ret = image_pre_load_sig_check_header_sig(&info, addr);
389 if (ret < 0)
390 goto out;
391
392 /* Check sha256 of the image signature */
393 ret = image_pre_load_sig_check_img_sig_sha256(&info, addr);
394 if (ret < 0)
395 goto out;
396
397 /* Check the image signature */
398 ret = image_pre_load_sig_check_img_sig(&info, addr);
399 if (!ret) {
400 u32 header_size;
401
402 ret = image_pre_load_sig_get_header_size(addr, &header_size);
403 if (ret) {
404 log_err("%s: can't get header size\n", __func__);
405 ret = -EINVAL;
406 goto out;
407 }
408
409 image_load_offset += header_size;
410 }
411
412 out:
413 return ret;
414}
415
416int image_pre_load(ulong addr)
417{
418 int ret = 0;
419
420 image_load_offset = 0;
421
422 if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD_SIG))
423 ret = image_pre_load_sig(addr);
424
425 return ret;
426}