aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorRajiv Andrade <srajiv@linux.vnet.ibm.com>2009-02-02 12:23:44 -0500
committerJames Morris <jmorris@namei.org>2009-02-02 19:23:12 -0500
commit659aaf2bb5496a425ba14036b5b5900f593e4484 (patch)
treea9736fc70c8837665bc0f0a375dab5382941d77a /drivers/char/tpm
parent0883743825e34b81f3ff78aaee3a97cba57586c5 (diff)
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>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r--drivers/char/tpm/tpm.c129
-rw-r--r--drivers/char/tpm/tpm.h18
2 files changed, 128 insertions, 19 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 9b9eb761cba9..62a5682578ca 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -661,28 +661,125 @@ ssize_t tpm_show_temp_deactivated(struct device * dev,
661} 661}
662EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); 662EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
663 663
664static const u8 pcrread[] = { 664/*
665 0, 193, /* TPM_TAG_RQU_COMMAND */ 665 * tpm_chip_find_get - return tpm_chip for given chip number
666 0, 0, 0, 14, /* length */ 666 */
667 0, 0, 0, 21, /* TPM_ORD_PcrRead */ 667static struct tpm_chip *tpm_chip_find_get(int chip_num)
668 0, 0, 0, 0 /* PCR index */ 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
685static struct tpm_input_header pcrread_header = {
686 .tag = TPM_TAG_RQU_COMMAND,
687 .length = cpu_to_be32(14),
688 .ordinal = TPM_ORDINAL_PCRREAD
689};
690
691int __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 */
719int 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}
731EXPORT_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
745static struct tpm_input_header pcrextend_header = {
746 .tag = TPM_TAG_RQU_COMMAND,
747 .length = cpu_to_be32(34),
748 .ordinal = TPM_ORD_PCR_EXTEND
669}; 749};
670 750
751int 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}
771EXPORT_SYMBOL_GPL(tpm_pcr_extend);
772
671ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, 773ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
672 char *buf) 774 char *buf)
673{ 775{
674 cap_t cap; 776 cap_t cap;
675 u8 *data; 777 u8 digest[TPM_DIGEST_SIZE];
676 ssize_t rc; 778 ssize_t rc;
677 int i, j, num_pcrs; 779 int i, j, num_pcrs;
678 __be32 index;
679 char *str = buf; 780 char *str = buf;
680 struct tpm_chip *chip = dev_get_drvdata(dev); 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 rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, 783 rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
687 "attempting to determine the number of PCRS"); 784 "attempting to determine the number of PCRS");
688 if (rc) 785 if (rc)
@@ -690,20 +787,14 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
690 787
691 num_pcrs = be32_to_cpu(cap.num_pcrs); 788 num_pcrs = be32_to_cpu(cap.num_pcrs);
692 for (i = 0; i < num_pcrs; i++) { 789 for (i = 0; i < num_pcrs; i++) {
693 memcpy(data, pcrread, sizeof(pcrread)); 790 rc = __tpm_pcr_read(chip, i, digest);
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");
699 if (rc) 791 if (rc)
700 break; 792 break;
701 str += sprintf(str, "PCR-%02d: ", i); 793 str += sprintf(str, "PCR-%02d: ", i);
702 for (j = 0; j < TPM_DIGEST_SIZE; j++) 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 str += sprintf(str, "\n"); 796 str += sprintf(str, "\n");
705 } 797 }
706 kfree(data);
707 return str - buf; 798 return str - buf;
708} 799}
709EXPORT_SYMBOL_GPL(tpm_show_pcrs); 800EXPORT_SYMBOL_GPL(tpm_show_pcrs);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index d64f6b7e5b82..8e00b4ddd083 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -26,6 +26,7 @@
26#include <linux/miscdevice.h> 26#include <linux/miscdevice.h>
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/tpm.h>
29 30
30enum tpm_timeout { 31enum tpm_timeout {
31 TPM_TIMEOUT = 5, /* msecs */ 32 TPM_TIMEOUT = 5, /* msecs */
@@ -234,11 +235,28 @@ typedef union {
234 struct tpm_output_header out; 235 struct tpm_output_header out;
235} tpm_cmd_header; 236} tpm_cmd_header;
236 237
238#define TPM_DIGEST_SIZE 20
239struct tpm_pcrread_out {
240 u8 pcr_result[TPM_DIGEST_SIZE];
241}__attribute__((packed));
242
243struct tpm_pcrread_in {
244 __be32 pcr_idx;
245}__attribute__((packed));
246
247struct tpm_pcrextend_in {
248 __be32 pcr_idx;
249 u8 hash[TPM_DIGEST_SIZE];
250}__attribute__((packed));
251
237typedef union { 252typedef union {
238 struct tpm_getcap_params_out getcap_out; 253 struct tpm_getcap_params_out getcap_out;
239 struct tpm_readpubek_params_out readpubek_out; 254 struct tpm_readpubek_params_out readpubek_out;
240 u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; 255 u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
241 struct tpm_getcap_params_in getcap_in; 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} tpm_cmd_params; 260} tpm_cmd_params;
243 261
244struct tpm_cmd_t { 262struct tpm_cmd_t {