Commit 366284cf authored by Eric Biggers's avatar Eric Biggers Committed by Jarkko Sakkinen
Browse files

KEYS: trusted_tpm1: Use SHA-1 library instead of crypto_shash



Use the SHA-1 and HMAC-SHA1 library functions instead of crypto_shash.
This is simpler and faster.

Replace the selection of CRYPTO, CRYPTO_HMAC, and CRYPTO_SHA1 with
CRYPTO_LIB_SHA1 and CRYPTO_LIB_UTILS.  The latter is needed for
crypto_memneq() which was previously being pulled in via CRYPTO.

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 eed0e3d3
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -5,10 +5,9 @@ config TRUSTED_KEYS_TPM
	bool "TPM-based trusted keys"
	depends on TCG_TPM >= TRUSTED_KEYS
	default y
	select CRYPTO
	select CRYPTO_HMAC
	select CRYPTO_SHA1
	select CRYPTO_HASH_INFO
	select CRYPTO_LIB_SHA1
	select CRYPTO_LIB_UTILS
	select ASN1_ENCODER
	select OID_REGISTRY
	select ASN1
+34 −187
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <crypto/hash_info.h>
#include <crypto/sha1.h>
#include <crypto/utils.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -15,78 +16,24 @@
#include <linux/err.h>
#include <keys/trusted-type.h>
#include <linux/key-type.h>
#include <linux/crypto.h>
#include <crypto/hash.h>
#include <crypto/sha1.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>

#include <keys/trusted_tpm.h>

static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
static struct tpm_chip *chip;
static struct tpm_digest *digests;

struct sdesc {
	struct shash_desc shash;
	char ctx[];
};

static struct crypto_shash *hashalg;
static struct crypto_shash *hmacalg;

static struct sdesc *init_sdesc(struct crypto_shash *alg)
{
	struct sdesc *sdesc;
	int size;

	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
	sdesc = kmalloc(size, GFP_KERNEL);
	if (!sdesc)
		return ERR_PTR(-ENOMEM);
	sdesc->shash.tfm = alg;
	return sdesc;
}

static int TSS_sha1(const unsigned char *data, unsigned int datalen,
		    unsigned char *digest)
{
	struct sdesc *sdesc;
	int ret;

	sdesc = init_sdesc(hashalg);
	if (IS_ERR(sdesc)) {
		pr_info("can't alloc %s\n", hash_alg);
		return PTR_ERR(sdesc);
	}

	ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
	kfree_sensitive(sdesc);
	return ret;
}

static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
		       unsigned int keylen, ...)
{
	struct sdesc *sdesc;
	struct hmac_sha1_ctx hmac_ctx;
	va_list argp;
	unsigned int dlen;
	unsigned char *data;
	int ret;

	sdesc = init_sdesc(hmacalg);
	if (IS_ERR(sdesc)) {
		pr_info("can't alloc %s\n", hmac_alg);
		return PTR_ERR(sdesc);
	}
	int ret = 0;

	ret = crypto_shash_setkey(hmacalg, key, keylen);
	if (ret < 0)
		goto out;
	ret = crypto_shash_init(&sdesc->shash);
	if (ret < 0)
		goto out;
	hmac_sha1_init_usingrawkey(&hmac_ctx, key, keylen);

	va_start(argp, keylen);
	for (;;) {
@@ -98,15 +45,11 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
			ret = -EINVAL;
			break;
		}
		ret = crypto_shash_update(&sdesc->shash, data, dlen);
		if (ret < 0)
			break;
		hmac_sha1_update(&hmac_ctx, data, dlen);
	}
	va_end(argp);
	if (!ret)
		ret = crypto_shash_final(&sdesc->shash, digest);
out:
	kfree_sensitive(sdesc);
		hmac_sha1_final(&hmac_ctx, digest);
	return ret;
}

