Commit 5af7f115 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull tpm updates from James Morris:

 - 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

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (37 commits)
  tpm/ppi: Enable submission of optional command parameter for PPI 1.3
  tpm/ppi: Possibly show command parameter if TPM PPI 1.3 is used
  tpm/ppi: Display up to 101 operations as define for version 1.3
  tpm/ppi: rename TPM_PPI_REVISION_ID to TPM_PPI_REVISION_ID_1
  tpm/ppi: pass function revision ID to tpm_eval_dsm()
  tpm: pass an array of tpm_extend_digest structures to tpm_pcr_extend()
  KEYS: trusted: explicitly use tpm_chip structure from tpm_default_chip()
  tpm: move tpm_chip definition to include/linux/tpm.h
  tpm: retrieve digest size of unknown algorithms with PCR read
  tpm: rename and export tpm2_digest and tpm2_algorithms
  tpm: dynamically allocate the allocated_banks array
  tpm: remove @flags from tpm_transmit()
  tpm: take TPM chip power gating out of tpm_transmit()
  tpm: introduce tpm_chip_start() and tpm_chip_stop()
  tpm: remove TPM_TRANSMIT_UNLOCKED flag
  tpm: use tpm_try_get_ops() in tpm-sysfs.c.
  tpm: remove @space from tpm_transmit()
  tpm: move TPM space code out of tpm_transmit()
  tpm: move tpm_validate_commmand() to tpm2-space.c
  tpm: clean up tpm_try_transmit() error handling flow
  ...
parents c3665a6b 5da10728
......@@ -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,39 +83,30 @@ 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);
}
}
/* now check if current entry is valid */
if ((addr + sizeof(struct tcpa_event)) >= limit)
return NULL;
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))
> limit))
return NULL;
if (i++ == *pos)
break;
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);
......
......@@ -19,7 +19,7 @@
#define __LOCAL_ST33ZP24_H__
#define TPM_WRITE_DIRECTION 0x80
#define TPM_BUFSIZE 2048
#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);
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)
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)
{
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)
static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
{
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: TPM chip to use
* @space: tpm space
* @buf: TPM command buffer
* @chip: a TPM chip to use
* @buf: a 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
* @chip: a TPM chip to use
* @buf: a TPM command buffer
* @min_rsp_body_length: minimum expected length of response body
* @flags: tpm transmit flags - bitmap
* @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;
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++;
}
for (i = 0; i < chip->nr_allocated_banks; i++)
if (digests[i].alg_id != chip->allocated_banks[i].alg_id)
return -EINVAL;
rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
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)
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
mutex_lock(&chip->tpm_mutex);
if (!tpm_chip_start(chip)) {
tpm2_shutdown(chip, TPM2_SU_STATE);
else
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,
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));
if (rc)
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,
if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version",
sizeof(cap.tpm_version));
if (rc)
return 0;
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 {
struct tpm_header {
__be16 tag;
__be32 length;
union {
__be32 ordinal;
} __packed;
struct tpm_output_header {
__be16 tag;
__be32 length;
__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,7 +377,6 @@ 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);
if (!chip->timeout_adjusted) {
......@@ -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) {
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];
memcpy(res_buf, out->digest, SHA1_DIGEST_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;
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,
hash_digest_size[tpm2_hash_map[j].crypto_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);
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);
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,
......
......@@ -40,9 +40,7 @@
#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_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)
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);
}
......
......@@ -50,6 +50,7 @@ ifneq (1, $(quicktest))
TARGETS += timers
endif
TARGETS += tmpfs
TARGETS += tpm2
TARGETS += user
TARGETS += vm
TARGETS += x86
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
include ../lib.mk
TEST_PROGS := test_smoke.sh test_space.sh
#!/bin/bash
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
python -m unittest -v tpm2_tests.SmokeTest
#!/bin/bash
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
python -m unittest -v tpm2_tests.SpaceTest
# 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
# 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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment