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