]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/image-sig.c
rsa: Verify RSA padding programatically
[people/ms/u-boot.git] / common / image-sig.c
CommitLineData
3e569a6b
SG
1/*
2 * Copyright (c) 2013, Google Inc.
3 *
1a459660 4 * SPDX-License-Identifier: GPL-2.0+
3e569a6b
SG
5 */
6
7#ifdef USE_HOSTCC
8#include "mkimage.h"
9#include <time.h>
10#else
11#include <common.h>
56518e71
SG
12#include <malloc.h>
13DECLARE_GLOBAL_DATA_PTR;
3e569a6b 14#endif /* !USE_HOSTCC*/
3e569a6b 15#include <image.h>
2b9912e6
JH
16#include <u-boot/rsa.h>
17#include <u-boot/rsa-checksum.h>
3e569a6b 18
4d098529
SG
19#define IMAGE_MAX_HASHED_NODES 100
20
646257d1 21#ifdef USE_HOSTCC
29a23f9d
HS
22void *host_blob;
23void image_set_host_blob(void *blob)
646257d1 24{
29a23f9d
HS
25 host_blob = blob;
26}
27void *image_get_host_blob(void)
28{
29 return host_blob;
646257d1
HS
30}
31#endif
32
33struct checksum_algo checksum_algos[] = {
34 {
35 "sha1",
36 SHA1_SUM_LEN,
da29f299
AD
37 SHA1_DER_LEN,
38 sha1_der_prefix,
db1b5f3d 39 RSA2048_BYTES,
646257d1
HS
40#if IMAGE_ENABLE_SIGN
41 EVP_sha1,
29a23f9d 42#endif
b37b46f0 43 hash_calculate,
646257d1
HS
44 },
45 {
46 "sha256",
47 SHA256_SUM_LEN,
da29f299
AD
48 SHA256_DER_LEN,
49 sha256_der_prefix,
db1b5f3d 50 RSA2048_BYTES,
646257d1
HS
51#if IMAGE_ENABLE_SIGN
52 EVP_sha256,
29a23f9d 53#endif
b37b46f0 54 hash_calculate,
db1b5f3d
HS
55 },
56 {
57 "sha256",
58 SHA256_SUM_LEN,
da29f299
AD
59 SHA256_DER_LEN,
60 sha256_der_prefix,
db1b5f3d
HS
61 RSA4096_BYTES,
62#if IMAGE_ENABLE_SIGN
63 EVP_sha256,
29a23f9d 64#endif
b37b46f0 65 hash_calculate,
646257d1 66 }
db1b5f3d 67
646257d1 68};
db1b5f3d 69
3e569a6b 70struct image_sig_algo image_sig_algos[] = {
19c402af
SG
71 {
72 "sha1,rsa2048",
73 rsa_sign,
74 rsa_add_verify_data,
75 rsa_verify,
646257d1
HS
76 &checksum_algos[0],
77 },
78 {
79 "sha256,rsa2048",
80 rsa_sign,
81 rsa_add_verify_data,
82 rsa_verify,
83 &checksum_algos[1],
db1b5f3d
HS
84 },
85 {
86 "sha256,rsa4096",
87 rsa_sign,
88 rsa_add_verify_data,
89 rsa_verify,
90 &checksum_algos[2],
19c402af 91 }
db1b5f3d 92
3e569a6b
SG
93};
94
95struct image_sig_algo *image_get_sig_algo(const char *name)
96{
97 int i;
98
99 for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) {
100 if (!strcmp(image_sig_algos[i].name, name))
101 return &image_sig_algos[i];
102 }
103
104 return NULL;
105}
56518e71 106
4d098529
SG
107/**
108 * fit_region_make_list() - Make a list of image regions
109 *
110 * Given a list of fdt_regions, create a list of image_regions. This is a
111 * simple conversion routine since the FDT and image code use different
112 * structures.
113 *
114 * @fit: FIT image
115 * @fdt_regions: Pointer to FDT regions
116 * @count: Number of FDT regions
117 * @region: Pointer to image regions, which must hold @count records. If
118 * region is NULL, then (except for an SPL build) the array will be
119 * allocated.
120 * @return: Pointer to image regions
121 */
122struct image_region *fit_region_make_list(const void *fit,
123 struct fdt_region *fdt_regions, int count,
124 struct image_region *region)
125{
126 int i;
127
128 debug("Hash regions:\n");
129 debug("%10s %10s\n", "Offset", "Size");
130
131 /*
132 * Use malloc() except in SPL (to save code size). In SPL the caller
133 * must allocate the array.
134 */
135#ifndef CONFIG_SPL_BUILD
136 if (!region)
137 region = calloc(sizeof(*region), count);
138#endif
139 if (!region)
140 return NULL;
141 for (i = 0; i < count; i++) {
142 debug("%10x %10x\n", fdt_regions[i].offset,
143 fdt_regions[i].size);
144 region[i].data = fit + fdt_regions[i].offset;
145 region[i].size = fdt_regions[i].size;
146 }
147
148 return region;
149}
150
56518e71
SG
151static int fit_image_setup_verify(struct image_sign_info *info,
152 const void *fit, int noffset, int required_keynode,
153 char **err_msgp)
154{
155 char *algo_name;
156
157 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
158 *err_msgp = "Can't get hash algo property";
159 return -1;
160 }
161 memset(info, '\0', sizeof(*info));
162 info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
163 info->fit = (void *)fit;
164 info->node_offset = noffset;
165 info->algo = image_get_sig_algo(algo_name);
166 info->fdt_blob = gd_fdt_blob();
167 info->required_keynode = required_keynode;
168 printf("%s:%s", algo_name, info->keyname);
169
170 if (!info->algo) {
171 *err_msgp = "Unknown signature algorithm";
172 return -1;
173 }
174
175 return 0;
176}
177
178int fit_image_check_sig(const void *fit, int noffset, const void *data,
179 size_t size, int required_keynode, char **err_msgp)
180{
181 struct image_sign_info info;
182 struct image_region region;
183 uint8_t *fit_value;
184 int fit_value_len;
185
186 *err_msgp = NULL;
187 if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
188 err_msgp))
189 return -1;
190
191 if (fit_image_hash_get_value(fit, noffset, &fit_value,
192 &fit_value_len)) {
193 *err_msgp = "Can't get hash value property";
194 return -1;
195 }
196
197 region.data = data;
198 region.size = size;
199
200 if (info.algo->verify(&info, &region, 1, fit_value, fit_value_len)) {
201 *err_msgp = "Verification failed";
202 return -1;
203 }
204
205 return 0;
206}
207
208static int fit_image_verify_sig(const void *fit, int image_noffset,
209 const char *data, size_t size, const void *sig_blob,
210 int sig_offset)
211{
212 int noffset;
213 char *err_msg = "";
214 int verified = 0;
215 int ret;
216
217 /* Process all hash subnodes of the component image node */
df87e6b1 218 fdt_for_each_subnode(noffset, fit, image_noffset) {
56518e71
SG
219 const char *name = fit_get_name(fit, noffset, NULL);
220
221 if (!strncmp(name, FIT_SIG_NODENAME,
222 strlen(FIT_SIG_NODENAME))) {
223 ret = fit_image_check_sig(fit, noffset, data,
224 size, -1, &err_msg);
225 if (ret) {
226 puts("- ");
227 } else {
228 puts("+ ");
229 verified = 1;
230 break;
231 }
232 }
233 }
234
235 if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
236 err_msg = "Corrupted or truncated tree";
237 goto error;
238 }
239
240 return verified ? 0 : -EPERM;
241
242error:
243 printf(" error!\n%s for '%s' hash node in '%s' image node\n",
244 err_msg, fit_get_name(fit, noffset, NULL),
245 fit_get_name(fit, image_noffset, NULL));
246 return -1;
247}
248
249int fit_image_verify_required_sigs(const void *fit, int image_noffset,
250 const char *data, size_t size, const void *sig_blob,
251 int *no_sigsp)
252{
253 int verify_count = 0;
254 int noffset;
255 int sig_node;
256
257 /* Work out what we need to verify */
258 *no_sigsp = 1;
259 sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
260 if (sig_node < 0) {
261 debug("%s: No signature node found: %s\n", __func__,
262 fdt_strerror(sig_node));
263 return 0;
264 }
265
df87e6b1 266 fdt_for_each_subnode(noffset, sig_blob, sig_node) {
56518e71
SG
267 const char *required;
268 int ret;
269
270 required = fdt_getprop(sig_blob, noffset, "required", NULL);
271 if (!required || strcmp(required, "image"))
272 continue;
273 ret = fit_image_verify_sig(fit, image_noffset, data, size,
274 sig_blob, noffset);
275 if (ret) {
276 printf("Failed to verify required signature '%s'\n",
277 fit_get_name(sig_blob, noffset, NULL));
278 return ret;
279 }
280 verify_count++;
281 }
282
283 if (verify_count)
284 *no_sigsp = 0;
285
286 return 0;
287}
4d098529
SG
288
289int fit_config_check_sig(const void *fit, int noffset, int required_keynode,
290 char **err_msgp)
291{
292 char * const exc_prop[] = {"data"};
293 const char *prop, *end, *name;
294 struct image_sign_info info;
295 const uint32_t *strings;
296 uint8_t *fit_value;
297 int fit_value_len;
298 int max_regions;
299 int i, prop_len;
300 char path[200];
301 int count;
302
303 debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
304 fit_get_name(fit, noffset, NULL),
305 fit_get_name(gd_fdt_blob(), required_keynode, NULL));
306 *err_msgp = NULL;
307 if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
308 err_msgp))
309 return -1;
310
311 if (fit_image_hash_get_value(fit, noffset, &fit_value,
312 &fit_value_len)) {
313 *err_msgp = "Can't get hash value property";
314 return -1;
315 }
316
317 /* Count the number of strings in the property */
318 prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
319 end = prop ? prop + prop_len : prop;
320 for (name = prop, count = 0; name < end; name++)
321 if (!*name)
322 count++;
323 if (!count) {
324 *err_msgp = "Can't get hashed-nodes property";
325 return -1;
326 }
327
328 /* Add a sanity check here since we are using the stack */
329 if (count > IMAGE_MAX_HASHED_NODES) {
330 *err_msgp = "Number of hashed nodes exceeds maximum";
331 return -1;
332 }
333
334 /* Create a list of node names from those strings */
335 char *node_inc[count];
336
337 debug("Hash nodes (%d):\n", count);
338 for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
339 debug(" '%s'\n", name);
340 node_inc[i] = (char *)name;
341 }
342
343 /*
344 * Each node can generate one region for each sub-node. Allow for
345 * 7 sub-nodes (hash@1, signature@1, etc.) and some extra.
346 */
347 max_regions = 20 + count * 7;
348 struct fdt_region fdt_regions[max_regions];
349
350 /* Get a list of regions to hash */
351 count = fdt_find_regions(fit, node_inc, count,
352 exc_prop, ARRAY_SIZE(exc_prop),
353 fdt_regions, max_regions - 1,
354 path, sizeof(path), 0);
355 if (count < 0) {
356 *err_msgp = "Failed to hash configuration";
357 return -1;
358 }
359 if (count == 0) {
360 *err_msgp = "No data to hash";
361 return -1;
362 }
363 if (count >= max_regions - 1) {
364 *err_msgp = "Too many hash regions";
365 return -1;
366 }
367
368 /* Add the strings */
369 strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
370 if (strings) {
371 fdt_regions[count].offset = fdt_off_dt_strings(fit) +
372 fdt32_to_cpu(strings[0]);
373 fdt_regions[count].size = fdt32_to_cpu(strings[1]);
374 count++;
375 }
376
377 /* Allocate the region list on the stack */
378 struct image_region region[count];
379
380 fit_region_make_list(fit, fdt_regions, count, region);
381 if (info.algo->verify(&info, region, count, fit_value,
382 fit_value_len)) {
383 *err_msgp = "Verification failed";
384 return -1;
385 }
386
387 return 0;
388}
389
390static int fit_config_verify_sig(const void *fit, int conf_noffset,
391 const void *sig_blob, int sig_offset)
392{
393 int noffset;
394 char *err_msg = "";
395 int verified = 0;
396 int ret;
397
398 /* Process all hash subnodes of the component conf node */
df87e6b1 399 fdt_for_each_subnode(noffset, fit, conf_noffset) {
4d098529
SG
400 const char *name = fit_get_name(fit, noffset, NULL);
401
402 if (!strncmp(name, FIT_SIG_NODENAME,
403 strlen(FIT_SIG_NODENAME))) {
404 ret = fit_config_check_sig(fit, noffset, sig_offset,
405 &err_msg);
406 if (ret) {
407 puts("- ");
408 } else {
409 puts("+ ");
410 verified = 1;
411 break;
412 }
413 }
414 }
415
416 if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
417 err_msg = "Corrupted or truncated tree";
418 goto error;
419 }
420
421 return verified ? 0 : -EPERM;
422
423error:
424 printf(" error!\n%s for '%s' hash node in '%s' config node\n",
425 err_msg, fit_get_name(fit, noffset, NULL),
426 fit_get_name(fit, conf_noffset, NULL));
427 return -1;
428}
429
430int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
431 const void *sig_blob)
432{
433 int noffset;
434 int sig_node;
435
436 /* Work out what we need to verify */
437 sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
438 if (sig_node < 0) {
439 debug("%s: No signature node found: %s\n", __func__,
440 fdt_strerror(sig_node));
441 return 0;
442 }
443
df87e6b1 444 fdt_for_each_subnode(noffset, sig_blob, sig_node) {
4d098529
SG
445 const char *required;
446 int ret;
447
448 required = fdt_getprop(sig_blob, noffset, "required", NULL);
449 if (!required || strcmp(required, "conf"))
450 continue;
451 ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
452 noffset);
453 if (ret) {
454 printf("Failed to verify required signature '%s'\n",
455 fit_get_name(sig_blob, noffset, NULL));
456 return ret;
457 }
458 }
459
460 return 0;
461}
462
463int fit_config_verify(const void *fit, int conf_noffset)
464{
12df2abe
SG
465 return fit_config_verify_required_sigs(fit, conf_noffset,
466 gd_fdt_blob());
4d098529 467}