Commit b1923914 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tpmdd-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull TPM updates from Jarkko Sakkinen:
 "These are the changes for the TPM driver with a single major new
  feature: TPM bus encryption and integrity protection. The key pair on
  TPM side is generated from so called null random seed per power on of
  the machine [1]. This supports the TPM encryption of the hard drive by
  adding layer of protection against bus interposer attacks.

  Other than that, a few minor fixes and documentation for tpm_tis to
  clarify basics of TPM localities for future patch review discussions
  (will be extended and refined over times, just a seed)"

Link: https://lore.kernel.org/linux-integrity/20240429202811.13643-1-James.Bottomley@HansenPartnership.com/ [1]

* tag 'tpmdd-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd: (28 commits)
  Documentation: tpm: Add TPM security docs toctree entry
  tpm: disable the TPM if NULL name changes
  Documentation: add tpm-security.rst
  tpm: add the null key name as a sysfs export
  KEYS: trusted: Add session encryption protection to the seal/unseal path
  tpm: add session encryption protection to tpm2_get_random()
  tpm: add hmac checks to tpm2_pcr_extend()
  tpm: Add the rest of the session HMAC API
  tpm: Add HMAC session name/handle append
  tpm: Add HMAC session start and end functions
  tpm: Add TCG mandated Key Derivation Functions (KDFs)
  tpm: Add NULL primary creation
  tpm: export the context save and load commands
  tpm: add buffer function to point to returned parameters
  crypto: lib - implement library version of AES in CFB mode
  KEYS: trusted: tpm2: Use struct tpm_buf for sized buffers
  tpm: Add tpm_buf_read_{u8,u16,u32}
  tpm: TPM2B formatted buffers
  tpm: Store the length of the tpm_buf data separately.
  tpm: Update struct tpm_buf documentation comments
  ...