@@ -118,26 +61,18 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key,
			unsigned char *h2, unsigned int h3, ...)
{
	unsigned char paramdigest[SHA1_DIGEST_SIZE];
	struct sdesc *sdesc;
	struct sha1_ctx sha_ctx;
	unsigned int dlen;
	unsigned char *data;
	unsigned char c;
	int ret;
	int ret = 0;
	va_list argp;

	if (!chip)
		return -ENODEV;

	sdesc = init_sdesc(hashalg);
	if (IS_ERR(sdesc)) {
		pr_info("can't alloc %s\n", hash_alg);
		return PTR_ERR(sdesc);
	}

	c = !!h3;
	ret = crypto_shash_init(&sdesc->shash);
	if (ret < 0)
		goto out;
	sha1_init(&sha_ctx);
	va_start(argp, h3);
	for (;;) {
		dlen = va_arg(argp, unsigned int);
@@ -148,19 +83,15 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key,
			ret = -EINVAL;
			break;
		}
		ret = crypto_shash_update(&sdesc->shash, data, dlen);
		if (ret < 0)
			break;
		sha1_update(&sha_ctx, data, dlen);
	}
	va_end(argp);
	if (!ret)
		ret = crypto_shash_final(&sdesc->shash, paramdigest);
		sha1_final(&sha_ctx, paramdigest);
	if (!ret)
		ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
				  paramdigest, TPM_NONCE_SIZE, h1,
				  TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
out:
	kfree_sensitive(sdesc);
	return ret;
}
EXPORT_SYMBOL_GPL(TSS_authhmac);
@@ -183,7 +114,7 @@ int TSS_checkhmac1(unsigned char *buffer,
	unsigned char *authdata;
	unsigned char testhmac[SHA1_DIGEST_SIZE];
	unsigned char paramdigest[SHA1_DIGEST_SIZE];
	struct sdesc *sdesc;
	struct sha1_ctx sha_ctx;
	unsigned int dlen;
	unsigned int dpos;
	va_list argp;
@@ -204,49 +135,29 @@ int TSS_checkhmac1(unsigned char *buffer,
	continueflag = authdata - 1;
	enonce = continueflag - TPM_NONCE_SIZE;

	sdesc = init_sdesc(hashalg);
	if (IS_ERR(sdesc)) {
		pr_info("can't alloc %s\n", hash_alg);
		return PTR_ERR(sdesc);
	}
	ret = crypto_shash_init(&sdesc->shash);
	if (ret < 0)
		goto out;
	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
				  sizeof result);
	if (ret < 0)
		goto out;
	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
				  sizeof ordinal);
	if (ret < 0)
		goto out;
	sha1_init(&sha_ctx);
	sha1_update(&sha_ctx, (const u8 *)&result, sizeof(result));
	sha1_update(&sha_ctx, (const u8 *)&ordinal, sizeof(ordinal));
	va_start(argp, keylen);
	for (;;) {
		dlen = va_arg(argp, unsigned int);
		if (dlen == 0)
			break;
		dpos = va_arg(argp, unsigned int);
		ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
		if (ret < 0)
			break;
		sha1_update(&sha_ctx, buffer + dpos, dlen);
	}
	va_end(argp);
	if (!ret)
		ret = crypto_shash_final(&sdesc->shash, paramdigest);
	if (ret < 0)
		goto out;
	sha1_final(&sha_ctx, paramdigest);

	ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
			  TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
			  1, continueflag, 0, 0);
	if (ret < 0)
		goto out;
		return ret;

	if (crypto_memneq(testhmac, authdata, SHA1_DIGEST_SIZE))
		ret = -EINVAL;
out:
	kfree_sensitive(sdesc);
	return ret;
		return -EINVAL;
	return 0;
}
EXPORT_SYMBOL_GPL(TSS_checkhmac1);

@@ -274,7 +185,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
	unsigned char testhmac1[SHA1_DIGEST_SIZE];
	unsigned char testhmac2[SHA1_DIGEST_SIZE];
	unsigned char paramdigest[SHA1_DIGEST_SIZE];
	struct sdesc *sdesc;
	struct sha1_ctx sha_ctx;
	unsigned int dlen;
	unsigned int dpos;
	va_list argp;
