Skip to content

Commit

Permalink
trusted-keys: additional TSS return code and other error handling
Browse files Browse the repository at this point in the history
Previously not all TSS return codes were tested, as they were all eventually
caught by the TPM. Now all returns are tested and handled immediately.

This patch also fixes memory leaks in error and non-error paths.

Signed-off-by: David Safford <safford@watson.ibm.com>
Acked-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: David Howells <dhowells@redhat.com>
Acked-by: Serge E. Hallyn <serge@hallyn.com>
Signed-off-by: James Morris <jmorris@namei.org>
  • Loading branch information
Mimi Zohar authored and James Morris committed Dec 15, 2010
1 parent 38ef4c2 commit bc5e0af
Showing 1 changed file with 87 additions and 62 deletions.
149 changes: 87 additions & 62 deletions security/keys/trusted_defined.c
Original file line number Diff line number Diff line change
@@ -108,7 +108,8 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
goto out;
}
va_end(argp);
ret = crypto_shash_final(&sdesc->shash, digest);
if (!ret)
ret = crypto_shash_final(&sdesc->shash, digest);
out:
kfree(sdesc);
return ret;
@@ -117,9 +118,9 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
/*
* calculate authorization info fields to send to TPM
*/
static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
const unsigned int keylen, unsigned char *h1,
unsigned char *h2, unsigned char h3, ...)
static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
const unsigned int keylen, unsigned char *h1,
unsigned char *h2, unsigned char h3, ...)
{
unsigned char paramdigest[SHA1_DIGEST_SIZE];
struct sdesc *sdesc;
@@ -146,15 +147,17 @@ static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
break;
data = va_arg(argp, unsigned char *);
ret = crypto_shash_update(&sdesc->shash, data, dlen);
if (ret < 0)
if (ret < 0) {
va_end(argp);
goto out;
}
}
va_end(argp);
ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (!ret)
TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
paramdigest, TPM_NONCE_SIZE, h1,
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
paramdigest, TPM_NONCE_SIZE, h1,
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
out:
kfree(sdesc);
return ret;
@@ -163,11 +166,11 @@ static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
/*
* verify the AUTH1_COMMAND (Seal) result from TPM
*/
static uint32_t TSS_checkhmac1(unsigned char *buffer,
const uint32_t command,
const unsigned char *ononce,
const unsigned char *key,
const unsigned int keylen, ...)
static int TSS_checkhmac1(unsigned char *buffer,
const uint32_t command,
const unsigned char *ononce,
const unsigned char *key,
const unsigned int keylen, ...)
{
uint32_t bufsize;
uint16_t tag;
@@ -219,18 +222,22 @@ static uint32_t TSS_checkhmac1(unsigned char *buffer,
break;
dpos = va_arg(argp, unsigned int);
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
if (ret < 0)
if (ret < 0) {
va_end(argp);
goto out;
}
}
va_end(argp);
ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (ret < 0)
goto out;

ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
1, continueflag, 0, 0);
if (ret < 0)
goto out;

if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
ret = -EINVAL;
out:
@@ -241,13 +248,13 @@ static uint32_t TSS_checkhmac1(unsigned char *buffer,
/*
* verify the AUTH2_COMMAND (unseal) result from TPM
*/
static uint32_t TSS_checkhmac2(unsigned char *buffer,
const uint32_t command,
const unsigned char *ononce,
const unsigned char *key1,
const unsigned int keylen1,
const unsigned char *key2,
const unsigned int keylen2, ...)
static int TSS_checkhmac2(unsigned char *buffer,
const uint32_t command,
const unsigned char *ononce,
const unsigned char *key1,
const unsigned int keylen1,
const unsigned char *key2,
const unsigned int keylen2, ...)
{
uint32_t bufsize;
uint16_t tag;
@@ -309,23 +316,30 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
break;
dpos = va_arg(argp, unsigned int);
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
if (ret < 0)
if (ret < 0) {
va_end(argp);
goto out;
}
}
va_end(argp);
ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (ret < 0)
goto out;

ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
paramdigest, TPM_NONCE_SIZE, enonce1,
TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
if (ret < 0)
goto out;
if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
ret = -EINVAL;
goto out;
}
ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
paramdigest, TPM_NONCE_SIZE, enonce2,
TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
if (ret < 0)
goto out;
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
ret = -EINVAL;
out:
@@ -364,8 +378,8 @@ static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
store32(tb, TPM_ORD_GETRANDOM);
store32(tb, len);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);

