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