* [PATCH 0/6] Add policy to sealed keys
@ 2024-05-24 13:04 James Bottomley
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
` (6 more replies)
0 siblings, 7 replies; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
TPM2 policy is much more complicated than the original TPM 1.2 which
only supported PCR value binding. TPM2 policy may be a sequence of
policy statements each of which must be correctly executed and may
include choices in which set of policy statements will execute
correctly. The actual policy is identified in the key by a single
hash, which is the end result of extending all the policy statements.
However, since it is impossible to reverse engineer the policy
statements from the hash value, the ASN.1 key format is extended to
give a broken out list of statements the kernel must execute to get
the correct policy hash value.
In order to create policy sessions (which are usable as HMAC sessions,
but also respond to policy statements), the TPM HMAC code is reused to
create the required policy sessions (while preserving bus security).
However, because the session hash algorithm must match the name
algorithm of the sealed data (which is used for the policy hash), the
TPM session code is changed to use a variable hash algorithm.
The first patch consolidates the hash definitions and conversion
routines, the second adds both variable hash type and policy support
and the remaining patches add specific policy statement
implementations.
James
---
James Bottomley (6):
tpm: consolidate TPM to crypto hash algorithm conversion
tpm: add policy sessions
KEYS: trusted: add PCR policy to TPM2 keys
KEYS: trusted: add ability to specify arbitrary policy
KEYS: trusted: implement counter/timer policy
KEYS: trusted: add support for TPM keys with signed policy
.../security/keys/trusted-encrypted.rst | 99 ++-
drivers/char/tpm/tpm2-cmd.c | 8 -
drivers/char/tpm/tpm2-sessions.c | 313 ++++++---
include/keys/trusted-type.h | 8 +-
include/linux/tpm.h | 81 ++-
security/keys/trusted-keys/Kconfig | 2 +
security/keys/trusted-keys/Makefile | 3 +
security/keys/trusted-keys/tpm2-policy.c | 662 ++++++++++++++++++
security/keys/trusted-keys/tpm2-policy.h | 61 ++
security/keys/trusted-keys/tpm2key.asn1 | 21 +
security/keys/trusted-keys/trusted_core.c | 7 +-
security/keys/trusted-keys/trusted_tpm1.c | 15 +
security/keys/trusted-keys/trusted_tpm2.c | 206 ++++--
13 files changed, 1314 insertions(+), 172 deletions(-)
create mode 100644 security/keys/trusted-keys/tpm2-policy.c
create mode 100644 security/keys/trusted-keys/tpm2-policy.h
--
2.35.3
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-05-24 13:40 ` Jarkko Sakkinen
` (2 more replies)
2024-05-24 13:04 ` [PATCH 2/6] tpm: add policy sessions James Bottomley
` (5 subsequent siblings)
6 siblings, 3 replies; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
linux crypto and the TPM use different numeric algorithm identifiers
for hash (and other) functions. The conversion array for this already
exists in two separate places. The new policy sessions code would
have to add a third copy, so instead of increasing the duplication,
move the definition to a single consolidated place in tpm.h so the
policy code can use it as is.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
drivers/char/tpm/tpm2-cmd.c | 8 ----
include/linux/tpm.h | 52 ++++++++++++++++++++++-
security/keys/trusted-keys/trusted_tpm2.c | 20 +--------
3 files changed, 53 insertions(+), 27 deletions(-)
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 0cdf892ec2a7..f4428e715dd8 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -14,14 +14,6 @@
#include "tpm.h"
#include <crypto/hash_info.h>
-static struct tpm2_hash tpm2_hash_map[] = {
- {HASH_ALGO_SHA1, TPM_ALG_SHA1},
- {HASH_ALGO_SHA256, TPM_ALG_SHA256},
- {HASH_ALGO_SHA384, TPM_ALG_SHA384},
- {HASH_ALGO_SHA512, TPM_ALG_SHA512},
- {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
-};
-
int tpm2_get_timeouts(struct tpm_chip *chip)
{
/* Fixed timeouts for TPM2 */
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index c17e4efbb2e5..07f532456a0c 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -418,11 +418,61 @@ enum tpm2_session_attributes {
TPM2_SA_AUDIT = BIT(7),
};
-struct tpm2_hash {
+static const struct {
unsigned int crypto_id;
unsigned int tpm_id;
+} tpm2_hash_map[] = {
+ {HASH_ALGO_SHA1, TPM_ALG_SHA1},
+ {HASH_ALGO_SHA256, TPM_ALG_SHA256},
+ {HASH_ALGO_SHA384, TPM_ALG_SHA384},
+ {HASH_ALGO_SHA512, TPM_ALG_SHA512},
+ {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
};
+/**
+ * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
+ *
+ * @hash: the crypto subsystem view of the hash
+ *
+ * Return: TPM algorithm id or -1 if no mapping was found.
+ */
+static inline int tpm2_crypto_to_alg(int hash)
+{
+ int i;
+ int tpm_alg = -1;
+
+ for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+ if (hash == tpm2_hash_map[i].crypto_id) {
+ tpm_alg = tpm2_hash_map[i].tpm_id;
+ break;
+ }
+ }
+
+ return tpm_alg;
+}
+
+/**
+ * tpm2_alg_to_crypto() - convert a TPM alg id to a crypto hash
+ *
+ * @hash: the TPM alg id view of the hash
+ *
+ * Return: TPM algorithm id or -1 if no mapping was found.
+ */
+static inline int tpm2_alg_to_crypto(int hash)
+{
+ int i;
+ int crypto_hash = -1;
+
+ for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+ if (hash == tpm2_hash_map[i].tpm_id) {
+ crypto_hash = tpm2_hash_map[i].crypto_id;
+ break;
+ }
+ }
+
+ return crypto_hash;
+}
+
int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
int tpm_buf_init_sized(struct tpm_buf *buf);
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index dfeec06301ce..94ff9ccae66e 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -18,14 +18,6 @@
#include "tpm2key.asn1.h"
-static struct tpm2_hash tpm2_hash_map[] = {
- {HASH_ALGO_SHA1, TPM_ALG_SHA1},
- {HASH_ALGO_SHA256, TPM_ALG_SHA256},
- {HASH_ALGO_SHA384, TPM_ALG_SHA384},
- {HASH_ALGO_SHA512, TPM_ALG_SHA512},
- {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
-};
-
static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
static int tpm2_key_encode(struct trusted_key_payload *payload,
@@ -231,19 +223,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
int blob_len = 0;
- u32 hash;
+ int hash = tpm2_crypto_to_alg(options->hash);
u32 flags;
- 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))
+ if (hash < 0)
return -EINVAL;
if (!options->keyhandle)
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 2/6] tpm: add policy sessions
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-07-16 11:53 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys James Bottomley
` (4 subsequent siblings)
6 siblings, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
TPM security uses hmac sessions to implement data protection and
integrity. The hash algorithm of these sessions isn't exposed to the
user (and doesn't depend on the object being authorized) so it is
currently fixed at a safe sha256. Policy sessions may also be used
for the same purpose and in addition, they can be used to express a
rich policy language. However, the session hash of policy sessions is
defined to be the same as the name algorithm of the TPM object they're
operating on, so we must update the session code to allow a variable
hash algorithm instead of the fixed sha256 one. Note that while this
affects most of the code, the KDFe algorithm still uses a fixed sha256
algorithm because it is define to follow the name algorithm of the
salt encryption key (which is a key we derive from the null seed and
set its name algorithm to sha256).
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
drivers/char/tpm/tpm2-sessions.c | 307 +++++++++++++++++++------------
include/linux/tpm.h | 6 +
2 files changed, 200 insertions(+), 113 deletions(-)
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index ea8860661876..63c175b2165c 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -105,10 +105,10 @@ struct tpm2_auth {
/*
* the size here is variable and set by the size of our_nonce
* which must be between 16 and the name hash length. we set
- * the maximum sha256 size for the greatest protection
+ * the maximum hash size for the greatest protection
*/
- u8 our_nonce[SHA256_DIGEST_SIZE];
- u8 tpm_nonce[SHA256_DIGEST_SIZE];
+ u8 our_nonce[HASH_MAX_DIGESTSIZE];
+ u8 tpm_nonce[HASH_MAX_DIGESTSIZE];
/*
* the salt is only used across the session command/response
* after that it can be used as a scratch area
@@ -119,17 +119,15 @@ struct tpm2_auth {
u8 scratch[AES_KEY_BYTES + AES_BLOCK_SIZE];
};
/*
- * the session key and passphrase are the same size as the
- * name digest (sha256 again). The session key is constant
- * for the use of the session and the passphrase can change
- * with every invocation.
- *
- * Note: these fields must be adjacent and in this order
- * because several HMAC/KDF schemes use the combination of the
- * session_key and passphrase.
+ * The session_key and passphrase must be next to each other
+ * to allow us to hash them as a unit. With a variable hash,
+ * this means that the passphrase must occur exactly one hash
+ * size after the session_key, so make session_key house both
+ * and passphrase is a pointer into where the passphrase
+ * begins in session_key.
*/
- u8 session_key[SHA256_DIGEST_SIZE];
- u8 passphrase[SHA256_DIGEST_SIZE];
+ u8 session_key[2*HASH_MAX_DIGESTSIZE];
+ u8 *passphrase;
int passphrase_len;
struct crypto_aes_ctx aes_ctx;
/* saved session attributes: */
@@ -142,7 +140,8 @@ struct tpm2_auth {
* we must compute and remember
*/
u32 name_h[AUTH_MAX_NAMES];
- u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
+ u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
+ struct crypto_shash *tfm;
};
/*
@@ -161,34 +160,36 @@ static u8 name_size(const u8 *name)
}
/*
- * It turns out the crypto hmac(sha256) is hard for us to consume
+ * It turns out the crypto hmac(shaX) is hard for us to consume
* because it assumes a fixed key and the TPM seems to change the key
* on every operation, so we weld the hmac init and final functions in
* here to give it the same usage characteristics as a regular hash
*/
-static void tpm2_hmac_init(struct sha256_state *sctx, u8 *key, u32 key_len)
+static void tpm2_hmac_init(struct shash_desc *sdesc, u8 *key, u32 key_len)
{
- u8 pad[SHA256_BLOCK_SIZE];
+ const int block_size = crypto_shash_blocksize(sdesc->tfm);
+ u8 pad[SHA512_BLOCK_SIZE];
int i;
- sha256_init(sctx);
- for (i = 0; i < sizeof(pad); i++) {
+ crypto_shash_init(sdesc);
+ for (i = 0; i < block_size; i++) {
if (i < key_len)
pad[i] = key[i];
else
pad[i] = 0;
pad[i] ^= HMAC_IPAD_VALUE;
}
- sha256_update(sctx, pad, sizeof(pad));
+ crypto_shash_update(sdesc, pad, block_size);
}
-static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
+static void tpm2_hmac_final(struct shash_desc *sdesc, u8 *key, u32 key_len,
u8 *out)
{
- u8 pad[SHA256_BLOCK_SIZE];
+ const int block_size = crypto_shash_blocksize(sdesc->tfm);
+ u8 pad[SHA512_BLOCK_SIZE];
int i;
- for (i = 0; i < sizeof(pad); i++) {
+ for (i = 0; i < block_size; i++) {
if (i < key_len)
pad[i] = key[i];
else
@@ -197,35 +198,42 @@ static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
}
/* collect the final hash; use out as temporary storage */
- sha256_final(sctx, out);
+ crypto_shash_final(sdesc, out);
- sha256_init(sctx);
- sha256_update(sctx, pad, sizeof(pad));
- sha256_update(sctx, out, SHA256_DIGEST_SIZE);
- sha256_final(sctx, out);
+ crypto_shash_init(sdesc);
+ crypto_shash_update(sdesc, pad, block_size);
+ crypto_shash_update(sdesc, out, crypto_shash_digestsize(sdesc->tfm));
+ crypto_shash_final(sdesc, out);
}
/*
- * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but
+ * assume hash sha256 and nonces u, v of hash digest size but
* otherwise standard tpm2_KDFa. Note output is in bytes not bits.
*/
static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
- u8 *v, u32 bytes, u8 *out)
+ u8 *v, u32 bytes, u8 *out, struct shash_desc *sdesc)
{
u32 counter = 1;
const __be32 bits = cpu_to_be32(bytes * 8);
+ const int digest_size = crypto_shash_digestsize(sdesc->tfm);
while (bytes > 0) {
- struct sha256_state sctx;
__be32 c = cpu_to_be32(counter);
- tpm2_hmac_init(&sctx, key, key_len);
- sha256_update(&sctx, (u8 *)&c, sizeof(c));
- sha256_update(&sctx, label, strlen(label)+1);
- sha256_update(&sctx, u, SHA256_DIGEST_SIZE);
- sha256_update(&sctx, v, SHA256_DIGEST_SIZE);
- sha256_update(&sctx, (u8 *)&bits, sizeof(bits));
- tpm2_hmac_final(&sctx, key, key_len, out);
+ tpm2_hmac_init(sdesc, key, key_len);
+ crypto_shash_update(sdesc, (u8 *)&c, sizeof(c));
+ crypto_shash_update(sdesc, label, strlen(label)+1);
+ crypto_shash_update(sdesc, u, digest_size);
+ crypto_shash_update(sdesc, v, digest_size);
+ crypto_shash_update(sdesc, (u8 *)&bits, sizeof(bits));
+ if (bytes < digest_size) {
+ u8 buf[HASH_MAX_DIGESTSIZE];
+
+ tpm2_hmac_final(sdesc, key, key_len, buf);
+ memcpy(out, buf, bytes);
+ } else {
+ tpm2_hmac_final(sdesc, key, key_len, out);
+ }
bytes -= SHA256_DIGEST_SIZE;
counter++;
@@ -236,9 +244,9 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
/*
* Somewhat of a bastardization of the real KDFe. We're assuming
* we're working with known point sizes for the input parameters and
- * the hash algorithm is fixed at sha256. Because we know that the
- * point size is 32 bytes like the hash size, there's no need to loop
- * in this KDF.
+ * the hash algorithm is fixed at sha256 (name algorithm of the
+ * encrypting key). Because we know that the point size is 32 bytes
+ * like the hash size, there's no need to loop in this KDF.
*/
static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
u8 *out)
@@ -370,9 +378,10 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
u8 attributes, u8 *passphrase,
int passphrase_len)
{
- u8 nonce[SHA256_DIGEST_SIZE];
+ u8 nonce[HASH_MAX_DIGESTSIZE];
u32 len;
struct tpm2_auth *auth = chip->auth;
+ const int digest_size = crypto_shash_digestsize(auth->tfm);
/*
* The Architecture Guide requires us to strip trailing zeros
@@ -384,8 +393,14 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
auth->attrs = attributes;
auth->passphrase_len = passphrase_len;
- if (passphrase_len)
+ if (passphrase_len) {
+ /*
+ * place the passphrase immediately adjacent to
+ * the session key
+ */
+ auth->passphrase = auth->session_key + digest_size;
memcpy(auth->passphrase, passphrase, passphrase_len);
+ }
if (auth->session != tpm_buf_length(buf)) {
/* we're not the first session */
@@ -396,23 +411,23 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
}
/* add our new session */
- len += 9 + 2 * SHA256_DIGEST_SIZE;
+ len += 9 + 2 * digest_size;
put_unaligned_be32(len, &buf->data[auth->session]);
} else {
- tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
+ tpm_buf_append_u32(buf, 9 + 2 * digest_size);
}
/* random number for our nonce */
- get_random_bytes(nonce, sizeof(nonce));
- memcpy(auth->our_nonce, nonce, sizeof(nonce));
+ get_random_bytes(nonce, digest_size);
+ memcpy(auth->our_nonce, nonce, digest_size);
tpm_buf_append_u32(buf, auth->handle);
/* our new nonce */
- tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
- tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
+ tpm_buf_append_u16(buf, digest_size);
+ tpm_buf_append(buf, nonce, digest_size);
tpm_buf_append_u8(buf, auth->attrs);
/* and put a placeholder for the hmac */
- tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
- tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
+ tpm_buf_append_u16(buf, digest_size);
+ tpm_buf_append(buf, nonce, digest_size);
}
EXPORT_SYMBOL(tpm_buf_append_hmac_session);
@@ -443,8 +458,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
off_t offset_s = TPM_HEADER_SIZE, offset_p;
u8 *hmac = NULL;
u32 attrs;
- u8 cphash[SHA256_DIGEST_SIZE];
- struct sha256_state sctx;
+ const int digest_size = crypto_shash_digestsize(auth->tfm);
+ u8 cphash[HASH_MAX_DIGESTSIZE];
+ SHASH_DESC_ON_STACK(sdesc, auth->tfm);
+
+ sdesc->tfm = auth->tfm;
/* save the command code in BE format */
auth->ordinal = head->ordinal;
@@ -515,10 +533,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
u16 len;
/* need key and IV */
- tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
+ tpm2_KDFa(auth->session_key, digest_size
+ auth->passphrase_len, "CFB", auth->our_nonce,
auth->tpm_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
- auth->scratch);
+ auth->scratch, sdesc);
len = tpm_buf_read_u16(buf, &offset_p);
aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
@@ -529,9 +547,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
offset_p -= 2;
}
- sha256_init(&sctx);
+ crypto_shash_init(sdesc);
/* ordinal is already BE */
- sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal));
+ crypto_shash_update(sdesc, (u8 *)&head->ordinal,
+ sizeof(head->ordinal));
/* add the handle names */
for (i = 0; i < handles; i++) {
enum tpm2_mso_type mso = tpm2_handle_mso(auth->name_h[i]);
@@ -539,27 +558,27 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
if (mso == TPM2_MSO_PERSISTENT ||
mso == TPM2_MSO_VOLATILE ||
mso == TPM2_MSO_NVRAM) {
- sha256_update(&sctx, auth->name[i],
- name_size(auth->name[i]));
+ crypto_shash_update(sdesc, auth->name[i],
+ name_size(auth->name[i]));
} else {
__be32 h = cpu_to_be32(auth->name_h[i]);
- sha256_update(&sctx, (u8 *)&h, 4);
+ crypto_shash_update(sdesc, (u8 *)&h, 4);
}
}
if (offset_s != tpm_buf_length(buf))
- sha256_update(&sctx, &buf->data[offset_s],
- tpm_buf_length(buf) - offset_s);
- sha256_final(&sctx, cphash);
+ crypto_shash_update(sdesc, &buf->data[offset_s],
+ tpm_buf_length(buf) - offset_s);
+ crypto_shash_final(sdesc, cphash);
/* now calculate the hmac */
- tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
+ tpm2_hmac_init(sdesc, auth->session_key, digest_size
+ auth->passphrase_len);
- sha256_update(&sctx, cphash, sizeof(cphash));
- sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
- sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
- sha256_update(&sctx, &auth->attrs, 1);
- tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
+ crypto_shash_update(sdesc, cphash, digest_size);
+ crypto_shash_update(sdesc, auth->our_nonce, digest_size);
+ crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
+ crypto_shash_update(sdesc, &auth->attrs, 1);
+ tpm2_hmac_final(sdesc, auth->session_key, digest_size
+ auth->passphrase_len, hmac);
}
EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
@@ -695,12 +714,15 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
struct tpm_header *head = (struct tpm_header *)buf->data;
struct tpm2_auth *auth = chip->auth;
off_t offset_s, offset_p;
- u8 rphash[SHA256_DIGEST_SIZE];
+ const int digest_size = crypto_shash_digestsize(auth->tfm);
+ u8 rphash[HASH_MAX_DIGESTSIZE];
u32 attrs;
- struct sha256_state sctx;
u16 tag = be16_to_cpu(head->tag);
u32 cc = be32_to_cpu(auth->ordinal);
int parm_len, len, i, handles;
+ SHASH_DESC_ON_STACK(sdesc, auth->tfm);
+
+ sdesc->tfm = auth->tfm;
if (auth->session >= TPM_HEADER_SIZE) {
WARN(1, "tpm session not filled correctly\n");
@@ -739,7 +761,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
len = tpm_buf_read_u16(buf, &offset_s);
if (offset_s + len > tpm_buf_length(buf))
goto out;
- if (len != SHA256_DIGEST_SIZE)
+ if (len != digest_size)
goto out;
memcpy(auth->tpm_nonce, &buf->data[offset_s], len);
offset_s += len;
@@ -747,32 +769,32 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
len = tpm_buf_read_u16(buf, &offset_s);
if (offset_s + len != tpm_buf_length(buf))
goto out;
- if (len != SHA256_DIGEST_SIZE)
+ if (len != digest_size)
goto out;
/*
* offset_s points to the HMAC. now calculate comparison, beginning
* with rphash
*/
- sha256_init(&sctx);
+ crypto_shash_init(sdesc);
/* yes, I know this is now zero, but it's what the standard says */
- sha256_update(&sctx, (u8 *)&head->return_code,
- sizeof(head->return_code));
+ crypto_shash_update(sdesc, (u8 *)&head->return_code,
+ sizeof(head->return_code));
/* ordinal is already BE */
- sha256_update(&sctx, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
- sha256_update(&sctx, &buf->data[offset_p], parm_len);
- sha256_final(&sctx, rphash);
+ crypto_shash_update(sdesc, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
+ crypto_shash_update(sdesc, &buf->data[offset_p], parm_len);
+ crypto_shash_final(sdesc, rphash);
/* now calculate the hmac */
- tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
+ tpm2_hmac_init(sdesc, auth->session_key, digest_size
+ auth->passphrase_len);
- sha256_update(&sctx, rphash, sizeof(rphash));
- sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
- sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
- sha256_update(&sctx, &auth->attrs, 1);
+ crypto_shash_update(sdesc, rphash, digest_size);
+ crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
+ crypto_shash_update(sdesc, auth->our_nonce, digest_size);
+ crypto_shash_update(sdesc, &auth->attrs, 1);
/* we're done with the rphash, so put our idea of the hmac there */
- tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
+ tpm2_hmac_final(sdesc, auth->session_key, digest_size
+ auth->passphrase_len, rphash);
- if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) == 0) {
+ if (memcmp(rphash, &buf->data[offset_s], digest_size) == 0) {
rc = 0;
} else {
dev_err(&chip->dev, "TPM: HMAC check failed\n");
@@ -782,10 +804,10 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
/* now do response decryption */
if (auth->attrs & TPM2_SA_ENCRYPT) {
/* need key and IV */
- tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
+ tpm2_KDFa(auth->session_key, digest_size
+ auth->passphrase_len, "CFB", auth->tpm_nonce,
auth->our_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
- auth->scratch);
+ auth->scratch, sdesc);
len = tpm_buf_read_u16(buf, &offset_p);
aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
@@ -799,6 +821,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
if (rc)
/* manually close the session if it wasn't consumed */
tpm2_flush_context(chip, auth->handle);
+ crypto_free_shash(auth->tfm);
memzero_explicit(auth, sizeof(*auth));
} else {
/* reset for next use */
@@ -821,8 +844,11 @@ EXPORT_SYMBOL(tpm_buf_check_hmac_response);
*/
void tpm2_end_auth_session(struct tpm_chip *chip)
{
- tpm2_flush_context(chip, chip->auth->handle);
- memzero_explicit(chip->auth, sizeof(*chip->auth));
+ struct tpm2_auth *auth = chip->auth;
+
+ tpm2_flush_context(chip, auth->handle);
+ crypto_free_shash(auth->tfm);
+ memzero_explicit(auth, sizeof(*auth));
}
EXPORT_SYMBOL(tpm2_end_auth_session);
@@ -833,23 +859,26 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
u32 tot_len = be32_to_cpu(head->length);
off_t offset = TPM_HEADER_SIZE;
u32 val;
+ const int digest_size = crypto_shash_digestsize(auth->tfm);
+ SHASH_DESC_ON_STACK(sdesc, auth->tfm);
+
+ sdesc->tfm = auth->tfm;
/* we're starting after the header so adjust the length */
tot_len -= TPM_HEADER_SIZE;
/* should have handle plus nonce */
- if (tot_len != 4 + 2 + sizeof(auth->tpm_nonce))
+ if (tot_len != 4 + 2 + digest_size)
return -EINVAL;
auth->handle = tpm_buf_read_u32(buf, &offset);
val = tpm_buf_read_u16(buf, &offset);
- if (val != sizeof(auth->tpm_nonce))
+ if (val != digest_size)
return -EINVAL;
- memcpy(auth->tpm_nonce, &buf->data[offset], sizeof(auth->tpm_nonce));
+ memcpy(auth->tpm_nonce, &buf->data[offset], digest_size);
/* now compute the session key from the nonces */
tpm2_KDFa(auth->salt, sizeof(auth->salt), "ATH", auth->tpm_nonce,
- auth->our_nonce, sizeof(auth->session_key),
- auth->session_key);
+ auth->our_nonce, digest_size, auth->session_key, sdesc);
return 0;
}
@@ -885,24 +914,23 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
return rc;
}
-/**
- * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
- * @chip: the TPM chip structure to create the session with
- *
- * This function loads the NULL seed from its saved context and starts
- * an authentication session on the null seed, fills in the
- * @chip->auth structure to contain all the session details necessary
- * for performing the HMAC, encrypt and decrypt operations and
- * returns. The NULL seed is flushed before this function returns.
- *
- * Return: zero on success or actual error encountered.
- */
-int tpm2_start_auth_session(struct tpm_chip *chip)
+static int __tpm2_start_session(struct tpm_chip *chip, u8 type, u16 hash)
{
struct tpm_buf buf;
struct tpm2_auth *auth = chip->auth;
int rc;
u32 null_key;
+ int tpm_hash = tpm2_crypto_to_alg(hash);
+ int digest_size;
+
+ if (tpm_hash < 0)
+ return -EINVAL;
+
+ auth->tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
+ if (IS_ERR(auth->tfm))
+ return PTR_ERR(auth->tfm);
+
+ digest_size = crypto_shash_digestsize(auth->tfm);
rc = tpm2_load_null(chip, &null_key);
if (rc)
@@ -919,14 +947,14 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
/* bind key handle */
tpm_buf_append_u32(&buf, TPM2_RH_NULL);
/* nonce caller */
- get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
- tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
- tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
+ get_random_bytes(auth->our_nonce, digest_size);
+ tpm_buf_append_u16(&buf, digest_size);
+ tpm_buf_append(&buf, auth->our_nonce, digest_size);
/* append encrypted salt and squirrel away unencrypted in auth */
tpm_buf_append_salt(&buf, chip);
/* session type (HMAC, audit or policy) */
- tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
+ tpm_buf_append_u8(&buf, type);
/* symmetric encryption parameters */
/* symmetric algorithm */
@@ -936,7 +964,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
/* symmetric algorithm mode (must be CFB) */
tpm_buf_append_u16(&buf, TPM_ALG_CFB);
/* hash algorithm for session */
- tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
+ tpm_buf_append_u16(&buf, tpm_hash);
rc = tpm_transmit_cmd(chip, &buf, 0, "start auth session");
tpm2_flush_context(chip, null_key);
@@ -949,11 +977,64 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
if (rc)
goto out;
+ return rc;
+
out:
+ crypto_free_shash(auth->tfm);
+ auth->tfm = NULL;
+
return rc;
}
+
+/**
+ * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
+ * @chip: the TPM chip structure to create the session with
+ *
+ * This function loads the NULL seed from its saved context and starts
+ * an authentication session on the null seed, fills in the
+ * @chip->auth structure to contain all the session details necessary
+ * for performing the HMAC, encrypt and decrypt operations and
+ * returns. The NULL seed is flushed before this function returns.
+ *
+ * Return: zero on success or actual error encountered.
+ */
+int tpm2_start_auth_session(struct tpm_chip *chip)
+{
+ return __tpm2_start_session(chip, TPM2_SE_HMAC, HASH_ALGO_SHA256);
+}
EXPORT_SYMBOL(tpm2_start_auth_session);
+/**
+ * tpm2_start_policy_session - create a policy session with the TPM
+ * @chip: the TPM chip structure to create the session with
+ * @handle: the policy session handle
+ * @hash: the crypto subsystem hash algorithm for the policy
+ *
+ * This function loads the NULL seed from its saved context and starts
+ * a policy session on the null seed, fills in the @chip->auth
+ * structure to contain all the session details necessary for
+ * performing the HMAC, encrypt and decrypt operations and returns.
+ * The NULL seed is flushed before this function returns.
+ *
+ * Note the hash algorthim has to match the name algorithm of the TPM
+ * object the policy will be used to authorize.
+ *
+ * Return: zero on success or actual error encountered.
+ */
+int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash)
+{
+ int rc;
+
+ rc = __tpm2_start_session(chip, TPM2_SE_POLICY, hash);
+ if (rc)
+ return rc;
+
+ *handle = chip->auth->handle;
+
+ return rc;
+}
+EXPORT_SYMBOL(tpm2_start_policy_session);
+
/**
* tpm2_parse_create_primary() - parse the data returned from TPM_CC_CREATE_PRIMARY
*
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 07f532456a0c..dc2dd98cf104 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -560,6 +560,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
#ifdef CONFIG_TCG_TPM2_HMAC
int tpm2_start_auth_session(struct tpm_chip *chip);
+int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
u32 handle, u8 *name);
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
@@ -585,6 +586,11 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
{
return 0;
}
+static inline int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle,
+ u8 hash)
+{
+ return -EINVAL;
+}
static inline void tpm2_end_auth_session(struct tpm_chip *chip)
{
}
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
2024-05-24 13:04 ` [PATCH 2/6] tpm: add policy sessions James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-07-16 12:01 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy James Bottomley
` (3 subsequent siblings)
6 siblings, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
This commit adds the ability to specify a PCR lock policy to TPM2
keys. There is a complexity in that keys that contain both a password
(blobauth) and a PCR lock have to have two policy statements
(POLICY_PCR and POLICY_AUTHVALUE). The way to construct a pcrinfo
statement for a key is simply to use the TPMS_PCR_SELECT structure to
specify the PCRs and follow this by a hash of all their values in
order of ascending PCR number.
To construct a policy around the value of the resettable PCR 16 using
the sha256 bank, first reset the pcr to zero giving a hash of all
zeros as:
66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Then the TPMS_PCR_SELECT value for sha256 bank PCR 16 is
000b03000001
So create a new 32 byte key with a policy locking the key to this
value of PCR 16 with a parent key of 81000001 would be:
keyctl add trusted kmk "new 32 keyhandle=0x81000001 pcrinfo=000b0300000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925" @u
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
.../security/keys/trusted-encrypted.rst | 53 ++-
include/keys/trusted-type.h | 5 +-
include/linux/tpm.h | 16 +
security/keys/trusted-keys/Kconfig | 2 +
security/keys/trusted-keys/Makefile | 3 +
security/keys/trusted-keys/tpm2-policy.c | 325 ++++++++++++++++++
security/keys/trusted-keys/tpm2-policy.h | 53 +++
security/keys/trusted-keys/tpm2key.asn1 | 13 +
security/keys/trusted-keys/trusted_core.c | 7 +-
security/keys/trusted-keys/trusted_tpm2.c | 147 +++++++-
10 files changed, 606 insertions(+), 18 deletions(-)
create mode 100644 security/keys/trusted-keys/tpm2-policy.c
create mode 100644 security/keys/trusted-keys/tpm2-policy.h
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index f4d7e162d5e4..c37c08956ec1 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -217,7 +217,10 @@ Usage::
(40 ascii zeros)
blobauth= ascii hex auth for sealed data default 0x00...
(40 ascii zeros)
- pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
+ pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no
+ default) on TPM 1.2 and a TPMS_PCR_SELECTION
+ coupled with a hash of all the selected PCRs on
+ TPM 2.0 using the selected hash.
pcrlock= pcr number to be extended to "lock" blob
migratable= 0|1 indicating permission to reseal to new PCR values,
default 1 (resealing allowed)
@@ -343,6 +346,37 @@ Load a trusted key from the saved blob::
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba
+Create a trusted key on TPM 2.0 using an all zero value of PCR16 and
+using the NV storage root 81000001 as the parent::
+
+ $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 pcrinfo=000b0300000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925" @u
+
+Note the TPMS_PCR_SELECT value for sha256 bank PCR 16 is 000b03000001
+because all current TPMs have 24 PCRs, so the initial 000b says sha256
+bank (other possible banks are sha1=0004; sha384=000c; sha512=000d),
+03 says there are three following bytes of selection and then because
+the bytes are big endian, 16 is bit zero of byte 2. the hash is the
+sha256 sum of all zeros (the value of PCR 16)::
+
+ $ dd if=/dev/zero bs=1 count=32 2>/dev/null|sha256sum
+ 66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
+
+If you want to compute a current PCR hash value, simply take the
+hashes of multiple PCRs (in ascending order) and compute the sha256sum
+over the total:
+
+ $ { cat /sys/class/tpm/tpm0/pcr-sha256/7; cat /sys/class/tpm/tpm0/pcr-sha256/16; }|xxd -r -p|sha256sum
+
+Then use this value to append to a TPMS_PCR_SELECT (for 7 and 16 that
+would be 000b03800001) to the calculated hash as before. Note also
+that the hash of the PCR registers has to use the name algorithm hash
+(the keyctl option hash=) not the bank algorithm hash. So to select
+the sha1 pcr16 bank you'd say::
+
+ keyctl add trusted kmk "new 32 keyhandle=0x81000001 pcrinfo=000403000001de47c9b27eb8d300dbb5f2c353e632c393262cf06340c4fa7f1b40c4cbd36f90" @u
+
+because the trailing hash is the sha256sum of 20 zero bytes.
+
Reseal (TPM specific) a trusted key under new PCR values::
$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
@@ -425,11 +459,17 @@ policy::
TPMKey ::= SEQUENCE {
type OBJECT IDENTIFIER
emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
+ policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
parent INTEGER
pubkey OCTET STRING
privkey OCTET STRING
}
+ TPMPolicy ::= SEQUENCE {
+ CommandCode [0] EXPLICIT INTEGER
+ CommandPolicy [1] EXPLICIT OCTET STRING
+ }
+
type is what distinguishes the key even in binary form since the OID
is provided by the TCG to be unique and thus forms a recognizable
binary pattern at offset 3 in the key. The OIDs currently made
@@ -455,6 +495,17 @@ is false or not present, the key requires an explicit authorization
phrase. This is used by most user space consumers to decide whether
to prompt for a password.
+policy represents a sequence of one or more policy statements that
+must be executed successfully into a session policy register. If
+policy isn't present then no policy is required to unlock the key, but
+if it is, commandCode is the TPM 2.0 command code of the policy
+instruction that must be executed and CommandPolicy represents the
+binary parameter area of the policy command.
+
+Note that the current sequential execution requirement means that only
+AND based policy can be constructed at the moment, so TPM2_PolicyOR is
+not currently supported.
+
parent represents the parent key handle, either in the 0x81 MSO space,
like 0x81000001 for the RSA primary storage key. Userspace programmes
also support specifying the primary handle in the 0x40 MSO space. If
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 4eb64548a74f..5d1d481a8a19 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -20,9 +20,11 @@
#define MIN_KEY_SIZE 32
#define MAX_KEY_SIZE 128
#define MAX_BLOB_SIZE 512
-#define MAX_PCRINFO_SIZE 64
+#define MAX_PCRINFO_SIZE 128
#define MAX_DIGEST_SIZE 64
+#define TPM2_MAX_POLICIES 16
+
struct trusted_key_payload {
struct rcu_head rcu;
unsigned int key_len;
@@ -31,6 +33,7 @@ struct trusted_key_payload {
unsigned char old_format;
unsigned char key[MAX_KEY_SIZE + 1];
unsigned char blob[MAX_BLOB_SIZE];
+ struct tpm2_policies *policies;
};
struct trusted_key_options {
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index dc2dd98cf104..154efceec0a4 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -248,7 +248,9 @@ enum tpm2_return_codes {
TPM2_RC_SUCCESS = 0x0000,
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
TPM2_RC_HANDLE = 0x008B,
+ TPM2_RC_AUTH_FAIL = 0x008E,
TPM2_RC_INTEGRITY = 0x009F,
+ TPM2_RC_BAD_AUTH = 0x00A2,
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_FAILURE = 0x0101,
TPM2_RC_DISABLED = 0x0120,
@@ -259,6 +261,18 @@ enum tpm2_return_codes {
TPM2_RC_RETRY = 0x0922,
};
+static inline int tpm2_error_code(u32 rc)
+{
+ if ((rc & 0x0180) == 0)
+ /* TPM 1.2 error */
+ return -1;
+ if ((rc & 0x0080) == 0)
+ /* Error or Warning */
+ return rc;
+ /* strip off encoded parameter, handle or session */
+ return rc & 0x00ff;
+}
+
enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
@@ -276,12 +290,14 @@ enum tpm2_command_codes {
TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
+ TPM2_CC_POLICY_AUTHVALUE = 0x016B,
TPM2_CC_READ_PUBLIC = 0x0173,
TPM2_CC_START_AUTH_SESS = 0x0176,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
+ TPM2_CC_POLICY_PCR = 0x017F,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig
index 1fb8aa001995..da271679330b 100644
--- a/security/keys/trusted-keys/Kconfig
+++ b/security/keys/trusted-keys/Kconfig
@@ -8,6 +8,8 @@ config TRUSTED_KEYS_TPM
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
select CRYPTO_HASH_INFO
select ASN1_ENCODER
select OID_REGISTRY
diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile
index f0f3b27f688b..1d22d9821876 100644
--- a/security/keys/trusted-keys/Makefile
+++ b/security/keys/trusted-keys/Makefile
@@ -10,6 +10,9 @@ trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm1.o
$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h
trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm2.o
trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2key.asn1.o
+ifeq ($(CONFIG_TCG_TPM2_HMAC),y)
+trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2-policy.o
+endif
trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
new file mode 100644
index 000000000000..8c3a09762c10
--- /dev/null
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 James.Bottomley@HansenPartnership.com
+ */
+
+#include <linux/asn1_encoder.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/printk.h>
+#include <linux/string.h>
+#include <linux/tpm.h>
+
+#include <asm/unaligned.h>
+
+#include <crypto/hash.h>
+
+#include <keys/trusted-type.h>
+#include <keys/trusted_tpm.h>
+
+#include "tpm2key.asn1.h"
+#include "tpm2-policy.h"
+
+int tpm2_key_code(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct tpm2_key_context *ctx = context;
+ u32 code = 0;
+ const u8 *v = value;
+ int i;
+
+ for (i = 0; i < vlen; i++) {
+ code <<= 8;
+ code |= v[i];
+ }
+
+ ctx->policy_code[ctx->policy_count] = code;
+
+ return 0;
+}
+
+int tpm2_key_policy(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct tpm2_key_context *ctx = context;
+
+ ctx->policies[ctx->policy_count] = value;
+ ctx->policy_len[ctx->policy_count++] = vlen;
+
+ return 0;
+}
+
+/* we only support a limited number of policy statement so
+ * make sure we don't have anything we can't support
+ */
+static int tpm2_validate_policy(struct tpm2_policies *pols)
+{
+ int i;
+
+ if (pols->count == 0)
+ return 0;
+
+ for (i = 0; i < pols->count; i++) {
+ switch (pols->code[i]) {
+ case TPM2_CC_POLICY_PCR:
+ case TPM2_CC_POLICY_AUTHVALUE:
+ break;
+ default:
+ pr_info("tpm2 policy 0x%x is unsupported\n",
+ pols->code[i]);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * tpm2_key_process_policy - collect the policty from the context
+ * @ctx: the context to collect from
+ * @payload: the payload structure to place it in
+ *
+ * THis function sizes the policy statements and allocates space
+ * within the payload to receive them before copying them over. It
+ * should be used after the ber decoder has completed successfully
+ */
+int tpm2_key_policy_process(struct tpm2_key_context *ctx,
+ struct trusted_key_payload *payload)
+{
+ int tot_len = 0;
+ u8 *buf;
+ int i, ret, len = 0;
+ struct tpm2_policies *pols;
+ u16 name_alg;
+
+ if (ctx->policy_count == 0)
+ return 0;
+
+ for (i = 0; i < ctx->policy_count; i++)
+ tot_len += ctx->policy_len[i];
+ tot_len += sizeof(*pols);
+
+ pols = kmalloc(tot_len, GFP_KERNEL);
+ if (!pols)
+ return -ENOMEM;
+
+ payload->policies = pols;
+ buf = (u8 *)(pols + 1);
+
+ for (i = 0; i < ctx->policy_count; i++) {
+ pols->policies[i] = &buf[len];
+ pols->len[i] = ctx->policy_len[i];
+ pols->code[i] = ctx->policy_code[i];
+ if (pols->len[i])
+ memcpy(pols->policies[i], ctx->policies[i],
+ ctx->policy_len[i]);
+ len += ctx->policy_len[i];
+ }
+ pols->count = ctx->policy_count;
+
+ ret = tpm2_validate_policy(pols);
+ if (ret)
+ goto out;
+
+ /* capture the hash and size */
+
+ /* the hash is the second algorithm (the nameAlg) */
+ name_alg = get_unaligned_be16(&ctx->pub[4]);
+ pols->hash = tpm2_alg_to_crypto(name_alg);
+
+ if (pols->hash < 0)
+ ret = -EINVAL;
+
+ /* and the digest appears after the attributes */
+ pols->hash_size = get_unaligned_be16(&ctx->pub[10]);
+
+ out:
+ if (ret) {
+ kfree(pols);
+ payload->policies = NULL;
+ }
+
+ return ret;
+}
+
+int tpm2_generate_policy_digest(struct tpm2_policies *pols,
+ u32 hash, u8 *policydigest, u32 *plen)
+{
+ int i;
+ struct crypto_shash *tfm;
+ int rc;
+
+ if (pols->count == 0)
+ return 0;
+
+ tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ rc = crypto_shash_digestsize(tfm);
+ if (WARN(rc > MAX_DIGEST_SIZE,
+ "BUG: trusted key code has alg %s with digest too large (%d)",
+ hash_algo_name[hash], rc)) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ pols->hash = hash;
+ pols->hash_size = rc;
+ *plen = rc;
+
+ /* policy digests always start out all zeros */
+ memset(policydigest, 0, rc);
+
+ for (i = 0; i < pols->count; i++) {
+ u8 *policy = pols->policies[i];
+ int len = pols->len[i];
+ u32 cmd = pols->code[i];
+ u8 code[4];
+ SHASH_DESC_ON_STACK(sdesc, tfm);
+
+ sdesc->tfm = tfm;
+ rc = crypto_shash_init(sdesc);
+ if (rc)
+ goto err;
+
+ /* first hash the previous digest */
+ crypto_shash_update(sdesc, policydigest, *plen);
+
+ /* then hash the command code */
+ put_unaligned_be32(cmd, code);
+ crypto_shash_update(sdesc, code, 4);
+
+ if (len)
+ crypto_shash_update(sdesc, policy, len);
+
+ /* now output the intermediate to the policydigest */
+ crypto_shash_final(sdesc, policydigest);
+
+ }
+ rc = 0;
+
+ err:
+ crypto_free_shash(tfm);
+ return rc;
+}
+
+int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
+{
+ const int SCRATCH_SIZE = PAGE_SIZE;
+ u8 *buf = kmalloc(2 * SCRATCH_SIZE, GFP_KERNEL);
+ u8 *work = buf + SCRATCH_SIZE;
+ u8 *ptr;
+ u8 *end_work = work + SCRATCH_SIZE;
+ int i, ret;
+
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < pols->count; i++) {
+ u8 *seq, *tag;
+ u32 cmd = pols->code[i];
+
+ if (WARN(work - buf + 14 + pols->len[i] > 2 * SCRATCH_SIZE,
+ "BUG: scratch buffer is too small"))
+ return -EINVAL;
+
+ work = asn1_encode_sequence(work, end_work, NULL, -1);
+ seq = work;
+
+ work = asn1_encode_tag(work, end_work, 0, NULL, -1);
+ tag = work;
+
+ work = asn1_encode_integer(work, end_work, cmd);
+ asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
+
+ work = asn1_encode_tag(work, end_work, 1, NULL, -1);
+ tag = work;
+
+ work = asn1_encode_octet_string(work, end_work,
+ pols->policies[i],
+ pols->len[i]);
+
+ asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
+
+ seq = asn1_encode_sequence(seq, end_work, NULL, work - seq);
+ if (IS_ERR(seq)) {
+ ret = PTR_ERR(seq);
+ goto err;
+ }
+ }
+ ptr = asn1_encode_sequence(buf, buf + SCRATCH_SIZE, buf + PAGE_SIZE,
+ work - buf - PAGE_SIZE);
+ if (IS_ERR(ptr)) {
+ ret = PTR_ERR(ptr);
+ goto err;
+ }
+
+ *data = buf;
+ *len = ptr - buf;
+
+ return 0;
+
+ err:
+ kfree(buf);
+ return ret;
+}
+
+int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
+{
+ int i, rc;
+ u32 handle;
+ const char *failure;
+
+ rc = tpm2_start_policy_session(chip, &handle, pols->hash);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < pols->count; i++) {
+ u32 cmd = pols->code[i];
+ struct tpm_buf buf;
+
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
+ if (rc)
+ return rc;
+
+ tpm_buf_append_u32(&buf, handle);
+
+ switch (cmd) {
+ case TPM2_CC_POLICY_PCR:
+ failure = "PCR";
+ /*
+ * for reasons best known to the TCG we have
+ * to reverse the two arguments to send to the
+ * policy command
+ */
+ tpm_buf_append_u16(&buf, pols->hash_size);
+ tpm_buf_append(&buf, pols->policies[i] + pols->len[i] -
+ pols->hash_size, pols->hash_size);
+ tpm_buf_append(&buf, pols->policies[i],
+ pols->len[i] - pols->hash_size);
+ break;
+
+ default:
+ failure = "unknown policy";
+ if (pols->len[i])
+ tpm_buf_append(&buf, pols->policies[i],
+ pols->len[i]);
+
+ break;
+ }
+
+ rc = tpm_transmit_cmd(chip, &buf, 0, "updating policy");
+ tpm_buf_destroy(&buf);
+ if (rc) {
+ pr_notice("TPM policy %s failed, rc=%d\n",
+ failure, rc);
+ tpm2_end_auth_session(chip);
+ return -EPERM;
+ }
+ }
+
+ return 0;
+}
diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
new file mode 100644
index 000000000000..b20e9c3e2f06
--- /dev/null
+++ b/security/keys/trusted-keys/tpm2-policy.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+struct tpm2_key_context {
+ u32 parent;
+ const u8 *pub;
+ u32 pub_len;
+ const u8 *priv;
+ u32 priv_len;
+ const u8 *policies[TPM2_MAX_POLICIES];
+ u32 policy_code[TPM2_MAX_POLICIES];
+ u16 policy_len[TPM2_MAX_POLICIES];
+ u8 policy_count;
+};
+
+struct tpm2_policies {
+ u32 code[TPM2_MAX_POLICIES];
+ u8 *policies[TPM2_MAX_POLICIES];
+ u16 len[TPM2_MAX_POLICIES];
+ u8 count;
+ int hash; /* crypto not TPM hash algorithm */
+ u16 hash_size;
+};
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+int tpm2_key_policy_process(struct tpm2_key_context *ctx,
+ struct trusted_key_payload *payload);
+int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash,
+ u8 *policydigest, u32 *plen);
+int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len);
+int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols);
+#else
+static inline int tpm2_key_policy_process(struct tpm2_key_context *ctx,
+ struct trusted_key_payload *payload)
+{
+ return 0;
+}
+static inline int tpm2_generate_policy_digest(struct tpm2_policies *pols,
+ u32 hash,
+ u8 *policydigest, u32 *plen)
+{
+ return -EINVAL;
+}
+static inline int tpm2_encode_policy(struct tpm2_policies *pols,
+ u8 **data, u32 *len)
+{
+ return -EINVAL;
+}
+static inline int tpm2_get_policy_session(struct tpm_chip *chip,
+ struct tpm2_policies *pols)
+{
+ return -EINVAL;
+}
+#endif
diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
index f57f869ad600..1684bd8f725e 100644
--- a/security/keys/trusted-keys/tpm2key.asn1
+++ b/security/keys/trusted-keys/tpm2key.asn1
@@ -1,11 +1,24 @@
---
--- ASN.1 for TPM 2.0 keys
---
+--- Note: This isn't quite the definition in the standard
+--- However, the Linux asn.1 parser doesn't understand
+--- [2] EXPLICIT SEQUENCE OF OPTIONAL
+--- So there's an extra intermediate TPMPolicySequence
+--- definition to work around this
TPMKey ::= SEQUENCE {
type OBJECT IDENTIFIER ({tpm2_key_type}),
emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
+ policy [1] EXPLICIT TPMPolicySequence OPTIONAL,
parent INTEGER ({tpm2_key_parent}),
pubkey OCTET STRING ({tpm2_key_pub}),
privkey OCTET STRING ({tpm2_key_priv})
}
+
+TPMPolicySequence ::= SEQUENCE OF TPMPolicy
+
+TPMPolicy ::= SEQUENCE {
+ commandCode [0] EXPLICIT INTEGER ({tpm2_key_code}),
+ commandPolicy [1] EXPLICIT OCTET STRING ({tpm2_key_policy})
+ }
diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
index 5113aeae5628..53f0f15b0f59 100644
--- a/security/keys/trusted-keys/trusted_core.c
+++ b/security/keys/trusted-keys/trusted_core.c
@@ -221,6 +221,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
struct trusted_key_payload *p;
p = container_of(rcu, struct trusted_key_payload, rcu);
+ kfree_sensitive(p->policies);
kfree_sensitive(p);
}
@@ -311,7 +312,11 @@ static long trusted_read(const struct key *key, char *buffer,
*/
static void trusted_destroy(struct key *key)
{
- kfree_sensitive(key->payload.data[0]);
+ struct trusted_key_payload *p;
+
+ p = key->payload.data[0];
+ kfree_sensitive(p->policies);
+ kfree_sensitive(p);
}
struct key_type key_type_trusted = {
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 94ff9ccae66e..64c922bbc36c 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -17,6 +17,7 @@
#include <asm/unaligned.h>
#include "tpm2key.asn1.h"
+#include "tpm2-policy.h"
static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
@@ -54,6 +55,21 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
work = asn1_encode_tag(work, end_work, 0, bool, w - bool);
}
+ if (payload->policies) {
+ u8 *encoded_pols;
+ u32 encoded_pol_len;
+ int ret;
+
+ ret = tpm2_encode_policy(payload->policies, &encoded_pols,
+ &encoded_pol_len);
+ if (ret)
+ return ret;
+
+ work = asn1_encode_tag(work, end_work, 1, encoded_pols,
+ encoded_pol_len);
+ kfree(encoded_pols);
+ }
+
/*
* Assume both octet strings will encode to a 2 byte definite length
*
@@ -77,14 +93,6 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
return work1 - payload->blob;
}
-struct tpm2_key_context {
- u32 parent;
- const u8 *pub;
- u32 pub_len;
- const u8 *priv;
- u32 priv_len;
-};
-
static int tpm2_key_decode(struct trusted_key_payload *payload,
struct trusted_key_options *options,
u8 **buf)
@@ -107,6 +115,12 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
if (!blob)
return -ENOMEM;
+ ret = tpm2_key_policy_process(&ctx, payload);
+ if (ret) {
+ kfree(blob);
+ return ret;
+ }
+
*buf = blob;
options->keyhandle = ctx.parent;
@@ -223,16 +237,85 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
int blob_len = 0;
- int hash = tpm2_crypto_to_alg(options->hash);
+ int name_alg = tpm2_crypto_to_alg(options->hash);
u32 flags;
int rc;
+ static const int POLICY_SIZE = 2 * PAGE_SIZE;
+ u8 *scratch = NULL;
+ const bool generate_policy = options->pcrinfo_len;
- if (hash < 0)
+ if (name_alg < 0)
return -EINVAL;
if (!options->keyhandle)
return -EINVAL;
+
+ if (generate_policy && payload->policies)
+ /*
+ * can't specify both policy construction options
+ * and passed in policy set
+ */
+ return -EINVAL;
+
+ if (generate_policy) {
+ struct tpm2_policies *pols;
+
+ pols = kmalloc(POLICY_SIZE, GFP_KERNEL);
+ if (!pols)
+ return -ENOMEM;
+ pols->count = 0;
+ payload->policies = pols;
+ scratch = (u8 *)(pols + 1);
+ }
+
+ if (options->pcrinfo_len) {
+ struct tpm2_policies *pols = payload->policies;
+ int i;
+ /* 4 array len */
+ const int len = 4 + options->pcrinfo_len;
+
+ i = pols->count++;
+ pols->len[i] = len;
+ pols->policies[i] = scratch;
+ pols->code[i] = TPM2_CC_POLICY_PCR;
+
+ /* only a single TPMS_PCR_SELECTION */
+ put_unaligned_be32(1, &scratch[0]);
+ memcpy(&scratch[4], options->pcrinfo, options->pcrinfo_len);
+ scratch += len;
+ }
+
+ if (options->policydigest_len != 0 && payload->policies)
+ /* can't specify both a digest and a policy */
+ return -EINVAL;
+
+ /*
+ * if we already have a policy, we have to add authorization
+ * to it. If we don't, we can simply follow the usual
+ * non-policy route.
+ */
+ if (generate_policy && options->blobauth_len) {
+ struct tpm2_policies *pols;
+ int i;
+
+ pols = payload->policies;
+ i = pols->count++;
+
+ /* the TPM2_PolicyPassword command has no payload */
+ pols->len[i] = 0;
+ pols->code[i] = TPM2_CC_POLICY_AUTHVALUE;
+ }
+
+ if (payload->policies) {
+ rc = tpm2_generate_policy_digest(payload->policies,
+ options->hash,
+ options->policydigest,
+ &options->policydigest_len);
+ if (rc)
+ return rc;
+ }
+
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
@@ -271,7 +354,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
/* public */
tpm_buf_reset_sized(&sized);
tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
- tpm_buf_append_u16(&sized, hash);
+ tpm_buf_append_u16(&sized, name_alg);
/* key properties */
flags = 0;
@@ -467,9 +550,9 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
u8 *data;
int rc;
- rc = tpm2_start_auth_session(chip);
- if (rc)
- return rc;
+ if (payload->policies && options->policyhandle)
+ /* can't have both a passed in policy and a key resident one */
+ return -EINVAL;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
if (rc) {
@@ -477,6 +560,13 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
return rc;
}
+ if (payload->policies)
+ rc = tpm2_get_policy_session(chip, payload->policies);
+ else
+ rc = tpm2_start_auth_session(chip);
+ if (rc)
+ goto out;
+
tpm_buf_append_name(chip, &buf, blob_handle, NULL);
if (!options->policyhandle) {
@@ -505,8 +595,14 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
rc = tpm_buf_check_hmac_response(chip, &buf, rc);
- if (rc > 0)
+ if (rc > 0) {
+ rc = tpm2_error_code(rc);
+ if (rc == TPM2_RC_BAD_AUTH)
+ pr_info("Bad blobauth\n");
+ else if (rc == TPM2_RC_AUTH_FAIL)
+ pr_info("Bad blobauth (DA Counter incremented)\n");
rc = -EPERM;
+ }
if (!rc) {
data_len = be16_to_cpup(
@@ -574,3 +670,24 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
return rc;
}
+
+/*
+ * weak symbols for policy statements in tpm2key.asn1 in case
+ * tpm2-policy.c can't be built
+ */
+
+int __weak tpm2_key_code(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ pr_err("TPM key policy is unsupported without CONFIG_TCG_TPM2_HMAC=Y\n");
+
+ return -EINVAL;
+}
+
+int __weak tpm2_key_policy(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ return -EINVAL;
+}
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
` (2 preceding siblings ...)
2024-05-24 13:04 ` [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-07-16 12:01 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 5/6] KEYS: trusted: implement counter/timer policy James Bottomley
` (2 subsequent siblings)
6 siblings, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
This patch adds a policy= argument to key creation. The policy is the
standard tss policymaker format and each separate policy line must
have a newline after it.
Thus to construct a policy requiring authorized value and pcr 16
locking using a sha256 hash, the policy (policy.txt) file would be two
lines:
0000017F00000001000B03000001303095B49BE85E381E5B20E557E46363EF55B0F43B132C2D8E3DE9AC436656F2
0000016b
This can be inserted into the key with
keyctl add trusted kmk "new 32 policy=`cat policy.txt` keyhandle=0x81000001 hash=sha256" @u
Note that although a few policies work like this, most require special
handling which must be added to the kernel policy construction
routine.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
.../security/keys/trusted-encrypted.rst | 17 +++++-
security/keys/trusted-keys/tpm2-policy.c | 53 +++++++++++++++++++
security/keys/trusted-keys/tpm2-policy.h | 5 ++
security/keys/trusted-keys/trusted_tpm1.c | 15 ++++++
4 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index c37c08956ec1..fbb41cf16f30 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -233,6 +233,9 @@ Usage::
policyhandle= handle to an authorization policy session that defines the
same policy and with the same hash algorithm as was used to
seal the key.
+ policy= specify an arbitrary set of policies. These must
+ be in policymaker format with each separate
+ policy line newline terminated.
"keyctl print" returns an ascii hex copy of the sealed key, which is in standard
TPM_STORED_DATA format. The key length for new keys are always in bytes.
@@ -377,6 +380,19 @@ the sha1 pcr16 bank you'd say::
because the trailing hash is the sha256sum of 20 zero bytes.
+You can also specify arbitrary policy in policymaker format, so a two
+value policy (the pcr example above and authvalue) would look like
+this in policymaker format::
+
+ 0000017F000000010004030000016768033e216468247bd031a0a2d9876d79818f8f
+ 0000016b
+
+This can be placed in a file (say policy.txt) and then added to the key as::
+
+ $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha1 policy=`cat policy.txt`" @u
+
+The newlines in the file policy.txt will be automatically processed.
+
Reseal (TPM specific) a trusted key under new PCR values::
$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
@@ -447,7 +463,6 @@ Another new format 'enc32' has been defined in order to support encrypted keys
with payload size of 32 bytes. This will initially be used for nvdimm security
but may expand to other usages that require 32 bytes payload.
-
TPM 2.0 ASN.1 Key Format
------------------------
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
index 8c3a09762c10..a731c10d9bba 100644
--- a/security/keys/trusted-keys/tpm2-policy.c
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -323,3 +323,56 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
return 0;
}
+
+int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
+{
+ struct tpm2_policies *pols;
+ char *p;
+ u8 *ptr;
+ int i = 0, left = PAGE_SIZE, res;
+
+ pols = kmalloc(left, GFP_KERNEL);
+ if (!pols)
+ return -ENOMEM;
+
+ ptr = (u8 *)(pols + 1);
+ left -= ptr - (u8 *)pols;
+
+ while ((p = strsep(&str, "\n"))) {
+ if (*p == '\0' || *p == '\n')
+ continue;
+
+ pols->len[i] = strlen(p)/2;
+ if (pols->len[i] > left) {
+ res = -E2BIG;
+ goto err;
+ }
+
+ res = hex2bin(ptr, p, pols->len[i]);
+ if (res)
+ goto err;
+
+ /* get command code and skip past */
+ pols->code[i] = get_unaligned_be32(ptr);
+ pols->policies[i] = ptr + 4;
+ ptr += pols->len[i];
+ left -= pols->len[i];
+ pols->len[i] -= 4;
+
+ /*
+ * FIXME: this does leave the code embedded in dead
+ * regions of the memory, but it's easier than
+ * hexdumping to a temporary or copying over
+ */
+ i++;
+ }
+
+ pols->count = i;
+ *ppols = pols;
+
+ return 0;
+
+ err:
+ kfree(pols);
+ return res;
+}
diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
index b20e9c3e2f06..8ddf235b3fec 100644
--- a/security/keys/trusted-keys/tpm2-policy.h
+++ b/security/keys/trusted-keys/tpm2-policy.h
@@ -28,6 +28,7 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash,
u8 *policydigest, u32 *plen);
int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len);
int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols);
+int tpm2_parse_policies(struct tpm2_policies **ppols, char *str);
#else
static inline int tpm2_key_policy_process(struct tpm2_key_context *ctx,
struct trusted_key_payload *payload)
@@ -50,4 +51,8 @@ static inline int tpm2_get_policy_session(struct tpm_chip *chip,
{
return -EINVAL;
}
+static inline int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
+{
+ return -EINVAL;
+}
#endif
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 89c9798d1800..4dcc1373dd05 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -22,6 +22,8 @@
#include <keys/trusted_tpm.h>
+#include "tpm2-policy.h"
+
static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
static struct tpm_chip *chip;
@@ -724,6 +726,7 @@ enum {
Opt_hash,
Opt_policydigest,
Opt_policyhandle,
+ Opt_policy,
};
static const match_table_t key_tokens = {
@@ -736,6 +739,7 @@ static const match_table_t key_tokens = {
{Opt_hash, "hash=%s"},
{Opt_policydigest, "policydigest=%s"},
{Opt_policyhandle, "policyhandle=%s"},
+ {Opt_policy, "policy=%s"},
{Opt_err, NULL}
};
@@ -869,6 +873,17 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
return -EINVAL;
opt->policyhandle = handle;
break;
+
+ case Opt_policy:
+ if (pay->policies)
+ return -EINVAL;
+ if (!tpm2)
+ return -EINVAL;
+ res = tpm2_parse_policies(&pay->policies, args[0].from);
+ if (res)
+ return res;
+ break;
+
default:
return -EINVAL;
}
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 5/6] KEYS: trusted: implement counter/timer policy
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
` (3 preceding siblings ...)
2024-05-24 13:04 ` [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-07-16 12:03 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy James Bottomley
2024-05-24 13:24 ` [PATCH 0/6] Add policy to sealed keys Jarkko Sakkinen
6 siblings, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
This is actually a generic policy allowing a range of comparisons
against any value set in the TPM Clock, which includes things like the
reset count, a monotonic millisecond count and the restart count. The
most useful comparison is against the millisecond count for expiring
keys. However, you have to remember that currently Linux doesn't try
to sync the epoch timer with the TPM, so the expiration is actually
measured in how long the TPM itself has been powered on ... the TPM
timer doesn't count while the system is powered down. The millisecond
counter is a u64 quantity found at offset 8 in the timer structure,
and the <= comparision operand is 9, so a policy set to expire after the
TPM has been up for 100 seconds would look like
0000016d00000000000f424000080009
Where 0x16d is the counter timer policy code and 0xf4240 is 100 000 in
hex.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
.../security/keys/trusted-encrypted.rst | 29 +++++++++++++++
include/linux/tpm.h | 1 +
security/keys/trusted-keys/tpm2-policy.c | 37 +++++++++++++++++++
3 files changed, 67 insertions(+)
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index fbb41cf16f30..7abda48089d8 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -545,3 +545,32 @@ DCP Blob Format
.. kernel-doc:: security/keys/trusted-keys/trusted_dcp.c
:identifiers: struct dcp_blob_fmt
+
+Appendix
+--------
+
+TPM 2.0 Policies
+----------------
+
+The current TPM supports PCR lock policies as documented above and
+CounterTimer policies which can be used to create expiring keys. One
+caveat with expiring keys is that the TPM millisecond counter does not
+update while a system is powered off and Linux does not sync the TPM
+millisecond count with its internal clock, so the best you can expire
+in is in terms of how long any given TPM has been powered on. (FIXME:
+Linux should simply update the millisecond clock to the current number
+of seconds past the epoch on boot).
+
+A CounterTimer policy is expressed in terms of length and offset
+against the TPM clock structure (TPMS_TIME_INFO), which looks like the
+packed structure::
+
+ struct tpms_time_info {
+ u64 uptime; /* time in ms since last start or reset */
+ u64 clock; /* cumulative uptime in ms */
+ u32 resetcount; /* number of times the TPM has been reset */
+ u32 restartcount; /* number of times the TPM has been restarted */
+ u8 safe /* time was safely loaded from NVRam */
+ };
+
+The usual comparison for expiring keys is against clock, at offset 8.
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 154efceec0a4..894e51a7fe3a 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -291,6 +291,7 @@ enum tpm2_command_codes {
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_POLICY_AUTHVALUE = 0x016B,
+ TPM2_CC_POLICY_COUNTER_TIMER = 0x016D,
TPM2_CC_READ_PUBLIC = 0x0173,
TPM2_CC_START_AUTH_SESS = 0x0176,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
index a731c10d9bba..c0508cb95923 100644
--- a/security/keys/trusted-keys/tpm2-policy.c
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -63,6 +63,7 @@ static int tpm2_validate_policy(struct tpm2_policies *pols)
for (i = 0; i < pols->count; i++) {
switch (pols->code[i]) {
+ case TPM2_CC_POLICY_COUNTER_TIMER:
case TPM2_CC_POLICY_PCR:
case TPM2_CC_POLICY_AUTHVALUE:
break;
@@ -177,6 +178,7 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols,
u8 *policy = pols->policies[i];
int len = pols->len[i];
u32 cmd = pols->code[i];
+ u8 digest[MAX_DIGEST_SIZE];
u8 code[4];
SHASH_DESC_ON_STACK(sdesc, tfm);
@@ -192,6 +194,19 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols,
put_unaligned_be32(cmd, code);
crypto_shash_update(sdesc, code, 4);
+ /* commands that need special handling */
+ if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
+ SHASH_DESC_ON_STACK(sdesc1, tfm);
+
+ sdesc1->tfm = tfm;
+
+ /* counter timer policies are double hashed */
+ crypto_shash_digest(sdesc1, policy, len,
+ digest);
+ policy = digest;
+ len = *plen;
+ }
+
if (len)
crypto_shash_update(sdesc, policy, len);
@@ -302,6 +317,28 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
pols->len[i] - pols->hash_size);
break;
+ case TPM2_CC_POLICY_COUNTER_TIMER: {
+ /*
+ * the format of this is the last two u16
+ * quantities are the offset and operation
+ * respectively. The rest is operandB which
+ * must be zero padded in a hash digest
+ */
+ u16 opb_len = pols->len[i] - 4;
+
+ if (opb_len > pols->hash_size)
+ return -EINVAL;
+
+ tpm_buf_append_u16(&buf, opb_len);
+ tpm_buf_append(&buf, pols->policies[i], opb_len);
+
+ /* offset and operand*/
+ tpm_buf_append(&buf, pols->policies[i] + opb_len, 4);
+ failure = "Counter Timer";
+
+ break;
+ }
+
default:
failure = "unknown policy";
if (pols->len[i])
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
` (4 preceding siblings ...)
2024-05-24 13:04 ` [PATCH 5/6] KEYS: trusted: implement counter/timer policy James Bottomley
@ 2024-05-24 13:04 ` James Bottomley
2024-07-16 12:03 ` Jarkko Sakkinen
2024-05-24 13:24 ` [PATCH 0/6] Add policy to sealed keys Jarkko Sakkinen
6 siblings, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-05-24 13:04 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, keyrings
Signed policy allows key policies to be modified after the TPM key is
created, provided the new policy is signed with a private key whose
public part is encoded into the initial policy. How this works is
described in
https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
Since this means that the key structure now contains public keys and
signatures, the maximum blob size has to be expanded simply to
accommodate a key with several policies. The code assumes (as does
all other signed policy engines) that the first policy is the most
likely one to succeed, so it tries all the available signed policies
in first to last order and loads the key when one of them succeeds.
This code allows the kernel to process signed policy keys correctly,
it does not allow the kernel to create them.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
drivers/char/tpm/tpm2-sessions.c | 6 +
include/keys/trusted-type.h | 3 +-
include/linux/tpm.h | 6 +
security/keys/trusted-keys/tpm2-policy.c | 473 ++++++++++++++++------
security/keys/trusted-keys/tpm2-policy.h | 19 +-
security/keys/trusted-keys/tpm2key.asn1 | 12 +-
security/keys/trusted-keys/trusted_tpm2.c | 63 +--
7 files changed, 434 insertions(+), 148 deletions(-)
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 63c175b2165c..c2b73283c46f 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -1365,3 +1365,9 @@ int tpm2_sessions_init(struct tpm_chip *chip)
return rc;
}
+
+struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip)
+{
+ return chip->auth->tfm;
+}
+EXPORT_SYMBOL(tpm2_get_policy_hash);
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 5d1d481a8a19..a6999800055e 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -19,11 +19,12 @@
#define MIN_KEY_SIZE 32
#define MAX_KEY_SIZE 128
-#define MAX_BLOB_SIZE 512
+#define MAX_BLOB_SIZE 4096
#define MAX_PCRINFO_SIZE 128
#define MAX_DIGEST_SIZE 64
#define TPM2_MAX_POLICIES 16
+#define TPM2_MAX_AUTHS 8
struct trusted_key_payload {
struct rcu_head rcu;
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 894e51a7fe3a..09f14482675b 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -290,6 +290,8 @@ enum tpm2_command_codes {
TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
+ TPM2_CC_LOAD_EXTERNAL = 0x0167,
+ TPM2_CC_POLICY_AUTHORIZE = 0x016A,
TPM2_CC_POLICY_AUTHVALUE = 0x016B,
TPM2_CC_POLICY_COUNTER_TIMER = 0x016D,
TPM2_CC_READ_PUBLIC = 0x0173,
@@ -299,14 +301,17 @@ enum tpm2_command_codes {
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_POLICY_PCR = 0x017F,
+ TPM2_CC_POLICY_RESTART = 0x0180,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
+ TPM2_CC_POLICY_GET_DIGEST = 0x0189,
TPM2_CC_CREATE_LOADED = 0x0191,
TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
};
enum tpm2_permanent_handles {
+ TPM2_RH_OWNER = 0x40000001,
TPM2_RH_NULL = 0x40000007,
TPM2_RS_PW = 0x40000009,
};
@@ -578,6 +583,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
int tpm2_start_auth_session(struct tpm_chip *chip);
int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
+struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip);
void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
u32 handle, u8 *name);
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
index c0508cb95923..f9ee57fed8fe 100644
--- a/security/keys/trusted-keys/tpm2-policy.c
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -28,13 +28,28 @@ int tpm2_key_code(void *context, size_t hdrlen,
u32 code = 0;
const u8 *v = value;
int i;
+ u8 a = ctx->auth_policies;
for (i = 0; i < vlen; i++) {
code <<= 8;
code |= v[i];
}
- ctx->policy_code[ctx->policy_count] = code;
+ ctx->policy_code[a][ctx->policy_count[a]] = code;
+
+ return 0;
+}
+
+int tpm2_pol_seq(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct tpm2_key_context *ctx = context;
+
+ ctx->auth_policies++;
+
+ if (ctx->auth_policies > TPM2_MAX_AUTHS)
+ return -EINVAL;
return 0;
}
@@ -44,9 +59,15 @@ int tpm2_key_policy(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct tpm2_key_context *ctx = context;
+ u8 a = ctx->auth_policies;
+ u8 policy_count = ctx->policy_count[a]++;
+
+ if (policy_count >= TPM2_MAX_POLICIES)
+ return -EINVAL;
- ctx->policies[ctx->policy_count] = value;
- ctx->policy_len[ctx->policy_count++] = vlen;
+ ctx->policies[a][policy_count] = value;
+ ctx->policy_len[a][policy_count] = vlen;
+ ctx->policy_tot_len += vlen;
return 0;
}
@@ -56,21 +77,24 @@ int tpm2_key_policy(void *context, size_t hdrlen,
*/
static int tpm2_validate_policy(struct tpm2_policies *pols)
{
- int i;
+ int i, j;
- if (pols->count == 0)
+ if (pols->auths == 0)
return 0;
- for (i = 0; i < pols->count; i++) {
- switch (pols->code[i]) {
- case TPM2_CC_POLICY_COUNTER_TIMER:
- case TPM2_CC_POLICY_PCR:
- case TPM2_CC_POLICY_AUTHVALUE:
- break;
- default:
- pr_info("tpm2 policy 0x%x is unsupported\n",
- pols->code[i]);
+ for (i = 0; i < pols->auths; i++) {
+ for (j = 0; j < pols->count[i]; j++) {
+ switch (pols->code[i][j]) {
+ case TPM2_CC_POLICY_COUNTER_TIMER:
+ case TPM2_CC_POLICY_PCR:
+ case TPM2_CC_POLICY_AUTHVALUE:
+ case TPM2_CC_POLICY_AUTHORIZE:
+ break;
+ default:
+ pr_info("tpm2 policy 0x%x is unsupported\n",
+ pols->code[i][j]);
return -EINVAL;
+ }
}
}
@@ -89,36 +113,35 @@ static int tpm2_validate_policy(struct tpm2_policies *pols)
int tpm2_key_policy_process(struct tpm2_key_context *ctx,
struct trusted_key_payload *payload)
{
- int tot_len = 0;
u8 *buf;
- int i, ret, len = 0;
+ int i, j, ret, len = 0;
struct tpm2_policies *pols;
u16 name_alg;
- if (ctx->policy_count == 0)
+ if (ctx->policy_tot_len == 0)
return 0;
- for (i = 0; i < ctx->policy_count; i++)
- tot_len += ctx->policy_len[i];
- tot_len += sizeof(*pols);
-
- pols = kmalloc(tot_len, GFP_KERNEL);
+ pols = kmalloc(ctx->policy_tot_len + sizeof(*pols), GFP_KERNEL);
if (!pols)
return -ENOMEM;
payload->policies = pols;
buf = (u8 *)(pols + 1);
- for (i = 0; i < ctx->policy_count; i++) {
- pols->policies[i] = &buf[len];
- pols->len[i] = ctx->policy_len[i];
- pols->code[i] = ctx->policy_code[i];
- if (pols->len[i])
- memcpy(pols->policies[i], ctx->policies[i],
- ctx->policy_len[i]);
- len += ctx->policy_len[i];
+ for (i = 0; i < ctx->auth_policies; i++) {
+ for (j = 0; j < ctx->policy_count[i]; j++) {
+ pols->policies[i][j] = &buf[len];
+ pols->len[i][j] = ctx->policy_len[i][j];
+ pols->code[i][j] = ctx->policy_code[i][j];
+ if (pols->len[i][j])
+ memcpy(pols->policies[i][j],
+ ctx->policies[i][j],
+ ctx->policy_len[i][j]);
+ len += ctx->policy_len[i][j];
+ }
+ pols->count[i] = ctx->policy_count[i];
}
- pols->count = ctx->policy_count;
+ pols->auths = ctx->auth_policies;
ret = tpm2_validate_policy(pols);
if (ret)
@@ -148,7 +171,7 @@ int tpm2_key_policy_process(struct tpm2_key_context *ctx,
int tpm2_generate_policy_digest(struct tpm2_policies *pols,
u32 hash, u8 *policydigest, u32 *plen)
{
- int i;
+ int i, j;
struct crypto_shash *tfm;
int rc;
@@ -174,45 +197,47 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols,
/* policy digests always start out all zeros */
memset(policydigest, 0, rc);
- for (i = 0; i < pols->count; i++) {
- u8 *policy = pols->policies[i];
- int len = pols->len[i];
- u32 cmd = pols->code[i];
- u8 digest[MAX_DIGEST_SIZE];
- u8 code[4];
- SHASH_DESC_ON_STACK(sdesc, tfm);
+ for (i = 0; i < pols->auths; i++) {
+ for (j = 0; j < pols->count[i]; j++) {
+ u8 *policy = pols->policies[i][j];
+ int len = pols->len[i][j];
+ u32 cmd = pols->code[i][j];
+ u8 digest[MAX_DIGEST_SIZE];
+ u8 code[4];
+ SHASH_DESC_ON_STACK(sdesc, tfm);
- sdesc->tfm = tfm;
- rc = crypto_shash_init(sdesc);
- if (rc)
- goto err;
+ sdesc->tfm = tfm;
+ rc = crypto_shash_init(sdesc);
+ if (rc)
+ goto err;
- /* first hash the previous digest */
- crypto_shash_update(sdesc, policydigest, *plen);
+ /* first hash the previous digest */
+ crypto_shash_update(sdesc, policydigest, *plen);
- /* then hash the command code */
- put_unaligned_be32(cmd, code);
- crypto_shash_update(sdesc, code, 4);
+ /* then hash the command code */
+ put_unaligned_be32(cmd, code);
+ crypto_shash_update(sdesc, code, 4);
- /* commands that need special handling */
- if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
- SHASH_DESC_ON_STACK(sdesc1, tfm);
+ /* commands that need special handling */
+ if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
+ SHASH_DESC_ON_STACK(sdesc1, tfm);
- sdesc1->tfm = tfm;
+ sdesc1->tfm = tfm;
- /* counter timer policies are double hashed */
- crypto_shash_digest(sdesc1, policy, len,
- digest);
- policy = digest;
- len = *plen;
- }
+ /* counter timer policies are double hashed */
+ crypto_shash_digest(sdesc1, policy, len,
+ digest);
+ policy = digest;
+ len = *plen;
+ }
- if (len)
- crypto_shash_update(sdesc, policy, len);
+ if (len)
+ crypto_shash_update(sdesc, policy, len);
- /* now output the intermediate to the policydigest */
- crypto_shash_final(sdesc, policydigest);
+ /* now output the intermediate to the policydigest */
+ crypto_shash_final(sdesc, policydigest);
+ }
}
rc = 0;
@@ -228,41 +253,45 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
u8 *work = buf + SCRATCH_SIZE;
u8 *ptr;
u8 *end_work = work + SCRATCH_SIZE;
- int i, ret;
+ int i, j, ret;
if (!buf)
return -ENOMEM;
- for (i = 0; i < pols->count; i++) {
- u8 *seq, *tag;
- u32 cmd = pols->code[i];
+ for (i = 0; i < pols->auths; i++) {
+ for (j = 0; j < pols->count[i]; j++) {
+ u8 *seq, *tag;
+ u32 cmd = pols->code[i][j];
- if (WARN(work - buf + 14 + pols->len[i] > 2 * SCRATCH_SIZE,
- "BUG: scratch buffer is too small"))
- return -EINVAL;
+ if (WARN(work - buf + 14 + pols->len[i][j] >
+ 2 * SCRATCH_SIZE,
+ "BUG: scratch buffer is too small"))
+ return -EINVAL;
- work = asn1_encode_sequence(work, end_work, NULL, -1);
- seq = work;
+ work = asn1_encode_sequence(work, end_work, NULL, -1);
+ seq = work;
- work = asn1_encode_tag(work, end_work, 0, NULL, -1);
- tag = work;
+ work = asn1_encode_tag(work, end_work, 0, NULL, -1);
+ tag = work;
- work = asn1_encode_integer(work, end_work, cmd);
- asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
+ work = asn1_encode_integer(work, end_work, cmd);
+ asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
- work = asn1_encode_tag(work, end_work, 1, NULL, -1);
- tag = work;
+ work = asn1_encode_tag(work, end_work, 1, NULL, -1);
+ tag = work;
- work = asn1_encode_octet_string(work, end_work,
- pols->policies[i],
- pols->len[i]);
+ work = asn1_encode_octet_string(work, end_work,
+ pols->policies[i][j],
+ pols->len[i][j]);
- asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
+ asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
- seq = asn1_encode_sequence(seq, end_work, NULL, work - seq);
- if (IS_ERR(seq)) {
- ret = PTR_ERR(seq);
- goto err;
+ seq = asn1_encode_sequence(seq, end_work, NULL,
+ work - seq);
+ if (IS_ERR(seq)) {
+ ret = PTR_ERR(seq);
+ goto err;
+ }
}
}
ptr = asn1_encode_sequence(buf, buf + SCRATCH_SIZE, buf + PAGE_SIZE,
@@ -282,18 +311,131 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
return ret;
}
-int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
+static int tpm2_policy_restart(struct tpm_chip *chip, u32 handle)
{
- int i, rc;
- u32 handle;
- const char *failure;
+ struct tpm_buf buf;
+ int rc;
- rc = tpm2_start_policy_session(chip, &handle, pols->hash);
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_RESTART);
+ if (rc)
+ return rc;
+
+ tpm_buf_append_u32(&buf, handle);
+
+ rc = tpm_transmit_cmd(chip, &buf, 0, "restarting policy");
+ tpm_buf_destroy(&buf);
+ if (rc) {
+ pr_notice("TPM policy restart failed, rc=%d\n", rc);
+ return -EPERM;
+ }
+ return 0;
+}
+
+static int tpm2_policy_gettkhash(struct tpm_chip *chip, u8 *pubkey, u8 *nonce,
+ u8 *signature, int siglen,
+ u32 handle, u8 **hash, u8 **name,
+ u8 **ticket)
+{
+ struct tpm_buf buf;
+ int rc;
+ int len;
+ u32 sigkey;
+ off_t offset;
+ SHASH_DESC_ON_STACK(sdesc, tpm2_get_policy_hash(chip));
+
+ sdesc->tfm = tpm2_get_policy_hash(chip);
+
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_GET_DIGEST);
if (rc)
return rc;
- for (i = 0; i < pols->count; i++) {
- u32 cmd = pols->code[i];
+ tpm_buf_append_u32(&buf, handle);
+
+ rc = tpm_transmit_cmd(chip, &buf, 0, "getting policy hash");
+ if (rc)
+ goto out;
+ len = get_unaligned_be16(&buf.data[TPM_HEADER_SIZE]) + 2;
+ rc = -ENOMEM;
+ *hash = kmalloc(len, GFP_KERNEL);
+ if (!*hash)
+ goto out;
+ memcpy(*hash, &buf.data[TPM_HEADER_SIZE], len);
+
+ tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_LOAD_EXTERNAL);
+
+ /* empty sensitive */
+ tpm_buf_append_u16(&buf, 0);
+ /* TPM2B_PUBLIC */
+ len = get_unaligned_be16(pubkey) + 2;
+ tpm_buf_append(&buf, pubkey, len);
+ /* hierarchy (use null because never a password) */
+ tpm_buf_append_u32(&buf, TPM2_RH_OWNER);
+
+ rc = tpm_transmit_cmd(chip, &buf, 4, "loading external key");
+ if (rc)
+ goto out;
+
+ offset = TPM_HEADER_SIZE;
+ sigkey = tpm_buf_read_u32(&buf, &offset);
+ len = get_unaligned_be16(&buf.data[offset]) + 2;
+ *name = kmalloc(len, GFP_KERNEL);
+ if (!*name) {
+ tpm2_flush_context(chip, sigkey);
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(*name, &buf.data[offset], len);
+
+ tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_VERIFY_SIGNATURE);
+ /* handle of public key to verify with */
+ tpm_buf_append_u32(&buf, sigkey);
+ /* digest hash(policy||nonce) */
+ len = get_unaligned_be16(*hash);
+ tpm_buf_append_u16(&buf, len);
+ /* now compute the signed data which is hash(policy||nonce) */
+ crypto_shash_init(sdesc);
+ len = get_unaligned_be16(*hash); /* better be the tfm hash size */
+ crypto_shash_update(sdesc, *hash + 2, len);
+ len = get_unaligned_be16(nonce);
+ crypto_shash_update(sdesc, nonce + 2, len);
+ crypto_shash_final(sdesc, &buf.data[buf.length]);
+ buf.length += len;
+ /* signature */
+ tpm_buf_append(&buf, signature, siglen);
+
+ rc = tpm_transmit_cmd(chip, &buf, 4, "verifying signature");
+ tpm2_flush_context(chip, sigkey);
+ if (rc)
+ goto out;
+
+ len = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
+ *ticket = kmalloc(len, GFP_KERNEL);
+ if (!*ticket) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(*ticket, &buf.data[TPM_HEADER_SIZE], len);
+
+ out:
+ if (rc) {
+ kfree(*hash);
+ *hash = NULL;
+ kfree(*name);
+ *name = NULL;
+ }
+ tpm_buf_destroy(&buf);
+ return rc;
+}
+
+
+static int tpm2_try_policy(struct tpm_chip *chip, struct tpm2_policies *pols,
+ u32 handle, int p)
+{
+ int i, rc;
+ const char *failure;
+
+ for (i = 0; i < pols->count[p]; i++) {
+ u32 cmd = pols->code[p][i];
struct tpm_buf buf;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
@@ -311,10 +453,11 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
* policy command
*/
tpm_buf_append_u16(&buf, pols->hash_size);
- tpm_buf_append(&buf, pols->policies[i] + pols->len[i] -
+ tpm_buf_append(&buf, pols->policies[p][i]
+ + pols->len[p][i] -
pols->hash_size, pols->hash_size);
- tpm_buf_append(&buf, pols->policies[i],
- pols->len[i] - pols->hash_size);
+ tpm_buf_append(&buf, pols->policies[p][i],
+ pols->len[p][i] - pols->hash_size);
break;
case TPM2_CC_POLICY_COUNTER_TIMER: {
@@ -324,26 +467,82 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
* respectively. The rest is operandB which
* must be zero padded in a hash digest
*/
- u16 opb_len = pols->len[i] - 4;
+ u16 opb_len = pols->len[p][i] - 4;
if (opb_len > pols->hash_size)
return -EINVAL;
tpm_buf_append_u16(&buf, opb_len);
- tpm_buf_append(&buf, pols->policies[i], opb_len);
+ tpm_buf_append(&buf, pols->policies[p][i], opb_len);
/* offset and operand*/
- tpm_buf_append(&buf, pols->policies[i] + opb_len, 4);
+ tpm_buf_append(&buf, pols->policies[p][i] + opb_len, 4);
failure = "Counter Timer";
break;
}
+ case TPM2_CC_POLICY_AUTHORIZE: {
+ u8 *pubkey = pols->policies[p][i];
+ u8 *nonce;
+ u8 *signature;
+ u8 *ticket = NULL;
+ u8 *hash = NULL;
+ u8 *name = NULL;
+ int len, siglen;
+ const int maxlen = pols->len[p][i];
+
+ if (i == 0)
+ /*
+ * If this is the first policy then skip
+ * because we should already have executed
+ * a successful PolicyAuthorize before getting
+ * here
+ */
+ continue;
+
+ len = get_unaligned_be16(pubkey);
+ if (len + 2 > maxlen) {
+ failure = "malformed policy";
+ break;
+ }
+ nonce = pubkey + len + 2;
+ len = get_unaligned_be16(nonce);
+ if (len + 2 > maxlen) {
+ failure = "malformed policy";
+ break;
+ }
+ signature = nonce + len + 2;
+ siglen = pubkey + maxlen - signature;
+ failure = "policy authorize";
+ rc = tpm2_policy_gettkhash(chip, pubkey, nonce,
+ signature, siglen,
+ handle, &hash,
+ &name, &ticket);
+ if (rc)
+ break;
+ len = get_unaligned_be16(hash);
+ tpm_buf_append(&buf, hash, len + 2);
+ kfree(hash);
+
+ len = get_unaligned_be16(nonce);
+ tpm_buf_append(&buf, nonce, len + 2);
+
+ len = get_unaligned_be16(name);
+ tpm_buf_append(&buf, name, len + 2);
+ kfree(name);
+
+ len = get_unaligned_be16(ticket + 6) + 8;
+ tpm_buf_append(&buf, ticket, len);
+ kfree(ticket);
+
+ break;
+ }
default:
failure = "unknown policy";
- if (pols->len[i])
- tpm_buf_append(&buf, pols->policies[i],
- pols->len[i]);
+ if (pols->len[p][i])
+ tpm_buf_append(&buf, pols->policies[p][i],
+ pols->len[p][i]);
break;
}
@@ -353,14 +552,62 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
if (rc) {
pr_notice("TPM policy %s failed, rc=%d\n",
failure, rc);
- tpm2_end_auth_session(chip);
- return -EPERM;
+ return rc;
}
}
-
return 0;
}
+int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
+{
+ int rc;
+ u32 handle;
+
+ if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE &&
+ pols->auths == 1) {
+ pr_notice("TPM Key requires signed policies but has none\n");
+ return -EINVAL;
+ }
+
+ rc = tpm2_start_policy_session(chip, &handle, pols->hash);
+ if (rc)
+ return rc;
+
+ if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE) {
+ int p;
+
+ for (p = 1; p < pols->auths; p++) {
+ if (p != 1) {
+ /* restart policy if looping */
+ rc = tpm2_policy_restart(chip, handle);
+ if (rc)
+ goto out;
+ }
+
+ rc = tpm2_try_policy(chip, pols, handle, p);
+ if (rc) {
+ pr_notice("TPM signed policy %d failed\n", p);
+ } else {
+ pr_notice("TPM signed policy %d succeeded\n",
+ p);
+ break;
+ }
+ }
+ if (rc)
+ /* no signed policies succeeded */
+ goto out;
+ }
+
+ rc = tpm2_try_policy(chip, pols, handle, 0);
+ out:
+ if (rc) {
+ rc = -EPERM;
+ tpm2_end_auth_session(chip);
+ }
+
+ return rc;
+}
+
int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
{
struct tpm2_policies *pols;
@@ -379,22 +626,22 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
if (*p == '\0' || *p == '\n')
continue;
- pols->len[i] = strlen(p)/2;
- if (pols->len[i] > left) {
+ pols->len[0][i] = strlen(p)/2;
+ if (pols->len[0][i] > left) {
res = -E2BIG;
goto err;
}
- res = hex2bin(ptr, p, pols->len[i]);
+ res = hex2bin(ptr, p, pols->len[0][i]);
if (res)
goto err;
/* get command code and skip past */
- pols->code[i] = get_unaligned_be32(ptr);
- pols->policies[i] = ptr + 4;
- ptr += pols->len[i];
- left -= pols->len[i];
- pols->len[i] -= 4;
+ pols->code[0][i] = get_unaligned_be32(ptr);
+ pols->policies[0][i] = ptr + 4;
+ ptr += pols->len[0][i];
+ left -= pols->len[0][i];
+ pols->len[0][i] -= 4;
/*
* FIXME: this does leave the code embedded in dead
@@ -404,7 +651,7 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
i++;
}
- pols->count = i;
+ pols->count[0] = i;
*ppols = pols;
return 0;
diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
index 8ddf235b3fec..da0ab99078b8 100644
--- a/security/keys/trusted-keys/tpm2-policy.h
+++ b/security/keys/trusted-keys/tpm2-policy.h
@@ -6,17 +6,20 @@ struct tpm2_key_context {
u32 pub_len;
const u8 *priv;
u32 priv_len;
- const u8 *policies[TPM2_MAX_POLICIES];
- u32 policy_code[TPM2_MAX_POLICIES];
- u16 policy_len[TPM2_MAX_POLICIES];
- u8 policy_count;
+ const u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u32 policy_code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u16 policy_len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u8 policy_count[TPM2_MAX_AUTHS];
+ u8 auth_policies;
+ int policy_tot_len;
};
struct tpm2_policies {
- u32 code[TPM2_MAX_POLICIES];
- u8 *policies[TPM2_MAX_POLICIES];
- u16 len[TPM2_MAX_POLICIES];
- u8 count;
+ u32 code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u16 len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+ u8 count[TPM2_MAX_AUTHS];
+ u8 auths;
int hash; /* crypto not TPM hash algorithm */
u16 hash_size;
};
diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
index 1684bd8f725e..c5a68b3e354f 100644
--- a/security/keys/trusted-keys/tpm2key.asn1
+++ b/security/keys/trusted-keys/tpm2key.asn1
@@ -5,12 +5,13 @@
--- However, the Linux asn.1 parser doesn't understand
--- [2] EXPLICIT SEQUENCE OF OPTIONAL
--- So there's an extra intermediate TPMPolicySequence
---- definition to work around this
+--- and TPMAuthPolicySequence definitions to work around this
TPMKey ::= SEQUENCE {
type OBJECT IDENTIFIER ({tpm2_key_type}),
emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
- policy [1] EXPLICIT TPMPolicySequence OPTIONAL,
+ policy [1] EXPLICIT TPMPolicySequence OPTIONAL ({tpm2_pol_seq}),
+ authPolicy [3] EXPLICIT TPMAuthPolicySequence OPTIONAL,
parent INTEGER ({tpm2_key_parent}),
pubkey OCTET STRING ({tpm2_key_pub}),
privkey OCTET STRING ({tpm2_key_priv})
@@ -22,3 +23,10 @@ TPMPolicy ::= SEQUENCE {
commandCode [0] EXPLICIT INTEGER ({tpm2_key_code}),
commandPolicy [1] EXPLICIT OCTET STRING ({tpm2_key_policy})
}
+
+TPMAuthPolicySequence ::= SEQUENCE OF TPMAuthPolicy ({tpm2_pol_seq})
+
+TPMAuthPolicy ::= SEQUENCE {
+ name [0] EXPLICIT UTF8String OPTIONAL,
+ policy [1] EXPLICIT TPMPolicySequence
+ }
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 64c922bbc36c..e2d937e44274 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -98,38 +98,45 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
u8 **buf)
{
int ret;
- struct tpm2_key_context ctx;
+ struct tpm2_key_context *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
u8 *blob;
- memset(&ctx, 0, sizeof(ctx));
+ if (!ctx)
+ return -ENOMEM;
- ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,
+ ret = asn1_ber_decoder(&tpm2key_decoder, ctx, payload->blob,
payload->blob_len);
if (ret < 0)
- return ret;
+ goto out;
- if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE)
- return -EINVAL;
+ if (ctx->priv_len + ctx->pub_len > MAX_BLOB_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
- blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL);
- if (!blob)
- return -ENOMEM;
+ blob = kmalloc(ctx->priv_len + ctx->pub_len + 4, GFP_KERNEL);
+ if (!blob) {
+ ret = -ENOMEM;
+ goto out;
+ }
- ret = tpm2_key_policy_process(&ctx, payload);
+ ret = tpm2_key_policy_process(ctx, payload);
if (ret) {
kfree(blob);
- return ret;
+ goto out;
}
*buf = blob;
- options->keyhandle = ctx.parent;
+ options->keyhandle = ctx->parent;
- memcpy(blob, ctx.priv, ctx.priv_len);
- blob += ctx.priv_len;
+ memcpy(blob, ctx->priv, ctx->priv_len);
+ blob += ctx->priv_len;
- memcpy(blob, ctx.pub, ctx.pub_len);
+ memcpy(blob, ctx->pub, ctx->pub_len);
- return 0;
+ out:
+ kfree(ctx);
+ return ret;
}
int tpm2_key_parent(void *context, size_t hdrlen,
@@ -264,7 +271,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
pols = kmalloc(POLICY_SIZE, GFP_KERNEL);
if (!pols)
return -ENOMEM;
- pols->count = 0;
+ pols->count[0] = 0;
+ pols->auths = 1;
payload->policies = pols;
scratch = (u8 *)(pols + 1);
}
@@ -275,10 +283,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
/* 4 array len */
const int len = 4 + options->pcrinfo_len;
- i = pols->count++;
- pols->len[i] = len;
- pols->policies[i] = scratch;
- pols->code[i] = TPM2_CC_POLICY_PCR;
+ i = pols->count[0]++;
+ pols->len[0][i] = len;
+ pols->policies[0][i] = scratch;
+ pols->code[0][i] = TPM2_CC_POLICY_PCR;
/* only a single TPMS_PCR_SELECTION */
put_unaligned_be32(1, &scratch[0]);
@@ -300,11 +308,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
int i;
pols = payload->policies;
- i = pols->count++;
+ i = pols->count[0]++;
/* the TPM2_PolicyPassword command has no payload */
- pols->len[i] = 0;
- pols->code[i] = TPM2_CC_POLICY_AUTHVALUE;
+ pols->len[0][i] = 0;
+ pols->code[0][i] = TPM2_CC_POLICY_AUTHVALUE;
}
if (payload->policies) {
@@ -685,6 +693,13 @@ int __weak tpm2_key_code(void *context, size_t hdrlen,
return -EINVAL;
}
+int __weak tpm2_pol_seq(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ return -EINVAL;
+}
+
int __weak tpm2_key_policy(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
--
2.35.3
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 0/6] Add policy to sealed keys
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
` (5 preceding siblings ...)
2024-05-24 13:04 ` [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy James Bottomley
@ 2024-05-24 13:24 ` Jarkko Sakkinen
6 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-05-24 13:24 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> TPM2 policy is much more complicated than the original TPM 1.2 which
> only supported PCR value binding. TPM2 policy may be a sequence of
> policy statements each of which must be correctly executed and may
> include choices in which set of policy statements will execute
> correctly. The actual policy is identified in the key by a single
> hash, which is the end result of extending all the policy statements.
> However, since it is impossible to reverse engineer the policy
> statements from the hash value, the ASN.1 key format is extended to
> give a broken out list of statements the kernel must execute to get
> the correct policy hash value.
>
> In order to create policy sessions (which are usable as HMAC sessions,
> but also respond to policy statements), the TPM HMAC code is reused to
> create the required policy sessions (while preserving bus security).
> However, because the session hash algorithm must match the name
> algorithm of the sealed data (which is used for the policy hash), the
> TPM session code is changed to use a variable hash algorithm.
>
> The first patch consolidates the hash definitions and conversion
> routines, the second adds both variable hash type and policy support
> and the remaining patches add specific policy statement
> implementations.
>
> James
>
> ---
>
> James Bottomley (6):
> tpm: consolidate TPM to crypto hash algorithm conversion
> tpm: add policy sessions
> KEYS: trusted: add PCR policy to TPM2 keys
> KEYS: trusted: add ability to specify arbitrary policy
> KEYS: trusted: implement counter/timer policy
> KEYS: trusted: add support for TPM keys with signed policy
>
> .../security/keys/trusted-encrypted.rst | 99 ++-
> drivers/char/tpm/tpm2-cmd.c | 8 -
> drivers/char/tpm/tpm2-sessions.c | 313 ++++++---
> include/keys/trusted-type.h | 8 +-
> include/linux/tpm.h | 81 ++-
> security/keys/trusted-keys/Kconfig | 2 +
> security/keys/trusted-keys/Makefile | 3 +
> security/keys/trusted-keys/tpm2-policy.c | 662 ++++++++++++++++++
> security/keys/trusted-keys/tpm2-policy.h | 61 ++
> security/keys/trusted-keys/tpm2key.asn1 | 21 +
> security/keys/trusted-keys/trusted_core.c | 7 +-
> security/keys/trusted-keys/trusted_tpm1.c | 15 +
> security/keys/trusted-keys/trusted_tpm2.c | 206 ++++--
> 13 files changed, 1314 insertions(+), 172 deletions(-)
> create mode 100644 security/keys/trusted-keys/tpm2-policy.c
> create mode 100644 security/keys/trusted-keys/tpm2-policy.h
I'd prefer to this postponed after asymmetric keys and also when
the issues have been fixed from HMAC.
Also I fixed myself some bugs like memory leak and useless WARN
from existing trusted keys code so those needs to be fixed too.
So NAK at the time can be rebased later on top.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
@ 2024-05-24 13:40 ` Jarkko Sakkinen
2024-05-24 13:52 ` Jarkko Sakkinen
2024-05-27 3:45 ` Ben Boeckel
2024-07-16 11:13 ` Jarkko Sakkinen
2 siblings, 1 reply; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-05-24 13:40 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> linux crypto and the TPM use different numeric algorithm identifiers
> for hash (and other) functions. The conversion array for this already
> exists in two separate places. The new policy sessions code would
> have to add a third copy, so instead of increasing the duplication,
> move the definition to a single consolidated place in tpm.h so the
> policy code can use it as is.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> drivers/char/tpm/tpm2-cmd.c | 8 ----
> include/linux/tpm.h | 52 ++++++++++++++++++++++-
> security/keys/trusted-keys/trusted_tpm2.c | 20 +--------
> 3 files changed, 53 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index 0cdf892ec2a7..f4428e715dd8 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -14,14 +14,6 @@
> #include "tpm.h"
> #include <crypto/hash_info.h>
>
> -static struct tpm2_hash tpm2_hash_map[] = {
> - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> -};
> -
> int tpm2_get_timeouts(struct tpm_chip *chip)
> {
> /* Fixed timeouts for TPM2 */
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index c17e4efbb2e5..07f532456a0c 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -418,11 +418,61 @@ enum tpm2_session_attributes {
> TPM2_SA_AUDIT = BIT(7),
> };
>
> -struct tpm2_hash {
> +static const struct {
> unsigned int crypto_id;
> unsigned int tpm_id;
> +} tpm2_hash_map[] = {
> + {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> + {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> + {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> + {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> };
>
> +/**
> + * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
> + *
> + * @hash: the crypto subsystem view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
> + */
> +static inline int tpm2_crypto_to_alg(int hash)
> +{
> + int i;
> + int tpm_alg = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].crypto_id) {
> + tpm_alg = tpm2_hash_map[i].tpm_id;
> + break;
> + }
> + }
> +
> + return tpm_alg;
> +}
> +
> +/**
> + * tpm2_alg_to_crypto() - convert a TPM alg id to a crypto hash
> + *
> + * @hash: the TPM alg id view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
> + */
> +static inline int tpm2_alg_to_crypto(int hash)
> +{
> + int i;
> + int crypto_hash = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].tpm_id) {
> + crypto_hash = tpm2_hash_map[i].crypto_id;
> + break;
> + }
> + }
> +
> + return crypto_hash;
> +}
> +
> int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
> void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
> int tpm_buf_init_sized(struct tpm_buf *buf);
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index dfeec06301ce..94ff9ccae66e 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -18,14 +18,6 @@
>
> #include "tpm2key.asn1.h"
>
> -static struct tpm2_hash tpm2_hash_map[] = {
> - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> -};
> -
> static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
>
> static int tpm2_key_encode(struct trusted_key_payload *payload,
> @@ -231,19 +223,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> off_t offset = TPM_HEADER_SIZE;
> struct tpm_buf buf, sized;
> int blob_len = 0;
> - u32 hash;
> + int hash = tpm2_crypto_to_alg(options->hash);
> u32 flags;
> - 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))
> + if (hash < 0)
> return -EINVAL;
>
> if (!options->keyhandle)
I want a patch set that renders out the WARN's before any other
modification to this code. I've spent fixing one myself plus
fixing totally trivial memory leak. That happens everyone but
still focus in now all wrong. I.e. adding new stuff without
polishing old first and let others take care cleaning up the
mess...
Also, HMAC still needs attention.
And this patch set is totally conflicting getting asymmetric
keys landed, which came first and if already maturing quite
well.
No issues reviewing after so this is not like rejecting the
idea but doing right things right and in right order.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-24 13:40 ` Jarkko Sakkinen
@ 2024-05-24 13:52 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-05-24 13:52 UTC (permalink / raw)
To: Jarkko Sakkinen, James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:40 PM EEST, Jarkko Sakkinen wrote:
> On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> > linux crypto and the TPM use different numeric algorithm identifiers
> > for hash (and other) functions. The conversion array for this already
> > exists in two separate places. The new policy sessions code would
> > have to add a third copy, so instead of increasing the duplication,
> > move the definition to a single consolidated place in tpm.h so the
> > policy code can use it as is.
> >
> > Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> > ---
> > drivers/char/tpm/tpm2-cmd.c | 8 ----
> > include/linux/tpm.h | 52 ++++++++++++++++++++++-
> > security/keys/trusted-keys/trusted_tpm2.c | 20 +--------
> > 3 files changed, 53 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> > index 0cdf892ec2a7..f4428e715dd8 100644
> > --- a/drivers/char/tpm/tpm2-cmd.c
> > +++ b/drivers/char/tpm/tpm2-cmd.c
> > @@ -14,14 +14,6 @@
> > #include "tpm.h"
> > #include <crypto/hash_info.h>
> >
> > -static struct tpm2_hash tpm2_hash_map[] = {
> > - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> > - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> > - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> > - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> > - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> > -};
> > -
> > int tpm2_get_timeouts(struct tpm_chip *chip)
> > {
> > /* Fixed timeouts for TPM2 */
> > diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> > index c17e4efbb2e5..07f532456a0c 100644
> > --- a/include/linux/tpm.h
> > +++ b/include/linux/tpm.h
> > @@ -418,11 +418,61 @@ enum tpm2_session_attributes {
> > TPM2_SA_AUDIT = BIT(7),
> > };
> >
> > -struct tpm2_hash {
> > +static const struct {
> > unsigned int crypto_id;
> > unsigned int tpm_id;
> > +} tpm2_hash_map[] = {
> > + {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> > + {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> > + {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> > + {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> > + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> > };
> >
> > +/**
> > + * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
> > + *
> > + * @hash: the crypto subsystem view of the hash
> > + *
> > + * Return: TPM algorithm id or -1 if no mapping was found.
> > + */
> > +static inline int tpm2_crypto_to_alg(int hash)
> > +{
> > + int i;
> > + int tpm_alg = -1;
> > +
> > + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> > + if (hash == tpm2_hash_map[i].crypto_id) {
> > + tpm_alg = tpm2_hash_map[i].tpm_id;
> > + break;
> > + }
> > + }
> > +
> > + return tpm_alg;
> > +}
> > +
> > +/**
> > + * tpm2_alg_to_crypto() - convert a TPM alg id to a crypto hash
> > + *
> > + * @hash: the TPM alg id view of the hash
> > + *
> > + * Return: TPM algorithm id or -1 if no mapping was found.
> > + */
> > +static inline int tpm2_alg_to_crypto(int hash)
> > +{
> > + int i;
> > + int crypto_hash = -1;
> > +
> > + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> > + if (hash == tpm2_hash_map[i].tpm_id) {
> > + crypto_hash = tpm2_hash_map[i].crypto_id;
> > + break;
> > + }
> > + }
> > +
> > + return crypto_hash;
> > +}
> > +
> > int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
> > void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
> > int tpm_buf_init_sized(struct tpm_buf *buf);
> > diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> > index dfeec06301ce..94ff9ccae66e 100644
> > --- a/security/keys/trusted-keys/trusted_tpm2.c
> > +++ b/security/keys/trusted-keys/trusted_tpm2.c
> > @@ -18,14 +18,6 @@
> >
> > #include "tpm2key.asn1.h"
> >
> > -static struct tpm2_hash tpm2_hash_map[] = {
> > - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> > - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> > - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> > - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> > - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> > -};
> > -
> > static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
> >
> > static int tpm2_key_encode(struct trusted_key_payload *payload,
> > @@ -231,19 +223,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> > off_t offset = TPM_HEADER_SIZE;
> > struct tpm_buf buf, sized;
> > int blob_len = 0;
> > - u32 hash;
> > + int hash = tpm2_crypto_to_alg(options->hash);
> > u32 flags;
> > - 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))
> > + if (hash < 0)
> > return -EINVAL;
> >
> > if (!options->keyhandle)
>
> I want a patch set that renders out the WARN's before any other
> modification to this code. I've spent fixing one myself plus
> fixing totally trivial memory leak. That happens everyone but
> still focus in now all wrong. I.e. adding new stuff without
> polishing old first and let others take care cleaning up the
> mess...
>
> Also, HMAC still needs attention.
>
> And this patch set is totally conflicting getting asymmetric
> keys landed, which came first and if already maturing quite
> well.
>
> No issues reviewing after so this is not like rejecting the
> idea but doing right things right and in right order.
Not conflicting in the sense that this would somehow fight against that
code. It is anyway for different subsystem. I think this is probably
legit work but does bunch of conflicting changes so not caring about
this before asymmetric keys have been landed.
I rarely implement anything and it is feature that I checked from
various parties that it is still relevant so it is best to land it
first. I did all the trouble and time and effort reviewing and
even rewriting some of the buffer code in HMAC to better form
exactly because I saw it more priority than landing asymmetric
keys.
So it is not like I prioritize my patch sets over others but
these mess in same areas so thus the decision.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
2024-05-24 13:40 ` Jarkko Sakkinen
@ 2024-05-27 3:45 ` Ben Boeckel
2024-05-27 11:18 ` Jarkko Sakkinen
2024-07-16 11:13 ` Jarkko Sakkinen
2 siblings, 1 reply; 24+ messages in thread
From: Ben Boeckel @ 2024-05-27 3:45 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-integrity, Jarkko Sakkinen, keyrings
On Fri, May 24, 2024 at 09:04:54 -0400, James Bottomley wrote:
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index c17e4efbb2e5..07f532456a0c 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -418,11 +418,61 @@ enum tpm2_session_attributes {
> TPM2_SA_AUDIT = BIT(7),
> };
>
> -struct tpm2_hash {
> +static const struct {
> unsigned int crypto_id;
> unsigned int tpm_id;
> +} tpm2_hash_map[] = {
> + {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> + {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> + {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> + {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> };
>
> +/**
> + * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
Should "alg id" be "algorithm id" everwhere in the docs?
> + *
> + * @hash: the crypto subsystem view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
> + */
> +static inline int tpm2_crypto_to_alg(int hash)
How about naming this `crypto_id`?
> +{
> + int i;
> + int tpm_alg = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].crypto_id) {
> + tpm_alg = tpm2_hash_map[i].tpm_id;
> + break;
> + }
> + }
> +
> + return tpm_alg;
> +}
> +
> +/**
> + * tpm2_alg_to_crypto() - convert a TPM alg id to a crypto hash
> + *
> + * @hash: the TPM alg id view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
Copy pasta? Should be "crypto hash" I think.
> + */
> +static inline int tpm2_alg_to_crypto(int hash)
Maybe name this `alg_id`?
> +{
> + int i;
> + int crypto_hash = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].tpm_id) {
> + crypto_hash = tpm2_hash_map[i].crypto_id;
> + break;
> + }
> + }
> +
> + return crypto_hash;
> +}
There seems to be some level of confusion with variable naming here. Are
these "hashes" or "ids" being passed around? The structure calls them
ids, the docs call them both, the variables call one a hash and the
other unadorned.
--Ben
> +
> int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
> void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
> int tpm_buf_init_sized(struct tpm_buf *buf);
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index dfeec06301ce..94ff9ccae66e 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -18,14 +18,6 @@
>
> #include "tpm2key.asn1.h"
>
> -static struct tpm2_hash tpm2_hash_map[] = {
> - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> -};
> -
> static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
>
> static int tpm2_key_encode(struct trusted_key_payload *payload,
> @@ -231,19 +223,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> off_t offset = TPM_HEADER_SIZE;
> struct tpm_buf buf, sized;
> int blob_len = 0;
> - u32 hash;
> + int hash = tpm2_crypto_to_alg(options->hash);
> u32 flags;
> - 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))
> + if (hash < 0)
> return -EINVAL;
>
> if (!options->keyhandle)
> --
> 2.35.3
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-27 3:45 ` Ben Boeckel
@ 2024-05-27 11:18 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-05-27 11:18 UTC (permalink / raw)
To: Ben Boeckel, James Bottomley; +Cc: linux-integrity, keyrings
On Mon May 27, 2024 at 6:45 AM EEST, Ben Boeckel wrote:
> On Fri, May 24, 2024 at 09:04:54 -0400, James Bottomley wrote:
> > diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> > index c17e4efbb2e5..07f532456a0c 100644
> > --- a/include/linux/tpm.h
> > +++ b/include/linux/tpm.h
> > @@ -418,11 +418,61 @@ enum tpm2_session_attributes {
> > TPM2_SA_AUDIT = BIT(7),
> > };
> >
> > -struct tpm2_hash {
> > +static const struct {
> > unsigned int crypto_id;
> > unsigned int tpm_id;
> > +} tpm2_hash_map[] = {
> > + {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> > + {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> > + {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> > + {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> > + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> > };
> >
> > +/**
> > + * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
>
> Should "alg id" be "algorithm id" everwhere in the docs?
tpm2_hash_algorithm_from() would work for me.
> > + *
> > + * @hash: the crypto subsystem view of the hash
It is an instance of &hash_algo not "crypto subsystem view of the hash".
> > + *
> > + * Return: TPM algorithm id or -1 if no mapping was found.
> > + */
> > +static inline int tpm2_crypto_to_alg(int hash)
>
> How about naming this `crypto_id`?
It really should be @hash_info, which an instance of &hash_info.
Despite comments, this patch set will be ignored up until hmac
encryption needs no active attention and asymmetric keys have been
landed.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
2024-05-24 13:40 ` Jarkko Sakkinen
2024-05-27 3:45 ` Ben Boeckel
@ 2024-07-16 11:13 ` Jarkko Sakkinen
2 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 11:13 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
Now I bandwidth to give this the first round.
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> linux crypto and the TPM use different numeric algorithm identifiers
> for hash (and other) functions. The conversion array for this already
Please use exact names i.e. conversion is between enum tpm2_algorithms
and enum hash_info. Much easier to lookup later on.
> exists in two separate places. The new policy sessions code would
> have to add a third copy, so instead of increasing the duplication,
> move the definition to a single consolidated place in tpm.h so the
> policy code can use it as is.
"the new policy session code" is not an artifact.
Instead, please say what needs the third instance and why. I don't
consume white paper text.
I'm fine if you just use merging two redundant copies together, with
no reference to the third copy. In this form this unconditional NAK
given that I have zero idea what the third copy is and where it is
located.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> drivers/char/tpm/tpm2-cmd.c | 8 ----
> include/linux/tpm.h | 52 ++++++++++++++++++++++-
> security/keys/trusted-keys/trusted_tpm2.c | 20 +--------
> 3 files changed, 53 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index 0cdf892ec2a7..f4428e715dd8 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -14,14 +14,6 @@
> #include "tpm.h"
> #include <crypto/hash_info.h>
>
> -static struct tpm2_hash tpm2_hash_map[] = {
> - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> -};
> -
> int tpm2_get_timeouts(struct tpm_chip *chip)
> {
> /* Fixed timeouts for TPM2 */
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index c17e4efbb2e5..07f532456a0c 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -418,11 +418,61 @@ enum tpm2_session_attributes {
> TPM2_SA_AUDIT = BIT(7),
> };
>
> -struct tpm2_hash {
> +static const struct {
> unsigned int crypto_id;
> unsigned int tpm_id;
> +} tpm2_hash_map[] = {
> + {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> + {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> + {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> + {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> };
>
> +/**
> + * tpm2_crypto_to_alg() - convert a crypto hash to a TPM alg id
> + *
> + * @hash: the crypto subsystem view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
> + */
> +static inline int tpm2_crypto_to_alg(int hash)
> +{
> + int i;
> + int tpm_alg = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].crypto_id) {
> + tpm_alg = tpm2_hash_map[i].tpm_id;
> + break;
> + }
> + }
> +
> + return tpm_alg;
> +}
> +
> +/**
> + * tpm2_alg_to_crypto() - convert a TPM alg id to a crypto hash
> + *
> + * @hash: the TPM alg id view of the hash
> + *
> + * Return: TPM algorithm id or -1 if no mapping was found.
> + */
> +static inline int tpm2_alg_to_crypto(int hash)
> +{
> + int i;
> + int crypto_hash = -1;
> +
> + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> + if (hash == tpm2_hash_map[i].tpm_id) {
> + crypto_hash = tpm2_hash_map[i].crypto_id;
> + break;
> + }
> + }
> +
> + return crypto_hash;
> +}
> +
> int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
> void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
> int tpm_buf_init_sized(struct tpm_buf *buf);
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index dfeec06301ce..94ff9ccae66e 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -18,14 +18,6 @@
>
> #include "tpm2key.asn1.h"
>
> -static struct tpm2_hash tpm2_hash_map[] = {
> - {HASH_ALGO_SHA1, TPM_ALG_SHA1},
> - {HASH_ALGO_SHA256, TPM_ALG_SHA256},
> - {HASH_ALGO_SHA384, TPM_ALG_SHA384},
> - {HASH_ALGO_SHA512, TPM_ALG_SHA512},
> - {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
> -};
> -
> static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };
>
> static int tpm2_key_encode(struct trusted_key_payload *payload,
> @@ -231,19 +223,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> off_t offset = TPM_HEADER_SIZE;
> struct tpm_buf buf, sized;
> int blob_len = 0;
> - u32 hash;
> + int hash = tpm2_crypto_to_alg(options->hash);
Please use reverse christmas tree order.
> u32 flags;
> - 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))
> + if (hash < 0)
> return -EINVAL;
>
> if (!options->keyhandle)
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-05-24 13:04 ` [PATCH 2/6] tpm: add policy sessions James Bottomley
@ 2024-07-16 11:53 ` Jarkko Sakkinen
2024-07-16 14:07 ` Jarkko Sakkinen
0 siblings, 1 reply; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 11:53 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
Please rewrite short summray to something understandable. Perhaps
"tpm: authenticated policy sessions for TPM2" would be more to
the point.
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> TPM security uses hmac sessions to implement data protection and
TPM2 sessions use HMAC ...
> integrity. The hash algorithm of these sessions isn't exposed to the
> user (and doesn't depend on the object being authorized) so it is
Either remove the text in parentheses or rewrite it as a separate
sentence if it is relevant.
> currently fixed at a safe sha256. Policy sessions may also be used
SHA-256
> for the same purpose and in addition, they can be used to express a
> rich policy language. However, the session hash of policy sessions is
> defined to be the same as the name algorithm of the TPM object they're
> operating on, so we must update the session code to allow a variable
No information about the TPM object in question, which means no
rationale to bundle variable digest size to this patch. I know that
null key uses SHA-256 as name algorithm:
/* name algorithm */
if (val != TPM_ALG_SHA256)
return -EINVAL;
val = tpm_buf_read_u32(buf, &offset_t);
Please state what other TPM object might be in question.
Also, describe your changes in imperative form. This is also stated in
SubmittingPatches.
> hash algorithm instead of the fixed sha256 one. Note that while this
> affects most of the code, the KDFe algorithm still uses a fixed sha256
> algorithm because it is define to follow the name algorithm of the
> salt encryption key (which is a key we derive from the null seed and
> set its name algorithm to sha256).
Split the long description to two paragraphs: one that describes the
motivation and one that describes the solution.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> drivers/char/tpm/tpm2-sessions.c | 307 +++++++++++++++++++------------
> include/linux/tpm.h | 6 +
> 2 files changed, 200 insertions(+), 113 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index ea8860661876..63c175b2165c 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -105,10 +105,10 @@ struct tpm2_auth {
> /*
> * the size here is variable and set by the size of our_nonce
> * which must be between 16 and the name hash length. we set
> - * the maximum sha256 size for the greatest protection
> + * the maximum hash size for the greatest protection
> */
> - u8 our_nonce[SHA256_DIGEST_SIZE];
> - u8 tpm_nonce[SHA256_DIGEST_SIZE];
> + u8 our_nonce[HASH_MAX_DIGESTSIZE];
> + u8 tpm_nonce[HASH_MAX_DIGESTSIZE];
> /*
> * the salt is only used across the session command/response
> * after that it can be used as a scratch area
> @@ -119,17 +119,15 @@ struct tpm2_auth {
> u8 scratch[AES_KEY_BYTES + AES_BLOCK_SIZE];
> };
> /*
> - * the session key and passphrase are the same size as the
> - * name digest (sha256 again). The session key is constant
> - * for the use of the session and the passphrase can change
> - * with every invocation.
> - *
> - * Note: these fields must be adjacent and in this order
> - * because several HMAC/KDF schemes use the combination of the
> - * session_key and passphrase.
> + * The session_key and passphrase must be next to each other
> + * to allow us to hash them as a unit. With a variable hash,
> + * this means that the passphrase must occur exactly one hash
> + * size after the session_key, so make session_key house both
> + * and passphrase is a pointer into where the passphrase
> + * begins in session_key.
> */
> - u8 session_key[SHA256_DIGEST_SIZE];
> - u8 passphrase[SHA256_DIGEST_SIZE];
> + u8 session_key[2*HASH_MAX_DIGESTSIZE];
> + u8 *passphrase;
> int passphrase_len;
> struct crypto_aes_ctx aes_ctx;
> /* saved session attributes: */
> @@ -142,7 +140,8 @@ struct tpm2_auth {
> * we must compute and remember
> */
> u32 name_h[AUTH_MAX_NAMES];
> - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
> + struct crypto_shash *tfm;
> };
>
> /*
> @@ -161,34 +160,36 @@ static u8 name_size(const u8 *name)
> }
>
> /*
> - * It turns out the crypto hmac(sha256) is hard for us to consume
> + * It turns out the crypto hmac(shaX) is hard for us to consume
> * because it assumes a fixed key and the TPM seems to change the key
> * on every operation, so we weld the hmac init and final functions in
> * here to give it the same usage characteristics as a regular hash
> */
> -static void tpm2_hmac_init(struct sha256_state *sctx, u8 *key, u32 key_len)
> +static void tpm2_hmac_init(struct shash_desc *sdesc, u8 *key, u32 key_len)
> {
> - u8 pad[SHA256_BLOCK_SIZE];
> + const int block_size = crypto_shash_blocksize(sdesc->tfm);
> + u8 pad[SHA512_BLOCK_SIZE];
> int i;
>
> - sha256_init(sctx);
> - for (i = 0; i < sizeof(pad); i++) {
> + crypto_shash_init(sdesc);
> + for (i = 0; i < block_size; i++) {
> if (i < key_len)
> pad[i] = key[i];
> else
> pad[i] = 0;
> pad[i] ^= HMAC_IPAD_VALUE;
> }
> - sha256_update(sctx, pad, sizeof(pad));
> + crypto_shash_update(sdesc, pad, block_size);
> }
>
> -static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
> +static void tpm2_hmac_final(struct shash_desc *sdesc, u8 *key, u32 key_len,
> u8 *out)
> {
> - u8 pad[SHA256_BLOCK_SIZE];
> + const int block_size = crypto_shash_blocksize(sdesc->tfm);
> + u8 pad[SHA512_BLOCK_SIZE];
> int i;
>
> - for (i = 0; i < sizeof(pad); i++) {
> + for (i = 0; i < block_size; i++) {
> if (i < key_len)
> pad[i] = key[i];
> else
> @@ -197,35 +198,42 @@ static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
> }
>
> /* collect the final hash; use out as temporary storage */
> - sha256_final(sctx, out);
> + crypto_shash_final(sdesc, out);
>
> - sha256_init(sctx);
> - sha256_update(sctx, pad, sizeof(pad));
> - sha256_update(sctx, out, SHA256_DIGEST_SIZE);
> - sha256_final(sctx, out);
> + crypto_shash_init(sdesc);
> + crypto_shash_update(sdesc, pad, block_size);
> + crypto_shash_update(sdesc, out, crypto_shash_digestsize(sdesc->tfm));
> + crypto_shash_final(sdesc, out);
> }
>
> /*
> - * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but
> + * assume hash sha256 and nonces u, v of hash digest size but
> * otherwise standard tpm2_KDFa. Note output is in bytes not bits.
> */
> static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
> - u8 *v, u32 bytes, u8 *out)
> + u8 *v, u32 bytes, u8 *out, struct shash_desc *sdesc)
> {
> u32 counter = 1;
> const __be32 bits = cpu_to_be32(bytes * 8);
> + const int digest_size = crypto_shash_digestsize(sdesc->tfm);
>
> while (bytes > 0) {
> - struct sha256_state sctx;
> __be32 c = cpu_to_be32(counter);
>
> - tpm2_hmac_init(&sctx, key, key_len);
> - sha256_update(&sctx, (u8 *)&c, sizeof(c));
> - sha256_update(&sctx, label, strlen(label)+1);
> - sha256_update(&sctx, u, SHA256_DIGEST_SIZE);
> - sha256_update(&sctx, v, SHA256_DIGEST_SIZE);
> - sha256_update(&sctx, (u8 *)&bits, sizeof(bits));
> - tpm2_hmac_final(&sctx, key, key_len, out);
> + tpm2_hmac_init(sdesc, key, key_len);
> + crypto_shash_update(sdesc, (u8 *)&c, sizeof(c));
> + crypto_shash_update(sdesc, label, strlen(label)+1);
> + crypto_shash_update(sdesc, u, digest_size);
> + crypto_shash_update(sdesc, v, digest_size);
> + crypto_shash_update(sdesc, (u8 *)&bits, sizeof(bits));
> + if (bytes < digest_size) {
> + u8 buf[HASH_MAX_DIGESTSIZE];
> +
> + tpm2_hmac_final(sdesc, key, key_len, buf);
> + memcpy(out, buf, bytes);
> + } else {
> + tpm2_hmac_final(sdesc, key, key_len, out);
> + }
>
> bytes -= SHA256_DIGEST_SIZE;
> counter++;
> @@ -236,9 +244,9 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
> /*
> * Somewhat of a bastardization of the real KDFe. We're assuming
> * we're working with known point sizes for the input parameters and
> - * the hash algorithm is fixed at sha256. Because we know that the
> - * point size is 32 bytes like the hash size, there's no need to loop
> - * in this KDF.
> + * the hash algorithm is fixed at sha256 (name algorithm of the
> + * encrypting key). Because we know that the point size is 32 bytes
> + * like the hash size, there's no need to loop in this KDF.
> */
> static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
> u8 *out)
> @@ -370,9 +378,10 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
> u8 attributes, u8 *passphrase,
> int passphrase_len)
> {
> - u8 nonce[SHA256_DIGEST_SIZE];
> + u8 nonce[HASH_MAX_DIGESTSIZE];
> u32 len;
> struct tpm2_auth *auth = chip->auth;
> + const int digest_size = crypto_shash_digestsize(auth->tfm);
>
> /*
> * The Architecture Guide requires us to strip trailing zeros
> @@ -384,8 +393,14 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
>
> auth->attrs = attributes;
> auth->passphrase_len = passphrase_len;
> - if (passphrase_len)
> + if (passphrase_len) {
> + /*
> + * place the passphrase immediately adjacent to
> + * the session key
> + */
> + auth->passphrase = auth->session_key + digest_size;
> memcpy(auth->passphrase, passphrase, passphrase_len);
> + }
>
> if (auth->session != tpm_buf_length(buf)) {
> /* we're not the first session */
> @@ -396,23 +411,23 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
> }
>
> /* add our new session */
> - len += 9 + 2 * SHA256_DIGEST_SIZE;
> + len += 9 + 2 * digest_size;
> put_unaligned_be32(len, &buf->data[auth->session]);
> } else {
> - tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
> + tpm_buf_append_u32(buf, 9 + 2 * digest_size);
> }
>
> /* random number for our nonce */
> - get_random_bytes(nonce, sizeof(nonce));
> - memcpy(auth->our_nonce, nonce, sizeof(nonce));
> + get_random_bytes(nonce, digest_size);
> + memcpy(auth->our_nonce, nonce, digest_size);
> tpm_buf_append_u32(buf, auth->handle);
> /* our new nonce */
> - tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
> - tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
> + tpm_buf_append_u16(buf, digest_size);
> + tpm_buf_append(buf, nonce, digest_size);
> tpm_buf_append_u8(buf, auth->attrs);
> /* and put a placeholder for the hmac */
> - tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
> - tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
> + tpm_buf_append_u16(buf, digest_size);
> + tpm_buf_append(buf, nonce, digest_size);
> }
> EXPORT_SYMBOL(tpm_buf_append_hmac_session);
>
> @@ -443,8 +458,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
> off_t offset_s = TPM_HEADER_SIZE, offset_p;
> u8 *hmac = NULL;
> u32 attrs;
> - u8 cphash[SHA256_DIGEST_SIZE];
> - struct sha256_state sctx;
> + const int digest_size = crypto_shash_digestsize(auth->tfm);
> + u8 cphash[HASH_MAX_DIGESTSIZE];
> + SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> + sdesc->tfm = auth->tfm;
>
> /* save the command code in BE format */
> auth->ordinal = head->ordinal;
> @@ -515,10 +533,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
> u16 len;
>
> /* need key and IV */
> - tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
> + tpm2_KDFa(auth->session_key, digest_size
> + auth->passphrase_len, "CFB", auth->our_nonce,
> auth->tpm_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
> - auth->scratch);
> + auth->scratch, sdesc);
>
> len = tpm_buf_read_u16(buf, &offset_p);
> aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
> @@ -529,9 +547,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
> offset_p -= 2;
> }
>
> - sha256_init(&sctx);
> + crypto_shash_init(sdesc);
> /* ordinal is already BE */
> - sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal));
> + crypto_shash_update(sdesc, (u8 *)&head->ordinal,
> + sizeof(head->ordinal));
> /* add the handle names */
> for (i = 0; i < handles; i++) {
> enum tpm2_mso_type mso = tpm2_handle_mso(auth->name_h[i]);
> @@ -539,27 +558,27 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
> if (mso == TPM2_MSO_PERSISTENT ||
> mso == TPM2_MSO_VOLATILE ||
> mso == TPM2_MSO_NVRAM) {
> - sha256_update(&sctx, auth->name[i],
> - name_size(auth->name[i]));
> + crypto_shash_update(sdesc, auth->name[i],
> + name_size(auth->name[i]));
> } else {
> __be32 h = cpu_to_be32(auth->name_h[i]);
>
> - sha256_update(&sctx, (u8 *)&h, 4);
> + crypto_shash_update(sdesc, (u8 *)&h, 4);
> }
> }
> if (offset_s != tpm_buf_length(buf))
> - sha256_update(&sctx, &buf->data[offset_s],
> - tpm_buf_length(buf) - offset_s);
> - sha256_final(&sctx, cphash);
> + crypto_shash_update(sdesc, &buf->data[offset_s],
> + tpm_buf_length(buf) - offset_s);
> + crypto_shash_final(sdesc, cphash);
>
> /* now calculate the hmac */
> - tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
> + tpm2_hmac_init(sdesc, auth->session_key, digest_size
> + auth->passphrase_len);
> - sha256_update(&sctx, cphash, sizeof(cphash));
> - sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
> - sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
> - sha256_update(&sctx, &auth->attrs, 1);
> - tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
> + crypto_shash_update(sdesc, cphash, digest_size);
> + crypto_shash_update(sdesc, auth->our_nonce, digest_size);
> + crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
> + crypto_shash_update(sdesc, &auth->attrs, 1);
> + tpm2_hmac_final(sdesc, auth->session_key, digest_size
> + auth->passphrase_len, hmac);
> }
> EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
> @@ -695,12 +714,15 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
> struct tpm_header *head = (struct tpm_header *)buf->data;
> struct tpm2_auth *auth = chip->auth;
> off_t offset_s, offset_p;
> - u8 rphash[SHA256_DIGEST_SIZE];
> + const int digest_size = crypto_shash_digestsize(auth->tfm);
> + u8 rphash[HASH_MAX_DIGESTSIZE];
> u32 attrs;
> - struct sha256_state sctx;
> u16 tag = be16_to_cpu(head->tag);
> u32 cc = be32_to_cpu(auth->ordinal);
> int parm_len, len, i, handles;
> + SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> + sdesc->tfm = auth->tfm;
>
> if (auth->session >= TPM_HEADER_SIZE) {
> WARN(1, "tpm session not filled correctly\n");
> @@ -739,7 +761,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
> len = tpm_buf_read_u16(buf, &offset_s);
> if (offset_s + len > tpm_buf_length(buf))
> goto out;
> - if (len != SHA256_DIGEST_SIZE)
> + if (len != digest_size)
> goto out;
> memcpy(auth->tpm_nonce, &buf->data[offset_s], len);
> offset_s += len;
> @@ -747,32 +769,32 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
> len = tpm_buf_read_u16(buf, &offset_s);
> if (offset_s + len != tpm_buf_length(buf))
> goto out;
> - if (len != SHA256_DIGEST_SIZE)
> + if (len != digest_size)
> goto out;
> /*
> * offset_s points to the HMAC. now calculate comparison, beginning
> * with rphash
> */
> - sha256_init(&sctx);
> + crypto_shash_init(sdesc);
> /* yes, I know this is now zero, but it's what the standard says */
> - sha256_update(&sctx, (u8 *)&head->return_code,
> - sizeof(head->return_code));
> + crypto_shash_update(sdesc, (u8 *)&head->return_code,
> + sizeof(head->return_code));
> /* ordinal is already BE */
> - sha256_update(&sctx, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
> - sha256_update(&sctx, &buf->data[offset_p], parm_len);
> - sha256_final(&sctx, rphash);
> + crypto_shash_update(sdesc, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
> + crypto_shash_update(sdesc, &buf->data[offset_p], parm_len);
> + crypto_shash_final(sdesc, rphash);
>
> /* now calculate the hmac */
> - tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
> + tpm2_hmac_init(sdesc, auth->session_key, digest_size
> + auth->passphrase_len);
> - sha256_update(&sctx, rphash, sizeof(rphash));
> - sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
> - sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
> - sha256_update(&sctx, &auth->attrs, 1);
> + crypto_shash_update(sdesc, rphash, digest_size);
> + crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
> + crypto_shash_update(sdesc, auth->our_nonce, digest_size);
> + crypto_shash_update(sdesc, &auth->attrs, 1);
> /* we're done with the rphash, so put our idea of the hmac there */
> - tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
> + tpm2_hmac_final(sdesc, auth->session_key, digest_size
> + auth->passphrase_len, rphash);
> - if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) == 0) {
> + if (memcmp(rphash, &buf->data[offset_s], digest_size) == 0) {
> rc = 0;
> } else {
> dev_err(&chip->dev, "TPM: HMAC check failed\n");
> @@ -782,10 +804,10 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
> /* now do response decryption */
> if (auth->attrs & TPM2_SA_ENCRYPT) {
> /* need key and IV */
> - tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
> + tpm2_KDFa(auth->session_key, digest_size
> + auth->passphrase_len, "CFB", auth->tpm_nonce,
> auth->our_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
> - auth->scratch);
> + auth->scratch, sdesc);
>
> len = tpm_buf_read_u16(buf, &offset_p);
> aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
> @@ -799,6 +821,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
> if (rc)
> /* manually close the session if it wasn't consumed */
> tpm2_flush_context(chip, auth->handle);
> + crypto_free_shash(auth->tfm);
> memzero_explicit(auth, sizeof(*auth));
> } else {
> /* reset for next use */
> @@ -821,8 +844,11 @@ EXPORT_SYMBOL(tpm_buf_check_hmac_response);
> */
> void tpm2_end_auth_session(struct tpm_chip *chip)
> {
> - tpm2_flush_context(chip, chip->auth->handle);
> - memzero_explicit(chip->auth, sizeof(*chip->auth));
> + struct tpm2_auth *auth = chip->auth;
> +
> + tpm2_flush_context(chip, auth->handle);
> + crypto_free_shash(auth->tfm);
> + memzero_explicit(auth, sizeof(*auth));
> }
> EXPORT_SYMBOL(tpm2_end_auth_session);
>
> @@ -833,23 +859,26 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
> u32 tot_len = be32_to_cpu(head->length);
> off_t offset = TPM_HEADER_SIZE;
> u32 val;
> + const int digest_size = crypto_shash_digestsize(auth->tfm);
> + SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> + sdesc->tfm = auth->tfm;
>
> /* we're starting after the header so adjust the length */
> tot_len -= TPM_HEADER_SIZE;
>
> /* should have handle plus nonce */
> - if (tot_len != 4 + 2 + sizeof(auth->tpm_nonce))
> + if (tot_len != 4 + 2 + digest_size)
> return -EINVAL;
>
> auth->handle = tpm_buf_read_u32(buf, &offset);
> val = tpm_buf_read_u16(buf, &offset);
> - if (val != sizeof(auth->tpm_nonce))
> + if (val != digest_size)
> return -EINVAL;
> - memcpy(auth->tpm_nonce, &buf->data[offset], sizeof(auth->tpm_nonce));
> + memcpy(auth->tpm_nonce, &buf->data[offset], digest_size);
> /* now compute the session key from the nonces */
> tpm2_KDFa(auth->salt, sizeof(auth->salt), "ATH", auth->tpm_nonce,
> - auth->our_nonce, sizeof(auth->session_key),
> - auth->session_key);
> + auth->our_nonce, digest_size, auth->session_key, sdesc);
>
> return 0;
> }
> @@ -885,24 +914,23 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
> return rc;
> }
>
> -/**
> - * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
> - * @chip: the TPM chip structure to create the session with
> - *
> - * This function loads the NULL seed from its saved context and starts
> - * an authentication session on the null seed, fills in the
> - * @chip->auth structure to contain all the session details necessary
> - * for performing the HMAC, encrypt and decrypt operations and
> - * returns. The NULL seed is flushed before this function returns.
> - *
> - * Return: zero on success or actual error encountered.
> - */
> -int tpm2_start_auth_session(struct tpm_chip *chip)
> +static int __tpm2_start_session(struct tpm_chip *chip, u8 type, u16 hash)
> {
> struct tpm_buf buf;
> struct tpm2_auth *auth = chip->auth;
> int rc;
> u32 null_key;
> + int tpm_hash = tpm2_crypto_to_alg(hash);
> + int digest_size;
> +
> + if (tpm_hash < 0)
> + return -EINVAL;
> +
> + auth->tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
> + if (IS_ERR(auth->tfm))
> + return PTR_ERR(auth->tfm);
> +
> + digest_size = crypto_shash_digestsize(auth->tfm);
>
> rc = tpm2_load_null(chip, &null_key);
> if (rc)
> @@ -919,14 +947,14 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> /* bind key handle */
> tpm_buf_append_u32(&buf, TPM2_RH_NULL);
> /* nonce caller */
> - get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
> - tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
> - tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
> + get_random_bytes(auth->our_nonce, digest_size);
> + tpm_buf_append_u16(&buf, digest_size);
> + tpm_buf_append(&buf, auth->our_nonce, digest_size);
>
> /* append encrypted salt and squirrel away unencrypted in auth */
> tpm_buf_append_salt(&buf, chip);
> /* session type (HMAC, audit or policy) */
> - tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
> + tpm_buf_append_u8(&buf, type);
>
> /* symmetric encryption parameters */
> /* symmetric algorithm */
> @@ -936,7 +964,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> /* symmetric algorithm mode (must be CFB) */
> tpm_buf_append_u16(&buf, TPM_ALG_CFB);
> /* hash algorithm for session */
> - tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
> + tpm_buf_append_u16(&buf, tpm_hash);
>
> rc = tpm_transmit_cmd(chip, &buf, 0, "start auth session");
> tpm2_flush_context(chip, null_key);
> @@ -949,11 +977,64 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> if (rc)
> goto out;
>
> + return rc;
> +
> out:
> + crypto_free_shash(auth->tfm);
> + auth->tfm = NULL;
> +
> return rc;
> }
> +
> +/**
> + * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
> + * @chip: the TPM chip structure to create the session with
> + *
> + * This function loads the NULL seed from its saved context and starts
> + * an authentication session on the null seed, fills in the
> + * @chip->auth structure to contain all the session details necessary
> + * for performing the HMAC, encrypt and decrypt operations and
> + * returns. The NULL seed is flushed before this function returns.
> + *
> + * Return: zero on success or actual error encountered.
> + */
> +int tpm2_start_auth_session(struct tpm_chip *chip)
> +{
> + return __tpm2_start_session(chip, TPM2_SE_HMAC, HASH_ALGO_SHA256);
> +}
> EXPORT_SYMBOL(tpm2_start_auth_session);
>
> +/**
> + * tpm2_start_policy_session - create a policy session with the TPM
> + * @chip: the TPM chip structure to create the session with
> + * @handle: the policy session handle
> + * @hash: the crypto subsystem hash algorithm for the policy
> + *
> + * This function loads the NULL seed from its saved context and starts
> + * a policy session on the null seed, fills in the @chip->auth
> + * structure to contain all the session details necessary for
> + * performing the HMAC, encrypt and decrypt operations and returns.
> + * The NULL seed is flushed before this function returns.
> + *
> + * Note the hash algorthim has to match the name algorithm of the TPM
> + * object the policy will be used to authorize.
> + *
> + * Return: zero on success or actual error encountered.
> + */
> +int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash)
> +{
> + int rc;
> +
> + rc = __tpm2_start_session(chip, TPM2_SE_POLICY, hash);
> + if (rc)
> + return rc;
> +
> + *handle = chip->auth->handle;
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(tpm2_start_policy_session);
> +
> /**
> * tpm2_parse_create_primary() - parse the data returned from TPM_CC_CREATE_PRIMARY
> *
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 07f532456a0c..dc2dd98cf104 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -560,6 +560,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
> #ifdef CONFIG_TCG_TPM2_HMAC
>
> int tpm2_start_auth_session(struct tpm_chip *chip);
> +int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
> void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
> u32 handle, u8 *name);
> void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
> @@ -585,6 +586,11 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
> {
> return 0;
> }
> +static inline int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle,
> + u8 hash)
> +{
> + return -EINVAL;
> +}
> static inline void tpm2_end_auth_session(struct tpm_chip *chip)
> {
> }
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys
2024-05-24 13:04 ` [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys James Bottomley
@ 2024-07-16 12:01 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 12:01 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> This commit adds the ability to specify a PCR lock policy to TPM2
> keys. There is a complexity in that keys that contain both a password
> (blobauth) and a PCR lock have to have two policy statements
> (POLICY_PCR and POLICY_AUTHVALUE). The way to construct a pcrinfo
> statement for a key is simply to use the TPMS_PCR_SELECT structure to
> specify the PCRs and follow this by a hash of all their values in
> order of ascending PCR number.
>
> To construct a policy around the value of the resettable PCR 16 using
> the sha256 bank, first reset the pcr to zero giving a hash of all
SHA-256 PCR
> zeros as:
>
> 66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Please also provide example how this kind of hash is constructed, and
no mention about trial and policy modes, which are essential in order
to understand what is going on here.
>
> Then the TPMS_PCR_SELECT value for sha256 bank PCR 16 is
>
> 000b03000001
>
> So create a new 32 byte key with a policy locking the key to this
> value of PCR 16 with a parent key of 81000001 would be:
>
> keyctl add trusted kmk "new 32 keyhandle=0x81000001 pcrinfo=000b0300000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925" @u
PCINFO=0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
HANDLE=0x81000001
keyctl add trusted kmk "new 32 keyhandle=$HANDLE pcrinfo=$KEYINFO" @u
I won't look at the code this round because commit message is lacking
explanation what it does.
606 is a huge addition for single patch and requires belieable story
why it can't be smaller. I won't even try to understand all the changes
just looking at the code.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy
2024-05-24 13:04 ` [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy James Bottomley
@ 2024-07-16 12:01 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 12:01 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> This patch adds a policy= argument to key creation. The policy is the
> standard tss policymaker format and each separate policy line must
> have a newline after it.
>
> Thus to construct a policy requiring authorized value and pcr 16
> locking using a sha256 hash, the policy (policy.txt) file would be two
> lines:
>
> 0000017F00000001000B03000001303095B49BE85E381E5B20E557E46363EF55B0F43B132C2D8E3DE9AC436656F2
> 0000016b
>
> This can be inserted into the key with
>
> keyctl add trusted kmk "new 32 policy=`cat policy.txt` keyhandle=0x81000001 hash=sha256" @u
>
> Note that although a few policies work like this, most require special
> handling which must be added to the kernel policy construction
> routine.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> .../security/keys/trusted-encrypted.rst | 17 +++++-
> security/keys/trusted-keys/tpm2-policy.c | 53 +++++++++++++++++++
> security/keys/trusted-keys/tpm2-policy.h | 5 ++
> security/keys/trusted-keys/trusted_tpm1.c | 15 ++++++
> 4 files changed, 89 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
> index c37c08956ec1..fbb41cf16f30 100644
> --- a/Documentation/security/keys/trusted-encrypted.rst
> +++ b/Documentation/security/keys/trusted-encrypted.rst
> @@ -233,6 +233,9 @@ Usage::
> policyhandle= handle to an authorization policy session that defines the
> same policy and with the same hash algorithm as was used to
> seal the key.
> + policy= specify an arbitrary set of policies. These must
> + be in policymaker format with each separate
> + policy line newline terminated.
>
> "keyctl print" returns an ascii hex copy of the sealed key, which is in standard
> TPM_STORED_DATA format. The key length for new keys are always in bytes.
> @@ -377,6 +380,19 @@ the sha1 pcr16 bank you'd say::
>
> because the trailing hash is the sha256sum of 20 zero bytes.
>
> +You can also specify arbitrary policy in policymaker format, so a two
> +value policy (the pcr example above and authvalue) would look like
> +this in policymaker format::
> +
> + 0000017F000000010004030000016768033e216468247bd031a0a2d9876d79818f8f
> + 0000016b
> +
> +This can be placed in a file (say policy.txt) and then added to the key as::
> +
> + $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha1 policy=`cat policy.txt`" @u
> +
> +The newlines in the file policy.txt will be automatically processed.
> +
> Reseal (TPM specific) a trusted key under new PCR values::
>
> $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
> @@ -447,7 +463,6 @@ Another new format 'enc32' has been defined in order to support encrypted keys
> with payload size of 32 bytes. This will initially be used for nvdimm security
> but may expand to other usages that require 32 bytes payload.
>
> -
> TPM 2.0 ASN.1 Key Format
> ------------------------
>
> diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
> index 8c3a09762c10..a731c10d9bba 100644
> --- a/security/keys/trusted-keys/tpm2-policy.c
> +++ b/security/keys/trusted-keys/tpm2-policy.c
Ditto.
> @@ -323,3 +323,56 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
>
> return 0;
> }
> +
> +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
> +{
> + struct tpm2_policies *pols;
> + char *p;
> + u8 *ptr;
> + int i = 0, left = PAGE_SIZE, res;
> +
> + pols = kmalloc(left, GFP_KERNEL);
> + if (!pols)
> + return -ENOMEM;
> +
> + ptr = (u8 *)(pols + 1);
> + left -= ptr - (u8 *)pols;
> +
> + while ((p = strsep(&str, "\n"))) {
> + if (*p == '\0' || *p == '\n')
> + continue;
> +
> + pols->len[i] = strlen(p)/2;
> + if (pols->len[i] > left) {
> + res = -E2BIG;
> + goto err;
> + }
> +
> + res = hex2bin(ptr, p, pols->len[i]);
> + if (res)
> + goto err;
> +
> + /* get command code and skip past */
> + pols->code[i] = get_unaligned_be32(ptr);
> + pols->policies[i] = ptr + 4;
> + ptr += pols->len[i];
> + left -= pols->len[i];
> + pols->len[i] -= 4;
> +
> + /*
> + * FIXME: this does leave the code embedded in dead
> + * regions of the memory, but it's easier than
> + * hexdumping to a temporary or copying over
> + */
> + i++;
> + }
> +
> + pols->count = i;
> + *ppols = pols;
> +
> + return 0;
> +
> + err:
> + kfree(pols);
> + return res;
> +}
> diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
> index b20e9c3e2f06..8ddf235b3fec 100644
> --- a/security/keys/trusted-keys/tpm2-policy.h
> +++ b/security/keys/trusted-keys/tpm2-policy.h
> @@ -28,6 +28,7 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash,
> u8 *policydigest, u32 *plen);
> int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len);
> int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols);
> +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str);
> #else
> static inline int tpm2_key_policy_process(struct tpm2_key_context *ctx,
> struct trusted_key_payload *payload)
> @@ -50,4 +51,8 @@ static inline int tpm2_get_policy_session(struct tpm_chip *chip,
> {
> return -EINVAL;
> }
> +static inline int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
> +{
> + return -EINVAL;
> +}
> #endif
> diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
> index 89c9798d1800..4dcc1373dd05 100644
> --- a/security/keys/trusted-keys/trusted_tpm1.c
> +++ b/security/keys/trusted-keys/trusted_tpm1.c
> @@ -22,6 +22,8 @@
>
> #include <keys/trusted_tpm.h>
>
> +#include "tpm2-policy.h"
> +
> static const char hmac_alg[] = "hmac(sha1)";
> static const char hash_alg[] = "sha1";
> static struct tpm_chip *chip;
> @@ -724,6 +726,7 @@ enum {
> Opt_hash,
> Opt_policydigest,
> Opt_policyhandle,
> + Opt_policy,
> };
>
> static const match_table_t key_tokens = {
> @@ -736,6 +739,7 @@ static const match_table_t key_tokens = {
> {Opt_hash, "hash=%s"},
> {Opt_policydigest, "policydigest=%s"},
> {Opt_policyhandle, "policyhandle=%s"},
> + {Opt_policy, "policy=%s"},
> {Opt_err, NULL}
> };
>
> @@ -869,6 +873,17 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> return -EINVAL;
> opt->policyhandle = handle;
> break;
> +
> + case Opt_policy:
> + if (pay->policies)
> + return -EINVAL;
> + if (!tpm2)
> + return -EINVAL;
> + res = tpm2_parse_policies(&pay->policies, args[0].from);
> + if (res)
> + return res;
> + break;
> +
> default:
> return -EINVAL;
> }
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 5/6] KEYS: trusted: implement counter/timer policy
2024-05-24 13:04 ` [PATCH 5/6] KEYS: trusted: implement counter/timer policy James Bottomley
@ 2024-07-16 12:03 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 12:03 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> This is actually a generic policy allowing a range of comparisons
> against any value set in the TPM Clock, which includes things like the
> reset count, a monotonic millisecond count and the restart count. The
> most useful comparison is against the millisecond count for expiring
> keys. However, you have to remember that currently Linux doesn't try
> to sync the epoch timer with the TPM, so the expiration is actually
> measured in how long the TPM itself has been powered on ... the TPM
> timer doesn't count while the system is powered down. The millisecond
> counter is a u64 quantity found at offset 8 in the timer structure,
> and the <= comparision operand is 9, so a policy set to expire after the
> TPM has been up for 100 seconds would look like
>
> 0000016d00000000000f424000080009
These random magic hex numbers confuse and do not bring any clarity.
Also, please learn to use multiple paragraph when you write text.
>
> Where 0x16d is the counter timer policy code and 0xf4240 is 100 000 in
> hex.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Skip because enough stuff to address in the head.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy
2024-05-24 13:04 ` [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy James Bottomley
@ 2024-07-16 12:03 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 12:03 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> Signed policy allows key policies to be modified after the TPM key is
> created, provided the new policy is signed with a private key whose
> public part is encoded into the initial policy. How this works is
> described in
>
> https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
>
> Since this means that the key structure now contains public keys and
> signatures, the maximum blob size has to be expanded simply to
> accommodate a key with several policies. The code assumes (as does
> all other signed policy engines) that the first policy is the most
> likely one to succeed, so it tries all the available signed policies
> in first to last order and loads the key when one of them succeeds.
>
> This code allows the kernel to process signed policy keys correctly,
> it does not allow the kernel to create them.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> drivers/char/tpm/tpm2-sessions.c | 6 +
> include/keys/trusted-type.h | 3 +-
> include/linux/tpm.h | 6 +
> security/keys/trusted-keys/tpm2-policy.c | 473 ++++++++++++++++------
> security/keys/trusted-keys/tpm2-policy.h | 19 +-
> security/keys/trusted-keys/tpm2key.asn1 | 12 +-
> security/keys/trusted-keys/trusted_tpm2.c | 63 +--
> 7 files changed, 434 insertions(+), 148 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index 63c175b2165c..c2b73283c46f 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -1365,3 +1365,9 @@ int tpm2_sessions_init(struct tpm_chip *chip)
>
> return rc;
> }
> +
> +struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip)
> +{
> + return chip->auth->tfm;
> +}
Please open code.
> +EXPORT_SYMBOL(tpm2_get_policy_hash);
> diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
> index 5d1d481a8a19..a6999800055e 100644
> --- a/include/keys/trusted-type.h
> +++ b/include/keys/trusted-type.h
> @@ -19,11 +19,12 @@
>
> #define MIN_KEY_SIZE 32
> #define MAX_KEY_SIZE 128
> -#define MAX_BLOB_SIZE 512
> +#define MAX_BLOB_SIZE 4096
> #define MAX_PCRINFO_SIZE 128
> #define MAX_DIGEST_SIZE 64
>
> #define TPM2_MAX_POLICIES 16
> +#define TPM2_MAX_AUTHS 8
>
> struct trusted_key_payload {
> struct rcu_head rcu;
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 894e51a7fe3a..09f14482675b 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -290,6 +290,8 @@ enum tpm2_command_codes {
> TPM2_CC_CONTEXT_LOAD = 0x0161,
> TPM2_CC_CONTEXT_SAVE = 0x0162,
> TPM2_CC_FLUSH_CONTEXT = 0x0165,
> + TPM2_CC_LOAD_EXTERNAL = 0x0167,
> + TPM2_CC_POLICY_AUTHORIZE = 0x016A,
> TPM2_CC_POLICY_AUTHVALUE = 0x016B,
> TPM2_CC_POLICY_COUNTER_TIMER = 0x016D,
> TPM2_CC_READ_PUBLIC = 0x0173,
> @@ -299,14 +301,17 @@ enum tpm2_command_codes {
> TPM2_CC_GET_RANDOM = 0x017B,
> TPM2_CC_PCR_READ = 0x017E,
> TPM2_CC_POLICY_PCR = 0x017F,
> + TPM2_CC_POLICY_RESTART = 0x0180,
> TPM2_CC_PCR_EXTEND = 0x0182,
> TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
> TPM2_CC_HASH_SEQUENCE_START = 0x0186,
> + TPM2_CC_POLICY_GET_DIGEST = 0x0189,
> TPM2_CC_CREATE_LOADED = 0x0191,
> TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
> };
>
> enum tpm2_permanent_handles {
> + TPM2_RH_OWNER = 0x40000001,
> TPM2_RH_NULL = 0x40000007,
> TPM2_RS_PW = 0x40000009,
> };
> @@ -578,6 +583,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
>
> int tpm2_start_auth_session(struct tpm_chip *chip);
> int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
> +struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip);
> void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
> u32 handle, u8 *name);
> void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
> diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
> index c0508cb95923..f9ee57fed8fe 100644
> --- a/security/keys/trusted-keys/tpm2-policy.c
> +++ b/security/keys/trusted-keys/tpm2-policy.c
> @@ -28,13 +28,28 @@ int tpm2_key_code(void *context, size_t hdrlen,
> u32 code = 0;
> const u8 *v = value;
> int i;
> + u8 a = ctx->auth_policies;
>
> for (i = 0; i < vlen; i++) {
> code <<= 8;
> code |= v[i];
> }
>
> - ctx->policy_code[ctx->policy_count] = code;
> + ctx->policy_code[a][ctx->policy_count[a]] = code;
> +
> + return 0;
> +}
> +
> +int tpm2_pol_seq(void *context, size_t hdrlen,
> + unsigned char tag,
> + const void *value, size_t vlen)
> +{
> + struct tpm2_key_context *ctx = context;
> +
> + ctx->auth_policies++;
> +
> + if (ctx->auth_policies > TPM2_MAX_AUTHS)
> + return -EINVAL;
>
> return 0;
> }
> @@ -44,9 +59,15 @@ int tpm2_key_policy(void *context, size_t hdrlen,
> const void *value, size_t vlen)
> {
> struct tpm2_key_context *ctx = context;
> + u8 a = ctx->auth_policies;
> + u8 policy_count = ctx->policy_count[a]++;
> +
> + if (policy_count >= TPM2_MAX_POLICIES)
> + return -EINVAL;
>
> - ctx->policies[ctx->policy_count] = value;
> - ctx->policy_len[ctx->policy_count++] = vlen;
> + ctx->policies[a][policy_count] = value;
> + ctx->policy_len[a][policy_count] = vlen;
> + ctx->policy_tot_len += vlen;
>
> return 0;
> }
> @@ -56,21 +77,24 @@ int tpm2_key_policy(void *context, size_t hdrlen,
> */
> static int tpm2_validate_policy(struct tpm2_policies *pols)
> {
> - int i;
> + int i, j;
>
> - if (pols->count == 0)
> + if (pols->auths == 0)
> return 0;
>
> - for (i = 0; i < pols->count; i++) {
> - switch (pols->code[i]) {
> - case TPM2_CC_POLICY_COUNTER_TIMER:
> - case TPM2_CC_POLICY_PCR:
> - case TPM2_CC_POLICY_AUTHVALUE:
> - break;
> - default:
> - pr_info("tpm2 policy 0x%x is unsupported\n",
> - pols->code[i]);
> + for (i = 0; i < pols->auths; i++) {
> + for (j = 0; j < pols->count[i]; j++) {
> + switch (pols->code[i][j]) {
> + case TPM2_CC_POLICY_COUNTER_TIMER:
> + case TPM2_CC_POLICY_PCR:
> + case TPM2_CC_POLICY_AUTHVALUE:
> + case TPM2_CC_POLICY_AUTHORIZE:
> + break;
> + default:
> + pr_info("tpm2 policy 0x%x is unsupported\n",
> + pols->code[i][j]);
> return -EINVAL;
> + }
> }
> }
>
> @@ -89,36 +113,35 @@ static int tpm2_validate_policy(struct tpm2_policies *pols)
> int tpm2_key_policy_process(struct tpm2_key_context *ctx,
> struct trusted_key_payload *payload)
> {
> - int tot_len = 0;
> u8 *buf;
> - int i, ret, len = 0;
> + int i, j, ret, len = 0;
> struct tpm2_policies *pols;
> u16 name_alg;
>
> - if (ctx->policy_count == 0)
> + if (ctx->policy_tot_len == 0)
> return 0;
>
> - for (i = 0; i < ctx->policy_count; i++)
> - tot_len += ctx->policy_len[i];
> - tot_len += sizeof(*pols);
> -
> - pols = kmalloc(tot_len, GFP_KERNEL);
> + pols = kmalloc(ctx->policy_tot_len + sizeof(*pols), GFP_KERNEL);
> if (!pols)
> return -ENOMEM;
>
> payload->policies = pols;
> buf = (u8 *)(pols + 1);
>
> - for (i = 0; i < ctx->policy_count; i++) {
> - pols->policies[i] = &buf[len];
> - pols->len[i] = ctx->policy_len[i];
> - pols->code[i] = ctx->policy_code[i];
> - if (pols->len[i])
> - memcpy(pols->policies[i], ctx->policies[i],
> - ctx->policy_len[i]);
> - len += ctx->policy_len[i];
> + for (i = 0; i < ctx->auth_policies; i++) {
> + for (j = 0; j < ctx->policy_count[i]; j++) {
> + pols->policies[i][j] = &buf[len];
> + pols->len[i][j] = ctx->policy_len[i][j];
> + pols->code[i][j] = ctx->policy_code[i][j];
> + if (pols->len[i][j])
> + memcpy(pols->policies[i][j],
> + ctx->policies[i][j],
> + ctx->policy_len[i][j]);
> + len += ctx->policy_len[i][j];
> + }
> + pols->count[i] = ctx->policy_count[i];
> }
> - pols->count = ctx->policy_count;
> + pols->auths = ctx->auth_policies;
>
> ret = tpm2_validate_policy(pols);
> if (ret)
> @@ -148,7 +171,7 @@ int tpm2_key_policy_process(struct tpm2_key_context *ctx,
> int tpm2_generate_policy_digest(struct tpm2_policies *pols,
> u32 hash, u8 *policydigest, u32 *plen)
> {
> - int i;
> + int i, j;
> struct crypto_shash *tfm;
> int rc;
>
> @@ -174,45 +197,47 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols,
> /* policy digests always start out all zeros */
> memset(policydigest, 0, rc);
>
> - for (i = 0; i < pols->count; i++) {
> - u8 *policy = pols->policies[i];
> - int len = pols->len[i];
> - u32 cmd = pols->code[i];
> - u8 digest[MAX_DIGEST_SIZE];
> - u8 code[4];
> - SHASH_DESC_ON_STACK(sdesc, tfm);
> + for (i = 0; i < pols->auths; i++) {
> + for (j = 0; j < pols->count[i]; j++) {
> + u8 *policy = pols->policies[i][j];
> + int len = pols->len[i][j];
> + u32 cmd = pols->code[i][j];
> + u8 digest[MAX_DIGEST_SIZE];
> + u8 code[4];
> + SHASH_DESC_ON_STACK(sdesc, tfm);
>
> - sdesc->tfm = tfm;
> - rc = crypto_shash_init(sdesc);
> - if (rc)
> - goto err;
> + sdesc->tfm = tfm;
> + rc = crypto_shash_init(sdesc);
> + if (rc)
> + goto err;
>
> - /* first hash the previous digest */
> - crypto_shash_update(sdesc, policydigest, *plen);
> + /* first hash the previous digest */
> + crypto_shash_update(sdesc, policydigest, *plen);
>
> - /* then hash the command code */
> - put_unaligned_be32(cmd, code);
> - crypto_shash_update(sdesc, code, 4);
> + /* then hash the command code */
> + put_unaligned_be32(cmd, code);
> + crypto_shash_update(sdesc, code, 4);
>
> - /* commands that need special handling */
> - if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
> - SHASH_DESC_ON_STACK(sdesc1, tfm);
> + /* commands that need special handling */
> + if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
> + SHASH_DESC_ON_STACK(sdesc1, tfm);
>
> - sdesc1->tfm = tfm;
> + sdesc1->tfm = tfm;
>
> - /* counter timer policies are double hashed */
> - crypto_shash_digest(sdesc1, policy, len,
> - digest);
> - policy = digest;
> - len = *plen;
> - }
> + /* counter timer policies are double hashed */
> + crypto_shash_digest(sdesc1, policy, len,
> + digest);
> + policy = digest;
> + len = *plen;
> + }
>
> - if (len)
> - crypto_shash_update(sdesc, policy, len);
> + if (len)
> + crypto_shash_update(sdesc, policy, len);
>
> - /* now output the intermediate to the policydigest */
> - crypto_shash_final(sdesc, policydigest);
> + /* now output the intermediate to the policydigest */
> + crypto_shash_final(sdesc, policydigest);
>
> + }
> }
> rc = 0;
>
> @@ -228,41 +253,45 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
> u8 *work = buf + SCRATCH_SIZE;
> u8 *ptr;
> u8 *end_work = work + SCRATCH_SIZE;
> - int i, ret;
> + int i, j, ret;
>
> if (!buf)
> return -ENOMEM;
>
> - for (i = 0; i < pols->count; i++) {
> - u8 *seq, *tag;
> - u32 cmd = pols->code[i];
> + for (i = 0; i < pols->auths; i++) {
> + for (j = 0; j < pols->count[i]; j++) {
> + u8 *seq, *tag;
> + u32 cmd = pols->code[i][j];
>
> - if (WARN(work - buf + 14 + pols->len[i] > 2 * SCRATCH_SIZE,
> - "BUG: scratch buffer is too small"))
> - return -EINVAL;
> + if (WARN(work - buf + 14 + pols->len[i][j] >
> + 2 * SCRATCH_SIZE,
> + "BUG: scratch buffer is too small"))
> + return -EINVAL;
>
> - work = asn1_encode_sequence(work, end_work, NULL, -1);
> - seq = work;
> + work = asn1_encode_sequence(work, end_work, NULL, -1);
> + seq = work;
>
> - work = asn1_encode_tag(work, end_work, 0, NULL, -1);
> - tag = work;
> + work = asn1_encode_tag(work, end_work, 0, NULL, -1);
> + tag = work;
>
> - work = asn1_encode_integer(work, end_work, cmd);
> - asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
> + work = asn1_encode_integer(work, end_work, cmd);
> + asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
>
> - work = asn1_encode_tag(work, end_work, 1, NULL, -1);
> - tag = work;
> + work = asn1_encode_tag(work, end_work, 1, NULL, -1);
> + tag = work;
>
> - work = asn1_encode_octet_string(work, end_work,
> - pols->policies[i],
> - pols->len[i]);
> + work = asn1_encode_octet_string(work, end_work,
> + pols->policies[i][j],
> + pols->len[i][j]);
>
> - asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
> + asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
>
> - seq = asn1_encode_sequence(seq, end_work, NULL, work - seq);
> - if (IS_ERR(seq)) {
> - ret = PTR_ERR(seq);
> - goto err;
> + seq = asn1_encode_sequence(seq, end_work, NULL,
> + work - seq);
> + if (IS_ERR(seq)) {
> + ret = PTR_ERR(seq);
> + goto err;
> + }
> }
> }
> ptr = asn1_encode_sequence(buf, buf + SCRATCH_SIZE, buf + PAGE_SIZE,
> @@ -282,18 +311,131 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
> return ret;
> }
>
> -int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
> +static int tpm2_policy_restart(struct tpm_chip *chip, u32 handle)
> {
> - int i, rc;
> - u32 handle;
> - const char *failure;
> + struct tpm_buf buf;
> + int rc;
>
> - rc = tpm2_start_policy_session(chip, &handle, pols->hash);
> + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_RESTART);
> + if (rc)
> + return rc;
> +
> + tpm_buf_append_u32(&buf, handle);
> +
> + rc = tpm_transmit_cmd(chip, &buf, 0, "restarting policy");
> + tpm_buf_destroy(&buf);
> + if (rc) {
> + pr_notice("TPM policy restart failed, rc=%d\n", rc);
> + return -EPERM;
> + }
> + return 0;
> +}
> +
> +static int tpm2_policy_gettkhash(struct tpm_chip *chip, u8 *pubkey, u8 *nonce,
> + u8 *signature, int siglen,
> + u32 handle, u8 **hash, u8 **name,
> + u8 **ticket)
> +{
> + struct tpm_buf buf;
> + int rc;
> + int len;
> + u32 sigkey;
> + off_t offset;
> + SHASH_DESC_ON_STACK(sdesc, tpm2_get_policy_hash(chip));
> +
> + sdesc->tfm = tpm2_get_policy_hash(chip);
> +
> + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_GET_DIGEST);
> if (rc)
> return rc;
>
> - for (i = 0; i < pols->count; i++) {
> - u32 cmd = pols->code[i];
> + tpm_buf_append_u32(&buf, handle);
> +
> + rc = tpm_transmit_cmd(chip, &buf, 0, "getting policy hash");
> + if (rc)
> + goto out;
> + len = get_unaligned_be16(&buf.data[TPM_HEADER_SIZE]) + 2;
> + rc = -ENOMEM;
> + *hash = kmalloc(len, GFP_KERNEL);
> + if (!*hash)
> + goto out;
> + memcpy(*hash, &buf.data[TPM_HEADER_SIZE], len);
> +
> + tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_LOAD_EXTERNAL);
> +
> + /* empty sensitive */
> + tpm_buf_append_u16(&buf, 0);
> + /* TPM2B_PUBLIC */
> + len = get_unaligned_be16(pubkey) + 2;
> + tpm_buf_append(&buf, pubkey, len);
> + /* hierarchy (use null because never a password) */
> + tpm_buf_append_u32(&buf, TPM2_RH_OWNER);
> +
> + rc = tpm_transmit_cmd(chip, &buf, 4, "loading external key");
> + if (rc)
> + goto out;
> +
> + offset = TPM_HEADER_SIZE;
> + sigkey = tpm_buf_read_u32(&buf, &offset);
> + len = get_unaligned_be16(&buf.data[offset]) + 2;
> + *name = kmalloc(len, GFP_KERNEL);
> + if (!*name) {
> + tpm2_flush_context(chip, sigkey);
> + rc = -ENOMEM;
> + goto out;
> + }
> + memcpy(*name, &buf.data[offset], len);
> +
> + tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_VERIFY_SIGNATURE);
> + /* handle of public key to verify with */
> + tpm_buf_append_u32(&buf, sigkey);
> + /* digest hash(policy||nonce) */
> + len = get_unaligned_be16(*hash);
> + tpm_buf_append_u16(&buf, len);
> + /* now compute the signed data which is hash(policy||nonce) */
> + crypto_shash_init(sdesc);
> + len = get_unaligned_be16(*hash); /* better be the tfm hash size */
> + crypto_shash_update(sdesc, *hash + 2, len);
> + len = get_unaligned_be16(nonce);
> + crypto_shash_update(sdesc, nonce + 2, len);
> + crypto_shash_final(sdesc, &buf.data[buf.length]);
> + buf.length += len;
> + /* signature */
> + tpm_buf_append(&buf, signature, siglen);
> +
> + rc = tpm_transmit_cmd(chip, &buf, 4, "verifying signature");
> + tpm2_flush_context(chip, sigkey);
> + if (rc)
> + goto out;
> +
> + len = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
> + *ticket = kmalloc(len, GFP_KERNEL);
> + if (!*ticket) {
> + rc = -ENOMEM;
> + goto out;
> + }
> + memcpy(*ticket, &buf.data[TPM_HEADER_SIZE], len);
> +
> + out:
> + if (rc) {
> + kfree(*hash);
> + *hash = NULL;
> + kfree(*name);
> + *name = NULL;
> + }
> + tpm_buf_destroy(&buf);
> + return rc;
> +}
> +
> +
> +static int tpm2_try_policy(struct tpm_chip *chip, struct tpm2_policies *pols,
> + u32 handle, int p)
> +{
> + int i, rc;
> + const char *failure;
> +
> + for (i = 0; i < pols->count[p]; i++) {
> + u32 cmd = pols->code[p][i];
> struct tpm_buf buf;
>
> rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
> @@ -311,10 +453,11 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
> * policy command
> */
> tpm_buf_append_u16(&buf, pols->hash_size);
> - tpm_buf_append(&buf, pols->policies[i] + pols->len[i] -
> + tpm_buf_append(&buf, pols->policies[p][i]
> + + pols->len[p][i] -
> pols->hash_size, pols->hash_size);
> - tpm_buf_append(&buf, pols->policies[i],
> - pols->len[i] - pols->hash_size);
> + tpm_buf_append(&buf, pols->policies[p][i],
> + pols->len[p][i] - pols->hash_size);
> break;
>
> case TPM2_CC_POLICY_COUNTER_TIMER: {
> @@ -324,26 +467,82 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
> * respectively. The rest is operandB which
> * must be zero padded in a hash digest
> */
> - u16 opb_len = pols->len[i] - 4;
> + u16 opb_len = pols->len[p][i] - 4;
>
> if (opb_len > pols->hash_size)
> return -EINVAL;
>
> tpm_buf_append_u16(&buf, opb_len);
> - tpm_buf_append(&buf, pols->policies[i], opb_len);
> + tpm_buf_append(&buf, pols->policies[p][i], opb_len);
>
> /* offset and operand*/
> - tpm_buf_append(&buf, pols->policies[i] + opb_len, 4);
> + tpm_buf_append(&buf, pols->policies[p][i] + opb_len, 4);
> failure = "Counter Timer";
>
> break;
> }
> + case TPM2_CC_POLICY_AUTHORIZE: {
> + u8 *pubkey = pols->policies[p][i];
> + u8 *nonce;
> + u8 *signature;
> + u8 *ticket = NULL;
> + u8 *hash = NULL;
> + u8 *name = NULL;
> + int len, siglen;
> + const int maxlen = pols->len[p][i];
> +
> + if (i == 0)
> + /*
> + * If this is the first policy then skip
> + * because we should already have executed
> + * a successful PolicyAuthorize before getting
> + * here
> + */
> + continue;
> +
> + len = get_unaligned_be16(pubkey);
> + if (len + 2 > maxlen) {
> + failure = "malformed policy";
> + break;
> + }
> + nonce = pubkey + len + 2;
> + len = get_unaligned_be16(nonce);
> + if (len + 2 > maxlen) {
> + failure = "malformed policy";
> + break;
> + }
> + signature = nonce + len + 2;
> + siglen = pubkey + maxlen - signature;
> + failure = "policy authorize";
> + rc = tpm2_policy_gettkhash(chip, pubkey, nonce,
> + signature, siglen,
> + handle, &hash,
> + &name, &ticket);
> + if (rc)
> + break;
> + len = get_unaligned_be16(hash);
> + tpm_buf_append(&buf, hash, len + 2);
> + kfree(hash);
> +
> + len = get_unaligned_be16(nonce);
> + tpm_buf_append(&buf, nonce, len + 2);
> +
> + len = get_unaligned_be16(name);
> + tpm_buf_append(&buf, name, len + 2);
> + kfree(name);
> +
> + len = get_unaligned_be16(ticket + 6) + 8;
> + tpm_buf_append(&buf, ticket, len);
> + kfree(ticket);
> +
> + break;
> + }
>
> default:
> failure = "unknown policy";
> - if (pols->len[i])
> - tpm_buf_append(&buf, pols->policies[i],
> - pols->len[i]);
> + if (pols->len[p][i])
> + tpm_buf_append(&buf, pols->policies[p][i],
> + pols->len[p][i]);
>
> break;
> }
> @@ -353,14 +552,62 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
> if (rc) {
> pr_notice("TPM policy %s failed, rc=%d\n",
> failure, rc);
> - tpm2_end_auth_session(chip);
> - return -EPERM;
> + return rc;
> }
> }
> -
> return 0;
> }
>
> +int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
> +{
> + int rc;
> + u32 handle;
> +
> + if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE &&
> + pols->auths == 1) {
> + pr_notice("TPM Key requires signed policies but has none\n");
> + return -EINVAL;
> + }
> +
> + rc = tpm2_start_policy_session(chip, &handle, pols->hash);
> + if (rc)
> + return rc;
> +
> + if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE) {
> + int p;
> +
> + for (p = 1; p < pols->auths; p++) {
> + if (p != 1) {
> + /* restart policy if looping */
> + rc = tpm2_policy_restart(chip, handle);
> + if (rc)
> + goto out;
> + }
> +
> + rc = tpm2_try_policy(chip, pols, handle, p);
> + if (rc) {
> + pr_notice("TPM signed policy %d failed\n", p);
> + } else {
> + pr_notice("TPM signed policy %d succeeded\n",
> + p);
> + break;
> + }
> + }
> + if (rc)
> + /* no signed policies succeeded */
> + goto out;
> + }
> +
> + rc = tpm2_try_policy(chip, pols, handle, 0);
> + out:
> + if (rc) {
> + rc = -EPERM;
> + tpm2_end_auth_session(chip);
> + }
> +
> + return rc;
> +}
> +
> int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
> {
> struct tpm2_policies *pols;
> @@ -379,22 +626,22 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
> if (*p == '\0' || *p == '\n')
> continue;
>
> - pols->len[i] = strlen(p)/2;
> - if (pols->len[i] > left) {
> + pols->len[0][i] = strlen(p)/2;
> + if (pols->len[0][i] > left) {
> res = -E2BIG;
> goto err;
> }
>
> - res = hex2bin(ptr, p, pols->len[i]);
> + res = hex2bin(ptr, p, pols->len[0][i]);
> if (res)
> goto err;
>
> /* get command code and skip past */
> - pols->code[i] = get_unaligned_be32(ptr);
> - pols->policies[i] = ptr + 4;
> - ptr += pols->len[i];
> - left -= pols->len[i];
> - pols->len[i] -= 4;
> + pols->code[0][i] = get_unaligned_be32(ptr);
> + pols->policies[0][i] = ptr + 4;
> + ptr += pols->len[0][i];
> + left -= pols->len[0][i];
> + pols->len[0][i] -= 4;
>
> /*
> * FIXME: this does leave the code embedded in dead
> @@ -404,7 +651,7 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
> i++;
> }
>
> - pols->count = i;
> + pols->count[0] = i;
> *ppols = pols;
>
> return 0;
> diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
> index 8ddf235b3fec..da0ab99078b8 100644
> --- a/security/keys/trusted-keys/tpm2-policy.h
> +++ b/security/keys/trusted-keys/tpm2-policy.h
> @@ -6,17 +6,20 @@ struct tpm2_key_context {
> u32 pub_len;
> const u8 *priv;
> u32 priv_len;
> - const u8 *policies[TPM2_MAX_POLICIES];
> - u32 policy_code[TPM2_MAX_POLICIES];
> - u16 policy_len[TPM2_MAX_POLICIES];
> - u8 policy_count;
> + const u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u32 policy_code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u16 policy_len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u8 policy_count[TPM2_MAX_AUTHS];
> + u8 auth_policies;
> + int policy_tot_len;
> };
>
> struct tpm2_policies {
> - u32 code[TPM2_MAX_POLICIES];
> - u8 *policies[TPM2_MAX_POLICIES];
> - u16 len[TPM2_MAX_POLICIES];
> - u8 count;
> + u32 code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u16 len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
> + u8 count[TPM2_MAX_AUTHS];
> + u8 auths;
> int hash; /* crypto not TPM hash algorithm */
> u16 hash_size;
> };
> diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
> index 1684bd8f725e..c5a68b3e354f 100644
> --- a/security/keys/trusted-keys/tpm2key.asn1
> +++ b/security/keys/trusted-keys/tpm2key.asn1
> @@ -5,12 +5,13 @@
> --- However, the Linux asn.1 parser doesn't understand
> --- [2] EXPLICIT SEQUENCE OF OPTIONAL
> --- So there's an extra intermediate TPMPolicySequence
> ---- definition to work around this
> +--- and TPMAuthPolicySequence definitions to work around this
>
> TPMKey ::= SEQUENCE {
> type OBJECT IDENTIFIER ({tpm2_key_type}),
> emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
> - policy [1] EXPLICIT TPMPolicySequence OPTIONAL,
> + policy [1] EXPLICIT TPMPolicySequence OPTIONAL ({tpm2_pol_seq}),
> + authPolicy [3] EXPLICIT TPMAuthPolicySequence OPTIONAL,
> parent INTEGER ({tpm2_key_parent}),
> pubkey OCTET STRING ({tpm2_key_pub}),
> privkey OCTET STRING ({tpm2_key_priv})
> @@ -22,3 +23,10 @@ TPMPolicy ::= SEQUENCE {
> commandCode [0] EXPLICIT INTEGER ({tpm2_key_code}),
> commandPolicy [1] EXPLICIT OCTET STRING ({tpm2_key_policy})
> }
> +
> +TPMAuthPolicySequence ::= SEQUENCE OF TPMAuthPolicy ({tpm2_pol_seq})
> +
> +TPMAuthPolicy ::= SEQUENCE {
> + name [0] EXPLICIT UTF8String OPTIONAL,
> + policy [1] EXPLICIT TPMPolicySequence
> + }
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index 64c922bbc36c..e2d937e44274 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -98,38 +98,45 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
> u8 **buf)
> {
> int ret;
> - struct tpm2_key_context ctx;
> + struct tpm2_key_context *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> u8 *blob;
>
> - memset(&ctx, 0, sizeof(ctx));
> + if (!ctx)
> + return -ENOMEM;
>
> - ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,
> + ret = asn1_ber_decoder(&tpm2key_decoder, ctx, payload->blob,
> payload->blob_len);
> if (ret < 0)
> - return ret;
> + goto out;
>
> - if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE)
> - return -EINVAL;
> + if (ctx->priv_len + ctx->pub_len > MAX_BLOB_SIZE) {
> + ret = -EINVAL;
> + goto out;
> + }
>
> - blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL);
> - if (!blob)
> - return -ENOMEM;
> + blob = kmalloc(ctx->priv_len + ctx->pub_len + 4, GFP_KERNEL);
> + if (!blob) {
> + ret = -ENOMEM;
> + goto out;
> + }
>
> - ret = tpm2_key_policy_process(&ctx, payload);
> + ret = tpm2_key_policy_process(ctx, payload);
> if (ret) {
> kfree(blob);
> - return ret;
> + goto out;
> }
>
> *buf = blob;
> - options->keyhandle = ctx.parent;
> + options->keyhandle = ctx->parent;
>
> - memcpy(blob, ctx.priv, ctx.priv_len);
> - blob += ctx.priv_len;
> + memcpy(blob, ctx->priv, ctx->priv_len);
> + blob += ctx->priv_len;
>
> - memcpy(blob, ctx.pub, ctx.pub_len);
> + memcpy(blob, ctx->pub, ctx->pub_len);
>
> - return 0;
> + out:
> + kfree(ctx);
> + return ret;
> }
>
> int tpm2_key_parent(void *context, size_t hdrlen,
> @@ -264,7 +271,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> pols = kmalloc(POLICY_SIZE, GFP_KERNEL);
> if (!pols)
> return -ENOMEM;
> - pols->count = 0;
> + pols->count[0] = 0;
> + pols->auths = 1;
> payload->policies = pols;
> scratch = (u8 *)(pols + 1);
> }
> @@ -275,10 +283,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> /* 4 array len */
> const int len = 4 + options->pcrinfo_len;
>
> - i = pols->count++;
> - pols->len[i] = len;
> - pols->policies[i] = scratch;
> - pols->code[i] = TPM2_CC_POLICY_PCR;
> + i = pols->count[0]++;
> + pols->len[0][i] = len;
> + pols->policies[0][i] = scratch;
> + pols->code[0][i] = TPM2_CC_POLICY_PCR;
>
> /* only a single TPMS_PCR_SELECTION */
> put_unaligned_be32(1, &scratch[0]);
> @@ -300,11 +308,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> int i;
>
> pols = payload->policies;
> - i = pols->count++;
> + i = pols->count[0]++;
>
> /* the TPM2_PolicyPassword command has no payload */
> - pols->len[i] = 0;
> - pols->code[i] = TPM2_CC_POLICY_AUTHVALUE;
> + pols->len[0][i] = 0;
> + pols->code[0][i] = TPM2_CC_POLICY_AUTHVALUE;
> }
>
> if (payload->policies) {
> @@ -685,6 +693,13 @@ int __weak tpm2_key_code(void *context, size_t hdrlen,
> return -EINVAL;
> }
>
> +int __weak tpm2_pol_seq(void *context, size_t hdrlen,
> + unsigned char tag,
> + const void *value, size_t vlen)
> +{
> + return -EINVAL;
> +}
> +
> int __weak tpm2_key_policy(void *context, size_t hdrlen,
> unsigned char tag,
> const void *value, size_t vlen)
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-16 11:53 ` Jarkko Sakkinen
@ 2024-07-16 14:07 ` Jarkko Sakkinen
2024-07-16 14:08 ` Jarkko Sakkinen
2024-07-18 2:30 ` James Bottomley
0 siblings, 2 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 14:07 UTC (permalink / raw)
To: Jarkko Sakkinen, James Bottomley, linux-integrity; +Cc: keyrings
On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
Ouch, we definitely do not want 2-dimensional arrays. I missed this in
the hmac review.
Why this is based on count (AUTH_MAX_NAMES) rather than space? Is that
value from the specs?
You could just as well replace name and name_h with a single tpm_buf
instance in "sized" mode and return -E2BIG from the functions that use
it. Right, those don't return anything but void, which should be also
fixed.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-16 14:07 ` Jarkko Sakkinen
@ 2024-07-16 14:08 ` Jarkko Sakkinen
2024-07-16 14:12 ` Jarkko Sakkinen
2024-07-18 2:30 ` James Bottomley
1 sibling, 1 reply; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 14:08 UTC (permalink / raw)
To: Jarkko Sakkinen, James Bottomley, linux-integrity; +Cc: keyrings
On Tue Jul 16, 2024 at 5:07 PM EEST, Jarkko Sakkinen wrote:
> On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
>
> Ouch, we definitely do not want 2-dimensional arrays. I missed this in
> the hmac review.
>
> Why this is based on count (AUTH_MAX_NAMES) rather than space? Is that
> value from the specs?
>
> You could just as well replace name and name_h with a single tpm_buf
> instance in "sized" mode and return -E2BIG from the functions that use
> it. Right, those don't return anything but void, which should be also
> fixed.
tpm_buf_write_u32()
tpm_buf_write()
tpm_buf_write_u32()
tpm_buf_write()
Two buffers stored. The read functions are non-destructive. Let's not
invent ad-hoc crap when we have already a tested and legit tool for
this.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-16 14:08 ` Jarkko Sakkinen
@ 2024-07-16 14:12 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-16 14:12 UTC (permalink / raw)
To: Jarkko Sakkinen, James Bottomley, linux-integrity; +Cc: keyrings
On Tue Jul 16, 2024 at 5:08 PM EEST, Jarkko Sakkinen wrote:
> On Tue Jul 16, 2024 at 5:07 PM EEST, Jarkko Sakkinen wrote:
> > On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > > > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > > > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
> >
> > Ouch, we definitely do not want 2-dimensional arrays. I missed this in
> > the hmac review.
> >
> > Why this is based on count (AUTH_MAX_NAMES) rather than space? Is that
> > value from the specs?
> >
> > You could just as well replace name and name_h with a single tpm_buf
> > instance in "sized" mode and return -E2BIG from the functions that use
> > it. Right, those don't return anything but void, which should be also
> > fixed.
>
> tpm_buf_write_u32()
> tpm_buf_write()
> tpm_buf_write_u32()
> tpm_buf_write()
>
> Two buffers stored. The read functions are non-destructive. Let's not
> invent ad-hoc crap when we have already a tested and legit tool for
> this.
Other issues that I saw is that the patch set does not apply anymore but
it is been two months so no wonder.
For the next version you should also specify a test transcript that
allows to test the functionality similarly as I've done for asymmetric
keys:
https://lore.kernel.org/linux-integrity/20240528210823.28798-1-jarkko@kernel.org/T/#mb07f85a8c3f4af388cbc08438e71ac8aea447d85
I don't want to invent the test case myself, and very few will do
I'd figure.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-16 14:07 ` Jarkko Sakkinen
2024-07-16 14:08 ` Jarkko Sakkinen
@ 2024-07-18 2:30 ` James Bottomley
2024-07-19 13:21 ` Jarkko Sakkinen
1 sibling, 1 reply; 24+ messages in thread
From: James Bottomley @ 2024-07-18 2:30 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-integrity; +Cc: keyrings
On Tue, 2024-07-16 at 17:07 +0300, Jarkko Sakkinen wrote:
> On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
>
> Ouch, we definitely do not want 2-dimensional arrays. I missed this
> in the hmac review.
>
> Why this is based on count (AUTH_MAX_NAMES) rather than space? Is
> that value from the specs?
Yes, it's based on the maximum number of session handles a command can
have. It's architecturally defined in Trusted Platform Module Library
Part 1: Architecture chapter 18 (TPM Command/Response Structure) where
it says in 18.1 "an Authorization Area containing one to three session
structures"
Although if I look at our code we really only use a maximum of two for
all the commands the kernel does.
> You could just as well replace name and name_h with a single tpm_buf
> instance in "sized" mode and return -E2BIG from the functions that
> use it. Right, those don't return anything but void, which should be
> also fixed.
I'll look into that: it would get us out of the buf->handles spat.
James
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-18 2:30 ` James Bottomley
@ 2024-07-19 13:21 ` Jarkko Sakkinen
2024-07-19 13:26 ` Jarkko Sakkinen
0 siblings, 1 reply; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-19 13:21 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Wed, 2024-07-17 at 22:30 -0400, James Bottomley wrote:
> On Tue, 2024-07-16 at 17:07 +0300, Jarkko Sakkinen wrote:
> > On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > > > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > > > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
> >
> > Ouch, we definitely do not want 2-dimensional arrays. I missed this
> > in the hmac review.
> >
> > Why this is based on count (AUTH_MAX_NAMES) rather than space? Is
> > that value from the specs?
>
> Yes, it's based on the maximum number of session handles a command can
> have. It's architecturally defined in Trusted Platform Module Library
> Part 1: Architecture chapter 18 (TPM Command/Response Structure) where
> it says in 18.1 "an Authorization Area containing one to three session
> structures"
>
> Although if I look at our code we really only use a maximum of two for
> all the commands the kernel does.
>
> > You could just as well replace name and name_h with a single tpm_buf
> > instance in "sized" mode and return -E2BIG from the functions that
> > use it. Right, those don't return anything but void, which should be
> > also fixed.
>
> I'll look into that: it would get us out of the buf->handles spat.
Also one thing I recalled after reviewing this: when updating
any of the exported functions:
1. Try to scope patch per function. Obviously when sanely
possible but at least goal should be this granularity.
2. It would make sense to take the documentation from header
and kdoc and merge them into a single entity.
This way I think it would be more digestable and easier both
test and review.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/6] tpm: add policy sessions
2024-07-19 13:21 ` Jarkko Sakkinen
@ 2024-07-19 13:26 ` Jarkko Sakkinen
0 siblings, 0 replies; 24+ messages in thread
From: Jarkko Sakkinen @ 2024-07-19 13:26 UTC (permalink / raw)
To: James Bottomley, linux-integrity; +Cc: keyrings
On Fri, 2024-07-19 at 16:21 +0300, Jarkko Sakkinen wrote:
> On Wed, 2024-07-17 at 22:30 -0400, James Bottomley wrote:
> > On Tue, 2024-07-16 at 17:07 +0300, Jarkko Sakkinen wrote:
> > > On Tue Jul 16, 2024 at 2:53 PM EEST, Jarkko Sakkinen wrote:
> > > > > - u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> > > > > + u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
> > >
> > > Ouch, we definitely do not want 2-dimensional arrays. I missed this
> > > in the hmac review.
> > >
> > > Why this is based on count (AUTH_MAX_NAMES) rather than space? Is
> > > that value from the specs?
> >
> > Yes, it's based on the maximum number of session handles a command can
> > have. It's architecturally defined in Trusted Platform Module Library
> > Part 1: Architecture chapter 18 (TPM Command/Response Structure) where
> > it says in 18.1 "an Authorization Area containing one to three session
> > structures"
> >
> > Although if I look at our code we really only use a maximum of two for
> > all the commands the kernel does.
> >
> > > You could just as well replace name and name_h with a single tpm_buf
> > > instance in "sized" mode and return -E2BIG from the functions that
> > > use it. Right, those don't return anything but void, which should be
> > > also fixed.
> >
> > I'll look into that: it would get us out of the buf->handles spat.
>
>
> Also one thing I recalled after reviewing this: when updating
> any of the exported functions:
>
> 1. Try to scope patch per function. Obviously when sanely
> possible but at least goal should be this granularity.
> 2. It would make sense to take the documentation from header
> and kdoc and merge them into a single entity.
>
> This way I think it would be more digestable and easier both
> test and review.
My philosophy here is like for any other new feature:
1. The first version can be messier, and all the issues I've complained about
(mostly because I came from holiday to fix them) are kind of part of the
job.
2. The second version or supplemental feature should make the code base
cleaner than it was before it existed.
So I kind of see the second iteration also a chance fix all the glitches
and rough corners. I don't think anything was done "wrong" durign the
first iteration, now it is just easier to reflect some of the choices.
BR, Jarkko
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2024-07-19 13:26 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-24 13:04 [PATCH 0/6] Add policy to sealed keys James Bottomley
2024-05-24 13:04 ` [PATCH 1/6] tpm: consolidate TPM to crypto hash algorithm conversion James Bottomley
2024-05-24 13:40 ` Jarkko Sakkinen
2024-05-24 13:52 ` Jarkko Sakkinen
2024-05-27 3:45 ` Ben Boeckel
2024-05-27 11:18 ` Jarkko Sakkinen
2024-07-16 11:13 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 2/6] tpm: add policy sessions James Bottomley
2024-07-16 11:53 ` Jarkko Sakkinen
2024-07-16 14:07 ` Jarkko Sakkinen
2024-07-16 14:08 ` Jarkko Sakkinen
2024-07-16 14:12 ` Jarkko Sakkinen
2024-07-18 2:30 ` James Bottomley
2024-07-19 13:21 ` Jarkko Sakkinen
2024-07-19 13:26 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 3/6] KEYS: trusted: add PCR policy to TPM2 keys James Bottomley
2024-07-16 12:01 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 4/6] KEYS: trusted: add ability to specify arbitrary policy James Bottomley
2024-07-16 12:01 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 5/6] KEYS: trusted: implement counter/timer policy James Bottomley
2024-07-16 12:03 ` Jarkko Sakkinen
2024-05-24 13:04 ` [PATCH 6/6] KEYS: trusted: add support for TPM keys with signed policy James Bottomley
2024-07-16 12:03 ` Jarkko Sakkinen
2024-05-24 13:24 ` [PATCH 0/6] Add policy to sealed keys Jarkko Sakkinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).