I had to think a lot how to put this into few paragraphs.  I hope this will
 makes sense to you and I'm not too confusing.
 
 The bulk of this pull request are Ross Philipson's TPM enablers for the
 Trenchboot patch series.  The commits expose TPM constants, and decouple
 and improve robustness of tpm_buf a bit in order to implement a minimal
 early TPM driver.
 
 Early boot code will call either SKINIT on AMD or GETSEC[SENTER] on Intel
 before jumping into kernel's entry point.  They re-initalize TPM PCRs but
 leave up to the early boot code measure initrd, boot_params and Trenchboot
 associated metadata.
 
 The motivation here is just that we would want in future iterations of the
 series put our full focus to the x86 part of the review, and call it a day
 as per TPM changes.  Further, even if Trenchboot turned out to be empty
 lottery the worst possible outcome for TPM driver is that things get
 cleaned up a bit.
 
 BR, Jarkko
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRE6pSOnaBC00OEHEIaerohdGur0gUCapClFwAKCRAaerohdGur
 0vM5AQDnmMUmfGD4aNBKx/b2gxPIgBy8KTGLDUp5sUSHGVGjuAEAzMLSz3BtTXSV
 7GaPKWp81egVjgp5/zxTbA83mEwfAwk=
 =Pq4i
 -----END PGP SIGNATURE-----

Merge tag 'for-next-tpm-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull TPM updates from Jarkko Sakkinen:
 "The bulk of this is Ross Philipson's TPM enablement for Trenchboot.
  That exposes TPM constants, and decouple and improve robustness of
  tpm_buf a bit in order to implement a minimal early TPM driver.

  Early boot code will call either SKINIT on AMD or GETSEC[SENTER] on
  Intel before jumping into kernel's entry point. They re-initalize TPM
  PCRs but leave up to the early boot code measure initrd, boot_params
  and Trenchboot associated metadata.

  The motivation here is just that we would want in future iterations of
  the series put our full focus to the x86 part of the review, and call
  it a day as per TPM changes. Further, even if Trenchboot turned out to
  be empty lottery the worst possible outcome for TPM driver is that
  things get cleaned up a bit"

* tag 'for-next-tpm-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  tpm-buf: Add TPM buffer support header for standalone reuse
  tpm-buf: Memory-safe allocations
  tpm-buf: Remove chip parameter from tpm_buf_append_handle()
  tpm-buf: Merge TPM_BUF_BOUNDARY_ERROR and TPM_BUF_OVERFLOW
  tpm: Remove main TPM header from TPM event log header
  tpm: Move platform specific definitions to the new PTP header
  tpm: Move TPM common base definitions to the command header
  tpm: Move TPM2 specific definitions to the command header
  tpm: Move TPM1 specific definitions to the command header
  tpm: Initial step to reorganize TPM public headers
  tpm: st33zp24: Validate locality read result
  tpm: st33zp24: Return zero on status read failure
  tpm: tpm_tis_spi: fix nodef CR50 tpm_tis_spi_resume is null
  tpm: atmel: depend on X86
  tpm: Remove redundant dev_err()
  tpm: tpm_i2c_nuvoton: disable IRQ on wait timeout
This commit is contained in:
Linus Torvalds 2026-08-28 09:36:27 -07:00
commit afe0579334
21 changed files with 1261 additions and 1102 deletions

View File

@ -163,8 +163,7 @@ config TCG_NSC
config TCG_ATMEL
tristate "Atmel TPM Interface"
depends on HAS_IOPORT_MAP
depends on HAS_IOPORT
depends on X86
help
If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver

View File

