All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] trusted-key: allow overwriting the migratable flag
@ 2011-11-02 12:41 Roberto Sassu
  2011-11-02 12:41 ` [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM Roberto Sassu
  2011-11-02 16:58 ` [PATCH 1/2] trusted-key: allow overwriting the migratable flag David Safford
  0 siblings, 2 replies; 8+ messages in thread
From: Roberto Sassu @ 2011-11-02 12:41 UTC (permalink / raw)
  To: keyrings
  Cc: linux-security-module, linux-kernel, safford, zohar, dhowells,
	jmorris, Roberto Sassu

[-- Attachment #1: Type: text/plain, Size: 823 bytes --]

The migratable should be modifiable during the key update() method. This
allows for example to update a migratable trusted key, wrapped by a TPM
key, to a a non-migratable one sealed under the SRK with a PCR set.

Signed-off-by: Roberto Sassu <roberto.sassu@polito.it>
---
 security/keys/trusted.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 0c33e2e..8777015 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -1036,7 +1036,6 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
 		goto out;
 	}
 	/* copy old key values, and reseal with new pcrs */
-	new_p->migratable = p->migratable;
 	new_p->key_len = p->key_len;
 	memcpy(new_p->key, p->key, p->key_len);
 	dump_payload(p);
-- 
1.7.6.4


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 2061 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM
  2011-11-02 12:41 [PATCH 1/2] trusted-key: allow overwriting the migratable flag Roberto Sassu
@ 2011-11-02 12:41 ` Roberto Sassu
  2011-11-02 17:26   ` David Safford
  2011-11-02 16:58 ` [PATCH 1/2] trusted-key: allow overwriting the migratable flag David Safford
  1 sibling, 1 reply; 8+ messages in thread
From: Roberto Sassu @ 2011-11-02 12:41 UTC (permalink / raw)
  To: keyrings
  Cc: linux-security-module, linux-kernel, safford, zohar, dhowells,
	jmorris, Roberto Sassu

[-- Attachment #1: Type: text/plain, Size: 12736 bytes --]

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@polito.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


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 2061 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] trusted-key: allow overwriting the migratable flag
  2011-11-02 12:41 [PATCH 1/2] trusted-key: allow overwriting the migratable flag Roberto Sassu
  2011-11-02 12:41 ` [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM Roberto Sassu
@ 2011-11-02 16:58 ` David Safford
  2011-11-02 17:37   ` Roberto Sassu
  1 sibling, 1 reply; 8+ messages in thread
From: David Safford @ 2011-11-02 16:58 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: keyrings, linux-security-module, linux-kernel, zohar, dhowells, jmorris

On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
> The migratable should be modifiable during the key update() method. This
> allows for example to update a migratable trusted key, wrapped by a TPM
> key, to a a non-migratable one sealed under the SRK with a PCR set.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@polito.it>

I can see a use case for updating a migratable key to a non-migratable
one - such as keeping a migratable master on a flash drive, and keeping
only the non-migratable copy on-line. I certainly don't want the 
ability to change a non-migratable to migratable, as that would defeat
the entire purpose of non-migratable.

I don't think this patch actually does either, though. 

> ---
>  security/keys/trusted.c |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
> 
> diff --git a/security/keys/trusted.c b/security/keys/trusted.c
> index 0c33e2e..8777015 100644
> --- a/security/keys/trusted.c
> +++ b/security/keys/trusted.c
> @@ -1036,7 +1036,6 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
>  		goto out;
>  	}
>  	/* copy old key values, and reseal with new pcrs */
> -	new_p->migratable = p->migratable;

Taking out this line appears only to remove a redundant assignment.
We can only get here if the old key is already migratable, and the
earlier trusted_payload_alloc() initializes the new copy to
migratable by default. I don't see how the flag can be changed
with this patch. Perhaps I'm missing something or this was just 
the start, and there is more to come?

dave

>  	new_p->key_len = p->key_len;
>  	memcpy(new_p->key, p->key, p->key_len);
>  	dump_payload(p);


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM
  2011-11-02 12:41 ` [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM Roberto Sassu
@ 2011-11-02 17:26   ` David Safford
  2011-11-02 17:43     ` Roberto Sassu
  0 siblings, 1 reply; 8+ messages in thread
From: David Safford @ 2011-11-02 17:26 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: keyrings, linux-security-module, linux-kernel, zohar, dhowells, jmorris

On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
> 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.

This looks like a nice extension.
I'll test it out thoroughly, but for now here are a couple of 
minor initial suggestions...

dave

> 
> Signed-off-by: Roberto Sassu <roberto.sassu@polito.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)

static?

> +{
> +	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)

static?

> +{
> +	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)


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] trusted-key: allow overwriting the migratable flag
  2011-11-02 16:58 ` [PATCH 1/2] trusted-key: allow overwriting the migratable flag David Safford
