lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed,  2 Nov 2011 13:41:19 +0100
From:	Roberto Sassu <roberto.sassu@...ito.it>
To:	keyrings@...ux-nfs.org
Cc:	linux-security-module@...r.kernel.org,
	linux-kernel@...r.kernel.org, safford@...son.ibm.com,
	zohar@...ibm.com, dhowells@...hat.com, jmorris@...ei.org,
	Roberto Sassu <roberto.sassu@...ito.it>
Subject: [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM

The new functions 'tpm_loadkey2', 'tpm_evictkey' and 'tpm_flushspecific'
allow to load/unload a TPM key whose blob is provided from the userspace
interface and to use it for sealing or unsealing the symmetric key.

Signed-off-by: Roberto Sassu <roberto.sassu@...ito.it>
---
 Documentation/security/keys-trusted-encrypted.txt |    6 +-
 include/linux/tpm_command.h                       |    6 +
 security/keys/trusted.c                           |  203 ++++++++++++++++++++-
 security/keys/trusted.h                           |   27 +++-
 4 files changed, 234 insertions(+), 8 deletions(-)

diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt
index 5f50cca..afebb58 100644
--- a/Documentation/security/keys-trusted-encrypted.txt
+++ b/Documentation/security/keys-trusted-encrypted.txt
@@ -27,8 +27,10 @@ Usage:
     keyctl print keyid
 
     options:
-       keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
-       keyauth=	  ascii hex auth for sealing key default 0x00...i
+       keyhandle= ascii hex value of sealing key handle default 0x40000000 (SRK)
+       keyblob=   ascii hex value of sealing key blob (no default)
+       srkauth=   ascii hex auth for SRK key default 0x00...
+       keyauth=	  ascii hex auth for sealing key (not SRK) default 0x00...
 		  (40 ascii zeros)
        blobauth=  ascii hex auth for sealed data default 0x00...
 		  (40 ascii zeros)
diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h
index 727512e..e3348b7 100644
--- a/include/linux/tpm_command.h
+++ b/include/linux/tpm_command.h
@@ -15,7 +15,10 @@
 #define TPM_TAG_RSP_AUTH2_COMMAND       198
 
 /* Command Ordinals */
+#define TPM_ORD_EVICTKEY                34
+#define TPM_ORD_FLUSHSPECIFIC          186
 #define TPM_ORD_GETRANDOM               70
+#define TPM_ORD_LOADKEY2                65
 #define TPM_ORD_OSAP                    11
 #define TPM_ORD_OIAP                    10
 #define TPM_ORD_SEAL                    23
@@ -24,5 +27,8 @@
 /* Other constants */
 #define SRKHANDLE                       0x40000000
 #define TPM_NONCE_SIZE                  20
+#define TPM_RT_KEY                      0x00000001
+#define TPM_TAG_KEY12                   0x0028
+#define TPM_BAD_ORDINAL                 10
 
 #endif
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 8777015..c332e3b 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -688,12 +688,118 @@ static int tpm_unseal(struct tpm_buf *tb,
 }
 
 /*
+ * Load a TPM key from the blob provided by userspace
+ */
+static int tpm_loadkey2(struct tpm_buf *tb,
+			uint32_t keyhandle, unsigned char *keyauth,
+			const unsigned char *keyblob, int keybloblen,
+			uint32_t *newhandle)
+{
+	unsigned char nonceodd[TPM_NONCE_SIZE];
+	unsigned char enonce[TPM_NONCE_SIZE];
+	unsigned char authdata[SHA1_DIGEST_SIZE];
+	uint32_t authhandle = 0;
+	unsigned char cont = 0;
+	uint32_t ordinal;
+	int ret;
+
+	ordinal = htonl(TPM_ORD_LOADKEY2);
+
+	/* session for loading the key */
+	ret = oiap(tb, &authhandle, enonce);
+	if (ret < 0) {
+		pr_info("trusted_key: oiap failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* generate odd nonce */
+	ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
+	if (ret < 0) {
+		pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* calculate authorization HMAC value */
+	ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce,
+			   nonceodd, cont, sizeof(uint32_t), &ordinal,
+			   keybloblen, keyblob, 0, 0);
+	if (ret < 0)
+		return ret;
+
+	/* build the request buffer */
+	INIT_BUF(tb);
+	store16(tb, TPM_TAG_RQU_AUTH1_COMMAND);
+	store32(tb, TPM_LOADKEY2_SIZE + keybloblen);
+	store32(tb, TPM_ORD_LOADKEY2);
+	store32(tb, keyhandle);
+	storebytes(tb, keyblob, keybloblen);
+	store32(tb, authhandle);
+	storebytes(tb, nonceodd, TPM_NONCE_SIZE);
+	store8(tb, cont);
+	storebytes(tb, authdata, SHA1_DIGEST_SIZE);
+
+	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+	if (ret < 0) {
+		pr_info("trusted_key: authhmac failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, keyauth,
+			     SHA1_DIGEST_SIZE, 0, 0);
+	if (ret < 0) {
+		pr_info("trusted_key: TSS_checkhmac1 failed (%d)\n", ret);
+		return ret;
+	}
+
+	*newhandle = LOAD32(tb->data, TPM_DATA_OFFSET);
+	return 0;
+}
+
+/*
+ * Execute the FlushSpecific TPM command
+ */
+uint32_t tpm_flushspecific(struct tpm_buf *tb, uint32_t handle,
+			   uint32_t resourcetype)
+{
+	INIT_BUF(tb);
+	store16(tb, TPM_TAG_RQU_COMMAND);
+	store32(tb, TPM_FLUSHSPECIFIC_SIZE);
+	store32(tb, TPM_ORD_FLUSHSPECIFIC);
+	store32(tb, handle);
+	store32(tb, resourcetype);
+
+	return trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+}
+
+/*
+ * Evict a key from the TPM
+ */
+uint32_t tpm_evictkey(struct tpm_buf *tb, uint32_t keyhandle)
+{
+	int ret;
+
+	INIT_BUF(tb);
+	store16(tb, TPM_TAG_RQU_COMMAND);
+	store32(tb, TPM_EVICTKEY_SIZE);
+	store32(tb, TPM_ORD_EVICTKEY);
+	store32(tb, keyhandle);
+
+	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
+	if (ret < 0)
+		ret = tpm_flushspecific(tb, keyhandle, TPM_RT_KEY);
+
+	return ret;
+}
+
+/*
  * Have the TPM seal(encrypt) the symmetric key
  */
 static int key_seal(struct trusted_key_payload *p,
 		    struct trusted_key_options *o)
 {
 	struct tpm_buf *tb;
+	uint32_t keyhandle;
+	unsigned char *parentauth;
 	int ret;
 
 	tb = kzalloc(sizeof *tb, GFP_KERNEL);
@@ -703,12 +809,40 @@ static int key_seal(struct trusted_key_payload *p,
 	/* include migratable flag at end of sealed key */
 	p->key[p->key_len] = p->migratable;
 
-	ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
+	/* set default values */
+	keyhandle = o->keyhandle;
+	parentauth = o->srkauth;
+
+	if (o->keytype == SEAL_keytype) {
+		parentauth = o->keyauth;
+		if (o->keyblob_len > 0) {
+			ret = tpm_loadkey2(tb, SRKHANDLE, o->srkauth,
+					   o->keyblob, o->keyblob_len,
+					   &keyhandle);
+			if (ret < 0) {
+				pr_info("trusted_key: loadkey2 failed (%d)\n",
+					ret);
+				goto out;
+			}
+
+			dump_tpm_key12_handle(keyhandle);
+		}
+	}
+
+	ret = tpm_seal(tb, o->keytype, keyhandle, parentauth,
 		       p->key, p->key_len + 1, p->blob, &p->blob_len,
 		       o->blobauth, o->pcrinfo, o->pcrinfo_len);
 	if (ret < 0)
 		pr_info("trusted_key: srkseal failed (%d)\n", ret);
 
+	if (o->keyblob_len > 0) {
+		int evictret = tpm_evictkey(tb, keyhandle);
+
+		if (evictret < 0)
+			pr_info("trusted_key: evictkey failed (%d)\n",
+				evictret);
+	}
+out:
 	kfree(tb);
 	return ret;
 }
@@ -720,13 +854,33 @@ static int key_unseal(struct trusted_key_payload *p,
 		      struct trusted_key_options *o)
 {
 	struct tpm_buf *tb;
+	uint32_t keyhandle;
+	unsigned char *parentauth;
 	int ret;
 
 	tb = kzalloc(sizeof *tb, GFP_KERNEL);
 	if (!tb)
 		return -ENOMEM;
 
-	ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+	/* set default values */
+	keyhandle = o->keyhandle;
+	parentauth = o->srkauth;
+
+	if (o->keytype == SEAL_keytype) {
+		parentauth = o->keyauth;
+		if (o->keyblob_len > 0) {
+			ret = tpm_loadkey2(tb, SRKHANDLE, o->srkauth,
+					   o->keyblob, o->keyblob_len,
+					   &keyhandle);
+			if (ret < 0) {
+				pr_info("trusted_key: loadkey2 failed (%d)\n",
+					ret);
+				goto out;
+			}
+		}
+	}
+
+	ret = tpm_unseal(tb, keyhandle, parentauth, p->blob, p->blob_len,
 			 o->blobauth, p->key, &p->key_len);
 	if (ret < 0)
 		pr_info("trusted_key: srkunseal failed (%d)\n", ret);
@@ -734,14 +888,22 @@ static int key_unseal(struct trusted_key_payload *p,
 		/* pull migratable flag out of sealed key */
 		p->migratable = p->key[--p->key_len];
 
+	if (o->keyblob_len > 0) {
+		int evictret = tpm_evictkey(tb, keyhandle);
+
+		if (evictret < 0)
+			pr_info("trusted_key: evictkey failed (%d)\n",
+				evictret);
+	}
+out:
 	kfree(tb);
 	return ret;
 }
 
 enum {
 	Opt_err = -1,
-	Opt_new, Opt_load, Opt_update,
-	Opt_keyhandle, Opt_keyauth, Opt_blobauth,
+	Opt_new, Opt_load, Opt_update, Opt_srkauth,
+	Opt_keyhandle, Opt_keyblob, Opt_keyauth, Opt_blobauth,
 	Opt_pcrinfo, Opt_pcrlock, Opt_migratable
 };
 
@@ -749,7 +911,9 @@ static const match_table_t key_tokens = {
 	{Opt_new, "new"},
 	{Opt_load, "load"},
 	{Opt_update, "update"},
+	{Opt_srkauth, "srkauth=%s"},
 	{Opt_keyhandle, "keyhandle=%s"},
+	{Opt_keyblob, "keyblob=%s"},
 	{Opt_keyauth, "keyauth=%s"},
 	{Opt_blobauth, "blobauth=%s"},
 	{Opt_pcrinfo, "pcrinfo=%s"},
@@ -768,6 +932,8 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
 	int res;
 	unsigned long handle;
 	unsigned long lock;
+	uint16_t tpm_key_tag;
+	uint32_t value;
 
 	while ((p = strsep(&c, " \t"))) {
 		if (*p == '\0' || *p == ' ' || *p == '\t')
@@ -788,6 +954,35 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
 			opt->keytype = SEAL_keytype;
 			opt->keyhandle = handle;
 			break;
+		case Opt_keyblob:
+			if (strlen(args[0].from) >= MAX_KEYBLOB_SIZE * 2)
+				return -EINVAL;
+			hex2bin(opt->keyblob, args[0].from, MAX_KEYBLOB_SIZE);
+			tpm_key_tag = LOAD16(opt->keyblob, 0);
+			if (tpm_key_tag != TPM_TAG_KEY12)
+				return -EINVAL;
+			opt->keytype = SEAL_keytype;
+			opt->keyblob_len = TPM_KEY12_EXPSIZE_OFFSET;
+			/* key exponent size */
+			value = LOAD32(opt->keyblob, opt->keyblob_len);
+			opt->keyblob_len += sizeof(uint32_t) + value;
+			/* PCRINFO size */
+			value = LOAD32(opt->keyblob, opt->keyblob_len);
+			opt->keyblob_len += sizeof(uint32_t) + value;
+			/* key length */
+			value = LOAD32(opt->keyblob, opt->keyblob_len);
+			opt->keyblob_len += sizeof(uint32_t) + value;
+			/* enc data size */
+			value = LOAD32(opt->keyblob, opt->keyblob_len);
+			opt->keyblob_len += sizeof(uint32_t) + value;
+			if (opt->keyblob_len >= MAX_KEYBLOB_SIZE)
+				return -EINVAL;
+			break;
+		case Opt_srkauth:
+			if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
+				return -EINVAL;
+			hex2bin(opt->srkauth, args[0].from, SHA1_DIGEST_SIZE);
+			break;
 		case Opt_keyauth:
 			if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
 				return -EINVAL;
diff --git a/security/keys/trusted.h b/security/keys/trusted.h
index 3249fbd..6a9f373 100644
--- a/security/keys/trusted.h
+++ b/security/keys/trusted.h
@@ -3,12 +3,16 @@
 
 /* implementation specific TPM constants */
 #define MAX_PCRINFO_SIZE		64
-#define MAX_BUF_SIZE			512
+#define MAX_BUF_SIZE			1024
+#define MAX_KEYBLOB_SIZE		1024
 #define TPM_GETRANDOM_SIZE		14
 #define TPM_OSAP_SIZE			36
 #define TPM_OIAP_SIZE			10
 #define TPM_SEAL_SIZE			87
 #define TPM_UNSEAL_SIZE			104
+#define TPM_LOADKEY2_SIZE		59
+#define TPM_EVICTKEY_SIZE		14
+#define TPM_FLUSHSPECIFIC_SIZE		18
 #define TPM_SIZE_OFFSET			2
 #define TPM_RETURN_OFFSET		6
 #define TPM_DATA_OFFSET			10
@@ -17,6 +21,8 @@
 #define LOAD32N(buffer, offset)	(*(uint32_t *)&buffer[offset])
 #define LOAD16(buffer, offset)	(ntohs(*(uint16_t *)&buffer[offset]))
 
+#define TPM_KEY12_EXPSIZE_OFFSET 31
+
 struct tpm_buf {
 	int len;
 	unsigned char data[MAX_BUF_SIZE];
@@ -39,6 +45,9 @@ enum {
 struct trusted_key_options {
 	uint16_t keytype;
 	uint32_t keyhandle;
+	uint32_t keyblob_len;
+	unsigned char keyblob[MAX_KEYBLOB_SIZE];
+	unsigned char srkauth[SHA1_DIGEST_SIZE];
 	unsigned char keyauth[SHA1_DIGEST_SIZE];
 	unsigned char blobauth[SHA1_DIGEST_SIZE];
 	uint32_t pcrinfo_len;
@@ -52,7 +61,12 @@ struct trusted_key_options {
 static inline void dump_options(struct trusted_key_options *o)
 {
 	pr_info("trusted_key: sealing key type %d\n", o->keytype);
-	pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
+	if (o->keyblob_len > 0) {
+		pr_info("trusted_key: sealing key blob %d\n", o->keyblob_len);
+		print_hex_dump(KERN_INFO, "keyblob ", DUMP_PREFIX_NONE,
+			      16, 1, o->keyblob, o->keyblob_len, 0);
+	} else
+		pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
 	pr_info("trusted_key: pcrlock %d\n", o->pcrlock);
 	pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len);
 	print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
@@ -90,6 +104,11 @@ static inline void dump_tpm_buf(unsigned char *buf)
 	len = LOAD32(buf, TPM_SIZE_OFFSET);
 	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
 }
+static inline void dump_tpm_key12_handle(uint32_t handle)
+{
+	print_hex_dump(KERN_INFO, "trusted-key: key handle ", DUMP_PREFIX_NONE,
+		       16, 1, &handle, 4, 0);
+}
 #else
 static inline void dump_options(struct trusted_key_options *o)
 {
@@ -106,6 +125,10 @@ static inline void dump_sess(struct osapsess *s)
 static inline void dump_tpm_buf(unsigned char *buf)
 {
 }
+
+static inline void dump_tpm_key12_handle(uint32_t handle)
+{
+}
 #endif
 
 static inline void store8(struct tpm_buf *buf, const unsigned char value)
-- 
1.7.6.4


Download attachment "smime.p7s" of type "application/x-pkcs7-signature" (2061 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