Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1636422 > unrolled thread
| Started by | Roberto Sassu <roberto.sassu@huawei.com> |
|---|---|
| First post | 2017-05-05 16:30 +0200 |
| Last post | 2017-05-05 16:30 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v2 0/5] Updated API for TPM 2.0 PCR extend Roberto Sassu <roberto.sassu@huawei.com> - 2017-05-05 16:30 +0200
[PATCH v2 5/5] ima: modify arguments of tpm_pcr_extend() Roberto Sassu <roberto.sassu@huawei.com> - 2017-05-05 16:30 +0200
[PATCH v2 2/5] tpm: introduce tpm_pcr_algo_to_crypto() and tpm_pcr_algo_from_crypto() Roberto Sassu <roberto.sassu@huawei.com> - 2017-05-05 16:30 +0200
| From | Roberto Sassu <roberto.sassu@huawei.com> |
|---|---|
| Date | 2017-05-05 16:30 +0200 |
| Subject | [PATCH v2 0/5] Updated API for TPM 2.0 PCR extend |
| Message-ID | <tDMp3-2VD-3@gated-at.bofh.it> |
The first version of the patch set can be retrieved at the URL:
https://sourceforge.net/p/tpmdd/mailman/message/35756302/
The patches in this set should be applied on top of the patch set
'tpm_pcr_extend() code split', which can be retrieved at the URL:
https://sourceforge.net/p/tpmdd/mailman/message/35820107/
This patch set updates the TPM driver API for extending Platform
Configuration Registers (PCRs). These are special TPM registers which
cannot be written directly, but can only be updated through the extend
operation, by passing a digest as input:
PCR_value_new = hash_func(PCR_value_old | digest)
While TPM 1.2 can only use SHA1 as hash function, TPM 2.0 can support
multiple algorithms. In the second case, PCR values extended with the same
algorithm are stored in a location called bank.
The primary use of the PCR extend operation is to protect the integrity
of measurements (e.g. of kernel, initial ram disk, application binaries),
which can be used by remote verifiers to determine if the software
running on a platform can be trusted to produce the expected outputs.
An example of software performing such measurements is Integrity
Measurement Architecture (IMA), which implements a set of hooks called
each time a subset of system calls, e.g. execve() or open(), is executed.
When IMA performs a measurement, it extends a PCR with the digest of a
measurement event log. The extend operation guarantees that modifications
of the measurements list can always be detected. Since PCRs cannot be
reverted to a previous value, it won't be possible for an attacker to hide
his actions by removing one of the log entries, because remote verifiers
would obtain a different value by replicating the extend operation with
the event log digests.
Currently, PCRs can only be extended from the kernel with a SHA1 digest,
through tpm_pcr_extend(). Remaining banks of a TPM 2.0 are extended with
the SHA1 digest padded with zeros. In order to take advantage of stronger
algorithms, IMA must be able to pass to the TPM driver interface digests
of different lengths. The second requirement comes from the TCG consortium,
which recommends to extend all banks, to prevent attackers from misusing
them. The third requirement is that TPM users should be able to obtain
from the driver interface TPM algorithm IDs, in order to produce an event
log with the format defined by TCG.
This patch set:
1) introduces tpm_pcr_algorithms(), to obtain the IDs of the algorithms
supported by the TPM (TPM2_ALG_SHA1 is returned for TPM 1.2)
2) introduces tpm_pcr_algo_to_crypto() and tpm_pcr_algo_from_crypto() to
convert TPM IDs to crypto IDs (in order to calculate the digest of
an event log with the crypto subsystem), and vice-versa
3) modifies the parameters of tpm_pcr_extend(), to pass multiple digests
4) modifies the callers of tpm_pcr_extend(), to pass the correct arguments:
- pcrlock() in security/keys/trusted.c
- ima_pcr_extend() in security/integrity/ima/ima_queue.c
Given this definition of the tpm2_digest structure:
struct tpm2_digest {
u16 alg_id;
u8 digest[SHA512_DIGEST_SIZE];
} __packed;
these are the two methods to extend PCRs:
1) by passing only one tpm2_digest structure containing a SHA1 digest
(as it is done in the patches 4/5 and 5/5); in this case, the SHA1
digest is padded with zeros (current behavior)
2) by calling tpm_pcr_algorithms() to obtain the algorithms supported by
the TPM, and by calling tpm_pcr_extend() with as many tpm2_digest
structures as the number of algorithms retrieved in the first step
API Usage Examples
In the following examples, an application extends PCR 16 with the digest
of an event (e.g. record of a software measurement), with the methods
described above.
void app_calc_event_digest(struct crypto_shash *tfm, char *event,
u8 *digest)
{
SHASH_DESC_ON_STACK(shash, tfm);
shash->tfm = tfm;
shash->flags = 0;
crypto_shash_init(shash);
crypto_shash_update(shash, event, strlen(event));
crypto_shash_final(shash, digest);
}
void app_pcr_extend_method_1(void)
{
char *event = "application event";
struct tpm2_digest digestarg = {.alg_id = TPM2_ALG_SHA1};
/* calculate event digest with current hash algorithm */
struct crypto_shash *tfm = crypto_alloc_shash("sha1", 0, 0);
app_calc_event_digest(tfm, event, digestarg.digest);
/* extend all PCR banks with SHA1 digest*/
tpm_pcr_extend(TPM_ANY_NUM, 16, 1, &digestarg);
}
void app_pcr_extend_method_2(void)
{
/* declare static arrays, limit is known */
enum tpm2_algorithms algo_array[TPM_ACTIVE_BANKS_MAX];
struct tpm2_digest digest_array[TPM_ACTIVE_BANKS_MAX];
int i, num_algo;
/* obtain algorithms supported by the TPM */
num_algo = tpm_pcr_algorithms(TPM_ANY_NUM, ARRAY_SIZE(algo_array),
algo_array);
for (i = 0; i < num_algo; i++) {
char *event = "application event";
/* convert TPM ID to crypto ID to calculate the digest */
unsigned int crypto_id = tpm_pcr_algo_to_crypto(algo_array[i]);
/* calculate event digest with current hash algorithm */
const char *algo_name = hash_algo_name[crypto_id];
struct crypto_shash *tfm = crypto_alloc_shash(algo_name, 0, 0);
app_calc_event_digest(tfm, event, digest_array[i].digest);
digest_array[i].alg_id = algo_array[i];
}
/* extend all PCR banks with calculated digests */
tpm_pcr_extend(TPM_ANY_NUM, 16, num_algo, digest_array);
}
Changelog:
v2
- removed tpm2_digests_all_banks(); input check is now done by
tpm_pcr_check_input(), called by tpm_pcr_extend(), also for TPM 1.2
- fixed return values of tpm2_pcr_algo_to_crypto() and
tpm2_pcr_algo_from_crypto() if TPM is not supported
- tpm_pcr_algorithms() returns supported algorithms also for TPM 1.2
- removed tpm_pcr_extend_digests()
- modified parameters of tpm_pcr_extend()
- modified callers of tpm_pcr_extend()
Roberto Sassu (5):
tpm: introduce tpm_pcr_algorithms()
tpm: introduce tpm_pcr_algo_to_crypto() and tpm_pcr_algo_from_crypto()
tpm: pass multiple digests to tpm_pcr_extend()
keys, trusted: modify arguments of tpm_pcr_extend()
ima: modify arguments of tpm_pcr_extend()
drivers/char/tpm/tpm-interface.c | 173 +++++++++++++++++++++++++++++++++++--
drivers/char/tpm/tpm.h | 19 +---
drivers/char/tpm/tpm2-cmd.c | 42 +++------
include/linux/tpm.h | 43 ++++++++-
security/integrity/ima/ima_queue.c | 4 +-
security/keys/trusted.c | 6 +-
6 files changed, 227 insertions(+), 60 deletions(-)
--
2.9.3
[toc] | [next] | [standalone]
| From | Roberto Sassu <roberto.sassu@huawei.com> |
|---|---|
| Date | 2017-05-05 16:30 +0200 |
| Subject | [PATCH v2 5/5] ima: modify arguments of tpm_pcr_extend() |
| Message-ID | <tDMp4-2VD-9@gated-at.bofh.it> |
| In reply to | #1636422 |
ima_pcr_extend() has been modified to pass the correct arguments
to tpm_pcr_extend(): the pointer of a tpm2_digest structure containing
the template digest and the size of the array (1).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_queue.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index d9aa5ab..f628968 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -140,12 +140,14 @@ unsigned long ima_get_binary_runtime_size(void)
static int ima_pcr_extend(const u8 *hash, int pcr)
{
+ struct tpm2_digest digestarg = {.alg_id = TPM2_ALG_SHA1};
int result = 0;
if (!ima_used_chip)
return result;
- result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash);
+ memcpy(digestarg.digest, hash, IMA_DIGEST_SIZE);
+ result = tpm_pcr_extend(TPM_ANY_NUM, pcr, 1, &digestarg);
if (result != 0)
pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result;
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Roberto Sassu <roberto.sassu@huawei.com> |
|---|---|
| Date | 2017-05-05 16:30 +0200 |
| Subject | [PATCH v2 2/5] tpm: introduce tpm_pcr_algo_to_crypto() and tpm_pcr_algo_from_crypto() |
| Message-ID | <tDMp4-2VD-11@gated-at.bofh.it> |
| In reply to | #1636422 |
tpm_pcr_algorithms() returns to its callers the IDs of the hash algorithms
supported by the TPM. This patch introduces tpm_pcr_algo_to_crypto(),
so that the callers can use the crypto subsystem to calculate the digest
to be passed to tpm_pcr_extend().
tpm_pcr_algo_from_crypto(), implemented for completeness, is instead used
by tpm2_seal_trusted() to perform the opposite conversion.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
v2
- fixed return values of tpm2_pcr_algo_to_crypto() and
tpm2_pcr_algo_from_crypto() if TPM support is disabled in the kernel
drivers/char/tpm/tpm-interface.c | 51 ++++++++++++++++++++++++++++++++++++++++
drivers/char/tpm/tpm2-cmd.c | 42 +++++++++------------------------
include/linux/tpm.h | 13 ++++++++++
3 files changed, 75 insertions(+), 31 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index b90de3d..aac703e 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -956,6 +956,57 @@ int tpm_pcr_algorithms(u32 chip_num, int count,
}
EXPORT_SYMBOL_GPL(tpm_pcr_algorithms);
+struct tpm2_hash {
+ unsigned int crypto_id;
+ unsigned int tpm_id;
+};
+
+static struct tpm2_hash tpm2_hash_map[] = {
+ {HASH_ALGO_SHA1, TPM2_ALG_SHA1},
+ {HASH_ALGO_SHA256, TPM2_ALG_SHA256},
+ {HASH_ALGO_SHA384, TPM2_ALG_SHA384},
+ {HASH_ALGO_SHA512, TPM2_ALG_SHA512},
+ {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
+};
+
+/**
+ * tpm_pcr_algo_to_crypto() - convert from TPM ID to crypto ID
+ * @tpm_id: TPM ID
+ *
+ * Return: crypto ID
+ */
+enum hash_algo tpm_pcr_algo_to_crypto(enum tpm2_algorithms tpm_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+ if (tpm_id == tpm2_hash_map[i].tpm_id)
+ return tpm2_hash_map[i].crypto_id;
+ }
+
+ return HASH_ALGO__LAST;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_algo_to_crypto);
+
+/**
+ * tpm_pcr_algo_from_crypto() - convert from crypto ID to TPM ID
+ * @crypto_id: crypto ID
+ *
+ * Return: TPM ID
+ */
+enum tpm2_algorithms tpm_pcr_algo_from_crypto(enum hash_algo crypto_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+ if (crypto_id == tpm2_hash_map[i].crypto_id)
+ return tpm2_hash_map[i].tpm_id;
+ }
+
+ return TPM2_ALG_ERROR;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_algo_from_crypto);
+
/**
* tpm_do_selftest - have the TPM continue its selftest and wait until it
* can receive further commands
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 3ee6883..828a688 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -92,19 +92,6 @@ struct tpm2_cmd {
union tpm2_cmd_params params;
} __packed;
-struct tpm2_hash {
- unsigned int crypto_id;
- unsigned int tpm_id;
-};
-
-static struct tpm2_hash tpm2_hash_map[] = {
- {HASH_ALGO_SHA1, TPM2_ALG_SHA1},
- {HASH_ALGO_SHA256, TPM2_ALG_SHA256},
- {HASH_ALGO_SHA384, TPM2_ALG_SHA384},
- {HASH_ALGO_SHA512, TPM2_ALG_SHA512},
- {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
-};
-
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The values
@@ -301,7 +288,6 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
struct tpm2_null_auth_area auth_area;
int rc;
int i;
- int j;
if (count > ARRAY_SIZE(chip->active_banks))
return -EINVAL;
@@ -323,14 +309,15 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
tpm_buf_append_u32(&buf, count);
for (i = 0; i < count; i++) {
- for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
- if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
- continue;
- tpm_buf_append_u16(&buf, digests[i].alg_id);
- tpm_buf_append(&buf, (const unsigned char
- *)&digests[i].digest,
- hash_digest_size[tpm2_hash_map[j].crypto_id]);
- }
+ enum tpm2_algorithms tpm_id = digests[i].alg_id;
+ enum hash_algo crypto_id = tpm_pcr_algo_to_crypto(tpm_id);
+
+ if (crypto_id == HASH_ALGO__LAST)
+ continue;
+
+ tpm_buf_append_u16(&buf, digests[i].alg_id);
+ tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
+ hash_digest_size[crypto_id]);
}
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
@@ -493,17 +480,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
unsigned int blob_len;
struct tpm_buf buf;
u32 hash, rlength;
- int i;
int rc;
- for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
- if (options->hash == tpm2_hash_map[i].crypto_id) {
- hash = tpm2_hash_map[i].tpm_id;
- break;
- }
- }
-
- if (i == ARRAY_SIZE(tpm2_hash_map))
+ hash = tpm_pcr_algo_from_crypto(options->hash);
+ if (hash == TPM2_ALG_ERROR)
return -EINVAL;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index b0d0061..9ecd12c 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -22,6 +22,8 @@
#ifndef __LINUX_TPM_H__
#define __LINUX_TPM_H__
+#include <crypto/hash_info.h>
+
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
#define TPM_ACTIVE_BANKS_MAX 7 /* Max num of active banks for TPM 2.0 */
@@ -71,6 +73,8 @@ extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
extern int tpm_pcr_algorithms(u32 chip_num, int count,
enum tpm2_algorithms *algorithms);
+extern enum hash_algo tpm_pcr_algo_to_crypto(enum tpm2_algorithms tpm_id);
+extern enum tpm2_algorithms tpm_pcr_algo_from_crypto(enum hash_algo crypto_id);
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
extern int tpm_seal_trusted(u32 chip_num,
@@ -95,6 +99,15 @@ static inline int tpm_pcr_algorithms(u32 chip_num, int count,
{
return -ENODEV;
}
+static inline enum hash_algo tpm_pcr_algo_to_crypto(enum tpm2_algorithms tpm_id)
+{
+ return HASH_ALGO__LAST;
+}
+static inline enum tpm2_algorithms tpm_pcr_algo_from_crypto(
+ enum hash_algo crypto_id)
+{
+ return TPM2_ALG_ERROR;
+}
static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
return -ENODEV;
}
--
2.9.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web