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