Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: utility/dev_sign_file.c

Issue 3151005: Add dev_sign_file utility for developers to sign their install scripts. (Closed) Base URL: ssh://gitrw.chromium.org/vboot_reference.git
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« utility/Makefile ('K') | « utility/Makefile ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« utility/Makefile ('K') | « utility/Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698