diff options
author | Bill Richardson <wfrichar@chromium.org> | 2014-07-15 12:52:19 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-07-31 22:46:27 +0000 |
commit | 6f3961507e73f90cec665896dece884e86be560a (patch) | |
tree | 0f11e2ca91c3c5be6ed30748b0d9224c6ede456a /utility | |
parent | b52d7b7acb14743747489ed7323b416bc001503b (diff) | |
download | vboot-6f3961507e73f90cec665896dece884e86be560a.tar.gz |
futility: Add remaining vboot binary utilities
This change adds these formerly external utilities into the futility binary:
dev_sign_file
dump_kernel_config
gbb_utility
vbutil_firmware
vbutil_kernel
These target binaries will remain independent of futility, since they are
not directly related to verified boot:
cgpt
crossystem
tpm_init_temp_fix
tpmc
Also, dumpRSAPublicKey is removed from the target, since it is only used on
the build host to create new keypairs.
This change also add several additional tests.
BUG=chromium:224734
BRANCH=ToT
CQ-DEPEND=CL:210391,CL:210568,CL:210587
TEST=manual
make runtests
make clean
Also build and test:
- normal image
- test image
- recovery image
- firmware shellball
Note that this CL depends on simultaneous changes to the chromeos-initramfs
ebuild.
Change-Id: If791b5e9b5aac218ceafa9f45fc1785f16b91a64
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/210403
Diffstat (limited to 'utility')
-rw-r--r-- | utility/dev_sign_file.c | 355 | ||||
-rw-r--r-- | utility/dump_kernel_config.c | 89 | ||||
-rw-r--r-- | utility/dump_kernel_config_lib.c | 119 | ||||
-rw-r--r-- | utility/gbb_utility.cc | 4 | ||||
-rw-r--r-- | utility/include/kernel_blob.h | 65 | ||||
-rw-r--r-- | utility/vbutil_firmware.c | 373 | ||||
-rw-r--r-- | utility/vbutil_kernel.c | 968 |
7 files changed, 2 insertions, 1971 deletions
diff --git a/utility/dev_sign_file.c b/utility/dev_sign_file.c deleted file mode 100644 index b20423ff..00000000 --- a/utility/dev_sign_file.c +++ /dev/null @@ -1,355 +0,0 @@ -/* Copyright (c) 2011 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. - * - * Developer file-signing utility - */ - -#include <errno.h> -#include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "cryptolib.h" -#include "host_common.h" -#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, -}; - -static 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} -}; - - -/* 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 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); -} - - -/* 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 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; -} - - -int main(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; -} diff --git a/utility/dump_kernel_config.c b/utility/dump_kernel_config.c deleted file mode 100644 index ec0ee5ab..00000000 --- a/utility/dump_kernel_config.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2012 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. - * - * Exports the kernel commandline from a given partition/image. - */ - - -#include <getopt.h> -#include <stdio.h> -#include <sys/mman.h> -#include <unistd.h> - -#include "vboot_host.h" - -enum { - OPT_KLOADADDR = 1000, -}; - -static struct option long_opts[] = { - { "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; -} - -int main(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; -} diff --git a/utility/dump_kernel_config_lib.c b/utility/dump_kernel_config_lib.c deleted file mode 100644 index 819ca921..00000000 --- a/utility/dump_kernel_config_lib.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2012 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. - * - * Exports the kernel commandline from a given partition/image. - */ - -#include <stdio.h> -#include <string.h> -#include <sys/mman.h> - -#include "host_common.h" -#include "kernel_blob.h" -#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 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; -} diff --git a/utility/gbb_utility.cc b/utility/gbb_utility.cc index 980521c5..2a8c2347 100644 --- a/utility/gbb_utility.cc +++ b/utility/gbb_utility.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +// Copyright 2011 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. // @@ -609,7 +609,7 @@ static bool parse_creation_param(const string &input_string, if (*parsed && *parsed != ',') return false; output_vector->push_back(param); - input = parsed + 1; + input = *parsed ? parsed + 1 : parsed; } while (*input); return true; diff --git a/utility/include/kernel_blob.h b/utility/include/kernel_blob.h deleted file mode 100644 index f9175f65..00000000 --- a/utility/include/kernel_blob.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 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 -#define CROS_CONFIG_SIZE 4096 - -// Size of the x86 zeropage table -#define CROS_PARAMS_SIZE 4096 - -// Alignment of various chunks within the kernel blob -#define CROS_ALIGN 4096 - -// 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 -#define CROS_32BIT_ENTRY_ADDR 0x100000 - -// 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 -} __attribute__ ((packed)); - - -#endif // VBOOT_REFERENCE_KERNEL_BLOB_H_ diff --git a/utility/vbutil_firmware.c b/utility/vbutil_firmware.c deleted file mode 100644 index f11d7b54..00000000 --- a/utility/vbutil_firmware.c +++ /dev/null @@ -1,373 +0,0 @@ -/* Copyright (c) 2011 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. - * - * Verified boot firmware utility - */ - -#include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "cryptolib.h" -#include "host_common.h" -#include "kernel_blob.h" -#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, -}; - -static 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} -}; - - -/* 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; -} - - -/* 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 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; -} - - -int main(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(); - } -} diff --git a/utility/vbutil_kernel.c b/utility/vbutil_kernel.c deleted file mode 100644 index 5fed77ac..00000000 --- a/utility/vbutil_kernel.c +++ /dev/null @@ -1,968 +0,0 @@ -/* Copyright (c) 2012 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. - * - * Verified boot kernel utility - */ - -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <inttypes.h> /* For PRIu64 */ -#include <sys/ioctl.h> -#include <linux/fs.h> /* For BLKGETSIZE64 */ -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "cryptolib.h" -#include "host_common.h" -#include "kernel_blob.h" -#include "util_misc.h" -#include "vboot_common.h" - -/* Global opts */ -static int opt_debug = 0; -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, -}; - -typedef enum { - ARCH_ARM, - ARCH_X86, /* default */ - ARCH_MIPS -} arch_t; - -static 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} -}; - - -/* 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 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); -} - -/* 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; -} - -/* 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; -} - - -/* 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; -} - - -/****************************************************************************/ -/* Here are globals containing all the bits & pieces I'm working on. */ - -/* The individual parts that go into the kernel blob */ -uint8_t *g_kernel_data; -uint64_t g_kernel_size; -uint8_t *g_param_data; -uint64_t g_param_size; -uint8_t *g_config_data; -uint64_t g_config_size; -uint8_t *g_bootloader_data; -uint64_t g_bootloader_size; -uint64_t g_bootloader_address; - - -/* The individual parts of the verification blob (including the data that - * immediately follows the headers) */ -VbKeyBlockHeader* g_keyblock; -VbKernelPreambleHeader* g_preamble; - -/****************************************************************************/ - -/* - * Read the kernel command line from a file. Get rid of \n characters along - * the way and verify that the line fits into a 4K buffer. - * - * 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) -{ - 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; -} - - -/* 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; -} - -/* 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; -} - -/* 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; -} - - -/* 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 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 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; -} - -/****************************************************************************/ - -int main(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")) - 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); - - case OPT_MODE_REPACK: - - /* Required */ - - 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"); - - /* Load the old blob */ - - kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size); - if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0)) - Fatal("The oldblob doesn't verify\n"); - - /* Take it apart */ - - UnpackKernelBlob(kernel_blob, kernel_size); - free(kernel_blob); - - /* Load optional params */ - - if (!version_str) - version = g_preamble->kernel_version; - - if (!address_str) - kernel_body_load_address = g_preamble->body_load_address; - - 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 (keyblock_file) { - if (g_keyblock) - free(g_keyblock); - g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0); - if (!g_keyblock) - Fatal("Error reading key block.\n"); - } - - /* Put it back together */ - - 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: - - /* Optional */ - - if (signpubkey_file) { - signpub_key = PublicKeyRead(signpubkey_file); - if (!signpub_key) - Fatal("Error reading public key.\n"); - } - - /* Do it */ - - kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size); - - 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); -} |