@ -93,7 +93,9 @@ static u8 st33zp24_status(struct tpm_chip *chip)
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
u8 data;
tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1);
if (tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1) != 1)
return 0;
return data;
}
@ -104,10 +106,10 @@ static bool check_locality(struct tpm_chip *chip)
{
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
u8 data;
u8 status;
int status;
status = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_ACCESS, &data, 1);
if (status && (data &
if (status == 1 && (data &
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
return true;

View File

@ -3,94 +3,122 @@
* Handling of TPM command and other buffers.
*/
#include <linux/tpm_command.h>
#include <linux/module.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>
#include <linux/tpm_buf.h>
/**
* tpm_buf_init() - Allocate and initialize a TPM command
* @buf: A &tpm_buf
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*
* Return: 0 or -ENOMEM
*/
int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
static void __tpm_buf_size_invariant(struct tpm_buf *buf, u16 buf_size)
{
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
if (!buf->data)
return -ENOMEM;
u32 buf_size_2 = (u32)buf->capacity + (u32)sizeof(*buf);
tpm_buf_reset(buf, tag, ordinal);
return 0;
if (!buf->capacity) {
if (buf_size > TPM_BUFSIZE) {
WARN(1, "%s: size overflow: %u\n", __func__, buf_size);
buf->flags |= TPM_BUF_INVALID;
}
} else {
if (buf_size != buf_size_2) {
WARN(1, "%s: size mismatch: %u != %u\n", __func__,
buf_size, buf_size_2);
buf->flags |= TPM_BUF_INVALID;
}
}
}
EXPORT_SYMBOL_GPL(tpm_buf_init);
/**
* tpm_buf_reset() - Initialize a TPM command
* @buf: A &tpm_buf
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*/
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
static void __tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag,
u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
__tpm_buf_size_invariant(buf, buf_size);
if (buf->flags & TPM_BUF_INVALID)
return;
WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
tag != TPM2_ST_SESSIONS && tag != 0);
buf->flags = 0;
buf->length = sizeof(*head);
buf->capacity = buf_size - sizeof(*buf);
buf->handles = 0;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
buf->handles = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset);
static void __tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
{
__tpm_buf_size_invariant(buf, buf_size);
if (buf->flags & TPM_BUF_INVALID)
return;
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
buf->capacity = buf_size - sizeof(*buf);
buf->handles = 0;
buf->data[0] = 0;
buf->data[1] = 0;
}
/**
* tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
* @buf: A @tpm_buf
*
* Return: 0 or -ENOMEM
* tpm_buf_init() - Initialize a TPM command
* @buf: A &tpm_buf
* @buf_size: Size of the buffer.
*/
int tpm_buf_init_sized(struct tpm_buf *buf)
void tpm_buf_init(struct tpm_buf *buf, u16 buf_size)
{
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
if (!buf->data)
return -ENOMEM;
memset(buf, 0, buf_size);
__tpm_buf_reset(buf, buf_size, TPM_TAG_RQU_COMMAND, 0);
}
EXPORT_SYMBOL_GPL(tpm_buf_init);
tpm_buf_reset_sized(buf);
return 0;
/**
* tpm_buf_init_sized() - Initialize a sized buffer
* @buf: A &tpm_buf
* @buf_size: Size of the buffer.
*/
void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size)
{
memset(buf, 0, buf_size);
__tpm_buf_reset_sized(buf, buf_size);
}
EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
/**
* tpm_buf_reset_sized() - Initialize a sized buffer
* tpm_buf_reset() - Re-initialize a TPM command
* @buf: A &tpm_buf
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*/
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
u16 buf_size = buf->capacity + sizeof(*buf);
__tpm_buf_reset(buf, buf_size, tag, ordinal);
}
EXPORT_SYMBOL_GPL(tpm_buf_reset);
/**
* tpm_buf_reset_sized() - Re-initialize a sized buffer
* @buf: A &tpm_buf
*/
void tpm_buf_reset_sized(struct tpm_buf *buf)
{
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
buf->data[0] = 0;
buf->data[1] = 0;
u16 buf_size = buf->capacity + sizeof(*buf);
__tpm_buf_reset_sized(buf, buf_size);
}
EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
void tpm_buf_destroy(struct tpm_buf *buf)
{
free_page((unsigned long)buf->data);
}
EXPORT_SYMBOL_GPL(tpm_buf_destroy);
/**
* tpm_buf_length() - Return the number of bytes consumed by the data
* @buf: A &tpm_buf
*
* Return: The number of bytes consumed by the buffer
*/
u32 tpm_buf_length(struct tpm_buf *buf)
u16 tpm_buf_length(struct tpm_buf *buf)
{
return buf->length;
}
@ -104,13 +132,14 @@ EXPORT_SYMBOL_GPL(tpm_buf_length);
*/
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
{
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_OVERFLOW)
u32 total_length = (u32)buf->length + (u32)new_length;
if (buf->flags & TPM_BUF_INVALID)
return;
if ((buf->length + new_length) > PAGE_SIZE) {
if (total_length > (u32)buf->capacity) {
WARN(1, "tpm_buf: write overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
buf->flags |= TPM_BUF_INVALID;
return;
}
@ -148,17 +177,20 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
/**
* tpm_buf_append_handle() - Add a handle
* @chip: &tpm_chip instance
* @buf: &tpm_buf instance
* @handle: a TPM object handle
*
* Add a handle to the buffer, and increase the count tracking the number of
* handles in the command buffer. Works only for command buffers.
*/
void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle)
void tpm_buf_append_handle(struct tpm_buf *buf, u32 handle)
{
if (buf->flags & TPM_BUF_INVALID)
return;
if (buf->flags & TPM_BUF_TPM2B) {
dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n");
WARN(1, "tpm-buf: invalid type: TPM2B\n");
buf->flags |= TPM_BUF_INVALID;
return;
}
@ -177,14 +209,13 @@ static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count, void
{
off_t next_offset;
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_BOUNDARY_ERROR)
if (buf->flags & TPM_BUF_INVALID)
return;
next_offset = *offset + count;
if (next_offset > buf->length) {
WARN(1, "tpm_buf: read out of boundary\n");
buf->flags |= TPM_BUF_BOUNDARY_ERROR;
buf->flags |= TPM_BUF_INVALID;
return;
}

View File

@ -32,28 +32,35 @@ struct tpm_readpubek_out {
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out;
int i;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
char anti_replay[20];
struct tpm_buf *tpm_buf __free(kfree) = NULL;
memset(&anti_replay, 0, sizeof(anti_replay));
if (tpm_try_get_ops(chip))
return 0;
if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
goto out_ops;
tpm_buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!tpm_buf) {
tpm_put_ops(chip);
return 0;
}
tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
tpm_buf_init(tpm_buf, TPM_BUFSIZE);
tpm_buf_reset(tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK"))
goto out_buf;
if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK")) {
tpm_put_ops(chip);
return 0;
}
out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
str +=
sprintf(str,
"Algorithm: %4ph\n"
@ -71,9 +78,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
for (i = 0; i < 256; i += 16)
str += sprintf(str, "%16ph\n", &out->modulus[i]);
out_buf:
tpm_buf_destroy(&tpm_buf);
out_ops:
tpm_put_ops(chip);
return str - buf;
}

View File

@ -33,7 +33,6 @@
#endif
#define TPM_MINOR 224 /* officially assigned */
#define TPM_BUFSIZE 4096
#define TPM_NUM_DEVICES 65536
#define TPM_RETRY 50
@ -52,185 +51,6 @@ enum tpm_addr {
TPM_ADDR = 0x4E,
};
#define TPM_WARN_RETRY 0x800
#define TPM_WARN_DOING_SELFTEST 0x802
#define TPM_ERR_DEACTIVATED 0x6
#define TPM_ERR_DISABLED 0x7
#define TPM_ERR_FAILEDSELFTEST 0x1C
#define TPM_ERR_INVALID_POSTINIT 38
#define TPM_TAG_RQU_COMMAND 193
/* TPM2 specific constants. */
#define TPM2_SPACE_BUFFER_SIZE 16384 /* 16 kB */
struct stclear_flags_t {
__be16 tag;
u8 deactivated;
u8 disableForceClear;
u8 physicalPresence;
u8 physicalPresenceLock;
u8 bGlobalLock;
} __packed;
struct tpm1_version {
u8 major;
u8 minor;
u8 rev_major;
u8 rev_minor;
} __packed;
struct tpm1_version2 {
__be16 tag;
struct tpm1_version version;
} __packed;
struct timeout_t {
__be32 a;
__be32 b;
__be32 c;
__be32 d;
} __packed;
struct duration_t {
__be32 tpm_short;
__be32 tpm_medium;
__be32 tpm_long;
} __packed;
struct permanent_flags_t {
__be16 tag;
u8 disable;
u8 ownership;
u8 deactivated;
u8 readPubek;
u8 disableOwnerClear;
u8 allowMaintenance;
u8 physicalPresenceLifetimeLock;
u8 physicalPresenceHWEnable;
u8 physicalPresenceCMDEnable;
u8 CEKPUsed;
u8 TPMpost;
u8 TPMpostLock;
u8 FIPS;
u8 operator;
u8 enableRevokeEK;
u8 nvLocked;
u8 readSRKPub;
u8 tpmEstablished;
u8 maintenanceDone;
u8 disableFullDALogicInfo;
} __packed;
typedef union {
struct permanent_flags_t perm_flags;
struct stclear_flags_t stclear_flags;
__u8 owned;
__be32 num_pcrs;
struct tpm1_version version1;
struct tpm1_version2 version2;
__be32 manufacturer_id;
struct timeout_t timeout;
struct duration_t duration;
} cap_t;
enum tpm_capabilities {
TPM_CAP_FLAG = 4,
TPM_CAP_PROP = 5,
TPM_CAP_VERSION_1_1 = 0x06,
TPM_CAP_VERSION_1_2 = 0x1A,
};
enum tpm_sub_capabilities {
TPM_CAP_PROP_PCR = 0x101,
TPM_CAP_PROP_MANUFACTURER = 0x103,
TPM_CAP_FLAG_PERM = 0x108,
TPM_CAP_FLAG_VOL = 0x109,
TPM_CAP_PROP_OWNER = 0x111,
TPM_CAP_PROP_TIS_TIMEOUT = 0x115,
TPM_CAP_PROP_TIS_DURATION = 0x120,
};
enum tpm2_pt_props {
TPM2_PT_NONE = 0x00000000,
TPM2_PT_GROUP = 0x00000100,
TPM2_PT_FIXED = TPM2_PT_GROUP * 1,
TPM2_PT_FAMILY_INDICATOR = TPM2_PT_FIXED + 0,
TPM2_PT_LEVEL = TPM2_PT_FIXED + 1,
TPM2_PT_REVISION = TPM2_PT_FIXED + 2,
TPM2_PT_DAY_OF_YEAR = TPM2_PT_FIXED + 3,
TPM2_PT_YEAR = TPM2_PT_FIXED + 4,
TPM2_PT_MANUFACTURER = TPM2_PT_FIXED + 5,
TPM2_PT_VENDOR_STRING_1 = TPM2_PT_FIXED + 6,
TPM2_PT_VENDOR_STRING_2 = TPM2_PT_FIXED + 7,
TPM2_PT_VENDOR_STRING_3 = TPM2_PT_FIXED + 8,
TPM2_PT_VENDOR_STRING_4 = TPM2_PT_FIXED + 9,
TPM2_PT_VENDOR_TPM_TYPE = TPM2_PT_FIXED + 10,
TPM2_PT_FIRMWARE_VERSION_1 = TPM2_PT_FIXED + 11,
TPM2_PT_FIRMWARE_VERSION_2 = TPM2_PT_FIXED + 12,
TPM2_PT_INPUT_BUFFER = TPM2_PT_FIXED + 13,
TPM2_PT_HR_TRANSIENT_MIN = TPM2_PT_FIXED + 14,
TPM2_PT_HR_PERSISTENT_MIN = TPM2_PT_FIXED + 15,
TPM2_PT_HR_LOADED_MIN = TPM2_PT_FIXED + 16,
TPM2_PT_ACTIVE_SESSIONS_MAX = TPM2_PT_FIXED + 17,
TPM2_PT_PCR_COUNT = TPM2_PT_FIXED + 18,
TPM2_PT_PCR_SELECT_MIN = TPM2_PT_FIXED + 19,
TPM2_PT_CONTEXT_GAP_MAX = TPM2_PT_FIXED + 20,
TPM2_PT_NV_COUNTERS_MAX = TPM2_PT_FIXED + 22,
TPM2_PT_NV_INDEX_MAX = TPM2_PT_FIXED + 23,
TPM2_PT_MEMORY = TPM2_PT_FIXED + 24,
TPM2_PT_CLOCK_UPDATE = TPM2_PT_FIXED + 25,
TPM2_PT_CONTEXT_HASH = TPM2_PT_FIXED + 26,
TPM2_PT_CONTEXT_SYM = TPM2_PT_FIXED + 27,
TPM2_PT_CONTEXT_SYM_SIZE = TPM2_PT_FIXED + 28,
TPM2_PT_ORDERLY_COUNT = TPM2_PT_FIXED + 29,
TPM2_PT_MAX_COMMAND_SIZE = TPM2_PT_FIXED + 30,
TPM2_PT_MAX_RESPONSE_SIZE = TPM2_PT_FIXED + 31,
TPM2_PT_MAX_DIGEST = TPM2_PT_FIXED + 32,
TPM2_PT_MAX_OBJECT_CONTEXT = TPM2_PT_FIXED + 33,
TPM2_PT_MAX_SESSION_CONTEXT = TPM2_PT_FIXED + 34,
TPM2_PT_PS_FAMILY_INDICATOR = TPM2_PT_FIXED + 35,
TPM2_PT_PS_LEVEL = TPM2_PT_FIXED + 36,
TPM2_PT_PS_REVISION = TPM2_PT_FIXED + 37,
TPM2_PT_PS_DAY_OF_YEAR = TPM2_PT_FIXED + 38,
TPM2_PT_PS_YEAR = TPM2_PT_FIXED + 39,
TPM2_PT_SPLIT_MAX = TPM2_PT_FIXED + 40,
TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41,
TPM2_PT_LIBRARY_COMMANDS = TPM2_PT_FIXED + 42,
TPM2_PT_VENDOR_COMMANDS = TPM2_PT_FIXED + 43,
TPM2_PT_NV_BUFFER_MAX = TPM2_PT_FIXED + 44,
TPM2_PT_MODES = TPM2_PT_FIXED + 45,
TPM2_PT_MAX_CAP_BUFFER = TPM2_PT_FIXED + 46,
TPM2_PT_VAR = TPM2_PT_GROUP * 2,
TPM2_PT_PERMANENT = TPM2_PT_VAR + 0,
TPM2_PT_STARTUP_CLEAR = TPM2_PT_VAR + 1,
TPM2_PT_HR_NV_INDEX = TPM2_PT_VAR + 2,
TPM2_PT_HR_LOADED = TPM2_PT_VAR + 3,
TPM2_PT_HR_LOADED_AVAIL = TPM2_PT_VAR + 4,
TPM2_PT_HR_ACTIVE = TPM2_PT_VAR + 5,
TPM2_PT_HR_ACTIVE_AVAIL = TPM2_PT_VAR + 6,
TPM2_PT_HR_TRANSIENT_AVAIL = TPM2_PT_VAR + 7,
TPM2_PT_HR_PERSISTENT = TPM2_PT_VAR + 8,
TPM2_PT_HR_PERSISTENT_AVAIL = TPM2_PT_VAR + 9,
TPM2_PT_NV_COUNTERS = TPM2_PT_VAR + 10,
TPM2_PT_NV_COUNTERS_AVAIL = TPM2_PT_VAR + 11,
TPM2_PT_ALGORITHM_SET = TPM2_PT_VAR + 12,
TPM2_PT_LOADED_CURVES = TPM2_PT_VAR + 13,
TPM2_PT_LOCKOUT_COUNTER = TPM2_PT_VAR + 14,
TPM2_PT_MAX_AUTH_FAIL = TPM2_PT_VAR + 15,
TPM2_PT_LOCKOUT_INTERVAL = TPM2_PT_VAR + 16,
TPM2_PT_LOCKOUT_RECOVERY = TPM2_PT_VAR + 17,
TPM2_PT_NV_WRITE_RECOVERY = TPM2_PT_VAR + 18,
TPM2_PT_AUDIT_COUNTER_0 = TPM2_PT_VAR + 19,
TPM2_PT_AUDIT_COUNTER_1 = TPM2_PT_VAR + 20,
};
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and
* anything much bigger causes users of struct tpm_cmd_t to start getting
* compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128
extern const struct class tpm_class;
extern const struct class tpmrm_class;
extern dev_t tpm_devt;

View File

@ -22,8 +22,6 @@
#include "tpm.h"
#define TPM_MAX_ORDINAL 243
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The ordinal
@ -308,9 +306,6 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
return duration;
}
#define TPM_ORD_STARTUP 153
#define TPM_ST_CLEAR 1
/**
* tpm1_startup() - turn on the TPM
* @chip: TPM chip to use
@ -323,20 +318,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
*/
static int tpm1_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
struct tpm_buf *buf __free(kfree) = NULL;
dev_info(&chip->dev, "starting up the TPM manually\n");
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
if (rc < 0)
return rc;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
tpm_buf_append_u16(buf, TPM_ST_CLEAR);
return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
int tpm1_get_timeouts(struct tpm_chip *chip)
@ -459,64 +452,56 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
return 0;
}
#define TPM_ORD_PCR_EXTEND 20
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
struct tpm_buf buf;
int rc;
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
if (rc)
return rc;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
tpm_buf_append_u32(buf, pcr_idx);
tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
tpm_buf_append_u32(&buf, pcr_idx);
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
tpm_buf_destroy(&buf);
return rc;
return tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
}
#define TPM_ORD_GET_CAP 101
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (rc)
return rc;
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
tpm_buf_append_u32(&buf, subcap_id);
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(buf, subcap_id);
tpm_buf_append_u32(buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
tpm_buf_append_u32(buf, TPM_CAP_FLAG);
else
tpm_buf_append_u32(&buf, TPM_CAP_PROP);
tpm_buf_append_u32(buf, TPM_CAP_PROP);
tpm_buf_append_u32(&buf, 4);
tpm_buf_append_u32(&buf, subcap_id);
tpm_buf_append_u32(buf, 4);
tpm_buf_append_u32(buf, subcap_id);
}
rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
tpm_buf_destroy(&buf);
*cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
#define TPM_ORD_GET_RANDOM 70
struct tpm1_get_random_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
} __packed;
/**
* tpm1_get_random() - get random bytes from the TPM's RNG
* @chip: a &struct tpm_chip instance
@ -530,86 +515,80 @@ struct tpm1_get_random_out {
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm1_get_random_out *out;
struct tpm_buf *buf __free(kfree) = NULL;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
struct tpm_buf buf;
u32 total = 0;
int retries = 5;
u32 recd;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
if (rc)
return rc;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
do {
tpm_buf_append_u32(&buf, num_bytes);
tpm_buf_append_u32(buf, num_bytes);
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
"attempting get random");
if (rc) {
if (rc > 0)
rc = -EIO;
goto out;
return rc;
}
out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
recd = be32_to_cpu(out->rng_data_len);
if (recd > num_bytes) {
rc = -EFAULT;
goto out;
}
if (recd > num_bytes)
return -EFAULT;
if (tpm_buf_length(buf) < TPM_HEADER_SIZE +
sizeof(out->rng_data_len) + recd)
return -EFAULT;
if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
sizeof(out->rng_data_len) + recd) {
rc = -EFAULT;
goto out;
}
memcpy(dest, out->rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
out:
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_READ);
tpm_buf_append_u32(buf, pcr_idx);
rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
return rc;
tpm_buf_append_u32(&buf, pcr_idx);
if (tpm_buf_length(buf) < TPM_DIGEST_SIZE)
return -EFAULT;
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
goto out;
memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
rc = -EFAULT;
goto out;
}
memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
out:
tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_CONTINUE_SELFTEST 83
/**
* tpm1_continue_selftest() - run TPM's selftest
* @chip: TPM chip to use
@ -619,16 +598,13 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
if (rc)
return rc;
rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
tpm_buf_destroy(&buf);
return rc;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
return tpm_transmit_cmd(chip, buf, 0, "continue selftest");
}
/**
@ -726,8 +702,6 @@ int tpm1_auto_startup(struct tpm_chip *chip)
return rc;
}
#define TPM_ORD_SAVESTATE 152
/**
* tpm1_pm_suspend() - pm suspend handler
* @chip: TPM chip to use.
@ -742,22 +716,24 @@ int tpm1_auto_startup(struct tpm_chip *chip)
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
struct tpm_buf buf;
unsigned int try;
struct tpm_buf *buf __free(kfree) = NULL;
int rc;
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
if (rc)
return rc;
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
@ -772,7 +748,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
}
if (rc)
@ -782,8 +758,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
tpm_buf_destroy(&buf);
return rc;
}

View File

@ -94,17 +94,6 @@ unsigned long tpm2_calc_ordinal_duration(u32 ordinal)
return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
}
struct tpm2_pcr_read_out {
__be32 update_cnt;
__be32 pcr_selects_cnt;
__be16 hash_alg;
u8 pcr_select_size;
u8 pcr_select[TPM2_PCR_SELECT_MIN];
__be32 digests_cnt;
__be16 digest_size;
u8 digest[];
} __packed;
/**
* tpm2_pcr_read() - read a PCR value
* @chip: TPM chip to use.
@ -119,12 +108,13 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
{
int i;
int rc;
struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
u16 digest_size;
u16 expected_digest_size = 0;
struct tpm_buf *buf __free(kfree) = NULL;
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
@ -139,36 +129,35 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
expected_digest_size = chip->allocated_banks[i].digest_size;
}
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
if (rc)
return rc;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
tpm_buf_append_u32(&buf, 1);
tpm_buf_append_u16(&buf, digest->alg_id);
tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
tpm_buf_append(&buf, (const unsigned char *)pcr_select,
tpm_buf_append_u32(buf, 1);
tpm_buf_append_u16(buf, digest->alg_id);
tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
tpm_buf_append(buf, (const unsigned char *)pcr_select,
sizeof(pcr_select));
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
if (rc)
goto out;
return rc;
out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
digest_size = be16_to_cpu(out->digest_size);
if (digest_size > sizeof(digest->digest) ||
(!digest_size_ptr && digest_size != expected_digest_size)) {
rc = -EINVAL;
goto out;
}
(!digest_size_ptr && digest_size != expected_digest_size))
return -EINVAL;
if (digest_size_ptr)
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
out:
tpm_buf_destroy(&buf);
return rc;
}
@ -184,7 +173,7 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
struct tpm_buf buf;
struct tpm_buf *buf __free(kfree) = NULL;
int rc;
int i;
@ -194,55 +183,49 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
return rc;
}
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc) {
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
if (!disable_pcr_integrity)
tpm2_end_auth_session(chip);
return rc;
return -ENOMEM;
}
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (!disable_pcr_integrity) {
rc = tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
rc = tpm_buf_append_name(chip, buf, pcr_idx, NULL);
if (rc) {
tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return rc;
}
tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
} else {
tpm_buf_append_handle(chip, &buf, pcr_idx);
tpm_buf_append_auth(chip, &buf, NULL, 0);
tpm_buf_append_handle(buf, pcr_idx);
tpm_buf_append_auth(chip, buf, NULL, 0);
}
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
tpm_buf_append_u32(buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) {
tpm_buf_append_u16(&buf, digests[i].alg_id);
tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
tpm_buf_append_u16(buf, digests[i].alg_id);
tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
chip->allocated_banks[i].digest_size);
}
if (!disable_pcr_integrity) {
rc = tpm_buf_fill_hmac_session(chip, &buf);
if (rc) {
tpm_buf_destroy(&buf);
rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
return rc;
}
}
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
if (!disable_pcr_integrity)
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
tpm_buf_destroy(&buf);
rc = tpm_buf_check_hmac_response(chip, buf, rc);
return rc;
}
struct tpm2_get_random_out {
__be16 size;
u8 buffer[TPM_MAX_RNG_DATA];
} __packed;
/**
* tpm2_get_random() - get random bytes from the TPM RNG
*
@ -258,7 +241,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
struct tpm_header *head;
struct tpm_buf buf;
u32 recd;
u32 num_bytes = max;
int err;
@ -267,6 +249,8 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
u8 *dest_ptr = dest;
off_t offset;
struct tpm_buf *buf __free(kfree) = NULL;
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
@ -274,55 +258,58 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
if (err)
return err;
err = tpm_buf_init(&buf, 0, 0);
if (err) {
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
tpm2_end_auth_session(chip);
return err;
return -ENOMEM;
}
tpm_buf_init(buf, TPM_BUFSIZE);
do {
tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
if (tpm2_chip_auth(chip)) {
tpm_buf_append_hmac_session(chip, &buf,
tpm_buf_append_hmac_session(chip, buf,
TPM2_SA_ENCRYPT |
TPM2_SA_CONTINUE_SESSION,
NULL, 0);
} else {
offset = buf.handles * 4 + TPM_HEADER_SIZE;
head = (struct tpm_header *)buf.data;
if (tpm_buf_length(&buf) == offset)
offset = buf->handles * 4 + TPM_HEADER_SIZE;
head = (struct tpm_header *)buf->data;
if (tpm_buf_length(buf) == offset)
head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
}
tpm_buf_append_u16(&buf, num_bytes);
err = tpm_buf_fill_hmac_session(chip, &buf);
tpm_buf_append_u16(buf, num_bytes);
err = tpm_buf_fill_hmac_session(chip, buf);
if (err)
goto out;
return err;
err = tpm_transmit_cmd(chip, &buf,
err = tpm_transmit_cmd(chip, buf,
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
err = tpm_buf_check_hmac_response(chip, &buf, err);
err = tpm_buf_check_hmac_response(chip, buf, err);
if (err) {
if (err > 0)
err = -EIO;
goto out;
tpm2_end_auth_session(chip);
return err;
}
head = (struct tpm_header *)buf.data;
head = (struct tpm_header *)buf->data;
offset = TPM_HEADER_SIZE;
/* Skip the parameter size field: */
if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
offset += 4;
out = (struct tpm2_get_random_out *)&buf.data[offset];
out = (struct tpm2_get_random_out *)&buf->data[offset];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
if (tpm_buf_length(&buf) <
if (tpm_buf_length(buf) <
TPM_HEADER_SIZE +
offsetof(struct tpm2_get_random_out, buffer) +
recd) {
err = -EFAULT;
goto out;
tpm2_end_auth_session(chip);
return -EFAULT;
}
memcpy(dest_ptr, out->buffer, recd);
@ -331,13 +318,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
tpm_buf_destroy(&buf);
return total ? total : -EIO;
out:
tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return err;
}
/**
@ -347,31 +328,21 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
if (rc) {
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
tpm_buf_append_u32(&buf, handle);
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
tpm_buf_append_u32(buf, handle);
tpm_transmit_cmd(chip, &buf, 0, "flushing context");
tpm_buf_destroy(&buf);
tpm_transmit_cmd(chip, buf, 0, "flushing context");
}
EXPORT_SYMBOL_GPL(tpm2_flush_context);
struct tpm2_get_cap_out {
u8 more_data;
__be32 subcap_id;
__be32 property_cnt;
__be32 property_id;
__be32 value;
} __packed;
/**
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
* @chip: a &tpm_chip instance
@ -387,19 +358,21 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, property_id);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(buf, property_id);
tpm_buf_append_u32(buf, 1);
rc = tpm_transmit_cmd(chip, buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
&buf.data[TPM_HEADER_SIZE];
&buf->data[TPM_HEADER_SIZE];
/*
* To prevent failing boot up of some systems, Infineon TPM2.0
* returns SUCCESS on TPM2_Startup in field upgrade mode. Also
@ -411,7 +384,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
else
rc = -ENODATA;
}
tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
@ -428,15 +400,14 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
if (rc)
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return;
tpm_buf_append_u16(&buf, shutdown_type);
tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
tpm_buf_destroy(&buf);
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
tpm_buf_append_u16(buf, shutdown_type);
tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
}
/**
@ -454,20 +425,21 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
struct tpm_buf buf;
int full;
int rc;
for (full = 0; full < 2; full++) {
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
if (rc)
return rc;
struct tpm_buf *buf __free(kfree) = NULL;
tpm_buf_append_u8(&buf, full);
rc = tpm_transmit_cmd(chip, &buf, 0,
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
tpm_buf_append_u8(buf, full);
rc = tpm_transmit_cmd(chip, buf, 0,
"attempting the self test");
tpm_buf_destroy(&buf);
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
@ -492,23 +464,24 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm_header *out;
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
tpm_buf_append_u32(buf, 1);
rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
out = (struct tpm_header *)buf.data;
out = (struct tpm_header *)buf->data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
tpm_buf_destroy(&buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
@ -539,16 +512,9 @@ static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index)
return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size);
}
struct tpm2_pcr_selection {
__be16 hash_alg;
u8 size_of_select;
u8 pcr_select[3];
} __packed;
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
struct tpm_buf buf;
void *marker;
void *end;
void *pcr_select_offset;
@ -560,31 +526,32 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
int rc;
int i = 0;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
tpm_buf_append_u32(buf, 0);
tpm_buf_append_u32(buf, 1);
rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
if (rc)
goto out;
nr_possible_banks = be32_to_cpup(
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
(__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
if (nr_possible_banks > TPM2_MAX_PCR_BANKS) {
pr_err("tpm: out of bank capacity: %u > %u\n",
nr_possible_banks, TPM2_MAX_PCR_BANKS);
rc = -ENOMEM;
goto out;
return -ENOMEM;
}
marker = &buf.data[TPM_HEADER_SIZE + 9];
marker = &buf->data[TPM_HEADER_SIZE + 9];
rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
end = &buf.data[rsp_len];
rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
end = &buf->data[rsp_len];
for (i = 0; i < nr_possible_banks; i++) {
pcr_select_offset = marker +
@ -616,21 +583,20 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
}
chip->nr_allocated_banks = nr_alloc_banks;
out:
tpm_buf_destroy(&buf);
return rc;
}
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
u32 cc;
int i;
int rc;
struct tpm_buf *buf __free(kfree) = NULL;
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
goto out;
@ -647,30 +613,31 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
goto out;
}
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
goto out;
tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
tpm_buf_append_u32(&buf, nr_commands);
rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
if (rc) {
tpm_buf_destroy(&buf);
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto out;
}
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
tpm_buf_append_u32(buf, TPM2_CC_FIRST);
tpm_buf_append_u32(buf, nr_commands);
rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
if (rc)
goto out;
if (nr_commands !=
be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
rc = -EFAULT;
tpm_buf_destroy(&buf);
goto out;
}
chip->nr_commands = nr_commands;
attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
@ -682,8 +649,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
}
}
tpm_buf_destroy(&buf);
out:
if (rc > 0)
rc = -ENODEV;
@ -704,20 +669,18 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
static int tpm2_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
struct tpm_buf *buf __free(kfree) = NULL;
dev_info(&chip->dev, "starting up the TPM manually\n");
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
if (rc < 0)
return rc;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
/**

View File

@ -167,8 +167,8 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
{
u32 mso = tpm2_handle_mso(handle);
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf *buf __free(kfree) = NULL;
int rc, name_size_alg;
struct tpm_buf buf;
if (mso != TPM2_MSO_PERSISTENT && mso != TPM2_MSO_VOLATILE &&
mso != TPM2_MSO_NVRAM) {
@ -176,50 +176,40 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
return sizeof(u32);
}
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
tpm_buf_append_u32(buf, handle);
rc = tpm_transmit_cmd(chip, buf, 0, "TPM2_ReadPublic");
if (rc)
return rc;
tpm_buf_append_u32(&buf, handle);
rc = tpm_transmit_cmd(chip, &buf, 0, "TPM2_ReadPublic");
if (rc) {
tpm_buf_destroy(&buf);
return tpm_ret_to_err(rc);
}
/* Skip TPMT_PUBLIC: */
offset += tpm_buf_read_u16(&buf, &offset);
offset += tpm_buf_read_u16(buf, &offset);
/*
* Ensure space for the length field of TPM2B_NAME and hashAlg field of
* TPMT_HA (the extra four bytes).
*/
if (offset + 4 > tpm_buf_length(&buf)) {
tpm_buf_destroy(&buf);
if (offset + 4 > tpm_buf_length(buf))
return -EIO;
}
rc = tpm_buf_read_u16(&buf, &offset);
name_size_alg = name_size(&buf.data[offset]);
if (name_size_alg < 0) {
tpm_buf_destroy(&buf);
rc = tpm_buf_read_u16(buf, &offset);
name_size_alg = name_size(&buf->data[offset]);
if (name_size_alg < 0)
return name_size_alg;
}
if (rc != name_size_alg) {
tpm_buf_destroy(&buf);
if (rc != name_size_alg)
return -EIO;
}
if (offset + rc > tpm_buf_length(&buf)) {
tpm_buf_destroy(&buf);
if (offset + rc > tpm_buf_length(buf))
return -EIO;
}
memcpy(name, &buf.data[offset], rc);
tpm_buf_destroy(&buf);
memcpy(name, &buf->data[offset], rc);
return name_size_alg;
}
#endif /* CONFIG_TCG_TPM2_HMAC */
@ -260,7 +250,7 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
#endif
if (!tpm2_chip_auth(chip)) {
tpm_buf_append_handle(chip, buf, handle);
tpm_buf_append_handle(buf, handle);
return 0;
}
@ -1005,8 +995,8 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
*/
int tpm2_start_auth_session(struct tpm_chip *chip)
{
struct tpm_buf *buf __free(kfree) = NULL;
struct tpm2_auth *auth;
struct tpm_buf buf;
u32 null_key;
int rc;
@ -1020,58 +1010,61 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
return -ENOMEM;
rc = tpm2_load_null(chip, &null_key);
if (rc)
goto out;
if (rc) {
kfree_sensitive(auth);
return rc;
}
auth->session = TPM_HEADER_SIZE;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
if (rc)
goto out;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
kfree_sensitive(auth);
return -ENOMEM;
}
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
/* salt key handle */
tpm_buf_append_u32(&buf, null_key);
tpm_buf_append_u32(buf, null_key);
/* bind key handle */
tpm_buf_append_u32(&buf, TPM2_RH_NULL);
tpm_buf_append_u32(buf, TPM2_RH_NULL);
/* nonce caller */
get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
/* append encrypted salt and squirrel away unencrypted in auth */
rc = tpm_buf_append_salt(&buf, chip, auth);
rc = tpm_buf_append_salt(buf, chip, auth);
if (rc) {
tpm2_flush_context(chip, null_key);
tpm_buf_destroy(&buf);
goto out;
kfree_sensitive(auth);
return rc;
}
/* session type (HMAC, audit or policy) */
tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
tpm_buf_append_u8(buf, TPM2_SE_HMAC);
/* symmetric encryption parameters */
/* symmetric algorithm */
tpm_buf_append_u16(&buf, TPM_ALG_AES);
tpm_buf_append_u16(buf, TPM_ALG_AES);
/* bits for symmetric algorithm */
tpm_buf_append_u16(&buf, AES_KEY_BITS);
tpm_buf_append_u16(buf, AES_KEY_BITS);
/* symmetric algorithm mode (must be CFB) */
tpm_buf_append_u16(&buf, TPM_ALG_CFB);
tpm_buf_append_u16(buf, TPM_ALG_CFB);
/* hash algorithm for session */
tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
tpm_buf_append_u16(buf, TPM_ALG_SHA256);
rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
tpm2_flush_context(chip, null_key);
if (rc == TPM2_RC_SUCCESS)
rc = tpm2_parse_start_auth_session(auth, &buf);
tpm_buf_destroy(&buf);
rc = tpm2_parse_start_auth_session(auth, buf);
if (rc == TPM2_RC_SUCCESS) {
chip->auth = auth;
return 0;
}
out:
kfree_sensitive(auth);
return rc;
}
@ -1285,19 +1278,21 @@ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name)
{
struct tpm_buf *template __free(kfree) = NULL;
struct tpm_buf *buf __free(kfree) = NULL;
int rc;
struct tpm_buf buf;
struct tpm_buf template;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
if (rc)
return rc;
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
rc = tpm_buf_init_sized(&template);
if (rc) {
tpm_buf_destroy(&buf);
return rc;
}
template = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!template)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
tpm_buf_init_sized(template, TPM_BUFSIZE);
/*
* create the template. Note: in order for userspace to
@ -1309,75 +1304,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
*/
/* key type */
tpm_buf_append_u16(&template, TPM_ALG_ECC);
tpm_buf_append_u16(template, TPM_ALG_ECC);
/* name algorithm */
tpm_buf_append_u16(&template, TPM_ALG_SHA256);
tpm_buf_append_u16(template, TPM_ALG_SHA256);
/* object properties */
tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
/* sauth policy (empty) */
tpm_buf_append_u16(&template, 0);
tpm_buf_append_u16(template, 0);
/* BEGIN parameters: key specific; for ECC*/
/* symmetric algorithm */
tpm_buf_append_u16(&template, TPM_ALG_AES);
tpm_buf_append_u16(template, TPM_ALG_AES);
/* bits for symmetric algorithm */
tpm_buf_append_u16(&template, AES_KEY_BITS);
tpm_buf_append_u16(template, AES_KEY_BITS);
/* algorithm mode (must be CFB) */
tpm_buf_append_u16(&template, TPM_ALG_CFB);
tpm_buf_append_u16(template, TPM_ALG_CFB);
/* scheme (NULL means any scheme) */
tpm_buf_append_u16(&template, TPM_ALG_NULL);
tpm_buf_append_u16(template, TPM_ALG_NULL);
/* ECC Curve ID */
tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
/* KDF Scheme */
tpm_buf_append_u16(&template, TPM_ALG_NULL);
tpm_buf_append_u16(template, TPM_ALG_NULL);
/* unique: key specific; for ECC it is two zero size points */
tpm_buf_append_u16(&template, 0);
tpm_buf_append_u16(&template, 0);
tpm_buf_append_u16(template, 0);
tpm_buf_append_u16(template, 0);
/* END parameters */
/* primary handle */
tpm_buf_append_u32(&buf, hierarchy);
tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
tpm_buf_append_u32(buf, hierarchy);
tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
/* sensitive create size is 4 for two empty buffers */
tpm_buf_append_u16(&buf, 4);
tpm_buf_append_u16(buf, 4);
/* sensitive create auth data (empty) */
tpm_buf_append_u16(&buf, 0);
tpm_buf_append_u16(buf, 0);
/* sensitive create sensitive data (empty) */
tpm_buf_append_u16(&buf, 0);
tpm_buf_append_u16(buf, 0);
/* the public template */
tpm_buf_append(&buf, template.data, template.length);
tpm_buf_destroy(&template);
tpm_buf_append(buf, template->data, template->length);
/* outside info (empty) */
tpm_buf_append_u16(&buf, 0);
tpm_buf_append_u16(buf, 0);
/* creation PCR (none) */
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(buf, 0);
rc = tpm_transmit_cmd(chip, &buf, 0,
rc = tpm_transmit_cmd(chip, buf, 0,
"attempting to create NULL primary");
if (rc == TPM2_RC_SUCCESS)
rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
name);
tpm_buf_destroy(&buf);
return rc;
}

