Provide a wrapper for memcpy to load bytes out of the reply, similar to LOAD32() and friends. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- drivers/char/tpm/tpm-library.c | 87 ++++++++++++++++++++-------------------- drivers/char/tpm/tpm-library.h | 43 +++++++++++++++++--- include/linux/tpm.h | 3 + 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 46cd12d30ec6..329b5c3f23a2 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -199,7 +199,7 @@ out: * @...: Pairs of size and pointer of data elements to load into hash * @0,NULL: Terminator */ -static int TSS_checkhmac1(unsigned char *buffer, +static int TSS_checkhmac1(struct tpm_buf *tb, __be32 ordinal, const struct tpm_odd_nonce *ononce, const unsigned char *key, unsigned keylen, @@ -219,14 +219,16 @@ static int TSS_checkhmac1(unsigned char *buffer, va_list argp; int ret; - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - result = LOAD32BE(buffer, TPM_RETURN_OFFSET); + SET_BUF_OFFSET(tb, 0); + tag = LOAD16(tb); + bufsize = LOAD32(tb); + result = LOAD32BE(tb); if (tag == TPM_TAG_RSP_COMMAND) return 0; if (tag != TPM_TAG_RSP_AUTH1_COMMAND) return -EINVAL; - authdata = buffer + bufsize - SHA1_DIGEST_SIZE; + + authdata = tb->data + bufsize - SHA1_DIGEST_SIZE; continueflag = authdata - 1; enonce = (void *)continueflag - TPM_NONCE_SIZE; @@ -255,7 +257,7 @@ static int TSS_checkhmac1(unsigned char *buffer, dpos = va_arg(argp, unsigned int); if (!dlen && !dpos) break; - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); + ret = crypto_shash_update(&sdesc->shash, tb->data + dpos, dlen); if (ret < 0) break; } @@ -296,7 +298,7 @@ out: * * verify the AUTH2_COMMAND (unseal) result from TPM */ -static int TSS_checkhmac2(const unsigned char *buffer, +static int TSS_checkhmac2(struct tpm_buf *tb, __be32 ordinal, const struct tpm_odd_nonce *ononce, const unsigned char *key1, unsigned keylen1, @@ -321,17 +323,17 @@ static int TSS_checkhmac2(const unsigned char *buffer, va_list argp; int ret; - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - result = LOAD32BE(buffer, TPM_RETURN_OFFSET); + bufsize = LOAD32(tb); + tag = LOAD16(tb); + result = LOAD32BE(tb); if (tag == TPM_TAG_RSP_COMMAND) return 0; if (tag != TPM_TAG_RSP_AUTH2_COMMAND) return -EINVAL; - authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 + authdata1 = tb->data + bufsize - (SHA1_DIGEST_SIZE + 1 + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); - authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); + authdata2 = tb->data + bufsize - (SHA1_DIGEST_SIZE); continueflag1 = authdata1 - 1; continueflag2 = authdata2 - 1; enonce1 = (const void *)continueflag1 - TPM_NONCE_SIZE; @@ -363,7 +365,7 @@ static int TSS_checkhmac2(const unsigned char *buffer, dpos = va_arg(argp, unsigned int); if (!dlen && !dpos) break; - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); + ret = crypto_shash_update(&sdesc->shash, tb->data + dpos, dlen); if (ret < 0) break; } @@ -404,17 +406,19 @@ out: * For key specific tpm requests, we will generate and send our * own TPM command packets using the drivers send function. */ -static int tpm_send_dump(struct tpm_chip *chip, - unsigned char *cmd, size_t buflen, const char *desc) +static int tpm_send_dump(struct tpm_chip *chip, struct tpm_buf *cmd, + const char *desc) { int rc; dump_tpm_buf(cmd); - rc = tpm_send_command(chip, cmd, buflen, desc); + rc = tpm_send_command(chip, cmd->data, MAX_BUF_SIZE, desc); dump_tpm_buf(cmd); if (rc > 0) /* Can't return positive return codes values to keyctl */ rc = -EPERM; + else + SET_BUF_OFFSET(cmd, TPM_DATA_OFFSET); return rc; } @@ -442,16 +446,14 @@ static int tpm_create_osap(struct tpm_chip *chip, store32(tb, keyhandle); store_s(tb, ononce.data, TPM_NONCE_SIZE); - ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, - "creating OSAP session"); + ret = tpm_send_dump(chip, tb, "creating OSAP session"); if (ret < 0) return ret; - s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(s->enonce.data, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), - TPM_NONCE_SIZE); - memcpy(enonce.data, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + - TPM_NONCE_SIZE]), TPM_NONCE_SIZE); + s->handle = LOAD32(tb); + LOAD_S(tb, s->enonce.data, TPM_NONCE_SIZE); + LOAD_S(tb, enonce.data, TPM_NONCE_SIZE); + return TSS_rawhmac(s->secret, keyauth, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, enonce.data, TPM_NONCE_SIZE, ononce.data, @@ -470,14 +472,12 @@ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); store32(tb, TPM_ORD_OIAP); - ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, - "creating OIAP session"); + ret = tpm_send_dump(chip, tb, "creating OIAP session"); if (ret < 0) return ret; - *handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(enonce->data, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], - TPM_NONCE_SIZE); + *handle = LOAD32(tb); + LOAD_S(tb, enonce->data, TPM_NONCE_SIZE); return 0; } @@ -590,27 +590,29 @@ int tpm_seal(struct tpm_chip *chip, store_8(tb, cont); store_s(tb, td->pubauth, SHA1_DIGEST_SIZE); - ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, - "sealing data"); + ret = tpm_send_dump(chip, tb, "sealing data"); if (ret < 0) goto out; - /* calculate the size of the returned encrypted data */ - sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t)); - encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) + - sizeof(uint32_t) + sealinfosize); - storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize + - sizeof(uint32_t) + encdatasize; + /* Look inside the TPM_STORED_DATA object to calculate the size of the + * returned encrypted data. + */ + SET_BUF_OFFSET(tb, TPM_DATA_OFFSET + sizeof(uint32_t)); + sealinfosize = LOAD32(tb); + SET_BUF_OFFSET(tb, TPM_DATA_OFFSET + sizeof(uint32_t) * 2 + sealinfosize); + storedsize = sizeof(uint32_t) * 2 + sealinfosize + + sizeof(uint32_t) + encdatasize; /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal_be, &td->ononce, + ret = TSS_checkhmac1(tb, ordinal_be, &td->ononce, sess.secret, SHA1_DIGEST_SIZE, /* 3S */ storedsize, TPM_DATA_OFFSET, 0, NULL); /* copy the encrypted data to caller's buffer */ if (!ret) { - memcpy(encbuffer, tb->data + TPM_DATA_OFFSET, storedsize); + SET_BUF_OFFSET(tb, TPM_DATA_OFFSET); + LOAD_S(tb, encbuffer, storedsize); *_enclen = storedsize; } out: @@ -697,15 +699,14 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, store_8(tb, cont); store_s(tb, authdata2, SHA1_DIGEST_SIZE); - ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, - "unsealing data"); + ret = tpm_send_dump(chip, tb, "unsealing data"); if (ret < 0) { pr_info("authhmac failed (%d)\n", ret); return ret; } - *_rawlen = LOAD32(tb->data, TPM_DATA_OFFSET); - ret = TSS_checkhmac2(tb->data, ordinal, &ononce, + *_rawlen = LOAD32(tb); + ret = TSS_checkhmac2(tb, ordinal, &ononce, keyauth, SHA1_DIGEST_SIZE, decauth, SHA1_DIGEST_SIZE, /* 3S */ sizeof(uint32_t), TPM_DATA_OFFSET, @@ -715,7 +716,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, pr_info("TSS_checkhmac2 failed (%d)\n", ret); return ret; } - memcpy(rawbuffer, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *_rawlen); + LOAD_S(tb, rawbuffer, *_rawlen); return 0; } EXPORT_SYMBOL_GPL(tpm_unseal); diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index c12d451704a2..3e288624b8e8 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -11,10 +11,6 @@ */ -#define LOAD32BE(buffer, offset) (*(__be32 *)&buffer[(offset)]) -#define LOAD16(buffer, offset) (be16_to_cpu(*(__be16 *)&buffer[(offset)])) -#define LOAD32(buffer, offset) (be32_to_cpu(LOAD32BE(buffer, (offset)))) - struct tpm_even_nonce { unsigned char data[TPM_NONCE_SIZE]; }; @@ -29,6 +25,38 @@ struct tpm_osapsess { struct tpm_even_nonce enonce; }; +static inline void SET_BUF_OFFSET(struct tpm_buf *buffer, unsigned offset) +{ + buffer->offset = offset; +} + +static inline uint16_t LOAD16(struct tpm_buf *buffer) +{ + __be16 *p = (__be16 *)(buffer->data + buffer->offset); + buffer->offset += 2; + return be16_to_cpup(p); +} + +static inline __be32 LOAD32BE(struct tpm_buf *buffer) +{ + __be32 val = *(__be32 *)(buffer->data + buffer->offset); + buffer->offset += 4; + return val; +} + +static inline uint32_t LOAD32(struct tpm_buf *buffer) +{ + __be32 *p = (__be32 *)(buffer->data + buffer->offset); + buffer->offset += 4; + return be32_to_cpup(p); +} + +static inline void LOAD_S(struct tpm_buf *buffer, void *data_buffer, size_t amount) +{ + memcpy(data_buffer, buffer->data + buffer->offset, amount); + buffer->offset += amount; +} + static inline void store_8(struct tpm_buf *buf, unsigned char value) { buf->data[buf->len++] = value; @@ -70,13 +98,14 @@ static inline void dump_sess(struct tpm_osapsess *s) 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); } -static inline void dump_tpm_buf(unsigned char *buf) +static inline void dump_tpm_buf(struct tpm_buf *tb) { int len; pr_info("\ntpm buffer\n"); - len = LOAD32(buf, TPM_SIZE_OFFSET); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); + SET_BUF_OFFSET(tb, TPM_SIZE_OFFSET); + len = LOAD32(tb); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, tb->data, len, 0); } #else diff --git a/include/linux/tpm.h b/include/linux/tpm.h index cbd13e03a869..398bfaef2325 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -110,7 +110,8 @@ enum tpm_entity_type { }; struct tpm_buf { - int len; + unsigned short len; + unsigned short offset; unsigned char data[MAX_BUF_SIZE]; };