blob: 95cae28df5aeb66388cce03789bd63e774cb7caf [file] [log] [blame]
Bill Richardson6f396152014-07-15 12:52:19 -07001/* Copyright 2011 The Chromium OS Authors. All rights reserved.
Randall Spanglerdcab8fa2010-06-15 14:50:51 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Verified boot firmware utility
6 */
7
8#include <getopt.h>
Bill Richardson31d95c22014-08-24 22:07:17 -07009#include <inttypes.h> /* For PRIu64 */
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070010#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14
15#include "cryptolib.h"
Bill Richardson6f396152014-07-15 12:52:19 -070016#include "futility.h"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070017#include "host_common.h"
18#include "kernel_blob.h"
Bill Richardson78299022014-06-20 14:33:00 -070019#include "util_misc.h"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070020#include "vboot_common.h"
21
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070022/* Command line options */
23enum {
Bill Richardson31d95c22014-08-24 22:07:17 -070024 OPT_MODE_VBLOCK = 1000,
25 OPT_MODE_VERIFY,
26 OPT_KEYBLOCK,
27 OPT_SIGNPUBKEY,
28 OPT_SIGNPRIVATE,
29 OPT_VERSION,
30 OPT_FV,
31 OPT_KERNELKEY,
32 OPT_FLAGS,
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070033};
34
Mike Frysinger7351ed72014-08-18 10:47:42 -040035static const struct option long_opts[] = {
Bill Richardson31d95c22014-08-24 22:07:17 -070036 {"vblock", 1, 0, OPT_MODE_VBLOCK},
37 {"verify", 1, 0, OPT_MODE_VERIFY},
38 {"keyblock", 1, 0, OPT_KEYBLOCK},
39 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
40 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
41 {"version", 1, 0, OPT_VERSION},
42 {"fv", 1, 0, OPT_FV},
43 {"kernelkey", 1, 0, OPT_KERNELKEY},
44 {"flags", 1, 0, OPT_FLAGS},
45 {NULL, 0, 0, 0}
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070046};
47
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070048/* Print help and return error */
Bill Richardson31d95c22014-08-24 22:07:17 -070049static int PrintHelp(void)
50{
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070051
Bill Richardson31d95c22014-08-24 22:07:17 -070052 puts("vbutil_firmware - Verified boot key block utility\n"
53 "\n"
54 "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
55 "\n"
56 "For '--vblock <file>', required OPTIONS are:\n"
57 " --keyblock <file> Key block in .keyblock format\n"
58 " --signprivate <file>"
59 " Signing private key in .vbprivk format\n"
60 " --version <number> Firmware version\n"
61 " --fv <file> Firmware volume to sign\n"
62 " --kernelkey <file> Kernel subkey in .vbpubk format\n"
63 "optional OPTIONS are:\n"
64 " --flags <number> Preamble flags (defaults to 0)\n"
65 "\n"
66 "For '--verify <file>', required OPTIONS are:\n"
67 " --signpubkey <file>"
68 " Signing public key in .vbpubk format\n"
69 " --fv <file> Firmware volume to verify\n"
70 "\n"
71 "For '--verify <file>', optional OPTIONS are:\n"
72 " --kernelkey <file>"
73 " Write the kernel subkey to this file\n"
74 "");
75 return 1;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070076}
77
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070078/* Create a firmware .vblock */
Bill Richardson31d95c22014-08-24 22:07:17 -070079static int Vblock(const char *outfile, const char *keyblock_file,
80 const char *signprivate, uint64_t version,
81 const char *fv_file, const char *kernelkey_file,
82 uint32_t preamble_flags)
83{
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070084
Bill Richardson31d95c22014-08-24 22:07:17 -070085 VbPrivateKey *signing_key;
86 VbPublicKey *kernel_subkey;
87 VbSignature *body_sig;
88 VbFirmwarePreambleHeader *preamble;
89 VbKeyBlockHeader *key_block;
90 uint64_t key_block_size;
91 uint8_t *fv_data;
92 uint64_t fv_size;
93 FILE *f;
94 uint64_t i;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070095
Bill Richardson31d95c22014-08-24 22:07:17 -070096 if (!outfile) {
97 VbExError("Must specify output filename\n");
98 return 1;
99 }
100 if (!keyblock_file || !signprivate || !kernelkey_file) {
101 VbExError("Must specify all keys\n");
102 return 1;
103 }
104 if (!fv_file) {
105 VbExError("Must specify firmware volume\n");
106 return 1;
107 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700108
Bill Richardson31d95c22014-08-24 22:07:17 -0700109 /* Read the key block and keys */
110 key_block =
111 (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
112 if (!key_block) {
113 VbExError("Error reading key block.\n");
114 return 1;
115 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700116
Bill Richardson31d95c22014-08-24 22:07:17 -0700117 signing_key = PrivateKeyRead(signprivate);
118 if (!signing_key) {
119 VbExError("Error reading signing key.\n");
120 return 1;
121 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700122
Bill Richardson31d95c22014-08-24 22:07:17 -0700123 kernel_subkey = PublicKeyRead(kernelkey_file);
124 if (!kernel_subkey) {
125 VbExError("Error reading kernel subkey.\n");
126 return 1;
127 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700128
Bill Richardson31d95c22014-08-24 22:07:17 -0700129 /* Read and sign the firmware volume */
130 fv_data = ReadFile(fv_file, &fv_size);
131 if (!fv_data)
132 return 1;
133 if (!fv_size) {
134 VbExError("Empty firmware volume file\n");
135 return 1;
136 }
137 body_sig = CalculateSignature(fv_data, fv_size, signing_key);
138 if (!body_sig) {
139 VbExError("Error calculating body signature\n");
140 return 1;
141 }
142 free(fv_data);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700143
Bill Richardson31d95c22014-08-24 22:07:17 -0700144 /* Create preamble */
145 preamble = CreateFirmwarePreamble(version,
146 kernel_subkey,
147 body_sig,
148 signing_key, preamble_flags);
149 if (!preamble) {
150 VbExError("Error creating preamble.\n");
151 return 1;
152 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700153
Bill Richardson31d95c22014-08-24 22:07:17 -0700154 /* Write the output file */
155 f = fopen(outfile, "wb");
156 if (!f) {
157 VbExError("Can't open output file %s\n", outfile);
158 return 1;
159 }
160 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
161 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
162 fclose(f);
163 if (i) {
164 VbExError("Can't write output file %s\n", outfile);
165 unlink(outfile);
166 return 1;
167 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700168
Bill Richardson31d95c22014-08-24 22:07:17 -0700169 /* Success */
170 return 0;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700171}
172
Bill Richardson31d95c22014-08-24 22:07:17 -0700173static int Verify(const char *infile, const char *signpubkey,
174 const char *fv_file, const char *kernelkey_file)
175{
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700176
Bill Richardson31d95c22014-08-24 22:07:17 -0700177 VbKeyBlockHeader *key_block;
178 VbFirmwarePreambleHeader *preamble;
179 VbPublicKey *data_key;
180 VbPublicKey *sign_key;
181 VbPublicKey *kernel_subkey;
182 RSAPublicKey *rsa;
183 uint8_t *blob;
184 uint64_t blob_size;
185 uint8_t *fv_data;
186 uint64_t fv_size;
187 uint64_t now = 0;
188 uint32_t flags;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700189
Bill Richardson31d95c22014-08-24 22:07:17 -0700190 if (!infile || !signpubkey || !fv_file) {
191 VbExError("Must specify filename, signpubkey, and fv\n");
192 return 1;
193 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700194
Bill Richardson31d95c22014-08-24 22:07:17 -0700195 /* Read public signing key */
196 sign_key = PublicKeyRead(signpubkey);
197 if (!sign_key) {
198 VbExError("Error reading signpubkey.\n");
199 return 1;
200 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700201
Bill Richardson31d95c22014-08-24 22:07:17 -0700202 /* Read blob */
203 blob = ReadFile(infile, &blob_size);
204 if (!blob) {
205 VbExError("Error reading input file\n");
206 return 1;
207 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700208
Bill Richardson31d95c22014-08-24 22:07:17 -0700209 /* Read firmware volume */
210 fv_data = ReadFile(fv_file, &fv_size);
211 if (!fv_data) {
212 VbExError("Error reading firmware volume\n");
213 return 1;
214 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700215
Bill Richardson31d95c22014-08-24 22:07:17 -0700216 /* Verify key block */
217 key_block = (VbKeyBlockHeader *) blob;
218 if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
219 VbExError("Error verifying key block.\n");
220 return 1;
221 }
222 free(sign_key);
223 now += key_block->key_block_size;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700224
Bill Richardson31d95c22014-08-24 22:07:17 -0700225 printf("Key block:\n");
226 data_key = &key_block->data_key;
227 printf(" Size: %" PRIu64 "\n",
228 key_block->key_block_size);
229 printf(" Flags: %" PRIu64 " (ignored)\n",
230 key_block->key_block_flags);
231 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
232 (data_key->algorithm <
233 kNumAlgorithms ? algo_strings[data_key->
234 algorithm] : "(invalid)"));
235 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
236 printf(" Data key sha1sum: ");
237 PrintPubKeySha1Sum(data_key);
238 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700239
Bill Richardson31d95c22014-08-24 22:07:17 -0700240 rsa = PublicKeyToRSA(&key_block->data_key);
241 if (!rsa) {
242 VbExError("Error parsing data key.\n");
243 return 1;
244 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700245
Bill Richardson31d95c22014-08-24 22:07:17 -0700246 /* Verify preamble */
247 preamble = (VbFirmwarePreambleHeader *) (blob + now);
248 if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
249 VbExError("Error verifying preamble.\n");
250 return 1;
251 }
252 now += preamble->preamble_size;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700253
Bill Richardson31d95c22014-08-24 22:07:17 -0700254 flags = VbGetFirmwarePreambleFlags(preamble);
255 printf("Preamble:\n");
256 printf(" Size: %" PRIu64 "\n",
257 preamble->preamble_size);
258 printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
259 preamble->header_version_major, preamble->header_version_minor);
260 printf(" Firmware version: %" PRIu64 "\n",
261 preamble->firmware_version);
262 kernel_subkey = &preamble->kernel_subkey;
263 printf(" Kernel key algorithm: %" PRIu64 " %s\n",
264 kernel_subkey->algorithm,
265 (kernel_subkey->algorithm < kNumAlgorithms ?
266 algo_strings[kernel_subkey->algorithm] : "(invalid)"));
267 printf(" Kernel key version: %" PRIu64 "\n",
268 kernel_subkey->key_version);
269 printf(" Kernel key sha1sum: ");
270 PrintPubKeySha1Sum(kernel_subkey);
271 printf("\n");
272 printf(" Firmware body size: %" PRIu64 "\n",
273 preamble->body_signature.data_size);
274 printf(" Preamble flags: %" PRIu32 "\n", flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700275
Bill Richardson31d95c22014-08-24 22:07:17 -0700276 /* TODO: verify body size same as signature size */
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700277
Bill Richardson31d95c22014-08-24 22:07:17 -0700278 /* Verify body */
279 if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
280 printf
281 ("Preamble requests USE_RO_NORMAL;"
282 " skipping body verification.\n");
283 } else {
284 if (0 !=
285 VerifyData(fv_data, fv_size, &preamble->body_signature,
286 rsa)) {
287 VbExError("Error verifying firmware body.\n");
288 return 1;
289 }
290 printf("Body verification succeeded.\n");
291 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700292
Bill Richardson31d95c22014-08-24 22:07:17 -0700293 if (kernelkey_file) {
294 if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
295 VbExError("Unable to write kernel subkey\n");
296 return 1;
297 }
298 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700299
Bill Richardson31d95c22014-08-24 22:07:17 -0700300 return 0;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700301}
302
Bill Richardson31d95c22014-08-24 22:07:17 -0700303static int do_vbutil_firmware(int argc, char *argv[])
304{
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700305
Bill Richardson31d95c22014-08-24 22:07:17 -0700306 char *filename = NULL;
307 char *key_block_file = NULL;
308 char *signpubkey = NULL;
309 char *signprivate = NULL;
310 uint64_t version = 0;
311 char *fv_file = NULL;
312 char *kernelkey_file = NULL;
313 uint32_t preamble_flags = 0;
314 int mode = 0;
315 int parse_error = 0;
316 char *e;
317 int i;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700318
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
320 switch (i) {
321 case '?':
322 /* Unhandled option */
323 printf("Unknown option\n");
324 parse_error = 1;
325 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700326
Bill Richardson31d95c22014-08-24 22:07:17 -0700327 case OPT_MODE_VBLOCK:
328 case OPT_MODE_VERIFY:
329 mode = i;
330 filename = optarg;
331 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700332
Bill Richardson31d95c22014-08-24 22:07:17 -0700333 case OPT_KEYBLOCK:
334 key_block_file = optarg;
335 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700336
Bill Richardson31d95c22014-08-24 22:07:17 -0700337 case OPT_SIGNPUBKEY:
338 signpubkey = optarg;
339 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700340
Bill Richardson31d95c22014-08-24 22:07:17 -0700341 case OPT_SIGNPRIVATE:
342 signprivate = optarg;
343 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700344
Bill Richardson31d95c22014-08-24 22:07:17 -0700345 case OPT_FV:
346 fv_file = optarg;
347 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700348
Bill Richardson31d95c22014-08-24 22:07:17 -0700349 case OPT_KERNELKEY:
350 kernelkey_file = optarg;
351 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700352
Bill Richardson31d95c22014-08-24 22:07:17 -0700353 case OPT_VERSION:
354 version = strtoul(optarg, &e, 0);
355 if (!*optarg || (e && *e)) {
356 printf("Invalid --version\n");
357 parse_error = 1;
358 }
359 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700360
Bill Richardson31d95c22014-08-24 22:07:17 -0700361 case OPT_FLAGS:
362 preamble_flags = strtoul(optarg, &e, 0);
363 if (!*optarg || (e && *e)) {
364 printf("Invalid --flags\n");
365 parse_error = 1;
366 }
367 break;
368 }
369 }
Randall Spanglera712e012011-07-13 09:48:41 -0700370
Bill Richardson31d95c22014-08-24 22:07:17 -0700371 if (parse_error)
372 return PrintHelp();
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700373
Bill Richardson31d95c22014-08-24 22:07:17 -0700374 switch (mode) {
375 case OPT_MODE_VBLOCK:
376 return Vblock(filename, key_block_file, signprivate, version,
377 fv_file, kernelkey_file, preamble_flags);
378 case OPT_MODE_VERIFY:
379 return Verify(filename, signpubkey, fv_file, kernelkey_file);
380 default:
381 printf("Must specify a mode.\n");
382 return PrintHelp();
383 }
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700384}
Bill Richardson6f396152014-07-15 12:52:19 -0700385
386DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
387 "Verified boot firmware utility");