doc: fix mistyped "env flags" command
[pandora-u-boot.git] / boot / image-fit-sig.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013, Google Inc.
4  */
5
6 #ifdef USE_HOSTCC
7 #include "mkimage.h"
8 #include <time.h>
9 #else
10 #include <common.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <asm/global_data.h>
14 DECLARE_GLOBAL_DATA_PTR;
15 #endif /* !USE_HOSTCC*/
16 #include <fdt_region.h>
17 #include <image.h>
18 #include <u-boot/rsa.h>
19 #include <u-boot/hash-checksum.h>
20
21 #define IMAGE_MAX_HASHED_NODES          100
22
23 /**
24  * fit_region_make_list() - Make a list of image regions
25  *
26  * Given a list of fdt_regions, create a list of image_regions. This is a
27  * simple conversion routine since the FDT and image code use different
28  * structures.
29  *
30  * @fit: FIT image
31  * @fdt_regions: Pointer to FDT regions
32  * @count: Number of FDT regions
33  * @region: Pointer to image regions, which must hold @count records. If
34  * region is NULL, then (except for an SPL build) the array will be
35  * allocated.
36  * @return: Pointer to image regions
37  */
38 struct image_region *fit_region_make_list(const void *fit,
39                                           struct fdt_region *fdt_regions,
40                                           int count,
41                                           struct image_region *region)
42 {
43         int i;
44
45         debug("Hash regions:\n");
46         debug("%10s %10s\n", "Offset", "Size");
47
48         /*
49          * Use malloc() except in SPL (to save code size). In SPL the caller
50          * must allocate the array.
51          */
52         if (!IS_ENABLED(CONFIG_SPL_BUILD) && !region)
53                 region = calloc(sizeof(*region), count);
54         if (!region)
55                 return NULL;
56         for (i = 0; i < count; i++) {
57                 debug("%10x %10x\n", fdt_regions[i].offset,
58                       fdt_regions[i].size);
59                 region[i].data = fit + fdt_regions[i].offset;
60                 region[i].size = fdt_regions[i].size;
61         }
62
63         return region;
64 }
65
66 static int fit_image_setup_verify(struct image_sign_info *info,
67                                   const void *fit, int noffset,
68                                   const void *key_blob, int required_keynode,
69                                   char **err_msgp)
70 {
71         const char *algo_name;
72         const char *padding_name;
73
74         if (fdt_totalsize(fit) > CONFIG_VAL(FIT_SIGNATURE_MAX_SIZE)) {
75                 *err_msgp = "Total size too large";
76                 return 1;
77         }
78         if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
79                 *err_msgp = "Can't get hash algo property";
80                 return -1;
81         }
82
83         padding_name = fdt_getprop(fit, noffset, "padding", NULL);
84         if (!padding_name)
85                 padding_name = RSA_DEFAULT_PADDING_NAME;
86
87         memset(info, '\0', sizeof(*info));
88         info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
89         info->fit = fit;
90         info->node_offset = noffset;
91         info->name = algo_name;
92         info->checksum = image_get_checksum_algo(algo_name);
93         info->crypto = image_get_crypto_algo(algo_name);
94         info->padding = image_get_padding_algo(padding_name);
95         info->fdt_blob = key_blob;
96         info->required_keynode = required_keynode;
97         printf("%s:%s", algo_name, info->keyname);
98
99         if (!info->checksum || !info->crypto || !info->padding) {
100                 *err_msgp = "Unknown signature algorithm";
101                 return -1;
102         }
103
104         return 0;
105 }
106
107 int fit_image_check_sig(const void *fit, int noffset, const void *data,
108                         size_t size, const void *key_blob, int required_keynode,
109                         char **err_msgp)
110 {
111         struct image_sign_info info;
112         struct image_region region;
113         uint8_t *fit_value;
114         int fit_value_len;
115
116         *err_msgp = NULL;
117         if (fit_image_setup_verify(&info, fit, noffset, key_blob,
118                                    required_keynode, err_msgp))
119                 return -1;
120
121         if (fit_image_hash_get_value(fit, noffset, &fit_value,
122                                      &fit_value_len)) {
123                 *err_msgp = "Can't get hash value property";
124                 return -1;
125         }
126
127         region.data = data;
128         region.size = size;
129
130         if (info.crypto->verify(&info, &region, 1, fit_value, fit_value_len)) {
131                 *err_msgp = "Verification failed";
132                 return -1;
133         }
134
135         return 0;
136 }
137
138 static int fit_image_verify_sig(const void *fit, int image_noffset,
139                                 const char *data, size_t size,
140                                 const void *key_blob, int key_offset)
141 {
142         int noffset;
143         char *err_msg = "";
144         int verified = 0;
145         int ret;
146
147         /* Process all hash subnodes of the component image node */
148         fdt_for_each_subnode(noffset, fit, image_noffset) {
149                 const char *name = fit_get_name(fit, noffset, NULL);
150
151                 /*
152                  * We don't support this since libfdt considers names with the
153                  * name root but different @ suffix to be equal
154                  */
155                 if (strchr(name, '@')) {
156                         err_msg = "Node name contains @";
157                         goto error;
158                 }
159                 if (!strncmp(name, FIT_SIG_NODENAME,
160                              strlen(FIT_SIG_NODENAME))) {
161                         ret = fit_image_check_sig(fit, noffset, data, size,
162                                                   key_blob, -1, &err_msg);
163                         if (ret) {
164                                 puts("- ");
165                         } else {
166                                 puts("+ ");
167                                 verified = 1;
168                                 break;
169                         }
170                 }
171         }
172
173         if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
174                 err_msg = "Corrupted or truncated tree";
175                 goto error;
176         }
177
178         return verified ? 0 : -EPERM;
179
180 error:
181         printf(" error!\n%s for '%s' hash node in '%s' image node\n",
182                err_msg, fit_get_name(fit, noffset, NULL),
183                fit_get_name(fit, image_noffset, NULL));
184         return -1;
185 }
186
187 int fit_image_verify_required_sigs(const void *fit, int image_noffset,
188                                    const char *data, size_t size,
189                                    const void *key_blob, int *no_sigsp)
190 {
191         int verify_count = 0;
192         int noffset;
193         int key_node;
194
195         /* Work out what we need to verify */
196         *no_sigsp = 1;
197         key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
198         if (key_node < 0) {
199                 debug("%s: No signature node found: %s\n", __func__,
200                       fdt_strerror(key_node));
201                 return 0;
202         }
203
204         fdt_for_each_subnode(noffset, key_blob, key_node) {
205                 const char *required;
206                 int ret;
207
208                 required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
209                                        NULL);
210                 if (!required || strcmp(required, "image"))
211                         continue;
212                 ret = fit_image_verify_sig(fit, image_noffset, data, size,
213                                            key_blob, noffset);
214                 if (ret) {
215                         printf("Failed to verify required signature '%s'\n",
216                                fit_get_name(key_blob, noffset, NULL));
217                         return ret;
218                 }
219                 verify_count++;
220         }
221
222         if (verify_count)
223                 *no_sigsp = 0;
224
225         return 0;
226 }
227
228 /**
229  * fit_config_check_sig() - Check the signature of a config
230  *
231  * Here we are looking at a particular signature that needs verification (here
232  * signature-1):
233  *
234  *      configurations {
235  *              default = "conf-1";
236  *              conf-1 {
237  *                      kernel = "kernel-1";
238  *                      fdt = "fdt-1";
239  *                      signature-1 {
240  *                              algo = "sha1,rsa2048";
241  *                              value = <...conf 1 signature...>;
242  *                      };
243  *              };
244  *
245  * @fit: FIT to check
246  * @noffset: Offset of the signature node being checked (e.g.
247  *       /configurations/conf-1/signature-1)
248  * @conf_noffset: Offset of configuration node (e.g. /configurations/conf-1)
249  * @key_blob: Blob containing the keys to check against
250  * @required_keynode:   Offset in @key_blob of the required key node,
251  *                      if any. If this is given, then the configuration wil not
252  *                      pass verification unless that key is used. If this is
253  *                      -1 then any signature will do.
254  * @err_msgp:           In the event of an error, this will be pointed to a
255  *                      help error string to display to the user.
256  * Return: 0 if all verified ok, <0 on error
257  */
258 static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
259                                 const void *key_blob, int required_keynode,
260                                 char **err_msgp)
261 {
262         static char * const exc_prop[] = {
263                 FIT_DATA_PROP,
264                 FIT_DATA_SIZE_PROP,
265                 FIT_DATA_POSITION_PROP,
266                 FIT_DATA_OFFSET_PROP,
267         };
268
269         const char *prop, *end, *name;
270         struct image_sign_info info;
271         const uint32_t *strings;
272         const char *config_name;
273         uint8_t *fit_value;
274         int fit_value_len;
275         bool found_config;
276         int max_regions;
277         int i, prop_len;
278         char path[200];
279         int count;
280
281         config_name = fit_get_name(fit, conf_noffset, NULL);
282         debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, key_blob,
283               fit_get_name(fit, noffset, NULL),
284               fit_get_name(key_blob, required_keynode, NULL));
285         *err_msgp = NULL;
286         if (fit_image_setup_verify(&info, fit, noffset, key_blob,
287                                    required_keynode, err_msgp))
288                 return -1;
289
290         if (fit_image_hash_get_value(fit, noffset, &fit_value,
291                                      &fit_value_len)) {
292                 *err_msgp = "Can't get hash value property";
293                 return -1;
294         }
295
296         /* Count the number of strings in the property */
297         prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
298         end = prop ? prop + prop_len : prop;
299         for (name = prop, count = 0; name < end; name++)
300                 if (!*name)
301                         count++;
302         if (!count) {
303                 *err_msgp = "Can't get hashed-nodes property";
304                 return -1;
305         }
306
307         if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') {
308                 *err_msgp = "hashed-nodes property must be null-terminated";
309                 return -1;
310         }
311
312         /* Add a sanity check here since we are using the stack */
313         if (count > IMAGE_MAX_HASHED_NODES) {
314                 *err_msgp = "Number of hashed nodes exceeds maximum";
315                 return -1;
316         }
317
318         /* Create a list of node names from those strings */
319         char *node_inc[count];
320
321         debug("Hash nodes (%d):\n", count);
322         found_config = false;
323         for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
324                 debug("   '%s'\n", name);
325                 node_inc[i] = (char *)name;
326                 if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) &&
327                     name[sizeof(FIT_CONFS_PATH) - 1] == '/' &&
328                     !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) {
329                         debug("      (found config node %s)", config_name);
330                         found_config = true;
331                 }
332         }
333         if (!found_config) {
334                 *err_msgp = "Selected config not in hashed nodes";
335                 return -1;
336         }
337
338         /*
339          * Each node can generate one region for each sub-node. Allow for
340          * 7 sub-nodes (hash-1, signature-1, etc.) and some extra.
341          */
342         max_regions = 20 + count * 7;
343         struct fdt_region fdt_regions[max_regions];
344
345         /* Get a list of regions to hash */
346         count = fdt_find_regions(fit, node_inc, count,
347                                  exc_prop, ARRAY_SIZE(exc_prop),
348                                  fdt_regions, max_regions - 1,
349                                  path, sizeof(path), 0);
350         if (count < 0) {
351                 *err_msgp = "Failed to hash configuration";
352                 return -1;
353         }
354         if (count == 0) {
355                 *err_msgp = "No data to hash";
356                 return -1;
357         }
358         if (count >= max_regions - 1) {
359                 *err_msgp = "Too many hash regions";
360                 return -1;
361         }
362
363         /* Add the strings */
364         strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
365         if (strings) {
366                 /*
367                  * The strings region offset must be a static 0x0.
368                  * This is set in tool/image-host.c
369                  */
370                 fdt_regions[count].offset = fdt_off_dt_strings(fit);
371                 fdt_regions[count].size = fdt32_to_cpu(strings[1]);
372                 count++;
373         }
374
375         /* Allocate the region list on the stack */
376         struct image_region region[count];
377
378         fit_region_make_list(fit, fdt_regions, count, region);
379         if (info.crypto->verify(&info, region, count, fit_value,
380                                 fit_value_len)) {
381                 *err_msgp = "Verification failed";
382                 return -1;
383         }
384
385         return 0;
386 }
387
388 /**
389  * fit_config_verify_key() - Verify that a configuration is signed with a key
390  *
391  * Here we are looking at a particular configuration that needs verification:
392  *
393  *      configurations {
394  *              default = "conf-1";
395  *              conf-1 {
396  *                      kernel = "kernel-1";
397  *                      fdt = "fdt-1";
398  *                      signature-1 {
399  *                              algo = "sha1,rsa2048";
400  *                              value = <...conf 1 signature...>;
401  *                      };
402  *              };
403  *
404  * We must check each of the signature subnodes of conf-1. Hopefully one of them
405  * will match the key at key_offset.
406  *
407  * @fit: FIT to check
408  * @conf_noffset: Offset of the configuration node to check (e.g.
409  *      /configurations/conf-1)
410  * @key_blob: Blob containing the keys to check against
411  * @key_offset: Offset of the key to check within @key_blob
412  * @return 0 if OK, -EPERM if any signatures did not verify, or the
413  *      configuration node has an invalid name
414  */
415 static int fit_config_verify_key(const void *fit, int conf_noffset,
416                                  const void *key_blob, int key_offset)
417 {
418         int noffset;
419         char *err_msg = "No 'signature' subnode found";
420         int verified = 0;
421         int ret;
422
423         /* Process all hash subnodes of the component conf node */
424         fdt_for_each_subnode(noffset, fit, conf_noffset) {
425                 const char *name = fit_get_name(fit, noffset, NULL);
426
427                 if (!strncmp(name, FIT_SIG_NODENAME,
428                              strlen(FIT_SIG_NODENAME))) {
429                         ret = fit_config_check_sig(fit, noffset, conf_noffset,
430                                                    key_blob, key_offset,
431                                                    &err_msg);
432                         if (ret) {
433                                 puts("- ");
434                         } else {
435                                 puts("+ ");
436                                 verified = 1;
437                                 break;
438                         }
439                 }
440         }
441
442         if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
443                 err_msg = "Corrupted or truncated tree";
444                 goto error;
445         }
446
447         if (verified)
448                 return 0;
449
450 error:
451         printf(" error!\n%s for '%s' hash node in '%s' config node\n",
452                err_msg, fit_get_name(fit, noffset, NULL),
453                fit_get_name(fit, conf_noffset, NULL));
454         return -EPERM;
455 }
456
457 /**
458  * fit_config_verify_required_keys() - verify any required signatures for config
459  *
460  * This looks through all the signatures we expect and verifies that at least
461  * all the required ones are valid signatures for the configuration
462  *
463  * @fit: FIT to check
464  * @conf_noffset: Offset of the configuration node to check (e.g.
465  *      /configurations/conf-1)
466  * @key_blob: Blob containing the keys to check against
467  * @return 0 if OK, -EPERM if any signatures did not verify, or the
468  *      configuration node has an invalid name
469  */
470 static int fit_config_verify_required_keys(const void *fit, int conf_noffset,
471                                            const void *key_blob)
472 {
473         const char *name = fit_get_name(fit, conf_noffset, NULL);
474         int noffset;
475         int key_node;
476         int verified = 0;
477         int reqd_sigs = 0;
478         bool reqd_policy_all = true;
479         const char *reqd_mode;
480
481         /*
482          * We don't support this since libfdt considers names with the
483          * name root but different @ suffix to be equal
484          */
485         if (strchr(name, '@')) {
486                 printf("Configuration node '%s' contains '@'\n", name);
487                 return -EPERM;
488         }
489
490         /* Work out what we need to verify */
491         key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
492         if (key_node < 0) {
493                 debug("%s: No signature node found: %s\n", __func__,
494                       fdt_strerror(key_node));
495                 return 0;
496         }
497
498         /* Get required-mode policy property from DTB */
499         reqd_mode = fdt_getprop(key_blob, key_node, "required-mode", NULL);
500         if (reqd_mode && !strcmp(reqd_mode, "any"))
501                 reqd_policy_all = false;
502
503         debug("%s: required-mode policy set to '%s'\n", __func__,
504               reqd_policy_all ? "all" : "any");
505
506         /*
507          * The algorithm here is a little convoluted due to how we want it to
508          * work. Here we work through each of the signature nodes in the
509          * public-key area. These are in the U-Boot control devicetree. Each
510          * node was created by signing a configuration, so we check if it is
511          * 'required' and if so, request that it be verified.
512          */
513         fdt_for_each_subnode(noffset, key_blob, key_node) {
514                 const char *required;
515                 int ret;
516
517                 required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
518                                        NULL);
519                 if (!required || strcmp(required, "conf"))
520                         continue;
521
522                 reqd_sigs++;
523
524                 ret = fit_config_verify_key(fit, conf_noffset, key_blob,
525                                             noffset);
526                 if (ret) {
527                         if (reqd_policy_all) {
528                                 printf("Failed to verify required signature '%s'\n",
529                                        fit_get_name(key_blob, noffset, NULL));
530                                 return ret;
531                         }
532                 } else {
533                         verified++;
534                         if (!reqd_policy_all)
535                                 break;
536                 }
537         }
538
539         if (reqd_sigs && !verified) {
540                 printf("Failed to verify 'any' of the required signature(s)\n");
541                 return -EPERM;
542         }
543
544         return 0;
545 }
546
547 int fit_config_verify(const void *fit, int conf_noffset)
548 {
549         return fit_config_verify_required_keys(fit, conf_noffset,
550                                                gd_fdt_blob());
551 }