summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/antirollback.h187
-rw-r--r--src/include/tpm_lite/tlcl.h209
-rw-r--r--src/include/tpm_lite/tss_constants.h96
-rw-r--r--src/lib/tlcl.c466
-rw-r--r--src/lib/tlcl_internal.h61
-rw-r--r--src/lib/tlcl_structures.h138
-rw-r--r--src/lib/tpm_error_messages.h250
-rw-r--r--src/vendorcode/google/chromeos/antirollback.c676
8 files changed, 2083 insertions, 0 deletions
diff --git a/src/include/antirollback.h b/src/include/antirollback.h
new file mode 100644
index 0000000000..dd0de32aef
--- /dev/null
+++ b/src/include/antirollback.h
@@ -0,0 +1,187 @@
+/* Copyright (c) 2013 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 "sysincludes.h"
+#include "tss_constants.h"
+
+/* TPM NVRAM location indices. */
+#define FIRMWARE_NV_INDEX 0x1007
+#define KERNEL_NV_INDEX 0x1008
+/* This is just an opaque space for backup purposes */
+#define BACKUP_NV_INDEX 0x1009
+#define BACKUP_NV_SIZE 16
+
+
+/* Structure definitions for TPM spaces */
+
+/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */
+#define ROLLBACK_SPACE_KERNEL_VERSION 2
+#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
+
+typedef struct RollbackSpaceKernel {
+ /* Struct version, for backwards compatibility */
+ uint8_t struct_version;
+ /* Unique ID to detect space redefinition */
+ uint32_t uid;
+ /* Kernel versions */
+ uint32_t kernel_versions;
+ /* Reserved for future expansion */
+ uint8_t reserved[3];
+ /* Checksum (v2 and later only) */
+ uint8_t crc8;
+} __attribute__((packed)) RollbackSpaceKernel;
+
+/* Flags for firmware space */
+/*
+ * Last boot was developer mode. TPM ownership is cleared when transitioning
+ * to/from developer mode.
+ */
+#define FLAG_LAST_BOOT_DEVELOPER 0x01
+/*
+ * Some systems may not have a dedicated dev-mode switch, but enter and leave
+ * dev-mode through some recovery-mode magic keypresses. For those systems, the
+ * dev-mode "switch" state is in this bit (0=normal, 1=dev). To make it work, a
+ * new flag is passed to VbInit(), indicating that the system lacks a physical
+ * dev-mode switch. If a physical switch is present, this bit is ignored.
+ */
+#define FLAG_VIRTUAL_DEV_MODE_ON 0x02
+
+/* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */
+#define ROLLBACK_SPACE_FIRMWARE_VERSION 2
+
+typedef struct RollbackSpaceFirmware {
+ /* Struct version, for backwards compatibility */
+ uint8_t struct_version;
+ /* Flags (see FLAG_* above) */
+ uint8_t flags;
+ /* Firmware versions */
+ uint32_t fw_versions;
+ /* Reserved for future expansion */
+ uint8_t reserved[3];
+ /* Checksum (v2 and later only) */
+ uint8_t crc8;
+} __attribute__((packed)) RollbackSpaceFirmware;
+
+
+/* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */
+
+/*
+ * These functions are called from VbInit(). They cannot use global
+ * variables.
+ */
+
+uint32_t RollbackS3Resume(void);
+
+/*
+ * These functions are callable from VbSelectFirmware(). They cannot use
+ * global variables.
+ */
+
+/**
+ * This must be called.
+ */
+uint32_t RollbackFirmwareSetup(int is_hw_dev,
+ int disable_dev_request,
+ int clear_tpm_owner_request,
+ /* two outputs on success */
+ int *is_virt_dev, uint32_t *tpm_version);
+
+/**
+ * Write may be called if the versions change.
+ */
+uint32_t RollbackFirmwareWrite(uint32_t version);
+
+/**
+ * Lock must be called.
+ */
+uint32_t RollbackFirmwareLock(void);
+
+/*
+ * These functions are callable from VbSelectAndLoadKernel(). They may use
+ * global variables.
+ */
+
+/**
+ * Read stored kernel version.
+ */
+uint32_t RollbackKernelRead(uint32_t *version);
+
+/**
+ * Write stored kernel version.
+ */
+uint32_t RollbackKernelWrite(uint32_t version);
+
+/**
+ * Read backup data.
+ */
+uint32_t RollbackBackupRead(uint8_t *raw);
+
+/**
+ * Write backup data.
+ */
+uint32_t RollbackBackupWrite(uint8_t *raw);
+
+/**
+ * Lock must be called. Internally, it's ignored in recovery mode.
+ */
+uint32_t RollbackKernelLock(int recovery_mode);
+
+/****************************************************************************/
+
+/*
+ * The following functions are internal apis, listed here for use by unit tests
+ * only.
+ */
+
+/**
+ * Issue a TPM_Clear and reenable/reactivate the TPM.
+ */
+uint32_t TPMClearAndReenable(void);
+
+/**
+ * Like TlclWrite(), but checks for write errors due to hitting the 64-write
+ * limit and clears the TPM when that happens. This can only happen when the
+ * TPM is unowned, so it is OK to clear it (and we really have no choice).
+ * This is not expected to happen frequently, but it could happen.
+ */
+uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length);
+
+/**
+ * Similarly to SafeWrite(), this ensures we don't fail a DefineSpace because
+ * we hit the TPM write limit. This is even less likely to happen than with
+ * writes because we only define spaces once at initialization, but we'd rather
+ * be paranoid about this.
+ */
+uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size);
+
+/**
+ * Perform one-time initializations.
+ *
+ * Create the NVRAM spaces, and set their initial values as needed. Sets the
+ * nvLocked bit and ensures the physical presence command is enabled and
+ * locked.
+ */
+uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
+ RollbackSpaceKernel *rsk);
+
+/**
+ * Start the TPM and establish the root of trust for the anti-rollback
+ * mechanism.
+ */
+uint32_t SetupTPM(int developer_mode, int disable_dev_request,
+ int clear_tpm_owner_request, RollbackSpaceFirmware *rsf);
+
+/**
+ * Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on.
+ */
+uint32_t SetVirtualDevMode(int val);
+
+#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */
diff --git a/src/include/tpm_lite/tlcl.h b/src/include/tpm_lite/tlcl.h
new file mode 100644
index 0000000000..5373120066
--- /dev/null
+++ b/src/include/tpm_lite/tlcl.h
@@ -0,0 +1,209 @@
+/* Copyright (c) 2013 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.
+ */
+
+/*
+ * TPM Lightweight Command Library.
+ *
+ * A low-level library for interfacing to TPM hardware or an emulator.
+ */
+
+#ifndef TPM_LITE_TLCL_H_
+#define TPM_LITE_TLCL_H_
+#include <stdint.h>
+
+#include "tss_constants.h"
+
+/*****************************************************************************/
+/* Functions implemented in tlcl.c */
+
+/**
+ * Call this first. Returns 0 if success, nonzero if error.
+ */
+uint32_t TlclLibInit(void);
+
+/**
+ * Call this on shutdown. Returns 0 if success, nonzero if error.
+ */
+uint32_t TlclLibClose(void);
+
+/* Low-level operations */
+
+/**
+ * Perform a raw TPM request/response transaction.
+ */
+uint32_t TlclSendReceive(const uint8_t *request, uint8_t *response,
+ int max_length);
+
+/**
+ * Return the size of a TPM request or response packet.
+ */
+int TlclPacketSize(const uint8_t *packet);
+
+/* Commands */
+
+/**
+ * Send a TPM_Startup(ST_CLEAR). The TPM error code is returned (0 for
+ * success).
+ */
+uint32_t TlclStartup(void);
+
+/**
+ * Save the TPM state. Normally done by the kernel before a suspend, included
+ * here for tests. The TPM error code is returned (0 for success).
+ */
+uint32_t TlclSaveState(void);
+
+/**
+ * Resume by sending a TPM_Startup(ST_STATE). The TPM error code is returned
+ * (0 for success).
+ */
+uint32_t TlclResume(void);
+
+/**
+ * Run the self test.
+ *
+ * Note---this is synchronous. To run this in parallel with other firmware,
+ * use ContinueSelfTest(). The TPM error code is returned.
+ */
+uint32_t TlclSelfTestFull(void);
+
+/**
+ * Run the self test in the background.
+ */
+uint32_t TlclContinueSelfTest(void);
+
+/**
+ * Define a space with permission [perm]. [index] is the index for the space,
+ * [size] the usable data size. The TPM error code is returned.
+ */
+uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size);
+
+/**
+ * Write [length] bytes of [data] to space at [index]. The TPM error code is
+ * returned.
+ */
+uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length);
+
+/**
+ * Read [length] bytes from space at [index] into [data]. The TPM error code
+ * is returned.
+ */
+uint32_t TlclRead(uint32_t index, void *data, uint32_t length);
+
+/**
+ * Read PCR at [index] into [data]. [length] must be TPM_PCR_DIGEST or
+ * larger. The TPM error code is returned.
+ */
+uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length);
+
+/**
+ * Write-lock space at [index]. The TPM error code is returned.
+ */
+uint32_t TlclWriteLock(uint32_t index);
+
+/**
+ * Read-lock space at [index]. The TPM error code is returned.
+ */
+uint32_t TlclReadLock(uint32_t index);
+
+/**
+ * Assert physical presence in software. The TPM error code is returned.
+ */
+uint32_t TlclAssertPhysicalPresence(void);
+
+/**
+ * Enable the physical presence command. The TPM error code is returned.
+ */
+uint32_t TlclPhysicalPresenceCMDEnable(void);
+
+/**
+ * Finalize the physical presence settings: sofware PP is enabled, hardware PP
+ * is disabled, and the lifetime lock is set. The TPM error code is returned.
+ */
+uint32_t TlclFinalizePhysicalPresence(void);
+
+uint32_t TlclAssertPhysicalPresenceResult(void);
+
+/**
+ * Turn off physical presence and locks it off until next reboot. The TPM
+ * error code is returned.
+ */
+uint32_t TlclLockPhysicalPresence(void);
+
+/**
+ * Set the nvLocked bit. The TPM error code is returned.
+ */
+uint32_t TlclSetNvLocked(void);
+
+/**
+ * Return 1 if the TPM is owned, 0 otherwise.
+ */
+int TlclIsOwned(void);
+
+/**
+ * Issue a ForceClear. The TPM error code is returned.
+ */
+uint32_t TlclForceClear(void);
+
+/**
+ * Issue a PhysicalEnable. The TPM error code is returned.
+ */
+uint32_t TlclSetEnable(void);
+
+/**
+ * Issue a PhysicalDisable. The TPM error code is returned.
+ */
+uint32_t TlclClearEnable(void);
+
+/**
+ * Issue a SetDeactivated. Pass 0 to activate. Returns result code.
+ */
+uint32_t TlclSetDeactivated(uint8_t flag);
+
+/**
+ * Get flags of interest. Pointers for flags you aren't interested in may
+ * be NULL. The TPM error code is returned.
+ */
+uint32_t TlclGetFlags(uint8_t *disable, uint8_t *deactivated,
+ uint8_t *nvlocked);
+
+/**
+ * Set the bGlobalLock flag, which only a reboot can clear. The TPM error
+ * code is returned.
+ */
+uint32_t TlclSetGlobalLock(void);
+
+/**
+ * Perform a TPM_Extend.
+ */
+uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest);
+
+/**
+ * Get the permission bits for the NVRAM space with |index|.
+ */
+uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions);
+
+/**
+ * Get the entire set of permanent flags.
+ */
+uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags);
+
+/**
+ * Get the entire set of volatile (ST_CLEAR) flags.
+ */
+uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags);
+
+/**
+ * Get the ownership flag. The TPM error code is returned.
+ */
+uint32_t TlclGetOwnership(uint8_t *owned);
+
+/**
+ * Request [length] bytes from TPM RNG to be stored in [data]. Actual number of
+ * bytes read is stored in [size]. The TPM error code is returned.
+ */
+uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size);
+
+#endif /* TPM_LITE_TLCL_H_ */
diff --git a/src/include/tpm_lite/tss_constants.h b/src/include/tpm_lite/tss_constants.h
new file mode 100644
index 0000000000..883a5ad85e
--- /dev/null
+++ b/src/include/tpm_lite/tss_constants.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2013 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.
+ *
+ * Some TPM constants and type definitions for standalone compilation for use
+ * in the firmware
+ */
+#ifndef VBOOT_REFERENCE_TSS_CONSTANTS_H_
+#define VBOOT_REFERENCE_TSS_CONSTANTS_H_
+#include <stdint.h>
+
+#define TPM_MAX_COMMAND_SIZE 4096
+#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */
+#define TPM_PUBEK_SIZE 256
+#define TPM_PCR_DIGEST 20
+
+#define TPM_E_NON_FATAL 0x800
+
+#define TPM_SUCCESS ((uint32_t)0x00000000)
+
+#define TPM_E_AREA_LOCKED ((uint32_t)0x0000003c)
+#define TPM_E_BADINDEX ((uint32_t)0x00000002)
+#define TPM_E_BAD_PRESENCE ((uint32_t)0x0000002d)
+#define TPM_E_IOERROR ((uint32_t)0x0000001f)
+#define TPM_E_INVALID_POSTINIT ((uint32_t)0x00000026)
+#define TPM_E_MAXNVWRITES ((uint32_t)0x00000048)
+#define TPM_E_OWNER_SET ((uint32_t)0x00000014)
+
+#define TPM_E_NEEDS_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 1))
+#define TPM_E_DOING_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 2))
+
+#define TPM_E_ALREADY_INITIALIZED ((uint32_t)0x00005000) /* vboot local */
+#define TPM_E_INTERNAL_INCONSISTENCY ((uint32_t)0x00005001) /* vboot local */
+#define TPM_E_MUST_REBOOT ((uint32_t)0x00005002) /* vboot local */
+#define TPM_E_CORRUPTED_STATE ((uint32_t)0x00005003) /* vboot local */
+#define TPM_E_COMMUNICATION_ERROR ((uint32_t)0x00005004) /* vboot local */
+#define TPM_E_RESPONSE_TOO_LARGE ((uint32_t)0x00005005) /* vboot local */
+#define TPM_E_NO_DEVICE ((uint32_t)0x00005006) /* vboot local */
+#define TPM_E_INPUT_TOO_SMALL ((uint32_t)0x00005007) /* vboot local */
+#define TPM_E_WRITE_FAILURE ((uint32_t)0x00005008) /* vboot local */
+#define TPM_E_READ_EMPTY ((uint32_t)0x00005009) /* vboot local */
+#define TPM_E_READ_FAILURE ((uint32_t)0x0000500a) /* vboot local */
+
+#define TPM_NV_INDEX0 ((uint32_t)0x00000000)
+#define TPM_NV_INDEX_LOCK ((uint32_t)0xffffffff)
+#define TPM_NV_PER_GLOBALLOCK (((uint32_t)1)<<15)
+#define TPM_NV_PER_PPWRITE (((uint32_t)1)<<0)
+#define TPM_NV_PER_READ_STCLEAR (((uint32_t)1)<<31)
+#define TPM_NV_PER_WRITE_STCLEAR (((uint32_t)1)<<14)
+
+#define TPM_TAG_RQU_COMMAND ((uint16_t) 0xc1)
+#define TPM_TAG_RQU_AUTH1_COMMAND ((uint16_t) 0xc2)
+#define TPM_TAG_RQU_AUTH2_COMMAND ((uint16_t) 0xc3)
+
+#define TPM_TAG_RSP_COMMAND ((uint16_t) 0xc4)
+#define TPM_TAG_RSP_AUTH1_COMMAND ((uint16_t) 0xc5)
+#define TPM_TAG_RSP_AUTH2_COMMAND ((uint16_t) 0xc6)
+
+typedef uint8_t TSS_BOOL;
+typedef uint16_t TPM_STRUCTURE_TAG;
+
+typedef struct tdTPM_PERMANENT_FLAGS
+{
+ TPM_STRUCTURE_TAG tag;
+ TSS_BOOL disable;
+ TSS_BOOL ownership;
+ TSS_BOOL deactivated;
+ TSS_BOOL readPubek;
+ TSS_BOOL disableOwnerClear;
+ TSS_BOOL allowMaintenance;
+ TSS_BOOL physicalPresenceLifetimeLock;
+ TSS_BOOL physicalPresenceHWEnable;
+ TSS_BOOL physicalPresenceCMDEnable;
+ TSS_BOOL CEKPUsed;
+ TSS_BOOL TPMpost;
+ TSS_BOOL TPMpostLock;
+ TSS_BOOL FIPS;
+ TSS_BOOL Operator;
+ TSS_BOOL enableRevokeEK;
+ TSS_BOOL nvLocked;
+ TSS_BOOL readSRKPub;
+ TSS_BOOL tpmEstablished;
+ TSS_BOOL maintenanceDone;
+ TSS_BOOL disableFullDALogicInfo;
+} TPM_PERMANENT_FLAGS;
+
+typedef struct tdTPM_STCLEAR_FLAGS{
+ TPM_STRUCTURE_TAG tag;
+ TSS_BOOL deactivated;
+ TSS_BOOL disableForceClear;
+ TSS_BOOL physicalPresence;
+ TSS_BOOL physicalPresenceLock;
+ TSS_BOOL bGlobalLock;
+} TPM_STCLEAR_FLAGS;
+
+#endif /* VBOOT_REFERENCE_TSS_CONSTANTS_H_ */
diff --git a/src/lib/tlcl.c b/src/lib/tlcl.c
new file mode 100644
index 0000000000..bf2d27f99c
--- /dev/null
+++ b/src/lib/tlcl.c
@@ -0,0 +1,466 @@
+/* Copyright (c) 2012 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.
+ */
+
+/* A lightweight TPM command library.
+ *
+ * The general idea is that TPM commands are array of bytes whose
+ * fields are mostly compile-time constant. The goal is to build much
+ * of the commands at compile time (or build time) and change some of
+ * the fields at run time as needed. The code in
+ * utility/tlcl_generator.c builds structures containing the commands,
+ * as well as the offsets of the fields that need to be set at run
+ * time.
+ */
+
+#include "sysincludes.h"
+
+#include "tlcl.h"
+#include "tlcl_internal.h"
+#include "tlcl_structures.h"
+#include "utility.h"
+#include "vboot_api.h"
+
+#ifdef FOR_TEST
+/* Allow unit testing implementation of TlclSendReceive() */
+#undef CHROMEOS_ENVIRONMENT
+#endif
+
+/* Sets the size field of a TPM command. */
+static inline void SetTpmCommandSize(uint8_t* buffer, uint32_t size) {
+ ToTpmUint32(buffer + sizeof(uint16_t), size);
+}
+
+/* Gets the size field of a TPM command. */
+__attribute__((unused))
+static inline int TpmCommandSize(const uint8_t* buffer) {
+ uint32_t size;
+ FromTpmUint32(buffer + sizeof(uint16_t), &size);
+ return (int) size;
+}
+
+/* Gets the size field of a TPM request or response. */
+int TlclPacketSize(const uint8_t* packet) {
+ return TpmCommandSize(packet);
+}
+
+/* Gets the code field of a TPM command. */
+static inline int TpmCommandCode(const uint8_t* buffer) {
+ uint32_t code;
+ FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
+ return code;
+}
+
+/* Gets the return code field of a TPM result. */
+static inline int TpmReturnCode(const uint8_t* buffer) {
+ return TpmCommandCode(buffer);
+}
+
+/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or
+ * DOING_SELFTEST errors are returned.
+ */
+static uint32_t TlclSendReceiveNoRetry(const uint8_t* request,
+ uint8_t* response, int max_length) {
+
+ uint32_t response_length = max_length;
+ uint32_t result;
+
+#ifdef EXTRA_LOGGING
+ VBDEBUG(("TPM: command: %x%x %x%x%x%x %x%x%x%x\n",
+ request[0], request[1],
+ request[2], request[3], request[4], request[5],
+ request[6], request[7], request[8], request[9]));
+#endif
+
+ result = VbExTpmSendReceive(request, TpmCommandSize(request),
+ response, &response_length);
+ if (0 != result) {
+ /* Communication with TPM failed, so response is garbage */
+ VBDEBUG(("TPM: command 0x%x send/receive failed: 0x%x\n",
+ TpmCommandCode(request), result));
+ return result;
+ }
+ /* Otherwise, use the result code from the response */
+ result = TpmReturnCode(response);
+
+ /* TODO: add paranoia about returned response_length vs. max_length
+ * (and possibly expected length from the response header). See
+ * crosbug.com/17017 */
+
+#ifdef EXTRA_LOGGING
+ VBDEBUG(("TPM: response: %x%x %x%x%x%x %x%x%x%x\n",
+ response[0], response[1],
+ response[2], response[3], response[4], response[5],
+ response[6], response[7], response[8], response[9]));
+#endif
+
+ VBDEBUG(("TPM: command 0x%x returned 0x%x\n",
+ TpmCommandCode(request), result));
+
+ return result;
+}
+
+
+/* Sends a TPM command and gets a response. Returns 0 if success or the TPM
+ * error code if error. In the firmware, waits for the self test to complete
+ * if needed. In the host, reports the first error without retries. */
+uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response,
+ int max_length) {
+ uint32_t result = TlclSendReceiveNoRetry(request, response, max_length);
+ /* When compiling for the firmware, hide command failures due to the self
+ * test not having run or completed. */
+#ifndef CHROMEOS_ENVIRONMENT
+ /* If the command fails because the self test has not completed, try it
+ * again after attempting to ensure that the self test has completed. */
+ if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) {
+ result = TlclContinueSelfTest();
+ if (result != TPM_SUCCESS) {
+ return result;
+ }
+#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE)
+ /* Retry only once */
+ result = TlclSendReceiveNoRetry(request, response, max_length);
+#else
+ /* This needs serious testing. The TPM specification says: "iii. The
+ * caller MUST wait for the actions of TPM_ContinueSelfTest to complete
+ * before reissuing the command C1." But, if ContinueSelfTest is
+ * non-blocking, how do we know that the actions have completed other than
+ * trying again? */
+ do {
+ result = TlclSendReceiveNoRetry(request, response, max_length);
+ } while (result == TPM_E_DOING_SELFTEST);
+#endif
+ }
+#endif /* ! defined(CHROMEOS_ENVIRONMENT) */
+ return result;
+}
+
+/* Sends a command and returns the error code. */
+static uint32_t Send(const uint8_t* command) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ return TlclSendReceive(command, response, sizeof(response));
+}
+
+/* Exported functions. */
+
+uint32_t TlclLibInit(void) {
+ return VbExTpmInit();
+}
+
+uint32_t TlclLibClose(void) {
+ return VbExTpmClose();
+}
+
+uint32_t TlclStartup(void) {
+ VBDEBUG(("TPM: Startup\n"));
+ return Send(tpm_startup_cmd.buffer);
+}
+
+uint32_t TlclSaveState(void) {
+ VBDEBUG(("TPM: SaveState\n"));
+ return Send(tpm_savestate_cmd.buffer);
+}
+
+uint32_t TlclResume(void) {
+ VBDEBUG(("TPM: Resume\n"));
+ return Send(tpm_resume_cmd.buffer);
+}
+
+uint32_t TlclSelfTestFull(void) {
+ VBDEBUG(("TPM: Self test full\n"));
+ return Send(tpm_selftestfull_cmd.buffer);
+}
+
+uint32_t TlclContinueSelfTest(void) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ VBDEBUG(("TPM: Continue self test\n"));
+ /* Call the No Retry version of SendReceive to avoid recursion. */
+ return TlclSendReceiveNoRetry(tpm_continueselftest_cmd.buffer,
+ response, sizeof(response));
+}
+
+uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
+ struct s_tpm_nv_definespace_cmd cmd;
+ VBDEBUG(("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size));
+ Memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.index, index);
+ ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm);
+ ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.size, size);
+ return Send(cmd.buffer);
+}
+
+uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length) {
+ struct s_tpm_nv_write_cmd cmd;
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ const int total_length =
+ kTpmRequestHeaderLength + kWriteInfoLength + length;
+
+ VBDEBUG(("TPM: TlclWrite(0x%x, %d)\n", index, length));
+ Memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd));
+ VbAssert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
+ SetTpmCommandSize(cmd.buffer, total_length);
+
+ ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.index, index);
+ ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.length, length);
+ Memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length);
+
+ return TlclSendReceive(cmd.buffer, response, sizeof(response));
+}
+
+uint32_t TlclRead(uint32_t index, void* data, uint32_t length) {
+ struct s_tpm_nv_read_cmd cmd;
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t result_length;
+ uint32_t result;
+
+ VBDEBUG(("TPM: TlclRead(0x%x, %d)\n", index, length));
+ Memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.index, index);
+ ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.length, length);
+
+ result = TlclSendReceive(cmd.buffer, response, sizeof(response));
+ if (result == TPM_SUCCESS && length > 0) {
+ uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength;
+ FromTpmUint32(nv_read_cursor, &result_length);
+ nv_read_cursor += sizeof(uint32_t);
+ Memcpy(data, nv_read_cursor, result_length);
+ }
+
+ return result;
+}
+
+uint32_t TlclPCRRead(uint32_t index, void* data, uint32_t length) {
+ struct s_tpm_pcr_read_cmd cmd;
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t result;
+
+ VBDEBUG(("TPM: TlclPCRRead(0x%x, %d)\n", index, length));
+ if (length < kPcrDigestLength) {
+ return TPM_E_IOERROR;
+ }
+ Memcpy(&cmd, &tpm_pcr_read_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_pcr_read_cmd.pcrNum, index);
+
+ result = TlclSendReceive(cmd.buffer, response, sizeof(response));
+ if (result == TPM_SUCCESS) {
+ uint8_t* pcr_read_cursor = response + kTpmResponseHeaderLength;
+ Memcpy(data, pcr_read_cursor, kPcrDigestLength);
+ }
+
+ return result;
+}
+
+uint32_t TlclWriteLock(uint32_t index) {
+ VBDEBUG(("TPM: Write lock 0x%x\n", index));
+ return TlclWrite(index, NULL, 0);
+}
+
+uint32_t TlclReadLock(uint32_t index) {
+ VBDEBUG(("TPM: Read lock 0x%x\n", index));
+ return TlclRead(index, NULL, 0);
+}
+
+uint32_t TlclAssertPhysicalPresence(void) {
+ VBDEBUG(("TPM: Asserting physical presence\n"));
+ return Send(tpm_ppassert_cmd.buffer);
+}
+
+uint32_t TlclPhysicalPresenceCMDEnable(void) {
+ VBDEBUG(("TPM: Enable the physical presence command\n"));
+ return Send(tpm_ppenable_cmd.buffer);
+}
+
+uint32_t TlclFinalizePhysicalPresence(void) {
+ VBDEBUG(("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n"));
+ return Send(tpm_finalizepp_cmd.buffer);
+}
+
+uint32_t TlclAssertPhysicalPresenceResult(void) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ return TlclSendReceive(tpm_ppassert_cmd.buffer, response, sizeof(response));
+}
+
+uint32_t TlclLockPhysicalPresence(void) {
+ VBDEBUG(("TPM: Lock physical presence\n"));
+ return Send(tpm_pplock_cmd.buffer);
+}
+
+uint32_t TlclSetNvLocked(void) {
+ VBDEBUG(("TPM: Set NV locked\n"));
+ return TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0);
+}
+
+int TlclIsOwned(void) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE];
+ uint32_t result;
+ result = TlclSendReceive(tpm_readpubek_cmd.buffer,
+ response, sizeof(response));
+ return (result != TPM_SUCCESS);
+}
+
+uint32_t TlclForceClear(void) {
+ VBDEBUG(("TPM: Force clear\n"));
+ return Send(tpm_forceclear_cmd.buffer);
+}
+
+uint32_t TlclSetEnable(void) {
+ VBDEBUG(("TPM: Enabling TPM\n"));
+ return Send(tpm_physicalenable_cmd.buffer);
+}
+
+uint32_t TlclClearEnable(void) {
+ VBDEBUG(("TPM: Disabling TPM\n"));
+ return Send(tpm_physicaldisable_cmd.buffer);
+}
+
+uint32_t TlclSetDeactivated(uint8_t flag) {
+ struct s_tpm_physicalsetdeactivated_cmd cmd;
+ VBDEBUG(("TPM: SetDeactivated(%d)\n", flag));
+ Memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd));
+ *(cmd.buffer + cmd.deactivated) = flag;
+ return Send(cmd.buffer);
+}
+
+uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t size;
+ uint32_t result =
+ TlclSendReceive(tpm_getflags_cmd.buffer, response, sizeof(response));
+ if (result != TPM_SUCCESS)
+ return result;
+ FromTpmUint32(response + kTpmResponseHeaderLength, &size);
+ /* TODO(crbug.com/379255): This fails. Find out why.
+ * VbAssert(size == sizeof(TPM_PERMANENT_FLAGS));
+ */
+ Memcpy(pflags,
+ response + kTpmResponseHeaderLength + sizeof(size),
+ sizeof(TPM_PERMANENT_FLAGS));
+ return result;
+}
+
+uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS* vflags) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t size;
+ uint32_t result =
+ TlclSendReceive(tpm_getstclearflags_cmd.buffer, response, sizeof(response));
+ if (result != TPM_SUCCESS)
+ return result;
+ FromTpmUint32(response + kTpmResponseHeaderLength, &size);
+ /* Ugly assertion, but the struct is padded up by one byte. */
+ /* TODO(crbug.com/379255): This fails. Find out why.
+ * VbAssert(size == 7 && sizeof(TPM_STCLEAR_FLAGS) - 1 == 7);
+ */
+ Memcpy(vflags,
+ response + kTpmResponseHeaderLength + sizeof(size),
+ sizeof(TPM_STCLEAR_FLAGS));
+ return result;
+}
+
+uint32_t TlclGetFlags(uint8_t* disable,
+ uint8_t* deactivated,
+ uint8_t *nvlocked) {
+ TPM_PERMANENT_FLAGS pflags;
+ uint32_t result = TlclGetPermanentFlags(&pflags);
+ if (result == TPM_SUCCESS) {
+ if (disable)
+ *disable = pflags.disable;
+ if (deactivated)
+ *deactivated = pflags.deactivated;
+ if (nvlocked)
+ *nvlocked = pflags.nvLocked;
+ VBDEBUG(("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n",
+ pflags.disable, pflags.deactivated, pflags.nvLocked));
+ }
+ return result;
+}
+
+uint32_t TlclSetGlobalLock(void) {
+ uint32_t x;
+ VBDEBUG(("TPM: Set global lock\n"));
+ return TlclWrite(TPM_NV_INDEX0, (uint8_t*) &x, 0);
+}
+
+uint32_t TlclExtend(int pcr_num, const uint8_t* in_digest,
+ uint8_t* out_digest) {
+ struct s_tpm_extend_cmd cmd;
+ uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength];
+ uint32_t result;
+
+ Memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
+ Memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
+
+ result = TlclSendReceive(cmd.buffer, response, sizeof(response));
+ if (result != TPM_SUCCESS)
+ return result;
+
+ Memcpy(out_digest, response + kTpmResponseHeaderLength, kPcrDigestLength);
+ return result;
+}
+
+uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) {
+ struct s_tpm_getpermissions_cmd cmd;
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint8_t* nvdata;
+ uint32_t result;
+ uint32_t size;
+
+ Memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_getpermissions_cmd.index, index);
+ result = TlclSendReceive(cmd.buffer, response, sizeof(response));
+ if (result != TPM_SUCCESS)
+ return result;
+
+ nvdata = response + kTpmResponseHeaderLength + sizeof(size);
+ FromTpmUint32(nvdata + kNvDataPublicPermissionsOffset, permissions);
+ return result;
+}
+
+uint32_t TlclGetOwnership(uint8_t* owned) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t size;
+ uint32_t result =
+ TlclSendReceive(tpm_getownership_cmd.buffer, response, sizeof(response));
+ if (result != TPM_SUCCESS)
+ return result;
+ FromTpmUint32(response + kTpmResponseHeaderLength, &size);
+ /* TODO(crbug.com/379255): This fails. Find out why.
+ * VbAssert(size == sizeof(*owned));
+ */
+ Memcpy(owned,
+ response + kTpmResponseHeaderLength + sizeof(size),
+ sizeof(*owned));
+ return result;
+}
+
+uint32_t TlclGetRandom(uint8_t* data, uint32_t length, uint32_t *size) {
+ struct s_tpm_get_random_cmd cmd;
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+ uint32_t result;
+
+ VBDEBUG(("TPM: TlclGetRandom(%d)\n", length));
+ Memcpy(&cmd, &tpm_get_random_cmd, sizeof(cmd));
+ ToTpmUint32(cmd.buffer + tpm_get_random_cmd.bytesRequested, length);
+ /* There must be room in the response buffer for the bytes. */
+ if (length > TPM_LARGE_ENOUGH_COMMAND_SIZE - kTpmResponseHeaderLength
+ - sizeof(uint32_t)) {
+ return TPM_E_IOERROR;
+ }
+
+ result = TlclSendReceive(cmd.buffer, response, sizeof(response));
+ if (result == TPM_SUCCESS) {
+ uint8_t* get_random_cursor;
+ FromTpmUint32(response + kTpmResponseHeaderLength, size);
+
+ /* There must be room in the target buffer for the bytes. */
+ if (*size > length) {
+ return TPM_E_RESPONSE_TOO_LARGE;
+ }
+ get_random_cursor = response + kTpmResponseHeaderLength
+ + sizeof(uint32_t);
+ Memcpy(data, get_random_cursor, *size);
+ }
+
+ return result;
+}
diff --git a/src/lib/tlcl_internal.h b/src/lib/tlcl_internal.h
new file mode 100644
index 0000000000..51fe6ef3f0
--- /dev/null
+++ b/src/lib/tlcl_internal.h
@@ -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.
+ */
+
+#ifndef TPM_LITE_TLCL_INTERNAL_H_
+#define TPM_LITE_TLCL_INTERNAL_H_
+
+/*
+ * These numbers derive from adding the sizes of command fields as shown in the
+ * TPM commands manual.
+ */
+#define kTpmRequestHeaderLength 10
+#define kTpmResponseHeaderLength 10
+#define kTpmReadInfoLength 12
+#define kEncAuthLength 20
+#define kPcrDigestLength 20
+
+
+/*
+ * Conversion functions. ToTpmTYPE puts a value of type TYPE into a TPM
+ * command buffer. FromTpmTYPE gets a value of type TYPE from a TPM command
+ * buffer into a variable.
+ */
+__attribute__((unused))
+static inline void ToTpmUint32(uint8_t *buffer, uint32_t x) {
+ buffer[0] = (uint8_t)(x >> 24);
+ buffer[1] = (uint8_t)((x >> 16) & 0xff);
+ buffer[2] = (uint8_t)((x >> 8) & 0xff);
+ buffer[3] = (uint8_t)(x & 0xff);
+}
+
+/*
+ * See comment for above function.
+ */
+__attribute__((unused))
+static inline void FromTpmUint32(const uint8_t *buffer, uint32_t *x) {
+ *x = ((buffer[0] << 24) |
+ (buffer[1] << 16) |
+ (buffer[2] << 8) |
+ buffer[3]);
+}
+
+/*
+ * See comment for above function.
+ */
+__attribute__((unused))
+static inline void ToTpmUint16(uint8_t *buffer, uint16_t x) {
+ buffer[0] = (uint8_t)(x >> 8);
+ buffer[1] = (uint8_t)(x & 0xff);
+}
+
+/*
+ * See comment for above function.
+ */
+__attribute__((unused))
+static inline void FromTpmUint16(const uint8_t *buffer, uint16_t *x) {
+ *x = (buffer[0] << 8) | buffer[1];
+}
+
+#endif /* TPM_LITE_TLCL_INTERNAL_H_ */
diff --git a/src/lib/tlcl_structures.h b/src/lib/tlcl_structures.h
new file mode 100644
index 0000000000..36c1bb9ed8
--- /dev/null
+++ b/src/lib/tlcl_structures.h
@@ -0,0 +1,138 @@
+/* This file is automatically generated */
+
+const struct s_tpm_extend_cmd{
+ uint8_t buffer[34];
+ uint16_t pcrNum;
+ uint16_t inDigest;
+} tpm_extend_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, },
+10, 14, };
+
+const struct s_tpm_get_random_cmd{
+ uint8_t buffer[14];
+ uint16_t bytesRequested;
+} tpm_get_random_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x46, },
+10, };
+
+const struct s_tpm_getownership_cmd{
+ uint8_t buffer[22];
+} tpm_getownership_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x11, },
+};
+
+const struct s_tpm_getpermissions_cmd{
+ uint8_t buffer[22];
+ uint16_t index;
+} tpm_getpermissions_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x4, },
+18, };
+
+const struct s_tpm_getstclearflags_cmd{
+ uint8_t buffer[22];
+} tpm_getstclearflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x9, },
+};
+
+const struct s_tpm_getflags_cmd{
+ uint8_t buffer[22];
+} tpm_getflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x8, },
+};
+
+const struct s_tpm_physicalsetdeactivated_cmd{
+ uint8_t buffer[11];
+ uint16_t deactivated;
+} tpm_physicalsetdeactivated_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, },
+10, };
+
+const struct s_tpm_physicalenable_cmd{
+ uint8_t buffer[10];
+} tpm_physicalenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, },
+};
+
+const struct s_tpm_physicaldisable_cmd{
+ uint8_t buffer[10];
+} tpm_physicaldisable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, },
+};
+
+const struct s_tpm_forceclear_cmd{
+ uint8_t buffer[10];
+} tpm_forceclear_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, },
+};
+
+const struct s_tpm_readpubek_cmd{
+ uint8_t buffer[30];
+} tpm_readpubek_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, },
+};
+
+const struct s_tpm_continueselftest_cmd{
+ uint8_t buffer[10];
+} tpm_continueselftest_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, },
+};
+
+const struct s_tpm_selftestfull_cmd{
+ uint8_t buffer[10];
+} tpm_selftestfull_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, },
+};
+
+const struct s_tpm_resume_cmd{
+ uint8_t buffer[12];
+} tpm_resume_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x2, },
+};
+
+const struct s_tpm_savestate_cmd{
+ uint8_t buffer[10];
+} tpm_savestate_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x98, },
+};
+
+const struct s_tpm_startup_cmd{
+ uint8_t buffer[12];
+} tpm_startup_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x1, },
+};
+
+const struct s_tpm_finalizepp_cmd{
+ uint8_t buffer[12];
+} tpm_finalizepp_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0, },
+};
+
+const struct s_tpm_pplock_cmd{
+ uint8_t buffer[12];
+} tpm_pplock_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x4, },
+};
+
+const struct s_tpm_ppenable_cmd{
+ uint8_t buffer[12];
+} tpm_ppenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x20, },
+};
+
+const struct s_tpm_ppassert_cmd{
+ uint8_t buffer[12];
+} tpm_ppassert_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x8, },
+};
+
+const struct s_tpm_pcr_read_cmd{
+ uint8_t buffer[14];
+ uint16_t pcrNum;
+} tpm_pcr_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, },
+10, };
+
+const struct s_tpm_nv_read_cmd{
+ uint8_t buffer[22];
+ uint16_t index;
+ uint16_t length;
+} tpm_nv_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, },
+10, 18, };
+
+const struct s_tpm_nv_write_cmd{
+ uint8_t buffer[256];
+ uint16_t index;
+ uint16_t length;
+ uint16_t data;
+} tpm_nv_write_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, },
+10, 18, 22, };
+
+const struct s_tpm_nv_definespace_cmd{
+ uint8_t buffer[101];
+ uint16_t index;
+ uint16_t perm;
+ uint16_t size;
+} tpm_nv_definespace_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x18, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x17, },
+12, 70, 77, };
+
+const int kWriteInfoLength = 12;
+const int kNvDataPublicPermissionsOffset = 60;
diff --git a/src/lib/tpm_error_messages.h b/src/lib/tpm_error_messages.h
new file mode 100644
index 0000000000..14cb86beae
--- /dev/null
+++ b/src/lib/tpm_error_messages.h
@@ -0,0 +1,250 @@
+/* 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.
+ */
+
+/* TPM error codes.
+ *
+ * Copy-pasted and lightly edited from TCG TPM Main Part 2 TPM Structures
+ * Version 1.2 Level 2 Revision 103 26 October 2006 Draft.
+ */
+
+#ifndef TPM_ERROR_MESSAGES_H
+#define TPM_ERROR_MESSAGES_H
+
+#define TPM_E_BASE 0x0
+#define TPM_E_NON_FATAL 0x800
+
+typedef struct tpm_error_info {
+ const char* name;
+ uint32_t code;
+ const char* description;
+} tpm_error_info;
+
+tpm_error_info tpm_error_table[] = {
+{ "TPM_AUTHFAIL", TPM_E_BASE + 1,
+"Authentication failed" },
+{ "TPM_BADINDEX", TPM_E_BASE + 2,
+"The index to a PCR, DIR or other register is incorrect" },
+{ "TPM_BAD_PARAMETER", TPM_E_BASE + 3,
+"One or more parameter is bad" },
+{ "TPM_AUDITFAILURE", TPM_E_BASE + 4,
+"An operation completed successfully\n\
+but the auditing of that operation failed" },
+{ "TPM_CLEAR_DISABLED", TPM_E_BASE + 5,
+"The clear disable flag is set and all clear operations now require\n\
+physical access" },
+{ "TPM_DEACTIVATED", TPM_E_BASE + 6,
+"The TPM is deactivated" },
+{ "TPM_DISABLED", TPM_E_BASE + 7,
+"The TPM is disabled" },
+{ "TPM_DISABLED_CMD", TPM_E_BASE + 8,
+"The target command has been disabled" },
+{ "TPM_FAIL", TPM_E_BASE + 9,
+"The operation failed" },
+{ "TPM_BAD_ORDINAL", TPM_E_BASE + 10,
+"The ordinal was unknown or inconsistent" },
+{ "TPM_INSTALL_DISABLED", TPM_E_BASE + 11,
+"The ability to install an owner is disabled" },
+{ "TPM_INVALID_KEYHANDLE", TPM_E_BASE + 12,
+"The key handle can not be interpreted" },
+{ "TPM_KEYNOTFOUND", TPM_E_BASE + 13,
+"The key handle points to an invalid key" },
+{ "TPM_INAPPROPRIATE_ENC", TPM_E_BASE + 14,
+"Unacceptable encryption scheme" },
+{ "TPM_MIGRATEFAIL", TPM_E_BASE + 15,
+"Migration authorization failed" },
+{ "TPM_INVALID_PCR_INFO", TPM_E_BASE + 16,
+"PCR information could not be interpreted" },
+{ "TPM_NOSPACE", TPM_E_BASE + 17,
+"No room to load key" },
+{ "TPM_NOSRK", TPM_E_BASE + 18,
+"There is no SRK set" },
+{ "TPM_NOTSEALED_BLOB", TPM_E_BASE + 19,
+"An encrypted blob is invalid or was not created by this TPM" },
+{ "TPM_OWNER_SET", TPM_E_BASE + 20,
+"There is already an Owner" },
+{ "TPM_RESOURCES", TPM_E_BASE + 21,
+"The TPM has insufficient internal resources to perform the requested action" },
+{ "TPM_SHORTRANDOM", TPM_E_BASE + 22,
+"A random string was too short" },
+{ "TPM_SIZE", TPM_E_BASE + 23,
+"The TPM does not have the space to perform the operation" },
+{ "TPM_WRONGPCRVAL", TPM_E_BASE + 24,
+"The named PCR value does not match the current PCR value" },
+{ "TPM_BAD_PARAM_SIZE", TPM_E_BASE + 25,
+"The paramSize argument to the command has the incorrect value" },
+{ "TPM_SHA_THREAD", TPM_E_BASE + 26,
+"There is no existing SHA-1 thread" },
+{ "TPM_SHA_ERROR", TPM_E_BASE + 27,
+"The calculation is unable to proceed because the existing SHA-1\n\
+thread has already encountered an error" },
+{ "TPM_FAILEDSELFTEST", TPM_E_BASE + 28,
+"Self-test has failed and the TPM has shutdown" },
+{ "TPM_AUTH2FAIL", TPM_E_BASE + 29,
+"The authorization for the second key in a 2 key function\n\
+failed authorization" },
+{ "TPM_BADTAG", TPM_E_BASE + 30,
+"The tag value sent to for a command is invalid" },
+{ "TPM_IOERROR", TPM_E_BASE + 31,
+"An IO error occurred transmitting information to the TPM" },
+{ "TPM_ENCRYPT_ERROR", TPM_E_BASE + 32,
+"The encryption process had a problem" },
+{ "TPM_DECRYPT_ERROR", TPM_E_BASE + 33,
+"The decryption process did not complete" },
+{ "TPM_INVALID_AUTHHANDLE", TPM_E_BASE + 34,
+"An invalid handle was used" },
+{ "TPM_NO_ENDORSEMENT", TPM_E_BASE + 35,
+"The TPM does not a EK installed" },
+{ "TPM_INVALID_KEYUSAGE", TPM_E_BASE + 36,
+"The usage of a key is not allowed" },
+{ "TPM_WRONG_ENTITYTYPE", TPM_E_BASE + 37,
+"The submitted entity type is not allowed" },
+{ "TPM_INVALID_POSTINIT", TPM_E_BASE + 38,
+"The command was received in the wrong sequence relative to TPM_Init\n\
+and a subsequent TPM_Startup" },
+{ "TPM_INAPPROPRIATE_SIG", TPM_E_BASE + 39,
+"Signed data cannot include additional DER information" },
+{ "TPM_BAD_KEY_PROPERTY", TPM_E_BASE + 40,
+"The key properties in TPM_KEY_PARMs are not supported by this TPM" },
+{ "TPM_BAD_MIGRATION", TPM_E_BASE + 41,
+"The migration properties of this key are incorrect" },
+{ "TPM_BAD_SCHEME", TPM_E_BASE + 42,
+"The signature or encryption scheme for this key is incorrect or not\n\
+permitted in this situation" },
+{ "TPM_BAD_DATASIZE", TPM_E_BASE + 43,
+"The size of the data (or blob) parameter is bad or inconsistent\n\
+with the referenced key" },
+{ "TPM_BAD_MODE", TPM_E_BASE + 44,
+"A mode parameter is bad, such as capArea or subCapArea for\n\
+TPM_GetCapability, physicalPresence parameter for TPM_PhysicalPresence,\n\
+or migrationType for, TPM_CreateMigrationBlob" },
+{ "TPM_BAD_PRESENCE", TPM_E_BASE + 45,
+"Either the physicalPresence or physicalPresenceLock bits\n\
+have the wrong value" },
+{ "TPM_BAD_VERSION", TPM_E_BASE + 46,
+"The TPM cannot perform this version of the capability" },
+{ "TPM_NO_WRAP_TRANSPORT", TPM_E_BASE + 47,
+"The TPM does not allow for wrapped transport sessions" },
+{ "TPM_AUDITFAIL_UNSUCCESSFUL", TPM_E_BASE + 48,
+"TPM audit construction failed and the underlying command\n\
+was returning a failure code also" },
+{ "TPM_AUDITFAIL_SUCCESSFUL", TPM_E_BASE + 49,
+"TPM audit construction failed and the underlying command\n\
+was returning success" },
+{ "TPM_NOTRESETABLE", TPM_E_BASE + 50,
+"Attempt to reset a PCR register that does not have the resettable attribute" },
+{ "TPM_NOTLOCAL", TPM_E_BASE + 51,
+"Attempt to reset a PCR register that requires locality\n\
+and locality modifier not part of command transport" },
+{ "TPM_BAD_TYPE", TPM_E_BASE + 52,
+"Make identity blob not properly typed" },
+{ "TPM_INVALID_RESOURCE", TPM_E_BASE + 53,
+"When saving context identified resource type does not match actual resource" },
+{ "TPM_NOTFIPS", TPM_E_BASE + 54,
+"The TPM is attempting to execute a command only available when in FIPS mode" },
+{ "TPM_INVALID_FAMILY", TPM_E_BASE + 55,
+"The command is attempting to use an invalid family ID" },
+{ "TPM_NO_NV_PERMISSION", TPM_E_BASE + 56,
+"The permission to manipulate the NV storage is not available" },
+{ "TPM_REQUIRES_SIGN", TPM_E_BASE + 57,
+"The operation requires a signed command" },
+{ "TPM_KEY_NOTSUPPORTED", TPM_E_BASE + 58,
+"Wrong operation to load an NV key" },
+{ "TPM_AUTH_CONFLICT", TPM_E_BASE + 59,
+"NV_LoadKey blob requires both owner and blob authorization" },
+{ "TPM_AREA_LOCKED", TPM_E_BASE + 60,
+"The NV area is locked and not writable" },
+{ "TPM_BAD_LOCALITY", TPM_E_BASE + 61,
+"The locality is incorrect for the attempted operation" },
+{ "TPM_READ_ONLY", TPM_E_BASE + 62,
+"The NV area is read only and canât be written to" },
+{ "TPM_PER_NOWRITE", TPM_E_BASE + 63,
+"There is no protection on the write to the NV area" },
+{ "TPM_FAMILYCOUNT", TPM_E_BASE + 64,
+"The family count value does not match" },
+{ "TPM_WRITE_LOCKED", TPM_E_BASE + 65,
+"The NV area has already been written to" },
+{ "TPM_BAD_ATTRIBUTES", TPM_E_BASE + 66,
+"The NV area attributes conflict" },
+{ "TPM_INVALID_STRUCTURE", TPM_E_BASE + 67,
+"The structure tag and version are invalid or inconsistent" },
+{ "TPM_KEY_OWNER_CONTROL", TPM_E_BASE + 68,
+"The key is under control of the TPM Owner and can only be evicted\n\
+by the TPM Owner" },
+{ "TPM_BAD_COUNTER", TPM_E_BASE + 69,
+"The counter handle is incorrect" },
+{ "TPM_NOT_FULLWRITE", TPM_E_BASE + 70,
+"The write is not a complete write of the area" },
+{ "TPM_CONTEXT_GAP", TPM_E_BASE + 71,
+"The gap between saved context counts is too large" },
+{ "TPM_MAXNVWRITES", TPM_E_BASE + 72,
+"The maximum number of NV writes without an owner has been exceeded" },
+{ "TPM_NOOPERATOR", TPM_E_BASE + 73,
+"No operator AuthData value is set" },
+{ "TPM_RESOURCEMISSING", TPM_E_BASE + 74,
+"The resource pointed to by context is not loaded" },
+{ "TPM_DELEGATE_LOCK", TPM_E_BASE + 75,
+"The delegate administration is locked" },
+{ "TPM_DELEGATE_FAMILY", TPM_E_BASE + 76,
+"Attempt to manage a family other then the delegated family" },
+{ "TPM_DELEGATE_ADMIN", TPM_E_BASE + 77,
+"Delegation table management not enabled" },
+{ "TPM_TRANSPORT_NOTEXCLUSIVE", TPM_E_BASE + 78,
+"There was a command executed outside of an exclusive transport session" },
+{ "TPM_OWNER_CONTROL", TPM_E_BASE + 79,
+"Attempt to context save a owner evict controlled key" },
+{ "TPM_DAA_RESOURCES", TPM_E_BASE + 80,
+"The DAA command has no resources available to execute the command" },
+{ "TPM_DAA_INPUT_DATA0", TPM_E_BASE + 81,
+"The consistency check on DAA parameter inputData0 has failed" },
+{ "TPM_DAA_INPUT_DATA1", TPM_E_BASE + 82,
+"The consistency check on DAA parameter inputData1 has failed" },
+{ "TPM_DAA_ISSUER_SETTINGS", TPM_E_BASE + 83,
+"The consistency check on DAA_issuerSettings has failed" },
+{ "TPM_DAA_TPM_SETTINGS", TPM_E_BASE + 84,
+"The consistency check on DAA_tpmSpecific has failed" },
+{ "TPM_DAA_STAGE", TPM_E_BASE + 85,
+"The atomic process indicated by the submitted DAA command is not\n\
+the expected process" },
+{ "TPM_DAA_ISSUER_VALIDITY", TPM_E_BASE + 86,
+"The issuerâs validity check has detected an inconsistency" },
+{ "TPM_DAA_WRONG_W", TPM_E_BASE + 87,
+"The consistency check on w has failed" },
+{ "TPM_BAD_HANDLE", TPM_E_BASE + 88,
+"The handle is incorrect" },
+{ "TPM_BAD_DELEGATE", TPM_E_BASE + 89,
+"Delegation is not correct" },
+{ "TPM_BADCONTEXT", TPM_E_BASE + 90,
+"The context blob is invalid" },
+{ "TPM_TOOMANYCONTEXTS", TPM_E_BASE + 91,
+"Too many contexts held by the TPM" },
+{ "TPM_MA_TICKET_SIGNATURE", TPM_E_BASE + 92,
+"Migration authority signature validation failure" },
+{ "TPM_MA_DESTINATION", TPM_E_BASE + 93,
+"Migration destination not authenticated" },
+{ "TPM_MA_SOURCE", TPM_E_BASE + 94,
+"Migration source incorrect" },
+{ "TPM_MA_AUTHORITY", TPM_E_BASE + 95,
+"Incorrect migration authority" },
+{ "TPM_PERMANENTEK", TPM_E_BASE + 97,
+"Attempt to revoke the EK and the EK is not revocable" },
+{ "TPM_BAD_SIGNATURE", TPM_E_BASE + 98,
+"Bad signature of CMK ticket" },
+{ "TPM_NOCONTEXTSPACE", TPM_E_BASE + 99,
+"There is no room in the context list for additional contexts" },
+{ "TPM_RETRY", TPM_E_BASE + TPM_E_NON_FATAL,
+"The TPM is too busy to respond to the command immediately, but\n\
+the command could be resubmitted at a later time. The TPM MAY\n\
+return TPM_RETRY for any command at any time" },
+{ "TPM_NEEDS_SELFTEST", TPM_E_BASE + TPM_E_NON_FATAL + 1,
+"TPM_ContinueSelfTest has not been run" },
+{ "TPM_DOING_SELFTEST", TPM_E_BASE + TPM_E_NON_FATAL + 2,
+"The TPM is currently executing the actions of TPM_ContinueSelfTest\n\
+because the ordinal required resources that have not been tested" },
+{ "TPM_DEFEND_LOCK_RUNNING", TPM_E_BASE + TPM_E_NON_FATAL + 3,
+"The TPM is defending against dictionary attacks and is in some\n\
+time-out period" },
+ };
+
+#endif /* TPM_ERROR_MESSAGES_H */
diff --git a/src/vendorcode/google/chromeos/antirollback.c b/src/vendorcode/google/chromeos/antirollback.c
new file mode 100644
index 0000000000..306e90329b
--- /dev/null
+++ b/src/vendorcode/google/chromeos/antirollback.c
@@ -0,0 +1,676 @@
+/* Copyright (c) 2013 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 "sysincludes.h"
+
+#include "crc8.h"
+#include "rollback_index.h"
+#include "tlcl.h"
+#include "tss_constants.h"
+#include "utility.h"
+#include "vboot_api.h"
+
+#ifndef offsetof
+#define offsetof(A,B) __builtin_offsetof(A,B)
+#endif
+
+/*
+ * Provide protoypes for functions not in the header file. These prototypes
+ * fix -Wmissing-prototypes warnings.
+ */
+uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf);
+uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf);
+uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk);
+uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk);
+
+#ifdef FOR_TEST
+/*
+ * Compiling for unit test, so we need the real implementations of
+ * rollback functions. The unit test mocks the underlying tlcl
+ * functions, so this is ok to run on the host.
+ */
+#undef CHROMEOS_ENVIRONMENT
+#undef DISABLE_ROLLBACK_TPM
+#endif
+
+#define RETURN_ON_FAILURE(tpm_command) do { \
+ uint32_t result_; \
+ if ((result_ = (tpm_command)) != TPM_SUCCESS) { \
+ VBDEBUG(("Rollback: %08x returned by " #tpm_command \
+ "\n", (int)result_)); \
+ return result_; \
+ } \
+ } while (0)
+
+
+uint32_t TPMClearAndReenable(void)
+{
+ VBDEBUG(("TPM: Clear and re-enable\n"));
+ RETURN_ON_FAILURE(TlclForceClear());
+ RETURN_ON_FAILURE(TlclSetEnable());
+ RETURN_ON_FAILURE(TlclSetDeactivated(0));
+
+ return TPM_SUCCESS;
+}
+
+uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length)
+{
+ uint32_t result = TlclWrite(index, data, length);
+ if (result == TPM_E_MAXNVWRITES) {
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ return TlclWrite(index, data, length);
+ } else {
+ return result;
+ }
+}
+
+uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
+{
+ uint32_t result = TlclDefineSpace(index, perm, size);
+ if (result == TPM_E_MAXNVWRITES) {
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ return TlclDefineSpace(index, perm, size);
+ } else {
+ return result;
+ }
+}
+
+/* Functions to read and write firmware and kernel spaces. */
+uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf)
+{
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(FIRMWARE_NV_INDEX, rsf,
+ sizeof(RollbackSpaceFirmware));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /*
+ * No CRC in this version, so we'll create one when we write
+ * it. Note that we're marking this as version 2, not
+ * ROLLBACK_SPACE_FIRMWARE_VERSION, because version 2 just
+ * added the CRC. Later versions will need to set default
+ * values for any extra fields explicitly (probably here).
+ */
+ if (rsf->struct_version < 2) {
+ /* Danger Will Robinson! Danger! */
+ rsf->struct_version = 2;
+ return TPM_SUCCESS;
+ }
+
+ /*
+ * If the CRC is good, we're done. If it's bad, try a couple
+ * more times to see if it gets better before we give up. It
+ * could just be noise.
+ */
+ if (rsf->crc8 == Crc8(rsf,
+ offsetof(RollbackSpaceFirmware, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
+}
+
+uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf)
+{
+ RollbackSpaceFirmware rsf2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsf->struct_version < 2)
+ rsf->struct_version = 2;
+ rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(FIRMWARE_NV_INDEX, rsf,
+ sizeof(RollbackSpaceFirmware));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
+}
+
+uint32_t SetVirtualDevMode(int val)
+{
+ RollbackSpaceFirmware rsf;
+
+ VBDEBUG(("TPM: Entering %s()\n", __func__));
+ if (TPM_SUCCESS != ReadSpaceFirmware(&rsf))
+ return VBERROR_TPM_FIRMWARE_SETUP;
+
+ VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags));
+ if (val)
+ rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON;
+ else
+ rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ /*
+ * NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That
+ * will be done by SetupTPM() on the next boot.
+ */
+ VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
+
+ if (TPM_SUCCESS != WriteSpaceFirmware(&rsf))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+
+ VBDEBUG(("TPM: Leaving %s()\n", __func__));
+ return VBERROR_SUCCESS;
+}
+
+uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk)
+{
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /*
+ * No CRC in this version, so we'll create one when we write
+ * it. Note that we're marking this as version 2, not
+ * ROLLBACK_SPACE_KERNEL_VERSION, because version 2 just added
+ * the CRC. Later versions will need to set default values for
+ * any extra fields explicitly (probably here).
+ */
+ if (rsk->struct_version < 2) {
+ /* Danger Will Robinson! Danger! */
+ rsk->struct_version = 2;
+ return TPM_SUCCESS;
+ }
+
+ /*
+ * If the CRC is good, we're done. If it's bad, try a couple
+ * more times to see if it gets better before we give up. It
+ * could just be noise.
+ */
+ if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
+}
+
+uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk)
+{
+ RollbackSpaceKernel rsk2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsk->struct_version < 2)
+ rsk->struct_version = 2;
+ rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(KERNEL_NV_INDEX, rsk,
+ sizeof(RollbackSpaceKernel));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceKernel(&rsk2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
+}
+
+uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
+ RollbackSpaceKernel *rsk)
+{
+ static const RollbackSpaceFirmware rsf_init = {
+ .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
+ };
+ static const RollbackSpaceKernel rsk_init = {
+ .struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
+ .uid = ROLLBACK_SPACE_KERNEL_UID,
+ };
+ TPM_PERMANENT_FLAGS pflags;
+ uint32_t result;
+
+ VBDEBUG(("TPM: One-time initialization\n"));
+
+ /*
+ * Do a full test. This only happens the first time the device is
+ * turned on in the factory, so performance is not an issue. This is
+ * almost certainly not necessary, but it gives us more confidence
+ * about some code paths below that are difficult to
+ * test---specifically the ones that set lifetime flags, and are only
+ * executed once per physical TPM.
+ */
+ result = TlclSelfTestFull();
+ if (result != TPM_SUCCESS)
+ return result;
+
+ result = TlclGetPermanentFlags(&pflags);
+ if (result != TPM_SUCCESS)
+ return result;
+
+ /*
+ * TPM may come from the factory without physical presence finalized.
+ * Fix if necessary.
+ */
+ VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
+ pflags.physicalPresenceLifetimeLock));
+ if (!pflags.physicalPresenceLifetimeLock) {
+ VBDEBUG(("TPM: Finalizing physical presence\n"));
+ RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
+ }
+
+ /*
+ * The TPM will not enforce the NV authorization restrictions until the
+ * execution of a TPM_NV_DefineSpace with the handle of
+ * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already
+ * exist. */
+ VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
+ if (!pflags.nvLocked) {
+ VBDEBUG(("TPM: Enabling NV locking\n"));
+ RETURN_ON_FAILURE(TlclSetNvLocked());
+ }
+
+ /* Clear TPM owner, in case the TPM is already owned for some reason. */
+ VBDEBUG(("TPM: Clearing owner\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+
+ /* Initializes the firmware and kernel spaces */
+ Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
+ Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
+
+ /* Define the backup space. No need to initialize it, though. */
+ RETURN_ON_FAILURE(SafeDefineSpace(
+ BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE));
+
+ /* Define and initialize the kernel space */
+ RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
+ sizeof(RollbackSpaceKernel)));
+ RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
+
+ /* Do the firmware space last, so we retry if we don't get this far. */
+ RETURN_ON_FAILURE(SafeDefineSpace(
+ FIRMWARE_NV_INDEX,
+ TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
+ sizeof(RollbackSpaceFirmware)));
+ RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
+
+ return TPM_SUCCESS;
+}
+
+
+/*
+ * SetupTPM starts the TPM and establishes the root of trust for the
+ * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
+ * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
+ * general we cannot easily distinguish the kind of failure, so our strategy is
+ * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
+ * again, which executes (almost) the same sequence of operations. There is a
+ * good chance that, if recovery mode was entered because of a TPM failure, the
+ * failure will repeat itself. (In general this is impossible to guarantee
+ * because we have no way of creating the exact TPM initial state at the
+ * previous boot.) In recovery mode, we ignore the failure and continue, thus
+ * giving the recovery kernel a chance to fix things (that's why we don't set
+ * bGlobalLock). The choice is between a knowingly insecure device and a
+ * bricked device.
+ *
+ * As a side note, observe that we go through considerable hoops to avoid using
+ * the STCLEAR permissions for the index spaces. We do this to avoid writing
+ * to the TPM flashram at every reboot or wake-up, because of concerns about
+ * the durability of the NVRAM.
+ */
+uint32_t SetupTPM(int developer_mode, int disable_dev_request,
+ int clear_tpm_owner_request, RollbackSpaceFirmware* rsf)
+{
+ uint8_t in_flags;
+ uint8_t disable;
+ uint8_t deactivated;
+ uint32_t result;
+ uint32_t versions;
+
+ RETURN_ON_FAILURE(TlclLibInit());
+
+#ifdef TEGRA_SOFT_REBOOT_WORKAROUND
+ result = TlclStartup();
+ if (result == TPM_E_INVALID_POSTINIT) {
+ /*
+ * Some prototype hardware doesn't reset the TPM on a CPU
+ * reset. We do a hard reset to get around this.
+ */
+ VBDEBUG(("TPM: soft reset detected\n", result));
+ return TPM_E_MUST_REBOOT;
+ } else if (result != TPM_SUCCESS) {
+ VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
+ return result;
+ }
+#else
+ RETURN_ON_FAILURE(TlclStartup());
+#endif
+
+ /*
+ * Some TPMs start the self test automatically at power on. In that case we
+ * don't need to call ContinueSelfTest. On some (other) TPMs,
+ * ContinueSelfTest may block. In that case, we definitely don't want to
+ * call it here. For TPMs in the intersection of these two sets, we're
+ * screwed. (In other words: TPMs that require manually starting the
+ * self-test AND block will have poor performance until we split
+ * TlclSendReceive() into Send() and Receive(), and have a state machine to
+ * control setup.)
+ *
+ * This comment is likely to become obsolete in the near future, so don't
+ * trust it. It may have not been updated.
+ */
+#ifdef TPM_MANUAL_SELFTEST
+#ifdef TPM_BLOCKING_CONTINUESELFTEST
+#warning "lousy TPM!"
+#endif
+ RETURN_ON_FAILURE(TlclContinueSelfTest());
+#endif
+ result = TlclAssertPhysicalPresence();
+ if (result != TPM_SUCCESS) {
+ /*
+ * It is possible that the TPM was delivered with the physical
+ * presence command disabled. This tries enabling it, then
+ * tries asserting PP again.
+ */
+ RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
+ RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
+ }
+
+ /* Check that the TPM is enabled and activated. */
+ RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
+ if (disable || deactivated) {
+ VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
+ disable, deactivated));
+ RETURN_ON_FAILURE(TlclSetEnable());
+ RETURN_ON_FAILURE(TlclSetDeactivated(0));
+ VBDEBUG(("TPM: Must reboot to re-enable\n"));
+ return TPM_E_MUST_REBOOT;
+ }
+
+ /* Read the firmware space. */
+ result = ReadSpaceFirmware(rsf);
+ if (TPM_E_BADINDEX == result) {
+ RollbackSpaceKernel rsk;
+
+ /*
+ * This is the first time we've run, and the TPM has not been
+ * initialized. Initialize it.
+ */
+ VBDEBUG(("TPM: Not initialized yet.\n"));
+ RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
+ } else if (TPM_SUCCESS != result) {
+ VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
+ return TPM_E_CORRUPTED_STATE;
+ }
+ Memcpy(&versions, &rsf->fw_versions, sizeof(versions));
+ VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
+ rsf->struct_version, rsf->flags, versions));
+ in_flags = rsf->flags;
+
+ /* If we've been asked to clear the virtual dev-mode flag, do so now */
+ if (disable_dev_request) {
+ rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
+ }
+
+ /*
+ * The developer_mode value that's passed in is only set by a hardware
+ * dev-switch. We should OR it with the virtual switch, whether or not
+ * the virtual switch is used. If it's not used, it shouldn't change,
+ * so it doesn't matter.
+ */
+ if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
+ developer_mode = 1;
+
+ /*
+ * Clear ownership if developer flag has toggled, or if an owner-clear
+ * has been requested.
+ */
+ if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
+ (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
+ VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ } else if (clear_tpm_owner_request) {
+ VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ }
+
+ if (developer_mode)
+ rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
+ else
+ rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
+
+
+ /* If firmware space is dirty, flush it back to the TPM */
+ if (rsf->flags != in_flags) {
+ VBDEBUG(("TPM: Updating firmware space.\n"));
+ RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
+ }
+
+ VBDEBUG(("TPM: SetupTPM() succeeded\n"));
+ return TPM_SUCCESS;
+}
+
+
+#ifdef DISABLE_ROLLBACK_TPM
+/* Dummy implementations which don't support TPM rollback protection */
+
+uint32_t RollbackS3Resume(void)
+{
+#ifndef CHROMEOS_ENVIRONMENT
+ /*
+ * Initialize the TPM, but ignore return codes. In ChromeOS
+ * environment, don't even talk to the TPM.
+ */
+ TlclLibInit();
+ TlclResume();
+#endif
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackFirmwareSetup(int is_hw_dev,
+ int disable_dev_request,
+ int clear_tpm_owner_request,
+ int *is_virt_dev, uint32_t *version)
+{
+#ifndef CHROMEOS_ENVIRONMENT
+ /*
+ * Initialize the TPM, but ignores return codes. In ChromeOS
+ * environment, don't even talk to the TPM.
+ */
+ TlclLibInit();
+ TlclStartup();
+ TlclContinueSelfTest();
+#endif
+ *is_virt_dev = 0;
+ *version = 0;
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackFirmwareWrite(uint32_t version)
+{
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackFirmwareLock(void)
+{
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackKernelRead(uint32_t* version)
+{
+ *version = 0;
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackKernelWrite(uint32_t version)
+{
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackBackupRead(uint8_t *raw)
+{
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackBackupWrite(uint8_t *raw)
+{
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackKernelLock(int recovery_mode)
+{
+ return TPM_SUCCESS;
+}
+
+#else
+
+uint32_t RollbackS3Resume(void)
+{
+ uint32_t result;
+ RETURN_ON_FAILURE(TlclLibInit());
+ result = TlclResume();
+ if (result == TPM_E_INVALID_POSTINIT) {
+ /*
+ * We're on a platform where the TPM maintains power in S3, so
+ * it's already initialized.
+ */
+ return TPM_SUCCESS;
+ }
+ return result;
+}
+
+uint32_t RollbackFirmwareSetup(int is_hw_dev,
+ int disable_dev_request,
+ int clear_tpm_owner_request,
+ int *is_virt_dev, uint32_t *version)
+{
+ RollbackSpaceFirmware rsf;
+
+ /* Set version to 0 in case we fail */
+ *version = 0;
+
+ RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request,
+ clear_tpm_owner_request, &rsf));
+ Memcpy(version, &rsf.fw_versions, sizeof(*version));
+ *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
+ VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version));
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackFirmwareWrite(uint32_t version)
+{
+ RollbackSpaceFirmware rsf;
+ uint32_t old_version;
+
+ RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
+ Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version));
+ VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version,
+ (int)version));
+ Memcpy(&rsf.fw_versions, &version, sizeof(version));
+ return WriteSpaceFirmware(&rsf);
+}
+
+uint32_t RollbackFirmwareLock(void)
+{
+ return TlclSetGlobalLock();
+}
+
+uint32_t RollbackKernelRead(uint32_t* version)
+{
+ RollbackSpaceKernel rsk;
+ uint32_t perms, uid;
+
+ /*
+ * Read the kernel space and verify its permissions. If the kernel
+ * space has the wrong permission, or it doesn't contain the right
+ * identifier, we give up. This will need to be fixed by the
+ * recovery kernel. We have to worry about this because at any time
+ * (even with PP turned off) the TPM owner can remove and redefine a
+ * PP-protected space (but not write to it).
+ */
+ RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
+ RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms));
+ Memcpy(&uid, &rsk.uid, sizeof(uid));
+ if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != uid)
+ return TPM_E_CORRUPTED_STATE;
+
+ Memcpy(version, &rsk.kernel_versions, sizeof(*version));
+ VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)*version));
+ return TPM_SUCCESS;
+}
+
+uint32_t RollbackKernelWrite(uint32_t version)
+{
+ RollbackSpaceKernel rsk;
+ uint32_t old_version;
+ RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
+ Memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version));
+ VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n",
+ (int)old_version, (int)version));
+ Memcpy(&rsk.kernel_versions, &version, sizeof(version));
+ return WriteSpaceKernel(&rsk);
+}
+
+/*
+ * We don't really care whether the TPM owner has been messing with this or
+ * not. We lock it along with the Kernel space just to avoid problems, but it's
+ * only useful in dev-mode and only when the battery has been drained
+ * completely. There aren't any security issues. It's just in the TPM because
+ * we don't have any other place to keep it.
+ */
+uint32_t RollbackBackupRead(uint8_t *raw)
+{
+ uint32_t r;
+ r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
+ VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
+ return r;
+}
+
+uint32_t RollbackBackupWrite(uint8_t *raw)
+{
+ uint32_t r;
+ r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
+ VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
+ return r;
+}
+
+uint32_t RollbackKernelLock(int recovery_mode)
+{
+ if (recovery_mode)
+ return TPM_SUCCESS;
+ else
+ return TlclLockPhysicalPresence();
+}
+
+#endif /* DISABLE_ROLLBACK_TPM */