summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav Shah <gauravsh@chromium.org>2010-03-24 13:48:55 -0700
committerGaurav Shah <gauravsh@chromium.org>2010-03-24 13:48:55 -0700
commitce0cc30e55987f3faac9f9bacdf5d66c86ede08e (patch)
treeb0b5995e83d17b3328b062f37a1dd7f55376a336
parent1e5669376388c46e924d43d1bfe6406347493a86 (diff)
downloadvboot-ce0cc30e55987f3faac9f9bacdf5d66c86ede08e.tar.gz
VBoot Reference: Add version checking to for preventing rollbacks.
This CL adds a new function VerifyFirmwareDriver_f() means to be a part of the RO firmware which determine which copy of the firmware to boot from. It is meant to ensure that a particular firmware is only booted if 1) it verifies successfully, 2) its version is newer or equal to current stored version. In addition, the driver function also updates the stored version if needed. Currently I am using the TLCL API with stub calls, (in fact, most of the TPM interaction is done in rollback_index.c which implements the actual version query/update API) used by the firmware. Review URL: http://codereview.chromium.org/1241002
-rw-r--r--common/Makefile4
-rw-r--r--common/tlcl_stub.c28
-rw-r--r--include/firmware_image.h29
-rw-r--r--include/rollback_index.h36
-rw-r--r--include/utility.h8
-rw-r--r--tests/Makefile51
-rw-r--r--tests/firmware_image_tests.c68
-rw-r--r--tests/firmware_rollback_tests.c145
-rw-r--r--tests/rollback_index_mock.c61
-rw-r--r--tests/test_common.c30
-rw-r--r--tests/test_common.h13
-rw-r--r--utils/Makefile18
-rw-r--r--utils/firmware_image.c169
-rw-r--r--utils/rollback_index.c148
14 files changed, 726 insertions, 82 deletions
diff --git a/common/Makefile b/common/Makefile
index fc73ec23..b9b4a512 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -2,13 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-SRCS = utility_stub.c
+SRCS = utility_stub.c tlcl_stub.c
OBJS = $(SRCS:.c=.o)
all: libcommon.a
libcommon.a: $(OBJS)
- ar rs $@ $<
+ ar rs $@ $^
.c.o: $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
diff --git a/common/tlcl_stub.c b/common/tlcl_stub.c
new file mode 100644
index 00000000..0b4625b3
--- /dev/null
+++ b/common/tlcl_stub.c
@@ -0,0 +1,28 @@
+/* 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.
+ *
+ * Stub implementations of TPM Lite Library.
+ */
+
+#include <tss/tcs.h>
+
+void TlclLibinit(void) { return; }
+void TlclStartup(void) { return; }
+void TlclSelftestfull(void) { return; }
+void TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) { return; }
+uint32_t TlclWrite(uint32_t index, uint8_t *data, uint32_t length) {
+ return TPM_SUCCESS;
+}
+uint32_t TlclRead(uint32_t index, uint8_t *data, uint32_t length) {
+ return TPM_SUCCESS;
+}
+void TlclWriteLock(uint32_t index) { return; }
+void TlclReadLock(uint32_t index) { return; }
+void TlclAssertPhysicalPresence(void) { return; }
+void TlclSetNvLocked(void) { return; }
+int TlclIsOwned(void) { return 0; }
+void TlclForceClear(void) { return; }
+void TlclPhysicalEnable(void) { return; }
+int TlclPhysicalSetDeactivated(uint8_t flag) { return TPM_SUCCESS; }
+int TlclGetFlags(uint8_t* disable, uint8_t* deactivated) { return TPM_SUCCESS; }
diff --git a/include/firmware_image.h b/include/firmware_image.h
index 3f7bc801..611d31d7 100644
--- a/include/firmware_image.h
+++ b/include/firmware_image.h
@@ -27,8 +27,8 @@ typedef struct FirmwareImage {
uint16_t header_len; /* Length of the header. */
uint16_t firmware_sign_algorithm; /* Signature algorithm used by the signing
* key. */
- uint8_t* firmware_sign_key; /* Pre-processed public half of signing key. */
uint16_t firmware_key_version; /* Key Version# for preventing rollbacks. */
+ uint8_t* firmware_sign_key; /* Pre-processed public half of signing key. */
uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 hash of the header.*/
uint8_t firmware_key_signature[RSA8192NUMBYTES]; /* Signature of the header
@@ -113,7 +113,10 @@ void PrintFirmwareImage(const FirmwareImage* image);
#define VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED 4
#define VERIFY_FIRMWARE_SIGNATURE_FAILED 5
#define VERIFY_FIRMWARE_WRONG_MAGIC 6
-#define VERIFY_FIRMWARE_MAX 7 /* Generic catch-all. */
+#define VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM 7
+#define VERIFY_FIRMWARE_KEY_ROLLBACK 8
+#define VERIFY_FIRMWARE_VERSION_ROLLBACK 9
+#define VERIFY_FIRMWARE_MAX 10 /* Total number of error codes. */
extern char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX];
@@ -198,4 +201,26 @@ int AddFirmwareKeySignature(FirmwareImage* image, const char* root_key_file);
*/
int AddFirmwareSignature(FirmwareImage* image, const char* signing_key_file);
+/* Returns the logical version of a firmware blob which is calculated as
+ * (firmware_key_version << 16 | firmware_version). */
+uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob);
+
+#define BOOT_FIRMWARE_A_CONTINUE 1
+#define BOOT_FIRMWARE_B_CONTINUE 2
+#define BOOT_FIRMWARE_RECOVERY_CONTINUE 3
+
+/* This function is the driver used by the RO firmware to
+ * determine which copy of the firmware to boot from. It performs
+ * the requisite rollback index checking, including updating them,
+ * if required.
+ *
+ * Returns the code path to follow. It is one of:
+ * BOOT_FIRMWARE_A_CONTINUE Boot from Firmware A
+ * BOOT_FIRMWARE_B_CONTINUE Boot from Firmware B
+ * BOOT_FIRMWARE_RECOVERY_CONTINUE Jump to recovery mode
+ */
+int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
+ uint8_t* firmwareA,
+ uint8_t* firmwareB);
+
#endif /* VBOOT_REFERENCE_FIRMWARE_IMAGE_H_ */
diff --git a/include/rollback_index.h b/include/rollback_index.h
new file mode 100644
index 00000000..d4e47ac8
--- /dev/null
+++ b/include/rollback_index.h
@@ -0,0 +1,36 @@
+/* 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.
+ *
+ * Functions for querying, manipulating and locking rollback indices
+ * stored in the TPM NVRAM.
+ */
+
+#ifndef VBOOT_REFERENCE_ROLLBACK_INDEX_H_
+#define VBOOT_REFERENCE_ROLLBACK_INDEX_H_
+
+#include <stdint.h>
+
+extern uint16_t g_firmware_key_version;
+extern uint16_t g_firmware_version;
+extern uint16_t g_kernel_key_version;
+extern uint16_t g_kernel_version;
+
+/* Rollback version types. */
+#define FIRMWARE_KEY_VERSION 0
+#define FIRMWARE_VERSION 1
+#define KERNEL_KEY_VERSION 2
+#define KERNEL_VERSION 3
+
+/* TPM NVRAM location indices. */
+#define FIRMWARE_KEY_VERSION_NV_INDEX 0x1001
+#define FIRMWARE_VERSION_NV_INDEX 0x1002
+#define KERNEL_KEY_VERSION_NV_INDEX 0x1003
+#define KERNEL_VERSION_NV_INDEX 0x1004
+
+void SetupTPM(void);
+uint16_t GetStoredVersion(int type);
+int WriteStoredVersion(int type, uint16_t version);
+void LockStoredVersion(int type);
+
+#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */
diff --git a/include/utility.h b/include/utility.h
index 5dc6d283..79713477 100644
--- a/include/utility.h
+++ b/include/utility.h
@@ -13,6 +13,14 @@
#include <inttypes.h>
#include <string.h>
+/* Combine [msw] and [lsw] uint16s to a uint32_t with its [msw] and
+ * [lsw] forming the most and least signficant 16-bit words.
+ */
+#define CombineUint16Pair(msw,lsw) (((msw) << 16) | \
+ (((lsw)) & 0xFFFF))
+/* Return the minimum of (a) or (b). */
+#define Min(a, b) (((a) < (b)) ? (a) : (b))
+
/* Allocate [size] bytes and return a pointer to the allocated memory. Abort
* on error.
*/
diff --git a/tests/Makefile b/tests/Makefile
index 6617a415..931e3f5d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -7,11 +7,13 @@ CFLAGS ?= -Wall -DNDEBUG -O3 -Werror
INCLUDES ?= -I../include/
TOP ?= ../
-FIRMWARE_LIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a
-LIBS = $(TOP)/utils/kernel_image.o $(TOP)/utils/firmware_image.o \
- $(TOP)/utils/file_keys.o $(TOP)/utils/signature_digest.o -lcrypto
+BASE_LIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a
+IMAGE_LIBS = $(TOP)/utils/firmware_image.o $(TOP)/utils/kernel_image.o
+UTIL_LIBS = $(TOP)/utils/file_keys.o $(TOP)/utils/signature_digest.o
+LIBS = $(IMAGE_LIBS) $(UTIL_LIBS) -lcrypto $(BASE_LIBS)
tests: firmware_image_tests \
+ firmware_rollback_tests \
firmware_verify_benchmark \
kernel_image_tests \
kernel_verify_benchmark \
@@ -22,38 +24,47 @@ tests: firmware_image_tests \
verify_firmware_fuzz_driver \
verify_kernel_fuzz_driver
-firmware_image_tests: firmware_image_tests.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+firmware_image_tests: firmware_image_tests.c rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
-firmware_verify_benchmark: firmware_verify_benchmark.c timer_utils.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS) $(FIRMWARE_LIBS)
+firmware_rollback_tests: firmware_rollback_tests.c rollback_index_mock.c test_common.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
-kernel_image_tests: kernel_image_tests.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+firmware_verify_benchmark: firmware_verify_benchmark.c timer_utils.c \
+ rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS)
-kernel_verify_benchmark: kernel_verify_benchmark.c timer_utils.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS) $(FIRMWARE_LIBS)
+kernel_image_tests: kernel_image_tests.c rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
+
+kernel_verify_benchmark: kernel_verify_benchmark.c timer_utils.c \
+ rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS)
rsa_padding_test: rsa_padding_test.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS) $(FIRMWARE_LIBS)
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(UTIL_LIBS) $(BASE_LIBS) \
+ -lcrypto
rsa_verify_benchmark: rsa_verify_benchmark.c timer_utils.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS) $(FIRMWARE_LIBS)
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(UTIL_LIBS) $(BASE_LIBS) \
+ -lcrypto
-sha_benchmark: sha_benchmark.c timer_utils.c $(FIRMWARE_LIBS)
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt
+sha_benchmark: sha_benchmark.c timer_utils.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(BASE_LIBS)
sha_tests: sha_tests.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(FIRMWARE_LIBS)
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(BASE_LIBS)
-verify_firmware_fuzz_driver: verify_firmware_fuzz_driver.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+verify_firmware_fuzz_driver: verify_firmware_fuzz_driver.c \
+ rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
-verify_kernel_fuzz_driver: verify_kernel_fuzz_driver.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+verify_kernel_fuzz_driver: verify_kernel_fuzz_driver.c rollback_index_mock.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
clean:
rm -f firmware_image_tests \
+ firmware_rollback_tests \
firmware_verify_benchmark \
kernel_image_tests \
kernel_verify_benchmark \
diff --git a/tests/firmware_image_tests.c b/tests/firmware_image_tests.c
index 3df7cb06..b252735d 100644
--- a/tests/firmware_image_tests.c
+++ b/tests/firmware_image_tests.c
@@ -12,18 +12,18 @@
#include "firmware_image.h"
#include "rsa_utility.h"
#include "utility.h"
+#include "rollback_index.h"
/* ANSI Color coding sequences. */
#define COL_GREEN "\e[1;32m"
-#define COL_RED "\e[0;31m]"
+#define COL_RED "\e[0;31m"
#define COL_STOP "\e[m"
int TEST_EQ(int result, int expected_result, char* testname) {
if (result == expected_result) {
fprintf(stderr, "%s Test " COL_GREEN " PASSED\n" COL_STOP, testname);
return 1;
- }
- else {
+ } else {
fprintf(stderr, "%s Test " COL_RED " FAILED\n" COL_STOP, testname);
return 0;
}
@@ -33,7 +33,9 @@ FirmwareImage* GenerateTestFirmwareImage(int algorithm,
uint8_t* firmware_sign_key,
int firmware_key_version,
int firmware_version,
- int firmware_len) {
+ int firmware_len,
+ const char* root_key_file,
+ const char* firmware_key_file) {
FirmwareImage* image = FirmwareImageNew();
Memcpy(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE);
@@ -58,6 +60,18 @@ FirmwareImage* GenerateTestFirmwareImage(int algorithm,
image->firmware_data = Malloc(image->firmware_len);
Memset(image->firmware_data, 'F', image->firmware_len);
+ /* Generate and populate signatures. */
+ if (!AddFirmwareKeySignature(image, root_key_file)) {
+ fprintf(stderr, "Couldn't create key signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
+
+ if (!AddFirmwareSignature(image, firmware_key_file)) {
+ fprintf(stderr, "Couldn't create firmware and preamble signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
return image;
}
@@ -79,7 +93,6 @@ int VerifyFirmwareTest(uint8_t* firmware_blob, uint8_t* root_key_blob) {
return success;
}
-
/* Normal FirmwareImage Verification Tests. */
int VerifyFirmwareImageTest(FirmwareImage* image,
RSAPublicKey* root_key) {
@@ -142,14 +155,17 @@ int VerifyFirmwareImageTamperTest(FirmwareImage* image,
int main(int argc, char* argv[]) {
uint64_t len;
+ const char* root_key_file = NULL;
+ const char* firmware_key_file = NULL;
uint8_t* firmware_sign_key_buf = NULL;
uint8_t* root_key_blob = NULL;
uint8_t* firmware_blob = NULL;
uint64_t firmware_blob_len = 0;
FirmwareImage* image = NULL;
- RSAPublicKey* root_key = NULL;
+ RSAPublicKey* root_key_pub = NULL;
int error_code = 0;
-
+ int algorithm;
+ SetupTPM();
if(argc != 6) {
fprintf(stderr, "Usage: %s <algorithm> <root key> <processed root pubkey>"
" <signing key> <processed signing key>\n", argv[0]);
@@ -157,30 +173,24 @@ int main(int argc, char* argv[]) {
}
/* Read verification keys and create a test image. */
- root_key = RSAPublicKeyFromFile(argv[3]);
+ algorithm = atoi(argv[1]);
+ root_key_pub = RSAPublicKeyFromFile(argv[3]);
root_key_blob = BufferFromFile(argv[3], &len);
firmware_sign_key_buf = BufferFromFile(argv[5], &len);
- image = GenerateTestFirmwareImage(atoi(argv[1]), firmware_sign_key_buf, 1,
- 1, 1000);
-
- if (!root_key || !firmware_sign_key_buf || !image) {
- error_code = 1;
- goto failure;
- }
-
- /* Generate and populate signatures. */
- if (!AddFirmwareKeySignature(image, argv[2])) {
- fprintf(stderr, "Couldn't create key signature.\n");
+ root_key_file = argv[2];
+ firmware_key_file = argv[4];
+ image = GenerateTestFirmwareImage(algorithm,
+ firmware_sign_key_buf,
+ 1, /* Firmware Key Version. */
+ 1, /* Firmware Version. */
+ 1000, /* Firmware length. */
+ root_key_file,
+ firmware_key_file);
+
+ if (!root_key_pub || !firmware_sign_key_buf || !image) {
error_code = 1;
goto failure;
}
-
- if (!AddFirmwareSignature(image, argv[4])) {
- fprintf(stderr, "Couldn't create firmware and preamble signature.\n");
- error_code = 1;
- goto failure;
- }
-
firmware_blob = GetFirmwareBlob(image, &firmware_blob_len);
/* Test Firmware blob verify operations. */
@@ -188,9 +198,9 @@ int main(int argc, char* argv[]) {
error_code = 255;
/* Test FirmwareImage verify operations. */
- if (!VerifyFirmwareImageTest(image, root_key))
+ if (!VerifyFirmwareImageTest(image, root_key_pub))
error_code = 255;
- if (!VerifyFirmwareImageTamperTest(image, root_key))
+ if (!VerifyFirmwareImageTamperTest(image, root_key_pub))
error_code = 255;
failure:
@@ -198,7 +208,7 @@ failure:
FirmwareImageFree(image);
Free(firmware_sign_key_buf);
Free(root_key_blob);
- RSAPublicKeyFree(root_key);
+ RSAPublicKeyFree(root_key_pub);
return error_code;
}
diff --git a/tests/firmware_rollback_tests.c b/tests/firmware_rollback_tests.c
new file mode 100644
index 00000000..19ac850c
--- /dev/null
+++ b/tests/firmware_rollback_tests.c
@@ -0,0 +1,145 @@
+/* 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.
+ *
+ * Tests for checking firmware rollback-prevention logic.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_keys.h"
+#include "firmware_image.h"
+#include "rsa_utility.h"
+#include "utility.h"
+#include "rollback_index.h"
+#include "test_common.h"
+
+/* Generates a test firmware image for rollback tests with a given
+ * [firmware_key_version] and [firmware_version]. If [is_corrupt] is 1,
+ * then the image has invalid signatures and will fail verification. */
+uint8_t* GenerateRollbackTestImage(int firmware_key_version,
+ int firmware_version,
+ int is_corrupt) {
+ FirmwareImage* image = NULL;
+ uint8_t* firmware_blob = NULL;
+ const char* firmare_sign_key_pub_file = "testkeys/key_rsa1024.keyb";
+ uint8_t* firmware_sign_key = NULL;
+ const char* root_key_file = "testkeys/key_rsa8192.pem";
+ const char* firmware_key_file = "testkeys/key_rsa1024.pem";
+ uint64_t len;
+ firmware_sign_key = BufferFromFile(firmare_sign_key_pub_file,
+ &len);
+ if (!firmware_sign_key)
+ return NULL;
+
+ image = FirmwareImageNew();
+ if (!image)
+ return NULL;
+
+ Memcpy(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE);
+ image->firmware_sign_algorithm = 0; /* RSA1024/SHA1 */
+ image->firmware_sign_key = (uint8_t*) Malloc(
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
+ Memcpy(image->firmware_sign_key, firmware_sign_key,
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
+ image->firmware_key_version = firmware_key_version;
+ Free(firmware_sign_key);
+
+ /* Update correct header length. */
+ image->header_len = GetFirmwareHeaderLen(image);
+
+ /* Calculate SHA-512 digest on header and populate header_checksum. */
+ CalculateFirmwareHeaderChecksum(image, image->header_checksum);
+
+ /* Populate firmware and preamble with dummy data. */
+ image->firmware_version = firmware_version;
+ image->firmware_len = 1;
+ image->preamble_signature = image->firmware_signature = NULL;
+ Memset(image->preamble, 'P', FIRMWARE_PREAMBLE_SIZE);
+ image->firmware_data = Malloc(image->firmware_len);
+ Memset(image->firmware_data, 'F', image->firmware_len);
+
+ /* Generate and populate signatures. */
+ if (!AddFirmwareKeySignature(image, root_key_file)) {
+ fprintf(stderr, "Couldn't create key signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
+
+ if (!AddFirmwareSignature(image, firmware_key_file)) {
+ fprintf(stderr, "Couldn't create firmware and preamble signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
+ if (is_corrupt) {
+ /* Invalidate image. */
+ Memset(image->firmware_data, 'X', image->firmware_len);
+ }
+
+ firmware_blob = GetFirmwareBlob(image, &len);
+ FirmwareImageFree(image);
+ return firmware_blob;
+}
+
+/* Tests that check for correctness of the VerifyFirmwareDriver_f() logic
+ * and rollback prevention. */
+void VerifyFirmwareDriverTest(void) {
+ uint8_t* valid_firmwareA = NULL;
+ uint8_t* valid_firmwareB = NULL;
+ uint8_t* corrupt_firmwareA = NULL;
+ uint8_t* corrupt_firmwareB = NULL;
+ uint64_t len;
+ uint8_t* root_key_pub = BufferFromFile("testkeys/key_rsa8192.keyb",
+ &len);
+
+ /* Initialize rollback index state. */
+ g_firmware_key_version = 1;
+ g_firmware_version = 1;
+
+ valid_firmwareA = GenerateRollbackTestImage(1, 1, 0);
+ valid_firmwareB = GenerateRollbackTestImage(1, 1, 0);
+ corrupt_firmwareA = GenerateRollbackTestImage(1, 1, 1);
+ corrupt_firmwareB = GenerateRollbackTestImage(1, 1, 1);
+
+ TEST_EQ(VerifyFirmwareDriver_f(root_key_pub,
+ valid_firmwareA, valid_firmwareB),
+ BOOT_FIRMWARE_A_CONTINUE,
+ "Firmware A (Valid with current version), "
+ "Firmware B (Valid with current version)");
+ TEST_EQ(VerifyFirmwareDriver_f(root_key_pub,
+ corrupt_firmwareA, valid_firmwareB),
+ BOOT_FIRMWARE_B_CONTINUE,
+ "Firmware A (Corrupt with current version), "
+ "FirmwareB (Valid with current version)");
+ TEST_EQ(VerifyFirmwareDriver_f(root_key_pub,
+ valid_firmwareA, corrupt_firmwareB),
+ BOOT_FIRMWARE_A_CONTINUE,
+ "Firmware A (Valid with current version), "
+ "FirmwareB (Corrupt with current version)");
+ TEST_EQ(VerifyFirmwareDriver_f(root_key_pub,
+ corrupt_firmwareA, corrupt_firmwareB),
+ BOOT_FIRMWARE_RECOVERY_CONTINUE,
+ "Firmware A (Corrupt with current version), "
+ "FirmwareB (Corrupt with current version");
+ g_firmware_key_version = 2;
+ g_firmware_version = 2;
+ TEST_EQ(VerifyFirmwareDriver_f(root_key_pub, valid_firmwareA, valid_firmwareB),
+ BOOT_FIRMWARE_RECOVERY_CONTINUE,
+ "Firmware A (Valid with old version), "
+ "Old Firmware B (Valid with old version)");
+
+ Free(root_key_pub);
+ Free(valid_firmwareA);
+ Free(valid_firmwareB);
+ Free(corrupt_firmwareA);
+ Free(corrupt_firmwareB);
+}
+
+int main(int argc, char* argv[]) {
+ int error_code = 0;
+ VerifyFirmwareDriverTest();
+ if (!gTestSuccess)
+ error_code = 255;
+ return error_code;
+}
diff --git a/tests/rollback_index_mock.c b/tests/rollback_index_mock.c
new file mode 100644
index 00000000..047fb8ac
--- /dev/null
+++ b/tests/rollback_index_mock.c
@@ -0,0 +1,61 @@
+/* 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.
+ *
+ * Mock rollback index library for testing.
+ */
+
+#include "rollback_index.h"
+
+#include <stdio.h>
+#include <stdint.h>
+
+uint16_t g_firmware_key_version = 0;
+uint16_t g_firmware_version = 0;
+uint16_t g_kernel_key_version = 0;
+uint16_t g_kernel_version = 0;
+
+void SetupTPM(void) {
+ fprintf(stderr, "Rollback Index Library Mock: TPM initialized.\n");
+}
+
+uint16_t GetStoredVersion(int type) {
+ switch (type) {
+ case FIRMWARE_KEY_VERSION:
+ return g_firmware_key_version;
+ break;
+ case FIRMWARE_VERSION:
+ return g_firmware_version;
+ break;
+ case KERNEL_KEY_VERSION:
+ return g_kernel_key_version;
+ break;
+ case KERNEL_VERSION:
+ return g_kernel_version;
+ break;
+ }
+ return 0;
+}
+
+int WriteStoredVersion(int type, uint16_t version) {
+ switch (type) {
+ case FIRMWARE_KEY_VERSION:
+ g_firmware_key_version = version;
+ break;
+ case FIRMWARE_VERSION:
+ g_firmware_version = version;
+ break;
+ case KERNEL_KEY_VERSION:
+ g_kernel_key_version = version;
+ break;
+ case KERNEL_VERSION:
+ g_kernel_version = version;
+ break;
+ }
+ fprintf(stderr, "Rollback Index Library Mock: Stored Version written.\n");
+ return 1;
+}
+
+void LockStoredVersion(int type) {
+ fprintf(stderr, "Rollback Index Library Mock: Version Locked.\n");
+}
diff --git a/tests/test_common.c b/tests/test_common.c
new file mode 100644
index 00000000..4a92f7d8
--- /dev/null
+++ b/tests/test_common.c
@@ -0,0 +1,30 @@
+/* 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.
+ *
+ * Common functions used by tests.
+ */
+
+#include "test_common.h"
+
+#include <stdio.h>
+
+/* ANSI Color coding sequences. */
+#define COL_GREEN "\e[1;32m"
+#define COL_RED "\e[0;31m]"
+#define COL_STOP "\e[m"
+
+/* Global test success flag. */
+int gTestSuccess = 1;
+
+int TEST_EQ(int result, int expected_result, char* testname) {
+ if (result == expected_result) {
+ fprintf(stderr, "%s Test " COL_GREEN " PASSED\n" COL_STOP, testname);
+ return 1;
+ }
+ else {
+ fprintf(stderr, "%s Test " COL_RED " FAILED\n" COL_STOP, testname);
+ gTestSuccess = 0;
+ return 0;
+ }
+}
diff --git a/tests/test_common.h b/tests/test_common.h
new file mode 100644
index 00000000..9fa3eecf
--- /dev/null
+++ b/tests/test_common.h
@@ -0,0 +1,13 @@
+/* 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.
+ *
+ */
+
+#ifndef VBOOT_REFERENCE_TEST_COMMON_H_
+#define VBOOT_REFERENCE_TEST_COMMON_H_
+
+int TEST_EQ(int result, int expected_result, char* testname);
+extern int gTestSuccess;
+
+#endif /* VBOOT_REFERENCE_TEST_COMMON_H_ */
diff --git a/utils/Makefile b/utils/Makefile
index 6d5546e1..597638e7 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -8,12 +8,15 @@ CFLAGS ?= -Wall -DNDEBUG -O3 -Werror
INCLUDES ?= -I../include/
TOP ?= ../
-LIBS = firmware_image.o kernel_image.o signature_digest.o file_keys.o
+LIBS = firmware_image.o kernel_image.o signature_digest.o file_keys.o \
+ rollback_index.o
+
FIRMWARELIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a
all: dumpRSAPublicKey verify_data file_keys.o signature_digest.o \
firmware_image.o kernel_image.o signature_digest.o \
- signature_digest_utility firmware_utility kernel_utility
+ signature_digest_utility firmware_utility kernel_utility \
+ rollback_index.o
dumpRSAPublicKey: dumpRSAPublicKey.c
$(CC) $(CFLAGS) $< -o $@ -lcrypto
@@ -26,16 +29,15 @@ signature_digest_utility: signature_digest_utility.c $(LIBS) $(FIRMWARELIBS)
firmware_utility: firmware_utility.cc $(LIBS) $(FIRMWARELIBS)
$(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \
- -o $@ $(FIRMWARELIBS) $(LIBS) -lcrypto
+ -o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \
+ -lcrypto
kernel_utility: kernel_utility.cc $(LIBS) $(FIRMWARELIBS)
$(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \
- -o $@ $(FIRMWARELIBS) $(LIBS) -lcrypto
-
-signature_digest.o: signature_digest.c
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ -o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \
+ -lcrypto
-file_keys.o: file_keys.c
+.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
firmware_image.o: firmware_image.c
diff --git a/utils/firmware_image.c b/utils/firmware_image.c
index ab41fec9..4098bb23 100644
--- a/utils/firmware_image.c
+++ b/utils/firmware_image.c
@@ -16,6 +16,7 @@
#include "file_keys.h"
#include "padding.h"
+#include "rollback_index.h"
#include "rsa_utility.h"
#include "sha_utility.h"
#include "signature_digest.h"
@@ -97,10 +98,10 @@ FirmwareImage* ReadFirmwareImage(const char* input_file) {
}
/* Read pre-processed public half of the sign key. */
- image->firmware_sign_key = (uint8_t*) Malloc(firmware_sign_key_len);
- StatefulMemcpy(&st, image->firmware_sign_key, firmware_sign_key_len);
StatefulMemcpy(&st, &image->firmware_key_version,
FIELD_LEN(firmware_key_version));
+ image->firmware_sign_key = (uint8_t*) Malloc(firmware_sign_key_len);
+ StatefulMemcpy(&st, image->firmware_sign_key, firmware_sign_key_len);
StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
/* Check whether the header checksum matches. */
@@ -155,10 +156,10 @@ void CalculateFirmwareHeaderChecksum(const FirmwareImage* image,
sizeof(image->header_len));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
sizeof(image->firmware_sign_algorithm));
- DigestUpdate(&ctx, image->firmware_sign_key,
- RSAProcessedKeySize(image->firmware_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_key_version,
sizeof(image->firmware_key_version));
+ DigestUpdate(&ctx, image->firmware_sign_key,
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
checksum = DigestFinal(&ctx);
Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
Free(checksum);
@@ -176,10 +177,10 @@ uint8_t* GetFirmwareHeaderBlob(const FirmwareImage* image) {
StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
StatefulMemcpy_r(&st, &image->firmware_sign_algorithm, FIELD_LEN(header_len));
- StatefulMemcpy_r(&st, image->firmware_sign_key,
- RSAProcessedKeySize(image->firmware_sign_algorithm));
StatefulMemcpy_r(&st, &image->firmware_key_version,
FIELD_LEN(firmware_key_version));
+ StatefulMemcpy_r(&st, image->firmware_sign_key,
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
if (st.remaining_len != 0) { /* Underrun or Overrun. */
@@ -314,6 +315,9 @@ char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = {
"Preamble Signature Failed.",
"Firmware Signature Failed.",
"Wrong Firmware Magic.",
+ "Invalid Firmware Header Checksum.",
+ "Firmware Signing Key Rollback.",
+ "Firmware Version Rollback."
};
int VerifyFirmwareHeader(const uint8_t* root_key_blob,
@@ -343,7 +347,7 @@ int VerifyFirmwareHeader(const uint8_t* root_key_blob,
*algorithm = (int) algo;
firmware_sign_key_len = RSAProcessedKeySize(*algorithm);
- /* Verify if header len is correct? */
+ /* Verify that header len is correct. */
if (hlen != (base_header_checksum_offset +
firmware_sign_key_len +
FIELD_LEN(header_checksum)))
@@ -360,19 +364,18 @@ int VerifyFirmwareHeader(const uint8_t* root_key_blob,
firmware_sign_key_len),
FIELD_LEN(header_checksum))) {
Free(header_checksum);
- return VERIFY_FIRMWARE_INVALID_IMAGE;
+ return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM;
}
Free(header_checksum);
- /* Verify root key signature unless we are in dev mode. */
- if (!dev_mode) {
- if (!RSAVerifyBinary_f(root_key_blob, NULL, /* Key to use */
- header_blob, /* Data to verify */
- *header_len, /* Length of data */
- header_blob + *header_len, /* Expected Signature */
- ROOT_SIGNATURE_ALGORITHM))
- return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
- }
+ /* Root key signature on the firmware signing key is always checked
+ * irrespective of dev mode. */
+ if (!RSAVerifyBinary_f(root_key_blob, NULL, /* Key to use */
+ header_blob, /* Data to verify */
+ *header_len, /* Length of data */
+ header_blob + *header_len, /* Expected Signature */
+ ROOT_SIGNATURE_ALGORITHM))
+ return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
return 0;
}
@@ -382,6 +385,10 @@ int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key,
int* firmware_len) {
uint32_t len;
int preamble_len;
+ uint16_t firmware_version;
+
+ Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version));
+
preamble_len = (FIELD_LEN(firmware_version) +
FIELD_LEN(firmware_len) +
FIELD_LEN(preamble));
@@ -442,7 +449,8 @@ int VerifyFirmware(const uint8_t* root_key_blob,
* times. */
firmware_sign_key_len = RSAProcessedKeySize(algorithm);
firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) +
- FIELD_LEN(firmware_sign_algorithm));
+ FIELD_LEN(firmware_sign_algorithm) +
+ FIELD_LEN(firmware_key_version));
firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr,
firmware_sign_key_len);
signature_len = siglen_map[algorithm];
@@ -458,7 +466,7 @@ int VerifyFirmware(const uint8_t* root_key_blob,
}
/* Only continue if firmware data verification succeeds. */
firmware_ptr = (preamble_ptr +
- GetFirmwarePreambleLen(NULL) +
+ GetFirmwarePreambleLen(NULL) +
signature_len);
if ((error_code = VerifyFirmwareData(firmware_sign_key, firmware_ptr,
@@ -494,16 +502,21 @@ int VerifyFirmwareImage(const RSAPublicKey* root_key,
* 1) verifying the header length is correct.
* 2) header_checksum is correct.
*/
+ /* TODO(gauravsh): The [dev_mode] switch is actually irrelevant
+ * for the firmware verification.
+ * Change this to always verify the root key signature and change
+ * test expectations appropriately.
+ */
if (!dev_mode) {
DigestInit(&ctx, ROOT_SIGNATURE_ALGORITHM);
DigestUpdate(&ctx, (uint8_t*) &image->header_len,
FIELD_LEN(header_len));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
FIELD_LEN(firmware_sign_algorithm));
- DigestUpdate(&ctx, image->firmware_sign_key,
- RSAProcessedKeySize(image->firmware_sign_algorithm));
DigestUpdate(&ctx, (uint8_t*) &image->firmware_key_version,
FIELD_LEN(firmware_key_version));
+ DigestUpdate(&ctx, image->firmware_sign_key,
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
DigestUpdate(&ctx, image->header_checksum,
FIELD_LEN(header_checksum));
header_digest = DigestFinal(&ctx);
@@ -613,3 +626,117 @@ int AddFirmwareSignature(FirmwareImage* image, const char* signing_key_file) {
Free(firmware_signature);
return 1;
}
+
+uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) {
+ uint16_t firmware_key_version;
+ uint16_t firmware_version;
+ uint16_t firmware_sign_algorithm;
+ int firmware_sign_key_len;
+ Memcpy(&firmware_sign_algorithm,
+ firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */
+ FIELD_LEN(header_len)),
+ sizeof(firmware_sign_algorithm));
+ Memcpy(&firmware_key_version,
+ firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */
+ FIELD_LEN(header_len) +
+ FIELD_LEN(firmware_sign_algorithm)),
+ sizeof(firmware_key_version));
+ if (firmware_sign_algorithm >= kNumAlgorithms)
+ return 0;
+ firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
+ Memcpy(&firmware_version,
+ firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */
+ FIELD_LEN(header_len) +
+ FIELD_LEN(firmware_key_version) +
+ firmware_sign_key_len +
+ FIELD_LEN(header_checksum) +
+ FIELD_LEN(firmware_key_signature)),
+ sizeof(firmware_version));
+ return CombineUint16Pair(firmware_key_version, firmware_version);
+}
+
+int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
+ uint8_t* firmwareA,
+ uint8_t* firmwareB) {
+ /* Contains the logical firmware version (32-bit) which is calculated as
+ * (firmware_key_version << 16 | firmware_version) where
+ * [firmware_key_version] [firmware_version] are both 16-bit.
+ */
+ uint32_t firmwareA_lversion, firmwareB_lversion;
+ uint8_t firmwareA_is_verified = 0; /* Whether firmwareA verify succeeded. */
+ uint32_t min_lversion; /* Minimum of firmware A and firmware lversion. */
+ uint32_t stored_lversion; /* Stored logical version in the TPM. */
+
+ /* Initialize the TPM since we'll be reading the rollback indices. */
+ SetupTPM();
+
+ /* We get the key versions by reading directly from the image blobs without
+ * any additional (expensive) sanity checking on the blob since it's faster to
+ * outright reject a firmware with an older firmware key version. A malformed
+ * or corrupted firmware blob will still fail when VerifyFirmware() is called
+ * on it.
+ */
+ firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA);
+ firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB);
+ min_lversion = Min(firmwareA_lversion, firmwareB_lversion);
+ stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION),
+ GetStoredVersion(FIRMWARE_VERSION));
+ /* Always try FirmwareA first. */
+ if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA,
+ 0))
+ firmwareA_is_verified = 1;
+ if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) {
+ /* Stored version may need to be updated but only if FirmwareB
+ * is successfully verified and has a logical version greater than
+ * the stored logical version. */
+ if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB,
+ 0)) {
+ if (stored_lversion < firmwareB_lversion) {
+ WriteStoredVersion(FIRMWARE_KEY_VERSION,
+ (uint16_t) (min_lversion >> 16));
+ WriteStoredVersion(FIRMWARE_VERSION,
+ (uint16_t) (min_lversion & 0x00FFFF));
+ stored_lversion = min_lversion; /* Update stored version as it's used
+ * later. */
+ }
+ }
+ }
+ /* Lock Firmware TPM rollback indices from further writes. */
+ /* TODO(gauravsh): Figure out if these can be combined into one
+ * 32-bit location since we seem to always use them together. This can help
+ * us minimize the number of NVRAM writes/locks (which are limited over flash
+ * memory lifetimes.
+ */
+ LockStoredVersion(FIRMWARE_KEY_VERSION);
+ LockStoredVersion(FIRMWARE_VERSION);
+
+ /* Determine which firmware (if any) to jump to.
+ *
+ * We always attempt to jump to FirmwareA first. If verification of FirmwareA
+ * fails, we try FirmwareB. In all cases, if the firmware successfully
+ * verified but is a rollback, we jump to recovery.
+ *
+ * Note: This means that if FirmwareA verified successfully and is a
+ * rollback, then no attempt is made to check FirmwareB. We still jump to
+ * recovery. FirmwareB is only used as a backup in case FirmwareA gets
+ * corrupted. Since newer firmware updates are always written to A,
+ * the case where firmware A is verified but a rollback should not occur in
+ * normal operation.
+ */
+ if (firmwareA_is_verified) {
+ if (stored_lversion <= firmwareA_lversion)
+ return BOOT_FIRMWARE_A_CONTINUE;
+ } else {
+ /* If FirmwareA was not valid, then we skipped over the
+ * check to update the rollback indices and a Verify of FirmwareB wasn't
+ * attempted.
+ * If FirmwareB is not a rollback, then we attempt to do the verification.
+ */
+ if (stored_lversion <= firmwareB_lversion &&
+ (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB,
+ 0)))
+ return BOOT_FIRMWARE_B_CONTINUE;
+ }
+ /* D'oh: No bootable firmware. */
+ return BOOT_FIRMWARE_RECOVERY_CONTINUE;
+}
diff --git a/utils/rollback_index.c b/utils/rollback_index.c
new file mode 100644
index 00000000..0b65bf49
--- /dev/null
+++ b/utils/rollback_index.c
@@ -0,0 +1,148 @@
+/* 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.
+ *
+ * Functions for querying, manipulating and locking rollback indices
+ * stored in the TPM NVRAM.
+ */
+
+#include "rollback_index.h"
+
+#include <stdint.h>
+#include <tss/tcs.h>
+
+#include "tlcl.h"
+
+uint16_t g_firmware_key_version = 0;
+uint16_t g_firmware_version = 0;
+uint16_t g_kernel_key_version = 0;
+uint16_t g_kernel_version = 0;
+
+static void InitializeSpaces(void) {
+ uint16_t zero = 0;
+ uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
+
+ printf("Initializing spaces\n");
+ TlclSetNvLocked(); /* useful only the first time */
+
+ TlclDefineSpace(FIRMWARE_KEY_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclWrite(FIRMWARE_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
+
+ TlclDefineSpace(FIRMWARE_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclWrite(FIRMWARE_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
+
+ TlclDefineSpace(KERNEL_KEY_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclWrite(KERNEL_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
+
+ TlclDefineSpace(KERNEL_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclWrite(KERNEL_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
+}
+
+static void EnterRecovery(void) {
+ /* Temporary recovery stub. Currently just initalizes spaces. */
+ InitializeSpaces();
+}
+
+static int GetTPMRollbackIndices(void) {
+ /* We just perform the reads, making sure they succeed. A failure means that
+ * the rollback index locations are some how messed up and we must jump to
+ * recovery */
+ if (TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &g_firmware_key_version,
+ sizeof(g_firmware_key_version)) ||
+ TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &g_firmware_key_version,
+ sizeof(g_firmware_key_version)) ||
+ TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &g_firmware_key_version,
+ sizeof(g_firmware_key_version)) ||
+ TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &g_firmware_key_version,
+ sizeof(g_firmware_key_version)))
+ return 0;
+ return 1;
+}
+
+
+void SetupTPM(void) {
+ TlclLibinit();
+ TlclStartup();
+ /* TODO(gauravsh): The call to self test should probably be deferred.
+ * As per semenzato@chromium.org -
+ * TlclStartup should be called before the firmware initializes the memory
+ * controller, so the selftest can run in parallel with that. Here we should
+ * just call TlclSelftestFull to make sure the self test has
+ * completed---unless we want to rely on the NVRAM operations being available
+ * before the selftest completes. */
+ TlclSelftestfull();
+ TlclAssertPhysicalPresence();
+ if (!GetTPMRollbackIndices()) {
+ fprintf(stderr, "Ho Ho Ho! We must jump to recovery.");
+ EnterRecovery();
+ }
+}
+
+
+uint16_t GetStoredVersion(int type) {
+ switch (type) {
+ case FIRMWARE_KEY_VERSION:
+ return g_firmware_key_version;
+ break;
+ case FIRMWARE_VERSION:
+ return g_firmware_version;
+ break;
+ case KERNEL_KEY_VERSION:
+ return g_kernel_key_version;
+ break;
+ case KERNEL_VERSION:
+ return g_kernel_version;
+ break;
+ }
+ return 0;
+}
+
+int WriteStoredVersion(int type, uint16_t version) {
+ switch (type) {
+ case FIRMWARE_KEY_VERSION:
+ return (TPM_SUCCESS == TlclWrite(FIRMWARE_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &version,
+ sizeof(uint16_t)));
+ break;
+ case FIRMWARE_VERSION:
+ return (TPM_SUCCESS == TlclWrite(FIRMWARE_VERSION_NV_INDEX,
+ (uint8_t*) &version,
+ sizeof(uint16_t)));
+ break;
+ case KERNEL_KEY_VERSION:
+ return (TPM_SUCCESS == TlclWrite(KERNEL_KEY_VERSION_NV_INDEX,
+ (uint8_t*) &version,
+ sizeof(uint16_t)));
+ break;
+ case KERNEL_VERSION:
+ return (TPM_SUCCESS == TlclWrite(KERNEL_VERSION_NV_INDEX,
+ (uint8_t*) &version,
+ sizeof(uint16_t)));
+ break;
+ }
+ return 0;
+}
+
+void LockStoredVersion(int type) {
+ /* TODO(gauravsh): Add error checking here to make sure TlclWriteLock
+ * did not fail. We must jump to recovery in that case.
+ */
+ switch (type) {
+ case FIRMWARE_KEY_VERSION:
+ TlclWriteLock(FIRMWARE_KEY_VERSION_NV_INDEX);
+ break;
+ case FIRMWARE_VERSION:
+ TlclWriteLock(FIRMWARE_VERSION_NV_INDEX);
+ break;
+ case KERNEL_KEY_VERSION:
+ TlclWriteLock(KERNEL_KEY_VERSION_NV_INDEX);
+ break;
+ case KERNEL_VERSION:
+ TlclWriteLock(KERNEL_VERSION_NV_INDEX);
+ break;
+ }
+}