Commit 659aaf2bb5496a425ba14036b5b5900f593e4484

Authored by Rajiv Andrade
Committed by James Morris
1 parent 0883743825

TPM: integrity interface

This patch adds internal kernel support for:
 - reading/extending a pcr value
 - looking up the tpm_chip for a given chip number

Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>

Showing 3 changed files with 163 additions and 19 deletions Side-by-side Diff

drivers/char/tpm/tpm.c
... ... @@ -661,28 +661,125 @@
661 661 }
662 662 EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
663 663  
664   -static const u8 pcrread[] = {
665   - 0, 193, /* TPM_TAG_RQU_COMMAND */
666   - 0, 0, 0, 14, /* length */
667   - 0, 0, 0, 21, /* TPM_ORD_PcrRead */
668   - 0, 0, 0, 0 /* PCR index */
  664 +/*
  665 + * tpm_chip_find_get - return tpm_chip for given chip number
  666 + */
  667 +static struct tpm_chip *tpm_chip_find_get(int chip_num)
  668 +{
  669 + struct tpm_chip *pos;
  670 +
  671 + rcu_read_lock();
  672 + list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
  673 + if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
  674 + continue;
  675 +
  676 + if (try_module_get(pos->dev->driver->owner))
  677 + break;
  678 + }
  679 + rcu_read_unlock();
  680 + return pos;
  681 +}
  682 +
  683 +#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
  684 +#define READ_PCR_RESULT_SIZE 30
  685 +static struct tpm_input_header pcrread_header = {
  686 + .tag = TPM_TAG_RQU_COMMAND,
  687 + .length = cpu_to_be32(14),
  688 + .ordinal = TPM_ORDINAL_PCRREAD
669 689 };
670 690  
  691 +int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
  692 +{
  693 + int rc;
  694 + struct tpm_cmd_t cmd;
  695 +
  696 + cmd.header.in = pcrread_header;
  697 + cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
  698 + BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
  699 + rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
  700 + "attempting to read a pcr value");
  701 +
  702 + if (rc == 0)
  703 + memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
  704 + TPM_DIGEST_SIZE);
  705 + return rc;
  706 +}
  707 +
  708 +/**
  709 + * tpm_pcr_read - read a pcr value
  710 + * @chip_num: tpm idx # or ANY
  711 + * @pcr_idx: pcr idx to retrieve
  712 + * @res_buf: TPM_PCR value
  713 + * size of res_buf is 20 bytes (or NULL if you don't care)
  714 + *
  715 + * The TPM driver should be built-in, but for whatever reason it
  716 + * isn't, protect against the chip disappearing, by incrementing
  717 + * the module usage count.
  718 + */
  719 +int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
  720 +{
  721 + struct tpm_chip *chip;
  722 + int rc;
  723 +
  724 + chip = tpm_chip_find_get(chip_num);
  725 + if (chip == NULL)
  726 + return -ENODEV;
  727 + rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
  728 + module_put(chip->dev->driver->owner);
  729 + return rc;
  730 +}
  731 +EXPORT_SYMBOL_GPL(tpm_pcr_read);
  732 +
  733 +/**
  734 + * tpm_pcr_extend - extend pcr value with hash
  735 + * @chip_num: tpm idx # or AN&
  736 + * @pcr_idx: pcr idx to extend
  737 + * @hash: hash value used to extend pcr value
  738 + *
  739 + * The TPM driver should be built-in, but for whatever reason it
  740 + * isn't, protect against the chip disappearing, by incrementing
  741 + * the module usage count.
  742 + */
  743 +#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
  744 +#define EXTEND_PCR_SIZE 34
  745 +static struct tpm_input_header pcrextend_header = {
  746 + .tag = TPM_TAG_RQU_COMMAND,
  747 + .length = cpu_to_be32(34),
  748 + .ordinal = TPM_ORD_PCR_EXTEND
  749 +};
  750 +
  751 +int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
  752 +{
  753 + struct tpm_cmd_t cmd;
  754 + int rc;
  755 + struct tpm_chip *chip;
  756 +
  757 + chip = tpm_chip_find_get(chip_num);
  758 + if (chip == NULL)
  759 + return -ENODEV;
  760 +
  761 + cmd.header.in = pcrextend_header;
  762 + BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE);
  763 + cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
  764 + memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
  765 + rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
  766 + "attempting extend a PCR value");
  767 +
  768 + module_put(chip->dev->driver->owner);
  769 + return rc;
  770 +}
  771 +EXPORT_SYMBOL_GPL(tpm_pcr_extend);
  772 +
671 773 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
672 774 char *buf)
673 775 {
674 776 cap_t cap;
675   - u8 *data;
  777 + u8 digest[TPM_DIGEST_SIZE];
676 778 ssize_t rc;
677 779 int i, j, num_pcrs;
678   - __be32 index;
679 780 char *str = buf;
680 781 struct tpm_chip *chip = dev_get_drvdata(dev);
681 782  
682   - data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
683   - if (!data)
684   - return -ENOMEM;
685   -
686 783 rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
687 784 "attempting to determine the number of PCRS");
688 785 if (rc)
689 786  
690 787  
... ... @@ -690,20 +787,14 @@
690 787  
691 788 num_pcrs = be32_to_cpu(cap.num_pcrs);
692 789 for (i = 0; i < num_pcrs; i++) {
693   - memcpy(data, pcrread, sizeof(pcrread));
694   - index = cpu_to_be32(i);
695   - memcpy(data + 10, &index, 4);
696   - rc = transmit_cmd(chip, (struct tpm_cmd_t *)data,
697   - TPM_INTERNAL_RESULT_SIZE,
698   - "attempting to read a PCR");
  790 + rc = __tpm_pcr_read(chip, i, digest);
699 791 if (rc)
700 792 break;
701 793 str += sprintf(str, "PCR-%02d: ", i);
702 794 for (j = 0; j < TPM_DIGEST_SIZE; j++)
703   - str += sprintf(str, "%02X ", *(data + 10 + j));
  795 + str += sprintf(str, "%02X ", digest[j]);
704 796 str += sprintf(str, "\n");
705 797 }
706   - kfree(data);
707 798 return str - buf;
708 799 }
709 800 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
drivers/char/tpm/tpm.h
... ... @@ -26,6 +26,7 @@
26 26 #include <linux/miscdevice.h>
27 27 #include <linux/platform_device.h>
28 28 #include <linux/io.h>
  29 +#include <linux/tpm.h>
29 30  
30 31 enum tpm_timeout {
31 32 TPM_TIMEOUT = 5, /* msecs */
32 33  
... ... @@ -234,11 +235,28 @@
234 235 struct tpm_output_header out;
235 236 } tpm_cmd_header;
236 237  
  238 +#define TPM_DIGEST_SIZE 20
  239 +struct tpm_pcrread_out {
  240 + u8 pcr_result[TPM_DIGEST_SIZE];
  241 +}__attribute__((packed));
  242 +
  243 +struct tpm_pcrread_in {
  244 + __be32 pcr_idx;
  245 +}__attribute__((packed));
  246 +
  247 +struct tpm_pcrextend_in {
  248 + __be32 pcr_idx;
  249 + u8 hash[TPM_DIGEST_SIZE];
  250 +}__attribute__((packed));
  251 +
237 252 typedef union {
238 253 struct tpm_getcap_params_out getcap_out;
239 254 struct tpm_readpubek_params_out readpubek_out;
240 255 u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
241 256 struct tpm_getcap_params_in getcap_in;
  257 + struct tpm_pcrread_in pcrread_in;
  258 + struct tpm_pcrread_out pcrread_out;
  259 + struct tpm_pcrextend_in pcrextend_in;
242 260 } tpm_cmd_params;
243 261  
244 262 struct tpm_cmd_t {
  1 +/*
  2 + * Copyright (C) 2004,2007,2008 IBM Corporation
  3 + *
  4 + * Authors:
  5 + * Leendert van Doorn <leendert@watson.ibm.com>
  6 + * Dave Safford <safford@watson.ibm.com>
  7 + * Reiner Sailer <sailer@watson.ibm.com>
  8 + * Kylene Hall <kjhall@us.ibm.com>
  9 + * Debora Velarde <dvelarde@us.ibm.com>
  10 + *
  11 + * Maintained by: <tpmdd_devel@lists.sourceforge.net>
  12 + *
  13 + * Device driver for TCG/TCPA TPM (trusted platform module).
  14 + * Specifications at www.trustedcomputinggroup.org
  15 + *
  16 + * This program is free software; you can redistribute it and/or
  17 + * modify it under the terms of the GNU General Public License as
  18 + * published by the Free Software Foundation, version 2 of the
  19 + * License.
  20 + *
  21 + */
  22 +#ifndef __LINUX_TPM_H__
  23 +#define __LINUX_TPM_H__
  24 +
  25 +/*
  26 + * Chip num is this value or a valid tpm idx
  27 + */
  28 +#define TPM_ANY_NUM 0xFFFF
  29 +
  30 +#if defined(CONFIG_TCG_TPM)
  31 +
  32 +extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
  33 +extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
  34 +#endif
  35 +#endif