blob: 9cff272998aaf29297b8b02359829067b460b7a2 [file] [log] [blame]
Randall Spanglerdcab8fa2010-06-15 14:50:51 -07001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * 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,
31};
32
33static struct option long_opts[] = {
34 {"vblock", 1, 0, OPT_MODE_VBLOCK },
35 {"verify", 1, 0, OPT_MODE_VERIFY },
36 {"keyblock", 1, 0, OPT_KEYBLOCK },
37 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
38 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
39 {"version", 1, 0, OPT_VERSION },
40 {"fv", 1, 0, OPT_FV },
41 {"kernelkey", 1, 0, OPT_KERNELKEY },
42 {NULL, 0, 0, 0}
43};
44
45
46/* Print help and return error */
47static int PrintHelp(void) {
48
49 puts("vbutil_firmware - Verified boot key block utility\n"
50 "\n"
51 "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
52 "\n"
53 "For '--vblock <file>', required OPTIONS are:\n"
54 " --keyblock <file> Key block in .keyblock format\n"
Randall Spanglerceef83f2010-07-02 13:14:42 -070055 " --signprivate <file> Signing private key in .vbprivk format\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070056 " --version <number> Firmware version\n"
57 " --fv <file> Firmware volume to sign\n"
58 " --kernelkey <file> Kernel subkey in .vbpubk format\n"
59 "\n"
60 "For '--verify <file>', required OPTIONS are:\n"
61 " --signpubkey <file> Signing public key in .vbpubk format\n"
62 " --fv <file> Firmware volume to verify\n"
Bill Richardson60bcbe32010-09-09 14:53:56 -070063 "\n"
64 "For '--verify <file>', optional OPTIONS are:\n"
65 " --kernelkey <file> Write the kernel subkey to this file\n"
Randall Spanglerdcab8fa2010-06-15 14:50:51 -070066 "");
67 return 1;
68}
69
70
71/* Create a firmware .vblock */
72static int Vblock(const char* outfile, const char* keyblock_file,
73 const char* signprivate, uint64_t version,
74 const char* fv_file, const char* kernelkey_file) {
75
76 VbPrivateKey* signing_key;
77 VbPublicKey* kernel_subkey;
78 VbSignature* body_sig;
79 VbFirmwarePreambleHeader* preamble;
80 VbKeyBlockHeader* key_block;
81 uint64_t key_block_size;
82 uint8_t* fv_data;
83 uint64_t fv_size;
84 FILE* f;
85 uint64_t i;
86
87 if (!outfile) {
88 error("Must specify output filename\n");
89 return 1;
90 }
91 if (!keyblock_file || !signprivate || !kernelkey_file) {
92 error("Must specify all keys\n");
93 return 1;
94 }
95 if (!fv_file) {
96 error("Must specify firmware volume\n");
97 return 1;
98 }
99
100 /* Read the key block and keys */
101 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
102 if (!key_block) {
103 error("Error reading key block.\n");
104 return 1;
105 }
106
Randall Spanglerceef83f2010-07-02 13:14:42 -0700107 signing_key = PrivateKeyRead(signprivate);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700108 if (!signing_key) {
109 error("Error reading signing key.\n");
110 return 1;
111 }
112
113 kernel_subkey = PublicKeyRead(kernelkey_file);
114 if (!kernel_subkey) {
115 error("Error reading kernel subkey.\n");
116 return 1;
117 }
118
119 /* Read and sign the firmware volume */
120 fv_data = ReadFile(fv_file, &fv_size);
121 if (!fv_data)
122 return 1;
123 if (!fv_size) {
124 error("Empty firmware volume file\n");
125 return 1;
126 }
127 body_sig = CalculateSignature(fv_data, fv_size, signing_key);
128 if (!body_sig) {
129 error("Error calculating body signature\n");
130 return 1;
131 }
132 Free(fv_data);
133
134 /* Create preamble */
135 preamble = CreateFirmwarePreamble(version,
136 kernel_subkey,
137 body_sig,
138 signing_key);
139 if (!preamble) {
140 error("Error creating preamble.\n");
141 return 1;
142 }
143
144 /* Write the output file */
145 f = fopen(outfile, "wb");
146 if (!f) {
147 error("Can't open output file %s\n", outfile);
148 return 1;
149 }
150 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
151 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
152 fclose(f);
153 if (i) {
154 error("Can't write output file %s\n", outfile);
155 unlink(outfile);
156 return 1;
157 }
158
159 /* Success */
160 return 0;
161}
162
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700163static int Verify(const char* infile, const char* signpubkey,
Bill Richardson60bcbe32010-09-09 14:53:56 -0700164 const char* fv_file, const char* kernelkey_file) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700165
166 VbKeyBlockHeader* key_block;
167 VbFirmwarePreambleHeader* preamble;
168 VbPublicKey* data_key;
169 VbPublicKey* sign_key;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700170 VbPublicKey* kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700171 RSAPublicKey* rsa;
172 uint8_t* blob;
173 uint64_t blob_size;
174 uint8_t* fv_data;
175 uint64_t fv_size;
176 uint64_t now = 0;
177
178 if (!infile || !signpubkey || !fv_file) {
179 error("Must specify filename, signpubkey, and fv\n");
180 return 1;
181 }
182
183 /* Read public signing key */
184 sign_key = PublicKeyRead(signpubkey);
185 if (!sign_key) {
186 error("Error reading signpubkey.\n");
187 return 1;
188 }
189
190 /* Read blob */
191 blob = ReadFile(infile, &blob_size);
192 if (!blob) {
193 error("Error reading input file\n");
194 return 1;
195 }
196
197 /* Read firmware volume */
198 fv_data = ReadFile(fv_file, &fv_size);
199 if (!fv_data) {
200 error("Error reading firmware volume\n");
201 return 1;
202 }
203
204 /* Verify key block */
205 key_block = (VbKeyBlockHeader*)blob;
Randall Spangler138acfe2010-08-17 15:45:21 -0700206 if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700207 error("Error verifying key block.\n");
208 return 1;
209 }
210 Free(sign_key);
211 now += key_block->key_block_size;
212
213 printf("Key block:\n");
214 data_key = &key_block->data_key;
215 printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700216 printf(" Flags: %" PRIu64 " (ignored)\n",
217 key_block->key_block_flags);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700218 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
219 (data_key->algorithm < kNumAlgorithms ?
220 algo_strings[data_key->algorithm] : "(invalid)"));
221 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700222 printf(" Data key sha1sum: ");
223 PrintPubKeySha1Sum(data_key);
224 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700225
226 rsa = PublicKeyToRSA(&key_block->data_key);
227 if (!rsa) {
228 error("Error parsing data key.\n");
229 return 1;
230 }
231
232 /* Verify preamble */
233 preamble = (VbFirmwarePreambleHeader*)(blob + now);
Randall Spangler87c13d82010-07-19 10:35:40 -0700234 if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700235 error("Error verifying preamble.\n");
236 return 1;
237 }
238 now += preamble->preamble_size;
239
240 printf("Preamble:\n");
241 printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
242 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
243 preamble->header_version_major, preamble->header_version_minor);
244 printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700245 kernel_subkey = &preamble->kernel_subkey;
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700246 printf(" Kernel key algorithm: %" PRIu64 " %s\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700247 kernel_subkey->algorithm,
248 (kernel_subkey->algorithm < kNumAlgorithms ?
249 algo_strings[kernel_subkey->algorithm] : "(invalid)"));
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700250 printf(" Kernel key version: %" PRIu64 "\n",
Bill Richardson60bcbe32010-09-09 14:53:56 -0700251 kernel_subkey->key_version);
252 printf(" Kernel key sha1sum: ");
253 PrintPubKeySha1Sum(kernel_subkey);
254 printf("\n");
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700255 printf(" Firmware body size: %" PRIu64 "\n",
256 preamble->body_signature.data_size);
257
258 /* TODO: verify body size same as signature size */
259
260 /* Verify body */
Randall Spangler87c13d82010-07-19 10:35:40 -0700261 if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700262 error("Error verifying firmware body.\n");
263 return 1;
264 }
265 printf("Body verification succeeded.\n");
Bill Richardson60bcbe32010-09-09 14:53:56 -0700266
267 if (kernelkey_file) {
268 if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
269 fprintf(stderr,
270 "vbutil_firmware: unable to write kernel subkey\n");
271 return 1;
272 }
273 }
274
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700275 return 0;
276}
277
278
279int main(int argc, char* argv[]) {
280
281 char* filename = NULL;
282 char* key_block_file = NULL;
283 char* signpubkey = NULL;
284 char* signprivate = NULL;
285 uint64_t version = 0;
286 char* fv_file = NULL;
287 char* kernelkey_file = NULL;
288 int mode = 0;
289 int parse_error = 0;
290 char* e;
291 int i;
292
293 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
294 switch (i) {
295 case '?':
296 /* Unhandled option */
297 printf("Unknown option\n");
298 parse_error = 1;
299 break;
300
301 case OPT_MODE_VBLOCK:
302 case OPT_MODE_VERIFY:
303 mode = i;
304 filename = optarg;
305 break;
306
307 case OPT_KEYBLOCK:
308 key_block_file = optarg;
309 break;
310
311 case OPT_SIGNPUBKEY:
312 signpubkey = optarg;
313 break;
314
315 case OPT_SIGNPRIVATE:
316 signprivate = optarg;
317 break;
318
319 case OPT_FV:
320 fv_file = optarg;
321 break;
322
323 case OPT_KERNELKEY:
324 kernelkey_file = optarg;
325 break;
326
327 case OPT_VERSION:
328 version = strtoul(optarg, &e, 0);
329 if (!*optarg || (e && *e)) {
330 printf("Invalid --version\n");
331 parse_error = 1;
332 }
333 break;
334 }
335 }
336
337 if (parse_error)
338 return PrintHelp();
339
340 switch(mode) {
341 case OPT_MODE_VBLOCK:
342 return Vblock(filename, key_block_file, signprivate, version, fv_file,
343 kernelkey_file);
344 case OPT_MODE_VERIFY:
Bill Richardson60bcbe32010-09-09 14:53:56 -0700345 return Verify(filename, signpubkey, fv_file, kernelkey_file);
Randall Spanglerdcab8fa2010-06-15 14:50:51 -0700346 default:
347 printf("Must specify a mode.\n");
348 return PrintHelp();
349 }
350}