Remove unused files, and tidy the directory structure of the remaining ones.

Review URL: http://codereview.chromium.org/2815011
This commit is contained in:
Randall Spangler
2010-06-17 14:45:22 -07:00
parent d52030f340
commit 620c38cf34
68 changed files with 91 additions and 2886 deletions

View File

@@ -6,17 +6,15 @@ export CC ?= gcc
export CXX ?= g++
export CFLAGS = -Wall -DNDEBUG -O3 -Werror
export TOP = $(shell pwd)
export FWDIR=$(TOP)/vboot_firmware
export FWDIR=$(TOP)/firmware
export HOSTDIR=$(TOP)/host
export INCLUDES = \
-I$(FWDIR)/include \
-I$(TOP)/misclibs/include
export INCLUDES = -I$(FWDIR)/include
export BUILD = ${TOP}/build
export FWLIB = ${BUILD}/vboot_fw.a
export HOSTLIB= ${BUILD}/vboot_host.a
SUBDIRS = vboot_firmware misclibs host vkernel utility cgpt tests
SUBDIRS = firmware host utility cgpt tests
all:
set -e; \

36
README
View File

@@ -7,22 +7,19 @@ Directory Structure
The source is organized into distinct modules -
vboot_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 vboot_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.
cgptlib/ - Work in progress for handling GPT headers. Parts of this will no
doubt be migrated into vboot_firmware/
cgpt/ - Utility to read/write/modify GPT partitions. Much like the
gpt tool, but with support for Chrome OS extensiosn.
misclibs/ - Miscellaneous functions used by userland utilities.
host/ - Miscellaneous functions used by userland utilities.
utility/ - Utilities for generating and verifying signed
firmware and kernel images, as well as arbitrary blobs.
vfirmware/ and vkernel/ - Functions for generating, verifying, and
manipulating signed firmware and kernel images.
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.
@@ -61,14 +58,17 @@ BUILD=../build make runtests
Some useful utilities:
----------
firmware_utility.c To generate verified boot firmware images.
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
kernel_utility.c To generate verified boot kernel images.
dumpRSAPublicKey.c Dump RSA Public key (from a DER-encoded X509
certificate) in a format suitable for
use by RSAVerify* functions in
crypto/.
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.
@@ -99,6 +99,8 @@ $ 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
************** TODO: STUFF PAST HERE IS OUT OF DATE ***************
At this point we have all the requisite keys needed to generate a signed
firmware image.

View File

@@ -4,12 +4,13 @@
*/
/* System includes for vboot reference library. This is the ONLY
* place in vboot_firmware where system headers may be included via
* place in firmware/ where system headers may be included via
* #include <...>, so that there's only one place that needs to be
* fixed up for platforms which don't have all the system includes.
*
* Stub files may still include system headers, because they're local
* implementations and will be ported to each system anyway. */
* Files in firmware/stub may still include system headers, because
* they're local implementations and will be ported to each system
* anyway. */
#ifndef VBOOT_REFERENCE_SYSINCLUDES_H_
#define VBOOT_REFERENCE_SYSINCLUDES_H_

View File

@@ -14,12 +14,13 @@ INCLUDES += \
# find ./lib -iname '*.c' | sort
ALL_SRCS = \
./lib/file_keys.c \
./lib/host_common.c \
./lib/host_key.c \
./lib/host_keyblock.c \
./lib/host_misc.c \
./lib/host_signature.c
./lib/host_signature.c \
./lib/signature_digest.c
test : $(HOSTLIB)
$(CC) $(CFLAGS) $(INCLUDES) -o $(BUILD_ROOT)/a.out $(TESTDIR)/main.c \

View File

@@ -37,7 +37,7 @@ uint8_t* DigestFile(char* input_file, int sig_algorithm);
*
* Returns the signature. Caller owns the buffer and must Free() it.
*/
uint8_t* SignatureFile(const char* input_fie, const char* key_file,
uint8_t* SignatureFile(const char* input_file, const char* key_file,
int algorithm);
#endif /* VBOOT_REFERENCE_FILE_KEYS_H_ */

View File

@@ -11,7 +11,7 @@
/* Returns a buffer with DigestInfo (which depends on [algorithm])
* prepended to [digest].
*/
uint8_t* prepend_digestinfo(int algorithm, uint8_t* digest);
uint8_t* PrependDigestInfo(int algorithm, uint8_t* digest);
/* Function that outputs the message digest of the contents of a buffer in a
* format that can be used as input to OpenSSL for an RSA signature.

View File

@@ -1,6 +1,8 @@
#include <stdio.h>
#include "host_common.h"
#include "file_keys.h"
#include "signature_digest.h"
int main(void)
{
@@ -32,5 +34,16 @@ int main(void)
CreateFirmwarePreamble(0, 0, 0, 0);
CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0);
/* file_keys.h */
BufferFromFile(0, 0);
RSAPublicKeyFromFile(0);
DigestFile(0, 0);
SignatureFile(0, 0, 0);
/* signature_digest.h */
PrependDigestInfo(0, 0);
SignatureDigest(0, 0, 0);
SignatureBuf(0, 0, 0, 0);
return 0;
}

View File

@@ -1,16 +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.
INCLUDES += -I./include \
-I$(TOP)/common/include \
-I$(TOP)/vboot_firmware/lib/cryptolib/include \
-I$(TOP)/vfirmware/include \
-I$(TOP)/vkernel/include
BUILD_ROOT := ${BUILD}/misclibs
ALL_SRCS = file_keys.c signature_digest.c
include ../common.mk

View File

@@ -6,29 +6,17 @@ INCLUDES += -I./include \
-I$(FWDIR)/lib/include \
-I$(FWDIR)/lib/cgptlib/include \
-I$(FWDIR)/lib/cryptolib/include \
-I../host/include \
-I../misclibs/include \
-I../vboot_firmware/lib/include\
-I../vkernel/include
IMAGE_LIBS = $(BUILD)/vkernel/kernel_image.o \
$(BUILD)/vkernel/kernel_image_fw.o
UTIL_LIBS = $(BUILD)/misclibs/file_keys.o $(BUILD)/misclibs/signature_digest.o
-I$(HOSTDIR)/include
BUILD_ROOT = ${BUILD}/tests
TEST_NAMES = big_kernel_tests \
cgptlib_test \
kernel_image_tests \
kernel_rollback_tests \
kernel_splicing_tests \
kernel_verify_benchmark \
TEST_NAMES = cgptlib_test \
rsa_padding_test \
rsa_verify_benchmark \
sha_benchmark \
sha_tests \
vboot_common_tests \
vboot_common2_tests \
vboot_common3_tests \
verify_kernel_fuzz_driver
vboot_common3_tests
TEST_BINS = $(addprefix ${BUILD_ROOT}/,$(TEST_NAMES))
TEST_LIB = ${BUILD_ROOT}/test.a
@@ -37,7 +25,7 @@ TEST_LIB_OBJS = $(TEST_LIB_SRCS:%.c=${BUILD_ROOT}/%.o)
ALL_DEPS = $(addsuffix .d,${TEST_BINS} ${TEST_LIB_OBJS})
CFLAGS += -MMD -MF $@.d
LIBS := ${TEST_LIB} $(IMAGE_LIBS) $(UTIL_LIBS) $(HOSTLIB) $(FWLIB)
LIBS := ${TEST_LIB} $(HOSTLIB) $(FWLIB)
all: $(TEST_BINS) ${EXTRA_TARGET}
@@ -51,37 +39,57 @@ ${BUILD_ROOT}/%.o : %.c
${BUILD_ROOT}/%: %.c ${LIBS}
$(CC) $(CFLAGS) $(INCLUDES) $< ${LIBS} -o $@ -lcrypto -lrt
# TODO: port these tests to vboot_firmware, if not already eqivalent
# functionality
# TODO: port these tests to new API, if not already eqivalent
# functionality in other tests
#
# big_firmware_tests
# firmware_image_tests
# firmware_rollback_tests
# firmware_splicing_tests
# firmware_verify_benchmark
# verify_firmware_fuzz_driver
#
# big_kernel_tests
# kernel_image_tests
# kernel_rollback_tests
# kernel_splicing_tests
# kernel_verify_benchmark
# verify_kernel_fuzz_driver
ifneq (${RUNTESTS},)
EXTRA_TARGET = runtests
endif
runtests:
# Generate test keys
genkeys:
./gen_test_keys.sh
# Crypto tests
./run_rsa_tests.sh
${BUILD_ROOT}/sha_tests
./run_vbutil_tests.sh
./run_vboot_common_tests.sh
./run_image_verification_tests.sh
# Splicing tests
#${BUILD_ROOT}/firmware_splicing_tests
${BUILD_ROOT}/kernel_splicing_tests
# Rollback Tests
#${BUILD_ROOT}/firmware_rollback_tests
${BUILD_ROOT}/kernel_rollback_tests
# Helper Library Tests
# Run cgpt tests
runcgpttests:
${BUILD_ROOT}/cgptlib_test
# Tool tests
./run_cgpt_tests.sh ${BUILD}/cgpt/cgpt
-include ${ALL_DEPS}
# Run crypto tests
runcryptotests:
./run_rsa_tests.sh
${BUILD_ROOT}/sha_tests
./run_vboot_common_tests.sh
# Run other misc tests
runmisctests:
./run_vbutil_tests.sh
runtests: genkeys runcgpttests runcryptotests runmisctests
# TODO: tests to run when ported to new API
# ./run_image_verification_tests.sh
# # Splicing tests
# ${BUILD_ROOT}/firmware_splicing_tests
# ${BUILD_ROOT}/kernel_splicing_tests
# # Rollback Tests
# ${BUILD_ROOT}/firmware_rollback_tests
# ${BUILD_ROOT}/kernel_rollback_tests
-include ${ALL_DEPS}

View File

@@ -70,10 +70,9 @@ ${kernel_hashalgo}${COL_STOP}"
check_test_keys
# TODO: re-enable when tests are ported to new vboot
#echo
#echo "Testing high-level firmware image verification..."
#test_firmware_verification
echo
echo "Testing high-level firmware image verification..."
test_firmware_verification
echo
echo "Testing high-level kernel image verification..."

View File

@@ -44,114 +44,3 @@ int TEST_NEQ(int result, int not_expected_result, char* testname) {
return 0;
}
}
KernelImage* GenerateTestKernelImage(int firmware_sign_algorithm,
int kernel_sign_algorithm,
const uint8_t* kernel_sign_key,
int kernel_key_version,
int kernel_version,
uint64_t kernel_len,
const char* firmware_key_file,
const char* kernel_key_file,
uint8_t kernel_data_fill_char) {
KernelImage* image = KernelImageNew();
Memcpy(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE);
image->header_version = 1;
image->firmware_sign_algorithm = firmware_sign_algorithm;
image->kernel_sign_algorithm = kernel_sign_algorithm;
image->kernel_key_version = kernel_key_version;
image->kernel_sign_key = (uint8_t*) Malloc(
RSAProcessedKeySize(image->kernel_sign_algorithm));
Memcpy(image->kernel_sign_key, kernel_sign_key,
RSAProcessedKeySize(image->kernel_sign_algorithm));
/* Update correct header length. */
image->header_len = GetKernelHeaderLen(image);
/* Calculate SHA-512 digest on header and populate header_checksum. */
CalculateKernelHeaderChecksum(image, image->header_checksum);
/* Populate kernel options and data with dummy data. */
image->kernel_version = kernel_version;
image->bootloader_offset = 0;
image->bootloader_size = 512;
image->padded_header_size = 100;
image->kernel_len = kernel_len;
image->kernel_key_signature = image->kernel_signature = NULL;
image->kernel_data = Malloc(kernel_len);
Memset(image->kernel_data, kernel_data_fill_char, kernel_len);
/* Generate and populate signatures. */
if (!AddKernelKeySignature(image, firmware_key_file)) {
debug("Couldn't create key signature.\n");
KernelImageFree(image);
return NULL;
}
if (!AddKernelSignature(image, kernel_key_file)) {
debug("Couldn't create kernel option and kernel signature.\n");
KernelImageFree(image);
return NULL;
}
return image;
}
uint8_t* GenerateTestKernelBlob(int firmware_sign_algorithm,
int kernel_sign_algorithm,
const uint8_t* kernel_sign_key,
int kernel_key_version,
int kernel_version,
uint64_t kernel_len,
const char* firmware_key_file,
const char* kernel_key_file) {
KernelImage* image = NULL;
uint8_t* kernel_blob = NULL;
uint64_t kernel_blob_len = 0;
image = GenerateTestKernelImage(firmware_sign_algorithm,
kernel_sign_algorithm,
kernel_sign_key,
kernel_key_version,
kernel_version,
kernel_len,
firmware_key_file,
kernel_key_file,
'K');
kernel_blob = GetKernelBlob(image, &kernel_blob_len);
KernelImageFree(image);
return kernel_blob;
}
uint8_t* GenerateRollbackTestKernelBlob(int kernel_key_version,
int kernel_version,
int is_corrupt) {
KernelImage* image = NULL;
uint64_t len;
uint8_t* kernel_blob = NULL;
uint8_t* kernel_sign_key = NULL;
kernel_sign_key = BufferFromFile("testkeys/key_rsa1024.keyb",
&len);
if (!kernel_sign_key)
return NULL;
image = GenerateTestKernelImage(0, /* Firmware algo: RSA1024/SHA1 */
0, /* Kernel algo: RSA1024/SHA1 */
kernel_sign_key,
kernel_key_version,
kernel_version,
1, /* kernel length. */
"testkeys/key_rsa1024.pem",
"testkeys/key_rsa1024.pem",
'K');
if (!image)
return NULL;
if (is_corrupt) {
/* Invalidate image. */
Memset(image->kernel_data, 'X', image->kernel_len);
}
kernel_blob = GetKernelBlob(image, &len);
KernelImageFree(image);
return kernel_blob;
}

