Skip to content

Commit c1f92b4

Browse files
naynajainJarkko Sakkinen
authored andcommitted
tpm: enhance TPM 2.0 PCR extend to support multiple banks
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> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Kenneth Goldman <kgold@linux.vnet.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
1 parent 1db1534 commit c1f92b4

File tree

4 files changed

+71
-44
lines changed

4 files changed

+71
-44
lines changed

drivers/char/tpm/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ menuconfig TCG_TPM
66
tristate "TPM Hardware Support"
77
depends on HAS_IOMEM
88
select SECURITYFS
9+
select CRYPTO_HASH_INFO
910
---help---
1011
If you have a TPM security chip in your system, which
1112
implements the Trusted Computing Group's specification,

drivers/char/tpm/tpm-interface.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,13 +789,25 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
789789
struct tpm_cmd_t cmd;
790790
int rc;
791791
struct tpm_chip *chip;
792+
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
793+
u32 count = 0;
794+
int i;
792795

793796
chip = tpm_chip_find_get(chip_num);
794797
if (chip == NULL)
795798
return -ENODEV;
796799

797800
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
798-
rc = tpm2_pcr_extend(chip, pcr_idx, hash);
801+
memset(digest_list, 0, sizeof(digest_list));
802+
803+
for (i = 0; chip->active_banks[i] != TPM2_ALG_ERROR &&
804+
i < ARRAY_SIZE(chip->active_banks); i++) {
805+
digest_list[i].alg_id = chip->active_banks[i];
806+
memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
807+
count++;
808+
}
809+
810+
rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
799811
tpm_put_ops(chip);
800812
return rc;
801813
}

drivers/char/tpm/tpm.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <linux/acpi.h>
3535
#include <linux/cdev.h>
3636
#include <linux/highmem.h>
37+
#include <crypto/hash_info.h>
3738

3839
#include "tpm_eventlog.h"
3940

@@ -380,6 +381,11 @@ struct tpm_cmd_t {
380381
tpm_cmd_params params;
381382
} __packed;
382383

