diff options
author | Randall Spangler <rspangler@chromium.org> | 2010-06-10 17:55:02 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2010-06-10 17:55:02 -0700 |
commit | 6a97b3e2a1bee35bf3c00f2fb0faafde4aaab9e2 (patch) | |
tree | 905d6442153a9c9bcaee12a7f37ed2a476e94b83 | |
parent | d55c64537245abca67a66fde5874b7f4a6cdc556 (diff) | |
download | vboot-6a97b3e2a1bee35bf3c00f2fb0faafde4aaab9e2.tar.gz |
Add vbutil_keyblock
Review URL: http://codereview.chromium.org/2748008
-rw-r--r-- | host/include/host_misc.h | 6 | ||||
-rw-r--r-- | host/lib/host_key.c | 41 | ||||
-rw-r--r-- | host/lib/host_misc.c | 19 | ||||
-rw-r--r-- | host/linktest/main.c | 1 | ||||
-rw-r--r-- | tests/Makefile | 3 | ||||
-rwxr-xr-x | tests/run_vbutil_tests.sh | 111 | ||||
-rw-r--r-- | utility/Makefile | 7 | ||||
-rw-r--r-- | utility/vbutil_keyblock.c | 222 |
8 files changed, 378 insertions, 32 deletions
diff --git a/host/include/host_misc.h b/host/include/host_misc.h index 7e66c73c..49afa299 100644 --- a/host/include/host_misc.h +++ b/host/include/host_misc.h @@ -22,4 +22,10 @@ uint8_t* ReadFile(const char* filename, uint64_t* size); +/* Writes [size] bytes of [data] to [filename]. + * + * Returns 0 if success, 1 if error. */ +int WriteFile(const char* filename, const void *data, uint64_t size); + + #endif /* VBOOT_REFERENCE_HOST_MISC_H_ */ diff --git a/host/lib/host_key.c b/host/lib/host_key.c index 388a2d4e..c5f49d31 100644 --- a/host/lib/host_key.c +++ b/host/lib/host_key.c @@ -187,37 +187,20 @@ VbPublicKey* PublicKeyRead(const char* filename) { int PublicKeyWrite(const char* filename, const VbPublicKey* key) { - VbPublicKey* kcopy = NULL; - FILE* f = NULL; - int rv = 1; + VbPublicKey* kcopy; + int rv; - do { - f = fopen(filename, "wb"); - if (!f) { - debug("PublicKeyWrite() unable to open file %s\n", filename); - break; - } - - /* Copy the key, so its data is contiguous with the header */ - kcopy = PublicKeyAlloc(key->key_size, 0, 0); - if (!kcopy || 0 != PublicKeyCopy(kcopy, key)) - break; - - if (1 != fwrite(kcopy, kcopy->key_offset + kcopy->key_size, 1, f)) - break; - - /* Success */ - rv = 0; - - } while(0); - - if (kcopy) + /* Copy the key, so its data is contiguous with the header */ + kcopy = PublicKeyAlloc(key->key_size, 0, 0); + if (!kcopy) + return 1; + if (0 != PublicKeyCopy(kcopy, key)) { Free(kcopy); - if (f) - fclose(f); - - if (0 != rv) - unlink(filename); /* Delete any partial file */ + return 1; + } + /* Write the copy, then free it */ + rv = WriteFile(filename, kcopy, kcopy->key_offset + kcopy->key_size); + Free(kcopy); return rv; } diff --git a/host/lib/host_misc.c b/host/lib/host_misc.c index f24bf40d..2620df7a 100644 --- a/host/lib/host_misc.c +++ b/host/lib/host_misc.c @@ -9,6 +9,7 @@ #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include "host_common.h" @@ -47,3 +48,21 @@ uint8_t* ReadFile(const char* filename, uint64_t* size) { fclose(f); return buf; } + + +int WriteFile(const char* filename, const void *data, uint64_t size) { + FILE *f = fopen(filename, "wb"); + if (!f) { + debug("Unable to open file %s\n", filename); + return 1; + } + + if (1 != fwrite(data, size, 1, f)) { + debug("Unable to write to file %s\n", filename); + fclose(f); + unlink(filename); /* Delete any partial file */ + } + + fclose(f); + return 0; +} diff --git a/host/linktest/main.c b/host/linktest/main.c index 767a9025..f1030ce7 100644 --- a/host/linktest/main.c +++ b/host/linktest/main.c @@ -16,6 +16,7 @@ int main(void) /* host_misc.h */ ReadFile(0, 0); + WriteFile(0, 0, 0); /* host_signature.h */ SignatureInit(0, 0, 0, 0); diff --git a/tests/Makefile b/tests/Makefile index 15799fb2..d52b2822 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -115,6 +115,7 @@ runtests: # Crypto tests ./run_rsa_tests.sh ./sha_tests + ./run_vbutil_tests.sh ./run_vboot_common_tests.sh ./run_image_verification_tests.sh # Splicing tests @@ -128,3 +129,5 @@ runtests: clean: rm -f $(TEST_BINS) + rm -f testkeys/*.vbpubk + rm -f testkeys/*.keyblock diff --git a/tests/run_vbutil_tests.sh b/tests/run_vbutil_tests.sh new file mode 100755 index 00000000..0e8beef8 --- /dev/null +++ b/tests/run_vbutil_tests.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Run verified boot firmware and kernel verification tests. + +# Load common constants and variables. +. "$(dirname "$0")/common.sh" + +return_code=0 + +function test_vbutil_key { + algorithmcounter=0 + for keylen in ${key_lengths[@]} + do + for hashalgo in ${hash_algos[@]} + do + echo -e "For signing key ${COL_YELLOW}RSA-$keylen/$hashalgo${COL_STOP}:" + # Pack the key + ${UTIL_DIR}/vbutil_key --pack \ + --in ${TESTKEY_DIR}/key_rsa${keylen}.keyb \ + --out ${TESTKEY_DIR}/key_alg${algorithmcounter}.vbpubk \ + --version 1 \ + --algorithm $algorithmcounter + if [ $? -ne 0 ] + then + return_code=255 + fi + + # Unpack the key + # TODO: should verify we get the same key back out? + ${UTIL_DIR}/vbutil_key --unpack \ + --in ${TESTKEY_DIR}/key_alg${algorithmcounter}.vbpubk + if [ $? -ne 0 ] + then + return_code=255 + fi + + let algorithmcounter=algorithmcounter+1 + done + done +} + + +function test_vbutil_keyblock { +# Test for various combinations of firmware signing algorithm and +# kernel signing algorithm + signing_algorithmcounter=0 + data_algorithmcounter=0 + for signing_keylen in ${key_lengths[@]} + do + for signing_hashalgo in ${hash_algos[@]} + do + let data_algorithmcounter=0 + for datakeylen in ${key_lengths[@]} + do + for datahashalgo in ${hash_algos[@]} + do + echo -e "For ${COL_YELLOW}signing algorithm \ +RSA-${signing_keylen}/${signing_hashalgo}${COL_STOP} \ +and ${COL_YELLOW}data key algorithm RSA-${datakeylen}/\ +${datahashalgo}${COL_STOP}" + # Remove old file + keyblockfile=${TESTKEY_DIR}/sign${signing_algorithmcounter}_data${data_algorithmcounter}.keyblock + rm -f ${keyblockfile} + + # Pack + ${UTIL_DIR}/vbutil_keyblock --pack ${keyblockfile} \ + --datapubkey \ + tests/testkeys/key_alg${data_algorithmcounter}.vbpubk \ + --signprivate ${TESTKEY_DIR}/key_rsa${signing_keylen}.pem \ + --algorithm $signing_algorithmcounter + if [ $? -ne 0 ] + then + return_code=255 + fi + + # Unpack + ${UTIL_DIR}/vbutil_keyblock --unpack ${keyblockfile} \ + --signpubkey \ + tests/testkeys/key_alg${signing_algorithmcounter}.vbpubk + # TODO: check data key against the packed one? + if [ $? -ne 0 ] + then + return_code=255 + fi + + let data_algorithmcounter=data_algorithmcounter+1 + done + done + let signing_algorithmcounter=signing_algorithmcounter+1 + done + done +} + + +check_test_keys + +echo +echo "Testing vbutil_key..." +test_vbutil_key + +echo +echo "Testing vbutil_keyblock..." +test_vbutil_keyblock + + +exit $return_code + diff --git a/utility/Makefile b/utility/Makefile index e6b1bc0e..666f7731 100644 --- a/utility/Makefile +++ b/utility/Makefile @@ -33,6 +33,7 @@ TARGET_BINS = dumpRSAPublicKey \ load_kernel_test \ signature_digest_utility \ vbutil_key \ + vbutil_keyblock \ verify_data all: $(TARGET_BINS) subdirs @@ -61,15 +62,15 @@ kernel_utility: kernel_utility.cc $(LIBS) $(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \ -o $@ $(LIBS) -lcrypto -load_kernel_test: load_kernel_test.c $(LIBS) - $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto - signature_digest_utility: signature_digest_utility.c $(LIBS) $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto vbutil_key: vbutil_key.c $(LIBS) $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto +vbutil_keyblock: vbutil_keyblock.c $(LIBS) + $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto + verify_data: verify_data.c $(LIBS) $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto diff --git a/utility/vbutil_keyblock.c b/utility/vbutil_keyblock.c new file mode 100644 index 00000000..37754c92 --- /dev/null +++ b/utility/vbutil_keyblock.c @@ -0,0 +1,222 @@ +#include <getopt.h> +#include <inttypes.h> /* For PRIu64 */ +#include <stdio.h> +#include <stdlib.h> + +#include "cryptolib.h" +#include "host_common.h" +#include "vboot_common.h" + + +/* Command line options */ +enum { + OPT_MODE_PACK = 1000, + OPT_MODE_UNPACK, + OPT_DATAPUBKEY, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_ALGORITHM, + OPT_FLAGS, +}; + +static struct option long_opts[] = { + {"pack", 1, 0, OPT_MODE_PACK }, + {"unpack", 1, 0, OPT_MODE_UNPACK }, + {"datapubkey", 1, 0, OPT_DATAPUBKEY }, + {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, + {"signprivate", 1, 0, OPT_SIGNPRIVATE }, + {"algorithm", 1, 0, OPT_ALGORITHM }, + {"flags", 1, 0, OPT_FLAGS }, + {NULL, 0, 0, 0} +}; + + +/* Print help and return error */ +static int PrintHelp(void) { + int i; + + puts("vbutil_keyblock - Verified boot key block utility\n" + "\n" + "Usage: vbutil_keyblock <--pack|--unpack> <file> [OPTIONS]\n" + "\n" + "For '--pack <file>', required OPTIONS are:\n" + " --datapubkey <file> Data public key in .vbpubk format\n" + " --signprivate <file> Signing private key in .pem format\n" + " --algorithm <algoid> Signing algorithm for key, one of:"); + + for (i = 0; i < kNumAlgorithms; i++) + printf(" %d (%s)\n", i, algo_strings[i]); + + puts("\n" + "Optional OPTIONS are:\n" + " --flags <number> Flags\n" + "\n" + "For '--unpack <file>', required OPTIONS are:\n" + " --signpubkey <file> Signing public key in .vbpubk format\n" + "Optional OPTIONS are:\n" + " --datapubkey <file> Data public key output file\n" + ""); + return 1; +} + + +/* Pack a .keyblock */ +static int Pack(const char* outfile, const char* datapubkey, + const char* signprivate, uint64_t algorithm, + uint64_t flags) { + VbPublicKey* data_key; + VbPrivateKey* signing_key; + VbKeyBlockHeader* block; + + if (!outfile) { + fprintf(stderr, "vbutil_keyblock: Must specify output filename\n"); + return 1; + } + if (!datapubkey || !signprivate) { + fprintf(stderr, "vbutil_keyblock: Must specify all keys\n"); + return 1; + } + if (algorithm >= kNumAlgorithms) { + fprintf(stderr, "Invalid algorithm\n"); + return 1; + } + + data_key = PublicKeyRead(datapubkey); + if (!data_key) { + fprintf(stderr, "vbutil_keyblock: Error reading data key.\n"); + return 1; + } + signing_key = PrivateKeyRead(signprivate, algorithm); + if (!signing_key) { + fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); + return 1; + } + + block = CreateKeyBlock(data_key, signing_key, flags); + Free(data_key); + Free(signing_key); + + if (0 != WriteFile(outfile, block, block->key_block_size)) { + fprintf(stderr, "vbutil_keyblock: Error writing key block.\n"); + return 1; + } + Free(block); + return 0; +} + + +static int Unpack(const char* infile, const char* datapubkey, + const char* signpubkey) { + VbPublicKey* data_key; + VbPublicKey* sign_key; + VbKeyBlockHeader* block; + uint64_t block_size; + + if (!infile || !signpubkey) { + fprintf(stderr, "vbutil_keyblock: Must specify filename and signpubkey\n"); + return 1; + } + + sign_key = PublicKeyRead(signpubkey); + if (!sign_key) { + fprintf(stderr, "vbutil_keyblock: Error reading signpubkey.\n"); + return 1; + } + + block = (VbKeyBlockHeader*)ReadFile(infile, &block_size); + if (!block) { + fprintf(stderr, "vbutil_keyblock: Error reading key block.\n"); + return 1; + } + if (0 != VerifyKeyBlock(block, block_size, sign_key)) { + fprintf(stderr, "vbutil_keyblock: Error verifying key block.\n"); + return 1; + } + Free(sign_key); + + printf("Key block file: %s\n", infile); + printf("Flags: %" PRIu64 "\n", block->key_block_flags); + + data_key = &block->data_key; + printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, + (data_key->algorithm < kNumAlgorithms ? + algo_strings[data_key->algorithm] : "(invalid)")); + printf("Data key version: %" PRIu64 "\n", data_key->key_version); + + /* TODO: write key data, if output file specified */ + + Free(block); + return 0; +} + + +int main(int argc, char* argv[]) { + + char* filename = NULL; + char* datapubkey = NULL; + char* signpubkey = NULL; + char* signprivate = NULL; + uint64_t flags = 0; + uint64_t algorithm = kNumAlgorithms; + int mode = 0; + int parse_error = 0; + char* e; + int i; + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + case '?': + /* Unhandled option */ + printf("Unknown option\n"); + parse_error = 1; + break; + + case OPT_MODE_PACK: + case OPT_MODE_UNPACK: + mode = i; + filename = optarg; + break; + + case OPT_DATAPUBKEY: + datapubkey = optarg; + break; + + case OPT_SIGNPUBKEY: + signpubkey = optarg; + break; + + case OPT_SIGNPRIVATE: + signprivate = optarg; + break; + + case OPT_ALGORITHM: + algorithm = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + printf("Invalid --algorithm\n"); + parse_error = 1; + } + break; + + case OPT_FLAGS: + flags = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + printf("Invalid --flags\n"); + parse_error = 1; + } + break; + } + } + + if (parse_error) + return PrintHelp(); + + switch(mode) { + case OPT_MODE_PACK: + return Pack(filename, datapubkey, signprivate, algorithm, flags); + case OPT_MODE_UNPACK: + return Unpack(filename, datapubkey, signpubkey); + default: + printf("Must specify a mode.\n"); + return PrintHelp(); + } +} |