View File

@@ -9,8 +9,6 @@
#include <stdint.h>
#include "kernel_image.h"
extern int gTestSuccess;
/* Return 1 if result is equal to expected_result, else return 0.
@@ -20,29 +18,4 @@ int TEST_EQ(int result, int expected_result, char* testname);
* Also update the global gTestSuccess flag if test fails. */
int TEST_NEQ(int result, int not_expected_result, char* testname);
/* Test kernel image generation functions. */
KernelImage* GenerateTestKernelImage(int firmware_sign_algorithm,
int kernel_sign_algorithm,
const uint8_t* kernel_sign_key,
int kernel_key_version,
int kernel_version,
uint64_t kernel_len,
const char* firmware_key_file,
const char* kernel_key_file,
uint8_t kernel_data_fill_char);
uint8_t* GenerateTestKernelBlob(int firmware_sign_algorithm,
int kernel_sign_algorithm,
const uint8_t* kernel_sign_key,
int kernel_key_version,
int kernel_version,
uint64_t kernel_len,
const char* firmware_key_file,
const char* kernel_key_file);
/* Generates a test kernel iamge for rollback tests with a given
* [kernel_key_version} and [kernel_version]. If [is_corrupt] is 1,
* then the image has invalid signatures and will fail verification. */
uint8_t* GenerateRollbackTestKernelBlob(int kernel_key_version,
int kernel_version,
int is_corrupt);
#endif /* VBOOT_REFERENCE_TEST_COMMON_H_ */

View File