View File

@ -15,19 +15,6 @@
#include <linux/unaligned.h>
#include "tpm.h"
enum tpm2_handle_types {
TPM2_HT_HMAC_SESSION = 0x02000000,
TPM2_HT_POLICY_SESSION = 0x03000000,
TPM2_HT_TRANSIENT = 0x80000000,
};
struct tpm2_context {
__be64 sequence;
__be32 saved_handle;
__be32 hierarchy;
__be16 blob_size;
} __packed;
static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
{
int i;
@ -71,24 +58,25 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
struct tpm_buf tbuf;
struct tpm2_context *ctx;
unsigned int body_size;
int rc;
rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
if (rc)
return rc;
struct tpm_buf *tbuf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!tbuf)
return -ENOMEM;
tpm_buf_init(tbuf, TPM_BUFSIZE);
tpm_buf_reset(tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
tpm_buf_append(&tbuf, &buf[*offset], body_size);
tpm_buf_append(tbuf, &buf[*offset], body_size);
rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
@ -103,64 +91,55 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
* flushed outside the space
*/
*handle = 0;
tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
tpm_buf_destroy(&tbuf);
return -EINVAL;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
}
*handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
*handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
*offset += body_size;
tpm_buf_destroy(&tbuf);
return 0;
}
int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset)
{
struct tpm_buf tbuf;
unsigned int body_size;
int rc;
rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
if (rc)
return rc;
struct tpm_buf *tbuf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!tbuf)
return -ENOMEM;
tpm_buf_append_u32(&tbuf, handle);
tpm_buf_init(tbuf, TPM_BUFSIZE);
tpm_buf_reset(tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
tpm_buf_append_u32(tbuf, handle);
rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (rc) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
}
body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
if ((*offset + body_size) > buf_size) {
dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
tpm_buf_destroy(&tbuf);
return -ENOMEM;
}
memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
*offset += body_size;
tpm_buf_destroy(&tbuf);
return 0;
}

View File

@ -182,8 +182,10 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
timeout);
if (rc > 0)
return 0;
/* At this point we know that the SINT pin is asserted, so we
* do not need to do i2c_nuvoton_check_status */
disable_irq(priv->irq);
if (rc < 0)
return rc;
} else {
unsigned long ten_msec, stop;
bool status_valid;

View File

@ -19,71 +19,9 @@
#ifndef __TPM_TIS_CORE_H__
#define __TPM_TIS_CORE_H__
#include <linux/tpm_ptp.h>
#include "tpm.h"
enum tis_access {
TPM_ACCESS_VALID = 0x80,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
TPM_ACCESS_REQUEST_PENDING = 0x04,
TPM_ACCESS_REQUEST_USE = 0x02,
};
enum tis_status {
TPM_STS_VALID = 0x80,
TPM_STS_COMMAND_READY = 0x40,
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
TPM_STS_RESPONSE_RETRY = 0x02,
TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
};
enum tis_int_flags {
TPM_GLOBAL_INT_ENABLE = 0x80000000,
TPM_INTF_BURST_COUNT_STATIC = 0x100,
TPM_INTF_CMD_READY_INT = 0x080,
TPM_INTF_INT_EDGE_FALLING = 0x040,
TPM_INTF_INT_EDGE_RISING = 0x020,
TPM_INTF_INT_LEVEL_LOW = 0x010,
TPM_INTF_INT_LEVEL_HIGH = 0x008,
TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
TPM_INTF_STS_VALID_INT = 0x002,
TPM_INTF_DATA_AVAIL_INT = 0x001,
};
enum tis_defaults {
TIS_MEM_LEN = 0x5000,
TIS_SHORT_TIMEOUT = 750, /* ms */
TIS_LONG_TIMEOUT = 4000, /* 4 secs */
TIS_TIMEOUT_MIN_ATML = 14700, /* usecs */
TIS_TIMEOUT_MAX_ATML = 15000, /* usecs */
};
/* Some timeout values are needed before it is known whether the chip is
* TPM 1.0 or TPM 2.0.
*/
#define TIS_TIMEOUT_A_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
#define TIS_TIMEOUT_B_MAX max_t(int, TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
#define TIS_TIMEOUT_C_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
#define TPM_STS(l) (0x0018 | ((l) << 12))
#define TPM_STS3(l) (0x001b | ((l) << 12))
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
#define TPM_RID(l) (0x0F04 | ((l) << 12))
#define LPC_CNTRL_OFFSET 0x84
#define LPC_CLKRUN_EN (1 << 2)
#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
#define ILB_REMAP_SIZE 0x100
enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = 0,
TPM_TIS_INVALID_STATUS = 1,

View File

@ -40,8 +40,12 @@ static inline int cr50_spi_probe(struct spi_device *spi)
}
#endif
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_TCG_TIS_SPI_CR50)
extern int tpm_tis_spi_resume(struct device *dev);
#if defined(CONFIG_PM_SLEEP)
#if defined(CONFIG_TCG_TIS_SPI_CR50)
extern int tpm_tis_spi_resume(struct device *dev);
#else
#define tpm_tis_spi_resume tpm_tis_resume
#endif
#else
#define tpm_tis_spi_resume NULL
#endif

