blob: 3892d02faa2c4406cf76be33aed83f24f02eb135 [file] [log] [blame]
Bill Richardson5aa673c2010-08-10 12:20:34 -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 * Developer file-signing utility
6 */
7
8#include <errno.h>
9#include <getopt.h>
10#include <inttypes.h> /* For PRIu64 */
11#include <stdarg.h>
12#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <unistd.h>
19
20#include "cryptolib.h"
21#include "host_common.h"
22#include "kernel_blob.h"
23#include "vboot_common.h"
24
25
26/* Global opt */
27static int opt_debug = 0;
28
29/* Command line options */
30enum {
31 OPT_MODE_SIGN = 1000,
32 OPT_MODE_VERIFY,
33 OPT_KEYBLOCK,
34 OPT_SIGNPRIVATE,
35 OPT_VBLOCK,
36};
37
38static struct option long_opts[] = {
39 {"sign", 1, 0, OPT_MODE_SIGN },
40 {"verify", 1, 0, OPT_MODE_VERIFY },
41 {"keyblock", 1, 0, OPT_KEYBLOCK },
42 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
43 {"vblock", 1, 0, OPT_VBLOCK },
44 {"debug", 0, &opt_debug, 1 },
45 {NULL, 0, 0, 0}
46};
47
48
49/* Print help and return error */
Bill Richardson83ba6d32010-08-11 13:23:35 -070050static int PrintHelp(const char *progname) {
Bill Richardson5aa673c2010-08-10 12:20:34 -070051 fprintf(stderr,
52 "This program is used to sign and verify developer-mode files\n");
53 fprintf(stderr,
54 "\n"
55 "Usage: %s --sign <file> [PARAMETERS]\n"
56 "\n"
57 " Required parameters:\n"
58 " --keyblock <file> Key block in .keyblock format\n"
59 " --signprivate <file>"
60 " Private key to sign file data, in .vbprivk format\n"
61 " --vblock <file> Output signature in .vblock format\n"
62 "\n",
63 progname);
64 fprintf(stderr,
65 "OR\n\n"
66 "Usage: %s --verify <file> [PARAMETERS]\n"
67 "\n"
68 " Required parameters:\n"
69 " --vblock <file> Signature file in .vblock format\n"
70 "\n",
71 progname);
72 return 1;
73}
74
75static void Debug(const char *format, ...) {
76 if (!opt_debug)
77 return;
78
79 va_list ap;
80 va_start(ap, format);
81 fprintf(stderr, "DEBUG: ");
82 vfprintf(stderr, format, ap);
83 va_end(ap);
84}
85
86
87/* Sign a file. We'll reuse the same structs used to sign kernels, to avoid
88 having to declare yet another one for just this purpose. */
89static int Sign(const char* filename, const char* keyblock_file,
90 const char* signprivate_file, const char* outfile) {
Bill Richardson83ba6d32010-08-11 13:23:35 -070091 uint8_t* file_data;
Bill Richardson5aa673c2010-08-10 12:20:34 -070092 uint64_t file_size;
93 VbKeyBlockHeader* key_block;
94 uint64_t key_block_size;
95 VbPrivateKey* signing_key;
96 VbSignature* body_sig;
97 VbKernelPreambleHeader* preamble;
Bill Richardson83ba6d32010-08-11 13:23:35 -070098 FILE* output_fp;
Bill Richardson5aa673c2010-08-10 12:20:34 -070099
100 /* Read the file that we're going to sign. */
101 file_data = ReadFile(filename, &file_size);
102 if (!file_data) {
103 error("Error reading file to sign.\n");
104 return 1;
105 }
106
107 /* Get the key block and read the private key corresponding to it. */
108 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
109 if (!key_block) {
110 error("Error reading key block.\n");
111 return 1;
112 }
113 signing_key = PrivateKeyRead(signprivate_file);
114 if (!signing_key) {
115 error("Error reading signing key.\n");
116 return 1;
117 }
118
119 /* Sign the file data */
120 body_sig = CalculateSignature(file_data, file_size, signing_key);
121 if (!body_sig) {
122 error("Error calculating body signature\n");
123 return 1;
124 }
125
126 /* Create preamble */
Bill Richardson83ba6d32010-08-11 13:23:35 -0700127 preamble = CreateKernelPreamble((uint64_t)0,
128 (uint64_t)0,
129 (uint64_t)0,
130 (uint64_t)0,
131 body_sig,
132 (uint64_t)0,
133 signing_key);
Bill Richardson5aa673c2010-08-10 12:20:34 -0700134 if (!preamble) {
135 error("Error creating preamble.\n");
136 return 1;
137 }
138
139 /* Write the output file */
140 Debug("writing %s...\n", outfile);
Bill Richardson83ba6d32010-08-11 13:23:35 -0700141 output_fp = fopen(outfile, "wb");
142 if (!output_fp) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700143 error("Can't open output file %s\n", outfile);
144 return 1;
145 }
146 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
147 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
Bill Richardson83ba6d32010-08-11 13:23:35 -0700148 if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) ||
149 (1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700150 error("Can't write output file %s\n", outfile);
Bill Richardson83ba6d32010-08-11 13:23:35 -0700151 fclose(output_fp);
Bill Richardson5aa673c2010-08-10 12:20:34 -0700152 unlink(outfile);
153 return 1;
154 }
Bill Richardson83ba6d32010-08-11 13:23:35 -0700155 fclose(output_fp);
Bill Richardson5aa673c2010-08-10 12:20:34 -0700156
157 /* Done */
158 Free(preamble);
159 Free(body_sig);
160 Free(signing_key);
161 Free(key_block);
162 Free(file_data);
163
164 /* Success */
165 return 0;
166}
167
168static int Verify(const char* filename, const char* vblock_file) {
Bill Richardson83ba6d32010-08-11 13:23:35 -0700169 uint8_t* file_data;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700170 uint64_t file_size;
Bill Richardson83ba6d32010-08-11 13:23:35 -0700171 uint8_t* buf;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700172 uint64_t buf_size;
173 VbKeyBlockHeader* key_block;
174 VbKernelPreambleHeader* preamble;
175 VbPublicKey* data_key;
176 RSAPublicKey* rsa;
Bill Richardson83ba6d32010-08-11 13:23:35 -0700177 uint64_t current_buf_offset = 0;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700178
179 /* Read the file that we're going to verify. */
180 file_data = ReadFile(filename, &file_size);
181 if (!file_data) {
182 error("Error reading file to sign.\n");
183 return 1;
184 }
185
186 /* Read the vblock that we're going to use on it */
187 buf = ReadFile(vblock_file, &buf_size);
188 if (!buf) {
189 error("Error reading vblock_file.\n");
190 return 1;
191 }
192
193 /* Find the key block */
194 key_block = (VbKeyBlockHeader*)buf;
195 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
Bill Richardson83ba6d32010-08-11 13:23:35 -0700196 current_buf_offset += key_block->key_block_size;
197 if (current_buf_offset > buf_size) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700198 error("key_block_size advances past the end of the buffer\n");
199 return 1;
200 }
201
202 /* Find the preamble */
Bill Richardson83ba6d32010-08-11 13:23:35 -0700203 preamble = (VbKernelPreambleHeader*)(buf + current_buf_offset);
Bill Richardson5aa673c2010-08-10 12:20:34 -0700204 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
Bill Richardson83ba6d32010-08-11 13:23:35 -0700205 current_buf_offset += preamble->preamble_size;
206 if (current_buf_offset > buf_size ) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700207 error("preamble_size advances past the end of the buffer\n");
208 return 1;
209 }
210
Bill Richardson83ba6d32010-08-11 13:23:35 -0700211 Debug("Current buf offset is at 0x%" PRIx64 " bytes\n", current_buf_offset);
Bill Richardson5aa673c2010-08-10 12:20:34 -0700212
Randall Spangler138acfe2010-08-17 15:45:21 -0700213 /* Check the key block (hash only) */
214 if (0 != KeyBlockVerify(key_block, file_size, NULL, 1)) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700215 error("Error verifying key block.\n");
216 return 1;
217 }
218
219 printf("Key block:\n");
220 data_key = &key_block->data_key;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700221 printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size);
222 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
223 (data_key->algorithm < kNumAlgorithms ?
224 algo_strings[data_key->algorithm] : "(invalid)"));
225 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
226 printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags);
227
228
229 /* Verify preamble */
230 rsa = PublicKeyToRSA(&key_block->data_key);
231 if (!rsa) {
232 error("Error parsing data key.\n");
233 return 1;
234 }
Bill Richardson83ba6d32010-08-11 13:23:35 -0700235 if (0 != VerifyKernelPreamble(preamble, file_size, rsa)) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700236 error("Error verifying preamble.\n");
237 return 1;
238 }
239
240 printf("Preamble:\n");
241 printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size);
242 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
243 preamble->header_version_major, preamble->header_version_minor);
244 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version);
245 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address);
246 printf(" Body size: 0x%" PRIx64 "\n",
247 preamble->body_signature.data_size);
248 printf(" Bootloader address: 0x%" PRIx64 "\n",
249 preamble->bootloader_address);
250 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size);
251
252 /* Verify body */
Bill Richardson83ba6d32010-08-11 13:23:35 -0700253 if (0 != VerifyData(file_data, file_size, &preamble->body_signature, rsa)) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700254 error("Error verifying kernel body.\n");
255 return 1;
256 }
257 printf("Body verification succeeded.\n");
258
Bill Richardson5aa673c2010-08-10 12:20:34 -0700259 return 0;
260}
261
262
263int main(int argc, char* argv[]) {
264 char* filename = NULL;
265 char* keyblock_file = NULL;
266 char* signprivate_file = NULL;
267 char* vblock_file = NULL;
268 int mode = 0;
269 int parse_error = 0;
Bill Richardson83ba6d32010-08-11 13:23:35 -0700270 int option_index;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700271
272 char *progname = strrchr(argv[0], '/');
273 if (progname)
274 progname++;
275 else
276 progname = argv[0];
277
Bill Richardson83ba6d32010-08-11 13:23:35 -0700278 while ((option_index = getopt_long(argc, argv, ":", long_opts, NULL)) != -1 &&
Bill Richardson5aa673c2010-08-10 12:20:34 -0700279 !parse_error) {
Bill Richardson83ba6d32010-08-11 13:23:35 -0700280 switch (option_index) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700281 default:
282 case '?':
283 /* Unhandled option */
284 parse_error = 1;
285 break;
286
287 case 0:
288 /* silently handled option */
289 break;
290
291 case OPT_MODE_SIGN:
292 case OPT_MODE_VERIFY:
Bill Richardson83ba6d32010-08-11 13:23:35 -0700293 if (mode && (mode != option_index)) {
Bill Richardson5aa673c2010-08-10 12:20:34 -0700294 fprintf(stderr, "Only a single mode can be specified\n");
295 parse_error = 1;
296 break;
297 }
Bill Richardson83ba6d32010-08-11 13:23:35 -0700298 mode = option_index;
Bill Richardson5aa673c2010-08-10 12:20:34 -0700299 filename = optarg;
300 break;
301
302 case OPT_KEYBLOCK:
303 keyblock_file = optarg;
304 break;
305
306 case OPT_SIGNPRIVATE:
307 signprivate_file = optarg;
308 break;
309
310 case OPT_VBLOCK:
311 vblock_file = optarg;
312 break;
313 }
314 }
315
316 if (parse_error)
317 return PrintHelp(progname);
318
319 switch(mode) {
320 case OPT_MODE_SIGN:
321 if (!keyblock_file || !signprivate_file || !vblock_file) {
322 fprintf(stderr, "Some required options are missing\n");
323 return PrintHelp(progname);
324 }
325 return Sign(filename, keyblock_file, signprivate_file, vblock_file);
326
327 case OPT_MODE_VERIFY:
328 if (!vblock_file) {
329 fprintf(stderr, "Some required options are missing\n");
330 return PrintHelp(progname);
331 }
332 return Verify(filename, vblock_file);
333
334 default:
335 fprintf(stderr,
336 "You must specify either --sign or --verify\n");
337 return PrintHelp(progname);
338 }
339
Bill Richardson83ba6d32010-08-11 13:23:35 -0700340 /* NOTREACHED */
Bill Richardson5aa673c2010-08-10 12:20:34 -0700341 return 1;
342}