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