Commit 659aaf2bb5496a425ba14036b5b5900f593e4484
Committed by
James Morris
1 parent
0883743825
Exists in
master
and in
39 other branches
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 { |
include/linux/tpm.h
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 |