diff options
-rw-r--r-- | futility/cmd_dev_sign_file.c | 633 | ||||
-rw-r--r-- | futility/cmd_dump_fmap.c | 775 | ||||
-rw-r--r-- | futility/cmd_dump_kernel_config.c | 129 | ||||
-rw-r--r-- | futility/cmd_gbb_utility.c | 1122 | ||||
-rw-r--r-- | futility/cmd_vbutil_firmware.c | 686 | ||||
-rw-r--r-- | futility/cmd_vbutil_kernel.c | 1675 | ||||
-rw-r--r-- | futility/cmd_vbutil_key.c | 407 | ||||
-rw-r--r-- | futility/cmd_vbutil_keyblock.c | 592 | ||||
-rw-r--r-- | futility/dump_kernel_config_lib.c | 195 | ||||
-rw-r--r-- | futility/futility.c | 336 | ||||
-rw-r--r-- | futility/futility.h | 8 | ||||
-rw-r--r-- | futility/kernel_blob.h | 85 |
12 files changed, 3372 insertions, 3271 deletions
diff --git a/futility/cmd_dev_sign_file.c b/futility/cmd_dev_sign_file.c index f377ff47..134339eb 100644 --- a/futility/cmd_dev_sign_file.c +++ b/futility/cmd_dev_sign_file.c @@ -7,7 +7,7 @@ #include <errno.h> #include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ +#include <inttypes.h> /* For PRIu64 */ #include <stdarg.h> #include <stddef.h> #include <stdio.h> @@ -23,336 +23,351 @@ #include "kernel_blob.h" #include "vboot_common.h" - /* Global opt */ static int opt_debug = 0; /* Command line options */ enum { - OPT_MODE_SIGN = 1000, - OPT_MODE_VERIFY, - OPT_KEYBLOCK, - OPT_SIGNPRIVATE, - OPT_VBLOCK, + OPT_MODE_SIGN = 1000, + OPT_MODE_VERIFY, + OPT_KEYBLOCK, + OPT_SIGNPRIVATE, + OPT_VBLOCK, }; static const struct option long_opts[] = { - {"sign", 1, 0, OPT_MODE_SIGN }, - {"verify", 1, 0, OPT_MODE_VERIFY }, - {"keyblock", 1, 0, OPT_KEYBLOCK }, - {"signprivate", 1, 0, OPT_SIGNPRIVATE }, - {"vblock", 1, 0, OPT_VBLOCK }, - {"debug", 0, &opt_debug, 1 }, - {NULL, 0, 0, 0} + {"sign", 1, 0, OPT_MODE_SIGN}, + {"verify", 1, 0, OPT_MODE_VERIFY}, + {"keyblock", 1, 0, OPT_KEYBLOCK}, + {"signprivate", 1, 0, OPT_SIGNPRIVATE}, + {"vblock", 1, 0, OPT_VBLOCK}, + {"debug", 0, &opt_debug, 1}, + {NULL, 0, 0, 0} }; - /* Print help and return error */ -static int PrintHelp(const char *progname) { - fprintf(stderr, - "This program is used to sign and verify developer-mode files\n"); - fprintf(stderr, - "\n" - "Usage: %s --sign <file> [PARAMETERS]\n" - "\n" - " Required parameters:\n" - " --keyblock <file> Key block in .keyblock format\n" - " --signprivate <file>" - " Private key to sign file data, in .vbprivk format\n" - " --vblock <file> Output signature in .vblock format\n" - "\n", - progname); - fprintf(stderr, - "OR\n\n" - "Usage: %s --verify <file> [PARAMETERS]\n" - "\n" - " Required parameters:\n" - " --vblock <file> Signature file in .vblock format\n" - "\n" - " Optional parameters:\n" - " --keyblock <file>" - " Extract .keyblock to file if verification succeeds\n" - "\n", - progname); - return 1; +static int PrintHelp(const char *progname) +{ + fprintf(stderr, + "This is used to sign and verify developer-mode files\n"); + fprintf(stderr, + "\n" + "Usage: %s --sign <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --signprivate <file>" + " Private key to sign file data, in .vbprivk format\n" + " --vblock <file>" + " Output signature in .vblock format\n" + "\n", progname); + fprintf(stderr, + "OR\n\n" + "Usage: %s --verify <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --vblock <file>" + " Signature file in .vblock format\n" + "\n" + " Optional parameters:\n" + " --keyblock <file>" + " Extract .keyblock to file if verification succeeds\n" + "\n", progname); + return 1; } -static void Debug(const char *format, ...) { - if (!opt_debug) - return; +static void Debug(const char *format, ...) +{ + if (!opt_debug) + return; - va_list ap; - va_start(ap, format); - fprintf(stderr, "DEBUG: "); - vfprintf(stderr, format, ap); - va_end(ap); + va_list ap; + va_start(ap, format); + fprintf(stderr, "DEBUG: "); + vfprintf(stderr, format, ap); + va_end(ap); } - /* Sign a file. We'll reuse the same structs used to sign kernels, to avoid having to declare yet another one for just this purpose. */ -static int Sign(const char* filename, const char* keyblock_file, - const char* signprivate_file, const char* outfile) { - uint8_t* file_data; - uint64_t file_size; - VbKeyBlockHeader* key_block; - uint64_t key_block_size; - VbPrivateKey* signing_key; - VbSignature* body_sig; - VbKernelPreambleHeader* preamble; - FILE* output_fp; - - /* Read the file that we're going to sign. */ - file_data = ReadFile(filename, &file_size); - if (!file_data) { - VbExError("Error reading file to sign.\n"); - return 1; - } - - /* Get the key block and read the private key corresponding to it. */ - key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); - if (!key_block) { - VbExError("Error reading key block.\n"); - return 1; - } - signing_key = PrivateKeyRead(signprivate_file); - if (!signing_key) { - VbExError("Error reading signing key.\n"); - return 1; - } - - /* Sign the file data */ - body_sig = CalculateSignature(file_data, file_size, signing_key); - if (!body_sig) { - VbExError("Error calculating body signature\n"); - return 1; - } - - /* Create preamble */ - preamble = CreateKernelPreamble((uint64_t)0, - (uint64_t)0, - (uint64_t)0, - (uint64_t)0, - body_sig, - (uint64_t)0, - signing_key); - if (!preamble) { - VbExError("Error creating preamble.\n"); - return 1; - } - - /* Write the output file */ - Debug("writing %s...\n", outfile); - output_fp = fopen(outfile, "wb"); - if (!output_fp) { - VbExError("Can't open output file %s\n", outfile); - return 1; - } - Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); - Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); - if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) || - (1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) { - VbExError("Can't write output file %s\n", outfile); - fclose(output_fp); - unlink(outfile); - return 1; - } - fclose(output_fp); - - /* Done */ - free(preamble); - free(body_sig); - free(signing_key); - free(key_block); - free(file_data); - - /* Success */ - return 0; +static int Sign(const char *filename, const char *keyblock_file, + const char *signprivate_file, const char *outfile) +{ + uint8_t *file_data; + uint64_t file_size; + VbKeyBlockHeader *key_block; + uint64_t key_block_size; + VbPrivateKey *signing_key; + VbSignature *body_sig; + VbKernelPreambleHeader *preamble; + FILE *output_fp; + + /* Read the file that we're going to sign. */ + file_data = ReadFile(filename, &file_size); + if (!file_data) { + VbExError("Error reading file to sign.\n"); + return 1; + } + + /* Get the key block and read the private key corresponding to it. */ + key_block = + (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size); + if (!key_block) { + VbExError("Error reading key block.\n"); + return 1; + } + signing_key = PrivateKeyRead(signprivate_file); + if (!signing_key) { + VbExError("Error reading signing key.\n"); + return 1; + } + + /* Sign the file data */ + body_sig = CalculateSignature(file_data, file_size, signing_key); + if (!body_sig) { + VbExError("Error calculating body signature\n"); + return 1; + } + + /* Create preamble */ + preamble = CreateKernelPreamble((uint64_t) 0, + (uint64_t) 0, + (uint64_t) 0, + (uint64_t) 0, + body_sig, (uint64_t) 0, signing_key); + if (!preamble) { + VbExError("Error creating preamble.\n"); + return 1; + } + + /* Write the output file */ + Debug("writing %s...\n", outfile); + output_fp = fopen(outfile, "wb"); + if (!output_fp) { + VbExError("Can't open output file %s\n", outfile); + return 1; + } + Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); + Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); + if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) || + (1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) { + VbExError("Can't write output file %s\n", outfile); + fclose(output_fp); + unlink(outfile); + return 1; + } + fclose(output_fp); + + /* Done */ + free(preamble); + free(body_sig); + free(signing_key); + free(key_block); + free(file_data); + + /* Success */ + return 0; } -static int Verify(const char* filename, const char* vblock_file, - const char* keyblock_file) { - uint8_t* file_data; - uint64_t file_size; - uint8_t* buf; - uint64_t buf_size; - VbKeyBlockHeader* key_block; - VbKernelPreambleHeader* preamble; - VbPublicKey* data_key; - RSAPublicKey* rsa; - uint64_t current_buf_offset = 0; - - /* Read the file that we're going to verify. */ - file_data = ReadFile(filename, &file_size); - if (!file_data) { - VbExError("Error reading file to sign.\n"); - return 1; - } - - /* Read the vblock that we're going to use on it */ - buf = ReadFile(vblock_file, &buf_size); - if (!buf) { - VbExError("Error reading vblock_file.\n"); - return 1; - } - - /* Find the key block */ - key_block = (VbKeyBlockHeader*)buf; - Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); - current_buf_offset += key_block->key_block_size; - if (current_buf_offset > buf_size) { - VbExError("key_block_size advances past the end of the buffer\n"); - return 1; - } - - /* Find the preamble */ - preamble = (VbKernelPreambleHeader*)(buf + current_buf_offset); - Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); - current_buf_offset += preamble->preamble_size; - if (current_buf_offset > buf_size ) { - VbExError("preamble_size advances past the end of the buffer\n"); - return 1; - } - - Debug("Current buf offset is at 0x%" PRIx64 " bytes\n", current_buf_offset); - - /* Check the key block (hash only) */ - if (0 != KeyBlockVerify(key_block, key_block->key_block_size, NULL, 1)) { - VbExError("Error verifying key block.\n"); - return 1; - } - - printf("Key block:\n"); - data_key = &key_block->data_key; - printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size); - printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, - (data_key->algorithm < kNumAlgorithms ? - algo_strings[data_key->algorithm] : "(invalid)")); - printf(" Data key version: %" PRIu64 "\n", data_key->key_version); - printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); - - - /* Verify preamble */ - rsa = PublicKeyToRSA(&key_block->data_key); - if (!rsa) { - VbExError("Error parsing data key.\n"); - return 1; - } - if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) { - VbExError("Error verifying preamble.\n"); - return 1; - } - - printf("Preamble:\n"); - printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size); - printf(" Header version: %" PRIu32 ".%" PRIu32"\n", - preamble->header_version_major, preamble->header_version_minor); - printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); - printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); - printf(" Body size: 0x%" PRIx64 "\n", - preamble->body_signature.data_size); - printf(" Bootloader address: 0x%" PRIx64 "\n", - preamble->bootloader_address); - printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); - - /* Verify body */ - if (0 != VerifyData(file_data, file_size, &preamble->body_signature, rsa)) { - VbExError("Error verifying kernel body.\n"); - return 1; - } - printf("Body verification succeeded.\n"); - - if (keyblock_file) { - if (0 != WriteFile(keyblock_file, key_block, key_block->key_block_size)) { - VbExError("Unable to export keyblock file\n"); - return 1; - } - printf("Key block exported to %s\n", keyblock_file); - } - - return 0; +static int Verify(const char *filename, const char *vblock_file, + const char *keyblock_file) +{ + uint8_t *file_data; + uint64_t file_size; + uint8_t *buf; + uint64_t buf_size; + VbKeyBlockHeader *key_block; + VbKernelPreambleHeader *preamble; + VbPublicKey *data_key; + RSAPublicKey *rsa; + uint64_t current_buf_offset = 0; + + /* Read the file that we're going to verify. */ + file_data = ReadFile(filename, &file_size); + if (!file_data) { + VbExError("Error reading file to sign.\n"); + return 1; + } + + /* Read the vblock that we're going to use on it */ + buf = ReadFile(vblock_file, &buf_size); + if (!buf) { + VbExError("Error reading vblock_file.\n"); + return 1; + } + + /* Find the key block */ + key_block = (VbKeyBlockHeader *) buf; + Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); + current_buf_offset += key_block->key_block_size; + if (current_buf_offset > buf_size) { + VbExError + ("key_block_size advances past the end of the buffer\n"); + return 1; + } + + /* Find the preamble */ + preamble = (VbKernelPreambleHeader *) (buf + current_buf_offset); + Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); + current_buf_offset += preamble->preamble_size; + if (current_buf_offset > buf_size) { + VbExError + ("preamble_size advances past the end of the buffer\n"); + return 1; + } + + Debug("Current buf offset is at 0x%" PRIx64 " bytes\n", + current_buf_offset); + + /* Check the key block (hash only) */ + if (0 != KeyBlockVerify(key_block, key_block->key_block_size, + NULL, 1)) { + VbExError("Error verifying key block.\n"); + return 1; + } + + printf("Key block:\n"); + data_key = &key_block->data_key; + printf(" Size: 0x%" PRIx64 "\n", + key_block->key_block_size); + printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, + (data_key->algorithm < + kNumAlgorithms ? algo_strings[data_key-> + algorithm] : "(invalid)")); + printf(" Data key version: %" PRIu64 "\n", data_key->key_version); + printf(" Flags: %" PRIu64 "\n", + key_block->key_block_flags); + + /* Verify preamble */ + rsa = PublicKeyToRSA(&key_block->data_key); + if (!rsa) { + VbExError("Error parsing data key.\n"); + return 1; + } + if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) { + VbExError("Error verifying preamble.\n"); + return 1; + } + + printf("Preamble:\n"); + printf(" Size: 0x%" PRIx64 "\n", + preamble->preamble_size); + printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", + preamble->header_version_major, preamble->header_version_minor); + printf(" Kernel version: %" PRIu64 "\n", + preamble->kernel_version); + printf(" Body load address: 0x%" PRIx64 "\n", + preamble->body_load_address); + printf(" Body size: 0x%" PRIx64 "\n", + preamble->body_signature.data_size); + printf(" Bootloader address: 0x%" PRIx64 "\n", + preamble->bootloader_address); + printf(" Bootloader size: 0x%" PRIx64 "\n", + preamble->bootloader_size); + + /* Verify body */ + if (0 != + VerifyData(file_data, file_size, &preamble->body_signature, rsa)) { + VbExError("Error verifying kernel body.\n"); + return 1; + } + printf("Body verification succeeded.\n"); + + if (keyblock_file) { + if (0 != + WriteFile(keyblock_file, key_block, + key_block->key_block_size)) { + VbExError("Unable to export keyblock file\n"); + return 1; + } + printf("Key block exported to %s\n", keyblock_file); + } + + return 0; } - -static int do_dev_sign_file(int argc, char* argv[]) { - char* filename = NULL; - char* keyblock_file = NULL; - char* signprivate_file = NULL; - char* vblock_file = NULL; - int mode = 0; - int parse_error = 0; - int option_index; - - char *progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - while ((option_index = getopt_long(argc, argv, ":", long_opts, NULL)) != -1 && - !parse_error) { - switch (option_index) { - default: - case '?': - /* Unhandled option */ - parse_error = 1; - break; - - case 0: - /* silently handled option */ - break; - - case OPT_MODE_SIGN: - case OPT_MODE_VERIFY: - if (mode && (mode != option_index)) { - fprintf(stderr, "Only a single mode can be specified\n"); - parse_error = 1; - break; - } - mode = option_index; - filename = optarg; - break; - - case OPT_KEYBLOCK: - keyblock_file = optarg; - break; - - case OPT_SIGNPRIVATE: - signprivate_file = optarg; - break; - - case OPT_VBLOCK: - vblock_file = optarg; - break; - } - } - - if (parse_error) - return PrintHelp(progname); - - switch(mode) { - case OPT_MODE_SIGN: - if (!keyblock_file || !signprivate_file || !vblock_file) { - fprintf(stderr, "Some required options are missing\n"); - return PrintHelp(progname); - } - return Sign(filename, keyblock_file, signprivate_file, vblock_file); - - case OPT_MODE_VERIFY: - if (!vblock_file) { - fprintf(stderr, "Some required options are missing\n"); - return PrintHelp(progname); - } - return Verify(filename, vblock_file, keyblock_file); - - default: - fprintf(stderr, - "You must specify either --sign or --verify\n"); - return PrintHelp(progname); - } - - /* NOTREACHED */ - return 1; +static int do_dev_sign_file(int argc, char *argv[]) +{ + char *filename = NULL; + char *keyblock_file = NULL; + char *signprivate_file = NULL; + char *vblock_file = NULL; + int mode = 0; + int parse_error = 0; + int option_index; + + char *progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + while ((option_index = + getopt_long(argc, argv, ":", long_opts, NULL)) != -1 + && !parse_error) { + switch (option_index) { + default: + case '?': + /* Unhandled option */ + parse_error = 1; + break; + + case 0: + /* silently handled option */ + break; + + case OPT_MODE_SIGN: + case OPT_MODE_VERIFY: + if (mode && (mode != option_index)) { + fprintf(stderr, + "Only one mode can be specified\n"); + parse_error = 1; + break; + } + mode = option_index; + filename = optarg; + break; + + case OPT_KEYBLOCK: + keyblock_file = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivate_file = optarg; + break; + + case OPT_VBLOCK: + vblock_file = optarg; + break; + } + } + + if (parse_error) + return PrintHelp(progname); + + switch (mode) { + case OPT_MODE_SIGN: + if (!keyblock_file || !signprivate_file || !vblock_file) { + fprintf(stderr, "Some required options are missing\n"); + return PrintHelp(progname); + } + return Sign(filename, keyblock_file, signprivate_file, + vblock_file); + + case OPT_MODE_VERIFY: + if (!vblock_file) { + fprintf(stderr, "Some required options are missing\n"); + return PrintHelp(progname); + } + return Verify(filename, vblock_file, keyblock_file); + + default: + fprintf(stderr, "You must specify either --sign or --verify\n"); + return PrintHelp(progname); + } + + /* NOTREACHED */ + return 1; } DECLARE_FUTIL_COMMAND(dev_sign_file, do_dev_sign_file, diff --git a/futility/cmd_dump_fmap.c b/futility/cmd_dump_fmap.c index bf9e7afd..14bedac6 100644 --- a/futility/cmd_dump_fmap.c +++ b/futility/cmd_dump_fmap.c @@ -29,452 +29,459 @@ static void *base_of_rom; static size_t size_of_rom; static int opt_gaps = 0; - /* Return 0 if successful */ static int dump_fmap(const void *ptr, int argc, char *argv[]) { - int i, retval = 0; - char buf[80]; // DWR: magic number - const FmapHeader *fmh = (const FmapHeader*)ptr; - const FmapAreaHeader *ah = (const FmapAreaHeader*)(ptr + sizeof(FmapHeader)); - - if (FMT_NORMAL == opt_format) { - snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature); - printf("fmap_signature %s\n", buf); - printf("fmap_version: %d.%d\n", - fmh->fmap_ver_major, fmh->fmap_ver_minor); - printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base); - printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, fmh->fmap_size); - snprintf(buf, FMAP_NAMELEN+1, "%s", fmh->fmap_name); - printf("fmap_name: %s\n", buf); - printf("fmap_nareas: %d\n", fmh->fmap_nareas); - } - - for (i = 0; i < fmh->fmap_nareas; i++, ah++) { - snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name); - - if (argc) { - int j, found=0; - for (j = 0; j < argc; j++) - if (!strcmp(argv[j], buf)) { - found = 1; - break; - } - if (!found) { - continue; - } - } - - switch (opt_format) { - case FMT_PRETTY: - printf("%s %d %d\n", buf, ah->area_offset, ah->area_size); - break; - case FMT_FLASHROM: - if (ah->area_size) - printf("0x%08x:0x%08x %s\n", ah->area_offset, - ah->area_offset + ah->area_size - 1, buf); - break; - default: - printf("area: %d\n", i+1); - printf("area_offset: 0x%08x\n", ah->area_offset); - printf("area_size: 0x%08x (%d)\n", ah->area_size, ah->area_size); - printf("area_name: %s\n", buf); - } - - if (opt_extract) { - char *s; - for (s = buf; *s; s++) - if (*s == ' ') - *s = '_'; - FILE *fp = fopen(buf,"wb"); - if (!fp) { - fprintf(stderr, "%s: can't open %s: %s\n", - progname, buf, strerror(errno)); - retval = 1; - } else if (!ah->area_size) { - fprintf(stderr, "%s: section %s has zero size\n", progname, buf); - } else if (ah->area_offset + ah->area_size > size_of_rom) { - fprintf(stderr, "%s: section %s is larger than the image\n", - progname, buf); - retval = 1; - } else if (1 != fwrite(base_of_rom + ah->area_offset, - ah->area_size, 1, fp)) { - fprintf(stderr, "%s: can't write %s: %s\n", - progname, buf, strerror(errno)); - retval = 1; - } else { - if (FMT_NORMAL == opt_format) - printf("saved as \"%s\"\n", buf); - } - fclose(fp); - } - } - - return retval; + int i, retval = 0; + char buf[80]; /* DWR: magic number */ + const FmapHeader *fmh = (const FmapHeader *)ptr; + const FmapAreaHeader *ah = + (const FmapAreaHeader *)(ptr + sizeof(FmapHeader)); + + if (FMT_NORMAL == opt_format) { + snprintf(buf, FMAP_SIGNATURE_SIZE + 1, "%s", + fmh->fmap_signature); + printf("fmap_signature %s\n", buf); + printf("fmap_version: %d.%d\n", + fmh->fmap_ver_major, fmh->fmap_ver_minor); + printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base); + printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, + fmh->fmap_size); + snprintf(buf, FMAP_NAMELEN + 1, "%s", fmh->fmap_name); + printf("fmap_name: %s\n", buf); + printf("fmap_nareas: %d\n", fmh->fmap_nareas); + } + + for (i = 0; i < fmh->fmap_nareas; i++, ah++) { + snprintf(buf, FMAP_NAMELEN + 1, "%s", ah->area_name); + + if (argc) { + int j, found = 0; + for (j = 0; j < argc; j++) + if (!strcmp(argv[j], buf)) { + found = 1; + break; + } + if (!found) { + continue; + } + } + + switch (opt_format) { + case FMT_PRETTY: + printf("%s %d %d\n", buf, ah->area_offset, + ah->area_size); + break; + case FMT_FLASHROM: + if (ah->area_size) + printf("0x%08x:0x%08x %s\n", ah->area_offset, + ah->area_offset + ah->area_size - 1, + buf); + break; + default: + printf("area: %d\n", i + 1); + printf("area_offset: 0x%08x\n", ah->area_offset); + printf("area_size: 0x%08x (%d)\n", ah->area_size, + ah->area_size); + printf("area_name: %s\n", buf); + } + + if (opt_extract) { + char *s; + for (s = buf; *s; s++) + if (*s == ' ') + *s = '_'; + FILE *fp = fopen(buf, "wb"); + if (!fp) { + fprintf(stderr, "%s: can't open %s: %s\n", + progname, buf, strerror(errno)); + retval = 1; + } else if (!ah->area_size) { + fprintf(stderr, + "%s: section %s has zero size\n", + progname, buf); + } else if (ah->area_offset + ah->area_size > + size_of_rom) { + fprintf(stderr, "%s: section %s is larger" + " than the image\n", progname, buf); + retval = 1; + } else if (1 != fwrite(base_of_rom + ah->area_offset, + ah->area_size, 1, fp)) { + fprintf(stderr, "%s: can't write %s: %s\n", + progname, buf, strerror(errno)); + retval = 1; + } else { + if (FMT_NORMAL == opt_format) + printf("saved as \"%s\"\n", buf); + } + fclose(fp); + } + } + + return retval; } - /****************************************************************************/ /* Stuff for human-readable form */ typedef struct dup_s { - char *name; - struct dup_s *next; + char *name; + struct dup_s *next; } dupe_t; typedef struct node_s { - char *name; - uint32_t start; - uint32_t size; - uint32_t end; - struct node_s *parent; - int num_children; - struct node_s **child; - dupe_t *alias; + char *name; + uint32_t start; + uint32_t size; + uint32_t end; + struct node_s *parent; + int num_children; + struct node_s **child; + dupe_t *alias; } node_t; static node_t *all_nodes; -static void sort_nodes(int num, node_t *ary[]) +static void sort_nodes(int num, node_t * ary[]) { - int i, j; - node_t *tmp; - - /* bubble-sort is quick enough with only a few entries */ - for (i = 0; i < num; i++) { - for (j = i + 1; j < num; j++) { - if (ary[j]->start > ary[i]->start) { - tmp = ary[i]; - ary[i] = ary[j]; - ary[j] = tmp; - } - } - } + int i, j; + node_t *tmp; + + /* bubble-sort is quick enough with only a few entries */ + for (i = 0; i < num; i++) { + for (j = i + 1; j < num; j++) { + if (ary[j]->start > ary[i]->start) { + tmp = ary[i]; + ary[i] = ary[j]; + ary[j] = tmp; + } + } + } } - static void line(int indent, char *name, - uint32_t start, uint32_t end, uint32_t size, char *append) + uint32_t start, uint32_t end, uint32_t size, char *append) { - int i; - for (i = 0; i < indent; i++) - printf(" "); - printf("%-25s %08x %08x %08x%s\n", name, start, end, size, - append ? append : ""); + int i; + for (i = 0; i < indent; i++) + printf(" "); + printf("%-25s %08x %08x %08x%s\n", name, start, end, size, + append ? append : ""); } static int gapcount; static void empty(int indent, uint32_t start, uint32_t end, char *name) { - char buf[80]; - if (opt_gaps) { - sprintf(buf, " // gap in %s", name); - line(indent + 1, "", start, end, end - start, buf); - } - gapcount++; + char buf[80]; + if (opt_gaps) { + sprintf(buf, " // gap in %s", name); + line(indent + 1, "", start, end, end - start, buf); + } + gapcount++; } -static void show(node_t *p, int indent, int show_first) +static void show(node_t * p, int indent, int show_first) { - int i; - dupe_t *alias; - if (show_first) { - line(indent, p->name, p->start, p->end, p->size, 0); - for (alias = p->alias; alias; alias = alias->next) - line(indent, alias->name, p->start, p->end, p->size, " // DUPLICATE"); - } - sort_nodes(p->num_children, p->child); - for (i = 0; i < p->num_children; i++) { - if (i == 0 && p->end != p->child[i]->end) - empty(indent, p->child[i]->end, p->end, p->name); - show(p->child[i], indent + show_first, 1); - if (i < p->num_children - 1 && p->child[i]->start != p->child[i+1]->end) - empty(indent, p->child[i+1]->end, p->child[i]->start, p->name); - if (i == p->num_children - 1 && p->child[i]->start != p->start) - empty(indent, p->start, p->child[i]->start, p->name); - } + int i; + dupe_t *alias; + if (show_first) { + line(indent, p->name, p->start, p->end, p->size, 0); + for (alias = p->alias; alias; alias = alias->next) + line(indent, alias->name, p->start, p->end, p->size, + " // DUPLICATE"); + } + sort_nodes(p->num_children, p->child); + for (i = 0; i < p->num_children; i++) { + if (i == 0 && p->end != p->child[i]->end) + empty(indent, p->child[i]->end, p->end, p->name); + show(p->child[i], indent + show_first, 1); + if (i < p->num_children - 1 + && p->child[i]->start != p->child[i + 1]->end) + empty(indent, p->child[i + 1]->end, p->child[i]->start, + p->name); + if (i == p->num_children - 1 && p->child[i]->start != p->start) + empty(indent, p->start, p->child[i]->start, p->name); + } } static int overlaps(int i, int j) { - node_t *a = all_nodes + i; - node_t *b = all_nodes + j; + node_t *a = all_nodes + i; + node_t *b = all_nodes + j; - return ((a->start < b->start) && (b->start < a->end) && - (b->start < a->end) && (a->end < b->end)); + return ((a->start < b->start) && (b->start < a->end) && + (b->start < a->end) && (a->end < b->end)); } static int encloses(int i, int j) { - node_t *a = all_nodes + i; - node_t *b = all_nodes + j; + node_t *a = all_nodes + i; + node_t *b = all_nodes + j; - return ((a->start <= b->start) && - (a->end >= b->end)); + return ((a->start <= b->start) && (a->end >= b->end)); } static int duplicates(int i, int j) { - node_t *a = all_nodes + i; - node_t *b = all_nodes + j; + node_t *a = all_nodes + i; + node_t *b = all_nodes + j; - return ((a->start == b->start) && - (a->end == b->end)); + return ((a->start == b->start) && (a->end == b->end)); } static void add_dupe(int i, int j, int numnodes) { - int k; - dupe_t *alias; - - alias = (dupe_t *)malloc(sizeof(dupe_t)); - alias->name = all_nodes[j].name; - alias->next = all_nodes[i].alias; - all_nodes[i].alias = alias; - for (k = j; k < numnodes; k++ ) - all_nodes[k] = all_nodes[k + 1]; + int k; + dupe_t *alias; + + alias = (dupe_t *) malloc(sizeof(dupe_t)); + alias->name = all_nodes[j].name; + alias->next = all_nodes[i].alias; + all_nodes[i].alias = alias; + for (k = j; k < numnodes; k++) + all_nodes[k] = all_nodes[k + 1]; } -static void add_child(node_t *p, int n) +static void add_child(node_t * p, int n) { - int i; - if (p->num_children && !p->child) { - p->child = (struct node_s **)calloc(p->num_children, sizeof(node_t *)); - if (!p->child) { - perror("calloc failed"); - exit(1); - } - } - for (i = 0; i < p->num_children; i++) - if (!p->child[i]) { - p->child[i] = all_nodes + n; - return; - } + int i; + if (p->num_children && !p->child) { + p->child = + (struct node_s **)calloc(p->num_children, sizeof(node_t *)); + if (!p->child) { + perror("calloc failed"); + exit(1); + } + } + for (i = 0; i < p->num_children; i++) + if (!p->child[i]) { + p->child[i] = all_nodes + n; + return; + } } static int human_fmap(void *p) { - FmapHeader *fmh; - FmapAreaHeader *ah; - int i, j, errorcnt=0; - int numnodes; - - fmh = (FmapHeader *)p; - ah = (FmapAreaHeader *)(fmh + 1); - - /* The challenge here is to generate a directed graph from the - * arbitrarily-ordered FMAP entries, and then to prune it until it's as - * simple (and deep) as possible. Overlapping regions are not allowed. - * Duplicate regions are okay, but may require special handling. */ - - /* Convert the FMAP info into our format. */ - numnodes = fmh->fmap_nareas; - - /* plus one for the all-enclosing "root" */ - all_nodes = (node_t *)calloc(numnodes+1, sizeof(node_t)); - if (!all_nodes) { - perror("calloc failed"); - exit(1); - } - for (i = 0; i < numnodes; i++) { - char buf[FMAP_NAMELEN+1]; - strncpy(buf, ah[i].area_name, FMAP_NAMELEN); - buf[FMAP_NAMELEN] = '\0'; - if (!(all_nodes[i].name = strdup(buf))) { - perror("strdup failed"); - exit(1); - } - all_nodes[i].start = ah[i].area_offset; - all_nodes[i].size = ah[i].area_size; - all_nodes[i].end = ah[i].area_offset + ah[i].area_size; - } - /* Now add the root node */ - all_nodes[numnodes].name = strdup("-entire flash-"); - all_nodes[numnodes].start = fmh->fmap_base; - all_nodes[numnodes].size = fmh->fmap_size; - all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size; - - - /* First, coalesce any duplicates */ - for (i = 0; i < numnodes; i++) { - for (j = i + 1; j < numnodes; j++) { - if (duplicates(i, j)) { - add_dupe(i, j, numnodes); - numnodes--; - } - } - } - - /* Each node should have at most one parent, which is the smallest enclosing - * node. Duplicate nodes "enclose" each other, but if there's already a - * relationship in one direction, we won't create another. */ - for (i = 0; i < numnodes; i++) { - /* Find the smallest parent, which might be the root node. */ - int k = numnodes; - for (j = 0; j < numnodes; j++) { /* full O(N^2), not triangular */ - if (i == j) - continue; - if (overlaps(i, j)) { - printf("ERROR: %s and %s overlap\n", - all_nodes[i].name, all_nodes[j].name); - printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name, - all_nodes[i].start, all_nodes[i].end); - printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name, - all_nodes[j].start, all_nodes[j].end); - if (opt_overlap < 2) { - printf("Use more -h args to ignore this error\n"); - errorcnt++; - } - continue; - } - if (encloses(j, i) && all_nodes[j].size < all_nodes[k].size) - k = j; - } - all_nodes[i].parent = all_nodes + k; - } - if (errorcnt) - return 1; - - /* Force those deadbeat parents to recognize their children */ - for (i = 0; i < numnodes; i++) /* how many */ - if (all_nodes[i].parent) - all_nodes[i].parent->num_children++; - for (i = 0; i < numnodes; i++) /* here they are */ - if (all_nodes[i].parent) - add_child(all_nodes[i].parent, i); - - /* Ready to go */ - printf("# name start end size\n"); - show(all_nodes + numnodes, 0, opt_gaps); - - if (gapcount && !opt_gaps) - printf("\nWARNING: unused regions found. Use -H to see them\n"); - - return 0; + FmapHeader *fmh; + FmapAreaHeader *ah; + int i, j, errorcnt = 0; + int numnodes; + + fmh = (FmapHeader *) p; + ah = (FmapAreaHeader *) (fmh + 1); + + /* The challenge here is to generate a directed graph from the + * arbitrarily-ordered FMAP entries, and then to prune it until it's as + * simple (and deep) as possible. Overlapping regions are not allowed. + * Duplicate regions are okay, but may require special handling. */ + + /* Convert the FMAP info into our format. */ + numnodes = fmh->fmap_nareas; + + /* plus one for the all-enclosing "root" */ + all_nodes = (node_t *) calloc(numnodes + 1, sizeof(node_t)); + if (!all_nodes) { + perror("calloc failed"); + exit(1); + } + for (i = 0; i < numnodes; i++) { + char buf[FMAP_NAMELEN + 1]; + strncpy(buf, ah[i].area_name, FMAP_NAMELEN); + buf[FMAP_NAMELEN] = '\0'; + if (!(all_nodes[i].name = strdup(buf))) { + perror("strdup failed"); + exit(1); + } + all_nodes[i].start = ah[i].area_offset; + all_nodes[i].size = ah[i].area_size; + all_nodes[i].end = ah[i].area_offset + ah[i].area_size; + } + /* Now add the root node */ + all_nodes[numnodes].name = strdup("-entire flash-"); + all_nodes[numnodes].start = fmh->fmap_base; + all_nodes[numnodes].size = fmh->fmap_size; + all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size; + + /* First, coalesce any duplicates */ + for (i = 0; i < numnodes; i++) { + for (j = i + 1; j < numnodes; j++) { + if (duplicates(i, j)) { + add_dupe(i, j, numnodes); + numnodes--; + } + } + } + + /* Each node should have at most one parent, which is the smallest + * enclosing node. Duplicate nodes "enclose" each other, but if there's + * already a relationship in one direction, we won't create another. + */ + for (i = 0; i < numnodes; i++) { + /* Find the smallest parent, which might be the root node. */ + int k = numnodes; + for (j = 0; j < numnodes; j++) { /* full O(N^2) comparison */ + if (i == j) + continue; + if (overlaps(i, j)) { + printf("ERROR: %s and %s overlap\n", + all_nodes[i].name, all_nodes[j].name); + printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name, + all_nodes[i].start, all_nodes[i].end); + printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name, + all_nodes[j].start, all_nodes[j].end); + if (opt_overlap < 2) { + printf("Use more -h args to ignore" + " this error\n"); + errorcnt++; + } + continue; + } + if (encloses(j, i) + && all_nodes[j].size < all_nodes[k].size) + k = j; + } + all_nodes[i].parent = all_nodes + k; + } + if (errorcnt) + return 1; + + /* Force those deadbeat parents to recognize their children */ + for (i = 0; i < numnodes; i++) /* how many */ + if (all_nodes[i].parent) + all_nodes[i].parent->num_children++; + for (i = 0; i < numnodes; i++) /* here they are */ + if (all_nodes[i].parent) + add_child(all_nodes[i].parent, i); + + /* Ready to go */ + printf("# name start end size\n"); + show(all_nodes + numnodes, 0, opt_gaps); + + if (gapcount && !opt_gaps) + printf("\nWARNING: unused regions found. Use -H to see them\n"); + + return 0; } /* End of human-reable stuff */ /****************************************************************************/ +static const char usage[] = + "\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n" + "Display (and extract with -x) the FMAP components from a BIOS image.\n" + "The -p option makes the output easier to parse by scripts.\n" + "The -f option emits the FMAP in the format used by flashrom.\n" + "\n" + "Specify one or more NAMEs to only print sections that exactly match.\n" + "\n" + "The -h option shows the whole FMAP in human-readable form.\n" + " Use -H to also display any gaps.\n" + "\n"; + static int do_dump_fmap(int argc, char *argv[]) { - int c; - int errorcnt = 0; - struct stat sb; - int fd; - const char *fmap; - int retval = 1; - - progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - opterr = 0; /* quiet, you */ - while ((c = getopt(argc, argv, ":xpfhH")) != -1) { - switch (c) { - case 'x': - opt_extract = 1; - break; - case 'p': - opt_format = FMT_PRETTY; - break; - case 'f': - opt_format = FMT_FLASHROM; - break; - case 'H': - opt_gaps = 1; - /* fallthrough */ - case 'h': - opt_format = FMT_HUMAN; - opt_overlap++; - break; - case '?': - fprintf(stderr, "%s: unrecognized switch: -%c\n", - progname, optopt); - errorcnt++; - break; - case ':': - fprintf(stderr, "%s: missing argument to -%c\n", - progname, optopt); - errorcnt++; - break; - default: - errorcnt++; - break; - } - } - - if (errorcnt || optind >= argc) { - fprintf(stderr, - "\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n" - "Display (and extract with -x) the FMAP components from a BIOS image.\n" - "The -p option makes the output easier to parse by scripts.\n" - "The -f option emits the FMAP in the format used by flashrom.\n" - "\n" - "Specify one or more NAMEs to only print sections that exactly match.\n" - "\n" - "The -h option shows the whole FMAP in human-readable form.\n" - " Use -H to also display any gaps.\n" - "\n", - progname); - return 1; - } - - if (0 != stat(argv[optind], &sb)) { - fprintf(stderr, "%s: can't stat %s: %s\n", - progname, - argv[optind], - strerror(errno)); - return 1; - } - - fd = open(argv[optind], O_RDONLY); - if (fd < 0) { - fprintf(stderr, "%s: can't open %s: %s\n", - progname, - argv[optind], - strerror(errno)); - return 1; - } - - base_of_rom = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - if (base_of_rom == (char*)-1) { - fprintf(stderr, "%s: can't mmap %s: %s\n", - progname, - argv[optind], - strerror(errno)); - close(fd); - return 1; - } - close(fd); /* done with this now */ - size_of_rom = sb.st_size; - - fmap = FmapFind((char*) base_of_rom, size_of_rom); - if (fmap) { - switch (opt_format) { - case FMT_HUMAN: - retval = human_fmap((void *)fmap); - break; - case FMT_NORMAL: - printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom)); - /* fallthrough */ - default: - retval = dump_fmap(fmap, argc-optind-1, argv+optind+1); - } - } - - if (0 != munmap(base_of_rom, sb.st_size)) { - fprintf(stderr, "%s: can't munmap %s: %s\n", - progname, - argv[optind], - strerror(errno)); - return 1; - } - - return retval; + int c; + int errorcnt = 0; + struct stat sb; + int fd; + const char *fmap; + int retval = 1; + + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + opterr = 0; /* quiet, you */ + while ((c = getopt(argc, argv, ":xpfhH")) != -1) { + switch (c) { + case 'x': + opt_extract = 1; + break; + case 'p': + opt_format = FMT_PRETTY; + break; + case 'f': + opt_format = FMT_FLASHROM; + break; + case 'H': + opt_gaps = 1; + /* fallthrough */ + case 'h': + opt_format = FMT_HUMAN; + opt_overlap++; + break; + case '?': + fprintf(stderr, "%s: unrecognized switch: -%c\n", + progname, optopt); + errorcnt++; + break; + case ':': + fprintf(stderr, "%s: missing argument to -%c\n", + progname, optopt); + errorcnt++; + break; + default: + errorcnt++; + break; + } + } + + if (errorcnt || optind >= argc) { + fprintf(stderr, usage, progname); + return 1; + } + + if (0 != stat(argv[optind], &sb)) { + fprintf(stderr, "%s: can't stat %s: %s\n", + progname, argv[optind], strerror(errno)); + return 1; + } + + fd = open(argv[optind], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: can't open %s: %s\n", + progname, argv[optind], strerror(errno)); + return 1; + } + + base_of_rom = + mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (base_of_rom == (char *)-1) { + fprintf(stderr, "%s: can't mmap %s: %s\n", + progname, argv[optind], strerror(errno)); + close(fd); + return 1; + } + close(fd); /* done with this now */ + size_of_rom = sb.st_size; + + fmap = FmapFind((char *)base_of_rom, size_of_rom); + if (fmap) { + switch (opt_format) { + case FMT_HUMAN: + retval = human_fmap((void *)fmap); + break; + case FMT_NORMAL: + printf("hit at 0x%08x\n", + (uint32_t) (fmap - (char *)base_of_rom)); + /* fallthrough */ + default: + retval = + dump_fmap(fmap, argc - optind - 1, + argv + optind + 1); + } + } + + if (0 != munmap(base_of_rom, sb.st_size)) { + fprintf(stderr, "%s: can't munmap %s: %s\n", + progname, argv[optind], strerror(errno)); + return 1; + } + + return retval; } DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap, - "Display FMAP contents from a firmware image"); + "Display FMAP contents from a firmware image"); diff --git a/futility/cmd_dump_kernel_config.c b/futility/cmd_dump_kernel_config.c index a6e987e2..1bf411b2 100644 --- a/futility/cmd_dump_kernel_config.c +++ b/futility/cmd_dump_kernel_config.c @@ -5,7 +5,6 @@ * Exports the kernel commandline from a given partition/image. */ - #include <getopt.h> #include <stdio.h> #include <sys/mman.h> @@ -15,78 +14,78 @@ #include "vboot_host.h" enum { - OPT_KLOADADDR = 1000, + OPT_KLOADADDR = 1000, }; static const struct option long_opts[] = { - { "kloadaddr", 1, NULL, OPT_KLOADADDR }, - { NULL, 0, NULL, 0 } + {"kloadaddr", 1, NULL, OPT_KLOADADDR}, + {NULL, 0, NULL, 0} }; /* Print help and return error */ -static int PrintHelp(void) { - puts("dump_kernel_config - Prints the kernel command line\n" - "\n" - "Usage: dump_kernel_config [--kloadaddr <ADDRESS>] " - "<image/blockdevice>\n" - "\n" - ""); - return 1; +static int PrintHelp(void) +{ + puts("dump_kernel_config - Prints the kernel command line\n" + "\n" + "Usage: dump_kernel_config [--kloadaddr <ADDRESS>] " + "<image/blockdevice>\n" "\n" ""); + return 1; } -static int do_dump_kernel_config(int argc, char* argv[]) { - char *infile = NULL; - char *config = NULL; - uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR; - int parse_error = 0; - char *e; - int i; - - while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && - !parse_error) { - switch (i) { - default: - case '?': - /* Unhandled option */ - parse_error = 1; - break; - - case 0: - /* silently handled option */ - break; - - case OPT_KLOADADDR: - kernel_body_load_address = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --kloadaddr\n"); - parse_error = 1; - } - break; - } - } - - if (optind >= argc) { - fprintf(stderr, "Expected argument after options\n"); - parse_error = 1; - } else - infile = argv[optind]; - - if (parse_error) - return PrintHelp(); - - if (!infile || !*infile) { - fprintf(stderr, "Must specify filename\n"); - return 1; - } - - config = FindKernelConfig(infile, kernel_body_load_address); - if (!config) - return 1; - - printf("%s", config); - - free(config); - return 0; +static int do_dump_kernel_config(int argc, char *argv[]) +{ + char *infile = NULL; + char *config = NULL; + uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR; + int parse_error = 0; + char *e; + int i; + + while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && + !parse_error) { + switch (i) { + default: + case '?': + /* Unhandled option */ + parse_error = 1; + break; + + case 0: + /* silently handled option */ + break; + + case OPT_KLOADADDR: + kernel_body_load_address = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --kloadaddr\n"); + parse_error = 1; + } + break; + } + } + + if (optind >= argc) { + fprintf(stderr, "Expected argument after options\n"); + parse_error = 1; + } else + infile = argv[optind]; + + if (parse_error) + return PrintHelp(); + + if (!infile || !*infile) { + fprintf(stderr, "Must specify filename\n"); + return 1; + } + + config = FindKernelConfig(infile, kernel_body_load_address); + if (!config) + return 1; + + printf("%s", config); + + free(config); + return 0; } DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config, diff --git a/futility/cmd_gbb_utility.c b/futility/cmd_gbb_utility.c index 966b7445..9810058d 100644 --- a/futility/cmd_gbb_utility.c +++ b/futility/cmd_gbb_utility.c @@ -18,593 +18,623 @@ #include "futility.h" #include "gbb_header.h" -static void help_and_quit(const char *prog) { - fprintf(stderr, "\n" - "Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n" - "\n" - "GET MODE:\n" - "-g, --get (default)\tGet (read) from bios_file, " - "with following options:\n" - " --hwid \tReport hardware id (default).\n" - " --flags \tReport header flags.\n" - " -k, --rootkey=FILE \tFile name to export Root Key.\n" - " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" - " -r --recoverykey=FILE\tFile name to export Recovery Key.\n" - "\n" - "SET MODE:\n" - "-s, --set \tSet (write) to bios_file, " - "with following options:\n" - " -o, --output=FILE \tNew file name for ouptput.\n" - " --hwid=HWID \tThe new hardware id to be changed.\n" - " --flags=FLAGS \tThe new (numeric) flags value.\n" - " -k, --rootkey=FILE \tFile name of new Root Key.\n" - " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" - " -r --recoverykey=FILE\tFile name of new Recovery Key.\n" - "\n" - "CREATE MODE:\n" - "-c, --create=hwid_size,rootkey_size,bmpfv_size,recoverykey_size\n" - " \tCreate a GBB blob by given size list.\n" - "SAMPLE:\n" - " %s -g bios.bin\n" - " %s --set --hwid='New Model' -k key.bin bios.bin newbios.bin\n" - " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n\n", - prog, prog, prog, prog); - exit(1); +static void help_and_quit(const char *prog) +{ + fprintf(stderr, "\n" + "Usage: %s [-g|-s|-c] [OPTIONS] bios_file [output_file]\n" + "\n" + "GET MODE:\n" + "-g, --get (default)\tGet (read) from bios_file, " + "with following options:\n" + " --hwid \tReport hardware id (default).\n" + " --flags \tReport header flags.\n" + " -k, --rootkey=FILE \tFile name to export Root Key.\n" + " -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n" + " -r --recoverykey=FILE\tFile name to export Recovery Key.\n" + "\n" + "SET MODE:\n" + "-s, --set \tSet (write) to bios_file, " + "with following options:\n" + " -o, --output=FILE \tNew file name for ouptput.\n" + " --hwid=HWID \tThe new hardware id to be changed.\n" + " --flags=FLAGS \tThe new (numeric) flags value.\n" + " -k, --rootkey=FILE \tFile name of new Root Key.\n" + " -b, --bmpfv=FILE \tFile name of new Bitmap FV.\n" + " -r --recoverykey=FILE\tFile name of new Recovery Key.\n" + "\n" + "CREATE MODE:\n" + "-c, --create=hwid_size,rootkey_size,bmpfv_size," + "recoverykey_size\n" + " \tCreate a GBB blob by given size list.\n" + "SAMPLE:\n" + " %s -g bios.bin\n" + " %s --set --hwid='New Model' -k key.bin" + " bios.bin newbios.bin\n" + " %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n\n", + prog, prog, prog, prog); + exit(1); } /* Command line options */ static const struct option long_opts[] = { - /* name hasarg *flag val */ - {"get", 0, NULL, 'g' }, - {"set", 0, NULL, 's' }, - {"create", 1, NULL, 'c' }, - {"output", 1, NULL, 'o' }, - {"rootkey", 1, NULL, 'k' }, - {"bmpfv", 1, NULL, 'b' }, - {"recoverykey", 1, NULL, 'R' }, - {"hwid", 2, NULL, 'i' }, - {"flags", 2, NULL, 'L' }, - { NULL, 0, NULL, 0 }, + /* name hasarg *flag val */ + {"get", 0, NULL, 'g'}, + {"set", 0, NULL, 's'}, + {"create", 1, NULL, 'c'}, + {"output", 1, NULL, 'o'}, + {"rootkey", 1, NULL, 'k'}, + {"bmpfv", 1, NULL, 'b'}, + {"recoverykey", 1, NULL, 'R'}, + {"hwid", 2, NULL, 'i'}, + {"flags", 2, NULL, 'L'}, + {NULL, 0, NULL, 0}, }; + static char *short_opts = ":gsc:o:k:b:R:r:h:i:L:f:"; static int errorcnt; -static int ValidGBB(GoogleBinaryBlockHeader *gbb, size_t maxlen) +static int ValidGBB(GoogleBinaryBlockHeader * gbb, size_t maxlen) { - uint32_t i; - char *s; - - if (gbb->major_version != GBB_MAJOR_VER) - goto bad; - if (gbb->header_size != GBB_HEADER_SIZE || gbb->header_size > maxlen) - goto bad; - if (gbb->hwid_offset < GBB_HEADER_SIZE) - goto bad; - if (gbb->hwid_offset + gbb->hwid_size > maxlen) - goto bad; - if (gbb->hwid_size) { - /* Make sure the HWID is null-terminated (assumes ASCII, not unicode). */ - s = (char *)((char *)gbb + gbb->hwid_offset); - for (i = 0; i < gbb->hwid_size; i++) - if (*s++ == '\0') - break; - if (i >= gbb->hwid_size) - goto bad; - } - if (gbb->rootkey_offset < GBB_HEADER_SIZE) - goto bad; - if (gbb->rootkey_offset + gbb->rootkey_size > maxlen) - goto bad; - if (gbb->bmpfv_offset < GBB_HEADER_SIZE) - goto bad; - if (gbb->bmpfv_offset + gbb->bmpfv_size > maxlen) - goto bad; - if (gbb->recovery_key_offset < GBB_HEADER_SIZE) - goto bad; - if (gbb->recovery_key_offset + gbb->recovery_key_size > maxlen) - goto bad; - - return 1; + uint32_t i; + char *s; + + if (gbb->major_version != GBB_MAJOR_VER) + goto bad; + if (gbb->header_size != GBB_HEADER_SIZE || gbb->header_size > maxlen) + goto bad; + if (gbb->hwid_offset < GBB_HEADER_SIZE) + goto bad; + if (gbb->hwid_offset + gbb->hwid_size > maxlen) + goto bad; + if (gbb->hwid_size) { + /* Make sure the HWID is null-terminated (ASCII, not unicode) */ + s = (char *)((char *)gbb + gbb->hwid_offset); + for (i = 0; i < gbb->hwid_size; i++) + if (*s++ == '\0') + break; + if (i >= gbb->hwid_size) + goto bad; + } + if (gbb->rootkey_offset < GBB_HEADER_SIZE) + goto bad; + if (gbb->rootkey_offset + gbb->rootkey_size > maxlen) + goto bad; + if (gbb->bmpfv_offset < GBB_HEADER_SIZE) + goto bad; + if (gbb->bmpfv_offset + gbb->bmpfv_size > maxlen) + goto bad; + if (gbb->recovery_key_offset < GBB_HEADER_SIZE) + goto bad; + if (gbb->recovery_key_offset + gbb->recovery_key_size > maxlen) + goto bad; + + return 1; bad: - errorcnt++; - return 0; + errorcnt++; + return 0; } #define GBB_SEARCH_STRIDE 4 -GoogleBinaryBlockHeader *FindGbbHeader(uint8_t *ptr, size_t size) +GoogleBinaryBlockHeader *FindGbbHeader(uint8_t * ptr, size_t size) { - size_t i; - GoogleBinaryBlockHeader *tmp, *gbb_header = NULL; - int count = 0; - - for (i = 0; - i <= size - GBB_SEARCH_STRIDE; - i += GBB_SEARCH_STRIDE) { - if (0 != memcmp(ptr + i, GBB_SIGNATURE, GBB_SIGNATURE_SIZE)) - continue; - - /* Found something. See if it's any good. */ - tmp = (GoogleBinaryBlockHeader *)(ptr + i); - if (ValidGBB(tmp, size - i)) - if (!count++) - gbb_header = tmp; - } - - switch (count) { - case 0: - errorcnt++; - return NULL; - case 1: - return gbb_header; - default: - fprintf(stderr, "ERROR: multiple GBB headers found\n"); - errorcnt++; - return NULL; - } + size_t i; + GoogleBinaryBlockHeader *tmp, *gbb_header = NULL; + int count = 0; + + for (i = 0; i <= size - GBB_SEARCH_STRIDE; i += GBB_SEARCH_STRIDE) { + if (0 != memcmp(ptr + i, GBB_SIGNATURE, GBB_SIGNATURE_SIZE)) + continue; + + /* Found something. See if it's any good. */ + tmp = (GoogleBinaryBlockHeader *) (ptr + i); + if (ValidGBB(tmp, size - i)) + if (!count++) + gbb_header = tmp; + } + + switch (count) { + case 0: + errorcnt++; + return NULL; + case 1: + return gbb_header; + default: + fprintf(stderr, "ERROR: multiple GBB headers found\n"); + errorcnt++; + return NULL; + } } -static uint8_t *create_gbb(const char *desc, off_t *sizeptr) +static uint8_t *create_gbb(const char *desc, off_t * sizeptr) { - char *str, *sizes, *param, *e = NULL; - size_t size = GBB_HEADER_SIZE; - int i = 0; - /* Danger Will Robinson! four entries ==> four paramater blocks */ - uint32_t val[] = {0, 0, 0, 0}; - uint8_t *buf; - GoogleBinaryBlockHeader *gbb; - - sizes = strdup(desc); - if (!sizes) { - errorcnt++; - fprintf(stderr, "ERROR: strdup() failed: %s\n", strerror(errno)); - return NULL; - } - - for (str = sizes; (param = strtok(str, ", ")) != NULL; str = NULL) { - val[i] = (uint32_t)strtoul(param, &e, 0); - if (e && *e) { - errorcnt++; - fprintf(stderr, "ERROR: invalid creation parameter: \"%s\"\n", param); - free(sizes); - return NULL; - } - size += val[i++]; - if (i > ARRAY_SIZE(val)) - break; - } - - buf = (uint8_t *)calloc(1, size); - if (!buf) { - errorcnt++; - fprintf(stderr, "ERROR: can't malloc %zu bytes: %s\n", - size, strerror(errno)); - free(sizes); - return NULL; - } else if (sizeptr) { - *sizeptr = size; - } - - gbb = (GoogleBinaryBlockHeader *)buf; - memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE); - gbb->major_version = GBB_MAJOR_VER; - gbb->minor_version = GBB_MINOR_VER; - gbb->header_size = GBB_HEADER_SIZE; - gbb->flags = 0; - - i = GBB_HEADER_SIZE; - gbb->hwid_offset = i; - gbb->hwid_size = val[0]; - i += val[0]; - - gbb->rootkey_offset = i; - gbb->rootkey_size = val[1]; - i += val[1]; - - gbb->bmpfv_offset = i; - gbb->bmpfv_size = val[2]; - i += val[2]; - - gbb->recovery_key_offset = i; - gbb->recovery_key_size = val[3]; - i += val[1]; - - free(sizes); - return buf; + char *str, *sizes, *param, *e = NULL; + size_t size = GBB_HEADER_SIZE; + int i = 0; + /* Danger Will Robinson! four entries ==> four paramater blocks */ + uint32_t val[] = { 0, 0, 0, 0 }; + uint8_t *buf; + GoogleBinaryBlockHeader *gbb; + + sizes = strdup(desc); + if (!sizes) { + errorcnt++; + fprintf(stderr, "ERROR: strdup() failed: %s\n", + strerror(errno)); + return NULL; + } + + for (str = sizes; (param = strtok(str, ", ")) != NULL; str = NULL) { + val[i] = (uint32_t) strtoul(param, &e, 0); + if (e && *e) { + errorcnt++; + fprintf(stderr, + "ERROR: invalid creation parameter: \"%s\"\n", + param); + free(sizes); + return NULL; + } + size += val[i++]; + if (i > ARRAY_SIZE(val)) + break; + } + + buf = (uint8_t *) calloc(1, size); + if (!buf) { + errorcnt++; + fprintf(stderr, "ERROR: can't malloc %zu bytes: %s\n", + size, strerror(errno)); + free(sizes); + return NULL; + } else if (sizeptr) { + *sizeptr = size; + } + + gbb = (GoogleBinaryBlockHeader *) buf; + memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE); + gbb->major_version = GBB_MAJOR_VER; + gbb->minor_version = GBB_MINOR_VER; + gbb->header_size = GBB_HEADER_SIZE; + gbb->flags = 0; + + i = GBB_HEADER_SIZE; + gbb->hwid_offset = i; + gbb->hwid_size = val[0]; + i += val[0]; + + gbb->rootkey_offset = i; + gbb->rootkey_size = val[1]; + i += val[1]; + + gbb->bmpfv_offset = i; + gbb->bmpfv_size = val[2]; + i += val[2]; + + gbb->recovery_key_offset = i; + gbb->recovery_key_size = val[3]; + i += val[1]; + + free(sizes); + return buf; } -uint8_t *read_entire_file(const char *filename, off_t *sizeptr) +uint8_t *read_entire_file(const char *filename, off_t * sizeptr) { - FILE *fp = NULL; - uint8_t *buf = NULL; - struct stat sb; - - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n", - filename, strerror(errno)); - goto fail; - } - - if (0 != fstat(fileno(fp), &sb)) { - fprintf(stderr, "ERROR: can't fstat %s: %s\n", - filename, strerror(errno)); - goto fail; - } - if (sizeptr) - *sizeptr = sb.st_size; - - buf = (uint8_t *)malloc(sb.st_size); - if (!buf) { - fprintf(stderr, "ERROR: can't malloc %" PRIi64 " bytes: %s\n", - sb.st_size, strerror(errno)); - goto fail; - } - - if (1 != fread(buf, sb.st_size, 1, fp)) { - fprintf(stderr, "ERROR: Unable to read from %s: %s\n", - filename, strerror(errno)); - goto fail; - } - - if (fp && 0 != fclose(fp)) { - fprintf(stderr, "ERROR: Unable to close %s: %s\n", - filename, strerror(errno)); - goto fail; - } - - return buf; + FILE *fp = NULL; + uint8_t *buf = NULL; + struct stat sb; + + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n", + filename, strerror(errno)); + goto fail; + } + + if (0 != fstat(fileno(fp), &sb)) { + fprintf(stderr, "ERROR: can't fstat %s: %s\n", + filename, strerror(errno)); + goto fail; + } + if (sizeptr) + *sizeptr = sb.st_size; + + buf = (uint8_t *) malloc(sb.st_size); + if (!buf) { + fprintf(stderr, "ERROR: can't malloc %" PRIi64 " bytes: %s\n", + sb.st_size, strerror(errno)); + goto fail; + } + + if (1 != fread(buf, sb.st_size, 1, fp)) { + fprintf(stderr, "ERROR: Unable to read from %s: %s\n", + filename, strerror(errno)); + goto fail; + } + + if (fp && 0 != fclose(fp)) { + fprintf(stderr, "ERROR: Unable to close %s: %s\n", + filename, strerror(errno)); + goto fail; + } + + return buf; fail: - errorcnt++; + errorcnt++; - if (buf) - free(buf); + if (buf) + free(buf); - if (fp && 0 != fclose(fp)) - fprintf(stderr, "ERROR: Unable to close %s: %s\n", - filename, strerror(errno)); - return NULL; + if (fp && 0 != fclose(fp)) + fprintf(stderr, "ERROR: Unable to close %s: %s\n", + filename, strerror(errno)); + return NULL; } static int write_to_file(const char *msg, const char *filename, - uint8_t *start, size_t size) + uint8_t * start, size_t size) { - FILE *fp; - int r = 0; - - fp = fopen(filename, "wb"); - if (!fp) { - fprintf(stderr, "ERROR: Unable to open %s for writing: %s\n", - filename, strerror(errno)); - errorcnt++; - return errno; - } - - /* Don't write zero bytes */ - if (size && 1 != fwrite(start, size, 1, fp)) { - fprintf(stderr, "ERROR: Unable to write to %s: %s\n", - filename, strerror(errno)); - errorcnt++; - r = errno; - } - - if (0 != fclose(fp)) { - fprintf(stderr, "ERROR: Unable to close %s: %s\n", - filename, strerror(errno)); - errorcnt++; - if (!r) - r = errno; - } - - if (!r && msg) - printf("%s %s\n", msg, filename); - - return r; + FILE *fp; + int r = 0; + + fp = fopen(filename, "wb"); + if (!fp) { + fprintf(stderr, "ERROR: Unable to open %s for writing: %s\n", + filename, strerror(errno)); + errorcnt++; + return errno; + } + + /* Don't write zero bytes */ + if (size && 1 != fwrite(start, size, 1, fp)) { + fprintf(stderr, "ERROR: Unable to write to %s: %s\n", + filename, strerror(errno)); + errorcnt++; + r = errno; + } + + if (0 != fclose(fp)) { + fprintf(stderr, "ERROR: Unable to close %s: %s\n", + filename, strerror(errno)); + errorcnt++; + if (!r) + r = errno; + } + + if (!r && msg) + printf("%s %s\n", msg, filename); + + return r; } static int read_from_file(const char *msg, const char *filename, - uint8_t *start, uint32_t size) + uint8_t * start, uint32_t size) { - FILE *fp; - struct stat sb; - size_t count; - int r = 0; - - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n", - filename, strerror(errno)); - errorcnt++; - return errno; - } - - if (0 != fstat(fileno(fp), &sb)) { - fprintf(stderr, "ERROR: can't fstat %s: %s\n", - filename, strerror(errno)); - errorcnt++; - r = errno; - goto done_close; - } - - if (sb.st_size > size) { - fprintf(stderr, "ERROR: file %s exceeds capacity (%" PRIu32 ")\n", - filename, size); - errorcnt++; - r = errno; - goto done_close; - } - - /* It's okay if we read less than size. That's just the max. */ - count = fread(start, 1, size, fp); - if (ferror(fp)) { - fprintf(stderr, "ERROR: Read %zu/%" PRIi64 " bytes from %s: %s\n", - count, sb.st_size, filename, strerror(errno)); - errorcnt++; - r = errno; - } + FILE *fp; + struct stat sb; + size_t count; + int r = 0; + + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: Unable to open %s for reading: %s\n", + filename, strerror(errno)); + errorcnt++; + return errno; + } + + if (0 != fstat(fileno(fp), &sb)) { + fprintf(stderr, "ERROR: can't fstat %s: %s\n", + filename, strerror(errno)); + errorcnt++; + r = errno; + goto done_close; + } + + if (sb.st_size > size) { + fprintf(stderr, + "ERROR: file %s exceeds capacity (%" PRIu32 ")\n", + filename, size); + errorcnt++; + r = errno; + goto done_close; + } + + /* It's okay if we read less than size. That's just the max. */ + count = fread(start, 1, size, fp); + if (ferror(fp)) { + fprintf(stderr, + "ERROR: Read %zu/%" PRIi64 " bytes from %s: %s\n", + count, sb.st_size, filename, strerror(errno)); + errorcnt++; + r = errno; + } done_close: - if (0 != fclose(fp)) { - fprintf(stderr, "ERROR: Unable to close %s: %s\n", - filename, strerror(errno)); - errorcnt++; - if (!r) - r = errno; - } - - if (!r && msg) - printf(" - import %s from %s: success\n", msg, filename); - - return r; + if (0 != fclose(fp)) { + fprintf(stderr, "ERROR: Unable to close %s: %s\n", + filename, strerror(errno)); + errorcnt++; + if (!r) + r = errno; + } + + if (!r && msg) + printf(" - import %s from %s: success\n", msg, filename); + + return r; } static int do_gbb_utility(int argc, char *argv[]) { - enum do_what_now {DO_GET, DO_SET, DO_CREATE} mode = DO_GET; - char *infile = NULL; - char *outfile = NULL; - char *opt_create = NULL; - char *opt_rootkey = NULL; - char *opt_bmpfv = NULL; - char *opt_recoverykey = NULL; - char *opt_hwid = NULL; - char *opt_flags = NULL; - int sel_hwid = 0; - int sel_flags = 0; - uint8_t *inbuf = NULL; - off_t filesize; - uint8_t *outbuf = NULL; - GoogleBinaryBlockHeader *gbb; - uint8_t *gbb_base; - int i; - - opterr = 0; /* quiet, you */ - while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) { - switch (i) { - case 'g': - mode = DO_GET; - break; - case 's': - mode = DO_SET; - break; - case 'c': - mode = DO_CREATE; - opt_create = optarg; - break; - case 'o': - outfile = optarg; - break; - case 'k': - opt_rootkey = optarg; - break; - case 'b': - opt_bmpfv = optarg; - break; - case 'R': case 'r': - opt_recoverykey = optarg; - break; - case 'i': case 'h': - /* --hwid is optional: might be null, which could be okay */ - opt_hwid = optarg; - sel_hwid = 1; - break; - case 'L': case 'f': - /* --flags is optional: might be null, which could be okay */ - opt_flags = optarg; - sel_flags = 1; - break; - case '?': - errorcnt++; - if (optopt) - fprintf(stderr, "ERROR: unrecognized option: -%c\n", optopt); - else if (argv[optind - 1] ) - fprintf(stderr, "ERROR: unrecognized option (possibly \"%s\")\n", - argv[optind - 1]); - else - fprintf(stderr, "ERROR: unrecognized option\n"); - break; - case ':': - errorcnt++; - if (argv[optind - 1]) - fprintf(stderr, "ERROR: missing argument to -%c (%s)\n", - optopt, argv[optind - 1]); - else - fprintf(stderr, "ERROR: missing argument to -%c\n", optopt); - break; - default: - errorcnt++; - fprintf(stderr, "ERROR: unexpected error while parsing options\n"); - } - } - - /* Problems? */ - if (errorcnt) - help_and_quit(argv[0]); - - /* Now try to do something */ - switch (mode) { - case DO_GET: - if (argc - optind < 1) { - fprintf(stderr, "\nERROR: missing input filename\n"); - help_and_quit(argv[0]); - } else { - infile = argv[optind++]; - } - - /* With no args, show the HWID */ - if (!opt_rootkey && !opt_bmpfv && !opt_recoverykey && !sel_flags) - sel_hwid = 1; - - inbuf = read_entire_file(infile, &filesize); - if (!inbuf) - break; - - gbb = FindGbbHeader(inbuf, filesize); - if (!gbb) { - fprintf(stderr, "ERROR: No GBB found in %s\n", infile); - break; - } - gbb_base = (uint8_t *)gbb; - - /* Get the stuff */ - if (sel_hwid) - printf("hardware_id: %s\n", - gbb->hwid_size ? (char *)(gbb_base + gbb->hwid_offset) : ""); - if (sel_flags) - printf("flags: 0x%08x\n", gbb->flags); - if (opt_rootkey) - write_to_file(" - exported root_key to file:", opt_rootkey, - gbb_base + gbb->rootkey_offset, - gbb->rootkey_size); - if (opt_bmpfv) - write_to_file(" - exported bmp_fv to file:", opt_bmpfv, - gbb_base + gbb->bmpfv_offset, - gbb->bmpfv_size); - if (opt_recoverykey) - write_to_file(" - exported recovery_key to file:", opt_recoverykey, - gbb_base + gbb->recovery_key_offset, - gbb->recovery_key_size); - break; - - case DO_SET: - if (argc - optind < 1) { - fprintf(stderr, "\nERROR: missing input filename\n"); - help_and_quit(argv[0]); - } - infile = argv[optind++]; - if (!outfile) - outfile = (argc - optind < 1) ? infile : argv[optind++]; - - if (sel_hwid && !opt_hwid) { - fprintf(stderr, "\nERROR: missing new HWID value\n"); - help_and_quit(argv[0]); - } - if (sel_flags && (!opt_flags || !*opt_flags)) { - fprintf(stderr, "\nERROR: missing new flags value\n"); - help_and_quit(argv[0]); - } - - /* With no args, we'll either copy it unchanged or do nothing */ - inbuf = read_entire_file(infile, &filesize); - if (!inbuf) - break; - - gbb = FindGbbHeader(inbuf, filesize); - if (!gbb) { - fprintf(stderr, "ERROR: No GBB found in %s\n", infile); - break; - } - gbb_base = (uint8_t *)gbb; - - outbuf = (uint8_t *)malloc(filesize); - if (!outbuf) { - errorcnt++; - fprintf(stderr, "ERROR: can't malloc %" PRIi64 " bytes: %s\n", - filesize, strerror(errno)); - break; - } - - /* Switch pointers to outbuf */ - memcpy(outbuf, inbuf, filesize); - gbb = FindGbbHeader(outbuf, filesize); - if (!gbb) { - fprintf(stderr, "INTERNAL ERROR: No GBB found in outbuf\n"); - exit(1); - } - gbb_base = (uint8_t *)gbb; - - if (opt_hwid) { - if (strlen(opt_hwid) + 1 > gbb->hwid_size) { - fprintf(stderr, - "ERROR: null-terminated HWID exceeds capacity (%d)\n", - gbb->hwid_size); - errorcnt++; - } else { - strcpy((char *)(gbb_base + gbb->hwid_offset), opt_hwid); - } - } - - if (opt_flags) { - char *e = NULL; - uint32_t val; - val = (uint32_t)strtoul(opt_flags, &e, 0); - if (e && *e) { - fprintf(stderr, "ERROR: invalid flags value: %s\n", opt_flags); - errorcnt++; - } else { - gbb->flags = val; - } - } - - if (opt_rootkey) - read_from_file("root_key", opt_rootkey, - gbb_base + gbb->rootkey_offset, - gbb->rootkey_size); - if (opt_bmpfv) - read_from_file("bmp_fv", opt_bmpfv, - gbb_base + gbb->bmpfv_offset, - gbb->bmpfv_size); - if (opt_recoverykey) - read_from_file("recovery_key", opt_recoverykey, - gbb_base + gbb->recovery_key_offset, - gbb->recovery_key_size); - - /* Write it out if there are no problems. */ - if (!errorcnt) - write_to_file("successfully saved new image to:", - outfile, outbuf, filesize); - - break; - - case DO_CREATE: - if (!outfile) { - if (argc - optind < 1) { - fprintf(stderr, "\nERROR: missing output filename\n"); - help_and_quit(argv[0]); + enum do_what_now { DO_GET, DO_SET, DO_CREATE } mode = DO_GET; + char *infile = NULL; + char *outfile = NULL; + char *opt_create = NULL; + char *opt_rootkey = NULL; + char *opt_bmpfv = NULL; + char *opt_recoverykey = NULL; + char *opt_hwid = NULL; + char *opt_flags = NULL; + int sel_hwid = 0; + int sel_flags = 0; + uint8_t *inbuf = NULL; + off_t filesize; + uint8_t *outbuf = NULL; + GoogleBinaryBlockHeader *gbb; + uint8_t *gbb_base; + int i; + + opterr = 0; /* quiet, you */ + while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) { + switch (i) { + case 'g': + mode = DO_GET; + break; + case 's': + mode = DO_SET; + break; + case 'c': + mode = DO_CREATE; + opt_create = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'k': + opt_rootkey = optarg; + break; + case 'b': + opt_bmpfv = optarg; + break; + case 'R': + case 'r': + opt_recoverykey = optarg; + break; + case 'i': + case 'h': + /* --hwid is optional: null might be okay */ + opt_hwid = optarg; + sel_hwid = 1; + break; + case 'L': + case 'f': + /* --flags is optional: null might be okay */ + opt_flags = optarg; + sel_flags = 1; + break; + case '?': + errorcnt++; + if (optopt) + fprintf(stderr, + "ERROR: unrecognized option: -%c\n", + optopt); + else if (argv[optind - 1]) + fprintf(stderr, + "ERROR: unrecognized option " + "(possibly \"%s\")\n", + argv[optind - 1]); + else + fprintf(stderr, "ERROR: unrecognized option\n"); + break; + case ':': + errorcnt++; + if (argv[optind - 1]) + fprintf(stderr, + "ERROR: missing argument to -%c (%s)\n", + optopt, argv[optind - 1]); + else + fprintf(stderr, + "ERROR: missing argument to -%c\n", + optopt); + break; + default: + errorcnt++; + fprintf(stderr, + "ERROR: error while parsing options\n"); + } } - outfile = argv[optind++]; - } - /* Parse the creation args */ - outbuf = create_gbb(opt_create, &filesize); - if (!outbuf) { - fprintf(stderr, - "\nERROR: unable to parse creation spec (%s)\n", opt_create); - help_and_quit(argv[0]); - } - if (!errorcnt) - write_to_file("successfully created new GBB to:", - outfile, outbuf, filesize); - break; - } - - - if (inbuf) - free(inbuf); - if (outbuf) - free(outbuf); - return !!errorcnt; + + /* Problems? */ + if (errorcnt) + help_and_quit(argv[0]); + + /* Now try to do something */ + switch (mode) { + case DO_GET: + if (argc - optind < 1) { + fprintf(stderr, "\nERROR: missing input filename\n"); + help_and_quit(argv[0]); + } else { + infile = argv[optind++]; + } + + /* With no args, show the HWID */ + if (!opt_rootkey && !opt_bmpfv && !opt_recoverykey + && !sel_flags) + sel_hwid = 1; + + inbuf = read_entire_file(infile, &filesize); + if (!inbuf) + break; + + gbb = FindGbbHeader(inbuf, filesize); + if (!gbb) { + fprintf(stderr, "ERROR: No GBB found in %s\n", infile); + break; + } + gbb_base = (uint8_t *) gbb; + + /* Get the stuff */ + if (sel_hwid) + printf("hardware_id: %s\n", + gbb->hwid_size ? (char *)(gbb_base + + gbb-> + hwid_offset) : ""); + if (sel_flags) + printf("flags: 0x%08x\n", gbb->flags); + if (opt_rootkey) + write_to_file(" - exported root_key to file:", + opt_rootkey, + gbb_base + gbb->rootkey_offset, + gbb->rootkey_size); + if (opt_bmpfv) + write_to_file(" - exported bmp_fv to file:", opt_bmpfv, + gbb_base + gbb->bmpfv_offset, + gbb->bmpfv_size); + if (opt_recoverykey) + write_to_file(" - exported recovery_key to file:", + opt_recoverykey, + gbb_base + gbb->recovery_key_offset, + gbb->recovery_key_size); + break; + + case DO_SET: + if (argc - optind < 1) { + fprintf(stderr, "\nERROR: missing input filename\n"); + help_and_quit(argv[0]); + } + infile = argv[optind++]; + if (!outfile) + outfile = (argc - optind < 1) ? infile : argv[optind++]; + + if (sel_hwid && !opt_hwid) { + fprintf(stderr, "\nERROR: missing new HWID value\n"); + help_and_quit(argv[0]); + } + if (sel_flags && (!opt_flags || !*opt_flags)) { + fprintf(stderr, "\nERROR: missing new flags value\n"); + help_and_quit(argv[0]); + } + + /* With no args, we'll either copy it unchanged or do nothing */ + inbuf = read_entire_file(infile, &filesize); + if (!inbuf) + break; + + gbb = FindGbbHeader(inbuf, filesize); + if (!gbb) { + fprintf(stderr, "ERROR: No GBB found in %s\n", infile); + break; + } + gbb_base = (uint8_t *) gbb; + + outbuf = (uint8_t *) malloc(filesize); + if (!outbuf) { + errorcnt++; + fprintf(stderr, + "ERROR: can't malloc %" PRIi64 " bytes: %s\n", + filesize, strerror(errno)); + break; + } + + /* Switch pointers to outbuf */ + memcpy(outbuf, inbuf, filesize); + gbb = FindGbbHeader(outbuf, filesize); + if (!gbb) { + fprintf(stderr, + "INTERNAL ERROR: No GBB found in outbuf\n"); + exit(1); + } + gbb_base = (uint8_t *) gbb; + + if (opt_hwid) { + if (strlen(opt_hwid) + 1 > gbb->hwid_size) { + fprintf(stderr, + "ERROR: null-terminated HWID" + " exceeds capacity (%d)\n", + gbb->hwid_size); + errorcnt++; + } else { + strcpy((char *)(gbb_base + gbb->hwid_offset), + opt_hwid); + } + } + + if (opt_flags) { + char *e = NULL; + uint32_t val; + val = (uint32_t) strtoul(opt_flags, &e, 0); + if (e && *e) { + fprintf(stderr, + "ERROR: invalid flags value: %s\n", + opt_flags); + errorcnt++; + } else { + gbb->flags = val; + } + } + + if (opt_rootkey) + read_from_file("root_key", opt_rootkey, + gbb_base + gbb->rootkey_offset, + gbb->rootkey_size); + if (opt_bmpfv) + read_from_file("bmp_fv", opt_bmpfv, + gbb_base + gbb->bmpfv_offset, + gbb->bmpfv_size); + if (opt_recoverykey) + read_from_file("recovery_key", opt_recoverykey, + gbb_base + gbb->recovery_key_offset, + gbb->recovery_key_size); + + /* Write it out if there are no problems. */ + if (!errorcnt) + write_to_file("successfully saved new image to:", + outfile, outbuf, filesize); + + break; + + case DO_CREATE: + if (!outfile) { + if (argc - optind < 1) { + fprintf(stderr, + "\nERROR: missing output filename\n"); + help_and_quit(argv[0]); + } + outfile = argv[optind++]; + } + /* Parse the creation args */ + outbuf = create_gbb(opt_create, &filesize); + if (!outbuf) { + fprintf(stderr, + "\nERROR: unable to parse creation spec (%s)\n", + opt_create); + help_and_quit(argv[0]); + } + if (!errorcnt) + write_to_file("successfully created new GBB to:", + outfile, outbuf, filesize); + break; + } + + if (inbuf) + free(inbuf); + if (outbuf) + free(outbuf); + return ! !errorcnt; } DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb_utility, diff --git a/futility/cmd_vbutil_firmware.c b/futility/cmd_vbutil_firmware.c index 7eea6c84..95cae28d 100644 --- a/futility/cmd_vbutil_firmware.c +++ b/futility/cmd_vbutil_firmware.c @@ -6,7 +6,7 @@ */ #include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ +#include <inttypes.h> /* For PRIu64 */ #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -19,358 +19,368 @@ #include "util_misc.h" #include "vboot_common.h" - /* Command line options */ enum { - OPT_MODE_VBLOCK = 1000, - OPT_MODE_VERIFY, - OPT_KEYBLOCK, - OPT_SIGNPUBKEY, - OPT_SIGNPRIVATE, - OPT_VERSION, - OPT_FV, - OPT_KERNELKEY, - OPT_FLAGS, + OPT_MODE_VBLOCK = 1000, + OPT_MODE_VERIFY, + OPT_KEYBLOCK, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_VERSION, + OPT_FV, + OPT_KERNELKEY, + OPT_FLAGS, }; static const struct option long_opts[] = { - {"vblock", 1, 0, OPT_MODE_VBLOCK }, - {"verify", 1, 0, OPT_MODE_VERIFY }, - {"keyblock", 1, 0, OPT_KEYBLOCK }, - {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, - {"signprivate", 1, 0, OPT_SIGNPRIVATE }, - {"version", 1, 0, OPT_VERSION }, - {"fv", 1, 0, OPT_FV }, - {"kernelkey", 1, 0, OPT_KERNELKEY }, - {"flags", 1, 0, OPT_FLAGS }, - {NULL, 0, 0, 0} + {"vblock", 1, 0, OPT_MODE_VBLOCK}, + {"verify", 1, 0, OPT_MODE_VERIFY}, + {"keyblock", 1, 0, OPT_KEYBLOCK}, + {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, + {"signprivate", 1, 0, OPT_SIGNPRIVATE}, + {"version", 1, 0, OPT_VERSION}, + {"fv", 1, 0, OPT_FV}, + {"kernelkey", 1, 0, OPT_KERNELKEY}, + {"flags", 1, 0, OPT_FLAGS}, + {NULL, 0, 0, 0} }; - /* Print help and return error */ -static int PrintHelp(void) { - - puts("vbutil_firmware - Verified boot key block utility\n" - "\n" - "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n" - "\n" - "For '--vblock <file>', required OPTIONS are:\n" - " --keyblock <file> Key block in .keyblock format\n" - " --signprivate <file> Signing private key in .vbprivk format\n" - " --version <number> Firmware version\n" - " --fv <file> Firmware volume to sign\n" - " --kernelkey <file> Kernel subkey in .vbpubk format\n" - "optional OPTIONS are:\n" - " --flags <number> Preamble flags (defaults to 0)\n" - "\n" - "For '--verify <file>', required OPTIONS are:\n" - " --signpubkey <file> Signing public key in .vbpubk format\n" - " --fv <file> Firmware volume to verify\n" - "\n" - "For '--verify <file>', optional OPTIONS are:\n" - " --kernelkey <file> Write the kernel subkey to this file\n" - ""); - return 1; +static int PrintHelp(void) +{ + + puts("vbutil_firmware - Verified boot key block utility\n" + "\n" + "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n" + "\n" + "For '--vblock <file>', required OPTIONS are:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --signprivate <file>" + " Signing private key in .vbprivk format\n" + " --version <number> Firmware version\n" + " --fv <file> Firmware volume to sign\n" + " --kernelkey <file> Kernel subkey in .vbpubk format\n" + "optional OPTIONS are:\n" + " --flags <number> Preamble flags (defaults to 0)\n" + "\n" + "For '--verify <file>', required OPTIONS are:\n" + " --signpubkey <file>" + " Signing public key in .vbpubk format\n" + " --fv <file> Firmware volume to verify\n" + "\n" + "For '--verify <file>', optional OPTIONS are:\n" + " --kernelkey <file>" + " Write the kernel subkey to this file\n" + ""); + return 1; } - /* Create a firmware .vblock */ -static int Vblock(const char* outfile, const char* keyblock_file, - const char* signprivate, uint64_t version, - const char* fv_file, const char* kernelkey_file, - uint32_t preamble_flags) { - - VbPrivateKey* signing_key; - VbPublicKey* kernel_subkey; - VbSignature* body_sig; - VbFirmwarePreambleHeader* preamble; - VbKeyBlockHeader* key_block; - uint64_t key_block_size; - uint8_t* fv_data; - uint64_t fv_size; - FILE* f; - uint64_t i; - - if (!outfile) { - VbExError("Must specify output filename\n"); - return 1; - } - if (!keyblock_file || !signprivate || !kernelkey_file) { - VbExError("Must specify all keys\n"); - return 1; - } - if (!fv_file) { - VbExError("Must specify firmware volume\n"); - return 1; - } - - /* Read the key block and keys */ - key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); - if (!key_block) { - VbExError("Error reading key block.\n"); - return 1; - } - - signing_key = PrivateKeyRead(signprivate); - if (!signing_key) { - VbExError("Error reading signing key.\n"); - return 1; - } - - kernel_subkey = PublicKeyRead(kernelkey_file); - if (!kernel_subkey) { - VbExError("Error reading kernel subkey.\n"); - return 1; - } - - /* Read and sign the firmware volume */ - fv_data = ReadFile(fv_file, &fv_size); - if (!fv_data) - return 1; - if (!fv_size) { - VbExError("Empty firmware volume file\n"); - return 1; - } - body_sig = CalculateSignature(fv_data, fv_size, signing_key); - if (!body_sig) { - VbExError("Error calculating body signature\n"); - return 1; - } - free(fv_data); - - /* Create preamble */ - preamble = CreateFirmwarePreamble(version, - kernel_subkey, - body_sig, - signing_key, - preamble_flags); - if (!preamble) { - VbExError("Error creating preamble.\n"); - return 1; - } - - /* Write the output file */ - f = fopen(outfile, "wb"); - if (!f) { - VbExError("Can't open output file %s\n", outfile); - return 1; - } - i = ((1 != fwrite(key_block, key_block_size, 1, f)) || - (1 != fwrite(preamble, preamble->preamble_size, 1, f))); - fclose(f); - if (i) { - VbExError("Can't write output file %s\n", outfile); - unlink(outfile); - return 1; - } - - /* Success */ - return 0; +static int Vblock(const char *outfile, const char *keyblock_file, + const char *signprivate, uint64_t version, + const char *fv_file, const char *kernelkey_file, + uint32_t preamble_flags) +{ + + VbPrivateKey *signing_key; + VbPublicKey *kernel_subkey; + VbSignature *body_sig; + VbFirmwarePreambleHeader *preamble; + VbKeyBlockHeader *key_block; + uint64_t key_block_size; + uint8_t *fv_data; + uint64_t fv_size; + FILE *f; + uint64_t i; + + if (!outfile) { + VbExError("Must specify output filename\n"); + return 1; + } + if (!keyblock_file || !signprivate || !kernelkey_file) { + VbExError("Must specify all keys\n"); + return 1; + } + if (!fv_file) { + VbExError("Must specify firmware volume\n"); + return 1; + } + + /* Read the key block and keys */ + key_block = + (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size); + if (!key_block) { + VbExError("Error reading key block.\n"); + return 1; + } + + signing_key = PrivateKeyRead(signprivate); + if (!signing_key) { + VbExError("Error reading signing key.\n"); + return 1; + } + + kernel_subkey = PublicKeyRead(kernelkey_file); + if (!kernel_subkey) { + VbExError("Error reading kernel subkey.\n"); + return 1; + } + + /* Read and sign the firmware volume */ + fv_data = ReadFile(fv_file, &fv_size); + if (!fv_data) + return 1; + if (!fv_size) { + VbExError("Empty firmware volume file\n"); + return 1; + } + body_sig = CalculateSignature(fv_data, fv_size, signing_key); + if (!body_sig) { + VbExError("Error calculating body signature\n"); + return 1; + } + free(fv_data); + + /* Create preamble */ + preamble = CreateFirmwarePreamble(version, + kernel_subkey, + body_sig, + signing_key, preamble_flags); + if (!preamble) { + VbExError("Error creating preamble.\n"); + return 1; + } + + /* Write the output file */ + f = fopen(outfile, "wb"); + if (!f) { + VbExError("Can't open output file %s\n", outfile); + return 1; + } + i = ((1 != fwrite(key_block, key_block_size, 1, f)) || + (1 != fwrite(preamble, preamble->preamble_size, 1, f))); + fclose(f); + if (i) { + VbExError("Can't write output file %s\n", outfile); + unlink(outfile); + return 1; + } + + /* Success */ + return 0; } -static int Verify(const char* infile, const char* signpubkey, - const char* fv_file, const char* kernelkey_file) { - - VbKeyBlockHeader* key_block; - VbFirmwarePreambleHeader* preamble; - VbPublicKey* data_key; - VbPublicKey* sign_key; - VbPublicKey* kernel_subkey; - RSAPublicKey* rsa; - uint8_t* blob; - uint64_t blob_size; - uint8_t* fv_data; - uint64_t fv_size; - uint64_t now = 0; - uint32_t flags; - - if (!infile || !signpubkey || !fv_file) { - VbExError("Must specify filename, signpubkey, and fv\n"); - return 1; - } - - /* Read public signing key */ - sign_key = PublicKeyRead(signpubkey); - if (!sign_key) { - VbExError("Error reading signpubkey.\n"); - return 1; - } - - /* Read blob */ - blob = ReadFile(infile, &blob_size); - if (!blob) { - VbExError("Error reading input file\n"); - return 1; - } - - /* Read firmware volume */ - fv_data = ReadFile(fv_file, &fv_size); - if (!fv_data) { - VbExError("Error reading firmware volume\n"); - return 1; - } - - /* Verify key block */ - key_block = (VbKeyBlockHeader*)blob; - if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) { - VbExError("Error verifying key block.\n"); - return 1; - } - free(sign_key); - now += key_block->key_block_size; - - printf("Key block:\n"); - data_key = &key_block->data_key; - printf(" Size: %" PRIu64 "\n", key_block->key_block_size); - printf(" Flags: %" PRIu64 " (ignored)\n", - key_block->key_block_flags); - printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, - (data_key->algorithm < kNumAlgorithms ? - algo_strings[data_key->algorithm] : "(invalid)")); - printf(" Data key version: %" PRIu64 "\n", data_key->key_version); - printf(" Data key sha1sum: "); - PrintPubKeySha1Sum(data_key); - printf("\n"); - - rsa = PublicKeyToRSA(&key_block->data_key); - if (!rsa) { - VbExError("Error parsing data key.\n"); - return 1; - } - - /* Verify preamble */ - preamble = (VbFirmwarePreambleHeader*)(blob + now); - if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) { - VbExError("Error verifying preamble.\n"); - return 1; - } - now += preamble->preamble_size; - - flags = VbGetFirmwarePreambleFlags(preamble); - printf("Preamble:\n"); - printf(" Size: %" PRIu64 "\n", preamble->preamble_size); - printf(" Header version: %" PRIu32 ".%" PRIu32"\n", - preamble->header_version_major, preamble->header_version_minor); - printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version); - kernel_subkey = &preamble->kernel_subkey; - printf(" Kernel key algorithm: %" PRIu64 " %s\n", - kernel_subkey->algorithm, - (kernel_subkey->algorithm < kNumAlgorithms ? - algo_strings[kernel_subkey->algorithm] : "(invalid)")); - printf(" Kernel key version: %" PRIu64 "\n", - kernel_subkey->key_version); - printf(" Kernel key sha1sum: "); - PrintPubKeySha1Sum(kernel_subkey); - printf("\n"); - printf(" Firmware body size: %" PRIu64 "\n", - preamble->body_signature.data_size); - printf(" Preamble flags: %" PRIu32 "\n", flags); - - /* TODO: verify body size same as signature size */ - - /* Verify body */ - if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { - printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n"); - } else { - if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) { - VbExError("Error verifying firmware body.\n"); - return 1; - } - printf("Body verification succeeded.\n"); - } - - if (kernelkey_file) { - if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) { - fprintf(stderr, - "vbutil_firmware: unable to write kernel subkey\n"); - return 1; - } - } - - return 0; +static int Verify(const char *infile, const char *signpubkey, + const char *fv_file, const char *kernelkey_file) +{ + + VbKeyBlockHeader *key_block; + VbFirmwarePreambleHeader *preamble; + VbPublicKey *data_key; + VbPublicKey *sign_key; + VbPublicKey *kernel_subkey; + RSAPublicKey *rsa; + uint8_t *blob; + uint64_t blob_size; + uint8_t *fv_data; + uint64_t fv_size; + uint64_t now = 0; + uint32_t flags; + + if (!infile || !signpubkey || !fv_file) { + VbExError("Must specify filename, signpubkey, and fv\n"); + return 1; + } + + /* Read public signing key */ + sign_key = PublicKeyRead(signpubkey); + if (!sign_key) { + VbExError("Error reading signpubkey.\n"); + return 1; + } + + /* Read blob */ + blob = ReadFile(infile, &blob_size); + if (!blob) { + VbExError("Error reading input file\n"); + return 1; + } + + /* Read firmware volume */ + fv_data = ReadFile(fv_file, &fv_size); + if (!fv_data) { + VbExError("Error reading firmware volume\n"); + return 1; + } + + /* Verify key block */ + key_block = (VbKeyBlockHeader *) blob; + if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) { + VbExError("Error verifying key block.\n"); + return 1; + } + free(sign_key); + now += key_block->key_block_size; + + printf("Key block:\n"); + data_key = &key_block->data_key; + printf(" Size: %" PRIu64 "\n", + key_block->key_block_size); + printf(" Flags: %" PRIu64 " (ignored)\n", + key_block->key_block_flags); + printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, + (data_key->algorithm < + kNumAlgorithms ? algo_strings[data_key-> + algorithm] : "(invalid)")); + printf(" Data key version: %" PRIu64 "\n", data_key->key_version); + printf(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + rsa = PublicKeyToRSA(&key_block->data_key); + if (!rsa) { + VbExError("Error parsing data key.\n"); + return 1; + } + + /* Verify preamble */ + preamble = (VbFirmwarePreambleHeader *) (blob + now); + if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) { + VbExError("Error verifying preamble.\n"); + return 1; + } + now += preamble->preamble_size; + + flags = VbGetFirmwarePreambleFlags(preamble); + printf("Preamble:\n"); + printf(" Size: %" PRIu64 "\n", + preamble->preamble_size); + printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", + preamble->header_version_major, preamble->header_version_minor); + printf(" Firmware version: %" PRIu64 "\n", + preamble->firmware_version); + kernel_subkey = &preamble->kernel_subkey; + printf(" Kernel key algorithm: %" PRIu64 " %s\n", + kernel_subkey->algorithm, + (kernel_subkey->algorithm < kNumAlgorithms ? + algo_strings[kernel_subkey->algorithm] : "(invalid)")); + printf(" Kernel key version: %" PRIu64 "\n", + kernel_subkey->key_version); + printf(" Kernel key sha1sum: "); + PrintPubKeySha1Sum(kernel_subkey); + printf("\n"); + printf(" Firmware body size: %" PRIu64 "\n", + preamble->body_signature.data_size); + printf(" Preamble flags: %" PRIu32 "\n", flags); + + /* TODO: verify body size same as signature size */ + + /* Verify body */ + if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { + printf + ("Preamble requests USE_RO_NORMAL;" + " skipping body verification.\n"); + } else { + if (0 != + VerifyData(fv_data, fv_size, &preamble->body_signature, + rsa)) { + VbExError("Error verifying firmware body.\n"); + return 1; + } + printf("Body verification succeeded.\n"); + } + + if (kernelkey_file) { + if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) { + VbExError("Unable to write kernel subkey\n"); + return 1; + } + } + + return 0; } - -static int do_vbutil_firmware(int argc, char* argv[]) { - - char* filename = NULL; - char* key_block_file = NULL; - char* signpubkey = NULL; - char* signprivate = NULL; - uint64_t version = 0; - char* fv_file = NULL; - char* kernelkey_file = NULL; - uint32_t preamble_flags = 0; - int mode = 0; - int parse_error = 0; - char* e; - int i; - - while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { - switch (i) { - case '?': - /* Unhandled option */ - printf("Unknown option\n"); - parse_error = 1; - break; - - case OPT_MODE_VBLOCK: - case OPT_MODE_VERIFY: - mode = i; - filename = optarg; - break; - - case OPT_KEYBLOCK: - key_block_file = optarg; - break; - - case OPT_SIGNPUBKEY: - signpubkey = optarg; - break; - - case OPT_SIGNPRIVATE: - signprivate = optarg; - break; - - case OPT_FV: - fv_file = optarg; - break; - - case OPT_KERNELKEY: - kernelkey_file = optarg; - break; - - case OPT_VERSION: - version = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - printf("Invalid --version\n"); - parse_error = 1; - } - break; - - case OPT_FLAGS: - preamble_flags = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - printf("Invalid --flags\n"); - parse_error = 1; - } - break; - } - } - - if (parse_error) - return PrintHelp(); - - switch(mode) { - case OPT_MODE_VBLOCK: - return Vblock(filename, key_block_file, signprivate, version, fv_file, - kernelkey_file, preamble_flags); - case OPT_MODE_VERIFY: - return Verify(filename, signpubkey, fv_file, kernelkey_file); - default: - printf("Must specify a mode.\n"); - return PrintHelp(); - } +static int do_vbutil_firmware(int argc, char *argv[]) +{ + + char *filename = NULL; + char *key_block_file = NULL; + char *signpubkey = NULL; + char *signprivate = NULL; + uint64_t version = 0; + char *fv_file = NULL; + char *kernelkey_file = NULL; + uint32_t preamble_flags = 0; + int mode = 0; + int parse_error = 0; + char *e; + int i; + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + case '?': + /* Unhandled option */ + printf("Unknown option\n"); + parse_error = 1; + break; + + case OPT_MODE_VBLOCK: + case OPT_MODE_VERIFY: + mode = i; + filename = optarg; + break; + + case OPT_KEYBLOCK: + key_block_file = optarg; + break; + + case OPT_SIGNPUBKEY: + signpubkey = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivate = optarg; + break; + + case OPT_FV: + fv_file = optarg; + break; + + case OPT_KERNELKEY: + kernelkey_file = optarg; + break; + + case OPT_VERSION: + version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + printf("Invalid --version\n"); + parse_error = 1; + } + break; + + case OPT_FLAGS: + preamble_flags = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + printf("Invalid --flags\n"); + parse_error = 1; + } + break; + } + } + + if (parse_error) + return PrintHelp(); + + switch (mode) { + case OPT_MODE_VBLOCK: + return Vblock(filename, key_block_file, signprivate, version, + fv_file, kernelkey_file, preamble_flags); + case OPT_MODE_VERIFY: + return Verify(filename, signpubkey, fv_file, kernelkey_file); + default: + printf("Must specify a mode.\n"); + return PrintHelp(); + } } DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c index 420e3b57..ebb4510e 100644 --- a/futility/cmd_vbutil_kernel.c +++ b/futility/cmd_vbutil_kernel.c @@ -8,9 +8,9 @@ #include <errno.h> #include <fcntl.h> #include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ +#include <inttypes.h> /* For PRIu64 */ #include <sys/ioctl.h> -#include <linux/fs.h> /* For BLKGETSIZE64 */ +#include <linux/fs.h> /* For BLKGETSIZE64 */ #include <stdarg.h> #include <stddef.h> #include <stdio.h> @@ -33,181 +33,183 @@ static int opt_verbose = 0; static int opt_vblockonly = 0; static uint64_t opt_pad = 65536; - /* Command line options */ enum { - OPT_MODE_PACK = 1000, - OPT_MODE_REPACK, - OPT_MODE_VERIFY, - OPT_ARCH, - OPT_OLDBLOB, - OPT_KLOADADDR, - OPT_KEYBLOCK, - OPT_SIGNPUBKEY, - OPT_SIGNPRIVATE, - OPT_VERSION, - OPT_VMLINUZ, - OPT_BOOTLOADER, - OPT_CONFIG, - OPT_VBLOCKONLY, - OPT_PAD, - OPT_VERBOSE, - OPT_MINVERSION, + OPT_MODE_PACK = 1000, + OPT_MODE_REPACK, + OPT_MODE_VERIFY, + OPT_ARCH, + OPT_OLDBLOB, + OPT_KLOADADDR, + OPT_KEYBLOCK, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_VERSION, + OPT_VMLINUZ, + OPT_BOOTLOADER, + OPT_CONFIG, + OPT_VBLOCKONLY, + OPT_PAD, + OPT_VERBOSE, + OPT_MINVERSION, }; typedef enum { - ARCH_ARM, - ARCH_X86, /* default */ - ARCH_MIPS + ARCH_ARM, + ARCH_X86, /* default */ + ARCH_MIPS } arch_t; static const struct option long_opts[] = { - {"pack", 1, 0, OPT_MODE_PACK }, - {"repack", 1, 0, OPT_MODE_REPACK }, - {"verify", 1, 0, OPT_MODE_VERIFY }, - {"arch", 1, 0, OPT_ARCH }, - {"oldblob", 1, 0, OPT_OLDBLOB }, - {"kloadaddr", 1, 0, OPT_KLOADADDR }, - {"keyblock", 1, 0, OPT_KEYBLOCK }, - {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, - {"signprivate", 1, 0, OPT_SIGNPRIVATE }, - {"version", 1, 0, OPT_VERSION }, - {"minversion", 1, 0, OPT_MINVERSION }, - {"vmlinuz", 1, 0, OPT_VMLINUZ }, - {"bootloader", 1, 0, OPT_BOOTLOADER }, - {"config", 1, 0, OPT_CONFIG }, - {"vblockonly", 0, 0, OPT_VBLOCKONLY }, - {"pad", 1, 0, OPT_PAD }, - {"verbose", 0, &opt_verbose, 1 }, - {"debug", 0, &opt_debug, 1 }, - {NULL, 0, 0, 0} + {"pack", 1, 0, OPT_MODE_PACK}, + {"repack", 1, 0, OPT_MODE_REPACK}, + {"verify", 1, 0, OPT_MODE_VERIFY}, + {"arch", 1, 0, OPT_ARCH}, + {"oldblob", 1, 0, OPT_OLDBLOB}, + {"kloadaddr", 1, 0, OPT_KLOADADDR}, + {"keyblock", 1, 0, OPT_KEYBLOCK}, + {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, + {"signprivate", 1, 0, OPT_SIGNPRIVATE}, + {"version", 1, 0, OPT_VERSION}, + {"minversion", 1, 0, OPT_MINVERSION}, + {"vmlinuz", 1, 0, OPT_VMLINUZ}, + {"bootloader", 1, 0, OPT_BOOTLOADER}, + {"config", 1, 0, OPT_CONFIG}, + {"vblockonly", 0, 0, OPT_VBLOCKONLY}, + {"pad", 1, 0, OPT_PAD}, + {"verbose", 0, &opt_verbose, 1}, + {"debug", 0, &opt_debug, 1}, + {NULL, 0, 0, 0} }; + +static const char usage[] = + "This program creates, signs, and verifies the kernel blob\n" + "\n" + "Usage: %s --pack <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --signprivate <file> Private key to sign kernel data,\n" + " in .vbprivk format\n" + " --version <number> Kernel version\n" + " --vmlinuz <file> Linux kernel bzImage file\n" + " --bootloader <file> Bootloader stub\n" + " --config <file> Command line file\n" + " --arch <arch> Cpu architecture (default x86)\n" + "\n" + " Optional:\n" + " --kloadaddr <address> Assign kernel body load address\n" + " --pad <number> Verification padding size in bytes\n" + " --vblockonly Emit just the verification blob\n" + "\nOR\n\n" + "Usage: %s --repack <file> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --signprivate <file> Private key to sign kernel data,\n" + " in .vbprivk format\n" + " --oldblob <file> Previously packed kernel blob\n" + " (including verfication blob)\n" + "\n" + " Optional:\n" + " --keyblock <file> Key block in .keyblock format\n" + " --config <file> New command line file\n" + " --version <number> Kernel version\n" + " --kloadaddr <address> Assign kernel body load address\n" + " --pad <number> Verification blob size in bytes\n" + " --vblockonly Emit just the verification blob\n" + "\nOR\n\n" + "Usage: %s --verify <file> [PARAMETERS]\n" + "\n" + " Optional:\n" + " --signpubkey <file>" + " Public key to verify kernel keyblock,\n" + " in .vbpubk format\n" + " --verbose Print a more detailed report\n" + " --keyblock <file> Outputs the verified key block,\n" + " in .keyblock format\n" + " --pad <number> Verification padding size in bytes\n" + " --minversion <number> Minimum combined kernel key version\n" + " and kernel version\n" + "\n"; + + /* Print help and return error */ -static int PrintHelp(char *progname) { - fprintf(stderr, - "This program creates, signs, and verifies the kernel blob\n"); - fprintf(stderr, - "\n" - "Usage: %s --pack <file> [PARAMETERS]\n" - "\n" - " Required parameters:\n" - " --keyblock <file> Key block in .keyblock format\n" - " --signprivate <file> Private key to sign kernel data,\n" - " in .vbprivk format\n" - " --version <number> Kernel version\n" - " --vmlinuz <file> Linux kernel bzImage file\n" - " --bootloader <file> Bootloader stub\n" - " --config <file> Command line file\n" - " --arch <arch> Cpu architecture (default x86)\n" - "\n" - " Optional:\n" - " --kloadaddr <address> Assign kernel body load address\n" - " --pad <number> Verification padding size in bytes\n" - " --vblockonly Emit just the verification blob\n", - progname); - fprintf(stderr, - "\nOR\n\n" - "Usage: %s --repack <file> [PARAMETERS]\n" - "\n" - " Required parameters:\n" - " --signprivate <file> Private key to sign kernel data,\n" - " in .vbprivk format\n" - " --oldblob <file> Previously packed kernel blob\n" - " (including verfication blob)\n" - "\n" - " Optional:\n" - " --keyblock <file> Key block in .keyblock format\n" - " --config <file> New command line file\n" - " --version <number> Kernel version\n" - " --kloadaddr <address> Assign kernel body load address\n" - " --pad <number> Verification blob size in bytes\n" - " --vblockonly Emit just the verification blob\n", - progname); - fprintf(stderr, - "\nOR\n\n" - "Usage: %s --verify <file> [PARAMETERS]\n" - "\n" - " Optional:\n" - " --signpubkey <file>" - " Public key to verify kernel keyblock,\n" - " in .vbpubk format\n" - " --verbose Print a more detailed report\n" - " --keyblock <file> Outputs the verified key block,\n" - " in .keyblock format\n" - " --pad <number> Verification padding size in bytes\n" - " --minversion <number> Minimum combined kernel key version\n" - " and kernel version\n" - "\n", - progname); - return 1; +static int PrintHelp(char *progname) +{ + fprintf(stderr, usage, progname, progname, progname); + return 1; } -static void Debug(const char *format, ...) { - if (!opt_debug) - return; - - va_list ap; - va_start(ap, format); - fprintf(stderr, "DEBUG: "); - vfprintf(stderr, format, ap); - va_end(ap); +static void Debug(const char *format, ...) +{ + if (!opt_debug) + return; + + va_list ap; + va_start(ap, format); + fprintf(stderr, "DEBUG: "); + vfprintf(stderr, format, ap); + va_end(ap); } -static void Fatal(const char *format, ...) { - va_list ap; - va_start(ap, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, format, ap); - va_end(ap); - exit(1); +static void Fatal(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); } /* Return an explanation when fread() fails. */ -static const char *error_fread(FILE *fp) { - const char *retval = "beats me why"; - if (feof(fp)) - retval = "EOF"; - else if (ferror(fp)) - retval = strerror(errno); - clearerr(fp); - return retval; +static const char *error_fread(FILE * fp) +{ + const char *retval = "beats me why"; + if (feof(fp)) + retval = "EOF"; + else if (ferror(fp)) + retval = strerror(errno); + clearerr(fp); + return retval; } /* Return the smallest integral multiple of [alignment] that is equal * to or greater than [val]. Used to determine the number of * pages/sectors/blocks/whatever needed to contain [val] * items/bytes/etc. */ -static uint64_t roundup(uint64_t val, uint64_t alignment) { - uint64_t rem = val % alignment; - if ( rem ) - return val + (alignment - rem); - return val; +static uint64_t roundup(uint64_t val, uint64_t alignment) +{ + uint64_t rem = val % alignment; + if (rem) + return val + (alignment - rem); + return val; } - /* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we * don't find one, we'll use the whole thing. */ -static unsigned int find_cmdline_start(char *input, unsigned int max_len) { - int start = 0; - int i; - for(i = 0; i < max_len - 1 && input[i]; i++) { - if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */ - if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */ - (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */ - start = i+2; /* note: hope there's a trailing '\0' */ - break; - } - } - } - while(' ' == input[start]) /* skip leading spaces */ - start++; - - return start; +static unsigned int find_cmdline_start(char *input, unsigned int max_len) +{ + int start = 0; + int i; + for (i = 0; i < max_len - 1 && input[i]; i++) { + if ('-' == input[i] && '-' == input[i + 1]) { + if ((i == 0 || ' ' == input[i - 1]) && + (i + 2 >= max_len || ' ' == input[i + 2])) { + /* found "--" with nothing before or after it */ + start = i + 2; /* hope for a trailing '\0' */ + break; + } + } + } + while (' ' == input[start]) /* skip leading spaces */ + start++; + + return start; } - /****************************************************************************/ /* Here are globals containing all the bits & pieces I'm working on. */ @@ -222,11 +224,10 @@ static uint8_t *g_bootloader_data; static uint64_t g_bootloader_size; static uint64_t g_bootloader_address; - /* The individual parts of the verification blob (including the data that * immediately follows the headers) */ -static VbKeyBlockHeader* g_keyblock; -static VbKernelPreambleHeader* g_preamble; +static VbKeyBlockHeader *g_keyblock; +static VbKernelPreambleHeader *g_preamble; /****************************************************************************/ @@ -237,736 +238,760 @@ static VbKernelPreambleHeader* g_preamble; * Return the buffer contaning the line on success (and set the line length * using the passed in parameter), or NULL in case something goes wrong. */ -static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size) +static uint8_t *ReadConfigFile(const char *config_file, uint64_t * config_size) { - uint8_t* config_buf; - int ii; - - config_buf = ReadFile(config_file, config_size); - Debug(" config file size=0x%" PRIx64 "\n", *config_size); - if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */ - VbExError("Config file %s is too large (>= %d bytes)\n", - config_file, CROS_CONFIG_SIZE); - return NULL; - } - - /* Replace newlines with spaces */ - for (ii = 0; ii < *config_size; ii++) { - if ('\n' == config_buf[ii]) { - config_buf[ii] = ' '; - } - } - return config_buf; + uint8_t *config_buf; + int ii; + + config_buf = ReadFile(config_file, config_size); + Debug(" config file size=0x%" PRIx64 "\n", *config_size); + if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */ + VbExError("Config file %s is too large (>= %d bytes)\n", + config_file, CROS_CONFIG_SIZE); + return NULL; + } + + /* Replace newlines with spaces */ + for (ii = 0; ii < *config_size; ii++) { + if ('\n' == config_buf[ii]) { + config_buf[ii] = ' '; + } + } + return config_buf; } - /* Offset of kernel command line string from start of packed kernel blob */ -static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) { - return preamble->bootloader_address - preamble->body_load_address - - CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; +static uint64_t CmdLineOffset(VbKernelPreambleHeader * preamble) +{ + return preamble->bootloader_address - preamble->body_load_address - + CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; } /* This initializes g_vmlinuz and g_param from a standard vmlinuz file. * It returns 0 on error. */ static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch, - uint64_t kernel_body_load_address) { - uint8_t *kernel_buf; - uint64_t kernel_size; - uint64_t kernel32_start = 0; - uint64_t kernel32_size = 0; - struct linux_kernel_params *params = NULL, *lh = NULL; - - /* Read the kernel */ - Debug("Reading %s\n", vmlinuz_file); - kernel_buf = ReadFile(vmlinuz_file, &kernel_size); - if (!kernel_buf) - return 0; - Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); - if (!kernel_size) - Fatal("Empty kernel file\n"); - - /* Go ahead and allocate the param region anyway. I don't think we need it - * for non-x86, but let's keep it for now. */ - g_param_size = CROS_PARAMS_SIZE; - g_param_data= VbExMalloc(g_param_size); - Memset(g_param_data, 0, g_param_size); - - /* Unless we're handling x86, the kernel is the kernel, so we're done. */ - if (arch != ARCH_X86) { - g_kernel_data = kernel_buf; - g_kernel_size = kernel_size; - return 1; - } - - /* The first part of the x86 vmlinuz is a header, followed by a real-mode - * boot stub. We only want the 32-bit part. */ - lh = (struct linux_kernel_params *)kernel_buf; - kernel32_start = (lh->setup_sects + 1) << 9; - if (kernel32_start >= kernel_size) - Fatal("Malformed kernel\n"); - kernel32_size = kernel_size - kernel32_start; - - Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); - Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); - - /* Keep just the 32-bit kernel. */ - if (kernel32_size) { - g_kernel_size = kernel32_size; - g_kernel_data = VbExMalloc(g_kernel_size); - Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size); - } - - /* Copy the original zeropage data from kernel_buf into g_param_data, then - * tweak a few fields for our purposes */ - params = (struct linux_kernel_params *)(g_param_data); - Memcpy(&(params->setup_sects), &(lh->setup_sects), - offsetof(struct linux_kernel_params, e820_entries) - - offsetof(struct linux_kernel_params, setup_sects)); - params->boot_flag = 0; - params->ramdisk_image = 0; /* we don't support initrd */ - params->ramdisk_size = 0; - params->type_of_loader = 0xff; - /* We need to point to the kernel commandline arg. On disk, it will come - * right after the 32-bit part of the kernel. */ - params->cmd_line_ptr = kernel_body_load_address + - roundup(kernel32_size, CROS_ALIGN) + - find_cmdline_start((char *)g_config_data, g_config_size); - Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); - Debug(" version=0x%x\n", params->version); - Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); - Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); - /* A fake e820 memory map with 2 entries */ - params->n_e820_entry = 2; - params->e820_entries[0].start_addr = 0x00000000; - params->e820_entries[0].segment_size = 0x00001000; - params->e820_entries[0].segment_type = E820_TYPE_RAM; - params->e820_entries[1].start_addr = 0xfffff000; - params->e820_entries[1].segment_size = 0x00001000; - params->e820_entries[1].segment_type = E820_TYPE_RESERVED; - - /* done */ - free(kernel_buf); - return 1; + uint64_t kernel_body_load_address) +{ + uint8_t *kernel_buf; + uint64_t kernel_size; + uint64_t kernel32_start = 0; + uint64_t kernel32_size = 0; + struct linux_kernel_params *params = NULL, *lh = NULL; + + /* Read the kernel */ + Debug("Reading %s\n", vmlinuz_file); + kernel_buf = ReadFile(vmlinuz_file, &kernel_size); + if (!kernel_buf) + return 0; + Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); + if (!kernel_size) + Fatal("Empty kernel file\n"); + + /* Go ahead and allocate the param region anyway. I don't think we need + * it for non-x86, but let's keep it for now. */ + g_param_size = CROS_PARAMS_SIZE; + g_param_data = VbExMalloc(g_param_size); + Memset(g_param_data, 0, g_param_size); + + /* Unless we're handling x86, the kernel is the kernel; we're done. */ + if (arch != ARCH_X86) { + g_kernel_data = kernel_buf; + g_kernel_size = kernel_size; + return 1; + } + + /* The first part of the x86 vmlinuz is a header, followed by a + * real-mode boot stub. We only want the 32-bit part. */ + lh = (struct linux_kernel_params *)kernel_buf; + kernel32_start = (lh->setup_sects + 1) << 9; + if (kernel32_start >= kernel_size) + Fatal("Malformed kernel\n"); + kernel32_size = kernel_size - kernel32_start; + + Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); + Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); + + /* Keep just the 32-bit kernel. */ + if (kernel32_size) { + g_kernel_size = kernel32_size; + g_kernel_data = VbExMalloc(g_kernel_size); + Memcpy(g_kernel_data, kernel_buf + kernel32_start, + kernel32_size); + } + + /* Copy the original zeropage data from kernel_buf into g_param_data, + * then tweak a few fields for our purposes */ + params = (struct linux_kernel_params *)(g_param_data); + Memcpy(&(params->setup_sects), &(lh->setup_sects), + offsetof(struct linux_kernel_params, e820_entries) + - offsetof(struct linux_kernel_params, setup_sects)); + params->boot_flag = 0; + params->ramdisk_image = 0; /* we don't support initrd */ + params->ramdisk_size = 0; + params->type_of_loader = 0xff; + /* We need to point to the kernel commandline arg. On disk, it will come + * right after the 32-bit part of the kernel. */ + params->cmd_line_ptr = kernel_body_load_address + + roundup(kernel32_size, CROS_ALIGN) + + find_cmdline_start((char *)g_config_data, g_config_size); + Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); + Debug(" version=0x%x\n", params->version); + Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); + Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); + /* A fake e820 memory map with 2 entries */ + params->n_e820_entry = 2; + params->e820_entries[0].start_addr = 0x00000000; + params->e820_entries[0].segment_size = 0x00001000; + params->e820_entries[0].segment_type = E820_TYPE_RAM; + params->e820_entries[1].start_addr = 0xfffff000; + params->e820_entries[1].segment_size = 0x00001000; + params->e820_entries[1].segment_type = E820_TYPE_RESERVED; + + /* done */ + free(kernel_buf); + return 1; } /* This returns just the kernel blob, with the verification blob separated * and copied to new memory in g_keyblock and g_preamble. */ -static uint8_t* ReadOldBlobFromFileOrDie(const char *filename, - uint64_t* size_ptr) { - FILE* fp = NULL; - struct stat statbuf; - VbKeyBlockHeader* key_block; - VbKernelPreambleHeader* preamble; - uint64_t now = 0; - uint8_t* buf; - uint8_t* kernel_blob_data; - uint64_t kernel_blob_size; - uint64_t file_size = 0; - - if (0 != stat(filename, &statbuf)) - Fatal("Unable to stat %s: %s\n", filename, strerror(errno)); - - if (S_ISBLK(statbuf.st_mode)) { - int fd; - - if ((fd = open(filename, O_RDONLY)) >= 0) { - ioctl(fd, BLKGETSIZE64, &file_size); - close(fd); - } - } else { - file_size = statbuf.st_size; - } - Debug("%s size is 0x%" PRIx64 "\n", filename, file_size); - if (file_size < opt_pad) - Fatal("%s is too small to be a valid kernel blob\n"); - - Debug("Reading %s\n", filename); - fp = fopen(filename, "rb"); - if (!fp) - Fatal("Unable to open file %s: %s\n", filename, strerror(errno)); - - buf = VbExMalloc(opt_pad); - if (1 != fread(buf, opt_pad, 1, fp)) - Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp)); - - /* Sanity-check the key_block */ - key_block = (VbKeyBlockHeader*)buf; - Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); - now += key_block->key_block_size; - if (now > file_size) - Fatal("key_block_size advances past the end of the blob\n"); - if (now > opt_pad) - Fatal("key_block_size advances past %" PRIu64 " byte padding\n", - opt_pad); - /* LGTM */ - g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size); - Memcpy(g_keyblock, key_block, key_block->key_block_size); - - /* And the preamble */ - preamble = (VbKernelPreambleHeader*)(buf + now); - Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); - now += preamble->preamble_size; - if (now > file_size) - Fatal("preamble_size advances past the end of the blob\n"); - if (now > opt_pad) - Fatal("preamble_size advances past %" PRIu64 " byte padding\n", - opt_pad); - /* LGTM */ - Debug(" kernel_version = %d\n", preamble->kernel_version); - Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address); - Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); - Debug(" kern_blob_size = 0x%" PRIx64 "\n", - preamble->body_signature.data_size); - g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size); - Memcpy(g_preamble, preamble, preamble->preamble_size); - - /* Now for the kernel blob */ - Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); - if (0 != fseek(fp, now, SEEK_SET)) - Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename, - strerror(errno)); - - /* Sanity check */ - kernel_blob_size = file_size - now; - if (!kernel_blob_size) - Fatal("No kernel blob found\n"); - if (kernel_blob_size < preamble->body_signature.data_size) - fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n", - kernel_blob_size); - kernel_blob_data = VbExMalloc(kernel_blob_size); - - /* Read it in */ - if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp)) - Fatal("Unable to read kernel blob from %s: %s\n", filename, - error_fread(fp)); - - /* Done */ - VbExFree(buf); - - if (size_ptr) - *size_ptr = kernel_blob_size; - - return kernel_blob_data; +static uint8_t *ReadOldBlobFromFileOrDie(const char *filename, + uint64_t * size_ptr) +{ + FILE *fp = NULL; + struct stat statbuf; + VbKeyBlockHeader *key_block; + VbKernelPreambleHeader *preamble; + uint64_t now = 0; + uint8_t *buf; + uint8_t *kernel_blob_data; + uint64_t kernel_blob_size; + uint64_t file_size = 0; + + if (0 != stat(filename, &statbuf)) + Fatal("Unable to stat %s: %s\n", filename, strerror(errno)); + + if (S_ISBLK(statbuf.st_mode)) { + int fd; + + if ((fd = open(filename, O_RDONLY)) >= 0) { + ioctl(fd, BLKGETSIZE64, &file_size); + close(fd); + } + } else { + file_size = statbuf.st_size; + } + Debug("%s size is 0x%" PRIx64 "\n", filename, file_size); + if (file_size < opt_pad) + Fatal("%s is too small to be a valid kernel blob\n"); + + Debug("Reading %s\n", filename); + fp = fopen(filename, "rb"); + if (!fp) + Fatal("Unable to open file %s: %s\n", filename, + strerror(errno)); + + buf = VbExMalloc(opt_pad); + if (1 != fread(buf, opt_pad, 1, fp)) + Fatal("Unable to read header from %s: %s\n", filename, + error_fread(fp)); + + /* Sanity-check the key_block */ + key_block = (VbKeyBlockHeader *) buf; + Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); + now += key_block->key_block_size; + if (now > file_size) + Fatal("key_block_size advances past the end of the blob\n"); + if (now > opt_pad) + Fatal("key_block_size advances past %" PRIu64 " byte padding\n", + opt_pad); + /* LGTM */ + g_keyblock = (VbKeyBlockHeader *) VbExMalloc(key_block->key_block_size); + Memcpy(g_keyblock, key_block, key_block->key_block_size); + + /* And the preamble */ + preamble = (VbKernelPreambleHeader *) (buf + now); + Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); + now += preamble->preamble_size; + if (now > file_size) + Fatal("preamble_size advances past the end of the blob\n"); + if (now > opt_pad) + Fatal("preamble_size advances past %" PRIu64 " byte padding\n", + opt_pad); + /* LGTM */ + Debug(" kernel_version = %d\n", preamble->kernel_version); + Debug(" bootloader_address = 0x%" PRIx64 "\n", + preamble->bootloader_address); + Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); + Debug(" kern_blob_size = 0x%" PRIx64 "\n", + preamble->body_signature.data_size); + g_preamble = + (VbKernelPreambleHeader *) VbExMalloc(preamble->preamble_size); + Memcpy(g_preamble, preamble, preamble->preamble_size); + + /* Now for the kernel blob */ + Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); + if (0 != fseek(fp, now, SEEK_SET)) + Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, + filename, strerror(errno)); + + /* Sanity check */ + kernel_blob_size = file_size - now; + if (!kernel_blob_size) + Fatal("No kernel blob found\n"); + if (kernel_blob_size < preamble->body_signature.data_size) + fprintf(stderr, + "Warning: kernel file only has 0x%" PRIx64 " bytes\n", + kernel_blob_size); + kernel_blob_data = VbExMalloc(kernel_blob_size); + + /* Read it in */ + if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp)) + Fatal("Unable to read kernel blob from %s: %s\n", filename, + error_fread(fp)); + + /* Done */ + VbExFree(buf); + + if (size_ptr) + *size_ptr = kernel_blob_size; + + return kernel_blob_data; } - /* Split a kernel blob into separate g_kernel, g_param, g_config, and * g_bootloader parts. */ -static void UnpackKernelBlob(uint8_t *kernel_blob_data, - uint64_t kernel_blob_size) { - - uint64_t k_blob_size = g_preamble->body_signature.data_size; - uint64_t k_blob_ofs = 0; - uint64_t b_size = g_preamble->bootloader_size; - uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address - - g_preamble->body_load_address; - uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE; - uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE; - - Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size ); - Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs ); - Debug("b_size = 0x%" PRIx64 "\n", b_size ); - Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs ); - Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs ); - Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs ); - - g_kernel_size = c_ofs; - g_kernel_data = VbExMalloc(g_kernel_size); - Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size); - - g_param_size = CROS_PARAMS_SIZE; - g_param_data = VbExMalloc(g_param_size); - Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size); - - g_config_size = CROS_CONFIG_SIZE; - g_config_data = VbExMalloc(g_config_size); - Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size); - - g_bootloader_size = b_size; - g_bootloader_data = VbExMalloc(g_bootloader_size); - Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size); -} - +static void UnpackKernelBlob(uint8_t * kernel_blob_data, + uint64_t kernel_blob_size) +{ + uint64_t k_blob_size = g_preamble->body_signature.data_size; + uint64_t k_blob_ofs = 0; + uint64_t b_size = g_preamble->bootloader_size; + uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address - + g_preamble->body_load_address; + uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE; + uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE; + + Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size); + Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs); + Debug("b_size = 0x%" PRIx64 "\n", b_size); + Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs); + Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs); + Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs); + + g_kernel_size = c_ofs; + g_kernel_data = VbExMalloc(g_kernel_size); + Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size); + + g_param_size = CROS_PARAMS_SIZE; + g_param_data = VbExMalloc(g_param_size); + Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size); + + g_config_size = CROS_CONFIG_SIZE; + g_config_data = VbExMalloc(g_config_size); + Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size); + + g_bootloader_size = b_size; + g_bootloader_data = VbExMalloc(g_bootloader_size); + Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size); +} /****************************************************************************/ -static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address, - arch_t arch, - uint64_t *size_ptr) { - uint8_t *kern_blob; - uint64_t kern_blob_size; - uint64_t now; - uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN); - - /* Put the kernel blob together */ - kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) + - CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size; - Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size); - kern_blob = VbExMalloc(kern_blob_size); - Memset(kern_blob, 0, kern_blob_size); - now = 0; - - Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now); - - Memcpy(kern_blob+now, g_kernel_data, g_kernel_size); - now += roundup(g_kernel_size, CROS_ALIGN); - - Debug("config goes at kern_blob+0x%" PRIx64 "\n", now); - if (g_config_size) - Memcpy(kern_blob + now, g_config_data, g_config_size); - now += CROS_CONFIG_SIZE; - - Debug("params goes at kern_blob+0x%" PRIx64 "\n", now); - if (g_param_size) { - Memcpy(kern_blob + now, g_param_data, g_param_size); - } - now += CROS_PARAMS_SIZE; - - Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now); - g_bootloader_address = kernel_body_load_address + now; - Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address); - Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size); - if (bootloader_size) - Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size); - now += bootloader_size; - Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); - - /* Done */ - if (size_ptr) - *size_ptr = kern_blob_size; - - return kern_blob; +static uint8_t *CreateKernelBlob(uint64_t kernel_body_load_address, + arch_t arch, uint64_t * size_ptr) +{ + uint8_t *kern_blob; + uint64_t kern_blob_size; + uint64_t now; + uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN); + + /* Put the kernel blob together */ + kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) + + CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size; + Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size); + kern_blob = VbExMalloc(kern_blob_size); + Memset(kern_blob, 0, kern_blob_size); + now = 0; + + Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now); + + Memcpy(kern_blob + now, g_kernel_data, g_kernel_size); + now += roundup(g_kernel_size, CROS_ALIGN); + + Debug("config goes at kern_blob+0x%" PRIx64 "\n", now); + if (g_config_size) + Memcpy(kern_blob + now, g_config_data, g_config_size); + now += CROS_CONFIG_SIZE; + + Debug("params goes at kern_blob+0x%" PRIx64 "\n", now); + if (g_param_size) { + Memcpy(kern_blob + now, g_param_data, g_param_size); + } + now += CROS_PARAMS_SIZE; + + Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now); + g_bootloader_address = kernel_body_load_address + now; + Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address); + Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size); + if (bootloader_size) + Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size); + now += bootloader_size; + Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); + + /* Done */ + if (size_ptr) + *size_ptr = kern_blob_size; + + return kern_blob; } -static int Pack(const char* outfile, - uint8_t *kernel_blob, - uint64_t kernel_size, - int version, - uint64_t kernel_body_load_address, - VbPrivateKey* signpriv_key) { - VbSignature* body_sig; - FILE* f; - uint64_t i; - uint64_t written = 0; - - /* Sign the kernel data */ - body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); - if (!body_sig) - Fatal("Error calculating body signature\n"); - - /* Create preamble */ - g_preamble = CreateKernelPreamble(version, - kernel_body_load_address, - g_bootloader_address, - roundup(g_bootloader_size, CROS_ALIGN), - body_sig, - opt_pad - g_keyblock->key_block_size, - signpriv_key); - if (!g_preamble) { - VbExError("Error creating preamble.\n"); - return 1; - } - /* Write the output file */ - Debug("writing %s...\n", outfile); - f = fopen(outfile, "wb"); - if (!f) { - VbExError("Can't open output file %s\n", outfile); - return 1; - } - Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size); - Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size); - i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) || - (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f))); - if (i) { - VbExError("Can't write output file %s\n", outfile); - fclose(f); - unlink(outfile); - return 1; - } - written += g_keyblock->key_block_size; - written += g_preamble->preamble_size; - - if (!opt_vblockonly) { - Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size); - i = (1 != fwrite(kernel_blob, kernel_size, 1, f)); - if (i) { - fclose(f); - unlink(outfile); - Fatal("Can't write output file %s\n", outfile); - } - written += kernel_size; - } - Debug("0x%" PRIx64 " bytes total\n", written); - fclose(f); - - /* Success */ - return 0; +static int Pack(const char *outfile, + uint8_t * kernel_blob, + uint64_t kernel_size, + int version, + uint64_t kernel_body_load_address, VbPrivateKey * signpriv_key) +{ + VbSignature *body_sig; + FILE *f; + uint64_t i; + uint64_t written = 0; + + /* Sign the kernel data */ + body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); + if (!body_sig) + Fatal("Error calculating body signature\n"); + + /* Create preamble */ + g_preamble = CreateKernelPreamble(version, + kernel_body_load_address, + g_bootloader_address, + roundup(g_bootloader_size, + CROS_ALIGN), body_sig, + opt_pad - g_keyblock->key_block_size, + signpriv_key); + if (!g_preamble) { + VbExError("Error creating preamble.\n"); + return 1; + } + /* Write the output file */ + Debug("writing %s...\n", outfile); + f = fopen(outfile, "wb"); + if (!f) { + VbExError("Can't open output file %s\n", outfile); + return 1; + } + Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size); + Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size); + i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) || + (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f))); + if (i) { + VbExError("Can't write output file %s\n", outfile); + fclose(f); + unlink(outfile); + return 1; + } + written += g_keyblock->key_block_size; + written += g_preamble->preamble_size; + + if (!opt_vblockonly) { + Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size); + i = (1 != fwrite(kernel_blob, kernel_size, 1, f)); + if (i) { + fclose(f); + unlink(outfile); + Fatal("Can't write output file %s\n", outfile); + } + written += kernel_size; + } + Debug("0x%" PRIx64 " bytes total\n", written); + fclose(f); + + /* Success */ + return 0; } -static int Verify(uint8_t* kernel_blob, - uint64_t kernel_size, - VbPublicKey* signpub_key, - const char* keyblock_outfile, - uint64_t min_version) { - VbPublicKey* data_key; - RSAPublicKey* rsa; - - if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, - signpub_key, (0 == signpub_key))) - Fatal("Error verifying key block.\n"); - - printf("Key block:\n"); - data_key = &g_keyblock->data_key; - if (opt_verbose) - printf(" Signature: %s\n", signpub_key ? "valid" : "ignored"); - printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size); - printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) - printf(" !DEV"); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) - printf(" DEV"); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) - printf(" !REC"); - if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) - printf(" REC"); - printf("\n"); - printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, - (data_key->algorithm < kNumAlgorithms ? - algo_strings[data_key->algorithm] : "(invalid)")); - printf(" Data key version: %" PRIu64 "\n", data_key->key_version); - printf(" Data key sha1sum: "); - PrintPubKeySha1Sum(data_key); - printf("\n"); - - if (keyblock_outfile) { - FILE* f = NULL; - f = fopen(keyblock_outfile, "wb"); - if (!f) - Fatal("Can't open key block file %s\n", keyblock_outfile); - if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) - Fatal("Can't write key block file %s\n", keyblock_outfile); - fclose(f); - } - - if (data_key->key_version < (min_version >> 16)) - Fatal("Data key version %" PRIu64 - " is lower than minimum %" PRIu64".\n", - data_key->key_version, (min_version >> 16)); - - rsa = PublicKeyToRSA(data_key); - if (!rsa) - Fatal("Error parsing data key.\n"); - - /* Verify preamble */ - if (0 != VerifyKernelPreamble( - g_preamble, g_preamble->preamble_size, rsa)) - Fatal("Error verifying preamble.\n"); - - printf("Preamble:\n"); - printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size); - printf(" Header version: %" PRIu32 ".%" PRIu32"\n", - g_preamble->header_version_major, g_preamble->header_version_minor); - printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version); - printf(" Body load address: 0x%" PRIx64 "\n", - g_preamble->body_load_address); - printf(" Body size: 0x%" PRIx64 "\n", - g_preamble->body_signature.data_size); - printf(" Bootloader address: 0x%" PRIx64 "\n", - g_preamble->bootloader_address); - printf(" Bootloader size: 0x%" PRIx64 "\n", - g_preamble->bootloader_size); - - if (g_preamble->kernel_version < (min_version & 0xFFFF)) - Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n", - g_preamble->kernel_version, (min_version & 0xFFFF)); - - /* Verify body */ - if (0 != VerifyData(kernel_blob, kernel_size, - &g_preamble->body_signature, rsa)) - Fatal("Error verifying kernel body.\n"); - printf("Body verification succeeded.\n"); - - - if (opt_verbose) - printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble)); - - return 0; +static int Verify(uint8_t * kernel_blob, + uint64_t kernel_size, + VbPublicKey * signpub_key, + const char *keyblock_outfile, uint64_t min_version) +{ + VbPublicKey *data_key; + RSAPublicKey *rsa; + + if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, + signpub_key, (0 == signpub_key))) + Fatal("Error verifying key block.\n"); + + printf("Key block:\n"); + data_key = &g_keyblock->data_key; + if (opt_verbose) + printf(" Signature: %s\n", + signpub_key ? "valid" : "ignored"); + printf(" Size: 0x%" PRIx64 "\n", + g_keyblock->key_block_size); + printf(" Flags: %" PRIu64 " ", + g_keyblock->key_block_flags); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) + printf(" REC"); + printf("\n"); + printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, + (data_key->algorithm < kNumAlgorithms ? + algo_strings[data_key->algorithm] : "(invalid)")); + printf(" Data key version: %" PRIu64 "\n", data_key->key_version); + printf(" Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + if (keyblock_outfile) { + FILE *f = NULL; + f = fopen(keyblock_outfile, "wb"); + if (!f) + Fatal("Can't open key block file %s\n", + keyblock_outfile); + if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) + Fatal("Can't write key block file %s\n", + keyblock_outfile); + fclose(f); + } + + if (data_key->key_version < (min_version >> 16)) + Fatal("Data key version %" PRIu64 + " is lower than minimum %" PRIu64 ".\n", + data_key->key_version, (min_version >> 16)); + + rsa = PublicKeyToRSA(data_key); + if (!rsa) + Fatal("Error parsing data key.\n"); + + /* Verify preamble */ + if (0 != + VerifyKernelPreamble(g_preamble, g_preamble->preamble_size, rsa)) + Fatal("Error verifying preamble.\n"); + + printf("Preamble:\n"); + printf(" Size: 0x%" PRIx64 "\n", + g_preamble->preamble_size); + printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", + g_preamble->header_version_major, + g_preamble->header_version_minor); + printf(" Kernel version: %" PRIu64 "\n", + g_preamble->kernel_version); + printf(" Body load address: 0x%" PRIx64 "\n", + g_preamble->body_load_address); + printf(" Body size: 0x%" PRIx64 "\n", + g_preamble->body_signature.data_size); + printf(" Bootloader address: 0x%" PRIx64 "\n", + g_preamble->bootloader_address); + printf(" Bootloader size: 0x%" PRIx64 "\n", + g_preamble->bootloader_size); + + if (g_preamble->kernel_version < (min_version & 0xFFFF)) + Fatal("Kernel version %" PRIu64 " is lower than minimum %" + PRIu64 ".\n", g_preamble->kernel_version, + (min_version & 0xFFFF)); + + /* Verify body */ + if (0 != VerifyData(kernel_blob, kernel_size, + &g_preamble->body_signature, rsa)) + Fatal("Error verifying kernel body.\n"); + printf("Body verification succeeded.\n"); + + if (opt_verbose) + printf("Config:\n%s\n", + kernel_blob + CmdLineOffset(g_preamble)); + + return 0; } /****************************************************************************/ -static int do_vbutil_kernel(int argc, char* argv[]) { - char* filename = NULL; - char* oldfile = NULL; - char* keyblock_file = NULL; - char* signpubkey_file = NULL; - char* signprivkey_file = NULL; - char* version_str = NULL; - int version = -1; - char* vmlinuz_file = NULL; - char* bootloader_file = NULL; - char* config_file = NULL; - arch_t arch = ARCH_X86; - char *address_str = NULL; - uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR; - int mode = 0; - int parse_error = 0; - uint64_t min_version = 0; - char* e; - int i; - VbPrivateKey* signpriv_key = NULL; - VbPublicKey* signpub_key = NULL; - uint8_t* kernel_blob = NULL; - uint64_t kernel_size = 0; - - char *progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && - !parse_error) { - switch (i) { - default: - case '?': - /* Unhandled option */ - parse_error = 1; - break; - - case 0: - /* silently handled option */ - break; - - case OPT_MODE_PACK: - case OPT_MODE_REPACK: - case OPT_MODE_VERIFY: - if (mode && (mode != i)) { - fprintf(stderr, "Only a single mode can be specified\n"); - parse_error = 1; - break; - } - mode = i; - filename = optarg; - break; - - case OPT_ARCH: - /* check the first 3 characters to also detect x86_64 */ - if ((!strncasecmp(optarg, "x86", 3)) || - (!strcasecmp(optarg, "amd64"))) - arch = ARCH_X86; - else if ((!strcasecmp(optarg, "arm")) || - (!strcasecmp(optarg, "aarch64"))) - arch = ARCH_ARM; - else if (!strcasecmp(optarg, "mips")) - arch = ARCH_MIPS; - else { - fprintf(stderr, "Unknown architecture string: %s\n", optarg); - parse_error = 1; - } - break; - - case OPT_OLDBLOB: - oldfile = optarg; - break; - - case OPT_KLOADADDR: - address_str = optarg; - kernel_body_load_address = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --kloadaddr\n"); - parse_error = 1; - } - break; - - case OPT_KEYBLOCK: - keyblock_file = optarg; - break; - - case OPT_SIGNPUBKEY: - signpubkey_file = optarg; - break; - - case OPT_SIGNPRIVATE: - signprivkey_file = optarg; - break; - - case OPT_VMLINUZ: - vmlinuz_file = optarg; - break; - - case OPT_BOOTLOADER: - bootloader_file = optarg; - break; - - case OPT_CONFIG: - config_file = optarg; - break; - - case OPT_VBLOCKONLY: - opt_vblockonly = 1; - break; - - case OPT_VERSION: - version_str = optarg; - version = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --version\n"); - parse_error = 1; - } - break; - - case OPT_MINVERSION: - min_version = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --minversion\n"); - parse_error = 1; - } - break; - - case OPT_PAD: - opt_pad = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --pad\n"); - parse_error = 1; - } - break; - } - } - - if (parse_error) - return PrintHelp(progname); - - switch(mode) { - case OPT_MODE_PACK: - - /* Required */ - - if (!keyblock_file) - Fatal("Missing required keyblock file.\n"); - - g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0); - if (!g_keyblock) - Fatal("Error reading key block.\n"); - - if (!signprivkey_file) - Fatal("Missing required signprivate file.\n"); - - signpriv_key = PrivateKeyRead(signprivkey_file); - if (!signpriv_key) - Fatal("Error reading signing key.\n"); - - /* Optional */ - - if (config_file) { - Debug("Reading %s\n", config_file); - g_config_data = ReadConfigFile(config_file, &g_config_size); - if (!g_config_data) - Fatal("Error reading config file.\n"); - } - - if (vmlinuz_file) - if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address)) - Fatal("Error reading kernel file.\n"); - - if (bootloader_file) { - Debug("Reading %s\n", bootloader_file); - g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size); - if (!g_bootloader_data) - Fatal("Error reading bootloader file.\n"); - Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size); - } - - /* Do it */ - - kernel_blob = CreateKernelBlob(kernel_body_load_address, arch, - &kernel_size); - - return Pack(filename, kernel_blob, kernel_size, - version, kernel_body_load_address, - signpriv_key); +static int do_vbutil_kernel(int argc, char *argv[]) +{ + char *filename = NULL; + char *oldfile = NULL; + char *keyblock_file = NULL; + char *signpubkey_file = NULL; + char *signprivkey_file = NULL; + char *version_str = NULL; + int version = -1; + char *vmlinuz_file = NULL; + char *bootloader_file = NULL; + char *config_file = NULL; + arch_t arch = ARCH_X86; + char *address_str = NULL; + uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR; + int mode = 0; + int parse_error = 0; + uint64_t min_version = 0; + char *e; + int i; + VbPrivateKey *signpriv_key = NULL; + VbPublicKey *signpub_key = NULL; + uint8_t *kernel_blob = NULL; + uint64_t kernel_size = 0; + + char *progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && + !parse_error) { + switch (i) { + default: + case '?': + /* Unhandled option */ + parse_error = 1; + break; + + case 0: + /* silently handled option */ + break; + + case OPT_MODE_PACK: + case OPT_MODE_REPACK: + case OPT_MODE_VERIFY: + if (mode && (mode != i)) { + fprintf(stderr, + "Only one mode can be specified\n"); + parse_error = 1; + break; + } + mode = i; + filename = optarg; + break; + + case OPT_ARCH: + /* check the first 3 characters to also detect x86_64 */ + if ((!strncasecmp(optarg, "x86", 3)) || + (!strcasecmp(optarg, "amd64"))) + arch = ARCH_X86; + else if ((!strcasecmp(optarg, "arm")) || + (!strcasecmp(optarg, "aarch64"))) + arch = ARCH_ARM; + else if (!strcasecmp(optarg, "mips")) + arch = ARCH_MIPS; + else { + fprintf(stderr, + "Unknown architecture string: %s\n", + optarg); + parse_error = 1; + } + break; + + case OPT_OLDBLOB: + oldfile = optarg; + break; + + case OPT_KLOADADDR: + address_str = optarg; + kernel_body_load_address = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --kloadaddr\n"); + parse_error = 1; + } + break; + + case OPT_KEYBLOCK: + keyblock_file = optarg; + break; + + case OPT_SIGNPUBKEY: + signpubkey_file = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivkey_file = optarg; + break; + + case OPT_VMLINUZ: + vmlinuz_file = optarg; + break; + + case OPT_BOOTLOADER: + bootloader_file = optarg; + break; + + case OPT_CONFIG: + config_file = optarg; + break; + + case OPT_VBLOCKONLY: + opt_vblockonly = 1; + break; + + case OPT_VERSION: + version_str = optarg; + version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --version\n"); + parse_error = 1; + } + break; + + case OPT_MINVERSION: + min_version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --minversion\n"); + parse_error = 1; + } + break; + + case OPT_PAD: + opt_pad = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --pad\n"); + parse_error = 1; + } + break; + } + } + + if (parse_error) + return PrintHelp(progname); + + switch (mode) { + case OPT_MODE_PACK: + + /* Required */ + + if (!keyblock_file) + Fatal("Missing required keyblock file.\n"); + + g_keyblock = (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); + if (!g_keyblock) + Fatal("Error reading key block.\n"); + + if (!signprivkey_file) + Fatal("Missing required signprivate file.\n"); + + signpriv_key = PrivateKeyRead(signprivkey_file); + if (!signpriv_key) + Fatal("Error reading signing key.\n"); + + /* Optional */ + + if (config_file) { + Debug("Reading %s\n", config_file); + g_config_data = + ReadConfigFile(config_file, &g_config_size); + if (!g_config_data) + Fatal("Error reading config file.\n"); + } + + if (vmlinuz_file) + if (!ImportVmlinuzFile + (vmlinuz_file, arch, kernel_body_load_address)) + Fatal("Error reading kernel file.\n"); + + if (bootloader_file) { + Debug("Reading %s\n", bootloader_file); + g_bootloader_data = + ReadFile(bootloader_file, &g_bootloader_size); + if (!g_bootloader_data) + Fatal("Error reading bootloader file.\n"); + Debug(" bootloader file size=0x%" PRIx64 "\n", + g_bootloader_size); + } - case OPT_MODE_REPACK: + /* Do it */ - /* Required */ + kernel_blob = CreateKernelBlob(kernel_body_load_address, arch, + &kernel_size); - if (!signprivkey_file) - Fatal("Missing required signprivate file.\n"); + return Pack(filename, kernel_blob, kernel_size, + version, kernel_body_load_address, signpriv_key); - signpriv_key = PrivateKeyRead(signprivkey_file); - if (!signpriv_key) - Fatal("Error reading signing key.\n"); + case OPT_MODE_REPACK: - if (!oldfile) - Fatal("Missing previously packed blob.\n"); + /* Required */ - /* Load the old blob */ + if (!signprivkey_file) + Fatal("Missing required signprivate file.\n"); + + signpriv_key = PrivateKeyRead(signprivkey_file); + if (!signpriv_key) + Fatal("Error reading signing key.\n"); + + if (!oldfile) + Fatal("Missing previously packed blob.\n"); - kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size); - if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0)) - Fatal("The oldblob doesn't verify\n"); + /* Load the old blob */ - /* Take it apart */ + kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size); + if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0)) + Fatal("The oldblob doesn't verify\n"); - UnpackKernelBlob(kernel_blob, kernel_size); - free(kernel_blob); + /* Take it apart */ - /* Load optional params */ + UnpackKernelBlob(kernel_blob, kernel_size); + free(kernel_blob); - if (!version_str) - version = g_preamble->kernel_version; + /* Load optional params */ - if (!address_str) - kernel_body_load_address = g_preamble->body_load_address; + if (!version_str) + version = g_preamble->kernel_version; - if (config_file) { - if (g_config_data) - free(g_config_data); - Debug("Reading %s\n", config_file); - g_config_data = ReadConfigFile(config_file, &g_config_size); - if (!g_config_data) - Fatal("Error reading config file.\n"); - } + if (!address_str) + kernel_body_load_address = + g_preamble->body_load_address; - if (keyblock_file) { - if (g_keyblock) - free(g_keyblock); - g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0); - if (!g_keyblock) - Fatal("Error reading key block.\n"); - } + if (config_file) { + if (g_config_data) + free(g_config_data); + Debug("Reading %s\n", config_file); + g_config_data = + ReadConfigFile(config_file, &g_config_size); + if (!g_config_data) + Fatal("Error reading config file.\n"); + } - /* Put it back together */ + if (keyblock_file) { + if (g_keyblock) + free(g_keyblock); + g_keyblock = + (VbKeyBlockHeader *) ReadFile(keyblock_file, 0); + if (!g_keyblock) + Fatal("Error reading key block.\n"); + } - kernel_blob = CreateKernelBlob(kernel_body_load_address, arch, - &kernel_size); + /* Put it back together */ - return Pack(filename, kernel_blob, kernel_size, - version, kernel_body_load_address, - signpriv_key); + kernel_blob = CreateKernelBlob(kernel_body_load_address, arch, + &kernel_size); + return Pack(filename, kernel_blob, kernel_size, + version, kernel_body_load_address, signpriv_key); - case OPT_MODE_VERIFY: + case OPT_MODE_VERIFY: - /* Optional */ + /* Optional */ - if (signpubkey_file) { - signpub_key = PublicKeyRead(signpubkey_file); - if (!signpub_key) - Fatal("Error reading public key.\n"); - } + if (signpubkey_file) { + signpub_key = PublicKeyRead(signpubkey_file); + if (!signpub_key) + Fatal("Error reading public key.\n"); + } - /* Do it */ + /* Do it */ - kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size); + kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size); - return Verify(kernel_blob, kernel_size, signpub_key, - keyblock_file, min_version); - } + return Verify(kernel_blob, kernel_size, signpub_key, + keyblock_file, min_version); + } - fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n"); - return PrintHelp(progname); + fprintf(stderr, + "You must specify a mode: --pack, --repack or --verify\n"); + return PrintHelp(progname); } DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel, diff --git a/futility/cmd_vbutil_key.c b/futility/cmd_vbutil_key.c index 88d8e83b..c8c1c61b 100644 --- a/futility/cmd_vbutil_key.c +++ b/futility/cmd_vbutil_key.c @@ -6,7 +6,7 @@ */ #include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ +#include <inttypes.h> /* For PRIu64 */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -18,224 +18,227 @@ #include "util_misc.h" #include "vboot_common.h" - /* Command line options */ enum { - OPT_INKEY = 1000, - OPT_KEY_VERSION, - OPT_ALGORITHM, - OPT_MODE_PACK, - OPT_MODE_UNPACK, - OPT_COPYTO, + OPT_INKEY = 1000, + OPT_KEY_VERSION, + OPT_ALGORITHM, + OPT_MODE_PACK, + OPT_MODE_UNPACK, + OPT_COPYTO, }; static const struct option long_opts[] = { - {"key", 1, 0, OPT_INKEY }, - {"version", 1, 0, OPT_KEY_VERSION }, - {"algorithm", 1, 0, OPT_ALGORITHM }, - {"pack", 1, 0, OPT_MODE_PACK }, - {"unpack", 1, 0, OPT_MODE_UNPACK }, - {"copyto", 1, 0, OPT_COPYTO }, - {NULL, 0, 0, 0} + {"key", 1, 0, OPT_INKEY}, + {"version", 1, 0, OPT_KEY_VERSION}, + {"algorithm", 1, 0, OPT_ALGORITHM}, + {"pack", 1, 0, OPT_MODE_PACK}, + {"unpack", 1, 0, OPT_MODE_UNPACK}, + {"copyto", 1, 0, OPT_COPYTO}, + {NULL, 0, 0, 0} }; - /* Print help and return error */ -static int PrintHelp(char *progname) { - int i; - - fprintf(stderr, - "This program wraps RSA keys with verified boot headers\n"); - fprintf(stderr, - "\n" - "Usage: %s --pack <outfile> [PARAMETERS]\n" - "\n" - " Required parameters:\n" - " --key <infile> RSA key file (.keyb or .pem)\n" - " --version <number> Key version number " - "(required for .keyb,\n" - " ignored for .pem)\n" - " --algorithm <number> " - "Signing algorithm to use with key:\n", - progname); - - for (i = 0; i < kNumAlgorithms; i++) { - fprintf(stderr, - " %d = (%s)\n", - i, algo_strings[i]); - } - - fprintf(stderr, - "\nOR\n\n" - "Usage: %s --unpack <infile>\n" - "\n" - " Optional parameters:\n" - " --copyto <file> " - "Write a copy of the key to this file.\n" - "\n", - progname); - - return 1; +static int PrintHelp(char *progname) +{ + int i; + + fprintf(stderr, + "This program wraps RSA keys with verified boot headers\n"); + fprintf(stderr, + "\n" + "Usage: %s --pack <outfile> [PARAMETERS]\n" + "\n" + " Required parameters:\n" + " --key <infile> RSA key file (.keyb or .pem)\n" + " --version <number> Key version number " + "(required for .keyb,\n" + " ignored for .pem)\n" + " --algorithm <number> " + "Signing algorithm to use with key:\n", progname); + + for (i = 0; i < kNumAlgorithms; i++) { + fprintf(stderr, + " %d = (%s)\n", + i, algo_strings[i]); + } + + fprintf(stderr, + "\nOR\n\n" + "Usage: %s --unpack <infile>\n" + "\n" + " Optional parameters:\n" + " --copyto <file> " + "Write a copy of the key to this file.\n" "\n", progname); + + return 1; } /* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */ static int Pack(const char *infile, const char *outfile, uint64_t algorithm, - uint64_t version) { - VbPublicKey* pubkey; - VbPrivateKey* privkey; - - if (!infile || !outfile) { - fprintf(stderr, "vbutil_key: Must specify --in and --out\n"); - return 1; - } - - if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) { - if (0 != PublicKeyWrite(outfile, pubkey)) { - fprintf(stderr, "vbutil_key: Error writing key.\n"); - return 1; - } - free(pubkey); - return 0; - } - - if ((privkey = PrivateKeyReadPem(infile, algorithm))) { - if (0 != PrivateKeyWrite(outfile, privkey)) { - fprintf(stderr, "vbutil_key: Error writing key.\n"); - return 1; - } - free(privkey); - return 0; - } - - VbExError("Unable to parse either .keyb or .pem from %s\n", infile); - return 1; + uint64_t version) +{ + VbPublicKey *pubkey; + VbPrivateKey *privkey; + + if (!infile || !outfile) { + fprintf(stderr, "vbutil_key: Must specify --in and --out\n"); + return 1; + } + + if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) { + if (0 != PublicKeyWrite(outfile, pubkey)) { + fprintf(stderr, "vbutil_key: Error writing key.\n"); + return 1; + } + free(pubkey); + return 0; + } + + if ((privkey = PrivateKeyReadPem(infile, algorithm))) { + if (0 != PrivateKeyWrite(outfile, privkey)) { + fprintf(stderr, "vbutil_key: Error writing key.\n"); + return 1; + } + free(privkey); + return 0; + } + + VbExError("Unable to parse either .keyb or .pem from %s\n", infile); + return 1; } - /* Unpack a .vbpubk or .vbprivk */ -static int Unpack(const char *infile, const char *outfile) { - VbPublicKey* pubkey; - VbPrivateKey* privkey; - - if (!infile) { - fprintf(stderr, "Need file to unpack\n"); - return 1; - } - - if ((pubkey = PublicKeyRead(infile))) { - printf("Public Key file: %s\n", infile); - printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm, - (pubkey->algorithm < kNumAlgorithms ? - algo_strings[pubkey->algorithm] : "(invalid)")); - printf("Key Version: %" PRIu64 "\n", pubkey->key_version); - printf("Key sha1sum: "); - PrintPubKeySha1Sum(pubkey); - printf("\n"); - if (outfile) { - if (0 != PublicKeyWrite(outfile, pubkey)) { - fprintf(stderr, "vbutil_key: Error writing key copy.\n"); - free(pubkey); - return 1; - } - } - free(pubkey); - return 0; - } - - if ((privkey = PrivateKeyRead(infile))) { - printf("Private Key file: %s\n", infile); - printf("Algorithm: %" PRIu64 " %s\n", privkey->algorithm, - (privkey->algorithm < kNumAlgorithms ? - algo_strings[privkey->algorithm] : "(invalid)")); - if (outfile) { - if (0 != PrivateKeyWrite(outfile, privkey)) { - fprintf(stderr, "vbutil_key: Error writing key copy.\n"); - free(privkey); - return 1; - } - } - free(privkey); - return 0; - } - - VbExError("Unable to parse either .vbpubk or vbprivk from %s\n", infile); - return 1; +static int Unpack(const char *infile, const char *outfile) +{ + VbPublicKey *pubkey; + VbPrivateKey *privkey; + + if (!infile) { + fprintf(stderr, "Need file to unpack\n"); + return 1; + } + + if ((pubkey = PublicKeyRead(infile))) { + printf("Public Key file: %s\n", infile); + printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm, + (pubkey->algorithm < kNumAlgorithms ? + algo_strings[pubkey->algorithm] : "(invalid)")); + printf("Key Version: %" PRIu64 "\n", pubkey->key_version); + printf("Key sha1sum: "); + PrintPubKeySha1Sum(pubkey); + printf("\n"); + if (outfile) { + if (0 != PublicKeyWrite(outfile, pubkey)) { + fprintf(stderr, + "vbutil_key: Error writing key copy\n"); + free(pubkey); + return 1; + } + } + free(pubkey); + return 0; + } + + if ((privkey = PrivateKeyRead(infile))) { + printf("Private Key file: %s\n", infile); + printf("Algorithm: %" PRIu64 " %s\n", + privkey->algorithm, + (privkey->algorithm < + kNumAlgorithms ? algo_strings[privkey-> + algorithm] : + "(invalid)")); + if (outfile) { + if (0 != PrivateKeyWrite(outfile, privkey)) { + fprintf(stderr, + "vbutil_key: Error writing key copy\n"); + free(privkey); + return 1; + } + } + free(privkey); + return 0; + } + + VbExError("Unable to parse either .vbpubk or vbprivk from %s\n", + infile); + return 1; } - -static int do_vbutil_key(int argc, char* argv[]) { - - char *infile = NULL; - char *outfile = NULL; - int mode = 0; - int parse_error = 0; - uint64_t version = 1; - uint64_t algorithm = kNumAlgorithms; - char* e; - int i; - - char *progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { - switch (i) { - case '?': - /* Unhandled option */ - VbExError("Unknown option\n"); - parse_error = 1; - break; - - case OPT_INKEY: - infile = optarg; - break; - - case OPT_KEY_VERSION: - version = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - VbExError("Invalid --version\n"); - parse_error = 1; - } - break; - - case OPT_ALGORITHM: - algorithm = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - VbExError("Invalid --algorithm\n"); - parse_error = 1; - } - break; - - case OPT_MODE_PACK: - mode = i; - outfile = optarg; - break; - - case OPT_MODE_UNPACK: - mode = i; - infile = optarg; - break; - - case OPT_COPYTO: - outfile = optarg; - break; - } - } - - if (parse_error) - return PrintHelp(progname); - - switch(mode) { - case OPT_MODE_PACK: - return Pack(infile, outfile, algorithm, version); - case OPT_MODE_UNPACK: - return Unpack(infile, outfile); - default: - printf("Must specify a mode.\n"); - return PrintHelp(progname); - } +static int do_vbutil_key(int argc, char *argv[]) +{ + + char *infile = NULL; + char *outfile = NULL; + int mode = 0; + int parse_error = 0; + uint64_t version = 1; + uint64_t algorithm = kNumAlgorithms; + char *e; + int i; + + char *progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + case '?': + /* Unhandled option */ + VbExError("Unknown option\n"); + parse_error = 1; + break; + + case OPT_INKEY: + infile = optarg; + break; + + case OPT_KEY_VERSION: + version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + VbExError("Invalid --version\n"); + parse_error = 1; + } + break; + + case OPT_ALGORITHM: + algorithm = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + VbExError("Invalid --algorithm\n"); + parse_error = 1; + } + break; + + case OPT_MODE_PACK: + mode = i; + outfile = optarg; + break; + + case OPT_MODE_UNPACK: + mode = i; + infile = optarg; + break; + + case OPT_COPYTO: + outfile = optarg; + break; + } + } + + if (parse_error) + return PrintHelp(progname); + + switch (mode) { + case OPT_MODE_PACK: + return Pack(infile, outfile, algorithm, version); + case OPT_MODE_UNPACK: + return Unpack(infile, outfile); + default: + printf("Must specify a mode.\n"); + return PrintHelp(progname); + } } DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key, diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c index 687537d8..58d89c1a 100644 --- a/futility/cmd_vbutil_keyblock.c +++ b/futility/cmd_vbutil_keyblock.c @@ -17,312 +17,324 @@ #include "util_misc.h" #include "vboot_common.h" - /* Command line options */ enum { - OPT_MODE_PACK = 1000, - OPT_MODE_UNPACK, - OPT_DATAPUBKEY, - OPT_SIGNPUBKEY, - OPT_SIGNPRIVATE, - OPT_SIGNPRIVATE_PEM, - OPT_PEM_ALGORITHM, - OPT_EXTERNAL_SIGNER, - OPT_FLAGS, + OPT_MODE_PACK = 1000, + OPT_MODE_UNPACK, + OPT_DATAPUBKEY, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_SIGNPRIVATE_PEM, + OPT_PEM_ALGORITHM, + OPT_EXTERNAL_SIGNER, + OPT_FLAGS, }; static const struct option long_opts[] = { - {"pack", 1, 0, OPT_MODE_PACK }, - {"unpack", 1, 0, OPT_MODE_UNPACK }, - {"datapubkey", 1, 0, OPT_DATAPUBKEY }, - {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, - {"signprivate", 1, 0, OPT_SIGNPRIVATE }, - {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM }, - {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM }, - {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER }, - {"flags", 1, 0, OPT_FLAGS }, - {NULL, 0, 0, 0} + {"pack", 1, 0, OPT_MODE_PACK}, + {"unpack", 1, 0, OPT_MODE_UNPACK}, + {"datapubkey", 1, 0, OPT_DATAPUBKEY}, + {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, + {"signprivate", 1, 0, OPT_SIGNPRIVATE}, + {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM}, + {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM}, + {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER}, + {"flags", 1, 0, OPT_FLAGS}, + {NULL, 0, 0, 0} }; +static const char usage[] = + "Verified boot key block utility\n" + "\n" + "Usage: %s <--pack|--unpack> <file> [OPTIONS]\n" + "\n" + "For '--pack <file>', required OPTIONS are:\n" + " --datapubkey <file> Data public key in .vbpubk format\n" + "\n" + "Optional OPTIONS are:\n" + " --signprivate <file>" + " Signing private key in .vbprivk format.\n" + "OR\n" + " --signprivate_pem <file>\n" + " --pem_algorithm <algo>\n" + " Signing private key in .pem format and algorithm id.\n" + "(If one of the above arguments is not specified, the keyblock will\n" + "not be signed.)\n" + "\n" + " --flags <number> Specifies allowed use conditions.\n" + " --externalsigner \"cmd\"" + " Use an external program cmd to calculate the signatures.\n" + "\n" + "For '--unpack <file>', optional OPTIONS are:\n" + " --signpubkey <file>" + " Signing public key in .vbpubk format. This is required to\n" + " verify a signed keyblock.\n" + " --datapubkey <file>" + " Write the data public key to this file.\n"; /* Print help and return error */ -static int PrintHelp(char *progname) { - fprintf(stderr, - "Verified boot key block utility\n" - "\n" - "Usage: %s <--pack|--unpack> <file> [OPTIONS]\n" - "\n" - "For '--pack <file>', required OPTIONS are:\n" - " --datapubkey <file> Data public key in .vbpubk format\n" - "\n" - "Optional OPTIONS are:\n" - " --signprivate <file>" - " Signing private key in .vbprivk format.\n" - "OR\n" - " --signprivate_pem <file>\n" - " --pem_algorithm <algo>\n" - " Signing private key in .pem format and algorithm id.\n" - "(If one of the above arguments is not specified, the keyblock will\n" - "not be signed.)\n" - "\n" - " --flags <number> Specifies allowed use conditions.\n" - " --externalsigner \"cmd\"" - " Use an external program cmd to calculate the signatures.\n" - "\n" - "For '--unpack <file>', optional OPTIONS are:\n" - " --signpubkey <file>" - " Signing public key in .vbpubk format. This is required to\n" - " verify a signed keyblock.\n" - " --datapubkey <file>" - " Write the data public key to this file.\n", - progname); - return 1; +static int PrintHelp(char *progname) +{ + fprintf(stderr, usage, progname); + return 1; } /* Pack a .keyblock */ -static int Pack(const char* outfile, const char* datapubkey, - const char* signprivate, - const char* signprivate_pem, uint64_t pem_algorithm, - uint64_t flags, - const char* external_signer) { - VbPublicKey* data_key; - VbPrivateKey* signing_key = NULL; - VbKeyBlockHeader* block; - - if (!outfile) { - fprintf(stderr, "vbutil_keyblock: Must specify output filename.\n"); - return 1; - } - if (!datapubkey) { - fprintf(stderr, "vbutil_keyblock: Must specify data public key.\n"); - return 1; - } - - data_key = PublicKeyRead(datapubkey); - if (!data_key) { - fprintf(stderr, "vbutil_keyblock: Error reading data key.\n"); - return 1; - } - - if (signprivate_pem) { - if (pem_algorithm >= kNumAlgorithms) { - fprintf(stderr, "vbutil_keyblock: Invalid --pem_algorithm %" PRIu64 "\n", - pem_algorithm); - return 1; - } - if (external_signer) { - /* External signing uses the PEM file directly. */ - block = KeyBlockCreate_external(data_key, - signprivate_pem, pem_algorithm, - flags, - external_signer); - } else { - signing_key = PrivateKeyReadPem(signprivate_pem, pem_algorithm); - if (!signing_key) { - fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); - return 1; - } - block = KeyBlockCreate(data_key, signing_key, flags); - } - } else { - if (signprivate) { - signing_key = PrivateKeyRead(signprivate); - if (!signing_key) { - fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); - return 1; - } - } - block = KeyBlockCreate(data_key, signing_key, flags); - } - - free(data_key); - if (signing_key) - free(signing_key); - - if (0 != KeyBlockWrite(outfile, block)) { - fprintf(stderr, "vbutil_keyblock: Error writing key block.\n"); - return 1; - } - free(block); - return 0; +static int Pack(const char *outfile, const char *datapubkey, + const char *signprivate, + const char *signprivate_pem, uint64_t pem_algorithm, + uint64_t flags, const char *external_signer) +{ + VbPublicKey *data_key; + VbPrivateKey *signing_key = NULL; + VbKeyBlockHeader *block; + + if (!outfile) { + fprintf(stderr, + "vbutil_keyblock: Must specify output filename.\n"); + return 1; + } + if (!datapubkey) { + fprintf(stderr, + "vbutil_keyblock: Must specify data public key.\n"); + return 1; + } + + data_key = PublicKeyRead(datapubkey); + if (!data_key) { + fprintf(stderr, "vbutil_keyblock: Error reading data key.\n"); + return 1; + } + + if (signprivate_pem) { + if (pem_algorithm >= kNumAlgorithms) { + fprintf(stderr, + "vbutil_keyblock: Invalid --pem_algorithm %" + PRIu64 "\n", pem_algorithm); + return 1; + } + if (external_signer) { + /* External signing uses the PEM file directly. */ + block = KeyBlockCreate_external(data_key, + signprivate_pem, + pem_algorithm, flags, + external_signer); + } else { + signing_key = + PrivateKeyReadPem(signprivate_pem, pem_algorithm); + if (!signing_key) { + fprintf(stderr, "vbutil_keyblock:" + " Error reading signing key.\n"); + return 1; + } + block = KeyBlockCreate(data_key, signing_key, flags); + } + } else { + if (signprivate) { + signing_key = PrivateKeyRead(signprivate); + if (!signing_key) { + fprintf(stderr, "vbutil_keyblock:" + " Error reading signing key.\n"); + return 1; + } + } + block = KeyBlockCreate(data_key, signing_key, flags); + } + + free(data_key); + if (signing_key) + free(signing_key); + + if (0 != KeyBlockWrite(outfile, block)) { + fprintf(stderr, "vbutil_keyblock: Error writing key block.\n"); + return 1; + } + free(block); + return 0; } -static int Unpack(const char* infile, const char* datapubkey, - const char* signpubkey) { - VbPublicKey* data_key; - VbPublicKey* sign_key = NULL; - VbKeyBlockHeader* block; - - if (!infile) { - fprintf(stderr, "vbutil_keyblock: Must specify filename\n"); - return 1; - } - - block = KeyBlockRead(infile); - if (!block) { - fprintf(stderr, "vbutil_keyblock: Error reading key block.\n"); - return 1; - } - - /* If the block is signed, then verify it with the signing public key, since - KeyBlockRead() only verified the hash. */ - if (block->key_block_signature.sig_size && signpubkey) { - sign_key = PublicKeyRead(signpubkey); - if (!sign_key) { - fprintf(stderr, "vbutil_keyblock: Error reading signpubkey.\n"); - return 1; - } - if (0 != KeyBlockVerify(block, block->key_block_size, sign_key, 0)) { - fprintf(stderr, "vbutil_keyblock: Error verifying key block.\n"); - return 1; - } - free(sign_key); - } - - printf("Key block file: %s\n", infile); - printf("Signature %s\n", sign_key ? "valid" : "ignored"); - printf("Flags: %" PRIu64 " ", block->key_block_flags); - if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) - printf(" !DEV"); - if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) - printf(" DEV"); - if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) - printf(" !REC"); - if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) - printf(" REC"); - printf("\n"); - - data_key = &block->data_key; - printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, - (data_key->algorithm < kNumAlgorithms ? - algo_strings[data_key->algorithm] : "(invalid)")); - printf("Data key version: %" PRIu64 "\n", data_key->key_version); - printf("Data key sha1sum: "); - PrintPubKeySha1Sum(data_key); - printf("\n"); - - if (datapubkey) { - if (0 != PublicKeyWrite(datapubkey, data_key)) { - fprintf(stderr, - "vbutil_keyblock: unable to write public key\n"); - return 1; - } - } - - free(block); - return 0; +static int Unpack(const char *infile, const char *datapubkey, + const char *signpubkey) +{ + VbPublicKey *data_key; + VbPublicKey *sign_key = NULL; + VbKeyBlockHeader *block; + + if (!infile) { + fprintf(stderr, "vbutil_keyblock: Must specify filename\n"); + return 1; + } + + block = KeyBlockRead(infile); + if (!block) { + fprintf(stderr, "vbutil_keyblock: Error reading key block.\n"); + return 1; + } + + /* If the block is signed, then verify it with the signing public key, + * since KeyBlockRead() only verified the hash. */ + if (block->key_block_signature.sig_size && signpubkey) { + sign_key = PublicKeyRead(signpubkey); + if (!sign_key) { + fprintf(stderr, + "vbutil_keyblock: Error reading signpubkey.\n"); + return 1; + } + if (0 != + KeyBlockVerify(block, block->key_block_size, sign_key, 0)) { + fprintf(stderr, "vbutil_keyblock:" + " Error verifying key block.\n"); + return 1; + } + free(sign_key); + } + + printf("Key block file: %s\n", infile); + printf("Signature %s\n", sign_key ? "valid" : "ignored"); + printf("Flags: %" PRIu64 " ", block->key_block_flags); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) + printf(" REC"); + printf("\n"); + + data_key = &block->data_key; + printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, + (data_key->algorithm < kNumAlgorithms ? + algo_strings[data_key->algorithm] : "(invalid)")); + printf("Data key version: %" PRIu64 "\n", data_key->key_version); + printf("Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + if (datapubkey) { + if (0 != PublicKeyWrite(datapubkey, data_key)) { + fprintf(stderr, "vbutil_keyblock:" + " unable to write public key\n"); + return 1; + } + } + + free(block); + return 0; } - -static int do_vbutil_keyblock(int argc, char* argv[]) { - - char* filename = NULL; - char* datapubkey = NULL; - char* signpubkey = NULL; - char* signprivate = NULL; - char* signprivate_pem = NULL; - char* external_signer = NULL; - uint64_t flags = 0; - uint64_t pem_algorithm = 0; - int is_pem_algorithm = 0; - int mode = 0; - int parse_error = 0; - char* e; - int i; - - char *progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { - switch (i) { - case '?': - /* Unhandled option */ - printf("Unknown option\n"); - parse_error = 1; - break; - - case OPT_MODE_PACK: - case OPT_MODE_UNPACK: - mode = i; - filename = optarg; - break; - - case OPT_DATAPUBKEY: - datapubkey = optarg; - break; - - case OPT_SIGNPUBKEY: - signpubkey = optarg; - break; - - case OPT_SIGNPRIVATE: - signprivate = optarg; - break; - - case OPT_SIGNPRIVATE_PEM: - signprivate_pem = optarg; - break; - - case OPT_PEM_ALGORITHM: - pem_algorithm = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --pem_algorithm\n"); - parse_error = 1; - } else { - is_pem_algorithm = 1; - } - break; - - case OPT_EXTERNAL_SIGNER: - external_signer = optarg; - break; - - case OPT_FLAGS: - flags = strtoul(optarg, &e, 0); - if (!*optarg || (e && *e)) { - fprintf(stderr, "Invalid --flags\n"); - parse_error = 1; - } - break; - } - } - - /* Check if the right combination of options was provided. */ - if (signprivate && signprivate_pem) { - fprintf(stderr, "Only one of --signprivate or --signprivate_pem must" - " be specified\n"); - parse_error = 1; - } - - if (signprivate_pem && !is_pem_algorithm) { - fprintf(stderr, "--pem_algorithm must be used with --signprivate_pem\n"); - parse_error = 1; - } - - if (external_signer && !signprivate_pem) { - fprintf(stderr, "--externalsigner must be used with --signprivate_pem" - "\n"); - parse_error = 1; - } - - if (parse_error) - return PrintHelp(progname); - - switch(mode) { - case OPT_MODE_PACK: - return Pack(filename, datapubkey, signprivate, - signprivate_pem, pem_algorithm, - flags, - external_signer); - case OPT_MODE_UNPACK: - return Unpack(filename, datapubkey, signpubkey); - default: - printf("Must specify a mode.\n"); - return PrintHelp(progname); - } +static int do_vbutil_keyblock(int argc, char *argv[]) +{ + + char *filename = NULL; + char *datapubkey = NULL; + char *signpubkey = NULL; + char *signprivate = NULL; + char *signprivate_pem = NULL; + char *external_signer = NULL; + uint64_t flags = 0; + uint64_t pem_algorithm = 0; + int is_pem_algorithm = 0; + int mode = 0; + int parse_error = 0; + char *e; + int i; + + char *progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + case '?': + /* Unhandled option */ + printf("Unknown option\n"); + parse_error = 1; + break; + + case OPT_MODE_PACK: + case OPT_MODE_UNPACK: + mode = i; + filename = optarg; + break; + + case OPT_DATAPUBKEY: + datapubkey = optarg; + break; + + case OPT_SIGNPUBKEY: + signpubkey = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivate = optarg; + break; + + case OPT_SIGNPRIVATE_PEM: + signprivate_pem = optarg; + break; + + case OPT_PEM_ALGORITHM: + pem_algorithm = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --pem_algorithm\n"); + parse_error = 1; + } else { + is_pem_algorithm = 1; + } + break; + + case OPT_EXTERNAL_SIGNER: + external_signer = optarg; + break; + + case OPT_FLAGS: + flags = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --flags\n"); + parse_error = 1; + } + break; + } + } + + /* Check if the right combination of options was provided. */ + if (signprivate && signprivate_pem) { + fprintf(stderr, + "Only one of --signprivate or --signprivate_pem must" + " be specified\n"); + parse_error = 1; + } + + if (signprivate_pem && !is_pem_algorithm) { + fprintf(stderr, "--pem_algorithm must be used with" + " --signprivate_pem\n"); + parse_error = 1; + } + + if (external_signer && !signprivate_pem) { + fprintf(stderr, + "--externalsigner must be used with --signprivate_pem" + "\n"); + parse_error = 1; + } + + if (parse_error) + return PrintHelp(progname); + + switch (mode) { + case OPT_MODE_PACK: + return Pack(filename, datapubkey, signprivate, + signprivate_pem, pem_algorithm, + flags, external_signer); + case OPT_MODE_UNPACK: + return Unpack(filename, datapubkey, signpubkey); + default: + printf("Must specify a mode.\n"); + return PrintHelp(progname); + } } DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, diff --git a/futility/dump_kernel_config_lib.c b/futility/dump_kernel_config_lib.c index 63c2899f..d3e88a96 100644 --- a/futility/dump_kernel_config_lib.c +++ b/futility/dump_kernel_config_lib.c @@ -14,106 +14,109 @@ #include "vboot_api.h" #include "vboot_host.h" -static uint8_t* GetKernelConfig(uint8_t* blob, size_t blob_size, - uint64_t kernel_body_load_address) { - - VbKeyBlockHeader* key_block; - VbKernelPreambleHeader* preamble; - uint32_t now = 0; - uint32_t offset = 0; - - /* Skip the key block */ - key_block = (VbKeyBlockHeader*)blob; - now += key_block->key_block_size; - if (now + blob > blob + blob_size) { - VbExError("key_block_size advances past the end of the blob\n"); - return NULL; - } - - /* Open up the preamble */ - preamble = (VbKernelPreambleHeader*)(blob + now); - now += preamble->preamble_size; - if (now + blob > blob + blob_size) { - VbExError("preamble_size advances past the end of the blob\n"); - return NULL; - } - - /* Read body_load_address from preamble if no kernel_body_load_address */ - if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR) - kernel_body_load_address = preamble->body_load_address; - - /* The x86 kernels have a pointer to the kernel commandline in the zeropage - * table, but that's irrelevant for ARM. Both types keep the config blob in - * the same place, so just go find it. */ - offset = preamble->bootloader_address - - (kernel_body_load_address + CROS_PARAMS_SIZE + - CROS_CONFIG_SIZE) + now; - if (offset > blob_size) { - VbExError("params are outside of the memory blob: %x\n", offset); - return NULL; - } - return blob + offset; -} +static uint8_t *GetKernelConfig(uint8_t * blob, size_t blob_size, + uint64_t kernel_body_load_address) +{ -static void* MMapFile(const char* filename, size_t *size) { - FILE* f; - uint8_t* buf; - long file_size = 0; - - f = fopen(filename, "rb"); - if (!f) { - VBDEBUG(("Unable to open file %s\n", filename)); - return NULL; - } - - fseek(f, 0, SEEK_END); - file_size = ftell(f); - rewind(f); - - if (file_size <= 0) { - fclose(f); - return NULL; - } - *size = (size_t) file_size; - - /* Uses a host primitive as this is not meant for firmware use. */ - buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0); - if (buf == MAP_FAILED) { - VbExError("Failed to mmap the file %s\n", filename); - fclose(f); - return NULL; - } - - fclose(f); - return buf; + VbKeyBlockHeader *key_block; + VbKernelPreambleHeader *preamble; + uint32_t now = 0; + uint32_t offset = 0; + + /* Skip the key block */ + key_block = (VbKeyBlockHeader *) blob; + now += key_block->key_block_size; + if (now + blob > blob + blob_size) { + VbExError("key_block_size advances past the end of the blob\n"); + return NULL; + } + + /* Open up the preamble */ + preamble = (VbKernelPreambleHeader *) (blob + now); + now += preamble->preamble_size; + if (now + blob > blob + blob_size) { + VbExError("preamble_size advances past the end of the blob\n"); + return NULL; + } + + /* Read body_load_address from preamble if no + * kernel_body_load_address */ + if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR) + kernel_body_load_address = preamble->body_load_address; + + /* The x86 kernels have a pointer to the kernel commandline in the + * zeropage table, but that's irrelevant for ARM. Both types keep the + * config blob in the same place, so just go find it. */ + offset = preamble->bootloader_address - + (kernel_body_load_address + CROS_PARAMS_SIZE + + CROS_CONFIG_SIZE) + now; + if (offset > blob_size) { + VbExError("params are outside of the memory blob: %x\n", + offset); + return NULL; + } + return blob + offset; } +static void *MMapFile(const char *filename, size_t * size) +{ + FILE *f; + uint8_t *buf; + long file_size = 0; + + f = fopen(filename, "rb"); + if (!f) { + VBDEBUG(("Unable to open file %s\n", filename)); + return NULL; + } + + fseek(f, 0, SEEK_END); + file_size = ftell(f); + rewind(f); + + if (file_size <= 0) { + fclose(f); + return NULL; + } + *size = (size_t) file_size; + + /* Uses a host primitive as this is not meant for firmware use. */ + buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0); + if (buf == MAP_FAILED) { + VbExError("Failed to mmap the file %s\n", filename); + fclose(f); + return NULL; + } + + fclose(f); + return buf; +} char *FindKernelConfig(const char *infile, uint64_t kernel_body_load_address) { - uint8_t* blob; - size_t blob_size; - uint8_t *config = NULL; - char *newstr = NULL; - - blob = MMapFile(infile, &blob_size); - if (!blob) { - VbExError("Error reading input file\n"); - return 0; - } - - config = GetKernelConfig(blob, blob_size, kernel_body_load_address); - if (!config) { - VbExError("Error parsing input file\n"); - munmap(blob, blob_size); - return 0; - } - - newstr = strndup((char *)config, CROS_CONFIG_SIZE); - if (!newstr) - VbExError("Can't allocate new string\n"); - - munmap(blob, blob_size); - - return newstr; + uint8_t *blob; + size_t blob_size; + uint8_t *config = NULL; + char *newstr = NULL; + + blob = MMapFile(infile, &blob_size); + if (!blob) { + VbExError("Error reading input file\n"); + return 0; + } + + config = GetKernelConfig(blob, blob_size, kernel_body_load_address); + if (!config) { + VbExError("Error parsing input file\n"); + munmap(blob, blob_size); + return 0; + } + + newstr = strndup((char *)config, CROS_CONFIG_SIZE); + if (!newstr) + VbExError("Can't allocate new string\n"); + + munmap(blob, blob_size); + + return newstr; } diff --git a/futility/futility.c b/futility/futility.c index a16beeb1..3496cdc2 100644 --- a/futility/futility.c +++ b/futility/futility.c @@ -28,7 +28,7 @@ /******************************************************************************/ -static const char * const usage= "\n\ +static const char *const usage = "\n\ Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\ \n\ This is the unified firmware utility, which will eventually replace\n\ @@ -45,25 +45,26 @@ In either case it will append some usage information to " LOGFILE "\n\ static int do_help(int argc, char *argv[]) { - const struct futil_cmd_t * const *cmd; - int i; + const struct futil_cmd_t *const *cmd; + int i; - fputs(usage, stdout); + fputs(usage, stdout); - printf("The following commands are built-in:\n\n"); + printf("The following commands are built-in:\n\n"); - for (cmd = futil_cmds; *cmd; cmd++) - printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp); - printf("\n"); + for (cmd = futil_cmds; *cmd; cmd++) + printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp); + printf("\n"); - if (argc) { - printf("FYI, you added these args that I'm ignoring:\n"); - for (i = 0; i < argc; i++) - printf("argv[%d] = %s\n", i, argv[i]); - } + if (argc) { + printf("FYI, you added these args that I'm ignoring:\n"); + for (i = 0; i < argc; i++) + printf("argv[%d] = %s\n", i, argv[i]); + } - return 0; + return 0; } + DECLARE_FUTIL_COMMAND(help, do_help, "Show a bit of help (you're looking at it)"); @@ -71,11 +72,11 @@ DECLARE_FUTIL_COMMAND(help, do_help, * These are built-in functions that we'd like to abandon completely someday. * TODO: If no one complains, get rid of them. */ -static const char * const dep_cmds[] = { - "dev_sign_file", +static const char *const dep_cmds[] = { + "dev_sign_file", }; -static const char * const dep_usage= "\n\ +static const char *const dep_usage = "\n\ The program \"%s\" is deprecated and may go away soon.\n\ \n\ If you feel this is in error, please open a bug at\n\ @@ -89,8 +90,8 @@ In the meantime, you may continue to use the program by invoking it as\n\ static void deprecated(const char *depname) { - fprintf(stderr, dep_usage, depname, depname); - exit(1); + fprintf(stderr, dep_usage, depname, depname); + exit(1); } /******************************************************************************/ @@ -101,188 +102,187 @@ static int log_fd = -1; /* Write the string and a newline. Silently give up on errors */ static void log_str(char *str) { - int len, done, n; + int len, done, n; - if (log_fd < 0) - return; + if (log_fd < 0) + return; - if (!str) - str = "(NULL)"; + if (!str) + str = "(NULL)"; - len = strlen(str); - if (len == 0) { - str = "(EMPTY)"; - len = strlen(str); - } + len = strlen(str); + if (len == 0) { + str = "(EMPTY)"; + len = strlen(str); + } - for (done = 0; done < len; done += n) { - n = write(log_fd, str + done, len - done); - if (n < 0) - return; - } + for (done = 0; done < len; done += n) { + n = write(log_fd, str + done, len - done); + if (n < 0) + return; + } - if (write(log_fd, "\n", 1) < 0) - return; + if (write(log_fd, "\n", 1) < 0) + return; } static void log_close(void) { - struct flock lock; - - if (log_fd >= 0) { - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - if (fcntl(log_fd, F_SETLKW, &lock)) - perror("Unable to unlock log file"); - - close(log_fd); - log_fd = -1; - } + struct flock lock; + + if (log_fd >= 0) { + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + if (fcntl(log_fd, F_SETLKW, &lock)) + perror("Unable to unlock log file"); + + close(log_fd); + log_fd = -1; + } } static void log_open(void) { - struct flock lock; - int ret; + struct flock lock; + int ret; #ifdef FORCE_LOGGING_ON - log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666); + log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666); #else - log_fd = open(LOGFILE, O_WRONLY|O_APPEND); + log_fd = open(LOGFILE, O_WRONLY | O_APPEND); #endif - if (log_fd < 0) { + if (log_fd < 0) { - if (errno != EACCES) - return; + if (errno != EACCES) + return; - /* Permission problems should improve shortly ... */ - sleep(1); - log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666); - if (log_fd < 0) /* Nope, they didn't */ - return; - } + /* Permission problems should improve shortly ... */ + sleep(1); + log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666); + if (log_fd < 0) /* Nope, they didn't */ + return; + } - /* Let anyone have a turn */ - fchmod(log_fd, 0666); + /* Let anyone have a turn */ + fchmod(log_fd, 0666); - /* But only one at a time */ - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_END; + /* But only one at a time */ + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_END; - ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */ - if (ret < 0) - log_close(); + ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */ + if (ret < 0) + log_close(); } #define CALLER_PREFIX "CALLER:" static void log_args(int argc, char *argv[]) { - int i; - ssize_t r; - pid_t parent; - char buf[80]; - char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX; - char *truename = str_caller + sizeof(CALLER_PREFIX) - 1; - /* Note: truename starts on the \0 from CALLER_PREFIX, so we can write - * PATH_MAX chars into truename and still append a \0 at the end. */ - - log_open(); - - /* delimiter */ - log_str("##### HEY #####"); - - /* Can we tell who called us? */ - parent = getppid(); - snprintf(buf, sizeof(buf), "/proc/%d/exe", parent); - r = readlink(buf, truename, PATH_MAX); - if (r >= 0) { - truename[r] = '\0'; - log_str(str_caller); - } - - /* Now log the stuff about ourselves */ - for (i = 0; i < argc; i++) - log_str(argv[i]); - - log_close(); + int i; + ssize_t r; + pid_t parent; + char buf[80]; + char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX; + char *truename = str_caller + sizeof(CALLER_PREFIX) - 1; + /* Note: truename starts on the \0 from CALLER_PREFIX, so we can write + * PATH_MAX chars into truename and still append a \0 at the end. */ + + log_open(); + + /* delimiter */ + log_str("##### HEY #####"); + + /* Can we tell who called us? */ + parent = getppid(); + snprintf(buf, sizeof(buf), "/proc/%d/exe", parent); + r = readlink(buf, truename, PATH_MAX); + if (r >= 0) { + truename[r] = '\0'; + log_str(str_caller); + } + + /* Now log the stuff about ourselves */ + for (i = 0; i < argc; i++) + log_str(argv[i]); + + log_close(); } - /******************************************************************************/ /* Here we go */ int main(int argc, char *argv[], char *envp[]) { - char *fullname, *progname; - char truename[PATH_MAX]; - char buf[80]; - pid_t myproc; - ssize_t r; - const struct futil_cmd_t * const *cmd; - int i; - int via_symlink = 0; - - log_args(argc, argv); - - /* How were we invoked? */ - fullname = strdup(argv[0]); - progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - /* Invoked directly by name */ - if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) { - if (argc < 2) { /* must have an argument */ - do_help(0, 0); - exit(1); - } - - /* We can just pass the rest along, then */ - argc--; - argv++; - - /* So now what function do we want to invoke? */ - progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - } else { /* Invoked by symlink */ - via_symlink = 1; - /* Block any deprecated functions. */ - for (i = 0; i < ARRAY_SIZE(dep_cmds); i++) - if (0 == strcmp(dep_cmds[i], progname)) - deprecated(progname); - } - - /* See if it's asking for something we know how to do ourselves */ - for (cmd = futil_cmds; *cmd; cmd++) - if (0 == strcmp((*cmd)->name, progname)) - return (*cmd)->handler(argc, argv); - - /* Nope */ - if (!via_symlink) { - do_help(0, 0); - exit(1); - } - - /* Complain about bogus symlink */ - - myproc = getpid(); - snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc); - r = readlink(buf, truename, PATH_MAX - 1); - if (r < 0) { - fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0], - buf, strerror(errno)); - exit(1); - } - truename[r] = '\0'; - - fprintf(stderr, "\n\ + char *fullname, *progname; + char truename[PATH_MAX]; + char buf[80]; + pid_t myproc; + ssize_t r; + const struct futil_cmd_t *const *cmd; + int i; + int via_symlink = 0; + + log_args(argc, argv); + + /* How were we invoked? */ + fullname = strdup(argv[0]); + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + /* Invoked directly by name */ + if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) { + if (argc < 2) { /* must have an argument */ + do_help(0, 0); + exit(1); + } + + /* We can just pass the rest along, then */ + argc--; + argv++; + + /* So now what function do we want to invoke? */ + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + } else { /* Invoked by symlink */ + via_symlink = 1; + /* Block any deprecated functions. */ + for (i = 0; i < ARRAY_SIZE(dep_cmds); i++) + if (0 == strcmp(dep_cmds[i], progname)) + deprecated(progname); + } + + /* See if it's asking for something we know how to do ourselves */ + for (cmd = futil_cmds; *cmd; cmd++) + if (0 == strcmp((*cmd)->name, progname)) + return (*cmd)->handler(argc, argv); + + /* Nope */ + if (!via_symlink) { + do_help(0, 0); + exit(1); + } + + /* Complain about bogus symlink */ + + myproc = getpid(); + snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc); + r = readlink(buf, truename, PATH_MAX - 1); + if (r < 0) { + fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0], + buf, strerror(errno)); + exit(1); + } + truename[r] = '\0'; + + fprintf(stderr, "\n\ The program\n\n %s\n\nis a symlink to\n\n %s\n\ \n\ However, " MYNAME " doesn't know how to implement that function.\n\ @@ -292,5 +292,5 @@ after a fresh checkout/build/install, please open a bug at\n\ \n\ http://dev.chromium.org/for-testers/bug-reporting-guidelines\n\ \n", fullname, truename); - return 1; + return 1; } diff --git a/futility/futility.h b/futility/futility.h index 387c7156..32c553db 100644 --- a/futility/futility.h +++ b/futility/futility.h @@ -10,9 +10,9 @@ /* Here's a structure to define the commands that futility implements. */ struct futil_cmd_t { - const char * const name; - int (*const handler)(int argc, char **argv); - const char * const shorthelp; + const char *const name; + int (*const handler) (int argc, char **argv); + const char *const shorthelp; }; /* @@ -33,7 +33,7 @@ struct futil_cmd_t { = &__cmd_##NAME /* This is the list of pointers to all commands. */ -extern const struct futil_cmd_t * const futil_cmds[]; +extern const struct futil_cmd_t *const futil_cmds[]; /* Size of an array */ #ifndef ARRAY_SIZE diff --git a/futility/kernel_blob.h b/futility/kernel_blob.h index 173d48d2..6ecc02d7 100644 --- a/futility/kernel_blob.h +++ b/futility/kernel_blob.h @@ -1,65 +1,62 @@ -// Copyright 2010 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Constants describing the kernel blob content. - +/* Copyright 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Constants describing the kernel blob content. + */ #ifndef VBOOT_REFERENCE_KERNEL_BLOB_H_ #define VBOOT_REFERENCE_KERNEL_BLOB_H_ - -// Maximum kernel command-line size +/* Maximum kernel command-line size */ #define CROS_CONFIG_SIZE 4096 -// Size of the x86 zeropage table +/* Size of the x86 zeropage table */ #define CROS_PARAMS_SIZE 4096 -// Alignment of various chunks within the kernel blob +/* Alignment of various chunks within the kernel blob */ #define CROS_ALIGN 4096 -// Sentinel RAM address indicating that no entry address is specified +/* Sentinel RAM address indicating that no entry address is specified */ #define CROS_NO_ENTRY_ADDR (~0) -// RAM address where the 32-bit kernel expects to be started +/* RAM address where the 32-bit kernel expects to be started */ #define CROS_32BIT_ENTRY_ADDR 0x100000 -// Simplified version of x86 kernel e820 memory map entries +/* Simplified version of x86 kernel e820 memory map entries */ #define E820_ENTRY_MAX 128 #define E820_TYPE_RAM 1 #define E820_TYPE_RESERVED 2 struct linux_kernel_e820entry { - uint64_t start_addr; - uint64_t segment_size; - uint32_t segment_type; -} __attribute__((packed)); - -// Simplified version of the x86 kernel zeropage table -struct linux_kernel_params -{ - uint8_t pad0[0x1e8 - 0x0]; - uint8_t n_e820_entry; // 1e8 - uint8_t pad1[0x1f1 - 0x1e9]; - uint8_t setup_sects; // 1f1 - uint8_t pad2[0x1fe - 0x1f2]; - uint16_t boot_flag; // 1fe - uint16_t jump; // 200 - uint32_t header; // 202 - uint16_t version; // 206 - uint8_t pad3[0x210 - 0x208]; - uint8_t type_of_loader; // 210 - uint8_t pad4[0x218 - 0x211]; - uint32_t ramdisk_image; // 218 - uint32_t ramdisk_size; // 21c - uint8_t pad5[0x228 - 0x220]; - uint32_t cmd_line_ptr; // 228 - uint32_t ramdisk_max; // 22c - uint32_t kernel_alignment; // 230 - uint8_t relocatable_kernel; // 234 - uint8_t min_alignment; // 235 - uint8_t pad6[0x2d0 - 0x236]; - struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; // 2d0 - cd0 + uint64_t start_addr; + uint64_t segment_size; + uint32_t segment_type; } __attribute__ ((packed)); +/* Simplified version of the x86 kernel zeropage table */ +struct linux_kernel_params { + uint8_t pad0[0x1e8 - 0x0]; + uint8_t n_e820_entry; /* 1e8 */ + uint8_t pad1[0x1f1 - 0x1e9]; + uint8_t setup_sects; /* 1f1 */ + uint8_t pad2[0x1fe - 0x1f2]; + uint16_t boot_flag; /* 1fe */ + uint16_t jump; /* 200 */ + uint32_t header; /* 202 */ + uint16_t version; /* 206 */ + uint8_t pad3[0x210 - 0x208]; + uint8_t type_of_loader; /* 210 */ + uint8_t pad4[0x218 - 0x211]; + uint32_t ramdisk_image; /* 218 */ + uint32_t ramdisk_size; /* 21c */ + uint8_t pad5[0x228 - 0x220]; + uint32_t cmd_line_ptr; /* 228 */ + uint32_t ramdisk_max; /* 22c */ + uint32_t kernel_alignment; /* 230 */ + uint8_t relocatable_kernel; /* 234 */ + uint8_t min_alignment; /* 235 */ + uint8_t pad6[0x2d0 - 0x236]; + struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; /* 2d0-cd0 */ +} __attribute__ ((packed)); -#endif // VBOOT_REFERENCE_KERNEL_BLOB_H_ +#endif /* VBOOT_REFERENCE_KERNEL_BLOB_H_ */ |