blob: ef60fde2e94457c27e0c188c3e666b60697909a6 [file] [log] [blame]
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <errno.h>
Bill Richardson6f72ffa2014-09-23 14:40:20 -07008#include <fcntl.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07009#include <stdint.h>
10#include <stdio.h>
11#include <string.h>
Bill Richardson6f72ffa2014-09-23 14:40:20 -070012#include <sys/stat.h>
13#include <sys/types.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070014#include <unistd.h>
15
16#include "fmap.h"
17#include "futility.h"
18#include "gbb_header.h"
Bill Richardson15dc6fc2014-09-02 14:45:44 -070019#include "host_common.h"
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070020#include "host_key.h"
21#include "traversal.h"
22
23/* What functions do we invoke for a particular operation and component? */
24
25/* FUTIL_OP_SHOW */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070026static int (* const cb_show_funcs[])(struct futil_traverse_state_s *state) = {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070027 futil_cb_show_begin, /* CB_BEGIN_TRAVERSAL */
28 NULL, /* CB_END_TRAVERSAL */
29 futil_cb_show_gbb, /* CB_FMAP_GBB */
30 futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_A */
31 futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_B */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070032 futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_A */
33 futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_B */
34 futil_cb_show_key, /* CB_PUBKEY */
35 futil_cb_show_keyblock, /* CB_KEYBLOCK */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070036 futil_cb_show_gbb, /* CB_GBB */
37 futil_cb_show_fw_preamble, /* CB_FW_PREAMBLE */
Bill Richardson5f2696d2014-09-23 22:03:56 -070038 futil_cb_show_kernel_preamble, /* CB_KERN_PREAMBLE */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070039 NULL, /* CB_RAW_FIRMWARE */
40 NULL, /* CB_RAW_KERNEL */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070041};
42BUILD_ASSERT(ARRAY_SIZE(cb_show_funcs) == NUM_CB_COMPONENTS);
43
Bill Richardson15dc6fc2014-09-02 14:45:44 -070044/* FUTIL_OP_SIGN */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070045static int (* const cb_sign_funcs[])(struct futil_traverse_state_s *state) = {
Bill Richardson15dc6fc2014-09-02 14:45:44 -070046 futil_cb_sign_begin, /* CB_BEGIN_TRAVERSAL */
47 futil_cb_sign_end, /* CB_END_TRAVERSAL */
48 NULL, /* CB_FMAP_GBB */
Bill Richardson5f2696d2014-09-23 22:03:56 -070049 futil_cb_sign_fw_vblock, /* CB_FMAP_VBLOCK_A */
50 futil_cb_sign_fw_vblock, /* CB_FMAP_VBLOCK_B */
51 futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_A */
52 futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_B */
53 futil_cb_sign_pubkey, /* CB_PUBKEY */
54 NULL, /* CB_KEYBLOCK */
55 NULL, /* CB_GBB */
56 NULL, /* CB_FW_PREAMBLE */
57 futil_cb_resign_kernel_part, /* CB_KERN_PREAMBLE */
58 futil_cb_sign_raw_firmware, /* CB_RAW_FIRMWARE */
59 futil_cb_create_kernel_part, /* CB_RAW_KERNEL */
Bill Richardson15dc6fc2014-09-02 14:45:44 -070060};
61BUILD_ASSERT(ARRAY_SIZE(cb_sign_funcs) == NUM_CB_COMPONENTS);
62
Bill Richardson6f72ffa2014-09-23 14:40:20 -070063static int (* const * const cb_func[])(struct futil_traverse_state_s *state) = {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070064 cb_show_funcs,
Bill Richardson15dc6fc2014-09-02 14:45:44 -070065 cb_sign_funcs,
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070066};
67BUILD_ASSERT(ARRAY_SIZE(cb_func) == NUM_FUTIL_OPS);
68
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070069/*
70 * File types that don't need iterating can use a lookup table to determine the
71 * callback component and name. The index is the file type.
72 */
73static const struct {
74 enum futil_cb_component component;
75 const char * const name;
76} direct_callback[] = {
77 {0, NULL}, /* FILE_TYPE_UNKNOWN */
78 {CB_PUBKEY, "VbPublicKey"}, /* FILE_TYPE_PUBKEY */
79 {CB_KEYBLOCK, "VbKeyBlock"}, /* FILE_TYPE_KEYBLOCK */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070080 {CB_FW_PREAMBLE, "FW Preamble"}, /* FILE_TYPE_FW_PREAMBLE */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070081 {CB_GBB, "GBB"}, /* FILE_TYPE_GBB */
82 {0, NULL}, /* FILE_TYPE_BIOS_IMAGE */
83 {0, NULL}, /* FILE_TYPE_OLD_BIOS_IMAGE */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070084 {CB_KERN_PREAMBLE, "Kernel Preamble"}, /* FILE_TYPE_KERN_PREAMBLE */
85 {CB_RAW_FIRMWARE, "raw firmware"}, /* FILE_TYPE_RAW_FIRMWARE */
86 {CB_RAW_KERNEL, "raw kernel"}, /* FILE_TYPE_RAW_KERNEL */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070087};
88BUILD_ASSERT(ARRAY_SIZE(direct_callback) == NUM_FILE_TYPES);
89
90/*
91 * The Chrome OS BIOS must contain specific FMAP areas, and we generally want
92 * to look at each one in a certain order.
93 */
94struct bios_area_s {
95 const char * const name;
96 enum futil_cb_component component;
97};
98
99/* This are the expected areas, in order of traversal. */
100static const struct bios_area_s bios_area[] = {
101 {"GBB", CB_FMAP_GBB},
102 {"FW_MAIN_A", CB_FMAP_FW_MAIN_A},
103 {"FW_MAIN_B", CB_FMAP_FW_MAIN_B},
104 {"VBLOCK_A", CB_FMAP_VBLOCK_A},
105 {"VBLOCK_B", CB_FMAP_VBLOCK_B},
106 {0, 0}
107};
108
109/* Really old BIOS images had different names, but worked the same. */
110static const struct bios_area_s old_bios_area[] = {
111 {"GBB Area", CB_FMAP_GBB},
112 {"Firmware A Data", CB_FMAP_FW_MAIN_A},
113 {"Firmware B Data", CB_FMAP_FW_MAIN_B},
114 {"Firmware A Key", CB_FMAP_VBLOCK_A},
115 {"Firmware B Key", CB_FMAP_VBLOCK_B},
116 {0, 0}
117};
118
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700119
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700120static int has_all_areas(uint8_t *buf, uint32_t len, FmapHeader *fmap,
121 const struct bios_area_s *area)
122{
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700123 /* We must have all the expected areas */
124 for (; area->name; area++)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700125 if (!fmap_find_by_name(buf, len, fmap, area->name, 0))
126 return 0;
127
128 /* Found 'em all */
129 return 1;
130}
131
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700132const char * const futil_file_type_str[] = {
133 "FILE_TYPE_UNKNOWN",
134 "FILE_TYPE_PUBKEY",
135 "FILE_TYPE_KEYBLOCK",
136 "FILE_TYPE_FW_PREAMBLE",
137 "FILE_TYPE_GBB",
138 "FILE_TYPE_BIOS_IMAGE",
139 "FILE_TYPE_OLD_BIOS_IMAGE",
140 "FILE_TYPE_KERN_PREAMBLE",
141 "FILE_TYPE_RAW_FIRMWARE",
142 "FILE_TYPE_RAW_KERNEL",
143};
144BUILD_ASSERT(ARRAY_SIZE(futil_file_type_str) == NUM_FILE_TYPES);
145
146const char * const futil_cb_component_str[] = {
147 "CB_BEGIN_TRAVERSAL",
148 "CB_END_TRAVERSAL",
149 "CB_FMAP_GBB",
150 "CB_FMAP_VBLOCK_A",
151 "CB_FMAP_VBLOCK_B",
152 "CB_FMAP_FW_MAIN_A",
153 "CB_FMAP_FW_MAIN_B",
154 "CB_PUBKEY",
155 "CB_KEYBLOCK",
156 "CB_GBB",
157 "CB_FW_PREAMBLE",
158 "CB_KERN_PREAMBLE",
159 "CB_RAW_FIRMWARE",
160 "CB_RAW_KERNEL",
161};
162BUILD_ASSERT(ARRAY_SIZE(futil_cb_component_str) == NUM_CB_COMPONENTS);
163
164
165static int invoke_callback(struct futil_traverse_state_s *state,
166 enum futil_cb_component c, const char *name,
167 uint32_t offset, uint8_t *buf, uint32_t len)
168{
169 Debug("%s: name \"%s\" op %d component %s"
170 " offset=0x%08x len=0x%08x, buf=%p\n",
171 __func__, name, state->op, futil_cb_component_str[c],
172 offset, len, buf);
173
174 if (c < 0 || c >= NUM_CB_COMPONENTS) {
175 fprintf(stderr, "Invalid component %d\n", c);
176 return 1;
177 }
178
179 state->component = c;
180 state->name = name;
181 state->cb_area[c].offset = offset;
182 state->cb_area[c].buf = buf;
183 state->cb_area[c].len = len;
184 state->my_area = &state->cb_area[c];
185
186 if (cb_func[state->op][c])
187 return cb_func[state->op][c](state);
188 else
189 Debug("<no callback registered>\n");
190
191 return 0;
192}
193
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700194enum futil_file_type futil_what_file_type_buf(uint8_t *buf, uint32_t len)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700195{
196 VbPublicKey *pubkey = (VbPublicKey *)buf;
197 VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf;
198 GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
199 VbFirmwarePreambleHeader *fw_preamble;
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700200 VbKernelPreambleHeader *kern_preamble;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700201 RSAPublicKey *rsa;
202 FmapHeader *fmap;
203
204 /*
205 * Complex structs may begin with simpler structs first, so try them
206 * in reverse order.
207 */
208
209 fmap = fmap_find(buf, len);
210 if (fmap) {
211 if (has_all_areas(buf, len, fmap, bios_area))
212 return FILE_TYPE_BIOS_IMAGE;
213 if (has_all_areas(buf, len, fmap, old_bios_area))
214 return FILE_TYPE_OLD_BIOS_IMAGE;
215 }
216
217 if (futil_looks_like_gbb(gbb, len))
218 return FILE_TYPE_GBB;
219
220 if (VBOOT_SUCCESS == KeyBlockVerify(key_block, len, NULL, 1)) {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700221 rsa = PublicKeyToRSA(&key_block->data_key);
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700222 uint32_t more = key_block->key_block_size;
223
224 /* and firmware preamble too? */
225 fw_preamble = (VbFirmwarePreambleHeader *)(buf + more);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700226 if (VBOOT_SUCCESS ==
227 VerifyFirmwarePreamble(fw_preamble, len - more, rsa))
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700228 return FILE_TYPE_FW_PREAMBLE;
229
230 /* or maybe kernel preamble? */
231 kern_preamble = (VbKernelPreambleHeader *)(buf + more);
232 if (VBOOT_SUCCESS ==
233 VerifyKernelPreamble(kern_preamble, len - more, rsa))
234 return FILE_TYPE_KERN_PREAMBLE;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700235
236 /* no, just keyblock */
237 return FILE_TYPE_KEYBLOCK;
238 }
239
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700240 if (PublicKeyLooksOkay(pubkey, len))
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700241 return FILE_TYPE_PUBKEY;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700242
243 return FILE_TYPE_UNKNOWN;
244}
245
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700246enum futil_file_type futil_what_file_type(const char *filename)
247{
248 enum futil_file_type type;
249 int ifd;
250 uint8_t *buf;
251 uint32_t buf_len;
252
253 ifd = open(filename, O_RDONLY);
254 if (ifd < 0) {
255 fprintf(stderr, "Can't open %s: %s\n",
256 filename, strerror(errno));
257 exit(1);
258 }
259
260 if (0 != futil_map_file(ifd, MAP_RO, &buf, &buf_len)) {
261 close(ifd);
262 exit(1);
263 }
264
265 type = futil_what_file_type_buf(buf, buf_len);
266
267 if (0 != futil_unmap_file(ifd, MAP_RO, buf, buf_len)) {
268 close(ifd);
269 exit(1);
270 }
271
272 if (close(ifd)) {
273 fprintf(stderr, "Error when closing %s: %s\n",
274 filename, strerror(errno));
275 exit(1);
276 }
277
278 return type;
279}
280
281int futil_traverse(uint8_t *buf, uint32_t len,
282 struct futil_traverse_state_s *state,
283 enum futil_file_type type)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700284{
285 FmapHeader *fmap;
286 FmapAreaHeader *ah = 0;
287 const struct bios_area_s *area;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700288 int retval = 0;
289
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700290 if (state->op < 0 || state->op >= NUM_FUTIL_OPS) {
291 fprintf(stderr, "Invalid op %d\n", state->op);
292 return 1;
293 }
294
295 if (type == FILE_TYPE_UNKNOWN)
296 type = futil_what_file_type_buf(buf, len);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700297 state->in_type = type;
298
299 state->errors = retval;
300 retval |= invoke_callback(state, CB_BEGIN_TRAVERSAL, "<begin>",
301 0, buf, len);
302 state->errors = retval;
303
304 switch (type) {
305 case FILE_TYPE_PUBKEY:
306 case FILE_TYPE_KEYBLOCK:
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700307 case FILE_TYPE_FW_PREAMBLE:
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700308 case FILE_TYPE_GBB:
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700309 case FILE_TYPE_KERN_PREAMBLE:
310 case FILE_TYPE_RAW_FIRMWARE:
311 case FILE_TYPE_RAW_KERNEL:
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700312 retval |= invoke_callback(state,
313 direct_callback[type].component,
314 direct_callback[type].name,
315 0, buf, len);
316 state->errors = retval;
317 break;
318
319 case FILE_TYPE_BIOS_IMAGE:
320 /* We've already checked, so we know this will work. */
321 fmap = fmap_find(buf, len);
322 for (area = bios_area; area->name; area++) {
323 /* We know this will work, too */
324 fmap_find_by_name(buf, len, fmap, area->name, &ah);
325 retval |= invoke_callback(state,
326 area->component,
327 area->name,
328 ah->area_offset,
329 buf + ah->area_offset,
330 ah->area_size);
331 state->errors = retval;
332 }
333 break;
334
335 case FILE_TYPE_OLD_BIOS_IMAGE:
336 /* We've already checked, so we know this will work. */
337 fmap = fmap_find(buf, len);
338 for (area = old_bios_area; area->name; area++) {
339 /* We know this will work, too */
340 fmap_find_by_name(buf, len, fmap, area->name, &ah);
341 retval |= invoke_callback(state,
342 area->component,
343 area->name,
344 ah->area_offset,
345 buf + ah->area_offset,
346 ah->area_size);
347 state->errors = retval;
348 }
349 break;
350
351 default:
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700352 Debug("%s:%d unhandled type %s\n", __FILE__, __LINE__,
353 futil_file_type_str[type]);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700354 retval = 1;
355 }
356
357 retval |= invoke_callback(state, CB_END_TRAVERSAL, "<end>",
358 0, buf, len);
359 return retval;
360}