image: Add RSA support for image signing
[kernel/u-boot.git] / common / image-sig.c
1 /*
2  * Copyright (c) 2013, Google Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  */
19
20 #ifdef USE_HOSTCC
21 #include "mkimage.h"
22 #include <time.h>
23 #else
24 #include <common.h>
25 #include <malloc.h>
26 DECLARE_GLOBAL_DATA_PTR;
27 #endif /* !USE_HOSTCC*/
28 #include <errno.h>
29 #include <image.h>
30 #include <rsa.h>
31
32 struct image_sig_algo image_sig_algos[] = {
33         {
34                 "sha1,rsa2048",
35                 rsa_sign,
36                 rsa_add_verify_data,
37                 rsa_verify,
38         }
39 };
40
41 struct image_sig_algo *image_get_sig_algo(const char *name)
42 {
43         int i;
44
45         for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) {
46                 if (!strcmp(image_sig_algos[i].name, name))
47                         return &image_sig_algos[i];
48         }
49
50         return NULL;
51 }
52
53 static int fit_image_setup_verify(struct image_sign_info *info,
54                 const void *fit, int noffset, int required_keynode,
55                 char **err_msgp)
56 {
57         char *algo_name;
58
59         if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
60                 *err_msgp = "Can't get hash algo property";
61                 return -1;
62         }
63         memset(info, '\0', sizeof(*info));
64         info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
65         info->fit = (void *)fit;
66         info->node_offset = noffset;
67         info->algo = image_get_sig_algo(algo_name);
68         info->fdt_blob = gd_fdt_blob();
69         info->required_keynode = required_keynode;
70         printf("%s:%s", algo_name, info->keyname);
71
72         if (!info->algo) {
73                 *err_msgp = "Unknown signature algorithm";
74                 return -1;
75         }
76
77         return 0;
78 }
79
80 int fit_image_check_sig(const void *fit, int noffset, const void *data,
81                 size_t size, int required_keynode, char **err_msgp)
82 {
83         struct image_sign_info info;
84         struct image_region region;
85         uint8_t *fit_value;
86         int fit_value_len;
87
88         *err_msgp = NULL;
89         if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
90                                    err_msgp))
91                 return -1;
92
93         if (fit_image_hash_get_value(fit, noffset, &fit_value,
94                                      &fit_value_len)) {
95                 *err_msgp = "Can't get hash value property";
96                 return -1;
97         }
98
99         region.data = data;
100         region.size = size;
101
102         if (info.algo->verify(&info, &region, 1, fit_value, fit_value_len)) {
103                 *err_msgp = "Verification failed";
104                 return -1;
105         }
106
107         return 0;
108 }
109
110 static int fit_image_verify_sig(const void *fit, int image_noffset,
111                 const char *data, size_t size, const void *sig_blob,
112                 int sig_offset)
113 {
114         int noffset;
115         char *err_msg = "";
116         int verified = 0;
117         int ret;
118
119         /* Process all hash subnodes of the component image node */
120         for (noffset = fdt_first_subnode(fit, image_noffset);
121              noffset >= 0;
122              noffset = fdt_next_subnode(fit, noffset)) {
123                 const char *name = fit_get_name(fit, noffset, NULL);
124
125                 if (!strncmp(name, FIT_SIG_NODENAME,
126                              strlen(FIT_SIG_NODENAME))) {
127                         ret = fit_image_check_sig(fit, noffset, data,
128                                                         size, -1, &err_msg);
129                         if (ret) {
130                                 puts("- ");
131                         } else {
132                                 puts("+ ");
133                                 verified = 1;
134                                 break;
135                         }
136                 }
137         }
138
139         if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
140                 err_msg = "Corrupted or truncated tree";
141                 goto error;
142         }
143
144         return verified ? 0 : -EPERM;
145
146 error:
147         printf(" error!\n%s for '%s' hash node in '%s' image node\n",
148                err_msg, fit_get_name(fit, noffset, NULL),
149                fit_get_name(fit, image_noffset, NULL));
150         return -1;
151 }
152
153 int fit_image_verify_required_sigs(const void *fit, int image_noffset,
154                 const char *data, size_t size, const void *sig_blob,
155                 int *no_sigsp)
156 {
157         int verify_count = 0;
158         int noffset;
159         int sig_node;
160
161         /* Work out what we need to verify */
162         *no_sigsp = 1;
163         sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
164         if (sig_node < 0) {
165                 debug("%s: No signature node found: %s\n", __func__,
166                       fdt_strerror(sig_node));
167                 return 0;
168         }
169
170         for (noffset = fdt_first_subnode(sig_blob, sig_node);
171              noffset >= 0;
172              noffset = fdt_next_subnode(sig_blob, noffset)) {
173                 const char *required;
174                 int ret;
175
176                 required = fdt_getprop(sig_blob, noffset, "required", NULL);
177                 if (!required || strcmp(required, "image"))
178                         continue;
179                 ret = fit_image_verify_sig(fit, image_noffset, data, size,
180                                         sig_blob, noffset);
181                 if (ret) {
182                         printf("Failed to verify required signature '%s'\n",
183                                fit_get_name(sig_blob, noffset, NULL));
184                         return ret;
185                 }
186                 verify_count++;
187         }
188
189         if (verify_count)
190                 *no_sigsp = 0;
191
192         return 0;
193 }