security/tpm: Move tpm TSS and TSPI layer to security section
* Move code from src/lib and src/include into src/security/tpm * Split TPM TSS 1.2 and 2.0 * Fix header includes * Add a new directory structure with kconfig and makefile includes Change-Id: Id15a9aa6bd367560318dfcfd450bf5626ea0ec2b Signed-off-by: Philipp Deppenwiese <zaolin@das-labor.org> Reviewed-on: https://review.coreboot.org/22103 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
committed by
Stefan Reinauer
parent
4fef7818ec
commit
64e2d19082
@@ -53,16 +53,6 @@ verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
|
||||
verstage-y += boot_device.c
|
||||
verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c
|
||||
|
||||
verstage-$(CONFIG_TPM) += tlcl.c
|
||||
verstage-$(CONFIG_TPM2) += tpm2_marshaling.c
|
||||
verstage-$(CONFIG_TPM2) += tpm2_tlcl.c
|
||||
|
||||
ifeq ($(CONFIG_VBOOT_SEPARATE_VERSTAGE),y)
|
||||
romstage-$(CONFIG_TPM) += tlcl.c
|
||||
romstage-$(CONFIG_TPM2) += tpm2_marshaling.c
|
||||
romstage-$(CONFIG_TPM2) += tpm2_tlcl.c
|
||||
endif # CONFIG_VBOOT_SEPARATE_VERSTAGE
|
||||
|
||||
verstage-$(CONFIG_GENERIC_UDELAY) += timer.c
|
||||
verstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
|
||||
|
||||
@@ -144,8 +134,6 @@ ramstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
|
||||
ramstage-$(CONFIG_GENERIC_UDELAY) += timer.c
|
||||
ramstage-y += b64_decode.c
|
||||
ramstage-$(CONFIG_ACPI_NHLT) += nhlt.c
|
||||
ramstage-$(CONFIG_TPM2) += tpm2_marshaling.c
|
||||
ramstage-$(CONFIG_TPM2) += tpm2_tlcl.c
|
||||
|
||||
romstage-y += cbmem_common.c
|
||||
romstage-y += imd_cbmem.c
|
||||
|
353
src/lib/tlcl.c
353
src/lib/tlcl.c
@@ -1,353 +0,0 @@
|
||||
/* 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 <arch/early_variables.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <tpm_lite/tlcl.h>
|
||||
#include <tpm.h>
|
||||
#include <vb2_api.h>
|
||||
#include "tlcl_internal.h"
|
||||
#include "tlcl_structures.h"
|
||||
|
||||
#ifdef FOR_TEST
|
||||
#include <stdio.h>
|
||||
#define VBDEBUG(format, args...) printf(format, ## args)
|
||||
#else
|
||||
#include <console/console.h>
|
||||
#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args)
|
||||
#endif
|
||||
|
||||
static int tpm_send_receive(const uint8_t *request,
|
||||
uint32_t request_length,
|
||||
uint8_t *response,
|
||||
uint32_t *response_length)
|
||||
{
|
||||
size_t len = *response_length;
|
||||
if (tis_sendrecv(request, request_length, response, &len))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
/* check 64->32bit overflow and (re)check response buffer overflow */
|
||||
if (len > *response_length)
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
*response_length = len;
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/* Sets the size field of a TPM command. */
|
||||
static inline void set_tpm_command_size(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
to_tpm_uint32(buffer + sizeof(uint16_t), size);
|
||||
}
|
||||
|
||||
/* Gets the size field of a TPM command. */
|
||||
__attribute__((unused))
|
||||
static inline int tpm_command_size(const uint8_t *buffer)
|
||||
{
|
||||
uint32_t size;
|
||||
from_tpm_uint32(buffer + sizeof(uint16_t), &size);
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
/* Gets the code field of a TPM command. */
|
||||
static inline int tpm_command_code(const uint8_t *buffer)
|
||||
{
|
||||
uint32_t code;
|
||||
from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Gets the return code field of a TPM result. */
|
||||
static inline int tpm_return_code(const uint8_t *buffer)
|
||||
{
|
||||
return tpm_command_code(buffer);
|
||||
}
|
||||
|
||||
/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or
|
||||
* DOING_SELFTEST errors are returned.
|
||||
*/
|
||||
static uint32_t tlcl_send_receive_no_retry(const uint8_t *request,
|
||||
uint8_t *response, int max_length)
|
||||
{
|
||||
uint32_t response_length = max_length;
|
||||
uint32_t result;
|
||||
|
||||
result = tpm_send_receive(request, tpm_command_size(request),
|
||||
response, &response_length);
|
||||
if (result != 0) {
|
||||
/* Communication with TPM failed, so response is garbage */
|
||||
VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n",
|
||||
tpm_command_code(request), result);
|
||||
return result;
|
||||
}
|
||||
/* Otherwise, use the result code from the response */
|
||||
result = tpm_return_code(response);
|
||||
|
||||
/* TODO: add paranoia about returned response_length vs. max_length
|
||||
* (and possibly expected length from the response header). See
|
||||
* crosbug.com/17017 */
|
||||
|
||||
VBDEBUG("TPM: command 0x%x returned 0x%x\n",
|
||||
tpm_command_code(request), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Sends a TPM command and gets a response. Returns 0 if success or the TPM
|
||||
* error code if error. Waits for the self test to complete if needed. */
|
||||
uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response,
|
||||
int max_length)
|
||||
{
|
||||
uint32_t result = tlcl_send_receive_no_retry(request, response,
|
||||
max_length);
|
||||
/* 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 = tlcl_continue_self_test();
|
||||
if (result != TPM_SUCCESS)
|
||||
return result;
|
||||
#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE)
|
||||
/* Retry only once */
|
||||
result = tlcl_send_receive_no_retry(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 = tlcl_send_receive_no_retry(request, response,
|
||||
max_length);
|
||||
} while (result == TPM_E_DOING_SELFTEST);
|
||||
#endif
|
||||
}
|
||||
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 tlcl_send_receive(command, response, sizeof(response));
|
||||
}
|
||||
|
||||
/* Exported functions. */
|
||||
|
||||
static uint8_t tlcl_init_done CAR_GLOBAL;
|
||||
|
||||
uint32_t tlcl_lib_init(void)
|
||||
{
|
||||
uint8_t done = car_get_var(tlcl_init_done);
|
||||
if (done)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
if (tis_init())
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
if (tis_open())
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
car_set_var(tlcl_init_done, 1);
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_startup(void)
|
||||
{
|
||||
VBDEBUG("TPM: Startup\n");
|
||||
return send(tpm_startup_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_resume(void)
|
||||
{
|
||||
VBDEBUG("TPM: Resume\n");
|
||||
return send(tpm_resume_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_self_test_full(void)
|
||||
{
|
||||
VBDEBUG("TPM: Self test full\n");
|
||||
return send(tpm_selftestfull_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_continue_self_test(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 tlcl_send_receive_no_retry(tpm_continueselftest_cmd.buffer,
|
||||
response, sizeof(response));
|
||||
}
|
||||
|
||||
uint32_t tlcl_define_space(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));
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.index, index);
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm);
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.size, size);
|
||||
return send(cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_write(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: tlcl_write(0x%x, %d)\n", index, length);
|
||||
memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd));
|
||||
assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
|
||||
set_tpm_command_size(cmd.buffer, total_length);
|
||||
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.index, index);
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.length, length);
|
||||
memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length);
|
||||
|
||||
return tlcl_send_receive(cmd.buffer, response, sizeof(response));
|
||||
}
|
||||
|
||||
uint32_t tlcl_read(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: tlcl_read(0x%x, %d)\n", index, length);
|
||||
memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd));
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.index, index);
|
||||
to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.length, length);
|
||||
|
||||
result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
|
||||
if (result == TPM_SUCCESS && length > 0) {
|
||||
uint8_t *nv_read_cursor = response + kTpmResponseHeaderLength;
|
||||
from_tpm_uint32(nv_read_cursor, &result_length);
|
||||
nv_read_cursor += sizeof(uint32_t);
|
||||
memcpy(data, nv_read_cursor, result_length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint32_t tlcl_assert_physical_presence(void)
|
||||
{
|
||||
VBDEBUG("TPM: Asserting physical presence\n");
|
||||
return send(tpm_ppassert_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_physical_presence_cmd_enable(void)
|
||||
{
|
||||
VBDEBUG("TPM: Enable the physical presence command\n");
|
||||
return send(tpm_ppenable_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_finalize_physical_presence(void)
|
||||
{
|
||||
VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n");
|
||||
return send(tpm_finalizepp_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_nv_locked(void)
|
||||
{
|
||||
VBDEBUG("TPM: Set NV locked\n");
|
||||
return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t tlcl_force_clear(void)
|
||||
{
|
||||
VBDEBUG("TPM: Force clear\n");
|
||||
return send(tpm_forceclear_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_enable(void)
|
||||
{
|
||||
VBDEBUG("TPM: Enabling TPM\n");
|
||||
return send(tpm_physicalenable_cmd.buffer);
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_deactivated(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 tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
|
||||
{
|
||||
uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
|
||||
uint32_t size;
|
||||
uint32_t result = tlcl_send_receive(tpm_getflags_cmd.buffer, response,
|
||||
sizeof(response));
|
||||
if (result != TPM_SUCCESS)
|
||||
return result;
|
||||
from_tpm_uint32(response + kTpmResponseHeaderLength, &size);
|
||||
assert(size == sizeof(TPM_PERMANENT_FLAGS));
|
||||
memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size),
|
||||
sizeof(TPM_PERMANENT_FLAGS));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
|
||||
uint8_t *nvlocked)
|
||||
{
|
||||
TPM_PERMANENT_FLAGS pflags;
|
||||
uint32_t result = tlcl_get_permanent_flags(&pflags);
|
||||
if (result == TPM_SUCCESS) {
|
||||
if (disable)
|
||||
*disable = pflags.disable;
|
||||
if (deactivated)
|
||||
*deactivated = pflags.deactivated;
|
||||
if (nvlocked)
|
||||
*nvlocked = pflags.nvLocked;
|
||||
VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n",
|
||||
pflags.disable, pflags.deactivated, pflags.nvLocked);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_global_lock(void)
|
||||
{
|
||||
uint32_t x;
|
||||
VBDEBUG("TPM: Set global lock\n");
|
||||
return tlcl_write(TPM_NV_INDEX0, (uint8_t *) &x, 0);
|
||||
}
|
||||
|
||||
uint32_t tlcl_extend(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));
|
||||
to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
|
||||
memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
|
||||
|
||||
result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
|
||||
if (result != TPM_SUCCESS)
|
||||
return result;
|
||||
|
||||
if (out_digest)
|
||||
memcpy(out_digest, response + kTpmResponseHeaderLength,
|
||||
kPcrDigestLength);
|
||||
return result;
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
/* 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. to_tpm_TYPE puts a value of type TYPE into a TPM
|
||||
* command buffer. from_tpm_TYPE gets a value of type TYPE from a TPM command
|
||||
* buffer into a variable.
|
||||
*/
|
||||
__attribute__((unused))
|
||||
static inline void to_tpm_uint32(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 from_tpm_uint32(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 to_tpm_uint16(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 from_tpm_uint16(const uint8_t *buffer, uint16_t *x)
|
||||
{
|
||||
*x = (buffer[0] << 8) | buffer[1];
|
||||
}
|
||||
|
||||
#endif /* TPM_LITE_TLCL_INTERNAL_H_ */
|
@@ -1,164 +0,0 @@
|
||||
/* 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;
|
@@ -1,559 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <arch/early_variables.h>
|
||||
#include <commonlib/iobuf.h>
|
||||
#include <console/console.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tpm2_marshaling.h"
|
||||
|
||||
static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
|
||||
|
||||
#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
|
||||
#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
|
||||
#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
|
||||
#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
|
||||
|
||||
#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
|
||||
#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
|
||||
|
||||
static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
|
||||
{
|
||||
return obuf_write_be16(ob, cmd_body->startup_type);
|
||||
}
|
||||
|
||||
static int marshal_get_capability(struct obuf *ob,
|
||||
struct tpm2_get_capability *cmd_body)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= obuf_write_be32(ob, cmd_body->capability);
|
||||
rc |= obuf_write_be32(ob, cmd_body->property);
|
||||
rc |= obuf_write_be32(ob, cmd_body->propertyCount);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= obuf_write_be16(ob, data->size);
|
||||
rc |= obuf_write(ob, data->buffer, data->size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
|
||||
{
|
||||
uint32_t v;
|
||||
|
||||
memcpy(&v, nv, sizeof(v));
|
||||
return obuf_write_be32(ob, v);
|
||||
}
|
||||
|
||||
static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
|
||||
rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
|
||||
rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
|
||||
rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
|
||||
rc |= obuf_write_be16(ob, nvpub->dataSize);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
|
||||
rc |= obuf_write(ob, tpmtha->digest.sha256,
|
||||
sizeof(tpmtha->digest.sha256));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
|
||||
TPML_DIGEST_VALUES *dvalues)
|
||||
{
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
rc |= obuf_write_be32(ob, dvalues->count);
|
||||
for (i = 0; i < dvalues->count; i++)
|
||||
rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_session_header(struct obuf *ob,
|
||||
struct tpm2_session_header *session_header)
|
||||
{
|
||||
int rc = 0;
|
||||
struct obuf ob_sz;
|
||||
size_t prev_written;
|
||||
|
||||
/* Snapshot current location to place size of header. */
|
||||
if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Write a size placeholder. */
|
||||
rc |= obuf_write_be32(ob, 0);
|
||||
|
||||
/* Keep track of session header data size by tracking num written. */
|
||||
prev_written = obuf_nr_written(ob);
|
||||
|
||||
rc |= obuf_write_be32(ob, session_header->session_handle);
|
||||
rc |= obuf_write_be16(ob, session_header->nonce_size);
|
||||
rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
|
||||
rc |= obuf_write_be8(ob, session_header->session_attrs);
|
||||
rc |= obuf_write_be16(ob, session_header->auth_size);
|
||||
rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
|
||||
|
||||
/* Fill back in proper size of session header. */
|
||||
rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common session header can include one or two handles and an empty
|
||||
* session_header structure.
|
||||
*/
|
||||
static int marshal_common_session_header(struct obuf *ob,
|
||||
const uint32_t *handles,
|
||||
size_t handle_count)
|
||||
{
|
||||
size_t i;
|
||||
struct tpm2_session_header session_header;
|
||||
int rc = 0;
|
||||
|
||||
car_set_var(tpm_tag, TPM_ST_SESSIONS);
|
||||
|
||||
for (i = 0; i < handle_count; i++)
|
||||
rc |= marshal_TPM_HANDLE(ob, handles[i]);
|
||||
|
||||
memset(&session_header, 0, sizeof(session_header));
|
||||
session_header.session_handle = TPM_RS_PW;
|
||||
rc |= marshal_session_header(ob, &session_header);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_nv_define_space(struct obuf *ob,
|
||||
struct tpm2_nv_define_space_cmd *nvd_in)
|
||||
{
|
||||
const uint32_t handle[] = { TPM_RH_PLATFORM };
|
||||
struct obuf ob_sz;
|
||||
size_t prev_written;
|
||||
int rc = 0;
|
||||
|
||||
rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
|
||||
rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
|
||||
|
||||
/* Snapshot current location to place size field. */
|
||||
if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Put placeholder for size */
|
||||
rc |= obuf_write_be16(ob, 0);
|
||||
|
||||
/* Keep track of nv define space data size by tracking num written. */
|
||||
prev_written = obuf_nr_written(ob);
|
||||
|
||||
rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
|
||||
rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_nv_write(struct obuf *ob,
|
||||
struct tpm2_nv_write_cmd *command_body)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
||||
|
||||
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
||||
rc |= marshal_TPM2B(ob, &command_body->data.b);
|
||||
rc |= obuf_write_be16(ob, command_body->offset);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_nv_write_lock(struct obuf *ob,
|
||||
struct tpm2_nv_write_lock_cmd *command_body)
|
||||
{
|
||||
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
||||
|
||||
return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
||||
}
|
||||
|
||||
static int marshal_pcr_extend(struct obuf *ob,
|
||||
struct tpm2_pcr_extend_cmd *command_body)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t handles[] = { command_body->pcrHandle };
|
||||
|
||||
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
||||
rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_nv_read(struct obuf *ob,
|
||||
struct tpm2_nv_read_cmd *command_body)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
||||
|
||||
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
||||
rc |= obuf_write_be16(ob, command_body->size);
|
||||
rc |= obuf_write_be16(ob, command_body->offset);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* TPM2_Clear command does not require paramaters. */
|
||||
static int marshal_clear(struct obuf *ob)
|
||||
{
|
||||
const uint32_t handle[] = { TPM_RH_PLATFORM };
|
||||
|
||||
return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
|
||||
}
|
||||
|
||||
static int marshal_selftest(struct obuf *ob,
|
||||
struct tpm2_self_test *command_body)
|
||||
{
|
||||
return obuf_write_be8(ob, command_body->yes_no);
|
||||
}
|
||||
|
||||
static int marshal_hierarchy_control(struct obuf *ob,
|
||||
struct tpm2_hierarchy_control_cmd *command_body)
|
||||
{
|
||||
int rc = 0;
|
||||
struct tpm2_session_header session_header;
|
||||
|
||||
car_set_var(tpm_tag, TPM_ST_SESSIONS);
|
||||
|
||||
rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
|
||||
memset(&session_header, 0, sizeof(session_header));
|
||||
session_header.session_handle = TPM_RS_PW;
|
||||
rc |= marshal_session_header(ob, &session_header);
|
||||
|
||||
rc |= marshal_TPM_HANDLE(ob, command_body->enable);
|
||||
rc |= obuf_write_be8(ob, command_body->state);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
|
||||
{
|
||||
int rc = 0;
|
||||
uint16_t *sub_command = command_body;
|
||||
|
||||
switch (*sub_command) {
|
||||
case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
|
||||
rc |= obuf_write_be16(ob, *sub_command);
|
||||
break;
|
||||
case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
|
||||
rc |= obuf_write_be16(ob, sub_command[0]);
|
||||
rc |= obuf_write_be16(ob, sub_command[1]);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported subcommand. */
|
||||
printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
|
||||
*sub_command);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
|
||||
{
|
||||
struct obuf ob_hdr;
|
||||
const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
|
||||
int rc = 0;
|
||||
|
||||
car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
|
||||
|
||||
if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
|
||||
return -1;
|
||||
|
||||
/* Write TPM command header with placeholder field values. */
|
||||
rc |= obuf_write_be16(ob, 0);
|
||||
rc |= obuf_write_be32(ob, 0);
|
||||
rc |= obuf_write_be32(ob, command);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
switch (command) {
|
||||
case TPM2_Startup:
|
||||
rc |= marshal_startup(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_GetCapability:
|
||||
rc |= marshal_get_capability(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_NV_Read:
|
||||
rc |= marshal_nv_read(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_NV_DefineSpace:
|
||||
rc |= marshal_nv_define_space(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_NV_Write:
|
||||
rc |= marshal_nv_write(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_NV_WriteLock:
|
||||
rc |= marshal_nv_write_lock(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_SelfTest:
|
||||
rc |= marshal_selftest(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_Hierarchy_Control:
|
||||
rc |= marshal_hierarchy_control(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_Clear:
|
||||
rc |= marshal_clear(ob);
|
||||
break;
|
||||
|
||||
case TPM2_PCR_Extend:
|
||||
rc |= marshal_pcr_extend(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
case TPM2_CR50_VENDOR_COMMAND:
|
||||
rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
|
||||
__FILE__, __LINE__, command);
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* Fix up the command header with known values. */
|
||||
rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
|
||||
rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int unmarshal_get_capability(struct ibuf *ib,
|
||||
struct get_cap_response *gcr)
|
||||
{
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
rc |= ibuf_read_be8(ib, &gcr->more_data);
|
||||
rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
switch (gcr->cd.capability) {
|
||||
case TPM_CAP_TPM_PROPERTIES:
|
||||
if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
|
||||
return -1;
|
||||
if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
|
||||
(gcr->cd.data.tpmProperties.tpmProperty)) {
|
||||
printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
|
||||
__FILE__, __func__, __LINE__,
|
||||
gcr->cd.data.tpmProperties.count);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
|
||||
TPMS_TAGGED_PROPERTY *pp;
|
||||
|
||||
pp = gcr->cd.data.tpmProperties.tpmProperty + i;
|
||||
rc |= unmarshal_TPM_PT(ib, &pp->property);
|
||||
rc |= ibuf_read_be32(ib, &pp->value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_ERR,
|
||||
"%s:%d - unable to unmarshal capability response",
|
||||
__func__, __LINE__);
|
||||
printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
|
||||
TPM2B_MAX_NV_BUFFER *nv_buffer)
|
||||
{
|
||||
if (ibuf_read_be16(ib, &nv_buffer->t.size))
|
||||
return -1;
|
||||
|
||||
nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
|
||||
|
||||
if (nv_buffer->t.buffer == NULL) {
|
||||
printk(BIOS_ERR, "%s:%d - "
|
||||
"size mismatch: expected %d, remaining %zd\n",
|
||||
__func__, __LINE__, nv_buffer->t.size,
|
||||
ibuf_remaining(ib));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
|
||||
{
|
||||
/* Total size of the parameter field. */
|
||||
if (ibuf_read_be32(ib, &nvr->params_size))
|
||||
return -1;
|
||||
|
||||
if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
|
||||
return -1;
|
||||
|
||||
if (nvr->params_size !=
|
||||
(nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
|
||||
printk(BIOS_ERR,
|
||||
"%s:%d - parameter/buffer %d/%d size mismatch",
|
||||
__func__, __LINE__, nvr->params_size,
|
||||
nvr->buffer.t.size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's ignore the authorisation section. It should be 5 bytes total,
|
||||
* just confirm that this is the case and report any discrepancy.
|
||||
*/
|
||||
if (ibuf_remaining(ib) != 5)
|
||||
printk(BIOS_ERR,
|
||||
"%s:%d - unexpected authorisation seciton size %zd\n",
|
||||
__func__, __LINE__, ibuf_remaining(ib));
|
||||
|
||||
ibuf_oob_drain(ib, ibuf_remaining(ib));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmarshal_vendor_command(struct ibuf *ib,
|
||||
struct vendor_command_response *vcr)
|
||||
{
|
||||
if (ibuf_read_be16(ib, &vcr->vc_subcommand))
|
||||
return -1;
|
||||
|
||||
switch (vcr->vc_subcommand) {
|
||||
case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
|
||||
break;
|
||||
case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
|
||||
return ibuf_read_be8(ib, &vcr->num_restored_headers);
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_ERR,
|
||||
"%s:%d - unsupported vendor command %#04x!\n",
|
||||
__func__, __LINE__, vcr->vc_subcommand);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
|
||||
{
|
||||
static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
|
||||
struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
|
||||
int rc = 0;
|
||||
|
||||
rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
|
||||
rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
|
||||
rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
|
||||
|
||||
if (rc != 0)
|
||||
return NULL;
|
||||
|
||||
if (ibuf_remaining(ib) == 0) {
|
||||
if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
|
||||
printk(BIOS_ERR,
|
||||
"%s: size mismatch in response to command %#x\n",
|
||||
__func__, command);
|
||||
return tpm2_resp;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case TPM2_Startup:
|
||||
break;
|
||||
|
||||
case TPM2_GetCapability:
|
||||
rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
|
||||
break;
|
||||
|
||||
case TPM2_NV_Read:
|
||||
rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
|
||||
break;
|
||||
|
||||
case TPM2_Hierarchy_Control:
|
||||
case TPM2_Clear:
|
||||
case TPM2_NV_DefineSpace:
|
||||
case TPM2_NV_Write:
|
||||
case TPM2_NV_WriteLock:
|
||||
case TPM2_PCR_Extend:
|
||||
/* Session data included in response can be safely ignored. */
|
||||
ibuf_oob_drain(ib, ibuf_remaining(ib));
|
||||
break;
|
||||
|
||||
case TPM2_CR50_VENDOR_COMMAND:
|
||||
rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
size_t i;
|
||||
size_t sz_left;
|
||||
const uint8_t *data;
|
||||
|
||||
printk(BIOS_INFO, "%s:%d:"
|
||||
"Request to unmarshal unexpected command %#x,"
|
||||
" code %#x",
|
||||
__func__, __LINE__, command,
|
||||
tpm2_resp->hdr.tpm_code);
|
||||
|
||||
sz_left = ibuf_remaining(ib);
|
||||
data = ibuf_oob_drain(ib, sz_left);
|
||||
|
||||
for (i = 0; i < sz_left; i++) {
|
||||
if (!(i % 16))
|
||||
printk(BIOS_INFO, "\n");
|
||||
printk(BIOS_INFO, "%2.2x ", data[i]);
|
||||
}
|
||||
}
|
||||
printk(BIOS_INFO, "\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ibuf_remaining(ib)) {
|
||||
printk(BIOS_INFO,
|
||||
"%s:%d got %d bytes back in response to %#x,"
|
||||
" failed to parse (%zd)\n",
|
||||
__func__, __LINE__, tpm2_resp->hdr.tpm_size,
|
||||
command, ibuf_remaining(ib));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The entire message have been parsed. */
|
||||
return tpm2_resp;
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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 __SRC_LIB_TPM2_MARSHALING_H
|
||||
#define __SRC_LIB_TPM2_MARSHALING_H
|
||||
|
||||
#include <commonlib/iobuf.h>
|
||||
#include "tpm2_tlcl_structures.h"
|
||||
|
||||
/* The below functions are used to serialize/deserialize TPM2 commands. */
|
||||
|
||||
/**
|
||||
* tpm_marshal_command
|
||||
*
|
||||
* Given a structure containing a TPM2 command, serialize the structure for
|
||||
* sending it to the TPM.
|
||||
*
|
||||
* @command: code of the TPM2 command to marshal
|
||||
* @tpm_command_body: a pointer to the command specific structure
|
||||
* @ob: output buffer where command is marshaled to
|
||||
*
|
||||
* Returns 0 on success or -1 on error.
|
||||
*
|
||||
*/
|
||||
int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
|
||||
struct obuf *ob);
|
||||
|
||||
/**
|
||||
* tpm_unmarshal_response
|
||||
*
|
||||
* Given a buffer received from the TPM in response to a certain command,
|
||||
* deserialize the buffer into the expeced response structure.
|
||||
*
|
||||
* struct tpm2_response is a union of all possible responses.
|
||||
*
|
||||
* @command: code of the TPM2 command for which a response is unmarshaled
|
||||
* @ib: input buffer containing the serialized response.
|
||||
*
|
||||
* Returns a pointer to the deserialized response or NULL in case of
|
||||
* unmarshaling problems.
|
||||
*/
|
||||
struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib);
|
||||
|
||||
#endif // __SRC_LIB_TPM2_MARSHALING_H
|
@@ -1,438 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <antirollback.h>
|
||||
#include <arch/early_variables.h>
|
||||
#include <console/console.h>
|
||||
#include <endian.h>
|
||||
#include <lib/tpm2_tlcl_structures.h>
|
||||
#include <string.h>
|
||||
#include <tpm.h>
|
||||
#include <vb2_api.h>
|
||||
|
||||
#include "tpm2_marshaling.h"
|
||||
|
||||
/*
|
||||
* This file provides interface between firmware and TPM2 device. The TPM1.2
|
||||
* API was copied as is and relevant functions modified to comply with the
|
||||
* TPM2 specification.
|
||||
*/
|
||||
|
||||
static void *tpm_process_command(TPM_CC command, void *command_body)
|
||||
{
|
||||
struct obuf ob;
|
||||
struct ibuf ib;
|
||||
size_t out_size;
|
||||
size_t in_size;
|
||||
const uint8_t *sendb;
|
||||
/* Command/response buffer. */
|
||||
static uint8_t cr_buffer[TPM_BUFFER_SIZE] CAR_GLOBAL;
|
||||
|
||||
uint8_t *cr_buffer_ptr = car_get_var_ptr(cr_buffer);
|
||||
|
||||
obuf_init(&ob, cr_buffer_ptr, sizeof(cr_buffer));
|
||||
|
||||
if (tpm_marshal_command(command, command_body, &ob) < 0) {
|
||||
printk(BIOS_ERR, "command %#x\n", command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sendb = obuf_contents(&ob, &out_size);
|
||||
|
||||
in_size = sizeof(cr_buffer);
|
||||
if (tis_sendrecv(sendb, out_size, cr_buffer_ptr, &in_size)) {
|
||||
printk(BIOS_ERR, "tpm transaction failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ibuf_init(&ib, cr_buffer_ptr, in_size);
|
||||
|
||||
return tpm_unmarshal_response(command, &ib);
|
||||
}
|
||||
|
||||
|
||||
uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
|
||||
{
|
||||
printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t tlcl_send_startup(TPM_SU type)
|
||||
{
|
||||
struct tpm2_startup startup;
|
||||
struct tpm2_response *response;
|
||||
|
||||
startup.startup_type = type;
|
||||
response = tpm_process_command(TPM2_Startup, &startup);
|
||||
|
||||
if (response && response->hdr.tpm_code &&
|
||||
(response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
|
||||
printk(BIOS_INFO, "%s: Startup return code is %x\n",
|
||||
__func__, response->hdr.tpm_code);
|
||||
return TPM_E_IOERROR;
|
||||
}
|
||||
return TPM_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
uint32_t tlcl_resume(void)
|
||||
{
|
||||
return tlcl_send_startup(TPM_SU_STATE);
|
||||
}
|
||||
|
||||
uint32_t tlcl_assert_physical_presence(void)
|
||||
{
|
||||
/*
|
||||
* Nothing to do on TPM2 for this, use platform hierarchy availability
|
||||
* instead.
|
||||
*/
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller will provide the digest in a 32 byte buffer, let's consider it a
|
||||
* sha256 digest.
|
||||
*/
|
||||
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
|
||||
uint8_t *out_digest)
|
||||
{
|
||||
struct tpm2_pcr_extend_cmd pcr_ext_cmd;
|
||||
struct tpm2_response *response;
|
||||
|
||||
pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
|
||||
pcr_ext_cmd.digests.count = 1;
|
||||
pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
|
||||
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
|
||||
sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
|
||||
|
||||
response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
|
||||
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_IOERROR;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_finalize_physical_presence(void)
|
||||
{
|
||||
/* Nothing needs to be done with tpm2. */
|
||||
printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_force_clear(void)
|
||||
{
|
||||
struct tpm2_response *response;
|
||||
|
||||
response = tpm_process_command(TPM2_Clear, NULL);
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_IOERROR;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
|
||||
uint8_t *nvlocked)
|
||||
{
|
||||
/*
|
||||
* TPM2 does not map directly into these flags TPM1.2 based firmware
|
||||
* expects to be able to retrieve.
|
||||
*
|
||||
* In any case, if any of these conditions are present, the following
|
||||
* firmware flow would be interrupted and will have a chance to report
|
||||
* an error. Let's just hardcode an "All OK" response for now.
|
||||
*/
|
||||
|
||||
if (disable)
|
||||
*disable = 0;
|
||||
|
||||
if (nvlocked)
|
||||
*nvlocked = 1;
|
||||
|
||||
if (deactivated)
|
||||
*deactivated = 0;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t tlcl_init_done CAR_GLOBAL;
|
||||
|
||||
/* This function is called directly by vboot, uses vboot return types. */
|
||||
uint32_t tlcl_lib_init(void)
|
||||
{
|
||||
uint8_t done = car_get_var(tlcl_init_done);
|
||||
if (done)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
if (tis_init())
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
if (tis_open())
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
car_set_var(tlcl_init_done, 1);
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_physical_presence_cmd_enable(void)
|
||||
{
|
||||
printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
|
||||
{
|
||||
struct tpm2_nv_read_cmd nv_readc;
|
||||
struct tpm2_response *response;
|
||||
|
||||
memset(&nv_readc, 0, sizeof(nv_readc));
|
||||
|
||||
nv_readc.nvIndex = HR_NV_INDEX + index;
|
||||
nv_readc.size = length;
|
||||
|
||||
response = tpm_process_command(TPM2_NV_Read, &nv_readc);
|
||||
|
||||
/* Need to map tpm error codes into internal values. */
|
||||
if (!response)
|
||||
return TPM_E_READ_FAILURE;
|
||||
|
||||
printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
|
||||
__FILE__, __LINE__, index, response->hdr.tpm_code);
|
||||
switch (response->hdr.tpm_code) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
/* Uninitialized, returned if the space hasn't been written. */
|
||||
case TPM_RC_NV_UNINITIALIZED:
|
||||
/*
|
||||
* Bad index, cr50 specific value, returned if the space
|
||||
* hasn't been defined.
|
||||
*/
|
||||
case TPM_RC_CR50_NV_UNDEFINED:
|
||||
return TPM_E_BADINDEX;
|
||||
|
||||
default:
|
||||
return TPM_E_READ_FAILURE;
|
||||
}
|
||||
|
||||
if (length > response->nvr.buffer.t.size)
|
||||
return TPM_E_RESPONSE_TOO_LARGE;
|
||||
|
||||
if (length < response->nvr.buffer.t.size)
|
||||
return TPM_E_READ_EMPTY;
|
||||
|
||||
memcpy(data, response->nvr.buffer.t.buffer, length);
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_self_test_full(void)
|
||||
{
|
||||
struct tpm2_self_test st;
|
||||
struct tpm2_response *response;
|
||||
|
||||
st.yes_no = 1;
|
||||
|
||||
response = tpm_process_command(TPM2_SelfTest, &st);
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_deactivated(uint8_t flag)
|
||||
{
|
||||
printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_set_enable(void)
|
||||
{
|
||||
printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_lock_nv_write(uint32_t index)
|
||||
{
|
||||
struct tpm2_response *response;
|
||||
/* TPM Wll reject attempts to write at non-defined index. */
|
||||
struct tpm2_nv_write_lock_cmd nv_wl = {
|
||||
.nvIndex = HR_NV_INDEX + index,
|
||||
};
|
||||
|
||||
response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
|
||||
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_IOERROR;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_startup(void)
|
||||
{
|
||||
return tlcl_send_startup(TPM_SU_CLEAR);
|
||||
}
|
||||
|
||||
uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
|
||||
{
|
||||
struct tpm2_nv_write_cmd nv_writec;
|
||||
struct tpm2_response *response;
|
||||
|
||||
memset(&nv_writec, 0, sizeof(nv_writec));
|
||||
|
||||
nv_writec.nvIndex = HR_NV_INDEX + index;
|
||||
nv_writec.data.t.size = length;
|
||||
nv_writec.data.t.buffer = data;
|
||||
|
||||
response = tpm_process_command(TPM2_NV_Write, &nv_writec);
|
||||
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
|
||||
/* Need to map tpm error codes into internal values. */
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_WRITE_FAILURE;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
|
||||
{
|
||||
struct tpm2_nv_define_space_cmd nvds_cmd;
|
||||
struct tpm2_response *response;
|
||||
/*
|
||||
* Different sets of NVRAM space attributes apply to the "ro" spaces,
|
||||
* i.e. those which should not be possible to delete or modify once
|
||||
* the RO exits, and the rest of the NVRAM spaces.
|
||||
*/
|
||||
const TPMA_NV ro_space_attributes = {
|
||||
.TPMA_NV_PPWRITE = 1,
|
||||
.TPMA_NV_AUTHREAD = 1,
|
||||
.TPMA_NV_PPREAD = 1,
|
||||
.TPMA_NV_PLATFORMCREATE = 1,
|
||||
.TPMA_NV_WRITE_STCLEAR = 1,
|
||||
.TPMA_NV_POLICY_DELETE = 1,
|
||||
};
|
||||
const TPMA_NV default_space_attributes = {
|
||||
.TPMA_NV_PPWRITE = 1,
|
||||
.TPMA_NV_AUTHREAD = 1,
|
||||
.TPMA_NV_PPREAD = 1,
|
||||
.TPMA_NV_PLATFORMCREATE = 1,
|
||||
};
|
||||
|
||||
/* Prepare the define space command structure. */
|
||||
memset(&nvds_cmd, 0, sizeof(nvds_cmd));
|
||||
|
||||
nvds_cmd.publicInfo.dataSize = space_size;
|
||||
nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
|
||||
nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
|
||||
|
||||
/* RO only NV spaces should be impossible to destroy. */
|
||||
if ((space_index == FIRMWARE_NV_INDEX) ||
|
||||
(space_index == REC_HASH_NV_INDEX)) {
|
||||
/*
|
||||
* This policy digest was obtained using TPM2_PolicyPCR
|
||||
* selecting only PCR_0 with a value of all zeros.
|
||||
*/
|
||||
const uint8_t pcr0_unchanged_policy[] = {
|
||||
0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
|
||||
0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
|
||||
0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
|
||||
0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
|
||||
};
|
||||
|
||||
nvds_cmd.publicInfo.attributes = ro_space_attributes;
|
||||
/*
|
||||
* Use policy digest based on default pcr0 value. This makes
|
||||
* sure that the space can not be deleted as soon as PCR0
|
||||
* value has been extended from default.
|
||||
*/
|
||||
nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
|
||||
nvds_cmd.publicInfo.authPolicy.t.size =
|
||||
sizeof(pcr0_unchanged_policy);
|
||||
} else {
|
||||
nvds_cmd.publicInfo.attributes = default_space_attributes;
|
||||
}
|
||||
|
||||
response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
|
||||
printk(BIOS_INFO, "%s: response is %x\n",
|
||||
__func__, response ? response->hdr.tpm_code : -1);
|
||||
|
||||
if (!response)
|
||||
return TPM_E_NO_DEVICE;
|
||||
|
||||
/* Map TPM2 retrun codes into common vboot represenation. */
|
||||
switch (response->hdr.tpm_code) {
|
||||
case TPM2_RC_SUCCESS:
|
||||
return TPM_SUCCESS;
|
||||
case TPM2_RC_NV_DEFINED:
|
||||
return TPM_E_NV_DEFINED;
|
||||
default:
|
||||
return TPM_E_INTERNAL_INCONSISTENCY;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t tlcl_disable_platform_hierarchy(void)
|
||||
{
|
||||
struct tpm2_response *response;
|
||||
struct tpm2_hierarchy_control_cmd hc = {
|
||||
.enable = TPM_RH_PLATFORM,
|
||||
.state = 0,
|
||||
};
|
||||
|
||||
response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
|
||||
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_INTERNAL_INCONSISTENCY;
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_cr50_enable_nvcommits(void)
|
||||
{
|
||||
uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
|
||||
struct tpm2_response *response;
|
||||
|
||||
printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
|
||||
|
||||
response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
|
||||
|
||||
if (response == NULL || (response && response->hdr.tpm_code)) {
|
||||
if (response)
|
||||
printk(BIOS_INFO, "%s: failed %x\n", __func__,
|
||||
response->hdr.tpm_code);
|
||||
else
|
||||
printk(BIOS_INFO, "%s: failed\n", __func__);
|
||||
return TPM_E_IOERROR;
|
||||
}
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms,
|
||||
uint8_t *num_restored_headers)
|
||||
{
|
||||
struct tpm2_response *response;
|
||||
uint16_t command_body[] = {
|
||||
TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
|
||||
};
|
||||
|
||||
printk(BIOS_INFO, "Checking cr50 for pending updates\n");
|
||||
|
||||
response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);
|
||||
|
||||
if (!response || response->hdr.tpm_code)
|
||||
return TPM_E_INTERNAL_INCONSISTENCY;
|
||||
|
||||
*num_restored_headers = response->vcr.num_restored_headers;
|
||||
return TPM_SUCCESS;
|
||||
}
|
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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 __SRC_LIB_TPM2_TLCL_STRUCTURES_H
|
||||
#define __SRC_LIB_TPM2_TLCL_STRUCTURES_H
|
||||
|
||||
/*
|
||||
* This file includes a subset of definitions of TPM protocol version 2.x
|
||||
* constants and structures needed for functions used in coreboot.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <compiler.h>
|
||||
#include <tpm_lite/tlcl.h>
|
||||
#include <types.h>
|
||||
|
||||
/* This should be plenty for what firmware needs. */
|
||||
#define TPM_BUFFER_SIZE 256
|
||||
|
||||
/* Basic TPM2 types. */
|
||||
typedef uint16_t TPM_SU;
|
||||
typedef uint16_t TPM_ALG_ID;
|
||||
typedef uint32_t TPM_CC;
|
||||
typedef uint32_t TPM_HANDLE;
|
||||
typedef uint32_t TPM_RC;
|
||||
typedef uint8_t TPMI_YES_NO;
|
||||
typedef TPM_ALG_ID TPMI_ALG_HASH;
|
||||
typedef TPM_HANDLE TPMI_DH_PCR;
|
||||
typedef TPM_HANDLE TPMI_RH_NV_INDEX;
|
||||
typedef TPM_HANDLE TPMI_RH_ENABLES;
|
||||
typedef TPM_HANDLE TPMI_SH_AUTH_SESSION;
|
||||
typedef TPM_HANDLE TPM_RH;
|
||||
|
||||
/* Some hardcoded algorithm values. */
|
||||
#define TPM_ALG_HMAC ((TPM_ALG_ID)0x0005)
|
||||
#define TPM_ALG_NULL ((TPM_ALG_ID)0x0010)
|
||||
#define TPM_ALG_SHA1 ((TPM_ALG_ID)0x0004)
|
||||
#define TPM_ALG_SHA256 ((TPM_ALG_ID)0x000b)
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
/* Some hardcoded hierarchies. */
|
||||
#define TPM_RH_NULL 0x40000007
|
||||
#define TPM_RS_PW 0x40000009
|
||||
#define TPM_RH_PLATFORM 0x4000000C
|
||||
|
||||
typedef struct {
|
||||
uint16_t size;
|
||||
uint8_t *buffer;
|
||||
} TPM2B;
|
||||
|
||||
/* Relevant TPM Command's structures. */
|
||||
/* Common command/response header. */
|
||||
struct tpm_header {
|
||||
uint16_t tpm_tag;
|
||||
uint32_t tpm_size;
|
||||
TPM_CC tpm_code;
|
||||
} __packed;
|
||||
|
||||
/* TPM command codes. */
|
||||
#define TPM2_Hierarchy_Control ((TPM_CC)0x00000121)
|
||||
#define TPM2_Clear ((TPM_CC)0x00000126)
|
||||
#define TPM2_NV_DefineSpace ((TPM_CC)0x0000012A)
|
||||
#define TPM2_NV_Write ((TPM_CC)0x00000137)
|
||||
#define TPM2_NV_WriteLock ((TPM_CC)0x00000138)
|
||||
#define TPM2_SelfTest ((TPM_CC)0x00000143)
|
||||
#define TPM2_Startup ((TPM_CC)0x00000144)
|
||||
#define TPM2_NV_Read ((TPM_CC)0x0000014E)
|
||||
#define TPM2_GetCapability ((TPM_CC)0x0000017A)
|
||||
#define TPM2_PCR_Extend ((TPM_CC)0x00000182)
|
||||
/* TPM2 specifies vendor commands need to have this bit set. Vendor command
|
||||
space is defined by the lower 16 bits. */
|
||||
#define TPM_CC_VENDOR_BIT_MASK 0x20000000
|
||||
/* FIXME: below is not enough to differentiate between vendors commands
|
||||
of numerous devices. However, the current tpm2 APIs aren't very amenable
|
||||
to extending generically because the marshaling code is assuming all
|
||||
knowledge of all commands. */
|
||||
#define TPM2_CR50_VENDOR_COMMAND ((TPM_CC)(TPM_CC_VENDOR_BIT_MASK | 0))
|
||||
#define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS (21)
|
||||
#define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON (24)
|
||||
|
||||
/* Startup values. */
|
||||
#define TPM_SU_CLEAR 0
|
||||
#define TPM_SU_STATE 1
|
||||
|
||||
#define TPM_HT_PCR 0x00
|
||||
#define TPM_HT_NV_INDEX 0x01
|
||||
#define TPM_HT_HMAC_SESSION 0x02
|
||||
#define TPM_HT_POLICY_SESSION 0x03
|
||||
|
||||
#define HR_SHIFT 24
|
||||
#define HR_PCR (TPM_HT_PCR << HR_SHIFT)
|
||||
#define HR_HMAC_SESSION (TPM_HT_HMAC_SESSION << HR_SHIFT)
|
||||
#define HR_POLICY_SESSION (TPM_HT_POLICY_SESSION << HR_SHIFT)
|
||||
#define HR_TRANSIENT (TPM_HT_TRANSIENT << HR_SHIFT)
|
||||
#define HR_PERSISTENT (TPM_HT_PERSISTENT << HR_SHIFT)
|
||||
#define HR_NV_INDEX (TPM_HT_NV_INDEX << HR_SHIFT)
|
||||
#define HR_PERMANENT (TPM_HT_PERMANENT << HR_SHIFT)
|
||||
#define PCR_FIRST (HR_PCR + 0)
|
||||
#define PCR_LAST (PCR_FIRST + IMPLEMENTATION_PCR-1)
|
||||
#define HMAC_SESSION_FIRST (HR_HMAC_SESSION + 0)
|
||||
#define HMAC_SESSION_LAST (HMAC_SESSION_FIRST+MAX_ACTIVE_SESSIONS-1)
|
||||
#define LOADED_SESSION_FIRST HMAC_SESSION_FIRST
|
||||
#define LOADED_SESSION_LAST HMAC_SESSION_LAST
|
||||
#define POLICY_SESSION_FIRST (HR_POLICY_SESSION + 0)
|
||||
#define POLICY_SESSION_LAST (POLICY_SESSION_FIRST + MAX_ACTIVE_SESSIONS-1)
|
||||
#define TRANSIENT_FIRST (HR_TRANSIENT + 0)
|
||||
#define ACTIVE_SESSION_FIRST POLICY_SESSION_FIRST
|
||||
#define ACTIVE_SESSION_LAST POLICY_SESSION_LAST
|
||||
#define TRANSIENT_LAST (TRANSIENT_FIRST+MAX_LOADED_OBJECTS-1)
|
||||
#define PERSISTENT_FIRST (HR_PERSISTENT + 0)
|
||||
#define PERSISTENT_LAST (PERSISTENT_FIRST + 0x00FFFFFF)
|
||||
#define PLATFORM_PERSISTENT (PERSISTENT_FIRST + 0x00800000)
|
||||
#define NV_INDEX_FIRST (HR_NV_INDEX + 0)
|
||||
#define NV_INDEX_LAST (NV_INDEX_FIRST + 0x00FFFFFF)
|
||||
#define PERMANENT_FIRST TPM_RH_FIRST
|
||||
#define PERMANENT_LAST TPM_RH_LAST
|
||||
|
||||
/* Tpm2 command tags. */
|
||||
#define TPM_ST_NO_SESSIONS 0x8001
|
||||
#define TPM_ST_SESSIONS 0x8002
|
||||
|
||||
/* Values copied from tpm2/tpm_types.h */
|
||||
#define RC_VER1 0x100
|
||||
#define TPM_RC_INITIALIZE ((TPM_RC)(RC_VER1 + 0x000))
|
||||
#define TPM_RC_NV_UNINITIALIZED ((TPM_RC)(RC_VER1 + 0x04A))
|
||||
|
||||
/*
|
||||
* Cr50 returns this code when an attempt is made to read an NV location which
|
||||
* has not yet been defined. This is an aggregation of various return code
|
||||
* extensions which may or may not match if a different TPM2 device is
|
||||
* used.
|
||||
*/
|
||||
#define TPM_RC_CR50_NV_UNDEFINED 0x28b
|
||||
|
||||
/* TPM command structures. */
|
||||
|
||||
struct tpm2_startup {
|
||||
TPM_SU startup_type;
|
||||
};
|
||||
|
||||
/* Various TPM capability types to use when querying the device. */
|
||||
typedef uint32_t TPM_CAP;
|
||||
#define TPM_CAP_TPM_PROPERTIES ((TPM_CAP)0x00000006)
|
||||
|
||||
typedef TPM_HANDLE TPMI_RH_NV_AUTH;
|
||||
typedef TPM_HANDLE TPMI_RH_NV_INDEX;
|
||||
|
||||
/* TPM Property capability constants. */
|
||||
typedef uint32_t TPM_PT;
|
||||
#define PT_GROUP 0x00000100
|
||||
#define PT_VAR (PT_GROUP * 2)
|
||||
#define TPM_PT_PERMANENT ((TPM_PT)(PT_VAR + 0))
|
||||
|
||||
/* Structures of payloads of various TPM2 commands. */
|
||||
struct tpm2_get_capability {
|
||||
TPM_CAP capability;
|
||||
uint32_t property;
|
||||
uint32_t propertyCount;
|
||||
};
|
||||
|
||||
/* get_capability response when PT_PERMANENT is requested. */
|
||||
typedef struct {
|
||||
uint32_t ownerAuthSet : 1;
|
||||
uint32_t endorsementAuthSet : 1;
|
||||
uint32_t lockoutAuthSet : 1;
|
||||
uint32_t reserved3_7 : 5;
|
||||
uint32_t disableClear : 1;
|
||||
uint32_t inLockout : 1;
|
||||
uint32_t tpmGeneratedEPS : 1;
|
||||
uint32_t reserved11_31 : 21;
|
||||
} TPMA_PERMANENT;
|
||||
|
||||
typedef struct {
|
||||
uint32_t TPMA_NV_PPWRITE : 1;
|
||||
uint32_t TPMA_NV_OWNERWRITE : 1;
|
||||
uint32_t TPMA_NV_AUTHWRITE : 1;
|
||||
uint32_t TPMA_NV_POLICYWRITE : 1;
|
||||
uint32_t TPMA_NV_COUNTER : 1;
|
||||
uint32_t TPMA_NV_BITS : 1;
|
||||
uint32_t TPMA_NV_EXTEND : 1;
|
||||
uint32_t reserved7_9 : 3;
|
||||
uint32_t TPMA_NV_POLICY_DELETE : 1;
|
||||
uint32_t TPMA_NV_WRITELOCKED : 1;
|
||||
uint32_t TPMA_NV_WRITEALL : 1;
|
||||
uint32_t TPMA_NV_WRITEDEFINE : 1;
|
||||
uint32_t TPMA_NV_WRITE_STCLEAR : 1;
|
||||
uint32_t TPMA_NV_GLOBALLOCK : 1;
|
||||
uint32_t TPMA_NV_PPREAD : 1;
|
||||
uint32_t TPMA_NV_OWNERREAD : 1;
|
||||
uint32_t TPMA_NV_AUTHREAD : 1;
|
||||
uint32_t TPMA_NV_POLICYREAD : 1;
|
||||
uint32_t reserved20_24 : 5;
|
||||
uint32_t TPMA_NV_NO_DA : 1;
|
||||
uint32_t TPMA_NV_ORDERLY : 1;
|
||||
uint32_t TPMA_NV_CLEAR_STCLEAR : 1;
|
||||
uint32_t TPMA_NV_READLOCKED : 1;
|
||||
uint32_t TPMA_NV_WRITTEN : 1;
|
||||
uint32_t TPMA_NV_PLATFORMCREATE : 1;
|
||||
uint32_t TPMA_NV_READ_STCLEAR : 1;
|
||||
} TPMA_NV;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t size;
|
||||
const uint8_t *buffer;
|
||||
} t;
|
||||
TPM2B b;
|
||||
} TPM2B_DIGEST;
|
||||
|
||||
typedef TPM2B_DIGEST TPM2B_AUTH;
|
||||
typedef TPM2B_DIGEST TPM2B_NONCE;
|
||||
|
||||
typedef struct {
|
||||
TPM_PT property;
|
||||
uint32_t value;
|
||||
} TPMS_TAGGED_PROPERTY;
|
||||
|
||||
#define MAX_CAP_DATA (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - \
|
||||
sizeof(TPMI_YES_NO) - sizeof(TPM_CAP) - sizeof(uint32_t))
|
||||
#define MAX_TPM_PROPERTIES (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))
|
||||
|
||||
/* Somewhat arbitrary, leave enough room for command wrappers. */
|
||||
#define MAX_NV_BUFFER_SIZE (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - 50)
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
TPMS_TAGGED_PROPERTY tpmProperty[MAX_TPM_PROPERTIES];
|
||||
} TPML_TAGGED_TPM_PROPERTY;
|
||||
|
||||
typedef union {
|
||||
TPML_TAGGED_TPM_PROPERTY tpmProperties;
|
||||
} TPMU_CAPABILITIES;
|
||||
|
||||
typedef struct {
|
||||
TPM_CAP capability;
|
||||
TPMU_CAPABILITIES data;
|
||||
} TPMS_CAPABILITY_DATA;
|
||||
|
||||
struct get_cap_response {
|
||||
TPMI_YES_NO more_data;
|
||||
TPMS_CAPABILITY_DATA cd;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
TPMI_RH_NV_INDEX nvIndex;
|
||||
TPMI_ALG_HASH nameAlg;
|
||||
TPMA_NV attributes;
|
||||
TPM2B_DIGEST authPolicy;
|
||||
uint16_t dataSize;
|
||||
} TPMS_NV_PUBLIC;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t size;
|
||||
TPMS_NV_PUBLIC nvPublic;
|
||||
} t;
|
||||
TPM2B b;
|
||||
} TPM2B_NV_PUBLIC;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t size;
|
||||
const uint8_t *buffer;
|
||||
} t;
|
||||
TPM2B b;
|
||||
} TPM2B_MAX_NV_BUFFER;
|
||||
|
||||
/*
|
||||
* This is a union, but as of now we support just one digest - sha256, so
|
||||
* there is just one element.
|
||||
*/
|
||||
typedef union {
|
||||
uint8_t sha256[SHA256_DIGEST_SIZE];
|
||||
} TPMU_HA;
|
||||
|
||||
typedef struct {
|
||||
TPMI_ALG_HASH hashAlg;
|
||||
TPMU_HA digest;
|
||||
} TPMT_HA;
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
TPMT_HA digests[1]; /* Limit max number of hashes to 1. */
|
||||
} TPML_DIGEST_VALUES;
|
||||
|
||||
struct nv_read_response {
|
||||
uint32_t params_size;
|
||||
TPM2B_MAX_NV_BUFFER buffer;
|
||||
};
|
||||
|
||||
struct vendor_command_response {
|
||||
uint16_t vc_subcommand;
|
||||
union {
|
||||
uint8_t num_restored_headers;
|
||||
};
|
||||
};
|
||||
|
||||
struct tpm2_session_attrs {
|
||||
uint8_t continueSession : 1;
|
||||
uint8_t auditExclusive : 1;
|
||||
uint8_t auditReset : 1;
|
||||
uint8_t reserved3_4 : 2;
|
||||
uint8_t decrypt : 1;
|
||||
uint8_t encrypt : 1;
|
||||
uint8_t audit : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
* TPM session header for commands requiring session information. Also
|
||||
* included in the responses to those commands.
|
||||
*/
|
||||
struct tpm2_session_header {
|
||||
uint32_t session_handle;
|
||||
uint16_t nonce_size;
|
||||
uint8_t *nonce;
|
||||
union {
|
||||
struct tpm2_session_attrs session_attr_bits;
|
||||
uint8_t session_attrs;
|
||||
} __packed;
|
||||
uint16_t auth_size;
|
||||
uint8_t *auth;
|
||||
};
|
||||
|
||||
struct tpm2_response {
|
||||
struct tpm_header hdr;
|
||||
union {
|
||||
struct get_cap_response gc;
|
||||
struct nv_read_response nvr;
|
||||
struct tpm2_session_header def_space;
|
||||
struct vendor_command_response vcr;
|
||||
};
|
||||
};
|
||||
|
||||
struct tpm2_nv_define_space_cmd {
|
||||
TPM2B_AUTH auth;
|
||||
TPMS_NV_PUBLIC publicInfo;
|
||||
};
|
||||
|
||||
struct tpm2_nv_write_cmd {
|
||||
TPMI_RH_NV_INDEX nvIndex;
|
||||
TPM2B_MAX_NV_BUFFER data;
|
||||
uint16_t offset;
|
||||
};
|
||||
|
||||
struct tpm2_self_test {
|
||||
TPMI_YES_NO yes_no;
|
||||
};
|
||||
|
||||
struct tpm2_nv_read_cmd {
|
||||
TPMI_RH_NV_INDEX nvIndex;
|
||||
uint16_t size;
|
||||
uint16_t offset;
|
||||
};
|
||||
|
||||
struct tpm2_nv_write_lock_cmd {
|
||||
TPMI_RH_NV_INDEX nvIndex;
|
||||
};
|
||||
|
||||
struct tpm2_pcr_extend_cmd {
|
||||
TPMI_DH_PCR pcrHandle;
|
||||
TPML_DIGEST_VALUES digests;
|
||||
};
|
||||
|
||||
struct tpm2_hierarchy_control_cmd {
|
||||
TPMI_RH_ENABLES enable;
|
||||
TPMI_YES_NO state;
|
||||
};
|
||||
|
||||
#endif // __SRC_LIB_TPM2_TLCL_STRUCTURES_H
|
@@ -1,255 +0,0 @@
|
||||
/* 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 */
|
Reference in New Issue
Block a user