* [PATCH v7 1/2] tpm: implement TPM 2.0 capability to get active PCR banks
2017-01-30 9:59 [PATCH v7 0/2] enhance TPM 2.0 extend function to support multiple PCR banks Nayna Jain
@ 2017-01-30 9:59 ` Nayna Jain
2017-01-30 9:59 ` [PATCH v7 2/2] tpm: enhance TPM 2.0 PCR extend to support multiple banks Nayna Jain
1 sibling, 0 replies; 3+ messages in thread
From: Nayna Jain @ 2017-01-30 9:59 UTC (permalink / raw)
To: tpmdd-devel
Cc: peterhuewe, tpmdd, jarkko.sakkinen, jgunthorpe,
linux-security-module, linux-kernel, Nayna Jain
This patch implements the TPM 2.0 capability TPM_CAP_PCRS to
retrieve the active PCR banks from the TPM. This is needed
to enable extending all active banks as recommended by TPM 2.0
TCG Specification.
Signed-off-by: Nayna Jain <nayna@linux.vnet.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Kenneth Goldman <kgold@linux.vnet.ibm.com>
---
drivers/char/tpm/tpm.h | 5 +++
drivers/char/tpm/tpm2-cmd.c | 77 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index dbe0c5a..db0398a 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -97,6 +97,7 @@ enum tpm2_return_codes {
};
enum tpm2_algorithms {
+ TPM2_ALG_ERROR = 0x0000,
TPM2_ALG_SHA1 = 0x0004,
TPM2_ALG_KEYEDHASH = 0x0008,
TPM2_ALG_SHA256 = 0x000B,
@@ -127,6 +128,7 @@ enum tpm2_permanent_handles {
};
enum tpm2_capabilities {
+ TPM2_CAP_PCRS = 5,
TPM2_CAP_TPM_PROPERTIES = 6,
};
@@ -187,6 +189,8 @@ struct tpm_chip {
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];
@@ -540,4 +544,5 @@ int tpm2_auto_startup(struct tpm_chip *chip);
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm2_probe(struct tpm_chip *chip);
+ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip);
#endif
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 42fe3dd..6fbd42c 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1030,3 +1030,80 @@ int tpm2_auto_startup(struct tpm_chip *chip)
rc = -ENODEV;
return rc;
}
+
+struct tpm2_pcr_selection {
+ __be16 hash_alg;
+ u8 size_of_select;
+ u8 pcr_select[3];
+} __packed;
+
+/**
+ * tpm2_get_pcr_allocation() - get TPM active PCR banks.
+ *
+ * @chip: TPM chip to use.
+ *
+ * Return: Same as with tpm_transmit_cmd.
+ */
+ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
+{
+ struct tpm2_pcr_selection pcr_selection;
+ struct tpm_buf buf;
+ void *marker;
+ void *end;
+ void *pcr_select_offset;
+ unsigned int count;
+ u32 sizeof_pcr_selection;
+ u32 rsp_len;
+ int rc;
+ int i = 0;
+
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ if (rc)
+ return rc;
+
+ tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
+ tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(&buf, 1);
+
+ rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9, 0,
+ "get tpm pcr allocation");
+ if (rc)
+ goto out;
+
+ count = be32_to_cpup(
+ (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
+
+ if (count > ARRAY_SIZE(chip->active_banks)) {
+ rc = -ENODEV;
+ goto out;
+ }
+
+ marker = &buf.data[TPM_HEADER_SIZE + 9];
+
+ rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
+ end = &buf.data[rsp_len];
+
+ for (i = 0; i < count; i++) {
+ pcr_select_offset = marker +
+ offsetof(struct tpm2_pcr_selection, size_of_select);
+ if (pcr_select_offset >= end) {
+ rc = -EFAULT;
+ break;
+ }
+
+ memcpy(&pcr_selection, marker, sizeof(pcr_selection));
+ chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg);
+ sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) +
+ sizeof(pcr_selection.size_of_select) +
+ pcr_selection.size_of_select;
+ marker = marker + sizeof_pcr_selection;
+ }
+
+out:
+ if (i < ARRAY_SIZE(chip->active_banks))
+ chip->active_banks[i] = TPM2_ALG_ERROR;
+
+ tpm_buf_destroy(&buf);
+
+ return rc;
+}
--
2.5.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v7 2/2] tpm: enhance TPM 2.0 PCR extend to support multiple banks
2017-01-30 9:59 [PATCH v7 0/2] enhance TPM 2.0 extend function to support multiple PCR banks Nayna Jain
2017-01-30 9:59 ` [PATCH v7 1/2] tpm: implement TPM 2.0 capability to get active " Nayna Jain
@ 2017-01-30 9:59 ` Nayna Jain
1 sibling, 0 replies; 3+ messages in thread
From: Nayna Jain @ 2017-01-30 9:59 UTC (permalink / raw)
To: tpmdd-devel
Cc: peterhuewe, tpmdd, jarkko.sakkinen, jgunthorpe,
linux-security-module, linux-kernel, Nayna Jain
The current TPM 2.0 device driver extends only the SHA1 PCR bank
but the TCG Specification[1] recommends extending all active PCR
banks, to prevent malicious users from setting unused PCR banks with
fake measurements and quoting them.
The existing in-kernel interface(tpm_pcr_extend()) expects only a
SHA1 digest. To extend all active PCR banks with differing
digest sizes, the SHA1 digest is padded with trailing 0's as needed.
This patch reuses the defined digest sizes from the crypto subsystem,
adding a dependency on CRYPTO_HASH_INFO module.
[1] TPM 2.0 Specification referred here is "TCG PC Client Specific
Platform Firmware Profile for TPM 2.0"
Signed-off-by: Nayna Jain <nayna@linux.vnet.ibm.com>
---
drivers/char/tpm/Kconfig | 1 +
drivers/char/tpm/tpm-interface.c | 15 ++++++-
drivers/char/tpm/tpm.h | 9 +++-
drivers/char/tpm/tpm2-cmd.c | 91 +++++++++++++++++++++-------------------
4 files changed, 72 insertions(+), 44 deletions(-)
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 277186d..af985cc 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -6,6 +6,7 @@ menuconfig TCG_TPM
tristate "TPM Hardware Support"
depends on HAS_IOMEM
select SECURITYFS
+ select CRYPTO_HASH_INFO
---help---
If you have a TPM security chip in your system, which
implements the Trusted Computing Group's specification,
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 2ea16ab..7fa05a9 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -789,13 +789,26 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
struct tpm_cmd_t cmd;
int rc;
struct tpm_chip *chip;
+ int max_active_banks = ARRAY_SIZE(chip->active_banks);
+ struct tpm2_digest digest_list[max_active_banks];
+ u32 count = 0;
+ int i;
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);
+ memset(digest_list, 0, sizeof(digest_list));
+
+ for (i = 0; (chip->active_banks[i] != TPM2_ALG_ERROR) &&
+ (i < max_active_banks); i++) {
+ digest_list[i].alg_id = chip->active_banks[i];
+ memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
+ count++;
+ }
+
+ rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
tpm_put_ops(chip);
return rc;
}
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index db0398a..4b7eca9 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -34,6 +34,7 @@
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/highmem.h>
+#include <crypto/hash_info.h>
#include "tpm_eventlog.h"
@@ -380,6 +381,11 @@ struct tpm_cmd_t {
tpm_cmd_params params;
} __packed;
+struct tpm2_digest {
+ u16 alg_id;
+ u8 digest[SHA512_DIGEST_SIZE];
+} __packed;
+
/* A string buffer type for constructing TPM commands. This is based on the
* ideas of string buffer code in security/keys/trusted.h but is heap based
* in order to keep the stack usage minimal.
@@ -529,7 +535,8 @@ static inline inline u32 tpm2_rc_value(u32 rc)
}
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
-int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
+ struct tpm2_digest *digests);
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 6fbd42c..60042f7 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -53,22 +53,6 @@ struct tpm2_pcr_read_out {
u8 digest[TPM_DIGEST_SIZE];
} __packed;
-struct tpm2_null_auth_area {
- __be32 handle;
- __be16 nonce_size;
- u8 attributes;
- __be16 auth_size;
-} __packed;
-
-struct tpm2_pcr_extend_in {
- __be32 pcr_idx;
- __be32 auth_area_size;
- struct tpm2_null_auth_area auth_area;
- __be32 digest_cnt;
- __be16 hash_alg;
- u8 digest[TPM_DIGEST_SIZE];
-} __packed;
-
struct tpm2_get_tpm_pt_in {
__be32 cap_id;
__be32 property_id;
@@ -97,7 +81,6 @@ union tpm2_cmd_params {
struct tpm2_self_test_in selftest_in;
struct tpm2_pcr_read_in pcrread_in;
struct tpm2_pcr_read_out pcrread_out;
- struct tpm2_pcr_extend_in pcrextend_in;
struct tpm2_get_tpm_pt_in get_tpm_pt_in;
struct tpm2_get_tpm_pt_out get_tpm_pt_out;
struct tpm2_get_random_in getrandom_in;
@@ -294,49 +277,71 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
return rc;
}
-#define TPM2_GET_PCREXTEND_IN_SIZE \
- (sizeof(struct tpm_input_header) + \
- sizeof(struct tpm2_pcr_extend_in))
-
-static const struct tpm_input_header tpm2_pcrextend_header = {
- .tag = cpu_to_be16(TPM2_ST_SESSIONS),
- .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
- .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
-};
+struct tpm2_null_auth_area {
+ __be32 handle;
+ __be16 nonce_size;
+ u8 attributes;
+ __be16 auth_size;
+} __packed;
/**
* tpm2_pcr_extend() - extend a PCR value
*
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR.
- * @hash: hash value to use for the extend operation.
+ * @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, int pcr_idx, const u8 *hash)
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
+ struct tpm2_digest *digests)
{
- struct tpm2_cmd cmd;
+ struct tpm_buf buf;
+ struct tpm2_null_auth_area auth_area;
int rc;
+ int i;
+ int j;
- cmd.header.in = tpm2_pcrextend_header;
- cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
- cmd.params.pcrextend_in.auth_area_size =
- cpu_to_be32(sizeof(struct tpm2_null_auth_area));
- cmd.params.pcrextend_in.auth_area.handle =
- cpu_to_be32(TPM2_RS_PW);
- cmd.params.pcrextend_in.auth_area.nonce_size = 0;
- cmd.params.pcrextend_in.auth_area.attributes = 0;
- cmd.params.pcrextend_in.auth_area.auth_size = 0;
- cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
- cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
- memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
+ if (count > ARRAY_SIZE(chip->active_banks))
+ return -EINVAL;
- rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
+ rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+ if (rc)
+ return rc;
+
+ tpm_buf_append_u32(&buf, pcr_idx);
+
+ 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_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);
+
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
+ if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
+ continue;
+ tpm_buf_append_u16(&buf, digests[i].alg_id);
+ tpm_buf_append(&buf, (const unsigned char
+ *)&digests[i].digest,
+ hash_digest_size[tpm2_hash_map[j].crypto_id]);
+ }
+ }
+
+ rc = tpm_transmit_cmd(chip, buf.data, tpm_buf_length(&buf), 0, 0,
"attempting extend a PCR value");
+ tpm_buf_destroy(&buf);
+
return rc;
}
+
#define TPM2_GETRANDOM_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_get_random_in))
@@ -1025,6 +1030,8 @@ int tpm2_auto_startup(struct tpm_chip *chip)
}
}
+ rc = tpm2_get_pcr_allocation(chip);
+
out:
if (rc > 0)
rc = -ENODEV;
--
2.5.0
^ permalink raw reply [flat|nested] 3+ messages in thread