trusted-keys: additional TSS return code and other error handling
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>
This commit is contained in:
parent
38ef4c2e43
commit
bc5e0af0b3
|
@ -108,7 +108,8 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
ret = crypto_shash_final(&sdesc->shash, digest);
|
if (!ret)
|
||||||
|
ret = crypto_shash_final(&sdesc->shash, digest);
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -117,9 +118,9 @@ out:
|
||||||
/*
|
/*
|
||||||
* calculate authorization info fields to send to TPM
|
* calculate authorization info fields to send to TPM
|
||||||
*/
|
*/
|
||||||
static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
|
static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
|
||||||
const unsigned int keylen, unsigned char *h1,
|
const unsigned int keylen, unsigned char *h1,
|
||||||
unsigned char *h2, unsigned char h3, ...)
|
unsigned char *h2, unsigned char h3, ...)
|
||||||
{
|
{
|
||||||
unsigned char paramdigest[SHA1_DIGEST_SIZE];
|
unsigned char paramdigest[SHA1_DIGEST_SIZE];
|
||||||
struct sdesc *sdesc;
|
struct sdesc *sdesc;
|
||||||
|
@ -146,15 +147,17 @@ static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
|
||||||
break;
|
break;
|
||||||
data = va_arg(argp, unsigned char *);
|
data = va_arg(argp, unsigned char *);
|
||||||
ret = crypto_shash_update(&sdesc->shash, data, dlen);
|
ret = crypto_shash_update(&sdesc->shash, data, dlen);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
va_end(argp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
|
ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
|
||||||
paramdigest, TPM_NONCE_SIZE, h1,
|
paramdigest, TPM_NONCE_SIZE, h1,
|
||||||
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
|
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -163,11 +166,11 @@ out:
|
||||||
/*
|
/*
|
||||||
* verify the AUTH1_COMMAND (Seal) result from TPM
|
* verify the AUTH1_COMMAND (Seal) result from TPM
|
||||||
*/
|
*/
|
||||||
static uint32_t TSS_checkhmac1(unsigned char *buffer,
|
static int TSS_checkhmac1(unsigned char *buffer,
|
||||||
const uint32_t command,
|
const uint32_t command,
|
||||||
const unsigned char *ononce,
|
const unsigned char *ononce,
|
||||||
const unsigned char *key,
|
const unsigned char *key,
|
||||||
const unsigned int keylen, ...)
|
const unsigned int keylen, ...)
|
||||||
{
|
{
|
||||||
uint32_t bufsize;
|
uint32_t bufsize;
|
||||||
uint16_t tag;
|
uint16_t tag;
|
||||||
|
@ -219,18 +222,22 @@ static uint32_t TSS_checkhmac1(unsigned char *buffer,
|
||||||
break;
|
break;
|
||||||
dpos = va_arg(argp, unsigned int);
|
dpos = va_arg(argp, unsigned int);
|
||||||
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
|
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
va_end(argp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
|
ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
|
||||||
TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
|
TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
|
||||||
1, continueflag, 0, 0);
|
1, continueflag, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
|
if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
out:
|
out:
|
||||||
|
@ -241,13 +248,13 @@ out:
|
||||||
/*
|
/*
|
||||||
* verify the AUTH2_COMMAND (unseal) result from TPM
|
* verify the AUTH2_COMMAND (unseal) result from TPM
|
||||||
*/
|
*/
|
||||||
static uint32_t TSS_checkhmac2(unsigned char *buffer,
|
static int TSS_checkhmac2(unsigned char *buffer,
|
||||||
const uint32_t command,
|
const uint32_t command,
|
||||||
const unsigned char *ononce,
|
const unsigned char *ononce,
|
||||||
const unsigned char *key1,
|
const unsigned char *key1,
|
||||||
const unsigned int keylen1,
|
const unsigned int keylen1,
|
||||||
const unsigned char *key2,
|
const unsigned char *key2,
|
||||||
const unsigned int keylen2, ...)
|
const unsigned int keylen2, ...)
|
||||||
{
|
{
|
||||||
uint32_t bufsize;
|
uint32_t bufsize;
|
||||||
uint16_t tag;
|
uint16_t tag;
|
||||||
|
@ -309,9 +316,12 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
|
||||||
break;
|
break;
|
||||||
dpos = va_arg(argp, unsigned int);
|
dpos = va_arg(argp, unsigned int);
|
||||||
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
|
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
va_end(argp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
va_end(argp);
|
||||||
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
ret = crypto_shash_final(&sdesc->shash, paramdigest);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -319,6 +329,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
|
||||||
ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
|
ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
|
||||||
paramdigest, TPM_NONCE_SIZE, enonce1,
|
paramdigest, TPM_NONCE_SIZE, enonce1,
|
||||||
TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
|
TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
|
if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -326,6 +338,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
|
||||||
ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
|
ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
|
||||||
paramdigest, TPM_NONCE_SIZE, enonce2,
|
paramdigest, TPM_NONCE_SIZE, enonce2,
|
||||||
TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
|
TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
|
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
out:
|
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, TPM_ORD_GETRANDOM);
|
||||||
store32(tb, len);
|
store32(tb, len);
|
||||||
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,10 +406,13 @@ static int my_get_random(unsigned char *buf, int len)
|
||||||
static int pcrlock(const int pcrnum)
|
static int pcrlock(const int pcrnum)
|
||||||
{
|
{
|
||||||
unsigned char hash[SHA1_DIGEST_SIZE];
|
unsigned char hash[SHA1_DIGEST_SIZE];
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
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;
|
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);
|
TPM_NONCE_SIZE);
|
||||||
memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
|
memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
|
||||||
TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
|
TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
|
||||||
ret = TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
|
return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
|
||||||
enonce, TPM_NONCE_SIZE, ononce, 0, 0);
|
enonce, TPM_NONCE_SIZE, ononce, 0, 0);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -454,7 +470,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
|
||||||
*handle = LOAD32(tb->data, TPM_DATA_OFFSET);
|
*handle = LOAD32(tb->data, TPM_DATA_OFFSET);
|
||||||
memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
|
memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
|
||||||
TPM_NONCE_SIZE);
|
TPM_NONCE_SIZE);
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tpm_digests {
|
struct tpm_digests {
|
||||||
|
@ -521,20 +537,23 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
|
||||||
/* calculate authorization HMAC value */
|
/* calculate authorization HMAC value */
|
||||||
if (pcrinfosize == 0) {
|
if (pcrinfosize == 0) {
|
||||||
/* no pcr info specified */
|
/* no pcr info specified */
|
||||||
TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
|
ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
|
||||||
sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
|
sess.enonce, td->nonceodd, cont,
|
||||||
&ordinal, SHA1_DIGEST_SIZE, td->encauth,
|
sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
|
||||||
sizeof(uint32_t), &pcrsize, sizeof(uint32_t),
|
td->encauth, sizeof(uint32_t), &pcrsize,
|
||||||
&datsize, datalen, data, 0, 0);
|
sizeof(uint32_t), &datsize, datalen, data, 0,
|
||||||
|
0);
|
||||||
} else {
|
} else {
|
||||||
/* pcr info specified */
|
/* pcr info specified */
|
||||||
TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
|
ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
|
||||||
sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
|
sess.enonce, td->nonceodd, cont,
|
||||||
&ordinal, SHA1_DIGEST_SIZE, td->encauth,
|
sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
|
||||||
sizeof(uint32_t), &pcrsize, pcrinfosize,
|
td->encauth, sizeof(uint32_t), &pcrsize,
|
||||||
pcrinfo, sizeof(uint32_t), &datsize, datalen,
|
pcrinfosize, pcrinfo, sizeof(uint32_t),
|
||||||
data, 0, 0);
|
&datsize, datalen, data, 0, 0);
|
||||||
}
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* build and send the TPM request packet */
|
/* build and send the TPM request packet */
|
||||||
INIT_BUF(tb);
|
INIT_BUF(tb);
|
||||||
|
@ -569,8 +588,10 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
/* copy the returned blob to caller */
|
/* copy the returned blob to caller */
|
||||||
memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
|
if (!ret) {
|
||||||
*bloblen = storedsize;
|
memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
|
||||||
|
*bloblen = storedsize;
|
||||||
|
}
|
||||||
return ret;
|
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);
|
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
|
ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
|
||||||
enonce1, nonceodd, cont, sizeof(uint32_t),
|
enonce1, nonceodd, cont, sizeof(uint32_t),
|
||||||
&ordinal, bloblen, blob, 0, 0);
|
&ordinal, bloblen, blob, 0, 0);
|
||||||
TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
|
if (ret < 0)
|
||||||
enonce2, nonceodd, cont, sizeof(uint32_t),
|
return ret;
|
||||||
&ordinal, bloblen, blob, 0, 0);
|
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 */
|
/* build and send TPM request packet */
|
||||||
INIT_BUF(tb);
|
INIT_BUF(tb);
|
||||||
|
@ -650,10 +675,12 @@ static int tpm_unseal(struct tpm_buf *tb,
|
||||||
sizeof(uint32_t), TPM_DATA_OFFSET,
|
sizeof(uint32_t), TPM_DATA_OFFSET,
|
||||||
*datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
|
*datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
|
||||||
0);
|
0);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
|
pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
|
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,
|
ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
|
||||||
o->blobauth, p->key, &p->key_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)
|
if (ret < 0)
|
||||||
pr_info("trusted_key: srkunseal failed (%d)\n", ret);
|
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);
|
kfree(tb);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -854,12 +881,11 @@ static struct trusted_key_options *trusted_options_alloc(void)
|
||||||
struct trusted_key_options *options;
|
struct trusted_key_options *options;
|
||||||
|
|
||||||
options = kzalloc(sizeof *options, GFP_KERNEL);
|
options = kzalloc(sizeof *options, GFP_KERNEL);
|
||||||
if (!options)
|
if (options) {
|
||||||
return options;
|
/* set any non-zero defaults */
|
||||||
|
options->keytype = SRK_keytype;
|
||||||
/* set any non-zero defaults */
|
options->keyhandle = SRKHANDLE;
|
||||||
options->keytype = SRK_keytype;
|
}
|
||||||
options->keyhandle = SRKHANDLE;
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,9 +898,8 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return p;
|
return p;
|
||||||
p = kzalloc(sizeof *p, GFP_KERNEL);
|
p = kzalloc(sizeof *p, GFP_KERNEL);
|
||||||
|
if (p)
|
||||||
/* migratable by default */
|
p->migratable = 1; /* migratable by default */
|
||||||
p->migratable = 1;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue