tpmdd updates for Linux v5.1
-----BEGIN PGP SIGNATURE----- iQJUBAABCgA+FiEEmiawYN7xokcVSACRcXm3ZwSroYsFAlxjzSMgHGphcmtrby5z YWtraW5lbkBsaW51eC5pbnRlbC5jb20ACgkQcXm3ZwSroYsF5Q/+OxrC7dlxs1Gn kLV/+7r9j+47F2QhNg85fXuBYbOsrTnIuttJggxFt0Hbn/dYOu0YTL/p4yw5WQpr uw5mH3thewetzasGjL0nmeP1ElacF4aT1ve9XS1gFrz3/0KWhOw5Ut9UAjLQEGAA dHCmsOj2Jb6mxBsPmh7XZmb+/WbNplJunH+weww3bpgUSVL8Vj8/9FBuq2oWbXw0 t/e7Uff42L5bTX+sJsbSc7ZxNUIKGNj6N1OEA/6sNn5jbbo+tgFPGwZLc4Bxf1Ei JwZmUIEbnQ2WOAF1x1hFX+4oQGz83iSWZPHpiNS/1Rmo8WXaMVRDN5iZk+Ti7KiY y17VPyFSymOlHjG0MERfDE0eLcRwMz454yuEoMw0LxnKipZDCAURZ8j5Jhjd677I 6hUQa4HGVXaCt0szTUEghV4z1DDSF4M+iZcgjDhZF5nuOvAowFLNnsuOofAXQPy/ piyrdgiIOT86cNFJU3j7o2FzwSSxotz/e4fnUzctdQRYXvB9aQLocNTkmGAdZKtB Qr1tfuSCaE+E+4M2+KkmUIHjZN8JGsnlydyqwKmurLQTQ0p+pdN1o4RJkUgB97Zj DdATFTC2iGKIhvzkWiqBnjflWQPim0a/8E7YfkogzFRjxg7vXNX3Bstjhula3X4z OE0IYzNgRW7Kii5NcWmK0Hl5cfp8WUE= =v3EU -----END PGP SIGNATURE----- Merge tag 'tpmdd-next-20190213' of git://git.infradead.org/users/jjs/linux-tpmdd into next-tpm tpmdd updates for Linux v5.1 From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Clean up the transmission flow ============================== Cleaned up the whole transmission flow. Locking of the chip is now done in the level of tpm_try_get_ops() and tpm_put_ops() instead taking the chip lock inside tpm_transmit(). The nested calls inside tpm_transmit(), used with the resource manager, have been refactored out. Should make easier to perform more complex transactions with the TPM without making the subsystem a bigger mess (e.g. encrypted channel patches by James Bottomley). PPI 1.3 support =============== TPM PPI 1.3 introduces an additional optional command parameter that may be needed for some commands. Display the parameter if the command requires such a parameter. Only command 23 (SetPCRBanks) needs one. The PPI request file will show output like this then: # echo "23 16" > request # cat request 23 16 # echo "5" > request # cat request 5 Extend all PCR banks in IMA =========================== Instead of static PCR banks array, the array of available PCR banks is now allocated dynamically. The digests sizes are determined dynamically using a probe PCR read without relying crypto's static list of hash algorithms. This should finally make sealing of measurements in IMA safe and secure. TPM 2.0 selftests ================= Added a test suite to tools/testing/selftests/tpm2 previously outside of the kernel tree: https://github.com/jsakkine-intel/tpm2-scripts.
This commit is contained in:
commit
5da1072803
|
@ -74,7 +74,7 @@ static const char* tcpa_pc_event_id_strings[] = {
|
|||
/* returns pointer to start of pos. entry of tcg log */
|
||||
static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
loff_t i;
|
||||
loff_t i = 0;
|
||||
struct tpm_chip *chip = m->private;
|
||||
struct tpm_bios_log *log = &chip->log;
|
||||
void *addr = log->bios_event_log;
|
||||
|
@ -83,38 +83,29 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
|
|||
u32 converted_event_size;
|
||||
u32 converted_event_type;
|
||||
|
||||
|
||||
/* read over *pos measurements */
|
||||
for (i = 0; i < *pos; i++) {
|
||||
do {
|
||||
event = addr;
|
||||
|
||||
/* check if current entry is valid */
|
||||
if (addr + sizeof(struct tcpa_event) > limit)
|
||||
return NULL;
|
||||
|
||||
converted_event_size =
|
||||
do_endian_conversion(event->event_size);
|
||||
converted_event_type =
|
||||
do_endian_conversion(event->event_type);
|
||||
|
||||
if ((addr + sizeof(struct tcpa_event)) < limit) {
|
||||
if ((converted_event_type == 0) &&
|
||||
(converted_event_size == 0))
|
||||
return NULL;
|
||||
addr += (sizeof(struct tcpa_event) +
|
||||
converted_event_size);
|
||||
}
|
||||
}
|
||||
if (((converted_event_type == 0) && (converted_event_size == 0))
|
||||
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
|
||||
> limit))
|
||||
return NULL;
|
||||
|
||||
/* now check if current entry is valid */
|
||||
if ((addr + sizeof(struct tcpa_event)) >= limit)
|
||||
return NULL;
|
||||
if (i++ == *pos)
|
||||
break;
|
||||
|
||||
event = addr;
|
||||
|
||||
converted_event_size = do_endian_conversion(event->event_size);
|
||||
converted_event_type = do_endian_conversion(event->event_type);
|
||||
|
||||
if (((converted_event_type == 0) && (converted_event_size == 0))
|
||||
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
|
||||
>= limit))
|
||||
return NULL;
|
||||
addr += (sizeof(struct tcpa_event) + converted_event_size);
|
||||
} while (1);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
@ -134,7 +125,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
|
|||
v += sizeof(struct tcpa_event) + converted_event_size;
|
||||
|
||||
/* now check if current entry is valid */
|
||||
if ((v + sizeof(struct tcpa_event)) >= limit)
|
||||
if ((v + sizeof(struct tcpa_event)) > limit)
|
||||
return NULL;
|
||||
|
||||
event = v;
|
||||
|
@ -143,7 +134,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
|
|||
converted_event_type = do_endian_conversion(event->event_type);
|
||||
|
||||
if (((converted_event_type == 0) && (converted_event_size == 0)) ||
|
||||
((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
|
||||
((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
|
||||
return NULL;
|
||||
|
||||
(*pos)++;
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
*
|
||||
* Returns size of the event. If it is an invalid event, returns 0.
|
||||
*/
|
||||
static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
|
||||
static int calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
|
||||
struct tcg_pcr_event *event_header)
|
||||
{
|
||||
struct tcg_efi_specid_event *efispecid;
|
||||
struct tcg_efi_specid_event_head *efispecid;
|
||||
struct tcg_event_field *event_field;
|
||||
void *marker;
|
||||
void *marker_start;
|
||||
|
@ -55,7 +55,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
|
|||
marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
|
||||
+ sizeof(event->count);
|
||||
|
||||
efispecid = (struct tcg_efi_specid_event *)event_header->event;
|
||||
efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
|
||||
|
||||
/* Check if event is malformed. */
|
||||
if (event->count > efispecid->num_algs)
|
||||
|
@ -95,7 +95,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
|
|||
void *addr = log->bios_event_log;
|
||||
void *limit = log->bios_event_log_end;
|
||||
struct tcg_pcr_event *event_header;
|
||||
struct tcg_pcr_event2 *event;
|
||||
struct tcg_pcr_event2_head *event;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
|
@ -136,7 +136,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
|
|||
loff_t *pos)
|
||||
{
|
||||
struct tcg_pcr_event *event_header;
|
||||
struct tcg_pcr_event2 *event;
|
||||
struct tcg_pcr_event2_head *event;
|
||||
struct tpm_chip *chip = m->private;
|
||||
struct tpm_bios_log *log = &chip->log;
|
||||
void *limit = log->bios_event_log_end;
|
||||
|
@ -180,7 +180,7 @@ static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
|
|||
struct tpm_chip *chip = m->private;
|
||||
struct tpm_bios_log *log = &chip->log;
|
||||
struct tcg_pcr_event *event_header = log->bios_event_log;
|
||||
struct tcg_pcr_event2 *event = v;
|
||||
struct tcg_pcr_event2_head *event = v;
|
||||
void *temp_ptr;
|
||||
size_t size;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
struct st33zp24_i2c_phy {
|
||||
struct i2c_client *client;
|
||||
u8 buf[TPM_BUFSIZE + 1];
|
||||
u8 buf[ST33ZP24_BUFSIZE + 1];
|
||||
int io_lpcpd;
|
||||
};
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
* some latency byte before the answer is available (max 15).
|
||||
* We have 2048 + 1024 + 15.
|
||||
*/
|
||||
#define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\
|
||||
#define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\
|
||||
MAX_SPI_LATENCY)
|
||||
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
return len;
|
||||
return 0;
|
||||
out_err:
|
||||
st33zp24_cancel(chip);
|
||||
release_locality(chip);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#ifndef __LOCAL_ST33ZP24_H__
|
||||
#define __LOCAL_ST33ZP24_H__
|
||||
|
||||
#define TPM_WRITE_DIRECTION 0x80
|
||||
#define TPM_BUFSIZE 2048
|
||||
#define TPM_WRITE_DIRECTION 0x80
|
||||
#define ST33ZP24_BUFSIZE 2048
|
||||
|
||||
struct st33zp24_dev {
|
||||
struct tpm_chip *chip;
|
||||
|
|
|
@ -37,6 +37,103 @@ struct class *tpm_class;
|
|||
struct class *tpmrm_class;
|
||||
dev_t tpm_devt;
|
||||
|
||||
static int tpm_request_locality(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!chip->ops->request_locality)
|
||||
return 0;
|
||||
|
||||
rc = chip->ops->request_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
chip->locality = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_relinquish_locality(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!chip->ops->relinquish_locality)
|
||||
return;
|
||||
|
||||
rc = chip->ops->relinquish_locality(chip, chip->locality);
|
||||
if (rc)
|
||||
dev_err(&chip->dev, "%s: : error %d\n", __func__, rc);
|
||||
|
||||
chip->locality = -1;
|
||||
}
|
||||
|
||||
static int tpm_cmd_ready(struct tpm_chip *chip)
|
||||
{
|
||||
if (!chip->ops->cmd_ready)
|
||||
return 0;
|
||||
|
||||
return chip->ops->cmd_ready(chip);
|
||||
}
|
||||
|
||||
static int tpm_go_idle(struct tpm_chip *chip)
|
||||
{
|
||||
if (!chip->ops->go_idle)
|
||||
return 0;
|
||||
|
||||
return chip->ops->go_idle(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_chip_start() - power on the TPM
|
||||
* @chip: a TPM chip to use
|
||||
*
|
||||
* Return:
|
||||
* * The response length - OK
|
||||
* * -errno - A system error
|
||||
*/
|
||||
int tpm_chip_start(struct tpm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (chip->ops->clk_enable)
|
||||
chip->ops->clk_enable(chip, true);
|
||||
|
||||
if (chip->locality == -1) {
|
||||
ret = tpm_request_locality(chip);
|
||||
if (ret) {
|
||||
chip->ops->clk_enable(chip, false);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tpm_cmd_ready(chip);
|
||||
if (ret) {
|
||||
tpm_relinquish_locality(chip);
|
||||
if (chip->ops->clk_enable)
|
||||
chip->ops->clk_enable(chip, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_chip_start);
|
||||
|
||||
/**
|
||||
* tpm_chip_stop() - power off the TPM
|
||||
* @chip: a TPM chip to use
|
||||
*
|
||||
* Return:
|
||||
* * The response length - OK
|
||||
* * -errno - A system error
|
||||
*/
|
||||
void tpm_chip_stop(struct tpm_chip *chip)
|
||||
{
|
||||
tpm_go_idle(chip);
|
||||
tpm_relinquish_locality(chip);
|
||||
if (chip->ops->clk_enable)
|
||||
chip->ops->clk_enable(chip, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_chip_stop);
|
||||
|
||||
/**
|
||||
* tpm_try_get_ops() - Get a ref to the tpm_chip
|
||||
* @chip: Chip to ref
|
||||
|
@ -56,10 +153,17 @@ int tpm_try_get_ops(struct tpm_chip *chip)
|
|||
|
||||
down_read(&chip->ops_sem);
|
||||
if (!chip->ops)
|
||||
goto out_ops;
|
||||
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
goto out_lock;
|
||||
|
||||
return 0;
|
||||
out_lock:
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
out_ops:
|
||||
up_read(&chip->ops_sem);
|
||||
put_device(&chip->dev);
|
||||
return rc;
|
||||
|
@ -75,6 +179,8 @@ EXPORT_SYMBOL_GPL(tpm_try_get_ops);
|
|||
*/
|
||||
void tpm_put_ops(struct tpm_chip *chip)
|
||||
{
|
||||
tpm_chip_stop(chip);
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
up_read(&chip->ops_sem);
|
||||
put_device(&chip->dev);
|
||||
}
|
||||
|
@ -160,6 +266,7 @@ static void tpm_dev_release(struct device *dev)
|
|||
kfree(chip->log.bios_event_log);
|
||||
kfree(chip->work_space.context_buf);
|
||||
kfree(chip->work_space.session_buf);
|
||||
kfree(chip->allocated_banks);
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
|
@ -189,7 +296,10 @@ static int tpm_class_shutdown(struct device *dev)
|
|||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
down_write(&chip->ops_sem);
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
chip->ops = NULL;
|
||||
up_write(&chip->ops_sem);
|
||||
}
|
||||
|
@ -368,8 +478,12 @@ static void tpm_del_char_device(struct tpm_chip *chip)
|
|||
|
||||
/* Make the driver uncallable. */
|
||||
down_write(&chip->ops_sem);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
}
|
||||
chip->ops = NULL;
|
||||
up_write(&chip->ops_sem);
|
||||
}
|
||||
|
@ -451,7 +565,11 @@ int tpm_chip_register(struct tpm_chip *chip)
|
|||
{
|
||||
int rc;
|
||||
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = tpm_auto_startup(chip);
|
||||
tpm_chip_stop(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
|
@ -27,7 +27,38 @@
|
|||
static struct workqueue_struct *tpm_dev_wq;
|
||||
static DEFINE_MUTEX(tpm_dev_wq_lock);
|
||||
|
||||
static void tpm_async_work(struct work_struct *work)
|
||||
static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz)
|
||||
{
|
||||
struct tpm_header *header = (void *)buf;
|
||||
ssize_t ret, len;
|
||||
|
||||
ret = tpm2_prepare_space(chip, space, buf, bufsiz);
|
||||
/* If the command is not implemented by the TPM, synthesize a
|
||||
* response with a TPM2_RC_COMMAND_CODE return for user-space.
|
||||
*/
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
header->length = cpu_to_be32(sizeof(*header));
|
||||
header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
|
||||
header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
|
||||
TSS2_RESMGR_TPM_RC_LAYER);
|
||||
ret = sizeof(*header);
|
||||
}
|
||||
if (ret)
|
||||
goto out_rc;
|
||||
|
||||
len = tpm_transmit(chip, buf, bufsiz);
|
||||
if (len < 0)
|
||||
ret = len;
|
||||
|
||||
if (!ret)
|
||||
ret = tpm2_commit_space(chip, space, buf, &len);
|
||||
|
||||
out_rc:
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static void tpm_dev_async_work(struct work_struct *work)
|
||||
{
|
||||
struct file_priv *priv =
|
||||
container_of(work, struct file_priv, async_work);
|
||||
|
@ -35,9 +66,8 @@ static void tpm_async_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&priv->buffer_mutex);
|
||||
priv->command_enqueued = false;
|
||||
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
|
||||
sizeof(priv->data_buffer), 0);
|
||||
|
||||
ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
|
||||
sizeof(priv->data_buffer));
|
||||
tpm_put_ops(priv->chip);
|
||||
if (ret > 0) {
|
||||
priv->response_length = ret;
|
||||
|
@ -80,7 +110,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
|
|||
mutex_init(&priv->buffer_mutex);
|
||||
timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
|
||||
INIT_WORK(&priv->timeout_work, tpm_timeout_work);
|
||||
INIT_WORK(&priv->async_work, tpm_async_work);
|
||||
INIT_WORK(&priv->async_work, tpm_dev_async_work);
|
||||
init_waitqueue_head(&priv->async_wait);
|
||||
file->private_data = priv;
|
||||
}
|
||||
|
@ -183,8 +213,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
|
|||
return size;
|
||||
}
|
||||
|
||||
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
|
||||
sizeof(priv->data_buffer), 0);
|
||||
ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
|
||||
sizeof(priv->data_buffer));
|
||||
tpm_put_ops(priv->chip);
|
||||
|
||||
if (ret > 0) {
|
||||
|
|
|
@ -62,137 +62,22 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
||||
|
||||
static int tpm_validate_command(struct tpm_chip *chip,
|
||||
struct tpm_space *space,
|
||||
const u8 *cmd,
|
||||
size_t len)
|
||||
static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
|
||||
{
|
||||
const struct tpm_input_header *header = (const void *)cmd;
|
||||
int i;
|
||||
u32 cc;
|
||||
u32 attrs;
|
||||
unsigned int nr_handles;
|
||||
|
||||
if (len < TPM_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (!space)
|
||||
return 0;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
|
||||
cc = be32_to_cpu(header->ordinal);
|
||||
|
||||
i = tpm2_find_cc(chip, cc);
|
||||
if (i < 0) {
|
||||
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
|
||||
cc);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
attrs = chip->cc_attrs_tbl[i];
|
||||
nr_handles =
|
||||
4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
|
||||
if (len < TPM_HEADER_SIZE + 4 * nr_handles)
|
||||
goto err_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_len:
|
||||
dev_dbg(&chip->dev,
|
||||
"%s: insufficient command length %zu", __func__, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
if (!chip->ops->request_locality)
|
||||
return 0;
|
||||
|
||||
rc = chip->ops->request_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
chip->locality = rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return;
|
||||
|
||||
if (!chip->ops->relinquish_locality)
|
||||
return;
|
||||
|
||||
rc = chip->ops->relinquish_locality(chip, chip->locality);
|
||||
if (rc)
|
||||
dev_err(&chip->dev, "%s: : error %d\n", __func__, rc);
|
||||
|
||||
chip->locality = -1;
|
||||
}
|
||||
|
||||
static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
if (!chip->ops->cmd_ready)
|
||||
return 0;
|
||||
|
||||
return chip->ops->cmd_ready(chip);
|
||||
}
|
||||
|
||||
static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
if (!chip->ops->go_idle)
|
||||
return 0;
|
||||
|
||||
return chip->ops->go_idle(chip);
|
||||
}
|
||||
|
||||
static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
||||
struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct tpm_output_header *header = (void *)buf;
|
||||
struct tpm_header *header = buf;
|
||||
int rc;
|
||||
ssize_t len = 0;
|
||||
u32 count, ordinal;
|
||||
unsigned long stop;
|
||||
bool need_locality;
|
||||
|
||||
rc = tpm_validate_command(chip, space, buf, bufsiz);
|
||||
if (rc == -EINVAL)
|
||||
return rc;
|
||||
/*
|
||||
* If the command is not implemented by the TPM, synthesize a
|
||||
* response with a TPM2_RC_COMMAND_CODE return for user-space.
|
||||
*/
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
header->length = cpu_to_be32(sizeof(*header));
|
||||
header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
|
||||
header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
|
||||
TSS2_RESMGR_TPM_RC_LAYER);
|
||||
return sizeof(*header);
|
||||
}
|
||||
if (bufsiz < TPM_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (bufsiz > TPM_BUFSIZE)
|
||||
bufsiz = TPM_BUFSIZE;
|
||||
|
||||
count = be32_to_cpu(*((__be32 *) (buf + 2)));
|
||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||
count = be32_to_cpu(header->length);
|
||||
ordinal = be32_to_cpu(header->ordinal);
|
||||
if (count == 0)
|
||||
return -ENODATA;
|
||||
if (count > bufsiz) {
|
||||
|
@ -201,37 +86,21 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
|||
return -E2BIG;
|
||||
}
|
||||
|
||||
if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, true);
|
||||
|
||||
/* Store the decision as chip->locality will be changed. */
|
||||
need_locality = chip->locality == -1;
|
||||
|
||||
if (need_locality) {
|
||||
rc = tpm_request_locality(chip, flags);
|
||||
if (rc < 0) {
|
||||
need_locality = false;
|
||||
goto out_locality;
|
||||
}
|
||||
}
|
||||
|
||||
rc = tpm_cmd_ready(chip, flags);
|
||||
if (rc)
|
||||
goto out_locality;
|
||||
|
||||
rc = tpm2_prepare_space(chip, space, ordinal, buf);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = chip->ops->send(chip, buf, count);
|
||||
if (rc < 0) {
|
||||
if (rc != -EPIPE)
|
||||
dev_err(&chip->dev,
|
||||
"%s: tpm_send: error %d\n", __func__, rc);
|
||||
goto out;
|
||||
"%s: send(): error %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* A sanity check. send() should just return zero on success e.g.
|
||||
* not the command length.
|
||||
*/
|
||||
if (rc > 0) {
|
||||
dev_warn(&chip->dev,
|
||||
"%s: send(): invalid value %d\n", __func__, rc);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_IRQ)
|
||||
|
@ -246,8 +115,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
|||
|
||||
if (chip->ops->req_canceled(chip, status)) {
|
||||
dev_err(&chip->dev, "Operation Canceled\n");
|
||||
rc = -ECANCELED;
|
||||
goto out;
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
tpm_msleep(TPM_TIMEOUT_POLL);
|
||||
|
@ -256,77 +124,45 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
|||
|
||||
chip->ops->cancel(chip);
|
||||
dev_err(&chip->dev, "Operation Timed out\n");
|
||||
rc = -ETIME;
|
||||
goto out;
|
||||
return -ETIME;
|
||||
|
||||
out_recv:
|
||||
len = chip->ops->recv(chip, buf, bufsiz);
|
||||
if (len < 0) {
|
||||
rc = len;
|
||||
dev_err(&chip->dev,
|
||||
"tpm_transmit: tpm_recv: error %d\n", rc);
|
||||
goto out;
|
||||
} else if (len < TPM_HEADER_SIZE) {
|
||||
dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc);
|
||||
} else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length))
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len != be32_to_cpu(header->length)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
|
||||
if (rc)
|
||||
dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
|
||||
|
||||
out:
|
||||
/* may fail but do not override previous error value in rc */
|
||||
tpm_go_idle(chip, flags);
|
||||
|
||||
out_locality:
|
||||
if (need_locality)
|
||||
tpm_relinquish_locality(chip, flags);
|
||||
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, false);
|
||||
|
||||
if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
return rc ? rc : len;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_transmit - Internal kernel interface to transmit TPM commands.
|
||||
* @chip: a TPM chip to use
|
||||
* @buf: a TPM command buffer
|
||||
* @bufsiz: length of the TPM command buffer
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
* @space: tpm space
|
||||
* @buf: TPM command buffer
|
||||
* @bufsiz: length of the TPM command buffer
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
* A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from
|
||||
* the TPM and retransmits the command after a delay up to a maximum wait of
|
||||
* TPM2_DURATION_LONG.
|
||||
*
|
||||
* A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY
|
||||
* returns from the TPM and retransmits the command after a delay up
|
||||
* to a maximum wait of TPM2_DURATION_LONG.
|
||||
*
|
||||
* Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2
|
||||
* only
|
||||
* Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0
|
||||
* only.
|
||||
*
|
||||
* Return:
|
||||
* the length of the return when the operation is successful.
|
||||
* A negative number for system errors (errno).
|
||||
* * The response length - OK
|
||||
* * -errno - A system error
|
||||
*/
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz, unsigned int flags)
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
|
||||
{
|
||||
struct tpm_output_header *header = (struct tpm_output_header *)buf;
|
||||
struct tpm_header *header = (struct tpm_header *)buf;
|
||||
/* space for header and handles */
|
||||
u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
|
||||
unsigned int delay_msec = TPM2_DURATION_SHORT;
|
||||
u32 rc = 0;
|
||||
ssize_t ret;
|
||||
const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
|
||||
bufsiz);
|
||||
const size_t save_size = min(sizeof(save), bufsiz);
|
||||
/* the command code is where the return code will be */
|
||||
u32 cc = be32_to_cpu(header->return_code);
|
||||
|
||||
|
@ -338,7 +174,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
|||
memcpy(save, buf, save_size);
|
||||
|
||||
for (;;) {
|
||||
ret = tpm_try_transmit(chip, space, buf, bufsiz, flags);
|
||||
ret = tpm_try_transmit(chip, buf, bufsiz);
|
||||
if (ret < 0)
|
||||
break;
|
||||
rc = be32_to_cpu(header->return_code);
|
||||
|
@ -365,39 +201,33 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_transmit_cmd - send a tpm command to the device
|
||||
* The function extracts tpm out header return code
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
* @space: tpm space
|
||||
* @buf: TPM command buffer
|
||||
* @bufsiz: length of the buffer
|
||||
* @min_rsp_body_length: minimum expected length of response body
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
* @desc: command description used in the error message
|
||||
* @chip: a TPM chip to use
|
||||
* @buf: a TPM command buffer
|
||||
* @min_rsp_body_length: minimum expected length of response body
|
||||
* @desc: command description used in the error message
|
||||
*
|
||||
* Return:
|
||||
* 0 when the operation is successful.
|
||||
* A negative number for system errors (errno).
|
||||
* A positive number for a TPM error.
|
||||
* * 0 - OK
|
||||
* * -errno - A system error
|
||||
* * TPM_RC - A TPM error
|
||||
*/
|
||||
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
|
||||
void *buf, size_t bufsiz,
|
||||
size_t min_rsp_body_length, unsigned int flags,
|
||||
const char *desc)
|
||||
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
size_t min_rsp_body_length, const char *desc)
|
||||
{
|
||||
const struct tpm_output_header *header = buf;
|
||||
const struct tpm_header *header = (struct tpm_header *)buf->data;
|
||||
int err;
|
||||
ssize_t len;
|
||||
|
||||
len = tpm_transmit(chip, space, buf, bufsiz, flags);
|
||||
len = tpm_transmit(chip, buf->data, PAGE_SIZE);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
err = be32_to_cpu(header->return_code);
|
||||
if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
|
||||
&& desc)
|
||||
&& err != TPM2_RC_TESTING && desc)
|
||||
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
|
||||
desc);
|
||||
if (err)
|
||||
|
@ -451,11 +281,12 @@ EXPORT_SYMBOL_GPL(tpm_is_tpm2);
|
|||
* tpm_pcr_read - read a PCR value from SHA1 bank
|
||||
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||
* @pcr_idx: the PCR to be retrieved
|
||||
* @res_buf: the value of the PCR
|
||||
* @digest: the PCR bank and buffer current PCR value is written to
|
||||
*
|
||||
* Return: same as with tpm_transmit_cmd()
|
||||
*/
|
||||
int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digest)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -464,9 +295,9 @@ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
|||
return -ENODEV;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
|
||||
rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL);
|
||||
else
|
||||
rc = tpm1_pcr_read(chip, pcr_idx, res_buf);
|
||||
rc = tpm1_pcr_read(chip, pcr_idx, digest->digest);
|
||||
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
|
@ -477,41 +308,34 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);
|
|||
* tpm_pcr_extend - extend a PCR value in SHA1 bank.
|
||||
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||
* @pcr_idx: the PCR to be retrieved
|
||||
* @hash: the hash value used to extend the PCR value
|
||||
* @digests: array of tpm_digest structures used to extend PCRs
|
||||
*
|
||||
* Note: with TPM 2.0 extends also those banks with a known digest size to the
|
||||
* cryto subsystem in order to prevent malicious use of those PCR banks. In the
|
||||
* future we should dynamically determine digest sizes.
|
||||
* Note: callers must pass a digest for every allocated PCR bank, in the same
|
||||
* order of the banks in chip->allocated_banks.
|
||||
*
|
||||
* Return: same as with tpm_transmit_cmd()
|
||||
*/
|
||||
int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash)
|
||||
int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests)
|
||||
{
|
||||
int rc;
|
||||
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
|
||||
u32 count = 0;
|
||||
int i;
|
||||
|
||||
chip = tpm_find_get_ops(chip);
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < chip->nr_allocated_banks; i++)
|
||||
if (digests[i].alg_id != chip->allocated_banks[i].alg_id)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
memset(digest_list, 0, sizeof(digest_list));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chip->active_banks) &&
|
||||
chip->active_banks[i] != TPM2_ALG_ERROR; i++) {
|
||||
digest_list[i].alg_id = chip->active_banks[i];
|
||||
memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
|
||||
count++;
|
||||
}
|
||||
|
||||
rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
|
||||
rc = tpm2_pcr_extend(chip, pcr_idx, digests);
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = tpm1_pcr_extend(chip, pcr_idx, hash,
|
||||
rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest,
|
||||
"attempting extend a PCR value");
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
|
@ -528,14 +352,21 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend);
|
|||
*/
|
||||
int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
|
||||
chip = tpm_find_get_ops(chip);
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
|
||||
"attempting to a send a command");
|
||||
rc = tpm_buf_init(&buf, 0, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
memcpy(buf.data, cmd, buflen);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command");
|
||||
tpm_buf_destroy(&buf);
|
||||
out:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
|
@ -571,10 +402,16 @@ int tpm_pm_suspend(struct device *dev)
|
|||
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
|
||||
return 0;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
else
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
} else {
|
||||
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct tpm_buf tpm_buf;
|
||||
struct tpm_readpubek_out *out;
|
||||
ssize_t rc;
|
||||
int i;
|
||||
char *str = buf;
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
|
@ -47,19 +46,17 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
memset(&anti_replay, 0, sizeof(anti_replay));
|
||||
|
||||
rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
|
||||
if (rc)
|
||||
return rc;
|
||||
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_append(&tpm_buf, anti_replay, sizeof(anti_replay));
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE,
|
||||
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
|
||||
"attempting to read the PUBEK");
|
||||
if (rc) {
|
||||
tpm_buf_destroy(&tpm_buf);
|
||||
return 0;
|
||||
}
|
||||
if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
|
||||
"attempting to read the PUBEK"))
|
||||
goto out_buf;
|
||||
|
||||
out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
|
||||
str +=
|
||||
|
@ -90,9 +87,11 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
|||
str += sprintf(str, "\n");
|
||||
}
|
||||
|
||||
rc = str - buf;
|
||||
out_buf:
|
||||
tpm_buf_destroy(&tpm_buf);
|
||||
return rc;
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return str - buf;
|
||||
}
|
||||
static DEVICE_ATTR_RO(pubek);
|
||||
|
||||
|
@ -101,27 +100,32 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
cap_t cap;
|
||||
u8 digest[TPM_DIGEST_SIZE];
|
||||
ssize_t rc;
|
||||
u32 i, j, num_pcrs;
|
||||
char *str = buf;
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
|
||||
rc = tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap,
|
||||
"attempting to determine the number of PCRS",
|
||||
sizeof(cap.num_pcrs));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap,
|
||||
"attempting to determine the number of PCRS",
|
||||
sizeof(cap.num_pcrs))) {
|
||||
tpm_put_ops(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
num_pcrs = be32_to_cpu(cap.num_pcrs);
|
||||
for (i = 0; i < num_pcrs; i++) {
|
||||
rc = tpm1_pcr_read(chip, i, digest);
|
||||
if (rc)
|
||||
if (tpm1_pcr_read(chip, i, digest)) {
|
||||
str = buf;
|
||||
break;
|
||||
}
|
||||
str += sprintf(str, "PCR-%02d: ", i);
|
||||
for (j = 0; j < TPM_DIGEST_SIZE; j++)
|
||||
str += sprintf(str, "%02X ", digest[j]);
|
||||
str += sprintf(str, "\n");
|
||||
}
|
||||
tpm_put_ops(chip);
|
||||
return str - buf;
|
||||
}
|
||||
static DEVICE_ATTR_RO(pcrs);
|
||||
|
@ -129,16 +133,21 @@ static DEVICE_ATTR_RO(pcrs);
|
|||
static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t rc = 0;
|
||||
cap_t cap;
|
||||
ssize_t rc;
|
||||
|
||||
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
|
||||
"attempting to determine the permanent enabled state",
|
||||
sizeof(cap.perm_flags));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap,
|
||||
"attempting to determine the permanent enabled state",
|
||||
sizeof(cap.perm_flags)))
|
||||
goto out_ops;
|
||||
|
||||
rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(enabled);
|
||||
|
@ -146,16 +155,21 @@ static DEVICE_ATTR_RO(enabled);
|
|||
static ssize_t active_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t rc = 0;
|
||||
cap_t cap;
|
||||
ssize_t rc;
|
||||
|
||||
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
|
||||
"attempting to determine the permanent active state",
|
||||
sizeof(cap.perm_flags));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap,
|
||||
"attempting to determine the permanent active state",
|
||||
sizeof(cap.perm_flags)))
|
||||
goto out_ops;
|
||||
|
||||
rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(active);
|
||||
|
@ -163,16 +177,21 @@ static DEVICE_ATTR_RO(active);
|
|||
static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t rc = 0;
|
||||
cap_t cap;
|
||||
ssize_t rc;
|
||||
|
||||
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
|
||||
"attempting to determine the owner state",
|
||||
sizeof(cap.owned));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
|
||||
"attempting to determine the owner state",
|
||||
sizeof(cap.owned)))
|
||||
goto out_ops;
|
||||
|
||||
rc = sprintf(buf, "%d\n", cap.owned);
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(owned);
|
||||
|
@ -180,16 +199,21 @@ static DEVICE_ATTR_RO(owned);
|
|||
static ssize_t temp_deactivated_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t rc = 0;
|
||||
cap_t cap;
|
||||
ssize_t rc;
|
||||
|
||||
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
|
||||
"attempting to determine the temporary state",
|
||||
sizeof(cap.stclear_flags));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
|
||||
"attempting to determine the temporary state",
|
||||
sizeof(cap.stclear_flags)))
|
||||
goto out_ops;
|
||||
|
||||
rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(temp_deactivated);
|
||||
|
@ -198,15 +222,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
|
|||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
cap_t cap;
|
||||
ssize_t rc;
|
||||
ssize_t rc = 0;
|
||||
char *str = buf;
|
||||
cap_t cap;
|
||||
|
||||
rc = tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
|
||||
"attempting to determine the manufacturer",
|
||||
sizeof(cap.manufacturer_id));
|
||||
if (rc)
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
if (tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
|
||||
"attempting to determine the manufacturer",
|
||||
sizeof(cap.manufacturer_id)))
|
||||
goto out_ops;
|
||||
|
||||
str += sprintf(str, "Manufacturer: 0x%x\n",
|
||||
be32_to_cpu(cap.manufacturer_id));
|
||||
|
||||
|
@ -223,11 +250,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
|
|||
cap.tpm_version_1_2.revMinor);
|
||||
} else {
|
||||
/* Otherwise just use TPM_STRUCT_VER */
|
||||
rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
|
||||
"attempting to determine the 1.1 version",
|
||||
sizeof(cap.tpm_version));
|
||||
if (rc)
|
||||
return 0;
|
||||
if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
|
||||
"attempting to determine the 1.1 version",
|
||||
sizeof(cap.tpm_version)))
|
||||
goto out_ops;
|
||||
str += sprintf(str,
|
||||
"TCG version: %d.%d\nFirmware version: %d.%d\n",
|
||||
cap.tpm_version.Major,
|
||||
|
@ -235,8 +261,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
|
|||
cap.tpm_version.revMajor,
|
||||
cap.tpm_version.revMinor);
|
||||
}
|
||||
|
||||
return str - buf;
|
||||
rc = str - buf;
|
||||
out_ops:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(caps);
|
||||
|
||||
|
@ -244,10 +272,12 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
if (chip == NULL)
|
||||
|
||||
if (tpm_try_get_ops(chip))
|
||||
return 0;
|
||||
|
||||
chip->ops->cancel(chip);
|
||||
tpm_put_ops(chip);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(cancel);
|
||||
|
|
|
@ -25,30 +25,22 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/tpm.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/tpm_eventlog.h>
|
||||
#include <crypto/hash_info.h>
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/intel-family.h>
|
||||
#endif
|
||||
|
||||
enum tpm_const {
|
||||
TPM_MINOR = 224, /* officially assigned */
|
||||
TPM_BUFSIZE = 4096,
|
||||
TPM_NUM_DEVICES = 65536,
|
||||
TPM_RETRY = 50, /* 5 seconds */
|
||||
TPM_NUM_EVENT_LOG_FILES = 3,
|
||||
};
|
||||
#define TPM_MINOR 224 /* officially assigned */
|
||||
#define TPM_BUFSIZE 4096
|
||||
#define TPM_NUM_DEVICES 65536
|
||||
#define TPM_RETRY 50
|
||||
|
||||
enum tpm_timeout {
|
||||
TPM_TIMEOUT = 5, /* msecs */
|
||||
|
@ -65,16 +57,6 @@ enum tpm_addr {
|
|||
TPM_ADDR = 0x4E,
|
||||
};
|
||||
|
||||
/* Indexes the duration array */
|
||||
enum tpm_duration {
|
||||
TPM_SHORT = 0,
|
||||
TPM_MEDIUM = 1,
|
||||
TPM_LONG = 2,
|
||||
TPM_LONG_LONG = 3,
|
||||
TPM_UNDEFINED,
|
||||
TPM_NUM_DURATIONS = TPM_UNDEFINED,
|
||||
};
|
||||
|
||||
#define TPM_WARN_RETRY 0x800
|
||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||
#define TPM_ERR_DEACTIVATED 0x6
|
||||
|
@ -122,17 +104,6 @@ enum tpm2_return_codes {
|
|||
TPM2_RC_RETRY = 0x0922,
|
||||
};
|
||||
|
||||
enum tpm2_algorithms {
|
||||
TPM2_ALG_ERROR = 0x0000,
|
||||
TPM2_ALG_SHA1 = 0x0004,
|
||||
TPM2_ALG_KEYEDHASH = 0x0008,
|
||||
TPM2_ALG_SHA256 = 0x000B,
|
||||
TPM2_ALG_SHA384 = 0x000C,
|
||||
TPM2_ALG_SHA512 = 0x000D,
|
||||
TPM2_ALG_NULL = 0x0010,
|
||||
TPM2_ALG_SM3_256 = 0x0012,
|
||||
};
|
||||
|
||||
enum tpm2_command_codes {
|
||||
TPM2_CC_FIRST = 0x011F,
|
||||
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
|
||||
|
@ -190,15 +161,6 @@ enum tpm2_cc_attrs {
|
|||
#define TPM_VID_WINBOND 0x1050
|
||||
#define TPM_VID_STM 0x104A
|
||||
|
||||
#define TPM_PPI_VERSION_LEN 3
|
||||
|
||||
struct tpm_space {
|
||||
u32 context_tbl[3];
|
||||
u8 *context_buf;
|
||||
u32 session_tbl[3];
|
||||
u8 *session_buf;
|
||||
};
|
||||
|
||||
enum tpm_chip_flags {
|
||||
TPM_CHIP_FLAG_TPM2 = BIT(1),
|
||||
TPM_CHIP_FLAG_IRQ = BIT(2),
|
||||
|
@ -207,82 +169,15 @@ enum tpm_chip_flags {
|
|||
TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
|
||||
};
|
||||
|
||||
struct tpm_bios_log {
|
||||
void *bios_event_log;
|
||||
void *bios_event_log_end;
|
||||
};
|
||||
|
||||
struct tpm_chip_seqops {
|
||||
struct tpm_chip *chip;
|
||||
const struct seq_operations *seqops;
|
||||
};
|
||||
|
||||
struct tpm_chip {
|
||||
struct device dev;
|
||||
struct device devs;
|
||||
struct cdev cdev;
|
||||
struct cdev cdevs;
|
||||
|
||||
/* A driver callback under ops cannot be run unless ops_sem is held
|
||||
* (sometimes implicitly, eg for the sysfs code). ops becomes null
|
||||
* when the driver is unregistered, see tpm_try_get_ops.
|
||||
*/
|
||||
struct rw_semaphore ops_sem;
|
||||
const struct tpm_class_ops *ops;
|
||||
|
||||
struct tpm_bios_log log;
|
||||
struct tpm_chip_seqops bin_log_seqops;
|
||||
struct tpm_chip_seqops ascii_log_seqops;
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
int dev_num; /* /dev/tpm# */
|
||||
unsigned long is_open; /* only one allowed */
|
||||
|
||||
char hwrng_name[64];
|
||||
struct hwrng hwrng;
|
||||
|
||||
struct mutex tpm_mutex; /* tpm is processing */
|
||||
|
||||
unsigned long timeout_a; /* jiffies */
|
||||
unsigned long timeout_b; /* jiffies */
|
||||
unsigned long timeout_c; /* jiffies */
|
||||
unsigned long timeout_d; /* jiffies */
|
||||
bool timeout_adjusted;
|
||||
unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
|
||||
bool duration_adjusted;
|
||||
|
||||
struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES];
|
||||
|
||||
const struct attribute_group *groups[3];
|
||||
unsigned int groups_cnt;
|
||||
|
||||
u16 active_banks[7];
|
||||
#ifdef CONFIG_ACPI
|
||||
acpi_handle acpi_dev_handle;
|
||||
char ppi_version[TPM_PPI_VERSION_LEN + 1];
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
struct tpm_space work_space;
|
||||
u32 nr_commands;
|
||||
u32 *cc_attrs_tbl;
|
||||
|
||||
/* active locality */
|
||||
int locality;
|
||||
};
|
||||
|
||||
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
|
||||
|
||||
struct tpm_input_header {
|
||||
__be16 tag;
|
||||
__be32 length;
|
||||
__be32 ordinal;
|
||||
} __packed;
|
||||
|
||||
struct tpm_output_header {
|
||||
__be16 tag;
|
||||
__be32 length;
|
||||
__be32 return_code;
|
||||
struct tpm_header {
|
||||
__be16 tag;
|
||||
__be32 length;
|
||||
union {
|
||||
__be32 ordinal;
|
||||
__be32 return_code;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define TPM_TAG_RQU_COMMAND 193
|
||||
|
@ -401,8 +296,8 @@ struct tpm_buf {
|
|||
|
||||
static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
|
||||
{
|
||||
struct tpm_input_header *head;
|
||||
head = (struct tpm_input_header *)buf->data;
|
||||
struct tpm_header *head = (struct tpm_header *)buf->data;
|
||||
|
||||
head->tag = cpu_to_be16(tag);
|
||||
head->length = cpu_to_be32(sizeof(*head));
|
||||
head->ordinal = cpu_to_be32(ordinal);
|
||||
|
@ -428,14 +323,14 @@ static inline void tpm_buf_destroy(struct tpm_buf *buf)
|
|||
|
||||
static inline u32 tpm_buf_length(struct tpm_buf *buf)
|
||||
{
|
||||
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
|
||||
struct tpm_header *head = (struct tpm_header *)buf->data;
|
||||
|
||||
return be32_to_cpu(head->length);
|
||||
}
|
||||
|
||||
static inline u16 tpm_buf_tag(struct tpm_buf *buf)
|
||||
{
|
||||
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
|
||||
struct tpm_header *head = (struct tpm_header *)buf->data;
|
||||
|
||||
return be16_to_cpu(head->tag);
|
||||
}
|
||||
|
@ -444,7 +339,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
|
|||
const unsigned char *new_data,
|
||||
unsigned int new_len)
|
||||
{
|
||||
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
|
||||
struct tpm_header *head = (struct tpm_header *)buf->data;
|
||||
u32 len = tpm_buf_length(buf);
|
||||
|
||||
/* Return silently if overflow has already happened. */
|
||||
|
@ -487,25 +382,9 @@ extern const struct file_operations tpm_fops;
|
|||
extern const struct file_operations tpmrm_fops;
|
||||
extern struct idr dev_nums_idr;
|
||||
|
||||
/**
|
||||
* enum tpm_transmit_flags - flags for tpm_transmit()
|
||||
*
|
||||
* @TPM_TRANSMIT_UNLOCKED: do not lock the chip
|
||||
* @TPM_TRANSMIT_NESTED: discard setup steps (power management,
|
||||
* locality) including locking (i.e. implicit
|
||||
* UNLOCKED)
|
||||
*/
|
||||
enum tpm_transmit_flags {
|
||||
TPM_TRANSMIT_UNLOCKED = BIT(0),
|
||||
TPM_TRANSMIT_NESTED = BIT(1),
|
||||
};
|
||||
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz, unsigned int flags);
|
||||
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
|
||||
void *buf, size_t bufsiz,
|
||||
size_t min_rsp_body_length, unsigned int flags,
|
||||
const char *desc);
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz);
|
||||
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
size_t min_rsp_body_length, const char *desc);
|
||||
int tpm_get_timeouts(struct tpm_chip *);
|
||||
int tpm_auto_startup(struct tpm_chip *chip);
|
||||
|
||||
|
@ -530,6 +409,8 @@ static inline void tpm_msleep(unsigned int delay_msec)
|
|||
delay_msec * 1000);
|
||||
};
|
||||
|
||||
int tpm_chip_start(struct tpm_chip *chip);
|
||||
void tpm_chip_stop(struct tpm_chip *chip);
|
||||
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
|
||||
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
|
||||
void tpm_put_ops(struct tpm_chip *chip);
|
||||
|
@ -558,12 +439,12 @@ static inline u32 tpm2_rc_value(u32 rc)
|
|||
}
|
||||
|
||||
int tpm2_get_timeouts(struct tpm_chip *chip);
|
||||
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf);
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
|
||||
struct tpm2_digest *digests);
|
||||
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digest, u16 *digest_size_ptr);
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests);
|
||||
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max);
|
||||
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
|
||||
unsigned int flags);
|
||||
void tpm2_flush_context(struct tpm_chip *chip, u32 handle);
|
||||
int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
struct trusted_key_payload *payload,
|
||||
struct trusted_key_options *options);
|
||||
|
@ -580,10 +461,11 @@ int tpm2_probe(struct tpm_chip *chip);
|
|||
int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
|
||||
int tpm2_init_space(struct tpm_space *space);
|
||||
void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space);
|
||||
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
|
||||
u8 *cmd);
|
||||
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u32 cc, u8 *buf, size_t *bufsiz);
|
||||
void tpm2_flush_space(struct tpm_chip *chip);
|
||||
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
|
||||
size_t cmdsiz);
|
||||
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
|
||||
size_t *bufsiz);
|
||||
|
||||
int tpm_bios_log_setup(struct tpm_chip *chip);
|
||||
void tpm_bios_log_teardown(struct tpm_chip *chip);
|
||||
|
|
|
@ -334,11 +334,8 @@ static int tpm1_startup(struct tpm_chip *chip)
|
|||
|
||||
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"attempting to start the TPM");
|
||||
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -380,8 +377,7 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
|
|||
* of misreporting.
|
||||
*/
|
||||
if (chip->ops->update_timeouts)
|
||||
chip->timeout_adjusted =
|
||||
chip->ops->update_timeouts(chip, timeout_eff);
|
||||
chip->ops->update_timeouts(chip, timeout_eff);
|
||||
|
||||
if (!chip->timeout_adjusted) {
|
||||
/* Restore default if chip reported 0 */
|
||||
|
@ -462,9 +458,7 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
|
|||
tpm_buf_append_u32(&buf, pcr_idx);
|
||||
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
TPM_DIGEST_SIZE, 0, log_msg);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
|
||||
tpm_buf_destroy(&buf);
|
||||
return rc;
|
||||
}
|
||||
|
@ -494,11 +488,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
|
|||
tpm_buf_append_u32(&buf, 4);
|
||||
tpm_buf_append_u32(&buf, subcap_id);
|
||||
}
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
min_cap_length, 0, 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);
|
||||
return rc;
|
||||
}
|
||||
|
@ -537,8 +529,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
|||
do {
|
||||
tpm_buf_append_u32(&buf, num_bytes);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
sizeof(out->rng_data_len), 0,
|
||||
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
|
||||
"attempting get random");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
@ -583,8 +574,7 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
|||
|
||||
tpm_buf_append_u32(&buf, pcr_idx);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
TPM_DIGEST_SIZE, 0,
|
||||
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
|
||||
"attempting to read a pcr value");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
@ -618,11 +608,8 @@ static int tpm1_continue_selftest(struct tpm_chip *chip)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
0, 0, "continue selftest");
|
||||
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -709,6 +696,18 @@ int tpm1_auto_startup(struct tpm_chip *chip)
|
|||
goto out;
|
||||
}
|
||||
|
||||
chip->allocated_banks = kcalloc(1, sizeof(*chip->allocated_banks),
|
||||
GFP_KERNEL);
|
||||
if (!chip->allocated_banks) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
chip->allocated_banks[0].alg_id = TPM_ALG_SHA1;
|
||||
chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1];
|
||||
chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1;
|
||||
chip->nr_allocated_banks = 1;
|
||||
|
||||
return rc;
|
||||
out:
|
||||
if (rc > 0)
|
||||
|
@ -747,9 +746,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
|
|||
return rc;
|
||||
/* now do the actual savestate */
|
||||
for (try = 0; try < TPM_RETRY; try++) {
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
0, 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
|
||||
|
|
|
@ -33,11 +33,11 @@ struct tpm2_hash {
|
|||
};
|
||||
|
||||
static struct tpm2_hash tpm2_hash_map[] = {
|
||||
{HASH_ALGO_SHA1, TPM2_ALG_SHA1},
|
||||
{HASH_ALGO_SHA256, TPM2_ALG_SHA256},
|
||||
{HASH_ALGO_SHA384, TPM2_ALG_SHA384},
|
||||
{HASH_ALGO_SHA512, TPM2_ALG_SHA512},
|
||||
{HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
|
||||
{HASH_ALGO_SHA1, TPM_ALG_SHA1},
|
||||
{HASH_ALGO_SHA256, TPM_ALG_SHA256},
|
||||
{HASH_ALGO_SHA384, TPM_ALG_SHA384},
|
||||
{HASH_ALGO_SHA512, TPM_ALG_SHA512},
|
||||
{HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
|
||||
};
|
||||
|
||||
int tpm2_get_timeouts(struct tpm_chip *chip)
|
||||
|
@ -171,20 +171,36 @@ struct tpm2_pcr_read_out {
|
|||
* tpm2_pcr_read() - read a PCR value
|
||||
* @chip: TPM chip to use.
|
||||
* @pcr_idx: index of the PCR to read.
|
||||
* @res_buf: buffer to store the resulting hash.
|
||||
* @digest: PCR bank and buffer current PCR value is written to.
|
||||
* @digest_size_ptr: pointer to variable that stores the digest size.
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd.
|
||||
*/
|
||||
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digest, u16 *digest_size_ptr)
|
||||
{
|
||||
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;
|
||||
|
||||
if (pcr_idx >= TPM2_PLATFORM_PCR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!digest_size_ptr) {
|
||||
for (i = 0; i < chip->nr_allocated_banks &&
|
||||
chip->allocated_banks[i].alg_id != digest->alg_id; i++)
|
||||
;
|
||||
|
||||
if (i == chip->nr_allocated_banks)
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
|
@ -192,18 +208,28 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
|||
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
|
||||
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_SHA1);
|
||||
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, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
res_buf ? "attempting to read a pcr value" : NULL);
|
||||
if (rc == 0 && res_buf) {
|
||||
out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
|
||||
memcpy(res_buf, out->digest, SHA1_DIGEST_SIZE);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (digest_size_ptr)
|
||||
*digest_size_ptr = digest_size;
|
||||
|
||||
memcpy(digest->digest, out->digest, digest_size);
|
||||
out:
|
||||
tpm_buf_destroy(&buf);
|
||||
return rc;
|
||||
}
|
||||
|
@ -220,22 +246,17 @@ struct tpm2_null_auth_area {
|
|||
*
|
||||
* @chip: TPM chip to use.
|
||||
* @pcr_idx: index of the PCR.
|
||||
* @count: number of digests passed.
|
||||
* @digests: list of pcr banks and corresponding digest values to extend.
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd.
|
||||
*/
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
|
||||
struct tpm2_digest *digests)
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
struct tpm2_null_auth_area auth_area;
|
||||
int rc;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (count > ARRAY_SIZE(chip->active_banks))
|
||||
return -EINVAL;
|
||||
|
||||
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
|
||||
if (rc)
|
||||
|
@ -251,21 +272,15 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
|
|||
tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
|
||||
tpm_buf_append(&buf, (const unsigned char *)&auth_area,
|
||||
sizeof(auth_area));
|
||||
tpm_buf_append_u32(&buf, count);
|
||||
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
|
||||
if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
|
||||
continue;
|
||||
tpm_buf_append_u16(&buf, digests[i].alg_id);
|
||||
tpm_buf_append(&buf, (const unsigned char
|
||||
*)&digests[i].digest,
|
||||
hash_digest_size[tpm2_hash_map[j].crypto_id]);
|
||||
}
|
||||
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,
|
||||
chip->allocated_banks[i].digest_size);
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"attempting extend a PCR value");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
|
||||
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
|
@ -309,10 +324,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
|||
do {
|
||||
tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
|
||||
tpm_buf_append_u16(&buf, num_bytes);
|
||||
err = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
err = tpm_transmit_cmd(chip, &buf,
|
||||
offsetof(struct tpm2_get_random_out,
|
||||
buffer),
|
||||
0, "attempting get random");
|
||||
"attempting get random");
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -341,14 +356,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
|||
}
|
||||
|
||||
/**
|
||||
* tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
|
||||
* tpm2_flush_context() - execute a TPM2_FlushContext command
|
||||
* @chip: TPM chip to use
|
||||
* @handle: context handle
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
*
|
||||
*/
|
||||
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
|
||||
unsigned int flags)
|
||||
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
|
@ -362,9 +374,7 @@ void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
|
|||
|
||||
tpm_buf_append_u32(&buf, handle);
|
||||
|
||||
(void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags,
|
||||
"flushing context");
|
||||
|
||||
tpm_transmit_cmd(chip, &buf, 0, "flushing context");
|
||||
tpm_buf_destroy(&buf);
|
||||
}
|
||||
|
||||
|
@ -449,7 +459,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||
|
||||
/* public */
|
||||
tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
|
||||
tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
|
||||
tpm_buf_append_u16(&buf, hash);
|
||||
|
||||
/* policy */
|
||||
|
@ -464,7 +474,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||
}
|
||||
|
||||
/* public parameters */
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
|
||||
tpm_buf_append_u16(&buf, TPM_ALG_NULL);
|
||||
tpm_buf_append_u16(&buf, 0);
|
||||
|
||||
/* outside info */
|
||||
|
@ -478,8 +488,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
|
||||
"sealing data");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
@ -516,7 +525,6 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||
* @payload: the key data in clear and encrypted form
|
||||
* @options: authentication values and other options
|
||||
* @blob_handle: returned blob handle
|
||||
* @flags: tpm transmit flags
|
||||
*
|
||||
* Return: 0 on success.
|
||||
* -E2BIG on wrong payload size.
|
||||
|
@ -526,7 +534,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||
static int tpm2_load_cmd(struct tpm_chip *chip,
|
||||
struct trusted_key_payload *payload,
|
||||
struct trusted_key_options *options,
|
||||
u32 *blob_handle, unsigned int flags)
|
||||
u32 *blob_handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
unsigned int private_len;
|
||||
|
@ -561,8 +569,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
|
||||
"loading blob");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
|
||||
if (!rc)
|
||||
*blob_handle = be32_to_cpup(
|
||||
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
|
||||
|
@ -583,7 +590,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
|
|||
* @payload: the key data in clear and encrypted form
|
||||
* @options: authentication values and other options
|
||||
* @blob_handle: blob handle
|
||||
* @flags: tpm_transmit_cmd flags
|
||||
*
|
||||
* Return: 0 on success
|
||||
* -EPERM on tpm error status
|
||||
|
@ -592,7 +598,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
|
|||
static int tpm2_unseal_cmd(struct tpm_chip *chip,
|
||||
struct trusted_key_payload *payload,
|
||||
struct trusted_key_options *options,
|
||||
u32 blob_handle, unsigned int flags)
|
||||
u32 blob_handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
u16 data_len;
|
||||
|
@ -612,8 +618,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
|
|||
options->blobauth /* hmac */,
|
||||
TPM_DIGEST_SIZE);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
|
||||
"unsealing");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
|
||||
if (rc > 0)
|
||||
rc = -EPERM;
|
||||
|
||||
|
@ -657,17 +662,12 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
|
|||
u32 blob_handle;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
|
||||
TPM_TRANSMIT_UNLOCKED);
|
||||
rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
|
||||
if (rc)
|
||||
goto out;
|
||||
return rc;
|
||||
|
||||
rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
|
||||
TPM_TRANSMIT_UNLOCKED);
|
||||
tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
|
||||
out:
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
|
||||
tpm2_flush_context(chip, blob_handle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -703,7 +703,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
|
|||
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, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
|
||||
if (!rc) {
|
||||
out = (struct tpm2_get_cap_out *)
|
||||
&buf.data[TPM_HEADER_SIZE];
|
||||
|
@ -733,8 +733,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
|
|||
if (rc)
|
||||
return;
|
||||
tpm_buf_append_u16(&buf, shutdown_type);
|
||||
tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"stopping the TPM");
|
||||
tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
|
||||
tpm_buf_destroy(&buf);
|
||||
}
|
||||
|
||||
|
@ -763,7 +762,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
|
|||
return rc;
|
||||
|
||||
tpm_buf_append_u8(&buf, full);
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0,
|
||||
"attempting the self test");
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
|
@ -790,7 +789,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
|
|||
*/
|
||||
int tpm2_probe(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_output_header *out;
|
||||
struct tpm_header *out;
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
|
||||
|
@ -800,10 +799,10 @@ int tpm2_probe(struct tpm_chip *chip)
|
|||
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, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
|
||||
/* We ignore TPM return codes on purpose. */
|
||||
if (rc >= 0) {
|
||||
out = (struct tpm_output_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;
|
||||
}
|
||||
|
@ -812,6 +811,30 @@ int tpm2_probe(struct tpm_chip *chip)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tpm2_probe);
|
||||
|
||||
static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index)
|
||||
{
|
||||
struct tpm_bank_info *bank = chip->allocated_banks + bank_index;
|
||||
struct tpm_digest digest = { .alg_id = bank->alg_id };
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Avoid unnecessary PCR read operations to reduce overhead
|
||||
* and obtain identifiers of the crypto subsystem.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
|
||||
enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id;
|
||||
|
||||
if (bank->alg_id != tpm2_hash_map[i].tpm_id)
|
||||
continue;
|
||||
|
||||
bank->digest_size = hash_digest_size[crypto_algo];
|
||||
bank->crypto_id = crypto_algo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size);
|
||||
}
|
||||
|
||||
struct tpm2_pcr_selection {
|
||||
__be16 hash_alg;
|
||||
u8 size_of_select;
|
||||
|
@ -825,8 +848,10 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
|||
void *marker;
|
||||
void *end;
|
||||
void *pcr_select_offset;
|
||||
unsigned int count;
|
||||
u32 sizeof_pcr_selection;
|
||||
u32 nr_possible_banks;
|
||||
u32 nr_alloc_banks = 0;
|
||||
u16 hash_alg;
|
||||
u32 rsp_len;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
@ -839,16 +864,18 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
|||
tpm_buf_append_u32(&buf, 0);
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0,
|
||||
"get tpm pcr allocation");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
count = be32_to_cpup(
|
||||
nr_possible_banks = be32_to_cpup(
|
||||
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
|
||||
|
||||
if (count > ARRAY_SIZE(chip->active_banks)) {
|
||||
rc = -ENODEV;
|
||||
chip->allocated_banks = kcalloc(nr_possible_banks,
|
||||
sizeof(*chip->allocated_banks),
|
||||
GFP_KERNEL);
|
||||
if (!chip->allocated_banks) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -857,7 +884,7 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
|||
rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
|
||||
end = &buf.data[rsp_len];
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < nr_possible_banks; i++) {
|
||||
pcr_select_offset = marker +
|
||||
offsetof(struct tpm2_pcr_selection, size_of_select);
|
||||
if (pcr_select_offset >= end) {
|
||||
|
@ -866,17 +893,28 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
|||
}
|
||||
|
||||
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
|
||||
chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg);
|
||||
hash_alg = be16_to_cpu(pcr_selection.hash_alg);
|
||||
|
||||
pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0,
|
||||
pcr_selection.size_of_select);
|
||||
if (pcr_select_offset) {
|
||||
chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg;
|
||||
|
||||
rc = tpm2_init_bank_info(chip, nr_alloc_banks);
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
nr_alloc_banks++;
|
||||
}
|
||||
|
||||
sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) +
|
||||
sizeof(pcr_selection.size_of_select) +
|
||||
pcr_selection.size_of_select;
|
||||
marker = marker + sizeof_pcr_selection;
|
||||
}
|
||||
|
||||
chip->nr_allocated_banks = nr_alloc_banks;
|
||||
out:
|
||||
if (i < ARRAY_SIZE(chip->active_banks))
|
||||
chip->active_banks[i] = TPM2_ALG_ERROR;
|
||||
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
return rc;
|
||||
|
@ -911,8 +949,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
|
|||
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
|
||||
tpm_buf_append_u32(&buf, nr_commands);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
9 + 4 * nr_commands, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
|
||||
if (rc) {
|
||||
tpm_buf_destroy(&buf);
|
||||
goto out;
|
||||
|
@ -969,8 +1006,7 @@ static int tpm2_startup(struct tpm_chip *chip)
|
|||
return rc;
|
||||
|
||||
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"attempting to start the TPM");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -38,8 +38,7 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
|
||||
if (space->session_tbl[i])
|
||||
tpm2_flush_context_cmd(chip, space->session_tbl[i],
|
||||
TPM_TRANSMIT_NESTED);
|
||||
tpm2_flush_context(chip, space->session_tbl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +60,10 @@ int tpm2_init_space(struct tpm_space *space)
|
|||
void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
|
||||
{
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
tpm2_flush_sessions(chip, space);
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_flush_sessions(chip, space);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
kfree(space->context_buf);
|
||||
kfree(space->session_buf);
|
||||
|
@ -83,8 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
|
|||
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
|
||||
tpm_buf_append(&tbuf, &buf[*offset], body_size);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
|
||||
TPM_TRANSMIT_NESTED, 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);
|
||||
|
@ -132,8 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
|
|||
|
||||
tpm_buf_append_u32(&tbuf, handle);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
|
||||
TPM_TRANSMIT_NESTED, 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);
|
||||
|
@ -162,15 +162,14 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tpm2_flush_space(struct tpm_chip *chip)
|
||||
void tpm2_flush_space(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_space *space = &chip->work_space;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
|
||||
if (space->context_tbl[i] && ~space->context_tbl[i])
|
||||
tpm2_flush_context_cmd(chip, space->context_tbl[i],
|
||||
TPM_TRANSMIT_NESTED);
|
||||
tpm2_flush_context(chip, space->context_tbl[i]);
|
||||
|
||||
tpm2_flush_sessions(chip, space);
|
||||
}
|
||||
|
@ -264,14 +263,54 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
|
||||
u8 *cmd)
|
||||
static int tpm_find_and_validate_cc(struct tpm_chip *chip,
|
||||
struct tpm_space *space,
|
||||
const void *cmd, size_t len)
|
||||
{
|
||||
const struct tpm_header *header = (const void *)cmd;
|
||||
int i;
|
||||
u32 cc;
|
||||
u32 attrs;
|
||||
unsigned int nr_handles;
|
||||
|
||||
if (len < TPM_HEADER_SIZE || !chip->nr_commands)
|
||||
return -EINVAL;
|
||||
|
||||
cc = be32_to_cpu(header->ordinal);
|
||||
|
||||
i = tpm2_find_cc(chip, cc);
|
||||
if (i < 0) {
|
||||
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
|
||||
cc);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
attrs = chip->cc_attrs_tbl[i];
|
||||
nr_handles =
|
||||
4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
|
||||
if (len < TPM_HEADER_SIZE + 4 * nr_handles)
|
||||
goto err_len;
|
||||
|
||||
return cc;
|
||||
err_len:
|
||||
dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
|
||||
len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
|
||||
size_t cmdsiz)
|
||||
{
|
||||
int rc;
|
||||
int cc;
|
||||
|
||||
if (!space)
|
||||
return 0;
|
||||
|
||||
cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
|
||||
if (cc < 0)
|
||||
return cc;
|
||||
|
||||
memcpy(&chip->work_space.context_tbl, &space->context_tbl,
|
||||
sizeof(space->context_tbl));
|
||||
memcpy(&chip->work_space.session_tbl, &space->session_tbl,
|
||||
|
@ -291,6 +330,7 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
|
|||
return rc;
|
||||
}
|
||||
|
||||
chip->last_cc = cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -334,7 +374,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
|
|||
size_t len)
|
||||
{
|
||||
struct tpm_space *space = &chip->work_space;
|
||||
struct tpm_output_header *header = (void *)rsp;
|
||||
struct tpm_header *header = (struct tpm_header *)rsp;
|
||||
u32 phandle;
|
||||
u32 phandle_type;
|
||||
u32 vhandle;
|
||||
|
@ -377,7 +417,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
|
|||
|
||||
return 0;
|
||||
out_no_slots:
|
||||
tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED);
|
||||
tpm2_flush_context(chip, phandle);
|
||||
dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
|
||||
phandle);
|
||||
return -ENOMEM;
|
||||
|
@ -394,7 +434,7 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
|
|||
size_t len)
|
||||
{
|
||||
struct tpm_space *space = &chip->work_space;
|
||||
struct tpm_output_header *header = (void *)rsp;
|
||||
struct tpm_header *header = (struct tpm_header *)rsp;
|
||||
struct tpm2_cap_handles *data;
|
||||
u32 phandle;
|
||||
u32 phandle_type;
|
||||
|
@ -464,8 +504,7 @@ static int tpm2_save_space(struct tpm_chip *chip)
|
|||
} else if (rc)
|
||||
return rc;
|
||||
|
||||
tpm2_flush_context_cmd(chip, space->context_tbl[i],
|
||||
TPM_TRANSMIT_NESTED);
|
||||
tpm2_flush_context(chip, space->context_tbl[i]);
|
||||
space->context_tbl[i] = ~0;
|
||||
}
|
||||
|
||||
|
@ -490,30 +529,30 @@ static int tpm2_save_space(struct tpm_chip *chip)
|
|||
}
|
||||
|
||||
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u32 cc, u8 *buf, size_t *bufsiz)
|
||||
void *buf, size_t *bufsiz)
|
||||
{
|
||||
struct tpm_output_header *header = (void *)buf;
|
||||
struct tpm_header *header = buf;
|
||||
int rc;
|
||||
|
||||
if (!space)
|
||||
return 0;
|
||||
|
||||
rc = tpm2_map_response_header(chip, cc, buf, *bufsiz);
|
||||
rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
|
||||
if (rc) {
|
||||
tpm2_flush_space(chip);
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm2_map_response_body(chip, cc, buf, *bufsiz);
|
||||
rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
|
||||
if (rc) {
|
||||
tpm2_flush_space(chip);
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm2_save_space(chip);
|
||||
if (rc) {
|
||||
tpm2_flush_space(chip);
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*bufsiz = be32_to_cpu(header->length);
|
||||
|
@ -526,4 +565,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
|
|||
memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
iowrite8(buf[i], priv->iobase);
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_atml_cancel(struct tpm_chip *chip)
|
||||
|
|
|
@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
|
||||
unsigned int expected;
|
||||
|
||||
/* sanity check */
|
||||
if (count < 6)
|
||||
/* A sanity check that the upper layer wants to get at least the header
|
||||
* as that is the minimum size for any TPM response.
|
||||
*/
|
||||
if (count < TPM_HEADER_SIZE)
|
||||
return -EIO;
|
||||
|
||||
/* If this bit is set, according to the spec, the TPM is in
|
||||
* unrecoverable condition.
|
||||
*/
|
||||
if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
|
||||
return -EIO;
|
||||
|
||||
memcpy_fromio(buf, priv->rsp, 6);
|
||||
expected = be32_to_cpup((__be32 *) &buf[2]);
|
||||
if (expected > count || expected < 6)
|
||||
/* Read the first 8 bytes in order to get the length of the response.
|
||||
* We read exactly a quad word in order to make sure that the remaining
|
||||
* reads will be aligned.
|
||||
*/
|
||||
memcpy_fromio(buf, priv->rsp, 8);
|
||||
|
||||
expected = be32_to_cpup((__be32 *)&buf[2]);
|
||||
if (expected > count || expected < TPM_HEADER_SIZE)
|
||||
return -EIO;
|
||||
|
||||
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
|
||||
memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ struct priv_data {
|
|||
/* This is the amount we read on the first try. 25 was chosen to fit a
|
||||
* fair number of read responses in the buffer so a 2nd retry can be
|
||||
* avoided in small message cases. */
|
||||
u8 buffer[sizeof(struct tpm_output_header) + 25];
|
||||
u8 buffer[sizeof(struct tpm_header) + 25];
|
||||
};
|
||||
|
||||
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
|
@ -65,15 +65,22 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
dev_dbg(&chip->dev,
|
||||
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
|
||||
(int)min_t(size_t, 64, len), buf, len, status);
|
||||
return status;
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* The upper layer does not support incomplete sends. */
|
||||
if (status != len)
|
||||
return -E2BIG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
struct priv_data *priv = dev_get_drvdata(&chip->dev);
|
||||
struct i2c_client *client = to_i2c_client(chip->dev.parent);
|
||||
struct tpm_output_header *hdr =
|
||||
(struct tpm_output_header *)priv->buffer;
|
||||
struct tpm_header *hdr = (struct tpm_header *)priv->buffer;
|
||||
u32 expected_len;
|
||||
int rc;
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include "tpm.h"
|
||||
|
||||
/* max. buffer size supported by our TPM */
|
||||
#define TPM_BUFSIZE 1260
|
||||
#define TPM_I2C_INFINEON_BUFSIZE 1260
|
||||
|
||||
/* max. number of iterations after I2C NAK */
|
||||
#define MAX_COUNT 3
|
||||
|
@ -63,11 +62,13 @@ enum i2c_chip_type {
|
|||
UNKNOWN,
|
||||
};
|
||||
|
||||
/* Structure to store I2C TPM specific stuff */
|
||||
struct tpm_inf_dev {
|
||||
struct i2c_client *client;
|
||||
int locality;
|
||||
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */
|
||||
/* In addition to the data itself, the buffer must fit the 7-bit I2C
|
||||
* address and the direction bit.
|
||||
*/
|
||||
u8 buf[TPM_I2C_INFINEON_BUFSIZE + 1];
|
||||
struct tpm_chip *chip;
|
||||
enum i2c_chip_type chip_type;
|
||||
unsigned int adapterlimit;
|
||||
|
@ -219,7 +220,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
|
|||
.buf = tpm_dev.buf
|
||||
};
|
||||
|
||||
if (len > TPM_BUFSIZE)
|
||||
if (len > TPM_I2C_INFINEON_BUFSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (!tpm_dev.client->adapter->algo->master_xfer)
|
||||
|
@ -527,8 +528,8 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
u8 retries = 0;
|
||||
u8 sts = TPM_STS_GO;
|
||||
|
||||
if (len > TPM_BUFSIZE)
|
||||
return -E2BIG; /* command is too long for our tpm, sorry */
|
||||
if (len > TPM_I2C_INFINEON_BUFSIZE)
|
||||
return -E2BIG;
|
||||
|
||||
if (request_locality(chip, 0) < 0)
|
||||
return -EBUSY;
|
||||
|
@ -587,7 +588,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
/* go and do it */
|
||||
iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1);
|
||||
|
||||
return len;
|
||||
return 0;
|
||||
out_err:
|
||||
tpm_tis_i2c_ready(chip);
|
||||
/* The TPM needs some time to clean up here,
|
||||
|
|
|
@ -35,14 +35,12 @@
|
|||
#include "tpm.h"
|
||||
|
||||
/* I2C interface offsets */
|
||||
#define TPM_STS 0x00
|
||||
#define TPM_BURST_COUNT 0x01
|
||||
#define TPM_DATA_FIFO_W 0x20
|
||||
#define TPM_DATA_FIFO_R 0x40
|
||||
#define TPM_VID_DID_RID 0x60
|
||||
/* TPM command header size */
|
||||
#define TPM_HEADER_SIZE 10
|
||||
#define TPM_RETRY 5
|
||||
#define TPM_STS 0x00
|
||||
#define TPM_BURST_COUNT 0x01
|
||||
#define TPM_DATA_FIFO_W 0x20
|
||||
#define TPM_DATA_FIFO_R 0x40
|
||||
#define TPM_VID_DID_RID 0x60
|
||||
#define TPM_I2C_RETRIES 5
|
||||
/*
|
||||
* I2C bus device maximum buffer size w/o counting I2C address or command
|
||||
* i.e. max size required for I2C write is 34 = addr, command, 32 bytes data
|
||||
|
@ -292,7 +290,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
dev_err(dev, "%s() count < header size\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
for (retries = 0; retries < TPM_RETRY; retries++) {
|
||||
for (retries = 0; retries < TPM_I2C_RETRIES; retries++) {
|
||||
if (retries > 0) {
|
||||
/* if this is not the first trial, set responseRetry */
|
||||
i2c_nuvoton_write_status(client,
|
||||
|
@ -467,7 +465,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
}
|
||||
|
||||
dev_dbg(dev, "%s() -> %zd\n", __func__, len);
|
||||
return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
|
|
|
@ -139,14 +139,14 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
}
|
||||
|
||||
/**
|
||||
* tpm_ibmvtpm_send - Send tpm request
|
||||
*
|
||||
* tpm_ibmvtpm_send() - Send a TPM command
|
||||
* @chip: tpm chip struct
|
||||
* @buf: buffer contains data to send
|
||||
* @count: size of buffer
|
||||
*
|
||||
* Return:
|
||||
* Number of bytes sent or < 0 on error.
|
||||
* 0 on success,
|
||||
* -errno on error
|
||||
*/
|
||||
static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
|
@ -192,7 +192,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
rc = 0;
|
||||
ibmvtpm->tpm_processing_cmd = false;
|
||||
} else
|
||||
rc = count;
|
||||
rc = 0;
|
||||
|
||||
spin_unlock(&ibmvtpm->rtce_lock);
|
||||
return rc;
|
||||
|
|
|
@ -354,7 +354,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
|
|||
for (i = 0; i < count; i++) {
|
||||
wait_and_send(chip, buf[i]);
|
||||
}
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_inf_cancel(struct tpm_chip *chip)
|
||||
|
|
|
@ -226,7 +226,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
|
|||
}
|
||||
outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND);
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_nsc_cancel(struct tpm_chip *chip)
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
#include <linux/acpi.h>
|
||||
#include "tpm.h"
|
||||
|
||||
#define TPM_PPI_REVISION_ID 1
|
||||
#define TPM_PPI_REVISION_ID_1 1
|
||||
#define TPM_PPI_REVISION_ID_2 2
|
||||
#define TPM_PPI_FN_VERSION 1
|
||||
#define TPM_PPI_FN_SUBREQ 2
|
||||
#define TPM_PPI_FN_GETREQ 3
|
||||
|
@ -28,7 +29,7 @@
|
|||
#define TPM_PPI_FN_GETRSP 5
|
||||
#define TPM_PPI_FN_SUBREQ2 7
|
||||
#define TPM_PPI_FN_GETOPR 8
|
||||
#define PPI_TPM_REQ_MAX 22
|
||||
#define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */
|
||||
#define PPI_VS_REQ_START 128
|
||||
#define PPI_VS_REQ_END 255
|
||||
|
||||
|
@ -36,14 +37,18 @@ static const guid_t tpm_ppi_guid =
|
|||
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
|
||||
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
|
||||
|
||||
static bool tpm_ppi_req_has_parameter(u64 req)
|
||||
{
|
||||
return req == 23;
|
||||
}
|
||||
|
||||
static inline union acpi_object *
|
||||
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
|
||||
union acpi_object *argv4)
|
||||
union acpi_object *argv4, u64 rev)
|
||||
{
|
||||
BUG_ON(!ppi_handle);
|
||||
return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID,
|
||||
func, argv4, type);
|
||||
rev, func, argv4, type);
|
||||
}
|
||||
|
||||
static ssize_t tpm_show_ppi_version(struct device *dev,
|
||||
|
@ -60,9 +65,14 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
|
|||
ssize_t size = -EINVAL;
|
||||
union acpi_object *obj;
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
u64 rev = TPM_PPI_REVISION_ID_2;
|
||||
u64 req;
|
||||
|
||||
if (strcmp(chip->ppi_version, "1.2") < 0)
|
||||
rev = TPM_PPI_REVISION_ID_1;
|
||||
|
||||
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
|
||||
ACPI_TYPE_PACKAGE, NULL);
|
||||
ACPI_TYPE_PACKAGE, NULL, rev);
|
||||
if (!obj)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -72,7 +82,23 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
|
|||
* error. The second is pending TPM operation requested by the OS, 0
|
||||
* means none and >0 means operation value.
|
||||
*/
|
||||
if (obj->package.count == 2 &&
|
||||
if (obj->package.count == 3 &&
|
||||
obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
|
||||
obj->package.elements[1].type == ACPI_TYPE_INTEGER &&
|
||||
obj->package.elements[2].type == ACPI_TYPE_INTEGER) {
|
||||
if (obj->package.elements[0].integer.value)
|
||||
size = -EFAULT;
|
||||
else {
|
||||
req = obj->package.elements[1].integer.value;
|
||||
if (tpm_ppi_req_has_parameter(req))
|
||||
size = scnprintf(buf, PAGE_SIZE,
|
||||
"%llu %llu\n", req,
|
||||
obj->package.elements[2].integer.value);
|
||||
else
|
||||
size = scnprintf(buf, PAGE_SIZE,
|
||||
"%llu\n", req);
|
||||
}
|
||||
} else if (obj->package.count == 2 &&
|
||||
obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
|
||||
obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
|
||||
if (obj->package.elements[0].integer.value)
|
||||
|
@ -94,9 +120,10 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
|||
u32 req;
|
||||
u64 ret;
|
||||
int func = TPM_PPI_FN_SUBREQ;
|
||||
union acpi_object *obj, tmp;
|
||||
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
|
||||
union acpi_object *obj, tmp[2];
|
||||
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp);
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
u64 rev = TPM_PPI_REVISION_ID_1;
|
||||
|
||||
/*
|
||||
* the function to submit TPM operation request to pre-os environment
|
||||
|
@ -104,7 +131,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
|||
* version 1.1
|
||||
*/
|
||||
if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
|
||||
TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2))
|
||||
func = TPM_PPI_FN_SUBREQ2;
|
||||
|
||||
/*
|
||||
|
@ -113,20 +140,29 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
|||
* string/package type. For PPI version 1.0 and 1.1, use buffer type
|
||||
* for compatibility, and use package type since 1.2 according to spec.
|
||||
*/
|
||||
if (strcmp(chip->ppi_version, "1.2") < 0) {
|
||||
if (strcmp(chip->ppi_version, "1.3") == 0) {
|
||||
if (sscanf(buf, "%llu %llu", &tmp[0].integer.value,
|
||||
&tmp[1].integer.value) != 2)
|
||||
goto ppi12;
|
||||
rev = TPM_PPI_REVISION_ID_2;
|
||||
tmp[0].type = ACPI_TYPE_INTEGER;
|
||||
tmp[1].type = ACPI_TYPE_INTEGER;
|
||||
} else if (strcmp(chip->ppi_version, "1.2") < 0) {
|
||||
if (sscanf(buf, "%d", &req) != 1)
|
||||
return -EINVAL;
|
||||
argv4.type = ACPI_TYPE_BUFFER;
|
||||
argv4.buffer.length = sizeof(req);
|
||||
argv4.buffer.pointer = (u8 *)&req;
|
||||
} else {
|
||||
tmp.type = ACPI_TYPE_INTEGER;
|
||||
if (sscanf(buf, "%llu", &tmp.integer.value) != 1)
|
||||
ppi12:
|
||||
argv4.package.count = 1;
|
||||
tmp[0].type = ACPI_TYPE_INTEGER;
|
||||
if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
|
||||
&argv4);
|
||||
&argv4, rev);
|
||||
if (!obj) {
|
||||
return -ENXIO;
|
||||
} else {
|
||||
|
@ -170,7 +206,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
|
|||
if (strcmp(chip->ppi_version, "1.2") < 0)
|
||||
obj = &tmp;
|
||||
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
|
||||
ACPI_TYPE_INTEGER, obj);
|
||||
ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1);
|
||||
if (!obj) {
|
||||
return -ENXIO;
|
||||
} else {
|
||||
|
@ -196,7 +232,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
|
|||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
|
||||
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
|
||||
ACPI_TYPE_PACKAGE, NULL);
|
||||
ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1);
|
||||
if (!obj)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -264,7 +300,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
|||
"User not required",
|
||||
};
|
||||
|
||||
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID,
|
||||
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
|
||||
1 << TPM_PPI_FN_GETOPR))
|
||||
return -EPERM;
|
||||
|
||||
|
@ -272,7 +308,8 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
|||
for (i = start; i <= end; i++) {
|
||||
tmp.integer.value = i;
|
||||
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
|
||||
ACPI_TYPE_INTEGER, &argv);
|
||||
ACPI_TYPE_INTEGER, &argv,
|
||||
TPM_PPI_REVISION_ID_1);
|
||||
if (!obj) {
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
|
@ -338,12 +375,13 @@ void tpm_add_ppi(struct tpm_chip *chip)
|
|||
return;
|
||||
|
||||
if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
|
||||
TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION))
|
||||
return;
|
||||
|
||||
/* Cache PPI version string. */
|
||||
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
|
||||
TPM_PPI_REVISION_ID_1,
|
||||
TPM_PPI_FN_VERSION,
|
||||
NULL, ACPI_TYPE_STRING);
|
||||
if (obj) {
|
||||
strlcpy(chip->ppi_version, obj->string.pointer,
|
||||
|
|
|
@ -481,7 +481,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
|
|||
goto out_err;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
return 0;
|
||||
out_err:
|
||||
tpm_tis_ready(chip);
|
||||
return rc;
|
||||
|
@ -521,35 +521,38 @@ static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
|
|||
(TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } },
|
||||
};
|
||||
|
||||
static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
|
||||
static void tpm_tis_update_timeouts(struct tpm_chip *chip,
|
||||
unsigned long *timeout_cap)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
int i, rc;
|
||||
u32 did_vid;
|
||||
|
||||
chip->timeout_adjusted = false;
|
||||
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, true);
|
||||
|
||||
rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
dev_warn(&chip->dev, "%s: failed to read did_vid: %d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
|
||||
if (vendor_timeout_overrides[i].did_vid != did_vid)
|
||||
continue;
|
||||
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
|
||||
sizeof(vendor_timeout_overrides[i].timeout_us));
|
||||
rc = true;
|
||||
chip->timeout_adjusted = true;
|
||||
}
|
||||
|
||||
rc = false;
|
||||
|
||||
out:
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, false);
|
||||
|
||||
return rc;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -913,7 +916,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
|||
intmask &= ~TPM_GLOBAL_INT_ENABLE;
|
||||
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
|
||||
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
rc = tpm2_probe(chip);
|
||||
tpm_chip_stop(chip);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
|
|
|
@ -303,9 +303,9 @@ static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
static int vtpm_proxy_is_driver_command(struct tpm_chip *chip,
|
||||
u8 *buf, size_t count)
|
||||
{
|
||||
struct tpm_input_header *hdr = (struct tpm_input_header *)buf;
|
||||
struct tpm_header *hdr = (struct tpm_header *)buf;
|
||||
|
||||
if (count < sizeof(struct tpm_input_header))
|
||||
if (count < sizeof(struct tpm_header))
|
||||
return 0;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
|
@ -335,7 +335,6 @@ static int vtpm_proxy_is_driver_command(struct tpm_chip *chip,
|
|||
static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
|
||||
int rc = 0;
|
||||
|
||||
if (count > sizeof(proxy_dev->buffer)) {
|
||||
dev_err(&chip->dev,
|
||||
|
@ -366,7 +365,7 @@ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
|
||||
wake_up_interruptible(&proxy_dev->wq);
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vtpm_proxy_tpm_op_cancel(struct tpm_chip *chip)
|
||||
|
@ -402,7 +401,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
|
|||
{
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
const struct tpm_output_header *header;
|
||||
const struct tpm_header *header;
|
||||
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
|
@ -417,9 +416,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
|
|||
|
||||
proxy_dev->state |= STATE_DRIVER_COMMAND;
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, tpm_buf_length(&buf), 0,
|
||||
TPM_TRANSMIT_NESTED,
|
||||
"attempting to set locality");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
|
||||
|
||||
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
|
||||
|
||||
|
@ -428,7 +425,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
|
|||
goto out;
|
||||
}
|
||||
|
||||
header = (const struct tpm_output_header *)buf.data;
|
||||
header = (const struct tpm_header *)buf.data;
|
||||
rc = be32_to_cpu(header->return_code);
|
||||
if (rc)
|
||||
locality = -1;
|
||||
|
|
|
@ -163,7 +163,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
wmb();
|
||||
notify_remote_via_evtchn(priv->evtchn);
|
||||
|
||||
ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal);
|
||||
ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal);
|
||||
duration = tpm_calc_ordinal_duration(chip, ordinal);
|
||||
|
||||
if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration,
|
||||
|
@ -173,7 +173,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||
return -ETIME;
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
|
|
|
@ -22,12 +22,41 @@
|
|||
#ifndef __LINUX_TPM_H__
|
||||
#define __LINUX_TPM_H__
|
||||
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/fs.h>
|
||||
#include <crypto/hash_info.h>
|
||||
|
||||
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
|
||||
#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||
|
||||
struct tpm_chip;
|
||||
struct trusted_key_payload;
|
||||
struct trusted_key_options;
|
||||
|
||||
enum tpm_algorithms {
|
||||
TPM_ALG_ERROR = 0x0000,
|
||||
TPM_ALG_SHA1 = 0x0004,
|
||||
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,
|
||||
};
|
||||
|
||||
struct tpm_digest {
|
||||
u16 alg_id;
|
||||
u8 digest[TPM_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),
|
||||
};
|
||||
|
@ -41,7 +70,7 @@ struct tpm_class_ops {
|
|||
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
|
||||
void (*cancel) (struct tpm_chip *chip);
|
||||
u8 (*status) (struct tpm_chip *chip);
|
||||
bool (*update_timeouts)(struct tpm_chip *chip,
|
||||
void (*update_timeouts)(struct tpm_chip *chip,
|
||||
unsigned long *timeout_cap);
|
||||
int (*go_idle)(struct tpm_chip *chip);
|
||||
int (*cmd_ready)(struct tpm_chip *chip);
|
||||
|
@ -50,11 +79,100 @@ struct tpm_class_ops {
|
|||
void (*clk_enable)(struct tpm_chip *chip, bool value);
|
||||
};
|
||||
|
||||
#define TPM_NUM_EVENT_LOG_FILES 3
|
||||
|
||||
/* Indexes the duration array */
|
||||
enum tpm_duration {
|
||||
TPM_SHORT = 0,
|
||||
TPM_MEDIUM = 1,
|
||||
TPM_LONG = 2,
|
||||
TPM_LONG_LONG = 3,
|
||||
TPM_UNDEFINED,
|
||||
TPM_NUM_DURATIONS = TPM_UNDEFINED,
|
||||
};
|
||||
|
||||
#define TPM_PPI_VERSION_LEN 3
|
||||
|
||||
struct tpm_space {
|
||||
u32 context_tbl[3];
|
||||
u8 *context_buf;
|
||||
u32 session_tbl[3];
|
||||
u8 *session_buf;
|
||||
};
|
||||
|
||||
struct tpm_bios_log {
|
||||
void *bios_event_log;
|
||||
void *bios_event_log_end;
|
||||
};
|
||||
|
||||
struct tpm_chip_seqops {
|
||||
struct tpm_chip *chip;
|
||||
const struct seq_operations *seqops;
|
||||
};
|
||||
|
||||
struct tpm_chip {
|
||||
struct device dev;
|
||||
struct device devs;
|
||||
struct cdev cdev;
|
||||
struct cdev cdevs;
|
||||
|
||||
/* A driver callback under ops cannot be run unless ops_sem is held
|
||||
* (sometimes implicitly, eg for the sysfs code). ops becomes null
|
||||
* when the driver is unregistered, see tpm_try_get_ops.
|
||||
*/
|
||||
struct rw_semaphore ops_sem;
|
||||
const struct tpm_class_ops *ops;
|
||||
|
||||
struct tpm_bios_log log;
|
||||
struct tpm_chip_seqops bin_log_seqops;
|
||||
struct tpm_chip_seqops ascii_log_seqops;
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
int dev_num; /* /dev/tpm# */
|
||||
unsigned long is_open; /* only one allowed */
|
||||
|
||||
char hwrng_name[64];
|
||||
struct hwrng hwrng;
|
||||
|
||||
struct mutex tpm_mutex; /* tpm is processing */
|
||||
|
||||
unsigned long timeout_a; /* jiffies */
|
||||
unsigned long timeout_b; /* jiffies */
|
||||
unsigned long timeout_c; /* jiffies */
|
||||
unsigned long timeout_d; /* jiffies */
|
||||
bool timeout_adjusted;
|
||||
unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
|
||||
bool duration_adjusted;
|
||||
|
||||
struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES];
|
||||
|
||||
const struct attribute_group *groups[3];
|
||||
unsigned int groups_cnt;
|
||||
|
||||
u32 nr_allocated_banks;
|
||||
struct tpm_bank_info *allocated_banks;
|
||||
#ifdef CONFIG_ACPI
|
||||
acpi_handle acpi_dev_handle;
|
||||
char ppi_version[TPM_PPI_VERSION_LEN + 1];
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
struct tpm_space work_space;
|
||||
u32 last_cc;
|
||||
u32 nr_commands;
|
||||
u32 *cc_attrs_tbl;
|
||||
|
||||
/* active locality */
|
||||
int locality;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
|
||||
|
||||
extern int tpm_is_tpm2(struct tpm_chip *chip);
|
||||
extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf);
|
||||
extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash);
|
||||
extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digest);
|
||||
extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests);
|
||||
extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
|
||||
extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
|
||||
extern int tpm_seal_trusted(struct tpm_chip *chip,
|
||||
|
@ -70,13 +188,14 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx,
|
||||
struct tpm_digest *digest)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
const u8 *hash)
|
||||
struct tpm_digest *digests)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
#ifndef __LINUX_TPM_EVENTLOG_H__
|
||||
#define __LINUX_TPM_EVENTLOG_H__
|
||||
|
||||
#include <crypto/hash_info.h>
|
||||
#include <linux/tpm.h>
|
||||
|
||||
#define TCG_EVENT_NAME_LEN_MAX 255
|
||||
#define MAX_TEXT_EVENT 1000 /* Max event string length */
|
||||
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
|
||||
#define TPM2_ACTIVE_PCR_BANKS 3
|
||||
|
||||
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
|
||||
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x2
|
||||
|
@ -82,7 +81,7 @@ struct tcg_efi_specid_event_algs {
|
|||
u16 digest_size;
|
||||
} __packed;
|
||||
|
||||
struct tcg_efi_specid_event {
|
||||
struct tcg_efi_specid_event_head {
|
||||
u8 signature[16];
|
||||
u32 platform_class;
|
||||
u8 spec_version_minor;
|
||||
|
@ -90,9 +89,7 @@ struct tcg_efi_specid_event {
|
|||
u8 spec_errata;
|
||||
u8 uintnsize;
|
||||
u32 num_algs;
|
||||
struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS];
|
||||
u8 vendor_info_size;
|
||||
u8 vendor_info[0];
|
||||
struct tcg_efi_specid_event_algs digest_sizes[];
|
||||
} __packed;
|
||||
|
||||
struct tcg_pcr_event {
|
||||
|
@ -108,17 +105,11 @@ struct tcg_event_field {
|
|||
u8 event[0];
|
||||
} __packed;
|
||||
|
||||
struct tpm2_digest {
|
||||
u16 alg_id;
|
||||
u8 digest[SHA512_DIGEST_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct tcg_pcr_event2 {
|
||||
struct tcg_pcr_event2_head {
|
||||
u32 pcr_idx;
|
||||
u32 event_type;
|
||||
u32 count;
|
||||
struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS];
|
||||
struct tcg_event_field event;
|
||||
struct tpm_digest digests[];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v);
|
|||
unsigned long ima_get_binary_runtime_size(void);
|
||||
int ima_init_template(void);
|
||||
void ima_init_template_list(void);
|
||||
int __init ima_init_digests(void);
|
||||
|
||||
/*
|
||||
* used to protect h_table and sha_table
|
||||
|
|
|
@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
|
|||
return calc_buffer_shash(buf, len, hash);
|
||||
}
|
||||
|
||||
static void __init ima_pcrread(u32 idx, u8 *pcr)
|
||||
static void __init ima_pcrread(u32 idx, struct tpm_digest *d)
|
||||
{
|
||||
if (!ima_tpm_chip)
|
||||
return;
|
||||
|
||||
if (tpm_pcr_read(ima_tpm_chip, idx, pcr) != 0)
|
||||
if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0)
|
||||
pr_err("Error Communicating to TPM chip\n");
|
||||
}
|
||||
|
||||
|
@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr)
|
|||
static int __init ima_calc_boot_aggregate_tfm(char *digest,
|
||||
struct crypto_shash *tfm)
|
||||
{
|
||||
u8 pcr_i[TPM_DIGEST_SIZE];
|
||||
struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} };
|
||||
int rc;
|
||||
u32 i;
|
||||
SHASH_DESC_ON_STACK(shash, tfm);
|
||||
|
@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
|
|||
|
||||
/* cumulative sha1 over tpm registers 0-7 */
|
||||
for (i = TPM_PCR0; i < TPM_PCR8; i++) {
|
||||
ima_pcrread(i, pcr_i);
|
||||
ima_pcrread(i, &d);
|
||||
/* now accumulate with current aggregate */
|
||||
rc = crypto_shash_update(shash, pcr_i, TPM_DIGEST_SIZE);
|
||||
rc = crypto_shash_update(shash, d.digest, TPM_DIGEST_SIZE);
|
||||
}
|
||||
if (!rc)
|
||||
crypto_shash_final(shash, digest);
|
||||
|
|
|
@ -123,8 +123,12 @@ int __init ima_init(void)
|
|||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* It can be called before ima_init_digests(), it does not use TPM. */
|
||||
ima_load_kexec_buffer();
|
||||
|
||||
rc = ima_init_digests();
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#define AUDIT_CAUSE_LEN_MAX 32
|
||||
|
||||
/* pre-allocated array of tpm_digest structures to extend a PCR */
|
||||
static struct tpm_digest *digests;
|
||||
|
||||
LIST_HEAD(ima_measurements); /* list of all measurements */
|
||||
#ifdef CONFIG_IMA_KEXEC
|
||||
static unsigned long binary_runtime_size;
|
||||
|
@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void)
|
|||
static int ima_pcr_extend(const u8 *hash, int pcr)
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
if (!ima_tpm_chip)
|
||||
return result;
|
||||
|
||||
result = tpm_pcr_extend(ima_tpm_chip, pcr, hash);
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
|
||||
memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE);
|
||||
|
||||
result = tpm_pcr_extend(ima_tpm_chip, pcr, digests);
|
||||
if (result != 0)
|
||||
pr_err("Error Communicating to TPM chip, result: %d\n", result);
|
||||
return result;
|
||||
|
@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
|
|||
mutex_unlock(&ima_extend_list_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
int __init ima_init_digests(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ima_tpm_chip)
|
||||
return 0;
|
||||
|
||||
digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests),
|
||||
GFP_NOFS);
|
||||
if (!digests)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
|
||||
digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
static const char hmac_alg[] = "hmac(sha1)";
|
||||
static const char hash_alg[] = "sha1";
|
||||
static struct tpm_chip *chip;
|
||||
static struct tpm_digest *digests;
|
||||
|
||||
struct sdesc {
|
||||
struct shash_desc shash;
|
||||
|
@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen)
|
|||
int rc;
|
||||
|
||||
dump_tpm_buf(cmd);
|
||||
rc = tpm_send(NULL, cmd, buflen);
|
||||
rc = tpm_send(chip, cmd, buflen);
|
||||
dump_tpm_buf(cmd);
|
||||
if (rc > 0)
|
||||
/* Can't return positive return codes values to keyctl */
|
||||
|
@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send);
|
|||
*/
|
||||
static int pcrlock(const int pcrnum)
|
||||
{
|
||||
unsigned char hash[SHA1_DIGEST_SIZE];
|
||||
int ret;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
|
||||
if (ret != SHA1_DIGEST_SIZE)
|
||||
return ret;
|
||||
return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
|
||||
|
||||
return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
|
|||
unsigned char ononce[TPM_NONCE_SIZE];
|
||||
int ret;
|
||||
|
||||
ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);
|
||||
ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE);
|
||||
if (ret != TPM_NONCE_SIZE)
|
||||
return ret;
|
||||
|
||||
|
@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);
|
||||
ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE);
|
||||
if (ret != TPM_NONCE_SIZE)
|
||||
goto out;
|
||||
ordinal = htonl(TPM_ORD_SEAL);
|
||||
|
@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb,
|
|||
|
||||
ordinal = htonl(TPM_ORD_UNSEAL);
|
||||
keyhndl = htonl(SRKHANDLE);
|
||||
ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);
|
||||
ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE);
|
||||
if (ret != TPM_NONCE_SIZE) {
|
||||
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
|
||||
return ret;
|
||||
|
@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
|
|||
int i;
|
||||
int tpm2;
|
||||
|
||||
tpm2 = tpm_is_tpm2(NULL);
|
||||
tpm2 = tpm_is_tpm2(chip);
|
||||
if (tpm2 < 0)
|
||||
return tpm2;
|
||||
|
||||
|
@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
|
|||
struct trusted_key_options *options;
|
||||
int tpm2;
|
||||
|
||||
tpm2 = tpm_is_tpm2(NULL);
|
||||
tpm2 = tpm_is_tpm2(chip);
|
||||
if (tpm2 < 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key,
|
|||
size_t key_len;
|
||||
int tpm2;
|
||||
|
||||
tpm2 = tpm_is_tpm2(NULL);
|
||||
tpm2 = tpm_is_tpm2(chip);
|
||||
if (tpm2 < 0)
|
||||
return tpm2;
|
||||
|
||||
|
@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key,
|
|||
switch (key_cmd) {
|
||||
case Opt_load:
|
||||
if (tpm2)
|
||||
ret = tpm_unseal_trusted(NULL, payload, options);
|
||||
ret = tpm_unseal_trusted(chip, payload, options);
|
||||
else
|
||||
ret = key_unseal(payload, options);
|
||||
dump_payload(payload);
|
||||
|
@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key,
|
|||
break;
|
||||
case Opt_new:
|
||||
key_len = payload->key_len;
|
||||
ret = tpm_get_random(NULL, payload->key, key_len);
|
||||
ret = tpm_get_random(chip, payload->key, key_len);
|
||||
if (ret != key_len) {
|
||||
pr_info("trusted_key: key_create failed (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if (tpm2)
|
||||
ret = tpm_seal_trusted(NULL, payload, options);
|
||||
ret = tpm_seal_trusted(chip, payload, options);
|
||||
else
|
||||
ret = key_seal(payload, options);
|
||||
if (ret < 0)
|
||||
|
@ -1221,21 +1218,59 @@ static int __init trusted_shash_alloc(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __init init_digests(void)
|
||||
{
|
||||
u8 digest[TPM_MAX_DIGEST_SIZE];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = tpm_get_random(chip, digest, TPM_MAX_DIGEST_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret < TPM_MAX_DIGEST_SIZE)
|
||||
return -EFAULT;
|
||||
|
||||
digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
|
||||
GFP_KERNEL);
|
||||
if (!digests)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < chip->nr_allocated_banks; i++)
|
||||
memcpy(digests[i].digest, digest, TPM_MAX_DIGEST_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init_trusted(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
chip = tpm_default_chip();
|
||||
if (!chip)
|
||||
return -ENOENT;
|
||||
ret = init_digests();
|
||||
if (ret < 0)
|
||||
goto err_put;
|
||||
ret = trusted_shash_alloc();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_free;
|
||||
ret = register_key_type(&key_type_trusted);
|
||||
if (ret < 0)
|
||||
trusted_shash_release();
|
||||
goto err_release;
|
||||
return 0;
|
||||
err_release:
|
||||
trusted_shash_release();
|
||||
err_free:
|
||||
kfree(digests);
|
||||
err_put:
|
||||
put_device(&chip->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit cleanup_trusted(void)
|
||||
{
|
||||
put_device(&chip->dev);
|
||||
kfree(digests);
|
||||
trusted_shash_release();
|
||||
unregister_key_type(&key_type_trusted);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ TARGETS += sysctl
|
|||
ifneq (1, $(quicktest))
|
||||
TARGETS += timers
|
||||
endif
|
||||
TARGETS += tpm2
|
||||
TARGETS += user
|
||||
TARGETS += vm
|
||||
TARGETS += x86
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
include ../lib.mk
|
||||
|
||||
TEST_PROGS := test_smoke.sh test_space.sh
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
|
||||
python -m unittest -v tpm2_tests.SmokeTest
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
|
||||
python -m unittest -v tpm2_tests.SpaceTest
|
|
@ -0,0 +1,696 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
import unittest
|
||||
from fcntl import ioctl
|
||||
|
||||
|
||||
TPM2_ST_NO_SESSIONS = 0x8001
|
||||
TPM2_ST_SESSIONS = 0x8002
|
||||
|
||||
TPM2_CC_FIRST = 0x01FF
|
||||
|
||||
TPM2_CC_CREATE_PRIMARY = 0x0131
|
||||
TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET = 0x0139
|
||||
TPM2_CC_CREATE = 0x0153
|
||||
TPM2_CC_LOAD = 0x0157
|
||||
TPM2_CC_UNSEAL = 0x015E
|
||||
TPM2_CC_FLUSH_CONTEXT = 0x0165
|
||||
TPM2_CC_START_AUTH_SESSION = 0x0176
|
||||
TPM2_CC_GET_CAPABILITY = 0x017A
|
||||
TPM2_CC_PCR_READ = 0x017E
|
||||
TPM2_CC_POLICY_PCR = 0x017F
|
||||
TPM2_CC_PCR_EXTEND = 0x0182
|
||||
TPM2_CC_POLICY_PASSWORD = 0x018C
|
||||
TPM2_CC_POLICY_GET_DIGEST = 0x0189
|
||||
|
||||
TPM2_SE_POLICY = 0x01
|
||||
TPM2_SE_TRIAL = 0x03
|
||||
|
||||
TPM2_ALG_RSA = 0x0001
|
||||
TPM2_ALG_SHA1 = 0x0004
|
||||
TPM2_ALG_AES = 0x0006
|
||||
TPM2_ALG_KEYEDHASH = 0x0008
|
||||
TPM2_ALG_SHA256 = 0x000B
|
||||
TPM2_ALG_NULL = 0x0010
|
||||
TPM2_ALG_CBC = 0x0042
|
||||
TPM2_ALG_CFB = 0x0043
|
||||
|
||||
TPM2_RH_OWNER = 0x40000001
|
||||
TPM2_RH_NULL = 0x40000007
|
||||
TPM2_RH_LOCKOUT = 0x4000000A
|
||||
TPM2_RS_PW = 0x40000009
|
||||
|
||||
TPM2_RC_SIZE = 0x01D5
|
||||
TPM2_RC_AUTH_FAIL = 0x098E
|
||||
TPM2_RC_POLICY_FAIL = 0x099D
|
||||
TPM2_RC_COMMAND_CODE = 0x0143
|
||||
|
||||
TSS2_RC_LAYER_SHIFT = 16
|
||||
TSS2_RESMGR_TPM_RC_LAYER = (11 << TSS2_RC_LAYER_SHIFT)
|
||||
|
||||
TPM2_CAP_HANDLES = 0x00000001
|
||||
TPM2_CAP_COMMANDS = 0x00000002
|
||||
TPM2_CAP_TPM_PROPERTIES = 0x00000006
|
||||
|
||||
TPM2_PT_FIXED = 0x100
|
||||
TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41
|
||||
|
||||
HR_SHIFT = 24
|
||||
HR_LOADED_SESSION = 0x02000000
|
||||
HR_TRANSIENT = 0x80000000
|
||||
|
||||
SHA1_DIGEST_SIZE = 20
|
||||
SHA256_DIGEST_SIZE = 32
|
||||
|
||||
TPM2_VER0_ERRORS = {
|
||||
0x000: "TPM_RC_SUCCESS",
|
||||
0x030: "TPM_RC_BAD_TAG",
|
||||
}
|
||||
|
||||
TPM2_VER1_ERRORS = {
|
||||
0x000: "TPM_RC_FAILURE",
|
||||
0x001: "TPM_RC_FAILURE",
|
||||
0x003: "TPM_RC_SEQUENCE",
|
||||
0x00B: "TPM_RC_PRIVATE",
|
||||
0x019: "TPM_RC_HMAC",
|
||||
0x020: "TPM_RC_DISABLED",
|
||||
0x021: "TPM_RC_EXCLUSIVE",
|
||||
0x024: "TPM_RC_AUTH_TYPE",
|
||||
0x025: "TPM_RC_AUTH_MISSING",
|
||||
0x026: "TPM_RC_POLICY",
|
||||
0x027: "TPM_RC_PCR",
|
||||
0x028: "TPM_RC_PCR_CHANGED",
|
||||
0x02D: "TPM_RC_UPGRADE",
|
||||
0x02E: "TPM_RC_TOO_MANY_CONTEXTS",
|
||||
0x02F: "TPM_RC_AUTH_UNAVAILABLE",
|
||||
0x030: "TPM_RC_REBOOT",
|
||||
0x031: "TPM_RC_UNBALANCED",
|
||||
0x042: "TPM_RC_COMMAND_SIZE",
|
||||
0x043: "TPM_RC_COMMAND_CODE",
|
||||
0x044: "TPM_RC_AUTHSIZE",
|
||||
0x045: "TPM_RC_AUTH_CONTEXT",
|
||||
0x046: "TPM_RC_NV_RANGE",
|
||||
0x047: "TPM_RC_NV_SIZE",
|
||||
0x048: "TPM_RC_NV_LOCKED",
|
||||
0x049: "TPM_RC_NV_AUTHORIZATION",
|
||||
0x04A: "TPM_RC_NV_UNINITIALIZED",
|
||||
0x04B: "TPM_RC_NV_SPACE",
|
||||
0x04C: "TPM_RC_NV_DEFINED",
|
||||
0x050: "TPM_RC_BAD_CONTEXT",
|
||||
0x051: "TPM_RC_CPHASH",
|
||||
0x052: "TPM_RC_PARENT",
|
||||
0x053: "TPM_RC_NEEDS_TEST",
|
||||
0x054: "TPM_RC_NO_RESULT",
|
||||
0x055: "TPM_RC_SENSITIVE",
|
||||
0x07F: "RC_MAX_FM0",
|
||||
}
|
||||
|
||||
TPM2_FMT1_ERRORS = {
|
||||
0x001: "TPM_RC_ASYMMETRIC",
|
||||
0x002: "TPM_RC_ATTRIBUTES",
|
||||
0x003: "TPM_RC_HASH",
|
||||
0x004: "TPM_RC_VALUE",
|
||||
0x005: "TPM_RC_HIERARCHY",
|
||||
0x007: "TPM_RC_KEY_SIZE",
|
||||
0x008: "TPM_RC_MGF",
|
||||
0x009: "TPM_RC_MODE",
|
||||
0x00A: "TPM_RC_TYPE",
|
||||
0x00B: "TPM_RC_HANDLE",
|
||||
0x00C: "TPM_RC_KDF",
|
||||
0x00D: "TPM_RC_RANGE",
|
||||
0x00E: "TPM_RC_AUTH_FAIL",
|
||||
0x00F: "TPM_RC_NONCE",
|
||||
0x010: "TPM_RC_PP",
|
||||
0x012: "TPM_RC_SCHEME",
|
||||
0x015: "TPM_RC_SIZE",
|
||||
0x016: "TPM_RC_SYMMETRIC",
|
||||
0x017: "TPM_RC_TAG",
|
||||
0x018: "TPM_RC_SELECTOR",
|
||||
0x01A: "TPM_RC_INSUFFICIENT",
|
||||
0x01B: "TPM_RC_SIGNATURE",
|
||||
0x01C: "TPM_RC_KEY",
|
||||
0x01D: "TPM_RC_POLICY_FAIL",
|
||||
0x01F: "TPM_RC_INTEGRITY",
|
||||
0x020: "TPM_RC_TICKET",
|
||||
0x021: "TPM_RC_RESERVED_BITS",
|
||||
0x022: "TPM_RC_BAD_AUTH",
|
||||
0x023: "TPM_RC_EXPIRED",
|
||||
0x024: "TPM_RC_POLICY_CC",
|
||||
0x025: "TPM_RC_BINDING",
|
||||
0x026: "TPM_RC_CURVE",
|
||||
0x027: "TPM_RC_ECC_POINT",
|
||||
}
|
||||
|
||||
TPM2_WARN_ERRORS = {
|
||||
0x001: "TPM_RC_CONTEXT_GAP",
|
||||
0x002: "TPM_RC_OBJECT_MEMORY",
|
||||
0x003: "TPM_RC_SESSION_MEMORY",
|
||||
0x004: "TPM_RC_MEMORY",
|
||||
0x005: "TPM_RC_SESSION_HANDLES",
|
||||
0x006: "TPM_RC_OBJECT_HANDLES",
|
||||
0x007: "TPM_RC_LOCALITY",
|
||||
0x008: "TPM_RC_YIELDED",
|
||||
0x009: "TPM_RC_CANCELED",
|
||||
0x00A: "TPM_RC_TESTING",
|
||||
0x010: "TPM_RC_REFERENCE_H0",
|
||||
0x011: "TPM_RC_REFERENCE_H1",
|
||||
0x012: "TPM_RC_REFERENCE_H2",
|
||||
0x013: "TPM_RC_REFERENCE_H3",
|
||||
0x014: "TPM_RC_REFERENCE_H4",
|
||||
0x015: "TPM_RC_REFERENCE_H5",
|
||||
0x016: "TPM_RC_REFERENCE_H6",
|
||||
0x018: "TPM_RC_REFERENCE_S0",
|
||||
0x019: "TPM_RC_REFERENCE_S1",
|
||||
0x01A: "TPM_RC_REFERENCE_S2",
|
||||
0x01B: "TPM_RC_REFERENCE_S3",
|
||||
0x01C: "TPM_RC_REFERENCE_S4",
|
||||
0x01D: "TPM_RC_REFERENCE_S5",
|
||||
0x01E: "TPM_RC_REFERENCE_S6",
|
||||
0x020: "TPM_RC_NV_RATE",
|
||||
0x021: "TPM_RC_LOCKOUT",
|
||||
0x022: "TPM_RC_RETRY",
|
||||
0x023: "TPM_RC_NV_UNAVAILABLE",
|
||||
0x7F: "TPM_RC_NOT_USED",
|
||||
}
|
||||
|
||||
RC_VER1 = 0x100
|
||||
RC_FMT1 = 0x080
|
||||
RC_WARN = 0x900
|
||||
|
||||
ALG_DIGEST_SIZE_MAP = {
|
||||
TPM2_ALG_SHA1: SHA1_DIGEST_SIZE,
|
||||
TPM2_ALG_SHA256: SHA256_DIGEST_SIZE,
|
||||
}
|
||||
|
||||
ALG_HASH_FUNCTION_MAP = {
|
||||
TPM2_ALG_SHA1: hashlib.sha1,
|
||||
TPM2_ALG_SHA256: hashlib.sha256
|
||||
}
|
||||
|
||||
NAME_ALG_MAP = {
|
||||
"sha1": TPM2_ALG_SHA1,
|
||||
"sha256": TPM2_ALG_SHA256,
|
||||
}
|
||||
|
||||
|
||||
class UnknownAlgorithmIdError(Exception):
|
||||
def __init__(self, alg):
|
||||
self.alg = alg
|
||||
|
||||
def __str__(self):
|
||||
return '0x%0x' % (alg)
|
||||
|
||||
|
||||
class UnknownAlgorithmNameError(Exception):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return name
|
||||
|
||||
|
||||
class UnknownPCRBankError(Exception):
|
||||
def __init__(self, alg):
|
||||
self.alg = alg
|
||||
|
||||
def __str__(self):
|
||||
return '0x%0x' % (alg)
|
||||
|
||||
|
||||
class ProtocolError(Exception):
|
||||
def __init__(self, cc, rc):
|
||||
self.cc = cc
|
||||
self.rc = rc
|
||||
|
||||
if (rc & RC_FMT1) == RC_FMT1:
|
||||
self.name = TPM2_FMT1_ERRORS.get(rc & 0x3f, "TPM_RC_UNKNOWN")
|
||||
elif (rc & RC_WARN) == RC_WARN:
|
||||
self.name = TPM2_WARN_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
|
||||
elif (rc & RC_VER1) == RC_VER1:
|
||||
self.name = TPM2_VER1_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
|
||||
else:
|
||||
self.name = TPM2_VER0_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
|
||||
|
||||
def __str__(self):
|
||||
if self.cc:
|
||||
return '%s: cc=0x%08x, rc=0x%08x' % (self.name, self.cc, self.rc)
|
||||
else:
|
||||
return '%s: rc=0x%08x' % (self.name, self.rc)
|
||||
|
||||
|
||||
class AuthCommand(object):
|
||||
"""TPMS_AUTH_COMMAND"""
|
||||
|
||||
def __init__(self, session_handle=TPM2_RS_PW, nonce='', session_attributes=0,
|
||||
hmac=''):
|
||||
self.session_handle = session_handle
|
||||
self.nonce = nonce
|
||||
self.session_attributes = session_attributes
|
||||
self.hmac = hmac
|
||||
|
||||
def __str__(self):
|
||||
fmt = '>I H%us B H%us' % (len(self.nonce), len(self.hmac))
|
||||
return struct.pack(fmt, self.session_handle, len(self.nonce),
|
||||
self.nonce, self.session_attributes, len(self.hmac),
|
||||
self.hmac)
|
||||
|
||||
def __len__(self):
|
||||
fmt = '>I H%us B H%us' % (len(self.nonce), len(self.hmac))
|
||||
return struct.calcsize(fmt)
|
||||
|
||||
|
||||
class SensitiveCreate(object):
|
||||
"""TPMS_SENSITIVE_CREATE"""
|
||||
|
||||
def __init__(self, user_auth='', data=''):
|
||||
self.user_auth = user_auth
|
||||
self.data = data
|
||||
|
||||
def __str__(self):
|
||||
fmt = '>H%us H%us' % (len(self.user_auth), len(self.data))
|
||||
return struct.pack(fmt, len(self.user_auth), self.user_auth,
|
||||
len(self.data), self.data)
|
||||
|
||||
def __len__(self):
|
||||
fmt = '>H%us H%us' % (len(self.user_auth), len(self.data))
|
||||
return struct.calcsize(fmt)
|
||||
|
||||
|
||||
class Public(object):
|
||||
"""TPMT_PUBLIC"""
|
||||
|
||||
FIXED_TPM = (1 << 1)
|
||||
FIXED_PARENT = (1 << 4)
|
||||
SENSITIVE_DATA_ORIGIN = (1 << 5)
|
||||
USER_WITH_AUTH = (1 << 6)
|
||||
RESTRICTED = (1 << 16)
|
||||
DECRYPT = (1 << 17)
|
||||
|
||||
def __fmt(self):
|
||||
return '>HHIH%us%usH%us' % \
|
||||
(len(self.auth_policy), len(self.parameters), len(self.unique))
|
||||
|
||||
def __init__(self, object_type, name_alg, object_attributes, auth_policy='',
|
||||
parameters='', unique=''):
|
||||
self.object_type = object_type
|
||||
self.name_alg = name_alg
|
||||
self.object_attributes = object_attributes
|
||||
self.auth_policy = auth_policy
|
||||
self.parameters = parameters
|
||||
self.unique = unique
|
||||
|
||||
def __str__(self):
|
||||
return struct.pack(self.__fmt(),
|
||||
self.object_type,
|
||||
self.name_alg,
|
||||
self.object_attributes,
|
||||
len(self.auth_policy),
|
||||
self.auth_policy,
|
||||
self.parameters,
|
||||
len(self.unique),
|
||||
self.unique)
|
||||
|
||||
def __len__(self):
|
||||
return struct.calcsize(self.__fmt())
|
||||
|
||||
|
||||
def get_digest_size(alg):
|
||||
ds = ALG_DIGEST_SIZE_MAP.get(alg)
|
||||
if not ds:
|
||||
raise UnknownAlgorithmIdError(alg)
|
||||
return ds
|
||||
|
||||
|
||||
def get_hash_function(alg):
|
||||
f = ALG_HASH_FUNCTION_MAP.get(alg)
|
||||
if not f:
|
||||
raise UnknownAlgorithmIdError(alg)
|
||||
return f
|
||||
|
||||
|
||||
def get_algorithm(name):
|
||||
alg = NAME_ALG_MAP.get(name)
|
||||
if not alg:
|
||||
raise UnknownAlgorithmNameError(name)
|
||||
return alg
|
||||
|
||||
|
||||
def hex_dump(d):
|
||||
d = [format(ord(x), '02x') for x in d]
|
||||
d = [d[i: i + 16] for i in xrange(0, len(d), 16)]
|
||||
d = [' '.join(x) for x in d]
|
||||
d = os.linesep.join(d)
|
||||
|
||||
return d
|
||||
|
||||
class Client:
|
||||
FLAG_DEBUG = 0x01
|
||||
FLAG_SPACE = 0x02
|
||||
TPM_IOC_NEW_SPACE = 0xa200
|
||||
|
||||
def __init__(self, flags = 0):
|
||||
self.flags = flags
|
||||
|
||||
if (self.flags & Client.FLAG_SPACE) == 0:
|
||||
self.tpm = open('/dev/tpm0', 'r+b')
|
||||
else:
|
||||
self.tpm = open('/dev/tpmrm0', 'r+b')
|
||||
|
||||
def close(self):
|
||||
self.tpm.close()
|
||||
|
||||
def send_cmd(self, cmd):
|
||||
self.tpm.write(cmd)
|
||||
rsp = self.tpm.read()
|
||||
|
||||
if (self.flags & Client.FLAG_DEBUG) != 0:
|
||||
sys.stderr.write('cmd' + os.linesep)
|
||||
sys.stderr.write(hex_dump(cmd) + os.linesep)
|
||||
sys.stderr.write('rsp' + os.linesep)
|
||||
sys.stderr.write(hex_dump(rsp) + os.linesep)
|
||||
|
||||
rc = struct.unpack('>I', rsp[6:10])[0]
|
||||
if rc != 0:
|
||||
cc = struct.unpack('>I', cmd[6:10])[0]
|
||||
raise ProtocolError(cc, rc)
|
||||
|
||||
return rsp
|
||||
|
||||
def read_pcr(self, i, bank_alg = TPM2_ALG_SHA1):
|
||||
pcrsel_len = max((i >> 3) + 1, 3)
|
||||
pcrsel = [0] * pcrsel_len
|
||||
pcrsel[i >> 3] = 1 << (i & 7)
|
||||
pcrsel = ''.join(map(chr, pcrsel))
|
||||
|
||||
fmt = '>HII IHB%us' % (pcrsel_len)
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_PCR_READ,
|
||||
1,
|
||||
bank_alg,
|
||||
pcrsel_len, pcrsel)
|
||||
|
||||
rsp = self.send_cmd(cmd)
|
||||
|
||||
pcr_update_cnt, pcr_select_cnt = struct.unpack('>II', rsp[10:18])
|
||||
assert pcr_select_cnt == 1
|
||||
rsp = rsp[18:]
|
||||
|
||||
alg2, pcrsel_len2 = struct.unpack('>HB', rsp[:3])
|
||||
assert bank_alg == alg2 and pcrsel_len == pcrsel_len2
|
||||
rsp = rsp[3 + pcrsel_len:]
|
||||
|
||||
digest_cnt = struct.unpack('>I', rsp[:4])[0]
|
||||
if digest_cnt == 0:
|
||||
return None
|
||||
rsp = rsp[6:]
|
||||
|
||||
return rsp
|
||||
|
||||
def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1):
|
||||
ds = get_digest_size(bank_alg)
|
||||
assert(ds == len(dig))
|
||||
|
||||
auth_cmd = AuthCommand()
|
||||
|
||||
fmt = '>HII I I%us IH%us' % (len(auth_cmd), ds)
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_PCR_EXTEND,
|
||||
i,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd),
|
||||
1, bank_alg, dig)
|
||||
|
||||
self.send_cmd(cmd)
|
||||
|
||||
def start_auth_session(self, session_type, name_alg = TPM2_ALG_SHA1):
|
||||
fmt = '>HII IIH16sHBHH'
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_START_AUTH_SESSION,
|
||||
TPM2_RH_NULL,
|
||||
TPM2_RH_NULL,
|
||||
16,
|
||||
'\0' * 16,
|
||||
0,
|
||||
session_type,
|
||||
TPM2_ALG_NULL,
|
||||
name_alg)
|
||||
|
||||
return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
|
||||
|
||||
def __calc_pcr_digest(self, pcrs, bank_alg = TPM2_ALG_SHA1,
|
||||
digest_alg = TPM2_ALG_SHA1):
|
||||
x = []
|
||||
f = get_hash_function(digest_alg)
|
||||
|
||||
for i in pcrs:
|
||||
pcr = self.read_pcr(i, bank_alg)
|
||||
if pcr == None:
|
||||
return None
|
||||
x += pcr
|
||||
|
||||
return f(bytearray(x)).digest()
|
||||
|
||||
def policy_pcr(self, handle, pcrs, bank_alg = TPM2_ALG_SHA1,
|
||||
name_alg = TPM2_ALG_SHA1):
|
||||
ds = get_digest_size(name_alg)
|
||||
dig = self.__calc_pcr_digest(pcrs, bank_alg, name_alg)
|
||||
if not dig:
|
||||
raise UnknownPCRBankError(bank_alg)
|
||||
|
||||
pcrsel_len = max((max(pcrs) >> 3) + 1, 3)
|
||||
pcrsel = [0] * pcrsel_len
|
||||
for i in pcrs:
|
||||
pcrsel[i >> 3] |= 1 << (i & 7)
|
||||
pcrsel = ''.join(map(chr, pcrsel))
|
||||
|
||||
fmt = '>HII IH%usIHB3s' % ds
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_POLICY_PCR,
|
||||
handle,
|
||||
len(dig), str(dig),
|
||||
1,
|
||||
bank_alg,
|
||||
pcrsel_len, pcrsel)
|
||||
|
||||
self.send_cmd(cmd)
|
||||
|
||||
def policy_password(self, handle):
|
||||
fmt = '>HII I'
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_POLICY_PASSWORD,
|
||||
handle)
|
||||
|
||||
self.send_cmd(cmd)
|
||||
|
||||
def get_policy_digest(self, handle):
|
||||
fmt = '>HII I'
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_POLICY_GET_DIGEST,
|
||||
handle)
|
||||
|
||||
return self.send_cmd(cmd)[12:]
|
||||
|
||||
def flush_context(self, handle):
|
||||
fmt = '>HIII'
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_FLUSH_CONTEXT,
|
||||
handle)
|
||||
|
||||
self.send_cmd(cmd)
|
||||
|
||||
def create_root_key(self, auth_value = ''):
|
||||
attributes = \
|
||||
Public.FIXED_TPM | \
|
||||
Public.FIXED_PARENT | \
|
||||
Public.SENSITIVE_DATA_ORIGIN | \
|
||||
Public.USER_WITH_AUTH | \
|
||||
Public.RESTRICTED | \
|
||||
Public.DECRYPT
|
||||
|
||||
auth_cmd = AuthCommand()
|
||||
sensitive = SensitiveCreate(user_auth=auth_value)
|
||||
|
||||
public_parms = struct.pack(
|
||||
'>HHHHHI',
|
||||
TPM2_ALG_AES,
|
||||
128,
|
||||
TPM2_ALG_CFB,
|
||||
TPM2_ALG_NULL,
|
||||
2048,
|
||||
0)
|
||||
|
||||
public = Public(
|
||||
object_type=TPM2_ALG_RSA,
|
||||
name_alg=TPM2_ALG_SHA1,
|
||||
object_attributes=attributes,
|
||||
parameters=public_parms)
|
||||
|
||||
fmt = '>HIII I%us H%us H%us HI' % \
|
||||
(len(auth_cmd), len(sensitive), len(public))
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_CREATE_PRIMARY,
|
||||
TPM2_RH_OWNER,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd),
|
||||
len(sensitive),
|
||||
str(sensitive),
|
||||
len(public),
|
||||
str(public),
|
||||
0, 0)
|
||||
|
||||
return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
|
||||
|
||||
def seal(self, parent_key, data, auth_value, policy_dig,
|
||||
name_alg = TPM2_ALG_SHA1):
|
||||
ds = get_digest_size(name_alg)
|
||||
assert(not policy_dig or ds == len(policy_dig))
|
||||
|
||||
attributes = 0
|
||||
if not policy_dig:
|
||||
attributes |= Public.USER_WITH_AUTH
|
||||
policy_dig = ''
|
||||
|
||||
auth_cmd = AuthCommand()
|
||||
sensitive = SensitiveCreate(user_auth=auth_value, data=data)
|
||||
|
||||
public = Public(
|
||||
object_type=TPM2_ALG_KEYEDHASH,
|
||||
name_alg=name_alg,
|
||||
object_attributes=attributes,
|
||||
auth_policy=policy_dig,
|
||||
parameters=struct.pack('>H', TPM2_ALG_NULL))
|
||||
|
||||
fmt = '>HIII I%us H%us H%us HI' % \
|
||||
(len(auth_cmd), len(sensitive), len(public))
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_CREATE,
|
||||
parent_key,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd),
|
||||
len(sensitive),
|
||||
str(sensitive),
|
||||
len(public),
|
||||
str(public),
|
||||
0, 0)
|
||||
|
||||
rsp = self.send_cmd(cmd)
|
||||
|
||||
return rsp[14:]
|
||||
|
||||
def unseal(self, parent_key, blob, auth_value, policy_handle):
|
||||
private_len = struct.unpack('>H', blob[0:2])[0]
|
||||
public_start = private_len + 2
|
||||
public_len = struct.unpack('>H', blob[public_start:public_start + 2])[0]
|
||||
blob = blob[:private_len + public_len + 4]
|
||||
|
||||
auth_cmd = AuthCommand()
|
||||
|
||||
fmt = '>HII I I%us %us' % (len(auth_cmd), len(blob))
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_LOAD,
|
||||
parent_key,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd),
|
||||
blob)
|
||||
|
||||
data_handle = struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
|
||||
|
||||
if policy_handle:
|
||||
auth_cmd = AuthCommand(session_handle=policy_handle, hmac=auth_value)
|
||||
else:
|
||||
auth_cmd = AuthCommand(hmac=auth_value)
|
||||
|
||||
fmt = '>HII I I%us' % (len(auth_cmd))
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_UNSEAL,
|
||||
data_handle,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd))
|
||||
|
||||
try:
|
||||
rsp = self.send_cmd(cmd)
|
||||
finally:
|
||||
self.flush_context(data_handle)
|
||||
|
||||
data_len = struct.unpack('>I', rsp[10:14])[0] - 2
|
||||
|
||||
return rsp[16:16 + data_len]
|
||||
|
||||
def reset_da_lock(self):
|
||||
auth_cmd = AuthCommand()
|
||||
|
||||
fmt = '>HII I I%us' % (len(auth_cmd))
|
||||
cmd = struct.pack(
|
||||
fmt,
|
||||
TPM2_ST_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET,
|
||||
TPM2_RH_LOCKOUT,
|
||||
len(auth_cmd),
|
||||
str(auth_cmd))
|
||||
|
||||
self.send_cmd(cmd)
|
||||
|
||||
def __get_cap_cnt(self, cap, pt, cnt):
|
||||
handles = []
|
||||
fmt = '>HII III'
|
||||
|
||||
cmd = struct.pack(fmt,
|
||||
TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt),
|
||||
TPM2_CC_GET_CAPABILITY,
|
||||
cap, pt, cnt)
|
||||
|
||||
rsp = self.send_cmd(cmd)[10:]
|
||||
more_data, cap, cnt = struct.unpack('>BII', rsp[:9])
|
||||
rsp = rsp[9:]
|
||||
|
||||
for i in xrange(0, cnt):
|
||||
handle = struct.unpack('>I', rsp[:4])[0]
|
||||
handles.append(handle)
|
||||
rsp = rsp[4:]
|
||||
|
||||
return handles, more_data
|
||||
|
||||
def get_cap(self, cap, pt):
|
||||
handles = []
|
||||
|
||||
more_data = True
|
||||
while more_data:
|
||||
next_handles, more_data = self.__get_cap_cnt(cap, pt, 1)
|
||||
handles += next_handles
|
||||
pt += 1
|
||||
|
||||
return handles
|
|
@ -0,0 +1,227 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from argparse import FileType
|
||||
import os
|
||||
import sys
|
||||
import tpm2
|
||||
from tpm2 import ProtocolError
|
||||
import unittest
|
||||
import logging
|
||||
import struct
|
||||
|
||||
class SmokeTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.client = tpm2.Client()
|
||||
self.root_key = self.client.create_root_key()
|
||||
|
||||
def tearDown(self):
|
||||
self.client.flush_context(self.root_key)
|
||||
self.client.close()
|
||||
|
||||
def test_seal_with_auth(self):
|
||||
data = 'X' * 64
|
||||
auth = 'A' * 15
|
||||
|
||||
blob = self.client.seal(self.root_key, data, auth, None)
|
||||
result = self.client.unseal(self.root_key, blob, auth, None)
|
||||
self.assertEqual(data, result)
|
||||
|
||||
def test_seal_with_policy(self):
|
||||
handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
|
||||
|
||||
data = 'X' * 64
|
||||
auth = 'A' * 15
|
||||
pcrs = [16]
|
||||
|
||||
try:
|
||||
self.client.policy_pcr(handle, pcrs)
|
||||
self.client.policy_password(handle)
|
||||
|
||||
policy_dig = self.client.get_policy_digest(handle)
|
||||
finally:
|
||||
self.client.flush_context(handle)
|
||||
|
||||
blob = self.client.seal(self.root_key, data, auth, policy_dig)
|
||||
|
||||
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
|
||||
|
||||
try:
|
||||
self.client.policy_pcr(handle, pcrs)
|
||||
self.client.policy_password(handle)
|
||||
|
||||
result = self.client.unseal(self.root_key, blob, auth, handle)
|
||||
except:
|
||||
self.client.flush_context(handle)
|
||||
raise
|
||||
|
||||
self.assertEqual(data, result)
|
||||
|
||||
def test_unseal_with_wrong_auth(self):
|
||||
data = 'X' * 64
|
||||
auth = 'A' * 20
|
||||
rc = 0
|
||||
|
||||
blob = self.client.seal(self.root_key, data, auth, None)
|
||||
try:
|
||||
result = self.client.unseal(self.root_key, blob, auth[:-1] + 'B', None)
|
||||
except ProtocolError, e:
|
||||
rc = e.rc
|
||||
|
||||
self.assertEqual(rc, tpm2.TPM2_RC_AUTH_FAIL)
|
||||
|
||||
def test_unseal_with_wrong_policy(self):
|
||||
handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
|
||||
|
||||
data = 'X' * 64
|
||||
auth = 'A' * 17
|
||||
pcrs = [16]
|
||||
|
||||
try:
|
||||
self.client.policy_pcr(handle, pcrs)
|
||||
self.client.policy_password(handle)
|
||||
|
||||
policy_dig = self.client.get_policy_digest(handle)
|
||||
finally:
|
||||
self.client.flush_context(handle)
|
||||
|
||||
blob = self.client.seal(self.root_key, data, auth, policy_dig)
|
||||
|
||||
# Extend first a PCR that is not part of the policy and try to unseal.
|
||||
# This should succeed.
|
||||
|
||||
ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
|
||||
self.client.extend_pcr(1, 'X' * ds)
|
||||
|
||||
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
|
||||
|
||||
try:
|
||||
self.client.policy_pcr(handle, pcrs)
|
||||
self.client.policy_password(handle)
|
||||
|
||||
result = self.client.unseal(self.root_key, blob, auth, handle)
|
||||
except:
|
||||
self.client.flush_context(handle)
|
||||
raise
|
||||
|
||||
self.assertEqual(data, result)
|
||||
|
||||
# Then, extend a PCR that is part of the policy and try to unseal.
|
||||
# This should fail.
|
||||
self.client.extend_pcr(16, 'X' * ds)
|
||||
|
||||
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
|
||||
|
||||
rc = 0
|
||||
|
||||
try:
|
||||
self.client.policy_pcr(handle, pcrs)
|
||||
self.client.policy_password(handle)
|
||||
|
||||
result = self.client.unseal(self.root_key, blob, auth, handle)
|
||||
except ProtocolError, e:
|
||||
rc = e.rc
|
||||
self.client.flush_context(handle)
|
||||
except:
|
||||
self.client.flush_context(handle)
|
||||
raise
|
||||
|
||||
self.assertEqual(rc, tpm2.TPM2_RC_POLICY_FAIL)
|
||||
|
||||
def test_seal_with_too_long_auth(self):
|
||||
ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
|
||||
data = 'X' * 64
|
||||
auth = 'A' * (ds + 1)
|
||||
|
||||
rc = 0
|
||||
try:
|
||||
blob = self.client.seal(self.root_key, data, auth, None)
|
||||
except ProtocolError, e:
|
||||
rc = e.rc
|
||||
|
||||
self.assertEqual(rc, tpm2.TPM2_RC_SIZE)
|
||||
|
||||
def test_too_short_cmd(self):
|
||||
rejected = False
|
||||
try:
|
||||
fmt = '>HIII'
|
||||
cmd = struct.pack(fmt,
|
||||
tpm2.TPM2_ST_NO_SESSIONS,
|
||||
struct.calcsize(fmt) + 1,
|
||||
tpm2.TPM2_CC_FLUSH_CONTEXT,
|
||||
0xDEADBEEF)
|
||||
|
||||
self.client.send_cmd(cmd)
|
||||
except IOError, e:
|
||||
rejected = True
|
||||
except:
|
||||
pass
|
||||
self.assertEqual(rejected, True)
|
||||
|
||||
class SpaceTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
logging.basicConfig(filename='SpaceTest.log', level=logging.DEBUG)
|
||||
|
||||
def test_make_two_spaces(self):
|
||||
log = logging.getLogger(__name__)
|
||||
log.debug("test_make_two_spaces")
|
||||
|
||||
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
root1 = space1.create_root_key()
|
||||
space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
root2 = space2.create_root_key()
|
||||
root3 = space2.create_root_key()
|
||||
|
||||
log.debug("%08x" % (root1))
|
||||
log.debug("%08x" % (root2))
|
||||
log.debug("%08x" % (root3))
|
||||
|
||||
def test_flush_context(self):
|
||||
log = logging.getLogger(__name__)
|
||||
log.debug("test_flush_context")
|
||||
|
||||
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
root1 = space1.create_root_key()
|
||||
log.debug("%08x" % (root1))
|
||||
|
||||
space1.flush_context(root1)
|
||||
|
||||
def test_get_handles(self):
|
||||
log = logging.getLogger(__name__)
|
||||
log.debug("test_get_handles")
|
||||
|
||||
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
space1.create_root_key()
|
||||
space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
space2.create_root_key()
|
||||
space2.create_root_key()
|
||||
|
||||
handles = space2.get_cap(tpm2.TPM2_CAP_HANDLES, tpm2.HR_TRANSIENT)
|
||||
|
||||
self.assertEqual(len(handles), 2)
|
||||
|
||||
log.debug("%08x" % (handles[0]))
|
||||
log.debug("%08x" % (handles[1]))
|
||||
|
||||
def test_invalid_cc(self):
|
||||
log = logging.getLogger(__name__)
|
||||
log.debug(sys._getframe().f_code.co_name)
|
||||
|
||||
TPM2_CC_INVALID = tpm2.TPM2_CC_FIRST - 1
|
||||
|
||||
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
|
||||
root1 = space1.create_root_key()
|
||||
log.debug("%08x" % (root1))
|
||||
|
||||
fmt = '>HII'
|
||||
cmd = struct.pack(fmt, tpm2.TPM2_ST_NO_SESSIONS, struct.calcsize(fmt),
|
||||
TPM2_CC_INVALID)
|
||||
|
||||
rc = 0
|
||||
try:
|
||||
space1.send_cmd(cmd)
|
||||
except ProtocolError, e:
|
||||
rc = e.rc
|
||||
|
||||
self.assertEqual(rc, tpm2.TPM2_RC_COMMAND_CODE |
|
||||
tpm2.TSS2_RESMGR_TPM_RC_LAYER)
|
Loading…
Reference in New Issue