OLD | NEW |
---|---|
(Empty) | |
1 /* 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 */ | |
27 static int opt_debug = 0; | |
28 | |
29 /* Command line options */ | |
30 enum { | |
31 OPT_MODE_SIGN = 1000, | |
32 OPT_MODE_VERIFY, | |
33 OPT_KEYBLOCK, | |
34 OPT_SIGNPRIVATE, | |
35 OPT_VBLOCK, | |
36 }; | |
37 | |
38 static 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 */ | |
50 static int PrintHelp(char *progname) { | |
adlr
2010/08/11 01:08:41
const char*?
Bill Richardson
2010/08/11 18:14:47
done
| |
51 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 | |
75 static 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. */ | |
89 static int Sign(const char* filename, const char* keyblock_file, | |
adlr
2010/08/11 01:08:41
i think our style says all args on one line or one
Bill Richardson
2010/08/11 18:14:47
Actually, no. It should just look nice.
| |
90 const char* signprivate_file, const char* outfile) { | |
91 uint8_t *file_data; | |
adlr
2010/08/11 01:08:41
put * w/ the type, not the variable
Bill Richardson
2010/08/11 18:14:47
Done
| |
92 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; | |
98 FILE* f; | |
adlr
2010/08/11 01:08:41
avoid 1-letter variables except for iterators (aga
| |
99 uint64_t i; | |
100 | |
101 /* Read the file that we're going to sign. */ | |
102 file_data = ReadFile(filename, &file_size); | |
103 if (!file_data) { | |
104 error("Error reading file to sign.\n"); | |
105 return 1; | |
106 } | |
107 | |
108 /* Get the key block and read the private key corresponding to it. */ | |
109 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); | |
110 if (!key_block) { | |
111 error("Error reading key block.\n"); | |
112 return 1; | |
113 } | |
114 signing_key = PrivateKeyRead(signprivate_file); | |
115 if (!signing_key) { | |
116 error("Error reading signing key.\n"); | |
117 return 1; | |
118 } | |
119 | |
120 /* Sign the file data */ | |
121 body_sig = CalculateSignature(file_data, file_size, signing_key); | |
122 if (!body_sig) { | |
123 error("Error calculating body signature\n"); | |
124 return 1; | |
125 } | |
126 | |
127 /* Create preamble */ | |
128 preamble = CreateKernelPreamble(0UL, 0UL, 0UL, 0UL, | |
adlr
2010/08/11 01:08:41
will you always compile this on 32 or 64-bit machi
Bill Richardson
2010/08/11 18:14:47
Ah. My bad. Thanks.
| |
129 body_sig, 0UL, signing_key); | |
130 if (!preamble) { | |
131 error("Error creating preamble.\n"); | |
132 return 1; | |
133 } | |
134 | |
135 /* Write the output file */ | |
136 Debug("writing %s...\n", outfile); | |
137 f = fopen(outfile, "wb"); | |
138 if (!f) { | |
139 error("Can't open output file %s\n", outfile); | |
140 return 1; | |
141 } | |
142 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); | |
143 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); | |
144 i = ((1 != fwrite(key_block, key_block_size, 1, f)) || | |
145 (1 != fwrite(preamble, preamble->preamble_size, 1, f))); | |
146 if (i) { | |
147 error("Can't write output file %s\n", outfile); | |
148 fclose(f); | |
149 unlink(outfile); | |
150 return 1; | |
151 } | |
152 fclose(f); | |
153 | |
154 /* Done */ | |
155 Free(preamble); | |
156 Free(body_sig); | |
157 Free(signing_key); | |
158 Free(key_block); | |
159 Free(file_data); | |
160 | |
161 /* Success */ | |
162 return 0; | |
163 } | |
164 | |
165 static int Verify(const char* filename, const char* vblock_file) { | |
166 uint8_t *file_data; | |
adlr
2010/08/11 01:08:41
* by type
Bill Richardson
2010/08/11 18:14:47
Done.
| |
167 uint64_t file_size; | |
168 uint8_t *buf; | |
169 uint64_t buf_size; | |
170 VbKeyBlockHeader* key_block; | |
171 VbKernelPreambleHeader* preamble; | |
172 VbPublicKey* data_key; | |
173 RSAPublicKey* rsa; | |
174 uint64_t now = 0; | |
adlr
2010/08/11 01:08:41
i'm not sure what 'now' means. usually it's a time
Bill Richardson
2010/08/11 18:14:47
Clarified.
| |
175 | |
176 /* Read the file that we're going to verify. */ | |
177 file_data = ReadFile(filename, &file_size); | |
178 if (!file_data) { | |
179 error("Error reading file to sign.\n"); | |
180 return 1; | |
181 } | |
182 | |
183 /* Read the vblock that we're going to use on it */ | |
184 buf = ReadFile(vblock_file, &buf_size); | |
185 if (!buf) { | |
186 error("Error reading vblock_file.\n"); | |
187 return 1; | |
188 } | |
189 | |
190 /* Find the key block */ | |
191 key_block = (VbKeyBlockHeader*)buf; | |
192 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); | |
193 now += key_block->key_block_size; | |
194 if (now > buf_size) { | |
195 error("key_block_size advances past the end of the buffer\n"); | |
196 return 1; | |
197 } | |
198 | |
199 /* Find the preamble */ | |
200 preamble = (VbKernelPreambleHeader*)(buf + now); | |
201 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); | |
202 now += preamble->preamble_size; | |
203 if (now > buf_size ) { | |
204 error("preamble_size advances past the end of the buffer\n"); | |
205 return 1; | |
206 } | |
207 | |
208 Debug("Now is at 0x%" PRIx64 " bytes\n", now); | |
209 | |
210 /* Check the keyblock */ | |
211 if (0 != KeyBlockVerify(key_block, file_size, NULL)) { | |
212 error("Error verifying key block.\n"); | |
213 return 1; | |
214 } | |
215 | |
216 printf("Key block:\n"); | |
217 data_key = &key_block->data_key; | |
218 //HEY printf(" Signature: %s\n", sign_key ? "valid" : "ignored"); | |
adlr
2010/08/11 01:08:41
delete this line?
Bill Richardson
2010/08/11 18:14:47
Yes, thanks.
| |
219 printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size); | |
220 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, | |
221 (data_key->algorithm < kNumAlgorithms ? | |
222 algo_strings[data_key->algorithm] : "(invalid)")); | |
223 printf(" Data key version: %" PRIu64 "\n", data_key->key_version); | |
224 printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); | |
225 | |
226 | |
227 /* Verify preamble */ | |
228 rsa = PublicKeyToRSA(&key_block->data_key); | |
229 if (!rsa) { | |
230 error("Error parsing data key.\n"); | |
231 return 1; | |
232 } | |
233 if (0 != VerifyKernelPreamble( | |
234 preamble, file_size, rsa)) { | |
adlr
2010/08/11 01:08:41
seems like you can easily fit this on one line
Bill Richardson
2010/08/11 18:14:47
done
| |
235 error("Error verifying preamble.\n"); | |
236 return 1; | |
237 } | |
238 | |
239 printf("Preamble:\n"); | |
240 printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size); | |
241 printf(" Header version: %" PRIu32 ".%" PRIu32"\n", | |
242 preamble->header_version_major, preamble->header_version_minor); | |
243 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); | |
244 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); | |
245 printf(" Body size: 0x%" PRIx64 "\n", | |
246 preamble->body_signature.data_size); | |
247 printf(" Bootloader address: 0x%" PRIx64 "\n", | |
248 preamble->bootloader_address); | |
249 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); | |
250 | |
251 /* Verify body */ | |
252 if (0 != VerifyData(file_data, file_size, &preamble->body_signature, | |
adlr
2010/08/11 01:08:41
all args on 1 line or 1 arg per line
Bill Richardson
2010/08/11 18:14:47
done.
| |
253 rsa)) { | |
254 error("Error verifying kernel body.\n"); | |
255 return 1; | |
256 } | |
257 printf("Body verification succeeded.\n"); | |
258 | |
259 // HEY | |
adlr
2010/08/11 01:08:41
delete?
Bill Richardson
2010/08/11 18:14:47
Yes, thanks.
| |
260 return 0; | |
261 } | |
262 | |
263 | |
264 int main(int argc, char* argv[]) { | |
265 char* filename = NULL; | |
266 char* keyblock_file = NULL; | |
267 char* signprivate_file = NULL; | |
268 char* vblock_file = NULL; | |
269 int mode = 0; | |
270 int parse_error = 0; | |
271 int i; | |
adlr
2010/08/11 01:08:41
rename "option_index"?
Bill Richardson
2010/08/11 18:14:47
Done.
| |
272 | |
273 char *progname = strrchr(argv[0], '/'); | |
274 if (progname) | |
275 progname++; | |
276 else | |
277 progname = argv[0]; | |
278 | |
279 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && | |
280 !parse_error) { | |
281 switch (i) { | |
282 default: | |
283 case '?': | |
284 /* Unhandled option */ | |
285 parse_error = 1; | |
286 break; | |
287 | |
288 case 0: | |
289 /* silently handled option */ | |
290 break; | |
291 | |
292 case OPT_MODE_SIGN: | |
293 case OPT_MODE_VERIFY: | |
294 if (mode && (mode != i)) { | |
295 fprintf(stderr, "Only a single mode can be specified\n"); | |
296 parse_error = 1; | |
297 break; | |
298 } | |
299 mode = i; | |
300 filename = optarg; | |
301 break; | |
302 | |
303 case OPT_KEYBLOCK: | |
304 keyblock_file = optarg; | |
305 break; | |
306 | |
307 case OPT_SIGNPRIVATE: | |
308 signprivate_file = optarg; | |
309 break; | |
310 | |
311 case OPT_VBLOCK: | |
312 vblock_file = optarg; | |
313 break; | |
314 } | |
315 } | |
316 | |
317 if (parse_error) | |
318 return PrintHelp(progname); | |
319 | |
320 switch(mode) { | |
321 case OPT_MODE_SIGN: | |
322 if (!keyblock_file || !signprivate_file || !vblock_file) { | |
323 fprintf(stderr, "Some required options are missing\n"); | |
324 return PrintHelp(progname); | |
325 } | |
326 return Sign(filename, keyblock_file, signprivate_file, vblock_file); | |
327 | |
328 case OPT_MODE_VERIFY: | |
329 if (!vblock_file) { | |
330 fprintf(stderr, "Some required options are missing\n"); | |
331 return PrintHelp(progname); | |
332 } | |
333 return Verify(filename, vblock_file); | |
334 | |
335 default: | |
336 fprintf(stderr, | |
337 "You must specify either --sign or --verify\n"); | |
338 return PrintHelp(progname); | |
339 } | |
340 | |
341 return 1; | |
adlr
2010/08/11 01:08:41
// unreached?
Bill Richardson
2010/08/11 18:14:47
Yes, but I don't like relying on the compiler to d
| |
342 } | |
OLD | NEW |