trusted-keys: additional TSS return code and other error handling
[pandora-kernel.git] / security / keys / trusted_defined.c
index aaaa069..3dc3db1 100644 (file)
@@ -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 @@ out:
 /*
  * 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 @@ out:
 /*
  * 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 @@ out:
 /*
  * 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,9 +316,12 @@ 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;
@@ -319,6 +329,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
        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;
@@ -326,6 +338,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
        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;
 }