int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { struct tpm_cmd_t cmd; int rc; struct tpm_chip *chip; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { rc = tpm2_pcr_extend(chip, pcr_idx, hash); tpm_put_ops(chip); return rc; } cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, "attempting extend a PCR value"); tpm_put_ops(chip); return rc; }
/** * 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 * @digests: array of tpm_digest structures used to extend PCRs * * 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, struct tpm_digest *digests) { int rc; int i; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; for (i = 0; i < chip->nr_allocated_banks; i++) if (digests[i].alg_id != chip->allocated_banks[i].alg_id) return -EINVAL; if (chip->flags & TPM_CHIP_FLAG_TPM2) { rc = tpm2_pcr_extend(chip, pcr_idx, digests); tpm_put_ops(chip); return rc; } rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest, "attempting extend a PCR value"); tpm_put_ops(chip); return rc; }
int tpm_send(u32 chip_num, void *cmd, size_t buflen) { struct tpm_chip *chip; int rc; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); tpm_put_ops(chip); return rc; }
static ssize_t tpm_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; size_t in_size = size; ssize_t out_size; /* cannot perform a write until the read has cleared either via tpm_read or a user_read_timer timeout. This also prevents splitted buffered writes from blocking here. */ if (atomic_read(&priv->data_pending) != 0) return -EBUSY; if (in_size > TPM_BUFSIZE) return -E2BIG; mutex_lock(&priv->buffer_mutex); if (copy_from_user (priv->data_buffer, (void __user *) buf, in_size)) { mutex_unlock(&priv->buffer_mutex); return -EFAULT; } /* atomic tpm command send and result receive. We only hold the ops * lock during this period so that the tpm can be unregistered even if * the char dev is held open. */ if (tpm_try_get_ops(priv->chip)) { mutex_unlock(&priv->buffer_mutex); return -EPIPE; } out_size = tpm_transmit(priv->chip, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); if (out_size < 0) { mutex_unlock(&priv->buffer_mutex); return out_size; } atomic_set(&priv->data_pending, out_size); mutex_unlock(&priv->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); return in_size; }
/** * tpm_seal_trusted() - seal a trusted key payload * @chip: a &struct tpm_chip instance, %NULL for the default chip * @options: authentication values and other options * @payload: the key data in clear and encrypted form * * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in * the keyring subsystem. * * Return: same as with tpm_transmit_cmd() */ int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { int rc; chip = tpm_find_get_ops(chip); if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_seal_trusted(chip, payload, options); tpm_put_ops(chip); return rc; }
/** * tpm_is_tpm2 - do we a have a TPM2 chip? * @chip: a &struct tpm_chip instance, %NULL for the default chip * * Return: * 1 if we have a TPM2 chip. * 0 if we don't have a TPM2 chip. * A negative number for system errors (errno). */ int tpm_is_tpm2(struct tpm_chip *chip) { int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; tpm_put_ops(chip); return rc; }
/** * tpm_pcr_read - read a pcr value * @chip_num: tpm idx # or ANY * @pcr_idx: pcr idx to retrieve * @res_buf: TPM_PCR value * size of res_buf is 20 bytes (or NULL if you don't care) * * The TPM driver should be built-in, but for whatever reason it * isn't, protect against the chip disappearing, by incrementing * the module usage count. */ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { struct tpm_chip *chip; int rc; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, res_buf); else rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); tpm_put_ops(chip); return rc; }
/** * tpm_is_tpm2 - is the chip a TPM2 chip? * @chip_num: tpm idx # or ANY * * Returns < 0 on error, and 1 or 0 on success depending whether the chip * is a TPM2 chip. */ int tpm_is_tpm2(u32 chip_num) { struct tpm_chip *chip; int rc; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; tpm_put_ops(chip); return rc; }
/** * 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 * @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, struct tpm_digest *digest) { int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); else rc = tpm1_pcr_read(chip, pcr_idx, digest->digest); tpm_put_ops(chip); return rc; }
static void tpm_dev_async_work(struct work_struct *work) { struct file_priv *priv = container_of(work, struct file_priv, async_work); ssize_t ret; mutex_lock(&priv->buffer_mutex); priv->command_enqueued = false; 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; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); } mutex_unlock(&priv->buffer_mutex); wake_up_interruptible(&priv->async_wait); }
/** * tpm_get_random() - get random bytes from the TPM's RNG * @chip: a &struct tpm_chip instance, %NULL for the default chip * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * * Return: number of random bytes read or a negative error value. */ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { int rc; if (!out || max > TPM_MAX_RNG_DATA) return -EINVAL; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_get_random(chip, out, max); else rc = tpm1_get_random(chip, out, max); tpm_put_ops(chip); return rc; }
/** * tpm_send - send a TPM command * @chip: a &struct tpm_chip instance, %NULL for the default chip * @cmd: a TPM command buffer * @buflen: the length of the TPM command buffer * * Return: same as with tpm_transmit_cmd() */ 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_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; }
/* * We are about to suspend. Save the TPM state * so that it can be restored. */ int tpm_pm_suspend(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_cmd_t cmd; int rc, try; u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; if (chip == NULL) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; } /* for buggy tpm, flush pcrs with extend to selected dummy */ if (tpm_suspend_pcr) { cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, NULL); /* * If the TPM indicates that it is too busy to respond to * this command then retry before giving up. It can take * several seconds for this TPM to be ready. * * This can happen if the TPM has already been sent the * SaveState command before the driver has loaded. TCG 1.2 * specification states that any communication after SaveState * may cause the TPM to invalidate previously saved state. */ if (rc != TPM_WARN_RETRY) break; msleep(TPM_TIMEOUT_RETRY); } if (rc) dev_err(&chip->dev, "Error (%d) sending savestate before suspend\n", rc); else if (try > 0) dev_warn(&chip->dev, "TPM savestate took %dms\n", try * TPM_TIMEOUT_RETRY); return rc; } EXPORT_SYMBOL_GPL(tpm_pm_suspend); /* * Resume from a power safe. The BIOS already restored * the TPM state. */ int tpm_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; return 0; } EXPORT_SYMBOL_GPL(tpm_pm_resume); #define TPM_GETRANDOM_RESULT_SIZE 18 static const struct tpm_input_header tpm_getrandom_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(14), .ordinal = TPM_ORD_GET_RANDOM }; /** * tpm_get_random() - Get random bytes from the tpm's RNG * @chip_num: A specific chip number for the request or TPM_ANY_NUM * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * * Returns < 0 on error and the number of bytes read on success */ int tpm_get_random(u32 chip_num, u8 *out, size_t max) { struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); int err, total = 0, retries = 5; u8 *dest = out; if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { err = tpm2_get_random(chip, out, max); tpm_put_ops(chip); return err; } do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, 0, "attempting get random"); if (err) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); dest += recd; total += recd; num_bytes -= recd; } while (retries-- && total < max); tpm_put_ops(chip); return total ? total : -EIO; } EXPORT_SYMBOL_GPL(tpm_get_random); /** * tpm_seal_trusted() - seal a trusted key * @chip_num: A specific chip number for the request or TPM_ANY_NUM * @options: authentication values and other options * @payload: the key data in clear and encrypted form * * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips * are supported. */ int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, struct trusted_key_options *options) { struct tpm_chip *chip; int rc; chip = tpm_chip_find_get(chip_num); if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_seal_trusted(chip, payload, options); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_seal_trusted); /** * tpm_unseal_trusted() - unseal a trusted key * @chip_num: A specific chip number for the request or TPM_ANY_NUM * @options: authentication values and other options * @payload: the key data in clear and encrypted form * * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips * are supported. */ int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, struct trusted_key_options *options) { struct tpm_chip *chip; int rc; chip = tpm_chip_find_get(chip_num); if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_unseal_trusted(chip, payload, options); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_unseal_trusted); static int __init tpm_init(void) { int rc; tpm_class = class_create(THIS_MODULE, "tpm"); if (IS_ERR(tpm_class)) { pr_err("couldn't create tpm class\n"); return PTR_ERR(tpm_class); } rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); if (rc < 0) { pr_err("tpm: failed to allocate char dev region\n"); class_destroy(tpm_class); return rc; } return 0; } static void __exit tpm_exit(void) { idr_destroy(&dev_nums_idr); class_destroy(tpm_class); unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); }
ssize_t tpm_common_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; int ret = 0; if (size > TPM_BUFSIZE) return -E2BIG; mutex_lock(&priv->buffer_mutex); /* Cannot perform a write until the read has cleared either via * tpm_read or a user_read_timer timeout. This also prevents split * buffered writes from blocking here. */ if ((!priv->response_read && priv->response_length) || priv->command_enqueued) { ret = -EBUSY; goto out; } if (copy_from_user(priv->data_buffer, buf, size)) { ret = -EFAULT; goto out; } if (size < 6 || size < be32_to_cpu(*((__be32 *)(priv->data_buffer + 2)))) { ret = -EINVAL; goto out; } /* atomic tpm command send and result receive. We only hold the ops * lock during this period so that the tpm can be unregistered even if * the char dev is held open. */ if (tpm_try_get_ops(priv->chip)) { ret = -EPIPE; goto out; } priv->response_length = 0; priv->response_read = false; *off = 0; /* * If in nonblocking mode schedule an async job to send * the command return the size. * In case of error the err code will be returned in * the subsequent read call. */ if (file->f_flags & O_NONBLOCK) { priv->command_enqueued = true; queue_work(tpm_dev_wq, &priv->async_work); mutex_unlock(&priv->buffer_mutex); return size; } 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; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); ret = size; } out: mutex_unlock(&priv->buffer_mutex); return ret; }