summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2010-06-10 17:55:02 -0700
committerRandall Spangler <rspangler@chromium.org>2010-06-10 17:55:02 -0700
commit6a97b3e2a1bee35bf3c00f2fb0faafde4aaab9e2 (patch)
tree905d6442153a9c9bcaee12a7f37ed2a476e94b83
parentd55c64537245abca67a66fde5874b7f4a6cdc556 (diff)
downloadvboot-6a97b3e2a1bee35bf3c00f2fb0faafde4aaab9e2.tar.gz
Add vbutil_keyblock
Review URL: http://codereview.chromium.org/2748008
-rw-r--r--host/include/host_misc.h6
-rw-r--r--host/lib/host_key.c41
-rw-r--r--host/lib/host_misc.c19
-rw-r--r--host/linktest/main.c1
-rw-r--r--tests/Makefile3
-rwxr-xr-xtests/run_vbutil_tests.sh111
-rw-r--r--utility/Makefile7
-rw-r--r--utility/vbutil_keyblock.c222
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();
+ }
+}