1 /* Copyright 2011 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Routines for verifying a firmware image's signature.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "2common.h"
13 #include "2misc.h"
14 #include "2secdata.h"
15 #include "2sysincludes.h"
16
17 const char *gbb_fname;
18 const char *vblock_fname;
19 const char *body_fname;
20
21 #if defined(ENABLE_HWCRYPTO_RSA_TESTS)
vb2api_hwcrypto_allowed(struct vb2_context * ctx)22 bool vb2api_hwcrypto_allowed(struct vb2_context *ctx)
23 {
24 printf("hwcrypto is allowed.\n");
25 return true;
26 }
27 #endif
28
29 /**
30 * Local implementation which reads resources from individual files. Could be
31 * more elegant and read from image.bin, if we understood the fmap.
32 */
vb2ex_read_resource(struct vb2_context * c,enum vb2_resource_index index,uint32_t offset,void * buf,uint32_t size)33 vb2_error_t vb2ex_read_resource(struct vb2_context *c,
34 enum vb2_resource_index index, uint32_t offset,
35 void *buf, uint32_t size)
36 {
37 const char *fname;
38 FILE *f;
39 int got_size;
40
41 /* Get the filename for the resource */
42 switch (index) {
43 case VB2_RES_GBB:
44 fname = gbb_fname;
45 break;
46 case VB2_RES_FW_VBLOCK:
47 fname = vblock_fname;
48 break;
49 default:
50 return VB2_ERROR_UNKNOWN;
51 }
52
53 /* Open file and seek to the requested offset */
54 f = fopen(fname, "rb");
55 if (!f)
56 return VB2_ERROR_UNKNOWN;
57
58 if (fseek(f, offset, SEEK_SET)) {
59 fclose(f);
60 return VB2_ERROR_UNKNOWN;
61 }
62
63 /* Read data and close file */
64 got_size = fread(buf, 1, size, f);
65 fclose(f);
66
67 /* Return success if we read everything */
68 return got_size == size ? VB2_SUCCESS : VB2_ERROR_UNKNOWN;
69 }
70
vb2ex_tpm_clear_owner(struct vb2_context * c)71 vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *c)
72 {
73 // TODO: implement
74 return VB2_SUCCESS;
75 }
76
77 /**
78 * Save non-volatile and/or secure data if needed.
79 */
save_if_needed(struct vb2_context * c)80 static void save_if_needed(struct vb2_context *c)
81 {
82
83 if (c->flags & VB2_CONTEXT_NVDATA_CHANGED) {
84 // TODO: implement
85 c->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
86 }
87
88 if (c->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) {
89 // TODO: implement
90 c->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
91 }
92 }
93
94 /**
95 * Verify firmware body
96 */
hash_body(struct vb2_context * c)97 static vb2_error_t hash_body(struct vb2_context *c)
98 {
99 uint32_t remaining;
100 uint8_t block[8192];
101 uint32_t size;
102 FILE *f;
103 vb2_error_t rv;
104
105 /* Open the body data */
106 f = fopen(body_fname, "rb");
107 if (!f)
108 return VB2_ERROR_TEST_INPUT_FILE;
109
110 /* Start the body hash */
111 rv = vb2api_init_hash(c, VB2_HASH_TAG_FW_BODY);
112 if (rv) {
113 fclose(f);
114 return rv;
115 }
116
117 remaining = vb2api_get_firmware_size(c);
118 printf("Expect %d bytes of body...\n", remaining);
119
120 /* Extend over the body */
121 while (remaining) {
122 size = sizeof(block);
123 if (size > remaining)
124 size = remaining;
125
126 /* Read next body block */
127 size = fread(block, 1, size, f);
128 if (size <= 0)
129 break;
130
131 /* Hash it */
132 rv = vb2api_extend_hash(c, block, size);
133 if (rv) {
134 fclose(f);
135 return rv;
136 }
137
138 remaining -= size;
139 }
140
141 fclose(f);
142
143 /* Check the result */
144 rv = vb2api_check_hash(c);
145 if (rv)
146 return rv;
147
148 return VB2_SUCCESS;
149 }
150
print_help(const char * progname)151 static void print_help(const char *progname)
152 {
153 printf("Usage: %s <gbb> <vblock> <body>\n", progname);
154 }
155
main(int argc,char * argv[])156 int main(int argc, char *argv[])
157 {
158 uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
159 __attribute__((aligned(VB2_WORKBUF_ALIGN)));
160 struct vb2_context *ctx;
161 struct vb2_shared_data *sd;
162 vb2_error_t rv;
163
164 if (argc < 4) {
165 print_help(argv[0]);
166 return 1;
167 }
168
169 /* Save filenames */
170 gbb_fname = argv[1];
171 vblock_fname = argv[2];
172 body_fname = argv[3];
173
174 /* Intialize workbuf with sentinel value to see how much we'll use. */
175 uint32_t *ptr = (uint32_t *)workbuf;
176 while ((uint8_t *)ptr + sizeof(*ptr) <= workbuf + sizeof(workbuf))
177 *ptr++ = 0xbeefdead;
178
179 /* Set up context */
180 if (vb2api_init(workbuf, sizeof(workbuf), &ctx)) {
181 printf("Failed to initialize workbuf.\n");
182 return 1;
183 }
184 sd = vb2_get_sd(ctx);
185
186 /* Initialize secure context */
187 vb2api_secdata_firmware_create(ctx);
188 vb2api_secdata_kernel_create(ctx);
189
190 // TODO: optional args to set contents for nvdata, secdata?
191
192 /* Do early init */
193 printf("Phase 1...\n");
194 rv = vb2api_fw_phase1(ctx);
195 if (rv) {
196 printf("Phase 1 wants recovery mode.\n");
197 save_if_needed(ctx);
198 return rv;
199 }
200
201 /* Determine which firmware slot to boot */
202 printf("Phase 2...\n");
203 rv = vb2api_fw_phase2(ctx);
204 if (rv) {
205 printf("Phase 2 wants reboot.\n");
206 save_if_needed(ctx);
207 return rv;
208 }
209
210 /* Try that slot */
211 printf("Phase 3...\n");
212 rv = vb2api_fw_phase3(ctx);
213 if (rv) {
214 printf("Phase 3 wants reboot.\n");
215 save_if_needed(ctx);
216 return rv;
217 }
218
219 /* Verify body */
220 printf("Hash body...\n");
221 rv = hash_body(ctx);
222 save_if_needed(ctx);
223 if (rv) {
224 printf("Phase 4 wants reboot.\n");
225 return rv;
226 }
227
228 printf("Yaay!\n");
229
230 while ((uint8_t *)ptr > workbuf && *--ptr == 0xbeefdead)
231 /* find last used workbuf offset */;
232 printf("Workbuf used = %d bytes, high watermark = %zu bytes\n",
233 sd->workbuf_used, (uint8_t *)ptr + sizeof(*ptr) - workbuf);
234
235 return 0;
236 }
237