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