sandbox: tpm: Enhance to support the latest Chromium OS

This driver was originally written against Chromium OS circa 2012. A few
new features have been added. Enhance the TPM driver to match. This mostly
includes a few new messages and properly modelling whether a particular
'space' is present or not.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2018-10-01 11:55:18 -06:00
parent 998af31903
commit ef8a25006d
2 changed files with 116 additions and 15 deletions

View file

@ -13,6 +13,10 @@
/* 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
@ -45,18 +49,28 @@ 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
* state file if enabled.
*/
static struct tpm_state {
uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
bool valid;
struct nvdata_state nvdata[NV_SEQ_COUNT];
} g_state;
/**
@ -82,9 +96,12 @@ static int sandbox_tpm_read_state(const void *blob, int node)
sprintf(prop_name, "nvdata%d", i);
prop = fdt_getprop(blob, node, prop_name, &len);
if (prop && len == NV_DATA_SIZE)
memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
if (prop && len == NV_DATA_SIZE) {
memcpy(g_state.nvdata[i].data, prop, NV_DATA_SIZE);
g_state.nvdata[i].present = true;
}
}
g_state.valid = true;
return 0;
}
@ -110,9 +127,11 @@ static int sandbox_tpm_write_state(void *blob, int node)
for (i = 0; i < NV_SEQ_COUNT; i++) {
char prop_name[20];
sprintf(prop_name, "nvdata%d", i);
fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
NV_DATA_SIZE);
if (g_state.nvdata[i].present) {
sprintf(prop_name, "nvdata%d", i);
fdt_setprop(blob, node, prop_name,
g_state.nvdata[i].data, NV_DATA_SIZE);
}
}
return 0;
@ -128,6 +147,12 @@ static int index_to_seq(uint32_t 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;
}
@ -136,6 +161,21 @@ static int index_to_seq(uint32_t index)
return -1;
}
static void handle_cap_flag_space(u8 **datap, uint index)
{
struct tpm_nv_data_public pub;
/* TPM_NV_PER_PPWRITE */
memset(&pub, '\0', sizeof(pub));
pub.nv_index = __cpu_to_be32(index);
pub.pcr_info_read.pcr_selection.size_of_select = __cpu_to_be16(
sizeof(pub.pcr_info_read.pcr_selection.pcr_select));
pub.permission.attributes = __cpu_to_be32(1);
pub.pcr_info_write = pub.pcr_info_read;
memcpy(*datap, &pub, sizeof(pub));
*datap += sizeof(pub);
}
static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
size_t send_size, uint8_t *recvbuf,
size_t *recv_len)
@ -159,19 +199,35 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
printf("Get flags index %#02x\n", index);
*recv_len = 22;
memset(recvbuf, '\0', *recv_len);
put_unaligned_be32(22, recvbuf +
TPM_RESPONSE_HEADER_LENGTH);
data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
sizeof(uint32_t);
switch (index) {
case FIRMWARE_NV_INDEX:
break;
case KERNEL_NV_INDEX:
/* TPM_NV_PER_PPWRITE */
put_unaligned_be32(1, data +
NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
handle_cap_flag_space(&data, index);
*recv_len = data - recvbuf -
TPM_RESPONSE_HEADER_LENGTH -
sizeof(uint32_t);
break;
case TPM_CAP_FLAG_PERMANENT: {
struct tpm_permanent_flags *pflags;
pflags = (struct tpm_permanent_flags *)data;
memset(pflags, '\0', sizeof(*pflags));
put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS,
&pflags->tag);
*recv_len = TPM_HEADER_SIZE + 4 +
sizeof(*pflags);
break;
}
default:
printf(" ** Unknown flags index %x\n", index);
return -ENOSYS;
}
put_unaligned_be32(*recv_len,
recvbuf +
TPM_RESPONSE_HEADER_LENGTH);
break;
case TPM_CAP_NV_INDEX:
index = get_unaligned_be32(sendbuf + 18);
@ -192,7 +248,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
if (seq < 0)
return -EINVAL;
printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
tpm->nvdata[seq].present = true;
*recv_len = 12;
memset(recvbuf, '\0', *recv_len);
break;
@ -202,7 +259,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
seq = index_to_seq(index);
if (seq < 0)
return -EINVAL;
printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
length, seq);
*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
length;
memset(recvbuf, '\0', *recv_len);
@ -220,17 +278,26 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
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], length);
sizeof(uint32_t), &tpm->nvdata[seq].data,
length);
}
break;
case TPM_CMD_EXTEND: /* tpm extend */
case TPM_CMD_EXTEND:
*recv_len = 30;
memset(recvbuf, '\0', *recv_len);
break;
case TPM_CMD_NV_DEFINE_SPACE:
case 0x15: /* pcr read */
case 0x5d: /* force clear */
case 0x6f: /* physical enable */
case 0x72: /* physical set deactivated */
case 0x99: /* startup */
case 0x50: /* self test full */
case 0x4000000a: /* assert physical presence */
*recv_len = 12;
memset(recvbuf, '\0', *recv_len);

View file

@ -245,6 +245,40 @@ struct tpm_permanent_flags {
u8 disable_full_da_logic_info;
} __packed;
#define TPM_SHA1_160_HASH_LEN 0x14
struct __packed tpm_composite_hash {
u8 digest[TPM_SHA1_160_HASH_LEN];
};
struct __packed tpm_pcr_selection {
__be16 size_of_select;
u8 pcr_select[3]; /* matches vboot's struct */
};
struct __packed tpm_pcr_info_short {
struct tpm_pcr_selection pcr_selection;
u8 locality_at_release;
struct tpm_composite_hash digest_at_release;
};
struct __packed tpm_nv_attributes {
__be16 tag;
__be32 attributes;
};
struct __packed tpm_nv_data_public {
__be16 tag;
__be32 nv_index;
struct tpm_pcr_info_short pcr_info_read;
struct tpm_pcr_info_short pcr_info_write;
struct tpm_nv_attributes permission;
u8 read_st_clear;
u8 write_st_clear;
u8 write_define;
__be32 data_size;
};
/**
* Issue a TPM_Startup command.
*