sandbox: tpm: Split out common nvdata code

We want to support nvdata in TPM2 as well. To avoid code duplicating the
associated code, move it into a common file.

Drop the special-case logic for the kernel space. This can be handled by
the higher-level code now, i.e. in vboot itself.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-07-18 14:17:57 -06:00
parent c03cb02230
commit 974c98f26c
4 changed files with 172 additions and 105 deletions

View file

@ -6,11 +6,11 @@ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-uclass.o
obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o
obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o
obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o

View file

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Common features for sandbox TPM1 and TPM2 implementations
*
* Copyright 2021 Google LLC
*/
#define LOG_CATEGORY UCLASS_TPM
#include <common.h>
#include <tpm-v1.h>
#include <tpm-v2.h>
#include <asm/unaligned.h>
#include "sandbox_common.h"
#define TPM_ERR_CODE_OFS (2 + 4) /* after tag and size */
int sb_tpm_index_to_seq(u32 index)
{
index &= ~HR_NV_INDEX;
switch (index) {
case FIRMWARE_NV_INDEX:
return NV_SEQ_FIRMWARE;
case KERNEL_NV_INDEX:
return NV_SEQ_KERNEL;
case BACKUP_NV_INDEX:
return NV_SEQ_BACKUP;
case FWMP_NV_INDEX:
return NV_SEQ_FWMP;
case MRC_REC_HASH_NV_INDEX:
return NV_SEQ_REC_HASH;
case 0:
return NV_SEQ_GLOBAL_LOCK;
case TPM_NV_INDEX_LOCK:
return NV_SEQ_ENABLE_LOCKING;
}
printf("Invalid nv index %#x\n", index);
return -1;
}
void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
enum sandbox_nv_space seq, u8 *buf, int data_ofs,
int length)
{
const struct nvdata_state *nvd = &nvdata[seq];
if (!nvd->present)
put_unaligned_be32(TPM_BADINDEX, buf + TPM_ERR_CODE_OFS);
else if (length > nvd->length)
put_unaligned_be32(TPM_BAD_DATASIZE, buf + TPM_ERR_CODE_OFS);
else
memcpy(buf + data_ofs, &nvd->data, length);
}
void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
int length)
{
struct nvdata_state *nvd = &nvdata[seq];
if (length > nvd->length)
log_err("Invalid length %x (max %x)\n", length, nvd->length);
else
memcpy(&nvdata[seq].data, buf + data_ofs, length);
}

View file

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Common features for sandbox TPM1 and TPM2 implementations
*
* Copyright 2021 Google LLC
*/
#ifndef __TPM_SANDBOX_COMMON_H
#define __TPM_SANDBOX_COMMON_H
/*
* These numbers derive from adding the sizes of command fields as shown in
* the TPM commands manual.
*/
#define TPM_HDR_LEN 10
/* These are the different non-volatile spaces that we emulate */
enum sandbox_nv_space {
NV_SEQ_ENABLE_LOCKING,
NV_SEQ_GLOBAL_LOCK,
NV_SEQ_FIRMWARE,
NV_SEQ_KERNEL,
NV_SEQ_BACKUP,
NV_SEQ_FWMP,
NV_SEQ_REC_HASH,
NV_SEQ_COUNT,
};
/* TPM NVRAM location indices */
#define FIRMWARE_NV_INDEX 0x1007
#define KERNEL_NV_INDEX 0x1008
#define BACKUP_NV_INDEX 0x1009
#define FWMP_NV_INDEX 0x100a
#define MRC_REC_HASH_NV_INDEX 0x100b
/* Size of each non-volatile space */
#define NV_DATA_SIZE 0x28
/**
* struct nvdata_state - state of a single non-volatile-data 'space'
*
* @present: true if present
* @length: length in bytes (max NV_DATA_SIZE)
* @data: contents of non-volatile space
*/
struct nvdata_state {
bool present;
int length;
u8 data[NV_DATA_SIZE];
};
/**
* sb_tpm_index_to_seq() - convert an index into a space sequence number
*
* This converts the index as used by the vboot code into an internal sequence
* number used by the sandbox emulation.
*
* @index: Index to use (FIRMWARE_NV_INDEX, etc.)
* @return associated space (enum sandbox_nv_space)
*/
int sb_tpm_index_to_seq(uint index);
/**
* sb_tpm_read_data() - Read non-volatile data
*
* This handles a TPM read of nvdata. If the nvdata is not present, a
* TPM_BADINDEX error is put in the buffer. If @length is too large,
* TPM_BAD_DATASIZE is put in the buffer.
*
* @nvdata: Current nvdata state
* @seq: Sequence number to read
* @recvbuf: Buffer to update with the TPM response, assumed to contain zeroes
* @data_ofs: Offset of the 'data' portion of @recvbuf
* @length: Number of bytes to read
*/
void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
enum sandbox_nv_space seq, u8 *recvbuf, int data_ofs,
int length);
/**
* sb_tpm_write_data() - Write non-volatile data
*
* If @length is too large, an error is logged and nothing is written.
*
* @nvdata: Current nvdata state
* @seq: Sequence number to read
* @buf: Buffer containing the data to write
* @data_ofs: Offset of the 'data' portion of @buf
* @length: Number of bytes to write
*/
void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
int length);
#endif

