Add vbutil_keyblock

Review URL: http://codereview.chromium.org/2748008
This commit is contained in:
Randall Spangler
2010-06-10 17:55:02 -07:00
parent d55c645372
commit 6a97b3e2a1
8 changed files with 378 additions and 32 deletions

View File

@@ -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_ */

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

111
tests/run_vbutil_tests.sh Executable file
View File

@@ -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

View File

@@ -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

222
utility/vbutil_keyblock.c Normal file
View File

@@ -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();
}
}