View File

@ -395,40 +395,36 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{
struct tpm_buf buf;
int rc;
const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
TPM2_CC_SET_LOCALITY);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
else
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
TPM_ORD_SET_LOCALITY);
if (rc)
return rc;
tpm_buf_append_u8(&buf, locality);
tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
tpm_buf_append_u8(buf, locality);
proxy_dev->state |= STATE_DRIVER_COMMAND;
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
if (rc < 0) {
locality = rc;
goto out;
}
if (rc < 0)
return rc;
header = (const struct tpm_header *)buf.data;
header = (const struct tpm_header *)buf->data;
rc = be32_to_cpu(header->return_code);
if (rc)
locality = -1;
out:
tpm_buf_destroy(&buf);
return locality;
}

View File

@ -3,7 +3,6 @@
#define __TRUSTED_TPM_H
#include <keys/trusted-type.h>
#include <linux/tpm_command.h>
extern struct trusted_key_ops trusted_key_tpm_ops;

View File

@ -25,10 +25,8 @@
#include <crypto/hash_info.h>
#include <crypto/aes.h>
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
#define TPM2_MAX_PCR_BANKS 8
#include <linux/tpm_command.h>
#include <linux/tpm_buf.h>
struct tpm_chip;
struct trusted_key_payload;
@ -36,49 +34,6 @@ struct trusted_key_options;
/* opaque structure, holds auth session parameters like the session key */
struct tpm2_auth;
enum tpm2_session_types {
TPM2_SE_HMAC = 0x00,
TPM2_SE_POLICY = 0x01,
TPM2_SE_TRIAL = 0x02,
};
/* if you add a new hash to this, increment TPM_MAX_HASHES below */
enum tpm_algorithms {
TPM_ALG_ERROR = 0x0000,
TPM_ALG_SHA1 = 0x0004,
TPM_ALG_AES = 0x0006,
TPM_ALG_KEYEDHASH = 0x0008,
TPM_ALG_SHA256 = 0x000B,
TPM_ALG_SHA384 = 0x000C,
TPM_ALG_SHA512 = 0x000D,
TPM_ALG_NULL = 0x0010,
TPM_ALG_SM3_256 = 0x0012,
TPM_ALG_ECC = 0x0023,
TPM_ALG_CFB = 0x0043,
};
/*
* maximum number of hashing algorithms a TPM can have. This is
* basically a count of every hash in tpm_algorithms above
*/
#define TPM_MAX_HASHES 5
enum tpm2_curves {
TPM2_ECC_NONE = 0x0000,
TPM2_ECC_NIST_P256 = 0x0003,
};
struct tpm_digest {
u16 alg_id;
u8 digest[TPM2_MAX_DIGEST_SIZE];
} __packed;
struct tpm_bank_info {
u16 alg_id;
u16 digest_size;
u16 crypto_id;
};
enum TPM_OPS_FLAGS {
TPM_OPS_AUTO_STARTUP = BIT(0),
};
@ -136,7 +91,7 @@ struct tpm_chip_seqops {
const struct seq_operations *seqops;
};
/* fixed define for the curve we use which is NIST_P256 */
/* Fixed define for the curve we use which is NIST_P256 */
#define EC_PT_SZ 32
/*
@ -218,124 +173,11 @@ struct tpm_chip {
#endif
};
#define TPM_HEADER_SIZE 10
enum tpm2_const {
TPM2_PLATFORM_PCR = 24,
TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
};
enum tpm2_timeouts {
TPM2_TIMEOUT_A = 750,
TPM2_TIMEOUT_B = 4000,
TPM2_TIMEOUT_C = 200,
TPM2_TIMEOUT_D = 30,
};
enum tpm2_durations {
TPM2_DURATION_SHORT = 20,
TPM2_DURATION_LONG = 2000,
TPM2_DURATION_DEFAULT = 120000,
};
enum tpm2_structures {
TPM2_ST_NO_SESSIONS = 0x8001,
TPM2_ST_SESSIONS = 0x8002,
TPM2_ST_CREATION = 0x8021,
};
/* Indicates from what layer of the software stack the error comes from */
#define TSS2_RC_LAYER_SHIFT 16
#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
enum tpm2_return_codes {
TPM2_RC_SUCCESS = 0x0000,
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
TPM2_RC_HANDLE = 0x008B,
TPM2_RC_INTEGRITY = 0x009F,
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_FAILURE = 0x0101,
TPM2_RC_DISABLED = 0x0120,
TPM2_RC_UPGRADE = 0x012D,
TPM2_RC_COMMAND_CODE = 0x0143,
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
TPM2_RC_REFERENCE_H0 = 0x0910,
TPM2_RC_RETRY = 0x0922,
TPM2_RC_SESSION_MEMORY = 0x0903,
};
enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
TPM2_CC_CREATE_PRIMARY = 0x0131,
TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_STARTUP = 0x0144,
TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_NV_READ = 0x014E,
TPM2_CC_CREATE = 0x0153,
TPM2_CC_LOAD = 0x0157,
TPM2_CC_SEQUENCE_UPDATE = 0x015C,
TPM2_CC_UNSEAL = 0x015E,
TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_READ_PUBLIC = 0x0173,
TPM2_CC_START_AUTH_SESS = 0x0176,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
TPM2_CC_CREATE_LOADED = 0x0191,
TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
};
enum tpm2_permanent_handles {
TPM2_RH_NULL = 0x40000007,
TPM2_RS_PW = 0x40000009,
};
/* Most Significant Octet for key types */
enum tpm2_mso_type {
TPM2_MSO_NVRAM = 0x01,
TPM2_MSO_SESSION = 0x02,
TPM2_MSO_POLICY = 0x03,
TPM2_MSO_PERMANENT = 0x40,
TPM2_MSO_VOLATILE = 0x80,
TPM2_MSO_PERSISTENT = 0x81,
};
static inline enum tpm2_mso_type tpm2_handle_mso(u32 handle)
{
return handle >> 24;
}
enum tpm2_capabilities {
TPM2_CAP_HANDLES = 1,
TPM2_CAP_COMMANDS = 2,
TPM2_CAP_PCRS = 5,
TPM2_CAP_TPM_PROPERTIES = 6,
};
enum tpm2_properties {
TPM_PT_TOTAL_COMMANDS = 0x0129,
};
enum tpm2_startup_types {
TPM2_SU_CLEAR = 0x0000,
TPM2_SU_STATE = 0x0001,
};
enum tpm2_cc_attrs {
TPM2_CC_ATTR_CHANDLES = 25,
TPM2_CC_ATTR_RHANDLE = 28,
TPM2_CC_ATTR_VENDOR = 29,
};
#define TPM_VID_INTEL 0x8086
#define TPM_VID_WINBOND 0x1050
#define TPM_VID_STM 0x104A
@ -359,77 +201,11 @@ enum tpm_chip_flags {
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
struct tpm_header {
__be16 tag;
__be32 length;
union {
__be32 ordinal;
__be32 return_code;
};
} __packed;
enum tpm_buf_flags {
/* the capacity exceeded: */
TPM_BUF_OVERFLOW = BIT(0),
/* TPM2B format: */
TPM_BUF_TPM2B = BIT(1),
/* read out of boundary: */
TPM_BUF_BOUNDARY_ERROR = BIT(2),
};
/*
* A string buffer type for constructing TPM commands.
*/
struct tpm_buf {
u32 flags;
u32 length;
u8 *data;
u8 handles;
};
enum tpm2_object_attributes {
TPM2_OA_FIXED_TPM = BIT(1),
TPM2_OA_ST_CLEAR = BIT(2),
TPM2_OA_FIXED_PARENT = BIT(4),
TPM2_OA_SENSITIVE_DATA_ORIGIN = BIT(5),
TPM2_OA_USER_WITH_AUTH = BIT(6),
TPM2_OA_ADMIN_WITH_POLICY = BIT(7),
TPM2_OA_NO_DA = BIT(10),
TPM2_OA_ENCRYPTED_DUPLICATION = BIT(11),
TPM2_OA_RESTRICTED = BIT(16),
TPM2_OA_DECRYPT = BIT(17),
TPM2_OA_SIGN = BIT(18),
};
enum tpm2_session_attributes {
TPM2_SA_CONTINUE_SESSION = BIT(0),
TPM2_SA_AUDIT_EXCLUSIVE = BIT(1),
TPM2_SA_AUDIT_RESET = BIT(3),
TPM2_SA_DECRYPT = BIT(5),
TPM2_SA_ENCRYPT = BIT(6),
TPM2_SA_AUDIT = BIT(7),
};
struct tpm2_hash {
unsigned int crypto_id;
unsigned int tpm_id;
};
int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
int tpm_buf_init_sized(struct tpm_buf *buf);
void tpm_buf_reset_sized(struct tpm_buf *buf);
void tpm_buf_destroy(struct tpm_buf *buf);
u32 tpm_buf_length(struct tpm_buf *buf);
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value);
void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle);
/*
* Check if TPM device is in the firmware upgrade mode.
*/

60
include/linux/tpm_buf.h Normal file
View File

@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Following copyright information was take from the original file
* <include/linux/tpm.h> where the definitions were moved from:
*
* Copyright (C) 2004,2007,2008 IBM Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
* Debora Velarde <dvelarde@us.ibm.com>
*
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*/
#ifndef __LINUX_TPM_BUF_H__
#define __LINUX_TPM_BUF_H__
#include <linux/types.h>
#include <linux/bits.h>
enum tpm_buf_flags {
/* TPM2B format: */
TPM_BUF_TPM2B = BIT(0),
/* The buffer is in invalid and unusable state: */
TPM_BUF_INVALID = BIT(1),
};
/*
* A buffer for constructing and parsing TPM commands, responses and sized
* (TPM2B) buffers.
*/
struct tpm_buf {
u8 flags;
u8 handles;
u16 length;
u16 capacity;
u8 data[];
};
void tpm_buf_init(struct tpm_buf *buf, u16 buf_size);
void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size);
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
void tpm_buf_reset_sized(struct tpm_buf *buf);
u16 tpm_buf_length(struct tpm_buf *buf);
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value);
void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
void tpm_buf_append_handle(struct tpm_buf *buf, u32 handle);
#endif

