147f9c279SSumit Garg // SPDX-License-Identifier: GPL-2.0-only
247f9c279SSumit Garg /*
347f9c279SSumit Garg  * Copyright (C) 2010 IBM Corporation
45d0682beSSumit Garg  * Copyright (c) 2019-2021, Linaro Limited
547f9c279SSumit Garg  *
647f9c279SSumit Garg  * See Documentation/security/keys/trusted-encrypted.rst
747f9c279SSumit Garg  */
847f9c279SSumit Garg 
947f9c279SSumit Garg #include <crypto/hash_info.h>
1047f9c279SSumit Garg #include <linux/init.h>
1147f9c279SSumit Garg #include <linux/slab.h>
1247f9c279SSumit Garg #include <linux/parser.h>
1347f9c279SSumit Garg #include <linux/string.h>
1447f9c279SSumit Garg #include <linux/err.h>
1547f9c279SSumit Garg #include <keys/trusted-type.h>
1647f9c279SSumit Garg #include <linux/key-type.h>
1747f9c279SSumit Garg #include <linux/crypto.h>
1847f9c279SSumit Garg #include <crypto/hash.h>
19a24d22b2SEric Biggers #include <crypto/sha1.h>
2047f9c279SSumit Garg #include <linux/tpm.h>
2147f9c279SSumit Garg #include <linux/tpm_command.h>
2247f9c279SSumit Garg 
2347f9c279SSumit Garg #include <keys/trusted_tpm.h>
2447f9c279SSumit Garg 
2547f9c279SSumit Garg static const char hmac_alg[] = "hmac(sha1)";
2647f9c279SSumit Garg static const char hash_alg[] = "sha1";
2747f9c279SSumit Garg static struct tpm_chip *chip;
2847f9c279SSumit Garg static struct tpm_digest *digests;
2947f9c279SSumit Garg 
3047f9c279SSumit Garg struct sdesc {
3147f9c279SSumit Garg 	struct shash_desc shash;
3247f9c279SSumit Garg 	char ctx[];
3347f9c279SSumit Garg };
3447f9c279SSumit Garg 
3547f9c279SSumit Garg static struct crypto_shash *hashalg;
3647f9c279SSumit Garg static struct crypto_shash *hmacalg;
3747f9c279SSumit Garg 
init_sdesc(struct crypto_shash * alg)3847f9c279SSumit Garg static struct sdesc *init_sdesc(struct crypto_shash *alg)
3947f9c279SSumit Garg {
4047f9c279SSumit Garg 	struct sdesc *sdesc;
4147f9c279SSumit Garg 	int size;
4247f9c279SSumit Garg 
4347f9c279SSumit Garg 	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
4447f9c279SSumit Garg 	sdesc = kmalloc(size, GFP_KERNEL);
4547f9c279SSumit Garg 	if (!sdesc)
4647f9c279SSumit Garg 		return ERR_PTR(-ENOMEM);
4747f9c279SSumit Garg 	sdesc->shash.tfm = alg;
4847f9c279SSumit Garg 	return sdesc;
4947f9c279SSumit Garg }
5047f9c279SSumit Garg 
TSS_sha1(const unsigned char * data,unsigned int datalen,unsigned char * digest)5147f9c279SSumit Garg static int TSS_sha1(const unsigned char *data, unsigned int datalen,
5247f9c279SSumit Garg 		    unsigned char *digest)
5347f9c279SSumit Garg {
5447f9c279SSumit Garg 	struct sdesc *sdesc;
5547f9c279SSumit Garg 	int ret;
5647f9c279SSumit Garg 
5747f9c279SSumit Garg 	sdesc = init_sdesc(hashalg);
5847f9c279SSumit Garg 	if (IS_ERR(sdesc)) {
595d0682beSSumit Garg 		pr_info("can't alloc %s\n", hash_alg);
6047f9c279SSumit Garg 		return PTR_ERR(sdesc);
6147f9c279SSumit Garg 	}
6247f9c279SSumit Garg 
6347f9c279SSumit Garg 	ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
64453431a5SWaiman Long 	kfree_sensitive(sdesc);
6547f9c279SSumit Garg 	return ret;
6647f9c279SSumit Garg }
6747f9c279SSumit Garg 
TSS_rawhmac(unsigned char * digest,const unsigned char * key,unsigned int keylen,...)6847f9c279SSumit Garg static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
6947f9c279SSumit Garg 		       unsigned int keylen, ...)
7047f9c279SSumit Garg {
7147f9c279SSumit Garg 	struct sdesc *sdesc;
7247f9c279SSumit Garg 	va_list argp;
7347f9c279SSumit Garg 	unsigned int dlen;
7447f9c279SSumit Garg 	unsigned char *data;
7547f9c279SSumit Garg 	int ret;
7647f9c279SSumit Garg 
7747f9c279SSumit Garg 	sdesc = init_sdesc(hmacalg);
7847f9c279SSumit Garg 	if (IS_ERR(sdesc)) {
795d0682beSSumit Garg 		pr_info("can't alloc %s\n", hmac_alg);
8047f9c279SSumit Garg 		return PTR_ERR(sdesc);
8147f9c279SSumit Garg 	}
8247f9c279SSumit Garg 
8347f9c279SSumit Garg 	ret = crypto_shash_setkey(hmacalg, key, keylen);
8447f9c279SSumit Garg 	if (ret < 0)
8547f9c279SSumit Garg 		goto out;
8647f9c279SSumit Garg 	ret = crypto_shash_init(&sdesc->shash);
8747f9c279SSumit Garg 	if (ret < 0)
8847f9c279SSumit Garg 		goto out;
8947f9c279SSumit Garg 
9047f9c279SSumit Garg 	va_start(argp, keylen);
9147f9c279SSumit Garg 	for (;;) {
9247f9c279SSumit Garg 		dlen = va_arg(argp, unsigned int);
9347f9c279SSumit Garg 		if (dlen == 0)
9447f9c279SSumit Garg 			break;
9547f9c279SSumit Garg 		data = va_arg(argp, unsigned char *);
9647f9c279SSumit Garg 		if (data == NULL) {
9747f9c279SSumit Garg 			ret = -EINVAL;
9847f9c279SSumit Garg 			break;
9947f9c279SSumit Garg 		}
10047f9c279SSumit Garg 		ret = crypto_shash_update(&sdesc->shash, data, dlen);
10147f9c279SSumit Garg 		if (ret < 0)
10247f9c279SSumit Garg 			break;
10347f9c279SSumit Garg 	}
10447f9c279SSumit Garg 	va_end(argp);
10547f9c279SSumit Garg 	if (!ret)
10647f9c279SSumit Garg 		ret = crypto_shash_final(&sdesc->shash, digest);
10747f9c279SSumit Garg out:
108453431a5SWaiman Long 	kfree_sensitive(sdesc);
10947f9c279SSumit Garg 	return ret;
11047f9c279SSumit Garg }
11147f9c279SSumit Garg 
11247f9c279SSumit Garg /*
11347f9c279SSumit Garg  * calculate authorization info fields to send to TPM
11447f9c279SSumit Garg  */
TSS_authhmac(unsigned char * digest,const unsigned char * key,unsigned int keylen,unsigned char * h1,unsigned char * h2,unsigned int h3,...)11547f9c279SSumit Garg int TSS_authhmac(unsigned char *digest, const unsigned char *key,
11647f9c279SSumit Garg 			unsigned int keylen, unsigned char *h1,
11747f9c279SSumit Garg 			unsigned char *h2, unsigned int h3, ...)
11847f9c279SSumit Garg {
11947f9c279SSumit Garg 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
12047f9c279SSumit Garg 	struct sdesc *sdesc;
12147f9c279SSumit Garg 	unsigned int dlen;
12247f9c279SSumit Garg 	unsigned char *data;
12347f9c279SSumit Garg 	unsigned char c;
12447f9c279SSumit Garg 	int ret;
12547f9c279SSumit Garg 	va_list argp;
12647f9c279SSumit Garg 
12747f9c279SSumit Garg 	if (!chip)
12847f9c279SSumit Garg 		return -ENODEV;
12947f9c279SSumit Garg 
13047f9c279SSumit Garg 	sdesc = init_sdesc(hashalg);
13147f9c279SSumit Garg 	if (IS_ERR(sdesc)) {
1325d0682beSSumit Garg 		pr_info("can't alloc %s\n", hash_alg);
13347f9c279SSumit Garg 		return PTR_ERR(sdesc);
13447f9c279SSumit Garg 	}
13547f9c279SSumit Garg 
13647f9c279SSumit Garg 	c = !!h3;
13747f9c279SSumit Garg 	ret = crypto_shash_init(&sdesc->shash);
13847f9c279SSumit Garg 	if (ret < 0)
13947f9c279SSumit Garg 		goto out;
14047f9c279SSumit Garg 	va_start(argp, h3);
14147f9c279SSumit Garg 	for (;;) {
14247f9c279SSumit Garg 		dlen = va_arg(argp, unsigned int);
14347f9c279SSumit Garg 		if (dlen == 0)
14447f9c279SSumit Garg 			break;
14547f9c279SSumit Garg 		data = va_arg(argp, unsigned char *);
14647f9c279SSumit Garg 		if (!data) {
14747f9c279SSumit Garg 			ret = -EINVAL;
14847f9c279SSumit Garg 			break;
14947f9c279SSumit Garg 		}
15047f9c279SSumit Garg 		ret = crypto_shash_update(&sdesc->shash, data, dlen);
15147f9c279SSumit Garg 		if (ret < 0)
15247f9c279SSumit Garg 			break;
15347f9c279SSumit Garg 	}
15447f9c279SSumit Garg 	va_end(argp);
15547f9c279SSumit Garg 	if (!ret)
15647f9c279SSumit Garg 		ret = crypto_shash_final(&sdesc->shash, paramdigest);
15747f9c279SSumit Garg 	if (!ret)
15847f9c279SSumit Garg 		ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
15947f9c279SSumit Garg 				  paramdigest, TPM_NONCE_SIZE, h1,
16047f9c279SSumit Garg 				  TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
16147f9c279SSumit Garg out:
162453431a5SWaiman Long 	kfree_sensitive(sdesc);
16347f9c279SSumit Garg 	return ret;
16447f9c279SSumit Garg }
16547f9c279SSumit Garg EXPORT_SYMBOL_GPL(TSS_authhmac);
16647f9c279SSumit Garg 
16747f9c279SSumit Garg /*
16847f9c279SSumit Garg  * verify the AUTH1_COMMAND (Seal) result from TPM
16947f9c279SSumit Garg  */
TSS_checkhmac1(unsigned char * buffer,const uint32_t command,const unsigned char * ononce,const unsigned char * key,unsigned int keylen,...)17047f9c279SSumit Garg int TSS_checkhmac1(unsigned char *buffer,
17147f9c279SSumit Garg 			  const uint32_t command,
17247f9c279SSumit Garg 			  const unsigned char *ononce,
17347f9c279SSumit Garg 			  const unsigned char *key,
17447f9c279SSumit Garg 			  unsigned int keylen, ...)
17547f9c279SSumit Garg {
17647f9c279SSumit Garg 	uint32_t bufsize;
17747f9c279SSumit Garg 	uint16_t tag;
17847f9c279SSumit Garg 	uint32_t ordinal;
17947f9c279SSumit Garg 	uint32_t result;
18047f9c279SSumit Garg 	unsigned char *enonce;
18147f9c279SSumit Garg 	unsigned char *continueflag;
18247f9c279SSumit Garg 	unsigned char *authdata;
18347f9c279SSumit Garg 	unsigned char testhmac[SHA1_DIGEST_SIZE];
18447f9c279SSumit Garg 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
18547f9c279SSumit Garg 	struct sdesc *sdesc;
18647f9c279SSumit Garg 	unsigned int dlen;
18747f9c279SSumit Garg 	unsigned int dpos;
18847f9c279SSumit Garg 	va_list argp;
18947f9c279SSumit Garg 	int ret;
19047f9c279SSumit Garg 
19147f9c279SSumit Garg 	if (!chip)
19247f9c279SSumit Garg 		return -ENODEV;
19347f9c279SSumit Garg 
19447f9c279SSumit Garg 	bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
19547f9c279SSumit Garg 	tag = LOAD16(buffer, 0);
19647f9c279SSumit Garg 	ordinal = command;
19747f9c279SSumit Garg 	result = LOAD32N(buffer, TPM_RETURN_OFFSET);
19847f9c279SSumit Garg 	if (tag == TPM_TAG_RSP_COMMAND)
19947f9c279SSumit Garg 		return 0;
20047f9c279SSumit Garg 	if (tag != TPM_TAG_RSP_AUTH1_COMMAND)
20147f9c279SSumit Garg 		return -EINVAL;
20247f9c279SSumit Garg 	authdata = buffer + bufsize - SHA1_DIGEST_SIZE;
20347f9c279SSumit Garg 	continueflag = authdata - 1;
20447f9c279SSumit Garg 	enonce = continueflag - TPM_NONCE_SIZE;
20547f9c279SSumit Garg 
20647f9c279SSumit Garg 	sdesc = init_sdesc(hashalg);
20747f9c279SSumit Garg 	if (IS_ERR(sdesc)) {
2085d0682beSSumit Garg 		pr_info("can't alloc %s\n", hash_alg);
20947f9c279SSumit Garg 		return PTR_ERR(sdesc);
21047f9c279SSumit Garg 	}
21147f9c279SSumit Garg 	ret = crypto_shash_init(&sdesc->shash);
21247f9c279SSumit Garg 	if (ret < 0)
21347f9c279SSumit Garg 		goto out;
21447f9c279SSumit Garg 	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
21547f9c279SSumit Garg 				  sizeof result);
21647f9c279SSumit Garg 	if (ret < 0)
21747f9c279SSumit Garg 		goto out;
21847f9c279SSumit Garg 	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
21947f9c279SSumit Garg 				  sizeof ordinal);
22047f9c279SSumit Garg 	if (ret < 0)
22147f9c279SSumit Garg 		goto out;
22247f9c279SSumit Garg 	va_start(argp, keylen);
22347f9c279SSumit Garg 	for (;;) {
22447f9c279SSumit Garg 		dlen = va_arg(argp, unsigned int);
22547f9c279SSumit Garg 		if (dlen == 0)
22647f9c279SSumit Garg 			break;
22747f9c279SSumit Garg 		dpos = va_arg(argp, unsigned int);
22847f9c279SSumit Garg 		ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
22947f9c279SSumit Garg 		if (ret < 0)
23047f9c279SSumit Garg 			break;
23147f9c279SSumit Garg 	}
23247f9c279SSumit Garg 	va_end(argp);
23347f9c279SSumit Garg 	if (!ret)
23447f9c279SSumit Garg 		ret = crypto_shash_final(&sdesc->shash, paramdigest);
23547f9c279SSumit Garg 	if (ret < 0)
23647f9c279SSumit Garg 		goto out;
23747f9c279SSumit Garg 
23847f9c279SSumit Garg 	ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
23947f9c279SSumit Garg 			  TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
24047f9c279SSumit Garg 			  1, continueflag, 0, 0);
24147f9c279SSumit Garg 	if (ret < 0)
24247f9c279SSumit Garg 		goto out;
24347f9c279SSumit Garg 
24447f9c279SSumit Garg 	if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
24547f9c279SSumit Garg 		ret = -EINVAL;
24647f9c279SSumit Garg out:
247453431a5SWaiman Long 	kfree_sensitive(sdesc);
24847f9c279SSumit Garg 	return ret;
24947f9c279SSumit Garg }
25047f9c279SSumit Garg EXPORT_SYMBOL_GPL(TSS_checkhmac1);
25147f9c279SSumit Garg 
25247f9c279SSumit Garg /*
25347f9c279SSumit Garg  * verify the AUTH2_COMMAND (unseal) result from TPM
25447f9c279SSumit Garg  */
TSS_checkhmac2(unsigned char * buffer,const uint32_t command,const unsigned char * ononce,const unsigned char * key1,unsigned int keylen1,const unsigned char * key2,unsigned int keylen2,...)25547f9c279SSumit Garg static int TSS_checkhmac2(unsigned char *buffer,
25647f9c279SSumit Garg 			  const uint32_t command,
25747f9c279SSumit Garg 			  const unsigned char *ononce,
25847f9c279SSumit Garg 			  const unsigned char *key1,
25947f9c279SSumit Garg 			  unsigned int keylen1,
26047f9c279SSumit Garg 			  const unsigned char *key2,
26147f9c279SSumit Garg 			  unsigned int keylen2, ...)
26247f9c279SSumit Garg {
26347f9c279SSumit Garg 	uint32_t bufsize;
26447f9c279SSumit Garg 	uint16_t tag;
26547f9c279SSumit Garg 	uint32_t ordinal;
26647f9c279SSumit Garg 	uint32_t result;
26747f9c279SSumit Garg 	unsigned char *enonce1;
26847f9c279SSumit Garg 	unsigned char *continueflag1;
26947f9c279SSumit Garg 	unsigned char *authdata1;
27047f9c279SSumit Garg 	unsigned char *enonce2;
27147f9c279SSumit Garg 	unsigned char *continueflag2;
27247f9c279SSumit Garg 	unsigned char *authdata2;
27347f9c279SSumit Garg 	unsigned char testhmac1[SHA1_DIGEST_SIZE];
27447f9c279SSumit Garg 	unsigned char testhmac2[SHA1_DIGEST_SIZE];
27547f9c279SSumit Garg 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
27647f9c279SSumit Garg 	struct sdesc *sdesc;
27747f9c279SSumit Garg 	unsigned int dlen;
27847f9c279SSumit Garg 	unsigned int dpos;
27947f9c279SSumit Garg 	va_list argp;
28047f9c279SSumit Garg 	int ret;
28147f9c279SSumit Garg 
28247f9c279SSumit Garg 	bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
28347f9c279SSumit Garg 	tag = LOAD16(buffer, 0);
28447f9c279SSumit Garg 	ordinal = command;
28547f9c279SSumit Garg 	result = LOAD32N(buffer, TPM_RETURN_OFFSET);
28647f9c279SSumit Garg 
28747f9c279SSumit Garg 	if (tag == TPM_TAG_RSP_COMMAND)
28847f9c279SSumit Garg 		return 0;
28947f9c279SSumit Garg 	if (tag != TPM_TAG_RSP_AUTH2_COMMAND)
29047f9c279SSumit Garg 		return -EINVAL;
29147f9c279SSumit Garg 	authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1
29247f9c279SSumit Garg 			+ SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE);
29347f9c279SSumit Garg 	authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE);
29447f9c279SSumit Garg 	continueflag1 = authdata1 - 1;
29547f9c279SSumit Garg 	continueflag2 = authdata2 - 1;
29647f9c279SSumit Garg 	enonce1 = continueflag1 - TPM_NONCE_SIZE;
29747f9c279SSumit Garg 	enonce2 = continueflag2 - TPM_NONCE_SIZE;
29847f9c279SSumit Garg 
29947f9c279SSumit Garg 	sdesc = init_sdesc(hashalg);
30047f9c279SSumit Garg 	if (IS_ERR(sdesc)) {
3015d0682beSSumit Garg 		pr_info("can't alloc %s\n", hash_alg);
30247f9c279SSumit Garg 		return PTR_ERR(sdesc);
30347f9c279SSumit Garg 	}
30447f9c279SSumit Garg 	ret = crypto_shash_init(&sdesc->shash);
30547f9c279SSumit Garg 	if (ret < 0)
30647f9c279SSumit Garg 		goto out;
30747f9c279SSumit Garg 	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
30847f9c279SSumit Garg 				  sizeof result);
30947f9c279SSumit Garg 	if (ret < 0)
31047f9c279SSumit Garg 		goto out;
31147f9c279SSumit Garg 	ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
31247f9c279SSumit Garg 				  sizeof ordinal);
31347f9c279SSumit Garg 	if (ret < 0)
31447f9c279SSumit Garg 		goto out;
31547f9c279SSumit Garg 
31647f9c279SSumit Garg 	va_start(argp, keylen2);
31747f9c279SSumit Garg 	for (;;) {
31847f9c279SSumit Garg 		dlen = va_arg(argp, unsigned int);
31947f9c279SSumit Garg 		if (dlen == 0)
32047f9c279SSumit Garg 			break;
32147f9c279SSumit Garg 		dpos = va_arg(argp, unsigned int);
32247f9c279SSumit Garg 		ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
32347f9c279SSumit Garg 		if (ret < 0)
32447f9c279SSumit Garg 			break;
32547f9c279SSumit Garg 	}
32647f9c279SSumit Garg 	va_end(argp);
32747f9c279SSumit Garg 	if (!ret)
32847f9c279SSumit Garg 		ret = crypto_shash_final(&sdesc->shash, paramdigest);
32947f9c279SSumit Garg 	if (ret < 0)
33047f9c279SSumit Garg 		goto out;
33147f9c279SSumit Garg 
33247f9c279SSumit Garg 	ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
33347f9c279SSumit Garg 			  paramdigest, TPM_NONCE_SIZE, enonce1,
33447f9c279SSumit Garg 			  TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
33547f9c279SSumit Garg 	if (ret < 0)
33647f9c279SSumit Garg 		goto out;
33747f9c279SSumit Garg 	if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
33847f9c279SSumit Garg 		ret = -EINVAL;
33947f9c279SSumit Garg 		goto out;
34047f9c279SSumit Garg 	}
34147f9c279SSumit Garg 	ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
34247f9c279SSumit Garg 			  paramdigest, TPM_NONCE_SIZE, enonce2,
34347f9c279SSumit Garg 			  TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
34447f9c279SSumit Garg 	if (ret < 0)
34547f9c279SSumit Garg 		goto out;
34647f9c279SSumit Garg 	if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
34747f9c279SSumit Garg 		ret = -EINVAL;
34847f9c279SSumit Garg out:
349453431a5SWaiman Long 	kfree_sensitive(sdesc);
35047f9c279SSumit Garg 	return ret;
35147f9c279SSumit Garg }
35247f9c279SSumit Garg 
35347f9c279SSumit Garg /*
35447f9c279SSumit Garg  * For key specific tpm requests, we will generate and send our
35547f9c279SSumit Garg  * own TPM command packets using the drivers send function.
35647f9c279SSumit Garg  */
trusted_tpm_send(unsigned char * cmd,size_t buflen)35747f9c279SSumit Garg int trusted_tpm_send(unsigned char *cmd, size_t buflen)
35847f9c279SSumit Garg {
35947f9c279SSumit Garg 	int rc;
36047f9c279SSumit Garg 
36147f9c279SSumit Garg 	if (!chip)
36247f9c279SSumit Garg 		return -ENODEV;
36347f9c279SSumit Garg 
36447f9c279SSumit Garg 	dump_tpm_buf(cmd);
36547f9c279SSumit Garg 	rc = tpm_send(chip, cmd, buflen);
36647f9c279SSumit Garg 	dump_tpm_buf(cmd);
36747f9c279SSumit Garg 	if (rc > 0)
36847f9c279SSumit Garg 		/* Can't return positive return codes values to keyctl */
36947f9c279SSumit Garg 		rc = -EPERM;
37047f9c279SSumit Garg 	return rc;
37147f9c279SSumit Garg }
37247f9c279SSumit Garg EXPORT_SYMBOL_GPL(trusted_tpm_send);
37347f9c279SSumit Garg 
37447f9c279SSumit Garg /*
37547f9c279SSumit Garg  * Lock a trusted key, by extending a selected PCR.
37647f9c279SSumit Garg  *
37747f9c279SSumit Garg  * Prevents a trusted key that is sealed to PCRs from being accessed.
37847f9c279SSumit Garg  * This uses the tpm driver's extend function.
37947f9c279SSumit Garg  */
pcrlock(const int pcrnum)38047f9c279SSumit Garg static int pcrlock(const int pcrnum)
38147f9c279SSumit Garg {
38247f9c279SSumit Garg 	if (!capable(CAP_SYS_ADMIN))
38347f9c279SSumit Garg 		return -EPERM;
38447f9c279SSumit Garg 
38547f9c279SSumit Garg 	return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0;
38647f9c279SSumit Garg }
38747f9c279SSumit Garg 
38847f9c279SSumit Garg /*
38947f9c279SSumit Garg  * Create an object specific authorisation protocol (OSAP) session
39047f9c279SSumit Garg  */
osap(struct tpm_buf * tb,struct osapsess * s,const unsigned char * key,uint16_t type,uint32_t handle)39147f9c279SSumit Garg static int osap(struct tpm_buf *tb, struct osapsess *s,
39247f9c279SSumit Garg 		const unsigned char *key, uint16_t type, uint32_t handle)
39347f9c279SSumit Garg {
39447f9c279SSumit Garg 	unsigned char enonce[TPM_NONCE_SIZE];
39547f9c279SSumit Garg 	unsigned char ononce[TPM_NONCE_SIZE];
39647f9c279SSumit Garg 	int ret;
39747f9c279SSumit Garg 
39847f9c279SSumit Garg 	ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE);
3995df16caaSJarkko Sakkinen 	if (ret < 0)
40047f9c279SSumit Garg 		return ret;
40147f9c279SSumit Garg 
4025df16caaSJarkko Sakkinen 	if (ret != TPM_NONCE_SIZE)
4035df16caaSJarkko Sakkinen 		return -EIO;
4045df16caaSJarkko Sakkinen 
40547f9c279SSumit Garg 	tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
40647f9c279SSumit Garg 	tpm_buf_append_u16(tb, type);
40747f9c279SSumit Garg 	tpm_buf_append_u32(tb, handle);
40847f9c279SSumit Garg 	tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
40947f9c279SSumit Garg 
41047f9c279SSumit Garg 	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
41147f9c279SSumit Garg 	if (ret < 0)
41247f9c279SSumit Garg 		return ret;
41347f9c279SSumit Garg 
41447f9c279SSumit Garg 	s->handle = LOAD32(tb->data, TPM_DATA_OFFSET);
41547f9c279SSumit Garg 	memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]),
41647f9c279SSumit Garg 	       TPM_NONCE_SIZE);
41747f9c279SSumit Garg 	memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
41847f9c279SSumit Garg 				  TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
41947f9c279SSumit Garg 	return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
42047f9c279SSumit Garg 			   enonce, TPM_NONCE_SIZE, ononce, 0, 0);
42147f9c279SSumit Garg }
42247f9c279SSumit Garg 
42347f9c279SSumit Garg /*
42447f9c279SSumit Garg  * Create an object independent authorisation protocol (oiap) session
42547f9c279SSumit Garg  */
oiap(struct tpm_buf * tb,uint32_t * handle,unsigned char * nonce)42647f9c279SSumit Garg int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
42747f9c279SSumit Garg {
42847f9c279SSumit Garg 	int ret;
42947f9c279SSumit Garg 
43047f9c279SSumit Garg 	if (!chip)
43147f9c279SSumit Garg 		return -ENODEV;
43247f9c279SSumit Garg 
43347f9c279SSumit Garg 	tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
43447f9c279SSumit Garg 	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
43547f9c279SSumit Garg 	if (ret < 0)
43647f9c279SSumit Garg 		return ret;
43747f9c279SSumit Garg 
43847f9c279SSumit Garg 	*handle = LOAD32(tb->data, TPM_DATA_OFFSET);
43947f9c279SSumit Garg 	memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
44047f9c279SSumit Garg 	       TPM_NONCE_SIZE);
44147f9c279SSumit Garg 	return 0;
44247f9c279SSumit Garg }
44347f9c279SSumit Garg EXPORT_SYMBOL_GPL(oiap);
44447f9c279SSumit Garg 
44547f9c279SSumit Garg struct tpm_digests {
44647f9c279SSumit Garg 	unsigned char encauth[SHA1_DIGEST_SIZE];
44747f9c279SSumit Garg 	unsigned char pubauth[SHA1_DIGEST_SIZE];
44847f9c279SSumit Garg 	unsigned char xorwork[SHA1_DIGEST_SIZE * 2];
44947f9c279SSumit Garg 	unsigned char xorhash[SHA1_DIGEST_SIZE];
45047f9c279SSumit Garg 	unsigned char nonceodd[TPM_NONCE_SIZE];
45147f9c279SSumit Garg };
45247f9c279SSumit Garg 
45347f9c279SSumit Garg /*
45447f9c279SSumit Garg  * Have the TPM seal(encrypt) the trusted key, possibly based on
45547f9c279SSumit Garg  * Platform Configuration Registers (PCRs). AUTH1 for sealing key.
45647f9c279SSumit Garg  */
tpm_seal(struct tpm_buf * tb,uint16_t keytype,uint32_t keyhandle,const unsigned char * keyauth,const unsigned char * data,uint32_t datalen,unsigned char * blob,uint32_t * bloblen,const unsigned char * blobauth,const unsigned char * pcrinfo,uint32_t pcrinfosize)45747f9c279SSumit Garg static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
45847f9c279SSumit Garg 		    uint32_t keyhandle, const unsigned char *keyauth,
45947f9c279SSumit Garg 		    const unsigned char *data, uint32_t datalen,
46047f9c279SSumit Garg 		    unsigned char *blob, uint32_t *bloblen,
46147f9c279SSumit Garg 		    const unsigned char *blobauth,
46247f9c279SSumit Garg 		    const unsigned char *pcrinfo, uint32_t pcrinfosize)
46347f9c279SSumit Garg {
46447f9c279SSumit Garg 	struct osapsess sess;
46547f9c279SSumit Garg 	struct tpm_digests *td;
46647f9c279SSumit Garg 	unsigned char cont;
46747f9c279SSumit Garg 	uint32_t ordinal;
46847f9c279SSumit Garg 	uint32_t pcrsize;
46947f9c279SSumit Garg 	uint32_t datsize;
47047f9c279SSumit Garg 	int sealinfosize;
47147f9c279SSumit Garg 	int encdatasize;
47247f9c279SSumit Garg 	int storedsize;
47347f9c279SSumit Garg 	int ret;
47447f9c279SSumit Garg 	int i;
47547f9c279SSumit Garg 
47647f9c279SSumit Garg 	/* alloc some work space for all the hashes */
47747f9c279SSumit Garg 	td = kmalloc(sizeof *td, GFP_KERNEL);
47847f9c279SSumit Garg 	if (!td)
47947f9c279SSumit Garg 		return -ENOMEM;
48047f9c279SSumit Garg 
48147f9c279SSumit Garg 	/* get session for sealing key */
48247f9c279SSumit Garg 	ret = osap(tb, &sess, keyauth, keytype, keyhandle);
48347f9c279SSumit Garg 	if (ret < 0)
48447f9c279SSumit Garg 		goto out;
48547f9c279SSumit Garg 	dump_sess(&sess);
48647f9c279SSumit Garg 
48747f9c279SSumit Garg 	/* calculate encrypted authorization value */
48847f9c279SSumit Garg 	memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE);
48947f9c279SSumit Garg 	memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
49047f9c279SSumit Garg 	ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
49147f9c279SSumit Garg 	if (ret < 0)
49247f9c279SSumit Garg 		goto out;
49347f9c279SSumit Garg 
49447f9c279SSumit Garg 	ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE);
4955df16caaSJarkko Sakkinen 	if (ret < 0)
496*83a775d5SColin Ian King 		goto out;
4975df16caaSJarkko Sakkinen 
498*83a775d5SColin Ian King 	if (ret != TPM_NONCE_SIZE) {
499*83a775d5SColin Ian King 		ret = -EIO;
500*83a775d5SColin Ian King 		goto out;
501*83a775d5SColin Ian King 	}
5025df16caaSJarkko Sakkinen 
50347f9c279SSumit Garg 	ordinal = htonl(TPM_ORD_SEAL);
50447f9c279SSumit Garg 	datsize = htonl(datalen);
50547f9c279SSumit Garg 	pcrsize = htonl(pcrinfosize);
50647f9c279SSumit Garg 	cont = 0;
50747f9c279SSumit Garg 
50847f9c279SSumit Garg 	/* encrypt data authorization key */
50947f9c279SSumit Garg 	for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
51047f9c279SSumit Garg 		td->encauth[i] = td->xorhash[i] ^ blobauth[i];
51147f9c279SSumit Garg 
51247f9c279SSumit Garg 	/* calculate authorization HMAC value */
51347f9c279SSumit Garg 	if (pcrinfosize == 0) {
51447f9c279SSumit Garg 		/* no pcr info specified */
51547f9c279SSumit Garg 		ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
51647f9c279SSumit Garg 				   sess.enonce, td->nonceodd, cont,
51747f9c279SSumit Garg 				   sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
51847f9c279SSumit Garg 				   td->encauth, sizeof(uint32_t), &pcrsize,
51947f9c279SSumit Garg 				   sizeof(uint32_t), &datsize, datalen, data, 0,
52047f9c279SSumit Garg 				   0);
52147f9c279SSumit Garg 	} else {
52247f9c279SSumit Garg 		/* pcr info specified */
52347f9c279SSumit Garg 		ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
52447f9c279SSumit Garg 				   sess.enonce, td->nonceodd, cont,
52547f9c279SSumit Garg 				   sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
52647f9c279SSumit Garg 				   td->encauth, sizeof(uint32_t), &pcrsize,
52747f9c279SSumit Garg 				   pcrinfosize, pcrinfo, sizeof(uint32_t),
52847f9c279SSumit Garg 				   &datsize, datalen, data, 0, 0);
52947f9c279SSumit Garg 	}
53047f9c279SSumit Garg 	if (ret < 0)
53147f9c279SSumit Garg 		goto out;
53247f9c279SSumit Garg 
53347f9c279SSumit Garg 	/* build and send the TPM request packet */
53447f9c279SSumit Garg 	tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
53547f9c279SSumit Garg 	tpm_buf_append_u32(tb, keyhandle);
53647f9c279SSumit Garg 	tpm_buf_append(tb, td->encauth, SHA1_DIGEST_SIZE);
53747f9c279SSumit Garg 	tpm_buf_append_u32(tb, pcrinfosize);
53847f9c279SSumit Garg 	tpm_buf_append(tb, pcrinfo, pcrinfosize);
53947f9c279SSumit Garg 	tpm_buf_append_u32(tb, datalen);
54047f9c279SSumit Garg 	tpm_buf_append(tb, data, datalen);
54147f9c279SSumit Garg 	tpm_buf_append_u32(tb, sess.handle);
54247f9c279SSumit Garg 	tpm_buf_append(tb, td->nonceodd, TPM_NONCE_SIZE);
54347f9c279SSumit Garg 	tpm_buf_append_u8(tb, cont);
54447f9c279SSumit Garg 	tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE);
54547f9c279SSumit Garg 
54647f9c279SSumit Garg 	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
54747f9c279SSumit Garg 	if (ret < 0)
54847f9c279SSumit Garg 		goto out;
54947f9c279SSumit Garg 
55047f9c279SSumit Garg 	/* calculate the size of the returned Blob */
55147f9c279SSumit Garg 	sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
55247f9c279SSumit Garg 	encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) +
55347f9c279SSumit Garg 			     sizeof(uint32_t) + sealinfosize);
55447f9c279SSumit Garg 	storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize +
55547f9c279SSumit Garg 	    sizeof(uint32_t) + encdatasize;
55647f9c279SSumit Garg 
55747f9c279SSumit Garg 	/* check the HMAC in the response */
55847f9c279SSumit Garg 	ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret,
55947f9c279SSumit Garg 			     SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0,
56047f9c279SSumit Garg 			     0);
56147f9c279SSumit Garg 
56247f9c279SSumit Garg 	/* copy the returned blob to caller */
56347f9c279SSumit Garg 	if (!ret) {
56447f9c279SSumit Garg 		memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
56547f9c279SSumit Garg 		*bloblen = storedsize;
56647f9c279SSumit Garg 	}
56747f9c279SSumit Garg out:
568453431a5SWaiman Long 	kfree_sensitive(td);
56947f9c279SSumit Garg 	return ret;
57047f9c279SSumit Garg }
57147f9c279SSumit Garg 
57247f9c279SSumit Garg /*
57347f9c279SSumit Garg  * use the AUTH2_COMMAND form of unseal, to authorize both key and blob
57447f9c279SSumit Garg  */
tpm_unseal(struct tpm_buf * tb,uint32_t keyhandle,const unsigned char * keyauth,const unsigned char * blob,int bloblen,const unsigned char * blobauth,unsigned char * data,unsigned int * datalen)57547f9c279SSumit Garg static int tpm_unseal(struct tpm_buf *tb,
57647f9c279SSumit Garg 		      uint32_t keyhandle, const unsigned char *keyauth,
57747f9c279SSumit Garg 		      const unsigned char *blob, int bloblen,
57847f9c279SSumit Garg 		      const unsigned char *blobauth,
57947f9c279SSumit Garg 		      unsigned char *data, unsigned int *datalen)
58047f9c279SSumit Garg {
58147f9c279SSumit Garg 	unsigned char nonceodd[TPM_NONCE_SIZE];
58247f9c279SSumit Garg 	unsigned char enonce1[TPM_NONCE_SIZE];
58347f9c279SSumit Garg 	unsigned char enonce2[TPM_NONCE_SIZE];
58447f9c279SSumit Garg 	unsigned char authdata1[SHA1_DIGEST_SIZE];
58547f9c279SSumit Garg 	unsigned char authdata2[SHA1_DIGEST_SIZE];
58647f9c279SSumit Garg 	uint32_t authhandle1 = 0;
58747f9c279SSumit Garg 	uint32_t authhandle2 = 0;
58847f9c279SSumit Garg 	unsigned char cont = 0;
58947f9c279SSumit Garg 	uint32_t ordinal;
59047f9c279SSumit Garg 	int ret;
59147f9c279SSumit Garg 
59247f9c279SSumit Garg 	/* sessions for unsealing key and data */
59347f9c279SSumit Garg 	ret = oiap(tb, &authhandle1, enonce1);
59447f9c279SSumit Garg 	if (ret < 0) {
5955d0682beSSumit Garg 		pr_info("oiap failed (%d)\n", ret);
59647f9c279SSumit Garg 		return ret;
59747f9c279SSumit Garg 	}
59847f9c279SSumit Garg 	ret = oiap(tb, &authhandle2, enonce2);
59947f9c279SSumit Garg 	if (ret < 0) {
6005d0682beSSumit Garg 		pr_info("oiap failed (%d)\n", ret);
60147f9c279SSumit Garg 		return ret;
60247f9c279SSumit Garg 	}
60347f9c279SSumit Garg 
60447f9c279SSumit Garg 	ordinal = htonl(TPM_ORD_UNSEAL);
60547f9c279SSumit Garg 	ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE);
6065df16caaSJarkko Sakkinen 	if (ret < 0)
6075df16caaSJarkko Sakkinen 		return ret;
6085df16caaSJarkko Sakkinen 
60947f9c279SSumit Garg 	if (ret != TPM_NONCE_SIZE) {
6105d0682beSSumit Garg 		pr_info("tpm_get_random failed (%d)\n", ret);
6115df16caaSJarkko Sakkinen 		return -EIO;
61247f9c279SSumit Garg 	}
61347f9c279SSumit Garg 	ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
61447f9c279SSumit Garg 			   enonce1, nonceodd, cont, sizeof(uint32_t),
61547f9c279SSumit Garg 			   &ordinal, bloblen, blob, 0, 0);
61647f9c279SSumit Garg 	if (ret < 0)
61747f9c279SSumit Garg 		return ret;
61847f9c279SSumit Garg 	ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
61947f9c279SSumit Garg 			   enonce2, nonceodd, cont, sizeof(uint32_t),
62047f9c279SSumit Garg 			   &ordinal, bloblen, blob, 0, 0);
62147f9c279SSumit Garg 	if (ret < 0)
62247f9c279SSumit Garg 		return ret;
62347f9c279SSumit Garg 
62447f9c279SSumit Garg 	/* build and send TPM request packet */
62547f9c279SSumit Garg 	tpm_buf_reset(tb, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
62647f9c279SSumit Garg 	tpm_buf_append_u32(tb, keyhandle);
62747f9c279SSumit Garg 	tpm_buf_append(tb, blob, bloblen);
62847f9c279SSumit Garg 	tpm_buf_append_u32(tb, authhandle1);
62947f9c279SSumit Garg 	tpm_buf_append(tb, nonceodd, TPM_NONCE_SIZE);
63047f9c279SSumit Garg 	tpm_buf_append_u8(tb, cont);
63147f9c279SSumit Garg 	tpm_buf_append(tb, authdata1, SHA1_DIGEST_SIZE);
63247f9c279SSumit Garg 	tpm_buf_append_u32(tb, authhandle2);
63347f9c279SSumit Garg 	tpm_buf_append(tb, nonceodd, TPM_NONCE_SIZE);
63447f9c279SSumit Garg 	tpm_buf_append_u8(tb, cont);
63547f9c279SSumit Garg 	tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE);
63647f9c279SSumit Garg 
63747f9c279SSumit Garg 	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
63847f9c279SSumit Garg 	if (ret < 0) {
6395d0682beSSumit Garg 		pr_info("authhmac failed (%d)\n", ret);
64047f9c279SSumit Garg 		return ret;
64147f9c279SSumit Garg 	}
64247f9c279SSumit Garg 
64347f9c279SSumit Garg 	*datalen = LOAD32(tb->data, TPM_DATA_OFFSET);
64447f9c279SSumit Garg 	ret = TSS_checkhmac2(tb->data, ordinal, nonceodd,
64547f9c279SSumit Garg 			     keyauth, SHA1_DIGEST_SIZE,
64647f9c279SSumit Garg 			     blobauth, SHA1_DIGEST_SIZE,
64747f9c279SSumit Garg 			     sizeof(uint32_t), TPM_DATA_OFFSET,
64847f9c279SSumit Garg 			     *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
64947f9c279SSumit Garg 			     0);
65047f9c279SSumit Garg 	if (ret < 0) {
6515d0682beSSumit Garg 		pr_info("TSS_checkhmac2 failed (%d)\n", ret);
65247f9c279SSumit Garg 		return ret;
65347f9c279SSumit Garg 	}
65447f9c279SSumit Garg 	memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
65547f9c279SSumit Garg 	return 0;
65647f9c279SSumit Garg }
65747f9c279SSumit Garg 
65847f9c279SSumit Garg /*
65947f9c279SSumit Garg  * Have the TPM seal(encrypt) the symmetric key
66047f9c279SSumit Garg  */
key_seal(struct trusted_key_payload * p,struct trusted_key_options * o)66147f9c279SSumit Garg static int key_seal(struct trusted_key_payload *p,
66247f9c279SSumit Garg 		    struct trusted_key_options *o)
66347f9c279SSumit Garg {
66447f9c279SSumit Garg 	struct tpm_buf tb;
66547f9c279SSumit Garg 	int ret;
66647f9c279SSumit Garg 
66747f9c279SSumit Garg 	ret = tpm_buf_init(&tb, 0, 0);
66847f9c279SSumit Garg 	if (ret)
66947f9c279SSumit Garg 		return ret;
67047f9c279SSumit Garg 
67147f9c279SSumit Garg 	/* include migratable flag at end of sealed key */
67247f9c279SSumit Garg 	p->key[p->key_len] = p->migratable;
67347f9c279SSumit Garg 
67447f9c279SSumit Garg 	ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
67547f9c279SSumit Garg 		       p->key, p->key_len + 1, p->blob, &p->blob_len,
67647f9c279SSumit Garg 		       o->blobauth, o->pcrinfo, o->pcrinfo_len);
67747f9c279SSumit Garg 	if (ret < 0)
6785d0682beSSumit Garg 		pr_info("srkseal failed (%d)\n", ret);
67947f9c279SSumit Garg 
68047f9c279SSumit Garg 	tpm_buf_destroy(&tb);
68147f9c279SSumit Garg 	return ret;
68247f9c279SSumit Garg }
68347f9c279SSumit Garg 
68447f9c279SSumit Garg /*
68547f9c279SSumit Garg  * Have the TPM unseal(decrypt) the symmetric key
68647f9c279SSumit Garg  */
key_unseal(struct trusted_key_payload * p,struct trusted_key_options * o)68747f9c279SSumit Garg static int key_unseal(struct trusted_key_payload *p,
68847f9c279SSumit Garg 		      struct trusted_key_options *o)
68947f9c279SSumit Garg {
69047f9c279SSumit Garg 	struct tpm_buf tb;
69147f9c279SSumit Garg 	int ret;
69247f9c279SSumit Garg 
69347f9c279SSumit Garg 	ret = tpm_buf_init(&tb, 0, 0);
69447f9c279SSumit Garg 	if (ret)
69547f9c279SSumit Garg 		return ret;
69647f9c279SSumit Garg 
69747f9c279SSumit Garg 	ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
69847f9c279SSumit Garg 			 o->blobauth, p->key, &p->key_len);
69947f9c279SSumit Garg 	if (ret < 0)
7005d0682beSSumit Garg 		pr_info("srkunseal failed (%d)\n", ret);
70147f9c279SSumit Garg 	else
70247f9c279SSumit Garg 		/* pull migratable flag out of sealed key */
70347f9c279SSumit Garg 		p->migratable = p->key[--p->key_len];
70447f9c279SSumit Garg 
70547f9c279SSumit Garg 	tpm_buf_destroy(&tb);
70647f9c279SSumit Garg 	return ret;
70747f9c279SSumit Garg }
70847f9c279SSumit Garg 
70947f9c279SSumit Garg enum {
71047f9c279SSumit Garg 	Opt_err,
71147f9c279SSumit Garg 	Opt_keyhandle, Opt_keyauth, Opt_blobauth,
71247f9c279SSumit Garg 	Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
71347f9c279SSumit Garg 	Opt_hash,
71447f9c279SSumit Garg 	Opt_policydigest,
71547f9c279SSumit Garg 	Opt_policyhandle,
71647f9c279SSumit Garg };
71747f9c279SSumit Garg 
71847f9c279SSumit Garg static const match_table_t key_tokens = {
71947f9c279SSumit Garg 	{Opt_keyhandle, "keyhandle=%s"},
72047f9c279SSumit Garg 	{Opt_keyauth, "keyauth=%s"},
72147f9c279SSumit Garg 	{Opt_blobauth, "blobauth=%s"},
72247f9c279SSumit Garg 	{Opt_pcrinfo, "pcrinfo=%s"},
72347f9c279SSumit Garg 	{Opt_pcrlock, "pcrlock=%s"},
72447f9c279SSumit Garg 	{Opt_migratable, "migratable=%s"},
72547f9c279SSumit Garg 	{Opt_hash, "hash=%s"},
72647f9c279SSumit Garg 	{Opt_policydigest, "policydigest=%s"},
72747f9c279SSumit Garg 	{Opt_policyhandle, "policyhandle=%s"},
72847f9c279SSumit Garg 	{Opt_err, NULL}
72947f9c279SSumit Garg };
73047f9c279SSumit Garg 
73147f9c279SSumit Garg /* can have zero or more token= options */
getoptions(char * c,struct trusted_key_payload * pay,struct trusted_key_options * opt)73247f9c279SSumit Garg static int getoptions(char *c, struct trusted_key_payload *pay,
73347f9c279SSumit Garg 		      struct trusted_key_options *opt)
73447f9c279SSumit Garg {
73547f9c279SSumit Garg 	substring_t args[MAX_OPT_ARGS];
73647f9c279SSumit Garg 	char *p = c;
73747f9c279SSumit Garg 	int token;
73847f9c279SSumit Garg 	int res;
73947f9c279SSumit Garg 	unsigned long handle;
74047f9c279SSumit Garg 	unsigned long lock;
74147f9c279SSumit Garg 	unsigned long token_mask = 0;
74247f9c279SSumit Garg 	unsigned int digest_len;
74347f9c279SSumit Garg 	int i;
74447f9c279SSumit Garg 	int tpm2;
74547f9c279SSumit Garg 
74647f9c279SSumit Garg 	tpm2 = tpm_is_tpm2(chip);
74747f9c279SSumit Garg 	if (tpm2 < 0)
74847f9c279SSumit Garg 		return tpm2;
74947f9c279SSumit Garg 
75047f9c279SSumit Garg 	opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
75147f9c279SSumit Garg 
75260dc5f1bSJames Bottomley 	if (!c)
75360dc5f1bSJames Bottomley 		return 0;
75460dc5f1bSJames Bottomley 
75547f9c279SSumit Garg 	while ((p = strsep(&c, " \t"))) {
75647f9c279SSumit Garg 		if (*p == '\0' || *p == ' ' || *p == '\t')
75747f9c279SSumit Garg 			continue;
75847f9c279SSumit Garg 		token = match_token(p, key_tokens, args);
75947f9c279SSumit Garg 		if (test_and_set_bit(token, &token_mask))
76047f9c279SSumit Garg 			return -EINVAL;
76147f9c279SSumit Garg 
76247f9c279SSumit Garg 		switch (token) {
76347f9c279SSumit Garg 		case Opt_pcrinfo:
76447f9c279SSumit Garg 			opt->pcrinfo_len = strlen(args[0].from) / 2;
76547f9c279SSumit Garg 			if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
76647f9c279SSumit Garg 				return -EINVAL;
76747f9c279SSumit Garg 			res = hex2bin(opt->pcrinfo, args[0].from,
76847f9c279SSumit Garg 				      opt->pcrinfo_len);
76947f9c279SSumit Garg 			if (res < 0)
77047f9c279SSumit Garg 				return -EINVAL;
77147f9c279SSumit Garg 			break;
77247f9c279SSumit Garg 		case Opt_keyhandle:
77347f9c279SSumit Garg 			res = kstrtoul(args[0].from, 16, &handle);
77447f9c279SSumit Garg 			if (res < 0)
77547f9c279SSumit Garg 				return -EINVAL;
77647f9c279SSumit Garg 			opt->keytype = SEAL_keytype;
77747f9c279SSumit Garg 			opt->keyhandle = handle;
77847f9c279SSumit Garg 			break;
77947f9c279SSumit Garg 		case Opt_keyauth:
78047f9c279SSumit Garg 			if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
78147f9c279SSumit Garg 				return -EINVAL;
78247f9c279SSumit Garg 			res = hex2bin(opt->keyauth, args[0].from,
78347f9c279SSumit Garg 				      SHA1_DIGEST_SIZE);
78447f9c279SSumit Garg 			if (res < 0)
78547f9c279SSumit Garg 				return -EINVAL;
78647f9c279SSumit Garg 			break;
78747f9c279SSumit Garg 		case Opt_blobauth:
788de66514dSJames Bottomley 			/*
789de66514dSJames Bottomley 			 * TPM 1.2 authorizations are sha1 hashes passed in as
790de66514dSJames Bottomley 			 * hex strings.  TPM 2.0 authorizations are simple
791de66514dSJames Bottomley 			 * passwords (although it can take a hash as well)
792de66514dSJames Bottomley 			 */
793de66514dSJames Bottomley 			opt->blobauth_len = strlen(args[0].from);
794de66514dSJames Bottomley 
795de66514dSJames Bottomley 			if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) {
79647f9c279SSumit Garg 				res = hex2bin(opt->blobauth, args[0].from,
797de66514dSJames Bottomley 					      TPM_DIGEST_SIZE);
79847f9c279SSumit Garg 				if (res < 0)
79947f9c279SSumit Garg 					return -EINVAL;
800de66514dSJames Bottomley 
801de66514dSJames Bottomley 				opt->blobauth_len = TPM_DIGEST_SIZE;
80247f9c279SSumit Garg 				break;
803de66514dSJames Bottomley 			}
804de66514dSJames Bottomley 
805de66514dSJames Bottomley 			if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) {
806de66514dSJames Bottomley 				memcpy(opt->blobauth, args[0].from,
807de66514dSJames Bottomley 				       opt->blobauth_len);
808de66514dSJames Bottomley 				break;
809de66514dSJames Bottomley 			}
810de66514dSJames Bottomley 
811de66514dSJames Bottomley 			return -EINVAL;
812de66514dSJames Bottomley 
813de66514dSJames Bottomley 			break;
814de66514dSJames Bottomley 
81547f9c279SSumit Garg 		case Opt_migratable:
81647f9c279SSumit Garg 			if (*args[0].from == '0')
81747f9c279SSumit Garg 				pay->migratable = 0;
8188da7520cSJarkko Sakkinen 			else if (*args[0].from != '1')
81947f9c279SSumit Garg 				return -EINVAL;
82047f9c279SSumit Garg 			break;
82147f9c279SSumit Garg 		case Opt_pcrlock:
82247f9c279SSumit Garg 			res = kstrtoul(args[0].from, 10, &lock);
82347f9c279SSumit Garg 			if (res < 0)
82447f9c279SSumit Garg 				return -EINVAL;
82547f9c279SSumit Garg 			opt->pcrlock = lock;
82647f9c279SSumit Garg 			break;
82747f9c279SSumit Garg 		case Opt_hash:
82847f9c279SSumit Garg 			if (test_bit(Opt_policydigest, &token_mask))
82947f9c279SSumit Garg 				return -EINVAL;
83047f9c279SSumit Garg 			for (i = 0; i < HASH_ALGO__LAST; i++) {
83147f9c279SSumit Garg 				if (!strcmp(args[0].from, hash_algo_name[i])) {
83247f9c279SSumit Garg 					opt->hash = i;
83347f9c279SSumit Garg 					break;
83447f9c279SSumit Garg 				}
83547f9c279SSumit Garg 			}
83647f9c279SSumit Garg 			if (i == HASH_ALGO__LAST)
83747f9c279SSumit Garg 				return -EINVAL;
83847f9c279SSumit Garg 			if  (!tpm2 && i != HASH_ALGO_SHA1) {
8395d0682beSSumit Garg 				pr_info("TPM 1.x only supports SHA-1.\n");
84047f9c279SSumit Garg 				return -EINVAL;
84147f9c279SSumit Garg 			}
84247f9c279SSumit Garg 			break;
84347f9c279SSumit Garg 		case Opt_policydigest:
84447f9c279SSumit Garg 			digest_len = hash_digest_size[opt->hash];
84547f9c279SSumit Garg 			if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
84647f9c279SSumit Garg 				return -EINVAL;
84747f9c279SSumit Garg 			res = hex2bin(opt->policydigest, args[0].from,
84847f9c279SSumit Garg 				      digest_len);
84947f9c279SSumit Garg 			if (res < 0)
85047f9c279SSumit Garg 				return -EINVAL;
85147f9c279SSumit Garg 			opt->policydigest_len = digest_len;
85247f9c279SSumit Garg 			break;
85347f9c279SSumit Garg 		case Opt_policyhandle:
85447f9c279SSumit Garg 			if (!tpm2)
85547f9c279SSumit Garg 				return -EINVAL;
85647f9c279SSumit Garg 			res = kstrtoul(args[0].from, 16, &handle);
85747f9c279SSumit Garg 			if (res < 0)
85847f9c279SSumit Garg 				return -EINVAL;
85947f9c279SSumit Garg 			opt->policyhandle = handle;
86047f9c279SSumit Garg 			break;
86147f9c279SSumit Garg 		default:
86247f9c279SSumit Garg 			return -EINVAL;
86347f9c279SSumit Garg 		}
86447f9c279SSumit Garg 	}
86547f9c279SSumit Garg 	return 0;
86647f9c279SSumit Garg }
86747f9c279SSumit Garg 
trusted_options_alloc(void)86847f9c279SSumit Garg static struct trusted_key_options *trusted_options_alloc(void)
86947f9c279SSumit Garg {
87047f9c279SSumit Garg 	struct trusted_key_options *options;
87147f9c279SSumit Garg 	int tpm2;
87247f9c279SSumit Garg 
87347f9c279SSumit Garg 	tpm2 = tpm_is_tpm2(chip);
87447f9c279SSumit Garg 	if (tpm2 < 0)
87547f9c279SSumit Garg 		return NULL;
87647f9c279SSumit Garg 
87747f9c279SSumit Garg 	options = kzalloc(sizeof *options, GFP_KERNEL);
87847f9c279SSumit Garg 	if (options) {
87947f9c279SSumit Garg 		/* set any non-zero defaults */
88047f9c279SSumit Garg 		options->keytype = SRK_keytype;
88147f9c279SSumit Garg 
88247f9c279SSumit Garg 		if (!tpm2)
88347f9c279SSumit Garg 			options->keyhandle = SRKHANDLE;
88447f9c279SSumit Garg 	}
88547f9c279SSumit Garg 	return options;
88647f9c279SSumit Garg }
88747f9c279SSumit Garg 
trusted_tpm_seal(struct trusted_key_payload * p,char * datablob)8885d0682beSSumit Garg static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
88947f9c279SSumit Garg {
89047f9c279SSumit Garg 	struct trusted_key_options *options = NULL;
89147f9c279SSumit Garg 	int ret = 0;
89247f9c279SSumit Garg 	int tpm2;
89347f9c279SSumit Garg 
89447f9c279SSumit Garg 	tpm2 = tpm_is_tpm2(chip);
89547f9c279SSumit Garg 	if (tpm2 < 0)
89647f9c279SSumit Garg 		return tpm2;
89747f9c279SSumit Garg 
89847f9c279SSumit Garg 	options = trusted_options_alloc();
8995d0682beSSumit Garg 	if (!options)
9005d0682beSSumit Garg 		return -ENOMEM;
90147f9c279SSumit Garg 
9025d0682beSSumit Garg 	ret = getoptions(datablob, p, options);
9035d0682beSSumit Garg 	if (ret < 0)
90447f9c279SSumit Garg 		goto out;
9055d0682beSSumit Garg 	dump_options(options);
90647f9c279SSumit Garg 
907f2219745SJames Bottomley 	if (!options->keyhandle && !tpm2) {
90847f9c279SSumit Garg 		ret = -EINVAL;
90947f9c279SSumit Garg 		goto out;
91047f9c279SSumit Garg 	}
91147f9c279SSumit Garg 
91247f9c279SSumit Garg 	if (tpm2)
9135d0682beSSumit Garg 		ret = tpm2_seal_trusted(chip, p, options);
91447f9c279SSumit Garg 	else
9155d0682beSSumit Garg 		ret = key_seal(p, options);
9165d0682beSSumit Garg 	if (ret < 0) {
9175d0682beSSumit Garg 		pr_info("key_seal failed (%d)\n", ret);
91847f9c279SSumit Garg 		goto out;
91947f9c279SSumit Garg 	}
9205d0682beSSumit Garg 
9215d0682beSSumit Garg 	if (options->pcrlock) {
92247f9c279SSumit Garg 		ret = pcrlock(options->pcrlock);
9235d0682beSSumit Garg 		if (ret < 0) {
9245d0682beSSumit Garg 			pr_info("pcrlock failed (%d)\n", ret);
9255d0682beSSumit Garg 			goto out;
9265d0682beSSumit Garg 		}
9275d0682beSSumit Garg 	}
92847f9c279SSumit Garg out:
929453431a5SWaiman Long 	kfree_sensitive(options);
93047f9c279SSumit Garg 	return ret;
93147f9c279SSumit Garg }
93247f9c279SSumit Garg 
trusted_tpm_unseal(struct trusted_key_payload * p,char * datablob)9335d0682beSSumit Garg static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
93447f9c279SSumit Garg {
9355d0682beSSumit Garg 	struct trusted_key_options *options = NULL;
93647f9c279SSumit Garg 	int ret = 0;
9375d0682beSSumit Garg 	int tpm2;
93847f9c279SSumit Garg 
9395d0682beSSumit Garg 	tpm2 = tpm_is_tpm2(chip);
9405d0682beSSumit Garg 	if (tpm2 < 0)
9415d0682beSSumit Garg 		return tpm2;
94247f9c279SSumit Garg 
9435d0682beSSumit Garg 	options = trusted_options_alloc();
9445d0682beSSumit Garg 	if (!options)
94547f9c279SSumit Garg 		return -ENOMEM;
94647f9c279SSumit Garg 
9475d0682beSSumit Garg 	ret = getoptions(datablob, p, options);
9485d0682beSSumit Garg 	if (ret < 0)
9495d0682beSSumit Garg 		goto out;
9505d0682beSSumit Garg 	dump_options(options);
9515d0682beSSumit Garg 
95260dc5f1bSJames Bottomley 	if (!options->keyhandle && !tpm2) {
95347f9c279SSumit Garg 		ret = -EINVAL;
95447f9c279SSumit Garg 		goto out;
95547f9c279SSumit Garg 	}
95647f9c279SSumit Garg 
9575d0682beSSumit Garg 	if (tpm2)
9585d0682beSSumit Garg 		ret = tpm2_unseal_trusted(chip, p, options);
9595d0682beSSumit Garg 	else
9605d0682beSSumit Garg 		ret = key_unseal(p, options);
9615d0682beSSumit Garg 	if (ret < 0)
9625d0682beSSumit Garg 		pr_info("key_unseal failed (%d)\n", ret);
96347f9c279SSumit Garg 
9645d0682beSSumit Garg 	if (options->pcrlock) {
9655d0682beSSumit Garg 		ret = pcrlock(options->pcrlock);
96647f9c279SSumit Garg 		if (ret < 0) {
9675d0682beSSumit Garg 			pr_info("pcrlock failed (%d)\n", ret);
96847f9c279SSumit Garg 			goto out;
96947f9c279SSumit Garg 		}
97047f9c279SSumit Garg 	}
97147f9c279SSumit Garg out:
9725d0682beSSumit Garg 	kfree_sensitive(options);
97347f9c279SSumit Garg 	return ret;
97447f9c279SSumit Garg }
97547f9c279SSumit Garg 
trusted_tpm_get_random(unsigned char * key,size_t key_len)9765d0682beSSumit Garg static int trusted_tpm_get_random(unsigned char *key, size_t key_len)
97747f9c279SSumit Garg {
9785d0682beSSumit Garg 	return tpm_get_random(chip, key, key_len);
97947f9c279SSumit Garg }
98047f9c279SSumit Garg 
trusted_shash_release(void)98147f9c279SSumit Garg static void trusted_shash_release(void)
98247f9c279SSumit Garg {
98347f9c279SSumit Garg 	if (hashalg)
98447f9c279SSumit Garg 		crypto_free_shash(hashalg);
98547f9c279SSumit Garg 	if (hmacalg)
98647f9c279SSumit Garg 		crypto_free_shash(hmacalg);
98747f9c279SSumit Garg }
98847f9c279SSumit Garg 
trusted_shash_alloc(void)98947f9c279SSumit Garg static int __init trusted_shash_alloc(void)
99047f9c279SSumit Garg {
99147f9c279SSumit Garg 	int ret;
99247f9c279SSumit Garg 
99347f9c279SSumit Garg 	hmacalg = crypto_alloc_shash(hmac_alg, 0, 0);
99447f9c279SSumit Garg 	if (IS_ERR(hmacalg)) {
9955d0682beSSumit Garg 		pr_info("could not allocate crypto %s\n",
99647f9c279SSumit Garg 			hmac_alg);
99747f9c279SSumit Garg 		return PTR_ERR(hmacalg);
99847f9c279SSumit Garg 	}
99947f9c279SSumit Garg 
100047f9c279SSumit Garg 	hashalg = crypto_alloc_shash(hash_alg, 0, 0);
100147f9c279SSumit Garg 	if (IS_ERR(hashalg)) {
10025d0682beSSumit Garg 		pr_info("could not allocate crypto %s\n",
100347f9c279SSumit Garg 			hash_alg);
100447f9c279SSumit Garg 		ret = PTR_ERR(hashalg);
100547f9c279SSumit Garg 		goto hashalg_fail;
100647f9c279SSumit Garg 	}
100747f9c279SSumit Garg 
100847f9c279SSumit Garg 	return 0;
100947f9c279SSumit Garg 
101047f9c279SSumit Garg hashalg_fail:
101147f9c279SSumit Garg 	crypto_free_shash(hmacalg);
101247f9c279SSumit Garg 	return ret;
101347f9c279SSumit Garg }
101447f9c279SSumit Garg 
init_digests(void)101547f9c279SSumit Garg static int __init init_digests(void)
101647f9c279SSumit Garg {
101747f9c279SSumit Garg 	int i;
101847f9c279SSumit Garg 
101947f9c279SSumit Garg 	digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
102047f9c279SSumit Garg 			  GFP_KERNEL);
102147f9c279SSumit Garg 	if (!digests)
102247f9c279SSumit Garg 		return -ENOMEM;
102347f9c279SSumit Garg 
102447f9c279SSumit Garg 	for (i = 0; i < chip->nr_allocated_banks; i++)
102547f9c279SSumit Garg 		digests[i].alg_id = chip->allocated_banks[i].alg_id;
102647f9c279SSumit Garg 
102747f9c279SSumit Garg 	return 0;
102847f9c279SSumit Garg }
102947f9c279SSumit Garg 
trusted_tpm_init(void)10305d0682beSSumit Garg static int __init trusted_tpm_init(void)
103147f9c279SSumit Garg {
103247f9c279SSumit Garg 	int ret;
103347f9c279SSumit Garg 
103447f9c279SSumit Garg 	chip = tpm_default_chip();
103547f9c279SSumit Garg 	if (!chip)
10365d0682beSSumit Garg 		return -ENODEV;
103747f9c279SSumit Garg 
103847f9c279SSumit Garg 	ret = init_digests();
103947f9c279SSumit Garg 	if (ret < 0)
104047f9c279SSumit Garg 		goto err_put;
104147f9c279SSumit Garg 	ret = trusted_shash_alloc();
104247f9c279SSumit Garg 	if (ret < 0)
104347f9c279SSumit Garg 		goto err_free;
104447f9c279SSumit Garg 	ret = register_key_type(&key_type_trusted);
104547f9c279SSumit Garg 	if (ret < 0)
104647f9c279SSumit Garg 		goto err_release;
104747f9c279SSumit Garg 	return 0;
104847f9c279SSumit Garg err_release:
104947f9c279SSumit Garg 	trusted_shash_release();
105047f9c279SSumit Garg err_free:
105147f9c279SSumit Garg 	kfree(digests);
105247f9c279SSumit Garg err_put:
105347f9c279SSumit Garg 	put_device(&chip->dev);
105447f9c279SSumit Garg 	return ret;
105547f9c279SSumit Garg }
105647f9c279SSumit Garg 
trusted_tpm_exit(void)10575d0682beSSumit Garg static void trusted_tpm_exit(void)
105847f9c279SSumit Garg {
105947f9c279SSumit Garg 	if (chip) {
106047f9c279SSumit Garg 		put_device(&chip->dev);
106147f9c279SSumit Garg 		kfree(digests);
106247f9c279SSumit Garg 		trusted_shash_release();
106347f9c279SSumit Garg 		unregister_key_type(&key_type_trusted);
106447f9c279SSumit Garg 	}
106547f9c279SSumit Garg }
106647f9c279SSumit Garg 
10675d0682beSSumit Garg struct trusted_key_ops trusted_key_tpm_ops = {
10685d0682beSSumit Garg 	.migratable = 1, /* migratable by default */
10695d0682beSSumit Garg 	.init = trusted_tpm_init,
10705d0682beSSumit Garg 	.seal = trusted_tpm_seal,
10715d0682beSSumit Garg 	.unseal = trusted_tpm_unseal,
10725d0682beSSumit Garg 	.get_random = trusted_tpm_get_random,
10735d0682beSSumit Garg 	.exit = trusted_tpm_exit,
10745d0682beSSumit Garg };
1075