blob: f6a547d6e9a74cc2429514bfb893c0f8c07cd305 [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;
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800183 uint32_t flags;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700184
185 if (!infile || !signpubkey || !fv_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700186 VbExError("Must specify filename, signpubkey, and fv\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700187 return 1;
188 }
189
190 /* Read public signing key */
191 sign_key = PublicKeyRead(signpubkey);
192 if (!sign_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700193 VbExError("Error reading signpubkey.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700194 return 1;
195 }
196
197 /* Read blob */
198 blob = ReadFile(infile, &blob_size);
199 if (!blob) {
Randall Spangler32a65262011-06-27 10:49:11 -0700200 VbExError("Error reading input file\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700201 return 1;
202 }
203
204 /* Read firmware volume */
205 fv_data = ReadFile(fv_file, &fv_size);
206 if (!fv_data) {
Randall Spangler32a65262011-06-27 10:49:11 -0700207 VbExError("Error reading firmware volume\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700208 return 1;
209 }
210
211 /* Verify key block */
212 key_block = (VbKeyBlockHeader*)blob;
Randall Spangler138acfe2010-08-17 15:45:21 -0700213 if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700214 VbExError("Error verifying key block.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700215 return 1;
216 }
Randall Spangler32a65262011-06-27 10:49:11 -0700217 free(sign_key);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700218 now += key_block->key_block_size;
219
220 printf("Key block:\n");
221 data_key = &key_block->data_key;
222 printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700223 printf(" Flags: %" PRIu64 " (ignored)\n",
224 key_block->key_block_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700225 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
226 (data_key->algorithm < kNumAlgorithms ?
227 algo_strings[data_key->algorithm] : "(invalid)"));
228 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700229 printf(" Data key sha1sum: ");
230 PrintPubKeySha1Sum(data_key);
231 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700232
233 rsa = PublicKeyToRSA(&key_block->data_key);
234 if (!rsa) {
Randall Spangler32a65262011-06-27 10:49:11 -0700235 VbExError("Error parsing data key.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700236 return 1;
237 }
238
239 /* Verify preamble */
240 preamble = (VbFirmwarePreambleHeader*)(blob + now);
Randall Spangler87c13d82010-07-19 10:35:40 -0700241 if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700242 VbExError("Error verifying preamble.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700243 return 1;
244 }
245 now += preamble->preamble_size;
246
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800247 flags = VbGetFirmwarePreambleFlags(preamble);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700248 printf("Preamble:\n");
249 printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
250 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
251 preamble->header_version_major, preamble->header_version_minor);
252 printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700253 kernel_subkey = &preamble->kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700254 printf(" Kernel key algorithm: %" PRIu64 " %s\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700255 kernel_subkey->algorithm,
256 (kernel_subkey->algorithm < kNumAlgorithms ?
257 algo_strings[kernel_subkey->algorithm] : "(invalid)"));
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700258 printf(" Kernel key version: %" PRIu64 "\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700259 kernel_subkey->key_version);
260 printf(" Kernel key sha1sum: ");
261 PrintPubKeySha1Sum(kernel_subkey);
262 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700263 printf(" Firmware body size: %" PRIu64 "\n",
264 preamble->body_signature.data_size);
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800265 printf(" Preamble flags: %" PRIu32 "\n", flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700266
267 /* TODO: verify body size same as signature size */
268
269 /* Verify body */
Tom Wai-Hong Tamefea8012011-08-22 18:45:31 +0800270 if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
271 printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n");
272 } else {
273 if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
274 VbExError("Error verifying firmware body.\n");
275 return 1;
276 }
277 printf("Body verification succeeded.\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700278 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700279
280 if (kernelkey_file) {
281 if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
282 fprintf(stderr,
283 "vbutil_firmware: unable to write kernel subkey\n");
284 return 1;
285 }
286 }
287
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700288 return 0;
289}
290
291
292int main(int argc, char* argv[]) {
293
294 char* filename = NULL;
295 char* key_block_file = NULL;
296 char* signpubkey = NULL;
297 char* signprivate = NULL;
298 uint64_t version = 0;
299 char* fv_file = NULL;
300 char* kernelkey_file = NULL;
Randall Spanglera712e012011-07-13 09:48:41 -0700301 uint32_t preamble_flags = 0;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700302 int mode = 0;
303 int parse_error = 0;
304 char* e;
305 int i;
306
307 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
308 switch (i) {
309 case '?':
310 /* Unhandled option */
311 printf("Unknown option\n");
312 parse_error = 1;
313 break;
314
315 case OPT_MODE_VBLOCK:
316 case OPT_MODE_VERIFY:
317 mode = i;
318 filename = optarg;
319 break;
320
321 case OPT_KEYBLOCK:
322 key_block_file = optarg;
323 break;
324
325 case OPT_SIGNPUBKEY:
326 signpubkey = optarg;
327 break;
328
329 case OPT_SIGNPRIVATE:
330 signprivate = optarg;
331 break;
332
333 case OPT_FV:
334 fv_file = optarg;
335 break;
336
337 case OPT_KERNELKEY:
338 kernelkey_file = optarg;
339 break;
340
341 case OPT_VERSION:
342 version = strtoul(optarg, &e, 0);
343 if (!*optarg || (e && *e)) {
344 printf("Invalid --version\n");
345 parse_error = 1;
346 }
347 break;
Randall Spanglera712e012011-07-13 09:48:41 -0700348
349 case OPT_FLAGS:
350 preamble_flags = strtoul(optarg, &e, 0);
351 if (!*optarg || (e && *e)) {
352 printf("Invalid --flags\n");
353 parse_error = 1;
354 }
355 break;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700356 }
357 }
358
359 if (parse_error)
360 return PrintHelp();
361
362 switch(mode) {
363 case OPT_MODE_VBLOCK:
364 return Vblock(filename, key_block_file, signprivate, version, fv_file,
Randall Spanglera712e012011-07-13 09:48:41 -0700365 kernelkey_file, preamble_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700366 case OPT_MODE_VERIFY:
Bill Richardson60bcbe32010-09-09 14:53:56 -0700367 return Verify(filename, signpubkey, fv_file, kernelkey_file);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700368 default:
369 printf("Must specify a mode.\n");
370 return PrintHelp();
371 }
372}