@@ -6,19 +6,10 @@ INCLUDES += -I./include \
-I$(FWDIR)/lib/include \
-I$(FWDIR)/lib/cgptlib/include \
-I$(FWDIR)/lib/cryptolib/include \
-I$(HOSTDIR)/include \
-I../misclibs/include \
-I../vboot_firmware/include\
-I../vkernel/include
-I$(HOSTDIR)/include
CFLAGS += $(INCLUDES)
CFLAGS += -MMD -MF $@.d
LIBS = $(BUILD)/misclibs/file_keys.o \
$(BUILD)/misclibs/signature_digest.o \
$(BUILD)/vkernel/kernel_image.o \
$(BUILD)/vkernel/kernel_image_fw.o \
$(BUILD)/vkernel/load_kernel_fw.o \
$(HOSTLIB) \
$(FWLIB)
LIBS = $(HOSTLIB) $(FWLIB)
BUILD_ROOT = ${BUILD}/utility
@@ -26,10 +17,7 @@ DESTDIR ?= /usr/bin
TARGET_NAMES = dumpRSAPublicKey \
gbb_utility \
kernel_utility \
load_kernel_test \
load_kernel_test_old \
sign_image \
signature_digest_utility \
vbutil_firmware \
vbutil_kernel \
@@ -51,13 +39,6 @@ ${BUILD_ROOT}/gbb_utility: gbb_utility.cc
${BUILD_ROOT}/load_kernel_test: load_kernel_test.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
${BUILD_ROOT}/load_kernel_test_old: load_kernel_test_old.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
${BUILD_ROOT}/kernel_utility: kernel_utility.cc $(LIBS)
$(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \
-o $@ $(LIBS) -lcrypto
${BUILD_ROOT}/signature_digest_utility: signature_digest_utility.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto

View File

@@ -1,76 +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.
#ifndef VBOOT_REFERENCE_FIRMWARE_UTILITY_H_
#define VBOOT_REFERENCE_FIRMWARE_UTILITY_H_
#include <string>
class FirmwareImage;
struct RSAPublicKey;
namespace vboot_reference {
// A class for handling verified boot firmware images.
class FirmwareUtility {
public:
FirmwareUtility();
~FirmwareUtility();
// Print usage to stderr.
void PrintUsage(void);
// Parse command line options and populate data members.
// Return true on success, false on failure.
bool ParseCmdLineOptions(int argc, char* argv[]);
// Print descriptio of verified boot firmware image.
void DescribeSignedImage();
// Generate a verified boot image by reading firmware data from in_file_.
// Return true on success, false on failure.
bool GenerateSignedImage();
// Verify a previously generated signed firmware image using the root key read
// from [root_key_pub_file_].
bool VerifySignedImage();
// Output the verified boot image to out_file_.
void OutputSignedImage();
bool is_generate() { return is_generate_; }
bool is_verify() { return is_verify_; }
bool is_describe() { return is_describe_; }
private:
// Check if all options were specified and sane.
// Return true on success, false on failure.
bool CheckOptions();
FirmwareImage* image_;
RSAPublicKey* root_key_pub_;
std::string root_key_file_;
std::string root_key_pub_file_;
std::string firmware_key_file_;
std::string firmware_key_pub_file_;
std::string subkey_in_file_; // Existing key signature header.
std::string in_file_;
std::string out_file_;
std::string kernel_subkey_sign_pub_file_;
int firmware_key_version_;
int firmware_sign_algorithm_;
int firmware_version_;
int kernel_subkey_sign_algorithm_;
bool is_generate_; // Are we generating a new image?
bool is_verify_; // Are we just verifying an already signed image?
bool is_describe_; // Should we print out description of the image?
bool is_only_vblock_; // Should we just output the verification block?
bool is_subkey_out_; // Should we just output the subkey header?
};
} // namespace vboot_reference
#endif // VBOOT_REFERENCE_FIRMWARE_UTILITY_H_

View File

@@ -1,87 +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.
#ifndef VBOOT_REFERENCE_KERNEL_UTILITY_H_
#define VBOOT_REFERENCE_KERNEL_UTILITY_H_
#include <string>
extern "C" {
#include "kernel_image.h"
}
struct RSAPublicKey;
namespace vboot_reference {
// A class for handling verified boot kernel images.
class KernelUtility {
public:
KernelUtility();
~KernelUtility();
// Print usage to stderr.
void PrintUsage(void);
// Parse command line options and populate data members.
// Return true on success, false on failure.
bool ParseCmdLineOptions(int argc, char* argv[]);
// Print description of a verified boot kernel image.
void DescribeSignedImage();
// Generate a verified boot image by reading kernel data from in_file_.
// Return true on success, false on failure.
bool GenerateSignedImage();
// Verify a previously generated signed firmware image using the key read
// from [firmware_key_pub_file_].
bool VerifySignedImage();
// Output the verified boot kernel image to out_file_.
void OutputSignedImage();
bool is_generate() { return is_generate_; }
bool is_verify() { return is_verify_; }
bool is_describe() { return is_describe_; }
private:
// Check if all options were specified and sane.
// Return true on success, false on failure.
bool CheckOptions();
KernelImage* image_;
RSAPublicKey* firmware_key_pub_; // Root key used for verification.
std::string firmware_key_file_; // Private key for signing the kernel key.
std::string firmware_key_pub_file_;
std::string kernel_key_file_; // Private key for signing the kernel.
std::string kernel_key_pub_file_;
std::string subkey_in_file_; // Existing key signature header.
std::string config_file_; // File containing kernel commandline parameters
std::string bootloader_file_; // Embedded bootloader code
std::string vmlinuz_file_; // Input vmlinuz to be embedded in signed blob.
// Fields of a KernelImage. (read from the command line).
int header_version_;
int firmware_sign_algorithm_;
int kernel_sign_algorithm_;
int kernel_key_version_;
int kernel_version_;
int padding_;
uint64_t kernel_len_;
uint8_t* kernel_config_;
std::string in_file_;
std::string out_file_;
bool is_generate_; // Are we generating a new image?
bool is_verify_; // Are we just verifying an already signed image?
bool is_describe_; // Should we print out description of the image?
bool is_only_vblock_; // Should we just output the verification block?
bool is_subkey_out_; // Should we just output the subkey header?
};
} // namespace vboot_reference
#endif // VBOOT_REFERENCE_FIRMWARE_UTILITY_H_

View File

@@ -1,525 +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.
//
// Utility for manipulating verified boot kernel images.
//
#include "kernel_utility.h"
#include <getopt.h>
#include <stdio.h>
#include <stdint.h> // Needed for UINT16_MAX.
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
extern "C" {
#include "cryptolib.h"
#include "file_keys.h"
#include "kernel_image.h"
#include "stateful_util.h"
#include "utility.h"
}
using std::cerr;
// Macro to determine the size of a field structure in the KernelImage
// structure.
#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
namespace vboot_reference {
KernelUtility::KernelUtility(): image_(NULL),
firmware_key_pub_(NULL),
header_version_(1),
firmware_sign_algorithm_(-1),
kernel_sign_algorithm_(-1),
kernel_key_version_(-1),
kernel_version_(-1),
padding_(0),
kernel_len_(0),
is_generate_(false),
is_verify_(false),
is_describe_(false),
is_only_vblock_(false) {}
KernelUtility::~KernelUtility() {
RSAPublicKeyFree(firmware_key_pub_);
KernelImageFree(image_);
}
void KernelUtility::PrintUsage(void) {
cerr << "\n"
"Utility to generate/verify/describe a verified boot kernel image\n"
"\n"
"Usage: kernel_utility <--generate|--verify|--describe> [OPTIONS]\n"
"\n"
"For \"--describe\", the required OPTIONS are:\n"
" --in <infile>\t\t\t\tSigned boot image to describe.\n"
"\n"
"For \"--verify\", required OPTIONS are:\n"
" --in <infile>\t\t\t\tSigned boot image to verify.\n"
" --firmware_key_pub <pubkeyfile>\tPre-processed public firmware key\n"
"\n"
"For \"--generate\", required OPTIONS are:\n"
" --firmware_key <privkeyfile>\t\tPrivate firmware signing key file\n"
" --kernel_key_pub <pubkeyfile>\t\tPre-processed public kernel signing"
" key\n"
" --firmware_sign_algorithm <algoid>\tSigning algorithm for firmware\n"
" --kernel_sign_algorithm <algoid>\tSigning algorithm for kernel\n"
" --kernel_key_version <number>\t\tKernel signing key version number\n"
"OR\n"
" --subkey_in <subkeyfile>\t\tExisting key signature header\n"
"\n"
" --kernel_key <privkeyfile>\t\tPrivate kernel signing key file\n"
" --kernel_version <number>\t\tKernel Version number\n"
" --config <file>\t\t\tEmbedded kernel command-line parameters\n"
" --bootloader <file>\t\t\tEmbedded bootloader stub\n"
" --vmlinuz <file>\t\t\tEmbedded kernel image\n"
" --out <outfile>\t\t\tOutput file for verified boot image\n"
"\n"
"Optional arguments for \"--generate\" are:\n"
" --padding <size>\t\t\tPad the header to this size\n"
" --subkey_out\t\t\t\tJust output the subkey (key verification) header\n"
" --vblock\t\t\t\tJust output the verification block\n"
"\n"
"<algoid> (for --*_sign_algorithm) is one of the following:\n";
for (int i = 0; i < kNumAlgorithms; i++) {
cerr << " " << i << " for " << algo_strings[i] << "\n";
}
cerr << "\n\n";
}
bool KernelUtility::ParseCmdLineOptions(int argc, char* argv[]) {
int option_index, i;
char *e = 0;
enum {
OPT_FIRMWARE_KEY = 1000,
OPT_FIRMWARE_KEY_PUB,
OPT_KERNEL_KEY,
OPT_KERNEL_KEY_PUB,
OPT_SUBKEY_IN,
OPT_FIRMWARE_SIGN_ALGORITHM,
OPT_KERNEL_SIGN_ALGORITHM,
OPT_KERNEL_KEY_VERSION,
OPT_KERNEL_VERSION,
OPT_IN,
OPT_OUT,
OPT_GENERATE,
OPT_VERIFY,
OPT_DESCRIBE,
OPT_VBLOCK,
OPT_BOOTLOADER,
OPT_VMLINUZ,
OPT_CONFIG,
OPT_PADDING,
OPT_SUBKEY_OUT,
};
static struct option long_options[] = {
{"firmware_key", 1, 0, OPT_FIRMWARE_KEY },
{"firmware_key_pub", 1, 0, OPT_FIRMWARE_KEY_PUB },
{"kernel_key", 1, 0, OPT_KERNEL_KEY },
{"kernel_key_pub", 1, 0, OPT_KERNEL_KEY_PUB },
{"subkey_in", 1, 0, OPT_SUBKEY_IN },
{"firmware_sign_algorithm", 1, 0, OPT_FIRMWARE_SIGN_ALGORITHM },
{"kernel_sign_algorithm", 1, 0, OPT_KERNEL_SIGN_ALGORITHM },
{"kernel_key_version", 1, 0, OPT_KERNEL_KEY_VERSION },
{"kernel_version", 1, 0, OPT_KERNEL_VERSION },
{"in", 1, 0, OPT_IN },
{"out", 1, 0, OPT_OUT },
{"generate", 0, 0, OPT_GENERATE },
{"verify", 0, 0, OPT_VERIFY },
{"describe", 0, 0, OPT_DESCRIBE },
{"vblock", 0, 0, OPT_VBLOCK },
{"bootloader", 1, 0, OPT_BOOTLOADER },
{"vmlinuz", 1, 0, OPT_VMLINUZ },
{"config", 1, 0, OPT_CONFIG },
{"padding", 1, 0, OPT_PADDING },
{"subkey_out", 0, 0, OPT_SUBKEY_OUT },
{NULL, 0, 0, 0}
};
while ((i = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
switch (i) {
case '?':
return false;
break;
case OPT_FIRMWARE_KEY:
firmware_key_file_ = optarg;
break;
case OPT_FIRMWARE_KEY_PUB:
firmware_key_pub_file_ = optarg;
break;
case OPT_KERNEL_KEY:
kernel_key_file_ = optarg;
break;
case OPT_KERNEL_KEY_PUB:
kernel_key_pub_file_ = optarg;
break;
case OPT_SUBKEY_IN:
subkey_in_file_ = optarg;
break;
case OPT_FIRMWARE_SIGN_ALGORITHM:
firmware_sign_algorithm_ = strtol(optarg, &e, 0);
if (!*optarg || (e && *e)) {
cerr << "Invalid argument to --"
<< long_options[option_index].name
<< ": " << optarg << "\n";
return false;
}
break;
case OPT_KERNEL_SIGN_ALGORITHM:
kernel_sign_algorithm_ = strtol(optarg, &e, 0);
if (!*optarg || (e && *e)) {
cerr << "Invalid argument to --"
<< long_options[option_index].name
<< ": " << optarg << "\n";
return false;
}
break;
case OPT_KERNEL_KEY_VERSION:
kernel_key_version_ = strtol(optarg, &e, 0);
if (!*optarg || (e && *e)) {
cerr << "Invalid argument to --"
<< long_options[option_index].name
<< ": " << optarg << "\n";
return false;
}
break;
case OPT_KERNEL_VERSION:
kernel_version_ = strtol(optarg, &e, 0);
if (!*optarg || (e && *e)) {
cerr << "Invalid argument to --"
<< long_options[option_index].name
<< ": " << optarg << "\n";
return false;
}
break;
case OPT_IN:
in_file_ = optarg;
break;
case OPT_OUT:
out_file_ = optarg;
break;
case OPT_GENERATE:
is_generate_ = true;
break;
case OPT_VERIFY:
is_verify_ = true;
break;
case OPT_DESCRIBE:
is_describe_ = true;
break;
case OPT_VBLOCK:
is_only_vblock_ = true;
break;
case OPT_BOOTLOADER:
bootloader_file_ = optarg;
break;
case OPT_VMLINUZ:
vmlinuz_file_ = optarg;
break;
case OPT_CONFIG:
config_file_ = optarg;
break;
case OPT_PADDING:
padding_ = strtol(optarg, &e, 0);
if (!*optarg || (e && *e)) {
cerr << "Invalid argument to --"
<< long_options[option_index].name
<< ": " << optarg << "\n";
return false;
}
break;
case OPT_SUBKEY_OUT:
is_subkey_out_ = true;
break;
}
}
return CheckOptions();
}
void KernelUtility::OutputSignedImage(void) {
if (image_) {
if (!WriteKernelImage(out_file_.c_str(), image_,
is_only_vblock_,
is_subkey_out_)) {
cerr << "Couldn't write verified boot kernel image to file "
<< out_file_ <<".\n";
}
}
}
void KernelUtility::DescribeSignedImage(void) {
image_ = ReadKernelImage(in_file_.c_str());
if (!image_) {
cerr << "Couldn't read kernel image or malformed image.\n";
return;
}
PrintKernelImage(image_);
}
bool KernelUtility::GenerateSignedImage(void) {
uint64_t kernel_key_pub_len;
image_ = KernelImageNew();
Memcpy(image_->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE);
if (subkey_in_file_.empty()) {
// We must generate the kernel key signature header (subkey header)
// ourselves.
image_->header_version = 1;
image_->firmware_sign_algorithm = (uint16_t) firmware_sign_algorithm_;
// Copy pre-processed public signing key.
image_->kernel_sign_algorithm = (uint16_t) kernel_sign_algorithm_;
image_->kernel_sign_key = BufferFromFile(kernel_key_pub_file_.c_str(),
&kernel_key_pub_len);
if (!image_->kernel_sign_key)
return false;
image_->kernel_key_version = kernel_key_version_;
// Update header length.
image_->header_len = GetKernelHeaderLen(image_);
// Calculate header checksum.
CalculateKernelHeaderChecksum(image_, image_->header_checksum);
// Generate and add the key signatures.
if (!AddKernelKeySignature(image_, firmware_key_file_.c_str())) {
cerr << "Couldn't write key signature to verified boot kernel image.\n";
return false;
}
} else {
// Use existing subkey header.
MemcpyState st;
uint8_t* subkey_header_buf = NULL;
uint64_t subkey_len;
int header_len;
int kernel_key_signature_len;
int kernel_sign_key_len;
uint8_t header_checksum[FIELD_LEN(header_checksum)];
subkey_header_buf = BufferFromFile(subkey_in_file_.c_str(), &subkey_len);
if (!subkey_header_buf) {
cerr << "Couldn't read subkey header from file %s\n"
<< subkey_in_file_.c_str();
return false;
}
st.remaining_len = subkey_len;
st.remaining_buf = subkey_header_buf;
st.overrun = 0;
// TODO(gauravsh): This is basically the same code as the first half of
// of ReadKernelImage(). Refactor to eliminate code duplication.
StatefulMemcpy(&st, &image_->header_version, FIELD_LEN(header_version));
StatefulMemcpy(&st, &image_->header_len, FIELD_LEN(header_len));
StatefulMemcpy(&st, &image_->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
StatefulMemcpy(&st, &image_->kernel_sign_algorithm,
FIELD_LEN(kernel_sign_algorithm));
// Valid Kernel Key signing algorithm.
if (image_->firmware_sign_algorithm >= kNumAlgorithms) {
Free(subkey_header_buf);
return NULL;
}
// Valid Kernel Signing Algorithm?
if (image_->kernel_sign_algorithm >= kNumAlgorithms) {
Free(subkey_header_buf);
return NULL;
}
// Compute size of pre-processed RSA public keys and signatures.
kernel_key_signature_len = siglen_map[image_->firmware_sign_algorithm];
kernel_sign_key_len = RSAProcessedKeySize(image_->kernel_sign_algorithm);
// Check whether key header length is correct.
header_len = GetKernelHeaderLen(image_);
if (header_len != image_->header_len) {
debug("Header length mismatch. Got: %d, Expected: %d\n",
image_->header_len, header_len);
Free(subkey_header_buf);
return NULL;
}
// Read pre-processed public half of the kernel signing key.
StatefulMemcpy(&st, &image_->kernel_key_version,
FIELD_LEN(kernel_key_version));
image_->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
StatefulMemcpy(&st, image_->kernel_sign_key, kernel_sign_key_len);
StatefulMemcpy(&st, image_->header_checksum, FIELD_LEN(header_checksum));
// Check whether the header checksum matches.
CalculateKernelHeaderChecksum(image_, header_checksum);
if (SafeMemcmp(header_checksum, image_->header_checksum,
FIELD_LEN(header_checksum))) {
debug("Invalid kernel header checksum!\n");
Free(subkey_header_buf);
return NULL;
}
// Read key signature.
image_->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
StatefulMemcpy(&st, image_->kernel_key_signature,
kernel_key_signature_len);
Free(subkey_header_buf);
if (st.overrun || st.remaining_len != 0) /* Overrun or underrun. */
return false;
return true;
}
// Fill up kernel preamble and kernel data.
image_->kernel_version = kernel_version_;
if (padding_)
image_->padded_header_size = padding_;
image_->kernel_data = GenerateKernelBlob(vmlinuz_file_.c_str(),
config_file_.c_str(),
bootloader_file_.c_str(),
&image_->kernel_len,
&image_->bootloader_offset,
&image_->bootloader_size);
if (!image_->kernel_data)
return false;
// Generate and add the preamble and data signatures.
if (!AddKernelSignature(image_, kernel_key_file_.c_str())) {
cerr << "Couldn't write firmware signature to verified boot kernel image.\n";
return false;
}
return true;
}
bool KernelUtility::VerifySignedImage(void) {
int error;
firmware_key_pub_ = RSAPublicKeyFromFile(firmware_key_pub_file_.c_str());
image_ = ReadKernelImage(in_file_.c_str());
if (!firmware_key_pub_) {
cerr << "Couldn't read pre-processed public root key.\n";
return false;
}
if (!image_) {
cerr << "Couldn't read kernel image or malformed image.\n";
return false;
}
if (!(error = VerifyKernelImage(firmware_key_pub_, image_, 0)))
return true;
cerr << VerifyKernelErrorString(error) << "\n";
return false;
}
bool KernelUtility::CheckOptions(void) {
// Ensure that only one of --{describe|generate|verify} is set.
if (!((is_describe_ && !is_generate_ && !is_verify_) ||
(!is_describe_ && is_generate_ && !is_verify_) ||
(!is_describe_ && !is_generate_ && is_verify_))) {
cerr << "One (and only one) of --describe, --generate or --verify "
<< "must be specified.\n";
return false;
}
// Common required options.
// Required options for --describe.
if (is_describe_) {
if (in_file_.empty()) {
cerr << "No input file specified.\n";
return false;
}
}
// Required options for --verify.
if (is_verify_) {
if (firmware_key_pub_file_.empty()) {
cerr << "No pre-processed public firmware key file specified.\n";
return false;
}
if (in_file_.empty()) {
cerr << "No input file specified.\n";
return false;
}
}
// Required options for --generate.
if (is_generate_) {
if (subkey_in_file_.empty()) {
// Firmware private key (root key), kernel signing public
// key, and signing algorithms are required to generate the key signature
// header.
if (firmware_key_file_.empty()) {
cerr << "No firmware key file specified.\n";
return false;
}
if (kernel_key_pub_file_.empty()) {
cerr << "No pre-processed public kernel key file specified\n";
return false;
}
if (kernel_key_version_ <= 0 || kernel_key_version_ > UINT16_MAX) {
cerr << "Invalid or no kernel key version specified.\n";
return false;
}
if (firmware_sign_algorithm_ < 0 ||
firmware_sign_algorithm_ >= kNumAlgorithms) {
cerr << "Invalid or no firmware signing key algorithm specified.\n";
return false;
}
if (kernel_sign_algorithm_ < 0 ||
kernel_sign_algorithm_ >= kNumAlgorithms) {
cerr << "Invalid or no kernel signing key algorithm specified.\n";
return false;
}
}
if (kernel_key_file_.empty()) {
cerr << "No kernel key file specified.\n";
return false;
}
if (kernel_version_ <=0 || kernel_version_ > UINT16_MAX) {
cerr << "Invalid or no kernel version specified.\n";
return false;
}
if (out_file_.empty()) {
cerr <<"No output file specified.\n";
return false;
}
if (config_file_.empty()) {
cerr << "No config file specified.\n";
return false;
}
if (bootloader_file_.empty()) {
cerr << "No bootloader file specified.\n";
return false;
}
if (vmlinuz_file_.empty()) {
cerr << "No vmlinuz file specified.\n";
return false;
}
// TODO(gauravsh): Enforce only one of --vblock or --subkey_out is specified
}
return true;
}
} // namespace vboot_reference
int main(int argc, char* argv[]) {
vboot_reference::KernelUtility ku;
if (!ku.ParseCmdLineOptions(argc, argv)) {
ku.PrintUsage();
return -1;
}
if (ku.is_describe()) {
ku.DescribeSignedImage();
}
else if (ku.is_generate()) {
if (!ku.GenerateSignedImage())
return -1;
ku.OutputSignedImage();
}
else if (ku.is_verify()) {
cerr << "Verification ";
if (ku.VerifySignedImage())
cerr << "SUCCESS.\n";
else
cerr << "FAILURE.\n";
}
return 0;
}

View File

@@ -1,147 +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.
*/
/* Routines for verifying a file's signature. Useful in testing the core
* RSA verification implementation.
*/
#include <inttypes.h> /* For PRIu64 macro */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "load_kernel_fw.h"
#include "boot_device.h"
#include "host_common.h"
#include "rollback_index.h"
#include "utility.h"
int LoadKernelOld(LoadKernelParams* params);
/* Attempts to load the kernel from the current device.
*
* Returns LOAD_KERNEL_SUCCESS if successful, error code on failure. */
/* ANSI Color coding sequences. */
#define COL_GREEN "\e[1;32m"
#define COL_RED "\e[0;31m"
#define COL_STOP "\e[m"
#define LBA_BYTES 512
#define KERNEL_BUFFER_SIZE 0x600000
/* Global variables for stub functions */
static LoadKernelParams lkp;
static FILE *image_file = NULL;
/* Boot device stub implementations to read from the image file */
int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer) {
printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
if (lba_start > lkp.ending_lba ||
lba_start + lba_count - 1 > lkp.ending_lba) {
fprintf(stderr, "Read overrun: %" PRIu64 " + %" PRIu64 " > %" PRIu64 "\n",
lba_start, lba_count, lkp.ending_lba);
return 1;
}
fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET);
if (1 != fread(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
fprintf(stderr, "Read error.");
return 1;
}
return 0;
}
int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count,
const void *buffer) {
printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
if (lba_start > lkp.ending_lba ||
lba_start + lba_count - 1 > lkp.ending_lba) {
fprintf(stderr, "Read overrun: %" PRIu64 " + %" PRIu64 " > %" PRIu64 "\n",
lba_start, lba_count, lkp.ending_lba);
return 1;
}
/* TODO: enable writes, once we're sure it won't trash our example file */
return 0;
fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET);
if (1 != fwrite(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
fprintf(stderr, "Read error.");
return 1;
}
return 0;
}
/* Main routine */
int main(int argc, char* argv[]) {
const char* image_name;
const char* keyfile_name;
int rv;
Memset(&lkp, 0, sizeof(LoadKernelParams));
lkp.bytes_per_lba = LBA_BYTES;
/* Read command line parameters */
if (3 > argc) {
fprintf(stderr, "usage: %s <drive_image> <sign_key>\n", argv[0]);
return 1;
}
image_name = argv[1];
keyfile_name = argv[2];
/* Read header signing key blob */
{
uint64_t key_size;
lkp.header_sign_key_blob = ReadFile(keyfile_name, &key_size);
if (!lkp.header_sign_key_blob) {
fprintf(stderr, "Unable to read key file %s\n", keyfile_name);
return 1;
}
}
/* Get image size */
printf("Reading from image: %s\n", image_name);
image_file = fopen(image_name, "rb");
if (!image_file) {
fprintf(stderr, "Unable to open image file %s\n", image_name);
return 1;
}
fseek(image_file, 0, SEEK_END);
lkp.ending_lba = (ftell(image_file) / LBA_BYTES) - 1;
rewind(image_file);
printf("Ending LBA: %" PRIu64 "\n", lkp.ending_lba);
/* Allocate a buffer for the kernel */
lkp.kernel_buffer = Malloc(KERNEL_BUFFER_SIZE);
if(!lkp.kernel_buffer) {
fprintf(stderr, "Unable to allocate kernel buffer.\n");
return 1;
}
/* TODO: Option for boot mode */
lkp.boot_flags = 0;
/* Call LoadKernel() */
rv = LoadKernelOld(&lkp);
printf("LoadKernelOld() returned %d\n", rv);
if (LOAD_KERNEL_SUCCESS == rv) {
printf("Partition number: %" PRIu64 "\n", lkp.partition_number);
printf("Bootloader address: %" PRIu64 "\n", lkp.bootloader_address);
printf("Bootloader size: %" PRIu64 "\n", lkp.bootloader_size);
}
fclose(image_file);
Free(lkp.kernel_buffer);
return 0;
}

View File

@@ -1,115 +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.
*
* Utility for signing boot firmware images.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "file_keys.h"
#include "utility.h"
#include "host_key.h"
#include "host_signature.h"
#include "host_common.h"
static void usage()
{
static char* help_mesg =
"Usage: sign_image <fw_version> <fw_key_block> <signing_key> "
"<kernel_public_key> <firmware_file> <output_file>\n";
printf("%s", help_mesg);
}
int SignAndWriteImage(uint64_t fw_version, VbKeyBlockHeader* wrapper_kb,
VbPrivateKey* signing_key,
VbPublicKey* nested_pubkey,
uint8_t* image, uint64_t image_size,
FILE* out_file)
{
VbFirmwarePreambleHeader* fw_preamble = NULL;
int rv = 1;
do { /* to be able to bail out anywhere */
VbSignature* firmware_sig;
/* sign the firmware first */
firmware_sig = CalculateSignature(image, image_size, signing_key);
/* write the original keyblock */
if (fwrite(wrapper_kb, wrapper_kb->key_block_size, 1, out_file) != 1) {
debug("failed writing key block\n");
break;
}
fw_preamble = CreateFirmwarePreamble(fw_version, nested_pubkey,
firmware_sig, signing_key);
if (!fw_preamble) {
debug("failed creating preamble\n");
break;
}
/* write the preamble */
if (fwrite(fw_preamble, fw_preamble->preamble_size, 1, out_file) != 1) {
debug("failed writing fw preamble\n");
break;
}
/* write the image */
if (fwrite(image, image_size, 1, out_file) != 1) {
debug("failed writing image\n");
break;
}
rv = 0;
} while(0);
if (fw_preamble) {
Free(fw_preamble);
}
return rv;
}
int main(int argc, char* argv[]) {
VbKeyBlockHeader* firmware_kb;
VbPublicKey* kernel_pubk;
uint8_t* firmware;
uint64_t fw_size;
uint64_t version;
VbPrivateKey* signing_key = NULL;
FILE* out_file;
int rv;
if (argc != 7) {
usage();
exit(1);
}
version = strtoul(argv[1], 0, 0);
firmware_kb = KeyBlockRead(argv[2]);
kernel_pubk = PublicKeyRead(argv[4]);
firmware = BufferFromFile(argv[5], &fw_size);
if (firmware_kb) {
signing_key = PrivateKeyRead(argv[3], firmware_kb->data_key.algorithm);
}
if (!firmware_kb || !kernel_pubk || !firmware || ! signing_key) {
return 1;
}
out_file = fopen(argv[6], "wb");
if (!out_file) {
debug("could not open %s for writing\n");
return 1;
}
rv = SignAndWriteImage(version, firmware_kb, signing_key,
kernel_pubk, firmware, fw_size, out_file);
fclose(out_file);
if (rv) {
unlink(argv[6]);
}
return rv;
}

View File

@@ -1,19 +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.
INCLUDES += -I./include \
-I$(FWDIR)/include \
-I$(FWDIR)/lib/include \
-I$(FWDIR)/lib/cgptlib/include \
-I$(FWDIR)/lib/cryptolib/include \
-I../common/include \
-I../utility/include \
-I../misclibs/include
BUILD_ROOT := ${BUILD}/vkernel
ALL_SRCS = kernel_image.c kernel_image_fw.c load_kernel_fw.c
include ../common.mk

View File

@@ -1,118 +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.
*
* API definitions for a generating and manipulating verified boot kernel images.
* (Userland portion.)
*/
#ifndef VBOOT_REFERENCE_KERNEL_IMAGE_H_
#define VBOOT_REFERENCE_KERNEL_IMAGE_H_
#include "kernel_image_fw.h"
/* Allocate and return a new KernelImage structure. */
KernelImage* KernelImageNew(void);
/* Deep free the contents of [image]. */
void KernelImageFree(KernelImage* image);
/* Read kernel data from file named [input_file].
*
* Returns a filled up KernelImage on success, NULL on error.
*/
KernelImage* ReadKernelImage(const char* input_file);
/* Get the length of the header for kernel image [image]. */
int GetKernelHeaderLen(const KernelImage* image);
/* Calculate and store the kernel header checksum of [image]
* in [header_checksum].
*
* [header_checksum] must be a valid pointer to a buffer of
* SHA512_DIGEST_SIZE.
*/
void CalculateKernelHeaderChecksum(const KernelImage* image,
uint8_t* header_checksum);
/* Get kernel header binary blob from an [image].
*
* Caller owns the returned pointer and must Free() it.
*/
uint8_t* GetKernelHeaderBlob(const KernelImage* image);
/* Get kernel config binary blob from an [image].
*
* Caller owns the returned pointer and must Free() it.
*/
uint8_t* GetKernelConfigBlob(const KernelImage* image);
/* Get a verified kernel binary blob from an [image] and fill
* its length into blob_len.
*
* Caller owns the returned pointer and must Free() it.
*/
uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len);
/* Write kernel data from [image] to a file named [input_file].
*
* If [is_only_vblock] is non-zero, only the verification block (excluding the
* actual kernel data) is output.
* If [is_subkey_out] is non-zero, only the kernel key verification (subkey)
* header is output.
*
* Return 1 on success, 0 on error.
*/
int WriteKernelImage(const char* input_file,
const KernelImage* image,
int is_only_vblock,
int is_subkey_out);
/* Create a kernel_data blob from its components and fill
* its length into blob_len, plus some information about the bootloader.
*
* Caller owns the returned pointer and must Free() it.
*/
uint8_t* GenerateKernelBlob(const char* vmlinuz_file,
const char* config_file,
const char* bootloader_file,
uint64_t* blob_len,
uint64_t* bootloader_offset,
uint64_t* bootloader_size);
/* Pretty print the contents of [image]. Only headers and metadata information
* is printed.
*/
void PrintKernelImage(const KernelImage* image);
/* Performs a chained verify of the kernel [image]. If [dev_mode] is
* 0 (inactive), then the [firmware_signing_key] is used to verify the signature
* of the signing key, else the check is skipped.
*
* Returns 0 on success, error code on failure.
*/
int VerifyKernelImage(const RSAPublicKey* firmware_signing_key,
const KernelImage* image,
int dev_mode);
/* Maps error codes from VerifyKernel*() to error description. */
const char* VerifyKernelErrorString(int error);
/* Add a kernel signing key signature to the key header to a kernel image
* [image] using the private key in file [firmware_key_file].
*
* Return 1 on success, 0 on failure.
*/
int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file);
/* Add a kernel and kernel config signature to a kernel image [image]
* using the private signing key in file [kernel_sigining_key_file].
*
* Return 1 on success, 0 on failure.
*/
int AddKernelSignature(KernelImage* image,
const char* kernel_sigining_key_file);
#endif /* VBOOT_REFERENCE_KERNEL_IMAGE_H_ */

