Commit 64a7cfbc authored by Eric Biggers's avatar Eric Biggers Committed by Jarkko Sakkinen
Browse files

tpm: Use HMAC-SHA256 library instead of open-coded HMAC



Now that there are easy-to-use HMAC-SHA256 library functions, use these
in tpm2-sessions.c instead of open-coding the HMAC algorithm.

Note that the new implementation correctly handles keys longer than 64
bytes (SHA256_BLOCK_SIZE), whereas the old implementation handled such
keys incorrectly.  But it doesn't appear that such keys were being used.

Signed-off-by: default avatarEric Biggers <ebiggers@kernel.org>
Reviewed-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
parent 2c2615c8
Loading
Loading
Loading
Loading
+27 −71
Original line number Diff line number Diff line
@@ -69,8 +69,7 @@
#include <linux/unaligned.h>
#include <crypto/kpp.h>
#include <crypto/ecdh.h>
#include <crypto/hash.h>
#include <crypto/hmac.h>
#include <crypto/sha2.h>
#include <crypto/utils.h>

/* maximum number of names the TPM must remember for authorization */
@@ -385,51 +384,6 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session);
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
			       u32 *handle, u8 *name);

/*
 * It turns out the crypto hmac(sha256) 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_ctx *sctx, u8 *key, u32 key_len)
{
	u8 pad[SHA256_BLOCK_SIZE];
	int i;

	sha256_init(sctx);
	for (i = 0; i < sizeof(pad); i++) {
		if (i < key_len)
			pad[i] = key[i];
		else
			pad[i] = 0;
		pad[i] ^= HMAC_IPAD_VALUE;
	}
	sha256_update(sctx, pad, sizeof(pad));
}

static void tpm2_hmac_final(struct sha256_ctx *sctx, u8 *key, u32 key_len,
			    u8 *out)
{
	u8 pad[SHA256_BLOCK_SIZE];
	int i;

	for (i = 0; i < sizeof(pad); i++) {
		if (i < key_len)
			pad[i] = key[i];
		else
			pad[i] = 0;
		pad[i] ^= HMAC_OPAD_VALUE;
	}

	/* collect the final hash;  use out as temporary storage */
	sha256_final(sctx, out);

	sha256_init(sctx);
	sha256_update(sctx, pad, sizeof(pad));
	sha256_update(sctx, out, SHA256_DIGEST_SIZE);
	sha256_final(sctx, out);
}

/*
 * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but
 * otherwise standard tpm2_KDFa.  Note output is in bytes not bits.
@@ -441,16 +395,16 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
	const __be32 bits = cpu_to_be32(bytes * 8);

	while (bytes > 0) {
		struct sha256_ctx sctx;
		struct hmac_sha256_ctx hctx;
		__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);
		hmac_sha256_init_usingrawkey(&hctx, key, key_len);
		hmac_sha256_update(&hctx, (u8 *)&c, sizeof(c));
		hmac_sha256_update(&hctx, label, strlen(label) + 1);
		hmac_sha256_update(&hctx, u, SHA256_DIGEST_SIZE);
		hmac_sha256_update(&hctx, v, SHA256_DIGEST_SIZE);
		hmac_sha256_update(&hctx, (u8 *)&bits, sizeof(bits));
		hmac_sha256_final(&hctx, out);

		bytes -= SHA256_DIGEST_SIZE;
		counter++;
@@ -594,6 +548,7 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
	u32 attrs;
	u8 cphash[SHA256_DIGEST_SIZE];
	struct sha256_ctx sctx;
	struct hmac_sha256_ctx hctx;

	if (!auth)
		return;
@@ -705,14 +660,14 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
	sha256_final(&sctx, cphash);

	/* now calculate the hmac */
	tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
		       + 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)
			+ auth->passphrase_len, hmac);
	hmac_sha256_init_usingrawkey(&hctx, auth->session_key,
				     sizeof(auth->session_key) +
					     auth->passphrase_len);
	hmac_sha256_update(&hctx, cphash, sizeof(cphash));
	hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce));
	hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
	hmac_sha256_update(&hctx, &auth->attrs, 1);
	hmac_sha256_final(&hctx, hmac);
}
EXPORT_SYMBOL(tpm_buf_fill_hmac_session);

@@ -752,6 +707,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
	u8 rphash[SHA256_DIGEST_SIZE];
	u32 attrs, cc;
	struct sha256_ctx sctx;
	struct hmac_sha256_ctx hctx;
	u16 tag = be16_to_cpu(head->tag);
	int parm_len, len, i, handles;

@@ -821,15 +777,15 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
	sha256_final(&sctx, rphash);

	/* now calculate the hmac */
	tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
		       + 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);
	hmac_sha256_init_usingrawkey(&hctx, auth->session_key,
				     sizeof(auth->session_key) +
					     auth->passphrase_len);
	hmac_sha256_update(&hctx, rphash, sizeof(rphash));
	hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
	hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce));
	hmac_sha256_update(&hctx, &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)
			+ auth->passphrase_len, rphash);
	hmac_sha256_final(&hctx, rphash);
	if (crypto_memneq(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE)) {
		dev_err(&chip->dev, "TPM: HMAC check failed\n");
		goto out;