diff options
author | Rajiv Andrade <srajiv@linux.vnet.ibm.com> | 2009-02-02 12:23:44 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-02-02 19:23:12 -0500 |
commit | 659aaf2bb5496a425ba14036b5b5900f593e4484 (patch) | |
tree | a9736fc70c8837665bc0f0a375dab5382941d77a /drivers/char/tpm | |
parent | 0883743825e34b81f3ff78aaee3a97cba57586c5 (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.c | 129 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 18 |
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 | } |
662 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | 662 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); |
663 | 663 | ||
664 | static 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 */ | 667 | static 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 | ||
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 | ||
689 | }; | ||
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 | ||
669 | }; | 749 | }; |
670 | 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 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 773 | ssize_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 | } |
709 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | 800 | EXPORT_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 | ||
30 | enum tpm_timeout { | 31 | enum 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 | ||
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 | typedef union { | 252 | typedef 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 | ||
244 | struct tpm_cmd_t { | 262 | struct tpm_cmd_t { |