View File

@@ -1,168 +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.
*
* Data structure and API definitions for a verified boot kernel image.
* (Firmware Portion)
*/
#ifndef VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_
#define VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_
#include <stdint.h>
#include "cryptolib.h"
#define KERNEL_MAGIC "CHROMEOS"
#define KERNEL_MAGIC_SIZE 8
#define DEV_MODE_ENABLED 1
#define DEV_MODE_DISABLED 0
typedef struct KernelImage {
uint8_t magic[KERNEL_MAGIC_SIZE];
/* Key header */
uint16_t header_version; /* Header version. */
uint16_t header_len; /* Length of the header. */
uint16_t firmware_sign_algorithm; /* Signature algorithm used by the firmware
* signing key (used to sign this kernel
* header. */
uint16_t kernel_sign_algorithm; /* Signature algorithm used by the kernel
* signing key. */
uint16_t kernel_key_version; /* Key Version# for preventing rollbacks. */
uint8_t* kernel_sign_key; /* Pre-processed public half of signing key. */
/* TODO(gauravsh): Do we need a choice of digest algorithms for the header
* checksum? */
uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 Crytographic hash of
* the concatenation of the
* header fields, i.e.
* [header_len,
* firmware_sign_algorithm,
* sign_algorithm, sign_key,
* key_version] */
/* End of kernel key header. */
uint8_t* kernel_key_signature; /* Signature of the header above. */
/* Kernel preamble */
uint16_t kernel_version; /* Kernel Version# for preventing rollbacks. */
uint64_t kernel_len; /* Length of the actual kernel image. */
uint64_t bootloader_offset; /* Offset of bootloader in kernel_data. */
uint64_t bootloader_size; /* Size of bootloader in bytes. */
uint64_t padded_header_size; /* start of kernel_data in disk partition */
uint8_t* kernel_signature; /* Signature on [kernel_data] below.
* NOTE: This is only considered valid
* if preamble_signature successfully verifies. */
/* end of preamble */
uint8_t* preamble_signature; /* signature on preamble, (includes
[kernel_signature]) */
uint8_t* kernel_data; /* Actual kernel data. */
} KernelImage;
/* Error Codes for VerifyFirmware. */
#define VERIFY_KERNEL_SUCCESS 0
#define VERIFY_KERNEL_INVALID_IMAGE 1
#define VERIFY_KERNEL_KEY_SIGNATURE_FAILED 2
#define VERIFY_KERNEL_INVALID_ALGORITHM 3
#define VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED 4
#define VERIFY_KERNEL_SIGNATURE_FAILED 5
#define VERIFY_KERNEL_WRONG_MAGIC 6
#define VERIFY_KERNEL_MAX 7 /* Generic catch-all. */
extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX];
/* Returns the length of the verified boot kernel preamble based on
* kernel signing algorithm [algorithm]. */
uint64_t GetKernelPreambleLen(int algorithm);
/* Returns the length of the Kernel Verified Boot header excluding
* [kernel_data].
*
* This is always non-zero, so a return value of 0 signifies an error.
*/
uint64_t GetVBlockHeaderSize(const uint8_t* vkernel_blob);
/* Checks for the sanity of the kernel key header at [kernel_header_blob].
* If [dev_mode] is enabled, also checks the kernel key signature using the
* pre-processed public firmware signing key [firmware_sign_key_blob].
*
* On success, puts firmware signature algorithm in [firmware_algorithm],
* kernel signature algorithm in [kernel_algorithm], kernel header
* length in [header_len], and return 0.
* Else, return error code on failure.
*/
int VerifyKernelKeyHeader(const uint8_t* firmware_sign_key_blob,
const uint8_t* kernel_header_blob,
const int dev_mode,
int* firmware_algorithm,
int* kernel_algorithm,
int* header_len);
/* Checks the kernel preamble signature at [kernel_preamble_blob]
* using the signing key [kernel_sign_key].
*
* On success, put kernel length into [kernel_len], and return 0.
* Else, return error code on failure.
*/
int VerifyKernelPreamble(RSAPublicKey* kernel_sign_key,
const uint8_t* kernel_preamble_blob,
int algorithm,
uint64_t* kernel_len);
/* Checks [kernel_signature] on the kernel data at location [kernel_data]. The
* signature is assumed to be generated using algorithm [algorithm].
* The length of the kernel data is [kernel_len].
*
* Return 0 on success, error code on failure.
*/
int VerifyKernelData(RSAPublicKey* kernel_sign_key,
const uint8_t* kernel_signature,
const uint8_t* kernel_data,
uint64_t kernel_len,
int algorithm);
/* Verifies the kernel key header and preamble at [kernel_header_blob]
* using the firmware public key [firmware_key_blob]. If [dev_mode] is 1
* (active), then key header verification is skipped.
*
* On success, fills in the fields of image with the kernel header and
* preamble fields.
*
* Note that pointers in the image point directly into the input
* kernel_header_blob. image->kernel_data is set to NULL, since it's not
* part of the header and preamble data itself.
*
* On success, the signing key to use for kernel data verification is
* returned in [kernel_sign_key], This must be free-d explicitly by
* the caller after use. On failure, the signing key is set to NULL.
*
* Returns 0 on success, error code on failure.
*/
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
const uint8_t* kernel_header_blob,
uint64_t kernel_header_blob_len,
const int dev_mode,
KernelImage* image,
RSAPublicKey** kernel_sign_key);
/* Performs a chained verify of the kernel blob [kernel_blob]. If
* [dev_mode] is 0 [inactive], then the pre-processed public signing key
* [root_key_blob] is used to verify the signature of the signing key,
* else the check is skipped.
* Returns 0 on success, error code on failure.
*
* NOTE: The length of the kernel blob is derived from reading the fields
* in the first few bytes of the buffer. This might look risky but in firmware
* land, the start address of the kernel_blob will always be fixed depending
* on the memory map on the particular platform. In addition, the signature on
* length itself is checked early in the verification process for extra safety.
*/
int VerifyKernel(const uint8_t* signing_key_blob,
const uint8_t* kernel_blob,
const int dev_mode);
/* Returns the logical version of a kernel blob which is calculated as
* (kernel_key_version << 16 | kernel_version). */
uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob);
#endif /* VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_ */