View File

@ -2,28 +2,520 @@
#ifndef __LINUX_TPM_COMMAND_H__
#define __LINUX_TPM_COMMAND_H__
#include <crypto/sha2.h>
/*
* TPM Command constants from specifications at
* http://www.trustedcomputinggroup.org
* == TPM 1 Family Chips ==
*
* TPM 1.2 Main Specification:
* https://trustedcomputinggroup.org/resource/tpm-main-specification/
*/
#define TPM_MAX_ORDINAL 243
/* Command TAGS */
#define TPM_TAG_RQU_COMMAND 193
#define TPM_TAG_RQU_AUTH1_COMMAND 194
#define TPM_TAG_RQU_AUTH2_COMMAND 195
#define TPM_TAG_RSP_COMMAND 196
#define TPM_TAG_RSP_AUTH1_COMMAND 197
#define TPM_TAG_RSP_AUTH2_COMMAND 198
enum tpm_command_tags {
TPM_TAG_RQU_COMMAND = 193,
TPM_TAG_RQU_AUTH1_COMMAND = 194,
TPM_TAG_RQU_AUTH2_COMMAND = 195,
TPM_TAG_RSP_COMMAND = 196,
TPM_TAG_RSP_AUTH1_COMMAND = 197,
TPM_TAG_RSP_AUTH2_COMMAND = 198,
};
/* Command Ordinals */
#define TPM_ORD_GETRANDOM 70
#define TPM_ORD_OSAP 11
#define TPM_ORD_OIAP 10
#define TPM_ORD_SEAL 23
#define TPM_ORD_UNSEAL 24
enum tpm_command_ordinals {
TPM_ORD_CONTINUE_SELFTEST = 83,
TPM_ORD_GET_CAP = 101,
TPM_ORD_GET_RANDOM = 70,
TPM_ORD_PCR_EXTEND = 20,
TPM_ORD_PCR_READ = 21,
TPM_ORD_OSAP = 11,
TPM_ORD_OIAP = 10,
TPM_ORD_SAVESTATE = 152,
TPM_ORD_SEAL = 23,
TPM_ORD_STARTUP = 153,
TPM_ORD_UNSEAL = 24,
};
enum tpm_capabilities {
TPM_CAP_FLAG = 4,
TPM_CAP_PROP = 5,
TPM_CAP_VERSION_1_1 = 0x06,
TPM_CAP_VERSION_1_2 = 0x1A,
};
enum tpm_sub_capabilities {
TPM_CAP_PROP_PCR = 0x101,
TPM_CAP_PROP_MANUFACTURER = 0x103,
TPM_CAP_FLAG_PERM = 0x108,
TPM_CAP_FLAG_VOL = 0x109,
TPM_CAP_PROP_OWNER = 0x111,
TPM_CAP_PROP_TIS_TIMEOUT = 0x115,
TPM_CAP_PROP_TIS_DURATION = 0x120,
};
/* Return Codes */
enum tpm_return_codes {
TPM_BASE_MASK = 0,
TPM_NON_FATAL_MASK = 0x00000800,
TPM_SUCCESS = TPM_BASE_MASK + 0,
TPM_ERR_DEACTIVATED = TPM_BASE_MASK + 6,
TPM_ERR_DISABLED = TPM_BASE_MASK + 7,
TPM_ERR_FAIL = TPM_BASE_MASK + 9,
TPM_ERR_FAILEDSELFTEST = TPM_BASE_MASK + 28,
TPM_ERR_INVALID_POSTINIT = TPM_BASE_MASK + 38,
TPM_ERR_INVALID_FAMILY = TPM_BASE_MASK + 55,
TPM_WARN_RETRY = TPM_BASE_MASK + TPM_NON_FATAL_MASK + 0,
TPM_WARN_DOING_SELFTEST = TPM_BASE_MASK + TPM_NON_FATAL_MASK + 2,
};
struct stclear_flags_t {
__be16 tag;
u8 deactivated;
u8 disableForceClear;
u8 physicalPresence;
u8 physicalPresenceLock;
u8 bGlobalLock;
} __packed;
struct tpm1_version {
u8 major;
u8 minor;
u8 rev_major;
u8 rev_minor;
} __packed;
struct tpm1_version2 {
__be16 tag;
struct tpm1_version version;
} __packed;
struct timeout_t {
__be32 a;
__be32 b;
__be32 c;
__be32 d;
} __packed;
struct duration_t {
__be32 tpm_short;
__be32 tpm_medium;
__be32 tpm_long;
} __packed;
struct permanent_flags_t {
__be16 tag;
u8 disable;
u8 ownership;
u8 deactivated;
u8 readPubek;
u8 disableOwnerClear;
u8 allowMaintenance;
u8 physicalPresenceLifetimeLock;
u8 physicalPresenceHWEnable;
u8 physicalPresenceCMDEnable;
u8 CEKPUsed;
u8 TPMpost;
u8 TPMpostLock;
u8 FIPS;
u8 operator;
u8 enableRevokeEK;
u8 nvLocked;
u8 readSRKPub;
u8 tpmEstablished;
u8 maintenanceDone;
u8 disableFullDALogicInfo;
} __packed;
typedef union {
struct permanent_flags_t perm_flags;
struct stclear_flags_t stclear_flags;
__u8 owned;
__be32 num_pcrs;
struct tpm1_version version1;
struct tpm1_version2 version2;
__be32 manufacturer_id;
struct timeout_t timeout;
struct duration_t duration;
} cap_t;
/*
* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and
* anything much bigger causes users of struct tpm_cmd_t to start getting
* compiler warnings about stack frame size.
*/
#define TPM_MAX_RNG_DATA 128
struct tpm1_get_random_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
} __packed;
/* Other constants */
#define SRKHANDLE 0x40000000
#define TPM_NONCE_SIZE 20
#define TPM_ST_CLEAR 1
/*
* == TPM 2 Family Chips ==
*
* TPM 2.0 Library
* https://trustedcomputinggroup.org/resource/tpm-library-specification/
*/
/* TPM2 specific constants. */
#define TPM2_SPACE_BUFFER_SIZE 16384 /* 16 kB */
enum tpm2_session_types {
TPM2_SE_HMAC = 0x00,
TPM2_SE_POLICY = 0x01,
TPM2_SE_TRIAL = 0x02,
};
enum tpm2_timeouts {
TPM2_TIMEOUT_A = 750,
TPM2_TIMEOUT_B = 4000,
TPM2_TIMEOUT_C = 200,
TPM2_TIMEOUT_D = 30,
TPM2_DURATION_SHORT = 20,
TPM2_DURATION_MEDIUM = 750,
TPM2_DURATION_LONG = 2000,
TPM2_DURATION_LONG_LONG = 300000,
TPM2_DURATION_DEFAULT = 120000,
};
enum tpm2_structures {
TPM2_ST_NO_SESSIONS = 0x8001,
TPM2_ST_SESSIONS = 0x8002,
TPM2_ST_CREATION = 0x8021,
};
/* Indicates from what layer of the software stack the error comes from */
#define TSS2_RC_LAYER_SHIFT 16
#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
enum tpm2_return_codes {
TPM2_RC_SUCCESS = 0x0000,
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
TPM2_RC_HANDLE = 0x008B,
TPM2_RC_INTEGRITY = 0x009F,
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_FAILURE = 0x0101,
TPM2_RC_DISABLED = 0x0120,
TPM2_RC_UPGRADE = 0x012D,
TPM2_RC_COMMAND_CODE = 0x0143,
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
TPM2_RC_REFERENCE_H0 = 0x0910,
TPM2_RC_RETRY = 0x0922,
TPM2_RC_SESSION_MEMORY = 0x0903,
};
enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
TPM2_CC_CREATE_PRIMARY = 0x0131,
TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_STARTUP = 0x0144,
TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_NV_READ = 0x014E,
TPM2_CC_CREATE = 0x0153,
TPM2_CC_LOAD = 0x0157,
TPM2_CC_SEQUENCE_UPDATE = 0x015C,
TPM2_CC_UNSEAL = 0x015E,
TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_READ_PUBLIC = 0x0173,
TPM2_CC_START_AUTH_SESS = 0x0176,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
TPM2_CC_CREATE_LOADED = 0x0191,
TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
};
enum tpm2_capabilities {
TPM2_CAP_HANDLES = 1,
TPM2_CAP_COMMANDS = 2,
TPM2_CAP_PCRS = 5,
TPM2_CAP_TPM_PROPERTIES = 6,
};
enum tpm2_properties {
TPM_PT_TOTAL_COMMANDS = 0x0129,
};
enum tpm2_startup_types {
TPM2_SU_CLEAR = 0x0000,
TPM2_SU_STATE = 0x0001,
};
enum tpm2_cc_attrs {
TPM2_CC_ATTR_CHANDLES = 25,
TPM2_CC_ATTR_RHANDLE = 28,
TPM2_CC_ATTR_VENDOR = 29,
};
enum tpm2_permanent_handles {
TPM2_RH_NULL = 0x40000007,
TPM2_RS_PW = 0x40000009,
};
/* Most Significant Octet for key types */
enum tpm2_mso_type {
TPM2_MSO_NVRAM = 0x01,
TPM2_MSO_SESSION = 0x02,
TPM2_MSO_POLICY = 0x03,
TPM2_MSO_PERMANENT = 0x40,
TPM2_MSO_VOLATILE = 0x80,
TPM2_MSO_PERSISTENT = 0x81,
};
enum tpm2_curves {
TPM2_ECC_NONE = 0x0000,
TPM2_ECC_NIST_P256 = 0x0003,
};
enum tpm2_object_attributes {
TPM2_OA_FIXED_TPM = BIT(1),
TPM2_OA_ST_CLEAR = BIT(2),
TPM2_OA_FIXED_PARENT = BIT(4),
TPM2_OA_SENSITIVE_DATA_ORIGIN = BIT(5),
TPM2_OA_USER_WITH_AUTH = BIT(6),
TPM2_OA_ADMIN_WITH_POLICY = BIT(7),
TPM2_OA_NO_DA = BIT(10),
TPM2_OA_ENCRYPTED_DUPLICATION = BIT(11),
TPM2_OA_RESTRICTED = BIT(16),
TPM2_OA_DECRYPT = BIT(17),
TPM2_OA_SIGN = BIT(18),
};
enum tpm2_session_attributes {
TPM2_SA_CONTINUE_SESSION = BIT(0),
TPM2_SA_AUDIT_EXCLUSIVE = BIT(1),
TPM2_SA_AUDIT_RESET = BIT(3),
TPM2_SA_DECRYPT = BIT(5),
TPM2_SA_ENCRYPT = BIT(6),
TPM2_SA_AUDIT = BIT(7),
};
enum tpm2_pcr_select {
TPM2_PLATFORM_PCR = 24,
TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
};
enum tpm2_handle_types {
TPM2_HT_HMAC_SESSION = 0x02000000,
TPM2_HT_POLICY_SESSION = 0x03000000,
TPM2_HT_TRANSIENT = 0x80000000,
};
enum tpm2_pt_props {
TPM2_PT_NONE = 0x00000000,
TPM2_PT_GROUP = 0x00000100,
TPM2_PT_FIXED = TPM2_PT_GROUP * 1,
TPM2_PT_FAMILY_INDICATOR = TPM2_PT_FIXED + 0,
TPM2_PT_LEVEL = TPM2_PT_FIXED + 1,
TPM2_PT_REVISION = TPM2_PT_FIXED + 2,
TPM2_PT_DAY_OF_YEAR = TPM2_PT_FIXED + 3,
TPM2_PT_YEAR = TPM2_PT_FIXED + 4,
TPM2_PT_MANUFACTURER = TPM2_PT_FIXED + 5,
TPM2_PT_VENDOR_STRING_1 = TPM2_PT_FIXED + 6,
TPM2_PT_VENDOR_STRING_2 = TPM2_PT_FIXED + 7,
TPM2_PT_VENDOR_STRING_3 = TPM2_PT_FIXED + 8,
TPM2_PT_VENDOR_STRING_4 = TPM2_PT_FIXED + 9,
TPM2_PT_VENDOR_TPM_TYPE = TPM2_PT_FIXED + 10,
TPM2_PT_FIRMWARE_VERSION_1 = TPM2_PT_FIXED + 11,
TPM2_PT_FIRMWARE_VERSION_2 = TPM2_PT_FIXED + 12,
TPM2_PT_INPUT_BUFFER = TPM2_PT_FIXED + 13,
TPM2_PT_HR_TRANSIENT_MIN = TPM2_PT_FIXED + 14,
TPM2_PT_HR_PERSISTENT_MIN = TPM2_PT_FIXED + 15,
TPM2_PT_HR_LOADED_MIN = TPM2_PT_FIXED + 16,
TPM2_PT_ACTIVE_SESSIONS_MAX = TPM2_PT_FIXED + 17,
TPM2_PT_PCR_COUNT = TPM2_PT_FIXED + 18,
TPM2_PT_PCR_SELECT_MIN = TPM2_PT_FIXED + 19,
TPM2_PT_CONTEXT_GAP_MAX = TPM2_PT_FIXED + 20,
TPM2_PT_NV_COUNTERS_MAX = TPM2_PT_FIXED + 22,
TPM2_PT_NV_INDEX_MAX = TPM2_PT_FIXED + 23,
TPM2_PT_MEMORY = TPM2_PT_FIXED + 24,
TPM2_PT_CLOCK_UPDATE = TPM2_PT_FIXED + 25,
TPM2_PT_CONTEXT_HASH = TPM2_PT_FIXED + 26,
TPM2_PT_CONTEXT_SYM = TPM2_PT_FIXED + 27,
TPM2_PT_CONTEXT_SYM_SIZE = TPM2_PT_FIXED + 28,
TPM2_PT_ORDERLY_COUNT = TPM2_PT_FIXED + 29,
TPM2_PT_MAX_COMMAND_SIZE = TPM2_PT_FIXED + 30,
TPM2_PT_MAX_RESPONSE_SIZE = TPM2_PT_FIXED + 31,
TPM2_PT_MAX_DIGEST = TPM2_PT_FIXED + 32,
TPM2_PT_MAX_OBJECT_CONTEXT = TPM2_PT_FIXED + 33,
TPM2_PT_MAX_SESSION_CONTEXT = TPM2_PT_FIXED + 34,
TPM2_PT_PS_FAMILY_INDICATOR = TPM2_PT_FIXED + 35,
TPM2_PT_PS_LEVEL = TPM2_PT_FIXED + 36,
TPM2_PT_PS_REVISION = TPM2_PT_FIXED + 37,
TPM2_PT_PS_DAY_OF_YEAR = TPM2_PT_FIXED + 38,
TPM2_PT_PS_YEAR = TPM2_PT_FIXED + 39,
TPM2_PT_SPLIT_MAX = TPM2_PT_FIXED + 40,
TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41,
TPM2_PT_LIBRARY_COMMANDS = TPM2_PT_FIXED + 42,
TPM2_PT_VENDOR_COMMANDS = TPM2_PT_FIXED + 43,
TPM2_PT_NV_BUFFER_MAX = TPM2_PT_FIXED + 44,
TPM2_PT_MODES = TPM2_PT_FIXED + 45,
TPM2_PT_MAX_CAP_BUFFER = TPM2_PT_FIXED + 46,
TPM2_PT_VAR = TPM2_PT_GROUP * 2,
TPM2_PT_PERMANENT = TPM2_PT_VAR + 0,
TPM2_PT_STARTUP_CLEAR = TPM2_PT_VAR + 1,
TPM2_PT_HR_NV_INDEX = TPM2_PT_VAR + 2,
TPM2_PT_HR_LOADED = TPM2_PT_VAR + 3,
TPM2_PT_HR_LOADED_AVAIL = TPM2_PT_VAR + 4,
TPM2_PT_HR_ACTIVE = TPM2_PT_VAR + 5,
TPM2_PT_HR_ACTIVE_AVAIL = TPM2_PT_VAR + 6,
TPM2_PT_HR_TRANSIENT_AVAIL = TPM2_PT_VAR + 7,
TPM2_PT_HR_PERSISTENT = TPM2_PT_VAR + 8,
TPM2_PT_HR_PERSISTENT_AVAIL = TPM2_PT_VAR + 9,
TPM2_PT_NV_COUNTERS = TPM2_PT_VAR + 10,
TPM2_PT_NV_COUNTERS_AVAIL = TPM2_PT_VAR + 11,
TPM2_PT_ALGORITHM_SET = TPM2_PT_VAR + 12,
TPM2_PT_LOADED_CURVES = TPM2_PT_VAR + 13,
TPM2_PT_LOCKOUT_COUNTER = TPM2_PT_VAR + 14,
TPM2_PT_MAX_AUTH_FAIL = TPM2_PT_VAR + 15,
TPM2_PT_LOCKOUT_INTERVAL = TPM2_PT_VAR + 16,
TPM2_PT_LOCKOUT_RECOVERY = TPM2_PT_VAR + 17,
TPM2_PT_NV_WRITE_RECOVERY = TPM2_PT_VAR + 18,
TPM2_PT_AUDIT_COUNTER_0 = TPM2_PT_VAR + 19,
TPM2_PT_AUDIT_COUNTER_1 = TPM2_PT_VAR + 20,
};
struct tpm2_pcr_read_out {
__be32 update_cnt;
__be32 pcr_selects_cnt;
__be16 hash_alg;
u8 pcr_select_size;
u8 pcr_select[TPM2_PCR_SELECT_MIN];
__be32 digests_cnt;
__be16 digest_size;
u8 digest[];
} __packed;
struct tpm2_get_random_out {
__be16 size;
u8 buffer[TPM_MAX_RNG_DATA];
} __packed;
struct tpm2_get_cap_out {
u8 more_data;
__be32 subcap_id;
__be32 property_cnt;
__be32 property_id;
__be32 value;
} __packed;
struct tpm2_pcr_selection {
__be16 hash_alg;
u8 size_of_select;
u8 pcr_select[3];
} __packed;
struct tpm2_context {
__be64 sequence;
__be32 saved_handle;
__be32 hierarchy;
__be16 blob_size;
} __packed;
/*
* == TPM Common Defs ==
*/
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
#define TPM_BUFSIZE 4096
/*
* SHA-512 is, as of today, the largest digest in the TCG algorithm repository.
*/
#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
/*
* A TPM name digest i.e., TPMT_HA, is a concatenation of TPM_ALG_ID of the
* name algorithm and hash of TPMT_PUBLIC.
*/
#define TPM2_MAX_NAME_SIZE (TPM2_MAX_DIGEST_SIZE + 2)
/*
* Fixed define for the size of a name. This is actually HASHALG size
* plus 2, so 32 for SHA256
*/
#define TPM2_NULL_NAME_SIZE 34
/*
* The maximum number of PCR banks.
*/
#define TPM2_MAX_PCR_BANKS 8
/* If you add a new hash to this, increment TPM_MAX_HASHES below */
enum tpm_algorithms {
TPM_ALG_ERROR = 0x0000,
TPM_ALG_SHA1 = 0x0004,
TPM_ALG_AES = 0x0006,
TPM_ALG_KEYEDHASH = 0x0008,
TPM_ALG_SHA256 = 0x000B,
TPM_ALG_SHA384 = 0x000C,
TPM_ALG_SHA512 = 0x000D,
TPM_ALG_NULL = 0x0010,
TPM_ALG_SM3_256 = 0x0012,
TPM_ALG_ECC = 0x0023,
TPM_ALG_CFB = 0x0043,
};
/*
* The locality (0 - 4) for a TPM, as defined in section 3.2 of the
* Client Platform Profile Specification.
*/
enum tpm_localities {
TPM_LOCALITY_0 = 0, /* Static RTM */
TPM_LOCALITY_1 = 1, /* Dynamic OS */
TPM_LOCALITY_2 = 2, /* DRTM Environment */
TPM_LOCALITY_3 = 3, /* Aux Components */
TPM_LOCALITY_4 = 4, /* CPU DRTM Establishment */
TPM_MAX_LOCALITY = TPM_LOCALITY_4
};
/*
* Structure to represent active PCR algorithm banks usable by the
* TPM chip.
*/
struct tpm_bank_info {
u16 alg_id;
u16 digest_size;
u16 crypto_id;
};
/*
* Maximum number of hashing algorithms a TPM can have. This is
* basically a count of every hash in tpm_algorithms above
*/
#define TPM_MAX_HASHES 5
struct tpm_digest {
u16 alg_id;
u8 digest[TPM2_MAX_DIGEST_SIZE];
} __packed;
#define TPM_HEADER_SIZE 10
struct tpm_header {
__be16 tag;
__be32 length;
union {
__be32 ordinal;
__be32 return_code;
};
} __packed;
#endif

