blob: 41f3d9f7e8e40ba5e74b7514097b02b1baf6457f [file] [log] [blame]
Bill Richardson15dc6fc2014-09-02 14:45:44 -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#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <inttypes.h>
10#include <limits.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <unistd.h>
19
20#include "bmpblk_header.h"
21#include "fmap.h"
22#include "futility.h"
23#include "gbb_header.h"
24#include "host_common.h"
25#include "traversal.h"
26#include "util_misc.h"
27#include "vboot_common.h"
28
29/* Local values for cb_area_s._flags */
30enum callback_flags {
31 AREA_IS_VALID = 0x00000001,
32};
33
34/* Local structure for args, etc. */
35struct local_data_s {
36 VbPrivateKey *signprivate;
37 VbKeyBlockHeader *keyblock;
38 VbPublicKey *kernel_subkey;
39 VbPrivateKey *devsignprivate;
40 VbKeyBlockHeader *devkeyblock;
41 uint32_t version;
42 uint32_t flags;
43 char *loemdir;
44 char *loemid;
45} option = {
46 .version = 1,
47};
48
49
50int futil_cb_sign_bogus(struct futil_traverse_state_s *state)
51{
52 fprintf(stderr, "Don't know how to sign %s\n", state->name);
53 return 1;
54}
55
56int futil_cb_sign_notyet(struct futil_traverse_state_s *state)
57{
58 fprintf(stderr, "Signing %s is not yet implemented\n", state->name);
59 return 1;
60}
61
62/*
63 * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
64 *
65 * The data in state->my_area is just the RW firmware blob, so there's nothing
66 * useful to show about it. We'll just mark it as present so when we encounter
67 * corresponding VBLOCK area, we'll have this to verify.
68 */
69int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
70{
71 state->my_area->_flags |= AREA_IS_VALID;
72 return 0;
73}
74
75
76int futil_cb_sign_fw_preamble(struct futil_traverse_state_s *state)
77{
78 VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
79 struct cb_area_s *fw_body_area = 0;
80
81 /* We don't (yet) handle standalone VBLOCKs */
82 if (state->component == CB_FW_PREAMBLE)
83 return futil_cb_sign_notyet(state);
84
85 /*
86 * We've already checked the Keyblock hash and taken a look at the
87 * preamble or we wouldn't be here.
88 */
89
90 uint32_t more = key_block->key_block_size;
91 VbFirmwarePreambleHeader *preamble =
92 (VbFirmwarePreambleHeader *)(state->my_area->buf + more);
93 uint32_t fw_size = preamble->body_signature.data_size;
94
95 switch (state->component) {
96 case CB_FMAP_VBLOCK_A:
97 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
98 break;
99 case CB_FMAP_VBLOCK_B:
100 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
101 break;
102 default:
103 DIE;
104 }
105
106 if (fw_size > fw_body_area->len) {
107 fprintf(stderr,
108 "%s says the firmware is larger than we have\n",
109 state->name);
110 return 1;
111 }
112
113 /* Update the firmware size */
114 fw_body_area->len = fw_size;
115
116 state->my_area->_flags |= AREA_IS_VALID;
117
118 return 0;
119}
120
121int futil_cb_sign_begin(struct futil_traverse_state_s *state)
122{
123 if (state->in_type == FILE_TYPE_UNKNOWN) {
124 fprintf(stderr, "Unable to determine type of %s\n",
125 state->in_filename);
126 return 1;
127 }
128
129 return 0;
130}
131
132static int write_new_preamble(struct cb_area_s *vblock,
133 struct cb_area_s *fw_body,
134 VbPrivateKey *signkey,
135 VbKeyBlockHeader *keyblock)
136{
137 VbSignature *body_sig;
138 VbFirmwarePreambleHeader *preamble;
139
140 body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
141 if (!body_sig) {
142 fprintf(stderr, "Error calculating body signature\n");
143 return 1;
144 }
145
146 preamble = CreateFirmwarePreamble(option.version,
147 option.kernel_subkey,
148 body_sig,
149 signkey,
150 option.flags);
151 if (!preamble) {
152 fprintf(stderr, "Error creating firmware preamble.\n");
153 free(body_sig);
154 return 1;
155 }
156
157 /* Write the new keyblock */
158 uint32_t more = keyblock->key_block_size;
159 memcpy(vblock->buf, keyblock, more);
160 /* and the new preamble */
161 memcpy(vblock->buf + more, preamble, preamble->preamble_size);
162
163 free(preamble);
164 free(body_sig);
165
166 return 0;
167}
168
169static int write_loem(const char *ab, struct cb_area_s *vblock)
170{
171 char filename[PATH_MAX];
172 int n;
173 n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
174 option.loemdir ? option.loemdir : ".",
175 ab, option.loemid);
176 if (n >= sizeof(filename)) {
177 fprintf(stderr, "LOEM args produce bogus filename\n");
178 return 1;
179 }
180
181 FILE *fp = fopen(filename, "w");
182 if (!fp) {
183 fprintf(stderr, "Can't open %s for writing: %s\n",
184 filename, strerror(errno));
185 return 1;
186 }
187
188 if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
189 fprintf(stderr, "Can't write to %s: %s\n",
190 filename, strerror(errno));
191 fclose(fp);
192 return 1;
193 }
194 if (fclose(fp)) {
195 fprintf(stderr, "Failed closing loem output: %s\n",
196 strerror(errno));
197 return 1;
198 }
199
200 return 0;
201}
202
203int futil_cb_sign_end(struct futil_traverse_state_s *state)
204{
205 struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
206 struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
207 struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
208 struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
209 int retval = 0;
210
211 if (state->errors ||
212 !(vblock_a->_flags & AREA_IS_VALID) ||
213 !(vblock_b->_flags & AREA_IS_VALID) ||
214 !(fw_a->_flags & AREA_IS_VALID) ||
215 !(fw_b->_flags & AREA_IS_VALID)) {
216 fprintf(stderr, "Something's wrong. Not changing anything\n");
217 return 1;
218 }
219
220 /* Do A & B differ ? */
221 if (fw_a->len != fw_b->len ||
222 memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
223 /* Yes, must use DEV keys for A */
224 if (!option.devsignprivate || !option.devkeyblock) {
225 fprintf(stderr,
226 "FW A & B differ. DEV keys are required.\n");
227 return 1;
228 }
229 retval |= write_new_preamble(vblock_a, fw_a,
230 option.devsignprivate,
231 option.devkeyblock);
232 } else {
233 retval |= write_new_preamble(vblock_a, fw_a,
234 option.signprivate,
235 option.keyblock);
236 }
237
238 /* FW B is always normal keys */
239 retval |= write_new_preamble(vblock_b, fw_b,
240 option.signprivate,
241 option.keyblock);
242
243
244
245
246 if (option.loemid) {
247 retval |= write_loem("A", vblock_a);
248 retval |= write_loem("B", vblock_b);
249 }
250
251 return retval;
252}
253
254static const char usage[] = "\n"
255 "Usage: " MYNAME " %s [OPTIONS] FILE [OUTFILE]\n"
256 "\n"
257 "[Re]Sign the specified BIOS image\n"
258 "\n"
259 "Required OPTIONS:\n"
260 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
261 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
262 " public firmware data key\n"
263 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
264 "\n"
265 "These are required if the A and B firmware differ:\n"
266 " -S|--devsign FILE.vbprivk The DEV private firmware data key\n"
267 " -B|--devkeyblock FILE.keyblock The keyblock containing the\n"
268 " DEV public firmware data key\n"
269 "\n"
270 "Optional OPTIONS:\n"
271 " -v|--version NUM The firmware version number (%d)\n"
272 " -f|--flags NUM The preamble flags value (%d)\n"
273 " -d|--loemdir DIR Local OEM output vblock directory\n"
274 " -l|--loemid STRING Local OEM vblock suffix\n"
275 "\n";
276
277static void help_and_quit(const char *prog)
278{
279 fprintf(stderr, usage, prog, option.version, option.flags);
280 exit(1);
281}
282
283static const struct option long_opts[] = {
284 /* name hasarg *flag val */
285 {"signprivate", 1, NULL, 's'},
286 {"keyblock", 1, NULL, 'b'},
287 {"kernelkey", 1, NULL, 'k'},
288 {"devsign", 1, NULL, 'S'},
289 {"devkeyblock", 1, NULL, 'B'},
290 {"version", 1, NULL, 'v'},
291 {"flags", 1, NULL, 'f'},
292 {"loemdir", 1, NULL, 'd'},
293 {"loemid", 1, NULL, 'l'},
294 {NULL, 0, NULL, 0},
295};
296static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
297
298static int do_sign(int argc, char *argv[])
299{
300 char *infile = 0;
301 char *outfile = 0;
302 int fd, i;
303 int errorcnt = 0;
304 struct futil_traverse_state_s state;
305 char *e = 0;
306
307 opterr = 0; /* quiet, you */
308 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
309 switch (i) {
310 case 's':
311 option.signprivate = PrivateKeyRead(optarg);
312 if (!option.signprivate) {
313 fprintf(stderr, "Error reading %s\n", optarg);
314 errorcnt++;
315 }
316 break;
317 case 'b':
318 option.keyblock = KeyBlockRead(optarg);
319 if (!option.keyblock) {
320 fprintf(stderr, "Error reading %s\n", optarg);
321 errorcnt++;
322 }
323 break;
324 case 'k':
325 option.kernel_subkey = PublicKeyRead(optarg);
326 if (!option.kernel_subkey) {
327 fprintf(stderr, "Error reading %s\n", optarg);
328 errorcnt++;
329 }
330 break;
331 case 'S':
332 option.devsignprivate = PrivateKeyRead(optarg);
333 if (!option.devsignprivate) {
334 fprintf(stderr, "Error reading %s\n", optarg);
335 errorcnt++;
336 }
337 break;
338 case 'B':
339 option.devkeyblock = KeyBlockRead(optarg);
340 if (!option.devkeyblock) {
341 fprintf(stderr, "Error reading %s\n", optarg);
342 errorcnt++;
343 }
344 break;
345 case 'v':
346 option.version = strtoul(optarg, &e, 0);
347 if (!*optarg || (e && *e)) {
348 fprintf(stderr,
349 "Invalid --version \"%s\"\n", optarg);
350 errorcnt++;
351 }
352 break;
353
354 case 'f':
355 option.flags = strtoul(optarg, &e, 0);
356 if (!*optarg || (e && *e)) {
357 fprintf(stderr,
358 "Invalid --flags \"%s\"\n", optarg);
359 errorcnt++;
360 }
361 case 'd':
362 option.loemdir = optarg;
363 break;
364 case 'l':
365 option.loemid = optarg;
366 break;
367
368 case '?':
369 if (optopt)
370 fprintf(stderr, "Unrecognized option: -%c\n",
371 optopt);
372 else
373 fprintf(stderr, "Unrecognized option\n");
374 errorcnt++;
375 break;
376 case ':':
377 fprintf(stderr, "Missing argument to -%c\n", optopt);
378 errorcnt++;
379 break;
380 default:
381 DIE;
382 }
383 }
384
385 if (!option.signprivate) {
386 fprintf(stderr,
387 "Missing required private firmware data key\n");
388 errorcnt++;
389 }
390
391 if (!option.keyblock) {
392 fprintf(stderr,
393 "Missing required keyblock\n");
394 errorcnt++;
395 }
396
397 if (!option.kernel_subkey) {
398 fprintf(stderr,
399 "Missing required kernel subkey\n");
400 errorcnt++;
401 }
402
403 if (errorcnt)
404 help_and_quit(argv[0]);
405
406 switch (argc - optind) {
407 case 2:
408 infile = argv[optind++];
409 outfile = argv[optind++];
410 copy_file_or_die(infile, outfile);
411 break;
412 case 1:
413 /* Stomping right on it. Errors will leave it garbled. */
414 /* TODO: Use a tempfile (mkstemp) for normal files. */
415 infile = argv[optind++];
416 outfile = infile;
417 break;
418 case 0:
419 fprintf(stderr, "ERROR: missing input filename\n");
420 help_and_quit(argv[0]);
421 break;
422 default:
423 fprintf(stderr, "ERROR: too many arguments left over\n");
424 help_and_quit(argv[0]);
425 }
426
427
428 fd = open(outfile, O_RDWR);
429 if (fd < 0) {
430 fprintf(stderr, "Can't open %s: %s\n",
431 outfile, strerror(errno));
432 return 1;
433 }
434
435 memset(&state, 0, sizeof(state));
436 state.in_filename = outfile ? outfile : "<none>";
437 state.op = FUTIL_OP_SIGN;
438
439 errorcnt += futil_traverse(fd, &state, 1);
440
441 if (close(fd)) {
442 errorcnt++;
443 fprintf(stderr, "Error when closing %s: %s\n",
444 outfile, strerror(errno));
445 }
446
447 if (option.signprivate)
448 free(option.signprivate);
449 if (option.keyblock)
450 free(option.keyblock);
451 if (option.kernel_subkey)
452 free(option.kernel_subkey);
453
454 return !!errorcnt;
455}
456
457DECLARE_FUTIL_COMMAND(sign, do_sign, "[Re]Sign a BIOS image");