@ 2011-11-02 17:37   ` Roberto Sassu
  2011-11-02 17:46     ` David Safford
  0 siblings, 1 reply; 8+ messages in thread
From: Roberto Sassu @ 2011-11-02 17:37 UTC (permalink / raw)
  To: David Safford
  Cc: keyrings, linux-security-module, linux-kernel, zohar, dhowells, jmorris

On 11/02/2011 05:58 PM, David Safford wrote:
> On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
>> The migratable should be modifiable during the key update() method. This
>> allows for example to update a migratable trusted key, wrapped by a TPM
>> key, to a a non-migratable one sealed under the SRK with a PCR set.
>>
>> Signed-off-by: Roberto Sassu<roberto.sassu@polito.it>
>
> I can see a use case for updating a migratable key to a non-migratable
> one - such as keeping a migratable master on a flash drive, and keeping
> only the non-migratable copy on-line. I certainly don't want the
> ability to change a non-migratable to migratable, as that would defeat
> the entire purpose of non-migratable.
>
> I don't think this patch actually does either, though.
>
>> ---
>>   security/keys/trusted.c |    1 -
>>   1 files changed, 0 insertions(+), 1 deletions(-)
>>
>> diff --git a/security/keys/trusted.c b/security/keys/trusted.c
>> index 0c33e2e..8777015 100644
>> --- a/security/keys/trusted.c
>> +++ b/security/keys/trusted.c
>> @@ -1036,7 +1036,6 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
>>   		goto out;
>>   	}
>>   	/* copy old key values, and reseal with new pcrs */
>> -	new_p->migratable = p->migratable;
>
> Taking out this line appears only to remove a redundant assignment.
> We can only get here if the old key is already migratable, and the
> earlier trusted_payload_alloc() initializes the new copy to
> migratable by default. I don't see how the flag can be changed
> with this patch. Perhaps I'm missing something or this was just
> the start, and there is more to come?
>

Hi Dave

i think this line should be removed because it overwrites
the assignment made in datablob_parse() -> getoptions().

You can see this behaviour by executing the following commands:

1) keyctl add trusted kmk "new 32" @u
2) keyctl update $(keyctl search @u trusted kmk) "update migratable=0"
3) keyctl update $(keyctl search @u trusted kmk) "update migratable=0"

The third operation should fail because of the lines at the
begin of trusted_update():

---------
	if (!p->migratable)
		return -EPERM;
---------

but instead, without the patch, it is performed successfully.

Thanks

Roberto Sassu


> dave
>
>>   	new_p->key_len = p->key_len;
>>   	memcpy(new_p->key, p->key, p->key_len);
>>   	dump_payload(p);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM
  2011-11-02 17:26   ` David Safford
@ 2011-11-02 17:43     ` Roberto Sassu
  2011-11-03 12:12       ` Roberto Sassu
  0 siblings, 1 reply; 8+ messages in thread
From: Roberto Sassu @ 2011-11-02 17:43 UTC (permalink / raw)
  To: David Safford
  Cc: keyrings, linux-security-module, linux-kernel, zohar, dhowells, jmorris

On 11/02/2011 06:26 PM, David Safford wrote:
> On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
>> 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.
>
> This looks like a nice extension.
> I'll test it out thoroughly, but for now here are a couple of
> minor initial suggestions...
>

Thanks, i will fix them and submit a new version of
the patches after receiving other comments.

Roberto Sassu


> dave
>
>>
>> Signed-off-by: Roberto Sassu<roberto.sassu@polito.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)
>
> static?
>
>> +{
>> +	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)
>
> static?
>
>> +{
>> +	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)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] trusted-key: allow overwriting the migratable flag
  2011-11-02 17:37   ` Roberto Sassu