View File

@ -3,7 +3,7 @@
#ifndef __LINUX_TPM_EVENTLOG_H__
#define __LINUX_TPM_EVENTLOG_H__
#include <linux/tpm.h>
#include <linux/tpm_command.h>
#define TCG_EVENT_NAME_LEN_MAX 255
#define MAX_TEXT_EVENT 1000 /* Max event string length */

133
include/linux/tpm_ptp.h Normal file
View File

@ -0,0 +1,133 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Following copyright information was take from the original file
* <drivers/char/tpm/tpm_tis_core.h> where the definitions were moved
* from:
*
* Copyright (C) 2005, 2006 IBM Corporation
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This device driver implements the TPM interface as defined in
* the TCG TPM Interface Spec version 1.2, revision 1.0.
*/
#ifndef __LINUX_TPM_PTP_H__
#define __LINUX_TPM_PTP_H__
/*
* TCG PC Client Platform TPM Profile (PTP) Specification
* https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
*/
/* TIS/FIFO macros and definitions */
enum tis_access {
TPM_ACCESS_VALID = 0x80,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20, /* (R) */
TPM_ACCESS_RELINQUISH_LOCALITY = 0x20, /* (W) */
TPM_ACCESS_REQUEST_PENDING = 0x04, /* (W) */
TPM_ACCESS_REQUEST_USE = 0x02, /* (W) */
};
enum tis_status {
TPM_STS_VALID = 0x80, /* (R) */
TPM_STS_COMMAND_READY = 0x40, /* (R) */
TPM_STS_DATA_AVAIL = 0x10, /* (R) */
TPM_STS_DATA_EXPECT = 0x08, /* (R) */
TPM_STS_GO = 0x20, /* (W) */
TPM_STS_RESPONSE_RETRY = 0x02, /* (R) */
TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
};
enum tis_int_flags {
TPM_GLOBAL_INT_ENABLE = 0x80000000,
TPM_INTF_BURST_COUNT_STATIC = 0x100,
TPM_INTF_CMD_READY_INT = 0x080,
TPM_INTF_INT_EDGE_FALLING = 0x040,
TPM_INTF_INT_EDGE_RISING = 0x020,
TPM_INTF_INT_LEVEL_LOW = 0x010,
TPM_INTF_INT_LEVEL_HIGH = 0x008,
TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
TPM_INTF_STS_VALID_INT = 0x002,
TPM_INTF_DATA_AVAIL_INT = 0x001,
};
enum tis_defaults {
TIS_MEM_LEN = 0x5000,
TIS_SHORT_TIMEOUT = 750, /* ms */
TIS_LONG_TIMEOUT = 4000, /* 4 secs */
TIS_TIMEOUT_MIN_ATML = 14700, /* usecs */
TIS_TIMEOUT_MAX_ATML = 15000, /* usecs */
};
#define TIS_MEM_X86_LPC_BASE 0xFED40000
#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
enum tis_x86_defaults {
TIS_MEM_X86_LEN = 0x5000,
ILB_REMAP_SIZE = 0x100,
LPC_CNTRL_OFFSET = 0x84,
LPC_CLKRUN_EN = (1 << 2),
};
/*
* Some timeout values are needed before it is known whether the chip is
* TPM 1.0 or TPM 2.0.
*/
#define TIS_TIMEOUT_A_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
#define TIS_TIMEOUT_B_MAX max_t(int, TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
#define TIS_TIMEOUT_C_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
#define TPM_STS(l) (0x0018 | ((l) << 12))
#define TPM_STS3(l) (0x001b | ((l) << 12))
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
#define TPM_INTF_ID(l) (0x0030 | ((l) << 12))
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
#define TPM_RID(l) (0x0F04 | ((l) << 12))
/* TPM HW Interface and Capabilities */
#define TPM_TIS_INTF_ACTIVE 0x00
#define TPM_CRB_INTF_ACTIVE 0x01
#define TPM_INTID_INTERFACE_TYPE GENMASK(3, 0)
#define TPM_INTID_INTERFACE_VERSION GENMASK(7, 4)
#define TPM_INTID_CAP_LOCALITY BIT(8)
#define TPM_INTID_CAP_TIS BIT(13)
#define TPM_INTID_CAP_CRB BIT(14)
#define TPM_INTID_CAP_IF_RES GENMASK(16, 15)
#define TPM_INTID_INTERFACE_SELECTOR GENMASK(18, 17)
#define TPM_INTID_INTF_SEL_LOCK BIT(19)
#define TPM_TIS_INTF_12 0x00
#define TPM_TIS_INTF_13 0x02
#define TPM2_TIS_INTF_13 0x03
#define TPM_INTF_DATA_AVAIL_INT_SUPPORT BIT(0)
#define TPM_INTF_STS_VALID_INT_SUPPORT BIT(1)
#define TPM_INTF_LOCALITY_CHANGE_INT_SUPPORT BIT(2)
#define TPM_INTF_INTERRUPT_LEVEL_HIGH BIT(3)
#define TPM_INTF_INTERRUPT_LEVEL_LOW BIT(4)
#define TPM_INTF_INTERRUPT_EDGE_RISING BIT(5)
#define TPM_INTF_INTERRUPT_EDGE_FALLING BIT(6)
#define TPM_INTF_COMMAND_READY_INT_SUPPORT BIT(7)
#define TPM_INTF_BURST_COUNT_STATIC BIT(8)
#define TPM_INTF_DATA_TRANSFER_SIZE_SUPPORT GENMASK(10, 9)
#define TPM_INTF_INTERFACE_VERSION GENMASK(30, 28)
#endif