384+
struct tpm2_digest {
385+
u16 alg_id;
386+
u8 digest[SHA512_DIGEST_SIZE];
387+
} __packed;
388+
383389
/* A string buffer type for constructing TPM commands. This is based on the
384390
* ideas of string buffer code in security/keys/trusted.h but is heap based
385391
* in order to keep the stack usage minimal.
@@ -529,7 +535,8 @@ static inline inline u32 tpm2_rc_value(u32 rc)
529535
}
530536

531537
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
532-
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
538+
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
539+
struct tpm2_digest *digests);
533540
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
534541
int tpm2_seal_trusted(struct tpm_chip *chip,
535542
struct trusted_key_payload *payload,

drivers/char/tpm/tpm2-cmd.c

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,6 @@ struct tpm2_pcr_read_out {
5353
u8 digest[TPM_DIGEST_SIZE];
5454
} __packed;
5555

56-
struct tpm2_null_auth_area {
57-
__be32 handle;
58-
__be16 nonce_size;
59-
u8 attributes;
60-
__be16 auth_size;
61-
} __packed;
62-
63-
struct tpm2_pcr_extend_in {
64-
__be32 pcr_idx;
65-
__be32 auth_area_size;
66-
struct tpm2_null_auth_area auth_area;
67-
__be32 digest_cnt;
68-
__be16 hash_alg;
69-
u8 digest[TPM_DIGEST_SIZE];
70-
} __packed;
71-
7256
struct tpm2_get_tpm_pt_in {
7357
__be32 cap_id;
7458
__be32 property_id;
@@ -97,7 +81,6 @@ union tpm2_cmd_params {
9781
struct tpm2_self_test_in selftest_in;
9882
struct tpm2_pcr_read_in pcrread_in;
9983
struct tpm2_pcr_read_out pcrread_out;
100-
struct tpm2_pcr_extend_in pcrextend_in;
10184
struct tpm2_get_tpm_pt_in get_tpm_pt_in;
10285
struct tpm2_get_tpm_pt_out get_tpm_pt_out;
10386
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)
294277
return rc;
295278
}
296279

297-
#define TPM2_GET_PCREXTEND_IN_SIZE \
298-
(sizeof(struct tpm_input_header) + \
299-
sizeof(struct tpm2_pcr_extend_in))
300-
301-
static const struct tpm_input_header tpm2_pcrextend_header = {
302-
.tag = cpu_to_be16(TPM2_ST_SESSIONS),
303-
.length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
304-
.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
305-
};
280+
struct tpm2_null_auth_area {
281+
__be32 handle;
282+
__be16 nonce_size;
283+
u8 attributes;
284+
__be16 auth_size;
285+
} __packed;
306286

307287
/**
308288
* tpm2_pcr_extend() - extend a PCR value
309289
*
310290
* @chip: TPM chip to use.
311291
* @pcr_idx: index of the PCR.
312-
* @hash: hash value to use for the extend operation.
292+
* @count: number of digests passed.
293+
* @digests: list of pcr banks and corresponding digest values to extend.
313294
*
314295
* Return: Same as with tpm_transmit_cmd.
315296
*/
316-
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
297+
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
298+
struct tpm2_digest *digests)
317299
{
318-
struct tpm2_cmd cmd;
300+
struct tpm_buf buf;
301+
struct tpm2_null_auth_area auth_area;
319302
int rc;
303+
int i;
304+
int j;
320305

321-
cmd.header.in = tpm2_pcrextend_header;
322-
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
323-
cmd.params.pcrextend_in.auth_area_size =
324-
cpu_to_be32(sizeof(struct tpm2_null_auth_area));
325-
cmd.params.pcrextend_in.auth_area.handle =
326-
cpu_to_be32(TPM2_RS_PW);
327-
cmd.params.pcrextend_in.auth_area.nonce_size = 0;
328-
cmd.params.pcrextend_in.auth_area.attributes = 0;
329-
cmd.params.pcrextend_in.auth_area.auth_size = 0;
330-
cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
331-
cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
332-
memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
306+
if (count > ARRAY_SIZE(chip->active_banks))
307+
return -EINVAL;
333308

334-
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
309+
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
310+
if (rc)
311+
return rc;
312+
313+
tpm_buf_append_u32(&buf, pcr_idx);
314+
315+
auth_area.handle = cpu_to_be32(TPM2_RS_PW);
316+
auth_area.nonce_size = 0;
317+
auth_area.attributes = 0;
318+
auth_area.auth_size = 0;
319+
320+
tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
321+
tpm_buf_append(&buf, (const unsigned char *)&auth_area,
322+
sizeof(auth_area));
323+
tpm_buf_append_u32(&buf, count);
324+
325+
for (i = 0; i < count; i++) {
326+
for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
327+
if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
328+
continue;
329+
tpm_buf_append_u16(&buf, digests[i].alg_id);
330+
tpm_buf_append(&buf, (const unsigned char
331+
*)&digests[i].digest,
332+
hash_digest_size[tpm2_hash_map[j].crypto_id]);
333+
}
334+
}
335+
336+
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0,
335337
"attempting extend a PCR value");
336338

339+
tpm_buf_destroy(&buf);
340+
337341
return rc;
338342
}
339343

344+
340345
#define TPM2_GETRANDOM_IN_SIZE \
341346
(sizeof(struct tpm_input_header) + \
342347
sizeof(struct tpm2_get_random_in))
@@ -1025,6 +1030,8 @@ int tpm2_auto_startup(struct tpm_chip *chip)
10251030
}
10261031
}
10271032

1033+
rc = tpm2_get_pcr_allocation(chip);
1034+
10281035
out:
10291036
if (rc > 0)
10301037
rc = -ENODEV;

0 commit comments

Comments
 (0)