if (!ret)
memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
return ret;
}

@@ -392,10 +406,13 @@ static int my_get_random(unsigned char *buf, int len)
static int pcrlock(const int pcrnum)
{
unsigned char hash[SHA1_DIGEST_SIZE];
int ret;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
my_get_random(hash, SHA1_DIGEST_SIZE);
ret = my_get_random(hash, SHA1_DIGEST_SIZE);
if (ret < 0)
return ret;
return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
}

@@ -431,9 +448,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
TPM_NONCE_SIZE);
memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
ret = TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
enonce, TPM_NONCE_SIZE, ononce, 0, 0);
return ret;
return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
enonce, TPM_NONCE_SIZE, ononce, 0, 0);
}

/*
@@ -454,7 +470,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
*handle = LOAD32(tb->data, TPM_DATA_OFFSET);
memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
TPM_NONCE_SIZE);
return ret;
return 0;
}

struct tpm_digests {
@@ -521,20 +537,23 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
/* calculate authorization HMAC value */
if (pcrinfosize == 0) {
/* no pcr info specified */
TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
&ordinal, SHA1_DIGEST_SIZE, td->encauth,
sizeof(uint32_t), &pcrsize, sizeof(uint32_t),
&datsize, datalen, data, 0, 0);
ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
sess.enonce, td->nonceodd, cont,
sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
td->encauth, sizeof(uint32_t), &pcrsize,
sizeof(uint32_t), &datsize, datalen, data, 0,
0);
} else {
/* pcr info specified */
TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
&ordinal, SHA1_DIGEST_SIZE, td->encauth,
sizeof(uint32_t), &pcrsize, pcrinfosize,
pcrinfo, sizeof(uint32_t), &datsize, datalen,
data, 0, 0);
ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
sess.enonce, td->nonceodd, cont,
sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
td->encauth, sizeof(uint32_t), &pcrsize,
pcrinfosize, pcrinfo, sizeof(uint32_t),
&datsize, datalen, data, 0, 0);
}
if (ret < 0)
return ret;

/* build and send the TPM request packet */
INIT_BUF(tb);
@@ -569,8 +588,10 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
0);

/* copy the returned blob to caller */
memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
*bloblen = storedsize;
if (!ret) {
memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
*bloblen = storedsize;
}
return ret;
}

@@ -614,12 +635,16 @@ static int tpm_unseal(struct tpm_buf *tb,
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
}
TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
enonce1, nonceodd, cont, sizeof(uint32_t),
&ordinal, bloblen, blob, 0, 0);
TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
enonce2, nonceodd, cont, sizeof(uint32_t),
&ordinal, bloblen, blob, 0, 0);
ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
enonce1, nonceodd, cont, sizeof(uint32_t),
&ordinal, bloblen, blob, 0, 0);
if (ret < 0)
return ret;
ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
enonce2, nonceodd, cont, sizeof(uint32_t),
&ordinal, bloblen, blob, 0, 0);
if (ret < 0)
return ret;

/* build and send TPM request packet */
INIT_BUF(tb);
@@ -650,10 +675,12 @@ static int tpm_unseal(struct tpm_buf *tb,
sizeof(uint32_t), TPM_DATA_OFFSET,
*datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
0);
if (ret < 0)
if (ret < 0) {
pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
return ret;
}
memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
return ret;
return 0;
}

/*
@@ -697,11 +724,11 @@ static int key_unseal(struct trusted_key_payload *p,

ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];

if (ret < 0)
pr_info("trusted_key: srkunseal failed (%d)\n", ret);
else
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];

kfree(tb);
return ret;
@@ -854,12 +881,11 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options;

options = kzalloc(sizeof *options, GFP_KERNEL);
if (!options)
return options;

/* set any non-zero defaults */
options->keytype = SRK_keytype;
options->keyhandle = SRKHANDLE;
if (options) {
/* set any non-zero defaults */
options->keytype = SRK_keytype;
options->keyhandle = SRKHANDLE;
}
return options;
}

@@ -872,9 +898,8 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
if (ret < 0)
return p;
p = kzalloc(sizeof *p, GFP_KERNEL);

/* migratable by default */
p->migratable = 1;
if (p)
p->migratable = 1; /* migratable by default */
return p;
}

0 comments on commit bc5e0af

Please sign in to comment.