@@ -297,22 +208,9 @@ static int TSS_checkhmac2(unsigned char *buffer,
	enonce1 = continueflag1 - TPM_NONCE_SIZE;
	enonce2 = continueflag2 - TPM_NONCE_SIZE;

	sdesc = init_sdesc(hashalg);
	if (IS_ERR(sdesc)) {
		pr_info("can't alloc %s\n", hash_alg);
		return PTR_ERR(sdesc);
	}
	ret = crypto_shash_init(&sdesc->shash);
	if (ret < 0)
		goto out;
	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
				  sizeof result);
	if (ret < 0)
		goto out;
	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
				  sizeof ordinal);
	if (ret < 0)
		goto out;
	sha1_init(&sha_ctx);
	sha1_update(&sha_ctx, (const u8 *)&result, sizeof(result));
	sha1_update(&sha_ctx, (const u8 *)&ordinal, sizeof(ordinal));

	va_start(argp, keylen2);
	for (;;) {
@@ -320,35 +218,26 @@ static int TSS_checkhmac2(unsigned char *buffer,
		if (dlen == 0)
			break;
		dpos = va_arg(argp, unsigned int);
		ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
		if (ret < 0)
			break;
		sha1_update(&sha_ctx, buffer + dpos, dlen);
	}
	va_end(argp);
	if (!ret)
		ret = crypto_shash_final(&sdesc->shash, paramdigest);
	if (ret < 0)
		goto out;
	sha1_final(&sha_ctx, paramdigest);

	ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
			  paramdigest, TPM_NONCE_SIZE, enonce1,
			  TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
	if (ret < 0)
		goto out;
	if (crypto_memneq(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
		ret = -EINVAL;
		goto out;
	}
		return ret;
	if (crypto_memneq(testhmac1, authdata1, SHA1_DIGEST_SIZE))
		return -EINVAL;
	ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
			  paramdigest, TPM_NONCE_SIZE, enonce2,
			  TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
	if (ret < 0)
		goto out;
	if (crypto_memneq(testhmac2, authdata2, SHA1_DIGEST_SIZE))
		ret = -EINVAL;
out:
	kfree_sensitive(sdesc);
		return ret;
	if (crypto_memneq(testhmac2, authdata2, SHA1_DIGEST_SIZE))
		return -EINVAL;
	return 0;
}

/*
@@ -499,9 +388,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
	/* calculate encrypted authorization value */
	memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE);
	memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
	ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
	if (ret < 0)
		goto out;
	sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);

	ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE);
	if (ret < 0)
@@ -990,40 +877,6 @@ static int trusted_tpm_get_random(unsigned char *key, size_t key_len)
	return tpm_get_random(chip, key, key_len);
}

static void trusted_shash_release(void)
{
	if (hashalg)
		crypto_free_shash(hashalg);
	if (hmacalg)
		crypto_free_shash(hmacalg);
}

static int __init trusted_shash_alloc(void)
{
	int ret;

	hmacalg = crypto_alloc_shash(hmac_alg, 0, 0);
	if (IS_ERR(hmacalg)) {
		pr_info("could not allocate crypto %s\n",
			hmac_alg);
		return PTR_ERR(hmacalg);
	}

	hashalg = crypto_alloc_shash(hash_alg, 0, 0);
	if (IS_ERR(hashalg)) {
		pr_info("could not allocate crypto %s\n",
			hash_alg);
		ret = PTR_ERR(hashalg);
		goto hashalg_fail;
	}

	return 0;

hashalg_fail:
	crypto_free_shash(hmacalg);
	return ret;
}

static int __init init_digests(void)
{
	int i;
@@ -1050,15 +903,10 @@ static int __init trusted_tpm_init(void)
	ret = init_digests();
	if (ret < 0)
		goto err_put;
	ret = trusted_shash_alloc();
	if (ret < 0)
		goto err_free;
	ret = register_key_type(&key_type_trusted);
	if (ret < 0)
		goto err_release;
		goto err_free;
	return 0;
err_release:
	trusted_shash_release();
err_free:
	kfree(digests);
err_put:
@@ -1071,7 +919,6 @@ static void trusted_tpm_exit(void)
	if (chip) {
		put_device(&chip->dev);
		kfree(digests);
		trusted_shash_release();
		unregister_key_type(&key_type_trusted);
	}
}