View File

@ -18,7 +18,6 @@
#include <keys/trusted-type.h>
#include <linux/key-type.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>
#include <keys/trusted_tpm.h>
@ -317,9 +316,8 @@ static int TSS_checkhmac2(unsigned char *buffer,
* For key specific tpm requests, we will generate and send our
* own TPM command packets using the drivers send function.
*/
static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
static int trusted_tpm_send(struct tpm_buf *buf)
{
struct tpm_buf buf;
int rc;
if (!chip)
@ -329,12 +327,9 @@ static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
if (rc)
return rc;
buf.flags = 0;
buf.length = buflen;
buf.data = cmd;
dump_tpm_buf(cmd);
rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
dump_tpm_buf(cmd);
dump_tpm_buf(buf->data);
rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
dump_tpm_buf(buf->data);
if (rc > 0)
/* TPM error */
@ -380,7 +375,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
tpm_buf_append_u32(tb, handle);
tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
ret = trusted_tpm_send(tb->data, tb->length);
ret = trusted_tpm_send(tb);
if (ret < 0)
return ret;
@ -404,7 +399,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
return -ENODEV;
tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
ret = trusted_tpm_send(tb->data, tb->length);
ret = trusted_tpm_send(tb);
if (ret < 0)
return ret;
@ -513,7 +508,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(tb->data, tb->length);
ret = trusted_tpm_send(tb);
if (ret < 0)
goto out;
@ -604,7 +599,7 @@ static int tpm_unseal(struct tpm_buf *tb,
tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(tb->data, tb->length);
ret = trusted_tpm_send(tb);
if (ret < 0) {
pr_info("authhmac failed (%d)\n", ret);
return ret;
@ -631,23 +626,23 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
struct tpm_buf tb;
int ret;
ret = tpm_buf_init(&tb, 0, 0);
if (ret)
return ret;
struct tpm_buf *tb __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!tb)
return -ENOMEM;
tpm_buf_init(tb, TPM_BUFSIZE);
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
o->blobauth, o->pcrinfo, o->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
tpm_buf_destroy(&tb);
return ret;
}
@ -657,14 +652,15 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
struct tpm_buf tb;
int ret;
ret = tpm_buf_init(&tb, 0, 0);
if (ret)
return ret;
struct tpm_buf *tb __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!tb)
return -ENOMEM;
ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
tpm_buf_init(tb, TPM_BUFSIZE);
ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
@ -672,7 +668,6 @@ static int key_unseal(struct trusted_key_payload *p,
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
tpm_buf_destroy(&tb);
return ret;
}

View File

@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/err.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>
#include <keys/trusted-type.h>
#include <keys/trusted_tpm.h>
@ -234,7 +233,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_options *options)
{
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
struct tpm_buf *buf __free(kfree) = NULL;
struct tpm_buf *sized __free(kfree) = NULL;
int blob_len = 0;
int hash;
u32 flags;
@ -255,97 +255,100 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc)
goto out_put;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
if (rc) {
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
tpm2_end_auth_session(chip);
goto out_put;
}
rc = tpm_buf_init_sized(&sized);
if (rc) {
tpm_buf_destroy(&buf);
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
sized = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!sized) {
rc = -ENOMEM;
tpm2_end_auth_session(chip);
goto out_put;
}
rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
tpm_buf_init_sized(sized, TPM_BUFSIZE);
rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
if (rc)
goto out;
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
options->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
tpm_buf_append_u16(&sized, options->blobauth_len);
tpm_buf_append_u16(sized, options->blobauth_len);
if (options->blobauth_len)
tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
tpm_buf_append(sized, options->blobauth, options->blobauth_len);
tpm_buf_append_u16(&sized, payload->key_len);
tpm_buf_append(&sized, payload->key, payload->key_len);
tpm_buf_append(&buf, sized.data, sized.length);
tpm_buf_append_u16(sized, payload->key_len);
tpm_buf_append(sized, payload->key, payload->key_len);
tpm_buf_append(buf, sized->data, sized->length);
/* public */
tpm_buf_reset_sized(&sized);
tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
tpm_buf_append_u16(&sized, hash);
tpm_buf_reset_sized(sized);
tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
tpm_buf_append_u16(sized, hash);
/* key properties */
flags = 0;
flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
tpm_buf_append_u32(&sized, flags);
tpm_buf_append_u32(sized, flags);
/* policy */
tpm_buf_append_u16(&sized, options->policydigest_len);
tpm_buf_append_u16(sized, options->policydigest_len);
if (options->policydigest_len)
tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
tpm_buf_append(sized, options->policydigest, options->policydigest_len);
/* public parameters */
tpm_buf_append_u16(&sized, TPM_ALG_NULL);
tpm_buf_append_u16(&sized, 0);
tpm_buf_append_u16(sized, TPM_ALG_NULL);
tpm_buf_append_u16(sized, 0);
tpm_buf_append(&buf, sized.data, sized.length);
tpm_buf_append(buf, sized->data, sized->length);
/* outside info */
tpm_buf_append_u16(&buf, 0);
tpm_buf_append_u16(buf, 0);
/* creation PCR */
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(buf, 0);
if (buf.flags & TPM_BUF_OVERFLOW) {
if (buf->flags & TPM_BUF_INVALID) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
rc = tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
goto out;
rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc)
goto out;
blob_len = tpm_buf_read_u32(&buf, &offset);
if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
blob_len = tpm_buf_read_u32(buf, &offset);
if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_INVALID) {
rc = -E2BIG;
goto out;
}
if (buf.length - offset < blob_len) {
if (buf->length - offset < blob_len) {
rc = -EFAULT;
goto out;
}
blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
blob_len = tpm2_key_encode(payload, options, &buf->data[offset], blob_len);
if (blob_len < 0)
rc = blob_len;
out:
tpm_buf_destroy(&sized);
tpm_buf_destroy(&buf);
if (!rc)
payload->blob_len = blob_len;
@ -373,7 +376,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
u32 *blob_handle)
{
u8 *blob_ref __free(kfree) = NULL;
struct tpm_buf buf;
struct tpm_buf *buf __free(kfree) = NULL;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
@ -427,39 +430,38 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (rc)
return rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
if (rc) {
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
tpm2_end_auth_session(chip);
return rc;
return -ENOMEM;
}
rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
if (rc)
goto out;
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
if (rc)
return rc;
tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
TPM_DIGEST_SIZE);
tpm_buf_append(&buf, blob, blob_len);
tpm_buf_append(buf, blob, blob_len);
if (buf.flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
if (buf->flags & TPM_BUF_INVALID) {
tpm2_end_auth_session(chip);
goto out;
return -E2BIG;
}
rc = tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
goto out;
return rc;
rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc)
*blob_handle = be32_to_cpup(
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
out:
tpm_buf_destroy(&buf);
(__be32 *)&buf->data[TPM_HEADER_SIZE]);
return tpm_ret_to_err(rc);
}
@ -482,7 +484,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
u32 blob_handle)
{
struct tpm_header *head;
struct tpm_buf buf;
struct tpm_buf *buf __free(kfree) = NULL;
u16 data_len;
int offset;
u8 *data;
@ -492,18 +494,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
if (rc)
return rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
if (rc) {
buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (!buf) {
tpm2_end_auth_session(chip);
return rc;
return -ENOMEM;
}
rc = tpm_buf_append_name(chip, &buf, blob_handle, NULL);
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
rc = tpm_buf_append_name(chip, buf, blob_handle, NULL);
if (rc)
goto out;
return rc;
if (!options->policyhandle) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
options->blobauth,
options->blobauth_len);
} else {
@ -518,39 +523,36 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
tpm2_buf_append_auth(&buf, options->policyhandle,
tpm2_buf_append_auth(buf, options->policyhandle,
NULL /* nonce */, 0, 0,
options->blobauth, options->blobauth_len);
if (tpm2_chip_auth(chip)) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, NULL, 0);
tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
NULL, 0);
} else {
offset = buf.handles * 4 + TPM_HEADER_SIZE;
head = (struct tpm_header *)buf.data;
if (tpm_buf_length(&buf) == offset)
offset = buf->handles * 4 + TPM_HEADER_SIZE;
head = (struct tpm_header *)buf->data;
if (tpm_buf_length(buf) == offset)
head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
}
}
rc = tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
goto out;
return rc;
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc) {
data_len = be16_to_cpup(
(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
rc = -EFAULT;
goto out;
}
(__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
return -EFAULT;
if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
rc = -EFAULT;
goto out;
}
data = &buf.data[TPM_HEADER_SIZE + 6];
if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
return -EFAULT;
data = &buf->data[TPM_HEADER_SIZE + 6];
if (payload->old_format) {
/* migratable flag is at the end of the key */
@ -567,8 +569,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
}
out:
tpm_buf_destroy(&buf);
return tpm_ret_to_err(rc);
}