[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4EB2852D.2060300@polito.it>
Date: Thu, 03 Nov 2011 13:12:29 +0100
From: Roberto Sassu <roberto.sassu@...ito.it>
To: unlisted-recipients:; (no To-header on input)
CC: David Safford <safford@...son.ibm.com>, keyrings@...ux-nfs.org,
linux-security-module@...r.kernel.org,
linux-kernel@...r.kernel.org, zohar@...ibm.com,
dhowells@...hat.com, jmorris@...ei.org
Subject: Re: [PATCH 2/2] trusted-key: added support for loading a key blob
in the TPM
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@...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)
>>
>> 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@...r.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@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists