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