parents c0248148 1d479e3c
...@@ -32,6 +32,7 @@ properties: ...@@ -32,6 +32,7 @@ properties:
- enum: - enum:
- infineon,slb9673 - infineon,slb9673
- nuvoton,npct75x - nuvoton,npct75x
- st,st33ktpm2xi2c
- const: tcg,tpm-tis-i2c - const: tcg,tpm-tis-i2c
- description: TPM 1.2 and 2.0 chips with vendor-specific I²C interface - description: TPM 1.2 and 2.0 chips with vendor-specific I²C interface
......
...@@ -5,6 +5,8 @@ Trusted Platform Module documentation ...@@ -5,6 +5,8 @@ Trusted Platform Module documentation
.. toctree:: .. toctree::
tpm_event_log tpm_event_log
tpm-security
tpm_tis
tpm_vtpm_proxy tpm_vtpm_proxy
xen-tpmfront xen-tpmfront
tpm_ftpm_tee tpm_ftpm_tee
This diff is collapsed.
.. SPDX-License-Identifier: GPL-2.0
=========================
TPM FIFO interface driver
=========================
TCG PTP Specification defines two interface types: FIFO and CRB. The former is
based on sequenced read and write operations, and the latter is based on a
buffer containing the full command or response.
FIFO (First-In-First-Out) interface is used by the tpm_tis_core dependent
drivers. Originally Linux had only a driver called tpm_tis, which covered
memory mapped (aka MMIO) interface but it was later on extended to cover other
physical interfaces supported by the TCG standard.
For historical reasons above the original MMIO driver is called tpm_tis and the
framework for FIFO drivers is named as tpm_tis_core. The postfix "tis" in
tpm_tis comes from the TPM Interface Specification, which is the hardware
interface specification for TPM 1.x chips.
Communication is based on a 20 KiB buffer shared by the TPM chip through a
hardware bus or memory map, depending on the physical wiring. The buffer is
further split into five equal-size 4 KiB buffers, which provide equivalent
sets of registers for communication between the CPU and TPM. These
communication endpoints are called localities in the TCG terminology.
When the kernel wants to send commands to the TPM chip, it first reserves
locality 0 by setting the requestUse bit in the TPM_ACCESS register. The bit is
cleared by the chip when the access is granted. Once it completes its
communication, the kernel writes the TPM_ACCESS.activeLocality bit. This
informs the chip that the locality has been relinquished.
Pending localities are served in order by the chip in descending order, one at
a time:
- Locality 0 has the lowest priority.
- Locality 5 has the highest priority.
Further information on the purpose and meaning of the localities can be found
in section 3.2 of the TCG PC Client Platform TPM Profile Specification.
References
==========
TCG PC Client Platform TPM Profile (PTP) Specification
https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
...@@ -27,6 +27,20 @@ menuconfig TCG_TPM ...@@ -27,6 +27,20 @@ menuconfig TCG_TPM
if TCG_TPM if TCG_TPM
config TCG_TPM2_HMAC
bool "Use HMAC and encrypted transactions on the TPM bus"
default y
select CRYPTO_ECDH
select CRYPTO_LIB_AESCFB
select CRYPTO_LIB_SHA256
help
Setting this causes us to deploy a scheme which uses request
and response HMACs in addition to encryption for
communicating with the TPM to prevent or detect bus snooping
and interposer attacks (see tpm-security.rst). Saying Y
here adds some encryption overhead to all kernel to TPM
transactions.
config HW_RANDOM_TPM config HW_RANDOM_TPM
bool "TPM HW Random Number Generator support" bool "TPM HW Random Number Generator support"
depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m) depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m)
...@@ -149,6 +163,7 @@ config TCG_NSC ...@@ -149,6 +163,7 @@ config TCG_NSC
config TCG_ATMEL config TCG_ATMEL
tristate "Atmel TPM Interface" tristate "Atmel TPM Interface"
depends on PPC64 || HAS_IOPORT_MAP depends on PPC64 || HAS_IOPORT_MAP
depends on HAS_IOPORT
help help
If you have a TPM security chip from Atmel say Yes and it If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver will be accessible from within Linux. To compile this driver
...@@ -156,7 +171,7 @@ config TCG_ATMEL ...@@ -156,7 +171,7 @@ config TCG_ATMEL
config TCG_INFINEON config TCG_INFINEON
tristate "Infineon Technologies TPM Interface" tristate "Infineon Technologies TPM Interface"
depends on PNP depends on PNP || COMPILE_TEST
help help
If you have a TPM security chip from Infineon Technologies If you have a TPM security chip from Infineon Technologies
(either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it
......
...@@ -15,7 +15,9 @@ tpm-y += tpm-sysfs.o ...@@ -15,7 +15,9 @@ tpm-y += tpm-sysfs.o
tpm-y += eventlog/common.o tpm-y += eventlog/common.o
tpm-y += eventlog/tpm1.o tpm-y += eventlog/tpm1.o
tpm-y += eventlog/tpm2.o tpm-y += eventlog/tpm2.o
tpm-y += tpm-buf.o
tpm-$(CONFIG_TCG_TPM2_HMAC) += tpm2-sessions.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
tpm-$(CONFIG_EFI) += eventlog/efi.o tpm-$(CONFIG_EFI) += eventlog/efi.o
tpm-$(CONFIG_OF) += eventlog/of.o tpm-$(CONFIG_OF) += eventlog/of.o
......
...@@ -142,7 +142,6 @@ int tpm_read_log_acpi(struct tpm_chip *chip) ...@@ -142,7 +142,6 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
log->bios_event_log_end = log->bios_event_log + len; log->bios_event_log_end = log->bios_event_log + len;
ret = -EIO;
virt = acpi_os_map_iomem(start, len); virt = acpi_os_map_iomem(start, len);
if (!virt) { if (!virt) {
dev_warn(&chip->dev, "%s: Failed to map ACPI memory\n", __func__); dev_warn(&chip->dev, "%s: Failed to map ACPI memory\n", __func__);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Handling of TPM command and other buffers.
*/
#include <linux/tpm_command.h>
#include <linux/module.h>
#include <linux/tpm.h>
/**
* tpm_buf_init() - Allocate and initialize a TPM command
* @buf: A &tpm_buf
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*
* Return: 0 or -ENOMEM
*/
int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
if (!buf->data)
return -ENOMEM;
tpm_buf_reset(buf, tag, ordinal);
return 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_init);
/**
* tpm_buf_reset() - Initialize a TPM command
* @buf: A &tpm_buf
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*/
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
tag != TPM2_ST_SESSIONS && tag != 0);
buf->flags = 0;
buf->length = sizeof(*head);
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
buf->handles = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset);
/**
* tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
* @buf: A @tpm_buf
*
* Return: 0 or -ENOMEM
*/
int tpm_buf_init_sized(struct tpm_buf *buf)
{
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
if (!buf->data)
return -ENOMEM;
tpm_buf_reset_sized(buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
/**
* tpm_buf_reset_sized() - Initialize a sized buffer
* @buf: A &tpm_buf
*/
void tpm_buf_reset_sized(struct tpm_buf *buf)
{
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
buf->data[0] = 0;
buf->data[1] = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
void tpm_buf_destroy(struct tpm_buf *buf)
{
free_page((unsigned long)buf->data);
}
EXPORT_SYMBOL_GPL(tpm_buf_destroy);
/**
* tpm_buf_length() - Return the number of bytes consumed by the data
* @buf: A &tpm_buf
*
* Return: The number of bytes consumed by the buffer
*/
u32 tpm_buf_length(struct tpm_buf *buf)
{
return buf->length;
}
EXPORT_SYMBOL_GPL(tpm_buf_length);
/**
* tpm_buf_append() - Append data to an initialized buffer
* @buf: A &tpm_buf
* @new_data: A data blob
* @new_length: Size of the appended data
*/
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
{
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_OVERFLOW)
return;
if ((buf->length + new_length) > PAGE_SIZE) {
WARN(1, "tpm_buf: write overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
}
memcpy(&buf->data[buf->length], new_data, new_length);
buf->length += new_length;
if (buf->flags & TPM_BUF_TPM2B)
((__be16 *)buf->data)[0] = cpu_to_be16(buf->length - 2);
else
((struct tpm_header *)buf->data)->length = cpu_to_be32(buf->length);
}
EXPORT_SYMBOL_GPL(tpm_buf_append);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
{
tpm_buf_append(buf, &value, 1);
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u8);
void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
{
__be16 value2 = cpu_to_be16(value);
tpm_buf_append(buf, (u8 *)&value2, 2);
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u16);
void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
{
__be32 value2 = cpu_to_be32(value);
tpm_buf_append(buf, (u8 *)&value2, 4);
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
/**
* tpm_buf_read() - Read from a TPM buffer
* @buf: &tpm_buf instance
* @offset: offset within the buffer
* @count: the number of bytes to read
* @output: the output buffer
*/
static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count, void *output)
{
off_t next_offset;
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_BOUNDARY_ERROR)
return;
next_offset = *offset + count;
if (next_offset > buf->length) {
WARN(1, "tpm_buf: read out of boundary\n");
buf->flags |= TPM_BUF_BOUNDARY_ERROR;
return;
}
memcpy(output, &buf->data[*offset], count);
*offset = next_offset;
}
/**
* tpm_buf_read_u8() - Read 8-bit word from a TPM buffer
* @buf: &tpm_buf instance
* @offset: offset within the buffer
*
* Return: next 8-bit word
*/
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset)
{
u8 value;
tpm_buf_read(buf, offset, sizeof(value), &value);
return value;
}
EXPORT_SYMBOL_GPL(tpm_buf_read_u8);
/**
* tpm_buf_read_u16() - Read 16-bit word from a TPM buffer
* @buf: &tpm_buf instance
* @offset: offset within the buffer
*
* Return: next 16-bit word
*/
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset)
{
u16 value;
tpm_buf_read(buf, offset, sizeof(value), &value);
return be16_to_cpu(value);
}
EXPORT_SYMBOL_GPL(tpm_buf_read_u16);
/**
* tpm_buf_read_u32() - Read 32-bit word from a TPM buffer
* @buf: &tpm_buf instance
* @offset: offset within the buffer
*
* Return: next 32-bit word
*/
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
{
u32 value;
tpm_buf_read(buf, offset, sizeof(value), &value);
return be32_to_cpu(value);
}
EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
static u16 tpm_buf_tag(struct tpm_buf *buf)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
return be16_to_cpu(head->tag);
}
/**
* tpm_buf_parameters - return the TPM response parameters area of the tpm_buf
* @buf: tpm_buf to use
*
* Where the parameters are located depends on the tag of a TPM
* command (it's immediately after the header for TPM_ST_NO_SESSIONS
* or 4 bytes after for TPM_ST_SESSIONS). Evaluate this and return a
* pointer to the first byte of the parameters area.
*
* @return: pointer to parameters area
*/
u8 *tpm_buf_parameters(struct tpm_buf *buf)
{
int offset = TPM_HEADER_SIZE;
if (tpm_buf_tag(buf) == TPM2_ST_SESSIONS)
offset += 4;
return &buf->data[offset];
}
...@@ -158,6 +158,9 @@ int tpm_try_get_ops(struct tpm_chip *chip) ...@@ -158,6 +158,9 @@ int tpm_try_get_ops(struct tpm_chip *chip)
{ {
int rc = -EIO; int rc = -EIO;
if (chip->flags & TPM_CHIP_FLAG_DISABLE)
return rc;
get_device(&chip->dev); get_device(&chip->dev);
down_read(&chip->ops_sem); down_read(&chip->ops_sem);
...@@ -275,6 +278,9 @@ static void tpm_dev_release(struct device *dev) ...@@ -275,6 +278,9 @@ static void tpm_dev_release(struct device *dev)
kfree(chip->work_space.context_buf); kfree(chip->work_space.context_buf);
kfree(chip->work_space.session_buf); kfree(chip->work_space.session_buf);
kfree(chip->allocated_banks); kfree(chip->allocated_banks);
#ifdef CONFIG_TCG_TPM2_HMAC
kfree(chip->auth);
#endif
kfree(chip); kfree(chip);
} }
......
...@@ -232,6 +232,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, ...@@ -232,6 +232,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
if (len < min_rsp_body_length + TPM_HEADER_SIZE) if (len < min_rsp_body_length + TPM_HEADER_SIZE)
return -EFAULT; return -EFAULT;
buf->length = len;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(tpm_transmit_cmd); EXPORT_SYMBOL_GPL(tpm_transmit_cmd);
...@@ -342,31 +343,6 @@ int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, ...@@ -342,31 +343,6 @@ int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
} }
EXPORT_SYMBOL_GPL(tpm_pcr_extend); EXPORT_SYMBOL_GPL(tpm_pcr_extend);
/**
* 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;
buf.data = cmd;
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command");
tpm_put_ops(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_send);
int tpm_auto_startup(struct tpm_chip *chip) int tpm_auto_startup(struct tpm_chip *chip)
{ {
int rc; int rc;
......
...@@ -309,6 +309,21 @@ static ssize_t tpm_version_major_show(struct device *dev, ...@@ -309,6 +309,21 @@ static ssize_t tpm_version_major_show(struct device *dev,
} }
static DEVICE_ATTR_RO(tpm_version_major); static DEVICE_ATTR_RO(tpm_version_major);
#ifdef CONFIG_TCG_TPM2_HMAC
static ssize_t null_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
int size = TPM2_NAME_SIZE;
bin2hex(buf, chip->null_key_name, size);
size *= 2;
buf[size++] = '\n';
return size;
}
static DEVICE_ATTR_RO(null_name);
#endif
static struct attribute *tpm1_dev_attrs[] = { static struct attribute *tpm1_dev_attrs[] = {
&dev_attr_pubek.attr, &dev_attr_pubek.attr,
&dev_attr_pcrs.attr, &dev_attr_pcrs.attr,
...@@ -326,6 +341,9 @@ static struct attribute *tpm1_dev_attrs[] = { ...@@ -326,6 +341,9 @@ static struct attribute *tpm1_dev_attrs[] = {
static struct attribute *tpm2_dev_attrs[] = { static struct attribute *tpm2_dev_attrs[] = {
&dev_attr_tpm_version_major.attr, &dev_attr_tpm_version_major.attr,
#ifdef CONFIG_TCG_TPM2_HMAC
&dev_attr_null_name.attr,
#endif
NULL NULL
}; };
......
...@@ -312,9 +312,23 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf, ...@@ -312,9 +312,23 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
size_t *bufsiz); size_t *bufsiz);
int tpm_devs_add(struct tpm_chip *chip); int tpm_devs_add(struct tpm_chip *chip);
void tpm_devs_remove(struct tpm_chip *chip); void tpm_devs_remove(struct tpm_chip *chip);
int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset);
int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle);
void tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_setup(struct tpm_chip *chip);
void tpm_bios_log_teardown(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip);
int tpm_dev_common_init(void); int tpm_dev_common_init(void);
void tpm_dev_common_exit(void); void tpm_dev_common_exit(void);
#ifdef CONFIG_TCG_TPM2_HMAC
int tpm2_sessions_init(struct tpm_chip *chip);
#else
static inline int tpm2_sessions_init(struct tpm_chip *chip)
{
return 0;
}
#endif
#endif #endif
...@@ -216,13 +216,6 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, ...@@ -216,13 +216,6 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
return rc; return rc;
} }
struct tpm2_null_auth_area {
__be32 handle;
__be16 nonce_size;
u8 attributes;
__be16 auth_size;
} __packed;
/** /**
* tpm2_pcr_extend() - extend a PCR value * tpm2_pcr_extend() - extend a PCR value
* *
...@@ -236,24 +229,22 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, ...@@ -236,24 +229,22 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests) struct tpm_digest *digests)
{ {
struct tpm_buf buf; struct tpm_buf buf;
struct tpm2_null_auth_area auth_area;
int rc; int rc;
int i; int i;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); rc = tpm2_start_auth_session(chip);
if (rc) if (rc)
return rc; return rc;
tpm_buf_append_u32(&buf, pcr_idx); rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc) {
tpm2_end_auth_session(chip);
return rc;
}
auth_area.handle = cpu_to_be32(TPM2_RS_PW); tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
auth_area.nonce_size = 0; tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
auth_area.attributes = 0;
auth_area.auth_size = 0;
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, chip->nr_allocated_banks); tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) { for (i = 0; i < chip->nr_allocated_banks; i++) {
...@@ -262,7 +253,9 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, ...@@ -262,7 +253,9 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
chip->allocated_banks[i].digest_size); chip->allocated_banks[i].digest_size);
} }
tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
...@@ -299,25 +292,35 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) ...@@ -299,25 +292,35 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
if (!num_bytes || max > TPM_MAX_RNG_DATA) if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL; return -EINVAL;
err = tpm_buf_init(&buf, 0, 0); err = tpm2_start_auth_session(chip);
if (err) if (err)
return err; return err;
err = tpm_buf_init(&buf, 0, 0);
if (err) {
tpm2_end_auth_session(chip);
return err;
}
do { do {
tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM); tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
| TPM2_SA_CONTINUE_SESSION,
NULL, 0);
tpm_buf_append_u16(&buf, num_bytes); tpm_buf_append_u16(&buf, num_bytes);
tpm_buf_fill_hmac_session(chip, &buf);
err = tpm_transmit_cmd(chip, &buf, err = tpm_transmit_cmd(chip, &buf,
offsetof(struct tpm2_get_random_out, offsetof(struct tpm2_get_random_out,
buffer), buffer),
"attempting get random"); "attempting get random");
err = tpm_buf_check_hmac_response(chip, &buf, err);
if (err) { if (err) {
if (err > 0) if (err > 0)
err = -EIO; err = -EIO;
goto out; goto out;
} }
out = (struct tpm2_get_random_out *) out = (struct tpm2_get_random_out *)tpm_buf_parameters(&buf);
&buf.data[TPM_HEADER_SIZE];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes); recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
if (tpm_buf_length(&buf) < if (tpm_buf_length(&buf) <
TPM_HEADER_SIZE + TPM_HEADER_SIZE +
...@@ -334,9 +337,12 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) ...@@ -334,9 +337,12 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
} while (retries-- && total < max); } while (retries-- && total < max);
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return total ? total : -EIO; return total ? total : -EIO;
out: out:
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return err; return err;
} }
...@@ -759,6 +765,11 @@ int tpm2_auto_startup(struct tpm_chip *chip) ...@@ -759,6 +765,11 @@ int tpm2_auto_startup(struct tpm_chip *chip)
rc = 0; rc = 0;
} }
if (rc)
goto out;
rc = tpm2_sessions_init(chip);
out: out:
/* /*
* Infineon TPM in field upgrade mode will return no data for the number * Infineon TPM in field upgrade mode will return no data for the number
......
This diff is collapsed.
...@@ -68,8 +68,8 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) ...@@ -68,8 +68,8 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
kfree(space->session_buf); kfree(space->session_buf);
} }
static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle) unsigned int *offset, u32 *handle)
{ {
struct tpm_buf tbuf; struct tpm_buf tbuf;
struct tpm2_context *ctx; struct tpm2_context *ctx;
...@@ -105,6 +105,9 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, ...@@ -105,6 +105,9 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
*handle = 0; *handle = 0;
tpm_buf_destroy(&tbuf); tpm_buf_destroy(&tbuf);
return -ENOENT; return -ENOENT;
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
tpm_buf_destroy(&tbuf);
return -EINVAL;
} else if (rc > 0) { } else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc); __func__, rc);
...@@ -119,8 +122,8 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, ...@@ -119,8 +122,8 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
return 0; return 0;
} }
static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset) unsigned int buf_size, unsigned int *offset)
{ {
struct tpm_buf tbuf; struct tpm_buf tbuf;
unsigned int body_size; unsigned int body_size;
......
...@@ -51,34 +51,40 @@ static struct tpm_inf_dev tpm_dev; ...@@ -51,34 +51,40 @@ static struct tpm_inf_dev tpm_dev;
static inline void tpm_data_out(unsigned char data, unsigned char offset) static inline void tpm_data_out(unsigned char data, unsigned char offset)
{ {
#ifdef CONFIG_HAS_IOPORT
if (tpm_dev.iotype == TPM_INF_IO_PORT) if (tpm_dev.iotype == TPM_INF_IO_PORT)
outb(data, tpm_dev.data_regs + offset); outb(data, tpm_dev.data_regs + offset);
else else
#endif
writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset); writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
} }
static inline unsigned char tpm_data_in(unsigned char offset) static inline unsigned char tpm_data_in(unsigned char offset)
{ {
#ifdef CONFIG_HAS_IOPORT
if (tpm_dev.iotype == TPM_INF_IO_PORT) if (tpm_dev.iotype == TPM_INF_IO_PORT)
return inb(tpm_dev.data_regs + offset); return inb(tpm_dev.data_regs + offset);
else #endif
return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
} }
static inline void tpm_config_out(unsigned char data, unsigned char offset) static inline void tpm_config_out(unsigned char data, unsigned char offset)
{ {
#ifdef CONFIG_HAS_IOPORT
if (tpm_dev.iotype == TPM_INF_IO_PORT) if (tpm_dev.iotype == TPM_INF_IO_PORT)
outb(data, tpm_dev.config_port + offset); outb(data, tpm_dev.config_port + offset);
else else
#endif
writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset); writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
} }
static inline unsigned char tpm_config_in(unsigned char offset) static inline unsigned char tpm_config_in(unsigned char offset)
{ {
#ifdef CONFIG_HAS_IOPORT
if (tpm_dev.iotype == TPM_INF_IO_PORT) if (tpm_dev.iotype == TPM_INF_IO_PORT)
return inb(tpm_dev.config_port + offset); return inb(tpm_dev.config_port + offset);
else #endif
return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
} }
/* TPM header definitions */ /* TPM header definitions */
......
...@@ -1057,11 +1057,6 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) ...@@ -1057,11 +1057,6 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value)
clkrun_val &= ~LPC_CLKRUN_EN; clkrun_val &= ~LPC_CLKRUN_EN;
iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
} else { } else {
data->clkrun_enabled--; data->clkrun_enabled--;
if (data->clkrun_enabled) if (data->clkrun_enabled)
...@@ -1072,13 +1067,15 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) ...@@ -1072,13 +1067,15 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value)
/* Enable LPC CLKRUN# */ /* Enable LPC CLKRUN# */
clkrun_val |= LPC_CLKRUN_EN; clkrun_val |= LPC_CLKRUN_EN;
iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
} }
#ifdef CONFIG_HAS_IOPORT
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
#endif
} }
static const struct tpm_class_ops tpm_tis = { static const struct tpm_class_ops tpm_tis = {
......
...@@ -87,4 +87,9 @@ void aes_decrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in); ...@@ -87,4 +87,9 @@ void aes_decrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in);
extern const u8 crypto_aes_sbox[]; extern const u8 crypto_aes_sbox[];
extern const u8 crypto_aes_inv_sbox[]; extern const u8 crypto_aes_inv_sbox[];
void aescfb_encrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE]);
void aescfb_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE]);
#endif #endif
...@@ -6,8 +6,6 @@ ...@@ -6,8 +6,6 @@
#include <linux/tpm_command.h> #include <linux/tpm_command.h>
/* implementation specific TPM constants */ /* implementation specific TPM constants */
#define MAX_BUF_SIZE 1024
#define TPM_GETRANDOM_SIZE 14
#define TPM_SIZE_OFFSET 2 #define TPM_SIZE_OFFSET 2
#define TPM_RETURN_OFFSET 6 #define TPM_RETURN_OFFSET 6
#define TPM_DATA_OFFSET 10 #define TPM_DATA_OFFSET 10
......
This diff is collapsed.
...@@ -8,6 +8,11 @@ config CRYPTO_LIB_UTILS ...@@ -8,6 +8,11 @@ config CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES config CRYPTO_LIB_AES
tristate tristate
config CRYPTO_LIB_AESCFB
tristate
select CRYPTO_LIB_AES
select CRYPTO_LIB_UTILS
config CRYPTO_LIB_AESGCM config CRYPTO_LIB_AESGCM
tristate tristate
select CRYPTO_LIB_AES select CRYPTO_LIB_AES
......
...@@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_LIB_CHACHA_GENERIC) += libchacha.o ...@@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_LIB_CHACHA_GENERIC) += libchacha.o
obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o
libaes-y := aes.o libaes-y := aes.o
obj-$(CONFIG_CRYPTO_LIB_AESCFB) += libaescfb.o
libaescfb-y := aescfb.o
obj-$(CONFIG_CRYPTO_LIB_AESGCM) += libaesgcm.o obj-$(CONFIG_CRYPTO_LIB_AESGCM) += libaesgcm.o
libaesgcm-y := aesgcm.o libaesgcm-y := aesgcm.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Minimal library implementation of AES in CFB mode
*
* Copyright 2023 Google LLC
*/
#include <linux/module.h>
#include <crypto/algapi.h>
#include <crypto/aes.h>
#include <asm/irqflags.h>
static void aescfb_encrypt_block(const struct crypto_aes_ctx *ctx, void *dst,
const void *src)
{
unsigned long flags;
/*
* In AES-CFB, the AES encryption operates on known 'plaintext' (the IV
* and ciphertext), making it susceptible to timing attacks on the
* encryption key. The AES library already mitigates this risk to some
* extent by pulling the entire S-box into the caches before doing any
* substitutions, but this strategy is more effective when running with
* interrupts disabled.
*/
local_irq_save(flags);
aes_encrypt(ctx, dst, src);
local_irq_restore(flags);
}
/**
* aescfb_encrypt - Perform AES-CFB encryption on a block of data
*
* @ctx: The AES-CFB key schedule
* @dst: Pointer to the ciphertext output buffer
* @src: Pointer the plaintext (may equal @dst for encryption in place)
* @len: The size in bytes of the plaintext and ciphertext.
* @iv: The initialization vector (IV) to use for this block of data
*/
void aescfb_encrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE])
{
u8 ks[AES_BLOCK_SIZE];
const u8 *v = iv;
while (len > 0) {
aescfb_encrypt_block(ctx, ks, v);
crypto_xor_cpy(dst, src, ks, min(len, AES_BLOCK_SIZE));
v = dst;
dst += AES_BLOCK_SIZE;
src += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
}
memzero_explicit(ks, sizeof(ks));
}
EXPORT_SYMBOL(aescfb_encrypt);
/**
* aescfb_decrypt - Perform AES-CFB decryption on a block of data
*
* @ctx: The AES-CFB key schedule
* @dst: Pointer to the plaintext output buffer
* @src: Pointer the ciphertext (may equal @dst for decryption in place)
* @len: The size in bytes of the plaintext and ciphertext.
* @iv: The initialization vector (IV) to use for this block of data
*/
void aescfb_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE])
{
u8 ks[2][AES_BLOCK_SIZE];
aescfb_encrypt_block(ctx, ks[0], iv);
for (int i = 0; len > 0; i ^= 1) {
if (len > AES_BLOCK_SIZE)
/*
* Generate the keystream for the next block before
* performing the XOR, as that may update in place and
* overwrite the ciphertext.
*/
aescfb_encrypt_block(ctx, ks[!i], src);
crypto_xor_cpy(dst, src, ks[i], min(len, AES_BLOCK_SIZE));
dst += AES_BLOCK_SIZE;
src += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
}
memzero_explicit(ks, sizeof(ks));
}
EXPORT_SYMBOL(aescfb_decrypt);
MODULE_DESCRIPTION("Generic AES-CFB library");
MODULE_AUTHOR("Ard Biesheuvel <ardb@kernel.org>");
MODULE_LICENSE("GPL");
#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
/*
* Test code below. Vectors taken from crypto/testmgr.h
*/
static struct {
u8 ptext[64];
u8 ctext[64];
u8 key[AES_MAX_KEY_SIZE];
u8 iv[AES_BLOCK_SIZE];
int klen;
int len;
} const aescfb_tv[] __initconst = {
{ /* From NIST SP800-38A */
.key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
.klen = 16,
.iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
.ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
"\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
"\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f"
"\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b"
"\x26\x75\x1f\x67\xa3\xcb\xb1\x40"
"\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf"
"\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e"
"\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6",
.len = 64,
}, {
.key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
"\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
"\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
.klen = 24,
.iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
.ctext = "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab"
"\x34\xc2\x59\x09\xc9\x9a\x41\x74"
"\x67\xce\x7f\x7f\x81\x17\x36\x21"
"\x96\x1a\x2b\x70\x17\x1d\x3d\x7a"
"\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1"
"\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9"
"\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0"
"\x42\xae\x8f\xba\x58\x4b\x09\xff",
.len = 64,
}, {
.key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
.klen = 32,
.iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
.ctext = "\xdc\x7e\x84\xbf\xda\x79\x16\x4b"
"\x7e\xcd\x84\x86\x98\x5d\x38\x60"
"\x39\xff\xed\x14\x3b\x28\xb1\xc8"
"\x32\x11\x3c\x63\x31\xe5\x40\x7b"
"\xdf\x10\x13\x24\x15\xe5\x4b\x92"
"\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9"
"\x75\xa3\x85\x74\x1a\xb9\xce\xf8"
"\x20\x31\x62\x3d\x55\xb1\xe4\x71",
.len = 64,
}, { /* > 16 bytes, not a multiple of 16 bytes */
.key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
.klen = 16,
.iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
"\xae",
.ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
"\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
"\xc8",
.len = 17,
}, { /* < 16 bytes */
.key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
.klen = 16,
.iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f",
.ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad",
.len = 7,
},
};
static int __init libaescfb_init(void)
{
for (int i = 0; i < ARRAY_SIZE(aescfb_tv); i++) {
struct crypto_aes_ctx ctx;
u8 buf[64];
if (aes_expandkey(&ctx, aescfb_tv[i].key, aescfb_tv[i].klen)) {
pr_err("aes_expandkey() failed on vector %d\n", i);
return -ENODEV;
}
aescfb_encrypt(&ctx, buf, aescfb_tv[i].ptext, aescfb_tv[i].len,
aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
pr_err("aescfb_encrypt() #1 failed on vector %d\n", i);
return -ENODEV;
}
/* decrypt in place */
aescfb_decrypt(&ctx, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ptext, aescfb_tv[i].len)) {
pr_err("aescfb_decrypt() failed on vector %d\n", i);
return -ENODEV;
}
/* encrypt in place */
aescfb_encrypt(&ctx, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
pr_err("aescfb_encrypt() #2 failed on vector %d\n", i);
return -ENODEV;
}
}
return 0;
}
module_init(libaescfb_init);
static void __exit libaescfb_exit(void)
{
}
module_exit(libaescfb_exit);
#endif
...@@ -356,17 +356,28 @@ static int TSS_checkhmac2(unsigned char *buffer, ...@@ -356,17 +356,28 @@ static int TSS_checkhmac2(unsigned char *buffer,
*/ */
int trusted_tpm_send(unsigned char *cmd, size_t buflen) int trusted_tpm_send(unsigned char *cmd, size_t buflen)
{ {
struct tpm_buf buf;
int rc; int rc;
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
buf.flags = 0;
buf.length = buflen;
buf.data = cmd;
dump_tpm_buf(cmd); dump_tpm_buf(cmd);
rc = tpm_send(chip, cmd, buflen); rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
dump_tpm_buf(cmd); dump_tpm_buf(cmd);
if (rc > 0) if (rc > 0)
/* Can't return positive return codes values to keyctl */ /* TPM error */
rc = -EPERM; rc = -EPERM;
tpm_put_ops(chip);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(trusted_tpm_send); EXPORT_SYMBOL_GPL(trusted_tpm_send);
...@@ -407,7 +418,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, ...@@ -407,7 +418,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
tpm_buf_append_u32(tb, handle); tpm_buf_append_u32(tb, handle);
tpm_buf_append(tb, ononce, TPM_NONCE_SIZE); tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -431,7 +442,7 @@ int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) ...@@ -431,7 +442,7 @@ int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
return -ENODEV; return -ENODEV;
tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP); tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -543,7 +554,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, ...@@ -543,7 +554,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
tpm_buf_append_u8(tb, cont); tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE); tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -634,7 +645,7 @@ static int tpm_unseal(struct tpm_buf *tb, ...@@ -634,7 +645,7 @@ static int tpm_unseal(struct tpm_buf *tb,
tpm_buf_append_u8(tb, cont); tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE); tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0) { if (ret < 0) {
pr_info("authhmac failed (%d)\n", ret); pr_info("authhmac failed (%d)\n", ret);
return ret; return ret;
......
...@@ -228,8 +228,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -228,8 +228,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload, struct trusted_key_payload *payload,
struct trusted_key_options *options) struct trusted_key_options *options)
{ {
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
int blob_len = 0; int blob_len = 0;
struct tpm_buf buf;
u32 hash; u32 hash;
u32 flags; u32 flags;
int i; int i;
...@@ -252,50 +253,58 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -252,50 +253,58 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc) if (rc)
return rc; return rc;
rc = tpm2_start_auth_session(chip);
if (rc)
goto out_put;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
if (rc) { if (rc) {
tpm_put_ops(chip); tpm2_end_auth_session(chip);
return rc; goto out_put;
} }
tpm_buf_append_u32(&buf, options->keyhandle); rc = tpm_buf_init_sized(&sized);
tpm2_buf_append_auth(&buf, TPM2_RS_PW, if (rc) {
NULL /* nonce */, 0, tpm_buf_destroy(&buf);
0 /* session_attributes */, tpm2_end_auth_session(chip);
options->keyauth /* hmac */, goto out_put;
TPM_DIGEST_SIZE); }
tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
options->keyauth, TPM_DIGEST_SIZE);
/* sensitive */ /* sensitive */
tpm_buf_append_u16(&buf, 4 + options->blobauth_len + payload->key_len); tpm_buf_append_u16(&sized, options->blobauth_len);
tpm_buf_append_u16(&buf, options->blobauth_len);
if (options->blobauth_len) if (options->blobauth_len)
tpm_buf_append(&buf, options->blobauth, options->blobauth_len); tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
tpm_buf_append_u16(&buf, payload->key_len); tpm_buf_append_u16(&sized, payload->key_len);
tpm_buf_append(&buf, payload->key, payload->key_len); tpm_buf_append(&sized, payload->key, payload->key_len);
tpm_buf_append(&buf, sized.data, sized.length);
/* public */ /* public */
tpm_buf_append_u16(&buf, 14 + options->policydigest_len); tpm_buf_reset_sized(&sized);
tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH); tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
tpm_buf_append_u16(&buf, hash); tpm_buf_append_u16(&sized, hash);
/* key properties */ /* key properties */
flags = 0; flags = 0;
flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH; flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
TPM2_OA_FIXED_PARENT); tpm_buf_append_u32(&sized, flags);
tpm_buf_append_u32(&buf, flags);
/* policy */ /* policy */
tpm_buf_append_u16(&buf, options->policydigest_len); tpm_buf_append_u16(&sized, options->policydigest_len);
if (options->policydigest_len) if (options->policydigest_len)
tpm_buf_append(&buf, options->policydigest, tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
options->policydigest_len);
/* public parameters */ /* public parameters */
tpm_buf_append_u16(&buf, TPM_ALG_NULL); tpm_buf_append_u16(&sized, TPM_ALG_NULL);
tpm_buf_append_u16(&buf, 0); tpm_buf_append_u16(&sized, 0);
tpm_buf_append(&buf, sized.data, sized.length);
/* outside info */ /* outside info */
tpm_buf_append_u16(&buf, 0); tpm_buf_append_u16(&buf, 0);
...@@ -305,28 +314,30 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -305,28 +314,30 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (buf.flags & TPM_BUF_OVERFLOW) { if (buf.flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG; rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out; goto out;
} }
tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data"); rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
if (rc) if (rc)
goto out; goto out;
blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]); blob_len = tpm_buf_read_u32(&buf, &offset);
if (blob_len > MAX_BLOB_SIZE) { if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
rc = -E2BIG; rc = -E2BIG;
goto out; goto out;
} }
if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) { if (buf.length - offset < blob_len) {
rc = -EFAULT; rc = -EFAULT;
goto out; goto out;
} }
blob_len = tpm2_key_encode(payload, options, blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
&buf.data[TPM_HEADER_SIZE + 4],
blob_len);
out: out:
tpm_buf_destroy(&sized);
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
if (rc > 0) { if (rc > 0) {
...@@ -340,6 +351,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -340,6 +351,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
else else
payload->blob_len = blob_len; payload->blob_len = blob_len;
out_put:
tpm_put_ops(chip); tpm_put_ops(chip);
return rc; return rc;
} }
...@@ -409,25 +421,31 @@ static int tpm2_load_cmd(struct tpm_chip *chip, ...@@ -409,25 +421,31 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (blob_len > payload->blob_len) if (blob_len > payload->blob_len)
return -E2BIG; return -E2BIG;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD); rc = tpm2_start_auth_session(chip);
if (rc) if (rc)
return rc; return rc;
tpm_buf_append_u32(&buf, options->keyhandle); rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
tpm2_buf_append_auth(&buf, TPM2_RS_PW, if (rc) {
NULL /* nonce */, 0, tpm2_end_auth_session(chip);
0 /* session_attributes */, return rc;
options->keyauth /* hmac */, }
TPM_DIGEST_SIZE);
tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
TPM_DIGEST_SIZE);
tpm_buf_append(&buf, blob, blob_len); tpm_buf_append(&buf, blob, blob_len);
if (buf.flags & TPM_BUF_OVERFLOW) { if (buf.flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG; rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out; goto out;
} }
tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob"); rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
if (!rc) if (!rc)
*blob_handle = be32_to_cpup( *blob_handle = be32_to_cpup(
(__be32 *) &buf.data[TPM_HEADER_SIZE]); (__be32 *) &buf.data[TPM_HEADER_SIZE]);
...@@ -465,20 +483,44 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, ...@@ -465,20 +483,44 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
u8 *data; u8 *data;
int rc; int rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); rc = tpm2_start_auth_session(chip);
if (rc) if (rc)
return rc; return rc;
tpm_buf_append_u32(&buf, blob_handle); rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
tpm2_buf_append_auth(&buf, if (rc) {
options->policyhandle ? tpm2_end_auth_session(chip);
options->policyhandle : TPM2_RS_PW, return rc;
NULL /* nonce */, 0, }
TPM2_SA_CONTINUE_SESSION,
options->blobauth /* hmac */, tpm_buf_append_name(chip, &buf, blob_handle, NULL);
options->blobauth_len);
if (!options->policyhandle) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
options->blobauth,
options->blobauth_len);
} else {
/*
* FIXME: The policy session was generated outside the
* kernel so we don't known the nonce and thus can't
* calculate a HMAC on it. Therefore, the user can
* only really use TPM2_PolicyPassword and we must
* send down the plain text password, which could be
* intercepted. We can still encrypt the returned
* key, but that's small comfort since the interposer
* could repeat our actions with the exfiltrated
* password.
*/
tpm2_buf_append_auth(&buf, options->policyhandle,
NULL /* nonce */, 0, 0,
options->blobauth, options->blobauth_len);
tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,
NULL, 0);
}
tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
if (rc > 0) if (rc > 0)
rc = -EPERM; rc = -EPERM;
......
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