blob: 76d46c6b5a3f239388991f5f19023a9eefd47223 [file] [log] [blame]
Randall Spangler32a65262011-06-27 10:49:11 -07001/* Copyright (c) 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"
16#include "host_common.h"
17#include "kernel_blob.h"
18#include "vboot_common.h"
19
20
21/* Command line options */
22enum {
23 OPT_MODE_VBLOCK = 1000,
24 OPT_MODE_VERIFY,
25 OPT_KEYBLOCK,
26 OPT_SIGNPUBKEY,
27 OPT_SIGNPRIVATE,
28 OPT_VERSION,
29 OPT_FV,
30 OPT_KERNELKEY,
Randall Spanglera712e012011-07-13 09:48:41 -070031 OPT_FLAGS,
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070032};
33
34static struct option long_opts[] = {
35 {"vblock", 1, 0, OPT_MODE_VBLOCK },
36 {"verify", 1, 0, OPT_MODE_VERIFY },
37 {"keyblock", 1, 0, OPT_KEYBLOCK },
38 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
39 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
40 {"version", 1, 0, OPT_VERSION },
41 {"fv", 1, 0, OPT_FV },
42 {"kernelkey", 1, 0, OPT_KERNELKEY },
Randall Spanglera712e012011-07-13 09:48:41 -070043 {"flags", 1, 0, OPT_FLAGS },
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070044 {NULL, 0, 0, 0}
45};
46
47
48/* Print help and return error */
49static int PrintHelp(void) {
50
51 puts("vbutil_firmware - Verified boot key block utility\n"
52 "\n"
53 "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
54 "\n"
55 "For '--vblock <file>', required OPTIONS are:\n"
56 " --keyblock <file> Key block in .keyblock format\n"
Randall Spanglerceef83f2010-07-02 13:14:42 -070057 " --signprivate <file> Signing private key in .vbprivk format\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070058 " --version <number> Firmware version\n"
59 " --fv <file> Firmware volume to sign\n"
60 " --kernelkey <file> Kernel subkey in .vbpubk format\n"
Randall Spanglera712e012011-07-13 09:48:41 -070061 "optional OPTIONS are:\n"
62 " --flags <number> Preamble flags (defaults to 0)\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070063 "\n"
64 "For '--verify <file>', required OPTIONS are:\n"
65 " --signpubkey <file> Signing public key in .vbpubk format\n"
66 " --fv <file> Firmware volume to verify\n"
Bill Richardson60bcbe32010-09-09 14:53:56 -070067 "\n"
68 "For '--verify <file>', optional OPTIONS are:\n"
69 " --kernelkey <file> Write the kernel subkey to this file\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070070 "");
71 return 1;
72}
73
74
75/* Create a firmware .vblock */
76static int Vblock(const char* outfile, const char* keyblock_file,
77 const char* signprivate, uint64_t version,
Randall Spanglera712e012011-07-13 09:48:41 -070078 const char* fv_file, const char* kernelkey_file,
79 uint32_t preamble_flags) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070080
81 VbPrivateKey* signing_key;
82 VbPublicKey* kernel_subkey;
83 VbSignature* body_sig;
84 VbFirmwarePreambleHeader* preamble;
85 VbKeyBlockHeader* key_block;
86 uint64_t key_block_size;
87 uint8_t* fv_data;
88 uint64_t fv_size;
89 FILE* f;
90 uint64_t i;
91
92 if (!outfile) {
Randall Spangler32a65262011-06-27 10:49:11 -070093 VbExError("Must specify output filename\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070094 return 1;
95 }
96 if (!keyblock_file || !signprivate || !kernelkey_file) {
Randall Spangler32a65262011-06-27 10:49:11 -070097 VbExError("Must specify all keys\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070098 return 1;
99 }
100 if (!fv_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700101 VbExError("Must specify firmware volume\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700102 return 1;
103 }
104
105 /* Read the key block and keys */
106 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
107 if (!key_block) {
Randall Spangler32a65262011-06-27 10:49:11 -0700108 VbExError("Error reading key block.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700109 return 1;
110 }
111
Randall Spanglerceef83f2010-07-02 13:14:42 -0700112 signing_key = PrivateKeyRead(signprivate);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700113 if (!signing_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700114 VbExError("Error reading signing key.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700115 return 1;
116 }
117
118 kernel_subkey = PublicKeyRead(kernelkey_file);
119 if (!kernel_subkey) {
Randall Spangler32a65262011-06-27 10:49:11 -0700120 VbExError("Error reading kernel subkey.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700121 return 1;
122 }
123
124 /* Read and sign the firmware volume */
125 fv_data = ReadFile(fv_file, &fv_size);
126 if (!fv_data)
127 return 1;
128 if (!fv_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700129 VbExError("Empty firmware volume file\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700130 return 1;
131 }
132 body_sig = CalculateSignature(fv_data, fv_size, signing_key);
133 if (!body_sig) {
Randall Spangler32a65262011-06-27 10:49:11 -0700134 VbExError("Error calculating body signature\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700135 return 1;
136 }
Randall Spangler32a65262011-06-27 10:49:11 -0700137 free(fv_data);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700138
139 /* Create preamble */
140 preamble = CreateFirmwarePreamble(version,
141 kernel_subkey,
142 body_sig,
Randall Spanglera712e012011-07-13 09:48:41 -0700143 signing_key,
144 preamble_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700145 if (!preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700146 VbExError("Error creating preamble.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700147 return 1;
148 }
149
150 /* Write the output file */
151 f = fopen(outfile, "wb");
152 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700153 VbExError("Can't open output file %s\n", outfile);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700154 return 1;
155 }
156 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
157 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
158 fclose(f);
159 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700160 VbExError("Can't write output file %s\n", outfile);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700161 unlink(outfile);
162 return 1;
163 }
164
165 /* Success */
166 return 0;
167}
168
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700169static int Verify(const char* infile, const char* signpubkey,
Bill Richardson60bcbe32010-09-09 14:53:56 -0700170 const char* fv_file, const char* kernelkey_file) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700171
172 VbKeyBlockHeader* key_block;
173 VbFirmwarePreambleHeader* preamble;
174 VbPublicKey* data_key;
175 VbPublicKey* sign_key;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700176 VbPublicKey* kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700177 RSAPublicKey* rsa;
178 uint8_t* blob;
179 uint64_t blob_size;
180 uint8_t* fv_data;
181 uint64_t fv_size;
182 uint64_t now = 0;
183
184 if (!infile || !signpubkey || !fv_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700185 VbExError("Must specify filename, signpubkey, and fv\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700186 return 1;
187 }
188
189 /* Read public signing key */
190 sign_key = PublicKeyRead(signpubkey);
191 if (!sign_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700192 VbExError("Error reading signpubkey.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700193 return 1;
194 }
195
196 /* Read blob */
197 blob = ReadFile(infile, &blob_size);
198 if (!blob) {
Randall Spangler32a65262011-06-27 10:49:11 -0700199 VbExError("Error reading input file\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700200 return 1;
201 }
202
203 /* Read firmware volume */
204 fv_data = ReadFile(fv_file, &fv_size);
205 if (!fv_data) {
Randall Spangler32a65262011-06-27 10:49:11 -0700206 VbExError("Error reading firmware volume\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700207 return 1;
208 }
209
210 /* Verify key block */
211 key_block = (VbKeyBlockHeader*)blob;
Randall Spangler138acfe2010-08-17 15:45:21 -0700212 if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700213 VbExError("Error verifying key block.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700214 return 1;
215 }
Randall Spangler32a65262011-06-27 10:49:11 -0700216 free(sign_key);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700217 now += key_block->key_block_size;
218
219 printf("Key block:\n");
220 data_key = &key_block->data_key;
221 printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700222 printf(" Flags: %" PRIu64 " (ignored)\n",
223 key_block->key_block_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700224 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
225 (data_key->algorithm < kNumAlgorithms ?
226 algo_strings[data_key->algorithm] : "(invalid)"));
227 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700228 printf(" Data key sha1sum: ");
229 PrintPubKeySha1Sum(data_key);
230 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700231
232 rsa = PublicKeyToRSA(&key_block->data_key);
233 if (!rsa) {
Randall Spangler32a65262011-06-27 10:49:11 -0700234 VbExError("Error parsing data key.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700235 return 1;
236 }
237
238 /* Verify preamble */
239 preamble = (VbFirmwarePreambleHeader*)(blob + now);
Randall Spangler87c13d82010-07-19 10:35:40 -0700240 if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700241 VbExError("Error verifying preamble.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700242 return 1;
243 }
244 now += preamble->preamble_size;
245
246 printf("Preamble:\n");
247 printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
248 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
249 preamble->header_version_major, preamble->header_version_minor);
250 printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700251 kernel_subkey = &preamble->kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700252 printf(" Kernel key algorithm: %" PRIu64 " %s\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700253 kernel_subkey->algorithm,
254 (kernel_subkey->algorithm < kNumAlgorithms ?
255 algo_strings[kernel_subkey->algorithm] : "(invalid)"));
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700256 printf(" Kernel key version: %" PRIu64 "\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700257 kernel_subkey->key_version);
258 printf(" Kernel key sha1sum: ");
259 PrintPubKeySha1Sum(kernel_subkey);
260 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700261 printf(" Firmware body size: %" PRIu64 "\n",
262 preamble->body_signature.data_size);
Randall Spanglera712e012011-07-13 09:48:41 -0700263 printf(" Preamble flags: %" PRIu32 "\n",
264 VbGetFirmwarePreambleFlags(preamble));
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700265
266 /* TODO: verify body size same as signature size */
267
268 /* Verify body */
Randall Spangler87c13d82010-07-19 10:35:40 -0700269 if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700270 VbExError("Error verifying firmware body.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700271 return 1;
272 }
273 printf("Body verification succeeded.\n");
Bill Richardson60bcbe32010-09-09 14:53:56 -0700274
275 if (kernelkey_file) {
276 if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
277 fprintf(stderr,
278 "vbutil_firmware: unable to write kernel subkey\n");
279 return 1;
280 }
281 }
282
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700283 return 0;
284}
285
286
287int main(int argc, char* argv[]) {
288
289 char* filename = NULL;
290 char* key_block_file = NULL;
291 char* signpubkey = NULL;
292 char* signprivate = NULL;
293 uint64_t version = 0;
294 char* fv_file = NULL;
295 char* kernelkey_file = NULL;
Randall Spanglera712e012011-07-13 09:48:41 -0700296 uint32_t preamble_flags = 0;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700297 int mode = 0;
298 int parse_error = 0;
299 char* e;
300 int i;
301
302 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
303 switch (i) {
304 case '?':
305 /* Unhandled option */
306 printf("Unknown option\n");
307 parse_error = 1;
308 break;
309
310 case OPT_MODE_VBLOCK:
311 case OPT_MODE_VERIFY:
312 mode = i;
313 filename = optarg;
314 break;
315
316 case OPT_KEYBLOCK:
317 key_block_file = optarg;
318 break;
319
320 case OPT_SIGNPUBKEY:
321 signpubkey = optarg;
322 break;
323
324 case OPT_SIGNPRIVATE:
325 signprivate = optarg;
326 break;
327
328 case OPT_FV:
329 fv_file = optarg;
330 break;
331
332 case OPT_KERNELKEY:
333 kernelkey_file = optarg;
334 break;
335
336 case OPT_VERSION:
337 version = strtoul(optarg, &e, 0);
338 if (!*optarg || (e && *e)) {
339 printf("Invalid --version\n");
340 parse_error = 1;
341 }
342 break;
Randall Spanglera712e012011-07-13 09:48:41 -0700343
344 case OPT_FLAGS:
345 preamble_flags = strtoul(optarg, &e, 0);
346 if (!*optarg || (e && *e)) {
347 printf("Invalid --flags\n");
348 parse_error = 1;
349 }
350 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700351 }
352 }
353
354 if (parse_error)
355 return PrintHelp();
356
357 switch(mode) {
358 case OPT_MODE_VBLOCK:
359 return Vblock(filename, key_block_file, signprivate, version, fv_file,
Randall Spanglera712e012011-07-13 09:48:41 -0700360 kernelkey_file, preamble_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700361 case OPT_MODE_VERIFY:
Bill Richardson60bcbe32010-09-09 14:53:56 -0700362 return Verify(filename, signpubkey, fv_file, kernelkey_file);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700363 default:
364 printf("Must specify a mode.\n");
365 return PrintHelp();
366 }
367}