blob: b58fa2bef677421ddd7d2c05638f9964283c853a [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>
9#include <inttypes.h> /* For PRIu64 */
10#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
22
23/* Command line options */
24enum {
25 OPT_MODE_VBLOCK = 1000,
26 OPT_MODE_VERIFY,
27 OPT_KEYBLOCK,
28 OPT_SIGNPUBKEY,
29 OPT_SIGNPRIVATE,
30 OPT_VERSION,
31 OPT_FV,
32 OPT_KERNELKEY,
Randall Spanglera712e012011-07-13 09:48:41 -070033 OPT_FLAGS,
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070034};
35
36static struct option long_opts[] = {
37 {"vblock", 1, 0, OPT_MODE_VBLOCK },
38 {"verify", 1, 0, OPT_MODE_VERIFY },
39 {"keyblock", 1, 0, OPT_KEYBLOCK },
40 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
41 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
42 {"version", 1, 0, OPT_VERSION },
43 {"fv", 1, 0, OPT_FV },
44 {"kernelkey", 1, 0, OPT_KERNELKEY },
Randall Spanglera712e012011-07-13 09:48:41 -070045 {"flags", 1, 0, OPT_FLAGS },
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070046 {NULL, 0, 0, 0}
47};
48
49
50/* Print help and return error */
51static int PrintHelp(void) {
52
53 puts("vbutil_firmware - Verified boot key block utility\n"
54 "\n"
55 "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
56 "\n"
57 "For '--vblock <file>', required OPTIONS are:\n"
58 " --keyblock <file> Key block in .keyblock format\n"
Randall Spanglerceef83f2010-07-02 13:14:42 -070059 " --signprivate <file> Signing private key in .vbprivk format\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070060 " --version <number> Firmware version\n"
61 " --fv <file> Firmware volume to sign\n"
62 " --kernelkey <file> Kernel subkey in .vbpubk format\n"
Randall Spanglera712e012011-07-13 09:48:41 -070063 "optional OPTIONS are:\n"
64 " --flags <number> Preamble flags (defaults to 0)\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070065 "\n"
66 "For '--verify <file>', required OPTIONS are:\n"
67 " --signpubkey <file> Signing public key in .vbpubk format\n"
68 " --fv <file> Firmware volume to verify\n"
Bill Richardson60bcbe32010-09-09 14:53:56 -070069 "\n"
70 "For '--verify <file>', optional OPTIONS are:\n"
71 " --kernelkey <file> Write the kernel subkey to this file\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070072 "");
73 return 1;
74}
75
76
77/* Create a firmware .vblock */
78static int Vblock(const char* outfile, const char* keyblock_file,
79 const char* signprivate, uint64_t version,
Randall Spanglera712e012011-07-13 09:48:41 -070080 const char* fv_file, const char* kernelkey_file,
81 uint32_t preamble_flags) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070082
83 VbPrivateKey* signing_key;
84 VbPublicKey* kernel_subkey;
85 VbSignature* body_sig;
86 VbFirmwarePreambleHeader* preamble;
87 VbKeyBlockHeader* key_block;
88 uint64_t key_block_size;
89 uint8_t* fv_data;
90 uint64_t fv_size;
91 FILE* f;
92 uint64_t i;
93
94 if (!outfile) {
Randall Spangler32a65262011-06-27 10:49:11 -070095 VbExError("Must specify output filename\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070096 return 1;
97 }
98 if (!keyblock_file || !signprivate || !kernelkey_file) {
Randall Spangler32a65262011-06-27 10:49:11 -070099 VbExError("Must specify all keys\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700100 return 1;
101 }
102 if (!fv_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700103 VbExError("Must specify firmware volume\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700104 return 1;
105 }
106
107 /* Read the key block and keys */
108 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
109 if (!key_block) {
Randall Spangler32a65262011-06-27 10:49:11 -0700110 VbExError("Error reading key block.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700111 return 1;
112 }
113
Randall Spanglerceef83f2010-07-02 13:14:42 -0700114 signing_key = PrivateKeyRead(signprivate);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700115 if (!signing_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700116 VbExError("Error reading signing key.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700117 return 1;
118 }
119
120 kernel_subkey = PublicKeyRead(kernelkey_file);
121 if (!kernel_subkey) {
Randall Spangler32a65262011-06-27 10:49:11 -0700122 VbExError("Error reading kernel subkey.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700123 return 1;
124 }
125
126 /* Read and sign the firmware volume */
127 fv_data = ReadFile(fv_file, &fv_size);
128 if (!fv_data)
129 return 1;
130 if (!fv_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700131 VbExError("Empty firmware volume file\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700132 return 1;
133 }
134 body_sig = CalculateSignature(fv_data, fv_size, signing_key);
135 if (!body_sig) {
Randall Spangler32a65262011-06-27 10:49:11 -0700136 VbExError("Error calculating body signature\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700137 return 1;
138 }
Randall Spangler32a65262011-06-27 10:49:11 -0700139 free(fv_data);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700140
141 /* Create preamble */
142 preamble = CreateFirmwarePreamble(version,
143 kernel_subkey,
144 body_sig,
Randall Spanglera712e012011-07-13 09:48:41 -0700145 signing_key,
146 preamble_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700147 if (!preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700148 VbExError("Error creating preamble.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700149 return 1;
150 }
151
152 /* Write the output file */
153 f = fopen(outfile, "wb");
154 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700155 VbExError("Can't open output file %s\n", outfile);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700156 return 1;
157 }
158 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
159 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
160 fclose(f);
161 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700162 VbExError("Can't write output file %s\n", outfile);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700163 unlink(outfile);
164 return 1;
165 }
166
167 /* Success */
168 return 0;
169}
170
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700171static int Verify(const char* infile, const char* signpubkey,
Bill Richardson60bcbe32010-09-09 14:53:56 -0700172 const char* fv_file, const char* kernelkey_file) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700173
174 VbKeyBlockHeader* key_block;
175 VbFirmwarePreambleHeader* preamble;
176 VbPublicKey* data_key;
177 VbPublicKey* sign_key;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700178 VbPublicKey* kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700179 RSAPublicKey* rsa;
180 uint8_t* blob;
181 uint64_t blob_size;
182 uint8_t* fv_data;
183 uint64_t fv_size;
184 uint64_t now = 0;
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800185 uint32_t flags;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700186
187 if (!infile || !signpubkey || !fv_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700188 VbExError("Must specify filename, signpubkey, and fv\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700189 return 1;
190 }
191
192 /* Read public signing key */
193 sign_key = PublicKeyRead(signpubkey);
194 if (!sign_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700195 VbExError("Error reading signpubkey.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700196 return 1;
197 }
198
199 /* Read blob */
200 blob = ReadFile(infile, &blob_size);
201 if (!blob) {
Randall Spangler32a65262011-06-27 10:49:11 -0700202 VbExError("Error reading input file\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700203 return 1;
204 }
205
206 /* Read firmware volume */
207 fv_data = ReadFile(fv_file, &fv_size);
208 if (!fv_data) {
Randall Spangler32a65262011-06-27 10:49:11 -0700209 VbExError("Error reading firmware volume\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700210 return 1;
211 }
212
213 /* Verify key block */
214 key_block = (VbKeyBlockHeader*)blob;
Randall Spangler138acfe2010-08-17 15:45:21 -0700215 if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700216 VbExError("Error verifying key block.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700217 return 1;
218 }
Randall Spangler32a65262011-06-27 10:49:11 -0700219 free(sign_key);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700220 now += key_block->key_block_size;
221
222 printf("Key block:\n");
223 data_key = &key_block->data_key;
224 printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700225 printf(" Flags: %" PRIu64 " (ignored)\n",
226 key_block->key_block_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700227 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
228 (data_key->algorithm < kNumAlgorithms ?
229 algo_strings[data_key->algorithm] : "(invalid)"));
230 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700231 printf(" Data key sha1sum: ");
232 PrintPubKeySha1Sum(data_key);
233 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700234
235 rsa = PublicKeyToRSA(&key_block->data_key);
236 if (!rsa) {
Randall Spangler32a65262011-06-27 10:49:11 -0700237 VbExError("Error parsing data key.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700238 return 1;
239 }
240
241 /* Verify preamble */
242 preamble = (VbFirmwarePreambleHeader*)(blob + now);
Randall Spangler87c13d82010-07-19 10:35:40 -0700243 if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700244 VbExError("Error verifying preamble.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700245 return 1;
246 }
247 now += preamble->preamble_size;
248
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800249 flags = VbGetFirmwarePreambleFlags(preamble);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700250 printf("Preamble:\n");
251 printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
252 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
253 preamble->header_version_major, preamble->header_version_minor);
254 printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700255 kernel_subkey = &preamble->kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700256 printf(" Kernel key algorithm: %" PRIu64 " %s\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700257 kernel_subkey->algorithm,
258 (kernel_subkey->algorithm < kNumAlgorithms ?
259 algo_strings[kernel_subkey->algorithm] : "(invalid)"));
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700260 printf(" Kernel key version: %" PRIu64 "\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700261 kernel_subkey->key_version);
262 printf(" Kernel key sha1sum: ");
263 PrintPubKeySha1Sum(kernel_subkey);
264 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700265 printf(" Firmware body size: %" PRIu64 "\n",
266 preamble->body_signature.data_size);
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800267 printf(" Preamble flags: %" PRIu32 "\n", flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700268
269 /* TODO: verify body size same as signature size */
270
271 /* Verify body */
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800272 if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
273 printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n");
274 } else {
275 if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
276 VbExError("Error verifying firmware body.\n");
277 return 1;
278 }
279 printf("Body verification succeeded.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700280 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700281
282 if (kernelkey_file) {
283 if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
284 fprintf(stderr,
285 "vbutil_firmware: unable to write kernel subkey\n");
286 return 1;
287 }
288 }
289
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700290 return 0;
291}
292
293
Bill Richardson6f396152014-07-15 12:52:19 -0700294int do_vbutil_firmware(int argc, char* argv[]) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700295
296 char* filename = NULL;
297 char* key_block_file = NULL;
298 char* signpubkey = NULL;
299 char* signprivate = NULL;
300 uint64_t version = 0;
301 char* fv_file = NULL;
302 char* kernelkey_file = NULL;
Randall Spanglera712e012011-07-13 09:48:41 -0700303 uint32_t preamble_flags = 0;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700304 int mode = 0;
305 int parse_error = 0;
306 char* e;
307 int i;
308
309 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
310 switch (i) {
311 case '?':
312 /* Unhandled option */
313 printf("Unknown option\n");
314 parse_error = 1;
315 break;
316
317 case OPT_MODE_VBLOCK:
318 case OPT_MODE_VERIFY:
319 mode = i;
320 filename = optarg;
321 break;
322
323 case OPT_KEYBLOCK:
324 key_block_file = optarg;
325 break;
326
327 case OPT_SIGNPUBKEY:
328 signpubkey = optarg;
329 break;
330
331 case OPT_SIGNPRIVATE:
332 signprivate = optarg;
333 break;
334
335 case OPT_FV:
336 fv_file = optarg;
337 break;
338
339 case OPT_KERNELKEY:
340 kernelkey_file = optarg;
341 break;
342
343 case OPT_VERSION:
344 version = strtoul(optarg, &e, 0);
345 if (!*optarg || (e && *e)) {
346 printf("Invalid --version\n");
347 parse_error = 1;
348 }
349 break;
Randall Spanglera712e012011-07-13 09:48:41 -0700350
351 case OPT_FLAGS:
352 preamble_flags = strtoul(optarg, &e, 0);
353 if (!*optarg || (e && *e)) {
354 printf("Invalid --flags\n");
355 parse_error = 1;
356 }
357 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700358 }
359 }
360
361 if (parse_error)
362 return PrintHelp();
363
364 switch(mode) {
365 case OPT_MODE_VBLOCK:
366 return Vblock(filename, key_block_file, signprivate, version, fv_file,
Randall Spanglera712e012011-07-13 09:48:41 -0700367 kernelkey_file, preamble_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700368 case OPT_MODE_VERIFY:
Bill Richardson60bcbe32010-09-09 14:53:56 -0700369 return Verify(filename, signpubkey, fv_file, kernelkey_file);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700370 default:
371 printf("Must specify a mode.\n");
372 return PrintHelp();
373 }
374}
Bill Richardson6f396152014-07-15 12:52:19 -0700375
376DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
377 "Verified boot firmware utility");