View File

@@ -1,754 +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.
*
* Functions for generating and manipulating a verified boot kernel image.
* (Userland portion)
*/
#include "kernel_image.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "cryptolib.h"
#include "file_keys.h"
#include "kernel_blob.h"
#include "rollback_index.h"
#include "signature_digest.h"
#include "stateful_util.h"
#include "utility.h"
/* Macro to determine the size of a field structure in the KernelImage
* structure. */
#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
KernelImage* KernelImageNew(void) {
KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage));
if (image) {
image->kernel_sign_key = NULL;
image->kernel_key_signature = NULL;
image->preamble_signature = NULL;
image->kernel_signature = NULL;
image->kernel_data = NULL;
image->padded_header_size = 0x4000;
}
return image;
}
void KernelImageFree(KernelImage* image) {
if (image) {
Free(image->kernel_sign_key);
Free(image->kernel_key_signature);
Free(image->preamble_signature);
Free(image->kernel_signature);
Free(image->kernel_data);
Free(image);
}
}
uint64_t GetHeaderSizeOnDisk(const KernelImage* image) {
uint64_t kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
uint64_t kernel_key_signature_len =
siglen_map[image->firmware_sign_algorithm];
return FIELD_LEN(magic) +
GetKernelHeaderLen(image) +
kernel_key_signature_len +
GetKernelPreambleLen(image->kernel_sign_algorithm) +
kernel_signature_len;
}
KernelImage* ReadKernelImage(const char* input_file) {
uint64_t file_size;
uint64_t on_disk_header_size;
uint64_t on_disk_padding;
int header_len = 0;
int kernel_key_signature_len;
int kernel_sign_key_len;
int kernel_signature_len;
uint8_t* kernel_buf;
uint8_t header_checksum[FIELD_LEN(header_checksum)];
MemcpyState st;
KernelImage* image = KernelImageNew();
if (!image)
return NULL;
kernel_buf = BufferFromFile(input_file, &file_size);
st.remaining_len = file_size;
st.remaining_buf = kernel_buf;
st.overrun = 0;
/* Read and compare magic bytes. */
StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
debug("Wrong Kernel Magic.\n");
Free(kernel_buf);
return NULL;
}
StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
StatefulMemcpy(&st, &image->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
StatefulMemcpy(&st, &image->kernel_sign_algorithm,
FIELD_LEN(kernel_sign_algorithm));
/* Valid Kernel Key signing algorithm. */
if (image->firmware_sign_algorithm >= kNumAlgorithms) {
Free(kernel_buf);
return NULL;
}
/* Valid Kernel Signing Algorithm? */
if (image->kernel_sign_algorithm >= kNumAlgorithms) {
Free(kernel_buf);
return NULL;
}
/* Compute size of pre-processed RSA public keys and signatures. */
kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
/* Check whether key header length is correct. */
header_len = GetKernelHeaderLen(image);
if (header_len != image->header_len) {
debug("Header length mismatch. Got: %d, Expected: %d\n",
image->header_len, header_len);
Free(kernel_buf);
return NULL;
}
/* Read pre-processed public half of the kernel signing key. */
StatefulMemcpy(&st, &image->kernel_key_version,
FIELD_LEN(kernel_key_version));
image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
/* Check whether the header checksum matches. */
CalculateKernelHeaderChecksum(image, header_checksum);
if (SafeMemcmp(header_checksum, image->header_checksum,
FIELD_LEN(header_checksum))) {
debug("Invalid kernel header checksum!\n");
Free(kernel_buf);
return NULL;
}
/* Read key signature. */
image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
StatefulMemcpy(&st, image->kernel_key_signature,
kernel_key_signature_len);
/* Read the kernel preamble. */
StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
StatefulMemcpy(&st, &image->padded_header_size,
FIELD_LEN(padded_header_size));
/* Read preamble and kernel signatures. */
image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len);
StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len);
/* Skip over the rest of the padded header, unless we're already past it. */
on_disk_header_size = file_size - st.remaining_len;
if (image->padded_header_size > on_disk_header_size) {
on_disk_padding = image->padded_header_size - on_disk_header_size;
if (st.remaining_len < on_disk_padding)
st.overrun = -1;
st.remaining_buf += on_disk_padding;
st.remaining_len -= on_disk_padding;
}
/* Read kernel image data. */
image->kernel_data = (uint8_t*) Malloc(image->kernel_len);
StatefulMemcpy(&st, image->kernel_data, image->kernel_len);
if(st.overrun) {
Free(kernel_buf);
return NULL;
}
Free(kernel_buf);
return image;
}
int GetKernelHeaderLen(const KernelImage* image) {
return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
FIELD_LEN(firmware_sign_algorithm) +
FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
RSAProcessedKeySize(image->kernel_sign_algorithm) +
FIELD_LEN(header_checksum));
}
void CalculateKernelHeaderChecksum(const KernelImage* image,
uint8_t* header_checksum) {
uint8_t* checksum;
DigestContext ctx;
DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
DigestUpdate(&ctx, (uint8_t*) &image->header_version,
sizeof(image->header_version));
DigestUpdate(&ctx, (uint8_t*) &image->header_len,
sizeof(image->header_len));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
sizeof(image->firmware_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
sizeof(image->kernel_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
sizeof(image->kernel_key_version));
DigestUpdate(&ctx, image->kernel_sign_key,
RSAProcessedKeySize(image->kernel_sign_algorithm));
checksum = DigestFinal(&ctx);
Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
Free(checksum);
return;
}
uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
uint8_t* header_blob = NULL;
MemcpyState st;
header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
st.remaining_len = GetKernelHeaderLen(image);
st.remaining_buf = header_blob;
st.overrun = 0;
StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
FIELD_LEN(kernel_sign_algorithm));
StatefulMemcpy_r(&st, &image->kernel_key_version,
FIELD_LEN(kernel_key_version));
StatefulMemcpy_r(&st, image->kernel_sign_key,
RSAProcessedKeySize(image->kernel_sign_algorithm));
StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Free(header_blob);
return NULL;
}
return header_blob;
}
uint8_t* GetKernelPreambleBlob(const KernelImage* image) {
uint8_t* preamble_blob = NULL;
MemcpyState st;
preamble_blob = (uint8_t*) Malloc(
GetKernelPreambleLen(image->kernel_sign_algorithm));
st.remaining_len = GetKernelPreambleLen(image->kernel_sign_algorithm);
st.remaining_buf = preamble_blob;
st.overrun = 0;
StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
StatefulMemcpy_r(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
StatefulMemcpy_r(&st, &image->padded_header_size,
FIELD_LEN(padded_header_size));
StatefulMemcpy_r(&st, image->kernel_signature,
siglen_map[image->kernel_sign_algorithm]);
if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Free(preamble_blob);
return NULL;
}
return preamble_blob;
}
uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
int kernel_key_signature_len;
int kernel_signature_len;
uint8_t* kernel_blob = NULL;
uint8_t* header_blob = NULL;
MemcpyState st;
uint64_t on_disk_header_size;
uint64_t on_disk_padding = 0;
if (!image)
return NULL;
kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
on_disk_header_size = GetHeaderSizeOnDisk(image);
if (image->padded_header_size > on_disk_header_size)
on_disk_padding = image->padded_header_size - on_disk_header_size;
*blob_len = on_disk_header_size + on_disk_padding + image->kernel_len;
kernel_blob = (uint8_t*) Malloc(*blob_len);
st.remaining_len = *blob_len;
st.remaining_buf = kernel_blob;
st.overrun = 0;
header_blob = GetKernelHeaderBlob(image);
StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
/* Copy over kernel preamble blob (including signatures.) */
StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
StatefulMemcpy_r(&st, &image->bootloader_offset,
FIELD_LEN(bootloader_offset));
StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
StatefulMemcpy_r(&st, &image->padded_header_size,
FIELD_LEN(padded_header_size));
StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len);
/* Copy a bunch of zeros to pad out the header */
if (on_disk_padding)
StatefulMemset_r(&st, 0, on_disk_padding);
StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
Free(header_blob);
if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
debug("GetKernelBlob() failed.\n");
Free(kernel_blob);
return NULL;
}
return kernel_blob;
}
int WriteKernelImage(const char* output_file,
const KernelImage* image,
int is_only_vblock,
int is_subkey_out) {
int fd;
int success = 1;
uint8_t* kernel_blob = NULL;
uint8_t* subkey_out_buf = NULL;
uint8_t* subkey_header = NULL;
uint64_t blob_len;
if (!image)
return 0;
if (-1 == (fd = creat(output_file, 0666))) {
debug("Couldn't open file for writing kernel image: %s\n",
output_file);
return 0;
}
if (is_subkey_out) {
blob_len = GetKernelHeaderLen(image) +
siglen_map[image->firmware_sign_algorithm];
subkey_out_buf = (uint8_t*) Malloc(blob_len);
subkey_header = GetKernelHeaderBlob(image);
Memcpy(subkey_out_buf, subkey_header, GetKernelHeaderLen(image));
Memcpy(subkey_out_buf + GetKernelHeaderLen(image),
image->kernel_key_signature,
siglen_map[image->firmware_sign_algorithm]);
if (blob_len != write(fd, subkey_out_buf, blob_len)) {
debug("Couldn't write Kernel Subkey header to file: %s\n",
output_file);
success = 0;
}
Free(subkey_header);
Free(subkey_out_buf);
close(fd);
return success;
}
kernel_blob = GetKernelBlob(image, &blob_len);
if (!kernel_blob) {
debug("Couldn't create kernel blob from KernelImage.\n");
return 0;
}
if (!is_only_vblock) {
if (blob_len != write(fd, kernel_blob, blob_len)) {
debug("Couldn't write Kernel Image to file: %s\n",
output_file);
success = 0;
}
} else {
/* Exclude kernel_data. */
int vblock_len = blob_len - (image->kernel_len);
if (vblock_len != write(fd, kernel_blob, vblock_len)) {
debug("Couldn't write Kernel Image Verification block to file: %s\n",
output_file);
success = 0;
}
}
Free(kernel_blob);
close(fd);
return success;
}
void PrintKernelImage(const KernelImage* image) {
uint64_t header_size;
if (!image)
return;
header_size = GetHeaderSizeOnDisk(image);
if (image->padded_header_size > header_size)
header_size = image->padded_header_size;
/* Print header. */
printf("Header Version = %d\n"
"Header Length = %d\n"
"Kernel Key Signature Algorithm = %s\n"
"Kernel Signature Algorithm = %s\n"
"Kernel Key Version = %d\n\n",
image->header_version,
image->header_len,
algo_strings[image->firmware_sign_algorithm],
algo_strings[image->kernel_sign_algorithm],
image->kernel_key_version);
/* TODO(gauravsh): Output hash and key signature here? */
/* Print preamble. */
printf("Kernel Version = %d\n"
"kernel Length = %" PRId64 " (0x%" PRIx64 ")\n"
"Bootloader Offset = %" PRId64 " (0x%" PRIx64 ")\n"
"Bootloader Size = %" PRId64 " (0x%" PRIx64 ")\n"
"Padded Header Size = %" PRId64 " (0x%" PRIx64 ")\n\n"
"Actual Header Size on disk = %" PRIu64 " (0x%" PRIx64 ")\n",
image->kernel_version,
image->kernel_len, image->kernel_len,
image->bootloader_offset, image->bootloader_offset,
image->bootloader_size, image->bootloader_size,
image->padded_header_size, image->padded_header_size,
header_size, header_size);
/* TODO(gauravsh): Output kernel signature here? */
}
int VerifyKernelImage(const RSAPublicKey* firmware_key,
const KernelImage* image,
const int dev_mode) {
RSAPublicKey* kernel_sign_key = NULL;
uint8_t* header_digest = NULL;
uint8_t* preamble_digest = NULL;
uint8_t* kernel_digest = NULL;
int kernel_sign_key_size;
int kernel_signature_size;
int error_code = 0;
DigestContext ctx;
if (!image)
return VERIFY_KERNEL_INVALID_IMAGE;
/* Verify kernel key signature on the key header if we
* are not in dev mode.
*
* TODO(gauravsh): Add additional sanity checks here for:
* 1) verifying the header length is correct.
* 2) header_checksum is correct.
*/
if (image->firmware_sign_algorithm >= kNumAlgorithms)
return VERIFY_KERNEL_INVALID_ALGORITHM;
if (image->kernel_sign_algorithm >= kNumAlgorithms)
return VERIFY_KERNEL_INVALID_ALGORITHM;
if (!dev_mode) {
DigestInit(&ctx, image->firmware_sign_algorithm);
DigestUpdate(&ctx, (uint8_t*) &image->header_version,
FIELD_LEN(header_version));
DigestUpdate(&ctx, (uint8_t*) &image->header_len,
FIELD_LEN(header_len));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
FIELD_LEN(kernel_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
FIELD_LEN(kernel_key_version));
DigestUpdate(&ctx, image->kernel_sign_key,
RSAProcessedKeySize(image->kernel_sign_algorithm));
DigestUpdate(&ctx, image->header_checksum,
FIELD_LEN(header_checksum));
header_digest = DigestFinal(&ctx);
if (!RSAVerify(firmware_key, image->kernel_key_signature,
siglen_map[image->firmware_sign_algorithm],
image->firmware_sign_algorithm,
header_digest)) {
debug("VerifyKernelImage(): Key signature check failed.\n");
error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
goto verify_failure;
}
}
/* Get kernel signing key to verify the rest of the kernel. */
kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
kernel_sign_key_size);
kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
/* Verify kernel preamble signature. */
DigestInit(&ctx, image->kernel_sign_algorithm);
DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
FIELD_LEN(kernel_version));
DigestUpdate(&ctx, (uint8_t*) &image->kernel_len,
FIELD_LEN(kernel_len));
DigestUpdate(&ctx, (uint8_t*) &image->bootloader_offset,
FIELD_LEN(bootloader_offset));
DigestUpdate(&ctx, (uint8_t*) &image->bootloader_size,
FIELD_LEN(bootloader_size));
DigestUpdate(&ctx, (uint8_t*) &image->padded_header_size,
FIELD_LEN(padded_header_size));
DigestUpdate(&ctx, (uint8_t*) image->kernel_signature,
kernel_signature_size);
preamble_digest = DigestFinal(&ctx);
if (!RSAVerify(kernel_sign_key, image->preamble_signature,
kernel_signature_size, image->kernel_sign_algorithm,
preamble_digest)) {
error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED;
goto verify_failure;
}
/* Verify kernel signature - kernel signature is computed on the contents
* of kernel_data.
* Association between the kernel_data and preamble is maintained by making
* the kernel signature a part of the preamble and verifying it as part
* of preamble signature checking. */
kernel_digest = DigestBuf(image->kernel_data,
image->kernel_len,
image->kernel_sign_algorithm);
if (!RSAVerify(kernel_sign_key, image->kernel_signature,
kernel_signature_size, image->kernel_sign_algorithm,
kernel_digest)) {
error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
goto verify_failure;
}
verify_failure:
RSAPublicKeyFree(kernel_sign_key);
Free(kernel_digest);
Free(preamble_digest);
Free(header_digest);
return error_code;
}
const char* VerifyKernelErrorString(int error) {
return kVerifyKernelErrors[error];
}
int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
uint8_t* header_blob = NULL;
uint8_t* signature = NULL;
int signature_len = siglen_map[image->firmware_sign_algorithm];
if (!image || !firmware_key_file)
return 0;
header_blob = GetKernelHeaderBlob(image);
if (!header_blob)
return 0;
if (!(signature = SignatureBuf(header_blob,
GetKernelHeaderLen(image),
firmware_key_file,
image->firmware_sign_algorithm))) {
Free(header_blob);
return 0;
}
image->kernel_key_signature = Malloc(signature_len);
Memcpy(image->kernel_key_signature, signature, signature_len);
Free(signature);
Free(header_blob);
return 1;
}
int AddKernelSignature(KernelImage* image,
const char* kernel_signing_key_file) {
uint8_t* preamble_blob = NULL;
uint8_t* preamble_signature = NULL;
uint8_t* kernel_signature = NULL;
uint8_t* kernel_buf;
int algorithm = image->kernel_sign_algorithm;
int signature_len = siglen_map[algorithm];
/* Kernel signature must be calculated first as its used for computing the
* preamble signature. */
kernel_buf = (uint8_t*) Malloc(image->kernel_len);
Memcpy(kernel_buf, image->kernel_data, image->kernel_len);
if (!(kernel_signature = SignatureBuf(kernel_buf,
image->kernel_len,
kernel_signing_key_file,
algorithm))) {
Free(preamble_blob);
Free(kernel_buf);
debug("Could not compute signature on the kernel.\n");
return 0;
}
image->kernel_signature = (uint8_t*) Malloc(signature_len);
Memcpy(image->kernel_signature, kernel_signature, signature_len);
preamble_blob = GetKernelPreambleBlob(image);
if (!(preamble_signature = SignatureBuf(preamble_blob,
GetKernelPreambleLen(algorithm),
kernel_signing_key_file,
algorithm))) {
debug("Could not compute signature on the kernel preamble.\n");
Free(preamble_blob);
return 0;
}
image->preamble_signature = (uint8_t*) Malloc(signature_len);
Memcpy(image->preamble_signature, preamble_signature, signature_len);
Free(preamble_signature);
Free(preamble_blob);
Free(kernel_signature);
Free(kernel_buf);
return 1;
}
/* 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;
}
uint8_t* GenerateKernelBlob(const char* kernel_file,
const char* config_file,
const char* bootloader_file,
uint64_t* ret_blob_len,
uint64_t* ret_bootloader_offset,
uint64_t* ret_bootloader_size) {
uint8_t* kernel_buf;
uint8_t* config_buf;
uint8_t* bootloader_buf;
uint8_t* blob = 0;
uint64_t kernel_size;
uint64_t config_size;
uint64_t bootloader_size;
uint64_t blob_size;
uint64_t kernel32_start = 0;
uint64_t kernel32_size = 0;
uint64_t bootloader_mem_start;
uint64_t bootloader_mem_size;
uint64_t now;
struct linux_kernel_header *lh = 0;
struct linux_kernel_params *params = 0;
uint32_t cmdline_addr;
uint64_t i;
/* Read the input files. */
kernel_buf = BufferFromFile(kernel_file, &kernel_size);
if (!kernel_buf)
goto done0;
config_buf = BufferFromFile(config_file, &config_size);
if (!config_buf)
goto done1;
if (config_size >= CROS_CONFIG_SIZE) { /* need room for trailing '\0' */
error("config file %s is too large (>= %d bytes)\n",
config_file, CROS_CONFIG_SIZE);
goto done1;
}
/* Replace any newlines with spaces in the config file. */
for (i=0; i < config_size; i++)
if (config_buf[i] == '\n')
config_buf[i] = ' ';
bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size);
if (!bootloader_buf)
goto done2;
/* The first part of vmlinuz is a header, followed by a real-mode boot stub.
* We only want the 32-bit part. */
if (kernel_size) {
lh = (struct linux_kernel_header *)kernel_buf;
kernel32_start = (lh->setup_sects+1) << 9;
kernel32_size = kernel_size - kernel32_start;
}
/* Allocate and zero the blob we need. */
blob_size = roundup(kernel32_size, CROS_ALIGN) +
CROS_CONFIG_SIZE +
CROS_PARAMS_SIZE +
roundup(bootloader_size, CROS_ALIGN);
blob = (uint8_t *)Malloc(blob_size);
if (!blob) {
error("Couldn't allocate %ld bytes.\n", blob_size);
goto done3;
}
Memset(blob, 0, blob_size);
now = 0;
/* Copy the 32-bit kernel. */
if (kernel32_size)
Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size);
now += roundup(now + kernel32_size, CROS_ALIGN);
/* Find the load address of the commandline. We'll need it later. */
cmdline_addr = CROS_32BIT_ENTRY_ADDR + now
+ find_cmdline_start((char *)config_buf, config_size);
/* Copy the config. */
if (config_size)
Memcpy(blob + now, config_buf, config_size);
now += CROS_CONFIG_SIZE;
/* The zeropage data is next. Overlay the linux_kernel_header onto it, and
* tweak a few fields. */
params = (struct linux_kernel_params *)(blob + now);
if (kernel_size)
Memcpy(&(params->setup_sects), &(lh->setup_sects),
sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
params->boot_flag = 0;
params->ramdisk_image = 0; /* we don't support initrd */
params->ramdisk_size = 0;
params->type_of_loader = 0xff;
params->cmd_line_ptr = cmdline_addr;
now += CROS_PARAMS_SIZE;
/* Finally, append the bootloader. Remember where it will load in memory, too.
*/
bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now;
bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN);
if (bootloader_size)
Memcpy(blob + now, bootloader_buf, bootloader_size);
now += bootloader_mem_size;
/* Pass back some info. */
if (ret_blob_len)
*ret_blob_len = blob_size;
if (ret_bootloader_offset)
*ret_bootloader_offset = bootloader_mem_start;
if (ret_bootloader_size)
*ret_bootloader_size = bootloader_mem_size;
/* Clean up and return the blob. */
done3:
Free(bootloader_buf);
done2:
Free(config_buf);
done1:
Free(kernel_buf);
done0:
return blob;
}