@ 2011-11-02 17:46     ` David Safford
  0 siblings, 0 replies; 8+ messages in thread
From: David Safford @ 2011-11-02 17:46 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: keyrings, linux-security-module, linux-kernel, zohar, dhowells, jmorris

On Wed, 2011-11-02 at 18:37 +0100, Roberto Sassu wrote:
> On 11/02/2011 05:58 PM, David Safford wrote:
> > On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
> >> The migratable should be modifiable during the key update() method. This
> >> allows for example to update a migratable trusted key, wrapped by a TPM
> >> key, to a a non-migratable one sealed under the SRK with a PCR set.
> >>
> >> Signed-off-by: Roberto Sassu<roberto.sassu@polito.it>
> >
> > I can see a use case for updating a migratable key to a non-migratable
> > one - such as keeping a migratable master on a flash drive, and keeping
> > only the non-migratable copy on-line. I certainly don't want the
> > ability to change a non-migratable to migratable, as that would defeat
> > the entire purpose of non-migratable.
> >
> > I don't think this patch actually does either, though.
> >
> >> ---
> >>   security/keys/trusted.c |    1 -
> >>   1 files changed, 0 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/security/keys/trusted.c b/security/keys/trusted.c
> >> index 0c33e2e..8777015 100644
> >> --- a/security/keys/trusted.c
> >> +++ b/security/keys/trusted.c
> >> @@ -1036,7 +1036,6 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
> >>   		goto out;
> >>   	}
> >>   	/* copy old key values, and reseal with new pcrs */
> >> -	new_p->migratable = p->migratable;
> >
> > Taking out this line appears only to remove a redundant assignment.
> > We can only get here if the old key is already migratable, and the
> > earlier trusted_payload_alloc() initializes the new copy to
> > migratable by default. I don't see how the flag can be changed
> > with this patch. Perhaps I'm missing something or this was just
> > the start, and there is more to come?
> >
> 
> Hi Dave
> 
> i think this line should be removed because it overwrites
> the assignment made in datablob_parse() -> getoptions().
> 
> You can see this behaviour by executing the following commands:
> 
> 1) keyctl add trusted kmk "new 32" @u
> 2) keyctl update $(keyctl search @u trusted kmk) "update migratable=0"
> 3) keyctl update $(keyctl search @u trusted kmk) "update migratable=0"
> 
> The third operation should fail because of the lines at the
> begin of trusted_update():
> 
> ---------
> 	if (!p->migratable)
> 		return -EPERM;
> ---------
> 
> but instead, without the patch, it is performed successfully.
> 
> Thanks
> 
> Roberto Sassu

Sorry - you are absolutely correct. The patch looks good,
and it is safe, as it allows only migratable -> non-migratable updates.
Give me a day to test both...
dave

> 
> > dave
> >
> >>   	new_p->key_len = p->key_len;
> >>   	memcpy(new_p->key, p->key, p->key_len);
> >>   	dump_payload(p);
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM
  2011-11-02 17:43     ` Roberto Sassu
@ 2011-11-03 12:12       ` Roberto Sassu
  0 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2011-11-03 12:12 UTC (permalink / raw)
  Cc: David Safford, keyrings, linux-security-module, linux-kernel,
	zohar, dhowells, jmorris

On 11/02/2011 06:43 PM, Roberto Sassu wrote:
> On 11/02/2011 06:26 PM, David Safford wrote:
>> On Wed, 2011-11-02 at 13:41 +0100, Roberto Sassu wrote:
>>> 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.
>>
>> This looks like a nice extension.
>> I'll test it out thoroughly, but for now here are a couple of
>> minor initial suggestions...
>>
>

Hi Dave

i've just discovered another issue in the patches.
MAX_KEYBLOB_SIZE should not be equal to MAX_BUF_SIZE,
because otherwise a buffer overflow may occur in the
allocated 'tpm_buf' structure during the tpm_loadkey2()
function.

So, in the new patches i've set:

#define MAX_KEYBLOB_SIZE ( MAX_BUF_SIZE - TPM_LOADKEY2_SIZE )


and i've fixed the checks in getoptions()

------
if (strlen(args[0].from) > MAX_KEYBLOB_SIZE * 2)
------

------
if (opt->keyblob_len > MAX_KEYBLOB_SIZE)
------

by replacing '>=' with '>'.


Roberto Sassu


> Thanks, i will fix them and submit a new version of
> the patches after receiving other comments.
>
> Roberto Sassu
>
>
>> dave
>>
>>>
>>> Signed-off-by: Roberto Sassu<roberto.sassu@polito.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)
>>
>> static?
>>
>>> +{
>>> + 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)
>>
>> static?
>>
>>> +{
>>> + 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)
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-security-module" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-11-03 12:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-02 12:41 [PATCH 1/2] trusted-key: allow overwriting the migratable flag Roberto Sassu
2011-11-02 12:41 ` [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM Roberto Sassu
2011-11-02 17:26   ` David Safford
2011-11-02 17:43     ` Roberto Sassu
2011-11-03 12:12       ` Roberto Sassu
2011-11-02 16:58 ` [PATCH 1/2] trusted-key: allow overwriting the migratable flag David Safford
2011-11-02 17:37   ` Roberto Sassu
2011-11-02 17:46     ` David Safford

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.