View file

@ -9,61 +9,10 @@
#include <asm/state.h> #include <asm/state.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <u-boot/crc.h> #include <u-boot/crc.h>
#include "sandbox_common.h"
/* TPM NVRAM location indices. */
#define FIRMWARE_NV_INDEX 0x1007
#define KERNEL_NV_INDEX 0x1008
#define BACKUP_NV_INDEX 0x1009
#define FWMP_NV_INDEX 0x100a
#define REC_HASH_NV_INDEX 0x100b
#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE
#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60 #define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
#define ROLLBACK_SPACE_KERNEL_VERSION 2
#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
struct rollback_space_kernel {
/* 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;
} __packed rollback_space_kernel;
/*
* These numbers derive from adding the sizes of command fields as shown in
* the TPM commands manual.
*/
#define TPM_REQUEST_HEADER_LENGTH 10
#define TPM_RESPONSE_HEADER_LENGTH 10
/* These are the different non-volatile spaces that we emulate */
enum {
NV_GLOBAL_LOCK,
NV_SEQ_FIRMWARE,
NV_SEQ_KERNEL,
NV_SEQ_BACKUP,
NV_SEQ_FWMP,
NV_SEQ_REC_HASH,
NV_SEQ_COUNT,
};
/* Size of each non-volatile space */
#define NV_DATA_SIZE 0x20
struct nvdata_state {
bool present;
u8 data[NV_DATA_SIZE];
};
/* /*
* Information about our TPM emulation. This is preserved in the sandbox * Information about our TPM emulation. This is preserved in the sandbox
* state file if enabled. * state file if enabled.
@ -140,27 +89,6 @@ static int sandbox_tpm_write_state(void *blob, int node)
SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state, SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
sandbox_tpm_write_state); sandbox_tpm_write_state);
static int index_to_seq(uint32_t index)
{
switch (index) {
case FIRMWARE_NV_INDEX:
return NV_SEQ_FIRMWARE;
case KERNEL_NV_INDEX:
return NV_SEQ_KERNEL;
case BACKUP_NV_INDEX:
return NV_SEQ_BACKUP;
case FWMP_NV_INDEX:
return NV_SEQ_FWMP;
case REC_HASH_NV_INDEX:
return NV_SEQ_REC_HASH;
case 0:
return NV_GLOBAL_LOCK;
}
printf("Invalid nv index %#x\n", index);
return -1;
}
static void handle_cap_flag_space(u8 **datap, uint index) static void handle_cap_flag_space(u8 **datap, uint index)
{ {
struct tpm_nv_data_public pub; struct tpm_nv_data_public pub;
@ -246,48 +174,25 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
case TPM_CMD_NV_WRITE_VALUE: case TPM_CMD_NV_WRITE_VALUE:
index = get_unaligned_be32(sendbuf + 10); index = get_unaligned_be32(sendbuf + 10);
length = get_unaligned_be32(sendbuf + 18); length = get_unaligned_be32(sendbuf + 18);
seq = index_to_seq(index); seq = sb_tpm_index_to_seq(index);
if (seq < 0) if (seq < 0)
return -EINVAL; return -EINVAL;
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length); printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length); sb_tpm_write_data(tpm->nvdata, seq, sendbuf, 22, length);
tpm->nvdata[seq].present = true;
*recv_len = 12;
memset(recvbuf, '\0', *recv_len);
break; break;
case TPM_CMD_NV_READ_VALUE: /* nvread */ case TPM_CMD_NV_READ_VALUE: /* nvread */
index = get_unaligned_be32(sendbuf + 10); index = get_unaligned_be32(sendbuf + 10);
length = get_unaligned_be32(sendbuf + 18); length = get_unaligned_be32(sendbuf + 18);
seq = index_to_seq(index); seq = sb_tpm_index_to_seq(index);
if (seq < 0) if (seq < 0)
return -EINVAL; return -EINVAL;
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index, printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
length, seq); length, seq);
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) + *recv_len = TPM_HDR_LEN + sizeof(uint32_t) + length;
length;
memset(recvbuf, '\0', *recv_len); memset(recvbuf, '\0', *recv_len);
put_unaligned_be32(length, recvbuf + put_unaligned_be32(length, recvbuf + TPM_HDR_LEN);
TPM_RESPONSE_HEADER_LENGTH); sb_tpm_read_data(tpm->nvdata, seq, recvbuf, TPM_HDR_LEN + 4,
if (seq == NV_SEQ_KERNEL) { length);
struct rollback_space_kernel rsk;
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
sizeof(uint32_t);
memset(&rsk, 0, sizeof(struct rollback_space_kernel));
rsk.struct_version = 2;
rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
rsk.crc8 = crc8(0, (unsigned char *)&rsk,
offsetof(struct rollback_space_kernel,
crc8));
memcpy(data, &rsk, sizeof(rsk));
} else if (!tpm->nvdata[seq].present) {
put_unaligned_be32(TPM_BADINDEX, recvbuf +
sizeof(uint16_t) + sizeof(uint32_t));
} else {
memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
sizeof(uint32_t), &tpm->nvdata[seq].data,
length);
}
break; break;
case TPM_CMD_EXTEND: case TPM_CMD_EXTEND:
*recv_len = 30; *recv_len = 30;