View File

@@ -1,384 +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.
*
* Functions for verifying a verified boot kernel image.
* (Firmware portion)
*/
#include "kernel_image_fw.h"
#include "cryptolib.h"
#include "rollback_index.h"
#include "stateful_util.h"
#include "utility.h"
/* Macro to determine the size of a field structure in the KernelImage
* structure. */
#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
"Success.",
"Invalid Image.",
"Kernel Key Signature Failed.",
"Invalid Kernel Verification Algorithm.",
"Preamble Signature Failed.",
"Kernel Signature Failed.",
"Wrong Kernel Magic.",
};
inline uint64_t GetKernelPreambleLen(int algorithm) {
return (FIELD_LEN(kernel_version) +
FIELD_LEN(kernel_len) +
FIELD_LEN(bootloader_offset) +
FIELD_LEN(bootloader_size) +
FIELD_LEN(padded_header_size) +
siglen_map[algorithm]);
}
uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) {
uint64_t len = 0;
uint16_t firmware_sign_algorithm;
uint16_t kernel_sign_algorithm;
int algorithms_offset = (FIELD_LEN(magic) +
FIELD_LEN(header_version) +
FIELD_LEN(header_len));
if (SafeMemcmp(vkernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
debug("Not a valid verified boot kernel blob.\n");
return 0;
}
Memcpy(&firmware_sign_algorithm,
vkernel_blob + algorithms_offset,
sizeof(firmware_sign_algorithm));
Memcpy(&kernel_sign_algorithm,
vkernel_blob + algorithms_offset + FIELD_LEN(kernel_sign_algorithm),
sizeof(kernel_sign_algorithm));
if (firmware_sign_algorithm >= kNumAlgorithms) {
debug("Invalid firmware signing algorithm.\n");
return 0;
}
if (kernel_sign_algorithm >= kNumAlgorithms) {
debug("Invalid kernel signing algorithm.\n");
return 0;
}
len = algorithms_offset; /* magic, header length and version. */
len += (FIELD_LEN(firmware_sign_algorithm) +
FIELD_LEN(kernel_sign_algorithm) +
FIELD_LEN(kernel_key_version) +
RSAProcessedKeySize(kernel_sign_algorithm) + /* kernel_sign_key */
FIELD_LEN(header_checksum) +
siglen_map[firmware_sign_algorithm] + /* kernel_key_signature */
GetKernelPreambleLen(kernel_sign_algorithm) +
siglen_map[kernel_sign_algorithm]); /* preamble_signature */
return len;
}
int VerifyKernelKeyHeader(const uint8_t* firmware_key_blob,
const uint8_t* header_blob,
const int dev_mode,
int* firmware_algorithm,
int* kernel_algorithm,
int* kernel_header_len) {
int kernel_sign_key_len;
int firmware_sign_key_len;
uint16_t header_version, header_len;
uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
uint8_t* header_checksum = NULL;
/* Base Offset for the header_checksum field. Actual offset is
* this + kernel_sign_key_len. */
int base_header_checksum_offset = (FIELD_LEN(header_version) +
FIELD_LEN(header_len) +
FIELD_LEN(firmware_sign_algorithm) +
FIELD_LEN(kernel_sign_algorithm) +
FIELD_LEN(kernel_key_version));
Memcpy(&header_version, header_blob, sizeof(header_version));
Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
sizeof(header_len));
Memcpy(&firmware_sign_algorithm,
header_blob + (FIELD_LEN(header_version) +
FIELD_LEN(header_len)),
sizeof(firmware_sign_algorithm));
Memcpy(&kernel_sign_algorithm,
header_blob + (FIELD_LEN(header_version) +
FIELD_LEN(header_len) +
FIELD_LEN(firmware_sign_algorithm)),
sizeof(kernel_sign_algorithm));
/* TODO(gauravsh): Make this return two different error types depending
* on whether the firmware or kernel signing algorithm is invalid. */
if (firmware_sign_algorithm >= kNumAlgorithms)
return VERIFY_KERNEL_INVALID_ALGORITHM;
if (kernel_sign_algorithm >= kNumAlgorithms)
return VERIFY_KERNEL_INVALID_ALGORITHM;
*firmware_algorithm = (int) firmware_sign_algorithm;
*kernel_algorithm = (int) kernel_sign_algorithm;
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
/* Verify if header len is correct? */
if (header_len != (base_header_checksum_offset +
kernel_sign_key_len +
FIELD_LEN(header_checksum))) {
debug("VerifyKernelKeyHeader: Header length mismatch\n");
return VERIFY_KERNEL_INVALID_IMAGE;
}
*kernel_header_len = (int) header_len;
/* Verify if the hash of the header is correct. */
header_checksum = DigestBuf(header_blob,
header_len - FIELD_LEN(header_checksum),
SHA512_DIGEST_ALGORITHM);
if (SafeMemcmp(header_checksum,
header_blob + (base_header_checksum_offset +
kernel_sign_key_len),
FIELD_LEN(header_checksum))) {
Free(header_checksum);
debug("VerifyKernelKeyHeader: Invalid header hash\n");
return VERIFY_KERNEL_INVALID_IMAGE;
}
Free(header_checksum);
/* Verify kernel key signature unless we are in dev mode. */
if (!dev_mode) {
if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
header_blob, /* Data to verify */
header_len, /* Length of data */
header_blob + header_len, /* Expected Signature */
firmware_sign_algorithm))
return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
}
return 0;
}
int VerifyKernelPreamble(RSAPublicKey* kernel_sign_key,
const uint8_t* preamble_blob,
int algorithm,
uint64_t* kernel_len) {
int preamble_len = GetKernelPreambleLen(algorithm);
if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
preamble_blob, /* Data to verify */
preamble_len, /* Length of data */
preamble_blob + preamble_len, /* Expected Signature */
algorithm))
return VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED;
Memcpy(kernel_len,
preamble_blob + FIELD_LEN(kernel_version),
FIELD_LEN(kernel_len));
return 0;
}
int VerifyKernelData(RSAPublicKey* kernel_sign_key,
const uint8_t* kernel_signature,
const uint8_t* kernel_data,
uint64_t kernel_len,
int algorithm) {
if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
kernel_data, /* Data to verify */
kernel_len, /* Length of data */
kernel_signature, /* Expected Signature */
algorithm))
return VERIFY_KERNEL_SIGNATURE_FAILED;
return 0;
}
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
const uint8_t* kernel_header_blob,
uint64_t kernel_header_blob_len,
const int dev_mode,
KernelImage* image,
RSAPublicKey** kernel_sign_key) {
int error_code;
int firmware_sign_algorithm; /* Firmware signing key algorithm. */
int kernel_sign_algorithm; /* Kernel signing key algorithm. */
int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
header_len;
uint64_t kernel_len;
const uint8_t* header_ptr = NULL; /* Pointer to key header. */
const uint8_t* preamble_ptr = NULL; /* Pointer to start of preamble. */
MemcpyState st;
/* Note: All the offset calculations are based on struct KernelImage which
* is defined in include/kernel_image_fw.h. */
st.remaining_buf = (void *)kernel_header_blob;
st.remaining_len = kernel_header_blob_len;
st.overrun = 0;
/* Clear destination image struct */
Memset(image, 0, sizeof(KernelImage));
/* Read and compare magic bytes. */
StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
return VERIFY_KERNEL_WRONG_MAGIC;
}
StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
StatefulMemcpy(&st, &image->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
StatefulMemcpy(&st, &image->kernel_sign_algorithm,
FIELD_LEN(kernel_sign_algorithm));
header_ptr = kernel_header_blob + KERNEL_MAGIC_SIZE;
/* Only continue if header verification succeeds. */
if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr,
dev_mode,
&firmware_sign_algorithm,
&kernel_sign_algorithm,
&header_len))) {
debug("VerifyKernelHeader: Kernel Key Header verification failed.\n");
return error_code; /* AKA jump to recovery. */
}
/* Read pre-processed public half of the kernel signing key. */
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
StatefulMemcpy(&st, &image->kernel_key_version,
FIELD_LEN(kernel_key_version));
image->kernel_sign_key = (uint8_t*)st.remaining_buf;
StatefulSkip(&st, kernel_sign_key_len);
StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
/* Parse signing key into RSAPublicKey structure since it is
* required multiple times. */
*kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
kernel_sign_key_len);
kernel_signature_len = siglen_map[kernel_sign_algorithm];
kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
image->kernel_key_signature = (uint8_t*)st.remaining_buf;
StatefulSkip(&st, kernel_key_signature_len);
/* Only continue if preamble verification succeeds. */
/* TODO: should pass the remaining len into VerifyKernelPreamble() */
preamble_ptr = (const uint8_t*)st.remaining_buf;
if ((error_code = VerifyKernelPreamble(*kernel_sign_key, preamble_ptr,
kernel_sign_algorithm,
&kernel_len))) {
RSAPublicKeyFree(*kernel_sign_key);
*kernel_sign_key = NULL;
return error_code; /* AKA jump to recovery. */
}
/* Copy preamble fields */
StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
StatefulMemcpy(&st, &image->padded_header_size,
FIELD_LEN(padded_header_size));
image->kernel_signature = (uint8_t*)st.remaining_buf;
StatefulSkip(&st, kernel_signature_len);
image->preamble_signature = (uint8_t*)st.remaining_buf;
return 0;
}
int VerifyKernel(const uint8_t* firmware_key_blob,
const uint8_t* kernel_blob,
const int dev_mode) {
int error_code;
int firmware_sign_algorithm; /* Firmware signing key algorithm. */
int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
RSAPublicKey* kernel_sign_key;
int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
header_len;
uint64_t kernel_len;
const uint8_t* header_ptr; /* Pointer to header. */
const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
const uint8_t* preamble_ptr; /* Pointer to kernel preamble block. */
const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
const uint8_t* kernel_signature;
/* Note: All the offset calculations are based on struct FirmwareImage which
* is defined in include/firmware_image.h. */
/* Compare magic bytes. */
if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
debug("VerifyKernel: Kernel magic bytes not found.\n");
return VERIFY_KERNEL_WRONG_MAGIC;
}
header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
/* Only continue if header verification succeeds. */
if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr, dev_mode,
&firmware_sign_algorithm,
&kernel_sign_algorithm, &header_len))) {
debug("VerifyKernel: Kernel header verification failed.\n");
return error_code; /* AKA jump to recovery. */
}
/* Parse signing key into RSAPublicKey structure since it is required multiple
* times. */
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
FIELD_LEN(header_len) +
FIELD_LEN(firmware_sign_algorithm) +
FIELD_LEN(kernel_sign_algorithm) +
FIELD_LEN(kernel_key_version));
kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
kernel_sign_key_len);
kernel_signature_len = siglen_map[kernel_sign_algorithm];
kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
/* Only continue if preamble verification succeeds. */
preamble_ptr = (header_ptr + header_len + kernel_key_signature_len);
if ((error_code = VerifyKernelPreamble(kernel_sign_key, preamble_ptr,
kernel_sign_algorithm,
&kernel_len))) {
debug("VerifyKernel: Kernel preamble verification failed.\n");
RSAPublicKeyFree(kernel_sign_key);
return error_code; /* AKA jump to recovery. */
}
/* Only continue if kernel data verification succeeds. */
kernel_ptr = (preamble_ptr +
GetKernelPreambleLen(kernel_sign_algorithm) +
kernel_signature_len); /* preamble signature. */
kernel_signature = kernel_ptr - 2 * kernel_signature_len; /* end of kernel
* preamble. */
if ((error_code = VerifyKernelData(kernel_sign_key, /* Verification key */
kernel_signature, /* kernel signature */
kernel_ptr, /* Start of kernel data */
kernel_len, /* Length of kernel data. */
kernel_sign_algorithm))) {
RSAPublicKeyFree(kernel_sign_key);
return error_code; /* AKA jump to recovery. */
}
RSAPublicKeyFree(kernel_sign_key);
return 0; /* Success! */
}
uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
uint8_t* kernel_ptr;
uint16_t kernel_key_version;
uint16_t kernel_version;
uint16_t firmware_sign_algorithm;
uint16_t kernel_sign_algorithm;
int kernel_key_signature_len;
int kernel_sign_key_len;
kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
FIELD_LEN(header_version) +
FIELD_LEN(header_len));
Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
if (firmware_sign_algorithm >= kNumAlgorithms)
return 0;
if (kernel_sign_algorithm >= kNumAlgorithms)
return 0;
kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
kernel_ptr += (FIELD_LEN(kernel_key_version) +
kernel_sign_key_len +
FIELD_LEN(header_checksum) +
kernel_key_signature_len);
Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
return CombineUint16Pair(kernel_key_version, kernel_version);
}

