summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2015-07-17 09:44:29 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-21 21:11:28 +0000
commit14f122601f45d95a0162be8ad1456d9824cb80f9 (patch)
tree30463f3d790c81a9e8cbd9317485adea3f0294ee
parenta0206634baea037a4958986d72e66231eef8769d (diff)
downloadvboot-14f122601f45d95a0162be8ad1456d9824cb80f9.tar.gz
futility: Compute / verify root key hash
Ryu will store a hash of the GBB root key in a struct inside its boot block. Add a vb2_ryu_root_key_hash struct for that. If 'futility gbb_utility' is used to set the root key, also look for a root key hash struct and fill it in. No error if not found, because this needs to work on other platforms where the struct is not present. This way, we don't need to change the signing scripts. Added a --roothash option which can be used to check if the root key hash is found, and if so, whether it's empty, valid, or invalid. BUG=chromium:511405 BRANCH=ryu TEST=manual Take any existing image.bin. cp image.bin image.orig gbb_utility --roothash image.bin - ryu root hash not found Extract the root key gbb_utility -k rootkey.bin image.bin - exported root_key to file: rootkey.bin Now, append a blank ryu root hash struct to it echo '0000000: 5274 4b79 4861 7368 0100 0000 3000 0000' | xxd -r >> image.bin echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin Nothing is set yet gbb_utility --roothash image.bin - ryu root hash is unset Setting the root key also sets the root hash gbb_utility -s -k rootkey.bin image.bin - import root_key from rootkey.bin: success - calculate ryu root hash: success successfully saved new image to: image.bin See, it verifies gbb_utility --roothash image.bin - ryu root hash verified Now, append a bad ryu root hash struct to it cp image.orig image.bin echo '0000000: 5274 4b79 4861 7368 0100 0000 3000 0000' | xxd -r >> image.bin echo '0000000: 0001 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin echo '0000000: 0000 0000 0000 0000 0000 0000 0000 0000' | xxd -r >> image.bin See, it fails gbb_utility --roothash image.bin - ryu root hash does not verify Make sure the library doesn't contain the magic string strings `which futility` | grep RtKyHash (should be no output) Change-Id: Ib46f93cac0f2b532bada4b187ae48efcf4926702 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/286237 Reviewed-by: Furquan Shaikh <furquan@chromium.org>
-rw-r--r--Makefile3
-rw-r--r--firmware/2lib/include/2struct.h36
-rw-r--r--futility/cmd_gbb_utility.c16
-rw-r--r--futility/futility.h8
-rw-r--r--futility/ryu_root_header.c165
5 files changed, 226 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 1273d80c..225097fc 100644
--- a/Makefile
+++ b/Makefile
@@ -615,7 +615,8 @@ FUTIL_STATIC_SRCS = \
futility/futility.c \
futility/cmd_dump_fmap.c \
futility/cmd_gbb_utility.c \
- futility/misc.c
+ futility/misc.c \
+ futility/ryu_root_header.c
FUTIL_SRCS = \
${FUTIL_STATIC_SRCS} \
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index ca05dfca..2d43218c 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -305,4 +305,40 @@ struct vb2_gbb_header {
/* The GBB is used outside of vboot_reference, so this size is important. */
#define EXPECTED_VB2_GBB_HEADER_SIZE 128
+/*
+ * Root key hash for Ryu devices only. Contains the hash of the root key.
+ * This will be embedded somewhere inside the RO part of the firmware, so that
+ * it can verify the GBB contains only the official root key.
+ */
+
+#define RYU_ROOT_KEY_HASH_MAGIC "RtKyHash"
+#define RYU_ROOT_KEY_HASH_MAGIC_INVCASE "rTkYhASH"
+#define RYU_ROOT_KEY_HASH_MAGIC_SIZE 8
+
+#define RYU_ROOT_KEY_HASH_VERSION_MAJOR 1
+#define RYU_ROOT_KEY_HASH_VERSION_MINOR 0
+
+struct vb2_ryu_root_key_hash {
+ /* Magic number (RYU_ROOT_KEY_HASH_MAGIC) */
+ uint8_t magic[RYU_ROOT_KEY_HASH_MAGIC_SIZE];
+
+ /* Version of this struct */
+ uint16_t header_version_major;
+ uint16_t header_version_minor;
+
+ /*
+ * Length of this struct, in bytes, including any variable length data
+ * which follows (there is none, yet).
+ */
+ uint32_t struct_size;
+
+ /*
+ * SHA-256 hash digest of the entire root key section from the GBB. If
+ * all 0 bytes, all root keys will be treated as if matching.
+ */
+ uint8_t root_key_hash_digest[32];
+};
+
+#define EXPECTED_VB2_RYU_ROOT_KEY_HASH_SIZE 48
+
#endif /* VBOOT_REFERENCE_VBOOT_2STRUCT_H_ */
diff --git a/futility/cmd_gbb_utility.c b/futility/cmd_gbb_utility.c
index df0a51db..fe21762e 100644
--- a/futility/cmd_gbb_utility.c
+++ b/futility/cmd_gbb_utility.c
@@ -30,6 +30,7 @@ static void print_help(int argc, char *argv[])
" --hwid \tReport hardware id (default).\n"
" --flags \tReport header flags.\n"
" --digest \tReport digest of hwid (>= v1.2)\n"
+ " --roothash \tCheck ryu root key hash\n"
" -k, --rootkey=FILE \tFile name to export Root Key.\n"
" -b, --bmpfv=FILE \tFile name to export Bitmap FV.\n"
" -r --recoverykey=FILE\tFile name to export Recovery Key.\n"
@@ -61,6 +62,7 @@ enum {
OPT_FLAGS,
OPT_DIGEST,
OPT_HELP,
+ OPT_ROOTHASH,
};
/* Command line options */
@@ -77,6 +79,7 @@ static struct option long_opts[] = {
{"flags", 0, NULL, OPT_FLAGS},
{"digest", 0, NULL, OPT_DIGEST},
{"help", 0, NULL, OPT_HELP},
+ {"roothash", 0, NULL, OPT_ROOTHASH},
{NULL, 0, NULL, 0},
};
@@ -363,6 +366,7 @@ static int do_gbb_utility(int argc, char *argv[])
int sel_hwid = 0;
int sel_digest = 0;
int sel_flags = 0;
+ int sel_roothash = 0;
uint8_t *inbuf = NULL;
off_t filesize;
uint8_t *outbuf = NULL;
@@ -412,6 +416,9 @@ static int do_gbb_utility(int argc, char *argv[])
case OPT_DIGEST:
sel_digest = 1;
break;
+ case OPT_ROOTHASH:
+ sel_roothash = 1;
+ break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
@@ -490,6 +497,9 @@ static int do_gbb_utility(int argc, char *argv[])
if (sel_digest)
print_hwid_digest(gbb, "digest: ", "\n");
+ if (sel_roothash)
+ verify_ryu_root_header(inbuf, filesize, gbb);
+
if (sel_flags)
printf("flags: 0x%08x\n", gbb->flags);
if (opt_rootkey)
@@ -591,10 +601,14 @@ static int do_gbb_utility(int argc, char *argv[])
}
}
- if (opt_rootkey)
+ if (opt_rootkey) {
read_from_file("root_key", opt_rootkey,
gbb_base + gbb->rootkey_offset,
gbb->rootkey_size);
+
+ if (fill_ryu_root_header(outbuf, filesize, gbb))
+ errorcnt++;
+ }
if (opt_bmpfv)
read_from_file("bmp_fv", opt_bmpfv,
gbb_base + gbb->bmpfv_offset,
diff --git a/futility/futility.h b/futility/futility.h
index e0754d86..c8150035 100644
--- a/futility/futility.h
+++ b/futility/futility.h
@@ -116,6 +116,14 @@ int print_hwid_digest(GoogleBinaryBlockHeader *gbb,
/* Copies a file or dies with an error message */
void futil_copy_file_or_die(const char *infile, const char *outfile);
+/* Update ryu root key header in the image */
+int fill_ryu_root_header(uint8_t *ptr, size_t size,
+ const GoogleBinaryBlockHeader *gbb);
+
+/* Verify ryu root key header */
+int verify_ryu_root_header(uint8_t *ptr, size_t size,
+ const GoogleBinaryBlockHeader *gbb);
+
/* Possible file operation errors */
enum futil_file_err {
FILE_ERR_NONE,
diff --git a/futility/ryu_root_header.c b/futility/ryu_root_header.c
new file mode 100644
index 00000000..a88f34c2
--- /dev/null
+++ b/futility/ryu_root_header.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 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.
+ */
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "2struct.h"
+#include "cryptolib.h"
+#include "futility.h"
+#include "gbb_header.h"
+
+#define SEARCH_STRIDE 4
+
+/**
+ * Check if the pointer contains the magic string. We need to use a
+ * case-swapped version, so that the actual magic string doesn't appear in the
+ * code, to avoid falsely finding it when searching for the struct.
+ */
+static int is_magic(const void *ptr)
+{
+ const char magic_inv[RYU_ROOT_KEY_HASH_MAGIC_SIZE] =
+ RYU_ROOT_KEY_HASH_MAGIC_INVCASE;
+ const char *magic = ptr;
+ int i;
+
+ for (i = 0; i < RYU_ROOT_KEY_HASH_MAGIC_SIZE; i++) {
+ if (magic[i] != (magic_inv[i] ^ 0x20))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int valid_ryu_root_header(struct vb2_ryu_root_key_hash *hash,
+ size_t size)
+{
+ if (!is_magic(hash->magic))
+ return 0; /* Wrong magic */
+
+ if (hash->header_version_major != RYU_ROOT_KEY_HASH_VERSION_MAJOR)
+ return 0; /* Version we can't parse */
+
+ if (hash->struct_size < EXPECTED_VB2_RYU_ROOT_KEY_HASH_SIZE)
+ return 0; /* Header too small */
+
+ if (hash->struct_size > size)
+ return 0; /* Claimed size doesn't fit in buffer */
+
+ return 1;
+}
+
+/**
+ * Find the root key hash struct and return it or NULL if error.
+ */
+static struct vb2_ryu_root_key_hash *find_ryu_root_header(uint8_t *ptr,
+ size_t size)
+{
+ size_t i;
+ struct vb2_ryu_root_key_hash *tmp, *hash = NULL;
+ int count = 0;
+
+ /* Look for the ryu root key hash header */
+ for (i = 0; i <= size - SEARCH_STRIDE; i += SEARCH_STRIDE) {
+ if (!is_magic(ptr + i))
+ continue;
+
+ /* Found something. See if it's any good. */
+ tmp = (struct vb2_ryu_root_key_hash *) (ptr + i);
+ if (valid_ryu_root_header(tmp, size - i))
+ if (!count++)
+ hash = tmp;
+ }
+
+ switch (count) {
+ case 0:
+ return NULL;
+ case 1:
+ return hash;
+ default:
+ fprintf(stderr,
+ "WARNING: multiple ryu root hash headers found\n");
+ /* But hey, it's only a warning. Use the first one. */
+ return hash;
+ }
+}
+
+static void calculate_root_key_hash(uint8_t *digest, size_t digest_size,
+ const GoogleBinaryBlockHeader *gbb)
+{
+ const uint8_t *gbb_base = (const uint8_t *)gbb;
+
+ internal_SHA256(gbb_base + gbb->rootkey_offset,
+ gbb->rootkey_size,
+ digest);
+}
+
+int fill_ryu_root_header(uint8_t *ptr, size_t size,
+ const GoogleBinaryBlockHeader *gbb)
+{
+ struct vb2_ryu_root_key_hash *hash;
+
+ /*
+ * Find the ryu root header. If not found, nothing we can do, but
+ * that's ok because most images don't have the header.
+ */
+ hash = find_ryu_root_header(ptr, size);
+ if (!hash)
+ return 0;
+
+ /* Update the hash stored in the header based on the root key */
+ calculate_root_key_hash(hash->root_key_hash_digest,
+ sizeof(hash->root_key_hash_digest),
+ gbb);
+
+ printf(" - calculate ryu root hash: success\n");
+ return 0;
+}
+
+int verify_ryu_root_header(uint8_t *ptr, size_t size,
+ const GoogleBinaryBlockHeader *gbb)
+{
+ uint8_t digest[SHA256_DIGEST_SIZE] = {0};
+
+ struct vb2_ryu_root_key_hash *hash;
+
+ /*
+ * Find the ryu root header. If not found, nothing we can do, but
+ * that's ok because most images don't have the header.
+ */
+ hash = find_ryu_root_header(ptr, size);
+ if (!hash) {
+ printf(" - ryu root hash not found\n");
+ return 0;
+ }
+
+ /* Check for all 0's, which means hash hasn't been set */
+ if (0 == memcmp(digest, hash->root_key_hash_digest,
+ SHA256_DIGEST_SIZE)) {
+ printf(" - ryu root hash is unset\n");
+ return 0;
+ }
+
+ /* Update the hash stored in the header based on the root key */
+ calculate_root_key_hash(digest, sizeof(digest), gbb);
+
+ if (0 == memcmp(digest, hash->root_key_hash_digest,
+ SHA256_DIGEST_SIZE)) {
+ printf(" - ryu root hash verified\n");
+ return 0;
+ } else {
+ printf(" - ryu root hash does not verify\n");
+ return -1;
+ }
+}