diff options
25 files changed, 2519 insertions, 212 deletions
diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml index 3ab4434b7352..af7720dc4a12 100644 --- a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml +++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml @@ -32,6 +32,7 @@ properties: - enum: - infineon,slb9673 - nuvoton,npct75x + - st,st33ktpm2xi2c - const: tcg,tpm-tis-i2c - description: TPM 1.2 and 2.0 chips with vendor-specific I²C interface diff --git a/Documentation/security/tpm/index.rst b/Documentation/security/tpm/index.rst index fc40e9f23c85..fa593d960040 100644 --- a/Documentation/security/tpm/index.rst +++ b/Documentation/security/tpm/index.rst @@ -5,6 +5,8 @@ Trusted Platform Module documentation .. toctree:: tpm_event_log + tpm-security + tpm_tis tpm_vtpm_proxy xen-tpmfront tpm_ftpm_tee diff --git a/Documentation/security/tpm/tpm-security.rst b/Documentation/security/tpm/tpm-security.rst new file mode 100644 index 000000000000..4f633f251033 --- /dev/null +++ b/Documentation/security/tpm/tpm-security.rst @@ -0,0 +1,216 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +TPM Security +============ + +The object of this document is to describe how we make the kernel's +use of the TPM reasonably robust in the face of external snooping and +packet alteration attacks (called passive and active interposer attack +in the literature). The current security document is for TPM 2.0. + +Introduction +------------ + +The TPM is usually a discrete chip attached to a PC via some type of +low bandwidth bus. There are exceptions to this such as the Intel +PTT, which is a software TPM running inside a software environment +close to the CPU, which are subject to different attacks, but right at +the moment, most hardened security environments require a discrete +hardware TPM, which is the use case discussed here. + +Snooping and Alteration Attacks against the bus +----------------------------------------------- + +The current state of the art for snooping the `TPM Genie`_ hardware +interposer which is a simple external device that can be installed in +a couple of seconds on any system or laptop. Recently attacks were +successfully demonstrated against the `Windows Bitlocker TPM`_ system. +Most recently the same `attack against TPM based Linux disk +encryption`_ schemes. The next phase of research seems to be hacking +existing devices on the bus to act as interposers, so the fact that +the attacker requires physical access for a few seconds might +evaporate. However, the goal of this document is to protect TPM +secrets and integrity as far as we are able in this environment and to +try to insure that if we can't prevent the attack then at least we can +detect it. + +Unfortunately, most of the TPM functionality, including the hardware +reset capability can be controlled by an attacker who has access to +the bus, so we'll discuss some of the disruption possibilities below. + +Measurement (PCR) Integrity +--------------------------- + +Since the attacker can send their own commands to the TPM, they can +send arbitrary PCR extends and thus disrupt the measurement system, +which would be an annoying denial of service attack. However, there +are two, more serious, classes of attack aimed at entities sealed to +trust measurements. + +1. The attacker could intercept all PCR extends coming from the system + and completely substitute their own values, producing a replay of + an untampered state that would cause PCR measurements to attest to + a trusted state and release secrets + +2. At some point in time the attacker could reset the TPM, clearing + the PCRs and then send down their own measurements which would + effectively overwrite the boot time measurements the TPM has + already done. + +The first can be thwarted by always doing HMAC protection of the PCR +extend and read command meaning measurement values cannot be +substituted without producing a detectable HMAC failure in the +response. However, the second can only really be detected by relying +on some sort of mechanism for protection which would change over TPM +reset. + +Secrets Guarding +---------------- + +Certain information passing in and out of the TPM, such as key sealing +and private key import and random number generation, is vulnerable to +interception which HMAC protection alone cannot protect against, so +for these types of command we must also employ request and response +encryption to prevent the loss of secret information. + +Establishing Initial Trust with the TPM +--------------------------------------- + +In order to provide security from the beginning, an initial shared or +asymmetric secret must be established which must also be unknown to +the attacker. The most obvious avenues for this are the endorsement +and storage seeds, which can be used to derive asymmetric keys. +However, using these keys is difficult because the only way to pass +them into the kernel would be on the command line, which requires +extensive support in the boot system, and there's no guarantee that +either hierarchy would not have some type of authorization. + +The mechanism chosen for the Linux Kernel is to derive the primary +elliptic curve key from the null seed using the standard storage seed +parameters. The null seed has two advantages: firstly the hierarchy +physically cannot have an authorization, so we are always able to use +it and secondly, the null seed changes across TPM resets, meaning if +we establish trust on the null seed at start of day, all sessions +salted with the derived key will fail if the TPM is reset and the seed +changes. + +Obviously using the null seed without any other prior shared secrets, +we have to create and read the initial public key which could, of +course, be intercepted and substituted by the bus interposer. +However, the TPM has a key certification mechanism (using the EK +endorsement certificate, creating an attestation identity key and +certifying the null seed primary with that key) which is too complex +to run within the kernel, so we keep a copy of the null primary key +name, which is what is exported via sysfs so user-space can run the +full certification when it boots. The definitive guarantee here is +that if the null primary key certifies correctly, you know all your +TPM transactions since start of day were secure and if it doesn't, you +know there's an interposer on your system (and that any secret used +during boot may have been leaked). + +Stacking Trust +-------------- + +In the current null primary scenario, the TPM must be completely +cleared before handing it on to the next consumer. However the kernel +hands to user-space the name of the derived null seed key which can +then be verified by certification in user-space. Therefore, this chain +of name handoff can be used between the various boot components as +well (via an unspecified mechanism). For instance, grub could use the +null seed scheme for security and hand the name off to the kernel in +the boot area. The kernel could make its own derivation of the key +and the name and know definitively that if they differ from the handed +off version that tampering has occurred. Thus it becomes possible to +chain arbitrary boot components together (UEFI to grub to kernel) via +the name handoff provided each successive component knows how to +collect the name and verifies it against its derived key. + +Session Properties +------------------ + +All TPM commands the kernel uses allow sessions. HMAC sessions may be +used to check the integrity of requests and responses and decrypt and +encrypt flags may be used to shield parameters and responses. The +HMAC and encryption keys are usually derived from the shared +authorization secret, but for a lot of kernel operations that is well +known (and usually empty). Thus, every HMAC session used by the +kernel must be created using the null primary key as the salt key +which thus provides a cryptographic input into the session key +derivation. Thus, the kernel creates the null primary key once (as a +volatile TPM handle) and keeps it around in a saved context stored in +tpm_chip for every in-kernel use of the TPM. Currently, because of a +lack of de-gapping in the in-kernel resource manager, the session must +be created and destroyed for each operation, but, in future, a single +session may also be reused for the in-kernel HMAC, encryption and +decryption sessions. + +Protection Types +---------------- + +For every in-kernel operation we use null primary salted HMAC to +protect the integrity. Additionally, we use parameter encryption to +protect key sealing and parameter decryption to protect key unsealing +and random number generation. + +Null Primary Key Certification in Userspace +=========================================== + +Every TPM comes shipped with a couple of X.509 certificates for the +primary endorsement key. This document assumes that the Elliptic +Curve version of the certificate exists at 01C00002, but will work +equally well with the RSA certificate (at 01C00001). + +The first step in the certification is primary creation using the +template from the `TCG EK Credential Profile`_ which allows comparison +of the generated primary key against the one in the certificate (the +public key must match). Note that generation of the EK primary +requires the EK hierarchy password, but a pre-generated version of the +EC primary should exist at 81010002 and a TPM2_ReadPublic() may be +performed on this without needing the key authority. Next, the +certificate itself must be verified to chain back to the manufacturer +root (which should be published on the manufacturer website). Once +this is done, an attestation key (AK) is generated within the TPM and +it's name and the EK public key can be used to encrypt a secret using +TPM2_MakeCredential. The TPM then runs TPM2_ActivateCredential which +will only recover the secret if the binding between the TPM, the EK +and the AK is true. the generated AK may now be used to run a +certification of the null primary key whose name the kernel has +exported. Since TPM2_MakeCredential/ActivateCredential are somewhat +complicated, a more simplified process involving an externally +generated private key is described below. + +This process is a simplified abbreviation of the usual privacy CA +based attestation process. The assumption here is that the +attestation is done by the TPM owner who thus has access to only the +owner hierarchy. The owner creates an external public/private key +pair (assume elliptic curve in this case) and wraps the private key +for import using an inner wrapping process and parented to the EC +derived storage primary. The TPM2_Import() is done using a parameter +decryption HMAC session salted to the EK primary (which also does not +require the EK key authority) meaning that the inner wrapping key is +the encrypted parameter and thus the TPM will not be able to perform +the import unless is possesses the certified EK so if the command +succeeds and the HMAC verifies on return we know we have a loadable +copy of the private key only for the certified TPM. This key is now +loaded into the TPM and the Storage primary flushed (to free up space +for the null key generation). + +The null EC primary is now generated using the Storage profile +outlined in the `TCG TPM v2.0 Provisioning Guidance`_; the name of +this key (the hash of the public area) is computed and compared to the +null seed name presented by the kernel in +/sys/class/tpm/tpm0/null_name. If the names do not match, the TPM is +compromised. If the names match, the user performs a TPM2_Certify() +using the null primary as the object handle and the loaded private key +as the sign handle and providing randomized qualifying data. The +signature of the returned certifyInfo is verified against the public +part of the loaded private key and the qualifying data checked to +prevent replay. If all of these tests pass, the user is now assured +that TPM integrity and privacy was preserved across the entire boot +sequence of this kernel. + +.. _TPM Genie: https://www.nccgroup.trust/globalassets/about-us/us/documents/tpm-genie.pdf +.. _Windows Bitlocker TPM: https://dolosgroup.io/blog/2021/7/9/from-stolen-laptop-to-inside-the-company-network +.. _attack against TPM based Linux disk encryption: https://www.secura.com/blog/tpm-sniffing-attacks-against-non-bitlocker-targets +.. _TCG EK Credential Profile: https://trustedcomputinggroup.org/resource/tcg-ek-credential-profile-for-tpm-family-2-0/ +.. _TCG TPM v2.0 Provisioning Guidance: https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance/ diff --git a/Documentation/security/tpm/tpm_tis.rst b/Documentation/security/tpm/tpm_tis.rst new file mode 100644 index 000000000000..b9637f295638 --- /dev/null +++ b/Documentation/security/tpm/tpm_tis.rst @@ -0,0 +1,46 @@ +.. 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/ diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 927088b2c3d3..e63a6a17793c 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -27,6 +27,20 @@ menuconfig 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 bool "TPM HW Random Number Generator support" depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m) @@ -149,6 +163,7 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" depends on PPC64 || HAS_IOPORT_MAP + depends on HAS_IOPORT help If you have a TPM security chip from Atmel say Yes and it will be accessible from within Linux. To compile this driver @@ -156,7 +171,7 @@ config TCG_ATMEL config TCG_INFINEON tristate "Infineon Technologies TPM Interface" - depends on PNP + depends on PNP || COMPILE_TEST help 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 diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 0222b1ddb310..4c695b0388f3 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -15,7 +15,9 @@ tpm-y += tpm-sysfs.o tpm-y += eventlog/common.o tpm-y += eventlog/tpm1.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_EFI) += eventlog/efi.o tpm-$(CONFIG_OF) += eventlog/of.o diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c index bd757d836c5c..69533d0bfb51 100644 --- a/drivers/char/tpm/eventlog/acpi.c +++ b/drivers/char/tpm/eventlog/acpi.c @@ -142,7 +142,6 @@ int tpm_read_log_acpi(struct tpm_chip *chip) log->bios_event_log_end = log->bios_event_log + len; - ret = -EIO; virt = acpi_os_map_iomem(start, len); if (!virt) { dev_warn(&chip->dev, "%s: Failed to map ACPI memory\n", __func__); diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c new file mode 100644 index 000000000000..647c6ca92ac3 --- /dev/null +++ b/drivers/char/tpm/tpm-buf.c @@ -0,0 +1,252 @@ +// 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]; +} diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 42b1062e33cd..854546000c92 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -158,6 +158,9 @@ int tpm_try_get_ops(struct tpm_chip *chip) { int rc = -EIO; + if (chip->flags & TPM_CHIP_FLAG_DISABLE) + return rc; + get_device(&chip->dev); down_read(&chip->ops_sem); @@ -275,6 +278,9 @@ static void tpm_dev_release(struct device *dev) kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); kfree(chip->allocated_banks); +#ifdef CONFIG_TCG_TPM2_HMAC + kfree(chip->auth); +#endif kfree(chip); } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 757336324c90..5da134f12c9a 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -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) return -EFAULT; + buf->length = len; return 0; } EXPORT_SYMBOL_GPL(tpm_transmit_cmd); @@ -342,31 +343,6 @@ out: } 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 rc; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 54c71473aa29..94231f052ea7 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -309,6 +309,21 @@ static ssize_t tpm_version_major_show(struct device *dev, } 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[] = { &dev_attr_pubek.attr, &dev_attr_pcrs.attr, @@ -326,6 +341,9 @@ static struct attribute *tpm1_dev_attrs[] = { static struct attribute *tpm2_dev_attrs[] = { &dev_attr_tpm_version_major.attr, +#ifdef CONFIG_TCG_TPM2_HMAC + &dev_attr_null_name.attr, +#endif NULL }; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 61445f1dc46d..6b8b9956ba69 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -312,9 +312,23 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf, size_t *bufsiz); int tpm_devs_add(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_teardown(struct tpm_chip *chip); int tpm_dev_common_init(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 diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 93545be190a5..0cdf892ec2a7 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -216,13 +216,6 @@ out: 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 * @@ -236,24 +229,22 @@ 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; - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); + rc = tpm2_start_auth_session(chip); if (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); - auth_area.nonce_size = 0; - auth_area.attributes = 0; - auth_area.auth_size = 0; + tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 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); for (i = 0; i < chip->nr_allocated_banks; i++) { @@ -262,7 +253,9 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, 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_buf_check_hmac_response(chip, &buf, rc); tpm_buf_destroy(&buf); @@ -299,25 +292,35 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, siz |