View File

@@ -1,251 +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.
*
* Functions for loading a kernel from disk.
* (Firmware portion)
*/
#include "load_kernel_fw.h"
#include "boot_device.h"
#include "cgptlib.h"
#include "kernel_image_fw.h"
#include "rollback_index.h"
#include "utility.h"
#include "vboot_kernel.h"
#define GPT_ENTRIES_SIZE 16384 /* Bytes to read for GPT entries */
#ifdef PRINT_DEBUG_INFO
// TODO: for testing
#include <stdio.h>
#include <inttypes.h> /* For PRIu64 macro */
#include "cgptlib_internal.h"
#endif
#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
int LoadKernelOld(LoadKernelParams* params) {
GptData gpt;
uint64_t part_start, part_size;
uint64_t blba = params->bytes_per_lba;
uint8_t* kbuf = NULL;
uint64_t kbuf_sectors;
int found_partition = 0;
int good_partition = -1;
uint16_t tpm_kernel_key_version, tpm_kernel_version;
uint16_t lowest_kernel_key_version = 0xFFFF;
uint16_t lowest_kernel_version = 0xFFFF;
KernelImage *kim = NULL;
int is_dev = ((BOOT_FLAG_DEVELOPER & params->boot_flags) &&
!(BOOT_FLAG_RECOVERY & params->boot_flags));
int is_normal = (!(BOOT_FLAG_DEVELOPER & params->boot_flags) &&
!(BOOT_FLAG_RECOVERY & params->boot_flags));
/* Clear output params in case we fail */
params->partition_number = 0;
params->bootloader_address = 0;
params->bootloader_size = 0;
if (is_normal) {
/* Read current kernel key index from TPM. Assumes TPM is already
* initialized. */
if (0 != GetStoredVersions(KERNEL_VERSIONS,
&tpm_kernel_key_version,
&tpm_kernel_version))
return LOAD_KERNEL_RECOVERY;
}
do {
/* Read GPT data */
gpt.sector_bytes = blba;
gpt.drive_sectors = params->ending_lba + 1;
if (0 != AllocAndReadGptData(&gpt))
break;
/* Initialize GPT library */
if (GPT_SUCCESS != GptInit(&gpt))
break;
/* Allocate kernel header and image work buffers */
kbuf = (uint8_t*)Malloc(KBUF_SIZE);
if (!kbuf)
break;
kbuf_sectors = KBUF_SIZE / blba;
kim = (KernelImage*)Malloc(sizeof(KernelImage));
if (!kim)
break;
/* Loop over candidate kernel partitions */
while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) {
RSAPublicKey *kernel_sign_key = NULL;
int kernel_start, kernel_sectors;
/* Found at least one kernel partition. */
found_partition = 1;
/* Read the first part of the kernel partition */
if (part_size < kbuf_sectors)
continue;
if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf))
continue;
/* Verify the kernel header and preamble */
if (VERIFY_KERNEL_SUCCESS != VerifyKernelHeader(
params->header_sign_key_blob,
kbuf,
KBUF_SIZE,
(is_dev ? 1 : 0),
kim,
&kernel_sign_key)) {
continue;
}
#ifdef PRINT_DEBUG_INFO
printf("Kernel header:\n");
printf("header version: %d\n", kim->header_version);
printf("header len: %d\n", kim->header_len);
printf("firmware sign alg: %d\n", kim->firmware_sign_algorithm);
printf("kernel sign alg: %d\n", kim->kernel_sign_algorithm);
printf("kernel key version: %d\n", kim->kernel_key_version);
printf("kernel version: %d\n", kim->kernel_version);
printf("kernel len: %" PRIu64 "\n", kim->kernel_len);
printf("bootloader addr: %" PRIu64 "\n", kim->bootloader_offset);
printf("bootloader size: %" PRIu64 "\n", kim->bootloader_size);
printf("padded header size: %" PRIu64 "\n", kim->padded_header_size);
#endif
/* Check for rollback of key version */
if (kim->kernel_key_version < tpm_kernel_key_version) {
RSAPublicKeyFree(kernel_sign_key);
continue;
}
/* Check for rollback of kernel version */
if (kim->kernel_key_version == tpm_kernel_key_version &&
kim->kernel_version < tpm_kernel_version) {
RSAPublicKeyFree(kernel_sign_key);
continue;
}
/* Check for lowest key version from a valid header. */
if (lowest_kernel_key_version > kim->kernel_key_version) {
lowest_kernel_key_version = kim->kernel_key_version;
lowest_kernel_version = kim->kernel_version;
}
else if (lowest_kernel_key_version == kim->kernel_key_version &&
lowest_kernel_version > kim->kernel_version) {
lowest_kernel_version = kim->kernel_version;
}
/* If we already have a good kernel, no need to read another
* one; we only needed to look at the versions to check for
* rollback. */
if (-1 != good_partition)
continue;
/* Verify kernel padding is a multiple of sector size. */
if (0 != kim->padded_header_size % blba) {
RSAPublicKeyFree(kernel_sign_key);
continue;
}
kernel_start = part_start + (kim->padded_header_size / blba);
kernel_sectors = (kim->kernel_len + blba - 1) / blba;
/* Read the kernel data */
if (0 != BootDeviceReadLBA(kernel_start, kernel_sectors,
params->kernel_buffer)) {
RSAPublicKeyFree(kernel_sign_key);
continue;
}
/* Verify kernel data */
if (0 != VerifyKernelData(kernel_sign_key,
kim->kernel_signature,
params->kernel_buffer,
kim->kernel_len,
kim->kernel_sign_algorithm)) {
RSAPublicKeyFree(kernel_sign_key);
continue;
}
/* Done with the kernel signing key, so can free it now */
RSAPublicKeyFree(kernel_sign_key);
/* If we're still here, the kernel is valid. */
/* Save the first good partition we find; that's the one we'll boot */
if (-1 == good_partition) {
good_partition = gpt.current_kernel;
params->partition_number = gpt.current_kernel;
params->bootloader_address = kim->bootloader_offset;
params->bootloader_size = kim->bootloader_size;
/* If we're in developer or recovery mode, there's no rollback
* protection, so we can stop at the first valid kernel. */
if (!is_normal)
break;
/* Otherwise, we're in normal boot mode, so we do care about
* the key index in the TPM. If the good partition's key
* version is the same as the tpm, then the TPM doesn't need
* updating; we can stop now. Otherwise, we'll check all the
* other headers to see if they contain a newer key. */
if (kim->kernel_key_version == tpm_kernel_key_version &&
kim->kernel_version == tpm_kernel_version)
break;
}
} /* while(GptNextKernelEntry) */
} while(0);
/* Free kernel work and image buffers */
if (kbuf)
Free(kbuf);
if (kim)
Free(kim);
/* Write and free GPT data */
WriteAndFreeGptData(&gpt);
/* Handle finding a good partition */
if (good_partition >= 0) {
if (is_normal) {
/* See if we need to update the TPM, for normal boot mode only. */
if ((lowest_kernel_key_version > tpm_kernel_key_version) ||
(lowest_kernel_key_version == tpm_kernel_key_version &&
lowest_kernel_version > tpm_kernel_version)) {
if (0 != WriteStoredVersions(KERNEL_VERSIONS,
lowest_kernel_key_version,
lowest_kernel_version))
return LOAD_KERNEL_RECOVERY;
}
}
if (!(BOOT_FLAG_RECOVERY & params->boot_flags)) {
/* We can lock the TPM now, since we've decided which kernel we
* like. If we don't find a good kernel, we leave the TPM
* unlocked so we can try again on the next boot device. If no
* kernels are good, we'll reboot to recovery mode, so it's ok to
* leave the TPM unlocked in that case too.
*
* If we're already in recovery mode, we need to leave PP unlocked,
* so don't lock the kernel versions. */
if (0 != LockKernelVersionsByLockingPP())
return LOAD_KERNEL_RECOVERY;
}
/* Success! */
return LOAD_KERNEL_SUCCESS;
}
/* Handle error cases */
if (found_partition)
return LOAD_KERNEL_INVALID;
else
return LOAD_KERNEL_NOT_FOUND;
}