summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-07-23 18:55:29 -0700
committerGerrit <chrome-bot@google.com>2012-07-24 17:02:23 -0700
commit262cef37e66c1a2f9a38cd8f2b35a7ba1ea50aa1 (patch)
tree4893d1a6097b92e4cd3cc98436b2b8bb6d6b214e
parent029ae65756993979c22035e3706e2b04049ef9fe (diff)
downloadvboot-262cef37e66c1a2f9a38cd8f2b35a7ba1ea50aa1.tar.gz
mount-encrypted: improve ancient Cr48 install detection
If a Cr48 was upgraded from pre-R12, it will lack an NVRAM lockbox area with no way to create one (TPM password has been thrown away already). Detect this case and allow fallback to the other system key methods. If it is a Cr48 running a modern OOBE, treat it like any other device and require a modern NVRAM lockbox area. BUG=chromium-os:32766 TEST=mario build, verified OOBE doesn't repeat, simulated pre-R12 uses UUID. Change-Id: I2acf7ad8c5d16b1f314ba16c673fa3979a40f3de Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/28231 Reviewed-by: Elly Jones <ellyjones@chromium.org>
-rw-r--r--utility/mount-encrypted.c120
1 files changed, 82 insertions, 38 deletions
diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c
index e67f7df3..2c0fa8b2 100644
--- a/utility/mount-encrypted.c
+++ b/utility/mount-encrypted.c
@@ -249,14 +249,34 @@ _read_nvram(uint8_t *buffer, size_t len, uint32_t index, uint32_t size)
}
/*
- * Cases:
- * - no NVRAM area at all (OOBE)
- * - defined NVRAM area, but TPM not Owned
- * - defined NVRAM area, but not Finalized
- * - legacy NVRAM area (migration needed)
- * - modern NVRAM area (\o/)
+ * TPM ownership cases:
+ * - unowned (OOBE):
+ * - expect modern lockbox (no migration allowed).
+ * - owned: depends on NVRAM area (below).
+ *
+ * NVRAM area cases:
+ * - no NVRAM area at all:
+ * - if cr48, assume this is going to always be missing the lockbox:
+ * - expect no lockbox (migration allowed).
+ * - otherwise, assume an interrupted install
+ * - expect modern lockbox (no migration allowed).
+ * - defined NVRAM area, but not written to ("Finalized"); interrupted OOBE:
+ * - if legacy size, allow migration.
+ * - if not, disallow migration.
+ * - written ("Finalized") NVRAM area:
+ * - if legacy size, allow migration.
+ * - if not, disallow migration.
+ *
+ * When returning 1: (NVRAM area found and used)
+ * - *digest populated with NVRAM area entropy.
+ * - *old_lockbox indicates which lockbox NVRAM area type was used.
+ * - *static_key will always be 0.
+ * When returning 0: (NVRAM missing or error)
+ * - *digest untouched.
+ * - *old_lockbox indicates future expected lockbox size (after Finalize).
+ * - *static_key=1 only if TPM owned, lockbox missing, and device is cr48.
*/
-static int get_nvram_key(uint8_t *digest, int *old_lockbox)
+static int get_nvram_key(uint8_t *digest, int *old_lockbox, int *static_key)
{
uint8_t owned = 0;
uint8_t value[kLockboxSizeV2], bytes_anded, bytes_ored;
@@ -264,6 +284,21 @@ static int get_nvram_key(uint8_t *digest, int *old_lockbox)
uint8_t *rand_bytes;
uint32_t rand_size;
+ /* Expect to use a new lockbox by default, and require NVRAM key. */
+ *old_lockbox = 0;
+ *static_key = 0;
+
+ /* Ignore unowned TPM's NVRAM area. */
+ result = tpm_owned(&owned);
+ if (result != TPM_SUCCESS) {
+ INFO("Could not read TPM Permanent Flags.");
+ return 0;
+ }
+ if (!owned) {
+ INFO("TPM not Owned, ignoring NVRAM area.");
+ return 0;
+ }
+
/* Reading the NVRAM takes 40ms. Instead of querying the NVRAM area
* for its size (which takes time), just read the expected size. If
* it fails, then fall back to the older size. This means cleared
@@ -272,7 +307,6 @@ static int get_nvram_key(uint8_t *digest, int *old_lockbox)
* which is the minimum possible time (instead of 40ms + time to
* query NVRAM size).
*/
- *old_lockbox = 0;
size = kLockboxSizeV2;
result = _read_nvram(value, sizeof(value), kLockboxIndex, size);
if (result != TPM_SUCCESS) {
@@ -281,6 +315,21 @@ static int get_nvram_key(uint8_t *digest, int *old_lockbox)
if (result != TPM_SUCCESS) {
/* No NVRAM area at all. */
INFO("No NVRAM area defined.");
+
+ /* TPM is owned, without an NVRAM area. If this is a
+ * Cr48, mark this as using an old NVRAM area to
+ * allow migration, and mark this as an ancient
+ * install that did not even know to create a lockbox
+ * at all. If this is actually a Cr48 that has had
+ * its OOBE interrupted at the perfect moment, then
+ * the user is going to lose their settings. This
+ * should be extremely rare.
+ */
+ if (is_cr48()) {
+ *static_key = 1;
+ *old_lockbox = 1;
+ }
+
return 0;
}
/* Legacy NVRAM area. */
@@ -292,21 +341,6 @@ static int get_nvram_key(uint8_t *digest, int *old_lockbox)
debug_dump_hex("nvram", value, size);
- /* Ignore defined but unowned NVRAM area. */
- /* TODO(keescook): remove this check (it adds 40ms) once the
- * NVRAM area is bound to owner so that it will be wiped out
- * across device mode changes.
- */
- result = tpm_owned(&owned);
- if (result != TPM_SUCCESS) {
- INFO("Could not read TPM Permanent Flags.");
- return 0;
- }
- if (!owned) {
- INFO("TPM not Owned, ignoring NVRAM area.");
- return 0;
- }
-
/* Ignore defined but unwritten NVRAM area. */
bytes_ored = 0x0;
bytes_anded = 0xff;
@@ -344,9 +378,9 @@ static int get_nvram_key(uint8_t *digest, int *old_lockbox)
}
/* Find the system key used for decrypting the stored encryption key.
- * ChromeOS devices are required to use the NVRAM area (excepting CR-48s),
- * all the rest will fallback through various places (kernel command line,
- * BIOS UUID, and finally a static value) for a system key.
+ * ChromeOS devices are required to use the NVRAM area, all the rest will
+ * fallback through various places (kernel command line, BIOS UUID, and
+ * finally a static value) for a system key.
*/
static int find_system_key(int mode, uint8_t *digest, int *migration_allowed)
{
@@ -368,17 +402,25 @@ static int find_system_key(int mode, uint8_t *digest, int *migration_allowed)
* NVRAM.
*/
if (has_chromefw()) {
- int rc;
- rc = get_nvram_key(digest, migration_allowed);
+ int rc, static_key = 0;
+ rc = get_nvram_key(digest, migration_allowed, &static_key);
- /* Since the CR-48 did not ship with a lockbox area, they
- * are allowed to fall back to non-NVRAM system keys.
- */
- if (rc || !is_cr48()) {
- INFO("Using NVRAM as system key; %s.",
- rc ? "already populated"
- : "needs population");
+ if (rc) {
+ /* Use populated NVRAM area. */
+ INFO("Using NVRAM as system key; already populated%s.",
+ migration_allowed ? " (legacy)" : "");
return rc;
+ } else {
+ if (!static_key) {
+ INFO("Using NVRAM as system key; area needed.");
+ return rc;
+ }
+ /* If a static key is allowed, it means the TPM is
+ * already owned, is missing the NVRAM area, and is
+ * running on a Cr48. In this special case, fall
+ * through to the other key methods below, since
+ * the NVRAM area will never be populated.
+ */
}
}
@@ -1027,6 +1069,7 @@ static int report_info(void)
uint8_t owned = 0;
struct bind_mount *mnt;
int old_lockbox = -1;
+ int static_key = -1;
printf("TPM: %s\n", has_tpm ? "yes" : "no");
if (has_tpm) {
@@ -1037,11 +1080,12 @@ static int report_info(void)
printf("CR48: %s\n", is_cr48() ? "yes" : "no");
if (has_chromefw()) {
int rc;
- rc = get_nvram_key(system_key, &old_lockbox);
+ rc = get_nvram_key(system_key, &old_lockbox, &static_key);
if (!rc)
- printf("NVRAM: missing\n");
+ printf("NVRAM: missing%s.\n",
+ static_key ? " (static key allowed)" : "");
else {
- printf("NVRAM: %s, %s\n",
+ printf("NVRAM: %s, %s.\n",
old_lockbox ? "legacy" : "modern",
rc ? "available" : "ignored");
}