From bc3f0b74f9e8c8ca043f579d25cbf22a92ea209d Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Fri, 5 Sep 2014 12:40:20 -0700 Subject: cleanup: remove a couple of unused functions and files scripts/sign_data.sh is just a wrapper to do this: ./signature_digest_utility $1 $3 \ | openssl rsautl -sign -pkcs -inkey $2 AFAICT, that script is only invoked by the SignatureFile() function in host/lib/file_keys.c, which is not referenced by anything. I think I can remove both of those things. Also remove utility/gbb_utility.cc, which should have been done long ago in commit 6f39615. BUG=none BRANCH=ToT TEST=make runalltests Also ran it on daisy_spring-paladin and link-tot-paladin. Change-Id: I16de5022765806f11bf6144d7ffd8cc849578a68 Signed-off-by: Bill Richardson Reviewed-on: https://chromium-review.googlesource.com/216719 Reviewed-by: Mike Frysinger --- README | 141 ++++--- host/lib/file_keys.c | 39 -- host/lib/include/file_keys.h | 9 - host/linktest/main.c | 1 - scripts/sign_data.sh | 13 - utility/gbb_utility.cc | 879 ------------------------------------------- 6 files changed, 80 insertions(+), 1002 deletions(-) delete mode 100755 scripts/sign_data.sh delete mode 100644 utility/gbb_utility.cc diff --git a/README b/README index 8242fff8..e0933904 100644 --- a/README +++ b/README @@ -1,30 +1,53 @@ This directory contains a reference implementation for Chrome OS verified boot in firmware. ----------- -Directory Structure +---------- +Directory Structure ---------- The source is organized into distinct modules - -firmware/ - Contains ONLY the code required by the BIOS to validate -the secure boot components. There shouldn't be any code in here that -signs or generates images. BIOS should require ONLY this directory to -implement secure boot. Refer to firmware/README for futher details. +firmware/ + + Contains ONLY the code required by the BIOS to validate the secure boot + components. There shouldn't be any code in here that signs or generates + images. BIOS should require ONLY this directory to implement secure boot. + Refer to firmware/README for futher details. + +cgpt/ + + Utility to read/write/modify GPT partitions. Similar to GNU parted or any + other GPT tool, but this has support for Chrome OS extensions. + +host/ + + Miscellaneous functions needed by userland utilities. + +futility/ + + The "firmware utility" tool, used to create, sign, and validate Chrome OS + images. + +utility/ + + Random other utilities, not necesssarily related to verified boot as such. + +tests/ -cgpt/ - Utility to read/write/modify GPT partitions. Much like the -gpt tool, but with support for Chrome OS extensiosn. + User-land tests and benchmarks that test the reference implementation. + Please have a look at these if you'd like to understand how to use the + reference implementation. -host/ - Miscellaneous functions used by userland utilities. +build/ -utility/ - Utilities for generating and verifying signed -firmware and kernel images, as well as arbitrary blobs. + The output directory where the generated files will be placed, and where + tests are run. -tests/ - User-land tests and benchmarks that test the reference -implementation. Please have a look at these if you'd like to -understand how to use the reference implementation. +scripts/ + + Tools and scripts used to generate and use new signing keypairs. These are + typically used only on a secure machine. -build/ - a directory where the generated files go to. -------------------- Building and testing @@ -37,67 +60,63 @@ there are host environment build problems due to missing .h files, try researching what packages the files belong to and install the missing packages before reporting a problem. -To build the software run - -make -in the top level directory. The build output is placed in the ./build -directory. +The commands are the more-or-less expected ones: -To run the tests either invoke + make + make runtests + make install [ DESTDIR=/usr/local/bin ] -RUNTESTS=1 make -in the top level directory or -cd tests -BUILD=../build make runtests +---------- +Some useful utilities: +---------- +futility vbutil_key Convert a public key into .vbpubk format +futility vbutil_keyblock Wrap a public key inside a signature and checksum +futility vbutil_firmware Create a .vblock with signature info for a + firmware image +futility vbutil_kernel Pack a kernel image, bootloader, and config into + a signed binary ----------- -Some useful utilities: ----------- +dumpRSAPublicKey Dump RSA Public key (from a DER-encoded X509 + certificate) in a format suitable for use by + RSAVerify* functions in crypto/. -vbutil_key Convert a public key into .vbpubk format -vbutil_keyblock Wrap a public key inside a signature and checksum -vbutil_firmware Create a .vblock with signature info for a - firmware image -vbutil_kernel Pack a kernel image, bootloader, and config into - a signed binary +verify_data.c Verify a given signature on a given file. -dumpRSAPublicKey Dump RSA Public key (from a DER-encoded X509 - certificate) in a format suitable for - use by RSAVerify* functions in - crypto/. -verify_data.c Verify a given signature on a given file. - - ----------- -Generating a signed firmware image: ---------- +Generating a signed firmware image: +---------- + +* Step 0: Build the tools, install them somewhere. * Step 1: Generate RSA root and signing keys. -# Root key is always 8192 bits. -$ openssl genrsa -F4 -out root_key.pem 8192 + The root key is always 8192 bits. + + $ openssl genrsa -F4 -out root_key.pem 8192 -# Signing key can be between 1024-8192 bits. -$ openssl genrsa -F4 -out signing_key.pem <1024|2048|4096|8192> + The signing key can be between 1024-8192 bits. -Note: The -F4 option must be specified to generate RSA keys with - a public exponent of 65535. RSA keys with 3 as a public - exponent (the default) won't work. + $ openssl genrsa -F4 -out signing_key.pem <1024|2048|4096|8192> + + Note: The -F4 option must be specified to generate RSA keys with a public + exponent of 65535. RSA keys with 3 as a public exponent (the default) + won't work. * Step 2: Generate pre-processed public versions of the above keys using - utility/dumpRSAPublicKey + dumpRSAPublicKey. This utility expects an x509 certificate as + input, and emits an intermediate representation for further + processing. -# dumpRSAPublicKey expects an x509 certificate as input. -$ openssl req -batch -new -x509 -key root_key.pem -out root_key.crt -$ openssl req -batch -new -x509 -key signing_key.pem -out signing_key.crt -$ utility/dumpRSAPublicKey root_key.crt > root_key.keyb -$ utility/dumpRSAPublicKey signing_key.crt > signing_key.keyb + $ openssl req -batch -new -x509 -key root_key.pem -out root_key.crt + $ openssl req -batch -new -x509 -key signing_key.pem -out signing_key.crt + $ dumpRSAPublicKey root_key.crt > root_key.keyb + $ dumpRSAPublicKey signing_key.crt > signing_key.keyb ************** TODO: STUFF PAST HERE IS OUT OF DATE *************** @@ -121,13 +140,13 @@ $ utility/firmware_utility --generate \ --in \ --out -Where is based on the signature algorithm to use for firmware +Where is based on the signature algorithm to use for firmware signining. The list of specifications can be output by running 'utility/firmware_utility' without any arguments. -Note: --firmware_key_version and --firmware_version are part of a signed +Note: --firmware_key_version and --firmware_version are part of a signed image and are used to prevent rollbacks to older version. For testing, - they can just be set valid values. + they can just be set to valid values. * Step 4: Verify that this image verifies. @@ -144,8 +163,8 @@ Note: The verification functions expects a pointer to the final firmware, this will be a fixed public key which cannot be changed and must be stored in RO firmware. ----------- -Generating a signed kernel image: +---------- +Generating a signed kernel image: ---------- The steps for generating a signed kernel image are similar to that of diff --git a/host/lib/file_keys.c b/host/lib/file_keys.c index c311e6ac..ac9af17d 100644 --- a/host/lib/file_keys.c +++ b/host/lib/file_keys.c @@ -79,42 +79,3 @@ uint8_t* DigestFile(char* input_file, int sig_algorithm) { close(input_fd); return digest; } - -uint8_t* SignatureFile(const char* input_file, const char* key_file, - unsigned int algorithm) { - char* sign_utility = "./sign_data.sh"; - char* cmd; /* Command line to invoke. */ - int cmd_len; - FILE* cmd_out; /* File descriptor to command output. */ - uint8_t* signature = NULL; - int signature_size = siglen_map[algorithm]; - - /* Build command line: - * sign_data.sh - */ - cmd_len = (strlen(sign_utility) + 1 + /* +1 for space. */ - 2 + 1 + /* For [algorithm]. */ - strlen(key_file) + 1 + /* +1 for space. */ - strlen(input_file) + - 1); /* For the trailing '\0'. */ - cmd = (char*) malloc(cmd_len); - snprintf(cmd, cmd_len, "%s %u %s %s", sign_utility, algorithm, key_file, - input_file); - cmd_out = popen(cmd, "r"); - free(cmd); - if (!cmd_out) { - VBDEBUG(("Couldn't execute: %s\n", cmd)); - return NULL; - } - - signature = (uint8_t*) malloc(signature_size); - if (fread(signature, signature_size, 1, cmd_out) != 1) { - VBDEBUG(("Couldn't read signature.\n")); - pclose(cmd_out); - free(signature); - return NULL; - } - - pclose(cmd_out); - return signature; -} diff --git a/host/lib/include/file_keys.h b/host/lib/include/file_keys.h index 39fdc5ac..ac6f9ee4 100644 --- a/host/lib/include/file_keys.h +++ b/host/lib/include/file_keys.h @@ -31,13 +31,4 @@ RSAPublicKey* RSAPublicKeyFromFile(const char* input_file); */ uint8_t* DigestFile(char* input_file, int sig_algorithm); -/* Helper function to invoke external program to calculate signature on - * [input_file] using private key [key_file] and signature algorithm - * [algorithm]. - * - * Returns the signature. Caller owns the buffer and must Free() it. - */ -uint8_t* SignatureFile(const char* input_file, const char* key_file, - unsigned int algorithm); - #endif /* VBOOT_REFERENCE_FILE_KEYS_H_ */ diff --git a/host/linktest/main.c b/host/linktest/main.c index 56ab21cd..7ad89ee6 100644 --- a/host/linktest/main.c +++ b/host/linktest/main.c @@ -47,7 +47,6 @@ int main(void) BufferFromFile(0, 0); RSAPublicKeyFromFile(0); DigestFile(0, 0); - SignatureFile(0, 0, 0); /* signature_digest.h */ PrependDigestInfo(0, 0); diff --git a/scripts/sign_data.sh b/scripts/sign_data.sh deleted file mode 100755 index 05de5a6b..00000000 --- a/scripts/sign_data.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# 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. - -if [ $# -ne 3 ] -then - echo "Usage: `basename $0` " - exit -1 -fi - -./signature_digest_utility $1 $3 | openssl rsautl -sign -pkcs -inkey $2 diff --git a/utility/gbb_utility.cc b/utility/gbb_utility.cc deleted file mode 100644 index 2a8c2347..00000000 --- a/utility/gbb_utility.cc +++ /dev/null @@ -1,879 +0,0 @@ -// 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. -// -// Utility for manipulating Google Binary Block (GBB) -// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "gbb_utility.h" - -using std::string; - -/////////////////////////////////////////////////////////////////////// -// Simple File Utilities - -// utility function: read a non-empty file. -// return file content, or empty for any failure. -static string read_nonempty_file(const char *filename) { - string file_content; - std::vector buffer; // since image files are small, should be OK - - FILE *fp = fopen(filename, "rb"); - if (!fp) { - perror(filename); - return file_content; - } - - // prepare buffer on successful seek - if (fseek(fp, 0, SEEK_END) == 0) { - buffer.resize(ftell(fp)); - rewind(fp); - } - - if (!buffer.empty()) { - if (fread(&buffer[0], buffer.size(), 1, fp) != 1) { - perror(filename); - buffer.clear(); // discard buffer when read fail. - } else { - file_content.assign(buffer.begin(), buffer.end()); - } - } - - fclose(fp); - return file_content; -} - -// utility function: write non-empty content to file. -// return true on success, otherwise false. -static bool write_nonempty_file(const char *filename, const string &content) { - assert(!content.empty()); - - FILE *fp = fopen(filename, "wb"); - if (!fp) { - perror(filename); - return false; - } - - int r = fwrite(content.c_str(), content.size(), 1, fp); - fclose(fp); - - if (r != 1) - perror(filename); - - return r == 1; -} - -// utility function: convert integer to little-endian encoded bytes -// return the byte array in string type -static string int2bytes(const uint32_t value) { - const char *pvalue = reinterpret_cast(&value); - return string(pvalue, sizeof(value)); -} - -// utility function: convert little-endian encoded bytes to integer -// return value in uint32_t type -static uint32_t bytes2int(const string &bytes) { - assert(bytes.size() == sizeof(uint32_t)); - return *reinterpret_cast(bytes.c_str()); -} - -// utility function: compare a GBB header with given version numbers. -// return 1 for "larger", 0 for "equal" and -1 for "smaller". -static int version_compare(const GoogleBinaryBlockHeader& header, - int major, int minor) { - if (header.major_version != major) - return header.major_version - major; - return header.minor_version - minor; -} - -/////////////////////////////////////////////////////////////////////// -// GBB Utility implementation - -namespace vboot_reference { - -GoogleBinaryBlockUtil::GoogleBinaryBlockUtil() { - assert(sizeof(header_) == GBB_HEADER_SIZE); - initialize(); -} - -GoogleBinaryBlockUtil::~GoogleBinaryBlockUtil() { -} - -void GoogleBinaryBlockUtil::initialize() { - verbose = true; - is_valid_gbb = false; - header_offset_ = 0; - memset(&header_, 0, sizeof(header_)); - file_content_.clear(); -} - -bool GoogleBinaryBlockUtil::create_new( - const std::vector &create_param) { - uint32_t *prop = &header_.hwid_offset; // must be first entry. - uint32_t allocated_size = sizeof(header_); - std::vector::const_iterator i = create_param.begin(); - - // max properties = available space in header / size of record (offset+size) - size_t max_properties = - (sizeof(header_) - (reinterpret_cast(prop) - - reinterpret_cast(&header_))) / - (sizeof(uint32_t) * 2); - - if (create_param.size() >= max_properties) { - if (verbose) - fprintf(stderr, "error: creation parameters cannot exceed %zu entries.\n", - max_properties); - return false; - } - - initialize(); - memcpy(header_.signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE); - header_.major_version = GBB_MAJOR_VER; - header_.minor_version = GBB_MINOR_VER; - header_.header_size = GBB_HEADER_SIZE; - - while (i != create_param.end()) { - *prop++ = allocated_size; // property offset - *prop++ = *i; // property size - allocated_size += *i; - i++; - } - - file_content_.resize(allocated_size); - std::copy(reinterpret_cast(&header_), - reinterpret_cast(&header_ + 1), - file_content_.begin()); - is_valid_gbb = true; - return true; -} - - -bool GoogleBinaryBlockUtil::load_from_file(const char *filename) { - is_valid_gbb = false; - - file_content_ = read_nonempty_file(filename); - if (file_content_.empty()) - return false; - - switch (search_header_signatures(file_content_, &header_offset_)) { - case 0: - if (verbose) - fprintf(stderr, " error: cannot find any GBB signature.\n"); - break; - - case 1: - // fetch a copy of block header to check more detail - if (!load_gbb_header(file_content_, header_offset_, &header_)) { - if (verbose) - fprintf(stderr, " error: invalid GBB in image file.\n"); - } else { - is_valid_gbb = true; - } - break; - - default: - if (verbose) - fprintf(stderr, " error: found multiple GBB signatures.\n"); - file_content_.clear(); - break; - } - - // discard if anything goes wrong - if (!is_valid_gbb) - initialize(); - - return is_valid_gbb; -} - -bool GoogleBinaryBlockUtil::save_to_file(const char *filename) { - assert(is_valid_gbb && !file_content_.empty()); - return write_nonempty_file(filename, file_content_); -} - -int GoogleBinaryBlockUtil::search_header_signatures(const string &image, - long *poffset) const { - int found_signatures = 0; - size_t last_found_pos = 0; - - while ((last_found_pos = - file_content_.find(GBB_SIGNATURE, last_found_pos, GBB_SIGNATURE_SIZE)) - != file_content_.npos) { - *poffset = last_found_pos; - found_signatures++; - last_found_pos++; // for next iteration - } - - return found_signatures; -} - -// utility function for load_gbb_header to check property range -static bool check_property_range(uint32_t off, uint32_t sz, - uint32_t hdr_sz, uint32_t max_sz, - const char *prop_name, bool verbose) { - // for backward compatibility, we allow zero entry here. - if (off == 0 && sz == 0) { - if (verbose) - fprintf(stderr, " warning: property %s is EMPTY.\n", prop_name); - return true; - } - - if (off + sz > max_sz) { - if (verbose) - fprintf(stderr, " error: property %s exceed GBB.\n", prop_name); - return false; - } - - if (off < hdr_sz) { - if (verbose) - fprintf(stderr, " error: property %s overlap GBB header.\n", prop_name); - return false; - } - - return true; -} - -bool GoogleBinaryBlockUtil::load_gbb_header(const string &image, long offset, - GoogleBinaryBlockHeader *phdr) const { - assert(phdr); - - // check that GBB header does not extend past end of image - if (image.size() < (size_t)offset + GBB_HEADER_SIZE) { - if (verbose) - fprintf(stderr, " error: incomplete GBB.\n"); - return false; - } - - string::const_iterator block_ptr = image.begin() + offset; - size_t block_size = image.size() - offset; - - std::copy(block_ptr, block_ptr + GBB_HEADER_SIZE, - reinterpret_cast(phdr)); - - const GoogleBinaryBlockHeader &h = *phdr; // for quick access - - // check version - if (h.major_version != GBB_MAJOR_VER) { - if (verbose) - fprintf(stderr, " error: invalid GBB version (%d.%d)\n", - h.major_version, h.minor_version); - return false; - } - - if (h.header_size < GBB_HEADER_SIZE) { - if (verbose) - fprintf(stderr, " error: incompatible header size (%d < %d)\n", - h.header_size, GBB_HEADER_SIZE); - return false; - } - - // verify properties - for (int i = 0; i < PROP_RANGE; i++) { - uint32_t off, size; - const char *name; - - if (!find_property(static_cast(i), - &off, &size, &name)) { - assert(!"invalid property."); - return false; - } - - if (!check_property_range(off, size, - h.header_size, block_size, name, verbose)) - return false; - } - - return true; -} - -bool GoogleBinaryBlockUtil::find_property(PROPINDEX i, - uint32_t *poffset, - uint32_t *psize, - const char** pname) const { - switch (i) { - case PROP_FLAGS: - *poffset = (uint8_t*)&header_.flags - (uint8_t*)&header_; - *psize = sizeof(header_.flags); - if (pname) - *pname = "flags"; - break; - - case PROP_HWID: - *poffset = header_.hwid_offset; - *psize = header_.hwid_size; - if (pname) - *pname = "hardware_id"; - break; - - case PROP_ROOTKEY: - *poffset = header_.rootkey_offset; - *psize = header_.rootkey_size; - if (pname) - *pname = "root_key"; - break; - - case PROP_BMPFV: - *poffset = header_.bmpfv_offset; - *psize = header_.bmpfv_size; - if (pname) - *pname = "bmp_fv"; - break; - - case PROP_RCVKEY: - *poffset = header_.recovery_key_offset;; - *psize = header_.recovery_key_size; - if (pname) - *pname = "recovery_key"; - break; - - default: - if (verbose) { - fprintf(stderr, " internal error: unknown property (%d).\n", - static_cast(i)); - } - assert(!"invalid property index."); - return false; - } - - return true; -} - -bool GoogleBinaryBlockUtil::set_property(PROPINDEX i, const string &value) { - uint32_t prop_size; - uint32_t prop_offset; - const char *prop_name; - - assert(is_valid_gbb); - - if (!find_property(i, &prop_offset, &prop_size, &prop_name)) - return false; - - // special processing by version - if (version_compare(header_, 1, 1) < 0) { - if (i == PROP_FLAGS) { - assert(value.size() == prop.size()); - if (int2bytes(0) != value) { - if (verbose) - fprintf(stderr, - "error: property %s is not supported on GBB version %d.%d\n", - prop_name, header_.major_version, header_.minor_version); - return false; - } - } - } - - - - if (prop_size < value.size()) { - if (verbose) - fprintf(stderr, "error: value size (%zu) exceed property capacity " - "(%u): %s\n", value.size(), prop_size, prop_name); - return false; - } - - // special properties - switch (i) { - case PROP_HWID: - if (value.size() == prop_size) { - if (verbose) - fprintf(stderr, - "error: NUL-terminated string exceed capacity (%d): %s\n", - prop_size, prop_name); - return false; - } - break; - - case PROP_FLAGS: - assert(value.size() == prop_size); - header_.flags = bytes2int(value); - break; - - default: - break; - } - - string::iterator dest = file_content_.begin() + header_offset_ + prop_offset; - file_content_.replace(dest, dest+prop_size, prop_size, '\0'); // wipe first - std::copy(value.begin(), value.end(), dest); - - return true; -} - -string GoogleBinaryBlockUtil::get_property(PROPINDEX i) const { - uint32_t prop_size; - uint32_t prop_offset; - const char *prop_name; - - assert(is_valid_gbb); - - if (!find_property(i, &prop_offset, &prop_size, &prop_name)) - return ""; - - // check range again to allow empty value (for compatbility) - if (prop_offset == 0 && prop_size == 0) { - if (verbose) - fprintf(stderr, " warning: empty property (%d): %s.\n", - static_cast(i), prop_name); - return ""; - } - - // special processing by version - if (version_compare(header_, 1, 1) < 0) { - if (i == PROP_FLAGS) - return int2bytes(0); - } - - string::const_iterator dest = file_content_.begin() + - header_offset_ + prop_offset; - return string(dest, dest + prop_size); -} - -string GoogleBinaryBlockUtil::get_property_name(PROPINDEX i) const { - uint32_t unused_off, unused_size; - const char *prop_name; - - if (!find_property(i, &unused_off, &unused_size, &prop_name)) { - assert(!"invalid property index."); - return ""; - } - - return prop_name; -} - -uint32_t GoogleBinaryBlockUtil::get_flags() const { - return bytes2int(get_property(PROP_FLAGS)); -} - -bool GoogleBinaryBlockUtil::set_flags(const uint32_t flags) { - return set_property(PROP_FLAGS, int2bytes(flags)); -} - -bool GoogleBinaryBlockUtil::set_hwid(const char *hwid) { - return set_property(PROP_HWID, hwid); -} - -bool GoogleBinaryBlockUtil::set_rootkey(const std::string &value) { - return set_property(PROP_ROOTKEY, value); -} - -bool GoogleBinaryBlockUtil::set_bmpfv(const string &value) { - return set_property(PROP_BMPFV, value); -} - -bool GoogleBinaryBlockUtil::set_recovery_key(const string &value) { - return set_property(PROP_RCVKEY, value); -} - -} // namespace vboot_reference - -#ifndef FOR_LIBRARY - -/////////////////////////////////////////////////////////////////////// -// command line utilities - -#include - -using vboot_reference::GoogleBinaryBlockUtil; - -// utility function: provide usage of this utility and exit. -static void usagehelp_exit(const char *prog_name) { - const char *basename = strrchr(prog_name, '/'); - if (basename) - basename++; - else - basename = prog_name; - fprintf(stderr, - "Utility to manage Google Binary Block (GBB)\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" - " --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" - " -i, --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" - " --recoverykey=FILE\tFile name of new Recovery Key.\n" - "\n" - "CREATE MODE:\n" - "-c, --create=prop1_size,prop2_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", - basename, basename, basename, basename); - exit(1); -} - -// utility function: export a property from GBB to given file. -// if filename was empty, export to console (screen). -// return true on success, otherwise false. -static bool export_property(GoogleBinaryBlockUtil::PROPINDEX idx, - const string &filename, - const GoogleBinaryBlockUtil &util) { - string prop_name = util.get_property_name(idx), - value = util.get_property(idx); - const char *name = prop_name.c_str(); - - if (filename.empty()) { - // write to console - if (idx == GoogleBinaryBlockUtil::PROP_FLAGS) - printf("%s: 0x%08x\n", name, bytes2int(value)); - else - printf("%s: %s\n", name, value.c_str()); - } else { - const char *fn = filename.c_str(); - - if (!write_nonempty_file(fn, value)) { - fprintf(stderr, "error: failed to export %s to file: %s\n", name, fn); - return false; - } - printf(" - exported %s to file: %s\n", name, fn); - } - - return true; -} - -// utility function: import a property to GBB by given source (file or string). -// return true on success, otherwise false. -// is succesfully imported into GBB. -static bool import_property( - GoogleBinaryBlockUtil::PROPINDEX idx, const string &source, - bool source_as_file, GoogleBinaryBlockUtil *putil) { - assert(!source.empty()); - string prop_name = putil->get_property_name(idx); - - if (source_as_file) { - printf(" - import %s from %s: ", prop_name.c_str(), source.c_str()); - string v = read_nonempty_file(source.c_str()); - if (v.empty()) { - printf("invalid file.\n"); - return false; - } - if (!putil->set_property(idx, v)) { - printf("invalid content.\n"); - return false; - } - printf("success.\n"); - } else { - // source as string - string old_value = putil->get_property(idx); - bool result = putil->set_property(idx, source); - if (idx == GoogleBinaryBlockUtil::PROP_FLAGS) - printf(" - %s changed from 0x%08x to 0x%08x: %s\n", - prop_name.c_str(), bytes2int(old_value), bytes2int(source), - result ? "success" : "failed"); - else - printf(" - %s changed from '%s' to '%s': %s\n", - prop_name.c_str(), old_value.c_str(), source.c_str(), - result ? "success" : "failed"); - if (!result) - return false; - } - - return true; -} - -static bool parse_creation_param(const string &input_string, - std::vector *output_vector) { - const char *input = input_string.c_str(); - char *parsed = NULL; - uint32_t param; - - if (input_string.empty()) - return false; - - do { - param = (uint32_t)strtol(input, &parsed, 0); - if (*parsed && *parsed != ',') - return false; - output_vector->push_back(param); - input = *parsed ? parsed + 1 : parsed; - } while (*input); - - return true; -} - -/////////////////////////////////////////////////////////////////////// -// main - -int main(int argc, char *argv[]) { - const char *myname = argv[0]; - int err_stage = 0; // an indicator for error exits - GoogleBinaryBlockUtil util; - - // small parameter helper class - class OptPropertyMap: public - std::map { - public: - bool set_new_value(GoogleBinaryBlockUtil::PROPINDEX id, const string &v) { - if (find(id) != end()) - return false; - - (*this)[id] = v; - return true; - } - }; - OptPropertyMap opt_props; - - struct GBBUtilOptions { - bool get_mode, set_mode, create_mode; - string input_fn, output_fn; - std::vector create_param; - } myopts; - myopts.get_mode = myopts.set_mode = myopts.create_mode = false; - - // snippets for getopt_long - int option_index, opt; - static struct option long_options[] = { - {"get", 0, NULL, 'g' }, - {"set", 0, NULL, 's' }, - {"create", 1, NULL, 'c' }, - {"output", 1, NULL, 'o' }, - {"hwid", 2, NULL, 'i' }, - {"rootkey", 1, NULL, 'k' }, - {"bmpfv", 1, NULL, 'b' }, - {"recoverykey", 1, NULL, 'R' }, - {"flags", 2, NULL, 'L' }, - { NULL, 0, NULL, 0 }, - }; - - // parse command line options - while ((opt = getopt_long(argc, argv, "gsc:o:i:k:b:", - long_options, &option_index)) >= 0) { - switch (opt) { - case 'g': - myopts.get_mode = true; - break; - - case 's': - myopts.set_mode = true; - break; - - case 'c': - myopts.create_mode = true; - assert(optarg); - if (!*optarg || !parse_creation_param(optarg, &myopts.create_param)) { - fprintf(stderr, "error: invalid creation parameter: %s\n", optarg); - usagehelp_exit(myname); - } - break; - - case 'o': - myopts.output_fn = optarg; - break; - - case 'i': - if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_HWID, optarg ? optarg : "")) { - fprintf(stderr, "error: cannot assign multiple HWID parameters\n"); - usagehelp_exit(myname); - } - break; - - case 'k': - if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_ROOTKEY, optarg)) { - fprintf(stderr, "error: cannot assign multiple rootkey parameters\n"); - usagehelp_exit(myname); - } - break; - - case 'b': - if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_BMPFV, optarg)) { - fprintf(stderr, "error: cannot assign multiple bmpfv parameters\n"); - usagehelp_exit(myname); - } - break; - - case 'R': - if (!opt_props.set_new_value( - GoogleBinaryBlockUtil::PROP_RCVKEY, optarg)) { - fprintf(stderr, - "error: cannot assign multiple recovery_key parameters\n"); - usagehelp_exit(myname); - } - break; - - case 'L': - { - uint32_t flags = 0; - char *endptr = optarg; - - if (optarg) { - flags = strtoul(optarg, &endptr, 0); - if (endptr == optarg) { - fprintf(stderr, "error: invalid --flags value\n"); - usagehelp_exit(myname); - } - } - - if (!opt_props.set_new_value(GoogleBinaryBlockUtil::PROP_FLAGS, - optarg ? int2bytes(flags) : "")) { - fprintf(stderr, "error: cannot assign multiple flags parameters\n"); - usagehelp_exit(myname); - } - } - break; - - default: - case '?': - fprintf(stderr, "error: unknown param: %c\n", opt); - usagehelp_exit(myname); - break; - } - } - argc -= optind; - argv += optind; - - // adjust non-dashed parameters - if (myopts.output_fn.empty() && argc == 2) { - myopts.output_fn = argv[1]; - argc--; - } - - // currently, the only parameter is 'input file'. - if (argc == 1) { - myopts.input_fn = argv[0]; - } else { - fprintf(stderr, "error: unexpected parameters (%d)\n", argc); - usagehelp_exit(myname); - } - - // stage: complete parameter parsing and checking - err_stage++; - if (myopts.create_mode) { - if (myopts.get_mode || myopts.set_mode) { - printf("error: please assign only one mode from get/set/create.\n"); - return err_stage; - } - if (!opt_props.empty() || myopts.create_param.empty()) { - printf("error: creation parameter syntax error.\n"); - return err_stage; - } - if (myopts.output_fn.empty()) { - myopts.output_fn = myopts.input_fn; - } - } else if (myopts.get_mode == myopts.set_mode) { - if (myopts.get_mode) { - printf("error: please assign either get or set mode.\n"); - return err_stage; - } else { - // enter 'get' mode by default, if not assigned. - myopts.get_mode = true; - } - } - if (myopts.get_mode && !myopts.output_fn.empty()) { - printf("error: get-mode does not create output files.\n"); - return err_stage; - } - - if (myopts.create_mode) { - if (!util.create_new(myopts.create_param)) - return err_stage; - - assert(!myopts.output_fn.empty()); - if (!util.save_to_file(myopts.output_fn.c_str())) { - printf("error: cannot create to file: %s\n", myopts.output_fn.c_str()); - return err_stage; - } else { - printf("successfully created new GBB to: %s\n", myopts.output_fn.c_str()); - } - return 0; - } - - // stage: load image files - err_stage++; - assert(!myopts.input_fn.empty()); - if (!util.load_from_file(myopts.input_fn.c_str())) { - printf("error: cannot load valid BIOS file: %s\n", myopts.input_fn.c_str()); - return err_stage; - } - - // stage: processing by mode - err_stage++; - if (myopts.get_mode) { - // get mode - if (opt_props.empty()) // enable hwid by default - opt_props.set_new_value(GoogleBinaryBlockUtil::PROP_HWID, ""); - - for (OptPropertyMap::const_iterator i = opt_props.begin(); - i != opt_props.end(); - i++) { - if (i->first == GoogleBinaryBlockUtil::PROP_HWID || - i->first == GoogleBinaryBlockUtil::PROP_FLAGS) { - if (!i->second.empty()) { - printf("error: cannot assign value for --hwid/flags in --get.\n"); - usagehelp_exit(myname); - } - } - export_property(i->first, i->second, util); - } - - } else { - // set mode - assert(myopts.set_mode); - - if (opt_props.empty()) { - printf("nothing to change. abort.\n"); - return err_stage; - } - - for (OptPropertyMap::const_iterator i = opt_props.begin(); - i != opt_props.end(); - i++) { - bool source_as_file = true; - - // the hwid/flags are assigned in command line parameters - if (i->first == GoogleBinaryBlockUtil::PROP_HWID || - i->first == GoogleBinaryBlockUtil::PROP_FLAGS) - source_as_file = false; - - if (!import_property(i->first, i->second, source_as_file, &util)) { - printf("error: cannot set properties. abort.\n"); - return err_stage; - } - } - - // stage: write output - err_stage++; - - // use input filename (overwrite) by default - if (myopts.output_fn.empty()) - myopts.output_fn = myopts.input_fn; - - assert(!myopts.output_fn.empty()); - if (!util.save_to_file(myopts.output_fn.c_str())) { - printf("error: cannot save to file: %s\n", myopts.output_fn.c_str()); - return err_stage; - } else { - printf("successfully saved new image to: %s\n", myopts.output_fn.c_str()); - } - } - - return 0; -} - -#endif // FOR_LIBRARY -- cgit v1.2.1