Chromium Code Reviews| 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 |