From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755978Ab1KBRaP (ORCPT ); Wed, 2 Nov 2011 13:30:15 -0400 Received: from igw2.watson.ibm.com ([129.34.20.6]:58692 "EHLO igw2.watson.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750774Ab1KBRaN convert rfc822-to-8bit (ORCPT ); Wed, 2 Nov 2011 13:30:13 -0400 Subject: Re: [PATCH 2/2] trusted-key: added support for loading a key blob in the TPM From: David Safford To: Roberto Sassu Cc: keyrings@linux-nfs.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, zohar@us.ibm.com, dhowells@redhat.com, jmorris@namei.org Date: Wed, 02 Nov 2011 13:26:06 -0400 In-Reply-To: <1320237682-3857-2-git-send-email-roberto.sassu@polito.it> References: <1320237682-3857-1-git-send-email-roberto.sassu@polito.it> <1320237682-3857-2-git-send-email-roberto.sassu@polito.it> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8BIT X-Mailer: Evolution 3.0.3 (3.0.3-1.fc15) Message-ID: <1320254766.3225.18.camel@localhost> Mime-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 > --- > 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)